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::arrays::bool::BoolArrayExt;
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 .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}