@@ -5,37 +5,61 @@ use itertools::izip;
55use ndarray:: { ArrayBase , Axis , Data , Ix1 , Ix2 } ;
66use std:: ops:: Range ;
77
8- /// A `Grid` is a partition of a rectangular region of an *n*-dimensional
9- /// space—e.g. [*a*<sub>0</sub>, *b*<sub>0</sub>) × ⋯ × [*a*<sub>*n*−1</sub>,
10- /// *b*<sub>*n*−1</sub>)—into a collection of rectangular *n*-dimensional bins.
8+ /// An orthogonal partition of a rectangular region in an *n*-dimensional space, e.g.
9+ /// [*a*<sub>0</sub>, *b*<sub>0</sub>) × ⋯ × [*a*<sub>*n*−1</sub>, *b*<sub>*n*−1</sub>),
10+ /// represented as a collection of rectangular *n*-dimensional bins.
11+ ///
12+ /// The grid is **solely determined by the Cartesian product of its projections** on each coordinate
13+ /// axis. Therefore, each element in the product set should correspond to a sub-region in the grid.
14+ ///
15+ /// For example, this partition can be represented as a `Grid` struct:
1116///
12- /// The grid is **fully determined by its 1-dimensional projections** on the
13- /// coordinate axes. For example, this is a partition that can be represented
14- /// as a `Grid` struct:
1517/// ```text
16- /// +---+-------+-+
17- /// | | | |
18- /// +---+-------+-+
19- /// | | | |
20- /// | | | |
21- /// | | | |
22- /// | | | |
23- /// +---+-------+-+
18+ ///
19+ /// g +---+-------+---+
20+ /// | 3 | 4 | 5 |
21+ /// f +---+-------+---+
22+ /// | | | |
23+ /// | 0 | 1 | 2 |
24+ /// | | | |
25+ /// e +---+-------+---+
26+ /// a b c d
27+ ///
28+ /// R0: [a, b) × [e, f)
29+ /// R1: [b, c) × [e, f)
30+ /// R2: [c, d) × [e, f)
31+ /// R3: [a, b) × [f, g)
32+ /// R4: [b, d) × [f, g)
33+ /// R5: [c, d) × [f, g)
34+ /// Grid: { [a, b), [b, c), [c, d) } × { [e, f), [f, g) } == { R0, R1, R2, R3, R4, R5 }
2435/// ```
36+ ///
2537/// while the next one can't:
38+ ///
2639/// ```text
27- /// +---+-------+-+
28- /// | | | |
29- /// | +-------+-+
30- /// | | |
31- /// | | |
32- /// | | |
33- /// | | |
34- /// +---+-------+-+
40+ /// g +---+-----+---+
41+ /// | | 2 | 3 |
42+ /// (f) | +-----+---+
43+ /// | 0 | |
44+ /// | | 1 |
45+ /// | | |
46+ /// e +---+-----+---+
47+ /// a b c d
48+ ///
49+ /// R0: [a, b) × [e, g)
50+ /// R1: [b, d) × [e, f)
51+ /// R2: [b, c) × [f, g)
52+ /// R3: [c, d) × [f, g)
53+ /// // 'f', as long as 'R1', 'R2', or 'R3', doesn't appear on LHS
54+ /// // [b, c) × [e, g), [c, d) × [e, g) doesn't appear on RHS
55+ /// Grid: { [a, b), [b, c), [c, d) } × { [e, g) } != { R0, R1, R2, R3 }
3556/// ```
3657///
3758/// # Examples
3859///
60+ /// Basic usage, building a `Grid` via [`GridBuilder`], with optimal grid layout determined by
61+ /// a given [`strategy`], and genrating a [`histogram`]:
62+ ///
3963/// ```
4064/// use ndarray::{Array, array};
4165/// use ndarray_stats::{
@@ -44,17 +68,14 @@ use std::ops::Range;
4468/// };
4569/// use noisy_float::types::{N64, n64};
4670///
47- /// // 1-dimensional observations, as a (n_observations, 1 ) 2-d matrix
71+ /// // 1-dimensional observations, as a (n_observations, n_dimension ) 2-d matrix
4872/// let observations = Array::from_shape_vec(
4973/// (12, 1),
5074/// vec![1, 4, 5, 2, 100, 20, 50, 65, 27, 40, 45, 23],
5175/// ).unwrap();
5276///
53- /// // The optimal grid layout is inferred from the data,
54- /// // specifying a strategy (Auto in this case)
77+ /// // The optimal grid layout is inferred from the data, given a chosen strategy, Auto in this case
5578/// let grid = GridBuilder::<Auto<usize>>::from_array(&observations).unwrap().build();
56- /// let expected_grid = Grid::from(vec![Bins::new(Edges::from(vec![1, 20, 39, 58, 77, 96, 115]))]);
57- /// assert_eq!(grid, expected_grid);
5879///
5980/// let histogram = observations.histogram(grid);
6081///
@@ -63,19 +84,22 @@ use std::ops::Range;
6384/// let expected = array![4, 3, 3, 1, 0, 1];
6485/// assert_eq!(histogram_matrix, expected.into_dyn());
6586/// ```
87+ ///
88+ /// [`histogram`]: trait.HistogramExt.html
89+ /// [`GridBuilder`]: struct.GridBuilder.html
90+ /// [`strategy`]: strategies/index.html
6691#[ derive( Clone , Debug , Eq , PartialEq ) ]
6792pub struct Grid < A : Ord > {
6893 projections : Vec < Bins < A > > ,
6994}
7095
7196impl < A : Ord > From < Vec < Bins < A > > > for Grid < A > {
72- /// Get a `Grid` instance from a `Vec<Bins<A>>` .
97+ /// Converts a `Vec<Bins<A>>` into a `Grid<A>`, consuming the vector of bins .
7398 ///
74- /// The `i`-th element in `Vec<Bins<A>>` represents the 1-dimensional
75- /// projection of the bin grid on the `i`-th axis.
99+ /// The `i`-th element in `Vec<Bins<A>>` represents the projection of the bin grid onto the
100+ /// `i`-th axis.
76101 ///
77- /// Alternatively, a `Grid` can be built directly from data using a
78- /// [`GridBuilder`].
102+ /// Alternatively, a `Grid` can be built directly from data using a [`GridBuilder`].
79103 ///
80104 /// [`GridBuilder`]: struct.GridBuilder.html
81105 fn from ( projections : Vec < Bins < A > > ) -> Self {
@@ -84,7 +108,7 @@ impl<A: Ord> From<Vec<Bins<A>>> for Grid<A> {
84108}
85109
86110impl < A : Ord > Grid < A > {
87- /// Returns `n`, the number of dimensions of the region partitioned by the grid.
111+ /// Returns the number of dimensions of the region partitioned by the grid.
88112 ///
89113 /// # Examples
90114 ///
@@ -101,7 +125,7 @@ impl<A: Ord> Grid<A> {
101125 self . projections . len ( )
102126 }
103127
104- /// Returns the number of bins along each coordinate axis.
128+ /// Returns the numbers of bins along each coordinate axis.
105129 ///
106130 /// # Examples
107131 ///
@@ -120,19 +144,19 @@ impl<A: Ord> Grid<A> {
120144 self . projections . iter ( ) . map ( |e| e. len ( ) ) . collect ( )
121145 }
122146
123- /// Returns the grid projections on the coordinate axes as a slice of immutable references.
147+ /// Returns the grid projections on each coordinate axis as a slice of immutable references.
124148 pub fn projections ( & self ) -> & [ Bins < A > ] {
125149 & self . projections
126150 }
127151
128- /// Returns the index of the *n*-dimensional bin containing the point, if
129- /// one exists.
152+ /// Returns an `n-dimensional` index, of bins along each axis that contains the point, if one
153+ /// exists.
130154 ///
131155 /// Returns `None` if the point is outside the grid.
132156 ///
133157 /// # Panics
134158 ///
135- /// Panics if `point.len()` does not equal `self.ndim()` .
159+ /// Panics if dimensionality of the point doesn't equal the grid's .
136160 ///
137161 /// # Examples
138162 ///
@@ -147,18 +171,19 @@ impl<A: Ord> Grid<A> {
147171 /// let bins = Bins::new(edges);
148172 /// let square_grid = Grid::from(vec![bins.clone(), bins.clone()]);
149173 ///
150- /// // `0.` and ` -0.7` falls in 1-st and 0-th bin respectively
174+ /// // (0., -0.7) falls in 1st and 0th bin respectively
151175 /// assert_eq!(
152176 /// square_grid.index_of(&array![n64(0.), n64(-0.7)]),
153177 /// Some(vec![1, 0]),
154178 /// );
155- /// // ` 1.` is outside of the grid, return `None`
179+ /// // Returns `None`, as ` 1.` is outside the grid since bins are right exclusive
156180 /// assert_eq!(
157181 /// square_grid.index_of(&array![n64(0.), n64(1.)]),
158182 /// None,
159183 /// );
160184 /// ```
161- /// A panic upon incompatible `point` length:
185+ ///
186+ /// A panic upon dimensionality mismatch:
162187 ///
163188 /// ```should_panic
164189 /// # use ndarray::array;
@@ -167,8 +192,8 @@ impl<A: Ord> Grid<A> {
167192 /// # let edges = Edges::from(vec![n64(-1.), n64(0.), n64(1.)]);
168193 /// # let bins = Bins::new(edges);
169194 /// # let square_grid = Grid::from(vec![bins.clone(), bins.clone()]);
195+ /// // the point has 3 dimensions, the grid expected 2 dimensions
170196 /// assert_eq!(
171- /// // the point has 3 dimensions, the grid expected 2 dimensions
172197 /// square_grid.index_of(&array![n64(0.), n64(-0.7), n64(0.5)]),
173198 /// Some(vec![1, 0, 1]),
174199 /// );
@@ -194,14 +219,15 @@ impl<A: Ord> Grid<A> {
194219}
195220
196221impl < A : Ord + Clone > Grid < A > {
197- /// Given `i= (i_0, ..., i_{n-1})`, an `n`-dimensional index, it returns
198- /// `I_{i_0}x ...xI_ {i_{n-1}}`, an `n`-dimensional bin, where `I_{i_j}` is
199- /// the `i_j`-th interval on the `j`-th projection of the grid on the coordinate axes.
222+ /// Given an `n`-dimensional index, `i = (i_0, ..., i_{n-1})`, returns an `n`-dimensional bin,
223+ /// `I_{i_0} x ... x I_ {i_{n-1}}`, where `I_{i_j}` is the `i_j`-th interval on the `j`-th
224+ /// projection of the grid on the coordinate axes.
200225 ///
201226 /// # Panics
202227 ///
203- /// Panics if at least one among `(i_0, ..., i_{n-1})` is out of bounds on the respective
204- /// coordinate axis - i.e. if there exists `j` such that `i_j >= self.projections[j].len()`.
228+ /// Panics if at least one in the index, `(i_0, ..., i_{n-1})`, is out of bound on the
229+ /// corresponding coordinate axis, i.e. if there exists `j` s.t.
230+ /// `i_j >= self.projections[j].len()`.
205231 ///
206232 /// # Examples
207233 ///
@@ -211,15 +237,16 @@ impl<A: Ord + Clone> Grid<A> {
211237 /// use ndarray::array;
212238 /// use ndarray_stats::histogram::{Edges, Bins, Grid};
213239 ///
214- /// let edges_x = Edges::from(vec![0, 1, 2 ]);
215- /// let edges_y = Edges::from(vec![3, 4, 5 ]);
240+ /// let edges_x = Edges::from(vec![0, 1]);
241+ /// let edges_y = Edges::from(vec![2, 3, 4 ]);
216242 /// let bins_x = Bins::new(edges_x);
217243 /// let bins_y = Bins::new(edges_y);
218244 /// let square_grid = Grid::from(vec![bins_x, bins_y]);
219245 ///
246+ /// // Query the 0-th bin on x-axis, and 1-st bin on y-axis
220247 /// assert_eq!(
221248 /// square_grid.index(&[0, 1]),
222- /// vec![0..1, 4..5 ],
249+ /// vec![0..1, 3..4 ],
223250 /// );
224251 /// ```
225252 ///
@@ -228,15 +255,15 @@ impl<A: Ord + Clone> Grid<A> {
228255 /// ```should_panic
229256 /// # use ndarray::array;
230257 /// # use ndarray_stats::histogram::{Edges, Bins, Grid};
231- /// # let edges_x = Edges::from(vec![0, 1, 2 ]);
232- /// # let edges_y = Edges::from(vec![3, 4, 5 ]);
258+ /// # let edges_x = Edges::from(vec![0, 1]);
259+ /// # let edges_y = Edges::from(vec![2, 3, 4 ]);
233260 /// # let bins_x = Bins::new(edges_x);
234261 /// # let bins_y = Bins::new(edges_y);
235262 /// # let square_grid = Grid::from(vec![bins_x, bins_y]);
263+ /// // out-of-bound on y-axis
236264 /// assert_eq!(
237- /// // out-of-bound on `edges_y`
238265 /// square_grid.index(&[0, 2]),
239- /// vec![0..1, 1..2 ],
266+ /// vec![0..1, 3..4 ],
240267 /// );
241268 /// ```
242269 pub fn index ( & self , index : & [ usize ] ) -> Vec < Range < A > > {
@@ -254,8 +281,32 @@ impl<A: Ord + Clone> Grid<A> {
254281 }
255282}
256283
257- /// Given a [`strategy`] and some observations, returns a [`Grid`] instance for [`histogram`]
258- /// computation.
284+ /// A builder used to create [`Grid`] instances for [`histogram`] computations.
285+ ///
286+ /// # Examples
287+ ///
288+ /// Basic usage, creating a `Grid` with some observations and a given [`strategy`]:
289+ ///
290+ /// ```
291+ /// use ndarray::{Array, array};
292+ /// use noisy_float::types::{N64, n64};
293+ /// use ndarray_stats::histogram::{
294+ /// strategies::Auto, Bins, Edges, Grid, GridBuilder, Histogram,
295+ /// };
296+ ///
297+ /// // 1-dimensional observations, as a (n_observations, n_dimension) 2-d matrix
298+ /// let observations = Array::from_shape_vec(
299+ /// (12, 1),
300+ /// vec![1, 4, 5, 2, 100, 20, 50, 65, 27, 40, 45, 23],
301+ /// ).unwrap();
302+ ///
303+ /// // The optimal grid layout is inferred from the data, given a chosen strategy, Auto in this case
304+ /// let grid = GridBuilder::<Auto<usize>>::from_array(&observations).unwrap().build();
305+ /// // Equivalently, build a Grid directly
306+ /// let expected_grid = Grid::from(vec![Bins::new(Edges::from(vec![1, 20, 39, 58, 77, 96, 115]))]);
307+ ///
308+ /// assert_eq!(grid, expected_grid);
309+ /// ```
259310///
260311/// [`Grid`]: struct.Grid.html
261312/// [`histogram`]: trait.HistogramExt.html
@@ -269,18 +320,22 @@ where
269320 A : Ord ,
270321 B : BinsBuildingStrategy < Elem = A > ,
271322{
272- /// Given some observations in a 2-dimensional array with shape `(n_observations, n_dimension)`
273- /// it returns a `GridBuilder` instance that has learned the required parameter
274- /// to build a [`Grid`] according to the specified [`strategy`].
323+ /// Returns a `GridBuilder` for building a [`Grid`] with a given [`strategy`] and some
324+ /// observations in a 2-dimensionalarray with shape `(n_observations, n_dimension)`.
275325 ///
276326 /// # Errors
277327 ///
278328 /// It returns [`BinsBuildError`] if it is not possible to build a [`Grid`] given
279329 /// the observed data according to the chosen [`strategy`].
280330 ///
331+ /// # Examples
332+ ///
333+ /// See [Trait-level examples] for basic usage.
334+ ///
281335 /// [`Grid`]: struct.Grid.html
282336 /// [`strategy`]: strategies/index.html
283337 /// [`BinsBuildError`]: errors/enum.BinsBuildError.html
338+ /// [Trait-level examples]: struct.GridBuilder.html#examples
284339 pub fn from_array < S > ( array : & ArrayBase < S , Ix2 > ) -> Result < Self , BinsBuildError >
285340 where
286341 S : Data < Elem = A > ,
@@ -292,8 +347,12 @@ where
292347 Ok ( Self { bin_builders } )
293348 }
294349
295- /// Returns a [`Grid`] instance, built accordingly to the specified [`strategy`]
296- /// using the parameters inferred from observations in [`from_array`].
350+ /// Returns a [`Grid`] instance, with building parameters infered in [`from_array`], according
351+ /// to the specified [`strategy`] and observations provided.
352+ ///
353+ /// # Examples
354+ ///
355+ /// See [Trait-level examples] for basic usage.
297356 ///
298357 /// [`Grid`]: struct.Grid.html
299358 /// [`strategy`]: strategies/index.html
0 commit comments