diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 927022ea6..0fa617970 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -199,6 +199,17 @@ impl ArrayBase unsafe { Ok(Self::from_vec_dim_unchecked(dim, v)) } } + /// Create an array from a vector (no copying needed) using fortran + /// memory order to interpret the data. + /// + /// **Errors** if `dim` does not correspond to the number of elements in `v`. + pub fn from_vec_dim_f(dim: D, v: Vec) -> Result, ShapeError> { + if dim.size_checked() != Some(v.len()) { + return Err(error::incompatible_shapes(&v.len(), &dim)); + } + unsafe { Ok(Self::from_vec_dim_unchecked_f(dim, v)) } + } + /// Create an array from a vector (no copying needed). /// /// Unsafe because dimension is unchecked, and must be correct. @@ -216,14 +227,10 @@ impl ArrayBase /// using fortran memory order to interpret the data. /// /// Unsafe because dimension is unchecked, and must be correct. - pub unsafe fn from_vec_dim_unchecked_f(dim: D, mut v: Vec) -> ArrayBase { + pub unsafe fn from_vec_dim_unchecked_f(dim: D, v: Vec) -> ArrayBase { debug_assert!(dim.size_checked() == Some(v.len())); - ArrayBase { - ptr: v.as_mut_ptr(), - data: DataOwned::new(v), - strides: dim.fortran_strides(), - dim: dim, - } + let strides = dim.fortran_strides(); + Self::from_vec_dim_stride_unchecked(dim, strides, v) } /// Create an array from a vector and interpret it according to the diff --git a/src/impl_linalg.rs b/src/impl_linalg.rs index b2a4edf9d..104e97703 100644 --- a/src/impl_linalg.rs +++ b/src/impl_linalg.rs @@ -140,6 +140,11 @@ impl ArrayBase self.subview_mut(Axis(0), index) } + /// Return the number of rows (length of `Axis(0)`) in the two-dimensional array. + pub fn rows(&self) -> Ix { + self.shape().axis(Axis(0)) + } + /// Return an array view of column `index`. /// /// **Panics** if `index` is out of bounds. @@ -157,6 +162,11 @@ impl ArrayBase self.subview_mut(Axis(1), index) } + /// Return the number of columns (length of `Axis(1)`) in the two-dimensional array. + pub fn cols(&self) -> Ix { + self.shape().axis(Axis(1)) + } + /// Perform matrix multiplication of rectangular arrays `self` and `rhs`. /// /// The array shapes must agree in the way that @@ -228,6 +238,27 @@ impl ArrayBase } } +impl ArrayBase + where S: Data, + D: Dimension, +{ + /// Perform the operation `self += alpha * rhs` efficiently, where + /// `alpha` is a scalar and `rhs` is another array. This operation is + /// also known as `axpy` in BLAS. + /// + /// If their shapes disagree, `rhs` is broadcast to the shape of `self`. + /// + /// **Panics** if broadcasting isn’t possible. + pub fn scaled_add(&mut self, alpha: A, rhs: &ArrayBase) + where S: DataMut, + S2: Data, + A: LinalgScalar, + E: Dimension, + { + self.zip_mut_with(rhs, move |y, &x| *y = *y + (alpha * x)); + } +} + #[cfg(not(feature="blas"))] use self::mat_mul_general as mat_mul_impl; diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 39e8084a4..33b19cb62 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -1154,8 +1154,8 @@ impl ArrayBase where S: Data, D: Dimension /// [1., 2.]]) /// ); /// ``` - pub fn mapv(&self, mut f: F) -> OwnedArray - where F: FnMut(A) -> B, + pub fn mapv(&self, f: F) -> OwnedArray + where F: Fn(A) -> B, A: Clone, { self.map(move |x| f(x.clone())) @@ -1167,7 +1167,7 @@ impl ArrayBase where S: Data, D: Dimension /// Elements are visited in arbitrary order. pub fn mapv_into(mut self, f: F) -> Self where S: DataMut, - F: FnMut(A) -> A, + F: Fn(A) -> A, A: Clone, { self.applyv(f); @@ -1179,7 +1179,7 @@ impl ArrayBase where S: Data, D: Dimension /// Elements are visited in arbitrary order. pub fn apply(&mut self, f: F) where S: DataMut, - F: FnMut(&mut A), + F: Fn(&mut A), { self.unordered_foreach_mut(f); } @@ -1200,9 +1200,9 @@ impl ArrayBase where S: Data, D: Dimension /// [0.36788, 7.38906]]), 1e-5) /// ); /// ``` - pub fn applyv(&mut self, mut f: F) + pub fn applyv(&mut self, f: F) where S: DataMut, - F: FnMut(A) -> A, + F: Fn(A) -> A, A: Clone, { self.unordered_foreach_mut(move |x| *x = f(x.clone())); diff --git a/src/stacking.rs b/src/stacking.rs index 9d83093fb..4165ed4f4 100644 --- a/src/stacking.rs +++ b/src/stacking.rs @@ -11,6 +11,11 @@ use error::{ShapeError, ErrorKind, from_kind}; /// Stack arrays along the given axis. /// +/// ***Errors*** if the arrays don't all have the same dimension +/// (may be made more flexible in the future).
+/// ***Errors*** if `arrays` is empty, if `axis` is out of bounds, +/// if the result is larger than is possible to represent. +/// /// ``` /// use ndarray::{arr2, Axis, stack}; /// diff --git a/tests/array.rs b/tests/array.rs index 4f156a7db..37e64c165 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -115,7 +115,7 @@ fn test_add() } let B = A.clone(); - A.iadd(&B); + A = A + &B; assert_eq!(A[[0, 0]], 0); assert_eq!(A[[0, 1]], 2); assert_eq!(A[[1, 0]], 4); @@ -132,7 +132,6 @@ fn test_multidim() *elt = i as u8; } } - //println!("shape={:?}, strides={:?}", mat.shape(), mat.strides); assert_eq!(mat.dim(), (2,3,4,5,6)); } @@ -152,7 +151,7 @@ array([[[ 7, 6], fn test_negative_stride_rcarray() { let mut mat = RcArray::zeros((2, 4, 2)); - mat[(0, 0, 0)] = 1.0f32; + mat[[0, 0, 0]] = 1.0f32; for (i, elt) in mat.iter_mut().enumerate() { *elt = i as f32; } @@ -167,8 +166,8 @@ fn test_negative_stride_rcarray() } } { - let vi = mat.slice(&[S, Si(0, None, -5), S]); - let seq = [6_f32, 7., 14., 15.]; + let vi = mat.slice(s![.., ..;-5, ..]); + let seq = [6., 7., 14., 15.]; for (a, b) in vi.iter().zip(seq.iter()) { assert_eq!(*a, *b); } @@ -178,7 +177,7 @@ fn test_negative_stride_rcarray() #[test] fn test_cow() { - let mut mat = RcArray::::zeros((2,2)); + let mut mat = RcArray::zeros((2,2)); mat[[0, 0]] = 1; let n = mat.clone(); mat[[0, 1]] = 2; @@ -343,10 +342,13 @@ fn iter_size_hint() #[test] fn zero_axes() { - let a = arr1::(&[]); + let mut a = arr1::(&[]); for _ in a.iter() { assert!(false); } + a.map(|_| assert!(false)); + a.apply(|_| assert!(false)); + a.visit(|_| assert!(false)); println!("{:?}", a); let b = arr2::(&[[], [], [], []]); println!("{:?}\n{:?}", b.shape(), b); @@ -377,7 +379,7 @@ fn map1() let b = a.map(|&x| (x / 3.) as isize); assert_eq!(b, arr2(&[[0, 0], [1, 1]])); // test map to reference with array's lifetime. - let c = a.map(|x| x).into_shared(); + let c = a.map(|x| x); assert_eq!(a[(0, 0)], *c[(0, 0)]); } diff --git a/tests/oper.rs b/tests/oper.rs index 5690be95c..128260f6c 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -216,3 +216,18 @@ fn mat_mul_order() { assert_eq!(cc.strides()[1], 1); assert_eq!(ff.strides()[0], 1); } + +#[test] +fn scaled_add() { + let a = range_mat(16, 15); + let mut b = range_mat(16, 15); + b.applyv(f32::exp); + + let alpha = 0.2_f32; + let mut c = a.clone(); + c.scaled_add(alpha, &b); + + let d = alpha * &b + &a; + assert_eq!(c, d); + +}