Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
06b82be
Promoted module to directory
LukeMathWalker Feb 2, 2019
47c1696
Moved interpolate to separate file
LukeMathWalker Feb 2, 2019
8f1e7cd
Re-implemented quantile_axis_mut to get closer to something we can us…
LukeMathWalker Feb 2, 2019
c81f6be
Use a set instead of a vec to avoid repeating computations
LukeMathWalker Feb 2, 2019
7aee452
Use bulk method for single quantile
LukeMathWalker Feb 2, 2019
745e45b
Implement bulk method to get sorted
LukeMathWalker Feb 4, 2019
74eda81
Refactored quantiles_axis_mut to use sorted_get_many_mut
LukeMathWalker Feb 6, 2019
93531de
Avoid recomputing index value
LukeMathWalker Feb 6, 2019
c00620d
Add quantiles_mut to 1d trait
LukeMathWalker Feb 6, 2019
a7111e9
Return hashmaps from bulk methods
LukeMathWalker Feb 9, 2019
36284d2
Fixed tests
LukeMathWalker Feb 9, 2019
fc56ca4
Use IndexSet to preserve insertion order
LukeMathWalker Feb 9, 2019
67a4477
Fix indentation
LukeMathWalker Feb 9, 2019
ac0ca03
IndexMap provides a more intuitive behaviour
LukeMathWalker Feb 9, 2019
a4c1508
Remove prints
LukeMathWalker Feb 9, 2019
aa3a157
Renamed methods
LukeMathWalker Feb 9, 2019
2ea9233
Docs for get_many_from_sorted_mut
LukeMathWalker Feb 9, 2019
12a7944
Added docs for private free function
LukeMathWalker Feb 9, 2019
ac93a1e
Docs for quantiles_mut
LukeMathWalker Feb 9, 2019
c408c67
Fixed several typos in docs
LukeMathWalker Feb 9, 2019
c471955
More robust test
LukeMathWalker Feb 11, 2019
1411f15
Added test for quantiles
LukeMathWalker Feb 11, 2019
48f2bf0
Test quantiles_axis_mut
LukeMathWalker Feb 11, 2019
c27feb1
Add comments
LukeMathWalker Feb 11, 2019
00e14f7
Return options when the lane we are computing against is empty
LukeMathWalker Feb 11, 2019
846c336
Fixed docs
LukeMathWalker Feb 11, 2019
ab8d701
Fixed tests
LukeMathWalker Feb 11, 2019
8b38345
Move *index* functions out of Interpolate trait
jturner314 Mar 9, 2019
5771514
Reduce indentation in quantiles_axis_mut
jturner314 Mar 9, 2019
e0eb686
Reduce indentation in quantile_axis_skipnan_mut
jturner314 Mar 9, 2019
6c51145
Use .into_scalar() method
jturner314 Mar 9, 2019
30c3466
Improve docs of partition_mut
jturner314 Mar 9, 2019
dca9c7b
Reformat quantiles_axis_mut
jturner314 Mar 9, 2019
92f08a4
Cargo fmt
LukeMathWalker Mar 10, 2019
35d2094
Fmt
LukeMathWalker Mar 10, 2019
1021507
Formatting
LukeMathWalker Mar 10, 2019
c2ed805
Log version works
LukeMathWalker Mar 12, 2019
9dc5eef
Refactor
LukeMathWalker Mar 15, 2019
c49ad04
Fix indexes
LukeMathWalker Mar 15, 2019
cf7b362
Working implementation
LukeMathWalker Mar 16, 2019
cb1d9f8
Shorter syntax
LukeMathWalker Mar 16, 2019
75d7d55
Formatting
LukeMathWalker Mar 16, 2019
ca951cf
Better docs
LukeMathWalker Mar 16, 2019
45e84cd
Comments
LukeMathWalker Mar 16, 2019
46a6834
Typo
LukeMathWalker Mar 16, 2019
01e794c
Don't lose pieces after rebase
LukeMathWalker Mar 16, 2019
0c70bbb
Fmt
LukeMathWalker Mar 16, 2019
1ba922a
Reduce code duplication
LukeMathWalker Mar 17, 2019
d5ab45c
Fmt
LukeMathWalker Mar 18, 2019
1d8c671
Merge branch 'master' into bulk-quantiles
LukeMathWalker Mar 26, 2019
7b4e0de
Clarify docs of get_many_from_sorted_mut_unchecked
jturner314 Apr 1, 2019
64ed72b
Add get_many_from_sorted_mut benchmark
jturner314 Apr 1, 2019
2c90309
Add get_from_sorted_mut benchmark
jturner314 Apr 1, 2019
3a4ea2e
Simplify get_many_from_sorted_mut_unchecked
jturner314 Apr 1, 2019
e5c9474
Eliminate allocations from _get_many_from_sorted_mut_unchecked
jturner314 Apr 1, 2019
24ee710
Call slice_axis_mut instead of slice_mut
jturner314 Apr 1, 2019
8739c3b
Replace iter::repeat with vec!
jturner314 Apr 1, 2019
88d896f
Fix typo in comment
jturner314 Apr 1, 2019
29d507b
Remove unnecessary type annotation
jturner314 Apr 1, 2019
d0879c8
Simplify quantiles tests
jturner314 Apr 1, 2019
54c11be
Check keys in test_sorted_get_many_mut
jturner314 Apr 1, 2019
847fcd5
Simplify sort tests
jturner314 Apr 1, 2019
c6f762a
Improve sort and quantiles docs
jturner314 Apr 1, 2019
1685095
Make Interpolate::interpolate operate elementwise
jturner314 Apr 2, 2019
e965e85
Make quantiles_* return Array instead of IndexMap
jturner314 Apr 2, 2019
cfc408f
Add interpolate parameter to quantile*
jturner314 Apr 2, 2019
b5d8a08
Make get_many_from_sorted_mut take array of indexes
jturner314 Apr 2, 2019
00a21c0
Make quantiles* take array instead of slice
jturner314 Apr 2, 2019
8f9f0b6
Remove unnecessary IndexSet
jturner314 Apr 2, 2019
a4e8c5d
Merge pull request #5 from jturner314/bulk-quantiles
LukeMathWalker Apr 2, 2019
beec7ae
Merge master
LukeMathWalker Apr 2, 2019
5ff4430
Return EmptyInput instead of None
LukeMathWalker Apr 2, 2019
ca9f3db
Fix tests
LukeMathWalker Apr 2, 2019
7ca6b7f
Match output type for argmin/max_skipnan
LukeMathWalker Apr 2, 2019
22cbfbb
Fix tests
LukeMathWalker Apr 2, 2019
56906cf
Fmt
LukeMathWalker Apr 2, 2019
950cd44
Update src/lib.rs
jturner314 Apr 5, 2019
37b3b19
Add quantile error
LukeMathWalker Apr 5, 2019
1f37d44
Renamed InvalidFraction to InvalidQuantile
LukeMathWalker Apr 5, 2019
1e9ba18
Return QuantileError
LukeMathWalker Apr 5, 2019
caad47d
Fix tests
LukeMathWalker Apr 5, 2019
fab842c
Fix docs
LukeMathWalker Apr 5, 2019
a32d9a8
Fmt
LukeMathWalker Apr 5, 2019
a315f70
Simplify and deduplicate
LukeMathWalker Apr 6, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Custom errors returned from our methods and functions.
use noisy_float::types::N64;
use std::error::Error;
use std::fmt;

Expand Down Expand Up @@ -112,3 +113,31 @@ impl From<ShapeMismatch> for MultiInputError {
MultiInputError::ShapeMismatch(err)
}
}

/// An error computing a quantile.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum QuantileError {
/// The input was empty.
EmptyInput,
/// The `q` was not between `0.` and `1.` (inclusive).
InvalidQuantile(N64),
}

impl fmt::Display for QuantileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
QuantileError::EmptyInput => write!(f, "Empty input."),
QuantileError::InvalidQuantile(q) => {
write!(f, "{:} is not between 0. and 1. (inclusive).", q)
}
}
}
}

impl Error for QuantileError {}

impl From<EmptyInput> for QuantileError {
fn from(_: EmptyInput) -> QuantileError {
QuantileError::EmptyInput
}
}
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ extern crate rand;

#[cfg(test)]
extern crate approx;
extern crate core;
#[cfg(test)]
extern crate ndarray_rand;
#[cfg(test)]
Expand Down
60 changes: 36 additions & 24 deletions src/quantile/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use self::interpolate::{higher_index, lower_index, Interpolate};
use super::sort::get_many_from_sorted_mut_unchecked;
use crate::errors::{EmptyInput, MinMaxError, MinMaxError::UndefinedOrder};
use errors::QuantileError;
use ndarray::prelude::*;
use ndarray::{Data, DataMut, RemoveAxis, Zip};
use noisy_float::types::N64;
Expand Down Expand Up @@ -213,14 +214,15 @@ where
///
/// Returns `Err(EmptyInput)` when the specified axis has length 0.
///
/// **Panics** if `axis` is out of bounds or if
/// `q` is not between `0.` and `1.` (inclusive).
/// Returns `Err(InvalidQuantile(q))` if `q` is not between `0.` and `1.` (inclusive).
///
/// **Panics** if `axis` is out of bounds.
fn quantile_axis_mut<I>(
&mut self,
axis: Axis,
q: N64,
interpolate: &I,
) -> Result<Array<A, D::Smaller>, EmptyInput>
) -> Result<Array<A, D::Smaller>, QuantileError>
where
D: RemoveAxis,
A: Ord + Clone,
Expand All @@ -238,8 +240,9 @@ where
///
/// Returns `Err(EmptyInput)` when the specified axis has length 0.
///
/// **Panics** if `axis` is out of bounds or if
/// any `q` in `qs` is not between `0.` and `1.` (inclusive).
/// Returns `Err(InvalidQuantile(q))` if any `q` in `qs` is not between `0.` and `1.` (inclusive).
///
/// **Panics** if `axis` is out of bounds.
///
/// [`quantile_axis_mut`]: #tymethod.quantile_axis_mut
///
Expand Down Expand Up @@ -269,7 +272,7 @@ where
axis: Axis,
qs: &ArrayBase<S2, Ix1>,
interpolate: &I,
) -> Result<Array<A, D>, EmptyInput>
) -> Result<Array<A, D>, QuantileError>
where
D: RemoveAxis,
A: Ord + Clone,
Expand All @@ -285,7 +288,7 @@ where
axis: Axis,
q: N64,
interpolate: &I,
) -> Result<Array<A, D::Smaller>, EmptyInput>
) -> Result<Array<A, D::Smaller>, QuantileError>
where
D: RemoveAxis,
A: MaybeNan,
Expand Down Expand Up @@ -438,7 +441,7 @@ where
axis: Axis,
qs: &ArrayBase<S2, Ix1>,
interpolate: &I,
) -> Result<Array<A, D>, EmptyInput>
) -> Result<Array<A, D>, QuantileError>
where
D: RemoveAxis,
A: Ord + Clone,
Expand All @@ -452,17 +455,21 @@ where
axis: Axis,
qs: ArrayView1<N64>,
_interpolate: &I,
) -> Result<Array<A, D>, EmptyInput>
) -> Result<Array<A, D>, QuantileError>
where
D: RemoveAxis,
A: Ord + Clone,
I: Interpolate<A>,
{
assert!(qs.iter().all(|x| (*x >= 0.) && (*x <= 1.)));
for &q in qs {
if !((q >= 0.) && (q <= 1.)) {
return Err(QuantileError::InvalidQuantile(q));
}
}

let axis_len = data.len_of(axis);
if axis_len == 0 {
return Err(EmptyInput);
return Err(QuantileError::EmptyInput);
}

let mut results_shape = data.raw_dim();
Expand Down Expand Up @@ -514,7 +521,7 @@ where
axis: Axis,
q: N64,
interpolate: &I,
) -> Result<Array<A, D::Smaller>, EmptyInput>
) -> Result<Array<A, D::Smaller>, QuantileError>
where
D: RemoveAxis,
A: Ord + Clone,
Expand All @@ -530,17 +537,22 @@ where
axis: Axis,
q: N64,
interpolate: &I,
) -> Result<Array<A, D::Smaller>, EmptyInput>
) -> Result<Array<A, D::Smaller>, QuantileError>
where
D: RemoveAxis,
A: MaybeNan,
A::NotNan: Clone + Ord,
S: DataMut,
I: Interpolate<A::NotNan>,
{
if !((q >= 0.) && (q <= 1.)) {
return Err(QuantileError::InvalidQuantile(q));
}

if self.len_of(axis) == 0 {
return Err(EmptyInput);
return Err(QuantileError::EmptyInput);
}

let quantile = self.map_axis_mut(axis, |lane| {
let mut not_nan = A::remove_nan_mut(lane);
A::from_not_nan_opt(if not_nan.is_empty() {
Expand Down Expand Up @@ -591,8 +603,8 @@ where
///
/// Returns `Err(EmptyInput)` if the array is empty.
///
/// **Panics** if `q` is not between `0.` and `1.` (inclusive).
fn quantile_mut<I>(&mut self, q: N64, interpolate: &I) -> Result<A, EmptyInput>
/// Returns `Err(InvalidQuantile(q))` if `q` is not between `0.` and `1.` (inclusive).
fn quantile_mut<I>(&mut self, q: N64, interpolate: &I) -> Result<A, QuantileError>
where
A: Ord + Clone,
S: DataMut,
Expand All @@ -606,17 +618,18 @@ where
///
/// Returns `Err(EmptyInput)` if the array is empty.
///
/// Returns `Err(InvalidQuantile(q))` if any `q` in
/// `qs` is not between `0.` and `1.` (inclusive).
///
/// See [`quantile_mut`] for additional details on quantiles and the algorithm
/// used to retrieve them.
///
/// **Panics** if any `q` in `qs` is not between `0.` and `1.` (inclusive).
///
/// [`quantile_mut`]: #tymethod.quantile_mut
fn quantiles_mut<S2, I>(
&mut self,
qs: &ArrayBase<S2, Ix1>,
interpolate: &I,
) -> Result<Array1<A>, EmptyInput>
) -> Result<Array1<A>, QuantileError>
where
A: Ord + Clone,
S: DataMut,
Expand All @@ -628,18 +641,17 @@ impl<A, S> Quantile1dExt<A, S> for ArrayBase<S, Ix1>
where
S: Data<Elem = A>,
{
fn quantile_mut<I>(&mut self, q: N64, interpolate: &I) -> Result<A, EmptyInput>
fn quantile_mut<I>(&mut self, q: N64, interpolate: &I) -> Result<A, QuantileError>
where
A: Ord + Clone,
S: DataMut,
I: Interpolate<A>,
{
if self.is_empty() {
Err(EmptyInput)
Err(QuantileError::EmptyInput)
} else {
Ok(self
.quantile_axis_mut(Axis(0), q, interpolate)
.unwrap()
.quantile_axis_mut(Axis(0), q, interpolate)?
.into_scalar())
}
}
Expand All @@ -648,7 +660,7 @@ where
&mut self,
qs: &ArrayBase<S2, Ix1>,
interpolate: &I,
) -> Result<Array1<A>, EmptyInput>
) -> Result<Array1<A>, QuantileError>
where
A: Ord + Clone,
S: DataMut,
Expand Down
4 changes: 2 additions & 2 deletions tests/quantile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use itertools::izip;
use ndarray::array;
use ndarray::prelude::*;
use ndarray_stats::{
errors::{EmptyInput, MinMaxError},
errors::{MinMaxError, QuantileError},
interpolate::{Higher, Interpolate, Linear, Lower, Midpoint, Nearest},
Quantile1dExt, QuantileExt,
};
Expand Down Expand Up @@ -192,7 +192,7 @@ fn test_quantile_axis_mut_with_zero_axis_length() {
let mut a = Array2::<i32>::zeros((5, 0));
assert_eq!(
a.quantile_axis_mut(Axis(1), n64(0.5), &Lower),
Err(EmptyInput)
Err(QuantileError::EmptyInput)
);
}

Expand Down