Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Sort1dExt in favor of SliceExt. #92

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- stable
- beta
- nightly
- 1.49.0 # MSRV
- 1.60.0 # MSRV
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
Expand All @@ -32,6 +32,8 @@ jobs:
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- name: Run tests with Rayon
run: cargo test --verbose --features rayon

cross_test:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -61,6 +63,8 @@ jobs:
run: cross build --verbose --target=${{ matrix.target }}
- name: Run tests
run: cross test --verbose --target=${{ matrix.target }}
- name: Run tests with Rayon
run: cross test --verbose --features rayon --target=${{ matrix.target }}

format:
runs-on: ubuntu-latest
Expand Down
14 changes: 11 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[package]
name = "ndarray-stats"
version = "0.5.1"
version = "0.6.0"
rust-version = "1.60"
edition = "2021"
authors = ["Jim Turner <[email protected]>", "LukeMathWalker <[email protected]>"]
edition = "2018"

license = "MIT/Apache-2.0"

Expand All @@ -17,12 +18,13 @@ categories = ["data-structures", "science"]

[dependencies]
ndarray = "0.15.0"
ndarray-slice = "0.2.2"
noisy_float = "0.2.0"
num-integer = "0.1"
num-traits = "0.2"
rand = "0.8.3"
itertools = { version = "0.10.0", default-features = false }
indexmap = "1.6.2"
rayon = { version = "1.7.0", optional = true }

[dev-dependencies]
ndarray = { version = "0.15.0", features = ["approx"] }
Expand All @@ -33,6 +35,9 @@ approx = "0.4"
quickcheck_macros = "1.0.0"
num-bigint = "0.4.0"

[features]
rayon = ["dep:rayon", "ndarray-slice/rayon", "ndarray/rayon"]

[[bench]]
name = "sort"
harness = false
Expand All @@ -44,3 +49,6 @@ harness = false
[[bench]]
name = "deviation"
harness = false

[profile.test]
opt-level = 2
7 changes: 4 additions & 3 deletions benches/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use criterion::{
black_box, criterion_group, criterion_main, AxisScale, BatchSize, Criterion, PlotConfiguration,
};
use ndarray::prelude::*;
use ndarray_stats::Sort1dExt;
use ndarray_slice::Slice1Ext;
use rand::prelude::*;

fn get_from_sorted_mut(c: &mut Criterion) {
Expand All @@ -19,7 +19,7 @@ fn get_from_sorted_mut(c: &mut Criterion) {
|| Array1::from(data.clone()),
|mut arr| {
for &i in &indices {
black_box(arr.get_from_sorted_mut(i));
black_box(arr.select_nth_unstable(i));
}
},
BatchSize::SmallInput,
Expand All @@ -42,7 +42,8 @@ fn get_many_from_sorted_mut(c: &mut Criterion) {
b.iter_batched(
|| Array1::from(data.clone()),
|mut arr| {
black_box(arr.get_many_from_sorted_mut(&indices));
let mut values = Vec::with_capacity(indices.len());
black_box(arr.select_many_nth_unstable(&indices, &mut values));
},
BatchSize::SmallInput,
)
Expand Down
20 changes: 13 additions & 7 deletions src/histogram/bins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
use ndarray::prelude::*;
use std::ops::{Index, Range};

#[cfg(feature = "rayon")]
use rayon::slice::ParallelSliceMut;

/// A sorted collection of type `A` elements used to represent the boundaries of intervals, i.e.
/// [`Bins`] on a 1-dimensional axis.
///
Expand Down Expand Up @@ -30,11 +33,11 @@ use std::ops::{Index, Range};
///
/// [`Bins`]: struct.Bins.html
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Edges<A: Ord> {
pub struct Edges<A: Ord + Send> {
edges: Vec<A>,
}

impl<A: Ord> From<Vec<A>> for Edges<A> {
impl<A: Ord + Send> From<Vec<A>> for Edges<A> {
/// Converts a `Vec<A>` into an `Edges<A>`, consuming the edges.
/// The vector will be sorted in increasing order using an unstable sorting algorithm, with
/// duplicates removed.
Expand Down Expand Up @@ -65,14 +68,17 @@ impl<A: Ord> From<Vec<A>> for Edges<A> {
/// [pdqsort]: https://github.com/orlp/pdqsort
fn from(mut edges: Vec<A>) -> Self {
// sort the array in-place
#[cfg(feature = "rayon")]
edges.par_sort_unstable();
#[cfg(not(feature = "rayon"))]
edges.sort_unstable();
// remove duplicates
edges.dedup();
Edges { edges }
}
}

impl<A: Ord + Clone> From<Array1<A>> for Edges<A> {
impl<A: Ord + Send + Clone> From<Array1<A>> for Edges<A> {
/// Converts an `Array1<A>` into an `Edges<A>`, consuming the 1-dimensional array.
/// The array will be sorted in increasing order using an unstable sorting algorithm, with
/// duplicates removed.
Expand Down Expand Up @@ -106,7 +112,7 @@ impl<A: Ord + Clone> From<Array1<A>> for Edges<A> {
}
}

impl<A: Ord> Index<usize> for Edges<A> {
impl<A: Ord + Send> Index<usize> for Edges<A> {
type Output = A;

/// Returns a reference to the `i`-th edge in `self`.
Expand All @@ -131,7 +137,7 @@ impl<A: Ord> Index<usize> for Edges<A> {
}
}

impl<A: Ord> Edges<A> {
impl<A: Ord + Send> Edges<A> {
/// Returns the number of edges in `self`.
///
/// # Examples
Expand Down Expand Up @@ -258,11 +264,11 @@ impl<A: Ord> Edges<A> {
/// );
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Bins<A: Ord> {
pub struct Bins<A: Ord + Send> {
edges: Edges<A>,
}

impl<A: Ord> Bins<A> {
impl<A: Ord + Send> Bins<A> {
/// Returns a `Bins` instance where each bin corresponds to two consecutive members of the given
/// [`Edges`], consuming the edges.
///
Expand Down
10 changes: 5 additions & 5 deletions src/histogram/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ use std::ops::Range;
/// [`GridBuilder`]: struct.GridBuilder.html
/// [`strategy`]: strategies/index.html
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Grid<A: Ord> {
pub struct Grid<A: Ord + Send> {
projections: Vec<Bins<A>>,
}

impl<A: Ord> From<Vec<Bins<A>>> for Grid<A> {
impl<A: Ord + Send> From<Vec<Bins<A>>> for Grid<A> {
/// Converts a `Vec<Bins<A>>` into a `Grid<A>`, consuming the vector of bins.
///
/// The `i`-th element in `Vec<Bins<A>>` represents the projection of the bin grid onto the
Expand All @@ -106,7 +106,7 @@ impl<A: Ord> From<Vec<Bins<A>>> for Grid<A> {
}
}

impl<A: Ord> Grid<A> {
impl<A: Ord + Send> Grid<A> {
/// Returns the number of dimensions of the region partitioned by the grid.
///
/// # Examples
Expand Down Expand Up @@ -220,7 +220,7 @@ impl<A: Ord> Grid<A> {
}
}

impl<A: Ord + Clone> Grid<A> {
impl<A: Ord + Send + Clone> Grid<A> {
/// Given an `n`-dimensional index, `i = (i_0, ..., i_{n-1})`, returns an `n`-dimensional bin,
/// `I_{i_0} x ... x I_{i_{n-1}}`, where `I_{i_j}` is the `i_j`-th interval on the `j`-th
/// projection of the grid on the coordinate axes.
Expand Down Expand Up @@ -318,7 +318,7 @@ pub struct GridBuilder<B: BinsBuildingStrategy> {

impl<A, B> GridBuilder<B>
where
A: Ord,
A: Ord + Send,
B: BinsBuildingStrategy<Elem = A>,
{
/// Returns a `GridBuilder` for building a [`Grid`] with a given [`strategy`] and some
Expand Down
10 changes: 5 additions & 5 deletions src/histogram/histograms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use ndarray::prelude::*;
use ndarray::Data;

/// Histogram data structure.
pub struct Histogram<A: Ord> {
pub struct Histogram<A: Ord + Send> {
counts: ArrayD<usize>,
grid: Grid<A>,
}

impl<A: Ord> Histogram<A> {
impl<A: Ord + Send> Histogram<A> {
/// Returns a new instance of Histogram given a [`Grid`].
///
/// [`Grid`]: struct.Grid.html
Expand Down Expand Up @@ -43,7 +43,7 @@ impl<A: Ord> Histogram<A> {
/// [0, 1],
/// ];
/// assert_eq!(histogram_matrix, expected.into_dyn());
/// # Ok::<(), Box<std::error::Error>>(())
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn add_observation<S>(&mut self, observation: &ArrayBase<S, Ix1>) -> Result<(), BinNotFound>
where
Expand Down Expand Up @@ -136,15 +136,15 @@ where
/// ```
fn histogram(&self, grid: Grid<A>) -> Histogram<A>
where
A: Ord;
A: Ord + Send;

private_decl! {}
}

impl<A, S> HistogramExt<A, S> for ArrayBase<S, Ix2>
where
S: Data<Elem = A>,
A: Ord,
A: Ord + Send,
{
fn histogram(&self, grid: Grid<A>) -> Histogram<A> {
let mut histogram = Histogram::new(grid);
Expand Down
26 changes: 13 additions & 13 deletions src/histogram/strategies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ use num_traits::{FromPrimitive, NumOps, Zero};
/// [`Grid`]: ../struct.Grid.html
pub trait BinsBuildingStrategy {
#[allow(missing_docs)]
type Elem: Ord;
type Elem: Ord + Send;
/// Returns a strategy that has learnt the required parameter fo building [`Bins`] for given
/// 1-dimensional array, or an `Err` if it is not possible to infer the required parameter
/// with the given data and specified strategy.
Expand Down Expand Up @@ -213,7 +213,7 @@ pub struct Auto<T> {

impl<T> EquiSpaced<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
/// Returns `Err(BinsBuildError::Strategy)` if `bin_width<=0` or `min` >= `max`.
/// Returns `Ok(Self)` otherwise.
Expand Down Expand Up @@ -256,7 +256,7 @@ where

impl<T> BinsBuildingStrategy for Sqrt<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
type Elem = T;

Expand Down Expand Up @@ -292,7 +292,7 @@ where

impl<T> Sqrt<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
/// The bin width (or bin length) according to the fitted strategy.
pub fn bin_width(&self) -> T {
Expand All @@ -302,7 +302,7 @@ where

impl<T> BinsBuildingStrategy for Rice<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
type Elem = T;

Expand Down Expand Up @@ -338,7 +338,7 @@ where

impl<T> Rice<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
/// The bin width (or bin length) according to the fitted strategy.
pub fn bin_width(&self) -> T {
Expand All @@ -348,7 +348,7 @@ where

impl<T> BinsBuildingStrategy for Sturges<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
type Elem = T;

Expand Down Expand Up @@ -384,7 +384,7 @@ where

impl<T> Sturges<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
/// The bin width (or bin length) according to the fitted strategy.
pub fn bin_width(&self) -> T {
Expand All @@ -394,7 +394,7 @@ where

impl<T> BinsBuildingStrategy for FreedmanDiaconis<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
type Elem = T;

Expand Down Expand Up @@ -433,7 +433,7 @@ where

impl<T> FreedmanDiaconis<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
fn compute_bin_width(n_bins: usize, iqr: T) -> T {
// casting `n_bins: usize` to `f64` may casus off-by-one error here if `n_bins` > 2 ^ 53,
Expand All @@ -451,7 +451,7 @@ where

impl<T> BinsBuildingStrategy for Auto<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
type Elem = T;

Expand Down Expand Up @@ -504,7 +504,7 @@ where

impl<T> Auto<T>
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
/// The bin width (or bin length) according to the fitted strategy.
pub fn bin_width(&self) -> T {
Expand All @@ -524,7 +524,7 @@ where
/// **Panics** if `n_bins == 0` and division by 0 panics for `T`.
fn compute_bin_width<T>(min: T, max: T, n_bins: usize) -> T
where
T: Ord + Clone + FromPrimitive + NumOps + Zero,
T: Ord + Send + Clone + FromPrimitive + NumOps + Zero,
{
let range = max - min;
range / T::from_usize(n_bins).unwrap()
Expand Down
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ pub use crate::entropy::EntropyExt;
pub use crate::histogram::HistogramExt;
pub use crate::maybe_nan::{MaybeNan, MaybeNanExt};
pub use crate::quantile::{interpolate, Quantile1dExt, QuantileExt};
pub use crate::sort::Sort1dExt;
pub use crate::summary_statistics::SummaryStatisticsExt;

#[cfg(test)]
Expand Down Expand Up @@ -105,5 +104,4 @@ pub mod errors;
pub mod histogram;
mod maybe_nan;
mod quantile;
mod sort;
mod summary_statistics;
Loading