1pub mod arithmetic;
19pub mod constructors;
20pub mod filled;
21pub mod mask_ops;
22pub mod masked_array;
23pub mod reductions;
24pub mod sorting;
25pub mod ufunc_support;
26
27pub use masked_array::MaskedArray;
29
30pub use constructors::{
32 masked_equal, masked_greater, masked_greater_equal, masked_inside, masked_invalid, masked_less,
33 masked_less_equal, masked_not_equal, masked_outside, masked_where,
34};
35
36pub use arithmetic::{
38 masked_add, masked_add_array, masked_div, masked_div_array, masked_mul, masked_mul_array,
39 masked_sub, masked_sub_array,
40};
41
42pub use mask_ops::{count_masked, getdata, getmask, is_masked};
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use ferray_core::Array;
49 use ferray_core::dimension::Ix1;
50
51 #[test]
55 fn ac1_masked_mean_skips_masked() {
56 let data =
57 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0, 2.0, 3.0, 4.0, 5.0]).unwrap();
58 let mask =
59 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, false, true, false, false])
60 .unwrap();
61 let ma = MaskedArray::new(data, mask).unwrap();
62 let mean = ma.mean().unwrap();
63 assert!((mean - 3.0).abs() < 1e-10);
65 }
66
67 #[test]
71 fn ac2_filled_replaces_masked() {
72 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
73 let mask =
74 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, true, false, true]).unwrap();
75 let ma = MaskedArray::new(data, mask).unwrap();
76 let filled = ma.filled(0.0).unwrap();
77 assert_eq!(filled.as_slice().unwrap(), &[1.0, 0.0, 3.0, 0.0]);
78 }
79
80 #[test]
84 fn ac3_compressed_returns_unmasked() {
85 let data =
86 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![10.0, 20.0, 30.0, 40.0, 50.0]).unwrap();
87 let mask =
88 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, true, false, true, false])
89 .unwrap();
90 let ma = MaskedArray::new(data, mask).unwrap();
91 let compressed = ma.compressed().unwrap();
92 assert_eq!(compressed.as_slice().unwrap(), &[10.0, 30.0, 50.0]);
93 }
94
95 #[test]
99 fn ac4_masked_invalid_nan_inf() {
100 let data =
101 Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, f64::NAN, 3.0, f64::INFINITY])
102 .unwrap();
103 let ma = masked_invalid(&data).unwrap();
104 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
105 assert_eq!(mask_vals, vec![false, true, false, true]);
106 }
107
108 #[test]
112 fn ac5_add_mask_union() {
113 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
114 let m1 =
115 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, true, false, false]).unwrap();
116 let ma1 = MaskedArray::new(d1, m1).unwrap();
117
118 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![10.0, 20.0, 30.0, 40.0]).unwrap();
119 let m2 =
120 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, false, true, false]).unwrap();
121 let ma2 = MaskedArray::new(d2, m2).unwrap();
122
123 let result = masked_add(&ma1, &ma2).unwrap();
124 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
125 assert_eq!(mask_vals, vec![false, true, true, false]);
127 let data_vals: Vec<f64> = result.data().iter().copied().collect();
129 assert!((data_vals[0] - 11.0).abs() < 1e-10);
130 assert!((data_vals[3] - 44.0).abs() < 1e-10);
131 }
132
133 #[test]
137 fn ac7_ufunc_sin_masked() {
138 use std::f64::consts::FRAC_PI_2;
139 let data =
140 Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![0.0, FRAC_PI_2, FRAC_PI_2]).unwrap();
141 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
142 let ma = MaskedArray::new(data, mask).unwrap();
143 let result = ufunc_support::sin(&ma).unwrap();
144 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
145 assert_eq!(mask_vals, vec![false, true, false]);
146 let data_vals: Vec<f64> = result.data().iter().copied().collect();
147 assert!((data_vals[0] - 0.0).abs() < 1e-10);
149 assert!((data_vals[2] - 1.0).abs() < 1e-10);
150 }
151
152 #[test]
156 fn ac8_sort_masked_at_end() {
157 let data =
158 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![5.0, 1.0, 3.0, 2.0, 4.0]).unwrap();
159 let mask =
160 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, false, true, false, false])
161 .unwrap();
162 let ma = MaskedArray::new(data, mask).unwrap();
163 let sorted = ma.sort().unwrap();
164 let data_vals: Vec<f64> = sorted.data().iter().copied().collect();
165 let mask_vals: Vec<bool> = sorted.mask().iter().copied().collect();
166 assert_eq!(data_vals, vec![1.0, 2.0, 4.0, 5.0, 3.0]);
168 assert_eq!(mask_vals, vec![false, false, false, false, true]);
169 }
170
171 #[test]
172 fn ac8_harden_mask_prevents_clearing() {
173 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
174 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
175 let mut ma = MaskedArray::new(data, mask).unwrap();
176
177 ma.harden_mask().unwrap();
178 assert!(ma.is_hard_mask());
179
180 ma.set_mask_flat(1, false).unwrap();
182 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
183 assert_eq!(mask_vals, vec![false, true, false]);
184
185 ma.set_mask_flat(0, true).unwrap();
187 let mask_vals2: Vec<bool> = ma.mask().iter().copied().collect();
188 assert_eq!(mask_vals2, vec![true, true, false]);
189
190 ma.soften_mask().unwrap();
192 assert!(!ma.is_hard_mask());
193 ma.set_mask_flat(1, false).unwrap();
194 let mask_vals3: Vec<bool> = ma.mask().iter().copied().collect();
195 assert_eq!(mask_vals3, vec![true, false, false]);
196 }
197
198 #[test]
202 fn ac9_is_masked() {
203 let data1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
204 let mask1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
205 let ma1 = MaskedArray::new(data1, mask1).unwrap();
206 assert!(is_masked(&ma1).unwrap());
207
208 let data2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
209 let mask2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
210 let ma2 = MaskedArray::new(data2, mask2).unwrap();
211 assert!(!is_masked(&ma2).unwrap());
212 }
213
214 #[test]
219 fn shape_mismatch_error() {
220 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
221 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([2]), vec![false, true]).unwrap();
222 assert!(MaskedArray::new(data, mask).is_err());
223 }
224
225 #[test]
226 fn from_data_no_mask() {
227 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
228 let ma = MaskedArray::from_data(data).unwrap();
229 assert!(!is_masked(&ma).unwrap());
230 assert_eq!(ma.count().unwrap(), 3);
231 }
232
233 #[test]
234 fn sum_skips_masked() {
235 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
236 let mask =
237 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, true, false, true]).unwrap();
238 let ma = MaskedArray::new(data, mask).unwrap();
239 assert!((ma.sum().unwrap() - 4.0).abs() < 1e-10);
240 }
241
242 #[test]
243 fn min_max_skip_masked() {
244 let data =
245 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![5.0, 1.0, 3.0, 2.0, 4.0]).unwrap();
246 let mask =
247 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, true, false, false, false])
248 .unwrap();
249 let ma = MaskedArray::new(data, mask).unwrap();
250 assert!((ma.min().unwrap() - 2.0).abs() < 1e-10);
251 assert!((ma.max().unwrap() - 5.0).abs() < 1e-10);
252 }
253
254 #[test]
255 fn var_std_skip_masked() {
256 let data =
258 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![2.0, 99.0, 4.0, 6.0, 99.0]).unwrap();
259 let mask =
260 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, true, false, false, true])
261 .unwrap();
262 let ma = MaskedArray::new(data, mask).unwrap();
263 let mean = ma.mean().unwrap();
264 assert!((mean - 4.0).abs() < 1e-10);
265 let v = ma.var().unwrap();
267 assert!((v - 8.0 / 3.0).abs() < 1e-10);
268 let s = ma.std().unwrap();
269 assert!((s - (8.0_f64 / 3.0).sqrt()).abs() < 1e-10);
270 }
271
272 #[test]
273 fn count_elements() {
274 let data = Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0; 5]).unwrap();
275 let mask =
276 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, true, true, false, false])
277 .unwrap();
278 let ma = MaskedArray::new(data, mask).unwrap();
279 assert_eq!(ma.count().unwrap(), 3);
280 }
281
282 #[test]
283 fn masked_equal_test() {
284 let data =
285 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0, 2.0, 3.0, 2.0, 1.0]).unwrap();
286 let ma = masked_equal(&data, 2.0).unwrap();
287 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
288 assert_eq!(mask_vals, vec![false, true, false, true, false]);
289 }
290
291 #[test]
292 fn masked_greater_test() {
293 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
294 let ma = masked_greater(&data, 2.0).unwrap();
295 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
296 assert_eq!(mask_vals, vec![false, false, true, true]);
297 }
298
299 #[test]
300 fn masked_less_test() {
301 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
302 let ma = masked_less(&data, 3.0).unwrap();
303 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
304 assert_eq!(mask_vals, vec![true, true, false, false]);
305 }
306
307 #[test]
308 fn masked_not_equal_test() {
309 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
310 let ma = masked_not_equal(&data, 2.0).unwrap();
311 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
312 assert_eq!(mask_vals, vec![true, false, true]);
313 }
314
315 #[test]
316 fn masked_greater_equal_test() {
317 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
318 let ma = masked_greater_equal(&data, 3.0).unwrap();
319 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
320 assert_eq!(mask_vals, vec![false, false, true, true]);
321 }
322
323 #[test]
324 fn masked_less_equal_test() {
325 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
326 let ma = masked_less_equal(&data, 2.0).unwrap();
327 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
328 assert_eq!(mask_vals, vec![true, true, false, false]);
329 }
330
331 #[test]
332 fn masked_inside_test() {
333 let data =
334 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0, 2.0, 3.0, 4.0, 5.0]).unwrap();
335 let ma = masked_inside(&data, 2.0, 4.0).unwrap();
336 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
337 assert_eq!(mask_vals, vec![false, true, true, true, false]);
338 }
339
340 #[test]
341 fn masked_outside_test() {
342 let data =
343 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0, 2.0, 3.0, 4.0, 5.0]).unwrap();
344 let ma = masked_outside(&data, 2.0, 4.0).unwrap();
345 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
346 assert_eq!(mask_vals, vec![true, false, false, false, true]);
347 }
348
349 #[test]
350 fn masked_where_test() {
351 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
352 let cond =
353 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![true, false, true, false]).unwrap();
354 let ma = masked_where(&cond, &data).unwrap();
355 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
356 assert_eq!(mask_vals, vec![true, false, true, false]);
357 }
358
359 #[test]
360 fn argsort_test() {
361 let data =
362 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![5.0, 1.0, 3.0, 2.0, 4.0]).unwrap();
363 let mask =
364 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, false, true, false, false])
365 .unwrap();
366 let ma = MaskedArray::new(data, mask).unwrap();
367 let indices = ma.argsort().unwrap();
368 let idx_vals: Vec<usize> = indices.iter().copied().collect();
369 assert_eq!(idx_vals, vec![1, 3, 4, 0, 2]);
371 }
372
373 #[test]
374 fn getmask_getdata_test() {
375 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
376 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
377 let ma = MaskedArray::new(data.clone(), mask.clone()).unwrap();
378
379 let got_mask = getmask(&ma).unwrap();
380 let got_data = getdata(&ma).unwrap();
381
382 assert_eq!(got_mask.as_slice().unwrap(), mask.as_slice().unwrap());
383 assert_eq!(got_data.as_slice().unwrap(), data.as_slice().unwrap());
384 }
385
386 #[test]
387 fn count_masked_test() {
388 let data = Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0; 5]).unwrap();
389 let mask =
390 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![true, false, true, true, false])
391 .unwrap();
392 let ma = MaskedArray::new(data, mask).unwrap();
393 assert_eq!(count_masked(&ma, None).unwrap(), 3);
394 }
395
396 #[test]
397 fn masked_add_array_test() {
398 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
399 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
400 let ma = MaskedArray::new(data, mask).unwrap();
401 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![10.0, 20.0, 30.0]).unwrap();
402 let result = masked_add_array(&ma, &arr).unwrap();
403 let data_vals: Vec<f64> = result.data().iter().copied().collect();
404 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
405 assert_eq!(mask_vals, vec![false, true, false]);
406 assert!((data_vals[0] - 11.0).abs() < 1e-10);
407 assert!((data_vals[2] - 33.0).abs() < 1e-10);
408 }
409
410 #[test]
411 fn all_masked_mean_is_nan() {
412 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
413 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![true, true, true]).unwrap();
414 let ma = MaskedArray::new(data, mask).unwrap();
415 assert!(ma.mean().unwrap().is_nan());
416 }
417
418 #[test]
419 fn all_masked_min_errors() {
420 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
421 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![true, true, true]).unwrap();
422 let ma = MaskedArray::new(data, mask).unwrap();
423 assert!(ma.min().is_err());
424 }
425
426 #[test]
427 fn ufunc_exp_masked() {
428 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![0.0, 1.0, 2.0]).unwrap();
429 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
430 let ma = MaskedArray::new(data, mask).unwrap();
431 let result = ufunc_support::exp(&ma).unwrap();
432 let data_vals: Vec<f64> = result.data().iter().copied().collect();
433 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
434 assert_eq!(mask_vals, vec![false, true, false]);
435 assert!((data_vals[0] - 1.0).abs() < 1e-10); assert!((data_vals[2] - 2.0_f64.exp()).abs() < 1e-10);
437 }
438
439 #[test]
440 fn ufunc_sqrt_masked() {
441 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![4.0, 9.0, 16.0, 25.0]).unwrap();
442 let mask =
443 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, true, false, true]).unwrap();
444 let ma = MaskedArray::new(data, mask).unwrap();
445 let result = ufunc_support::sqrt(&ma).unwrap();
446 let data_vals: Vec<f64> = result.data().iter().copied().collect();
447 assert!((data_vals[0] - 2.0).abs() < 1e-10);
448 assert!((data_vals[2] - 4.0).abs() < 1e-10);
449 }
450
451 #[test]
452 fn set_mask_hardened() {
453 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
454 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
455 let mut ma = MaskedArray::new(data, mask).unwrap();
456 ma.harden_mask().unwrap();
457
458 let new_mask =
460 Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
461 ma.set_mask(new_mask).unwrap();
462 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
463 assert_eq!(mask_vals, vec![false, true, false]);
465 }
466
467 #[test]
468 fn masked_sub_test() {
469 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![10.0, 20.0, 30.0]).unwrap();
470 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, true]).unwrap();
471 let ma1 = MaskedArray::new(d1, m1).unwrap();
472
473 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
474 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
475 let ma2 = MaskedArray::new(d2, m2).unwrap();
476
477 let result = masked_sub(&ma1, &ma2).unwrap();
478 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
479 assert_eq!(mask_vals, vec![false, true, true]);
480 let data_vals: Vec<f64> = result.data().iter().copied().collect();
481 assert!((data_vals[0] - 9.0).abs() < 1e-10);
482 }
483
484 #[test]
485 fn masked_mul_test() {
486 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![2.0, 3.0, 4.0]).unwrap();
487 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
488 let ma1 = MaskedArray::new(d1, m1).unwrap();
489
490 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![5.0, 6.0, 7.0]).unwrap();
491 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
492 let ma2 = MaskedArray::new(d2, m2).unwrap();
493
494 let result = masked_mul(&ma1, &ma2).unwrap();
495 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
496 assert_eq!(mask_vals, vec![false, true, false]);
497 let data_vals: Vec<f64> = result.data().iter().copied().collect();
498 assert!((data_vals[0] - 10.0).abs() < 1e-10);
499 assert!((data_vals[2] - 28.0).abs() < 1e-10);
500 }
501
502 #[test]
503 fn masked_div_test() {
504 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![10.0, 20.0, 30.0]).unwrap();
505 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, true]).unwrap();
506 let ma1 = MaskedArray::new(d1, m1).unwrap();
507
508 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![2.0, 5.0, 6.0]).unwrap();
509 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
510 let ma2 = MaskedArray::new(d2, m2).unwrap();
511
512 let result = masked_div(&ma1, &ma2).unwrap();
513 let data_vals: Vec<f64> = result.data().iter().copied().collect();
514 assert!((data_vals[0] - 5.0).abs() < 1e-10);
515 assert!((data_vals[1] - 4.0).abs() < 1e-10);
516 }
517
518 #[test]
519 fn masked_invalid_negative_inf() {
520 let data =
521 Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, f64::NEG_INFINITY, 3.0]).unwrap();
522 let ma = masked_invalid(&data).unwrap();
523 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
524 assert_eq!(mask_vals, vec![false, true, false]);
525 }
526
527 #[test]
528 fn empty_array_operations() {
529 let data = Array::<f64, Ix1>::from_vec(Ix1::new([0]), vec![]).unwrap();
530 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([0]), vec![]).unwrap();
531 let ma = MaskedArray::new(data, mask).unwrap();
532 assert_eq!(ma.count().unwrap(), 0);
533 assert!(ma.mean().unwrap().is_nan());
534 let compressed = ma.compressed().unwrap();
535 assert_eq!(compressed.size(), 0);
536 }
537
538 #[test]
539 fn ndim_shape_size() {
540 let data = Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0; 5]).unwrap();
541 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false; 5]).unwrap();
542 let ma = MaskedArray::new(data, mask).unwrap();
543 assert_eq!(ma.ndim(), 1);
544 assert_eq!(ma.shape(), &[5]);
545 assert_eq!(ma.size(), 5);
546 }
547
548 #[test]
549 fn ufunc_binary_power() {
550 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![2.0, 3.0, 4.0]).unwrap();
551 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
552 let ma1 = MaskedArray::new(d1, m1).unwrap();
553
554 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![3.0, 2.0, 2.0]).unwrap();
555 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
556 let ma2 = MaskedArray::new(d2, m2).unwrap();
557
558 let result = ufunc_support::power(&ma1, &ma2).unwrap();
559 let data_vals: Vec<f64> = result.data().iter().copied().collect();
560 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
561 assert_eq!(mask_vals, vec![false, true, false]);
562 assert!((data_vals[0] - 8.0).abs() < 1e-10); assert!((data_vals[2] - 16.0).abs() < 1e-10); }
565
566 #[test]
567 fn filled_with_custom_value() {
568 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
569 let mask =
570 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![true, false, true, false]).unwrap();
571 let ma = MaskedArray::new(data, mask).unwrap();
572 let filled = ma.filled(-999.0).unwrap();
573 assert_eq!(filled.as_slice().unwrap(), &[-999.0, 2.0, -999.0, 4.0]);
574 }
575}