Skip to content

Commit b911705

Browse files
authored
Merge branch 'master' into mean
2 parents afd13bd + c569f75 commit b911705

File tree

3 files changed

+170
-17
lines changed

3 files changed

+170
-17
lines changed

src/impl_methods.rs

+39-3
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,53 @@ where
8383
}
8484

8585
/// Return the shape of the array as it stored in the array.
86+
///
87+
/// This is primarily useful for passing to other `ArrayBase`
88+
/// functions, such as when creating another array of the same
89+
/// shape and dimensionality.
90+
///
91+
/// ```
92+
/// use ndarray::Array;
93+
///
94+
/// let a = Array::from_elem((2, 3), 5.);
95+
///
96+
/// // Create an array of zeros that's the same shape and dimensionality as `a`.
97+
/// let b = Array::<f64, _>::zeros(a.raw_dim());
98+
/// ```
8699
pub fn raw_dim(&self) -> D {
87100
self.dim.clone()
88101
}
89102

90103
/// Return the shape of the array as a slice.
91-
pub fn shape(&self) -> &[Ix] {
104+
///
105+
/// Note that you probably don't want to use this to create an array of the
106+
/// same shape as another array because creating an array with e.g.
107+
/// [`Array::zeros()`](ArrayBase::zeros) using a shape of type `&[usize]`
108+
/// results in a dynamic-dimensional array. If you want to create an array
109+
/// that has the same shape and dimensionality as another array, use
110+
/// [`.raw_dim()`](ArrayBase::raw_dim) instead:
111+
///
112+
/// ```rust
113+
/// use ndarray::{Array, Array2};
114+
///
115+
/// let a = Array2::<i32>::zeros((3, 4));
116+
/// let shape = a.shape();
117+
/// assert_eq!(shape, &[3, 4]);
118+
///
119+
/// // Since `a.shape()` returned `&[usize]`, we get an `ArrayD` instance:
120+
/// let b = Array::zeros(shape);
121+
/// assert_eq!(a.clone().into_dyn(), b);
122+
///
123+
/// // To get the same dimension type, use `.raw_dim()` instead:
124+
/// let c = Array::zeros(a.raw_dim());
125+
/// assert_eq!(a, c);
126+
/// ```
127+
pub fn shape(&self) -> &[usize] {
92128
self.dim.slice()
93129
}
94130

95-
/// Return the strides of the array as a slice
96-
pub fn strides(&self) -> &[Ixs] {
131+
/// Return the strides of the array as a slice.
132+
pub fn strides(&self) -> &[isize] {
97133
let s = self.strides.slice();
98134
// reinterpret unsigned integer as signed
99135
unsafe {

src/lib.rs

+116-1
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,25 @@ pub type Ixs = isize;
638638
/// - `B @ &A` which consumes `B`, updates it with the result, and returns it
639639
/// - `C @= &A` which performs an arithmetic operation in place
640640
///
641+
/// Note that the element type needs to implement the operator trait and the
642+
/// `Clone` trait.
643+
///
644+
/// ```
645+
/// use ndarray::{array, ArrayView1};
646+
///
647+
/// let owned1 = array![1, 2];
648+
/// let owned2 = array![3, 4];
649+
/// let view1 = ArrayView1::from(&[5, 6]);
650+
/// let view2 = ArrayView1::from(&[7, 8]);
651+
/// let mut mutable = array![9, 10];
652+
///
653+
/// let sum1 = &view1 + &view2; // Allocates a new array. Note the explicit `&`.
654+
/// // let sum2 = view1 + &view2; // This doesn't work because `view1` is not an owned array.
655+
/// let sum3 = owned1 + view1; // Consumes `owned1`, updates it, and returns it.
656+
/// let sum4 = owned2 + &view2; // Consumes `owned2`, updates it, and returns it.
657+
/// mutable += &view2; // Updates `mutable` in-place.
658+
/// ```
659+
///
641660
/// ### Binary Operators with Array and Scalar
642661
///
643662
/// The trait [`ScalarOperand`](trait.ScalarOperand.html) marks types that can be used in arithmetic
@@ -920,7 +939,8 @@ pub type Ixs = isize;
920939
/// <sup><a name="req_contig">3</a></sup>Works only if the array is contiguous.
921940
///
922941
/// The table above does not include all the constructors; it only shows
923-
/// conversions to/from `Vec`s/slices. See below for more constructors.
942+
/// conversions to/from `Vec`s/slices. See
943+
/// [below](#constructor-methods-for-owned-arrays) for more constructors.
924944
///
925945
/// [ArrayView::reborrow()]: type.ArrayView.html#method.reborrow
926946
/// [ArrayViewMut::reborrow()]: type.ArrayViewMut.html#method.reborrow
@@ -933,6 +953,101 @@ pub type Ixs = isize;
933953
/// [.view()]: #method.view
934954
/// [.view_mut()]: #method.view_mut
935955
///
956+
/// ### Conversions from Nested `Vec`s/`Array`s
957+
///
958+
/// It's generally a good idea to avoid nested `Vec`/`Array` types, such as
959+
/// `Vec<Vec<A>>` or `Vec<Array2<A>>` because:
960+
///
961+
/// * they require extra heap allocations compared to a single `Array`,
962+
///
963+
/// * they can scatter data all over memory (because of multiple allocations),
964+
///
965+
/// * they cause unnecessary indirection (traversing multiple pointers to reach
966+
/// the data),
967+
///
968+
/// * they don't enforce consistent shape within the nested
969+
/// `Vec`s/`ArrayBase`s, and
970+
///
971+
/// * they are generally more difficult to work with.
972+
///
973+
/// The most common case where users might consider using nested
974+
/// `Vec`s/`Array`s is when creating an array by appending rows/subviews in a
975+
/// loop, where the rows/subviews are computed within the loop. However, there
976+
/// are better ways than using nested `Vec`s/`Array`s.
977+
///
978+
/// If you know ahead-of-time the shape of the final array, the cleanest
979+
/// solution is to allocate the final array before the loop, and then assign
980+
/// the data to it within the loop, like this:
981+
///
982+
/// ```rust
983+
/// use ndarray::{array, Array2, Axis};
984+
///
985+
/// let mut arr = Array2::zeros((2, 3));
986+
/// for (i, mut row) in arr.axis_iter_mut(Axis(0)).enumerate() {
987+
/// // Perform calculations and assign to `row`; this is a trivial example:
988+
/// row.fill(i);
989+
/// }
990+
/// assert_eq!(arr, array![[0, 0, 0], [1, 1, 1]]);
991+
/// ```
992+
///
993+
/// If you don't know ahead-of-time the shape of the final array, then the
994+
/// cleanest solution is generally to append the data to a flat `Vec`, and then
995+
/// convert it to an `Array` at the end with
996+
/// [`::from_shape_vec()`](#method.from_shape_vec). You just have to be careful
997+
/// that the layout of the data (the order of the elements in the flat `Vec`)
998+
/// is correct.
999+
///
1000+
/// ```rust
1001+
/// use ndarray::{array, Array2};
1002+
///
1003+
/// # fn main() -> Result<(), Box<std::error::Error>> {
1004+
/// let ncols = 3;
1005+
/// let mut data = Vec::new();
1006+
/// let mut nrows = 0;
1007+
/// for i in 0..2 {
1008+
/// // Compute `row` and append it to `data`; this is a trivial example:
1009+
/// let row = vec![i; ncols];
1010+
/// data.extend_from_slice(&row);
1011+
/// nrows += 1;
1012+
/// }
1013+
/// let arr = Array2::from_shape_vec((nrows, ncols), data)?;
1014+
/// assert_eq!(arr, array![[0, 0, 0], [1, 1, 1]]);
1015+
/// # Ok(())
1016+
/// # }
1017+
/// ```
1018+
///
1019+
/// If neither of these options works for you, and you really need to convert
1020+
/// nested `Vec`/`Array` instances to an `Array`, the cleanest solution is
1021+
/// generally to use
1022+
/// [`Iterator::flatten()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flatten)
1023+
/// to get a flat `Vec`, and then convert the `Vec` to an `Array` with
1024+
/// [`::from_shape_vec()`](#method.from_shape_vec), like this:
1025+
///
1026+
/// ```rust
1027+
/// use ndarray::{array, Array2, Array3};
1028+
///
1029+
/// # fn main() -> Result<(), Box<std::error::Error>> {
1030+
/// let nested: Vec<Array2<i32>> = vec![
1031+
/// array![[1, 2, 3], [4, 5, 6]],
1032+
/// array![[7, 8, 9], [10, 11, 12]],
1033+
/// ];
1034+
/// let inner_shape = nested[0].dim();
1035+
/// let shape = (nested.len(), inner_shape.0, inner_shape.1);
1036+
/// let flat: Vec<i32> = nested.iter().flatten().cloned().collect();
1037+
/// let arr = Array3::from_shape_vec(shape, flat)?;
1038+
/// assert_eq!(arr, array![
1039+
/// [[1, 2, 3], [4, 5, 6]],
1040+
/// [[7, 8, 9], [10, 11, 12]],
1041+
/// ]);
1042+
/// # Ok(())
1043+
/// # }
1044+
/// ```
1045+
///
1046+
/// Note that this implementation assumes that the nested `Vec`s are all the
1047+
/// same shape and that the `Vec` is non-empty. Depending on your application,
1048+
/// it may be a good idea to add checks for these assumptions and possibly
1049+
/// choose a different way to handle the empty case.
1050+
///
9361051
// # For implementors
9371052
//
9381053
// All methods must uphold the following constraints:

src/numeric/impl_numeric.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,13 @@ impl<A, S, D> ArrayBase<S, D>
115115
/// ```
116116
/// use ndarray::{aview0, aview1, arr2, Axis};
117117
///
118-
/// let a = arr2(&[[1., 2.],
119-
/// [3., 4.]]);
118+
/// let a = arr2(&[[1., 2., 3.],
119+
/// [4., 5., 6.]]);
120120
/// assert!(
121-
/// a.sum_axis(Axis(0)) == aview1(&[4., 6.]) &&
122-
/// a.sum_axis(Axis(1)) == aview1(&[3., 7.]) &&
121+
/// a.sum_axis(Axis(0)) == aview1(&[5., 7., 9.]) &&
122+
/// a.sum_axis(Axis(1)) == aview1(&[6., 15.]) &&
123123
///
124-
/// a.sum_axis(Axis(0)).sum_axis(Axis(0)) == aview0(&10.)
124+
/// a.sum_axis(Axis(0)).sum_axis(Axis(0)) == aview0(&21.)
125125
/// );
126126
/// ```
127127
///
@@ -156,13 +156,15 @@ impl<A, S, D> ArrayBase<S, D>
156156
/// fails for the axis length.
157157
///
158158
/// ```
159-
/// use ndarray::{aview1, arr2, Axis};
159+
/// use ndarray::{aview0, aview1, arr2, Axis};
160160
///
161-
/// let a = arr2(&[[1., 2.],
162-
/// [3., 4.]]);
161+
/// let a = arr2(&[[1., 2., 3.],
162+
/// [4., 5., 6.]]);
163163
/// assert!(
164-
/// a.mean_axis(Axis(0)).unwrap() == aview1(&[2.0, 3.0]) &&
165-
/// a.mean_axis(Axis(1)).unwrap() == aview1(&[1.5, 3.5])
164+
/// a.mean_axis(Axis(0)).unwrap() == aview1(&[2.5, 3.5, 4.5]) &&
165+
/// a.mean_axis(Axis(1)).unwrap() == aview1(&[2., 5.]) &&
166+
///
167+
/// a.mean_axis(Axis(0)).unwrap().mean_axis(Axis(0)).unwrap() == aview0(&3.5)
166168
/// );
167169
/// ```
168170
pub fn mean_axis(&self, axis: Axis) -> Option<Array<A, D::Smaller>>
@@ -260,9 +262,9 @@ impl<A, S, D> ArrayBase<S, D>
260262
/// The standard deviation is defined as:
261263
///
262264
/// ```text
263-
/// 1 n
264-
/// stddev = sqrt ( ―――――――― ∑ (xᵢ - x̅)² )
265-
/// n - ddof i=1
265+
/// 1 n
266+
/// stddev = sqrt ―――――――― ∑ (xᵢ - x̅)²
267+
/// n - ddof i=1
266268
/// ```
267269
///
268270
/// where

0 commit comments

Comments
 (0)