1pub mod arithmetic;
19pub mod constructors;
20pub mod filled;
21pub mod interop;
22#[cfg(feature = "io")]
28pub mod io;
29pub mod manipulation;
30pub mod mask_ops;
31pub mod masked_array;
32pub mod reductions;
33pub mod sorting;
34pub mod ufunc_support;
35
36pub use masked_array::MaskedArray;
38
39pub use constructors::{
41 fix_invalid, masked_equal, masked_greater, masked_greater_equal, masked_inside, masked_invalid,
42 masked_less, masked_less_equal, masked_not_equal, masked_outside, masked_where,
43};
44
45pub use arithmetic::{
47 masked_add, masked_add_array, masked_div, masked_div_array, masked_mul, masked_mul_array,
48 masked_sub, masked_sub_array,
49};
50
51pub use mask_ops::{count_masked, getdata, getmask, is_masked};
53
54pub use interop::{MaskAware, ma_apply_unary};
57
58pub use ufunc_support::{masked_binary, masked_unary};
63
64pub use ufunc_support::{
67 arccos_domain, arccosh_domain, arcsin_domain, arctanh_domain, divide_domain, log_domain,
68 log2_domain, log10_domain, masked_binary_domain, masked_unary_domain, sqrt_domain,
69};
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use ferray_core::Array;
75 use ferray_core::dimension::Ix1;
76
77 #[test]
81 fn ac1_masked_mean_skips_masked() {
82 let data =
83 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0, 2.0, 3.0, 4.0, 5.0]).unwrap();
84 let mask =
85 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, false, true, false, false])
86 .unwrap();
87 let ma = MaskedArray::new(data, mask).unwrap();
88 let mean = ma.mean().unwrap();
89 assert!((mean - 3.0).abs() < 1e-10);
91 }
92
93 #[test]
97 fn ac2_filled_replaces_masked() {
98 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
99 let mask =
100 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, true, false, true]).unwrap();
101 let ma = MaskedArray::new(data, mask).unwrap();
102 let filled = ma.filled(0.0).unwrap();
103 assert_eq!(filled.as_slice().unwrap(), &[1.0, 0.0, 3.0, 0.0]);
104 }
105
106 #[test]
110 fn ac3_compressed_returns_unmasked() {
111 let data =
112 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![10.0, 20.0, 30.0, 40.0, 50.0]).unwrap();
113 let mask =
114 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, true, false, true, false])
115 .unwrap();
116 let ma = MaskedArray::new(data, mask).unwrap();
117 let compressed = ma.compressed().unwrap();
118 assert_eq!(compressed.as_slice().unwrap(), &[10.0, 30.0, 50.0]);
119 }
120
121 #[test]
125 fn ac4_masked_invalid_nan_inf() {
126 let data =
127 Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, f64::NAN, 3.0, f64::INFINITY])
128 .unwrap();
129 let ma = masked_invalid(&data).unwrap();
130 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
131 assert_eq!(mask_vals, vec![false, true, false, true]);
132 }
133
134 #[test]
138 fn ac5_add_mask_union() {
139 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
140 let m1 =
141 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, true, false, false]).unwrap();
142 let ma1 = MaskedArray::new(d1, m1).unwrap();
143
144 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![10.0, 20.0, 30.0, 40.0]).unwrap();
145 let m2 =
146 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, false, true, false]).unwrap();
147 let ma2 = MaskedArray::new(d2, m2).unwrap();
148
149 let result = masked_add(&ma1, &ma2).unwrap();
150 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
151 assert_eq!(mask_vals, vec![false, true, true, false]);
153 let data_vals: Vec<f64> = result.data().iter().copied().collect();
155 assert!((data_vals[0] - 11.0).abs() < 1e-10);
156 assert!((data_vals[3] - 44.0).abs() < 1e-10);
157 }
158
159 #[test]
160 fn operator_add_matches_masked_add() {
161 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
162 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
163 let ma1 = MaskedArray::new(d1, m1).unwrap();
164
165 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![10.0, 20.0, 30.0]).unwrap();
166 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, true]).unwrap();
167 let ma2 = MaskedArray::new(d2, m2).unwrap();
168
169 let result = (&ma1 + &ma2).unwrap();
171 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
172 assert_eq!(mask_vals, vec![false, true, true]);
173 let data_vals: Vec<f64> = result.data().iter().copied().collect();
174 assert!((data_vals[0] - 11.0).abs() < 1e-10);
175 }
176
177 #[test]
181 fn ac7_ufunc_sin_masked() {
182 use std::f64::consts::FRAC_PI_2;
183 let data =
184 Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![0.0, FRAC_PI_2, FRAC_PI_2]).unwrap();
185 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
186 let ma = MaskedArray::new(data, mask).unwrap();
187 let result = ufunc_support::sin(&ma).unwrap();
188 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
189 assert_eq!(mask_vals, vec![false, true, false]);
190 let data_vals: Vec<f64> = result.data().iter().copied().collect();
191 assert!((data_vals[0] - 0.0).abs() < 1e-10);
193 assert!((data_vals[2] - 1.0).abs() < 1e-10);
194 }
195
196 #[test]
200 fn ac8_sort_masked_at_end() {
201 let data =
202 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![5.0, 1.0, 3.0, 2.0, 4.0]).unwrap();
203 let mask =
204 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, false, true, false, false])
205 .unwrap();
206 let ma = MaskedArray::new(data, mask).unwrap();
207 let sorted = ma.sort().unwrap();
208 let data_vals: Vec<f64> = sorted.data().iter().copied().collect();
209 let mask_vals: Vec<bool> = sorted.mask().iter().copied().collect();
210 assert_eq!(data_vals, vec![1.0, 2.0, 4.0, 5.0, 3.0]);
212 assert_eq!(mask_vals, vec![false, false, false, false, true]);
213 }
214
215 #[test]
216 fn ac8_harden_mask_prevents_clearing() {
217 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
218 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
219 let mut ma = MaskedArray::new(data, mask).unwrap();
220
221 ma.harden_mask().unwrap();
222 assert!(ma.is_hard_mask());
223
224 ma.set_mask_flat(1, false).unwrap();
226 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
227 assert_eq!(mask_vals, vec![false, true, false]);
228
229 ma.set_mask_flat(0, true).unwrap();
231 let mask_vals2: Vec<bool> = ma.mask().iter().copied().collect();
232 assert_eq!(mask_vals2, vec![true, true, false]);
233
234 ma.soften_mask().unwrap();
236 assert!(!ma.is_hard_mask());
237 ma.set_mask_flat(1, false).unwrap();
238 let mask_vals3: Vec<bool> = ma.mask().iter().copied().collect();
239 assert_eq!(mask_vals3, vec![true, false, false]);
240 }
241
242 #[test]
246 fn ac9_is_masked() {
247 let data1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
248 let mask1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
249 let ma1 = MaskedArray::new(data1, mask1).unwrap();
250 assert!(is_masked(&ma1).unwrap());
251
252 let data2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
253 let mask2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
254 let ma2 = MaskedArray::new(data2, mask2).unwrap();
255 assert!(!is_masked(&ma2).unwrap());
256 }
257
258 #[test]
263 fn shape_mismatch_error() {
264 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
265 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([2]), vec![false, true]).unwrap();
266 assert!(MaskedArray::new(data, mask).is_err());
267 }
268
269 #[test]
270 fn from_data_no_mask() {
271 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
272 let ma = MaskedArray::from_data(data).unwrap();
273 assert!(!is_masked(&ma).unwrap());
274 assert_eq!(ma.count().unwrap(), 3);
275 }
276
277 #[test]
278 fn sum_skips_masked() {
279 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
280 let mask =
281 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, true, false, true]).unwrap();
282 let ma = MaskedArray::new(data, mask).unwrap();
283 assert!((ma.sum().unwrap() - 4.0).abs() < 1e-10);
284 }
285
286 #[test]
287 fn min_max_skip_masked() {
288 let data =
289 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![5.0, 1.0, 3.0, 2.0, 4.0]).unwrap();
290 let mask =
291 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, true, false, false, false])
292 .unwrap();
293 let ma = MaskedArray::new(data, mask).unwrap();
294 assert!((ma.min().unwrap() - 2.0).abs() < 1e-10);
295 assert!((ma.max().unwrap() - 5.0).abs() < 1e-10);
296 }
297
298 #[test]
299 fn var_std_skip_masked() {
300 let data =
302 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![2.0, 99.0, 4.0, 6.0, 99.0]).unwrap();
303 let mask =
304 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, true, false, false, true])
305 .unwrap();
306 let ma = MaskedArray::new(data, mask).unwrap();
307 let mean = ma.mean().unwrap();
308 assert!((mean - 4.0).abs() < 1e-10);
309 let v = ma.var().unwrap();
311 assert!((v - 8.0 / 3.0).abs() < 1e-10);
312 let s = ma.std().unwrap();
313 assert!((s - (8.0_f64 / 3.0).sqrt()).abs() < 1e-10);
314 }
315
316 #[test]
317 fn count_elements() {
318 let data = Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0; 5]).unwrap();
319 let mask =
320 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, true, true, false, false])
321 .unwrap();
322 let ma = MaskedArray::new(data, mask).unwrap();
323 assert_eq!(ma.count().unwrap(), 3);
324 }
325
326 #[test]
327 fn masked_equal_test() {
328 let data =
329 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0, 2.0, 3.0, 2.0, 1.0]).unwrap();
330 let ma = masked_equal(&data, 2.0).unwrap();
331 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
332 assert_eq!(mask_vals, vec![false, true, false, true, false]);
333 }
334
335 #[test]
336 fn masked_greater_test() {
337 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
338 let ma = masked_greater(&data, 2.0).unwrap();
339 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
340 assert_eq!(mask_vals, vec![false, false, true, true]);
341 }
342
343 #[test]
344 fn masked_less_test() {
345 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
346 let ma = masked_less(&data, 3.0).unwrap();
347 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
348 assert_eq!(mask_vals, vec![true, true, false, false]);
349 }
350
351 #[test]
352 fn masked_not_equal_test() {
353 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
354 let ma = masked_not_equal(&data, 2.0).unwrap();
355 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
356 assert_eq!(mask_vals, vec![true, false, true]);
357 }
358
359 #[test]
360 fn masked_greater_equal_test() {
361 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
362 let ma = masked_greater_equal(&data, 3.0).unwrap();
363 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
364 assert_eq!(mask_vals, vec![false, false, true, true]);
365 }
366
367 #[test]
368 fn masked_less_equal_test() {
369 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
370 let ma = masked_less_equal(&data, 2.0).unwrap();
371 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
372 assert_eq!(mask_vals, vec![true, true, false, false]);
373 }
374
375 #[test]
376 fn masked_inside_test() {
377 let data =
378 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0, 2.0, 3.0, 4.0, 5.0]).unwrap();
379 let ma = masked_inside(&data, 2.0, 4.0).unwrap();
380 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
381 assert_eq!(mask_vals, vec![false, true, true, true, false]);
382 }
383
384 #[test]
385 fn masked_outside_test() {
386 let data =
387 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0, 2.0, 3.0, 4.0, 5.0]).unwrap();
388 let ma = masked_outside(&data, 2.0, 4.0).unwrap();
389 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
390 assert_eq!(mask_vals, vec![true, false, false, false, true]);
391 }
392
393 #[test]
394 fn masked_where_test() {
395 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
396 let cond =
397 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![true, false, true, false]).unwrap();
398 let ma = masked_where(&cond, &data).unwrap();
399 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
400 assert_eq!(mask_vals, vec![true, false, true, false]);
401 }
402
403 #[test]
404 fn argsort_test() {
405 let data =
406 Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![5.0, 1.0, 3.0, 2.0, 4.0]).unwrap();
407 let mask =
408 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false, false, true, false, false])
409 .unwrap();
410 let ma = MaskedArray::new(data, mask).unwrap();
411 let indices = ma.argsort().unwrap();
412 let idx_vals: Vec<usize> = indices.to_vec();
413 assert_eq!(idx_vals, vec![1, 3, 4, 0, 2]);
415 }
416
417 #[test]
418 fn getmask_getdata_test() {
419 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
420 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
421 let ma = MaskedArray::new(data.clone(), mask.clone()).unwrap();
422
423 let got_mask = getmask(&ma).unwrap();
424 let got_data = getdata(&ma).unwrap();
425
426 assert_eq!(got_mask.as_slice().unwrap(), mask.as_slice().unwrap());
427 assert_eq!(got_data.as_slice().unwrap(), data.as_slice().unwrap());
428 }
429
430 #[test]
431 fn count_masked_test() {
432 let data = Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0; 5]).unwrap();
433 let mask =
434 Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![true, false, true, true, false])
435 .unwrap();
436 let ma = MaskedArray::new(data, mask).unwrap();
437 assert_eq!(count_masked(&ma, None).unwrap(), 3);
438 }
439
440 #[test]
441 fn masked_add_array_test() {
442 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
443 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
444 let ma = MaskedArray::new(data, mask).unwrap();
445 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![10.0, 20.0, 30.0]).unwrap();
446 let result = masked_add_array(&ma, &arr).unwrap();
447 let data_vals: Vec<f64> = result.data().iter().copied().collect();
448 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
449 assert_eq!(mask_vals, vec![false, true, false]);
450 assert!((data_vals[0] - 11.0).abs() < 1e-10);
451 assert!((data_vals[2] - 33.0).abs() < 1e-10);
452 }
453
454 #[test]
455 fn all_masked_mean_is_nan() {
456 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
457 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![true, true, true]).unwrap();
458 let ma = MaskedArray::new(data, mask).unwrap();
459 assert!(ma.mean().unwrap().is_nan());
460 }
461
462 #[test]
463 fn all_masked_min_errors() {
464 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
465 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![true, true, true]).unwrap();
466 let ma = MaskedArray::new(data, mask).unwrap();
467 assert!(ma.min().is_err());
468 }
469
470 #[test]
471 fn ufunc_exp_masked() {
472 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![0.0, 1.0, 2.0]).unwrap();
473 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
474 let ma = MaskedArray::new(data, mask).unwrap();
475 let result = ufunc_support::exp(&ma).unwrap();
476 let data_vals: Vec<f64> = result.data().iter().copied().collect();
477 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
478 assert_eq!(mask_vals, vec![false, true, false]);
479 assert!((data_vals[0] - 1.0).abs() < 1e-10); assert!((data_vals[2] - 2.0_f64.exp()).abs() < 1e-10);
481 }
482
483 #[test]
484 fn ufunc_sqrt_masked() {
485 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![4.0, 9.0, 16.0, 25.0]).unwrap();
486 let mask =
487 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![false, true, false, true]).unwrap();
488 let ma = MaskedArray::new(data, mask).unwrap();
489 let result = ufunc_support::sqrt(&ma).unwrap();
490 let data_vals: Vec<f64> = result.data().iter().copied().collect();
491 assert!((data_vals[0] - 2.0).abs() < 1e-10);
492 assert!((data_vals[2] - 4.0).abs() < 1e-10);
493 }
494
495 #[test]
496 fn set_mask_hardened() {
497 let data = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
498 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
499 let mut ma = MaskedArray::new(data, mask).unwrap();
500 ma.harden_mask().unwrap();
501
502 let new_mask =
504 Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
505 ma.set_mask(new_mask).unwrap();
506 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
507 assert_eq!(mask_vals, vec![false, true, false]);
509 }
510
511 #[test]
512 fn masked_sub_test() {
513 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![10.0, 20.0, 30.0]).unwrap();
514 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, true]).unwrap();
515 let ma1 = MaskedArray::new(d1, m1).unwrap();
516
517 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
518 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
519 let ma2 = MaskedArray::new(d2, m2).unwrap();
520
521 let result = masked_sub(&ma1, &ma2).unwrap();
522 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
523 assert_eq!(mask_vals, vec![false, true, true]);
524 let data_vals: Vec<f64> = result.data().iter().copied().collect();
525 assert!((data_vals[0] - 9.0).abs() < 1e-10);
526 }
527
528 #[test]
529 fn masked_mul_test() {
530 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![2.0, 3.0, 4.0]).unwrap();
531 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
532 let ma1 = MaskedArray::new(d1, m1).unwrap();
533
534 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![5.0, 6.0, 7.0]).unwrap();
535 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
536 let ma2 = MaskedArray::new(d2, m2).unwrap();
537
538 let result = masked_mul(&ma1, &ma2).unwrap();
539 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
540 assert_eq!(mask_vals, vec![false, true, false]);
541 let data_vals: Vec<f64> = result.data().iter().copied().collect();
542 assert!((data_vals[0] - 10.0).abs() < 1e-10);
543 assert!((data_vals[2] - 28.0).abs() < 1e-10);
544 }
545
546 #[test]
547 fn masked_div_test() {
548 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![10.0, 20.0, 30.0]).unwrap();
549 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, true]).unwrap();
550 let ma1 = MaskedArray::new(d1, m1).unwrap();
551
552 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![2.0, 5.0, 6.0]).unwrap();
553 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
554 let ma2 = MaskedArray::new(d2, m2).unwrap();
555
556 let result = masked_div(&ma1, &ma2).unwrap();
557 let data_vals: Vec<f64> = result.data().iter().copied().collect();
558 assert!((data_vals[0] - 5.0).abs() < 1e-10);
559 assert!((data_vals[1] - 4.0).abs() < 1e-10);
560 }
561
562 #[test]
563 fn masked_invalid_negative_inf() {
564 let data =
565 Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, f64::NEG_INFINITY, 3.0]).unwrap();
566 let ma = masked_invalid(&data).unwrap();
567 let mask_vals: Vec<bool> = ma.mask().iter().copied().collect();
568 assert_eq!(mask_vals, vec![false, true, false]);
569 }
570
571 #[test]
572 fn empty_array_operations() {
573 let data = Array::<f64, Ix1>::from_vec(Ix1::new([0]), vec![]).unwrap();
574 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([0]), vec![]).unwrap();
575 let ma = MaskedArray::new(data, mask).unwrap();
576 assert_eq!(ma.count().unwrap(), 0);
577 assert!(ma.mean().unwrap().is_nan());
578 let compressed = ma.compressed().unwrap();
579 assert_eq!(compressed.size(), 0);
580 }
581
582 #[test]
583 fn ndim_shape_size() {
584 let data = Array::<f64, Ix1>::from_vec(Ix1::new([5]), vec![1.0; 5]).unwrap();
585 let mask = Array::<bool, Ix1>::from_vec(Ix1::new([5]), vec![false; 5]).unwrap();
586 let ma = MaskedArray::new(data, mask).unwrap();
587 assert_eq!(ma.ndim(), 1);
588 assert_eq!(ma.shape(), &[5]);
589 assert_eq!(ma.size(), 5);
590 }
591
592 #[test]
593 fn ufunc_binary_power() {
594 let d1 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![2.0, 3.0, 4.0]).unwrap();
595 let m1 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, true, false]).unwrap();
596 let ma1 = MaskedArray::new(d1, m1).unwrap();
597
598 let d2 = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![3.0, 2.0, 2.0]).unwrap();
599 let m2 = Array::<bool, Ix1>::from_vec(Ix1::new([3]), vec![false, false, false]).unwrap();
600 let ma2 = MaskedArray::new(d2, m2).unwrap();
601
602 let result = ufunc_support::power(&ma1, &ma2).unwrap();
603 let data_vals: Vec<f64> = result.data().iter().copied().collect();
604 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
605 assert_eq!(mask_vals, vec![false, true, false]);
606 assert!((data_vals[0] - 8.0).abs() < 1e-10); assert!((data_vals[2] - 16.0).abs() < 1e-10); }
609
610 #[test]
611 fn filled_with_custom_value() {
612 let data = Array::<f64, Ix1>::from_vec(Ix1::new([4]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
613 let mask =
614 Array::<bool, Ix1>::from_vec(Ix1::new([4]), vec![true, false, true, false]).unwrap();
615 let ma = MaskedArray::new(data, mask).unwrap();
616 let filled = ma.filled(-999.0).unwrap();
617 assert_eq!(filled.as_slice().unwrap(), &[-999.0, 2.0, -999.0, 4.0]);
618 }
619
620 #[test]
623 fn masked_2d_construction() {
624 use ferray_core::dimension::Ix2;
625 let data =
626 Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
627 .unwrap();
628 let mask = Array::<bool, Ix2>::from_vec(
629 Ix2::new([2, 3]),
630 vec![false, true, false, false, false, true],
631 )
632 .unwrap();
633 let ma = MaskedArray::new(data, mask).unwrap();
634 assert_eq!(ma.ndim(), 2);
635 assert_eq!(ma.shape(), &[2, 3]);
636 assert_eq!(ma.size(), 6);
637 assert_eq!(ma.count().unwrap(), 4);
638 }
639
640 #[test]
641 fn masked_2d_mean() {
642 use ferray_core::dimension::Ix2;
643 let data =
644 Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
645 .unwrap();
646 let mask = Array::<bool, Ix2>::from_vec(
648 Ix2::new([2, 3]),
649 vec![false, true, false, false, false, true],
650 )
651 .unwrap();
652 let ma = MaskedArray::new(data, mask).unwrap();
653 let m = ma.mean().unwrap();
655 assert!((m - 3.25).abs() < 1e-10);
656 }
657
658 #[test]
659 fn masked_2d_sum() {
660 use ferray_core::dimension::Ix2;
661 let data =
662 Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
663 .unwrap();
664 let mask = Array::<bool, Ix2>::from_vec(
665 Ix2::new([2, 3]),
666 vec![false, true, false, false, false, true],
667 )
668 .unwrap();
669 let ma = MaskedArray::new(data, mask).unwrap();
670 assert!((ma.sum().unwrap() - 13.0).abs() < 1e-10);
672 }
673
674 #[test]
675 fn masked_2d_add_operator() {
676 use ferray_core::dimension::Ix2;
677 let d1 = Array::<f64, Ix2>::from_vec(Ix2::new([2, 2]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
678 let m1 = Array::<bool, Ix2>::from_vec(Ix2::new([2, 2]), vec![false, true, false, false])
679 .unwrap();
680 let ma1 = MaskedArray::new(d1, m1).unwrap();
681
682 let d2 =
683 Array::<f64, Ix2>::from_vec(Ix2::new([2, 2]), vec![10.0, 20.0, 30.0, 40.0]).unwrap();
684 let m2 = Array::<bool, Ix2>::from_vec(Ix2::new([2, 2]), vec![false, false, true, false])
685 .unwrap();
686 let ma2 = MaskedArray::new(d2, m2).unwrap();
687
688 let result = (&ma1 + &ma2).unwrap();
689 let mask_vals: Vec<bool> = result.mask().iter().copied().collect();
690 assert_eq!(mask_vals, vec![false, true, true, false]);
691 let data_vals: Vec<f64> = result.data().iter().copied().collect();
692 assert!((data_vals[0] - 11.0).abs() < 1e-10);
693 assert!((data_vals[3] - 44.0).abs() < 1e-10);
694 }
695
696 #[test]
697 fn masked_2d_compressed() {
698 use ferray_core::dimension::Ix2;
699 let data = Array::<f64, Ix2>::from_vec(Ix2::new([2, 2]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
700 let mask =
701 Array::<bool, Ix2>::from_vec(Ix2::new([2, 2]), vec![false, true, false, true]).unwrap();
702 let ma = MaskedArray::new(data, mask).unwrap();
703 let compressed = ma.compressed().unwrap();
704 assert_eq!(compressed.as_slice().unwrap(), &[1.0, 3.0]);
705 }
706}