1use self::interpolate::{Interpolate, higher_index, lower_index};
2use crate::errors::QuantileError;
3use crate::errors::{EmptyInput, MinMaxError, MinMaxError::UndefinedOrder};
4use crate::{MaybeNan, MaybeNanExt};
5use ndarray::prelude::*;
6use ndarray::{Data, DataMut, RemoveAxis, Zip};
7use ndarray_slice::Slice1Ext;
8use num_traits::Float;
9use std::{cmp, collections::HashMap, fmt::Debug};
10
11pub trait QuantileExt<A, S, D>
13where
14 A: Send,
15 S: Data<Elem = A>,
16 D: Dimension,
17{
18 fn argmin(&self) -> Result<D::Pattern, MinMaxError>
40 where
41 A: PartialOrd + Send;
42
43 fn argmin_skipnan(&self) -> Result<D::Pattern, EmptyInput>
62 where
63 A: MaybeNan,
64 A::NotNan: Ord + Send;
65
66 fn min(&self) -> Result<&A, MinMaxError>
78 where
79 A: PartialOrd + Send;
80
81 fn min_skipnan(&self) -> &A
91 where
92 A: MaybeNan,
93 A::NotNan: Ord + Send;
94
95 fn argmax(&self) -> Result<D::Pattern, MinMaxError>
117 where
118 A: PartialOrd + Send;
119
120 fn argmax_skipnan(&self) -> Result<D::Pattern, EmptyInput>
139 where
140 A: MaybeNan,
141 A::NotNan: Ord + Send;
142
143 fn max(&self) -> Result<&A, MinMaxError>
155 where
156 A: PartialOrd + Send;
157
158 fn max_skipnan(&self) -> &A
168 where
169 A: MaybeNan,
170 A::NotNan: Ord + Send;
171
172 fn quantile_axis_mut<F, I>(
208 &mut self,
209 axis: Axis,
210 q: F,
211 interpolate: &I,
212 ) -> Result<Array<A, D::Smaller>, QuantileError<F>>
213 where
214 D: RemoveAxis,
215 A: Ord + Send + Clone,
216 S: DataMut,
217 F: Float + Debug,
218 I: Interpolate<A>;
219
220 fn quantiles_axis_mut<S2, F, I>(
254 &mut self,
255 axis: Axis,
256 qs: &ArrayBase<S2, Ix1>,
257 interpolate: &I,
258 ) -> Result<Array<A, D>, QuantileError<F>>
259 where
260 D: RemoveAxis,
261 A: Ord + Send + Clone,
262 S: DataMut,
263 S2: Data<Elem = F>,
264 F: Float + Debug,
265 I: Interpolate<A>;
266
267 fn quantile_axis_skipnan_mut<F, I>(
271 &mut self,
272 axis: Axis,
273 q: F,
274 interpolate: &I,
275 ) -> Result<Array<A, D::Smaller>, QuantileError<F>>
276 where
277 D: RemoveAxis,
278 A: MaybeNan,
279 A::NotNan: Clone + Ord + Send,
280 S: DataMut,
281 F: Float + Debug,
282 I: Interpolate<A::NotNan>;
283
284 private_decl! {}
285}
286
287impl<A, S, D> QuantileExt<A, S, D> for ArrayBase<S, D>
288where
289 A: Send,
290 S: Data<Elem = A>,
291 D: Dimension,
292{
293 fn argmin(&self) -> Result<D::Pattern, MinMaxError>
294 where
295 A: PartialOrd + Send,
296 {
297 let mut current_min = self.first().ok_or(EmptyInput)?;
298 let mut current_pattern_min = D::zeros(self.ndim()).into_pattern();
299
300 for (pattern, elem) in self.indexed_iter() {
301 if elem.partial_cmp(current_min).ok_or(UndefinedOrder)? == cmp::Ordering::Less {
302 current_pattern_min = pattern;
303 current_min = elem
304 }
305 }
306
307 Ok(current_pattern_min)
308 }
309
310 fn argmin_skipnan(&self) -> Result<D::Pattern, EmptyInput>
311 where
312 A: MaybeNan,
313 A::NotNan: Ord + Send,
314 {
315 let mut pattern_min = D::zeros(self.ndim()).into_pattern();
316 let min = self.indexed_fold_skipnan(None, |current_min, (pattern, elem)| {
317 Some(match current_min {
318 Some(m) if (m <= elem) => m,
319 _ => {
320 pattern_min = pattern;
321 elem
322 }
323 })
324 });
325 if min.is_some() {
326 Ok(pattern_min)
327 } else {
328 Err(EmptyInput)
329 }
330 }
331
332 fn min(&self) -> Result<&A, MinMaxError>
333 where
334 A: PartialOrd + Send,
335 {
336 let first = self.first().ok_or(EmptyInput)?;
337 self.fold(Ok(first), |acc, elem| {
338 let acc = acc?;
339 match elem.partial_cmp(acc).ok_or(UndefinedOrder)? {
340 cmp::Ordering::Less => Ok(elem),
341 _ => Ok(acc),
342 }
343 })
344 }
345
346 fn min_skipnan(&self) -> &A
347 where
348 A: MaybeNan,
349 A::NotNan: Ord + Send,
350 {
351 let first = self.first().and_then(|v| v.try_as_not_nan());
352 A::from_not_nan_ref_opt(self.fold_skipnan(first, |acc, elem| {
353 Some(match acc {
354 Some(acc) => acc.min(elem),
355 None => elem,
356 })
357 }))
358 }
359
360 fn argmax(&self) -> Result<D::Pattern, MinMaxError>
361 where
362 A: PartialOrd + Send,
363 {
364 let mut current_max = self.first().ok_or(EmptyInput)?;
365 let mut current_pattern_max = D::zeros(self.ndim()).into_pattern();
366
367 for (pattern, elem) in self.indexed_iter() {
368 if elem.partial_cmp(current_max).ok_or(UndefinedOrder)? == cmp::Ordering::Greater {
369 current_pattern_max = pattern;
370 current_max = elem
371 }
372 }
373
374 Ok(current_pattern_max)
375 }
376
377 fn argmax_skipnan(&self) -> Result<D::Pattern, EmptyInput>
378 where
379 A: MaybeNan,
380 A::NotNan: Ord + Send,
381 {
382 let mut pattern_max = D::zeros(self.ndim()).into_pattern();
383 let max = self.indexed_fold_skipnan(None, |current_max, (pattern, elem)| {
384 Some(match current_max {
385 Some(m) if m >= elem => m,
386 _ => {
387 pattern_max = pattern;
388 elem
389 }
390 })
391 });
392 if max.is_some() {
393 Ok(pattern_max)
394 } else {
395 Err(EmptyInput)
396 }
397 }
398
399 fn max(&self) -> Result<&A, MinMaxError>
400 where
401 A: PartialOrd + Send,
402 {
403 let first = self.first().ok_or(EmptyInput)?;
404 self.fold(Ok(first), |acc, elem| {
405 let acc = acc?;
406 match elem.partial_cmp(acc).ok_or(UndefinedOrder)? {
407 cmp::Ordering::Greater => Ok(elem),
408 _ => Ok(acc),
409 }
410 })
411 }
412
413 fn max_skipnan(&self) -> &A
414 where
415 A: MaybeNan,
416 A::NotNan: Ord + Send,
417 {
418 let first = self.first().and_then(|v| v.try_as_not_nan());
419 A::from_not_nan_ref_opt(self.fold_skipnan(first, |acc, elem| {
420 Some(match acc {
421 Some(acc) => acc.max(elem),
422 None => elem,
423 })
424 }))
425 }
426
427 fn quantiles_axis_mut<S2, F, I>(
428 &mut self,
429 axis: Axis,
430 qs: &ArrayBase<S2, Ix1>,
431 interpolate: &I,
432 ) -> Result<Array<A, D>, QuantileError<F>>
433 where
434 D: RemoveAxis,
435 A: Ord + Send + Clone,
436 S: DataMut,
437 S2: Data<Elem = F>,
438 F: Float + Debug,
439 I: Interpolate<A>,
440 {
441 fn quantiles_axis_mut<A, D, F, I>(
443 mut data: ArrayViewMut<'_, A, D>,
444 axis: Axis,
445 qs: ArrayView1<'_, F>,
446 _interpolate: &I,
447 ) -> Result<Array<A, D>, QuantileError<F>>
448 where
449 D: RemoveAxis,
450 A: Ord + Send + Clone,
451 F: Float + Debug,
452 I: Interpolate<A>,
453 {
454 for &q in qs {
455 if !(F::from(0.).unwrap()..=F::from(1.).unwrap()).contains(&q) {
456 return Err(QuantileError::InvalidQuantile(q));
457 }
458 }
459
460 let axis_len = data.len_of(axis);
461 if axis_len == 0 {
462 return Err(QuantileError::EmptyInput);
463 }
464
465 let mut results_shape = data.raw_dim();
466 results_shape[axis.index()] = qs.len();
467 if results_shape.size() == 0 {
468 return Ok(Array::from_shape_vec(results_shape, Vec::new()).unwrap());
469 }
470
471 let mut searched_indexes = Vec::with_capacity(2 * qs.len());
472 for &q in &qs {
473 if I::needs_lower(q, axis_len) {
474 searched_indexes.push(lower_index(q, axis_len));
475 }
476 if I::needs_higher(q, axis_len) {
477 searched_indexes.push(higher_index(q, axis_len));
478 }
479 }
480 let mut indexes = Array1::from_vec(searched_indexes);
481 indexes.sort_unstable();
482 let (indexes, _duplicates) = indexes.partition_dedup();
483
484 let mut results = Array::from_elem(results_shape, data.first().unwrap().clone());
485 Zip::from(results.lanes_mut(axis))
486 .and(data.lanes_mut(axis))
487 .for_each(|mut results, mut data| {
488 #[cfg(feature = "rayon")]
489 let values = {
490 let mut values = Vec::new();
491 data.par_select_many_nth_unstable(&indexes, &mut values);
492 HashMap::<usize, &mut A>::from_iter(
493 indexes.iter().copied().zip(values.into_iter()),
494 )
495 };
496 #[cfg(not(feature = "rayon"))]
497 let values = {
498 let mut values = HashMap::new();
499 data.select_many_nth_unstable(&indexes, &mut values);
500 values
501 };
502 for (result, &q) in results.iter_mut().zip(qs) {
503 let lower = if I::needs_lower(q, axis_len) {
504 Some(values[&lower_index(q, axis_len)].clone())
505 } else {
506 None
507 };
508 let higher = if I::needs_higher(q, axis_len) {
509 Some(values[&higher_index(q, axis_len)].clone())
510 } else {
511 None
512 };
513 *result = I::interpolate(lower, higher, q, axis_len);
514 }
515 });
516 Ok(results)
517 }
518
519 quantiles_axis_mut(self.view_mut(), axis, qs.view(), interpolate)
520 }
521
522 fn quantile_axis_mut<F, I>(
523 &mut self,
524 axis: Axis,
525 q: F,
526 interpolate: &I,
527 ) -> Result<Array<A, D::Smaller>, QuantileError<F>>
528 where
529 D: RemoveAxis,
530 A: Ord + Send + Clone,
531 S: DataMut,
532 F: Float + Debug,
533 I: Interpolate<A>,
534 {
535 self.quantiles_axis_mut(axis, &aview1(&[q]), interpolate)
536 .map(|a| a.index_axis_move(axis, 0))
537 }
538
539 fn quantile_axis_skipnan_mut<F, I>(
540 &mut self,
541 axis: Axis,
542 q: F,
543 interpolate: &I,
544 ) -> Result<Array<A, D::Smaller>, QuantileError<F>>
545 where
546 D: RemoveAxis,
547 A: MaybeNan,
548 A::NotNan: Clone + Ord + Send,
549 S: DataMut,
550 F: Float + Debug,
551 I: Interpolate<A::NotNan>,
552 {
553 if !(F::from(0.).unwrap()..=F::from(1.).unwrap()).contains(&q) {
554 return Err(QuantileError::InvalidQuantile(q));
555 }
556
557 if self.len_of(axis) == 0 {
558 return Err(QuantileError::EmptyInput);
559 }
560
561 let quantile = self.map_axis_mut(axis, |lane| {
562 let mut not_nan = A::remove_nan_mut(lane);
563 A::from_not_nan_opt(if not_nan.is_empty() {
564 None
565 } else {
566 Some(
567 not_nan
568 .quantile_axis_mut::<F, I>(Axis(0), q, interpolate)
569 .unwrap()
570 .into_scalar(),
571 )
572 })
573 });
574 Ok(quantile)
575 }
576
577 private_impl! {}
578}
579
580pub trait Quantile1dExt<A, S>
582where
583 A: Send,
584 S: Data<Elem = A>,
585{
586 fn quantile_mut<F, I>(&mut self, q: F, interpolate: &I) -> Result<A, QuantileError<F>>
618 where
619 A: Ord + Send + Clone,
620 S: DataMut,
621 F: Float + Debug,
622 I: Interpolate<A>;
623
624 fn quantiles_mut<S2, F, I>(
640 &mut self,
641 qs: &ArrayBase<S2, Ix1>,
642 interpolate: &I,
643 ) -> Result<Array1<A>, QuantileError<F>>
644 where
645 A: Ord + Send + Clone,
646 S: DataMut,
647 F: Float + Debug,
648 S2: Data<Elem = F>,
649 I: Interpolate<A>;
650
651 private_decl! {}
652}
653
654impl<A, S> Quantile1dExt<A, S> for ArrayBase<S, Ix1>
655where
656 A: Send,
657 S: Data<Elem = A>,
658{
659 fn quantile_mut<F, I>(&mut self, q: F, interpolate: &I) -> Result<A, QuantileError<F>>
660 where
661 A: Ord + Send + Clone,
662 S: DataMut,
663 F: Float + Debug,
664 I: Interpolate<A>,
665 {
666 Ok(self
667 .quantile_axis_mut(Axis(0), q, interpolate)?
668 .into_scalar())
669 }
670
671 fn quantiles_mut<S2, F, I>(
672 &mut self,
673 qs: &ArrayBase<S2, Ix1>,
674 interpolate: &I,
675 ) -> Result<Array1<A>, QuantileError<F>>
676 where
677 A: Ord + Send + Clone,
678 S: DataMut,
679 F: Float + Debug,
680 S2: Data<Elem = F>,
681 I: Interpolate<A>,
682 {
683 self.quantiles_axis_mut(Axis(0), qs, interpolate)
684 }
685
686 private_impl! {}
687}
688
689pub mod interpolate;