From 89198b1b230d5eccb97464f3dd3e3a38f0374f9f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 10:07:39 +0100 Subject: [PATCH 01/72] Added new submodule --- src/histogram.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/histogram.rs diff --git a/src/histogram.rs b/src/histogram.rs new file mode 100644 index 00000000..e69de29b From 1d019f1a11649f41ba1c43b2581a12eeb1993bab Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 10:11:24 +0100 Subject: [PATCH 02/72] Barebone trait HistogramExt added and exported --- src/histogram.rs | 3 +++ src/lib.rs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/histogram.rs b/src/histogram.rs index e69de29b..b1d650f2 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -0,0 +1,3 @@ +pub trait HistogramExt { + +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index cf8e56d8..fd8d7aca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,10 @@ pub use maybe_nan::{MaybeNan, MaybeNanExt}; pub use quantile::{interpolate, QuantileExt}; pub use sort::Sort1dExt; pub use correlation::CorrelationExt; +pub use histogram::HistogramExt; mod maybe_nan; mod quantile; mod sort; -mod correlation; \ No newline at end of file +mod correlation; +mod histogram; \ No newline at end of file From 231d2bf0629dc26df81454f3ee768446783aa9b0 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 11:29:30 +0100 Subject: [PATCH 03/72] New module for bin functionalities --- src/histogram.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/histogram.rs b/src/histogram.rs index b1d650f2..b364bf83 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -1,3 +1,7 @@ +mod bins { + +} + pub trait HistogramExt { } \ No newline at end of file From bedd5d3feae4db25e9335f7e9aeba0c573173a69 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 12:38:03 +0100 Subject: [PATCH 04/72] Skeleton of the bin system --- src/histogram.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/histogram.rs b/src/histogram.rs index b364bf83..cdca07a6 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -1,5 +1,69 @@ mod bins { + use ndarray::prelude::*; + use ndarray::Data; + struct Bins1d { + bins: Vec, + } + struct BinsNd { + bins: Vec, + } + + /// `Bins` is a collection of non-overlapping + /// sub-regions (`Bin`) in a `n` dimensional space. + pub trait Bins { + /// Return `n`, the number of dimensions. + fn ndim(&self) -> usize; + + /// Given a point `P`, it returns an `Option`: + /// - `Some(B)`, if `P` belongs to the `Bin` `B`; + /// - `None`, if `P` does not belong to any `Bin` in `Bins`. + /// + /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. + fn find(&self, point: ArrayBase) -> Option + where + S: Data, + D: Dimension, + B: Bin; + } + + impl Bins for Bins1d { + fn ndim(&self) -> usize { + 1 + } + + fn find(&self, _point: ArrayBase) -> Option + where + S: Data, + D: Dimension, + B: Bin, + { + unimplemented!() + } + } + + impl Bins for BinsNd { + fn ndim(&self) -> usize { + unimplemented!() + } + + fn find(&self, _point: ArrayBase) -> Option + where + S: Data, + D: Dimension, + B: Bin, + { + unimplemented!() + } + } + + pub trait Bin { + + } + struct Bin1d {} + struct BinNd {} + impl Bin for Bin1d {} + impl Bin for BinNd {} } pub trait HistogramExt { From 3bd8dc10915826d070909631748d4b1137123911 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 13:17:12 +0100 Subject: [PATCH 05/72] Bins have to be generic with respect to element type T --- src/histogram.rs | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/histogram.rs b/src/histogram.rs index cdca07a6..d118c1a6 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -2,16 +2,16 @@ mod bins { use ndarray::prelude::*; use ndarray::Data; - struct Bins1d { - bins: Vec, + struct Bins1d { + bins: Vec>, } - struct BinsNd { - bins: Vec, + struct BinsNd { + bins: Vec>, } /// `Bins` is a collection of non-overlapping /// sub-regions (`Bin`) in a `n` dimensional space. - pub trait Bins { + pub trait Bins { /// Return `n`, the number of dimensions. fn ndim(&self) -> usize; @@ -20,21 +20,21 @@ mod bins { /// - `None`, if `P` does not belong to any `Bin` in `Bins`. /// /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. - fn find(&self, point: ArrayBase) -> Option + fn find(&self, point: ArrayBase) -> Option where - S: Data, + S: Data, D: Dimension, B: Bin; } - impl Bins for Bins1d { + impl Bins for Bins1d { fn ndim(&self) -> usize { 1 } - fn find(&self, _point: ArrayBase) -> Option + fn find(&self, _point: ArrayBase) -> Option where - S: Data, + S: Data, D: Dimension, B: Bin, { @@ -42,14 +42,14 @@ mod bins { } } - impl Bins for BinsNd { + impl Bins for BinsNd { fn ndim(&self) -> usize { unimplemented!() } - fn find(&self, _point: ArrayBase) -> Option + fn find(&self, _point: ArrayBase) -> Option where - S: Data, + S: Data, D: Dimension, B: Bin, { @@ -60,10 +60,15 @@ mod bins { pub trait Bin { } - struct Bin1d {} - struct BinNd {} - impl Bin for Bin1d {} - impl Bin for BinNd {} + struct Bin1d { + left: T, + right: T, + } + struct BinNd { + projections: Vec>, + } + impl Bin for Bin1d {} + impl Bin for BinNd {} } pub trait HistogramExt { From 979ae1118275fb6af14c53059c28e7bbb13f12e2 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 13:50:35 +0100 Subject: [PATCH 06/72] Added barebone of histogram trait, both 1d and Nd --- src/histogram.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 2 +- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/histogram.rs b/src/histogram.rs index d118c1a6..90a22b06 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -71,6 +71,53 @@ mod bins { impl Bin for BinNd {} } -pub trait HistogramExt { +use std::collections::HashMap; +use self::bins::{Bin, Bins}; +use ndarray::prelude::*; +use ndarray::Data; +type Histogram = HashMap, usize>; + +pub trait HistogramNdExt +where + S: Data, + D: Dimension, +{ + fn histogram(&self, bins: B) -> Histogram + where + B: Bins; +} + +impl HistogramNdExt for ArrayBase +where + S: Data, + D: Dimension, +{ + fn histogram(&self, _bins: B) -> Histogram + where + B: Bins, + { + unimplemented!() + } +} + +pub trait Histogram1dExt +where + S: Data, +{ + fn histogram(&self, bins: B) -> Histogram + where + B: Bins; +} + +impl Histogram1dExt for ArrayBase +where + S: Data, +{ + fn histogram(&self, _bins: B) -> Histogram + where + B: Bins, + { + unimplemented!() + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fd8d7aca..e63873b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ pub use maybe_nan::{MaybeNan, MaybeNanExt}; pub use quantile::{interpolate, QuantileExt}; pub use sort::Sort1dExt; pub use correlation::CorrelationExt; -pub use histogram::HistogramExt; +pub use histogram::{Histogram1dExt, HistogramNdExt}; mod maybe_nan; mod quantile; From f3f02e069eb7b30da59e7d7d4a2c65461c45dff2 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 14:26:03 +0100 Subject: [PATCH 07/72] As far as I can go with this structure --- src/histogram.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/histogram.rs b/src/histogram.rs index 90a22b06..190fd937 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -9,8 +9,7 @@ mod bins { bins: Vec>, } - /// `Bins` is a collection of non-overlapping - /// sub-regions (`Bin`) in a `n` dimensional space. + /// `Bins` is a collection of non-overlapping /// sub-regions (`Bin`) in a `n` dimensional space. pub trait Bins { /// Return `n`, the number of dimensions. fn ndim(&self) -> usize; @@ -78,26 +77,41 @@ use ndarray::Data; type Histogram = HashMap, usize>; -pub trait HistogramNdExt +pub trait HistogramNdExt where S: Data, - D: Dimension, { + /// Return the [histogram](https://en.wikipedia.org/wiki/Histogram) + /// for a 2-dimensional array of points `M`. + /// + /// Let `(n, d)` be the shape of `M`: + /// - `n` is the number of points; + /// - `d` is the number of dimensions of the space those points belong to. + /// It follows that every column in `M` is a `d`-dimensional point. + /// + /// For example: a (3, 4) matrix `M` is a collection of 3 points in a + /// 4-dimensional space. fn histogram(&self, bins: B) -> Histogram where B: Bins; } -impl HistogramNdExt for ArrayBase +impl HistogramNdExt for ArrayBase where S: Data, - D: Dimension, { - fn histogram(&self, _bins: B) -> Histogram + fn histogram(&self, bins: B) -> Histogram where B: Bins, { - unimplemented!() + let mut histogram = HashMap::new(); + for point in self.axis_iter(Axis(0)) { + let bin = bins.find(point); + if let Some(b) = bin { + histogram.insert(b, 1); + }; + } + histogram } } From d2b29d10a32faf3e2f52fc00d0587ad0513024d0 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 14:41:58 +0100 Subject: [PATCH 08/72] Getting rid of Bin and Bins traits, for now --- src/histogram.rs | 71 ++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 45 deletions(-) diff --git a/src/histogram.rs b/src/histogram.rs index 190fd937..2098fcf2 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -2,80 +2,67 @@ mod bins { use ndarray::prelude::*; use ndarray::Data; - struct Bins1d { + /// `Bins` is a collection of non-overlapping + /// intervals (`Bin1d`) in a 1-dimensional space. + pub struct Bins1d { bins: Vec>, } - struct BinsNd { + /// `Bins` is a collection of non-overlapping + /// sub-regions (`BinNd`) in a `n`-dimensional space. + pub struct BinsNd { bins: Vec>, } - /// `Bins` is a collection of non-overlapping /// sub-regions (`Bin`) in a `n` dimensional space. - pub trait Bins { - /// Return `n`, the number of dimensions. - fn ndim(&self) -> usize; - + impl Bins1d { /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin` `B`; /// - `None`, if `P` does not belong to any `Bin` in `Bins`. /// /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. - fn find(&self, point: ArrayBase) -> Option - where - S: Data, - D: Dimension, - B: Bin; - } - - impl Bins for Bins1d { - fn ndim(&self) -> usize { - 1 - } - - fn find(&self, _point: ArrayBase) -> Option + pub fn find(&self, _point: ArrayBase) -> Option> where S: Data, D: Dimension, - B: Bin, { unimplemented!() } } - impl Bins for BinsNd { + impl BinsNd { + /// Return `n`, the number of dimensions. fn ndim(&self) -> usize { unimplemented!() } - fn find(&self, _point: ArrayBase) -> Option + /// Given a point `P`, it returns an `Option`: + /// - `Some(B)`, if `P` belongs to the `Bin` `B`; + /// - `None`, if `P` does not belong to any `Bin` in `Bins`. + /// + /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. + pub fn find(&self, _point: ArrayBase) -> Option> where S: Data, D: Dimension, - B: Bin, { unimplemented!() } } - pub trait Bin { - - } - struct Bin1d { + pub struct Bin1d { left: T, right: T, } - struct BinNd { + pub struct BinNd { projections: Vec>, } - impl Bin for Bin1d {} - impl Bin for BinNd {} } use std::collections::HashMap; -use self::bins::{Bin, Bins}; +use self::bins::{Bin1d, BinNd, BinsNd, Bins1d}; use ndarray::prelude::*; use ndarray::Data; -type Histogram = HashMap, usize>; +type HistogramNd = HashMap, usize>; pub trait HistogramNdExt where @@ -91,18 +78,14 @@ where /// /// For example: a (3, 4) matrix `M` is a collection of 3 points in a /// 4-dimensional space. - fn histogram(&self, bins: B) -> Histogram - where - B: Bins; + fn histogram(&self, bins: BinsNd) -> HistogramNd; } impl HistogramNdExt for ArrayBase where S: Data, { - fn histogram(&self, bins: B) -> Histogram - where - B: Bins, + fn histogram(&self, bins: BinsNd) -> HistogramNd { let mut histogram = HashMap::new(); for point in self.axis_iter(Axis(0)) { @@ -115,22 +98,20 @@ where } } +type Histogram1d = HashMap, usize>; + pub trait Histogram1dExt where S: Data, { - fn histogram(&self, bins: B) -> Histogram - where - B: Bins; + fn histogram(&self, bins: Bins1d) -> Histogram1d; } impl Histogram1dExt for ArrayBase where S: Data, { - fn histogram(&self, _bins: B) -> Histogram - where - B: Bins, + fn histogram(&self, bins: Bins1d) -> Histogram1d { unimplemented!() } From 2806eaaff972c71a360d1c08d04e07a0abe3a378 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 14:56:51 +0100 Subject: [PATCH 09/72] Added bounds to allow storage in HashMap --- src/histogram.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/histogram.rs b/src/histogram.rs index 2098fcf2..9014d1f9 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -1,19 +1,23 @@ mod bins { use ndarray::prelude::*; use ndarray::Data; + use std::hash::Hash; /// `Bins` is a collection of non-overlapping /// intervals (`Bin1d`) in a 1-dimensional space. - pub struct Bins1d { + pub struct Bins1d { bins: Vec>, } /// `Bins` is a collection of non-overlapping /// sub-regions (`BinNd`) in a `n`-dimensional space. - pub struct BinsNd { + pub struct BinsNd { bins: Vec>, } - impl Bins1d { + impl Bins1d + where + T: Hash + Eq + { /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin` `B`; /// - `None`, if `P` does not belong to any `Bin` in `Bins`. @@ -28,7 +32,10 @@ mod bins { } } - impl BinsNd { + impl BinsNd + where + T: Hash + Eq + { /// Return `n`, the number of dimensions. fn ndim(&self) -> usize { unimplemented!() @@ -48,16 +55,20 @@ mod bins { } } - pub struct Bin1d { + #[derive(Hash, PartialEq, Eq)] + pub struct Bin1d { left: T, right: T, } - pub struct BinNd { + + #[derive(Hash, PartialEq, Eq)] + pub struct BinNd { projections: Vec>, } } use std::collections::HashMap; +use std::hash::Hash; use self::bins::{Bin1d, BinNd, BinsNd, Bins1d}; use ndarray::prelude::*; use ndarray::Data; @@ -67,6 +78,7 @@ type HistogramNd = HashMap, usize>; pub trait HistogramNdExt where S: Data, + A: Hash + Eq, { /// Return the [histogram](https://en.wikipedia.org/wiki/Histogram) /// for a 2-dimensional array of points `M`. @@ -84,6 +96,7 @@ where impl HistogramNdExt for ArrayBase where S: Data, + A: Hash + Eq, { fn histogram(&self, bins: BinsNd) -> HistogramNd { @@ -103,6 +116,7 @@ type Histogram1d = HashMap, usize>; pub trait Histogram1dExt where S: Data, + A: Hash + Eq, { fn histogram(&self, bins: Bins1d) -> Histogram1d; } @@ -110,6 +124,7 @@ where impl Histogram1dExt for ArrayBase where S: Data, + A: Hash + Eq, { fn histogram(&self, bins: Bins1d) -> Histogram1d { From 28ef955851fab2d5cf7d097d34ce298d92d66227 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 15:12:42 +0100 Subject: [PATCH 10/72] Let's ignore code duplication for now - histogram 1d implemented --- src/histogram.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/histogram.rs b/src/histogram.rs index 9014d1f9..a8ad58aa 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -128,6 +128,13 @@ where { fn histogram(&self, bins: Bins1d) -> Histogram1d { - unimplemented!() + let mut histogram = HashMap::new(); + for point in self.axis_iter(Axis(0)) { + let bin = bins.find(point); + if let Some(b) = bin { + histogram.insert(b, 1); + }; + } + histogram } } \ No newline at end of file From dbc499362f849e0c62426e64945d8745ac52e8b1 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 15:26:32 +0100 Subject: [PATCH 11/72] Restructured as submodules --- src/histogram.rs | 140 ---------------------------------- src/histogram/bins/mod.rs | 5 ++ src/histogram/bins/n_dim.rs | 39 ++++++++++ src/histogram/bins/one_dim.rs | 33 ++++++++ src/histogram/mod.rs | 72 +++++++++++++++++ 5 files changed, 149 insertions(+), 140 deletions(-) delete mode 100644 src/histogram.rs create mode 100644 src/histogram/bins/mod.rs create mode 100644 src/histogram/bins/n_dim.rs create mode 100644 src/histogram/bins/one_dim.rs create mode 100644 src/histogram/mod.rs diff --git a/src/histogram.rs b/src/histogram.rs deleted file mode 100644 index a8ad58aa..00000000 --- a/src/histogram.rs +++ /dev/null @@ -1,140 +0,0 @@ -mod bins { - use ndarray::prelude::*; - use ndarray::Data; - use std::hash::Hash; - - /// `Bins` is a collection of non-overlapping - /// intervals (`Bin1d`) in a 1-dimensional space. - pub struct Bins1d { - bins: Vec>, - } - /// `Bins` is a collection of non-overlapping - /// sub-regions (`BinNd`) in a `n`-dimensional space. - pub struct BinsNd { - bins: Vec>, - } - - impl Bins1d - where - T: Hash + Eq - { - /// Given a point `P`, it returns an `Option`: - /// - `Some(B)`, if `P` belongs to the `Bin` `B`; - /// - `None`, if `P` does not belong to any `Bin` in `Bins`. - /// - /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. - pub fn find(&self, _point: ArrayBase) -> Option> - where - S: Data, - D: Dimension, - { - unimplemented!() - } - } - - impl BinsNd - where - T: Hash + Eq - { - /// Return `n`, the number of dimensions. - fn ndim(&self) -> usize { - unimplemented!() - } - - /// Given a point `P`, it returns an `Option`: - /// - `Some(B)`, if `P` belongs to the `Bin` `B`; - /// - `None`, if `P` does not belong to any `Bin` in `Bins`. - /// - /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. - pub fn find(&self, _point: ArrayBase) -> Option> - where - S: Data, - D: Dimension, - { - unimplemented!() - } - } - - #[derive(Hash, PartialEq, Eq)] - pub struct Bin1d { - left: T, - right: T, - } - - #[derive(Hash, PartialEq, Eq)] - pub struct BinNd { - projections: Vec>, - } -} - -use std::collections::HashMap; -use std::hash::Hash; -use self::bins::{Bin1d, BinNd, BinsNd, Bins1d}; -use ndarray::prelude::*; -use ndarray::Data; - -type HistogramNd = HashMap, usize>; - -pub trait HistogramNdExt -where - S: Data, - A: Hash + Eq, -{ - /// Return the [histogram](https://en.wikipedia.org/wiki/Histogram) - /// for a 2-dimensional array of points `M`. - /// - /// Let `(n, d)` be the shape of `M`: - /// - `n` is the number of points; - /// - `d` is the number of dimensions of the space those points belong to. - /// It follows that every column in `M` is a `d`-dimensional point. - /// - /// For example: a (3, 4) matrix `M` is a collection of 3 points in a - /// 4-dimensional space. - fn histogram(&self, bins: BinsNd) -> HistogramNd; -} - -impl HistogramNdExt for ArrayBase -where - S: Data, - A: Hash + Eq, -{ - fn histogram(&self, bins: BinsNd) -> HistogramNd - { - let mut histogram = HashMap::new(); - for point in self.axis_iter(Axis(0)) { - let bin = bins.find(point); - if let Some(b) = bin { - histogram.insert(b, 1); - }; - } - histogram - } -} - -type Histogram1d = HashMap, usize>; - -pub trait Histogram1dExt -where - S: Data, - A: Hash + Eq, -{ - fn histogram(&self, bins: Bins1d) -> Histogram1d; -} - -impl Histogram1dExt for ArrayBase -where - S: Data, - A: Hash + Eq, -{ - fn histogram(&self, bins: Bins1d) -> Histogram1d - { - let mut histogram = HashMap::new(); - for point in self.axis_iter(Axis(0)) { - let bin = bins.find(point); - if let Some(b) = bin { - histogram.insert(b, 1); - }; - } - histogram - } -} \ No newline at end of file diff --git a/src/histogram/bins/mod.rs b/src/histogram/bins/mod.rs new file mode 100644 index 00000000..927856b5 --- /dev/null +++ b/src/histogram/bins/mod.rs @@ -0,0 +1,5 @@ +pub use self::one_dim::{Bin1d, Bins1d}; +pub use self::n_dim::{BinNd, BinsNd}; + +mod one_dim; +mod n_dim; \ No newline at end of file diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs new file mode 100644 index 00000000..0d0a5864 --- /dev/null +++ b/src/histogram/bins/n_dim.rs @@ -0,0 +1,39 @@ +use ndarray::prelude::*; +use ndarray::Data; +use std::hash::Hash; +use histogram::bins::Bin1d; + +#[derive(Hash, PartialEq, Eq)] +pub struct BinNd { + projections: Vec>, +} + +/// `Bins` is a collection of non-overlapping +/// sub-regions (`BinNd`) in a `n`-dimensional space. +pub struct BinsNd { + bins: Vec>, +} + + +impl BinsNd +where + T: Hash + Eq +{ + /// Return `n`, the number of dimensions. + fn ndim(&self) -> usize { + unimplemented!() + } + + /// Given a point `P`, it returns an `Option`: + /// - `Some(B)`, if `P` belongs to the `Bin` `B`; + /// - `None`, if `P` does not belong to any `Bin` in `Bins`. + /// + /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. + pub fn find(&self, _point: ArrayBase) -> Option> + where + S: Data, + D: Dimension, + { + unimplemented!() + } +} diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs new file mode 100644 index 00000000..f28ce0ed --- /dev/null +++ b/src/histogram/bins/one_dim.rs @@ -0,0 +1,33 @@ +use ndarray::prelude::*; +use ndarray::Data; +use std::hash::Hash; + +#[derive(Hash, PartialEq, Eq)] +pub struct Bin1d { + left: T, + right: T, +} + +/// `Bins` is a collection of non-overlapping +/// intervals (`Bin1d`) in a 1-dimensional space. +pub struct Bins1d { + bins: Vec>, +} + +impl Bins1d +where + T: Hash + Eq +{ + /// Given a point `P`, it returns an `Option`: + /// - `Some(B)`, if `P` belongs to the `Bin` `B`; + /// - `None`, if `P` does not belong to any `Bin` in `Bins`. + /// + /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. + pub fn find(&self, _point: ArrayBase) -> Option> + where + S: Data, + D: Dimension, + { + unimplemented!() + } +} \ No newline at end of file diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs new file mode 100644 index 00000000..292b538b --- /dev/null +++ b/src/histogram/mod.rs @@ -0,0 +1,72 @@ +use std::collections::HashMap; +use std::hash::Hash; +mod bins; +use self::bins::{Bin1d, BinNd, BinsNd, Bins1d}; +use ndarray::prelude::*; +use ndarray::Data; + +type HistogramNd = HashMap, usize>; + +pub trait HistogramNdExt +where + S: Data, + A: Hash + Eq, +{ + /// Return the [histogram](https://en.wikipedia.org/wiki/Histogram) + /// for a 2-dimensional array of points `M`. + /// + /// Let `(n, d)` be the shape of `M`: + /// - `n` is the number of points; + /// - `d` is the number of dimensions of the space those points belong to. + /// It follows that every column in `M` is a `d`-dimensional point. + /// + /// For example: a (3, 4) matrix `M` is a collection of 3 points in a + /// 4-dimensional space. + fn histogram(&self, bins: BinsNd) -> HistogramNd; +} + +impl HistogramNdExt for ArrayBase +where + S: Data, + A: Hash + Eq, +{ + fn histogram(&self, bins: BinsNd) -> HistogramNd + { + let mut histogram = HashMap::new(); + for point in self.axis_iter(Axis(0)) { + let bin = bins.find(point); + if let Some(b) = bin { + histogram.insert(b, 1); + }; + } + histogram + } +} + +type Histogram1d = HashMap, usize>; + +pub trait Histogram1dExt +where + S: Data, + A: Hash + Eq, +{ + fn histogram(&self, bins: Bins1d) -> Histogram1d; +} + +impl Histogram1dExt for ArrayBase +where + S: Data, + A: Hash + Eq, +{ + fn histogram(&self, bins: Bins1d) -> Histogram1d + { + let mut histogram = HashMap::new(); + for point in self.axis_iter(Axis(0)) { + let bin = bins.find(point); + if let Some(b) = bin { + histogram.insert(b, 1); + }; + } + histogram + } +} \ No newline at end of file From a3358eaa817f1e7d76eeadb8e7bc1e3b942b9331 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 16:06:44 +0100 Subject: [PATCH 12/72] Constructors have been implemented for BinNd and BinsNd --- src/histogram/bins/n_dim.rs | 45 +++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 0d0a5864..9a7dcb3f 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -1,6 +1,7 @@ use ndarray::prelude::*; use ndarray::Data; use std::hash::Hash; +use std::ops::Index; use histogram::bins::Bin1d; #[derive(Hash, PartialEq, Eq)] @@ -8,20 +9,60 @@ pub struct BinNd { projections: Vec>, } +impl BinNd +where + T: Hash + Eq +{ + /// Creates a new instance of BinNd from a vector + /// of its 1-dimensional projections. + pub fn new(projections: Vec>) -> Self { + if projections.is_empty() { + panic!( + "The 1-dimensional projections of an n-dimensional + bin can't be empty!" + ) + } else { + Self { projections } + } + } + + pub fn ndim(&self) -> usize { + self.projections.len() + } +} + /// `Bins` is a collection of non-overlapping /// sub-regions (`BinNd`) in a `n`-dimensional space. pub struct BinsNd { bins: Vec>, + ndim: usize, } - impl BinsNd where T: Hash + Eq { + /// Creates a new instance of BinNd from a vector + /// of its 1-dimensional projections. + pub fn new(bins: Vec>) -> Self { + assert!(!bins.is_empty(), "The bins collection cannot be empty!"); + // All bins must have the same number of dimensions! + let first_bin = bins.index(0); + let ndim = first_bin.ndim(); + &bins.iter().map( + |b| assert_eq!( + b.ndim(), ndim, + "There at least two bins with different \ + number of dimensions: {0} and {1}.", b, first_bin) + ); + Self { bins, ndim } + } + /// Return `n`, the number of dimensions. + /// + /// **Panics** if `bins` is empty. fn ndim(&self) -> usize { - unimplemented!() + self.ndim } /// Given a point `P`, it returns an `Option`: From f6b88ad5013fd07b3c92bd4ec796ca17537702ec Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 16:33:55 +0100 Subject: [PATCH 13/72] Implemented Display for Bins in order to show proper error messages --- src/histogram/bins/n_dim.rs | 40 ++++++++++++++++++++++++----------- src/histogram/bins/one_dim.rs | 10 +++++++++ src/histogram/mod.rs | 9 ++++---- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 9a7dcb3f..b299c78b 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -2,16 +2,29 @@ use ndarray::prelude::*; use ndarray::Data; use std::hash::Hash; use std::ops::Index; +use std::fmt; use histogram::bins::Bin1d; #[derive(Hash, PartialEq, Eq)] -pub struct BinNd { +pub struct BinNd { projections: Vec>, } +impl fmt::Display for BinNd +where + T: Hash + Eq + fmt::Debug +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let repr = self.projections.iter().map( + |p| format!("{}", p) + ).collect::>().join("x"); + write!(f, "{}", repr) + } +} + impl BinNd where - T: Hash + Eq + T: Hash + Eq + fmt::Debug { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. @@ -33,28 +46,31 @@ where /// `Bins` is a collection of non-overlapping /// sub-regions (`BinNd`) in a `n`-dimensional space. -pub struct BinsNd { +pub struct BinsNd { bins: Vec>, ndim: usize, } impl BinsNd where - T: Hash + Eq + T: Hash + Eq + fmt::Debug { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. pub fn new(bins: Vec>) -> Self { assert!(!bins.is_empty(), "The bins collection cannot be empty!"); // All bins must have the same number of dimensions! - let first_bin = bins.index(0); - let ndim = first_bin.ndim(); - &bins.iter().map( - |b| assert_eq!( - b.ndim(), ndim, - "There at least two bins with different \ - number of dimensions: {0} and {1}.", b, first_bin) - ); + let ndim = { + let first_bin = bins.index(0); + let ndim = first_bin.ndim(); + &bins.iter().map( + |b| assert_eq!( + b.ndim(), ndim, + "There at least two bins with different \ + number of dimensions: {0} and {1}.", b, first_bin) + ); + ndim + }; Self { bins, ndim } } diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index f28ce0ed..3fbe71f7 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -1,5 +1,6 @@ use ndarray::prelude::*; use ndarray::Data; +use std::fmt; use std::hash::Hash; #[derive(Hash, PartialEq, Eq)] @@ -8,6 +9,15 @@ pub struct Bin1d { right: T, } +impl fmt::Display for Bin1d +where + T: Hash + Eq + fmt::Debug +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({0:?}, {1:?})", self.left, self.right) + } +} + /// `Bins` is a collection of non-overlapping /// intervals (`Bin1d`) in a 1-dimensional space. pub struct Bins1d { diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index 292b538b..ecf2adfd 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::hash::Hash; +use std::fmt; mod bins; use self::bins::{Bin1d, BinNd, BinsNd, Bins1d}; use ndarray::prelude::*; @@ -10,7 +11,7 @@ type HistogramNd = HashMap, usize>; pub trait HistogramNdExt where S: Data, - A: Hash + Eq, + A: Hash + Eq + fmt::Debug, { /// Return the [histogram](https://en.wikipedia.org/wiki/Histogram) /// for a 2-dimensional array of points `M`. @@ -28,7 +29,7 @@ where impl HistogramNdExt for ArrayBase where S: Data, - A: Hash + Eq, + A: Hash + Eq + fmt::Debug, { fn histogram(&self, bins: BinsNd) -> HistogramNd { @@ -48,7 +49,7 @@ type Histogram1d = HashMap, usize>; pub trait Histogram1dExt where S: Data, - A: Hash + Eq, + A: Hash + Eq + fmt::Debug, { fn histogram(&self, bins: Bins1d) -> Histogram1d; } @@ -56,7 +57,7 @@ where impl Histogram1dExt for ArrayBase where S: Data, - A: Hash + Eq, + A: Hash + Eq + fmt::Debug, { fn histogram(&self, bins: Bins1d) -> Histogram1d { From c3ab8a832ff09fc5e03ecd60fb44d51312dfb05e Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 16:41:05 +0100 Subject: [PATCH 14/72] ndim method has to be public --- src/histogram/bins/n_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index b299c78b..6dea6bd2 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -77,7 +77,7 @@ where /// Return `n`, the number of dimensions. /// /// **Panics** if `bins` is empty. - fn ndim(&self) -> usize { + pub fn ndim(&self) -> usize { self.ndim } From 8d43d5e3458232a5c894affa8555682fd4be25b2 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 16:56:48 +0100 Subject: [PATCH 15/72] Added Clone bound --- src/histogram/bins/one_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 3fbe71f7..67baab79 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -3,7 +3,7 @@ use ndarray::Data; use std::fmt; use std::hash::Hash; -#[derive(Hash, PartialEq, Eq)] +#[derive(Hash, PartialEq, Eq, Clone)] pub struct Bin1d { left: T, right: T, From eda210e5393d70a4e2bb7ba73ec7982872c8130d Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 16:57:02 +0100 Subject: [PATCH 16/72] Implemented find method. Added clone bound --- src/histogram/bins/n_dim.rs | 27 ++++++++++++++++++--------- src/histogram/mod.rs | 8 ++++---- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 6dea6bd2..47c9456e 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -5,14 +5,14 @@ use std::ops::Index; use std::fmt; use histogram::bins::Bin1d; -#[derive(Hash, PartialEq, Eq)] -pub struct BinNd { +#[derive(Hash, PartialEq, Eq, Clone)] +pub struct BinNd { projections: Vec>, } impl fmt::Display for BinNd where - T: Hash + Eq + fmt::Debug + T: Hash + Eq + fmt::Debug + Clone { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let repr = self.projections.iter().map( @@ -24,7 +24,7 @@ where impl BinNd where - T: Hash + Eq + fmt::Debug + T: Hash + Eq + fmt::Debug + Clone { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. @@ -42,18 +42,23 @@ where pub fn ndim(&self) -> usize { self.projections.len() } + + pub fn contains(&self, _point: ArrayView1) -> bool + { + unimplemented!() + } } /// `Bins` is a collection of non-overlapping /// sub-regions (`BinNd`) in a `n`-dimensional space. -pub struct BinsNd { +pub struct BinsNd { bins: Vec>, ndim: usize, } impl BinsNd where - T: Hash + Eq + fmt::Debug + T: Hash + Eq + fmt::Debug + Clone { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. @@ -86,11 +91,15 @@ where /// - `None`, if `P` does not belong to any `Bin` in `Bins`. /// /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. - pub fn find(&self, _point: ArrayBase) -> Option> + pub fn find(&self, point: ArrayBase) -> Option> where S: Data, - D: Dimension, { - unimplemented!() + for bin in self.bins.iter() { + if bin.contains(point.view()) { + return Some((*bin).clone()) + } + } + None } } diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index ecf2adfd..e72a9b23 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -11,7 +11,7 @@ type HistogramNd = HashMap, usize>; pub trait HistogramNdExt where S: Data, - A: Hash + Eq + fmt::Debug, + A: Hash + Eq + fmt::Debug + Clone, { /// Return the [histogram](https://en.wikipedia.org/wiki/Histogram) /// for a 2-dimensional array of points `M`. @@ -29,7 +29,7 @@ where impl HistogramNdExt for ArrayBase where S: Data, - A: Hash + Eq + fmt::Debug, + A: Hash + Eq + fmt::Debug + Clone, { fn histogram(&self, bins: BinsNd) -> HistogramNd { @@ -49,7 +49,7 @@ type Histogram1d = HashMap, usize>; pub trait Histogram1dExt where S: Data, - A: Hash + Eq + fmt::Debug, + A: Hash + Eq + fmt::Debug + Clone, { fn histogram(&self, bins: Bins1d) -> Histogram1d; } @@ -57,7 +57,7 @@ where impl Histogram1dExt for ArrayBase where S: Data, - A: Hash + Eq + fmt::Debug, + A: Hash + Eq + fmt::Debug + Clone, { fn histogram(&self, bins: Bins1d) -> Histogram1d { From 1ac42e4f94a64b986dc519ca9b987e62e18c5c43 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 17:08:32 +0100 Subject: [PATCH 17/72] Added contains method to Bin1d --- src/histogram/bins/one_dim.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 67baab79..0348c3fe 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -9,6 +9,16 @@ pub struct Bin1d { right: T, } +impl Bin1d +where + T: Hash + Eq + fmt::Debug + Clone +{ + pub fn contains(&self, point: T) -> bool + { + unimplemented!() + } +} + impl fmt::Display for Bin1d where T: Hash + Eq + fmt::Debug @@ -18,21 +28,21 @@ where } } -/// `Bins` is a collection of non-overlapping +/// `Bins` is a collection of non-overlapping /// intervals (`Bin1d`) in a 1-dimensional space. pub struct Bins1d { bins: Vec>, } -impl Bins1d -where - T: Hash + Eq +impl Bins1d +where + T: Hash + Eq { /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin` `B`; /// - `None`, if `P` does not belong to any `Bin` in `Bins`. - /// - /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. + /// + /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. pub fn find(&self, _point: ArrayBase) -> Option> where S: Data, From 0bea875a490bdaaab936629965e8f85d8cd35378 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 17:09:03 +0100 Subject: [PATCH 18/72] Taking a reference, instead of moving value --- src/histogram/bins/one_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 0348c3fe..64568673 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -13,7 +13,7 @@ impl Bin1d where T: Hash + Eq + fmt::Debug + Clone { - pub fn contains(&self, point: T) -> bool + pub fn contains(&self, point: &T) -> bool { unimplemented!() } From edfc4139922a55af359c69a88f98674c5633d03b Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 17:13:06 +0100 Subject: [PATCH 19/72] Implemented contains for BinNd --- src/histogram/bins/n_dim.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 47c9456e..56db1a83 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -27,12 +27,12 @@ where T: Hash + Eq + fmt::Debug + Clone { /// Creates a new instance of BinNd from a vector - /// of its 1-dimensional projections. + /// of its 1-dimensional projections. pub fn new(projections: Vec>) -> Self { if projections.is_empty() { panic!( "The 1-dimensional projections of an n-dimensional - bin can't be empty!" + bin can't be empty!" ) } else { Self { projections } @@ -43,25 +43,28 @@ where self.projections.len() } - pub fn contains(&self, _point: ArrayView1) -> bool + pub fn contains(&self, point: ArrayView1) -> bool { - unimplemented!() + point.iter(). + zip(self.projections.iter()). + map(|(element, projection)| projection.contains(element)). + fold(true, |acc, v| acc & v) } } -/// `Bins` is a collection of non-overlapping +/// `Bins` is a collection of non-overlapping /// sub-regions (`BinNd`) in a `n`-dimensional space. pub struct BinsNd { bins: Vec>, ndim: usize, } -impl BinsNd -where +impl BinsNd +where T: Hash + Eq + fmt::Debug + Clone { /// Creates a new instance of BinNd from a vector - /// of its 1-dimensional projections. + /// of its 1-dimensional projections. pub fn new(bins: Vec>) -> Self { assert!(!bins.is_empty(), "The bins collection cannot be empty!"); // All bins must have the same number of dimensions! @@ -70,7 +73,7 @@ where let ndim = first_bin.ndim(); &bins.iter().map( |b| assert_eq!( - b.ndim(), ndim, + b.ndim(), ndim, "There at least two bins with different \ number of dimensions: {0} and {1}.", b, first_bin) ); @@ -80,7 +83,7 @@ where } /// Return `n`, the number of dimensions. - /// + /// /// **Panics** if `bins` is empty. pub fn ndim(&self) -> usize { self.ndim @@ -89,8 +92,8 @@ where /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin` `B`; /// - `None`, if `P` does not belong to any `Bin` in `Bins`. - /// - /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. + /// + /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. pub fn find(&self, point: ArrayBase) -> Option> where S: Data, @@ -102,4 +105,4 @@ where } None } -} +} \ No newline at end of file From af62d85a153eaac1176dcecb8d0b32a1ebe1161c Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Mon, 1 Oct 2018 18:10:04 +0100 Subject: [PATCH 20/72] Added contains method implementation for Bin1d --- src/histogram/bins/n_dim.rs | 4 ++-- src/histogram/bins/one_dim.rs | 13 +++++++++++-- src/histogram/mod.rs | 8 ++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 56db1a83..6db125ab 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -24,7 +24,7 @@ where impl BinNd where - T: Hash + Eq + fmt::Debug + Clone + T: Hash + Eq + fmt::Debug + Clone + PartialOrd { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. @@ -61,7 +61,7 @@ pub struct BinsNd { impl BinsNd where - T: Hash + Eq + fmt::Debug + Clone + T: Hash + Eq + fmt::Debug + Clone + PartialOrd { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 64568673..e0918e2a 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -2,6 +2,7 @@ use ndarray::prelude::*; use ndarray::Data; use std::fmt; use std::hash::Hash; +use std::cmp::Ordering; #[derive(Hash, PartialEq, Eq, Clone)] pub struct Bin1d { @@ -11,11 +12,19 @@ pub struct Bin1d { impl Bin1d where - T: Hash + Eq + fmt::Debug + Clone + T: Hash + Eq + fmt::Debug + Clone + PartialOrd { pub fn contains(&self, point: &T) -> bool { - unimplemented!() + match point.partial_cmp(&self.left) { + Some(Ordering::Greater) => { + match point.partial_cmp(&self.right) { + Some(Ordering::Less) => true, + _ => false + } + }, + _ => false + } } } diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index e72a9b23..614a3cb8 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -20,8 +20,8 @@ where /// - `n` is the number of points; /// - `d` is the number of dimensions of the space those points belong to. /// It follows that every column in `M` is a `d`-dimensional point. - /// - /// For example: a (3, 4) matrix `M` is a collection of 3 points in a + /// + /// For example: a (3, 4) matrix `M` is a collection of 3 points in a /// 4-dimensional space. fn histogram(&self, bins: BinsNd) -> HistogramNd; } @@ -29,7 +29,7 @@ where impl HistogramNdExt for ArrayBase where S: Data, - A: Hash + Eq + fmt::Debug + Clone, + A: Hash + Eq + fmt::Debug + Clone + PartialOrd, { fn histogram(&self, bins: BinsNd) -> HistogramNd { @@ -57,7 +57,7 @@ where impl Histogram1dExt for ArrayBase where S: Data, - A: Hash + Eq + fmt::Debug + Clone, + A: Hash + Eq + fmt::Debug + Clone + PartialOrd, { fn histogram(&self, bins: Bins1d) -> Histogram1d { From 3f0aacce6b94bc1a40bb0ff70435416ee177886f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 10:52:30 +0100 Subject: [PATCH 21/72] Using std::ops::Range* to implement Bin1d as an enum --- src/histogram/bins/one_dim.rs | 62 +++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index e0918e2a..ecf225e6 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -2,12 +2,32 @@ use ndarray::prelude::*; use ndarray::Data; use std::fmt; use std::hash::Hash; -use std::cmp::Ordering; +use std::ops::*; #[derive(Hash, PartialEq, Eq, Clone)] -pub struct Bin1d { - left: T, - right: T, +pub enum Bin1d { + Range(Range), + RangeFrom(RangeFrom), + RangeFull(RangeFull), + RangeInclusive(RangeInclusive), + RangeTo(RangeTo), + RangeToInclusive(RangeToInclusive), +} + +impl fmt::Display for Bin1d +where + T: Hash + Eq + fmt::Debug +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Bin1d::Range(x) => write!(f, "{:?}", x), + Bin1d::RangeFrom(x) => write!(f, "{:?}", x), + Bin1d::RangeFull(x) => write!(f, "{:?}", x), + Bin1d::RangeInclusive(x) => write!(f, "{:?}", x), + Bin1d::RangeTo(x) => write!(f, "{:?}", x), + Bin1d::RangeToInclusive(x) => write!(f, "{:?}", x), + } + } } impl Bin1d @@ -16,25 +36,33 @@ where { pub fn contains(&self, point: &T) -> bool { - match point.partial_cmp(&self.left) { - Some(Ordering::Greater) => { - match point.partial_cmp(&self.right) { - Some(Ordering::Less) => true, - _ => false - } - }, - _ => false + match self { + Bin1d::Range(x) => contains::, T>(x, point), + Bin1d::RangeFrom(x) => contains::, T>(x, point), + Bin1d::RangeFull(_) => true, + Bin1d::RangeInclusive(x) => contains::, T>(x, point), + Bin1d::RangeTo(x) => contains::, T>(x, point), + Bin1d::RangeToInclusive(x) => contains::, T>(x, point), } } } -impl fmt::Display for Bin1d +fn contains(range: &R, item: &T) -> bool where - T: Hash + Eq + fmt::Debug + R: RangeBounds, + T: PartialOrd, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({0:?}, {1:?})", self.left, self.right) - } + (match range.start_bound() { + Bound::Included(ref start) => *start <= item, + Bound::Excluded(ref start) => *start < item, + Bound::Unbounded => true, + }) + && + (match range.end_bound() { + Bound::Included(ref end) => item <= *end, + Bound::Excluded(ref end) => item < *end, + Bound::Unbounded => true, + }) } /// `Bins` is a collection of non-overlapping From bf9965e7671683830d982f5fe5395a4e5f8d8283 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 10:58:59 +0100 Subject: [PATCH 22/72] Implemented find --- src/histogram/bins/one_dim.rs | 24 ++++++++++++------------ src/histogram/mod.rs | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index ecf225e6..b379a8cc 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -1,11 +1,9 @@ -use ndarray::prelude::*; -use ndarray::Data; use std::fmt; use std::hash::Hash; use std::ops::*; #[derive(Hash, PartialEq, Eq, Clone)] -pub enum Bin1d { +pub enum Bin1d { Range(Range), RangeFrom(RangeFrom), RangeFull(RangeFull), @@ -16,7 +14,7 @@ pub enum Bin1d { impl fmt::Display for Bin1d where - T: Hash + Eq + fmt::Debug + T: Hash + Eq + Clone + fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -32,7 +30,7 @@ where impl Bin1d where - T: Hash + Eq + fmt::Debug + Clone + PartialOrd + T: Hash + Eq + Clone + PartialOrd { pub fn contains(&self, point: &T) -> bool { @@ -67,24 +65,26 @@ where /// `Bins` is a collection of non-overlapping /// intervals (`Bin1d`) in a 1-dimensional space. -pub struct Bins1d { +pub struct Bins1d { bins: Vec>, } impl Bins1d where - T: Hash + Eq + T: Hash + Eq + Clone + PartialOrd { /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin` `B`; /// - `None`, if `P` does not belong to any `Bin` in `Bins`. /// /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. - pub fn find(&self, _point: ArrayBase) -> Option> - where - S: Data, - D: Dimension, + pub fn find(&self, point: &T) -> Option> { - unimplemented!() + for bin in self.bins.iter() { + if bin.contains(point) { + return Some((*bin).clone()) + } + } + None } } \ No newline at end of file diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index 614a3cb8..a88593ad 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -62,7 +62,7 @@ where fn histogram(&self, bins: Bins1d) -> Histogram1d { let mut histogram = HashMap::new(); - for point in self.axis_iter(Axis(0)) { + for point in self.iter() { let bin = bins.find(point); if let Some(b) = bin { histogram.insert(b, 1); From 641ed57a92dbbf11bc6b3cb0f8c1d5260b3665e3 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 11:00:33 +0100 Subject: [PATCH 23/72] Fixed docs --- src/histogram/bins/one_dim.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index b379a8cc..c32821c3 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -74,10 +74,8 @@ where T: Hash + Eq + Clone + PartialOrd { /// Given a point `P`, it returns an `Option`: - /// - `Some(B)`, if `P` belongs to the `Bin` `B`; - /// - `None`, if `P` does not belong to any `Bin` in `Bins`. - /// - /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. + /// - `Some(B)`, if `P` belongs to the `Bin1d` `B`; + /// - `None`, if `P` does not belong to any `Bin1d` in `Bins`. pub fn find(&self, point: &T) -> Option> { for bin in self.bins.iter() { From 4ea33b74f76de8cfe490bdee21aa92a3c0f687e0 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 11:04:25 +0100 Subject: [PATCH 24/72] Unglobed import --- src/histogram/bins/one_dim.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index c32821c3..1ff2a11a 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -1,6 +1,7 @@ use std::fmt; use std::hash::Hash; -use std::ops::*; +use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, + RangeInclusive, RangeTo, RangeToInclusive}; #[derive(Hash, PartialEq, Eq, Clone)] pub enum Bin1d { From e8569514c35c287ecfc96fff84522538babf625a Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 14:04:59 +0100 Subject: [PATCH 25/72] Rexporting functions --- src/histogram/mod.rs | 5 +++-- src/lib.rs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index a88593ad..45f08b8e 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -1,8 +1,9 @@ +mod bins; +pub use self::bins::{Bin1d, BinNd, BinsNd, Bins1d}; + use std::collections::HashMap; use std::hash::Hash; use std::fmt; -mod bins; -use self::bins::{Bin1d, BinNd, BinsNd, Bins1d}; use ndarray::prelude::*; use ndarray::Data; diff --git a/src/lib.rs b/src/lib.rs index e63873b3..e32e9944 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,8 @@ pub use maybe_nan::{MaybeNan, MaybeNanExt}; pub use quantile::{interpolate, QuantileExt}; pub use sort::Sort1dExt; pub use correlation::CorrelationExt; -pub use histogram::{Histogram1dExt, HistogramNdExt}; +pub use histogram::{Histogram1dExt, HistogramNdExt, + Bin1d, Bins1d, BinNd, BinsNd}; mod maybe_nan; mod quantile; From 782fb1bc1fd1adbb1998b2fb81403eda8774b643 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 14:05:13 +0100 Subject: [PATCH 26/72] Added example in docs --- src/histogram/bins/one_dim.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 1ff2a11a..70781a22 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -3,6 +3,21 @@ use std::hash::Hash; use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; +/// One-dimensional intervals. +/// +/// # Example +/// +/// ``` +/// extern crate ndarray_stats; +/// extern crate noisy_float; +/// use ndarray_stats::Bin1d; +/// use noisy_float::types::n64; +/// +/// let unit_interval = Bin1d::RangeInclusive(n64(0.)..=n64(1.)); +/// assert!(unit_interval.contains(&n64(1.))); +/// assert!(unit_interval.contains(&n64(0.))); +/// assert!(unit_interval.contains(&n64(0.5))); +/// ``` #[derive(Hash, PartialEq, Eq, Clone)] pub enum Bin1d { Range(Range), From ac9d924c9e2993cfd7c695e8398fd1f42ecf8a84 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 14:07:47 +0100 Subject: [PATCH 27/72] Added docstring to contains method --- src/histogram/bins/one_dim.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 70781a22..0bec5207 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -48,6 +48,7 @@ impl Bin1d where T: Hash + Eq + Clone + PartialOrd { + /// Return `true` if `point` belongs to the interval, `false` otherwise. pub fn contains(&self, point: &T) -> bool { match self { From be08f357b6b3b21cae6fdd6be80df946ca038a47 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 14:12:05 +0100 Subject: [PATCH 28/72] Test time! --- src/histogram/bins/one_dim.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 0bec5207..bc36bfe4 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -62,6 +62,9 @@ where } } +// Reimplemented here given that [RFC 1434](https://github.com/nox/rust-rfcs/blob/master/text/1434-contains-method-for-ranges.md) +// has not being stabilized yet and we don't want to force nightly +// for the whole library because of it fn contains(range: &R, item: &T) -> bool where R: RangeBounds, @@ -92,7 +95,7 @@ where { /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin1d` `B`; - /// - `None`, if `P` does not belong to any `Bin1d` in `Bins`. + /// - `None`, if `P` does not belong to any `Bin1d` in `Bins1d`. pub fn find(&self, point: &T) -> Option> { for bin in self.bins.iter() { @@ -102,4 +105,9 @@ where } None } +} + +#[cfg(test)] +mod tests { + } \ No newline at end of file From 50db577a51f5171e703e5e242f0de661b6aa06d2 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 15:00:56 +0100 Subject: [PATCH 29/72] Testing Bins1d --- src/histogram/bins/one_dim.rs | 36 ++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index bc36bfe4..58ee0f54 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -18,7 +18,7 @@ use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, /// assert!(unit_interval.contains(&n64(0.))); /// assert!(unit_interval.contains(&n64(0.5))); /// ``` -#[derive(Hash, PartialEq, Eq, Clone)] +#[derive(Hash, PartialEq, Eq, Clone, Debug)] pub enum Bin1d { Range(Range), RangeFrom(RangeFrom), @@ -85,6 +85,7 @@ where /// `Bins` is a collection of non-overlapping /// intervals (`Bin1d`) in a 1-dimensional space. +#[derive(Debug, Clone)] pub struct Bins1d { bins: Vec>, } @@ -109,5 +110,38 @@ where #[cfg(test)] mod tests { + use super::*; + extern crate noisy_float; + #[test] + fn find() { + let bins = vec![ + Bin1d::RangeTo(..0), + Bin1d::Range(0..5), + Bin1d::Range(5..9), + Bin1d::Range(10..15), + Bin1d::RangeFrom(15..), + ]; + let b = Bins1d { bins }; + assert_eq!(b.find(&9), None); + assert_eq!(b.find(&15), Some(Bin1d::RangeFrom(15..))); + } + + #[test] + fn find_with_overlapping_bins() { + let bins = vec![ + Bin1d::RangeToInclusive(..=0), + Bin1d::Range(0..5), + ]; + let b = Bins1d { bins }; + // The first one is matched and returned + assert_eq!(b.find(&0), Some(Bin1d::RangeToInclusive(..=0))); + } + + quickcheck! { + fn find_with_empty_bins(point: i64) -> bool { + let b = Bins1d { bins: vec![] }; + b.find(&point).is_none() + } + } } \ No newline at end of file From de277edc3e733425914a94669f69c2b96e1df37d Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 15:12:28 +0100 Subject: [PATCH 30/72] Minimizing trait bounds --- src/histogram/bins/n_dim.rs | 30 +++++++++++++++++++++++------- src/histogram/bins/one_dim.rs | 11 +++++------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 6db125ab..53165ebd 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -1,18 +1,17 @@ use ndarray::prelude::*; use ndarray::Data; -use std::hash::Hash; use std::ops::Index; use std::fmt; use histogram::bins::Bin1d; -#[derive(Hash, PartialEq, Eq, Clone)] -pub struct BinNd { +#[derive(Hash, PartialEq, Eq, Clone, Debug)] +pub struct BinNd { projections: Vec>, } impl fmt::Display for BinNd where - T: Hash + Eq + fmt::Debug + Clone + T: fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let repr = self.projections.iter().map( @@ -24,7 +23,7 @@ where impl BinNd where - T: Hash + Eq + fmt::Debug + Clone + PartialOrd + T: fmt::Debug + PartialOrd { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. @@ -38,11 +37,19 @@ where Self { projections } } } +} +impl BinNd +{ pub fn ndim(&self) -> usize { self.projections.len() } +} +impl BinNd +where + T: PartialOrd +{ pub fn contains(&self, point: ArrayView1) -> bool { point.iter(). @@ -54,14 +61,15 @@ where /// `Bins` is a collection of non-overlapping /// sub-regions (`BinNd`) in a `n`-dimensional space. -pub struct BinsNd { +#[derive(Clone, Debug)] +pub struct BinsNd { bins: Vec>, ndim: usize, } impl BinsNd where - T: Hash + Eq + fmt::Debug + Clone + PartialOrd + T: fmt::Debug { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. @@ -81,14 +89,22 @@ where }; Self { bins, ndim } } +} +impl BinsNd +{ /// Return `n`, the number of dimensions. /// /// **Panics** if `bins` is empty. pub fn ndim(&self) -> usize { self.ndim } +} +impl BinsNd +where + T: PartialOrd + Clone +{ /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin` `B`; /// - `None`, if `P` does not belong to any `Bin` in `Bins`. diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 58ee0f54..93c3465f 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -1,5 +1,4 @@ use std::fmt; -use std::hash::Hash; use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; @@ -19,7 +18,7 @@ use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, /// assert!(unit_interval.contains(&n64(0.5))); /// ``` #[derive(Hash, PartialEq, Eq, Clone, Debug)] -pub enum Bin1d { +pub enum Bin1d { Range(Range), RangeFrom(RangeFrom), RangeFull(RangeFull), @@ -30,7 +29,7 @@ pub enum Bin1d { impl fmt::Display for Bin1d where - T: Hash + Eq + Clone + fmt::Debug + T: fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -46,7 +45,7 @@ where impl Bin1d where - T: Hash + Eq + Clone + PartialOrd + T: PartialOrd { /// Return `true` if `point` belongs to the interval, `false` otherwise. pub fn contains(&self, point: &T) -> bool @@ -86,13 +85,13 @@ where /// `Bins` is a collection of non-overlapping /// intervals (`Bin1d`) in a 1-dimensional space. #[derive(Debug, Clone)] -pub struct Bins1d { +pub struct Bins1d { bins: Vec>, } impl Bins1d where - T: Hash + Eq + Clone + PartialOrd + T: PartialOrd + Clone { /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin1d` `B`; From eda63b2abd83e9ddb2d5c7c18f969ed7015c06e8 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 15:14:30 +0100 Subject: [PATCH 31/72] Remove unneeded trait bound --- src/histogram/bins/n_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 53165ebd..4758bf9d 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -23,7 +23,7 @@ where impl BinNd where - T: fmt::Debug + PartialOrd + T: fmt::Debug { /// Creates a new instance of BinNd from a vector /// of its 1-dimensional projections. From 28f28d9e2e26006e00343120d4b0eed43d44c21f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 15:33:16 +0100 Subject: [PATCH 32/72] Added docs + doc test + relaxed bound on array in contains --- src/histogram/bins/n_dim.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 4758bf9d..912b7c9e 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -4,6 +4,32 @@ use std::ops::Index; use std::fmt; use histogram::bins::Bin1d; +/// `n`-dimensional bin: `I_1xI_2x..xI_n` where +/// `I_k` is a one-dimensional interval (`Bin1d`). +/// +/// It is instantiated by specifiying the ordered sequence +/// of its 1-dimensional projections on the axes. +/// +/// # Example +/// +/// ``` +/// #[macro_use(array)] +/// extern crate ndarray; +/// extern crate ndarray_stats; +/// extern crate noisy_float; +/// use noisy_float::types::n64; +/// use ndarray_stats::{BinNd, Bin1d}; +/// +/// fn main() { +/// let projections = vec![ +/// Bin1d::RangeInclusive(n64(0.)..=n64(1.)), +/// Bin1d::RangeInclusive(n64(0.)..=n64(1.)), +/// ]; +/// let unit_square = BinNd::new(projections); +/// let point = array![n64(0.5), n64(0.5)]; +/// assert!(unit_square.contains(point)); +/// } +/// ``` #[derive(Hash, PartialEq, Eq, Clone, Debug)] pub struct BinNd { projections: Vec>, @@ -50,7 +76,9 @@ impl BinNd where T: PartialOrd { - pub fn contains(&self, point: ArrayView1) -> bool + pub fn contains(&self, point: ArrayBase) -> bool + where + S: Data { point.iter(). zip(self.projections.iter()). From df4984aea4fede0462ba8770dcf5f710254a8e89 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 15:35:49 +0100 Subject: [PATCH 33/72] Fixed typo. --- src/histogram/bins/n_dim.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 912b7c9e..3fb27b97 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -7,8 +7,8 @@ use histogram::bins::Bin1d; /// `n`-dimensional bin: `I_1xI_2x..xI_n` where /// `I_k` is a one-dimensional interval (`Bin1d`). /// -/// It is instantiated by specifiying the ordered sequence -/// of its 1-dimensional projections on the axes. +/// It is instantiated by specifying the ordered sequence +/// of its 1-dimensional projections on the coordinate axes. /// /// # Example /// From 185bcf6b1c246a37d2fd2e9ef37f76c677cf9cdb Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 15:36:07 +0100 Subject: [PATCH 34/72] Fixed typo --- src/histogram/bins/n_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 3fb27b97..ae692fd2 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -88,7 +88,7 @@ where } /// `Bins` is a collection of non-overlapping -/// sub-regions (`BinNd`) in a `n`-dimensional space. +/// sub-regions (`BinNd`) in an `n`-dimensional space. #[derive(Clone, Debug)] pub struct BinsNd { bins: Vec>, From 367d14cee046cca79e6e6ac662db88cf084476c3 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 15:40:03 +0100 Subject: [PATCH 35/72] Better formatting for docs --- src/histogram/bins/n_dim.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index ae692fd2..3152435e 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -20,15 +20,15 @@ use histogram::bins::Bin1d; /// use noisy_float::types::n64; /// use ndarray_stats::{BinNd, Bin1d}; /// -/// fn main() { -/// let projections = vec![ -/// Bin1d::RangeInclusive(n64(0.)..=n64(1.)), -/// Bin1d::RangeInclusive(n64(0.)..=n64(1.)), -/// ]; -/// let unit_square = BinNd::new(projections); -/// let point = array![n64(0.5), n64(0.5)]; -/// assert!(unit_square.contains(point)); -/// } +/// # fn main() { +/// let projections = vec![ +/// Bin1d::RangeInclusive(n64(0.)..=n64(1.)), +/// Bin1d::RangeInclusive(n64(0.)..=n64(1.)), +/// ]; +/// let unit_square = BinNd::new(projections); +/// let point = array![n64(0.5), n64(0.5)]; +/// assert!(unit_square.contains(point)); +/// # } /// ``` #[derive(Hash, PartialEq, Eq, Clone, Debug)] pub struct BinNd { From 7f80e8f409bd02171f123aa888ef77449305fd00 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 15:40:19 +0100 Subject: [PATCH 36/72] Better wording --- src/histogram/bins/n_dim.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 3152435e..4ad93f9e 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -51,8 +51,8 @@ impl BinNd where T: fmt::Debug { - /// Creates a new instance of BinNd from a vector - /// of its 1-dimensional projections. + /// Creates a new instance of BinNd from the ordered sequence + /// of its 1-dimensional projections on the coordinate axes. pub fn new(projections: Vec>) -> Self { if projections.is_empty() { panic!( From bd3c2de8ed2eca120128c5601183cca4e149dd6a Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:20:26 +0100 Subject: [PATCH 37/72] Allow point to be any type of iterator as long as it has a length --- src/histogram/bins/n_dim.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 4ad93f9e..8d788cbf 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -27,7 +27,7 @@ use histogram::bins::Bin1d; /// ]; /// let unit_square = BinNd::new(projections); /// let point = array![n64(0.5), n64(0.5)]; -/// assert!(unit_square.contains(point)); +/// assert!(unit_square.contains(point.view())); /// # } /// ``` #[derive(Hash, PartialEq, Eq, Clone, Debug)] @@ -72,15 +72,16 @@ impl BinNd } } -impl BinNd +impl<'a, T: 'a> BinNd where T: PartialOrd { - pub fn contains(&self, point: ArrayBase) -> bool + pub fn contains(&self, point: S) -> bool where - S: Data + S: IntoIterator, + I: Iterator + ExactSizeIterator, { - point.iter(). + point.into_iter(). zip(self.projections.iter()). map(|(element, projection)| projection.contains(element)). fold(true, |acc, v| acc & v) @@ -143,7 +144,7 @@ where S: Data, { for bin in self.bins.iter() { - if bin.contains(point.view()) { + if bin.contains(point.view()){ return Some((*bin).clone()) } } From a4e2cb6fdaa7ccb392ae637d3e887a6260248375 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:23:24 +0100 Subject: [PATCH 38/72] Documented contains. Added a panic case --- src/histogram/bins/n_dim.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 8d788cbf..9572133c 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -76,13 +76,18 @@ impl<'a, T: 'a> BinNd where T: PartialOrd { + /// Return `true` if `point` is in the bin, false otherwise. + /// + /// **Panics** if `point`'s dimensionality + /// (`point.into_iter().len()`) is different from `self.ndim()`. pub fn contains(&self, point: S) -> bool where S: IntoIterator, I: Iterator + ExactSizeIterator, { - point.into_iter(). - zip(self.projections.iter()). + let point_iter = point.into_iter(); + assert_eq!(point_iter.len(), self.ndim()); + point_iter.zip(self.projections.iter()). map(|(element, projection)| projection.contains(element)). fold(true, |acc, v| acc & v) } From d431992dd6b15531b8b6c66c15f3c1b8ea6535a9 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:31:19 +0100 Subject: [PATCH 39/72] Added doc-test to contains for BinNd --- src/histogram/bins/n_dim.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 9572133c..05bc61df 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -80,6 +80,25 @@ where /// /// **Panics** if `point`'s dimensionality /// (`point.into_iter().len()`) is different from `self.ndim()`. + /// + /// # Example + /// + /// ``` + /// extern crate ndarray_stats; + /// extern crate noisy_float; + /// use noisy_float::types::n64; + /// use ndarray_stats::{BinNd, Bin1d}; + /// + /// let projections = vec![ + /// Bin1d::RangeFrom(n64(0.)..), + /// Bin1d::RangeFrom(n64(0.)..), + /// ]; + /// let first_quadrant = BinNd::new(projections); + /// let good_point = vec![n64(1e6), n64(1e8)]; + /// let bad_point = vec![n64(-1.), n64(0.)]; + /// assert!(first_quadrant.contains(&good_point)); + /// assert!(!first_quadrant.contains(&bad_point)); + /// ``` pub fn contains(&self, point: S) -> bool where S: IntoIterator, From e684d9e7a11ef9750cc1074f5d8846bc47eb0d20 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:34:08 +0100 Subject: [PATCH 40/72] Better formatting in docs --- src/histogram/bins/n_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 05bc61df..d8f884d3 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -76,7 +76,7 @@ impl<'a, T: 'a> BinNd where T: PartialOrd { - /// Return `true` if `point` is in the bin, false otherwise. + /// Return `true` if `point` is in the bin, `false` otherwise. /// /// **Panics** if `point`'s dimensionality /// (`point.into_iter().len()`) is different from `self.ndim()`. From 74bda89278a0314674f8527eb2e5c9d41009d114 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:36:08 +0100 Subject: [PATCH 41/72] Fixing wrong doc in ndim for BinsNd --- src/histogram/bins/n_dim.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index d8f884d3..3ee53c1c 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -147,8 +147,6 @@ where impl BinsNd { /// Return `n`, the number of dimensions. - /// - /// **Panics** if `bins` is empty. pub fn ndim(&self) -> usize { self.ndim } From 87cdfc861e5a67dea2e5a9cd14fafd21eb8530b1 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:36:44 +0100 Subject: [PATCH 42/72] Added docstrings to ndim for BinNd --- src/histogram/bins/n_dim.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 3ee53c1c..3d37949e 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -67,6 +67,7 @@ where impl BinNd { + /// Return `n`, the number of dimensions. pub fn ndim(&self) -> usize { self.projections.len() } From 5438acf5a4a959552fdefeb546b0350424c3863f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:38:36 +0100 Subject: [PATCH 43/72] Added correct docs to BinsNd::new --- src/histogram/bins/n_dim.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 3d37949e..bac6da9a 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -125,8 +125,10 @@ impl BinsNd where T: fmt::Debug { - /// Creates a new instance of BinNd from a vector - /// of its 1-dimensional projections. + /// Creates a new instance of `BinsNd` from a vector + /// of `BinNd`. + /// + /// **Panics** if `bins` is empty. pub fn new(bins: Vec>) -> Self { assert!(!bins.is_empty(), "The bins collection cannot be empty!"); // All bins must have the same number of dimensions! From 3ffb62ed213593638e4dd03df770bd7f83d68b70 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:39:53 +0100 Subject: [PATCH 44/72] Added one more panic case to BinsNd::new --- src/histogram/bins/n_dim.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index bac6da9a..9161acb8 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -128,7 +128,8 @@ where /// Creates a new instance of `BinsNd` from a vector /// of `BinNd`. /// - /// **Panics** if `bins` is empty. + /// **Panics** if `bins` is empty or if there are two bins in `bins` + /// with different dimensionality. pub fn new(bins: Vec>) -> Self { assert!(!bins.is_empty(), "The bins collection cannot be empty!"); // All bins must have the same number of dimensions! From c3b3a500978caa3ceb1fa49909ccf3bc3351b222 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:45:55 +0100 Subject: [PATCH 45/72] Formatting --- src/histogram/bins/n_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 9161acb8..c2874bd7 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -51,7 +51,7 @@ impl BinNd where T: fmt::Debug { - /// Creates a new instance of BinNd from the ordered sequence + /// Creates a new instance of `BinNd` from the ordered sequence /// of its 1-dimensional projections on the coordinate axes. pub fn new(projections: Vec>) -> Self { if projections.is_empty() { From 4f5fbb9a359d177f36004f7f8855d012554acd91 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:51:11 +0100 Subject: [PATCH 46/72] Details on overlapping case for BinsNd::find --- src/histogram/bins/n_dim.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index c2874bd7..86e1b18a 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -113,8 +113,11 @@ where } } -/// `Bins` is a collection of non-overlapping -/// sub-regions (`BinNd`) in an `n`-dimensional space. +/// `BinsNd` is a collection of sub-regions (`BinNd`) +/// in an `n`-dimensional space. +/// +/// It is not required (or enforced) that the sub-regions +/// in `self` must be not-overlapping. #[derive(Clone, Debug)] pub struct BinsNd { bins: Vec>, @@ -162,7 +165,10 @@ where { /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin` `B`; - /// - `None`, if `P` does not belong to any `Bin` in `Bins`. + /// - `None`, if `P` does not belong to any `Bin` in `self`. + /// + /// If more than one bin in `self` contains `P`, no assumptions + /// can be made on which bin will be returned by `find`. /// /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. pub fn find(&self, point: ArrayBase) -> Option> From 84c56e85b2b7a23012811954735b2ab925651f5d Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 2 Oct 2018 16:57:25 +0100 Subject: [PATCH 47/72] Improved docs for Bins1d --- src/histogram/bins/one_dim.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 93c3465f..56eed0df 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -82,8 +82,8 @@ where }) } -/// `Bins` is a collection of non-overlapping -/// intervals (`Bin1d`) in a 1-dimensional space. +/// `Bins` is a collection of intervals (`Bin1d`) +/// in a 1-dimensional space. #[derive(Debug, Clone)] pub struct Bins1d { bins: Vec>, @@ -94,8 +94,11 @@ where T: PartialOrd + Clone { /// Given a point `P`, it returns an `Option`: - /// - `Some(B)`, if `P` belongs to the `Bin1d` `B`; - /// - `None`, if `P` does not belong to any `Bin1d` in `Bins1d`. + /// - `Some(B)`, if `P` belongs to the bin `B`; + /// - `None`, if `P` does not belong to any bin in `self`. + /// + /// If more than one bin in `self` contains `P`, no assumptions + /// can be made on which bin will be returned by `find`. pub fn find(&self, point: &T) -> Option> { for bin in self.bins.iter() { From 3e37267ec1cfa89be2289d1b795061055634fcda Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 09:11:04 +0100 Subject: [PATCH 48/72] Too much effort - let's use arrays --- src/histogram/bins/n_dim.rs | 14 ++++++-------- src/histogram/mod.rs | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 86e1b18a..84e429e1 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -100,14 +100,12 @@ where /// assert!(first_quadrant.contains(&good_point)); /// assert!(!first_quadrant.contains(&bad_point)); /// ``` - pub fn contains(&self, point: S) -> bool + pub fn contains(&self, point: ArrayBase) -> bool where - S: IntoIterator, - I: Iterator + ExactSizeIterator, + S: Data, { - let point_iter = point.into_iter(); - assert_eq!(point_iter.len(), self.ndim()); - point_iter.zip(self.projections.iter()). + assert_eq!(point.len(), self.ndim()); + point.iter().zip(self.projections.iter()). map(|(element, projection)| projection.contains(element)). fold(true, |acc, v| acc & v) } @@ -159,7 +157,7 @@ impl BinsNd } } -impl BinsNd +impl<'a, T: 'a> BinsNd where T: PartialOrd + Clone { @@ -173,7 +171,7 @@ where /// **Panics** if `P.ndim()` is different from `Bins.ndim()`. pub fn find(&self, point: ArrayBase) -> Option> where - S: Data, + S: Data, { for bin in self.bins.iter() { if bin.contains(point.view()){ diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index 45f08b8e..5f5b56e6 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -36,7 +36,7 @@ where { let mut histogram = HashMap::new(); for point in self.axis_iter(Axis(0)) { - let bin = bins.find(point); + let bin = bins.find(point.view()); if let Some(b) = bin { histogram.insert(b, 1); }; From 546dea5893f3fd1034e624d6bc47bb1f8d5f8d9f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 09:14:10 +0100 Subject: [PATCH 49/72] Fixed doc --- src/histogram/bins/n_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 84e429e1..2abdcee9 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -80,7 +80,7 @@ where /// Return `true` if `point` is in the bin, `false` otherwise. /// /// **Panics** if `point`'s dimensionality - /// (`point.into_iter().len()`) is different from `self.ndim()`. + /// (`point.len()`) is different from `self.ndim()`. /// /// # Example /// From 8325807474157db20108dd9d96d3793036535470 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 09:16:36 +0100 Subject: [PATCH 50/72] Added error message if it panics --- src/histogram/bins/n_dim.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 2abdcee9..e157b474 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -75,7 +75,7 @@ impl BinNd impl<'a, T: 'a> BinNd where - T: PartialOrd + T: PartialOrd + fmt::Debug, { /// Return `true` if `point` is in the bin, `false` otherwise. /// @@ -104,7 +104,9 @@ where where S: Data, { - assert_eq!(point.len(), self.ndim()); + assert_eq!(point.len(), self.ndim(), + "Dimensionalities do not match. Point {0:?} has {1} dimensions. \ + Bin {2:?} has {3} dimensions", point, point.len(), self, self.ndim()); point.iter().zip(self.projections.iter()). map(|(element, projection)| projection.contains(element)). fold(true, |acc, v| acc & v) @@ -159,7 +161,7 @@ impl BinsNd impl<'a, T: 'a> BinsNd where - T: PartialOrd + Clone + T: PartialOrd + Clone + fmt::Debug, { /// Given a point `P`, it returns an `Option`: /// - `Some(B)`, if `P` belongs to the `Bin` `B`; From d2fa5885232393594cc4e75fe4c5cb4741ad6b7a Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 09:35:45 +0100 Subject: [PATCH 51/72] Adding IDE-related files to .gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 69369904..4135c77e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ /target **/*.rs.bk Cargo.lock + +# IDE and similar +rusty-tags.vi +tags +.vscode/* From ba80459ad125b7b665f11be06532487a7f6c7a5f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 09:58:29 +0100 Subject: [PATCH 52/72] Fixed doc-test, added new test --- src/histogram/bins/n_dim.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index e157b474..6a533d1b 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -53,6 +53,8 @@ where { /// Creates a new instance of `BinNd` from the ordered sequence /// of its 1-dimensional projections on the coordinate axes. + /// + /// **Panics** if `projections` is empty. pub fn new(projections: Vec>) -> Self { if projections.is_empty() { panic!( @@ -85,20 +87,24 @@ where /// # Example /// /// ``` + /// #[macro_use(array)] + /// extern crate ndarray; /// extern crate ndarray_stats; /// extern crate noisy_float; /// use noisy_float::types::n64; /// use ndarray_stats::{BinNd, Bin1d}; /// + /// # fn main() { /// let projections = vec![ /// Bin1d::RangeFrom(n64(0.)..), /// Bin1d::RangeFrom(n64(0.)..), /// ]; /// let first_quadrant = BinNd::new(projections); - /// let good_point = vec![n64(1e6), n64(1e8)]; - /// let bad_point = vec![n64(-1.), n64(0.)]; - /// assert!(first_quadrant.contains(&good_point)); - /// assert!(!first_quadrant.contains(&bad_point)); + /// let good_point = array![n64(1e6), n64(1e8)]; + /// let bad_point = array![n64(-1.), n64(0.)]; + /// assert!(first_quadrant.contains(good_point.view())); + /// assert!(!first_quadrant.contains(bad_point.view())); + /// # } /// ``` pub fn contains(&self, point: ArrayBase) -> bool where @@ -182,4 +188,16 @@ where } None } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn new_w_empty_vec() { + let _: BinNd = BinNd::new(vec![]); + } + } \ No newline at end of file From f799c8be67c6381efc5430152152644469364963 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:03:15 +0100 Subject: [PATCH 53/72] Added new test for BinNd - dimension mismatch in contains --- src/histogram/bins/n_dim.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 6a533d1b..4fd34ece 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -200,4 +200,13 @@ mod tests { let _: BinNd = BinNd::new(vec![]); } + #[test] + #[should_panic] + fn contains_w_dimensions_mismatch() { + let bin2d = BinNd::new( + vec![Bin1d::Range(0..1), Bin1d::Range(2..4)] + ); + let point1d = array![1]; + bin2d.contains(point1d.view()); + } } \ No newline at end of file From 955c04b13f2bff3980b29613d10f63c4e93aba12 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:05:52 +0100 Subject: [PATCH 54/72] Added test for contains w matching dimensions --- src/histogram/bins/n_dim.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 4fd34ece..42a3f5dd 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -209,4 +209,13 @@ mod tests { let point1d = array![1]; bin2d.contains(point1d.view()); } + + #[test] + fn contains_w_matching_dimensions() { + let bin2d = BinNd::new( + vec![Bin1d::Range(0..1), Bin1d::Range(2..4)] + ); + let point2d = array![0, 3]; + bin2d.contains(point2d.view()); + } } \ No newline at end of file From addd56f6533fc122966b16cad145d27fff30755b Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:06:39 +0100 Subject: [PATCH 55/72] Rename test module --- src/histogram/bins/n_dim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 42a3f5dd..4ff4e994 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -191,7 +191,7 @@ where } #[cfg(test)] -mod tests { +mod bin_nd_tests { use super::*; #[test] From ac5520afd1be635d3b9aeeba71f0561a39e0ce51 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:07:37 +0100 Subject: [PATCH 56/72] Added test for BinsNd - empty vec to new --- src/histogram/bins/n_dim.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 4ff4e994..322569aa 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -218,4 +218,14 @@ mod bin_nd_tests { let point2d = array![0, 3]; bin2d.contains(point2d.view()); } +} + +mod bins_nd_tests { + use super::*; + + #[test] + #[should_panic] + fn new_w_empty_vec() { + let _: BinsNd = BinsNd::new(vec![]); + } } \ No newline at end of file From e0a3cab6b213fd89480874594a88824822a898bd Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:25:25 +0100 Subject: [PATCH 57/72] Fixed dim computation in BinsNd::new - added a test for it --- src/histogram/bins/n_dim.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 322569aa..cccda732 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -143,14 +143,13 @@ where assert!(!bins.is_empty(), "The bins collection cannot be empty!"); // All bins must have the same number of dimensions! let ndim = { - let first_bin = bins.index(0); - let ndim = first_bin.ndim(); - &bins.iter().map( - |b| assert_eq!( - b.ndim(), ndim, - "There at least two bins with different \ - number of dimensions: {0} and {1}.", b, first_bin) - ); + let ndim = bins.index(0).ndim(); + let flag = &bins.iter(). + map(|b| b.ndim() == ndim). + fold(true, |acc, new| acc & new); + // It would be better to print the bad bins as well! + assert!(flag, "There at least two bins with different \ + number of dimensions"); ndim }; Self { bins, ndim } @@ -228,4 +227,17 @@ mod bins_nd_tests { fn new_w_empty_vec() { let _: BinsNd = BinsNd::new(vec![]); } + + #[test] + #[should_panic] + fn new_w_bins_of_different_dimensions() { + let bin1d = BinNd::new(vec![Bin1d::Range(0..5)]); + let bin2d = BinNd::new(vec![Bin1d::Range(0..5), + Bin1d::RangeFrom(2..)]); + assert_eq!(bin1d.ndim(), 1); + assert_eq!(bin2d.ndim(), 2); + let _: BinsNd = BinsNd::new( + vec![bin1d, bin2d], + ); + } } \ No newline at end of file From 03d79a13ed489436c05d25f11091f87566132543 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:26:32 +0100 Subject: [PATCH 58/72] Remove fmt::Debug bound on T given that is not used anymore --- src/histogram/bins/n_dim.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index cccda732..f2e068c4 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -131,8 +131,6 @@ pub struct BinsNd { } impl BinsNd -where - T: fmt::Debug { /// Creates a new instance of `BinsNd` from a vector /// of `BinNd`. @@ -154,10 +152,7 @@ where }; Self { bins, ndim } } -} -impl BinsNd -{ /// Return `n`, the number of dimensions. pub fn ndim(&self) -> usize { self.ndim From 85bab2f810a64fc307b2f5996365bf983ab5dd4a Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:32:31 +0100 Subject: [PATCH 59/72] Added new test for find with mismatched dimensions --- src/histogram/bins/n_dim.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index f2e068c4..50eed018 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -235,4 +235,14 @@ mod bins_nd_tests { vec![bin1d, bin2d], ); } + + #[test] + #[should_panic] + fn find_w_mismatched_dimensions() { + let bin2d = BinNd::new(vec![Bin1d::Range(0..5), + Bin1d::RangeFrom(2..)]); + let point3d = array![1, 2, 3]; + let bins = BinsNd::new(vec![bin2d]); + bins.find(point3d); + } } \ No newline at end of file From b61a6aa30a38a53dc54e6b259b29ca9f75526045 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:33:37 +0100 Subject: [PATCH 60/72] Improved test --- src/histogram/bins/n_dim.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 50eed018..942a2278 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -241,7 +241,9 @@ mod bins_nd_tests { fn find_w_mismatched_dimensions() { let bin2d = BinNd::new(vec![Bin1d::Range(0..5), Bin1d::RangeFrom(2..)]); + assert_eq!(bin2d.ndim(), 2); let point3d = array![1, 2, 3]; + assert_eq!(point3d.len(), 3); let bins = BinsNd::new(vec![bin2d]); bins.find(point3d); } From 8306259fcd961e58ce66a038cb46bbd9975e9414 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:41:24 +0100 Subject: [PATCH 61/72] Added new test for BinsNd::find --- src/histogram/bins/n_dim.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 942a2278..2fd64d3c 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -247,4 +247,15 @@ mod bins_nd_tests { let bins = BinsNd::new(vec![bin2d]); bins.find(point3d); } + + #[test] + fn find_w_matching_dimensions() { + let bin = BinNd::new(vec![Bin1d::Range(0..5), + Bin1d::RangeFrom(2..)]); + let bins = BinsNd::new(vec![bin.clone()]); + let p = array![1, 2]; + let q = array![1, 1]; + assert_eq!(bins.find(p), Some(bin)); + assert_eq!(bins.find(q), None); + } } \ No newline at end of file From d597f15379d7040170159bbe6e5cd3178e64e4c8 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 10:48:17 +0100 Subject: [PATCH 62/72] Histogram is now updated correctly --- src/histogram/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index 5f5b56e6..40e7070e 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -38,7 +38,8 @@ where for point in self.axis_iter(Axis(0)) { let bin = bins.find(point.view()); if let Some(b) = bin { - histogram.insert(b, 1); + let counter = histogram.entry(b).or_insert(0); + *counter += 1; }; } histogram @@ -66,7 +67,8 @@ where for point in self.iter() { let bin = bins.find(point); if let Some(b) = bin { - histogram.insert(b, 1); + let counter = histogram.entry(b).or_insert(0); + *counter += 1; }; } histogram From f42aa4806c22d45290d1cdb2655120d4f3554b66 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:07:14 +0100 Subject: [PATCH 63/72] Added a test for histogram --- src/histogram/mod.rs | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index 40e7070e..f8ed8e9a 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -24,7 +24,7 @@ where /// /// For example: a (3, 4) matrix `M` is a collection of 3 points in a /// 4-dimensional space. - fn histogram(&self, bins: BinsNd) -> HistogramNd; + fn histogram(&self, bins: BinsNd) -> HistogramNd; } impl HistogramNdExt for ArrayBase @@ -32,7 +32,7 @@ where S: Data, A: Hash + Eq + fmt::Debug + Clone + PartialOrd, { - fn histogram(&self, bins: BinsNd) -> HistogramNd + fn histogram(&self, bins: BinsNd) -> HistogramNd { let mut histogram = HashMap::new(); for point in self.axis_iter(Axis(0)) { @@ -53,7 +53,7 @@ where S: Data, A: Hash + Eq + fmt::Debug + Clone, { - fn histogram(&self, bins: Bins1d) -> Histogram1d; + fn histogram(&self, bins: Bins1d) -> Histogram1d; } impl Histogram1dExt for ArrayBase @@ -61,7 +61,7 @@ where S: Data, A: Hash + Eq + fmt::Debug + Clone + PartialOrd, { - fn histogram(&self, bins: Bins1d) -> Histogram1d + fn histogram(&self, bins: Bins1d) -> Histogram1d { let mut histogram = HashMap::new(); for point in self.iter() { @@ -73,4 +73,40 @@ where } histogram } +} + +#[cfg(test)] +mod histogram_nd_tests { + use super::*; + + #[test] + fn histogram() { + let first_quadrant = BinNd::new( + vec![Bin1d::RangeFrom(0..), + Bin1d::RangeFrom(0..) + ] + ); + let second_quadrant = BinNd::new( + vec![Bin1d::RangeTo(..0), + Bin1d::RangeFrom(0..) + ] + ); + let bins = BinsNd::new(vec![first_quadrant.clone(), + second_quadrant.clone()]); + let points = array![ + [1, 1], + [1, 2], + [0, 1], + [-1, 2], + [-1, -1], // a point that doesn't belong to any bin in bins + ]; + assert_eq!(points.shape(), &[5, 2]); + let histogram = points.histogram(bins); + + let mut expected = HashMap::new(); + expected.insert(first_quadrant, 3); + expected.insert(second_quadrant, 1); + + assert_eq!(expected, histogram); + } } \ No newline at end of file From 2ac73575d5eaec0bd01da72385b035ae1a232a84 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:26:12 +0100 Subject: [PATCH 64/72] Fixed doc for HistogramNdExt and added a test for the panic case --- src/histogram/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index f8ed8e9a..fc6fcc13 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -24,6 +24,8 @@ where /// /// For example: a (3, 4) matrix `M` is a collection of 3 points in a /// 4-dimensional space. + /// + /// **Panics** if `d` is different from `bins.ndim()`. fn histogram(&self, bins: BinsNd) -> HistogramNd; } @@ -109,4 +111,17 @@ mod histogram_nd_tests { assert_eq!(expected, histogram); } + + #[test] + #[should_panic] + fn histogram_w_mismatched_dimensions() { + let bin = BinNd::new(vec![Bin1d::RangeFrom(0..)]); + let bins = BinsNd::new(vec![bin.clone()]); + let points = array![ + [1, 1], + [1, 2], + ]; + assert_eq!(points.shape(), &[2, 2]); + points.histogram(bins); + } } \ No newline at end of file From 2758e016782dbe94d899b53bb931898c15f77b56 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:30:45 +0100 Subject: [PATCH 65/72] Added docstring to Histogram1dExt::histogram --- src/histogram/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index fc6fcc13..46209280 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -55,6 +55,8 @@ where S: Data, A: Hash + Eq + fmt::Debug + Clone, { + /// Return the [histogram](https://en.wikipedia.org/wiki/Histogram) + /// for a 1-dimensional array of points `M`. fn histogram(&self, bins: Bins1d) -> Histogram1d; } From 77130896e5619e255881c5de699ff0eb894b7f54 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:44:32 +0100 Subject: [PATCH 66/72] Hyperlinks everywhere --- src/histogram/bins/n_dim.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index 2fd64d3c..b3da6d05 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -5,7 +5,7 @@ use std::fmt; use histogram::bins::Bin1d; /// `n`-dimensional bin: `I_1xI_2x..xI_n` where -/// `I_k` is a one-dimensional interval (`Bin1d`). +/// `I_k` is a one-dimensional interval ([`Bin1d`]). /// /// It is instantiated by specifying the ordered sequence /// of its 1-dimensional projections on the coordinate axes. @@ -30,6 +30,8 @@ use histogram::bins::Bin1d; /// assert!(unit_square.contains(point.view())); /// # } /// ``` +/// +/// [`Bin1d`]: enum.Bin1d.html #[derive(Hash, PartialEq, Eq, Clone, Debug)] pub struct BinNd { projections: Vec>, @@ -119,11 +121,13 @@ where } } -/// `BinsNd` is a collection of sub-regions (`BinNd`) +/// `BinsNd` is a collection of sub-regions ([`BinNd`]) /// in an `n`-dimensional space. /// /// It is not required (or enforced) that the sub-regions /// in `self` must be not-overlapping. +/// +/// [`BinNd`]: struct.BinNd.html #[derive(Clone, Debug)] pub struct BinsNd { bins: Vec>, From 018840ebc89cbd4b2ea40f3668330278ff255a97 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:44:45 +0100 Subject: [PATCH 67/72] Hyperlinks everywhere --- src/histogram/bins/one_dim.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 56eed0df..00b97200 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -82,8 +82,10 @@ where }) } -/// `Bins` is a collection of intervals (`Bin1d`) +/// `Bins1d` is a collection of intervals ([`Bin1d`]) /// in a 1-dimensional space. +/// +/// [`Bin1d`]: enum.Bin1d.html #[derive(Debug, Clone)] pub struct Bins1d { bins: Vec>, From 07803b81e92e8e66c5e88e3db077cf99ddb18fce Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:46:45 +0100 Subject: [PATCH 68/72] Docstring for traits in histogram.mod --- src/histogram/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index 46209280..591772f0 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -9,6 +9,7 @@ use ndarray::Data; type HistogramNd = HashMap, usize>; +// Extension trait for ArrayBase providing methods to compute n-dimensional histograms. pub trait HistogramNdExt where S: Data, @@ -50,6 +51,7 @@ where type Histogram1d = HashMap, usize>; +// Extension trait for one-dimensional ArrayBase providing methods to compute histograms. pub trait Histogram1dExt where S: Data, From 3616a97e28532f847921a98f6b012b93a480ae7a Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:47:21 +0100 Subject: [PATCH 69/72] Missing one / to show up in docs --- src/histogram/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index 591772f0..ba5e9f4d 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -9,7 +9,7 @@ use ndarray::Data; type HistogramNd = HashMap, usize>; -// Extension trait for ArrayBase providing methods to compute n-dimensional histograms. +/// Extension trait for ArrayBase providing methods to compute n-dimensional histograms. pub trait HistogramNdExt where S: Data, @@ -51,7 +51,7 @@ where type Histogram1d = HashMap, usize>; -// Extension trait for one-dimensional ArrayBase providing methods to compute histograms. +/// Extension trait for one-dimensional ArrayBase providing methods to compute histograms. pub trait Histogram1dExt where S: Data, From aa46698b2717f9f6d1aaa5c5547e9b210e50cd1c Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:53:04 +0100 Subject: [PATCH 70/72] Encapsulated bins in bins module --- src/histogram/mod.rs | 4 ++-- src/lib.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index ba5e9f4d..2ebee167 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -1,5 +1,5 @@ -mod bins; -pub use self::bins::{Bin1d, BinNd, BinsNd, Bins1d}; +pub mod bins; +use self::bins::{BinNd, BinsNd, Bin1d, Bins1d}; use std::collections::HashMap; use std::hash::Hash; diff --git a/src/lib.rs b/src/lib.rs index e32e9944..3d673c0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,7 @@ pub use maybe_nan::{MaybeNan, MaybeNanExt}; pub use quantile::{interpolate, QuantileExt}; pub use sort::Sort1dExt; pub use correlation::CorrelationExt; -pub use histogram::{Histogram1dExt, HistogramNdExt, - Bin1d, Bins1d, BinNd, BinsNd}; +pub use histogram::{Histogram1dExt, HistogramNdExt, bins}; mod maybe_nan; mod quantile; From 2ec7af4cf2ddcf2e6f6af9802d12b099dec0816f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:54:16 +0100 Subject: [PATCH 71/72] Fixed tests --- src/histogram/bins/n_dim.rs | 4 ++-- src/histogram/bins/one_dim.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/histogram/bins/n_dim.rs b/src/histogram/bins/n_dim.rs index b3da6d05..d9d0d22b 100644 --- a/src/histogram/bins/n_dim.rs +++ b/src/histogram/bins/n_dim.rs @@ -18,7 +18,7 @@ use histogram::bins::Bin1d; /// extern crate ndarray_stats; /// extern crate noisy_float; /// use noisy_float::types::n64; -/// use ndarray_stats::{BinNd, Bin1d}; +/// use ndarray_stats::bins::{BinNd, Bin1d}; /// /// # fn main() { /// let projections = vec![ @@ -94,7 +94,7 @@ where /// extern crate ndarray_stats; /// extern crate noisy_float; /// use noisy_float::types::n64; - /// use ndarray_stats::{BinNd, Bin1d}; + /// use ndarray_stats::bins::{BinNd, Bin1d}; /// /// # fn main() { /// let projections = vec![ diff --git a/src/histogram/bins/one_dim.rs b/src/histogram/bins/one_dim.rs index 00b97200..097f91fc 100644 --- a/src/histogram/bins/one_dim.rs +++ b/src/histogram/bins/one_dim.rs @@ -9,7 +9,7 @@ use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, /// ``` /// extern crate ndarray_stats; /// extern crate noisy_float; -/// use ndarray_stats::Bin1d; +/// use ndarray_stats::bins::Bin1d; /// use noisy_float::types::n64; /// /// let unit_interval = Bin1d::RangeInclusive(n64(0.)..=n64(1.)); From d2f4bebdbf363bf109e12fbdff4b9294068e4d55 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 3 Oct 2018 11:56:20 +0100 Subject: [PATCH 72/72] Added module docs --- src/histogram/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/histogram/mod.rs b/src/histogram/mod.rs index 2ebee167..6a5b3dc7 100644 --- a/src/histogram/mod.rs +++ b/src/histogram/mod.rs @@ -1,3 +1,4 @@ +/// Bins for histogram computation. pub mod bins; use self::bins::{BinNd, BinsNd, Bin1d, Bins1d};