From 5eba7467712f541026ebfcd48efa60d8f99e23ce Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 14 Dec 2015 13:49:37 +0100 Subject: [PATCH 01/43] Convert Array into ArrayBase with pluggable storage type --- src/lib.rs | 273 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 192 insertions(+), 81 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 24438951c..5f9f28c95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,23 +121,132 @@ pub type Ixs = i32; /// ); /// ``` /// -pub struct Array { - // FIXME: Unsafecell around vec needed? +pub struct ArrayBase where S: Storage { /// Rc data when used as view, Uniquely held data when being mutated - data: Rc>, + data: S, /// A pointer into the buffer held by data, may point anywhere /// in its range. - ptr: *mut A, + ptr: *mut S::Elem, /// The size of each axis dim: D, /// The element count stride per axis. To be parsed as **isize**. strides: D, } -impl Clone for Array +pub trait Storage { + type Elem; + fn slice(&self) -> &[Self::Elem]; +} + +pub trait StorageMut : Storage { + fn slice_mut(&mut self) -> &mut [Self::Elem]; +} + +impl Storage for Rc> { + type Elem = A; + fn slice(&self) -> &[A] { self } +} + +// NOTE: Copy on write +impl StorageMut for Rc> where A: Clone { + fn slice_mut(&mut self) -> &mut [A] { &mut Rc::make_mut(self)[..] } +} + +impl Storage for Vec { + type Elem = A; + fn slice(&self) -> &[A] { self } +} + +impl StorageMut for Vec { + fn slice_mut(&mut self) -> &mut [A] { self } +} + +impl<'a, A> Storage for &'a [A] { + type Elem = A; + fn slice(&self) -> &[A] { self } +} + +impl<'a, A> Storage for &'a mut [A] { + type Elem = A; + fn slice(&self) -> &[A] { self } +} + +impl<'a, A> StorageMut for &'a mut [A] { + fn slice_mut(&mut self) -> &mut [A] { self } +} + +pub trait StorageNew : Storage { + fn new(elements: Vec) -> Self; +} + +pub trait Shared : Clone { } + +impl Shared for Rc> { } +impl<'a, A> Shared for &'a [A] { } + +impl StorageNew for Vec { + fn new(elements: Vec) -> Self { elements } +} + +impl StorageNew for Rc> { + fn new(elements: Vec) -> Self { Rc::new(elements) } +} + +pub trait StoragePolicy { + fn ensure_unique(&mut self); +} + +impl StoragePolicy for ArrayBase, D> + where D: Dimension, +{ + fn ensure_unique(&mut self) { } +} + +impl<'a, A, D> StoragePolicy for ArrayBase<&'a mut [A], D> + where D: Dimension, +{ + fn ensure_unique(&mut self) { } +} + +impl StoragePolicy for ArrayBase>, D> + where D: Dimension, + A: Clone, +{ + /// Make the array unshared. + /// + /// This method is mostly only useful with unsafe code. + fn ensure_unique(&mut self) + { + if Rc::get_mut(&mut self.data).is_some() { + return + } + if self.dim.size() <= self.data.len() / 2 { + unsafe { + *self = Array::from_vec_dim(self.dim.clone(), + self.iter().map(|x| x.clone()).collect()); + } + return; + } + let our_off = (self.ptr as isize - self.data.as_ptr() as isize) + / mem::size_of::() as isize; + let rvec = Rc::make_mut(&mut self.data); + unsafe { + self.ptr = rvec.as_mut_ptr().offset(our_off); + } + } +} + + +pub type Array = ArrayBase>, D>; +pub type OwnedArray = ArrayBase, D>; + +pub type ArrayView<'a, A, D> = ArrayBase<&'a [A], D>; +pub type ArrayViewMut<'a, A, D> = ArrayBase<&'a mut [A], D>; + +impl Clone for ArrayBase { - fn clone(&self) -> Array { - Array { + fn clone(&self) -> ArrayBase { + ArrayBase { data: self.data.clone(), ptr: self.ptr, dim: self.dim.clone(), @@ -146,17 +255,20 @@ impl Clone for Array } } -impl Array +impl Copy for ArrayBase { } + +impl ArrayBase + where S: StorageNew, { /// Create a one-dimensional array from a vector (no allocation needed). - pub fn from_vec(v: Vec) -> Array { + pub fn from_vec(v: Vec) -> Self { unsafe { - Array::from_vec_dim(v.len() as Ix, v) + Self::from_vec_dim(v.len() as Ix, v) } } /// Create a one-dimensional array from an iterable. - pub fn from_iter>(iterable: I) -> Array { + pub fn from_iter>(iterable: I) -> ArrayBase { Self::from_vec(iterable.into_iter().collect()) } } @@ -174,22 +286,28 @@ impl Array } } -impl Array where D: Dimension +impl ArrayBase + where S: StorageNew, + D: Dimension, { - /// Construct an Array with zeros. - pub fn zeros(dim: D) -> Array where A: Clone + libnum::Zero + /// Create an array from a vector (with no allocation needed). + /// + /// Unsafe because dimension is unchecked, and must be correct. + pub unsafe fn from_vec_dim(dim: D, mut v: Vec) -> ArrayBase { - Array::from_elem(dim, libnum::zero()) + debug_assert!(dim.size() == v.len()); + ArrayBase { + ptr: v.as_mut_ptr(), + data: StorageNew::new(v), + strides: dim.default_strides(), + dim: dim + } } - /// Construct an Array with default values, dimension `dim`. - pub fn default(dim: D) -> Array - where A: Default + /// Construct an Array with zeros. + pub fn zeros(dim: D) -> ArrayBase where S::Elem: Clone + libnum::Zero { - let v = (0..dim.size()).map(|_| A::default()).collect(); - unsafe { - Array::from_vec_dim(dim, v) - } + Self::from_elem(dim, libnum::zero()) } /// Construct an Array with copies of **elem**. @@ -207,28 +325,28 @@ impl Array where D: Dimension /// [1., 1.]]]) /// ); /// ``` - pub fn from_elem(dim: D, elem: A) -> Array where A: Clone + pub fn from_elem(dim: D, elem: S::Elem) -> ArrayBase where S::Elem: Clone { let v = std::iter::repeat(elem).take(dim.size()).collect(); unsafe { - Array::from_vec_dim(dim, v) + Self::from_vec_dim(dim, v) } } - /// Create an array from a vector (with no allocation needed). - /// - /// Unsafe because dimension is unchecked, and must be correct. - pub unsafe fn from_vec_dim(dim: D, mut v: Vec) -> Array + /// Construct an Array with default values, dimension `dim`. + pub fn default(dim: D) -> ArrayBase + where S::Elem: Default { - debug_assert!(dim.size() == v.len()); - Array { - ptr: v.as_mut_ptr(), - data: std::rc::Rc::new(v), - strides: dim.default_strides(), - dim: dim + let v = (0..dim.size()).map(|_| ::default()).collect(); + unsafe { + Self::from_vec_dim(dim, v) } } +} + +impl ArrayBase where S: Storage, D: Dimension +{ /// Return the total number of elements in the Array. pub fn len(&self) -> usize { @@ -263,13 +381,14 @@ impl Array where D: Dimension /// Array's view. pub fn raw_data<'a>(&'a self) -> &'a [A] { - &self.data + self.data.slice() } /// Return a sliced array. /// /// **Panics** if **indexes** does not match the number of array axes. - pub fn slice(&self, indexes: &[Si]) -> Array + pub fn slice(&self, indexes: &[Si]) -> Self + where S: Shared { let mut arr = self.clone(); arr.islice(indexes); @@ -328,8 +447,10 @@ impl Array where D: Dimension /// **Note:** Only unchecked for non-debug builds of ndarray.
/// **Note:** The array must be uniquely held when mutating it. #[inline] - pub unsafe fn uchk_at_mut(&mut self, index: D) -> &mut A { - debug_assert!(Rc::get_mut(&mut self.data).is_some()); + pub unsafe fn uchk_at_mut(&mut self, index: D) -> &mut A + where S: StorageMut + { + //debug_assert!(Rc::get_mut(&mut self.data).is_some()); debug_assert!(self.dim.stride_offset_checked(&self.strides, &index).is_some()); let off = Dimension::stride_offset(&index, &self.strides); &mut *self.ptr.offset(off) @@ -512,9 +633,11 @@ impl Array where D: Dimension } /// Return the diagonal as a one-dimensional array. - pub fn diag(&self) -> Array { + pub fn diag(&self) -> ArrayBase + where S: Shared, + { let (len, stride) = self.diag_params(); - Array { + ArrayBase { data: self.data.clone(), ptr: self.ptr, dim: len, @@ -537,8 +660,9 @@ impl Array where D: Dimension /// == arr2(&[[0, 1], [1, 2]]) /// ); /// ``` - pub fn map<'a, B, F>(&'a self, mut f: F) -> Array where - F: FnMut(&'a A) -> B + pub fn map<'a, B, F>(&'a self, mut f: F) -> Array + where F: FnMut(&'a A) -> B, + A: 'a, { let mut res = Vec::::with_capacity(self.dim.size()); for elt in self.iter() { @@ -565,14 +689,15 @@ impl Array where D: Dimension /// a.subview(1, 1) == arr1(&[2., 4.]) /// ); /// ``` - pub fn subview(&self, axis: usize, index: Ix) -> Array::Smaller> where - D: RemoveAxis + pub fn subview(&self, axis: usize, index: Ix) -> ArrayBase::Smaller> + where D: RemoveAxis, + S: Shared, { let mut res = self.clone(); res.isubview(axis, index); // don't use reshape -- we always know it will fit the size, // and we can use remove_axis on the strides as well - Array{ + ArrayBase { data: res.data, ptr: res.ptr, dim: res.dim.remove_axis(axis), @@ -580,32 +705,10 @@ impl Array where D: Dimension } } - /// Make the array unshared. - /// - /// This method is mostly only useful with unsafe code. - pub fn ensure_unique(&mut self) where A: Clone - { - if Rc::get_mut(&mut self.data).is_some() { - return - } - if self.dim.size() <= self.data.len() / 2 { - unsafe { - *self = Array::from_vec_dim(self.dim.clone(), - self.iter().map(|x| x.clone()).collect()); - } - return; - } - let our_off = (self.ptr as isize - self.data.as_ptr() as isize) - / mem::size_of::
() as isize; - let rvec = Rc::make_mut(&mut self.data); - unsafe { - self.ptr = rvec.as_mut_ptr().offset(our_off); - } - } - /// Return a mutable reference to the element at **index**, or return **None** /// if the index is out of bounds. - pub fn at_mut<'a>(&'a mut self, index: D) -> Option<&'a mut A> where A: Clone + pub fn at_mut<'a>(&'a mut self, index: D) -> Option<&'a mut A> + where Self: StoragePolicy, { self.ensure_unique(); self.dim.stride_offset_checked(&self.strides, &index) @@ -617,7 +720,8 @@ impl Array where D: Dimension /// Return an iterator of mutable references to the elements of the array. /// /// Iterator element type is **&'a mut A**. - pub fn iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, D> where A: Clone + pub fn iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, D> + where Self: StoragePolicy, { self.ensure_unique(); ElementsMut { inner: self.base_iter() } @@ -626,7 +730,8 @@ impl Array where D: Dimension /// Return an iterator of indexes and mutable references to the elements of the array. /// /// Iterator element type is **(D, &'a mut A)**. - pub fn indexed_iter_mut<'a>(&'a mut self) -> Indexed> where A: Clone + pub fn indexed_iter_mut<'a>(&'a mut self) -> Indexed> + where Self: StoragePolicy, { self.iter_mut().indexed() } @@ -637,7 +742,8 @@ impl Array where D: Dimension /// Iterator element type is **&'a mut A**. /// /// **Panics** if **indexes** does not match the number of array axes. - pub fn slice_iter_mut<'a>(&'a mut self, indexes: &[Si]) -> ElementsMut<'a, A, D> where A: Clone + pub fn slice_iter_mut<'a>(&'a mut self, indexes: &[Si]) -> ElementsMut<'a, A, D> + where Self: StoragePolicy, { let mut it = self.iter_mut(); let offset = Dimension::do_slices(&mut it.inner.dim, &mut it.inner.strides, indexes); @@ -654,7 +760,8 @@ impl Array where D: Dimension /// /// **Panics** if **axis** or **index** is out of bounds. pub fn sub_iter_mut<'a>(&'a mut self, axis: usize, index: Ix) - -> ElementsMut<'a, A, D> where A: Clone + -> ElementsMut<'a, A, D> + where Self: StoragePolicy, { let mut it = self.iter_mut(); dimension::do_sub(&mut it.inner.dim, &mut it.inner.ptr, &it.inner.strides, axis, index); @@ -662,7 +769,8 @@ impl Array where D: Dimension } /// Return an iterator over the diagonal elements of the array. - pub fn diag_iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, Ix> where A: Clone + pub fn diag_iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, Ix> + where Self: StoragePolicy, { self.ensure_unique(); let (len, stride) = self.diag_params(); @@ -682,10 +790,10 @@ impl Array where D: Dimension /// **Note:** The data is uniquely held and nonaliased /// while it is mutably borrowed. pub fn raw_data_mut<'a>(&'a mut self) -> &'a mut [A] - where A: Clone + where Self: StoragePolicy, S: StorageMut { self.ensure_unique(); - &mut Rc::make_mut(&mut self.data)[..] + self.data.slice_mut() } @@ -703,7 +811,8 @@ impl Array where D: Dimension /// [3., 4.]]) /// ); /// ``` - pub fn reshape(&self, shape: E) -> Array where A: Clone + pub fn reshape(&self, shape: E) -> ArrayBase + where S: Shared + StorageNew, A: Clone, { if shape.size() != self.dim.size() { panic!("Incompatible sizes in reshape, attempted from: {:?}, to: {:?}", @@ -712,7 +821,7 @@ impl Array where D: Dimension // Check if contiguous, if not => copy all, else just adapt strides if self.is_standard_layout() { let cl = self.clone(); - Array{ + ArrayBase { data: cl.data, ptr: cl.ptr, strides: shape.default_strides(), @@ -721,7 +830,7 @@ impl Array where D: Dimension } else { let v = self.iter().map(|x| x.clone()).collect::>(); unsafe { - Array::from_vec_dim(shape, v) + ArrayBase::from_vec_dim(shape, v) } } } @@ -731,7 +840,8 @@ impl Array where D: Dimension /// If their shapes disagree, **other** is broadcast to the shape of **self**. /// /// **Panics** if broadcasting isn't possible. - pub fn assign(&mut self, other: &Array) where A: Clone + pub fn assign(&mut self, other: &Array) + where Self: StoragePolicy, A: Clone, { if self.shape() == other.shape() { for (x, y) in self.iter_mut().zip(other.iter()) { @@ -746,7 +856,8 @@ impl Array where D: Dimension } /// Perform an elementwise assigment to **self** from scalar **x**. - pub fn assign_scalar(&mut self, x: &A) where A: Clone + pub fn assign_scalar(&mut self, x: &A) + where Self: StoragePolicy, S: StorageMut, A: Clone, { for elt in self.raw_data_mut().iter_mut() { *elt = x.clone(); From cc19ded2f8eb398ba7da2353405df9fc0dacf632 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 14 Dec 2015 23:45:56 +0100 Subject: [PATCH 02/43] Rename trait to ArrayMut --- src/lib.rs | 26 +++++++++++++------------- tests/array.rs | 18 ++++++++++++++++-- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5f9f28c95..c60ceb7a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,23 +192,23 @@ impl StorageNew for Rc> { fn new(elements: Vec) -> Self { Rc::new(elements) } } -pub trait StoragePolicy { +pub trait ArrayMut { fn ensure_unique(&mut self); } -impl StoragePolicy for ArrayBase, D> +impl ArrayMut for ArrayBase, D> where D: Dimension, { fn ensure_unique(&mut self) { } } -impl<'a, A, D> StoragePolicy for ArrayBase<&'a mut [A], D> +impl<'a, A, D> ArrayMut for ArrayBase<&'a mut [A], D> where D: Dimension, { fn ensure_unique(&mut self) { } } -impl StoragePolicy for ArrayBase>, D> +impl ArrayMut for ArrayBase>, D> where D: Dimension, A: Clone, { @@ -708,7 +708,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Return a mutable reference to the element at **index**, or return **None** /// if the index is out of bounds. pub fn at_mut<'a>(&'a mut self, index: D) -> Option<&'a mut A> - where Self: StoragePolicy, + where Self: ArrayMut, { self.ensure_unique(); self.dim.stride_offset_checked(&self.strides, &index) @@ -721,7 +721,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// Iterator element type is **&'a mut A**. pub fn iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, D> - where Self: StoragePolicy, + where Self: ArrayMut, { self.ensure_unique(); ElementsMut { inner: self.base_iter() } @@ -731,7 +731,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// Iterator element type is **(D, &'a mut A)**. pub fn indexed_iter_mut<'a>(&'a mut self) -> Indexed> - where Self: StoragePolicy, + where Self: ArrayMut, { self.iter_mut().indexed() } @@ -743,7 +743,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// **Panics** if **indexes** does not match the number of array axes. pub fn slice_iter_mut<'a>(&'a mut self, indexes: &[Si]) -> ElementsMut<'a, A, D> - where Self: StoragePolicy, + where Self: ArrayMut, { let mut it = self.iter_mut(); let offset = Dimension::do_slices(&mut it.inner.dim, &mut it.inner.strides, indexes); @@ -761,7 +761,7 @@ impl ArrayBase where S: Storage, D: Dimension /// **Panics** if **axis** or **index** is out of bounds. pub fn sub_iter_mut<'a>(&'a mut self, axis: usize, index: Ix) -> ElementsMut<'a, A, D> - where Self: StoragePolicy, + where Self: ArrayMut, { let mut it = self.iter_mut(); dimension::do_sub(&mut it.inner.dim, &mut it.inner.ptr, &it.inner.strides, axis, index); @@ -770,7 +770,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Return an iterator over the diagonal elements of the array. pub fn diag_iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, Ix> - where Self: StoragePolicy, + where Self: ArrayMut, { self.ensure_unique(); let (len, stride) = self.diag_params(); @@ -790,7 +790,7 @@ impl ArrayBase where S: Storage, D: Dimension /// **Note:** The data is uniquely held and nonaliased /// while it is mutably borrowed. pub fn raw_data_mut<'a>(&'a mut self) -> &'a mut [A] - where Self: StoragePolicy, S: StorageMut + where Self: ArrayMut, S: StorageMut { self.ensure_unique(); self.data.slice_mut() @@ -841,7 +841,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// **Panics** if broadcasting isn't possible. pub fn assign(&mut self, other: &Array) - where Self: StoragePolicy, A: Clone, + where Self: ArrayMut, A: Clone, { if self.shape() == other.shape() { for (x, y) in self.iter_mut().zip(other.iter()) { @@ -857,7 +857,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Perform an elementwise assigment to **self** from scalar **x**. pub fn assign_scalar(&mut self, x: &A) - where Self: StoragePolicy, S: StorageMut, A: Clone, + where Self: ArrayMut, S: StorageMut, A: Clone, { for elt in self.raw_data_mut().iter_mut() { *elt = x.clone(); diff --git a/tests/array.rs b/tests/array.rs index daa644988..f59699c1d 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -2,7 +2,9 @@ extern crate ndarray; -use ndarray::{Array, S, Si}; +use ndarray::{Array, S, Si, + OwnedArray, +}; use ndarray::{arr0, arr1, arr2}; use ndarray::Indexes; use ndarray::SliceRange; @@ -340,10 +342,22 @@ fn map1() #[test] fn raw_data_mut() { - let mut a = arr2(&[[1., 2.], [3., 4.0f32]]); + let a = arr2(&[[1., 2.], [3., 4.0f32]]); let mut b = a.clone(); for elt in b.raw_data_mut() { *elt = 0.; } assert!(a != b, "{:?} != {:?}", a, b); } + +#[test] +fn owned_array1() { + let mut a = OwnedArray::from_vec(vec![1, 2, 3, 4]); + for elt in a.iter_mut() { + *elt = 2; + } + for elt in a.iter() { + assert_eq!(*elt, 2); + } + assert_eq!(a.shape(), &[4]); +} From b4bd888022f8bcf01b23c880d47551809a34c4f0 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 14 Dec 2015 23:47:42 +0100 Subject: [PATCH 03/43] Update docs --- src/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c60ceb7a2..8bf686d21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,13 @@ #![crate_name="ndarray"] #![crate_type="dylib"] -//! The **ndarray** crate provides the [**Array**](./struct.Array.html) type, an -//! n-dimensional container similar to numpy's ndarray. +//! The **ndarray** crate provides an n-dimensional container similar to numpy's ndarray. +//! +//! - `ArrayBase` +//! - `Array` +//! - `OwnedArray` +//! - `ArrayView` +//! - `ArrayViewMut` //! //! ## Crate Summary and Status //! From 740198378e767e160d0440330aa345f56a71c631 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 00:07:54 +0100 Subject: [PATCH 04/43] Update ArrayBase::map --- src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8bf686d21..843ae8eac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -665,16 +665,17 @@ impl ArrayBase where S: Storage, D: Dimension /// == arr2(&[[0, 1], [1, 2]]) /// ); /// ``` - pub fn map<'a, B, F>(&'a self, mut f: F) -> Array - where F: FnMut(&'a A) -> B, + pub fn map<'a, F, S2>(&'a self, mut f: F) -> ArrayBase + where F: FnMut(&'a A) -> S2::Elem, A: 'a, + S2: StorageNew, { - let mut res = Vec::::with_capacity(self.dim.size()); + let mut res = Vec::with_capacity(self.dim.size()); for elt in self.iter() { res.push(f(elt)) } unsafe { - Array::from_vec_dim(self.dim.clone(), res) + ArrayBase::from_vec_dim(self.dim.clone(), res) } } From 6ccc90ed4a642cfec3a73b8c9cf9bfcd5a945abe Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 00:10:26 +0100 Subject: [PATCH 05/43] Make ArrayBase::assign generic --- src/lib.rs | 6 ++++-- tests/array.rs | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 843ae8eac..c1c70ec4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -846,8 +846,10 @@ impl ArrayBase where S: Storage, D: Dimension /// If their shapes disagree, **other** is broadcast to the shape of **self**. /// /// **Panics** if broadcasting isn't possible. - pub fn assign(&mut self, other: &Array) - where Self: ArrayMut, A: Clone, + pub fn assign(&mut self, other: &ArrayBase) + where Self: ArrayMut, + A: Clone, + S2: Storage, { if self.shape() == other.shape() { for (x, y) in self.iter_mut().zip(other.iter()) { diff --git a/tests/array.rs b/tests/array.rs index f59699c1d..55d000e40 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -236,6 +236,10 @@ fn assign() /* Test broadcasting */ a.assign(&Array::zeros(1)); assert_eq!(a, Array::zeros((2, 2))); + + /* Test other type */ + a.assign(&OwnedArray::from_elem((2, 2), 3.)); + assert_eq!(a, Array::from_elem((2, 2), 3.)); } #[test] From cce7ff642e5c237d0c679c29a06f86952c4eb595 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 00:11:27 +0100 Subject: [PATCH 06/43] Update Storage / StorageMut to be unsafe traits --- src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c1c70ec4f..d7c663a98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,45 +138,45 @@ pub struct ArrayBase where S: Storage { strides: D, } -pub trait Storage { +pub unsafe trait Storage { type Elem; fn slice(&self) -> &[Self::Elem]; } -pub trait StorageMut : Storage { +pub unsafe trait StorageMut : Storage { fn slice_mut(&mut self) -> &mut [Self::Elem]; } -impl Storage for Rc> { +unsafe impl Storage for Rc> { type Elem = A; fn slice(&self) -> &[A] { self } } // NOTE: Copy on write -impl StorageMut for Rc> where A: Clone { +unsafe impl StorageMut for Rc> where A: Clone { fn slice_mut(&mut self) -> &mut [A] { &mut Rc::make_mut(self)[..] } } -impl Storage for Vec { +unsafe impl Storage for Vec { type Elem = A; fn slice(&self) -> &[A] { self } } -impl StorageMut for Vec { +unsafe impl StorageMut for Vec { fn slice_mut(&mut self) -> &mut [A] { self } } -impl<'a, A> Storage for &'a [A] { +unsafe impl<'a, A> Storage for &'a [A] { type Elem = A; fn slice(&self) -> &[A] { self } } -impl<'a, A> Storage for &'a mut [A] { +unsafe impl<'a, A> Storage for &'a mut [A] { type Elem = A; fn slice(&self) -> &[A] { self } } -impl<'a, A> StorageMut for &'a mut [A] { +unsafe impl<'a, A> StorageMut for &'a mut [A] { fn slice_mut(&mut self) -> &mut [A] { self } } From 10d0f63300e1bcf1ea5686cb38416606d731d5ce Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 00:21:36 +0100 Subject: [PATCH 07/43] Generalize PartialEq --- src/arraytraits.rs | 22 ++++++++++++++++------ src/lib.rs | 4 ++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 0d18b2721..bef479b6d 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -9,7 +9,11 @@ use std::ops::{ IndexMut, }; -use super::{Array, Dimension, Ix, Elements, ElementsMut}; +use super::{ + Array, Dimension, Ix, Elements, ElementsMut, + ArrayBase, + Storage, +}; impl<'a, A, D: Dimension> Index for Array { @@ -35,20 +39,26 @@ impl<'a, A: Clone, D: Dimension> IndexMut for Array } -impl -PartialEq for Array +impl PartialEq> for ArrayBase + where D: Dimension, + S: Storage, + S2: Storage, + S::Elem: PartialEq, { /// Return `true` if the array shapes and all elements of `self` and /// `other` are equal. Return `false` otherwise. - fn eq(&self, other: &Array) -> bool + fn eq(&self, other: &ArrayBase) -> bool { self.shape() == other.shape() && self.iter().zip(other.iter()).all(|(a, b)| a == b) } } -impl -Eq for Array {} +impl Eq for ArrayBase + where D: Dimension, + S: Storage, + S::Elem: Eq, +{ } impl FromIterator for Array { diff --git a/src/lib.rs b/src/lib.rs index d7c663a98..311b05c95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -661,11 +661,11 @@ impl ArrayBase where S: Storage, D: Dimension /// let a = arr2(&[[1., 2.], /// [3., 4.]]); /// assert!( - /// a.map(|&x| (x / 2.) as i32) + /// a.map::, _>(|&x| (x / 2.) as i32) /// == arr2(&[[0, 1], [1, 2]]) /// ); /// ``` - pub fn map<'a, F, S2>(&'a self, mut f: F) -> ArrayBase + pub fn map<'a, S2, F>(&'a self, mut f: F) -> ArrayBase where F: FnMut(&'a A) -> S2::Elem, A: 'a, S2: StorageNew, From ac1b457961794491bf544fe5a8f1a766c4feba5d Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 00:26:05 +0100 Subject: [PATCH 08/43] Update IntoIterator, Hash --- src/arraytraits.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/arraytraits.rs b/src/arraytraits.rs index bef479b6d..d5515ba96 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -13,6 +13,8 @@ use super::{ Array, Dimension, Ix, Elements, ElementsMut, ArrayBase, Storage, + StorageMut, + ArrayMut, }; impl<'a, A, D: Dimension> Index for Array @@ -68,24 +70,25 @@ impl FromIterator for Array } } -impl<'a, A, D> IntoIterator for &'a Array where - D: Dimension, +impl<'a, S, D> IntoIterator for &'a ArrayBase + where D: Dimension, + S: Storage, { - type Item = &'a A; - type IntoIter = Elements<'a, A, D>; + type Item = &'a S::Elem; + type IntoIter = Elements<'a, S::Elem, D>; - fn into_iter(self) -> Self::IntoIter - { + fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl<'a, A, D> IntoIterator for &'a mut Array where - A: Clone, - D: Dimension, +impl<'a, S, D> IntoIterator for &'a mut ArrayBase + where D: Dimension, + S: StorageMut, + ArrayBase: ArrayMut, { - type Item = &'a mut A; - type IntoIter = ElementsMut<'a, A, D>; + type Item = &'a mut S::Elem; + type IntoIter = ElementsMut<'a, S::Elem, D>; fn into_iter(self) -> Self::IntoIter { @@ -93,10 +96,12 @@ impl<'a, A, D> IntoIterator for &'a mut Array where } } -impl -hash::Hash for Array +impl<'a, S, D> hash::Hash for ArrayBase + where D: Dimension, + S: Storage, + S::Elem: hash::Hash, { - fn hash(&self, state: &mut S) + fn hash(&self, state: &mut H) { self.shape().hash(state); for elt in self.iter() { From d442bed7ed1391f8fc30b985bceed9bcd69d404d Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 00:33:54 +0100 Subject: [PATCH 09/43] Generalize Index, IndexMut and Debug --- src/arrayformat.rs | 15 +++++++++++---- src/arraytraits.rs | 27 ++++++++++++++++----------- tests/array.rs | 10 ++++++++-- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index aeab4f8a9..522b1daec 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -1,9 +1,15 @@ use std::fmt; use super::{Array, Dimension}; +use super::{ + ArrayBase, + Storage, +}; -fn format_array(view: &Array, f: &mut fmt::Formatter, - mut format: F) -> fmt::Result where - F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result, +fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, + mut format: F) -> fmt::Result + where F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result, + D: Dimension, + S: Storage, { let ndim = view.dim.slice().len(); /* private nowadays @@ -80,7 +86,8 @@ impl<'a, A: fmt::Display, D: Dimension> fmt::Display for Array } } -impl<'a, A: fmt::Debug, D: Dimension> fmt::Debug for Array +impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase + where S: Storage, { /// Format the array using `Debug` and apply the formatting parameters used /// to each element. diff --git a/src/arraytraits.rs b/src/arraytraits.rs index d5515ba96..0d93f3c2e 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -17,25 +17,30 @@ use super::{ ArrayMut, }; -impl<'a, A, D: Dimension> Index for Array +/// Access the element at **index**. +/// +/// **Panics** if index is out of bounds. +impl Index for ArrayBase + where D: Dimension, + S: Storage, { - type Output = A; + type Output = S::Elem; #[inline] - /// Access the element at **index**. - /// - /// **Panics** if index is out of bounds. - fn index(&self, index: D) -> &A { + fn index(&self, index: D) -> &S::Elem { self.at(index).expect("Array::index: out of bounds") } } -impl<'a, A: Clone, D: Dimension> IndexMut for Array +/// Access the element at **index** mutably. +/// +/// **Panics** if index is out of bounds. +impl IndexMut for ArrayBase + where D: Dimension, + S: StorageMut, + ArrayBase: ArrayMut, { #[inline] - /// Access the element at **index** mutably. - /// - /// **Panics** if index is out of bounds. - fn index_mut(&mut self, index: D) -> &mut A { + fn index_mut(&mut self, index: D) -> &mut S::Elem { self.at_mut(index).expect("Array::index_mut: out of bounds") } } diff --git a/tests/array.rs b/tests/array.rs index 55d000e40..429d1893f 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -336,10 +336,10 @@ fn equality() fn map1() { let a = arr2(&[[1., 2.], [3., 4.]]); - let b = a.map(|&x| (x / 3.) as isize); + 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); + let c = a.map::, _>(|x| x); assert_eq!(a[(0, 0)], *c[(0, 0)]); } @@ -364,4 +364,10 @@ fn owned_array1() { assert_eq!(*elt, 2); } assert_eq!(a.shape(), &[4]); + + let mut a = OwnedArray::zeros((2, 2)); + let mut b = Array::zeros((2, 2)); + a[(1, 1)] = 3; + b[(1, 1)] = 3; + assert_eq!(a, b); } From 7bdc14a6684e190feebb1f75950c17f36e11b64a Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 01:32:54 +0100 Subject: [PATCH 10/43] Generalize mat_mul slightly --- src/lib.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 311b05c95..ca36724dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1056,7 +1056,8 @@ impl Array where } } -impl Array +impl ArrayBase + where S: Storage, { /// Return an iterator over the elements of row **index**. /// @@ -1092,7 +1093,8 @@ impl Array // Matrix multiplication only defined for simple types to // avoid trouble with failing + and *, and destructors -impl<'a, A: Copy + linalg::Ring> Array +impl<'a, A: Copy + linalg::Ring, S> ArrayBase + where S: Storage, { /// Perform matrix multiplication of rectangular arrays **self** and **other**. /// @@ -1117,7 +1119,7 @@ impl<'a, A: Copy + linalg::Ring> Array /// ); /// ``` /// - pub fn mat_mul(&self, other: &Array) -> Array + pub fn mat_mul(&self, other: &ArrayBase) -> Array { let ((m, a), (b, n)) = (self.dim, other.dim); let (self_columns, other_rows) = (a, b); @@ -1144,7 +1146,7 @@ impl<'a, A: Copy + linalg::Ring> Array } } unsafe { - Array::from_vec_dim((m, n), res_elems) + ArrayBase::from_vec_dim((m, n), res_elems) } } @@ -1157,7 +1159,7 @@ impl<'a, A: Copy + linalg::Ring> Array /// Return a result array with shape *M*. /// /// **Panics** if sizes are incompatible. - pub fn mat_mul_col(&self, other: &Array) -> Array + pub fn mat_mul_col(&self, other: &ArrayBase) -> Array { let ((m, a), n) = (self.dim, other.dim); let (self_columns, other_rows) = (a, n); @@ -1179,7 +1181,7 @@ impl<'a, A: Copy + linalg::Ring> Array i += 1; } unsafe { - Array::from_vec_dim(m, res_elems) + ArrayBase::from_vec_dim(m, res_elems) } } } From 1e7400c1af8583982a6bfbae8977e29bf883a58a Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 11/43] Generalize iops --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ca36724dc..6200a8b2b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1204,8 +1204,10 @@ impl Array macro_rules! impl_binary_op( ($trt:ident, $mth:ident, $imethod:ident, $imth_scalar:ident) => ( -impl Array where +impl ArrayBase where A: Clone + $trt, + ArrayBase: ArrayMut, + S: StorageMut, D: Dimension, { /// Perform an elementwise arithmetic operation between **self** and **other**, @@ -1214,7 +1216,8 @@ impl Array where /// If their shapes disagree, **other** is broadcast to the shape of **self**. /// /// **Panics** if broadcasting isn't possible. - pub fn $imethod (&mut self, other: &Array) + pub fn $imethod (&mut self, other: &ArrayBase) + where S2: Storage, { if self.dim.ndim() == other.dim.ndim() && self.shape() == other.shape() { From 88a90b6bd2d54d679b005ad9e1851dc7ccddb397 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 12/43] Update arithmetic operations --- src/lib.rs | 20 +++++++++++++------- tests/array.rs | 7 +++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6200a8b2b..b34dba069 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1248,13 +1248,16 @@ impl ArrayBase where /// If their shapes disagree, **other** is broadcast to the shape of **self**. /// /// **Panics** if broadcasting isn't possible. -impl<'a, A, D, E> $trt> for Array +impl<'a, A, S, S2, D, E> $trt> for ArrayBase where A: Clone + $trt, + S: StorageMut, + ArrayBase: ArrayMut, + S2: Storage, D: Dimension, E: Dimension, { - type Output = Array; - fn $mth (mut self, other: Array) -> Array + type Output = ArrayBase; + fn $mth (mut self, other: ArrayBase) -> ArrayBase { // FIXME: Can we co-broadcast arrays here? And how? if self.shape() == other.shape() { @@ -1277,13 +1280,16 @@ impl<'a, A, D, E> $trt> for Array /// If their shapes disagree, **other** is broadcast to the shape of **self**. /// /// **Panics** if broadcasting isn't possible. -impl<'a, A, D, E> $trt<&'a Array> for &'a Array +impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for &'a ArrayBase where A: Clone + $trt, + S: StorageMut, + S2: Storage, + ArrayBase: ArrayMut, D: Dimension, E: Dimension, { - type Output = Array; - fn $mth (self, other: &'a Array) -> Array + type Output = OwnedArray; + fn $mth (self, other: &'a ArrayBase) -> OwnedArray { // FIXME: Can we co-broadcast arrays here? And how? let mut result = Vec::::with_capacity(self.dim.size()); @@ -1298,7 +1304,7 @@ impl<'a, A, D, E> $trt<&'a Array> for &'a Array } } unsafe { - Array::from_vec_dim(self.dim.clone(), result) + ArrayBase::from_vec_dim(self.dim.clone(), result) } } } diff --git a/tests/array.rs b/tests/array.rs index 429d1893f..4be171a74 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -370,4 +370,11 @@ fn owned_array1() { a[(1, 1)] = 3; b[(1, 1)] = 3; assert_eq!(a, b); + + let c = a.clone(); + + let d1 = &a + &b; + let d2 = a + b; + assert_eq!(c, d1); + assert_eq!(d1, d2); } From fe027cfc271c7aba9b42c6e51a7f7358965a8eac Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 13/43] Adjust arithmetic ops impls --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b34dba069..2f5fec31f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1282,9 +1282,8 @@ impl<'a, A, S, S2, D, E> $trt> for ArrayBase /// **Panics** if broadcasting isn't possible. impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for &'a ArrayBase where A: Clone + $trt, - S: StorageMut, + S: Storage, S2: Storage, - ArrayBase: ArrayMut, D: Dimension, E: Dimension, { From 46848ce724aee8b42d21407b98da99bf0d006a5f Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 14/43] Add .view() and .view_mut() --- src/lib.rs | 24 ++++++++++++++++++++++++ tests/array.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2f5fec31f..763e4be4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -379,6 +379,30 @@ impl ArrayBase where S: Storage, D: Dimension self.strides == self.dim.default_strides() } + /// Return a read-only view of the array + pub fn view(&self) -> ArrayView { + ArrayView { + ptr: self.ptr, + dim: self.dim.clone(), + strides: self.strides.clone(), + data: self.raw_data(), + } + } + + /// Return a read-only view of the array + pub fn view_mut(&mut self) -> ArrayViewMut + where Self: ArrayMut, + S: StorageMut, + { + self.ensure_unique(); + ArrayViewMut { + ptr: self.ptr, + dim: self.dim.clone(), + strides: self.strides.clone(), + data: self.data.slice_mut(), + } + } + /// Return a slice of the array's backing data in memory order. /// /// **Note:** Data memory order may not correspond to the index order diff --git a/tests/array.rs b/tests/array.rs index 4be171a74..28bf9fd84 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -378,3 +378,29 @@ fn owned_array1() { assert_eq!(c, d1); assert_eq!(d1, d2); } + +#[test] +fn views() { + let a = Array::from_vec(vec![1, 2, 3, 4]).reshape((2, 2)); + let b = a.view(); + assert_eq!(a, b); + assert_eq!(a.shape(), b.shape()); + assert_eq!(a.clone() + a.clone(), &b + &b); + assert_eq!(a.clone() + b, &b + &b); + a.clone()[(0, 0)] = 99; + assert_eq!(b[(0, 0)], 1); +} + +#[test] +fn view_mut() { + let mut a = Array::from_vec(vec![1, 2, 3, 4]).reshape((2, 2)); + for elt in &mut a.view_mut() { + *elt = 0; + } + assert_eq!(a, OwnedArray::zeros((2, 2))); + { + let mut b = a.view_mut(); + b[(0, 0)] = 7; + } + assert_eq!(a[(0, 0)], 7); +} From dd341394b2298ed115dc664f0ec6bcf29292be03 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 15/43] Port assign ops to be generic --- src/lib.rs | 7 +++++-- tests/array.rs | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 763e4be4b..d8c0e7223 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1371,12 +1371,15 @@ mod assign_ops { /// **Panics** if broadcasting isn't possible. /// /// **Requires `feature = "assign_ops"`** - impl<'a, A, D, E> $trt<&'a Array> for Array + impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for ArrayBase where A: Clone + $trt, + S: StorageMut, + ArrayBase: ArrayMut, + S2: Storage, D: Dimension, E: Dimension, { - fn $method(&mut self, other: &Array) { + fn $method(&mut self, other: &ArrayBase) { if self.shape() == other.shape() { for (x, y) in self.iter_mut().zip(other.iter()) { x.$method(y.clone()); diff --git a/tests/array.rs b/tests/array.rs index 28bf9fd84..3744a0203 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -1,4 +1,5 @@ #![allow(non_snake_case)] +#![cfg_attr(feature = "assign_ops", feature(augmented_assignments))] extern crate ndarray; @@ -404,3 +405,17 @@ fn view_mut() { } assert_eq!(a[(0, 0)], 7); } + +#[cfg(feature = "assign_ops")] +#[test] +fn assign_ops() +{ + let mut a = arr2(&[[1., 2.], [3., 4.]]); + let b = arr2(&[[1., 3.], [2., 4.]]); + (*&mut a.view_mut()) += &b; + assert_eq!(a, arr2(&[[2., 5.], [5., 8.]])); + + a -= &b; + a -= &b; + assert_eq!(a, arr2(&[[0., -1.,], [1., 0.]])); +} From 9eef2edc8e46cd842cb2e5ceb81e5b660c1880d9 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 16/43] Fix doc for views --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index d8c0e7223..af11906c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -389,7 +389,7 @@ impl ArrayBase where S: Storage, D: Dimension } } - /// Return a read-only view of the array + /// Return a read-write view of the array pub fn view_mut(&mut self) -> ArrayViewMut where Self: ArrayMut, S: StorageMut, From 8983e3fab9be5b7d49fa817af4d132b68f99c822 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 17/43] Add test for view().diag() --- tests/array.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/array.rs b/tests/array.rs index 3744a0203..abe60accd 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -189,7 +189,8 @@ fn diag() { let d = arr2(&[[1., 2., 3.0f32]]).diag(); assert_eq!(d.dim(), 1); - let d = arr2(&[[1., 2., 3.0f32], [0., 0., 0.]]).diag(); + let a = arr2(&[[1., 2., 3.0f32], [0., 0., 0.]]); + let d = a.view().diag(); assert_eq!(d.dim(), 2); let d = arr2::(&[[]]).diag(); assert_eq!(d.dim(), 0); From e78ca9148a6d09de7b643fda8bc104fb008b29be Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 18/43] Impl Sync and Send for ArrayBase Does not apply to the Rc version, but the owned array and views are send & sync --- src/arraytraits.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 0d93f3c2e..2efda1973 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -115,6 +115,22 @@ impl<'a, S, D> hash::Hash for ArrayBase } } +// NOTE: ArrayBase keeps an internal raw pointer that always +// points into the storage. This is Sync & Send as long as we +// follow the usual inherited mutability rules, as we do with +// Vec, &[] and &mut [] + +/// `ArrayBase` is `Sync` when the storage type is. +unsafe impl Sync for ArrayBase + where S: Sync + Storage, D: Sync +{ } + +/// `ArrayBase` is `Send` when the storage type is. +unsafe impl Send for ArrayBase + where S: Send + Storage, D: Send +{ } + + #[cfg(feature = "rustc-serialize")] // Use version number so we can add a packed format later. static ARRAY_FORMAT_VERSION: u8 = 1u8; From c1de0a5b7c70c36dc0c719b59f56a389b9094ee5 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 19/43] Add broadcast() -> ArrayView method --- src/lib.rs | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index af11906c0..1c4a17a85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -350,6 +350,21 @@ impl ArrayBase } +impl<'a, A, D> ArrayView<'a, A, D> + where D: Dimension, +{ + #[inline] + fn into_base_iter(self) -> Baseiter<'a, A, D> { + unsafe { + Baseiter::new(self.ptr, self.dim.clone(), self.strides.clone()) + } + } + + fn into_iter(self) -> Elements<'a, A, D> { + Elements { inner: self.into_base_iter() } + } +} + impl ArrayBase where S: Storage, D: Dimension { /// Return the total number of elements in the Array. @@ -544,12 +559,12 @@ impl ArrayBase where S: Storage, D: Dimension /// use ndarray::arr1; /// /// assert!( - /// arr1(&[1., 0.]).broadcast_iter((10, 2)).unwrap().count() - /// == 20 + /// arr1(&[1., 0.]).broadcast((10, 2)).unwrap().dim() + /// == (10, 2) /// ); /// ``` - pub fn broadcast_iter<'a, E: Dimension>(&'a self, dim: E) - -> Option> + pub fn broadcast<'a, E: Dimension>(&'a self, dim: E) + -> Option> { /// Return new stride when trying to grow **from** into shape **to** /// @@ -598,14 +613,24 @@ impl ArrayBase where S: Storage, D: Dimension Some(st) => st, None => return None, }; - Some(Elements { - inner: - unsafe { - Baseiter::new(self.ptr, dim, broadcast_strides) - } + Some(ArrayView { + data: self.raw_data(), + ptr: self.ptr, + dim: dim, + strides: broadcast_strides, }) } + /// Act like a larger size and/or shape array by *broadcasting* + /// into a larger shape, if possible. + /// + /// Return **None** if shapes can not be broadcast together. + pub fn broadcast_iter<'a, E: Dimension>(&'a self, dim: E) + -> Option> + { + self.broadcast(dim).map(|v| v.into_iter()) + } + #[inline(never)] fn broadcast_iter_unwrap<'a, E: Dimension>(&'a self, dim: E) -> Elements<'a, A, E> From 1515ceb925667e981d14892ba28db6883c76caad Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 20/43] Merge ArrayMut and StorageMut traits Less trait mess visible in the docs & simpler code --- src/arraytraits.rs | 3 -- src/lib.rs | 102 +++++++++++++++++++-------------------------- 2 files changed, 44 insertions(+), 61 deletions(-) diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 2efda1973..20c1c41a7 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -14,7 +14,6 @@ use super::{ ArrayBase, Storage, StorageMut, - ArrayMut, }; /// Access the element at **index**. @@ -37,7 +36,6 @@ impl Index for ArrayBase impl IndexMut for ArrayBase where D: Dimension, S: StorageMut, - ArrayBase: ArrayMut, { #[inline] fn index_mut(&mut self, index: D) -> &mut S::Elem { @@ -90,7 +88,6 @@ impl<'a, S, D> IntoIterator for &'a ArrayBase impl<'a, S, D> IntoIterator for &'a mut ArrayBase where D: Dimension, S: StorageMut, - ArrayBase: ArrayMut, { type Item = &'a mut S::Elem; type IntoIter = ElementsMut<'a, S::Elem, D>; diff --git a/src/lib.rs b/src/lib.rs index 1c4a17a85..1b2ba00fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,6 +145,10 @@ pub unsafe trait Storage { pub unsafe trait StorageMut : Storage { fn slice_mut(&mut self) -> &mut [Self::Elem]; + fn ensure_unique(&mut ArrayBase) + where Self: Sized, D: Dimension + { + } } unsafe impl Storage for Rc> { @@ -155,6 +159,27 @@ unsafe impl Storage for Rc> { // NOTE: Copy on write unsafe impl StorageMut for Rc> where A: Clone { fn slice_mut(&mut self) -> &mut [A] { &mut Rc::make_mut(self)[..] } + + fn ensure_unique(self_: &mut ArrayBase) + where Self: Sized, D: Dimension + { + if Rc::get_mut(&mut self_.data).is_some() { + return + } + if self_.dim.size() <= self_.data.len() / 2 { + unsafe { + *self_ = Array::from_vec_dim(self_.dim.clone(), + self_.iter().map(|x| x.clone()).collect()); + } + return; + } + let our_off = (self_.ptr as isize - self_.data.as_ptr() as isize) + / mem::size_of::() as isize; + let rvec = Rc::make_mut(&mut self_.data); + unsafe { + self_.ptr = rvec.as_mut_ptr().offset(our_off); + } + } } unsafe impl Storage for Vec { @@ -197,50 +222,6 @@ impl StorageNew for Rc> { fn new(elements: Vec) -> Self { Rc::new(elements) } } -pub trait ArrayMut { - fn ensure_unique(&mut self); -} - -impl ArrayMut for ArrayBase, D> - where D: Dimension, -{ - fn ensure_unique(&mut self) { } -} - -impl<'a, A, D> ArrayMut for ArrayBase<&'a mut [A], D> - where D: Dimension, -{ - fn ensure_unique(&mut self) { } -} - -impl ArrayMut for ArrayBase>, D> - where D: Dimension, - A: Clone, -{ - /// Make the array unshared. - /// - /// This method is mostly only useful with unsafe code. - fn ensure_unique(&mut self) - { - if Rc::get_mut(&mut self.data).is_some() { - return - } - if self.dim.size() <= self.data.len() / 2 { - unsafe { - *self = Array::from_vec_dim(self.dim.clone(), - self.iter().map(|x| x.clone()).collect()); - } - return; - } - let our_off = (self.ptr as isize - self.data.as_ptr() as isize) - / mem::size_of::() as isize; - let rvec = Rc::make_mut(&mut self.data); - unsafe { - self.ptr = rvec.as_mut_ptr().offset(our_off); - } - } -} - pub type Array = ArrayBase>, D>; pub type OwnedArray = ArrayBase, D>; @@ -406,8 +387,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Return a read-write view of the array pub fn view_mut(&mut self) -> ArrayViewMut - where Self: ArrayMut, - S: StorageMut, + where S: StorageMut, { self.ensure_unique(); ArrayViewMut { @@ -760,10 +740,19 @@ impl ArrayBase where S: Storage, D: Dimension } } + /// Make the array unshared. + /// + /// This method is mostly only useful with unsafe code. + fn ensure_unique(&mut self) + where S: StorageMut + { + S::ensure_unique(self); + } + /// Return a mutable reference to the element at **index**, or return **None** /// if the index is out of bounds. pub fn at_mut<'a>(&'a mut self, index: D) -> Option<&'a mut A> - where Self: ArrayMut, + where S: StorageMut, { self.ensure_unique(); self.dim.stride_offset_checked(&self.strides, &index) @@ -776,7 +765,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// Iterator element type is **&'a mut A**. pub fn iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, D> - where Self: ArrayMut, + where S: StorageMut, { self.ensure_unique(); ElementsMut { inner: self.base_iter() } @@ -786,7 +775,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// Iterator element type is **(D, &'a mut A)**. pub fn indexed_iter_mut<'a>(&'a mut self) -> Indexed> - where Self: ArrayMut, + where S: StorageMut, { self.iter_mut().indexed() } @@ -798,7 +787,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// **Panics** if **indexes** does not match the number of array axes. pub fn slice_iter_mut<'a>(&'a mut self, indexes: &[Si]) -> ElementsMut<'a, A, D> - where Self: ArrayMut, + where S: StorageMut, { let mut it = self.iter_mut(); let offset = Dimension::do_slices(&mut it.inner.dim, &mut it.inner.strides, indexes); @@ -816,7 +805,7 @@ impl ArrayBase where S: Storage, D: Dimension /// **Panics** if **axis** or **index** is out of bounds. pub fn sub_iter_mut<'a>(&'a mut self, axis: usize, index: Ix) -> ElementsMut<'a, A, D> - where Self: ArrayMut, + where S: StorageMut, { let mut it = self.iter_mut(); dimension::do_sub(&mut it.inner.dim, &mut it.inner.ptr, &it.inner.strides, axis, index); @@ -825,7 +814,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Return an iterator over the diagonal elements of the array. pub fn diag_iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, Ix> - where Self: ArrayMut, + where S: StorageMut, { self.ensure_unique(); let (len, stride) = self.diag_params(); @@ -845,7 +834,7 @@ impl ArrayBase where S: Storage, D: Dimension /// **Note:** The data is uniquely held and nonaliased /// while it is mutably borrowed. pub fn raw_data_mut<'a>(&'a mut self) -> &'a mut [A] - where Self: ArrayMut, S: StorageMut + where S: StorageMut, { self.ensure_unique(); self.data.slice_mut() @@ -896,7 +885,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// **Panics** if broadcasting isn't possible. pub fn assign(&mut self, other: &ArrayBase) - where Self: ArrayMut, + where S: StorageMut, A: Clone, S2: Storage, { @@ -914,7 +903,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Perform an elementwise assigment to **self** from scalar **x**. pub fn assign_scalar(&mut self, x: &A) - where Self: ArrayMut, S: StorageMut, A: Clone, + where S: StorageMut, A: Clone, { for elt in self.raw_data_mut().iter_mut() { *elt = x.clone(); @@ -1255,7 +1244,6 @@ macro_rules! impl_binary_op( ($trt:ident, $mth:ident, $imethod:ident, $imth_scalar:ident) => ( impl ArrayBase where A: Clone + $trt, - ArrayBase: ArrayMut, S: StorageMut, D: Dimension, { @@ -1300,7 +1288,6 @@ impl ArrayBase where impl<'a, A, S, S2, D, E> $trt> for ArrayBase where A: Clone + $trt, S: StorageMut, - ArrayBase: ArrayMut, S2: Storage, D: Dimension, E: Dimension, @@ -1399,7 +1386,6 @@ mod assign_ops { impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for ArrayBase where A: Clone + $trt, S: StorageMut, - ArrayBase: ArrayMut, S2: Storage, D: Dimension, E: Dimension, From 4f0a8a7306f6c71d6384591b81036e71ec2a6764 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 21/43] impl IntoIterator for the array views --- src/arraytraits.rs | 24 ++++++++++++++++++++++++ src/lib.rs | 19 +++++++++++++++++-- tests/array.rs | 8 ++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 20c1c41a7..ea91fce43 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -12,6 +12,8 @@ use std::ops::{ use super::{ Array, Dimension, Ix, Elements, ElementsMut, ArrayBase, + ArrayView, + ArrayViewMut, Storage, StorageMut, }; @@ -98,6 +100,28 @@ impl<'a, S, D> IntoIterator for &'a mut ArrayBase } } +impl<'a, A, D> IntoIterator for ArrayView<'a, A, D> + where D: Dimension, +{ + type Item = &'a A; + type IntoIter = Elements<'a, A, D>; + + fn into_iter(self) -> Self::IntoIter { + self.into_iter_() + } +} + +impl<'a, A, D> IntoIterator for ArrayViewMut<'a, A, D> + where D: Dimension, +{ + type Item = &'a mut A; + type IntoIter = ElementsMut<'a, A, D>; + + fn into_iter(self) -> Self::IntoIter { + self.into_iter_() + } +} + impl<'a, S, D> hash::Hash for ArrayBase where D: Dimension, S: Storage, diff --git a/src/lib.rs b/src/lib.rs index 1b2ba00fa..3d816e99c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -341,11 +341,26 @@ impl<'a, A, D> ArrayView<'a, A, D> } } - fn into_iter(self) -> Elements<'a, A, D> { + fn into_iter_(self) -> Elements<'a, A, D> { Elements { inner: self.into_base_iter() } } } +impl<'a, A, D> ArrayViewMut<'a, A, D> + where D: Dimension, +{ + #[inline] + fn into_base_iter(self) -> Baseiter<'a, A, D> { + unsafe { + Baseiter::new(self.ptr, self.dim.clone(), self.strides.clone()) + } + } + + fn into_iter_(self) -> ElementsMut<'a, A, D> { + ElementsMut { inner: self.into_base_iter() } + } +} + impl ArrayBase where S: Storage, D: Dimension { /// Return the total number of elements in the Array. @@ -608,7 +623,7 @@ impl ArrayBase where S: Storage, D: Dimension pub fn broadcast_iter<'a, E: Dimension>(&'a self, dim: E) -> Option> { - self.broadcast(dim).map(|v| v.into_iter()) + self.broadcast(dim).map(|v| v.into_iter_()) } #[inline(never)] diff --git a/tests/array.rs b/tests/array.rs index abe60accd..5f9daca35 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -391,6 +391,9 @@ fn views() { assert_eq!(a.clone() + b, &b + &b); a.clone()[(0, 0)] = 99; assert_eq!(b[(0, 0)], 1); + + assert_eq!(a.view().into_iter().cloned().collect::>(), + vec![1, 2, 3, 4]); } #[test] @@ -405,6 +408,11 @@ fn view_mut() { b[(0, 0)] = 7; } assert_eq!(a[(0, 0)], 7); + + for elt in a.view_mut() { + *elt = 2; + } + assert_eq!(a, Array::from_elem((2, 2), 2)); } #[cfg(feature = "assign_ops")] From 43867d4e152c457cd887f3284ca52ed77f0f01ab Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 22/43] Update docs --- src/lib.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3d816e99c..f9e51a147 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,11 +3,17 @@ //! The **ndarray** crate provides an n-dimensional container similar to numpy's ndarray. //! -//! - `ArrayBase` -//! - `Array` -//! - `OwnedArray` -//! - `ArrayView` -//! - `ArrayViewMut` +//! - [`ArrayBase`](struct.ArrayBase.html)
+//! The n-dimensional array type itself, parameterized by data storage. +//! - `Array`
+//! Array where the data is reference counted and copy on write, it +//! can act as both an owner as the data as well as a lightweight view. +//! - `OwnedArray`
+//! Array where the data is owned uniquely. +//! - `ArrayView`
+//! A lightweight immutable array view. +//! - `ArrayViewMut`
+//! A lightweight read-write array view. //! //! ## Crate Summary and Status //! @@ -15,6 +21,7 @@ //! - `Array` is clone on write, so it can be both a view or an owner of the //! data. //! - Striding and broadcasting is fully implemented +//! - Focus is on being a generic n-dimensional container //! - Due to iterators, arithmetic operations, matrix multiplication etc //! are not very well optimized, this is not a serious crate for numerics //! or linear algebra. `Array` is a good container. From 4bb1ba90dca71147e21f55ff2a81a68a678d6f58 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 23/43] Update docs --- src/lib.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f9e51a147..1500b94e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ //! - `OwnedArray`
//! Array where the data is owned uniquely. //! - `ArrayView`
-//! A lightweight immutable array view. +//! A lightweight array view. //! - `ArrayViewMut`
//! A lightweight read-write array view. //! @@ -145,11 +145,13 @@ pub struct ArrayBase where S: Storage { strides: D, } +/// Array's inner representation. pub unsafe trait Storage { type Elem; fn slice(&self) -> &[Self::Elem]; } +/// Array's writable inner representation. pub unsafe trait StorageMut : Storage { fn slice_mut(&mut self) -> &mut [Self::Elem]; fn ensure_unique(&mut ArrayBase) @@ -212,28 +214,36 @@ unsafe impl<'a, A> StorageMut for &'a mut [A] { fn slice_mut(&mut self) -> &mut [A] { self } } -pub trait StorageNew : Storage { +/// Array representation that is a unique or shared owner of its data. +pub trait OwnedStorage : Storage { fn new(elements: Vec) -> Self; } +/// Array representation that is a lightweight view. pub trait Shared : Clone { } impl
Shared for Rc> { } impl<'a, A> Shared for &'a [A] { } -impl StorageNew for Vec { +impl OwnedStorage for Vec { fn new(elements: Vec) -> Self { elements } } -impl StorageNew for Rc> { +impl OwnedStorage for Rc> { fn new(elements: Vec) -> Self { Rc::new(elements) } } +/// Array where the data is reference counted and copy on write, it +/// can act as both an owner as the data as well as a lightweight view. pub type Array = ArrayBase>, D>; + +/// Array where the data is owned uniquely. pub type OwnedArray = ArrayBase, D>; +/// A lightweight array view. pub type ArrayView<'a, A, D> = ArrayBase<&'a [A], D>; +/// A lightweight read-write array view. pub type ArrayViewMut<'a, A, D> = ArrayBase<&'a mut [A], D>; impl Clone for ArrayBase @@ -251,7 +261,7 @@ impl Clone for ArrayBase impl Copy for ArrayBase { } impl ArrayBase - where S: StorageNew, + where S: OwnedStorage, { /// Create a one-dimensional array from a vector (no allocation needed). pub fn from_vec(v: Vec) -> Self { @@ -280,7 +290,7 @@ impl Array } impl ArrayBase - where S: StorageNew, + where S: OwnedStorage, D: Dimension, { /// Create an array from a vector (with no allocation needed). @@ -291,7 +301,7 @@ impl ArrayBase debug_assert!(dim.size() == v.len()); ArrayBase { ptr: v.as_mut_ptr(), - data: StorageNew::new(v), + data: OwnedStorage::new(v), strides: dim.default_strides(), dim: dim } @@ -719,7 +729,7 @@ impl ArrayBase where S: Storage, D: Dimension pub fn map<'a, S2, F>(&'a self, mut f: F) -> ArrayBase where F: FnMut(&'a A) -> S2::Elem, A: 'a, - S2: StorageNew, + S2: OwnedStorage, { let mut res = Vec::with_capacity(self.dim.size()); for elt in self.iter() { @@ -878,7 +888,7 @@ impl ArrayBase where S: Storage, D: Dimension /// ); /// ``` pub fn reshape(&self, shape: E) -> ArrayBase - where S: Shared + StorageNew, A: Clone, + where S: Shared + OwnedStorage, A: Clone, { if shape.size() != self.dim.size() { panic!("Incompatible sizes in reshape, attempted from: {:?}, to: {:?}", From 9491c87ec1af363716bc7529aea6f009b1ee187d Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 24/43] Make Shared require Storage --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1500b94e8..cb5b2cc22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -220,7 +220,7 @@ pub trait OwnedStorage : Storage { } /// Array representation that is a lightweight view. -pub trait Shared : Clone { } +pub trait Shared : Clone + Storage { } impl Shared for Rc> { } impl<'a, A> Shared for &'a [A] { } From e7f91e77755805af66332b52d1eb88db792ec2be Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 25/43] Add aview1 and aview2 to create array views --- src/lib.rs | 61 ++++++++++++++++++++++++++++++++++++++++---------- tests/array.rs | 10 +++++++++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cb5b2cc22..5ecc971a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -957,26 +957,62 @@ pub fn arr1(xs: &[A]) -> Array Array::from_vec(xs.to_vec()) } +/// Return a one-dimensional array view with elements borrowing **xs**. +pub fn aview1(xs: &[A]) -> ArrayView { + ArrayView { + data: xs, + ptr: xs.as_ptr() as *mut _, + dim: xs.len() as Ix, + strides: 1, + } +} + +/// Return a two-dimensional array view with elements borrowing **xs**. +pub fn aview2>(xs: &[V]) -> ArrayView { + let cols = V::len(); + let rows = xs.len(); + let data = unsafe { + std::slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows) + }; + let dim = (rows as Ix, cols as Ix); + ArrayView { + data: data, + ptr: data.as_ptr() as *mut _, + strides: dim.default_strides(), + dim: dim, + } +} + /// Slice or fixed-size array used for array initialization -pub unsafe trait ArrInit { - fn as_init_slice(&self) -> &[T]; +pub unsafe trait Initializer { + type Elem; + fn as_init_slice(&self) -> &[Self::Elem]; fn is_fixed_size() -> bool { false } } -unsafe impl ArrInit for [T] -{ - fn as_init_slice(&self) -> &[T] - { +/// Fixed-size array used for array initialization +pub unsafe trait FixedInitializer: Initializer { + fn len() -> usize; +} + +unsafe impl Initializer for [T] { + type Elem = T; + fn as_init_slice(&self) -> &[T] { self } } macro_rules! impl_arr_init { (__impl $n: expr) => ( - unsafe impl ArrInit for [T; $n] { + unsafe impl Initializer for [T; $n] { + type Elem = T; fn as_init_slice(&self) -> &[T] { self } fn is_fixed_size() -> bool { true } } + + unsafe impl FixedInitializer for [T; $n] { + fn len() -> usize { $n } + } ); () => (); ($n: expr, $($m:expr,)*) => ( @@ -1001,7 +1037,7 @@ impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,); /// a.shape() == [2, 3] /// ); /// ``` -pub fn arr2>(xs: &[V]) -> Array +pub fn arr2>(xs: &[V]) -> Array { // FIXME: Simplify this when V is fix size array let (m, n) = (xs.len() as Ix, @@ -1010,7 +1046,7 @@ pub fn arr2>(xs: &[V]) -> Array let mut result = Vec::::with_capacity(dim.size()); for snd in xs.iter() { let snd = snd.as_init_slice(); - assert!(>::is_fixed_size() || snd.len() as Ix == n); + assert!(::is_fixed_size() || snd.len() as Ix == n); result.extend(snd.iter().map(|x| x.clone())) } unsafe { @@ -1035,7 +1071,8 @@ pub fn arr2>(xs: &[V]) -> Array /// a.shape() == [3, 2, 2] /// ); /// ``` -pub fn arr3, U: ArrInit>(xs: &[V]) -> Array +pub fn arr3, U: Initializer>(xs: &[V]) + -> Array { // FIXME: Simplify this when U/V are fix size arrays let m = xs.len() as Ix; @@ -1047,10 +1084,10 @@ pub fn arr3, U: ArrInit>(xs: &[V]) -> Array::with_capacity(dim.size()); for snd in xs.iter() { let snd = snd.as_init_slice(); - assert!(>::is_fixed_size() || snd.len() as Ix == n); + assert!(::is_fixed_size() || snd.len() as Ix == n); for thr in snd.iter() { let thr = thr.as_init_slice(); - assert!(>::is_fixed_size() || thr.len() as Ix == o); + assert!(::is_fixed_size() || thr.len() as Ix == o); result.extend(thr.iter().map(|x| x.clone())) } } diff --git a/tests/array.rs b/tests/array.rs index 5f9daca35..38305d676 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -7,6 +7,7 @@ use ndarray::{Array, S, Si, OwnedArray, }; use ndarray::{arr0, arr1, arr2}; +use ndarray::{aview2}; use ndarray::Indexes; use ndarray::SliceRange; @@ -428,3 +429,12 @@ fn assign_ops() a -= &b; assert_eq!(a, arr2(&[[0., -1.,], [1., 0.]])); } + +#[test] +fn aview() { + let a = arr2(&[[1., 2., 3.], [4., 5., 6.]]); + let data = [[1., 2., 3.], [4., 5., 6.]]; + let b = aview2(&data); + assert_eq!(a, b); + assert_eq!(b.shape(), &[2, 3]); +} From 07f121cfd98723a8ec5ea6a8a92b4cdc76c8f5c2 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 26/43] Add StorageClone to fix Clone for ArrayBase --- src/lib.rs | 54 ++++++++++++++++++++++++++++++++++++++++++-------- tests/array.rs | 2 +- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5ecc971a8..c1d259346 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,6 +160,12 @@ pub unsafe trait StorageMut : Storage { } } +/// Clone an Array's storage. +pub unsafe trait StorageClone : Storage { + /// Unsafe because, `ptr` must point inside the current storage. + unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem); +} + unsafe impl Storage for Rc> { type Elem = A; fn slice(&self) -> &[A] { self } @@ -191,6 +197,15 @@ unsafe impl StorageMut for Rc> where A: Clone { } } +unsafe impl StorageClone for Rc> { + unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) + -> (Self, *mut Self::Elem) + { + // pointer is preserved + (self.clone(), ptr) + } +} + unsafe impl Storage for Vec { type Elem = A; fn slice(&self) -> &[A] { self } @@ -200,11 +215,31 @@ unsafe impl StorageMut for Vec { fn slice_mut(&mut self) -> &mut [A] { self } } +unsafe impl StorageClone for Vec where A: Clone { + unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) + -> (Self, *mut Self::Elem) + { + let mut u = self.clone(); + let our_off = (self.as_ptr() as isize - ptr as isize) + / mem::size_of::() as isize; + let new_ptr = u.as_mut_ptr().offset(our_off); + (u, new_ptr) + } +} + unsafe impl<'a, A> Storage for &'a [A] { type Elem = A; fn slice(&self) -> &[A] { self } } +unsafe impl<'a, A> StorageClone for &'a [A] { + unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) + -> (Self, *mut Self::Elem) + { + (*self, ptr) + } +} + unsafe impl<'a, A> Storage for &'a mut [A] { type Elem = A; fn slice(&self) -> &[A] { self } @@ -220,7 +255,7 @@ pub trait OwnedStorage : Storage { } /// Array representation that is a lightweight view. -pub trait Shared : Clone + Storage { } +pub trait Shared : Clone + StorageClone { } impl Shared for Rc> { } impl<'a, A> Shared for &'a [A] { } @@ -246,19 +281,22 @@ pub type ArrayView<'a, A, D> = ArrayBase<&'a [A], D>; /// A lightweight read-write array view. pub type ArrayViewMut<'a, A, D> = ArrayBase<&'a mut [A], D>; -impl Clone for ArrayBase +impl Clone for ArrayBase { fn clone(&self) -> ArrayBase { - ArrayBase { - data: self.data.clone(), - ptr: self.ptr, - dim: self.dim.clone(), - strides: self.strides.clone(), + unsafe { + let (data, ptr) = self.data.clone_with_ptr(self.ptr); + ArrayBase { + data: data, + ptr: ptr, + dim: self.dim.clone(), + strides: self.strides.clone(), + } } } } -impl Copy for ArrayBase { } +impl Copy for ArrayBase { } impl ArrayBase where S: OwnedStorage, diff --git a/tests/array.rs b/tests/array.rs index 38305d676..5ad16f83c 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -378,7 +378,7 @@ fn owned_array1() { let d1 = &a + &b; let d2 = a + b; - assert_eq!(c, d1); + assert!(c != d1); assert_eq!(d1, d2); } From 4234b7fb5e1ad43d9c9a4af273d44778b8ebc56f Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 27/43] Add ArrayBase::to_owned and make .sum() and .mean() generic --- src/lib.rs | 34 ++++++++++++++++++++++++---------- tests/array.rs | 7 +++++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c1d259346..449949d3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -468,6 +468,17 @@ impl ArrayBase where S: Storage, D: Dimension } } + /// Return an uniquely owned copy of the array or view + pub fn to_owned(&self) -> OwnedArray + where A: Clone + { + // FIXME: Use standard layout / more efficient copy? + let data = self.iter().cloned().collect(); + unsafe { + ArrayBase::from_vec_dim(self.dim.clone(), data) + } + } + /// Return a slice of the array's backing data in memory order. /// /// **Note:** Data memory order may not correspond to the index order @@ -1135,9 +1146,10 @@ pub fn arr3, U: Initializer>(xs: &[V]) } -impl Array where - A: Clone + Add, - D: RemoveAxis, +impl ArrayBase + where A: Clone + Add, + S: Storage, + D: RemoveAxis, { /// Return sum along **axis**. /// @@ -1155,20 +1167,22 @@ impl Array where /// ``` /// /// **Panics** if **axis** is out of bounds. - pub fn sum(&self, axis: usize) -> Array::Smaller> + pub fn sum(&self, axis: usize) -> OwnedArray::Smaller> { let n = self.shape()[axis]; - let mut res = self.subview(axis, 0); + let mut res = self.view().subview(axis, 0).to_owned(); for i in 1..n { - res.iadd(&self.subview(axis, i)) + let view = self.view().subview(axis, i); + res.iadd(&view); } res } } -impl Array where - A: Copy + linalg::Field, - D: RemoveAxis, +impl ArrayBase + where A: Copy + linalg::Field, + S: Storage, + D: RemoveAxis, { /// Return mean along **axis**. /// @@ -1185,7 +1199,7 @@ impl Array where /// /// /// **Panics** if **axis** is out of bounds. - pub fn mean(&self, axis: usize) -> Array::Smaller> + pub fn mean(&self, axis: usize) -> OwnedArray::Smaller> { let n = self.shape()[axis]; let mut sum = self.sum(axis); diff --git a/tests/array.rs b/tests/array.rs index 5ad16f83c..2a2d79df4 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -6,8 +6,10 @@ extern crate ndarray; use ndarray::{Array, S, Si, OwnedArray, }; -use ndarray::{arr0, arr1, arr2}; -use ndarray::{aview2}; +use ndarray::{arr0, arr1, arr2, + aview1, + aview2, +}; use ndarray::Indexes; use ndarray::SliceRange; @@ -267,6 +269,7 @@ fn sum_mean() assert_eq!(a.mean(0), arr1(&[2., 3.])); assert_eq!(a.mean(1), arr1(&[1.5, 3.5])); assert_eq!(a.sum(1).sum(0), arr0(10.)); + assert_eq!(a.view().mean(1), aview1(&[1.5, 3.5])); } #[test] From 11f3889984f87d5daac56082bbe74bd5ead2c3cb Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 21:26:51 +0100 Subject: [PATCH 28/43] Fix bug in assign_scalar --- src/lib.rs | 2 +- tests/array.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 449949d3d..66e7d222f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -986,7 +986,7 @@ impl ArrayBase where S: Storage, D: Dimension pub fn assign_scalar(&mut self, x: &A) where S: StorageMut, A: Clone, { - for elt in self.raw_data_mut().iter_mut() { + for elt in self.iter_mut() { *elt = x.clone(); } } diff --git a/tests/array.rs b/tests/array.rs index 2a2d79df4..29e78bf53 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -245,6 +245,15 @@ fn assign() /* Test other type */ a.assign(&OwnedArray::from_elem((2, 2), 3.)); assert_eq!(a, Array::from_elem((2, 2), 3.)); + + /* Test mut view */ + let mut a = arr2(&[[1, 2], [3, 4]]); + { + let mut v = a.view_mut(); + v.islice(&[Si(0, Some(1), 1), S]); + v.assign_scalar(&0); + } + assert_eq!(a, arr2(&[[0, 0], [3, 4]])); } #[test] From 959f2f4e49ca7f6566be8c4df82381b8f0bb34d9 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 29/43] Edit docs --- src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 66e7d222f..b0f172040 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,7 +115,7 @@ pub type Ixs = i32; /// Arrays support limited *broadcasting*, where arithmetic operations with /// array operands of different sizes can be carried out by repeating the /// elements of the smaller dimension array. See -/// [*.broadcast_iter()*](#method.broadcast_iter) for a more detailed +/// [`.broadcast()`](#method.broadcast) for a more detailed /// description. /// /// ``` @@ -600,7 +600,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// Return **None** if shapes can not be broadcast together. /// - /// ## Background + /// ***Background*** /// /// * Two axes are compatible if they are equal, or one of them is 1. /// * In this instance, only the axes of the smaller side (self) can be 1. @@ -611,10 +611,10 @@ impl ArrayBase where S: Storage, D: Dimension /// because its axes are either equal or 1 (or missing); /// while (2, 2) can *not* be broadcast into (2, 4). /// - /// The implementation creates an iterator with strides set to 0 for the + /// The implementation creates a view with strides set to zero for the /// axes that are to be repeated. /// - /// See broadcasting documentation for Numpy for more information. + /// The broadcasting documentation for Numpy has more information. /// /// ``` /// use ndarray::arr1; @@ -669,6 +669,7 @@ impl ArrayBase where S: Storage, D: Dimension Some(new_stride) } + // Note: zero strides are safe precisely because we return an read-only view let broadcast_strides = match upcast(&dim, &self.dim, &self.strides) { Some(st) => st, From 668662b2bedf08db0069633f437a2498bed4dd19 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 30/43] Rename all Storage traits to Data.* --- src/arrayformat.rs | 6 +-- src/arraytraits.rs | 24 +++++----- src/lib.rs | 112 ++++++++++++++++++++++----------------------- 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 522b1daec..55e1b1466 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -2,14 +2,14 @@ use std::fmt; use super::{Array, Dimension}; use super::{ ArrayBase, - Storage, + Data, }; fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, mut format: F) -> fmt::Result where F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result, D: Dimension, - S: Storage, + S: Data, { let ndim = view.dim.slice().len(); /* private nowadays @@ -87,7 +87,7 @@ impl<'a, A: fmt::Display, D: Dimension> fmt::Display for Array } impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase - where S: Storage, + where S: Data, { /// Format the array using `Debug` and apply the formatting parameters used /// to each element. diff --git a/src/arraytraits.rs b/src/arraytraits.rs index ea91fce43..c1815479d 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -14,8 +14,8 @@ use super::{ ArrayBase, ArrayView, ArrayViewMut, - Storage, - StorageMut, + Data, + DataMut, }; /// Access the element at **index**. @@ -23,7 +23,7 @@ use super::{ /// **Panics** if index is out of bounds. impl Index for ArrayBase where D: Dimension, - S: Storage, + S: Data, { type Output = S::Elem; #[inline] @@ -37,7 +37,7 @@ impl Index for ArrayBase /// **Panics** if index is out of bounds. impl IndexMut for ArrayBase where D: Dimension, - S: StorageMut, + S: DataMut, { #[inline] fn index_mut(&mut self, index: D) -> &mut S::Elem { @@ -48,8 +48,8 @@ impl IndexMut for ArrayBase impl PartialEq> for ArrayBase where D: Dimension, - S: Storage, - S2: Storage, + S: Data, + S2: Data, S::Elem: PartialEq, { /// Return `true` if the array shapes and all elements of `self` and @@ -63,7 +63,7 @@ impl PartialEq> for ArrayBase impl Eq for ArrayBase where D: Dimension, - S: Storage, + S: Data, S::Elem: Eq, { } @@ -77,7 +77,7 @@ impl FromIterator for Array impl<'a, S, D> IntoIterator for &'a ArrayBase where D: Dimension, - S: Storage, + S: Data, { type Item = &'a S::Elem; type IntoIter = Elements<'a, S::Elem, D>; @@ -89,7 +89,7 @@ impl<'a, S, D> IntoIterator for &'a ArrayBase impl<'a, S, D> IntoIterator for &'a mut ArrayBase where D: Dimension, - S: StorageMut, + S: DataMut, { type Item = &'a mut S::Elem; type IntoIter = ElementsMut<'a, S::Elem, D>; @@ -124,7 +124,7 @@ impl<'a, A, D> IntoIterator for ArrayViewMut<'a, A, D> impl<'a, S, D> hash::Hash for ArrayBase where D: Dimension, - S: Storage, + S: Data, S::Elem: hash::Hash, { fn hash(&self, state: &mut H) @@ -143,12 +143,12 @@ impl<'a, S, D> hash::Hash for ArrayBase /// `ArrayBase` is `Sync` when the storage type is. unsafe impl Sync for ArrayBase - where S: Sync + Storage, D: Sync + where S: Sync + Data, D: Sync { } /// `ArrayBase` is `Send` when the storage type is. unsafe impl Send for ArrayBase - where S: Send + Storage, D: Send + where S: Send + Data, D: Send { } diff --git a/src/lib.rs b/src/lib.rs index b0f172040..0211a21d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,7 +133,7 @@ pub type Ixs = i32; /// ); /// ``` /// -pub struct ArrayBase where S: Storage { +pub struct ArrayBase where S: Data { /// Rc data when used as view, Uniquely held data when being mutated data: S, /// A pointer into the buffer held by data, may point anywhere @@ -146,13 +146,13 @@ pub struct ArrayBase where S: Storage { } /// Array's inner representation. -pub unsafe trait Storage { +pub unsafe trait Data { type Elem; fn slice(&self) -> &[Self::Elem]; } /// Array's writable inner representation. -pub unsafe trait StorageMut : Storage { +pub unsafe trait DataMut : Data { fn slice_mut(&mut self) -> &mut [Self::Elem]; fn ensure_unique(&mut ArrayBase) where Self: Sized, D: Dimension @@ -161,18 +161,18 @@ pub unsafe trait StorageMut : Storage { } /// Clone an Array's storage. -pub unsafe trait StorageClone : Storage { +pub unsafe trait DataClone : Data { /// Unsafe because, `ptr` must point inside the current storage. unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem); } -unsafe impl Storage for Rc> { +unsafe impl Data for Rc> { type Elem = A; fn slice(&self) -> &[A] { self } } // NOTE: Copy on write -unsafe impl StorageMut for Rc> where A: Clone { +unsafe impl DataMut for Rc> where A: Clone { fn slice_mut(&mut self) -> &mut [A] { &mut Rc::make_mut(self)[..] } fn ensure_unique(self_: &mut ArrayBase) @@ -197,7 +197,7 @@ unsafe impl StorageMut for Rc> where A: Clone { } } -unsafe impl StorageClone for Rc> { +unsafe impl DataClone for Rc> { unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem) { @@ -206,16 +206,16 @@ unsafe impl StorageClone for Rc> { } } -unsafe impl Storage for Vec { +unsafe impl Data for Vec { type Elem = A; fn slice(&self) -> &[A] { self } } -unsafe impl StorageMut for Vec { +unsafe impl DataMut for Vec { fn slice_mut(&mut self) -> &mut [A] { self } } -unsafe impl StorageClone for Vec where A: Clone { +unsafe impl DataClone for Vec where A: Clone { unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem) { @@ -227,12 +227,12 @@ unsafe impl StorageClone for Vec where A: Clone { } } -unsafe impl<'a, A> Storage for &'a [A] { +unsafe impl<'a, A> Data for &'a [A] { type Elem = A; fn slice(&self) -> &[A] { self } } -unsafe impl<'a, A> StorageClone for &'a [A] { +unsafe impl<'a, A> DataClone for &'a [A] { unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem) { @@ -240,31 +240,31 @@ unsafe impl<'a, A> StorageClone for &'a [A] { } } -unsafe impl<'a, A> Storage for &'a mut [A] { +unsafe impl<'a, A> Data for &'a mut [A] { type Elem = A; fn slice(&self) -> &[A] { self } } -unsafe impl<'a, A> StorageMut for &'a mut [A] { +unsafe impl<'a, A> DataMut for &'a mut [A] { fn slice_mut(&mut self) -> &mut [A] { self } } /// Array representation that is a unique or shared owner of its data. -pub trait OwnedStorage : Storage { +pub trait DataOwned : Data { fn new(elements: Vec) -> Self; } /// Array representation that is a lightweight view. -pub trait Shared : Clone + StorageClone { } +pub trait DataShared : Clone + DataClone { } -impl Shared for Rc> { } -impl<'a, A> Shared for &'a [A] { } +impl DataShared for Rc> { } +impl<'a, A> DataShared for &'a [A] { } -impl OwnedStorage for Vec { +impl DataOwned for Vec { fn new(elements: Vec) -> Self { elements } } -impl OwnedStorage for Rc> { +impl DataOwned for Rc> { fn new(elements: Vec) -> Self { Rc::new(elements) } } @@ -281,7 +281,7 @@ pub type ArrayView<'a, A, D> = ArrayBase<&'a [A], D>; /// A lightweight read-write array view. pub type ArrayViewMut<'a, A, D> = ArrayBase<&'a mut [A], D>; -impl Clone for ArrayBase +impl Clone for ArrayBase { fn clone(&self) -> ArrayBase { unsafe { @@ -296,10 +296,10 @@ impl Clone for ArrayBase } } -impl Copy for ArrayBase { } +impl Copy for ArrayBase { } impl ArrayBase - where S: OwnedStorage, + where S: DataOwned, { /// Create a one-dimensional array from a vector (no allocation needed). pub fn from_vec(v: Vec) -> Self { @@ -328,7 +328,7 @@ impl Array } impl ArrayBase - where S: OwnedStorage, + where S: DataOwned, D: Dimension, { /// Create an array from a vector (with no allocation needed). @@ -339,7 +339,7 @@ impl ArrayBase debug_assert!(dim.size() == v.len()); ArrayBase { ptr: v.as_mut_ptr(), - data: OwnedStorage::new(v), + data: DataOwned::new(v), strides: dim.default_strides(), dim: dim } @@ -416,7 +416,7 @@ impl<'a, A, D> ArrayViewMut<'a, A, D> } } -impl ArrayBase where S: Storage, D: Dimension +impl ArrayBase where S: Data, D: Dimension { /// Return the total number of elements in the Array. pub fn len(&self) -> usize @@ -457,7 +457,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Return a read-write view of the array pub fn view_mut(&mut self) -> ArrayViewMut - where S: StorageMut, + where S: DataMut, { self.ensure_unique(); ArrayViewMut { @@ -493,7 +493,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// **Panics** if **indexes** does not match the number of array axes. pub fn slice(&self, indexes: &[Si]) -> Self - where S: Shared + where S: DataShared { let mut arr = self.clone(); arr.islice(indexes); @@ -553,7 +553,7 @@ impl ArrayBase where S: Storage, D: Dimension /// **Note:** The array must be uniquely held when mutating it. #[inline] pub unsafe fn uchk_at_mut(&mut self, index: D) -> &mut A - where S: StorageMut + where S: DataMut { //debug_assert!(Rc::get_mut(&mut self.data).is_some()); debug_assert!(self.dim.stride_offset_checked(&self.strides, &index).is_some()); @@ -750,7 +750,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Return the diagonal as a one-dimensional array. pub fn diag(&self) -> ArrayBase - where S: Shared, + where S: DataShared, { let (len, stride) = self.diag_params(); ArrayBase { @@ -779,7 +779,7 @@ impl ArrayBase where S: Storage, D: Dimension pub fn map<'a, S2, F>(&'a self, mut f: F) -> ArrayBase where F: FnMut(&'a A) -> S2::Elem, A: 'a, - S2: OwnedStorage, + S2: DataOwned, { let mut res = Vec::with_capacity(self.dim.size()); for elt in self.iter() { @@ -808,7 +808,7 @@ impl ArrayBase where S: Storage, D: Dimension /// ``` pub fn subview(&self, axis: usize, index: Ix) -> ArrayBase::Smaller> where D: RemoveAxis, - S: Shared, + S: DataShared, { let mut res = self.clone(); res.isubview(axis, index); @@ -826,7 +826,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// This method is mostly only useful with unsafe code. fn ensure_unique(&mut self) - where S: StorageMut + where S: DataMut { S::ensure_unique(self); } @@ -834,7 +834,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Return a mutable reference to the element at **index**, or return **None** /// if the index is out of bounds. pub fn at_mut<'a>(&'a mut self, index: D) -> Option<&'a mut A> - where S: StorageMut, + where S: DataMut, { self.ensure_unique(); self.dim.stride_offset_checked(&self.strides, &index) @@ -847,7 +847,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// Iterator element type is **&'a mut A**. pub fn iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, D> - where S: StorageMut, + where S: DataMut, { self.ensure_unique(); ElementsMut { inner: self.base_iter() } @@ -857,7 +857,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// Iterator element type is **(D, &'a mut A)**. pub fn indexed_iter_mut<'a>(&'a mut self) -> Indexed> - where S: StorageMut, + where S: DataMut, { self.iter_mut().indexed() } @@ -869,7 +869,7 @@ impl ArrayBase where S: Storage, D: Dimension /// /// **Panics** if **indexes** does not match the number of array axes. pub fn slice_iter_mut<'a>(&'a mut self, indexes: &[Si]) -> ElementsMut<'a, A, D> - where S: StorageMut, + where S: DataMut, { let mut it = self.iter_mut(); let offset = Dimension::do_slices(&mut it.inner.dim, &mut it.inner.strides, indexes); @@ -887,7 +887,7 @@ impl ArrayBase where S: Storage, D: Dimension /// **Panics** if **axis** or **index** is out of bounds. pub fn sub_iter_mut<'a>(&'a mut self, axis: usize, index: Ix) -> ElementsMut<'a, A, D> - where S: StorageMut, + where S: DataMut, { let mut it = self.iter_mut(); dimension::do_sub(&mut it.inner.dim, &mut it.inner.ptr, &it.inner.strides, axis, index); @@ -896,7 +896,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Return an iterator over the diagonal elements of the array. pub fn diag_iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, Ix> - where S: StorageMut, + where S: DataMut, { self.ensure_unique(); let (len, stride) = self.diag_params(); @@ -916,7 +916,7 @@ impl ArrayBase where S: Storage, D: Dimension /// **Note:** The data is uniquely held and nonaliased /// while it is mutably borrowed. pub fn raw_data_mut<'a>(&'a mut self) -> &'a mut [A] - where S: StorageMut, + where S: DataMut, { self.ensure_unique(); self.data.slice_mut() @@ -938,7 +938,7 @@ impl ArrayBase where S: Storage, D: Dimension /// ); /// ``` pub fn reshape(&self, shape: E) -> ArrayBase - where S: Shared + OwnedStorage, A: Clone, + where S: DataShared + DataOwned, A: Clone, { if shape.size() != self.dim.size() { panic!("Incompatible sizes in reshape, attempted from: {:?}, to: {:?}", @@ -967,9 +967,9 @@ impl ArrayBase where S: Storage, D: Dimension /// /// **Panics** if broadcasting isn't possible. pub fn assign(&mut self, other: &ArrayBase) - where S: StorageMut, + where S: DataMut, A: Clone, - S2: Storage, + S2: Data, { if self.shape() == other.shape() { for (x, y) in self.iter_mut().zip(other.iter()) { @@ -985,7 +985,7 @@ impl ArrayBase where S: Storage, D: Dimension /// Perform an elementwise assigment to **self** from scalar **x**. pub fn assign_scalar(&mut self, x: &A) - where S: StorageMut, A: Clone, + where S: DataMut, A: Clone, { for elt in self.iter_mut() { *elt = x.clone(); @@ -1149,7 +1149,7 @@ pub fn arr3, U: Initializer>(xs: &[V]) impl ArrayBase where A: Clone + Add, - S: Storage, + S: Data, D: RemoveAxis, { /// Return sum along **axis**. @@ -1182,7 +1182,7 @@ impl ArrayBase impl ArrayBase where A: Copy + linalg::Field, - S: Storage, + S: Data, D: RemoveAxis, { /// Return mean along **axis**. @@ -1217,7 +1217,7 @@ impl ArrayBase } impl ArrayBase - where S: Storage, + where S: Data, { /// Return an iterator over the elements of row **index**. /// @@ -1254,7 +1254,7 @@ impl ArrayBase // Matrix multiplication only defined for simple types to // avoid trouble with failing + and *, and destructors impl<'a, A: Copy + linalg::Ring, S> ArrayBase - where S: Storage, + where S: Data, { /// Perform matrix multiplication of rectangular arrays **self** and **other**. /// @@ -1366,7 +1366,7 @@ macro_rules! impl_binary_op( ($trt:ident, $mth:ident, $imethod:ident, $imth_scalar:ident) => ( impl ArrayBase where A: Clone + $trt, - S: StorageMut, + S: DataMut, D: Dimension, { /// Perform an elementwise arithmetic operation between **self** and **other**, @@ -1376,7 +1376,7 @@ impl ArrayBase where /// /// **Panics** if broadcasting isn't possible. pub fn $imethod (&mut self, other: &ArrayBase) - where S2: Storage, + where S2: Data, { if self.dim.ndim() == other.dim.ndim() && self.shape() == other.shape() { @@ -1409,8 +1409,8 @@ impl ArrayBase where /// **Panics** if broadcasting isn't possible. impl<'a, A, S, S2, D, E> $trt> for ArrayBase where A: Clone + $trt, - S: StorageMut, - S2: Storage, + S: DataMut, + S2: Data, D: Dimension, E: Dimension, { @@ -1440,8 +1440,8 @@ impl<'a, A, S, S2, D, E> $trt> for ArrayBase /// **Panics** if broadcasting isn't possible. impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for &'a ArrayBase where A: Clone + $trt, - S: Storage, - S2: Storage, + S: Data, + S2: Data, D: Dimension, E: Dimension, { @@ -1507,8 +1507,8 @@ mod assign_ops { /// **Requires `feature = "assign_ops"`** impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for ArrayBase where A: Clone + $trt, - S: StorageMut, - S2: Storage, + S: DataMut, + S2: Data, D: Dimension, E: Dimension, { From 9fe4dc75977afccc069768bc466f21074c5c0540 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 31/43] Mark DataOwned unsafe too --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0211a21d6..9beff0860 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ unsafe impl<'a, A> DataMut for &'a mut [A] { } /// Array representation that is a unique or shared owner of its data. -pub trait DataOwned : Data { +pub unsafe trait DataOwned : Data { fn new(elements: Vec) -> Self; } @@ -260,11 +260,11 @@ pub trait DataShared : Clone + DataClone { } impl DataShared for Rc> { } impl<'a, A> DataShared for &'a [A] { } -impl DataOwned for Vec { +unsafe impl DataOwned for Vec { fn new(elements: Vec) -> Self { elements } } -impl DataOwned for Rc> { +unsafe impl DataOwned for Rc> { fn new(elements: Vec) -> Self { Rc::new(elements) } } From 8a9be9fcf2dc31905788410ef7ac952b6ab30209 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 32/43] Add .subview_mut() --- src/lib.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 9beff0860..2311fcda8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -879,6 +879,38 @@ impl ArrayBase where S: Data, D: Dimension it } + /// Select the subview **index** along **axis** and return a read-write view. + /// + /// **Panics** if **axis** or **index** is out of bounds. + /// + /// ``` + /// use ndarray::{arr2, aview2}; + /// + /// let mut a = arr2(&[[1., 2.], + /// [3., 4.]]); + /// + /// a.subview_mut(1, 1).iadd_scalar(&10.); + /// + /// assert!( + /// a == aview2(&[[1., 12.], + /// [3., 14.]]) + /// ); + /// ``` + pub fn subview_mut(&mut self, axis: usize, index: Ix) + -> ArrayViewMut + where S: DataMut, + D: RemoveAxis, + { + let mut res = self.view_mut(); + res.isubview(axis, index); + ArrayBase { + data: res.data, + ptr: res.ptr, + dim: res.dim.remove_axis(axis), + strides: res.strides.remove_axis(axis), + } + } + /// Select the subview **index** along **axis** and return an iterator /// of the subview. /// From f550edccbdc25b1b55a275c81901e14f53e14145 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 33/43] Add aview0 and adjust docs --- src/lib.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2311fcda8..4f8e60016 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1039,6 +1039,19 @@ pub fn arr1(xs: &[A]) -> Array Array::from_vec(xs.to_vec()) } +/// Return a zero-dimensional array view borrowing `x`. +pub fn aview0(x: &A) -> ArrayView { + let data = unsafe { + std::slice::from_raw_parts(x, 1) + }; + ArrayView { + data: data, + ptr: data.as_ptr() as *mut _, + dim: (), + strides: (), + } +} + /// Return a one-dimensional array view with elements borrowing **xs**. pub fn aview1(xs: &[A]) -> ArrayView { ArrayView { @@ -1187,15 +1200,15 @@ impl ArrayBase /// Return sum along **axis**. /// /// ``` - /// use ndarray::{arr0, arr1, arr2}; + /// use ndarray::{aview0, aview1, arr2}; /// /// let a = arr2(&[[1., 2.], /// [3., 4.]]); /// assert!( - /// a.sum(0) == arr1(&[4., 6.]) && - /// a.sum(1) == arr1(&[3., 7.]) && + /// a.sum(0) == aview1(&[4., 6.]) && + /// a.sum(1) == aview1(&[3., 7.]) && /// - /// a.sum(0).sum(0) == arr0(10.) + /// a.sum(0).sum(0) == aview0(&10.) /// ); /// ``` /// @@ -1220,13 +1233,13 @@ impl ArrayBase /// Return mean along **axis**. /// /// ``` - /// use ndarray::{arr1, arr2}; + /// use ndarray::{aview1, arr2}; /// /// let a = arr2(&[[1., 2.], /// [3., 4.]]); /// assert!( - /// a.mean(0) == arr1(&[2.0, 3.0]) && - /// a.mean(1) == arr1(&[1.5, 3.5]) + /// a.mean(0) == aview1(&[2.0, 3.0]) && + /// a.mean(1) == aview1(&[1.5, 3.5]) /// ); /// ``` /// From e2935bdf01cbe9a0a556fd82ba9e29f19e461cbe Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 34/43] Add .slice_mut() --- src/lib.rs | 11 +++++++++++ tests/array.rs | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 4f8e60016..7adf30ed5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -862,6 +862,17 @@ impl ArrayBase where S: Data, D: Dimension self.iter_mut().indexed() } + /// Return a sliced read-write view of the array. + /// + /// **Panics** if **indexes** does not match the number of array axes. + pub fn slice_mut(&mut self, indexes: &[Si]) -> ArrayViewMut + where S: DataMut + { + let mut arr = self.view_mut(); + arr.islice(indexes); + arr + } + /// Return an iterator of mutable references into the sliced view /// of the array. /// diff --git a/tests/array.rs b/tests/array.rs index 29e78bf53..cbe305129 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -428,6 +428,31 @@ fn view_mut() { assert_eq!(a, Array::from_elem((2, 2), 2)); } +#[test] +fn slice_mut() { + let mut a = Array::from_vec(vec![1, 2, 3, 4]).reshape((2, 2)); + for elt in a.slice_mut(&[S, S]) { + *elt = 0; + } + assert_eq!(a, aview2(&[[0, 0], [0, 0]])); + + let mut b = arr2(&[[1, 2, 3], + [4, 5, 6]]); + let c = b.clone(); // make sure we can mutate b even if it has to be unshared first + for elt in b.slice_mut(&[S, Si(0, Some(1), 1)]) { + *elt = 0; + } + assert_eq!(b, aview2(&[[0, 2, 3], + [0, 5, 6]])); + assert!(c != b); + + for elt in b.slice_mut(&[S, Si(0, None, 2)]) { + *elt = 99; + } + assert_eq!(b, aview2(&[[99, 2, 99], + [99, 5, 99]])); +} + #[cfg(feature = "assign_ops")] #[test] fn assign_ops() From a22edc004a5e636c61c0c9a3b9044e0ea7d5a97f Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 35/43] Remove explicit lifetime parameters where lifetime elision is already equivalent --- src/lib.rs | 62 +++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7adf30ed5..46aff6405 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -484,7 +484,7 @@ impl ArrayBase where S: Data, D: Dimension /// **Note:** Data memory order may not correspond to the index order /// of the array. Neither is the raw data slice is restricted to just the /// Array's view. - pub fn raw_data<'a>(&'a self) -> &'a [A] + pub fn raw_data(&self) -> &[A] { self.data.slice() } @@ -514,7 +514,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator over a sliced view. /// /// **Panics** if **indexes** does not match the number of array axes. - pub fn slice_iter<'a>(&'a self, indexes: &[Si]) -> Elements<'a, A, D> + pub fn slice_iter(&self, indexes: &[Si]) -> Elements { let mut it = self.iter(); let offset = Dimension::do_slices(&mut it.inner.dim, &mut it.inner.strides, indexes); @@ -526,7 +526,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return a reference to the element at **index**, or return **None** /// if the index is out of bounds. - pub fn at<'a>(&'a self, index: D) -> Option<&'a A> { + pub fn at(&self, index: D) -> Option<&A> { self.dim.stride_offset_checked(&self.strides, &index) .map(|offset| unsafe { &*self.ptr.offset(offset) @@ -539,7 +539,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Note:** only unchecked for non-debug builds of ndarray. #[inline] - pub unsafe fn uchk_at<'a>(&'a self, index: D) -> &'a A { + pub unsafe fn uchk_at(&self, index: D) -> &A { debug_assert!(self.dim.stride_offset_checked(&self.strides, &index).is_some()); let off = Dimension::stride_offset(&index, &self.strides); &*self.ptr.offset(off) @@ -572,16 +572,16 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of references to the elements of the array. /// - /// Iterator element type is **&'a A**. - pub fn iter<'a>(&'a self) -> Elements<'a, A, D> + /// Iterator element type is **&A**. + pub fn iter(&self) -> Elements { Elements { inner: self.base_iter() } } /// Return an iterator of references to the elements of the array. /// - /// Iterator element type is **(D, &'a A)**. - pub fn indexed_iter<'a>(&'a self) -> Indexed> + /// Iterator element type is **(D, &A)**. + pub fn indexed_iter(&self) -> Indexed> { self.iter().indexed() } @@ -624,8 +624,8 @@ impl ArrayBase where S: Data, D: Dimension /// == (10, 2) /// ); /// ``` - pub fn broadcast<'a, E: Dimension>(&'a self, dim: E) - -> Option> + pub fn broadcast(&self, dim: E) + -> Option> { /// Return new stride when trying to grow **from** into shape **to** /// @@ -687,15 +687,15 @@ impl ArrayBase where S: Data, D: Dimension /// into a larger shape, if possible. /// /// Return **None** if shapes can not be broadcast together. - pub fn broadcast_iter<'a, E: Dimension>(&'a self, dim: E) - -> Option> + pub fn broadcast_iter(&self, dim: E) + -> Option> { self.broadcast(dim).map(|v| v.into_iter_()) } #[inline(never)] - fn broadcast_iter_unwrap<'a, E: Dimension>(&'a self, dim: E) - -> Elements<'a, A, E> + fn broadcast_iter_unwrap(&self, dim: E) + -> Elements { match self.broadcast_iter(dim.clone()) { Some(it) => it, @@ -738,7 +738,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// The diagonal is simply the sequence indexed by *(0, 0, .., 0)*, /// *(1, 1, ..., 1)* etc as long as all axes have elements. - pub fn diag_iter<'a>(&'a self) -> Elements<'a, A, Ix> + pub fn diag_iter(&self) -> Elements { let (len, stride) = self.diag_params(); unsafe { @@ -833,7 +833,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return a mutable reference to the element at **index**, or return **None** /// if the index is out of bounds. - pub fn at_mut<'a>(&'a mut self, index: D) -> Option<&'a mut A> + pub fn at_mut(&mut self, index: D) -> Option<&mut A> where S: DataMut, { self.ensure_unique(); @@ -845,8 +845,8 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of mutable references to the elements of the array. /// - /// Iterator element type is **&'a mut A**. - pub fn iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, D> + /// Iterator element type is **&mut A**. + pub fn iter_mut(&mut self) -> ElementsMut where S: DataMut, { self.ensure_unique(); @@ -855,8 +855,8 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of indexes and mutable references to the elements of the array. /// - /// Iterator element type is **(D, &'a mut A)**. - pub fn indexed_iter_mut<'a>(&'a mut self) -> Indexed> + /// Iterator element type is **(D, &mut A)**. + pub fn indexed_iter_mut(&mut self) -> Indexed> where S: DataMut, { self.iter_mut().indexed() @@ -876,10 +876,10 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of mutable references into the sliced view /// of the array. /// - /// Iterator element type is **&'a mut A**. + /// Iterator element type is **&mut A**. /// /// **Panics** if **indexes** does not match the number of array axes. - pub fn slice_iter_mut<'a>(&'a mut self, indexes: &[Si]) -> ElementsMut<'a, A, D> + pub fn slice_iter_mut(&mut self, indexes: &[Si]) -> ElementsMut where S: DataMut, { let mut it = self.iter_mut(); @@ -925,11 +925,11 @@ impl ArrayBase where S: Data, D: Dimension /// Select the subview **index** along **axis** and return an iterator /// of the subview. /// - /// Iterator element type is **&'a mut A**. + /// Iterator element type is **&mut A**. /// /// **Panics** if **axis** or **index** is out of bounds. - pub fn sub_iter_mut<'a>(&'a mut self, axis: usize, index: Ix) - -> ElementsMut<'a, A, D> + pub fn sub_iter_mut(&mut self, axis: usize, index: Ix) + -> ElementsMut where S: DataMut, { let mut it = self.iter_mut(); @@ -938,7 +938,7 @@ impl ArrayBase where S: Data, D: Dimension } /// Return an iterator over the diagonal elements of the array. - pub fn diag_iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, Ix> + pub fn diag_iter_mut(&mut self) -> ElementsMut where S: DataMut, { self.ensure_unique(); @@ -958,7 +958,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Note:** The data is uniquely held and nonaliased /// while it is mutably borrowed. - pub fn raw_data_mut<'a>(&'a mut self) -> &'a mut [A] + pub fn raw_data_mut(&mut self) -> &mut [A] where S: DataMut, { self.ensure_unique(); @@ -1278,7 +1278,7 @@ impl ArrayBase /// Return an iterator over the elements of row **index**. /// /// **Panics** if **index** is out of bounds. - pub fn row_iter<'a>(&'a self, index: Ix) -> Elements<'a, A, Ix> + pub fn row_iter(&self, index: Ix) -> Elements { let (m, n) = self.dim; let (sr, sc) = self.strides; @@ -1293,7 +1293,7 @@ impl ArrayBase /// Return an iterator over the elements of column **index**. /// /// **Panics** if **index** is out of bounds. - pub fn col_iter<'a>(&'a self, index: Ix) -> Elements<'a, A, Ix> + pub fn col_iter(&self, index: Ix) -> Elements { let (m, n) = self.dim; let (sr, sc) = self.strides; @@ -1309,7 +1309,7 @@ impl ArrayBase // Matrix multiplication only defined for simple types to // avoid trouble with failing + and *, and destructors -impl<'a, A: Copy + linalg::Ring, S> ArrayBase +impl ArrayBase where S: Data, { /// Perform matrix multiplication of rectangular arrays **self** and **other**. @@ -1463,7 +1463,7 @@ impl ArrayBase where /// If their shapes disagree, **other** is broadcast to the shape of **self**. /// /// **Panics** if broadcasting isn't possible. -impl<'a, A, S, S2, D, E> $trt> for ArrayBase +impl $trt> for ArrayBase where A: Clone + $trt, S: DataMut, S2: Data, From 01c7be1eb2dc40c8e20262f8ffcbe9e684b2464a Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 36/43] Change .map() to return an OwnedArray --- src/lib.rs | 7 +++---- tests/array.rs | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 46aff6405..00f25baf2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -772,14 +772,13 @@ impl ArrayBase where S: Data, D: Dimension /// let a = arr2(&[[1., 2.], /// [3., 4.]]); /// assert!( - /// a.map::, _>(|&x| (x / 2.) as i32) + /// a.map(|&x| (x / 2.) as i32) /// == arr2(&[[0, 1], [1, 2]]) /// ); /// ``` - pub fn map<'a, S2, F>(&'a self, mut f: F) -> ArrayBase - where F: FnMut(&'a A) -> S2::Elem, + pub fn map<'a, B, F>(&'a self, mut f: F) -> OwnedArray + where F: FnMut(&'a A) -> B, A: 'a, - S2: DataOwned, { let mut res = Vec::with_capacity(self.dim.size()); for elt in self.iter() { diff --git a/tests/array.rs b/tests/array.rs index cbe305129..c96b4fb99 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -351,10 +351,10 @@ fn equality() fn map1() { let a = arr2(&[[1., 2.], [3., 4.]]); - let b = a.map::, _>(|&x| (x / 3.) as isize); + 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); + let c = a.map(|x| x); assert_eq!(a[(0, 0)], *c[(0, 0)]); } From 4f123408d38bcebcebdd8a2e232c278fc06690fb Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 37/43] Add .to_shared() and .into_shared() --- src/lib.rs | 28 ++++++++++++++++++++++++++++ tests/array.rs | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 00f25baf2..5335a1979 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -252,6 +252,7 @@ unsafe impl<'a, A> DataMut for &'a mut [A] { /// Array representation that is a unique or shared owner of its data. pub unsafe trait DataOwned : Data { fn new(elements: Vec) -> Self; + fn into_shared(self) -> Rc>; } /// Array representation that is a lightweight view. @@ -262,10 +263,12 @@ impl<'a, A> DataShared for &'a [A] { } unsafe impl DataOwned for Vec { fn new(elements: Vec) -> Self { elements } + fn into_shared(self) -> Rc> { Rc::new(self) } } unsafe impl DataOwned for Rc> { fn new(elements: Vec) -> Self { Rc::new(elements) } + fn into_shared(self) -> Rc> { self } } @@ -479,6 +482,31 @@ impl ArrayBase where S: Data, D: Dimension } } + /// Return a shared ownership (copy on write) array. + pub fn to_shared(&self) -> Array + where A: Clone + { + // FIXME: Avoid copying if it's already an Array. + // FIXME: Use standard layout / more efficient copy? + let data = self.iter().cloned().collect(); + unsafe { + ArrayBase::from_vec_dim(self.dim.clone(), data) + } + } + + /// Return a shared ownership (copy on write) array. + pub fn into_shared(self) -> Array + where S: DataOwned, + { + let data = self.data.into_shared(); + ArrayBase { + data: data, + ptr: self.ptr, + dim: self.dim, + strides: self.strides, + } + } + /// Return a slice of the array's backing data in memory order. /// /// **Note:** Data memory order may not correspond to the index order diff --git a/tests/array.rs b/tests/array.rs index c96b4fb99..9b57bbf82 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -354,7 +354,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); + let c = a.map(|x| x).into_shared(); assert_eq!(a[(0, 0)], *c[(0, 0)]); } From 518a8881c13849dff4c8159868c7a0818fdf1f08 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 38/43] Add .get() and .get_mut() and deprecate .at(), .at_mut() --- src/arraytraits.rs | 4 ++-- src/lib.rs | 40 ++++++++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/arraytraits.rs b/src/arraytraits.rs index c1815479d..d1c6ebd4b 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -28,7 +28,7 @@ impl Index for ArrayBase type Output = S::Elem; #[inline] fn index(&self, index: D) -> &S::Elem { - self.at(index).expect("Array::index: out of bounds") + self.get(index).expect("Array::index: out of bounds") } } @@ -41,7 +41,7 @@ impl IndexMut for ArrayBase { #[inline] fn index_mut(&mut self, index: D) -> &mut S::Elem { - self.at_mut(index).expect("Array::index_mut: out of bounds") + self.get_mut(index).expect("Array::index_mut: out of bounds") } } diff --git a/src/lib.rs b/src/lib.rs index 5335a1979..9b7f73395 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,7 +96,7 @@ pub type Ixs = i32; /// values. /// /// Calling a method for mutating elements, for example -/// [*at_mut()*](#method.at_mut), [*iadd()*](#method.iadd) or +/// [*get_mut()*](#method.get_mut), [*iadd()*](#method.iadd) or /// [*iter_mut()*](#method.iter_mut) will break sharing and require a clone of /// the data (if it is not uniquely held). /// @@ -554,13 +554,37 @@ impl ArrayBase where S: Data, D: Dimension /// Return a reference to the element at **index**, or return **None** /// if the index is out of bounds. - pub fn at(&self, index: D) -> Option<&A> { + pub fn get(&self, index: D) -> Option<&A> { self.dim.stride_offset_checked(&self.strides, &index) .map(|offset| unsafe { &*self.ptr.offset(offset) }) } + /// ***Deprecated: use .get(i)*** + pub fn at(&self, index: D) -> Option<&A> { + self.get(index) + } + + /// Return a mutable reference to the element at **index**, or return **None** + /// if the index is out of bounds. + pub fn get_mut(&mut self, index: D) -> Option<&mut A> + where S: DataMut, + { + self.ensure_unique(); + self.dim.stride_offset_checked(&self.strides, &index) + .map(|offset| unsafe { + &mut *self.ptr.offset(offset) + }) + } + + /// ***Deprecated: use .get_mut(i)*** + pub fn at_mut(&mut self, index: D) -> Option<&mut A> + where S: DataMut, + { + self.get_mut(index) + } + /// Perform *unchecked* array indexing. /// /// Return a reference to the element at **index**. @@ -858,18 +882,6 @@ impl ArrayBase where S: Data, D: Dimension S::ensure_unique(self); } - /// Return a mutable reference to the element at **index**, or return **None** - /// if the index is out of bounds. - pub fn at_mut(&mut self, index: D) -> Option<&mut A> - where S: DataMut, - { - self.ensure_unique(); - self.dim.stride_offset_checked(&self.strides, &index) - .map(|offset| unsafe { - &mut *self.ptr.offset(offset) - }) - } - /// Return an iterator of mutable references to the elements of the array. /// /// Iterator element type is **&mut A**. From 348993cf1ee3e3320353ed670525a8282da2a6b8 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 39/43] Edit docs for all arithmetic operators --- src/lib.rs | 67 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9b7f73395..e29161a10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1458,13 +1458,15 @@ impl Array // Array OPERATORS macro_rules! impl_binary_op( - ($trt:ident, $mth:ident, $imethod:ident, $imth_scalar:ident) => ( + ($trt:ident, $mth:ident, $imethod:ident, $imth_scalar:ident, $doc:expr) => ( impl ArrayBase where A: Clone + $trt, S: DataMut, D: Dimension, { - /// Perform an elementwise arithmetic operation between **self** and **other**, + /// Perform elementwise + #[doc=$doc] + /// between **self** and **other**, /// *in place*. /// /// If their shapes disagree, **other** is broadcast to the shape of **self**. @@ -1486,7 +1488,9 @@ impl ArrayBase where } } - /// Perform an elementwise arithmetic operation between **self** and the scalar **x**, + /// Perform elementwise + #[doc=$doc] + /// between **self** and the scalar **x**, /// *in place*. pub fn $imth_scalar (&mut self, x: &A) { @@ -1496,7 +1500,9 @@ impl ArrayBase where } } -/// Perform an elementwise arithmetic operation between **self** and **other**, +/// Perform elementwise +#[doc=$doc] +/// between **self** and **other**, /// and return the result. /// /// If their shapes disagree, **other** is broadcast to the shape of **self**. @@ -1527,7 +1533,9 @@ impl $trt> for ArrayBase } } -/// Perform an elementwise arithmetic operation between **self** and **other**, +/// Perform elementwise +#[doc=$doc] +/// between **self** and **other**, /// and return the result. /// /// If their shapes disagree, **other** is broadcast to the shape of **self**. @@ -1563,16 +1571,16 @@ impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for &'a ArrayBase ); ); -impl_binary_op!(Add, add, iadd, iadd_scalar); -impl_binary_op!(Sub, sub, isub, isub_scalar); -impl_binary_op!(Mul, mul, imul, imul_scalar); -impl_binary_op!(Div, div, idiv, idiv_scalar); -impl_binary_op!(Rem, rem, irem, irem_scalar); -impl_binary_op!(BitAnd, bitand, ibitand, ibitand_scalar); -impl_binary_op!(BitOr, bitor, ibitor, ibitor_scalar); -impl_binary_op!(BitXor, bitxor, ibitxor, ibitxor_scalar); -impl_binary_op!(Shl, shl, ishl, ishl_scalar); -impl_binary_op!(Shr, shr, ishr, ishr_scalar); +impl_binary_op!(Add, add, iadd, iadd_scalar, "Addition"); +impl_binary_op!(Sub, sub, isub, isub_scalar, "Subtraction"); +impl_binary_op!(Mul, mul, imul, imul_scalar, "Multiplication"); +impl_binary_op!(Div, div, idiv, idiv_scalar, "Divsion"); +impl_binary_op!(Rem, rem, irem, irem_scalar, "Remainder"); +impl_binary_op!(BitAnd, bitand, ibitand, ibitand_scalar, "Bit and"); +impl_binary_op!(BitOr, bitor, ibitor, ibitor_scalar, "Bit or"); +impl_binary_op!(BitXor, bitxor, ibitxor, ibitxor_scalar, "Bit xor"); +impl_binary_op!(Shl, shl, ishl, ishl_scalar, "Shift left"); +impl_binary_op!(Shr, shr, ishr, ishr_scalar, "Shift right"); #[cfg(feature = "assign_ops")] mod assign_ops { @@ -1591,10 +1599,9 @@ mod assign_ops { macro_rules! impl_assign_op { - ($trt:ident, $method:ident) => { + ($trt:ident, $method:ident, $doc:expr) => { - /// Perform an elementwise in place arithmetic operation between **self** and **other**, - /// + #[doc=$doc] /// If their shapes disagree, **other** is broadcast to the shape of **self**. /// /// **Panics** if broadcasting isn't possible. @@ -1624,14 +1631,22 @@ mod assign_ops { }; } - impl_assign_op!(AddAssign, add_assign); - impl_assign_op!(SubAssign, sub_assign); - impl_assign_op!(MulAssign, mul_assign); - impl_assign_op!(DivAssign, div_assign); - impl_assign_op!(RemAssign, rem_assign); - impl_assign_op!(BitAndAssign, bitand_assign); - impl_assign_op!(BitOrAssign, bitor_assign); - impl_assign_op!(BitXorAssign, bitxor_assign); + impl_assign_op!(AddAssign, add_assign, + "Implement `self += other` as elementwise addition (in place).\n"); + impl_assign_op!(SubAssign, sub_assign, + "Implement `self -= other` as elementwise subtraction (in place).\n"); + impl_assign_op!(MulAssign, mul_assign, + "Implement `self *= other` as elementwise multiplication (in place).\n"); + impl_assign_op!(DivAssign, div_assign, + "Implement `self /= other` as elementwise division (in place).\n"); + impl_assign_op!(RemAssign, rem_assign, + "Implement `self %= other` as elementwise remainder (in place).\n"); + impl_assign_op!(BitAndAssign, bitand_assign, + "Implement `self &= other` as elementwise bit and (in place).\n"); + impl_assign_op!(BitOrAssign, bitor_assign, + "Implement `self |= other` as elementwise bit or (in place).\n"); + impl_assign_op!(BitXorAssign, bitxor_assign, + "Implement `self ^= other` as elementwise bit xor (in place).\n"); } impl, D: Dimension> From 875ff8d9a4157e85d5f5fc64b831e80dad90c4f5 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 40/43] Use backticks (code) markup where applicable --- src/lib.rs | 156 ++++++++++++++++++++++++++--------------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e29161a10..f2e283ef9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![crate_name="ndarray"] #![crate_type="dylib"] -//! The **ndarray** crate provides an n-dimensional container similar to numpy's ndarray. +//! The `ndarray` crate provides an n-dimensional container similar to numpy's ndarray. //! //! - [`ArrayBase`](struct.ArrayBase.html)
//! The n-dimensional array type itself, parameterized by data storage. @@ -81,7 +81,7 @@ pub type Ix = u32; /// Array index type (signed) pub type Ixs = i32; -/// The **Array** type is an *N-dimensional array*. +/// The `Array` type is an *N-dimensional array*. /// /// A reference counted array with copy-on-write mutability. /// @@ -107,7 +107,7 @@ pub type Ixs = i32; /// /// ## Indexing /// -/// Arrays use **u32** for indexing, represented by the types **Ix** and **Ixs** +/// Arrays use `u32` for indexing, represented by the types `Ix` and `Ixs` /// (signed). /// /// ## Broadcasting @@ -141,7 +141,7 @@ pub struct ArrayBase where S: Data { ptr: *mut S::Elem, /// The size of each axis dim: D, - /// The element count stride per axis. To be parsed as **isize**. + /// The element count stride per axis. To be parsed as `isize`. strides: D, } @@ -319,7 +319,7 @@ impl ArrayBase impl Array { - /// Create a one-dimensional Array from interval **[begin, end)** + /// Create a one-dimensional Array from interval `[begin, end)` pub fn range(begin: f32, end: f32) -> Array { let n = (end - begin) as usize; @@ -354,7 +354,7 @@ impl ArrayBase Self::from_elem(dim, libnum::zero()) } - /// Construct an Array with copies of **elem**. + /// Construct an Array with copies of `elem`. /// /// ``` /// use ndarray::Array; @@ -437,11 +437,11 @@ impl ArrayBase where S: Data, D: Dimension self.dim.slice() } - /// Return **true** if the array data is laid out in + /// Return `true` if the array data is laid out in /// contiguous “C order” where the last index is the most rapidly /// varying. /// - /// Return **false** otherwise, i.e the array is possibly not + /// Return `false` otherwise, i.e the array is possibly not /// contiguous in memory, it has custom strides, etc. pub fn is_standard_layout(&self) -> bool { @@ -519,7 +519,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return a sliced array. /// - /// **Panics** if **indexes** does not match the number of array axes. + /// **Panics** if `indexes` does not match the number of array axes. pub fn slice(&self, indexes: &[Si]) -> Self where S: DataShared { @@ -530,7 +530,7 @@ impl ArrayBase where S: Data, D: Dimension /// Slice the array's view in place. /// - /// **Panics** if **indexes** does not match the number of array axes. + /// **Panics** if `indexes` does not match the number of array axes. pub fn islice(&mut self, indexes: &[Si]) { let offset = Dimension::do_slices(&mut self.dim, &mut self.strides, indexes); @@ -541,7 +541,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator over a sliced view. /// - /// **Panics** if **indexes** does not match the number of array axes. + /// **Panics** if `indexes` does not match the number of array axes. pub fn slice_iter(&self, indexes: &[Si]) -> Elements { let mut it = self.iter(); @@ -552,7 +552,7 @@ impl ArrayBase where S: Data, D: Dimension it } - /// Return a reference to the element at **index**, or return **None** + /// Return a reference to the element at `index`, or return `None` /// if the index is out of bounds. pub fn get(&self, index: D) -> Option<&A> { self.dim.stride_offset_checked(&self.strides, &index) @@ -566,7 +566,7 @@ impl ArrayBase where S: Data, D: Dimension self.get(index) } - /// Return a mutable reference to the element at **index**, or return **None** + /// Return a mutable reference to the element at `index`, or return `None` /// if the index is out of bounds. pub fn get_mut(&mut self, index: D) -> Option<&mut A> where S: DataMut, @@ -587,7 +587,7 @@ impl ArrayBase where S: Data, D: Dimension /// Perform *unchecked* array indexing. /// - /// Return a reference to the element at **index**. + /// Return a reference to the element at `index`. /// /// **Note:** only unchecked for non-debug builds of ndarray. #[inline] @@ -599,7 +599,7 @@ impl ArrayBase where S: Data, D: Dimension /// Perform *unchecked* array indexing. /// - /// Return a mutable reference to the element at **index**. + /// Return a mutable reference to the element at `index`. /// /// **Note:** Only unchecked for non-debug builds of ndarray.
/// **Note:** The array must be uniquely held when mutating it. @@ -624,7 +624,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of references to the elements of the array. /// - /// Iterator element type is **&A**. + /// Iterator element type is `&A`. pub fn iter(&self) -> Elements { Elements { inner: self.base_iter() } @@ -632,16 +632,16 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of references to the elements of the array. /// - /// Iterator element type is **(D, &A)**. + /// Iterator element type is `(D, &A)`. pub fn indexed_iter(&self) -> Indexed> { self.iter().indexed() } - /// Collapse dimension **axis** into length one, - /// and select the subview of **index** along that axis. + /// Collapse dimension `axis` into length one, + /// and select the subview of `index` along that axis. /// - /// **Panics** if **index** is past the length of the axis. + /// **Panics** if `index` is past the length of the axis. pub fn isubview(&mut self, axis: usize, index: Ix) { dimension::do_sub(&mut self.dim, &mut self.ptr, &self.strides, axis, index) @@ -650,7 +650,7 @@ impl ArrayBase where S: Data, D: Dimension /// Act like a larger size and/or shape array by *broadcasting* /// into a larger shape, if possible. /// - /// Return **None** if shapes can not be broadcast together. + /// Return `None` if shapes can not be broadcast together. /// /// ***Background*** /// @@ -679,7 +679,7 @@ impl ArrayBase where S: Data, D: Dimension pub fn broadcast(&self, dim: E) -> Option> { - /// Return new stride when trying to grow **from** into shape **to** + /// Return new stride when trying to grow `from` into shape `to` /// /// Broadcasting works by returning a "fake stride" where elements /// to repeat are in axes with 0 stride, so that several indexes point @@ -738,7 +738,7 @@ impl ArrayBase where S: Data, D: Dimension /// Act like a larger size and/or shape array by *broadcasting* /// into a larger shape, if possible. /// - /// Return **None** if shapes can not be broadcast together. + /// Return `None` if shapes can not be broadcast together. pub fn broadcast_iter(&self, dim: E) -> Option> { @@ -756,7 +756,7 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Swap axes **ax** and **bx**. + /// Swap axes `ax` and `bx`. /// /// **Panics** if the axes are out of bounds. /// @@ -813,7 +813,7 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Apply **f** elementwise and return a new array with + /// Apply `f` elementwise and return a new array with /// the results. /// /// Return an array with the same shape as *self*. @@ -841,10 +841,10 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Select the subview **index** along **axis** and return an + /// Select the subview `index` along `axis` and return an /// array with that axis removed. /// - /// **Panics** if **index** is past the length of the axis. + /// **Panics** if `index` is past the length of the axis. /// /// ``` /// use ndarray::{arr1, arr2}; @@ -884,7 +884,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of mutable references to the elements of the array. /// - /// Iterator element type is **&mut A**. + /// Iterator element type is `&mut A`. pub fn iter_mut(&mut self) -> ElementsMut where S: DataMut, { @@ -894,7 +894,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of indexes and mutable references to the elements of the array. /// - /// Iterator element type is **(D, &mut A)**. + /// Iterator element type is `(D, &mut A)`. pub fn indexed_iter_mut(&mut self) -> Indexed> where S: DataMut, { @@ -903,7 +903,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return a sliced read-write view of the array. /// - /// **Panics** if **indexes** does not match the number of array axes. + /// **Panics** if `indexes` does not match the number of array axes. pub fn slice_mut(&mut self, indexes: &[Si]) -> ArrayViewMut where S: DataMut { @@ -915,9 +915,9 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of mutable references into the sliced view /// of the array. /// - /// Iterator element type is **&mut A**. + /// Iterator element type is `&mut A`. /// - /// **Panics** if **indexes** does not match the number of array axes. + /// **Panics** if `indexes` does not match the number of array axes. pub fn slice_iter_mut(&mut self, indexes: &[Si]) -> ElementsMut where S: DataMut, { @@ -929,9 +929,9 @@ impl ArrayBase where S: Data, D: Dimension it } - /// Select the subview **index** along **axis** and return a read-write view. + /// Select the subview `index` along `axis` and return a read-write view. /// - /// **Panics** if **axis** or **index** is out of bounds. + /// **Panics** if `axis` or `index` is out of bounds. /// /// ``` /// use ndarray::{arr2, aview2}; @@ -961,12 +961,12 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Select the subview **index** along **axis** and return an iterator + /// Select the subview `index` along `axis` and return an iterator /// of the subview. /// - /// Iterator element type is **&mut A**. + /// Iterator element type is `&mut A`. /// - /// **Panics** if **axis** or **index** is out of bounds. + /// **Panics** if `axis` or `index` is out of bounds. pub fn sub_iter_mut(&mut self, axis: usize, index: Ix) -> ElementsMut where S: DataMut, @@ -1005,7 +1005,7 @@ impl ArrayBase where S: Data, D: Dimension } - /// Transform the array into **shape**; any other shape + /// Transform the array into `shape`; any other shape /// with the same number of elements is accepted. /// /// **Panics** if sizes are incompatible. @@ -1043,9 +1043,9 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Perform an elementwise assigment to **self** from **other**. + /// Perform an elementwise assigment to `self` from `other`. /// - /// If their shapes disagree, **other** is broadcast to the shape of **self**. + /// If their shapes disagree, `other` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. pub fn assign(&mut self, other: &ArrayBase) @@ -1065,7 +1065,7 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Perform an elementwise assigment to **self** from scalar **x**. + /// Perform an elementwise assigment to `self` from scalar `x`. pub fn assign_scalar(&mut self, x: &A) where S: DataMut, A: Clone, { @@ -1075,7 +1075,7 @@ impl ArrayBase where S: Data, D: Dimension } } -/// Return a zero-dimensional array with the element **x**. +/// Return a zero-dimensional array with the element `x`. pub fn arr0
(x: A) -> Array { let mut v = Vec::with_capacity(1); @@ -1083,7 +1083,7 @@ pub fn arr0(x: A) -> Array unsafe { Array::from_vec_dim((), v) } } -/// Return a one-dimensional array with elements from **xs**. +/// Return a one-dimensional array with elements from `xs`. pub fn arr1(xs: &[A]) -> Array { Array::from_vec(xs.to_vec()) @@ -1102,7 +1102,7 @@ pub fn aview0(x: &A) -> ArrayView { } } -/// Return a one-dimensional array view with elements borrowing **xs**. +/// Return a one-dimensional array view with elements borrowing `xs`. pub fn aview1(xs: &[A]) -> ArrayView { ArrayView { data: xs, @@ -1112,7 +1112,7 @@ pub fn aview1(xs: &[A]) -> ArrayView { } } -/// Return a two-dimensional array view with elements borrowing **xs**. +/// Return a two-dimensional array view with elements borrowing `xs`. pub fn aview2>(xs: &[V]) -> ArrayView { let cols = V::len(); let rows = xs.len(); @@ -1169,7 +1169,7 @@ macro_rules! impl_arr_init { impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,); -/// Return a two-dimensional array with elements from **xs**. +/// Return a two-dimensional array with elements from `xs`. /// /// **Panics** if the slices are not all of the same length. /// @@ -1199,7 +1199,7 @@ pub fn arr2>(xs: &[V]) -> Array } } -/// Return a three-dimensional array with elements from **xs**. +/// Return a three-dimensional array with elements from `xs`. /// /// **Panics** if the slices are not all of the same length. /// @@ -1247,7 +1247,7 @@ impl ArrayBase S: Data, D: RemoveAxis, { - /// Return sum along **axis**. + /// Return sum along `axis`. /// /// ``` /// use ndarray::{aview0, aview1, arr2}; @@ -1262,7 +1262,7 @@ impl ArrayBase /// ); /// ``` /// - /// **Panics** if **axis** is out of bounds. + /// **Panics** if `axis` is out of bounds. pub fn sum(&self, axis: usize) -> OwnedArray::Smaller> { let n = self.shape()[axis]; @@ -1280,7 +1280,7 @@ impl ArrayBase S: Data, D: RemoveAxis, { - /// Return mean along **axis**. + /// Return mean along `axis`. /// /// ``` /// use ndarray::{aview1, arr2}; @@ -1294,7 +1294,7 @@ impl ArrayBase /// ``` /// /// - /// **Panics** if **axis** is out of bounds. + /// **Panics** if `axis` is out of bounds. pub fn mean(&self, axis: usize) -> OwnedArray::Smaller> { let n = self.shape()[axis]; @@ -1314,9 +1314,9 @@ impl ArrayBase impl ArrayBase where S: Data, { - /// Return an iterator over the elements of row **index**. + /// Return an iterator over the elements of row `index`. /// - /// **Panics** if **index** is out of bounds. + /// **Panics** if `index` is out of bounds. pub fn row_iter(&self, index: Ix) -> Elements { let (m, n) = self.dim; @@ -1329,9 +1329,9 @@ impl ArrayBase } } - /// Return an iterator over the elements of column **index**. + /// Return an iterator over the elements of column `index`. /// - /// **Panics** if **index** is out of bounds. + /// **Panics** if `index` is out of bounds. pub fn col_iter(&self, index: Ix) -> Elements { let (m, n) = self.dim; @@ -1351,10 +1351,10 @@ impl ArrayBase impl ArrayBase where S: Data, { - /// Perform matrix multiplication of rectangular arrays **self** and **other**. + /// Perform matrix multiplication of rectangular arrays `self` and `other`. /// /// The array sizes must agree in the way that - /// if **self** is *M* × *N*, then **other** is *N* × *K*. + /// if `self` is *M* × *N*, then `other` is *N* × *K*. /// /// Return a result array with shape *M* × *K*. /// @@ -1405,11 +1405,11 @@ impl ArrayBase } } - /// Perform the matrix multiplication of the rectangular array **self** and - /// column vector **other**. + /// Perform the matrix multiplication of the rectangular array `self` and + /// column vector `other`. /// /// The array sizes must agree in the way that - /// if **self** is *M* × *N*, then **other** is *N*. + /// if `self` is *M* × *N*, then `other` is *N*. /// /// Return a result array with shape *M*. /// @@ -1444,9 +1444,9 @@ impl ArrayBase impl Array { - /// Return **true** if the arrays' elementwise differences are all within + /// Return `true` if the arrays' elementwise differences are all within /// the given absolute tolerance.
- /// Return **false** otherwise, or if the shapes disagree. + /// Return `false` otherwise, or if the shapes disagree. pub fn allclose(&self, other: &Array, tol: A) -> bool { self.shape() == other.shape() && @@ -1466,10 +1466,10 @@ impl ArrayBase where { /// Perform elementwise #[doc=$doc] - /// between **self** and **other**, + /// between `self` and `other`, /// *in place*. /// - /// If their shapes disagree, **other** is broadcast to the shape of **self**. + /// If their shapes disagree, `other` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. pub fn $imethod (&mut self, other: &ArrayBase) @@ -1490,7 +1490,7 @@ impl ArrayBase where /// Perform elementwise #[doc=$doc] - /// between **self** and the scalar **x**, + /// between `self` and the scalar `x`, /// *in place*. pub fn $imth_scalar (&mut self, x: &A) { @@ -1502,10 +1502,10 @@ impl ArrayBase where /// Perform elementwise #[doc=$doc] -/// between **self** and **other**, +/// between `self` and `other`, /// and return the result. /// -/// If their shapes disagree, **other** is broadcast to the shape of **self**. +/// If their shapes disagree, `other` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. impl $trt> for ArrayBase @@ -1535,10 +1535,10 @@ impl $trt> for ArrayBase /// Perform elementwise #[doc=$doc] -/// between **self** and **other**, +/// between `self` and `other`, /// and return the result. /// -/// If their shapes disagree, **other** is broadcast to the shape of **self**. +/// If their shapes disagree, `other` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for &'a ArrayBase @@ -1602,7 +1602,7 @@ mod assign_ops { ($trt:ident, $method:ident, $doc:expr) => { #[doc=$doc] - /// If their shapes disagree, **other** is broadcast to the shape of **self**. + /// If their shapes disagree, `other` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. /// @@ -1652,7 +1652,7 @@ mod assign_ops { impl, D: Dimension> Array { - /// Perform an elementwise negation of **self**, *in place*. + /// Perform an elementwise negation of `self`, *in place*. pub fn ineg(&mut self) { for elt in self.iter_mut() { @@ -1665,7 +1665,7 @@ impl, D: Dimension> Neg for Array { type Output = Self; - /// Perform an elementwise negation of **self** and return the result. + /// Perform an elementwise negation of `self` and return the result. fn neg(mut self) -> Array { self.ineg(); @@ -1676,7 +1676,7 @@ Neg for Array impl, D: Dimension> Array { - /// Perform an elementwise unary not of **self**, *in place*. + /// Perform an elementwise unary not of `self`, *in place*. pub fn inot(&mut self) { for elt in self.iter_mut() { @@ -1689,7 +1689,7 @@ impl, D: Dimension> Not for Array { type Output = Self; - /// Perform an elementwise unary not of **self** and return the result. + /// Perform an elementwise unary not of `self` and return the result. fn not(mut self) -> Array { self.inot(); @@ -1699,7 +1699,7 @@ Not for Array /// An iterator over the elements of an array. /// -/// Iterator element type is **&'a A**. +/// Iterator element type is `&'a A`. pub struct Elements<'a, A: 'a, D> { inner: Baseiter<'a, A, D>, } @@ -1714,7 +1714,7 @@ impl<'a, A, D> Elements<'a, A, D> where D: Clone /// Return an indexed version of the iterator. /// - /// Iterator element type is **(D, &'a A)**. + /// Iterator element type is `(D, &'a A)`. /// /// **Note:** the indices run over the logical dimension of the iterator, /// i.e. a *.slice_iter()* will yield indices relative to the slice, not the @@ -1729,7 +1729,7 @@ impl<'a, A, D> Elements<'a, A, D> where D: Clone /// An iterator over the elements of an array. /// -/// Iterator element type is **&'a mut A**. +/// Iterator element type is `&'a mut A`. pub struct ElementsMut<'a, A: 'a, D> { inner: Baseiter<'a, A, D>, } @@ -1744,7 +1744,7 @@ impl<'a, A, D> ElementsMut<'a, A, D> where D: Clone /// Return an indexed version of the iterator. /// - /// Iterator element type is **(D, &'a mut A)**. + /// Iterator element type is `(D, &'a mut A)`. pub fn indexed(self) -> Indexed> { Indexed { From 399e99792fb26549befb43327dd922581274dcc5 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 41/43] Use argument name `rhs` instead of `other` --- src/lib.rs | 102 ++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f2e283ef9..362fcdd90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1043,22 +1043,22 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Perform an elementwise assigment to `self` from `other`. + /// Perform an elementwise assigment to `self` from `rhs`. /// - /// If their shapes disagree, `other` is broadcast to the shape of `self`. + /// If their shapes disagree, `rhs` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. - pub fn assign(&mut self, other: &ArrayBase) + pub fn assign(&mut self, rhs: &ArrayBase) where S: DataMut, A: Clone, S2: Data, { - if self.shape() == other.shape() { - for (x, y) in self.iter_mut().zip(other.iter()) { + if self.shape() == rhs.shape() { + for (x, y) in self.iter_mut().zip(rhs.iter()) { *x = y.clone(); } } else { - let other_iter = other.broadcast_iter_unwrap(self.dim()); + let other_iter = rhs.broadcast_iter_unwrap(self.dim()); for (x, y) in self.iter_mut().zip(other_iter) { *x = y.clone(); } @@ -1351,10 +1351,10 @@ impl ArrayBase impl ArrayBase where S: Data, { - /// Perform matrix multiplication of rectangular arrays `self` and `other`. + /// Perform matrix multiplication of rectangular arrays `self` and `rhs`. /// /// The array sizes must agree in the way that - /// if `self` is *M* × *N*, then `other` is *N* × *K*. + /// if `self` is *M* × *N*, then `rhs` is *N* × *K*. /// /// Return a result array with shape *M* × *K*. /// @@ -1374,9 +1374,9 @@ impl ArrayBase /// ); /// ``` /// - pub fn mat_mul(&self, other: &ArrayBase) -> Array + pub fn mat_mul(&self, rhs: &ArrayBase) -> Array { - let ((m, a), (b, n)) = (self.dim, other.dim); + let ((m, a), (b, n)) = (self.dim, rhs.dim); let (self_columns, other_rows) = (a, b); assert!(self_columns == other_rows); @@ -1390,7 +1390,7 @@ impl ArrayBase for rr in res_elems.iter_mut() { unsafe { let dot = (0..a).fold(libnum::zero::
(), - |s, k| s + *self.uchk_at((i, k)) * *other.uchk_at((k, j)) + |s, k| s + *self.uchk_at((i, k)) * *rhs.uchk_at((k, j)) ); std::ptr::write(rr, dot); } @@ -1406,17 +1406,17 @@ impl ArrayBase } /// Perform the matrix multiplication of the rectangular array `self` and - /// column vector `other`. + /// column vector `rhs`. /// /// The array sizes must agree in the way that - /// if `self` is *M* × *N*, then `other` is *N*. + /// if `self` is *M* × *N*, then `rhs` is *N*. /// /// Return a result array with shape *M*. /// /// **Panics** if sizes are incompatible. - pub fn mat_mul_col(&self, other: &ArrayBase) -> Array + pub fn mat_mul_col(&self, rhs: &ArrayBase) -> Array { - let ((m, a), n) = (self.dim, other.dim); + let ((m, a), n) = (self.dim, rhs.dim); let (self_columns, other_rows) = (a, n); assert!(self_columns == other_rows); @@ -1429,7 +1429,7 @@ impl ArrayBase for rr in res_elems.iter_mut() { unsafe { let dot = (0..a).fold(libnum::zero::(), - |s, k| s + *self.uchk_at((i, k)) * *other.uchk_at(k) + |s, k| s + *self.uchk_at((i, k)) * *rhs.uchk_at(k) ); std::ptr::write(rr, dot); } @@ -1447,10 +1447,10 @@ impl Array /// Return `true` if the arrays' elementwise differences are all within /// the given absolute tolerance.
/// Return `false` otherwise, or if the shapes disagree. - pub fn allclose(&self, other: &Array, tol: A) -> bool + pub fn allclose(&self, rhs: &Array, tol: A) -> bool { - self.shape() == other.shape() && - self.iter().zip(other.iter()).all(|(x, y)| (*x - *y).abs() <= tol) + self.shape() == rhs.shape() && + self.iter().zip(rhs.iter()).all(|(x, y)| (*x - *y).abs() <= tol) } } @@ -1466,22 +1466,22 @@ impl ArrayBase where { /// Perform elementwise #[doc=$doc] - /// between `self` and `other`, + /// between `self` and `rhs`, /// *in place*. /// - /// If their shapes disagree, `other` is broadcast to the shape of `self`. + /// If their shapes disagree, `rhs` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. - pub fn $imethod (&mut self, other: &ArrayBase) + pub fn $imethod (&mut self, rhs: &ArrayBase) where S2: Data, { - if self.dim.ndim() == other.dim.ndim() && - self.shape() == other.shape() { - for (x, y) in self.iter_mut().zip(other.iter()) { + if self.dim.ndim() == rhs.dim.ndim() && + self.shape() == rhs.shape() { + for (x, y) in self.iter_mut().zip(rhs.iter()) { *x = (x.clone()). $mth (y.clone()); } } else { - let other_iter = other.broadcast_iter_unwrap(self.dim()); + let other_iter = rhs.broadcast_iter_unwrap(self.dim()); for (x, y) in self.iter_mut().zip(other_iter) { *x = (x.clone()). $mth (y.clone()); } @@ -1502,10 +1502,10 @@ impl ArrayBase where /// Perform elementwise #[doc=$doc] -/// between `self` and `other`, +/// between `self` and `rhs`, /// and return the result. /// -/// If their shapes disagree, `other` is broadcast to the shape of `self`. +/// If their shapes disagree, `rhs` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. impl $trt> for ArrayBase @@ -1516,15 +1516,15 @@ impl $trt> for ArrayBase E: Dimension, { type Output = ArrayBase; - fn $mth (mut self, other: ArrayBase) -> ArrayBase + fn $mth (mut self, rhs: ArrayBase) -> ArrayBase { // FIXME: Can we co-broadcast arrays here? And how? - if self.shape() == other.shape() { - for (x, y) in self.iter_mut().zip(other.iter()) { + if self.shape() == rhs.shape() { + for (x, y) in self.iter_mut().zip(rhs.iter()) { *x = x.clone(). $mth (y.clone()); } } else { - let other_iter = other.broadcast_iter_unwrap(self.dim()); + let other_iter = rhs.broadcast_iter_unwrap(self.dim()); for (x, y) in self.iter_mut().zip(other_iter) { *x = x.clone(). $mth (y.clone()); } @@ -1535,10 +1535,10 @@ impl $trt> for ArrayBase /// Perform elementwise #[doc=$doc] -/// between `self` and `other`, +/// between `self` and `rhs`, /// and return the result. /// -/// If their shapes disagree, `other` is broadcast to the shape of `self`. +/// If their shapes disagree, `rhs` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for &'a ArrayBase @@ -1549,16 +1549,16 @@ impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for &'a ArrayBase E: Dimension, { type Output = OwnedArray; - fn $mth (self, other: &'a ArrayBase) -> OwnedArray + fn $mth (self, rhs: &'a ArrayBase) -> OwnedArray { // FIXME: Can we co-broadcast arrays here? And how? let mut result = Vec::
::with_capacity(self.dim.size()); - if self.shape() == other.shape() { - for (x, y) in self.iter().zip(other.iter()) { + if self.shape() == rhs.shape() { + for (x, y) in self.iter().zip(rhs.iter()) { result.push((x.clone()). $mth (y.clone())); } } else { - let other_iter = other.broadcast_iter_unwrap(self.dim()); + let other_iter = rhs.broadcast_iter_unwrap(self.dim()); for (x, y) in self.iter().zip(other_iter) { result.push((x.clone()). $mth (y.clone())); } @@ -1602,7 +1602,7 @@ mod assign_ops { ($trt:ident, $method:ident, $doc:expr) => { #[doc=$doc] - /// If their shapes disagree, `other` is broadcast to the shape of `self`. + /// If their shapes disagree, `rhs` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn't possible. /// @@ -1614,13 +1614,13 @@ mod assign_ops { D: Dimension, E: Dimension, { - fn $method(&mut self, other: &ArrayBase) { - if self.shape() == other.shape() { - for (x, y) in self.iter_mut().zip(other.iter()) { + fn $method(&mut self, rhs: &ArrayBase) { + if self.shape() == rhs.shape() { + for (x, y) in self.iter_mut().zip(rhs.iter()) { x.$method(y.clone()); } } else { - let other_iter = other.broadcast_iter_unwrap(self.dim()); + let other_iter = rhs.broadcast_iter_unwrap(self.dim()); for (x, y) in self.iter_mut().zip(other_iter) { x.$method(y.clone()); } @@ -1632,21 +1632,21 @@ mod assign_ops { } impl_assign_op!(AddAssign, add_assign, - "Implement `self += other` as elementwise addition (in place).\n"); + "Implement `self += rhs` as elementwise addition (in place).\n"); impl_assign_op!(SubAssign, sub_assign, - "Implement `self -= other` as elementwise subtraction (in place).\n"); + "Implement `self -= rhs` as elementwise subtraction (in place).\n"); impl_assign_op!(MulAssign, mul_assign, - "Implement `self *= other` as elementwise multiplication (in place).\n"); + "Implement `self *= rhs` as elementwise multiplication (in place).\n"); impl_assign_op!(DivAssign, div_assign, - "Implement `self /= other` as elementwise division (in place).\n"); + "Implement `self /= rhs` as elementwise division (in place).\n"); impl_assign_op!(RemAssign, rem_assign, - "Implement `self %= other` as elementwise remainder (in place).\n"); + "Implement `self %= rhs` as elementwise remainder (in place).\n"); impl_assign_op!(BitAndAssign, bitand_assign, - "Implement `self &= other` as elementwise bit and (in place).\n"); + "Implement `self &= rhs` as elementwise bit and (in place).\n"); impl_assign_op!(BitOrAssign, bitor_assign, - "Implement `self |= other` as elementwise bit or (in place).\n"); + "Implement `self |= rhs` as elementwise bit or (in place).\n"); impl_assign_op!(BitXorAssign, bitxor_assign, - "Implement `self ^= other` as elementwise bit xor (in place).\n"); + "Implement `self ^= rhs` as elementwise bit xor (in place).\n"); } impl, D: Dimension> From ed2eaf7b095b9da65a776d469b7b57becd963dbb Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 42/43] Generalize .allclose() --- src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 362fcdd90..71fdcf854 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1442,12 +1442,16 @@ impl ArrayBase } -impl Array +impl ArrayBase + where A: Float + PartialOrd, + S: Data, + D: Dimension { /// Return `true` if the arrays' elementwise differences are all within /// the given absolute tolerance.
/// Return `false` otherwise, or if the shapes disagree. - pub fn allclose(&self, rhs: &Array, tol: A) -> bool + pub fn allclose(&self, rhs: &ArrayBase, tol: A) -> bool + where S2: Data, { self.shape() == rhs.shape() && self.iter().zip(rhs.iter()).all(|(x, y)| (*x - *y).abs() <= tol) From 5842355f71b0ac853679411434c641cd91dc03c8 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 15 Dec 2015 23:47:29 +0100 Subject: [PATCH 43/43] Generalize Not and Neg --- src/lib.rs | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 71fdcf854..7c42d6214 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1653,8 +1653,10 @@ mod assign_ops { "Implement `self ^= rhs` as elementwise bit xor (in place).\n"); } -impl, D: Dimension> -Array +impl ArrayBase + where A: Clone + Neg, + S: DataMut, + D: Dimension { /// Perform an elementwise negation of `self`, *in place*. pub fn ineg(&mut self) @@ -1665,20 +1667,23 @@ Array } } -impl, D: Dimension> -Neg for Array +impl Neg for ArrayBase + where A: Clone + Neg, + S: DataMut, + D: Dimension { type Output = Self; /// Perform an elementwise negation of `self` and return the result. - fn neg(mut self) -> Array - { + fn neg(mut self) -> Self { self.ineg(); self } } -impl, D: Dimension> -Array +impl ArrayBase + where A: Clone + Not, + S: DataMut, + D: Dimension { /// Perform an elementwise unary not of `self`, *in place*. pub fn inot(&mut self) @@ -1689,13 +1694,15 @@ Array } } -impl, D: Dimension> -Not for Array + +impl Not for ArrayBase + where A: Clone + Not, + S: DataMut, + D: Dimension { type Output = Self; /// Perform an elementwise unary not of `self` and return the result. - fn not(mut self) -> Array - { + fn not(mut self) -> Self { self.inot(); self }