1use ndarray::prelude::*;
2use ndarray::{s, Data, DataMut, RemoveAxis};
3use noisy_float::types::{N32, N64};
4use std::mem;
5
6pub trait MaybeNan: Sized {
8 type NotNan;
10
11 fn is_nan(&self) -> bool;
13
14 fn try_as_not_nan(&self) -> Option<&Self::NotNan>;
18
19 fn from_not_nan(_: Self::NotNan) -> Self;
23
24 fn from_not_nan_opt(_: Option<Self::NotNan>) -> Self;
28
29 fn from_not_nan_ref_opt(_: Option<&Self::NotNan>) -> &Self;
33
34 fn remove_nan_mut(_: ArrayViewMut1<'_, Self>) -> ArrayViewMut1<'_, Self::NotNan>;
41}
42
43fn remove_nan_mut<A: MaybeNan>(mut view: ArrayViewMut1<'_, A>) -> ArrayViewMut1<'_, A> {
47 if view.is_empty() {
48 return view.slice_move(s![..0]);
49 }
50 let mut i = 0;
51 let mut j = view.len() - 1;
52 loop {
53 while i <= j && !view[i].is_nan() {
56 i += 1;
57 }
58 while j > i && view[j].is_nan() {
60 j -= 1;
61 }
62 if i >= j {
64 return view.slice_move(s![..i]);
65 } else {
66 view.swap(i, j);
67 i += 1;
68 j -= 1;
69 }
70 }
71}
72
73unsafe fn cast_view_mut<T, U>(mut view: ArrayViewMut1<'_, T>) -> ArrayViewMut1<'_, U> {
83 assert_eq!(mem::size_of::<T>(), mem::size_of::<U>());
84 assert_eq!(mem::align_of::<T>(), mem::align_of::<U>());
85 let ptr: *mut U = view.as_mut_ptr().cast();
86 let len: usize = view.len_of(Axis(0));
87 let stride: isize = view.stride_of(Axis(0));
88 if len <= 1 {
89 let stride = 0;
91 ArrayViewMut1::from_shape_ptr([len].strides([stride]), ptr)
92 } else if stride >= 0 {
93 let stride = stride as usize;
94 ArrayViewMut1::from_shape_ptr([len].strides([stride]), ptr)
95 } else {
96 let neg_stride = stride.checked_neg().unwrap() as usize;
100 let neg_ptr = ptr.offset((len - 1) as isize * stride);
103 let mut v = ArrayViewMut1::from_shape_ptr([len].strides([neg_stride]), neg_ptr);
104 v.invert_axis(Axis(0));
105 v
106 }
107}
108
109macro_rules! impl_maybenan_for_fxx {
110 ($fxx:ident, $Nxx:ident) => {
111 impl MaybeNan for $fxx {
112 type NotNan = $Nxx;
113
114 fn is_nan(&self) -> bool {
115 $fxx::is_nan(*self)
116 }
117
118 fn try_as_not_nan(&self) -> Option<&$Nxx> {
119 $Nxx::try_borrowed(self)
120 }
121
122 fn from_not_nan(value: $Nxx) -> $fxx {
123 value.raw()
124 }
125
126 fn from_not_nan_opt(value: Option<$Nxx>) -> $fxx {
127 match value {
128 None => ::std::$fxx::NAN,
129 Some(num) => num.raw(),
130 }
131 }
132
133 fn from_not_nan_ref_opt(value: Option<&$Nxx>) -> &$fxx {
134 match value {
135 None => &::std::$fxx::NAN,
136 Some(num) => num.as_ref(),
137 }
138 }
139
140 fn remove_nan_mut(view: ArrayViewMut1<'_, $fxx>) -> ArrayViewMut1<'_, $Nxx> {
141 let not_nan = remove_nan_mut(view);
142 unsafe { cast_view_mut(not_nan) }
145 }
146 }
147 };
148}
149impl_maybenan_for_fxx!(f32, N32);
150impl_maybenan_for_fxx!(f64, N64);
151
152macro_rules! impl_maybenan_for_opt_never_nan {
153 ($ty:ty) => {
154 impl MaybeNan for Option<$ty> {
155 type NotNan = NotNone<$ty>;
156
157 fn is_nan(&self) -> bool {
158 self.is_none()
159 }
160
161 fn try_as_not_nan(&self) -> Option<&NotNone<$ty>> {
162 if self.is_none() {
163 None
164 } else {
165 Some(unsafe { &*(self as *const Option<$ty> as *const NotNone<$ty>) })
168 }
169 }
170
171 fn from_not_nan(value: NotNone<$ty>) -> Option<$ty> {
172 value.into_inner()
173 }
174
175 fn from_not_nan_opt(value: Option<NotNone<$ty>>) -> Option<$ty> {
176 value.and_then(|v| v.into_inner())
177 }
178
179 fn from_not_nan_ref_opt(value: Option<&NotNone<$ty>>) -> &Option<$ty> {
180 match value {
181 None => &None,
182 Some(num) => unsafe { &*(num as *const NotNone<$ty> as *const Option<$ty>) },
185 }
186 }
187
188 fn remove_nan_mut(view: ArrayViewMut1<'_, Self>) -> ArrayViewMut1<'_, Self::NotNan> {
189 let not_nan = remove_nan_mut(view);
190 unsafe {
193 ArrayViewMut1::from_shape_ptr(
194 not_nan.dim(),
195 not_nan.as_ptr() as *mut NotNone<$ty>,
196 )
197 }
198 }
199 }
200 };
201}
202impl_maybenan_for_opt_never_nan!(u8);
203impl_maybenan_for_opt_never_nan!(u16);
204impl_maybenan_for_opt_never_nan!(u32);
205impl_maybenan_for_opt_never_nan!(u64);
206impl_maybenan_for_opt_never_nan!(u128);
207impl_maybenan_for_opt_never_nan!(i8);
208impl_maybenan_for_opt_never_nan!(i16);
209impl_maybenan_for_opt_never_nan!(i32);
210impl_maybenan_for_opt_never_nan!(i64);
211impl_maybenan_for_opt_never_nan!(i128);
212impl_maybenan_for_opt_never_nan!(N32);
213impl_maybenan_for_opt_never_nan!(N64);
214
215#[derive(Clone, Copy, Debug)]
218#[repr(transparent)]
219pub struct NotNone<T>(Option<T>);
220
221impl<T> NotNone<T> {
222 pub fn new(value: T) -> NotNone<T> {
224 NotNone(Some(value))
225 }
226
227 pub fn try_new(value: Option<T>) -> Option<NotNone<T>> {
231 if value.is_some() {
232 Some(NotNone(value))
233 } else {
234 None
235 }
236 }
237
238 pub fn into_inner(self) -> Option<T> {
240 self.0
241 }
242
243 pub fn unwrap(self) -> T {
247 match self.0 {
248 Some(inner) => inner,
249 None => unsafe { ::std::hint::unreachable_unchecked() },
250 }
251 }
252
253 pub fn map<U, F>(self, f: F) -> NotNone<U>
256 where
257 F: FnOnce(T) -> U,
258 {
259 NotNone::new(f(self.unwrap()))
260 }
261}
262
263pub trait MaybeNanExt<A, S, D>
265where
266 A: MaybeNan,
267 S: Data<Elem = A>,
268 D: Dimension,
269{
270 fn fold_skipnan<'a, F, B>(&'a self, init: B, f: F) -> B
275 where
276 A: 'a,
277 F: FnMut(B, &'a A::NotNan) -> B;
278
279 fn indexed_fold_skipnan<'a, F, B>(&'a self, init: B, f: F) -> B
284 where
285 A: 'a,
286 F: FnMut(B, (D::Pattern, &'a A::NotNan)) -> B;
287
288 fn visit_skipnan<'a, F>(&'a self, f: F)
292 where
293 A: 'a,
294 F: FnMut(&'a A::NotNan);
295
296 fn fold_axis_skipnan<B, F>(&self, axis: Axis, init: B, fold: F) -> Array<B, D::Smaller>
301 where
302 D: RemoveAxis,
303 F: FnMut(&B, &A::NotNan) -> B,
304 B: Clone;
305
306 fn map_axis_skipnan_mut<'a, B, F>(&'a mut self, axis: Axis, mapping: F) -> Array<B, D::Smaller>
322 where
323 A: 'a,
324 S: DataMut,
325 D: RemoveAxis,
326 F: FnMut(ArrayViewMut1<'a, A::NotNan>) -> B;
327
328 private_decl! {}
329}
330
331impl<A, S, D> MaybeNanExt<A, S, D> for ArrayBase<S, D>
332where
333 A: MaybeNan,
334 S: Data<Elem = A>,
335 D: Dimension,
336{
337 fn fold_skipnan<'a, F, B>(&'a self, init: B, mut f: F) -> B
338 where
339 A: 'a,
340 F: FnMut(B, &'a A::NotNan) -> B,
341 {
342 self.fold(init, |acc, elem| {
343 if let Some(not_nan) = elem.try_as_not_nan() {
344 f(acc, not_nan)
345 } else {
346 acc
347 }
348 })
349 }
350
351 fn indexed_fold_skipnan<'a, F, B>(&'a self, init: B, mut f: F) -> B
352 where
353 A: 'a,
354 F: FnMut(B, (D::Pattern, &'a A::NotNan)) -> B,
355 {
356 self.indexed_iter().fold(init, |acc, (idx, elem)| {
357 if let Some(not_nan) = elem.try_as_not_nan() {
358 f(acc, (idx, not_nan))
359 } else {
360 acc
361 }
362 })
363 }
364
365 fn visit_skipnan<'a, F>(&'a self, mut f: F)
366 where
367 A: 'a,
368 F: FnMut(&'a A::NotNan),
369 {
370 self.for_each(|elem| {
371 if let Some(not_nan) = elem.try_as_not_nan() {
372 f(not_nan)
373 }
374 })
375 }
376
377 fn fold_axis_skipnan<B, F>(&self, axis: Axis, init: B, mut fold: F) -> Array<B, D::Smaller>
378 where
379 D: RemoveAxis,
380 F: FnMut(&B, &A::NotNan) -> B,
381 B: Clone,
382 {
383 self.fold_axis(axis, init, |acc, elem| {
384 if let Some(not_nan) = elem.try_as_not_nan() {
385 fold(acc, not_nan)
386 } else {
387 acc.clone()
388 }
389 })
390 }
391
392 fn map_axis_skipnan_mut<'a, B, F>(
393 &'a mut self,
394 axis: Axis,
395 mut mapping: F,
396 ) -> Array<B, D::Smaller>
397 where
398 A: 'a,
399 S: DataMut,
400 D: RemoveAxis,
401 F: FnMut(ArrayViewMut1<'a, A::NotNan>) -> B,
402 {
403 self.map_axis_mut(axis, |lane| mapping(A::remove_nan_mut(lane)))
404 }
405
406 private_impl! {}
407}
408
409#[cfg(test)]
410mod tests {
411 use super::*;
412 use quickcheck_macros::quickcheck;
413
414 #[quickcheck]
415 fn remove_nan_mut_idempotent(is_nan: Vec<bool>) -> bool {
416 let mut values: Vec<_> = is_nan
417 .into_iter()
418 .map(|is_nan| if is_nan { None } else { Some(1) })
419 .collect();
420 let view = ArrayViewMut1::from_shape(values.len(), &mut values).unwrap();
421 let removed = remove_nan_mut(view);
422 removed == remove_nan_mut(removed.to_owned().view_mut())
423 }
424
425 #[quickcheck]
426 fn remove_nan_mut_only_nan_remaining(is_nan: Vec<bool>) -> bool {
427 let mut values: Vec<_> = is_nan
428 .into_iter()
429 .map(|is_nan| if is_nan { None } else { Some(1) })
430 .collect();
431 let view = ArrayViewMut1::from_shape(values.len(), &mut values).unwrap();
432 remove_nan_mut(view).iter().all(|elem| !elem.is_nan())
433 }
434
435 #[quickcheck]
436 fn remove_nan_mut_keep_all_non_nan(is_nan: Vec<bool>) -> bool {
437 let non_nan_count = is_nan.iter().filter(|&&is_nan| !is_nan).count();
438 let mut values: Vec<_> = is_nan
439 .into_iter()
440 .map(|is_nan| if is_nan { None } else { Some(1) })
441 .collect();
442 let view = ArrayViewMut1::from_shape(values.len(), &mut values).unwrap();
443 remove_nan_mut(view).len() == non_nan_count
444 }
445}
446
447mod impl_not_none;