vortex_array/compute/conformance/
mask.rs1use vortex_error::VortexExpect;
5use vortex_mask::Mask;
6
7use crate::ArrayRef;
8use crate::IntoArray;
9use crate::arrays::BoolArray;
10use crate::builtins::ArrayBuiltins;
11
12pub fn test_mask_conformance(array: &ArrayRef) {
15 let len = array.len();
16
17 if len > 0 {
18 test_heterogenous_mask(array);
19 test_empty_mask(array);
20 test_full_mask(array);
21 test_alternating_mask(array);
22 test_sparse_mask(array);
23 test_single_element_mask(array);
24 }
25
26 if len >= 5 {
27 test_double_mask(array);
28 }
29
30 if len > 0 {
31 test_nullable_mask_input(array);
32 }
33}
34
35fn test_heterogenous_mask(array: &ArrayRef) {
37 let len = array.len();
38
39 let mask_pattern: Vec<bool> = (0..len).map(|i| i % 3 != 1).collect();
41 let mask_array = Mask::from_iter(mask_pattern.clone());
42
43 let masked = array
44 .clone()
45 .mask((!&mask_array).into_array())
46 .vortex_expect("mask should succeed in conformance test");
47 assert_eq!(masked.len(), array.len());
48
49 for (i, &masked_out) in mask_pattern.iter().enumerate() {
51 if masked_out {
52 assert!(
53 !masked
54 .is_valid(i)
55 .vortex_expect("is_valid should succeed in conformance test")
56 );
57 } else {
58 assert_eq!(
59 masked
60 .scalar_at(i)
61 .vortex_expect("scalar_at should succeed in conformance test"),
62 array
63 .scalar_at(i)
64 .vortex_expect("scalar_at should succeed in conformance test")
65 .into_nullable()
66 );
67 }
68 }
69}
70
71fn test_empty_mask(array: &ArrayRef) {
73 let len = array.len();
74 let all_unmasked = vec![false; len];
75 let mask_array = Mask::from_iter(all_unmasked);
76
77 let masked = array
78 .clone()
79 .mask((!&mask_array).into_array())
80 .vortex_expect("mask should succeed in conformance test");
81 assert_eq!(masked.len(), array.len());
82
83 for i in 0..len {
85 assert_eq!(
86 masked
87 .scalar_at(i)
88 .vortex_expect("scalar_at should succeed in conformance test"),
89 array
90 .scalar_at(i)
91 .vortex_expect("scalar_at should succeed in conformance test")
92 .into_nullable()
93 );
94 }
95}
96
97fn test_full_mask(array: &ArrayRef) {
99 let len = array.len();
100 let all_masked = vec![true; len];
101 let mask_array = Mask::from_iter(all_masked);
102
103 let masked = array
104 .clone()
105 .mask((!&mask_array).into_array())
106 .vortex_expect("mask should succeed in conformance test");
107 assert_eq!(masked.len(), array.len());
108
109 for i in 0..len {
111 assert!(
112 !masked
113 .is_valid(i)
114 .vortex_expect("is_valid should succeed in conformance test")
115 );
116 }
117}
118
119fn test_alternating_mask(array: &ArrayRef) {
121 let len = array.len();
122 let pattern: Vec<bool> = (0..len).map(|i| i % 2 == 0).collect();
123 let mask_array = Mask::from_iter(pattern);
124
125 let masked = array
126 .clone()
127 .mask((!&mask_array).into_array())
128 .vortex_expect("mask should succeed in conformance test");
129 assert_eq!(masked.len(), array.len());
130
131 for i in 0..len {
132 if i % 2 == 0 {
133 assert!(
134 !masked
135 .is_valid(i)
136 .vortex_expect("is_valid should succeed in conformance test")
137 );
138 } else {
139 assert_eq!(
140 masked
141 .scalar_at(i)
142 .vortex_expect("scalar_at should succeed in conformance test"),
143 array
144 .scalar_at(i)
145 .vortex_expect("scalar_at should succeed in conformance test")
146 .into_nullable()
147 );
148 }
149 }
150}
151
152fn test_sparse_mask(array: &ArrayRef) {
154 let len = array.len();
155 if len < 10 {
156 return; }
158
159 let pattern: Vec<bool> = (0..len).map(|i| i % 10 == 0).collect();
161 let mask_array = Mask::from_iter(pattern.clone());
162
163 let masked = array
164 .clone()
165 .mask((!&mask_array).into_array())
166 .vortex_expect("mask should succeed in conformance test");
167 assert_eq!(masked.len(), array.len());
168
169 let valid_count = (0..len)
171 .filter(|&i| {
172 masked
173 .is_valid(i)
174 .vortex_expect("is_valid should succeed in conformance test")
175 })
176 .count();
177
178 let expected_invalid_count = (0..len)
182 .filter(|&i| {
183 pattern[i]
184 || !array
185 .is_valid(i)
186 .vortex_expect("is_valid should succeed in conformance test")
187 })
188 .count();
189
190 assert_eq!(valid_count, len - expected_invalid_count);
191}
192
193fn test_single_element_mask(array: &ArrayRef) {
195 let len = array.len();
196
197 let mut pattern = vec![false; len];
199 pattern[0] = true;
200 let mask_array = Mask::from_iter(pattern);
201
202 let masked = array
203 .clone()
204 .mask((!&mask_array).into_array())
205 .vortex_expect("mask should succeed in conformance test");
206 assert!(
207 !masked
208 .is_valid(0)
209 .vortex_expect("is_valid should succeed in conformance test")
210 );
211
212 for i in 1..len {
213 assert_eq!(
214 masked
215 .scalar_at(i)
216 .vortex_expect("scalar_at should succeed in conformance test"),
217 array
218 .scalar_at(i)
219 .vortex_expect("scalar_at should succeed in conformance test")
220 .into_nullable()
221 );
222 }
223}
224
225fn test_double_mask(array: &ArrayRef) {
227 let len = array.len();
228
229 let mask1_pattern: Vec<bool> = (0..len).map(|i| i % 3 == 0).collect();
231 let mask2_pattern: Vec<bool> = (0..len).map(|i| i % 2 == 0).collect();
232
233 let mask1 = Mask::from_iter(mask1_pattern.clone());
234 let mask2 = Mask::from_iter(mask2_pattern.clone());
235
236 let first_masked = array
237 .clone()
238 .mask((!&mask1).into_array())
239 .vortex_expect("mask should succeed in conformance test");
240 let double_masked = first_masked
241 .clone()
242 .mask((!&mask2).into_array())
243 .vortex_expect("mask should succeed in conformance test");
244
245 for i in 0..len {
247 if mask1_pattern[i] || mask2_pattern[i] {
248 assert!(
249 !double_masked
250 .is_valid(i)
251 .vortex_expect("is_valid should succeed in conformance test")
252 );
253 } else {
254 assert_eq!(
255 double_masked
256 .scalar_at(i)
257 .vortex_expect("scalar_at should succeed in conformance test"),
258 array
259 .scalar_at(i)
260 .vortex_expect("scalar_at should succeed in conformance test")
261 .into_nullable()
262 );
263 }
264 }
265}
266
267fn test_nullable_mask_input(array: &ArrayRef) {
269 let len = array.len();
270 if len < 3 {
271 return; }
273
274 let bool_values: Vec<bool> = (0..len).map(|i| i % 2 == 0).collect();
276 let validity_values: Vec<bool> = (0..len).map(|i| i % 3 != 0).collect();
277
278 let bool_array = BoolArray::from_iter(bool_values.clone());
279 let validity = crate::validity::Validity::from_iter(validity_values.clone());
280 let nullable_mask = BoolArray::new(bool_array.to_bit_buffer(), validity);
281
282 let mask_array = nullable_mask.to_mask_fill_null_false();
283 let masked = array
284 .clone()
285 .mask((!&mask_array).into_array())
286 .vortex_expect("mask should succeed in conformance test");
287
288 for i in 0..len {
290 if bool_values[i] && validity_values[i] {
291 assert!(
292 !masked
293 .is_valid(i)
294 .vortex_expect("is_valid should succeed in conformance test")
295 );
296 } else {
297 assert_eq!(
298 masked
299 .scalar_at(i)
300 .vortex_expect("scalar_at should succeed in conformance test"),
301 array
302 .scalar_at(i)
303 .vortex_expect("scalar_at should succeed in conformance test")
304 .into_nullable()
305 );
306 }
307 }
308}