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