From 78aa5d33b770a656729d9ace568f0ce48284054d Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 24 Oct 2016 11:29:24 +0200 Subject: [PATCH 001/107] Add iterator filter sum benchmarks, just for interest --- benches/iter.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/benches/iter.rs b/benches/iter.rs index 720ba117f..0f64f4437 100644 --- a/benches/iter.rs +++ b/benches/iter.rs @@ -6,6 +6,7 @@ use test::Bencher; #[macro_use(s)] extern crate ndarray; use ndarray::prelude::*; +use ndarray::Array2; #[bench] fn iter_sum_2d_regular(bench: &mut Bencher) @@ -47,3 +48,45 @@ fn iter_sum_2d_transpose(bench: &mut Bencher) a.iter().fold(0, |acc, &x| acc + x) }); } + +#[bench] +fn iter_filter_sum_2d_u32(bench: &mut Bencher) +{ + let a = Array::linspace(0., 1., 256).into_shape((16, 16)).unwrap(); + let b = a.mapv(|x| (x * 100.) as u32); + bench.iter(|| { + b.iter().filter(|&&x| x < 75).fold(0, |acc, &x| acc + x) + }); +} + +#[bench] +fn iter_filter_sum_2d_f32(bench: &mut Bencher) +{ + let a = Array::linspace(0., 1., 256).into_shape((16, 16)).unwrap(); + let b = a * 100.; + bench.iter(|| { + b.iter().filter(|&&x| x < 75.).fold(0., |acc, &x| acc + x) + }); +} + +#[bench] +fn iter_filter_sum_2d_stride_u32(bench: &mut Bencher) +{ + let a = Array::linspace(0., 1., 256).into_shape((16, 16)).unwrap(); + let b = a.mapv(|x| (x * 100.) as u32); + let b = b.slice(s![.., ..;2]); + bench.iter(|| { + b.iter().filter(|&&x| x < 75).fold(0, |acc, &x| acc + x) + }); +} + +#[bench] +fn iter_filter_sum_2d_stride_f32(bench: &mut Bencher) +{ + let a = Array::linspace(0., 1., 256).into_shape((16, 16)).unwrap(); + let b = a * 100.; + let b = b.slice(s![.., ..;2]); + bench.iter(|| { + b.iter().filter(|&&x| x < 75.).fold(0., |acc, &x| acc + x) + }); +} From 6b6d1fc386bf53c4cfc58f07812400702727817c Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 002/107] Initiate work on using fixed size arrays as dimensions --- examples/life.rs | 3 +- src/aliases.rs | 6 +- src/arraytraits.rs | 4 +- src/dimension.rs | 210 +++++++++++++++++++++++++++++++++++++- src/free_functions.rs | 4 +- src/impl_constructors.rs | 15 +-- src/impl_methods.rs | 20 +++- src/linalg/impl_linalg.rs | 44 ++++---- src/shape_builder.rs | 80 +++++++++++++-- tests/dimension.rs | 2 + 10 files changed, 338 insertions(+), 50 deletions(-) diff --git a/examples/life.rs b/examples/life.rs index 7d9a3d503..292caad30 100644 --- a/examples/life.rs +++ b/examples/life.rs @@ -58,7 +58,8 @@ fn iterate(z: &mut Board, scratch: &mut Board) { } fn turn_on_corners(z: &mut Board) { - let (n, m) = z.dim(); + let n = z.rows(); + let m = z.cols(); z[[1 , 1 ]] = 1; z[[1 , m - 2]] = 1; z[[n - 2, 1 ]] = 1; diff --git a/src/aliases.rs b/src/aliases.rs index aaec281c3..1c0ec6fe8 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -4,11 +4,11 @@ use ::{Ix, Array, ArrayView, ArrayViewMut}; /// zero-dimensionial -pub type Ix0 = (); +pub type Ix0 = [Ix; 0]; /// one-dimensional -pub type Ix1 = Ix; +pub type Ix1 = [Ix; 1]; /// two-dimensional -pub type Ix2 = (Ix, Ix); +pub type Ix2 = [Ix; 2]; /// three-dimensional pub type Ix3 = (Ix, Ix, Ix); /// four-dimensional diff --git a/src/arraytraits.rs b/src/arraytraits.rs index a8dcc2b45..f6a3f2148 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -221,7 +221,7 @@ impl<'a, A, Slice: ?Sized> From<&'a Slice> for ArrayBase, Ix1> fn from(slice: &'a Slice) -> Self { let xs = slice.as_ref(); unsafe { - Self::new_(xs.as_ptr(), xs.len(), 1) + Self::new_(xs.as_ptr(), [xs.len()], [1]) } } } @@ -247,7 +247,7 @@ impl<'a, A, Slice: ?Sized> From<&'a mut Slice> for ArrayBase fn from(slice: &'a mut Slice) -> Self { let xs = slice.as_mut(); unsafe { - Self::new_(xs.as_mut_ptr(), xs.len(), 1) + Self::new_(xs.as_mut_ptr(), [xs.len()], [1]) } } } diff --git a/src/dimension.rs b/src/dimension.rs index 179e9f874..eb420e1c4 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -141,6 +141,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { /// The easiest way to create a `&SliceArg` is using the macro /// [`s![]`](macro.s!.html). type SliceArg: ?Sized + AsRef<[Si]>; + type Tuple; #[doc(hidden)] fn ndim(&self) -> usize; #[doc(hidden)] @@ -150,6 +151,10 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { } } + fn as_tuple(&self) -> Self::Tuple { + panic!() + } + #[doc(hidden)] fn slice_mut(&mut self) -> &mut [Ix] { unsafe { @@ -418,9 +423,126 @@ pub fn do_sub(dims: &mut D, ptr: &mut *mut A, strides: &D, } } +// Tuple to array conversion + +/// $m: macro callback +/// $m is called with $arg and then the indices corresponding to the size argument +macro_rules! index { + ($m:ident $arg:tt 0) => ($m!($arg)); + ($m:ident $arg:tt 1) => ($m!($arg 0)); + ($m:ident $arg:tt 2) => ($m!($arg 0 1)); + ($m:ident $arg:tt 3) => ($m!($arg 0 1 2)); + ($m:ident $arg:tt 4) => ($m!($arg 0 1 2 3)); + ($m:ident $arg:tt 5) => ($m!($arg 0 1 2 3 4)); + ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5)); +} +macro_rules! index_item { + ($m:ident $arg:tt 0) => (); + ($m:ident $arg:tt 1) => ($m!($arg 0);); + ($m:ident $arg:tt 2) => ($m!($arg 0 1);); + ($m:ident $arg:tt 3) => ($m!($arg 0 1 2);); + ($m:ident $arg:tt 4) => ($m!($arg 0 1 2 3);); + ($m:ident $arg:tt 5) => ($m!($arg 0 1 2 3 4);); + ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5);); +} + +pub trait IntoDimension { + type Dim: Dimension; + fn into_dimension(self) -> Self::Dim; +} + +impl IntoDimension for () { + type Dim = [Ix; 0]; + #[inline] + fn into_dimension(self) -> [Ix; 0] { [] } +} +impl IntoDimension for Ix { + type Dim = [Ix; 1]; + #[inline] + fn into_dimension(self) -> [Ix; 1] { [self] } +} +impl IntoDimension for (Ix, Ix) { + type Dim = [Ix; 2]; + #[inline] + fn into_dimension(self) -> [Ix; 2] { [self.0, self.1] } +} + +pub trait Convert { + type To; + fn convert(self) -> Self::To; +} + +pub trait ToIndex { + fn to_index(self) -> D; +} + +impl ToIndex for T where T: Dimension { + fn to_index(self) -> Self { self } +} + +impl ToIndex<[Ix; 1]> for Ix { + fn to_index(self) -> [Ix; 1] { [self] } +} +impl ToIndex<[Ix; 2]> for (Ix, Ix) { + fn to_index(self) -> [Ix; 2] { [self.0, self.1] } +} + +impl Convert for Ix { + type To = [Ix; 1]; + fn convert(self) -> Self::To { [self] } +} +/* +*/ + +macro_rules! sub { + ($_x:tt $y:tt) => ($y); +} + +macro_rules! tuple_type { + ([$T:ident] $($index:tt)*) => ( + ( $(sub!($index $T), )* ) + ) +} + +macro_rules! tuple_expr { + ([$self_:expr] $($index:tt)*) => ( + ( $($self_[$index], )* ) + ) +} + +macro_rules! array_expr { + ([$self_:expr] $($index:tt)*) => ( + [$($self_ . $index, )*] + ) +} + +macro_rules! tuple_to_array { + ([] $($n:tt)*) => { + $( + impl Convert for [T; $n] { + type To = index!(tuple_type [T] $n); + fn convert(self) -> Self::To { + index!(tuple_expr [self] $n) + } + } + + impl Convert for index!(tuple_type [T] $n) { + type To = [T; $n]; + fn convert(self) -> Self::To { + index!(array_expr [self] $n) + } + } + )* + } +} + +index_item!(tuple_to_array [] 6); + +/* unsafe impl Dimension for () { type SliceArg = [Si; 0]; + type Tuple = (); // empty product is 1 -> size is 1 #[inline] fn ndim(&self) -> usize { 0 } @@ -431,9 +553,37 @@ unsafe impl Dimension for () { #[inline] fn _fastest_varying_stride_order(&self) -> Self { } } +*/ +unsafe impl Dimension for [Ix; 0] { + type SliceArg = [Si; 0]; + type Tuple = (); + // empty product is 1 -> size is 1 + #[inline] + fn ndim(&self) -> usize { 0 } + #[inline] + fn slice(&self) -> &[Ix] { self } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self } + #[inline] + fn _fastest_varying_stride_order(&self) -> Self { [] } +} + +unsafe impl Dimension for [Ix; 1] { + type SliceArg = [Si; 1]; + type Tuple = Ix; + #[inline] + fn ndim(&self) -> usize { 1 } + #[inline] + fn slice(&self) -> &[Ix] { self } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self } +} + +/* unsafe impl Dimension for Ix { type SliceArg = [Si; 1]; + type Tuple = Ix; #[inline] fn ndim(&self) -> usize { 1 } #[inline] @@ -483,7 +633,25 @@ unsafe impl Dimension for Ix { } } } +*/ + +unsafe impl Dimension for [Ix; 2] { + type SliceArg = [Si; 2]; + type Tuple = (Ix, Ix); + #[inline] + fn ndim(&self) -> usize { 2 } + #[inline] + fn as_tuple(&self) -> Self::Tuple { + self.convert() + } + #[inline] + fn slice(&self) -> &[Ix] { self } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self } +} + +/* unsafe impl Dimension for (Ix, Ix) { type SliceArg = [Si; 2]; #[inline] @@ -556,9 +724,11 @@ unsafe impl Dimension for (Ix, Ix) { } } } +*/ unsafe impl Dimension for (Ix, Ix, Ix) { type SliceArg = [Si; 3]; + type Tuple = Self; #[inline] fn ndim(&self) -> usize { 3 } #[inline] @@ -618,6 +788,7 @@ macro_rules! large_dim { ($n:expr, $($ix:ident),+) => ( unsafe impl Dimension for ($($ix),+) { type SliceArg = [Si; $n]; + type Tuple = Self; #[inline] fn ndim(&self) -> usize { $n } } @@ -639,6 +810,7 @@ large_dim!(12, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); unsafe impl Dimension for Vec { type SliceArg = [Si]; + type Tuple = Self; fn ndim(&self) -> usize { self.len() } fn slice(&self) -> &[Ix] { self } fn slice_mut(&mut self) -> &mut [Ix] { self } @@ -682,6 +854,7 @@ impl RemoveAxis for ($from $(,$more)*) ) ); +/* impl RemoveAxis for Ix { type Smaller = (); #[inline] @@ -697,6 +870,7 @@ impl RemoveAxis for (Ix, Ix) { if axis == 0 { self.1 } else { self.0 } } } +*/ macro_rules! impl_shrink_recursive( ($ix:ident, ) => (impl_shrink!($ix,);); @@ -706,8 +880,36 @@ macro_rules! impl_shrink_recursive( ) ); +macro_rules! impl_remove_axis_array( + ($n:expr) => ( +impl RemoveAxis for [Ix; $n] +{ + type Smaller = [Ix; $n - 1]; + #[inline] + fn remove_axis(&self, axis: Axis) -> Self::Smaller { + let mut tup = [0; $n - 1]; + { + let mut it = tup.slice_mut().iter_mut(); + for (i, &d) in self.slice().iter().enumerate() { + if i == axis.axis() { + continue; + } + for rr in it.by_ref() { + *rr = d; + break + } + } + } + tup + } +} + ); +); + +impl_remove_axis_array!(2); + // 12 is the maximum number for having the Eq trait from libstd -impl_shrink_recursive!(Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix,); +//impl_shrink_recursive!(Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix,); impl RemoveAxis for Vec { type Smaller = Vec; @@ -745,6 +947,7 @@ unsafe impl NdIndex for D } } +/* unsafe impl NdIndex for [Ix; 0] { type Dim = (); #[inline] @@ -752,7 +955,9 @@ unsafe impl NdIndex for [Ix; 0] { dim.stride_offset_checked(strides, &()) } } +*/ +/* unsafe impl NdIndex for [Ix; 1] { type Dim = Ix; #[inline] @@ -760,7 +965,9 @@ unsafe impl NdIndex for [Ix; 1] { dim.stride_offset_checked(strides, &self[0]) } } +*/ +/* unsafe impl NdIndex for [Ix; 2] { type Dim = (Ix, Ix); #[inline] @@ -769,6 +976,7 @@ unsafe impl NdIndex for [Ix; 2] { dim.stride_offset_checked(strides, &index) } } +*/ unsafe impl NdIndex for [Ix; 3] { type Dim = (Ix, Ix, Ix); diff --git a/src/free_functions.rs b/src/free_functions.rs index 32837c28d..5bc12dbde 100644 --- a/src/free_functions.rs +++ b/src/free_functions.rs @@ -56,7 +56,7 @@ pub fn aview2>(xs: &[V]) -> ArrayView2 { let data = unsafe { slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows) }; - let dim = (rows as Ix, cols as Ix); + let dim = [rows as Ix, cols as Ix]; unsafe { let strides = dim.default_strides(); ArrayView::new_(data.as_ptr(), dim, strides) @@ -123,7 +123,7 @@ impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,); /// ``` pub fn arr2>(xs: &[V]) -> Array2 { let (m, n) = (xs.len() as Ix, V::len() as Ix); - let dim = (m, n); + let dim = [m, n]; let mut result = Vec::::with_capacity(dim.size()); for snd in xs { result.extend_from_slice(snd.as_init_slice()); diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 5eb989e34..5cd92e709 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -19,6 +19,7 @@ use linspace; use error::{self, ShapeError, ErrorKind}; use Indexes; use iterators::{to_vec, to_vec_mapped}; +use shape_builder::IntoShape; /// Constructor methods for one-dimensional arrays. /// @@ -140,12 +141,12 @@ impl ArrayBase /// ``` pub fn from_elem(shape: Sh, elem: A) -> Self where A: Clone, - Sh: Into>, + Sh: IntoShape, { // Note: We don't need to check the case of a size between // isize::MAX -> usize::MAX; in this case, the vec constructor itself // panics. - let shape = shape.into(); + let shape = shape.into_shape(); let size = size_checked_unwrap!(shape.dim); let v = vec![elem; size]; unsafe { Self::from_shape_vec_unchecked(shape, v) } @@ -156,7 +157,7 @@ impl ArrayBase /// **Panics** if the number of elements in `shape` would overflow usize. pub fn zeros(shape: Sh) -> Self where A: Clone + Zero, - Sh: Into>, + Sh: IntoShape, { Self::from_elem(shape, A::zero()) } @@ -166,9 +167,9 @@ impl ArrayBase /// **Panics** if the number of elements in `shape` would overflow usize. pub fn default(shape: Sh) -> Self where A: Default, - Sh: Into>, + Sh: IntoShape, { - let shape = shape.into(); + let shape = shape.into_shape(); let v = to_vec((0..shape.dim.size()).map(|_| A::default())); unsafe { Self::from_shape_vec_unchecked(shape, v) } } @@ -179,10 +180,10 @@ impl ArrayBase /// /// **Panics** if the number of elements in `shape` would overflow usize. pub fn from_shape_fn(shape: Sh, f: F) -> Self - where Sh: Into>, + where Sh: IntoShape, F: FnMut(D) -> A, { - let shape = shape.into(); + let shape = shape.into_shape(); let v = to_vec_mapped(Indexes::new(shape.dim.clone()), f); unsafe { Self::from_shape_vec_unchecked(shape, v) } } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 29af2a677..089498b27 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -46,6 +46,11 @@ impl ArrayBase where S: Data, D: Dimension /// Return the shape of the array. pub fn dim(&self) -> D { self.dim.clone() + //self.dim.as_tuple() + } + + pub fn dim_tuple(&self) -> D::Tuple { + self.dim.as_tuple() } /// Return the shape of the array as a slice. @@ -248,7 +253,10 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Note:** only unchecked for non-debug builds of ndarray. #[inline] - pub unsafe fn uget(&self, index: D) -> &A { + pub unsafe fn uget(&self, index: I) -> &A + where I: ::dimension::ToIndex, + { + let index = index.to_index(); arraytraits::debug_bounds_check(self, &index); let off = D::stride_offset(&index, &self.strides); &*self.ptr.offset(off) @@ -261,9 +269,11 @@ impl ArrayBase where S: Data, 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 uget_mut(&mut self, index: D) -> &mut A - where S: DataMut + pub unsafe fn uget_mut(&mut self, index: I) -> &mut A + where S: DataMut, + I: ::dimension::ToIndex, { + let index = index.to_index(); debug_assert!(self.data.is_unique()); arraytraits::debug_bounds_check(self, &index); let off = D::stride_offset(&index, &self.strides); @@ -621,8 +631,8 @@ impl ArrayBase where S: Data, D: Dimension ArrayBase { data: self.data, ptr: self.ptr, - dim: len, - strides: stride as Ix, + dim: [len], + strides: [stride as Ix], } } diff --git a/src/linalg/impl_linalg.rs b/src/linalg/impl_linalg.rs index 7e7b71080..ad55346af 100644 --- a/src/linalg/impl_linalg.rs +++ b/src/linalg/impl_linalg.rs @@ -40,7 +40,7 @@ const GEMM_BLAS_CUTOFF: usize = 7; type blas_index = c_int; // blas index type -impl ArrayBase +impl ArrayBase where S: Data, { /// Compute the dot product of one-dimensional arrays. @@ -49,14 +49,14 @@ impl ArrayBase /// of complex operands, and thus not their inner product). /// /// **Panics** if the arrays are not of the same length. - pub fn dot(&self, rhs: &ArrayBase) -> A + pub fn dot(&self, rhs: &ArrayBase) -> A where S2: Data, A: LinalgScalar, { self.dot_impl(rhs) } - fn dot_generic(&self, rhs: &ArrayBase) -> A + fn dot_generic(&self, rhs: &ArrayBase) -> A where S2: Data, A: LinalgScalar, { @@ -77,7 +77,7 @@ impl ArrayBase } #[cfg(not(feature="blas"))] - fn dot_impl(&self, rhs: &ArrayBase) -> A + fn dot_impl(&self, rhs: &ArrayBase) -> A where S2: Data, A: LinalgScalar, { @@ -85,7 +85,7 @@ impl ArrayBase } #[cfg(feature="blas")] - fn dot_impl(&self, rhs: &ArrayBase) -> A + fn dot_impl(&self, rhs: &ArrayBase) -> A where S2: Data, A: LinalgScalar, { @@ -199,7 +199,7 @@ impl Dot> for ArrayBase { let a = self.view(); let b = b.view(); - let ((m, k), (k2, n)) = (a.dim(), b.dim()); + let ((m, k), (k2, n)) = (a.dim_tuple(), b.dim_tuple()); if k != k2 || m.checked_mul(n).is_none() { return dot_shape_error(m, k, k2, n); } @@ -212,7 +212,7 @@ impl Dot> for ArrayBase let mut c; unsafe { v.set_len(m * n); - c = Array::from_shape_vec_unchecked((m, n).set_f(column_major), v); + c = Array::from_shape_vec_unchecked([m, n].set_f(column_major), v); } mat_mul_impl(A::one(), &a, &b, A::zero(), &mut c.view_mut()); c @@ -245,15 +245,15 @@ fn general_dot_shape_error(m: usize, k: usize, k2: usize, n: usize, c1: usize, c /// Return a result array with shape *M*. /// /// **Panics** if shapes are incompatible. -impl Dot> for ArrayBase +impl Dot> for ArrayBase where S: Data, S2: Data, A: LinalgScalar, { - type Output = Array; - fn dot(&self, rhs: &ArrayBase) -> Array + type Output = Array; + fn dot(&self, rhs: &ArrayBase) -> Array { - let ((m, a), n) = (self.dim(), rhs.dim()); + let ((m, a), n) = (self.dim_tuple(), rhs.dim_tuple()); if a != n { return dot_shape_error(m, a, n, 1); } @@ -266,7 +266,7 @@ impl Dot> for ArrayBase for (i, rr) in enumerate(&mut res_elems) { unsafe { *rr = (0..a).fold(A::zero(), - move |s, k| s + *self.uget((i, k)) * *rhs.uget(k) + move |s, k| s + *self.uget([i, k]) * *rhs.uget(k) ); } } @@ -312,7 +312,7 @@ fn mat_mul_impl
(alpha: A, { // size cutoff for using BLAS let cut = GEMM_BLAS_CUTOFF; - let ((mut m, a), (_, mut n)) = (lhs.dim, rhs.dim); + let ((mut m, a), (_, mut n)) = (lhs.dim_tuple(), rhs.dim_tuple()); if !(m > cut || n > cut || a > cut) || !(same_type::() || same_type::()) { return mat_mul_general(alpha, lhs, rhs, beta, c); @@ -351,15 +351,15 @@ fn mat_mul_impl(alpha: A, && blas_row_major_2d::<$ty, _>(&c_) { let (m, k) = match lhs_trans { - CblasNoTrans => lhs_.dim(), + CblasNoTrans => lhs_.dim_tuple(), _ => { - let (rows, cols) = lhs_.dim(); + let (rows, cols) = lhs_.dim_tuple(); (cols, rows) } }; let n = match rhs_trans { - CblasNoTrans => rhs_.dim().1, - _ => rhs_.dim().0, + CblasNoTrans => rhs_.dim()[1], + _ => rhs_.dim()[0], }; // adjust strides, these may [1, 1] for column matrices let lhs_stride = cmp::max(lhs_.strides()[0] as blas_index, k as blas_index); @@ -403,7 +403,7 @@ fn mat_mul_general(alpha: A, c: &mut ArrayViewMut2) where A: LinalgScalar, { - let ((m, k), (_, n)) = (lhs.dim, rhs.dim); + let ((m, k), (_, n)) = (lhs.dim_tuple(), rhs.dim_tuple()); // common parameters for gemm let ap = lhs.as_ptr(); @@ -486,8 +486,8 @@ pub fn general_mat_mul(alpha: A, S3: DataMut, A: LinalgScalar, { - let ((m, k), (k2, n)) = (a.dim(), b.dim()); - let (m2, n2) = c.dim(); + let ((m, k), (k2, n)) = (a.dim_tuple(), b.dim_tuple()); + let (m2, n2) = c.dim_tuple(); if k != k2 || m != m2 || n != n2 { return general_dot_shape_error(m, k, k2, n, m2, n2); } @@ -511,7 +511,7 @@ fn cast_as(a: &A) -> B { } #[cfg(feature="blas")] -fn blas_compat_1d(a: &ArrayBase) -> bool +fn blas_compat_1d(a: &ArrayBase) -> bool where S: Data, A: Any, S::Elem: Any, @@ -552,7 +552,7 @@ fn blas_row_major_2d(a: &ArrayBase) -> bool { return false; } - let (m, n) = a.dim(); + let (m, n) = a.dim_tuple(); if m > blas_index::max_value() as usize || n > blas_index::max_value() as usize { diff --git a/src/shape_builder.rs b/src/shape_builder.rs index 5001f1d6d..77345ff8f 100644 --- a/src/shape_builder.rs +++ b/src/shape_builder.rs @@ -1,6 +1,7 @@ use Dimension; use {Shape, StrideShape}; +use Ix; /// A trait for `Shape` and `D where D: Dimension` that allows /// customizing the memory layout (strides) of an array shape. @@ -15,6 +16,53 @@ pub trait ShapeBuilder { fn strides(self, strides: Self::Dim) -> StrideShape; } +pub trait IntoShape { + type Dim: Dimension; + fn into_shape(self) -> Shape; +} + +impl IntoShape for D { + type Dim = D; + fn into_shape(self) -> Shape { + Shape { + dim: self, + is_c: true, + } + } +} +/* +*/ + +impl IntoShape for () { + type Dim = [Ix; 0]; + fn into_shape(self) -> Shape { + Shape { + dim: [], + is_c: true, + } + } +} + +impl IntoShape for Ix { + type Dim = [Ix; 1]; + fn into_shape(self) -> Shape { + Shape { + dim: [self], + is_c: true, + } + } +} + +impl IntoShape for (Ix, Ix) { + type Dim = [Ix; 2]; + fn into_shape(self) -> Shape { + Shape { + dim: [self.0, self.1], + is_c: true, + } + } +} + impl From for Shape where D: Dimension { @@ -26,18 +74,36 @@ impl From for Shape } } -impl From for StrideShape - where D: Dimension +impl From for Shape<[Ix; 1]> { - fn from(d: D) -> Self { - StrideShape { - strides: d.default_strides(), - dim: d, - custom: false, + fn from(ix: Ix) -> Self { + Shape { + dim: [ix], + is_c: true, } } } +impl From<(Ix, Ix)> for Shape<[Ix; 2]> +{ + fn from(ix: (Ix, Ix)) -> Self { + Shape { + dim: [ix.0, ix.1], + is_c: true, + } + } +} + +impl From for StrideShape + where D: Dimension, + T: IntoShape, +{ + fn from(d: T) -> Self { + let shape = d.into_shape(); + StrideShape::from(shape) + } +} + impl From> for StrideShape where D: Dimension { diff --git a/tests/dimension.rs b/tests/dimension.rs index d8c88c696..a727e8ec6 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -22,8 +22,10 @@ fn remove_axis() let a = RcArray::::zeros((4,5)); a.subview(Axis(1), 0); + /* let a = RcArray::::zeros(vec![4,5,6]); let _b = a.into_subview(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]); + */ } From 06b053c05f78144d3aa3d6a41bbb4f0214d4a94e Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 003/107] Convert users of 0/1d to use Ix0/Ix1 functions --- src/aliases.rs | 5 +++++ src/free_functions.rs | 2 +- src/impl_constructors.rs | 2 +- src/impl_methods.rs | 2 +- src/iterators.rs | 6 +++--- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index 1c0ec6fe8..4b7e87ac3 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -3,6 +3,11 @@ use ::{Ix, Array, ArrayView, ArrayViewMut}; +#[allow(non_snake_case)] +pub fn Ix0() -> Ix0 { [] } +#[allow(non_snake_case)] +pub fn Ix1(i0: Ix) -> Ix1 { [i0] } + /// zero-dimensionial pub type Ix0 = [Ix; 0]; /// one-dimensional diff --git a/src/free_functions.rs b/src/free_functions.rs index 5bc12dbde..35c35b1c6 100644 --- a/src/free_functions.rs +++ b/src/free_functions.rs @@ -28,7 +28,7 @@ pub fn rcarr1(xs: &[A]) -> RcArray { /// Create a zero-dimensional array view borrowing `x`. pub fn aview0(x: &A) -> ArrayView0 { - unsafe { ArrayView::new_(x, (), ()) } + unsafe { ArrayView::new_(x, Ix0(), Ix0()) } } /// Create a one-dimensional array view with elements borrowing `xs`. diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 5cd92e709..f1d82b265 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -232,7 +232,7 @@ impl ArrayBase let dim = shape.dim; let strides = shape.strides; if dim.size_checked() != Some(v.len()) { - return Err(error::incompatible_shapes(&v.len(), &dim)); + return Err(error::incompatible_shapes(&Ix1(v.len()), &dim)); } unsafe { Ok(Self::from_vec_dim_stride_unchecked(dim, strides, v)) } } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 089498b27..34752f79c 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -1298,7 +1298,7 @@ impl ArrayBase where S: Data, D: Dimension // the 0th element. self.subview(axis, 0).map(|first_elt| { unsafe { - mapping(ArrayView::new_(first_elt, view_len, view_stride)) + mapping(ArrayView::new_(first_elt, Ix1(view_len), Ix1(view_stride))) } }) } diff --git a/src/iterators.rs b/src/iterators.rs index 65f5f40b7..598a179f8 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -126,7 +126,7 @@ impl<'a, A> Baseiter<'a, A, Ix1> { None => return None, Some(ix) => ix, }; - self.dim -= 1; + self.dim[0] -= 1; let offset = <_>::stride_offset(&self.dim, &self.strides); if index == self.dim { self.index = None; @@ -394,7 +394,7 @@ impl<'a, A, D> Iterator for InnerIter<'a, A, D> type Item = ArrayView<'a, A, Ix1>; fn next(&mut self) -> Option { self.iter.next().map(|ptr| { - unsafe { ArrayView::new_(ptr, self.inner_len, self.inner_stride as Ix) } + unsafe { ArrayView::new_(ptr, Ix1(self.inner_len), Ix1(self.inner_stride as Ix)) } }) } @@ -452,7 +452,7 @@ impl<'a, A, D> Iterator for InnerIterMut<'a, A, D> fn next(&mut self) -> Option { self.iter.next().map(|ptr| { unsafe { - ArrayViewMut::new_(ptr, self.inner_len, self.inner_stride as Ix) + ArrayViewMut::new_(ptr, Ix1(self.inner_len), Ix1(self.inner_stride as Ix)) } }) } From f58b5e260f9932d037bb68eaae31c4ea73336af4 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 004/107] Adjust .into_shape() to use IntoDimension --- src/dimension.rs | 6 ++++++ src/impl_methods.rs | 7 +++++-- src/shape_builder.rs | 11 +++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index eb420e1c4..b10417433 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -468,6 +468,12 @@ impl IntoDimension for (Ix, Ix) { fn into_dimension(self) -> [Ix; 2] { [self.0, self.1] } } +impl IntoDimension for D where D: Dimension { + type Dim = D; + #[inline] + fn into_dimension(self) -> Self { self } +} + pub trait Convert { type To; fn convert(self) -> Self::To; diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 34752f79c..3edd750b2 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -20,6 +20,8 @@ use iterators; use error::{self, ShapeError}; use super::zipsl; use super::ZipExt; +use shape_builder::IntoShape; +use dimension::IntoDimension; use { NdIndex, @@ -836,9 +838,10 @@ impl ArrayBase where S: Data, D: Dimension /// [3., 4.]]) /// ); /// ``` - pub fn into_shape(self, shape: E) -> Result, ShapeError> - where E: Dimension + pub fn into_shape(self, shape: E) -> Result, ShapeError> + where E: IntoDimension, { + let shape = shape.into_dimension(); if shape.size_checked() != Some(self.dim.size()) { return Err(error::incompatible_shapes(&self.dim, &shape)); } diff --git a/src/shape_builder.rs b/src/shape_builder.rs index 77345ff8f..40a38e8e0 100644 --- a/src/shape_builder.rs +++ b/src/shape_builder.rs @@ -2,6 +2,7 @@ use Dimension; use {Shape, StrideShape}; use Ix; +use dimension::IntoDimension; /// A trait for `Shape` and `D where D: Dimension` that allows /// customizing the memory layout (strides) of an array shape. @@ -21,17 +22,18 @@ pub trait IntoShape { fn into_shape(self) -> Shape; } -impl IntoShape for D { - type Dim = D; +impl IntoShape for D + where D: IntoDimension, +{ + type Dim = D::Dim; fn into_shape(self) -> Shape { Shape { - dim: self, + dim: self.into_dimension(), is_c: true, } } } /* -*/ impl IntoShape for () { type Dim = [Ix; 0]; @@ -62,6 +64,7 @@ impl IntoShape for (Ix, Ix) { } } } +*/ impl From for Shape where D: Dimension From d5cc148d9c395aad55b8d7012a7a015e7a6ebbb1 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 005/107] .reshape() and .broadcast() use conversion traits --- src/impl_methods.rs | 10 ++++++---- src/shape_builder.rs | 22 +++++++++++++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 3edd750b2..7456203cf 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -795,11 +795,12 @@ impl ArrayBase where S: Data, D: Dimension /// [3., 4.]]) /// ); /// ``` - pub fn reshape(&self, shape: E) -> ArrayBase + pub fn reshape(&self, shape: E) -> ArrayBase where S: DataShared + DataOwned, A: Clone, - E: Dimension, + E: IntoDimension, { + let shape = shape.into_dimension(); if shape.size_checked() != Some(self.dim.size()) { panic!("ndarray: incompatible shapes in reshape, attempted from: {:?}, to: {:?}", self.dim.slice(), @@ -894,8 +895,8 @@ impl ArrayBase where S: Data, D: Dimension /// == aview2(&[[1., 0.]; 10]) /// ); /// ``` - pub fn broadcast(&self, dim: E) -> Option> - where E: Dimension + pub fn broadcast(&self, dim: E) -> Option> + where E: IntoDimension { /// Return new stride when trying to grow `from` into shape `to` /// @@ -938,6 +939,7 @@ impl ArrayBase where S: Data, D: Dimension } Some(new_stride) } + let dim = dim.into_dimension(); // Note: zero strides are safe precisely because we return an read-only view let broadcast_strides = match upcast(&dim, &self.dim, &self.strides) { diff --git a/src/shape_builder.rs b/src/shape_builder.rs index 40a38e8e0..5097aa6d8 100644 --- a/src/shape_builder.rs +++ b/src/shape_builder.rs @@ -33,6 +33,14 @@ impl IntoShape for D } } } +impl IntoShape for Shape + where D: Dimension, +{ + type Dim = D; + fn into_shape(self) -> Shape { + self + } +} /* impl IntoShape for () { @@ -101,12 +109,19 @@ impl From for StrideShape where D: Dimension, T: IntoShape, { - fn from(d: T) -> Self { - let shape = d.into_shape(); - StrideShape::from(shape) + fn from(value: T) -> Self { + let shape = value.into_shape(); + let d = shape.dim; + let st = if shape.is_c { d.default_strides() } else { d.fortran_strides() }; + StrideShape { + strides: st, + dim: d, + custom: false, + } } } +/* impl From> for StrideShape where D: Dimension { @@ -120,6 +135,7 @@ impl From> for StrideShape } } } +*/ impl ShapeBuilder for D where D: Dimension From 23bebbe9bf156c2a4b82b27ae738ef5cbd0a1dd4 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 006/107] Use Ix2 in tests/array.rs --- tests/array.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/array.rs b/tests/array.rs index 73fc56aaa..9f6e15175 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -10,6 +10,7 @@ use ndarray::{ rcarr2, arr0, arr3, aview_mut1, + Ix2, }; use ndarray::Indexes; use itertools::free::enumerate; @@ -1053,7 +1054,7 @@ fn test_view_from_shape_ptr() { #[test] fn test_default() { - let a = as Default>::default(); + let a = as Default>::default(); assert_eq!(a, aview2(&[[0.0; 0]; 0])); From 8a4db802ac67dbe83cf3cf44108c686b387636b3 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 007/107] Use Array2 in oper.rs --- tests/oper.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/oper.rs b/tests/oper.rs index 3eb937f58..916415e74 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -5,6 +5,8 @@ use ndarray::prelude::*; use ndarray::{arr0, rcarr1, rcarr2}; use ndarray::{LinalgScalar, Data}; use ndarray::linalg::general_mat_mul; +use ndarray::Array2; +use ndarray::{Ix1, Ix2}; use std::fmt; use num_traits::Float; @@ -263,26 +265,26 @@ fn fold_and_sum() { } } -fn range_mat(m: Ix, n: Ix) -> Array { +fn range_mat(m: Ix, n: Ix) -> Array2 { Array::linspace(0., (m * n - 1) as f32, m * n).into_shape((m, n)).unwrap() } -fn range_mat64(m: Ix, n: Ix) -> Array { +fn range_mat64(m: Ix, n: Ix) -> Array2 { Array::linspace(0., (m * n - 1) as f64, m * n).into_shape((m, n)).unwrap() } -fn range_i32(m: Ix, n: Ix) -> Array { +fn range_i32(m: Ix, n: Ix) -> Array2 { Array::from_iter(0..(m * n) as i32).into_shape((m, n)).unwrap() } // simple, slow, correct (hopefully) mat mul -fn reference_mat_mul(lhs: &ArrayBase, rhs: &ArrayBase) - -> Array +fn reference_mat_mul(lhs: &ArrayBase, rhs: &ArrayBase) + -> Array2 where A: LinalgScalar, S: Data, S2: Data, { - let ((m, k), (k2, n)) = (lhs.dim(), rhs.dim()); + let ((m, k), (k2, n)) = (lhs.dim_tuple(), rhs.dim_tuple()); assert!(m.checked_mul(n).is_some()); assert_eq!(k, k2); let mut res_elems = Vec::::with_capacity(m * n); From 62caab792d1c02e5c29dae428543f2ce2441f7b8 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 008/107] Update tests/dimension.rs --- tests/dimension.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/dimension.rs b/tests/dimension.rs index a727e8ec6..1170e2409 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -12,9 +12,9 @@ use ndarray::{ #[test] fn remove_axis() { - assert_eq!(3.remove_axis(Axis(0)), ()); - assert_eq!((1, 2).remove_axis(Axis(0)), 2); - assert_eq!((4, 5, 6).remove_axis(Axis(1)), (4, 6)); + assert_eq!([3].remove_axis(Axis(0)), []); + assert_eq!([1, 2].remove_axis(Axis(0)), [2]); + assert_eq!([4, 5, 6].remove_axis(Axis(1)), [4, 6]); assert_eq!(vec![1,2].remove_axis(Axis(0)), vec![2]); assert_eq!(vec![4, 5, 6].remove_axis(Axis(1)), vec![4, 6]); @@ -50,14 +50,14 @@ fn fastest_varying_order() { let order = strides._fastest_varying_stride_order(); assert_eq!(order.slice(), &[3, 0, 2, 1]); - assert_eq!((1, 3)._fastest_varying_stride_order(), (0, 1)); - assert_eq!((7, 2)._fastest_varying_stride_order(), (1, 0)); - assert_eq!((6, 1, 3)._fastest_varying_stride_order(), (1, 2, 0)); + assert_eq!([1, 3]._fastest_varying_stride_order(), [0, 1]); + assert_eq!([7, 2]._fastest_varying_stride_order(), [1, 0]); + assert_eq!([6, 1, 3]._fastest_varying_stride_order(), [1, 2, 0]); // it's important that it produces distinct indices. Prefer the stable order // where 0 is before 1 when they are equal. - assert_eq!((2, 2)._fastest_varying_stride_order(), (0, 1)); - assert_eq!((2, 2, 1)._fastest_varying_stride_order(), (2, 0, 1)); - assert_eq!((2, 2, 3, 1, 2)._fastest_varying_stride_order(), (3, 0, 1, 4, 2)); + assert_eq!([2, 2]._fastest_varying_stride_order(), [0, 1]); + assert_eq!([2, 2, 1]._fastest_varying_stride_order(), [2, 0, 1]); + assert_eq!([2, 2, 3, 1, 2]._fastest_varying_stride_order(), [3, 0, 1, 4, 2]); } From 5fb5ae8c43c43830172fc17d777da690e36b19d2 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 009/107] Impl RemoveAxis for Ix1 --- src/dimension.rs | 59 +++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index b10417433..82067c5cf 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -14,6 +14,7 @@ use super::{Si, Ix, Ixs}; use super::{zipsl, zipsl_mut}; use error::{from_kind, ErrorKind, ShapeError}; use ZipExt; +use {Ix0, Ix1, Ix2}; /// Calculate offset from `Ix` stride converting sign properly #[inline] @@ -860,24 +861,23 @@ impl RemoveAxis for ($from $(,$more)*) ) ); -/* -impl RemoveAxis for Ix { - type Smaller = (); +impl RemoveAxis for Ix1 { + type Smaller = Ix0; #[inline] - fn remove_axis(&self, _: Axis) { } + fn remove_axis(&self, _: Axis) -> Ix0 { Ix0() } } -impl RemoveAxis for (Ix, Ix) { - type Smaller = Ix; +impl RemoveAxis for Ix2 { + type Smaller = Ix1; #[inline] - fn remove_axis(&self, axis: Axis) -> Ix { + fn remove_axis(&self, axis: Axis) -> Ix1 { let axis = axis.axis(); debug_assert!(axis < self.ndim()); - if axis == 0 { self.1 } else { self.0 } + if axis == 0 { Ix1(self[1]) } else { Ix1(self[0]) } } } -*/ +/* macro_rules! impl_shrink_recursive( ($ix:ident, ) => (impl_shrink!($ix,);); ($ix1:ident, $($ix:ident,)*) => ( @@ -885,34 +885,37 @@ macro_rules! impl_shrink_recursive( impl_shrink!($ix1, $($ix,)*); ) ); +*/ macro_rules! impl_remove_axis_array( - ($n:expr) => ( -impl RemoveAxis for [Ix; $n] -{ - type Smaller = [Ix; $n - 1]; - #[inline] - fn remove_axis(&self, axis: Axis) -> Self::Smaller { - let mut tup = [0; $n - 1]; + ($($n:expr),*) => ( + $( + impl RemoveAxis for [Ix; $n] { - let mut it = tup.slice_mut().iter_mut(); - for (i, &d) in self.slice().iter().enumerate() { - if i == axis.axis() { - continue; - } - for rr in it.by_ref() { - *rr = d; - break + type Smaller = [Ix; $n - 1]; + #[inline] + fn remove_axis(&self, axis: Axis) -> Self::Smaller { + let mut tup = [0; $n - 1]; + { + let mut it = tup.slice_mut().iter_mut(); + for (i, &d) in self.slice().iter().enumerate() { + if i == axis.axis() { + continue; + } + for rr in it.by_ref() { + *rr = d; + break + } + } } + tup } } - tup - } -} + )* ); ); -impl_remove_axis_array!(2); +impl_remove_axis_array!(); // 12 is the maximum number for having the Eq trait from libstd //impl_shrink_recursive!(Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix,); From 24d28843f24e74a251d1282506486c50f701aa6d Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 010/107] Update tests/stacking.rs to use Array2 --- tests/stacking.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/stacking.rs b/tests/stacking.rs index edf0f2485..4204ee48c 100644 --- a/tests/stacking.rs +++ b/tests/stacking.rs @@ -7,8 +7,7 @@ use ndarray::{ aview1, arr2, Axis, - Ix, - Array, + Array2, ErrorKind, }; @@ -39,6 +38,6 @@ fn stacking() { let res = ndarray::stack(Axis(2), &[a.view(), c.view()]); assert_eq!(res.unwrap_err().kind(), ErrorKind::OutOfBounds); - let res: Result, _> = ndarray::stack(Axis(0), &[]); + let res: Result, _> = ndarray::stack(Axis(0), &[]); assert_eq!(res.unwrap_err().kind(), ErrorKind::Unsupported); } From 61d723ffa1b91709e79a537152d4193d1294bd35 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 011/107] Improve Dimension::into_tuple --- src/dimension.rs | 8 ++++++-- src/impl_methods.rs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 82067c5cf..e443ff7c7 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -152,7 +152,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { } } - fn as_tuple(&self) -> Self::Tuple { + fn into_tuple(self) -> Self::Tuple { panic!() } @@ -648,7 +648,7 @@ unsafe impl Dimension for [Ix; 2] { #[inline] fn ndim(&self) -> usize { 2 } #[inline] - fn as_tuple(&self) -> Self::Tuple { + fn into_tuple(self) -> Self::Tuple { self.convert() } #[inline] @@ -821,6 +821,10 @@ unsafe impl Dimension for Vec fn ndim(&self) -> usize { self.len() } fn slice(&self) -> &[Ix] { self } fn slice_mut(&mut self) -> &mut [Ix] { self } + #[inline] + fn into_tuple(self) -> Self::Tuple { + self + } } /// Array shape with a next smaller dimension. diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 7456203cf..30e2d7698 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -52,7 +52,7 @@ impl ArrayBase where S: Data, D: Dimension } pub fn dim_tuple(&self) -> D::Tuple { - self.dim.as_tuple() + self.dim.clone().into_tuple() } /// Return the shape of the array as a slice. From 7dd57061cb2d21814b9c920c060eb93322689f39 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 012/107] Make indexed iterators produce a tuple of the indices by default --- src/arrayformat.rs | 2 ++ src/dimension.rs | 2 +- src/impl_methods.rs | 4 ++-- src/iterators.rs | 12 ++++++------ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 53232d94c..3ce83ad05 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -11,6 +11,7 @@ use super::{ Data, Dimension, }; +use dimension::IntoDimension; fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, mut format: F) @@ -37,6 +38,7 @@ fn format_array(view: &ArrayBase, f: &mut fmt::Formatter, // Simply use the indexed iterator, and take the index wraparounds // as cues for when to add []'s and how many to add. for (index, elt) in view.indexed_iter() { + let index = index.into_dimension(); let take_n = if ndim == 0 { 1 } else { ndim - 1 }; let mut update_index = false; for (i, (a, b)) in index.slice() diff --git a/src/dimension.rs b/src/dimension.rs index e443ff7c7..468485ed4 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -142,7 +142,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { /// The easiest way to create a `&SliceArg` is using the macro /// [`s![]`](macro.s!.html). type SliceArg: ?Sized + AsRef<[Si]>; - type Tuple; + type Tuple: IntoDimension; #[doc(hidden)] fn ndim(&self) -> usize; #[doc(hidden)] diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 30e2d7698..ffbc807fb 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -148,14 +148,14 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of indexes and references to the elements of the array. /// - /// Iterator element type is `(D, &A)`. + /// Iterator element type is `(D::Tuple, &A)`. pub fn indexed_iter(&self) -> Indexed { Indexed(self.view().into_elements_base()) } /// 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::Tuple, &mut A)`. pub fn indexed_iter_mut(&mut self) -> IndexedMut where S: DataMut, { diff --git a/src/iterators.rs b/src/iterators.rs index 598a179f8..573e40b75 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -259,16 +259,16 @@ impl<'a, A, D> ExactSizeIterator for Elements<'a, A, D> impl<'a, A, D: Dimension> Iterator for Indexed<'a, A, D> { - type Item = (D, &'a A); + type Item = (D::Tuple, &'a A); #[inline] - fn next(&mut self) -> Option<(D, &'a A)> { + fn next(&mut self) -> Option { let index = match self.0.inner.index { None => return None, Some(ref ix) => ix.clone(), }; match self.0.inner.next_ref() { None => None, - Some(p) => Some((index, p)), + Some(p) => Some((index.into_tuple(), p)), } } @@ -336,16 +336,16 @@ impl<'a, A> DoubleEndedIterator for ElementsBaseMut<'a, A, Ix1> { } impl<'a, A, D: Dimension> Iterator for IndexedMut<'a, A, D> { - type Item = (D, &'a mut A); + type Item = (D::Tuple, &'a mut A); #[inline] - fn next(&mut self) -> Option<(D, &'a mut A)> { + fn next(&mut self) -> Option { let index = match self.0.inner.index { None => return None, Some(ref ix) => ix.clone(), }; match self.0.inner.next_ref_mut() { None => None, - Some(p) => Some((index, p)), + Some(p) => Some((index.into_tuple(), p)), } } From dc647b7a3528112a638cb08ec0a82f9e2518d220 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 013/107] Update examples/convo.rs to compile --- examples/convo.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/convo.rs b/examples/convo.rs index a15132fa7..1149db5b4 100644 --- a/examples/convo.rs +++ b/examples/convo.rs @@ -18,8 +18,8 @@ type Kernel3x3 = [[A; 3]; 3]; fn conv_3x3(a: &ArrayView2, out: &mut ArrayViewMut2, kernel: &Kernel3x3) where F: Float, { - let (n, m) = a.dim(); - let (np, mp) = out.dim(); + let (n, m) = a.dim_tuple(); + let (np, mp) = out.dim_tuple(); if n < 3 || m < 3 { return; } From b0c20ea178375e76d805130f29d555a7e5dd5368 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 014/107] Make Indexes iterator produce a tuple of indices as well --- src/impl_constructors.rs | 2 +- src/indexes.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index f1d82b265..8fdf91364 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -181,7 +181,7 @@ impl ArrayBase /// **Panics** if the number of elements in `shape` would overflow usize. pub fn from_shape_fn(shape: Sh, f: F) -> Self where Sh: IntoShape, - F: FnMut(D) -> A, + F: FnMut(D::Tuple) -> A, { let shape = shape.into_shape(); let v = to_vec_mapped(Indexes::new(shape.dim.clone()), f); diff --git a/src/indexes.rs b/src/indexes.rs index 855b082ac..82be900b4 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -6,6 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use super::Dimension; +use dimension::IntoDimension; /// An iterator over the indexes of an array shape. /// @@ -18,7 +19,10 @@ pub struct Indexes { impl Indexes { /// Create an iterator over the array shape `dim`. - pub fn new(dim: D) -> Indexes { + pub fn new(shape: E) -> Indexes + where E: IntoDimension, + { + let dim = shape.into_dimension(); Indexes { index: dim.first_index(), dim: dim, @@ -29,15 +33,15 @@ impl Indexes { impl Iterator for Indexes where D: Dimension, { - type Item = D; + type Item = D::Tuple; #[inline] - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { let index = match self.index { None => return None, Some(ref ix) => ix.clone(), }; self.index = self.dim.next_for(index.clone()); - Some(index) + Some(index.into_tuple()) } fn size_hint(&self) -> (usize, Option) { From 3b645cc87f91de591c07e3232c61551e8523367f Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 015/107] Update NdIndex with new implementations --- src/aliases.rs | 5 +++++ src/dimension.rs | 43 +++++++++---------------------------------- 2 files changed, 14 insertions(+), 34 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index 4b7e87ac3..248985dfd 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -4,9 +4,14 @@ use ::{Ix, Array, ArrayView, ArrayViewMut}; #[allow(non_snake_case)] +#[inline(always)] pub fn Ix0() -> Ix0 { [] } #[allow(non_snake_case)] +#[inline(always)] pub fn Ix1(i0: Ix) -> Ix1 { [i0] } +#[allow(non_snake_case)] +#[inline(always)] +pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { [i0, i1] } /// zero-dimensionial pub type Ix0 = [Ix; 0]; diff --git a/src/dimension.rs b/src/dimension.rs index 468485ed4..b71135d4e 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -960,52 +960,27 @@ unsafe impl NdIndex for D } } -/* -unsafe impl NdIndex for [Ix; 0] { - type Dim = (); - #[inline] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { - dim.stride_offset_checked(strides, &()) - } -} -*/ - -/* -unsafe impl NdIndex for [Ix; 1] { - type Dim = Ix; +unsafe impl NdIndex for () { + type Dim = Ix0; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { - dim.stride_offset_checked(strides, &self[0]) + dim.stride_offset_checked(strides, &Ix0()) } } -*/ - -/* -unsafe impl NdIndex for [Ix; 2] { - type Dim = (Ix, Ix); - #[inline] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { - let index = (self[0], self[1]); - dim.stride_offset_checked(strides, &index) - } -} -*/ -unsafe impl NdIndex for [Ix; 3] { - type Dim = (Ix, Ix, Ix); +unsafe impl NdIndex for Ix { + type Dim = Ix1; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { - let index = (self[0], self[1], self[2]); - dim.stride_offset_checked(strides, &index) + dim.stride_offset_checked(strides, &Ix1(*self)) } } -unsafe impl NdIndex for [Ix; 4] { - type Dim = (Ix, Ix, Ix, Ix); +unsafe impl NdIndex for (Ix, Ix) { + type Dim = Ix2; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { - let index = (self[0], self[1], self[2], self[3]); - dim.stride_offset_checked(strides, &index) + dim.stride_offset_checked(strides, &Ix2(self.0, self.1)) } } From efcaced211e9e76757f9f7c0e114e2a63a18e694 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 016/107] Implement Ix3 as a fixed size array --- src/aliases.rs | 2 +- src/dimension.rs | 23 +++++++++++++++++++++++ src/free_functions.rs | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index 248985dfd..9ff94b80d 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -20,7 +20,7 @@ pub type Ix1 = [Ix; 1]; /// two-dimensional pub type Ix2 = [Ix; 2]; /// three-dimensional -pub type Ix3 = (Ix, Ix, Ix); +pub type Ix3 = [Ix; 3]; /// four-dimensional pub type Ix4 = (Ix, Ix, Ix, Ix); /// dynamic-dimensional diff --git a/src/dimension.rs b/src/dimension.rs index b71135d4e..5be15f519 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -469,6 +469,12 @@ impl IntoDimension for (Ix, Ix) { fn into_dimension(self) -> [Ix; 2] { [self.0, self.1] } } +impl IntoDimension for (Ix, Ix, Ix) { + type Dim = [Ix; 3]; + #[inline] + fn into_dimension(self) -> [Ix; 3] { [self.0, self.1, self.2] } +} + impl IntoDimension for D where D: Dimension { type Dim = D; #[inline] @@ -657,6 +663,21 @@ unsafe impl Dimension for [Ix; 2] { fn slice_mut(&mut self) -> &mut [Ix] { self } } +unsafe impl Dimension for [Ix; 3] { + type SliceArg = [Si; 3]; + type Tuple = (Ix, Ix, Ix); + #[inline] + fn ndim(&self) -> usize { 3 } + #[inline] + fn into_tuple(self) -> Self::Tuple { + self.convert() + } + #[inline] + fn slice(&self) -> &[Ix] { self } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self } +} + /* unsafe impl Dimension for (Ix, Ix) { @@ -733,6 +754,7 @@ unsafe impl Dimension for (Ix, Ix) { } */ +/* unsafe impl Dimension for (Ix, Ix, Ix) { type SliceArg = [Si; 3]; type Tuple = Self; @@ -790,6 +812,7 @@ unsafe impl Dimension for (Ix, Ix, Ix) { order } } +*/ macro_rules! large_dim { ($n:expr, $($ix:ident),+) => ( diff --git a/src/free_functions.rs b/src/free_functions.rs index 35c35b1c6..6a0619b17 100644 --- a/src/free_functions.rs +++ b/src/free_functions.rs @@ -159,7 +159,7 @@ pub fn rcarr2>(xs: &[V]) -> RcArray, U: FixedInitializer>(xs: &[V]) -> Array3 { - let dim = (xs.len() as Ix, V::len() as Ix, U::len() as Ix); + let dim = [xs.len() as Ix, V::len() as Ix, U::len() as Ix]; let mut result = Vec::::with_capacity(dim.size()); for snd in xs { for thr in snd.as_init_slice() { From 1045bc5d44b8f65e0b4ae6b12499155bda4ead59 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 017/107] Expand ShapeBuilder to cover IntoDimension --- src/shape_builder.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/shape_builder.rs b/src/shape_builder.rs index 5097aa6d8..76ae98be6 100644 --- a/src/shape_builder.rs +++ b/src/shape_builder.rs @@ -11,10 +11,11 @@ use dimension::IntoDimension; /// `Array::from_shape_vec`. pub trait ShapeBuilder { type Dim: Dimension; + type Strides; fn f(self) -> Shape; fn set_f(self, is_f: bool) -> Shape; - fn strides(self, strides: Self::Dim) -> StrideShape; + fn strides(self, strides: Self::Strides) -> StrideShape; } pub trait IntoShape { @@ -137,16 +138,17 @@ impl From> for StrideShape } */ -impl ShapeBuilder for D - where D: Dimension +impl ShapeBuilder for T + where T: IntoDimension { - type Dim = D; - fn f(self) -> Shape { self.set_f(true) } - fn set_f(self, is_f: bool) -> Shape { - Shape::from(self).set_f(is_f) + type Dim = T::Dim; + type Strides = T; + fn f(self) -> Shape { self.set_f(true) } + fn set_f(self, is_f: bool) -> Shape { + self.into_shape().set_f(is_f) } - fn strides(self, st: D) -> StrideShape { - Shape::from(self).strides(st) + fn strides(self, st: T) -> StrideShape { + self.into_shape().strides(st.into_dimension()) } } @@ -154,6 +156,7 @@ impl ShapeBuilder for Shape where D: Dimension { type Dim = D; + type Strides = D; fn f(self) -> Self { self.set_f(true) } fn set_f(mut self, is_f: bool) -> Self { self.is_c = !is_f; From 901813f013f82c841b9b3b6d0676d3baae08deb2 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 018/107] Add .into_tuple() impls and RemoveAxis for Ix3 --- src/dimension.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/dimension.rs b/src/dimension.rs index 5be15f519..123a29b57 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -580,6 +580,10 @@ unsafe impl Dimension for [Ix; 0] { fn slice_mut(&mut self) -> &mut [Ix] { self } #[inline] fn _fastest_varying_stride_order(&self) -> Self { [] } + #[inline] + fn into_tuple(self) -> Self::Tuple { + self.convert() + } } unsafe impl Dimension for [Ix; 1] { @@ -591,6 +595,10 @@ unsafe impl Dimension for [Ix; 1] { fn slice(&self) -> &[Ix] { self } #[inline] fn slice_mut(&mut self) -> &mut [Ix] { self } + #[inline] + fn into_tuple(self) -> Self::Tuple { + self[0] + } } /* @@ -942,7 +950,7 @@ macro_rules! impl_remove_axis_array( ); ); -impl_remove_axis_array!(); +impl_remove_axis_array!(3); // 12 is the maximum number for having the Eq trait from libstd //impl_shrink_recursive!(Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix,); From 801c44ae5c739d61636956f79709e2f1091ea7bc Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 019/107] Update tests/array.rs to use .dim_tuple() --- tests/array.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/array.rs b/tests/array.rs index 9f6e15175..b6bb4f420 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -10,7 +10,7 @@ use ndarray::{ rcarr2, arr0, arr3, aview_mut1, - Ix2, + Ix0, Ix2, }; use ndarray::Indexes; use itertools::free::enumerate; @@ -61,7 +61,7 @@ fn test_slice() } let vi = A.slice(s![1.., ..;2]); - assert_eq!(vi.dim(), (2, 2)); + assert_eq!(vi.dim(), [2, 2]); let vi = A.slice(&[S, S]); assert_eq!(vi.shape(), A.shape()); assert!(vi.iter().zip(A.iter()).all(|(a, b)| a == b)); @@ -154,7 +154,7 @@ fn test_negative_stride_rcarray() { let vi = mat.slice(&[S, Si(0, None, -1), Si(0, None, -1)]); - assert_eq!(vi.dim(), (2,4,2)); + assert_eq!(vi.shape(), &[2, 4, 2]); // Test against sequential iterator let seq = [7f32,6., 5.,4.,3.,2.,1.,0.,15.,14.,13., 12.,11., 10., 9., 8.]; for (a, b) in vi.clone().iter().zip(seq.iter()) { @@ -207,10 +207,10 @@ fn test_cow() fn test_sub() { let mat = RcArray::linspace(0., 15., 16).reshape((2, 4, 2)); - let s1 = mat.subview(Axis(0),0); - let s2 = mat.subview(Axis(0),1); - assert_eq!(s1.dim(), (4, 2)); - assert_eq!(s2.dim(), (4, 2)); + let s1 = mat.subview(Axis(0), 0); + let s2 = mat.subview(Axis(0), 1); + assert_eq!(s1.shape(), &[4, 2]); + assert_eq!(s2.shape(), &[4, 2]); let n = RcArray::linspace(8., 15., 8).reshape((4,2)); assert_eq!(n, s2); let m = RcArray::from_vec(vec![2., 3., 10., 11.]).reshape((2, 2)); @@ -248,14 +248,14 @@ fn test_select(){ fn diag() { let d = arr2(&[[1., 2., 3.0f32]]).into_diag(); - assert_eq!(d.dim(), 1); + assert_eq!(d.dim_tuple(), 1); let a = arr2(&[[1., 2., 3.0f32], [0., 0., 0.]]); let d = a.view().into_diag(); - assert_eq!(d.dim(), 2); + assert_eq!(d.dim_tuple(), 2); let d = arr2::(&[[]]).into_diag(); - assert_eq!(d.dim(), 0); + assert_eq!(d.dim_tuple(), 0); let d = RcArray::::zeros(()).into_diag(); - assert_eq!(d.dim(), 1); + assert_eq!(d.dim_tuple(), 1); } #[test] @@ -378,7 +378,7 @@ fn zero_axes() // we can even get a subarray of b let bsub = b.subview(Axis(0), 2); - assert_eq!(bsub.dim(), 0); + assert_eq!(bsub.dim_tuple(), 0); } #[test] @@ -486,7 +486,7 @@ fn from_vec_dim_stride_0d() { #[test] fn from_vec_dim_stride_2d_1() { let two = [1., 2.]; - let d = (2, 1); + let d = [2, 1]; let s = d.default_strides(); assert_matches!(Array::from_shape_vec(d.strides(s), two.to_vec()), Ok(_)); } @@ -494,7 +494,7 @@ fn from_vec_dim_stride_2d_1() { #[test] fn from_vec_dim_stride_2d_2() { let two = [1., 2.]; - let d = (1, 2); + let d = [1, 2]; let s = d.default_strides(); assert_matches!(Array::from_shape_vec(d.strides(s), two.to_vec()), Ok(_)); } @@ -1060,7 +1060,7 @@ fn test_default() { #[derive(Default, Debug, PartialEq)] struct Foo(i32); - let b = as Default>::default(); + let b = as Default>::default(); assert_eq!(b, arr0(Foo::default())); } From e81f057cd11728c3374c3e8dc6f734abaaa65257 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 020/107] Update examples/linalg.rs --- examples/linalg.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/linalg.rs b/examples/linalg.rs index 358f537a4..69f5a9432 100644 --- a/examples/linalg.rs +++ b/examples/linalg.rs @@ -12,14 +12,14 @@ use num_traits::Float; use num_complex::Complex; use std::ops::{Add, Sub, Mul, Div}; -use ndarray::{RcArray, Ix}; +use ndarray::{RcArray, Ix1, Ix2}; use ndarray::{rcarr1, rcarr2}; use ndarray::LinalgScalar; /// Column vector. -pub type Col = RcArray; +pub type Col = RcArray; /// Rectangular matrix. -pub type Mat = RcArray; +pub type Mat = RcArray; /// Trait union for a ring with 1. pub trait Ring : Clone + Zero + Add + Sub @@ -178,7 +178,7 @@ pub fn least_squares(a: &Mat, b: &Col) -> Col if ::is_complex() { // conjugate transpose // only elements below the diagonal have imag part - let (m, _) = L.dim(); + let (m, _) = L.dim_tuple(); for i in 1..m { for j in 0..i { let elt = &mut L[[i, j]]; @@ -210,7 +210,7 @@ pub fn least_squares(a: &Mat, b: &Col) -> Col pub fn cholesky(a: Mat) -> Mat { let z = A::zero(); - let (m, n) = a.dim(); + let (m, n) = a.dim_tuple(); assert!(m == n); // Perform the operation in-place on `a` let mut L = a; @@ -259,9 +259,9 @@ pub fn cholesky(a: Mat) -> Mat /// Solve *L x = b* where *L* is a lower triangular matrix. pub fn subst_fw(l: &Mat, b: &Col) -> Col { - let (m, n) = l.dim(); + let (m, n) = l.dim_tuple(); assert!(m == n); - assert!(m == b.dim()); + assert!(m == b.len()); let mut x = Col::zeros(m); for i in 0..m { // b_lx_sum = b[i] - Sum(for j = 0 .. i) L_ij x_j @@ -277,9 +277,9 @@ pub fn subst_fw(l: &Mat, b: &Col) -> Col /// Solve *U x = b* where *U* is an upper triangular matrix. pub fn subst_bw(u: &Mat, b: &Col) -> Col { - let (m, n) = u.dim(); + let (m, n) = u.dim_tuple(); assert!(m == n); - assert!(m == b.dim()); + assert!(m == b.len()); let mut x = Col::zeros(m); for i in (0..m).rev() { // b_ux_sum = b[i] - Sum(for j = i .. m) U_ij x_j From 4158bd9ae4624eea8c0e07c8ce06cb80759dc977 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 021/107] Update tests/broadcast.rs --- tests/broadcast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/broadcast.rs b/tests/broadcast.rs index daaa3cd9d..f6dd583cc 100644 --- a/tests/broadcast.rs +++ b/tests/broadcast.rs @@ -12,7 +12,7 @@ fn broadcast_1() let b = RcArray::linspace(0., 1., b_dim.size()).reshape(b_dim); assert!(b.broadcast(a.dim()).is_some()); - let c_dim = (2, 1); + let c_dim = [2, 1]; let c = RcArray::linspace(0., 1., c_dim.size()).reshape(c_dim); assert!(c.broadcast(1).is_none()); assert!(c.broadcast(()).is_none()); From a7cd9246aa7c1b987b2d587402bd18532856533f Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 022/107] Add Dimension method to convert it to an array view --- src/dimension.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dimension.rs b/src/dimension.rs index 123a29b57..e83f059af 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -15,6 +15,7 @@ use super::{zipsl, zipsl_mut}; use error::{from_kind, ErrorKind, ShapeError}; use ZipExt; use {Ix0, Ix1, Ix2}; +use {ArrayView1, ArrayViewMut1}; /// Calculate offset from `Ix` stride converting sign properly #[inline] @@ -163,6 +164,13 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { } } + fn array_view(&self) -> ArrayView1 { + ArrayView1::from(self.slice()) + } + fn array_view_mut(&mut self) -> ArrayViewMut1 { + ArrayViewMut1::from(self.slice_mut()) + } + #[doc(hidden)] fn size(&self) -> usize { self.slice().iter().fold(1, |s, &a| s * a as usize) From 902f3af40793e0516d1ba102e541beac67e723e4 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 023/107] Implement more dimension sizes --- src/dimension.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index e83f059af..1dd4a277c 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -461,16 +461,19 @@ pub trait IntoDimension { fn into_dimension(self) -> Self::Dim; } +/* impl IntoDimension for () { type Dim = [Ix; 0]; #[inline] fn into_dimension(self) -> [Ix; 0] { [] } } +*/ impl IntoDimension for Ix { type Dim = [Ix; 1]; #[inline] fn into_dimension(self) -> [Ix; 1] { [self] } } +/* impl IntoDimension for (Ix, Ix) { type Dim = [Ix; 2]; #[inline] @@ -482,6 +485,7 @@ impl IntoDimension for (Ix, Ix, Ix) { #[inline] fn into_dimension(self) -> [Ix; 3] { [self.0, self.1, self.2] } } +*/ impl IntoDimension for D where D: Dimension { type Dim = D; @@ -489,7 +493,7 @@ impl IntoDimension for D where D: Dimension { fn into_dimension(self) -> Self { self } } -pub trait Convert { +trait Convert { type To; fn convert(self) -> Self::To; } @@ -554,6 +558,14 @@ macro_rules! tuple_to_array { index!(array_expr [self] $n) } } + + impl IntoDimension for index!(tuple_type [Ix] $n) { + type Dim = [Ix; $n]; + fn into_dimension(self) -> Self::Dim { + index!(array_expr [self] $n) + } + } + )* } } @@ -832,17 +844,26 @@ unsafe impl Dimension for (Ix, Ix, Ix) { macro_rules! large_dim { ($n:expr, $($ix:ident),+) => ( - unsafe impl Dimension for ($($ix),+) { + unsafe impl Dimension for [Ix; $n] { type SliceArg = [Si; $n]; - type Tuple = Self; + type Tuple = ($($ix,)*); #[inline] fn ndim(&self) -> usize { $n } + #[inline] + fn into_tuple(self) -> Self::Tuple { + self.convert() + } + #[inline] + fn slice(&self) -> &[Ix] { self } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self } } ) } large_dim!(4, Ix, Ix, Ix, Ix); large_dim!(5, Ix, Ix, Ix, Ix, Ix); +/* large_dim!(6, Ix, Ix, Ix, Ix, Ix, Ix); large_dim!(7, Ix, Ix, Ix, Ix, Ix, Ix, Ix); large_dim!(8, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); @@ -850,6 +871,7 @@ large_dim!(9, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); large_dim!(10, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); large_dim!(11, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); large_dim!(12, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); +*/ /// Vec is a "dynamic" index, pretty hard to use when indexing, /// and memory wasteful, but it allows an arbitrary and dynamic number of axes. @@ -1022,6 +1044,28 @@ unsafe impl NdIndex for (Ix, Ix) { dim.stride_offset_checked(strides, &Ix2(self.0, self.1)) } } +unsafe impl NdIndex for (Ix, Ix, Ix) { + type Dim = [Ix; 3]; + #[inline] + fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + dim.stride_offset_checked(strides, &self.convert()) + } +} + +unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { + type Dim = [Ix; 4]; + #[inline] + fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + dim.stride_offset_checked(strides, &self.convert()) + } +} +unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { + type Dim = [Ix; 5]; + #[inline] + fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + dim.stride_offset_checked(strides, &self.convert()) + } +} unsafe impl<'a> NdIndex for &'a [Ix] { type Dim = Vec; From 12de9b1b794c8fdb2aff2ea04ba620e27c4e421c Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 024/107] Update tests to use array-shapes and .shape() --- tests/array.rs | 2 +- tests/broadcast.rs | 10 +++++----- tests/dimension.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/array.rs b/tests/array.rs index b6bb4f420..e9f261f40 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -128,7 +128,7 @@ fn test_multidim() *elt = i as u8; } } - assert_eq!(mat.dim(), (2,3,4,5,6)); + assert_eq!(mat.shape(), &[2,3,4,5,6]); } diff --git a/tests/broadcast.rs b/tests/broadcast.rs index f6dd583cc..1a03c7055 100644 --- a/tests/broadcast.rs +++ b/tests/broadcast.rs @@ -6,8 +6,8 @@ use ndarray::prelude::*; #[test] fn broadcast_1() { - let a_dim = (2, 4, 2, 2); - let b_dim = (2, 1, 2, 1); + let a_dim = [2, 4, 2, 2]; + let b_dim = [2, 1, 2, 1]; let a = RcArray::linspace(0., 1., a_dim.size()).reshape(a_dim); let b = RcArray::linspace(0., 1., b_dim.size()).reshape(b_dim); assert!(b.broadcast(a.dim()).is_some()); @@ -32,8 +32,8 @@ fn broadcast_1() #[test] fn test_add() { - let a_dim = (2, 4, 2, 2); - let b_dim = (2, 1, 2, 1); + let a_dim = [2, 4, 2, 2]; + let b_dim = [2, 1, 2, 1]; let mut a = RcArray::linspace(0.0, 1., a_dim.size()).reshape(a_dim); let b = RcArray::linspace(0.0, 1., b_dim.size()).reshape(b_dim); a += &b; @@ -44,7 +44,7 @@ fn test_add() #[test] #[should_panic] fn test_add_incompat() { - let a_dim = (2, 4, 2, 2); + let a_dim = [2, 4, 2, 2]; let mut a = RcArray::linspace(0.0, 1., a_dim.size()).reshape(a_dim); let incompat = RcArray::from_elem(3, 1.0f32); a += &incompat; diff --git a/tests/dimension.rs b/tests/dimension.rs index 1170e2409..649787187 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -46,7 +46,7 @@ fn dyn_dimension() #[test] fn fastest_varying_order() { - let strides = (2, 8, 4, 1); + let strides = [2, 8, 4, 1]; let order = strides._fastest_varying_stride_order(); assert_eq!(order.slice(), &[3, 0, 2, 1]); From 9c7efb339a7672af147db68cdd95a54282867ce8 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 025/107] Add back the special case methods for Ix1, Ix2 --- src/dimension.rs | 155 +++++++++++++++++++++++------------------------ 1 file changed, 77 insertions(+), 78 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 1dd4a277c..5238cd6bf 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -604,6 +604,10 @@ unsafe impl Dimension for [Ix; 0] { fn into_tuple(self) -> Self::Tuple { self.convert() } + #[inline] + fn next_for(&self, _index: Self) -> Option { + None + } } unsafe impl Dimension for [Ix; 1] { @@ -619,40 +623,35 @@ unsafe impl Dimension for [Ix; 1] { fn into_tuple(self) -> Self::Tuple { self[0] } -} - -/* -unsafe impl Dimension for Ix { - type SliceArg = [Si; 1]; - type Tuple = Ix; #[inline] - fn ndim(&self) -> usize { 1 } + fn next_for(&self, mut index: Self) -> Option { + index[0] += 1; + if index[0] < self[0] { + Some(index) + } else { + None + } + } + #[inline] - fn size(&self) -> usize { *self as usize } + fn size(&self) -> usize { self[0] } #[inline] - fn size_checked(&self) -> Option { Some(*self as usize) } + fn size_checked(&self) -> Option { Some(self[0]) } #[inline] - fn default_strides(&self) -> Self { 1 } + fn default_strides(&self) -> Self { + Ix1(1) + } #[inline] fn _fastest_varying_stride_order(&self) -> Self { - 0 + Ix1(0) } #[inline] - fn first_index(&self) -> Option { - if *self != 0 { - Some(0) - } else { - None - } - } - #[inline] - fn next_for(&self, mut index: Ix) -> Option { - index += 1; - if index < *self { - Some(index) + fn first_index(&self) -> Option { + if self[0] != 0 { + Some(Ix1(0)) } else { None } @@ -660,21 +659,20 @@ unsafe impl Dimension for Ix { /// Self is an index, return the stride offset #[inline] - fn stride_offset(index: &Ix, stride: &Ix) -> isize { - stride_offset(*index, *stride) + fn stride_offset(index: &Self, stride: &Self) -> isize { + stride_offset(index[0], stride[0]) } /// Return stride offset for this dimension and index. #[inline] - fn stride_offset_checked(&self, stride: &Ix, index: &Ix) -> Option { - if *index < *self { - Some(stride_offset(*index, *stride)) + fn stride_offset_checked(&self, stride: &Self, index: &Self) -> Option { + if index[0] < self[0] { + Some(stride_offset(index[0], stride[0])) } else { None } } } -*/ unsafe impl Dimension for [Ix; 2] { type SliceArg = [Si; 2]; @@ -689,36 +687,31 @@ unsafe impl Dimension for [Ix; 2] { fn slice(&self) -> &[Ix] { self } #[inline] fn slice_mut(&mut self) -> &mut [Ix] { self } -} - -unsafe impl Dimension for [Ix; 3] { - type SliceArg = [Si; 3]; - type Tuple = (Ix, Ix, Ix); - #[inline] - fn ndim(&self) -> usize { 3 } #[inline] - fn into_tuple(self) -> Self::Tuple { - self.convert() + fn next_for(&self, index: Self) -> Option { + let mut i = index[0]; + let mut j = index[1]; + let imax = self[0]; + let jmax = self[1]; + j += 1; + if j == jmax { + j = 0; + i += 1; + if i == imax { + return None; + } + } + Some([i, j]) } - #[inline] - fn slice(&self) -> &[Ix] { self } - #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self } -} - -/* -unsafe impl Dimension for (Ix, Ix) { - type SliceArg = [Si; 2]; - #[inline] - fn ndim(&self) -> usize { 2 } #[inline] - fn size(&self) -> usize { let (m, n) = *self; m as usize * n as usize } + fn size(&self) -> usize { self[0] * self[1] } #[inline] fn size_checked(&self) -> Option { - let (m, n) = *self; + let m = self[0]; + let n = self[1]; (m as usize).checked_mul(n as usize) } @@ -726,53 +719,45 @@ unsafe impl Dimension for (Ix, Ix) { fn default_strides(&self) -> Self { // Compute default array strides // Shape (a, b, c) => Give strides (b * c, c, 1) - (self.1, 1) + Ix2(self[1], 1) } #[inline] fn _fastest_varying_stride_order(&self) -> Self { - if self.0 as Ixs <= self.1 as Ixs { (0, 1) } else { (1, 0) } + if self[0] as Ixs <= self[1] as Ixs { Ix2(0, 1) } else { Ix2(1, 0) } } #[inline] - fn first_index(&self) -> Option<(Ix, Ix)> { - let (m, n) = *self; + fn first_index(&self) -> Option { + let m = self[0]; + let n = self[1]; if m != 0 && n != 0 { - Some((0, 0)) + Some(Ix2(0, 0)) } else { None } } - #[inline] - fn next_for(&self, index: (Ix, Ix)) -> Option<(Ix, Ix)> { - let (mut i, mut j) = index; - let (imax, jmax) = *self; - j += 1; - if j == jmax { - j = 0; - i += 1; - if i == imax { - return None; - } - } - Some((i, j)) - } /// Self is an index, return the stride offset #[inline] - fn stride_offset(index: &(Ix, Ix), strides: &(Ix, Ix)) -> isize { - let (i, j) = *index; - let (s, t) = *strides; + fn stride_offset(index: &Self, strides: &Self) -> isize { + let i = index[0]; + let j = index[1]; + let s = strides[0]; + let t = strides[1]; stride_offset(i, s) + stride_offset(j, t) } /// Return stride offset for this dimension and index. #[inline] - fn stride_offset_checked(&self, strides: &(Ix, Ix), index: &(Ix, Ix)) -> Option + fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option { - let (m, n) = *self; - let (i, j) = *index; - let (s, t) = *strides; + let m = self[0]; + let n = self[1]; + let i = index[0]; + let j = index[1]; + let s = strides[0]; + let t = strides[1]; if i < m && j < n { Some(stride_offset(i, s) + stride_offset(j, t)) } else { @@ -780,7 +765,21 @@ unsafe impl Dimension for (Ix, Ix) { } } } -*/ + +unsafe impl Dimension for [Ix; 3] { + type SliceArg = [Si; 3]; + type Tuple = (Ix, Ix, Ix); + #[inline] + fn ndim(&self) -> usize { 3 } + #[inline] + fn into_tuple(self) -> Self::Tuple { + self.convert() + } + #[inline] + fn slice(&self) -> &[Ix] { self } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self } +} /* unsafe impl Dimension for (Ix, Ix, Ix) { From 1283f0df51f3dbe7c4023e9ca1085fd150eb72f0 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 026/107] Use inline(always) for a few small functions --- src/dimension.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 5238cd6bf..a10f03684 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -18,7 +18,7 @@ use {Ix0, Ix1, Ix2}; use {ArrayView1, ArrayViewMut1}; /// Calculate offset from `Ix` stride converting sign properly -#[inline] +#[inline(always)] pub fn stride_offset(n: Ix, stride: Ix) -> isize { (n as isize) * ((stride as Ixs) as isize) } @@ -658,7 +658,7 @@ unsafe impl Dimension for [Ix; 1] { } /// Self is an index, return the stride offset - #[inline] + #[inline(always)] fn stride_offset(index: &Self, stride: &Self) -> isize { stride_offset(index[0], stride[0]) } @@ -739,7 +739,7 @@ unsafe impl Dimension for [Ix; 2] { } /// Self is an index, return the stride offset - #[inline] + #[inline(always)] fn stride_offset(index: &Self, strides: &Self) -> isize { let i = index[0]; let j = index[1]; From 4d2d82f2a1bf90ca77a736233a0f239121e6f300 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 027/107] Fix doctest for s![] --- src/si.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/si.rs b/src/si.rs index 8ae8ede3a..bc67874e8 100644 --- a/src/si.rs +++ b/src/si.rs @@ -108,13 +108,9 @@ pub const S: Si = Si(0, None, 1); /// #[macro_use] /// extern crate ndarray; /// -/// use ndarray::{ -/// ArrayView, -/// Ix, -/// Array, -/// }; +/// use ndarray::{Array2, ArrayView2}; /// -/// fn laplacian(v: &ArrayView) -> Array { +/// fn laplacian(v: &ArrayView2) -> Array2 { /// -4. * &v.slice(s![1..-1, 1..-1]) /// + v.slice(s![ ..-2, 1..-1]) /// + v.slice(s![1..-1, ..-2]) From b5758ef901c33e97979f978781424ba83e77a910 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 028/107] Remove ToIndex and use NdIndex for .uget() --- src/dimension.rs | 33 ++++++++------------------------- src/impl_methods.rs | 8 ++++---- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index a10f03684..c18488e1f 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -498,21 +498,6 @@ trait Convert { fn convert(self) -> Self::To; } -pub trait ToIndex { - fn to_index(self) -> D; -} - -impl ToIndex for T where T: Dimension { - fn to_index(self) -> Self { self } -} - -impl ToIndex<[Ix; 1]> for Ix { - fn to_index(self) -> [Ix; 1] { [self] } -} -impl ToIndex<[Ix; 2]> for (Ix, Ix) { - fn to_index(self) -> [Ix; 2] { [self.0, self.1] } -} - impl Convert for Ix { type To = [Ix; 1]; fn convert(self) -> Self::To { [self] } @@ -1005,8 +990,7 @@ impl RemoveAxis for Vec { /// ``` /// /// **Note** that `NdIndex` is implemented for all `D where D: Dimension`. -pub unsafe trait NdIndex : Debug { - type Dim: Dimension; +pub unsafe trait NdIndex : Debug + IntoDimension { #[doc(hidden)] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option; } @@ -1014,14 +998,12 @@ pub unsafe trait NdIndex : Debug { unsafe impl NdIndex for D where D: Dimension { - type Dim = D; fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, self) } } unsafe impl NdIndex for () { - type Dim = Ix0; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, &Ix0()) @@ -1029,7 +1011,6 @@ unsafe impl NdIndex for () { } unsafe impl NdIndex for Ix { - type Dim = Ix1; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, &Ix1(*self)) @@ -1037,14 +1018,12 @@ unsafe impl NdIndex for Ix { } unsafe impl NdIndex for (Ix, Ix) { - type Dim = Ix2; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, &Ix2(self.0, self.1)) } } unsafe impl NdIndex for (Ix, Ix, Ix) { - type Dim = [Ix; 3]; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, &self.convert()) @@ -1052,22 +1031,26 @@ unsafe impl NdIndex for (Ix, Ix, Ix) { } unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { - type Dim = [Ix; 4]; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, &self.convert()) } } unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { - type Dim = [Ix; 5]; #[inline] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, &self.convert()) } } -unsafe impl<'a> NdIndex for &'a [Ix] { +impl<'a> IntoDimension for &'a [Ix] { type Dim = Vec; + fn into_dimension(self) -> Self::Dim { + self.to_vec() + } +} + +unsafe impl<'a> NdIndex for &'a [Ix] { fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { let mut offset = 0; for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { diff --git a/src/impl_methods.rs b/src/impl_methods.rs index ffbc807fb..a043f058d 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -256,9 +256,9 @@ impl ArrayBase where S: Data, D: Dimension /// **Note:** only unchecked for non-debug builds of ndarray. #[inline] pub unsafe fn uget(&self, index: I) -> &A - where I: ::dimension::ToIndex, + where I: NdIndex, { - let index = index.to_index(); + let index = index.into_dimension(); arraytraits::debug_bounds_check(self, &index); let off = D::stride_offset(&index, &self.strides); &*self.ptr.offset(off) @@ -273,9 +273,9 @@ impl ArrayBase where S: Data, D: Dimension #[inline] pub unsafe fn uget_mut(&mut self, index: I) -> &mut A where S: DataMut, - I: ::dimension::ToIndex, + I: NdIndex, { - let index = index.to_index(); + let index = index.into_dimension(); debug_assert!(self.data.is_unique()); arraytraits::debug_bounds_check(self, &index); let off = D::stride_offset(&index, &self.strides); From e28303e7a5181de235fc1ac0c02a7abfd9c3a196 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 029/107] Update benchmarks --- benches/bench1.rs | 3 ++- benches/higher-order.rs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/benches/bench1.rs b/benches/bench1.rs index bd0bb82f7..fb74f5a3d 100644 --- a/benches/bench1.rs +++ b/benches/bench1.rs @@ -9,6 +9,7 @@ use ndarray::{ Array, Axis, Ix, + Array2, }; use ndarray::{arr0, arr1, arr2}; @@ -717,7 +718,7 @@ fn dot_extended(bench: &mut test::Bencher) { const MEAN_SUM_N: usize = 127; -fn range_mat(m: Ix, n: Ix) -> Array { +fn range_mat(m: Ix, n: Ix) -> Array2 { assert!(m * n != 0); Array::linspace(0., (m * n - 1) as f32, m * n).into_shape((m, n)).unwrap() } diff --git a/benches/higher-order.rs b/benches/higher-order.rs index a3f3c9098..0b2e5fe0a 100644 --- a/benches/higher-order.rs +++ b/benches/higher-order.rs @@ -23,7 +23,7 @@ fn map_regular(bench: &mut Bencher) #[bench] -fn map_stride(bench: &mut Bencher) +fn map_stride_f64(bench: &mut Bencher) { let a = Array::linspace(0., 127., N * 2).into_shape((X, Y * 2)).unwrap(); let av = a.slice(s![.., ..;2]); @@ -31,3 +31,14 @@ fn map_stride(bench: &mut Bencher) av.map(|&x| 2. * x) }); } + +#[bench] +fn map_stride_u32(bench: &mut Bencher) +{ + let a = Array::linspace(0., 127., N * 2).into_shape((X, Y * 2)).unwrap(); + let b = a.mapv(|x| x as u32); + let av = b.slice(s![.., ..;2]); + bench.iter(|| { + av.map(|&x| 2 * x) + }); +} From c36b6f363e6bbc412681b7c2a43def087bfcc586 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 030/107] Move some functionality into the Dimension trait (for special casing) --- src/dimension.rs | 84 +++++++++++++++++++++++++++++++++++++++++++-- src/impl_methods.rs | 22 ++---------- 2 files changed, 84 insertions(+), 22 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index c18488e1f..1c6319ec3 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -153,6 +153,10 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { } } + fn equal(&self, rhs: &Self) -> bool { + self.slice() == rhs.slice() + } + fn into_tuple(self) -> Self::Tuple { panic!() } @@ -292,6 +296,12 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { if self.ndim() == 0 { 0 } else { self.slice()[self.ndim() - 1] } } + #[doc(hidden)] + fn set_last_elem(&mut self, i: usize) { + let nd = self.ndim(); + self.slice_mut()[nd - 1] = i; + } + #[doc(hidden)] /// Modify dimension, strides and return data pointer offset /// @@ -345,6 +355,29 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { offset } + #[doc(hidden)] + fn is_contiguous(dim: &Self, strides: &Self) -> bool { + let defaults = dim.default_strides(); + if strides.equal(&defaults) { + return true; + } + if dim.ndim() == 1 { return false; } + let order = strides._fastest_varying_stride_order(); + let strides = strides.slice(); + + // FIXME: Negative strides + let dim_slice = dim.slice(); + let mut cstride = 1; + for &i in order.slice() { + // a dimension of length 1 can have unequal strides + if dim_slice[i] != 1 && strides[i] != cstride { + return false; + } + cstride *= dim_slice[i]; + } + true + } + /// Return the axis ordering corresponding to the fastest variation /// (in ascending order). /// @@ -618,6 +651,11 @@ unsafe impl Dimension for [Ix; 1] { } } + #[inline] + fn equal(&self, rhs: &Self) -> bool { + self[0] == rhs[0] + } + #[inline] fn size(&self) -> usize { self[0] } #[inline] @@ -679,16 +717,20 @@ unsafe impl Dimension for [Ix; 2] { let imax = self[0]; let jmax = self[1]; j += 1; - if j == jmax { + if j >= jmax { j = 0; i += 1; - if i == imax { + if i >= imax { return None; } } Some([i, j]) } + #[inline] + fn equal(&self, rhs: &Self) -> bool { + self[0] == rhs[0] && self[1] == rhs[1] + } #[inline] fn size(&self) -> usize { self[0] * self[1] } @@ -700,18 +742,56 @@ unsafe impl Dimension for [Ix; 2] { (m as usize).checked_mul(n as usize) } + #[inline] + fn last_elem(&self) -> usize { + self[1] + } + + #[inline] + fn set_last_elem(&mut self, i: usize) { + self[1] = i; + } + #[inline] fn default_strides(&self) -> Self { // Compute default array strides // Shape (a, b, c) => Give strides (b * c, c, 1) Ix2(self[1], 1) } + #[inline] + fn fortran_strides(&self) -> Self { + Ix2(1, self[0]) + } #[inline] fn _fastest_varying_stride_order(&self) -> Self { if self[0] as Ixs <= self[1] as Ixs { Ix2(0, 1) } else { Ix2(1, 0) } } + #[inline] + fn is_contiguous(dim: &Self, strides: &Self) -> bool { + let defaults = dim.default_strides(); + if strides.equal(&defaults) { + return true; + } + + if dim.ndim() == 1 { return false; } + let order = strides._fastest_varying_stride_order(); + let strides = strides.slice(); + + // FIXME: Negative strides + let dim_slice = dim.slice(); + let mut cstride = 1; + for &i in order.slice() { + // a dimension of length 1 can have unequal strides + if dim_slice[i] != 1 && strides[i] != cstride { + return false; + } + cstride *= dim_slice[i]; + } + true + } + #[inline] fn first_index(&self) -> Option { let m = self[0]; diff --git a/src/impl_methods.rs b/src/impl_methods.rs index a043f058d..3822b13c1 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -656,7 +656,7 @@ impl ArrayBase where S: Data, D: Dimension /// contiguous in memory, it has custom strides, etc. pub fn is_standard_layout(&self) -> bool { let defaults = self.dim.default_strides(); - if self.strides == defaults { + if self.strides.equal(&defaults) { return true; } if self.ndim() == 1 { return false; } @@ -672,25 +672,7 @@ impl ArrayBase where S: Data, D: Dimension } fn is_contiguous(&self) -> bool { - let defaults = self.dim.default_strides(); - if self.strides == defaults { - return true; - } - if self.ndim() == 1 { return false; } - let order = self.strides._fastest_varying_stride_order(); - let strides = self.strides.slice(); - - // FIXME: Negative strides - let dim = self.dim.slice(); - let mut cstride = 1; - for &i in order.slice() { - // a dimension of length 1 can have unequal strides - if dim[i] != 1 && strides[i] != cstride { - return false; - } - cstride *= dim[i]; - } - true + D::is_contiguous(&self.dim, &self.strides) } /// Return a pointer to the first element in the array. From 2fe2db37792be476096966bc5733bb5edfc8d775 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 031/107] Tune iterator's .fold() a small bit --- src/iterators.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/iterators.rs b/src/iterators.rs index 573e40b75..f95f1ea37 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -96,7 +96,7 @@ impl<'a, A, D: Dimension> Baseiter<'a, A, D> { where G: FnMut(Acc, *mut A) -> Acc, { let ndim = self.dim.ndim(); - assert!(ndim > 0); + debug_assert!(ndim > 0); let mut accum = init; loop { if let Some(mut index) = self.index.clone() { @@ -104,12 +104,19 @@ impl<'a, A, D: Dimension> Baseiter<'a, A, D> { let elem_index = index.last_elem(); let len = self.dim.last_elem(); let offset = D::stride_offset(&index, &self.strides); - for i in 0..len - elem_index { - unsafe { - accum = g(accum, self.ptr.offset(offset + i as isize * stride)); + unsafe { + let mut ptr = self.ptr.offset(offset); + let mut i = elem_index; + loop { + accum = g(accum, ptr); + i += 1; + if i >= len { + break; + } + ptr = ptr.offset(stride); } } - index.slice_mut()[ndim - 1] = len - 1; + index.set_last_elem(len - 1); self.index = self.dim.next_for(index); } else { break; @@ -180,7 +187,7 @@ impl<'a, A, D: Dimension> Iterator for ElementsBase<'a, A, D> { where G: FnMut(Acc, Self::Item) -> Acc, { unsafe { - self.inner.fold(init, |acc, ptr| g(acc, &*ptr)) + self.inner.fold(init, move |acc, ptr| g(acc, &*ptr)) } } } From 62539695275bbed43b96d7dff9dcac6e069e4611 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 032/107] Add another bench in higher-order --- benches/higher-order.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/benches/higher-order.rs b/benches/higher-order.rs index 0b2e5fe0a..9167d80b2 100644 --- a/benches/higher-order.rs +++ b/benches/higher-order.rs @@ -7,6 +7,7 @@ use test::Bencher; #[macro_use(s)] extern crate ndarray; use ndarray::prelude::*; +use ndarray::ArrayViewMut2; const N: usize = 1024; const X: usize = 64; @@ -22,6 +23,21 @@ fn map_regular(bench: &mut Bencher) } +pub fn double_array(mut a: ArrayViewMut2) { + a *= 2.0; +} + +#[bench] +fn map_stride_double_f64(bench: &mut Bencher) +{ + let mut a = Array::linspace(0., 127., N * 2).into_shape((X, Y * 2)).unwrap(); + let mut av = a.slice_mut(s![.., ..;2]); + bench.iter(|| { + double_array(av.view_mut()); + + }); +} + #[bench] fn map_stride_f64(bench: &mut Bencher) { From 4dee643579a75700484e77316ea98149f7586e25 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 033/107] Add crucial inlining directive to IntoDimension --- src/dimension.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dimension.rs b/src/dimension.rs index 1c6319ec3..5e9caff0f 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -579,6 +579,7 @@ macro_rules! tuple_to_array { impl IntoDimension for index!(tuple_type [Ix] $n) { type Dim = [Ix; $n]; + #[inline] fn into_dimension(self) -> Self::Dim { index!(array_expr [self] $n) } From 674b01257f09ad4fa9c4492bbea8adb681c52c92 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 034/107] Update benches --- benches/bench1.rs | 5 +++-- benches/higher-order.rs | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/benches/bench1.rs b/benches/bench1.rs index fb74f5a3d..4f1b2d6bd 100644 --- a/benches/bench1.rs +++ b/benches/bench1.rs @@ -9,6 +9,7 @@ use ndarray::{ Array, Axis, Ix, + Array1, Array2, }; use ndarray::{arr0, arr1, arr2}; @@ -292,8 +293,8 @@ fn add_2d_cutout(bench: &mut test::Bencher) #[bench] fn add_2d_broadcast_1_to_2(bench: &mut test::Bencher) { - let mut a = Array::::zeros((64, 64)); - let b = Array::::zeros(64); + let mut a = Array2::::zeros((64, 64)); + let b = Array1::::zeros(64); let bv = b.view(); bench.iter(|| { a += &bv; diff --git a/benches/higher-order.rs b/benches/higher-order.rs index 9167d80b2..7df304d11 100644 --- a/benches/higher-order.rs +++ b/benches/higher-order.rs @@ -30,7 +30,7 @@ pub fn double_array(mut a: ArrayViewMut2) { #[bench] fn map_stride_double_f64(bench: &mut Bencher) { - let mut a = Array::linspace(0., 127., N * 2).into_shape((X, Y * 2)).unwrap(); + let mut a = Array::linspace(0., 127., N * 2).into_shape([X, Y * 2]).unwrap(); let mut av = a.slice_mut(s![.., ..;2]); bench.iter(|| { double_array(av.view_mut()); @@ -41,7 +41,7 @@ fn map_stride_double_f64(bench: &mut Bencher) #[bench] fn map_stride_f64(bench: &mut Bencher) { - let a = Array::linspace(0., 127., N * 2).into_shape((X, Y * 2)).unwrap(); + let a = Array::linspace(0., 127., N * 2).into_shape([X, Y * 2]).unwrap(); let av = a.slice(s![.., ..;2]); bench.iter(|| { av.map(|&x| 2. * x) @@ -51,7 +51,7 @@ fn map_stride_f64(bench: &mut Bencher) #[bench] fn map_stride_u32(bench: &mut Bencher) { - let a = Array::linspace(0., 127., N * 2).into_shape((X, Y * 2)).unwrap(); + let a = Array::linspace(0., 127., N * 2).into_shape([X, Y * 2]).unwrap(); let b = a.mapv(|x| x as u32); let av = b.slice(s![.., ..;2]); bench.iter(|| { From fba724f226795fc42d5745e245440274b157ed28 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 035/107] Update inner iter to use last_elem() / set_last_elem() --- src/dimension.rs | 16 +++++++++++++--- src/impl_methods.rs | 8 +++++--- src/iterators.rs | 20 ++++++++++---------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 5e9caff0f..643cca34b 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -503,7 +503,7 @@ impl IntoDimension for () { */ impl IntoDimension for Ix { type Dim = [Ix; 1]; - #[inline] + #[inline(always)] fn into_dimension(self) -> [Ix; 1] { [self] } } /* @@ -522,7 +522,7 @@ impl IntoDimension for (Ix, Ix, Ix) { impl IntoDimension for D where D: Dimension { type Dim = D; - #[inline] + #[inline(always)] fn into_dimension(self) -> Self { self } } @@ -579,7 +579,7 @@ macro_rules! tuple_to_array { impl IntoDimension for index!(tuple_type [Ix] $n) { type Dim = [Ix; $n]; - #[inline] + #[inline(always)] fn into_dimension(self) -> Self::Dim { index!(array_expr [self] $n) } @@ -1074,6 +1074,9 @@ impl RemoveAxis for Vec { pub unsafe trait NdIndex : Debug + IntoDimension { #[doc(hidden)] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option; + fn index_unchecked(&self, strides: &Self::Dim) -> isize { + panic!() + } } unsafe impl NdIndex for D @@ -1082,6 +1085,9 @@ unsafe impl NdIndex for D fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, self) } + fn index_unchecked(&self, strides: &Self::Dim) -> isize { + D::stride_offset(self, strides) + } } unsafe impl NdIndex for () { @@ -1103,6 +1109,10 @@ unsafe impl NdIndex for (Ix, Ix) { fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { dim.stride_offset_checked(strides, &Ix2(self.0, self.1)) } + fn index_unchecked(&self, strides: &Self::Dim) -> isize { + stride_offset(self.0, strides[0]) + + stride_offset(self.1, strides[1]) + } } unsafe impl NdIndex for (Ix, Ix, Ix) { #[inline] diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 3822b13c1..42262322e 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -260,7 +260,8 @@ impl ArrayBase where S: Data, D: Dimension { let index = index.into_dimension(); arraytraits::debug_bounds_check(self, &index); - let off = D::stride_offset(&index, &self.strides); + //let off = D::stride_offset(&index, &self.strides); + let off = index.index_unchecked(&self.strides); &*self.ptr.offset(off) } @@ -278,7 +279,8 @@ impl ArrayBase where S: Data, D: Dimension let index = index.into_dimension(); debug_assert!(self.data.is_unique()); arraytraits::debug_bounds_check(self, &index); - let off = D::stride_offset(&index, &self.strides); + //let off = D::stride_offset(&index, &self.strides); + let off = index.index_unchecked(&self.strides); &mut *self.ptr.offset(off) } @@ -1048,7 +1050,7 @@ impl ArrayBase where S: Data, D: Dimension // otherwise, break the arrays up into their inner rows let mut try_slices = true; let mut rows = self.inner_iter_mut().zip(rhs.inner_iter()); - for (mut s_row, r_row) in &mut rows { + for (mut s_row, r_row) in rows { if try_slices { if let Some(self_s) = s_row.as_slice_mut() { if let Some(rhs_s) = r_row.as_slice() { diff --git a/src/iterators.rs b/src/iterators.rs index f95f1ea37..1a4988144 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -375,7 +375,8 @@ pub struct InnerIter<'a, A: 'a, D> { pub fn new_inner_iter(mut v: ArrayView) -> InnerIter where D: Dimension { - if v.shape().len() == 0 { + let ndim = v.ndim(); + if ndim == 0 { InnerIter { inner_len: 1, inner_stride: 1, @@ -383,10 +384,9 @@ pub fn new_inner_iter(mut v: ArrayView) -> InnerIter } } else { // Set length of innerest dimension to 1, start iteration - let ndim = v.shape().len(); - let len = v.shape()[ndim - 1]; - let stride = v.strides()[ndim - 1]; - v.dim.slice_mut()[ndim - 1] = 1; + let len = v.dim.last_elem(); + let stride = v.strides.last_elem() as isize; + v.dim.set_last_elem(1); InnerIter { inner_len: len, inner_stride: stride, @@ -432,7 +432,8 @@ pub struct InnerIterMut<'a, A: 'a, D> { pub fn new_inner_iter_mut(mut v: ArrayViewMut) -> InnerIterMut where D: Dimension, { - if v.shape().len() == 0 { + let ndim = v.ndim(); + if ndim == 0 { InnerIterMut { inner_len: 1, inner_stride: 1, @@ -440,10 +441,9 @@ pub fn new_inner_iter_mut(mut v: ArrayViewMut) -> InnerIterMut } } else { // Set length of innerest dimension to 1, start iteration - let ndim = v.shape().len(); - let len = v.shape()[ndim - 1]; - let stride = v.strides()[ndim - 1]; - v.dim.slice_mut()[ndim - 1] = 1; + let len = v.dim.last_elem(); + let stride = v.strides.last_elem() as isize; + v.dim.set_last_elem(1); InnerIterMut { inner_len: len, inner_stride: stride, From 2c5eda32d7bf41b82a3622cc98b3e39d00616d35 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 036/107] Clean up dimension a bit --- src/dimension.rs | 123 ++++++++++------------------------------------- 1 file changed, 26 insertions(+), 97 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 643cca34b..447896fe5 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -494,31 +494,11 @@ pub trait IntoDimension { fn into_dimension(self) -> Self::Dim; } -/* -impl IntoDimension for () { - type Dim = [Ix; 0]; - #[inline] - fn into_dimension(self) -> [Ix; 0] { [] } -} -*/ impl IntoDimension for Ix { type Dim = [Ix; 1]; #[inline(always)] fn into_dimension(self) -> [Ix; 1] { [self] } } -/* -impl IntoDimension for (Ix, Ix) { - type Dim = [Ix; 2]; - #[inline] - fn into_dimension(self) -> [Ix; 2] { [self.0, self.1] } -} - -impl IntoDimension for (Ix, Ix, Ix) { - type Dim = [Ix; 3]; - #[inline] - fn into_dimension(self) -> [Ix; 3] { [self.0, self.1, self.2] } -} -*/ impl IntoDimension for D where D: Dimension { type Dim = D; @@ -591,22 +571,6 @@ macro_rules! tuple_to_array { index_item!(tuple_to_array [] 6); -/* -unsafe impl Dimension for () { - type SliceArg = [Si; 0]; - type Tuple = (); - // empty product is 1 -> size is 1 - #[inline] - fn ndim(&self) -> usize { 0 } - #[inline] - fn slice(&self) -> &[Ix] { &[] } - #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut [] } - #[inline] - fn _fastest_varying_stride_order(&self) -> Self { } -} -*/ - unsafe impl Dimension for [Ix; 0] { type SliceArg = [Si; 0]; type Tuple = (); @@ -845,20 +809,23 @@ unsafe impl Dimension for [Ix; 3] { fn slice(&self) -> &[Ix] { self } #[inline] fn slice_mut(&mut self) -> &mut [Ix] { self } -} -/* -unsafe impl Dimension for (Ix, Ix, Ix) { - type SliceArg = [Si; 3]; - type Tuple = Self; - #[inline] - fn ndim(&self) -> usize { 3 } #[inline] - fn size(&self) -> usize { let (m, n, o) = *self; m as usize * n as usize * o as usize } + fn size(&self) -> usize { + let m = self[0]; + let n = self[1]; + let o = self[2]; + m as usize * n as usize * o as usize + } + #[inline] - fn next_for(&self, index: (Ix, Ix, Ix)) -> Option<(Ix, Ix, Ix)> { - let (mut i, mut j, mut k) = index; - let (imax, jmax, kmax) = *self; + fn next_for(&self, index: Self) -> Option { + let mut i = index[0]; + let mut j = index[1]; + let mut k = index[2]; + let imax = self[0]; + let jmax = self[1]; + let kmax = self[2]; k += 1; if k == kmax { k = 0; @@ -871,21 +838,25 @@ unsafe impl Dimension for (Ix, Ix, Ix) { } } } - Some((i, j, k)) + Some([i, j, k]) } /// Self is an index, return the stride offset #[inline] - fn stride_offset(index: &(Ix, Ix, Ix), strides: &(Ix, Ix, Ix)) -> isize { - let (i, j, k) = *index; - let (s, t, u) = *strides; + fn stride_offset(index: &Self, strides: &Self) -> isize { + let i = index[0]; + let j = index[1]; + let k = index[2]; + let s = strides[0]; + let t = strides[1]; + let u = strides[2]; stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u) } #[inline] fn _fastest_varying_stride_order(&self) -> Self { let mut stride = *self; - let mut order = (0, 1, 2); + let mut order = [0, 1, 2]; macro_rules! swap { ($stride:expr, $order:expr, $x:expr, $y:expr) => { if $stride[$x] > $stride[$y] { @@ -896,7 +867,6 @@ unsafe impl Dimension for (Ix, Ix, Ix) { } { // stable sorting network for 3 elements - let order = order.slice_mut(); let strides = stride.slice_mut(); swap![strides, order, 1, 2]; swap![strides, order, 0, 1]; @@ -905,7 +875,6 @@ unsafe impl Dimension for (Ix, Ix, Ix) { order } } -*/ macro_rules! large_dim { ($n:expr, $($ix:ident),+) => ( @@ -962,35 +931,6 @@ pub trait RemoveAxis : Dimension { fn remove_axis(&self, axis: Axis) -> Self::Smaller; } -macro_rules! impl_shrink( - ($_a:ident, ) => {}; // implement this case manually below - ($_a:ident, $_b:ident, ) => {}; // implement this case manually below - ($from:ident, $($more:ident,)*) => ( -impl RemoveAxis for ($from $(,$more)*) -{ - type Smaller = ($($more),*); - #[allow(unused_parens)] - #[inline] - fn remove_axis(&self, axis: Axis) -> ($($more),*) { - let mut tup = ($(0 as $more),*); - { - let mut it = tup.slice_mut().iter_mut(); - for (i, &d) in self.slice().iter().enumerate() { - if i == axis.axis() { - continue; - } - for rr in it.by_ref() { - *rr = d; - break - } - } - } - tup - } -} - ) -); - impl RemoveAxis for Ix1 { type Smaller = Ix0; #[inline] @@ -1007,16 +947,6 @@ impl RemoveAxis for Ix2 { } } -/* -macro_rules! impl_shrink_recursive( - ($ix:ident, ) => (impl_shrink!($ix,);); - ($ix1:ident, $($ix:ident,)*) => ( - impl_shrink_recursive!($($ix,)*); - impl_shrink!($ix1, $($ix,)*); - ) -); -*/ - macro_rules! impl_remove_axis_array( ($($n:expr),*) => ( $( @@ -1045,10 +975,9 @@ macro_rules! impl_remove_axis_array( ); ); -impl_remove_axis_array!(3); - // 12 is the maximum number for having the Eq trait from libstd -//impl_shrink_recursive!(Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix,); +impl_remove_axis_array!(3, 4, 5); + impl RemoveAxis for Vec { type Smaller = Vec; @@ -1075,7 +1004,7 @@ pub unsafe trait NdIndex : Debug + IntoDimension { #[doc(hidden)] fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option; fn index_unchecked(&self, strides: &Self::Dim) -> isize { - panic!() + unimplemented!() } } From adb9e42bc2c5df130e9eea63f82b6c1e1840015a Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 037/107] Generalize NdIndex to have dimension as a type parameter, not associated type This allows extending the number of types that can index for example an IxD-array. --- src/aliases.rs | 4 +++- src/arraytraits.rs | 6 +++--- src/dimension.rs | 50 +++++++++++++++++++++++++-------------------- src/impl_methods.rs | 14 +++++-------- 4 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index 9ff94b80d..97cc0f181 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -22,7 +22,9 @@ pub type Ix2 = [Ix; 2]; /// three-dimensional pub type Ix3 = [Ix; 3]; /// four-dimensional -pub type Ix4 = (Ix, Ix, Ix, Ix); +pub type Ix4 = [Ix; 4]; +/// five-dimensional +pub type Ix5 = [Ix; 5]; /// dynamic-dimensional pub type IxDyn = Vec; diff --git a/src/arraytraits.rs b/src/arraytraits.rs index f6a3f2148..a58a19be0 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -48,7 +48,7 @@ macro_rules! debug_bounds_check { #[inline(always)] pub fn debug_bounds_check(_a: &ArrayBase, _index: &I) where D: Dimension, - I: NdIndex, + I: NdIndex, S: Data, { debug_bounds_check!(_a, *_index); @@ -59,7 +59,7 @@ pub fn debug_bounds_check(_a: &ArrayBase, _index: &I) /// **Panics** if index is out of bounds. impl Index for ArrayBase where D: Dimension, - I: NdIndex, + I: NdIndex, S: Data, { type Output = S::Elem; @@ -75,7 +75,7 @@ impl Index for ArrayBase /// **Panics** if index is out of bounds. impl IndexMut for ArrayBase where D: Dimension, - I: NdIndex, + I: NdIndex, S: DataMut, { #[inline] diff --git a/src/dimension.rs b/src/dimension.rs index 447896fe5..889745c21 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -14,7 +14,7 @@ use super::{Si, Ix, Ixs}; use super::{zipsl, zipsl_mut}; use error::{from_kind, ErrorKind, ShapeError}; use ZipExt; -use {Ix0, Ix1, Ix2}; +use {Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, IxDyn}; use {ArrayView1, ArrayViewMut1}; /// Calculate offset from `Ix` stride converting sign properly @@ -1000,65 +1000,71 @@ impl RemoveAxis for Vec { /// ``` /// /// **Note** that `NdIndex` is implemented for all `D where D: Dimension`. -pub unsafe trait NdIndex : Debug + IntoDimension { +pub unsafe trait NdIndex : Debug { #[doc(hidden)] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option; - fn index_unchecked(&self, strides: &Self::Dim) -> isize { + fn index_checked(&self, dim: &E, strides: &E) -> Option; + fn index_unchecked(&self, strides: &E) -> isize { unimplemented!() } } -unsafe impl NdIndex for D +unsafe impl NdIndex for D where D: Dimension { - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + fn index_checked(&self, dim: &D, strides: &D) -> Option { dim.stride_offset_checked(strides, self) } - fn index_unchecked(&self, strides: &Self::Dim) -> isize { + fn index_unchecked(&self, strides: &D) -> isize { D::stride_offset(self, strides) } } -unsafe impl NdIndex for () { +unsafe impl NdIndex for () { #[inline] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + fn index_checked(&self, dim: &Ix0, strides: &Ix0) -> Option { dim.stride_offset_checked(strides, &Ix0()) } + fn index_unchecked(&self, strides: &Ix0) -> isize { + 0 + } } -unsafe impl NdIndex for Ix { +unsafe impl NdIndex for Ix { #[inline] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + fn index_checked(&self, dim: &Ix1, strides: &Ix1) -> Option { dim.stride_offset_checked(strides, &Ix1(*self)) } + fn index_unchecked(&self, strides: &Ix1) -> isize { + stride_offset(*self, strides[0]) + } } -unsafe impl NdIndex for (Ix, Ix) { +unsafe impl NdIndex for (Ix, Ix) { #[inline] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { dim.stride_offset_checked(strides, &Ix2(self.0, self.1)) } - fn index_unchecked(&self, strides: &Self::Dim) -> isize { + fn index_unchecked(&self, strides: &Ix2) -> isize { stride_offset(self.0, strides[0]) + stride_offset(self.1, strides[1]) } } -unsafe impl NdIndex for (Ix, Ix, Ix) { +unsafe impl NdIndex for (Ix, Ix, Ix) { #[inline] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { dim.stride_offset_checked(strides, &self.convert()) } } -unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { +unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { #[inline] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option { dim.stride_offset_checked(strides, &self.convert()) } } -unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { +unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { #[inline] - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { + fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option { dim.stride_offset_checked(strides, &self.convert()) } } @@ -1070,8 +1076,8 @@ impl<'a> IntoDimension for &'a [Ix] { } } -unsafe impl<'a> NdIndex for &'a [Ix] { - fn index_checked(&self, dim: &Self::Dim, strides: &Self::Dim) -> Option { +unsafe impl<'a> NdIndex for &'a [Ix] { + fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { let mut offset = 0; for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { if i >= d { diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 42262322e..abdccdb14 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -231,7 +231,7 @@ impl ArrayBase where S: Data, D: Dimension /// ); /// ``` pub fn get(&self, index: I) -> Option<&A> - where I: NdIndex, + where I: NdIndex, { let ptr = self.ptr; index.index_checked(&self.dim, &self.strides) @@ -242,7 +242,7 @@ impl ArrayBase where S: Data, D: Dimension /// if the index is out of bounds. pub fn get_mut(&mut self, index: I) -> Option<&mut A> where S: DataMut, - I: NdIndex, + I: NdIndex, { let ptr = self.as_mut_ptr(); index.index_checked(&self.dim, &self.strides) @@ -256,11 +256,9 @@ impl ArrayBase where S: Data, D: Dimension /// **Note:** only unchecked for non-debug builds of ndarray. #[inline] pub unsafe fn uget(&self, index: I) -> &A - where I: NdIndex, + where I: NdIndex, { - let index = index.into_dimension(); arraytraits::debug_bounds_check(self, &index); - //let off = D::stride_offset(&index, &self.strides); let off = index.index_unchecked(&self.strides); &*self.ptr.offset(off) } @@ -274,12 +272,10 @@ impl ArrayBase where S: Data, D: Dimension #[inline] pub unsafe fn uget_mut(&mut self, index: I) -> &mut A where S: DataMut, - I: NdIndex, + I: NdIndex, { - let index = index.into_dimension(); debug_assert!(self.data.is_unique()); arraytraits::debug_bounds_check(self, &index); - //let off = D::stride_offset(&index, &self.strides); let off = index.index_unchecked(&self.strides); &mut *self.ptr.offset(off) } @@ -291,7 +287,7 @@ impl ArrayBase where S: Data, D: Dimension /// ***Panics*** if an index is out of bounds. pub fn swap(&mut self, index1: I, index2: I) where S: DataMut, - I: NdIndex, + I: NdIndex, { let ptr1: *mut _ = &mut self[index1]; let ptr2: *mut _ = &mut self[index2]; From c07e5cb9520b92daa0594d74f93dd2645d436847 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 20:30:17 +0100 Subject: [PATCH 038/107] =?UTF-8?q?Rename=20dim=5Ftuple=20=E2=86=92=20dim?= =?UTF-8?q?=5Fpattern,=20into=5Ftuple=20=E2=86=92=20into=5Fpattern=20and?= =?UTF-8?q?=20D::Tuple=20=E2=86=92=20D::Pattern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/convo.rs | 4 ++-- examples/linalg.rs | 8 ++++---- src/dimension.rs | 43 ++++++++++++++++++++------------------- src/impl_constructors.rs | 2 +- src/impl_methods.rs | 9 ++++---- src/indexes.rs | 4 ++-- src/iterators.rs | 8 ++++---- src/linalg/impl_linalg.rs | 18 ++++++++-------- tests/array.rs | 10 ++++----- tests/oper.rs | 2 +- 10 files changed, 55 insertions(+), 53 deletions(-) diff --git a/examples/convo.rs b/examples/convo.rs index 1149db5b4..a944e635a 100644 --- a/examples/convo.rs +++ b/examples/convo.rs @@ -18,8 +18,8 @@ type Kernel3x3 = [[A; 3]; 3]; fn conv_3x3(a: &ArrayView2, out: &mut ArrayViewMut2, kernel: &Kernel3x3) where F: Float, { - let (n, m) = a.dim_tuple(); - let (np, mp) = out.dim_tuple(); + let (n, m) = a.dim_pattern(); + let (np, mp) = out.dim_pattern(); if n < 3 || m < 3 { return; } diff --git a/examples/linalg.rs b/examples/linalg.rs index 69f5a9432..3d602dd80 100644 --- a/examples/linalg.rs +++ b/examples/linalg.rs @@ -178,7 +178,7 @@ pub fn least_squares(a: &Mat, b: &Col) -> Col if ::is_complex() { // conjugate transpose // only elements below the diagonal have imag part - let (m, _) = L.dim_tuple(); + let (m, _) = L.dim_pattern(); for i in 1..m { for j in 0..i { let elt = &mut L[[i, j]]; @@ -210,7 +210,7 @@ pub fn least_squares(a: &Mat, b: &Col) -> Col pub fn cholesky(a: Mat) -> Mat { let z = A::zero(); - let (m, n) = a.dim_tuple(); + let (m, n) = a.dim_pattern(); assert!(m == n); // Perform the operation in-place on `a` let mut L = a; @@ -259,7 +259,7 @@ pub fn cholesky(a: Mat) -> Mat /// Solve *L x = b* where *L* is a lower triangular matrix. pub fn subst_fw(l: &Mat, b: &Col) -> Col { - let (m, n) = l.dim_tuple(); + let (m, n) = l.dim_pattern(); assert!(m == n); assert!(m == b.len()); let mut x = Col::zeros(m); @@ -277,7 +277,7 @@ pub fn subst_fw(l: &Mat, b: &Col) -> Col /// Solve *U x = b* where *U* is an upper triangular matrix. pub fn subst_bw(u: &Mat, b: &Col) -> Col { - let (m, n) = u.dim_tuple(); + let (m, n) = u.dim_pattern(); assert!(m == n); assert!(m == b.len()); let mut x = Col::zeros(m); diff --git a/src/dimension.rs b/src/dimension.rs index 889745c21..9f96d7513 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -131,19 +131,22 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { /// `SliceArg` is the type which is used to specify slicing for this /// dimension. /// - /// For the fixed size dimensions (tuples) it is a fixed size array - /// of the correct size, which you pass by reference. For the `Vec` - /// dimension it is a slice. + /// For the fixed size dimensions it is a fixed size array of the correct + /// size, which you pass by reference. For the `Vec` dimension it is + /// a slice. /// - /// - For `Ix`: `[Si; 1]` - /// - For `(Ix, Ix)`: `[Si; 2]` + /// - For `Ix1`: `[Si; 1]` + /// - For `Ix2`: `[Si; 2]` /// - and so on.. /// - For `Vec`: `[Si]` /// /// The easiest way to create a `&SliceArg` is using the macro /// [`s![]`](macro.s!.html). type SliceArg: ?Sized + AsRef<[Si]>; - type Tuple: IntoDimension; + /// Pattern matching friendly form of the dimension value. + /// + /// Usually a tuple. + type Pattern: IntoDimension; #[doc(hidden)] fn ndim(&self) -> usize; #[doc(hidden)] @@ -157,9 +160,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { self.slice() == rhs.slice() } - fn into_tuple(self) -> Self::Tuple { - panic!() - } + fn into_pattern(self) -> Self::Pattern; #[doc(hidden)] fn slice_mut(&mut self) -> &mut [Ix] { @@ -573,7 +574,7 @@ index_item!(tuple_to_array [] 6); unsafe impl Dimension for [Ix; 0] { type SliceArg = [Si; 0]; - type Tuple = (); + type Pattern = (); // empty product is 1 -> size is 1 #[inline] fn ndim(&self) -> usize { 0 } @@ -584,7 +585,7 @@ unsafe impl Dimension for [Ix; 0] { #[inline] fn _fastest_varying_stride_order(&self) -> Self { [] } #[inline] - fn into_tuple(self) -> Self::Tuple { + fn into_pattern(self) -> Self::Pattern { self.convert() } #[inline] @@ -595,7 +596,7 @@ unsafe impl Dimension for [Ix; 0] { unsafe impl Dimension for [Ix; 1] { type SliceArg = [Si; 1]; - type Tuple = Ix; + type Pattern = Ix; #[inline] fn ndim(&self) -> usize { 1 } #[inline] @@ -603,7 +604,7 @@ unsafe impl Dimension for [Ix; 1] { #[inline] fn slice_mut(&mut self) -> &mut [Ix] { self } #[inline] - fn into_tuple(self) -> Self::Tuple { + fn into_pattern(self) -> Self::Pattern { self[0] } #[inline] @@ -664,11 +665,11 @@ unsafe impl Dimension for [Ix; 1] { unsafe impl Dimension for [Ix; 2] { type SliceArg = [Si; 2]; - type Tuple = (Ix, Ix); + type Pattern = (Ix, Ix); #[inline] fn ndim(&self) -> usize { 2 } #[inline] - fn into_tuple(self) -> Self::Tuple { + fn into_pattern(self) -> Self::Pattern { self.convert() } #[inline] @@ -798,11 +799,11 @@ unsafe impl Dimension for [Ix; 2] { unsafe impl Dimension for [Ix; 3] { type SliceArg = [Si; 3]; - type Tuple = (Ix, Ix, Ix); + type Pattern = (Ix, Ix, Ix); #[inline] fn ndim(&self) -> usize { 3 } #[inline] - fn into_tuple(self) -> Self::Tuple { + fn into_pattern(self) -> Self::Pattern { self.convert() } #[inline] @@ -880,11 +881,11 @@ macro_rules! large_dim { ($n:expr, $($ix:ident),+) => ( unsafe impl Dimension for [Ix; $n] { type SliceArg = [Si; $n]; - type Tuple = ($($ix,)*); + type Pattern = ($($ix,)*); #[inline] fn ndim(&self) -> usize { $n } #[inline] - fn into_tuple(self) -> Self::Tuple { + fn into_pattern(self) -> Self::Pattern { self.convert() } #[inline] @@ -912,12 +913,12 @@ large_dim!(12, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); unsafe impl Dimension for Vec { type SliceArg = [Si]; - type Tuple = Self; + type Pattern = Self; fn ndim(&self) -> usize { self.len() } fn slice(&self) -> &[Ix] { self } fn slice_mut(&mut self) -> &mut [Ix] { self } #[inline] - fn into_tuple(self) -> Self::Tuple { + fn into_pattern(self) -> Self::Pattern { self } } diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 8fdf91364..caa2ed05e 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -181,7 +181,7 @@ impl ArrayBase /// **Panics** if the number of elements in `shape` would overflow usize. pub fn from_shape_fn(shape: Sh, f: F) -> Self where Sh: IntoShape, - F: FnMut(D::Tuple) -> A, + F: FnMut(D::Pattern) -> A, { let shape = shape.into_shape(); let v = to_vec_mapped(Indexes::new(shape.dim.clone()), f); diff --git a/src/impl_methods.rs b/src/impl_methods.rs index abdccdb14..94ecee5ee 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -51,8 +51,9 @@ impl ArrayBase where S: Data, D: Dimension //self.dim.as_tuple() } - pub fn dim_tuple(&self) -> D::Tuple { - self.dim.clone().into_tuple() + /// Return the shape of the array as the "pattern" type (usually a tuple). + pub fn dim_pattern(&self) -> D::Pattern { + self.dim.clone().into_pattern() } /// Return the shape of the array as a slice. @@ -148,14 +149,14 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator of indexes and references to the elements of the array. /// - /// Iterator element type is `(D::Tuple, &A)`. + /// Iterator element type is `(D::Pattern, &A)`. pub fn indexed_iter(&self) -> Indexed { Indexed(self.view().into_elements_base()) } /// Return an iterator of indexes and mutable references to the elements of the array. /// - /// Iterator element type is `(D::Tuple, &mut A)`. + /// Iterator element type is `(D::Pattern, &mut A)`. pub fn indexed_iter_mut(&mut self) -> IndexedMut where S: DataMut, { diff --git a/src/indexes.rs b/src/indexes.rs index 82be900b4..7744b9d9e 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -33,7 +33,7 @@ impl Indexes { impl Iterator for Indexes where D: Dimension, { - type Item = D::Tuple; + type Item = D::Pattern; #[inline] fn next(&mut self) -> Option { let index = match self.index { @@ -41,7 +41,7 @@ impl Iterator for Indexes Some(ref ix) => ix.clone(), }; self.index = self.dim.next_for(index.clone()); - Some(index.into_tuple()) + Some(index.into_pattern()) } fn size_hint(&self) -> (usize, Option) { diff --git a/src/iterators.rs b/src/iterators.rs index 1a4988144..2c31570a3 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -266,7 +266,7 @@ impl<'a, A, D> ExactSizeIterator for Elements<'a, A, D> impl<'a, A, D: Dimension> Iterator for Indexed<'a, A, D> { - type Item = (D::Tuple, &'a A); + type Item = (D::Pattern, &'a A); #[inline] fn next(&mut self) -> Option { let index = match self.0.inner.index { @@ -275,7 +275,7 @@ impl<'a, A, D: Dimension> Iterator for Indexed<'a, A, D> { }; match self.0.inner.next_ref() { None => None, - Some(p) => Some((index.into_tuple(), p)), + Some(p) => Some((index.into_pattern(), p)), } } @@ -343,7 +343,7 @@ impl<'a, A> DoubleEndedIterator for ElementsBaseMut<'a, A, Ix1> { } impl<'a, A, D: Dimension> Iterator for IndexedMut<'a, A, D> { - type Item = (D::Tuple, &'a mut A); + type Item = (D::Pattern, &'a mut A); #[inline] fn next(&mut self) -> Option { let index = match self.0.inner.index { @@ -352,7 +352,7 @@ impl<'a, A, D: Dimension> Iterator for IndexedMut<'a, A, D> { }; match self.0.inner.next_ref_mut() { None => None, - Some(p) => Some((index.into_tuple(), p)), + Some(p) => Some((index.into_pattern(), p)), } } diff --git a/src/linalg/impl_linalg.rs b/src/linalg/impl_linalg.rs index ad55346af..f9f62f49a 100644 --- a/src/linalg/impl_linalg.rs +++ b/src/linalg/impl_linalg.rs @@ -199,7 +199,7 @@ impl Dot> for ArrayBase { let a = self.view(); let b = b.view(); - let ((m, k), (k2, n)) = (a.dim_tuple(), b.dim_tuple()); + let ((m, k), (k2, n)) = (a.dim_pattern(), b.dim_pattern()); if k != k2 || m.checked_mul(n).is_none() { return dot_shape_error(m, k, k2, n); } @@ -253,7 +253,7 @@ impl Dot> for ArrayBase type Output = Array; fn dot(&self, rhs: &ArrayBase) -> Array { - let ((m, a), n) = (self.dim_tuple(), rhs.dim_tuple()); + let ((m, a), n) = (self.dim_pattern(), rhs.dim_pattern()); if a != n { return dot_shape_error(m, a, n, 1); } @@ -312,7 +312,7 @@ fn mat_mul_impl(alpha: A, { // size cutoff for using BLAS let cut = GEMM_BLAS_CUTOFF; - let ((mut m, a), (_, mut n)) = (lhs.dim_tuple(), rhs.dim_tuple()); + let ((mut m, a), (_, mut n)) = (lhs.dim_pattern(), rhs.dim_pattern()); if !(m > cut || n > cut || a > cut) || !(same_type::() || same_type::()) { return mat_mul_general(alpha, lhs, rhs, beta, c); @@ -351,9 +351,9 @@ fn mat_mul_impl(alpha: A, && blas_row_major_2d::<$ty, _>(&c_) { let (m, k) = match lhs_trans { - CblasNoTrans => lhs_.dim_tuple(), + CblasNoTrans => lhs_.dim_pattern(), _ => { - let (rows, cols) = lhs_.dim_tuple(); + let (rows, cols) = lhs_.dim_pattern(); (cols, rows) } }; @@ -403,7 +403,7 @@ fn mat_mul_general(alpha: A, c: &mut ArrayViewMut2) where A: LinalgScalar, { - let ((m, k), (_, n)) = (lhs.dim_tuple(), rhs.dim_tuple()); + let ((m, k), (_, n)) = (lhs.dim_pattern(), rhs.dim_pattern()); // common parameters for gemm let ap = lhs.as_ptr(); @@ -486,8 +486,8 @@ pub fn general_mat_mul(alpha: A, S3: DataMut, A: LinalgScalar, { - let ((m, k), (k2, n)) = (a.dim_tuple(), b.dim_tuple()); - let (m2, n2) = c.dim_tuple(); + let ((m, k), (k2, n)) = (a.dim_pattern(), b.dim_pattern()); + let (m2, n2) = c.dim_pattern(); if k != k2 || m != m2 || n != n2 { return general_dot_shape_error(m, k, k2, n, m2, n2); } @@ -552,7 +552,7 @@ fn blas_row_major_2d(a: &ArrayBase) -> bool { return false; } - let (m, n) = a.dim_tuple(); + let (m, n) = a.dim_pattern(); if m > blas_index::max_value() as usize || n > blas_index::max_value() as usize { diff --git a/tests/array.rs b/tests/array.rs index e9f261f40..73c2d69f9 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -248,14 +248,14 @@ fn test_select(){ fn diag() { let d = arr2(&[[1., 2., 3.0f32]]).into_diag(); - assert_eq!(d.dim_tuple(), 1); + assert_eq!(d.dim_pattern(), 1); let a = arr2(&[[1., 2., 3.0f32], [0., 0., 0.]]); let d = a.view().into_diag(); - assert_eq!(d.dim_tuple(), 2); + assert_eq!(d.dim_pattern(), 2); let d = arr2::(&[[]]).into_diag(); - assert_eq!(d.dim_tuple(), 0); + assert_eq!(d.dim_pattern(), 0); let d = RcArray::::zeros(()).into_diag(); - assert_eq!(d.dim_tuple(), 1); + assert_eq!(d.dim_pattern(), 1); } #[test] @@ -378,7 +378,7 @@ fn zero_axes() // we can even get a subarray of b let bsub = b.subview(Axis(0), 2); - assert_eq!(bsub.dim_tuple(), 0); + assert_eq!(bsub.dim_pattern(), 0); } #[test] diff --git a/tests/oper.rs b/tests/oper.rs index 916415e74..2c00110d3 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -284,7 +284,7 @@ fn reference_mat_mul(lhs: &ArrayBase, rhs: &ArrayBase S: Data, S2: Data, { - let ((m, k), (k2, n)) = (lhs.dim_tuple(), rhs.dim_tuple()); + let ((m, k), (k2, n)) = (lhs.dim_pattern(), rhs.dim_pattern()); assert!(m.checked_mul(n).is_some()); assert_eq!(k, k2); let mut res_elems = Vec::::with_capacity(m * n); From 91d82c8ed0f1b35be00d5c33d65625300edf2d2e Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 30 Oct 2016 23:53:36 +0100 Subject: [PATCH 039/107] Add dimension/index newtype --- src/aliases.rs | 44 +++++++++--- src/arraytraits.rs | 4 +- src/dimension.rs | 137 +++++++++++++++++++++++++++----------- src/free_functions.rs | 8 +-- src/impl_methods.rs | 6 +- src/linalg/impl_linalg.rs | 4 +- tests/array.rs | 6 +- tests/broadcast.rs | 13 ++-- tests/dimension.rs | 25 +++---- 9 files changed, 166 insertions(+), 81 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index 97cc0f181..8833d18d5 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -5,28 +5,52 @@ use ::{Ix, Array, ArrayView, ArrayViewMut}; #[allow(non_snake_case)] #[inline(always)] -pub fn Ix0() -> Ix0 { [] } +pub fn Ix0() -> Ix0 { Dim([]) } #[allow(non_snake_case)] #[inline(always)] -pub fn Ix1(i0: Ix) -> Ix1 { [i0] } +pub fn Ix1(i0: Ix) -> Ix1 { Dim([i0]) } #[allow(non_snake_case)] #[inline(always)] -pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { [i0, i1] } +pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { Dim([i0, i1]) } +#[allow(non_snake_case)] +#[inline(always)] +pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 { Dim([i0, i1, i2]) } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] +pub struct Dim(pub I); /// zero-dimensionial -pub type Ix0 = [Ix; 0]; +pub type Ix0 = Dim<[Ix; 0]>; /// one-dimensional -pub type Ix1 = [Ix; 1]; +pub type Ix1 = Dim<[Ix; 1]>; /// two-dimensional -pub type Ix2 = [Ix; 2]; +pub type Ix2 = Dim<[Ix; 2]>; /// three-dimensional -pub type Ix3 = [Ix; 3]; +pub type Ix3 = Dim<[Ix; 3]>; /// four-dimensional -pub type Ix4 = [Ix; 4]; +pub type Ix4 = Dim<[Ix; 4]>; /// five-dimensional -pub type Ix5 = [Ix; 5]; +pub type Ix5 = Dim<[Ix; 5]>; /// dynamic-dimensional -pub type IxDyn = Vec; +pub type IxDyn = Dim>; + +impl PartialEq for Dim + where I: PartialEq, +{ + fn eq(&self, rhs: &I) -> bool { + self.0 == *rhs + } +} + +use std::ops::{Deref, DerefMut}; + +impl Deref for Dim { + type Target = I; + fn deref(&self) -> &I { &self.0 } +} +impl DerefMut for Dim +{ + fn deref_mut(&mut self) -> &mut I { &mut self.0 } +} /// zero-dimensional array pub type Array0 = Array; diff --git a/src/arraytraits.rs b/src/arraytraits.rs index a58a19be0..7e4739c76 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -221,7 +221,7 @@ impl<'a, A, Slice: ?Sized> From<&'a Slice> for ArrayBase, Ix1> fn from(slice: &'a Slice) -> Self { let xs = slice.as_ref(); unsafe { - Self::new_(xs.as_ptr(), [xs.len()], [1]) + Self::new_(xs.as_ptr(), Ix1(xs.len()), Ix1(1)) } } } @@ -247,7 +247,7 @@ impl<'a, A, Slice: ?Sized> From<&'a mut Slice> for ArrayBase fn from(slice: &'a mut Slice) -> Self { let xs = slice.as_mut(); unsafe { - Self::new_(xs.as_mut_ptr(), [xs.len()], [1]) + Self::new_(xs.as_mut_ptr(), Ix1(xs.len()), Ix1(1)) } } } diff --git a/src/dimension.rs b/src/dimension.rs index 9f96d7513..7a88763a7 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -16,6 +16,7 @@ use error::{from_kind, ErrorKind, ShapeError}; use ZipExt; use {Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, IxDyn}; use {ArrayView1, ArrayViewMut1}; +use aliases::Dim; /// Calculate offset from `Ix` stride converting sign properly #[inline(always)] @@ -496,9 +497,9 @@ pub trait IntoDimension { } impl IntoDimension for Ix { - type Dim = [Ix; 1]; + type Dim = Ix1; #[inline(always)] - fn into_dimension(self) -> [Ix; 1] { [self] } + fn into_dimension(self) -> Ix1 { Ix1(self) } } impl IntoDimension for D where D: Dimension { @@ -507,14 +508,20 @@ impl IntoDimension for D where D: Dimension { fn into_dimension(self) -> Self { self } } +impl IntoDimension for Vec { + type Dim = IxDyn; + #[inline(always)] + fn into_dimension(self) -> Self::Dim { Dim(self) } +} + trait Convert { type To; fn convert(self) -> Self::To; } impl Convert for Ix { - type To = [Ix; 1]; - fn convert(self) -> Self::To { [self] } + type To = Ix1; + fn convert(self) -> Self::To { Ix1(self) } } /* */ @@ -552,17 +559,17 @@ macro_rules! tuple_to_array { } impl Convert for index!(tuple_type [T] $n) { - type To = [T; $n]; + type To = Dim<[T; $n]>; fn convert(self) -> Self::To { - index!(array_expr [self] $n) + Dim(index!(array_expr [self] $n)) } } impl IntoDimension for index!(tuple_type [Ix] $n) { - type Dim = [Ix; $n]; + type Dim = Dim<[Ix; $n]>; #[inline(always)] fn into_dimension(self) -> Self::Dim { - index!(array_expr [self] $n) + Dim(index!(array_expr [self] $n)) } } @@ -572,18 +579,18 @@ macro_rules! tuple_to_array { index_item!(tuple_to_array [] 6); -unsafe impl Dimension for [Ix; 0] { +unsafe impl Dimension for Ix0 { type SliceArg = [Si; 0]; type Pattern = (); // empty product is 1 -> size is 1 #[inline] fn ndim(&self) -> usize { 0 } #[inline] - fn slice(&self) -> &[Ix] { self } + fn slice(&self) -> &[Ix] { &self.0 } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } #[inline] - fn _fastest_varying_stride_order(&self) -> Self { [] } + fn _fastest_varying_stride_order(&self) -> Self { Ix0() } #[inline] fn into_pattern(self) -> Self::Pattern { self.convert() @@ -594,15 +601,15 @@ unsafe impl Dimension for [Ix; 0] { } } -unsafe impl Dimension for [Ix; 1] { +unsafe impl Dimension for Ix1 { type SliceArg = [Si; 1]; type Pattern = Ix; #[inline] fn ndim(&self) -> usize { 1 } #[inline] - fn slice(&self) -> &[Ix] { self } + fn slice(&self) -> &[Ix] { &self.0 } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } #[inline] fn into_pattern(self) -> Self::Pattern { self[0] @@ -663,7 +670,7 @@ unsafe impl Dimension for [Ix; 1] { } } -unsafe impl Dimension for [Ix; 2] { +unsafe impl Dimension for Ix2 { type SliceArg = [Si; 2]; type Pattern = (Ix, Ix); #[inline] @@ -673,9 +680,9 @@ unsafe impl Dimension for [Ix; 2] { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { self } + fn slice(&self) -> &[Ix] { &self.0 } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } #[inline] fn next_for(&self, index: Self) -> Option { let mut i = index[0]; @@ -690,7 +697,7 @@ unsafe impl Dimension for [Ix; 2] { return None; } } - Some([i, j]) + Some(Ix2(i, j)) } #[inline] @@ -797,7 +804,7 @@ unsafe impl Dimension for [Ix; 2] { } } -unsafe impl Dimension for [Ix; 3] { +unsafe impl Dimension for Ix3 { type SliceArg = [Si; 3]; type Pattern = (Ix, Ix, Ix); #[inline] @@ -807,9 +814,9 @@ unsafe impl Dimension for [Ix; 3] { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { self } + fn slice(&self) -> &[Ix] { &self.0 } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } #[inline] fn size(&self) -> usize { @@ -839,7 +846,7 @@ unsafe impl Dimension for [Ix; 3] { } } } - Some([i, j, k]) + Some(Ix3(i, j, k)) } /// Self is an index, return the stride offset @@ -857,7 +864,7 @@ unsafe impl Dimension for [Ix; 3] { #[inline] fn _fastest_varying_stride_order(&self) -> Self { let mut stride = *self; - let mut order = [0, 1, 2]; + let mut order = Ix3(0, 1, 2); macro_rules! swap { ($stride:expr, $order:expr, $x:expr, $y:expr) => { if $stride[$x] > $stride[$y] { @@ -879,7 +886,7 @@ unsafe impl Dimension for [Ix; 3] { macro_rules! large_dim { ($n:expr, $($ix:ident),+) => ( - unsafe impl Dimension for [Ix; $n] { + unsafe impl Dimension for Dim<[Ix; $n]> { type SliceArg = [Si; $n]; type Pattern = ($($ix,)*); #[inline] @@ -889,9 +896,9 @@ macro_rules! large_dim { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { self } + fn slice(&self) -> &[Ix] { &self.0 } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } } ) } @@ -910,7 +917,7 @@ large_dim!(12, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); /// Vec is a "dynamic" index, pretty hard to use when indexing, /// and memory wasteful, but it allows an arbitrary and dynamic number of axes. -unsafe impl Dimension for Vec +unsafe impl Dimension for Dim> { type SliceArg = [Si]; type Pattern = Self; @@ -951,12 +958,12 @@ impl RemoveAxis for Ix2 { macro_rules! impl_remove_axis_array( ($($n:expr),*) => ( $( - impl RemoveAxis for [Ix; $n] + impl RemoveAxis for Dim<[Ix; $n]> { - type Smaller = [Ix; $n - 1]; + type Smaller = Dim<[Ix; $n - 1]>; #[inline] fn remove_axis(&self, axis: Axis) -> Self::Smaller { - let mut tup = [0; $n - 1]; + let mut tup = Dim([0; $n - 1]); { let mut it = tup.slice_mut().iter_mut(); for (i, &d) in self.slice().iter().enumerate() { @@ -980,9 +987,9 @@ macro_rules! impl_remove_axis_array( impl_remove_axis_array!(3, 4, 5); -impl RemoveAxis for Vec { - type Smaller = Vec; - fn remove_axis(&self, axis: Axis) -> Vec { +impl RemoveAxis for Dim> { + type Smaller = Self; + fn remove_axis(&self, axis: Axis) -> Self { let mut res = self.clone(); res.remove(axis.axis()); res @@ -1004,9 +1011,7 @@ impl RemoveAxis for Vec { pub unsafe trait NdIndex : Debug { #[doc(hidden)] fn index_checked(&self, dim: &E, strides: &E) -> Option; - fn index_unchecked(&self, strides: &E) -> isize { - unimplemented!() - } + fn index_unchecked(&self, strides: &E) -> isize; } unsafe impl NdIndex for D @@ -1055,6 +1060,12 @@ unsafe impl NdIndex for (Ix, Ix, Ix) { fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { dim.stride_offset_checked(strides, &self.convert()) } + + fn index_unchecked(&self, strides: &Ix3) -> isize { + stride_offset(self.0, strides[0]) + + stride_offset(self.1, strides[1]) + + stride_offset(self.2, strides[2]) + } } unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { @@ -1062,18 +1073,47 @@ unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option { dim.stride_offset_checked(strides, &self.convert()) } + fn index_unchecked(&self, strides: &Ix4) -> isize { + zip(&**strides, &*self.convert()).map(|(&s, &i)| stride_offset(i, s)).sum() + } } unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { #[inline] fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option { dim.stride_offset_checked(strides, &self.convert()) } + fn index_unchecked(&self, strides: &Ix5) -> isize { + zip(&**strides, &*self.convert()).map(|(&s, &i)| stride_offset(i, s)).sum() + } +} + +unsafe impl NdIndex for [Ix; 2] { + #[inline] + fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { + dim.stride_offset_checked(strides, &Ix2(self[0], self[1])) + } + fn index_unchecked(&self, strides: &Ix2) -> isize { + stride_offset(self[0], strides[0]) + + stride_offset(self[1], strides[1]) + } +} + +unsafe impl NdIndex for [Ix; 3] { + #[inline] + fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { + dim.stride_offset_checked(strides, &Ix3(self[0], self[1], self[2])) + } + fn index_unchecked(&self, strides: &Ix3) -> isize { + stride_offset(self[0], strides[0]) + + stride_offset(self[1], strides[1]) + + stride_offset(self[2], strides[2]) + } } impl<'a> IntoDimension for &'a [Ix] { - type Dim = Vec; + type Dim = Dim>; fn into_dimension(self) -> Self::Dim { - self.to_vec() + Dim(self.to_vec()) } } @@ -1088,6 +1128,25 @@ unsafe impl<'a> NdIndex for &'a [Ix] { } Some(offset) } + fn index_unchecked(&self, strides: &IxDyn) -> isize { + zip(&**strides, *self).map(|(&s, &i)| stride_offset(i, s)).sum() + } +} + +unsafe impl<'a> NdIndex for Vec { + fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { + let mut offset = 0; + for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { + if i >= d { + return None; + } + offset += stride_offset(i, s); + } + Some(offset) + } + fn index_unchecked(&self, strides: &IxDyn) -> isize { + zip(&**strides, self).map(|(&s, &i)| stride_offset(i, s)).sum() + } } // NOTE: These tests are not compiled & tested diff --git a/src/free_functions.rs b/src/free_functions.rs index 6a0619b17..deae37752 100644 --- a/src/free_functions.rs +++ b/src/free_functions.rs @@ -56,7 +56,7 @@ pub fn aview2>(xs: &[V]) -> ArrayView2 { let data = unsafe { slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows) }; - let dim = [rows as Ix, cols as Ix]; + let dim = Ix2(rows, cols); unsafe { let strides = dim.default_strides(); ArrayView::new_(data.as_ptr(), dim, strides) @@ -122,8 +122,8 @@ impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,); /// ); /// ``` pub fn arr2>(xs: &[V]) -> Array2 { - let (m, n) = (xs.len() as Ix, V::len() as Ix); - let dim = [m, n]; + let (m, n) = (xs.len(), V::len()); + let dim = Ix2(m, n); let mut result = Vec::::with_capacity(dim.size()); for snd in xs { result.extend_from_slice(snd.as_init_slice()); @@ -159,7 +159,7 @@ pub fn rcarr2>(xs: &[V]) -> RcArray, U: FixedInitializer>(xs: &[V]) -> Array3 { - let dim = [xs.len() as Ix, V::len() as Ix, U::len() as Ix]; + let dim = Ix3(xs.len(), V::len(), U::len()); let mut result = Vec::::with_capacity(dim.size()); for snd in xs { for thr in snd.as_init_slice() { diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 94ecee5ee..af447bd0e 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -632,8 +632,8 @@ impl ArrayBase where S: Data, D: Dimension ArrayBase { data: self.data, ptr: self.ptr, - dim: [len], - strides: [stride as Ix], + dim: Ix1(len), + strides: Ix1(stride as Ix), } } @@ -1046,7 +1046,7 @@ impl ArrayBase where S: Data, D: Dimension } // otherwise, break the arrays up into their inner rows let mut try_slices = true; - let mut rows = self.inner_iter_mut().zip(rhs.inner_iter()); + let rows = self.inner_iter_mut().zip(rhs.inner_iter()); for (mut s_row, r_row) in rows { if try_slices { if let Some(self_s) = s_row.as_slice_mut() { diff --git a/src/linalg/impl_linalg.rs b/src/linalg/impl_linalg.rs index f9f62f49a..42973128c 100644 --- a/src/linalg/impl_linalg.rs +++ b/src/linalg/impl_linalg.rs @@ -212,7 +212,7 @@ impl Dot> for ArrayBase let mut c; unsafe { v.set_len(m * n); - c = Array::from_shape_vec_unchecked([m, n].set_f(column_major), v); + c = Array::from_shape_vec_unchecked((m, n).set_f(column_major), v); } mat_mul_impl(A::one(), &a, &b, A::zero(), &mut c.view_mut()); c @@ -266,7 +266,7 @@ impl Dot> for ArrayBase for (i, rr) in enumerate(&mut res_elems) { unsafe { *rr = (0..a).fold(A::zero(), - move |s, k| s + *self.uget([i, k]) * *rhs.uget(k) + move |s, k| s + *self.uget(Ix2(i, k)) * *rhs.uget(k) ); } } diff --git a/tests/array.rs b/tests/array.rs index 73c2d69f9..6728c3aee 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -61,7 +61,7 @@ fn test_slice() } let vi = A.slice(s![1.., ..;2]); - assert_eq!(vi.dim(), [2, 2]); + assert_eq!(vi.shape(), &[2, 2]); let vi = A.slice(&[S, S]); assert_eq!(vi.shape(), A.shape()); assert!(vi.iter().zip(A.iter()).all(|(a, b)| a == b)); @@ -486,7 +486,7 @@ fn from_vec_dim_stride_0d() { #[test] fn from_vec_dim_stride_2d_1() { let two = [1., 2.]; - let d = [2, 1]; + let d = Ix2(2, 1); let s = d.default_strides(); assert_matches!(Array::from_shape_vec(d.strides(s), two.to_vec()), Ok(_)); } @@ -494,7 +494,7 @@ fn from_vec_dim_stride_2d_1() { #[test] fn from_vec_dim_stride_2d_2() { let two = [1., 2.]; - let d = [1, 2]; + let d = Ix2(1, 2); let s = d.default_strides(); assert_matches!(Array::from_shape_vec(d.strides(s), two.to_vec()), Ok(_)); } diff --git a/tests/broadcast.rs b/tests/broadcast.rs index 1a03c7055..7675c032a 100644 --- a/tests/broadcast.rs +++ b/tests/broadcast.rs @@ -2,17 +2,18 @@ extern crate ndarray; use ndarray::prelude::*; +use ndarray::Dim; #[test] fn broadcast_1() { - let a_dim = [2, 4, 2, 2]; - let b_dim = [2, 1, 2, 1]; + let a_dim = Dim([2, 4, 2, 2]); + let b_dim = Dim([2, 1, 2, 1]); let a = RcArray::linspace(0., 1., a_dim.size()).reshape(a_dim); let b = RcArray::linspace(0., 1., b_dim.size()).reshape(b_dim); assert!(b.broadcast(a.dim()).is_some()); - let c_dim = [2, 1]; + let c_dim = Dim([2, 1]); let c = RcArray::linspace(0., 1., c_dim.size()).reshape(c_dim); assert!(c.broadcast(1).is_none()); assert!(c.broadcast(()).is_none()); @@ -32,8 +33,8 @@ fn broadcast_1() #[test] fn test_add() { - let a_dim = [2, 4, 2, 2]; - let b_dim = [2, 1, 2, 1]; + let a_dim = Dim([2, 4, 2, 2]); + let b_dim = Dim([2, 1, 2, 1]); let mut a = RcArray::linspace(0.0, 1., a_dim.size()).reshape(a_dim); let b = RcArray::linspace(0.0, 1., b_dim.size()).reshape(b_dim); a += &b; @@ -44,7 +45,7 @@ fn test_add() #[test] #[should_panic] fn test_add_incompat() { - let a_dim = [2, 4, 2, 2]; + let a_dim = Dim([2, 4, 2, 2]); let mut a = RcArray::linspace(0.0, 1., a_dim.size()).reshape(a_dim); let incompat = RcArray::from_elem(3, 1.0f32); a += &incompat; diff --git a/tests/dimension.rs b/tests/dimension.rs index 649787187..9f9f24946 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -7,17 +7,18 @@ use ndarray::{ arr2, Axis, Dimension, + Dim, }; #[test] fn remove_axis() { - assert_eq!([3].remove_axis(Axis(0)), []); - assert_eq!([1, 2].remove_axis(Axis(0)), [2]); - assert_eq!([4, 5, 6].remove_axis(Axis(1)), [4, 6]); + assert_eq!(Dim([3]).remove_axis(Axis(0)), Dim([])); + assert_eq!(Dim([1, 2]).remove_axis(Axis(0)), Dim([2])); + assert_eq!(Dim([4, 5, 6]).remove_axis(Axis(1)), Dim([4, 6])); - assert_eq!(vec![1,2].remove_axis(Axis(0)), vec![2]); - assert_eq!(vec![4, 5, 6].remove_axis(Axis(1)), vec![4, 6]); + assert_eq!(Dim(vec![1,2]).remove_axis(Axis(0)), Dim(vec![2])); + assert_eq!(Dim(vec![4, 5, 6]).remove_axis(Axis(1)), Dim(vec![4, 6])); let a = RcArray::::zeros((4,5)); a.subview(Axis(1), 0); @@ -46,18 +47,18 @@ fn dyn_dimension() #[test] fn fastest_varying_order() { - let strides = [2, 8, 4, 1]; + let strides = Dim([2, 8, 4, 1]); let order = strides._fastest_varying_stride_order(); assert_eq!(order.slice(), &[3, 0, 2, 1]); - assert_eq!([1, 3]._fastest_varying_stride_order(), [0, 1]); - assert_eq!([7, 2]._fastest_varying_stride_order(), [1, 0]); - assert_eq!([6, 1, 3]._fastest_varying_stride_order(), [1, 2, 0]); + assert_eq!(Dim([1, 3])._fastest_varying_stride_order(), Dim([0, 1])); + assert_eq!(Dim([7, 2])._fastest_varying_stride_order(), Dim([1, 0])); + assert_eq!(Dim([6, 1, 3])._fastest_varying_stride_order(), Dim([1, 2, 0])); // it's important that it produces distinct indices. Prefer the stable order // where 0 is before 1 when they are equal. - assert_eq!([2, 2]._fastest_varying_stride_order(), [0, 1]); - assert_eq!([2, 2, 1]._fastest_varying_stride_order(), [2, 0, 1]); - assert_eq!([2, 2, 3, 1, 2]._fastest_varying_stride_order(), [3, 0, 1, 4, 2]); + assert_eq!(Dim([2, 2])._fastest_varying_stride_order(), [0, 1]); + assert_eq!(Dim([2, 2, 1])._fastest_varying_stride_order(), [2, 0, 1]); + assert_eq!(Dim([2, 2, 3, 1, 2])._fastest_varying_stride_order(), [3, 0, 1, 4, 2]); } From d2add7a89114d466ecb7885ebbb893ee3f256dcb Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 31 Oct 2016 00:15:38 +0100 Subject: [PATCH 040/107] Add more From impls for Dim --- src/dimension.rs | 20 ++++++++++++++++++++ src/lib.rs | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/dimension.rs b/src/dimension.rs index 7a88763a7..b3e70edbc 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -548,6 +548,20 @@ macro_rules! array_expr { ) } +impl From for Dim + where Dim: ::Dimension +{ + fn from(x: I) -> Self { + Dim(x) + } +} + +impl From for Dim<[usize; 1]> { + fn from(x: usize) -> Self { + Dim([x]) + } +} + macro_rules! tuple_to_array { ([] $($n:tt)*) => { $( @@ -573,6 +587,12 @@ macro_rules! tuple_to_array { } } + impl From for Dim<[usize; $n]> { + fn from(x: index!(tuple_type [Ix] $n)) -> Self { + x.convert() + } + } + )* } } diff --git a/src/lib.rs b/src/lib.rs index 5539674a1..6c90379e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,7 +110,7 @@ pub use arraytraits::AsArray; pub use linalg_traits::{LinalgScalar, NdFloat}; pub use stacking::stack; -pub use shape_builder::{ ShapeBuilder }; +pub use shape_builder::{ ShapeBuilder, IntoShape }; mod aliases; mod arraytraits; From 31aed0fb8f216b604611862a54c90b16d3da498c Mon Sep 17 00:00:00 2001 From: bluss Date: Wed, 2 Nov 2016 01:33:40 +0100 Subject: [PATCH 041/107] Shape: Add .size() method --- src/shape_builder.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/shape_builder.rs b/src/shape_builder.rs index 76ae98be6..4151513cf 100644 --- a/src/shape_builder.rs +++ b/src/shape_builder.rs @@ -172,3 +172,11 @@ impl ShapeBuilder for Shape } +impl Shape + where D: Dimension, +{ + // Return a reference to the dimension + //pub fn dimension(&self) -> &D { &self.dim } + /// Return the size of the shape in number of elements + pub fn size(&self) -> usize { self.dim.size() } +} From ac45233c8b3d0aadcae095cfec866903ada47ae0 Mon Sep 17 00:00:00 2001 From: bluss Date: Wed, 2 Nov 2016 01:34:02 +0100 Subject: [PATCH 042/107] ndarray-rand: Update for IntoShape --- ndarray-rand/src/lib.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/ndarray-rand/src/lib.rs b/ndarray-rand/src/lib.rs index 11cccbf76..3520a062b 100644 --- a/ndarray-rand/src/lib.rs +++ b/ndarray-rand/src/lib.rs @@ -21,6 +21,7 @@ use ndarray::{ Dimension, DataOwned, }; +use ndarray::IntoShape; /// Constructors for n-dimensional arrays with random elements. /// @@ -53,34 +54,39 @@ pub trait RandomExt /// // [[ 8.6900, 6.9824, 3.8922, 6.5861, 2.4890], /// // [ 0.0914, 5.5186, 5.8135, 5.2361, 3.1879]] /// # } - fn random(dim: D, distribution: IdS) -> ArrayBase - where IdS: IndependentSample; + fn random(shape: Sh, distribution: IdS) -> ArrayBase + where IdS: IndependentSample, + Sh: IntoShape; /// Create an array with shape `dim` with elements drawn from /// `distribution`, using a specific Rng `rng`. /// /// ***Panics*** if the number of elements overflows usize. - fn random_using(dim: D, distribution: IdS, rng: &mut R) -> ArrayBase + fn random_using(shape: Sh, distribution: IdS, rng: &mut R) -> ArrayBase where IdS: IndependentSample, - R: Rng; + R: Rng, + Sh: IntoShape; } impl RandomExt for ArrayBase where S: DataOwned, D: Dimension, { - fn random(dim: D, dist: IdS) -> ArrayBase - where IdS: IndependentSample + fn random(shape: Sh, dist: IdS) -> ArrayBase + where IdS: IndependentSample, + Sh: IntoShape, { - Self::random_using(dim, dist, &mut rand::weak_rng()) + Self::random_using(shape, dist, &mut rand::weak_rng()) } - fn random_using(dim: D, dist: IdS, rng: &mut R) -> ArrayBase + fn random_using(shape: Sh, dist: IdS, rng: &mut R) -> ArrayBase where IdS: IndependentSample, - R: Rng + R: Rng, + Sh: IntoShape, { - let elements = Vec::from_iter((0..dim.size()).map(move |_| dist.ind_sample(rng))); - Self::from_shape_vec(dim, elements).unwrap() + let shape = shape.into_shape(); + let elements = Vec::from_iter((0..shape.size()).map(move |_| dist.ind_sample(rng))); + Self::from_shape_vec(shape, elements).unwrap() } } From e050a87205e8129bdd3f98df65c19fef0ae45847 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 20:58:02 +0100 Subject: [PATCH 043/107] Revert ".broadcast(): Work around miscompile" This reverts commit 1ba3e60a116c42c2ee7b3e0e12459fc9b05b6ad0. --- src/impl_methods.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index af447bd0e..9fa52647b 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -896,9 +896,10 @@ impl ArrayBase where S: Data, D: Dimension } { + let mut new_stride_iter = new_stride.slice_mut().iter_mut().rev(); for ((er, es), dr) in from.slice().iter().rev() .zip(stride.slice().iter().rev()) - .zip(new_stride.slice_mut().iter_mut().rev()) + .zip(new_stride_iter.by_ref()) { /* update strides */ if *dr == *er { @@ -913,8 +914,7 @@ impl ArrayBase where S: Data, D: Dimension } /* set remaining strides to zero */ - let tail_len = to.ndim() - from.ndim(); - for dr in &mut new_stride.slice_mut()[..tail_len] { + for dr in new_stride_iter { *dr = 0; } } From a1611b76f89e97aba131ebf6b24c2841218c2339 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 22:08:58 +0100 Subject: [PATCH 044/107] Make `Dim()` into a function that converts using IntoDimension --- src/aliases.rs | 23 ++---------- src/dimension.rs | 92 +++++++++++++++++++++++++++++------------------- src/lib.rs | 1 + 3 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index 8833d18d5..dffd61526 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -2,6 +2,8 @@ //! use ::{Ix, Array, ArrayView, ArrayViewMut}; +use ::dimension::IntoDimension; +pub use ::dimension::Dim; #[allow(non_snake_case)] #[inline(always)] @@ -16,8 +18,6 @@ pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { Dim([i0, i1]) } #[inline(always)] pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 { Dim([i0, i1, i2]) } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -pub struct Dim(pub I); /// zero-dimensionial pub type Ix0 = Dim<[Ix; 0]>; /// one-dimensional @@ -33,25 +33,6 @@ pub type Ix5 = Dim<[Ix; 5]>; /// dynamic-dimensional pub type IxDyn = Dim>; -impl PartialEq for Dim - where I: PartialEq, -{ - fn eq(&self, rhs: &I) -> bool { - self.0 == *rhs - } -} - -use std::ops::{Deref, DerefMut}; - -impl Deref for Dim { - type Target = I; - fn deref(&self) -> &I { &self.0 } -} -impl DerefMut for Dim -{ - fn deref_mut(&mut self) -> &mut I { &mut self.0 } -} - /// zero-dimensional array pub type Array0 = Array; /// one-dimensional array diff --git a/src/dimension.rs b/src/dimension.rs index b3e70edbc..39de71f08 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -16,7 +16,6 @@ use error::{from_kind, ErrorKind, ShapeError}; use ZipExt; use {Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, IxDyn}; use {ArrayView1, ArrayViewMut1}; -use aliases::Dim; /// Calculate offset from `Ix` stride converting sign properly #[inline(always)] @@ -511,15 +510,15 @@ impl IntoDimension for D where D: Dimension { impl IntoDimension for Vec { type Dim = IxDyn; #[inline(always)] - fn into_dimension(self) -> Self::Dim { Dim(self) } + fn into_dimension(self) -> Self::Dim { Dim { index: self } } } -trait Convert { +trait Convert { type To; fn convert(self) -> Self::To; } -impl Convert for Ix { +impl Convert for Ix { type To = Ix1; fn convert(self) -> Self::To { Ix1(self) } } @@ -548,48 +547,38 @@ macro_rules! array_expr { ) } -impl From for Dim - where Dim: ::Dimension -{ - fn from(x: I) -> Self { - Dim(x) - } -} - -impl From for Dim<[usize; 1]> { - fn from(x: usize) -> Self { - Dim([x]) - } -} - macro_rules! tuple_to_array { ([] $($n:tt)*) => { $( - impl Convert for [T; $n] { - type To = index!(tuple_type [T] $n); + impl Convert for [Ix; $n] { + type To = index!(tuple_type [Ix] $n); fn convert(self) -> Self::To { index!(tuple_expr [self] $n) } } - impl Convert for index!(tuple_type [T] $n) { - type To = Dim<[T; $n]>; + impl Convert for index!(tuple_type [Ix] $n) { + type To = Dim<[Ix; $n]>; fn convert(self) -> Self::To { Dim(index!(array_expr [self] $n)) } } - impl IntoDimension for index!(tuple_type [Ix] $n) { + impl IntoDimension for [Ix; $n] { type Dim = Dim<[Ix; $n]>; #[inline(always)] fn into_dimension(self) -> Self::Dim { - Dim(index!(array_expr [self] $n)) + Dim { + index: self, + } } } - impl From for Dim<[usize; $n]> { - fn from(x: index!(tuple_type [Ix] $n)) -> Self { - x.convert() + impl IntoDimension for index!(tuple_type [Ix] $n) { + type Dim = Dim<[Ix; $n]>; + #[inline(always)] + fn into_dimension(self) -> Self::Dim { + Dim { index: index!(array_expr [self] $n) } } } @@ -606,9 +595,9 @@ unsafe impl Dimension for Ix0 { #[inline] fn ndim(&self) -> usize { 0 } #[inline] - fn slice(&self) -> &[Ix] { &self.0 } + fn slice(&self) -> &[Ix] { &self[..] } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } #[inline] fn _fastest_varying_stride_order(&self) -> Self { Ix0() } #[inline] @@ -627,9 +616,9 @@ unsafe impl Dimension for Ix1 { #[inline] fn ndim(&self) -> usize { 1 } #[inline] - fn slice(&self) -> &[Ix] { &self.0 } + fn slice(&self) -> &[Ix] { &self[..] } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } #[inline] fn into_pattern(self) -> Self::Pattern { self[0] @@ -700,9 +689,9 @@ unsafe impl Dimension for Ix2 { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { &self.0 } + fn slice(&self) -> &[Ix] { &self[..] } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } #[inline] fn next_for(&self, index: Self) -> Option { let mut i = index[0]; @@ -834,9 +823,9 @@ unsafe impl Dimension for Ix3 { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { &self.0 } + fn slice(&self) -> &[Ix] { &self[..] } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } #[inline] fn size(&self) -> usize { @@ -916,9 +905,9 @@ macro_rules! large_dim { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { &self.0 } + fn slice(&self) -> &[Ix] { &self[..] } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self.0 } + fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } } ) } @@ -1238,3 +1227,32 @@ derive_cmp!{PartialEq for Axis, eq -> bool} derive_cmp!{PartialOrd for Axis, partial_cmp -> Option} clone_from_copy!{Axis} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] +pub struct Dim { + index: I, +} +pub fn Dim(index: T) -> T::Dim + where T: IntoDimension +{ + index.into_dimension() +} + +impl PartialEq for Dim + where I: PartialEq, +{ + fn eq(&self, rhs: &I) -> bool { + self.index == *rhs + } +} + +use std::ops::{Deref, DerefMut}; + +impl Deref for Dim { + type Target = I; + fn deref(&self) -> &I { &self.index } +} +impl DerefMut for Dim +{ + fn deref_mut(&mut self) -> &mut I { &mut self.index } +} + diff --git a/src/lib.rs b/src/lib.rs index 6c90379e2..745d01b92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,6 +87,7 @@ use std::marker::PhantomData; pub use dimension::{ Dimension, + IntoDimension, RemoveAxis, Axis, }; From 140bd12469f3403bcf1283775b0b20d02977c423 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 22:19:49 +0100 Subject: [PATCH 045/107] Merge IntoShape into ShapeBuilder trait --- src/aliases.rs | 1 - src/impl_constructors.rs | 9 ++-- src/impl_methods.rs | 1 - src/lib.rs | 2 +- src/shape_builder.rs | 98 ++++------------------------------------ 5 files changed, 14 insertions(+), 97 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index dffd61526..fbfcb865c 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -2,7 +2,6 @@ //! use ::{Ix, Array, ArrayView, ArrayViewMut}; -use ::dimension::IntoDimension; pub use ::dimension::Dim; #[allow(non_snake_case)] diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index caa2ed05e..1a7f7677c 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -19,7 +19,6 @@ use linspace; use error::{self, ShapeError, ErrorKind}; use Indexes; use iterators::{to_vec, to_vec_mapped}; -use shape_builder::IntoShape; /// Constructor methods for one-dimensional arrays. /// @@ -141,7 +140,7 @@ impl ArrayBase /// ``` pub fn from_elem(shape: Sh, elem: A) -> Self where A: Clone, - Sh: IntoShape, + Sh: ShapeBuilder, { // Note: We don't need to check the case of a size between // isize::MAX -> usize::MAX; in this case, the vec constructor itself @@ -157,7 +156,7 @@ impl ArrayBase /// **Panics** if the number of elements in `shape` would overflow usize. pub fn zeros(shape: Sh) -> Self where A: Clone + Zero, - Sh: IntoShape, + Sh: ShapeBuilder, { Self::from_elem(shape, A::zero()) } @@ -167,7 +166,7 @@ impl ArrayBase /// **Panics** if the number of elements in `shape` would overflow usize. pub fn default(shape: Sh) -> Self where A: Default, - Sh: IntoShape, + Sh: ShapeBuilder, { let shape = shape.into_shape(); let v = to_vec((0..shape.dim.size()).map(|_| A::default())); @@ -180,7 +179,7 @@ impl ArrayBase /// /// **Panics** if the number of elements in `shape` would overflow usize. pub fn from_shape_fn(shape: Sh, f: F) -> Self - where Sh: IntoShape, + where Sh: ShapeBuilder, F: FnMut(D::Pattern) -> A, { let shape = shape.into_shape(); diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 9fa52647b..3466fd3e4 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -20,7 +20,6 @@ use iterators; use error::{self, ShapeError}; use super::zipsl; use super::ZipExt; -use shape_builder::IntoShape; use dimension::IntoDimension; use { diff --git a/src/lib.rs b/src/lib.rs index 745d01b92..45730d0da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,7 @@ pub use arraytraits::AsArray; pub use linalg_traits::{LinalgScalar, NdFloat}; pub use stacking::stack; -pub use shape_builder::{ ShapeBuilder, IntoShape }; +pub use shape_builder::{ ShapeBuilder}; mod aliases; mod arraytraits; diff --git a/src/shape_builder.rs b/src/shape_builder.rs index 4151513cf..95676bed9 100644 --- a/src/shape_builder.rs +++ b/src/shape_builder.rs @@ -13,102 +13,15 @@ pub trait ShapeBuilder { type Dim: Dimension; type Strides; + fn into_shape(self) -> Shape; fn f(self) -> Shape; fn set_f(self, is_f: bool) -> Shape; fn strides(self, strides: Self::Strides) -> StrideShape; } -pub trait IntoShape { - type Dim: Dimension; - fn into_shape(self) -> Shape; -} - -impl IntoShape for D - where D: IntoDimension, -{ - type Dim = D::Dim; - fn into_shape(self) -> Shape { - Shape { - dim: self.into_dimension(), - is_c: true, - } - } -} -impl IntoShape for Shape - where D: Dimension, -{ - type Dim = D; - fn into_shape(self) -> Shape { - self - } -} -/* - -impl IntoShape for () { - type Dim = [Ix; 0]; - fn into_shape(self) -> Shape { - Shape { - dim: [], - is_c: true, - } - } -} - -impl IntoShape for Ix { - type Dim = [Ix; 1]; - fn into_shape(self) -> Shape { - Shape { - dim: [self], - is_c: true, - } - } -} - -impl IntoShape for (Ix, Ix) { - type Dim = [Ix; 2]; - fn into_shape(self) -> Shape { - Shape { - dim: [self.0, self.1], - is_c: true, - } - } -} -*/ - -impl From for Shape - where D: Dimension -{ - fn from(d: D) -> Self { - Shape { - dim: d, - is_c: true, - } - } -} - -impl From for Shape<[Ix; 1]> -{ - fn from(ix: Ix) -> Self { - Shape { - dim: [ix], - is_c: true, - } - } -} - -impl From<(Ix, Ix)> for Shape<[Ix; 2]> -{ - fn from(ix: (Ix, Ix)) -> Self { - Shape { - dim: [ix.0, ix.1], - is_c: true, - } - } -} - impl From for StrideShape where D: Dimension, - T: IntoShape, + T: ShapeBuilder, { fn from(value: T) -> Self { let shape = value.into_shape(); @@ -143,6 +56,12 @@ impl ShapeBuilder for T { type Dim = T::Dim; type Strides = T; + fn into_shape(self) -> Shape { + Shape { + dim: self.into_dimension(), + is_c: true, + } + } fn f(self) -> Shape { self.set_f(true) } fn set_f(self, is_f: bool) -> Shape { self.into_shape().set_f(is_f) @@ -157,6 +76,7 @@ impl ShapeBuilder for Shape { type Dim = D; type Strides = D; + fn into_shape(self) -> Shape { self } fn f(self) -> Self { self.set_f(true) } fn set_f(mut self, is_f: bool) -> Self { self.is_c = !is_f; From 18ab7774d3bad3a35b3626fafb2c36566e8e6de5 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 22:30:13 +0100 Subject: [PATCH 046/107] ndarray-rand: Migrate to ShapeBuilder --- ndarray-rand/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ndarray-rand/src/lib.rs b/ndarray-rand/src/lib.rs index 3520a062b..eee86d7d8 100644 --- a/ndarray-rand/src/lib.rs +++ b/ndarray-rand/src/lib.rs @@ -21,7 +21,7 @@ use ndarray::{ Dimension, DataOwned, }; -use ndarray::IntoShape; +use ndarray::ShapeBuilder; /// Constructors for n-dimensional arrays with random elements. /// @@ -56,7 +56,7 @@ pub trait RandomExt /// # } fn random(shape: Sh, distribution: IdS) -> ArrayBase where IdS: IndependentSample, - Sh: IntoShape; + Sh: ShapeBuilder; /// Create an array with shape `dim` with elements drawn from /// `distribution`, using a specific Rng `rng`. @@ -65,7 +65,7 @@ pub trait RandomExt fn random_using(shape: Sh, distribution: IdS, rng: &mut R) -> ArrayBase where IdS: IndependentSample, R: Rng, - Sh: IntoShape; + Sh: ShapeBuilder; } impl RandomExt for ArrayBase @@ -74,7 +74,7 @@ impl RandomExt for ArrayBase { fn random(shape: Sh, dist: IdS) -> ArrayBase where IdS: IndependentSample, - Sh: IntoShape, + Sh: ShapeBuilder, { Self::random_using(shape, dist, &mut rand::weak_rng()) } @@ -82,7 +82,7 @@ impl RandomExt for ArrayBase fn random_using(shape: Sh, dist: IdS, rng: &mut R) -> ArrayBase where IdS: IndependentSample, R: Rng, - Sh: IntoShape, + Sh: ShapeBuilder, { let shape = shape.into_shape(); let elements = Vec::from_iter((0..shape.size()).map(move |_| dist.ind_sample(rng))); From d60f94a2135bf7dcd4cd9997bf608ac8e29bcc1d Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 22:36:31 +0100 Subject: [PATCH 047/107] Add #[inline] annotations to non-generic methods --- src/dimension.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/dimension.rs b/src/dimension.rs index 39de71f08..8baa0dbe1 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -1039,7 +1039,8 @@ unsafe impl NdIndex for () { fn index_checked(&self, dim: &Ix0, strides: &Ix0) -> Option { dim.stride_offset_checked(strides, &Ix0()) } - fn index_unchecked(&self, strides: &Ix0) -> isize { + #[inline(always)] + fn index_unchecked(&self, _strides: &Ix0) -> isize { 0 } } @@ -1049,6 +1050,7 @@ unsafe impl NdIndex for Ix { fn index_checked(&self, dim: &Ix1, strides: &Ix1) -> Option { dim.stride_offset_checked(strides, &Ix1(*self)) } + #[inline(always)] fn index_unchecked(&self, strides: &Ix1) -> isize { stride_offset(*self, strides[0]) } @@ -1059,6 +1061,7 @@ unsafe impl NdIndex for (Ix, Ix) { fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { dim.stride_offset_checked(strides, &Ix2(self.0, self.1)) } + #[inline] fn index_unchecked(&self, strides: &Ix2) -> isize { stride_offset(self.0, strides[0]) + stride_offset(self.1, strides[1]) @@ -1070,6 +1073,7 @@ unsafe impl NdIndex for (Ix, Ix, Ix) { dim.stride_offset_checked(strides, &self.convert()) } + #[inline] fn index_unchecked(&self, strides: &Ix3) -> isize { stride_offset(self.0, strides[0]) + stride_offset(self.1, strides[1]) + @@ -1082,6 +1086,7 @@ unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option { dim.stride_offset_checked(strides, &self.convert()) } + #[inline] fn index_unchecked(&self, strides: &Ix4) -> isize { zip(&**strides, &*self.convert()).map(|(&s, &i)| stride_offset(i, s)).sum() } @@ -1091,6 +1096,7 @@ unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option { dim.stride_offset_checked(strides, &self.convert()) } + #[inline] fn index_unchecked(&self, strides: &Ix5) -> isize { zip(&**strides, &*self.convert()).map(|(&s, &i)| stride_offset(i, s)).sum() } @@ -1101,6 +1107,7 @@ unsafe impl NdIndex for [Ix; 2] { fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { dim.stride_offset_checked(strides, &Ix2(self[0], self[1])) } + #[inline] fn index_unchecked(&self, strides: &Ix2) -> isize { stride_offset(self[0], strides[0]) + stride_offset(self[1], strides[1]) @@ -1112,6 +1119,7 @@ unsafe impl NdIndex for [Ix; 3] { fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { dim.stride_offset_checked(strides, &Ix3(self[0], self[1], self[2])) } + #[inline] fn index_unchecked(&self, strides: &Ix3) -> isize { stride_offset(self[0], strides[0]) + stride_offset(self[1], strides[1]) + From b939a481de6f5dd468f42feb89b8c1bec9f9e04b Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 22:48:02 +0100 Subject: [PATCH 048/107] Make sure both Dims are exported --- src/aliases.rs | 2 +- src/dimension.rs | 72 ++++++++++++++++++++++++++++++------------------ src/lib.rs | 1 + 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index fbfcb865c..5ce282a04 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -2,7 +2,7 @@ //! use ::{Ix, Array, ArrayView, ArrayViewMut}; -pub use ::dimension::Dim; +use ::dimension::Dim; #[allow(non_snake_case)] #[inline(always)] diff --git a/src/dimension.rs b/src/dimension.rs index 8baa0dbe1..bd4c26cd4 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -510,7 +510,7 @@ impl IntoDimension for D where D: Dimension { impl IntoDimension for Vec { type Dim = IxDyn; #[inline(always)] - fn into_dimension(self) -> Self::Dim { Dim { index: self } } + fn into_dimension(self) -> Self::Dim { Dim::new(self) } } trait Convert { @@ -568,9 +568,7 @@ macro_rules! tuple_to_array { type Dim = Dim<[Ix; $n]>; #[inline(always)] fn into_dimension(self) -> Self::Dim { - Dim { - index: self, - } + Dim::new(self) } } @@ -578,7 +576,7 @@ macro_rules! tuple_to_array { type Dim = Dim<[Ix; $n]>; #[inline(always)] fn into_dimension(self) -> Self::Dim { - Dim { index: index!(array_expr [self] $n) } + Dim::new(index!(array_expr [self] $n)) } } @@ -1235,32 +1233,52 @@ derive_cmp!{PartialEq for Axis, eq -> bool} derive_cmp!{PartialOrd for Axis, partial_cmp -> Option} clone_from_copy!{Axis} -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -pub struct Dim { - index: I, -} -pub fn Dim(index: T) -> T::Dim - where T: IntoDimension -{ - index.into_dimension() +trait DimNew { + fn new(index: I) -> Self; } -impl PartialEq for Dim - where I: PartialEq, -{ - fn eq(&self, rhs: &I) -> bool { - self.index == *rhs +pub use self::dim::*; +pub mod dim { + use super::IntoDimension; + use super::DimNew; + + #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] + pub struct Dim { + index: I, } -} -use std::ops::{Deref, DerefMut}; + impl DimNew for Dim { + fn new(index: I) -> Dim { + Dim { + index: index, + } + } + } + + pub fn Dim(index: T) -> T::Dim + where T: IntoDimension + { + index.into_dimension() + } + + impl PartialEq for Dim + where I: PartialEq, + { + fn eq(&self, rhs: &I) -> bool { + self.index == *rhs + } + } + + use std::ops::{Deref, DerefMut}; + + impl Deref for Dim { + type Target = I; + fn deref(&self) -> &I { &self.index } + } + impl DerefMut for Dim + { + fn deref_mut(&mut self) -> &mut I { &mut self.index } + } -impl Deref for Dim { - type Target = I; - fn deref(&self) -> &I { &self.index } -} -impl DerefMut for Dim -{ - fn deref_mut(&mut self) -> &mut I { &mut self.index } } diff --git a/src/lib.rs b/src/lib.rs index 45730d0da..12c4ad3d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,7 @@ pub use dimension::{ RemoveAxis, Axis, }; +pub use dimension::dim::*; pub use dimension::NdIndex; pub use indexes::Indexes; From 14f60da65ebd78665f249c7b6e36e1a673a32091 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 23:08:23 +0100 Subject: [PATCH 049/107] Add non_snake_case warning to Dim --- src/dimension.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dimension.rs b/src/dimension.rs index bd4c26cd4..b3442250a 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -1255,6 +1255,7 @@ pub mod dim { } } + #[allow(non_snake_case)] pub fn Dim(index: T) -> T::Dim where T: IntoDimension { From 15fac2a49c524332098aad0d6ce9c7dbc2737193 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 23:10:49 +0100 Subject: [PATCH 050/107] Document Dimension::Pattern --- src/dimension.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dimension.rs b/src/dimension.rs index b3442250a..47a79d82c 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -145,7 +145,10 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { type SliceArg: ?Sized + AsRef<[Si]>; /// Pattern matching friendly form of the dimension value. /// - /// Usually a tuple. + /// - For `Ix1`: `usize`, + /// - For `Ix2`: `(usize, usize)` + /// - and so on.. + /// - For `Vec`: `Vec`, type Pattern: IntoDimension; #[doc(hidden)] fn ndim(&self) -> usize; From 09c13adabb95591c0acb18cdaaef52910a3341b7 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 23:32:31 +0100 Subject: [PATCH 051/107] Implement indexing, addition, subtraction, multiplication for indices --- src/dimension.rs | 121 ++++++++++++++++++++++++++++++++++++++++----- tests/dimension.rs | 26 ++++++++++ 2 files changed, 135 insertions(+), 12 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 47a79d82c..031bb6195 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -8,6 +8,8 @@ use std::cmp::Ordering; use std::fmt::Debug; use std::slice; +use std::ops::{Index, IndexMut}; + use itertools::{enumerate, zip}; use super::{Si, Ix, Ixs}; @@ -127,7 +129,9 @@ fn stride_offset_checked_arithmetic(dim: &D, strides: &D, index: &D) /// /// ***Don't implement or call methods in this trait, its interface is internal /// to the crate and will evolve at will.*** -pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default { +pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + + IndexMut +{ /// `SliceArg` is the type which is used to specify slicing for this /// dimension. /// @@ -596,9 +600,9 @@ unsafe impl Dimension for Ix0 { #[inline] fn ndim(&self) -> usize { 0 } #[inline] - fn slice(&self) -> &[Ix] { &self[..] } + fn slice(&self) -> &[Ix] { &**self } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } + fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } #[inline] fn _fastest_varying_stride_order(&self) -> Self { Ix0() } #[inline] @@ -617,9 +621,9 @@ unsafe impl Dimension for Ix1 { #[inline] fn ndim(&self) -> usize { 1 } #[inline] - fn slice(&self) -> &[Ix] { &self[..] } + fn slice(&self) -> &[Ix] { &**self } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } + fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } #[inline] fn into_pattern(self) -> Self::Pattern { self[0] @@ -690,9 +694,9 @@ unsafe impl Dimension for Ix2 { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { &self[..] } + fn slice(&self) -> &[Ix] { &**self } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } + fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } #[inline] fn next_for(&self, index: Self) -> Option { let mut i = index[0]; @@ -824,9 +828,9 @@ unsafe impl Dimension for Ix3 { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { &self[..] } + fn slice(&self) -> &[Ix] { &**self } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } + fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } #[inline] fn size(&self) -> usize { @@ -906,9 +910,9 @@ macro_rules! large_dim { self.convert() } #[inline] - fn slice(&self) -> &[Ix] { &self[..] } + fn slice(&self) -> &[Ix] { &**self } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut self[..] } + fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } } ) } @@ -1244,6 +1248,10 @@ pub use self::dim::*; pub mod dim { use super::IntoDimension; use super::DimNew; + use super::Dimension; + use Ix; + + use itertools::{enumerate, zip}; #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] pub struct Dim { @@ -1273,7 +1281,7 @@ pub mod dim { } } - use std::ops::{Deref, DerefMut}; + use std::ops::{Deref, DerefMut, Index, IndexMut}; impl Deref for Dim { type Target = I; @@ -1284,5 +1292,94 @@ pub mod dim { fn deref_mut(&mut self) -> &mut I { &mut self.index } } + impl Index for Dim + where [usize]: Index, + Dim: Dimension, + { + type Output = <[usize] as Index>::Output; + fn index(&self, index: J) -> &Self::Output { + self.slice().index(index) + } + } + + impl IndexMut for Dim + where [usize]: IndexMut, + Dim: Dimension, + { + fn index_mut(&mut self, index: J) -> &mut Self::Output { + self.slice_mut().index_mut(index) + } + } + + use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; + + macro_rules! impl_op { + ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { + impl $op for Dim + where Dim: Dimension, + { + type Output = Self; + fn $op_m(mut self, rhs: Self) -> Self { + $expr!(self, &rhs); + self + } + } + + impl $op for Dim + where Dim: Dimension, + { + type Output = Self; + fn $op_m(mut self, rhs: Ix) -> Self { + $expr!(self, rhs); + self + } + } + + impl $opassign for Dim + where Dim: Dimension, + { + fn $opassign_m(&mut self, rhs: Self) { + $expr!(*self, &rhs); + } + } + + impl<'a, I> $opassign<&'a Dim> for Dim + where Dim: Dimension, + { + fn $opassign_m(&mut self, rhs: &Self) { + for (x, &y) in zip(self.slice_mut(), rhs.slice()) { + $expr!(*x, y); + } + } + } + + impl $opassign for Dim + where Dim: Dimension, + { + fn $opassign_m(&mut self, rhs: Ix) { + for x in self.slice_mut() { + $expr!(*x, rhs); + } + } + } + } + } + + macro_rules! add { + ($x:expr, $y:expr) => { $x += $y; } + } + macro_rules! sub { + ($x:expr, $y:expr) => { $x -= $y; } + } + macro_rules! mul { + ($x:expr, $y:expr) => { $x *= $y; } + } + impl_op!(Add, add, AddAssign, add_assign, add); + impl_op!(Sub, sub, SubAssign, sub_assign, sub); + impl_op!(Mul, mul, MulAssign, mul_assign, mul); } + +#[test] +fn test_dim() { +} diff --git a/tests/dimension.rs b/tests/dimension.rs index 9f9f24946..cc9652da0 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -62,3 +62,29 @@ fn fastest_varying_order() { assert_eq!(Dim([2, 2, 3, 1, 2])._fastest_varying_stride_order(), [3, 0, 1, 4, 2]); } +#[test] +fn test_indexing() { + let mut x = Dim([1, 2]); + + assert_eq!(x[0], 1); + assert_eq!(x[1], 2); + + x[0] = 7; + assert_eq!(x, [7, 2]); +} + +#[test] +fn test_operations() { + let mut x = Dim([1, 2]); + let mut y = Dim([1, 1]); + + assert_eq!(x + y, [2, 3]); + + x += y; + assert_eq!(x, [2, 3]); + x *= 2; + assert_eq!(x, [4, 6]); + + y -= 1; + assert_eq!(y, [0, 0]); +} From 33e874ac764195cfa702c56e82e34c558f64bcc2 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 5 Nov 2016 23:39:40 +0100 Subject: [PATCH 052/107] Index and arithmetic operations in the Dimension trait --- src/dimension.rs | 18 ++++++++++++++++-- tests/dimension.rs | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 031bb6195..bf9b19837 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -123,14 +123,28 @@ fn stride_offset_checked_arithmetic(dim: &D, strides: &D, index: &D) Some(offset) } +use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; +use std::ops::{Range, RangeTo, RangeFrom, RangeFull}; + /// Array shape and index trait. /// /// `unsafe` because of the assumptions in the default methods. /// /// ***Don't implement or call methods in this trait, its interface is internal /// to the crate and will evolve at will.*** -pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default - + IndexMut +pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + + IndexMut + + IndexMut, Output=[usize]> + + IndexMut, Output=[usize]> + + IndexMut, Output=[usize]> + + IndexMut + + Add + Add + + AddAssign + for<'x> AddAssign<&'x Self> + AddAssign + + Sub + Sub + + SubAssign + for<'x> SubAssign<&'x Self> + SubAssign + + Mul + Mul + + MulAssign + for<'x> MulAssign<&'x Self> + MulAssign + { /// `SliceArg` is the type which is used to specify slicing for this /// dimension. diff --git a/tests/dimension.rs b/tests/dimension.rs index cc9652da0..418be87e1 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -88,3 +88,22 @@ fn test_operations() { y -= 1; assert_eq!(y, [0, 0]); } + +#[test] +fn test_generic_operations() { + fn test_dim(d: &D) { + let mut x = d.clone(); + assert_eq!(x[0], 2); + x += 1; + assert_eq!(x[0], 3); + x += d; + assert_eq!(x[0], 5); + + assert_eq!(x[..].len(), x.ndim()); + assert_eq!(&x[..], x.slice()); + } + + test_dim(&Dim([2, 3, 4])); + test_dim(&Dim(vec![2, 3, 4, 1])); + test_dim(&Dim(2)); +} From 66d5fd5cee341da98788391c47b3a5e6cc14729b Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 00:06:51 +0100 Subject: [PATCH 053/107] Improve .fold() again --- src/iterators.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/iterators.rs b/src/iterators.rs index 2c31570a3..763d3123e 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -105,15 +105,9 @@ impl<'a, A, D: Dimension> Baseiter<'a, A, D> { let len = self.dim.last_elem(); let offset = D::stride_offset(&index, &self.strides); unsafe { - let mut ptr = self.ptr.offset(offset); - let mut i = elem_index; - loop { - accum = g(accum, ptr); - i += 1; - if i >= len { - break; - } - ptr = ptr.offset(stride); + let row_ptr = self.ptr.offset(offset); + for i in 0..(len - elem_index) { + accum = g(accum, row_ptr.offset(i as isize * stride)); } } index.set_last_elem(len - 1); From a2b97c2b9077fd0f493dabd4111a24760bc06376 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 00:17:11 +0100 Subject: [PATCH 054/107] Specific last-item stuff --- src/dimension.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index bf9b19837..013c3b0dd 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -745,12 +745,12 @@ unsafe impl Dimension for Ix2 { #[inline] fn last_elem(&self) -> usize { - self[1] + (**self)[1] } #[inline] fn set_last_elem(&mut self, i: usize) { - self[1] = i; + (**self)[1] = i; } #[inline] From f3735ea558eb9a3a953dfde7efcf52ac16a0d7aa Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 00:33:09 +0100 Subject: [PATCH 055/107] Skip Index for Dim/Dimension for now --- src/dimension.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dimension.rs b/src/dimension.rs index 013c3b0dd..72b4334ae 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -133,11 +133,13 @@ use std::ops::{Range, RangeTo, RangeFrom, RangeFull}; /// ***Don't implement or call methods in this trait, its interface is internal /// to the crate and will evolve at will.*** pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + +/* IndexMut + IndexMut, Output=[usize]> + IndexMut, Output=[usize]> + IndexMut, Output=[usize]> + IndexMut + + */ Add + Add + AddAssign + for<'x> AddAssign<&'x Self> + AddAssign + Sub + Sub + @@ -1306,6 +1308,7 @@ pub mod dim { fn deref_mut(&mut self) -> &mut I { &mut self.index } } + /* impl Index for Dim where [usize]: Index, Dim: Dimension, @@ -1324,6 +1327,7 @@ pub mod dim { self.slice_mut().index_mut(index) } } + */ use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; From edd8501543f07ad868be1c73e2b2d3b7f07a656f Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 15:03:59 +0100 Subject: [PATCH 056/107] Drop default impls for slice (they are unused) --- src/dimension.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 72b4334ae..6ae2348d3 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -172,13 +172,6 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + type Pattern: IntoDimension; #[doc(hidden)] fn ndim(&self) -> usize; - #[doc(hidden)] - fn slice(&self) -> &[Ix] { - unsafe { - slice::from_raw_parts(self as *const _ as *const Ix, self.ndim()) - } - } - fn equal(&self, rhs: &Self) -> bool { self.slice() == rhs.slice() } @@ -186,11 +179,10 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + fn into_pattern(self) -> Self::Pattern; #[doc(hidden)] - fn slice_mut(&mut self) -> &mut [Ix] { - unsafe { - slice::from_raw_parts_mut(self as *mut _ as *mut Ix, self.ndim()) - } - } + fn slice(&self) -> &[Ix]; + + #[doc(hidden)] + fn slice_mut(&mut self) -> &mut [Ix]; fn array_view(&self) -> ArrayView1 { ArrayView1::from(self.slice()) From 95a24b210d79033082cda55954ef204de3e18999 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 15:49:57 +0100 Subject: [PATCH 057/107] Implement ScalarOperand for isize, usize --- src/impl_ops.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/impl_ops.rs b/src/impl_ops.rs index 6cc0ddfcf..b8b763ba8 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -40,6 +40,8 @@ impl ScalarOperand for i32 { } impl ScalarOperand for u32 { } impl ScalarOperand for i64 { } impl ScalarOperand for u64 { } +impl ScalarOperand for isize { } +impl ScalarOperand for usize { } impl ScalarOperand for f32 { } impl ScalarOperand for f64 { } impl ScalarOperand for Complex { } From e8ab881999d454300ba8b136b05fd69967f65649 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 16:13:35 +0100 Subject: [PATCH 058/107] Rename Dimension's array vec methods to use the as_ convention --- src/dimension.rs | 4 ++-- tests/dimension.rs | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 6ae2348d3..e1f2cf8ca 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -184,10 +184,10 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + #[doc(hidden)] fn slice_mut(&mut self) -> &mut [Ix]; - fn array_view(&self) -> ArrayView1 { + fn as_array_view(&self) -> ArrayView1 { ArrayView1::from(self.slice()) } - fn array_view_mut(&mut self) -> ArrayViewMut1 { + fn as_array_view_mut(&mut self) -> ArrayViewMut1 { ArrayViewMut1::from(self.slice_mut()) } diff --git a/tests/dimension.rs b/tests/dimension.rs index 418be87e1..8e8995834 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -93,14 +93,15 @@ fn test_operations() { fn test_generic_operations() { fn test_dim(d: &D) { let mut x = d.clone(); - assert_eq!(x[0], 2); - x += 1; - assert_eq!(x[0], 3); - x += d; - assert_eq!(x[0], 5); - - assert_eq!(x[..].len(), x.ndim()); - assert_eq!(&x[..], x.slice()); + let mut v = x.as_array_view_mut(); + assert_eq!(v[0], 2); + v += 1; + assert_eq!(v[0], 3); + v += &d.as_array_view(); + assert_eq!(v[0], 5); + + assert_eq!(v[..].len(), x.ndim()); + assert_eq!(&v[..], x.slice()); } test_dim(&Dim([2, 3, 4])); From 5315b70f6e923b8640554087f4e92b15fe71e715 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 16:20:55 +0100 Subject: [PATCH 059/107] Update dimension tests --- tests/dimension.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tests/dimension.rs b/tests/dimension.rs index 8e8995834..8de0ef9a6 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -93,15 +93,10 @@ fn test_operations() { fn test_generic_operations() { fn test_dim(d: &D) { let mut x = d.clone(); - let mut v = x.as_array_view_mut(); - assert_eq!(v[0], 2); - v += 1; - assert_eq!(v[0], 3); - v += &d.as_array_view(); - assert_eq!(v[0], 5); - - assert_eq!(v[..].len(), x.ndim()); - assert_eq!(&v[..], x.slice()); + x += 1; + assert_eq!(x.as_array_view()[0], 3); + x += d; + assert_eq!(x.as_array_view()[0], 5); } test_dim(&Dim([2, 3, 4])); From 5dc2fe3364b4552a8b10cd4a5ad61470d75e501c Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 16:53:58 +0100 Subject: [PATCH 060/107] Use a macro to index Dim --- src/dimension.rs | 126 +++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 60 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index e1f2cf8ca..b14caf891 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -623,6 +623,12 @@ unsafe impl Dimension for Ix0 { } } +/// Indexing macro for Dim<[usize; N]> this +/// gets the index at `$i` in the underlying array +macro_rules! get { + ($dim:expr, $i:expr) => { (**$dim)[$i] } +} + unsafe impl Dimension for Ix1 { type SliceArg = [Si; 1]; type Pattern = Ix; @@ -634,12 +640,12 @@ unsafe impl Dimension for Ix1 { fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } #[inline] fn into_pattern(self) -> Self::Pattern { - self[0] + get!(&self, 0) } #[inline] fn next_for(&self, mut index: Self) -> Option { - index[0] += 1; - if index[0] < self[0] { + get!(&mut index, 0) += 1; + if get!(&index, 0) < get!(self, 0) { Some(index) } else { None @@ -648,13 +654,13 @@ unsafe impl Dimension for Ix1 { #[inline] fn equal(&self, rhs: &Self) -> bool { - self[0] == rhs[0] + get!(self, 0) == get!(rhs, 0) } #[inline] - fn size(&self) -> usize { self[0] } + fn size(&self) -> usize { get!(self, 0) } #[inline] - fn size_checked(&self) -> Option { Some(self[0]) } + fn size_checked(&self) -> Option { Some(get!(self, 0)) } #[inline] fn default_strides(&self) -> Self { @@ -668,7 +674,7 @@ unsafe impl Dimension for Ix1 { #[inline] fn first_index(&self) -> Option { - if self[0] != 0 { + if get!(self, 0) != 0 { Some(Ix1(0)) } else { None @@ -678,14 +684,14 @@ unsafe impl Dimension for Ix1 { /// Self is an index, return the stride offset #[inline(always)] fn stride_offset(index: &Self, stride: &Self) -> isize { - stride_offset(index[0], stride[0]) + stride_offset(get!(index, 0), get!(stride, 0)) } /// Return stride offset for this dimension and index. #[inline] fn stride_offset_checked(&self, stride: &Self, index: &Self) -> Option { - if index[0] < self[0] { - Some(stride_offset(index[0], stride[0])) + if get!(index, 0) < get!(self, 0) { + Some(stride_offset(get!(index, 0), get!(stride, 0))) } else { None } @@ -707,10 +713,10 @@ unsafe impl Dimension for Ix2 { fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } #[inline] fn next_for(&self, index: Self) -> Option { - let mut i = index[0]; - let mut j = index[1]; - let imax = self[0]; - let jmax = self[1]; + let mut i = get!(&index, 0); + let mut j = get!(&index, 1); + let imax = get!(self, 0); + let jmax = get!(self, 1); j += 1; if j >= jmax { j = 0; @@ -724,16 +730,16 @@ unsafe impl Dimension for Ix2 { #[inline] fn equal(&self, rhs: &Self) -> bool { - self[0] == rhs[0] && self[1] == rhs[1] + get!(self, 0) == get!(rhs, 0) && get!(self, 1) == get!(rhs, 1) } #[inline] - fn size(&self) -> usize { self[0] * self[1] } + fn size(&self) -> usize { get!(self, 0) * get!(self, 1) } #[inline] fn size_checked(&self) -> Option { - let m = self[0]; - let n = self[1]; + let m = get!(self, 0); + let n = get!(self, 1); (m as usize).checked_mul(n as usize) } @@ -751,16 +757,16 @@ unsafe impl Dimension for Ix2 { fn default_strides(&self) -> Self { // Compute default array strides // Shape (a, b, c) => Give strides (b * c, c, 1) - Ix2(self[1], 1) + Ix2(get!(self, 1), 1) } #[inline] fn fortran_strides(&self) -> Self { - Ix2(1, self[0]) + Ix2(1, get!(self, 0)) } #[inline] fn _fastest_varying_stride_order(&self) -> Self { - if self[0] as Ixs <= self[1] as Ixs { Ix2(0, 1) } else { Ix2(1, 0) } + if get!(self, 0) as Ixs <= get!(self, 1) as Ixs { Ix2(0, 1) } else { Ix2(1, 0) } } #[inline] @@ -789,8 +795,8 @@ unsafe impl Dimension for Ix2 { #[inline] fn first_index(&self) -> Option { - let m = self[0]; - let n = self[1]; + let m = get!(self, 0); + let n = get!(self, 1); if m != 0 && n != 0 { Some(Ix2(0, 0)) } else { @@ -801,10 +807,10 @@ unsafe impl Dimension for Ix2 { /// Self is an index, return the stride offset #[inline(always)] fn stride_offset(index: &Self, strides: &Self) -> isize { - let i = index[0]; - let j = index[1]; - let s = strides[0]; - let t = strides[1]; + let i = get!(index, 0); + let j = get!(index, 1); + let s = get!(strides, 0); + let t = get!(strides, 1); stride_offset(i, s) + stride_offset(j, t) } @@ -812,12 +818,12 @@ unsafe impl Dimension for Ix2 { #[inline] fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option { - let m = self[0]; - let n = self[1]; - let i = index[0]; - let j = index[1]; - let s = strides[0]; - let t = strides[1]; + let m = get!(self, 0); + let n = get!(self, 1); + let i = get!(index, 0); + let j = get!(index, 1); + let s = get!(strides, 0); + let t = get!(strides, 1); if i < m && j < n { Some(stride_offset(i, s) + stride_offset(j, t)) } else { @@ -842,20 +848,20 @@ unsafe impl Dimension for Ix3 { #[inline] fn size(&self) -> usize { - let m = self[0]; - let n = self[1]; - let o = self[2]; + let m = get!(self, 0); + let n = get!(self, 1); + let o = get!(self, 2); m as usize * n as usize * o as usize } #[inline] fn next_for(&self, index: Self) -> Option { - let mut i = index[0]; - let mut j = index[1]; - let mut k = index[2]; - let imax = self[0]; - let jmax = self[1]; - let kmax = self[2]; + let mut i = get!(&index, 0); + let mut j = get!(&index, 1); + let mut k = get!(&index, 2); + let imax = get!(self, 0); + let jmax = get!(self, 1); + let kmax = get!(self, 2); k += 1; if k == kmax { k = 0; @@ -874,12 +880,12 @@ unsafe impl Dimension for Ix3 { /// Self is an index, return the stride offset #[inline] fn stride_offset(index: &Self, strides: &Self) -> isize { - let i = index[0]; - let j = index[1]; - let k = index[2]; - let s = strides[0]; - let t = strides[1]; - let u = strides[2]; + let i = get!(index, 0); + let j = get!(index, 1); + let k = get!(index, 2); + let s = get!(strides, 0); + let t = get!(strides, 1); + let u = get!(strides, 2); stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u) } @@ -973,7 +979,7 @@ impl RemoveAxis for Ix2 { fn remove_axis(&self, axis: Axis) -> Ix1 { let axis = axis.axis(); debug_assert!(axis < self.ndim()); - if axis == 0 { Ix1(self[1]) } else { Ix1(self[0]) } + if axis == 0 { Ix1(get!(self, 1)) } else { Ix1(get!(self, 0)) } } } @@ -1065,7 +1071,7 @@ unsafe impl NdIndex for Ix { } #[inline(always)] fn index_unchecked(&self, strides: &Ix1) -> isize { - stride_offset(*self, strides[0]) + stride_offset(*self, get!(strides, 0)) } } @@ -1076,8 +1082,8 @@ unsafe impl NdIndex for (Ix, Ix) { } #[inline] fn index_unchecked(&self, strides: &Ix2) -> isize { - stride_offset(self.0, strides[0]) + - stride_offset(self.1, strides[1]) + stride_offset(self.0, get!(strides, 0)) + + stride_offset(self.1, get!(strides, 1)) } } unsafe impl NdIndex for (Ix, Ix, Ix) { @@ -1088,9 +1094,9 @@ unsafe impl NdIndex for (Ix, Ix, Ix) { #[inline] fn index_unchecked(&self, strides: &Ix3) -> isize { - stride_offset(self.0, strides[0]) + - stride_offset(self.1, strides[1]) + - stride_offset(self.2, strides[2]) + stride_offset(self.0, get!(strides, 0)) + + stride_offset(self.1, get!(strides, 1)) + + stride_offset(self.2, get!(strides, 2)) } } @@ -1122,8 +1128,8 @@ unsafe impl NdIndex for [Ix; 2] { } #[inline] fn index_unchecked(&self, strides: &Ix2) -> isize { - stride_offset(self[0], strides[0]) + - stride_offset(self[1], strides[1]) + stride_offset(self[0], get!(strides, 0)) + + stride_offset(self[1], get!(strides, 1)) } } @@ -1134,9 +1140,9 @@ unsafe impl NdIndex for [Ix; 3] { } #[inline] fn index_unchecked(&self, strides: &Ix3) -> isize { - stride_offset(self[0], strides[0]) + - stride_offset(self[1], strides[1]) + - stride_offset(self[2], strides[2]) + stride_offset(self[0], get!(strides, 0)) + + stride_offset(self[1], get!(strides, 1)) + + stride_offset(self[2], get!(strides, 2)) } } From c23897a3354b98bee524859b90062f01e643a50b Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 17:03:10 +0100 Subject: [PATCH 061/107] Put in place element indexing on dimensions --- src/dimension.rs | 62 ++++++++++++++++++++++++---------------------- tests/dimension.rs | 16 ++++++++++-- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index b14caf891..f6ca8d529 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -124,7 +124,6 @@ fn stride_offset_checked_arithmetic(dim: &D, strides: &D, index: &D) } use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; -use std::ops::{Range, RangeTo, RangeFrom, RangeFull}; /// Array shape and index trait. /// @@ -133,13 +132,7 @@ use std::ops::{Range, RangeTo, RangeFrom, RangeFull}; /// ***Don't implement or call methods in this trait, its interface is internal /// to the crate and will evolve at will.*** pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + -/* IndexMut + - IndexMut, Output=[usize]> + - IndexMut, Output=[usize]> + - IndexMut, Output=[usize]> + - IndexMut + - */ Add + Add + AddAssign + for<'x> AddAssign<&'x Self> + AddAssign + Sub + Sub + @@ -595,6 +588,21 @@ macro_rules! tuple_to_array { } } + impl Index for Dim<[Ix; $n]> { + type Output = usize; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + &(**self)[index] + } + } + + impl IndexMut for Dim<[Ix; $n]> { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut (**self)[index] + } + } + )* } } @@ -958,6 +966,23 @@ unsafe impl Dimension for Dim> } } +impl Index for Dim> + where Vec: Index, +{ + type Output = as Index>::Output; + fn index(&self, index: J) -> &Self::Output { + &(**self)[index] + } +} + +impl IndexMut for Dim> + where Vec: IndexMut, +{ + fn index_mut(&mut self, index: J) -> &mut Self::Output { + &mut (**self)[index] + } +} + /// Array shape with a next smaller dimension. /// /// `RemoveAxis` defines a larger-than relation for array shapes: @@ -1295,7 +1320,7 @@ pub mod dim { } } - use std::ops::{Deref, DerefMut, Index, IndexMut}; + use std::ops::{Deref, DerefMut}; impl Deref for Dim { type Target = I; @@ -1306,27 +1331,6 @@ pub mod dim { fn deref_mut(&mut self) -> &mut I { &mut self.index } } - /* - impl Index for Dim - where [usize]: Index, - Dim: Dimension, - { - type Output = <[usize] as Index>::Output; - fn index(&self, index: J) -> &Self::Output { - self.slice().index(index) - } - } - - impl IndexMut for Dim - where [usize]: IndexMut, - Dim: Dimension, - { - fn index_mut(&mut self, index: J) -> &mut Self::Output { - self.slice_mut().index_mut(index) - } - } - */ - use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; macro_rules! impl_op { diff --git a/tests/dimension.rs b/tests/dimension.rs index 8de0ef9a6..5410a8038 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -94,12 +94,24 @@ fn test_generic_operations() { fn test_dim(d: &D) { let mut x = d.clone(); x += 1; - assert_eq!(x.as_array_view()[0], 3); + assert_eq!(x[0], 3); x += d; - assert_eq!(x.as_array_view()[0], 5); + assert_eq!(x[0], 5); } test_dim(&Dim([2, 3, 4])); test_dim(&Dim(vec![2, 3, 4, 1])); test_dim(&Dim(2)); } + +#[test] +fn test_array_view() { + fn test_dim(d: &D) { + assert_eq!(d.as_array_view().scalar_sum(), 7); + assert_eq!(d.as_array_view().strides(), &[1]); + } + + test_dim(&Dim([1, 2, 4])); + test_dim(&Dim(vec![1, 1, 2, 3])); + test_dim(&Dim(7)); +} From d0c88d686a1085c87b282be6e9dc752a4618b58f Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 17:07:28 +0100 Subject: [PATCH 062/107] Remove unused imports in dimension --- src/dimension.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index f6ca8d529..023a2424a 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -7,7 +7,6 @@ // except according to those terms. use std::cmp::Ordering; use std::fmt::Debug; -use std::slice; use std::ops::{Index, IndexMut}; use itertools::{enumerate, zip}; @@ -1290,7 +1289,7 @@ pub mod dim { use super::Dimension; use Ix; - use itertools::{enumerate, zip}; + use itertools::zip; #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] pub struct Dim { From 0b062fd8d3be23e684e0d62049e69efda3836039 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 17:07:41 +0100 Subject: [PATCH 063/107] Remove unused imports in shape_builder.rs --- src/shape_builder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shape_builder.rs b/src/shape_builder.rs index 95676bed9..d6fd71482 100644 --- a/src/shape_builder.rs +++ b/src/shape_builder.rs @@ -1,7 +1,6 @@ use Dimension; use {Shape, StrideShape}; -use Ix; use dimension::IntoDimension; /// A trait for `Shape` and `D where D: Dimension` that allows From 695bb921ef2fa78cdc125bc6b2d5ab0ec7fd1134 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 17:08:30 +0100 Subject: [PATCH 064/107] Remove unused imports in constructors --- src/impl_constructors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 1a7f7677c..ff58d00ff 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -13,7 +13,7 @@ use libnum::{Zero, One, Float}; use imp_prelude::*; -use {Shape, StrideShape}; +use StrideShape; use dimension; use linspace; use error::{self, ShapeError, ErrorKind}; From 77166f99720f9c2ec3772b5cb40fcda8faadcd22 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 17:14:18 +0100 Subject: [PATCH 065/107] Remove unused lifetime parameter --- src/dimension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dimension.rs b/src/dimension.rs index 023a2424a..b081dbfef 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -1193,7 +1193,7 @@ unsafe impl<'a> NdIndex for &'a [Ix] { } } -unsafe impl<'a> NdIndex for Vec { +unsafe impl NdIndex for Vec { fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { let mut offset = 0; for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { From 90d2a5cc16d1280b2ca99a4d28a8e12a72ca4234 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 17:54:15 +0100 Subject: [PATCH 066/107] Docs for Ix, Dim functions --- src/aliases.rs | 8 ++++++++ src/dimension.rs | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/aliases.rs b/src/aliases.rs index 5ce282a04..452004e2f 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -4,18 +4,26 @@ use ::{Ix, Array, ArrayView, ArrayViewMut}; use ::dimension::Dim; +/// Create a zero-dimensional index #[allow(non_snake_case)] #[inline(always)] pub fn Ix0() -> Ix0 { Dim([]) } +/// Create a one-dimensional index #[allow(non_snake_case)] #[inline(always)] pub fn Ix1(i0: Ix) -> Ix1 { Dim([i0]) } +/// Create a two-dimensional index #[allow(non_snake_case)] #[inline(always)] pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { Dim([i0, i1]) } +/// Create a three-dimensional index #[allow(non_snake_case)] #[inline(always)] pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 { Dim([i0, i1, i2]) } +/// Create a four-dimensional index +#[allow(non_snake_case)] +#[inline(always)] +pub fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 { Dim([i0, i1, i2, i3]) } /// zero-dimensionial pub type Ix0 = Dim<[Ix; 0]>; diff --git a/src/dimension.rs b/src/dimension.rs index b081dbfef..d49140d43 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -497,6 +497,7 @@ macro_rules! index_item { ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5);); } +/// Convert a value into a dimension. pub trait IntoDimension { type Dim: Dimension; fn into_dimension(self) -> Self::Dim; @@ -1304,6 +1305,7 @@ pub mod dim { } } + /// Create a new dimension value. #[allow(non_snake_case)] pub fn Dim(index: T) -> T::Dim where T: IntoDimension From d33b07af97fee0b99dd4b14f237c73692c7e7bdf Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 20:33:25 +0100 Subject: [PATCH 067/107] Edit dimension docs, expose size(), size_checked() --- src/dimension.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index d49140d43..571f9cb5f 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -128,8 +128,7 @@ use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; /// /// `unsafe` because of the assumptions in the default methods. /// -/// ***Don't implement or call methods in this trait, its interface is internal -/// to the crate and will evolve at will.*** +/// ***Don't implement this trait, it will evolve at will.*** pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + IndexMut + Add + Add + @@ -164,34 +163,39 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + type Pattern: IntoDimension; #[doc(hidden)] fn ndim(&self) -> usize; - fn equal(&self, rhs: &Self) -> bool { - self.slice() == rhs.slice() - } + /// Convert the dimension into a pattern matching friendly value. fn into_pattern(self) -> Self::Pattern; + /// Compute the size of the dimension (number of elements) + fn size(&self) -> usize { + self.slice().iter().fold(1, |s, &a| s * a as usize) + } + + /// Compute the size while checking for overflow. + fn size_checked(&self) -> Option { + self.slice().iter().fold(Some(1), |s, &a| s.and_then(|s_| s_.checked_mul(a))) + } + #[doc(hidden)] fn slice(&self) -> &[Ix]; #[doc(hidden)] fn slice_mut(&mut self) -> &mut [Ix]; + /// Borrow as a read-only array view. fn as_array_view(&self) -> ArrayView1 { ArrayView1::from(self.slice()) } + + /// Borrow as a read-write array view. fn as_array_view_mut(&mut self) -> ArrayViewMut1 { ArrayViewMut1::from(self.slice_mut()) } #[doc(hidden)] - fn size(&self) -> usize { - self.slice().iter().fold(1, |s, &a| s * a as usize) - } - - #[doc(hidden)] - /// Compute the size while checking for overflow - fn size_checked(&self) -> Option { - self.slice().iter().fold(Some(1), |s, &a| s.and_then(|s_| s_.checked_mul(a))) + fn equal(&self, rhs: &Self) -> bool { + self.slice() == rhs.slice() } #[doc(hidden)] From 32efd4f8486b6e7827dd216da62fd6112f6461eb Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 20:44:05 +0100 Subject: [PATCH 068/107] Make dimensions consistent for Ix0-Ix6 with aliases and constructors --- src/aliases.rs | 22 ++++++++++++++++++++++ src/dimension.rs | 33 +++++++++++++-------------------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index 452004e2f..b07d9d10d 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -24,6 +24,14 @@ pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 { Dim([i0, i1, i2]) } #[allow(non_snake_case)] #[inline(always)] pub fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 { Dim([i0, i1, i2, i3]) } +/// Create a five-dimensional index +#[allow(non_snake_case)] +#[inline(always)] +pub fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 { Dim([i0, i1, i2, i3, i4]) } +/// Create a six-dimensional index +#[allow(non_snake_case)] +#[inline(always)] +pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 { Dim([i0, i1, i2, i3, i4, i5]) } /// zero-dimensionial pub type Ix0 = Dim<[Ix; 0]>; @@ -37,6 +45,8 @@ pub type Ix3 = Dim<[Ix; 3]>; pub type Ix4 = Dim<[Ix; 4]>; /// five-dimensional pub type Ix5 = Dim<[Ix; 5]>; +/// six-dimensional +pub type Ix6 = Dim<[Ix; 6]>; /// dynamic-dimensional pub type IxDyn = Dim>; @@ -50,6 +60,10 @@ pub type Array2 = Array; pub type Array3 = Array; /// four-dimensional array pub type Array4 = Array; +/// five-dimensional array +pub type Array5 = Array; +/// six-dimensional array +pub type Array6 = Array; /// dynamic-dimensional array pub type ArrayD = Array; @@ -63,6 +77,10 @@ pub type ArrayView2<'a, A> = ArrayView<'a, A, Ix2>; pub type ArrayView3<'a, A> = ArrayView<'a, A, Ix3>; /// four-dimensional array view pub type ArrayView4<'a, A> = ArrayView<'a, A, Ix4>; +/// five-dimensional array view +pub type ArrayView5<'a, A> = ArrayView<'a, A, Ix5>; +/// six-dimensional array view +pub type ArrayView6<'a, A> = ArrayView<'a, A, Ix6>; /// dynamic-dimensional array view pub type ArrayViewD<'a, A> = ArrayView<'a, A, IxDyn>; @@ -76,5 +94,9 @@ pub type ArrayViewMut2<'a, A> = ArrayViewMut<'a, A, Ix2>; pub type ArrayViewMut3<'a, A> = ArrayViewMut<'a, A, Ix3>; /// four-dimensional read-write array view pub type ArrayViewMut4<'a, A> = ArrayViewMut<'a, A, Ix4>; +/// five-dimensional read-write array view +pub type ArrayViewMut5<'a, A> = ArrayViewMut<'a, A, Ix5>; +/// six-dimensional read-write array view +pub type ArrayViewMut6<'a, A> = ArrayViewMut<'a, A, Ix6>; /// dynamic-dimensional read-write array view pub type ArrayViewMutD<'a, A> = ArrayViewMut<'a, A, IxDyn>; diff --git a/src/dimension.rs b/src/dimension.rs index 571f9cb5f..182726e84 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -15,7 +15,7 @@ use super::{Si, Ix, Ixs}; use super::{zipsl, zipsl_mut}; use error::{from_kind, ErrorKind, ShapeError}; use ZipExt; -use {Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, IxDyn}; +use {Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn}; use {ArrayView1, ArrayViewMut1}; /// Calculate offset from `Ix` stride converting sign properly @@ -489,6 +489,7 @@ macro_rules! index { ($m:ident $arg:tt 4) => ($m!($arg 0 1 2 3)); ($m:ident $arg:tt 5) => ($m!($arg 0 1 2 3 4)); ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5)); + ($m:ident $arg:tt 7) => ($m!($arg 0 1 2 3 4 5 6)); } macro_rules! index_item { @@ -499,6 +500,7 @@ macro_rules! index_item { ($m:ident $arg:tt 4) => ($m!($arg 0 1 2 3);); ($m:ident $arg:tt 5) => ($m!($arg 0 1 2 3 4);); ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5);); + ($m:ident $arg:tt 7) => ($m!($arg 0 1 2 3 4 5 6);); } /// Convert a value into a dimension. @@ -611,7 +613,7 @@ macro_rules! tuple_to_array { } } -index_item!(tuple_to_array [] 6); +index_item!(tuple_to_array [] 7); unsafe impl Dimension for Ix0 { type SliceArg = [Si; 0]; @@ -925,8 +927,8 @@ unsafe impl Dimension for Ix3 { } macro_rules! large_dim { - ($n:expr, $($ix:ident),+) => ( - unsafe impl Dimension for Dim<[Ix; $n]> { + ($n:expr, $name:ident, $($ix:ident),+) => ( + unsafe impl Dimension for $name { type SliceArg = [Si; $n]; type Pattern = ($($ix,)*); #[inline] @@ -943,21 +945,13 @@ macro_rules! large_dim { ) } -large_dim!(4, Ix, Ix, Ix, Ix); -large_dim!(5, Ix, Ix, Ix, Ix, Ix); -/* -large_dim!(6, Ix, Ix, Ix, Ix, Ix, Ix); -large_dim!(7, Ix, Ix, Ix, Ix, Ix, Ix, Ix); -large_dim!(8, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); -large_dim!(9, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); -large_dim!(10, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); -large_dim!(11, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); -large_dim!(12, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix); -*/ +large_dim!(4, Ix4, Ix, Ix, Ix, Ix); +large_dim!(5, Ix5, Ix, Ix, Ix, Ix, Ix); +large_dim!(6, Ix6, Ix, Ix, Ix, Ix, Ix, Ix); /// Vec is a "dynamic" index, pretty hard to use when indexing, /// and memory wasteful, but it allows an arbitrary and dynamic number of axes. -unsafe impl Dimension for Dim> +unsafe impl Dimension for IxDyn { type SliceArg = [Si]; type Pattern = Self; @@ -996,13 +990,13 @@ pub trait RemoveAxis : Dimension { fn remove_axis(&self, axis: Axis) -> Self::Smaller; } -impl RemoveAxis for Ix1 { +impl RemoveAxis for Dim<[Ix; 1]> { type Smaller = Ix0; #[inline] fn remove_axis(&self, _: Axis) -> Ix0 { Ix0() } } -impl RemoveAxis for Ix2 { +impl RemoveAxis for Dim<[Ix; 2]> { type Smaller = Ix1; #[inline] fn remove_axis(&self, axis: Axis) -> Ix1 { @@ -1040,8 +1034,7 @@ macro_rules! impl_remove_axis_array( ); ); -// 12 is the maximum number for having the Eq trait from libstd -impl_remove_axis_array!(3, 4, 5); +impl_remove_axis_array!(3, 4, 5, 6); impl RemoveAxis for Dim> { From ce3a29e663423aa7ee5633d65d03fb830dd3d281 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 21:36:26 +0100 Subject: [PATCH 069/107] Remove unused Convert impls --- src/dimension.rs | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 182726e84..c5c0ddf53 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -532,13 +532,6 @@ trait Convert { fn convert(self) -> Self::To; } -impl Convert for Ix { - type To = Ix1; - fn convert(self) -> Self::To { Ix1(self) } -} -/* -*/ - macro_rules! sub { ($_x:tt $y:tt) => ($y); } @@ -571,13 +564,6 @@ macro_rules! tuple_to_array { } } - impl Convert for index!(tuple_type [Ix] $n) { - type To = Dim<[Ix; $n]>; - fn convert(self) -> Self::To { - Dim(index!(array_expr [self] $n)) - } - } - impl IntoDimension for [Ix; $n] { type Dim = Dim<[Ix; $n]>; #[inline(always)] @@ -1111,7 +1097,7 @@ unsafe impl NdIndex for (Ix, Ix) { unsafe impl NdIndex for (Ix, Ix, Ix) { #[inline] fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { - dim.stride_offset_checked(strides, &self.convert()) + dim.stride_offset_checked(strides, &self.into_dimension()) } #[inline] @@ -1125,21 +1111,21 @@ unsafe impl NdIndex for (Ix, Ix, Ix) { unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { #[inline] fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option { - dim.stride_offset_checked(strides, &self.convert()) + dim.stride_offset_checked(strides, &self.into_dimension()) } #[inline] fn index_unchecked(&self, strides: &Ix4) -> isize { - zip(&**strides, &*self.convert()).map(|(&s, &i)| stride_offset(i, s)).sum() + zip(&**strides, &*self.into_dimension()).map(|(&s, &i)| stride_offset(i, s)).sum() } } unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { #[inline] fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option { - dim.stride_offset_checked(strides, &self.convert()) + dim.stride_offset_checked(strides, &self.into_dimension()) } #[inline] fn index_unchecked(&self, strides: &Ix5) -> isize { - zip(&**strides, &*self.convert()).map(|(&s, &i)| stride_offset(i, s)).sum() + zip(&**strides, &*self.into_dimension()).map(|(&s, &i)| stride_offset(i, s)).sum() } } From 3c68b864bd05c7b586bb07744011e31b63406cab Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 21:51:57 +0100 Subject: [PATCH 070/107] dimension: Only multiplication is implemented as scalar op, impl Zero --- src/dimension.rs | 78 ++++++++++++++++++++++++++++++++++++---------- tests/dimension.rs | 6 ++-- 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index c5c0ddf53..70d5ffbc2 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -10,6 +10,7 @@ use std::fmt::Debug; use std::ops::{Index, IndexMut}; use itertools::{enumerate, zip}; +use libnum::Zero; use super::{Si, Ix, Ixs}; use super::{zipsl, zipsl_mut}; @@ -131,12 +132,12 @@ use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; /// ***Don't implement this trait, it will evolve at will.*** pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + IndexMut + - Add + Add + - AddAssign + for<'x> AddAssign<&'x Self> + AddAssign + - Sub + Sub + - SubAssign + for<'x> SubAssign<&'x Self> + SubAssign + + Add + + AddAssign + for<'x> AddAssign<&'x Self> + + Sub + + SubAssign + for<'x> SubAssign<&'x Self> + Mul + Mul + - MulAssign + for<'x> MulAssign<&'x Self> + MulAssign + MulAssign + for<'x> MulAssign<&'x Self> + MulAssign { /// `SliceArg` is the type which is used to specify slicing for this @@ -554,6 +555,12 @@ macro_rules! array_expr { ) } +macro_rules! array_zero { + ([] $($index:tt)*) => ( + [$(sub!($index 0), )*] + ) +} + macro_rules! tuple_to_array { ([] $($n:tt)*) => { $( @@ -595,6 +602,16 @@ macro_rules! tuple_to_array { } } + impl Zero for Dim<[Ix; $n]> { + #[inline] + fn zero() -> Self { + Dim::new(index!(array_zero [] $n)) + } + fn is_zero(&self) -> bool { + self.slice().iter().all(|x| *x == 0) + } + } + )* } } @@ -1329,16 +1346,6 @@ pub mod dim { } } - impl $op for Dim - where Dim: Dimension, - { - type Output = Self; - fn $op_m(mut self, rhs: Ix) -> Self { - $expr!(self, rhs); - self - } - } - impl $opassign for Dim where Dim: Dimension, { @@ -1357,6 +1364,42 @@ pub mod dim { } } + } + } + + macro_rules! impl_single_op { + ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { + impl $op for Dim<[Ix; 1]> + { + type Output = Self; + #[inline] + fn $op_m(mut self, rhs: Ix) -> Self { + $expr!(self, rhs); + self + } + } + + impl $opassign for Dim<[Ix; 1]> { + #[inline] + fn $opassign_m(&mut self, rhs: Ix) { + $expr!((*self)[0], rhs); + } + } + }; + } + + macro_rules! impl_scalar_op { + ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { + impl $op for Dim + where Dim: Dimension, + { + type Output = Self; + fn $op_m(mut self, rhs: Ix) -> Self { + $expr!(self, rhs); + self + } + } + impl $opassign for Dim where Dim: Dimension, { @@ -1366,7 +1409,7 @@ pub mod dim { } } } - } + }; } macro_rules! add { @@ -1379,8 +1422,11 @@ pub mod dim { ($x:expr, $y:expr) => { $x *= $y; } } impl_op!(Add, add, AddAssign, add_assign, add); + impl_single_op!(Add, add, AddAssign, add_assign, add); impl_op!(Sub, sub, SubAssign, sub_assign, sub); + impl_single_op!(Sub, sub, SubAssign, sub_assign, sub); impl_op!(Mul, mul, MulAssign, mul_assign, mul); + impl_scalar_op!(Mul, mul, MulAssign, mul_assign, mul); } diff --git a/tests/dimension.rs b/tests/dimension.rs index 5410a8038..53409f99f 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -85,15 +85,15 @@ fn test_operations() { x *= 2; assert_eq!(x, [4, 6]); - y -= 1; - assert_eq!(y, [0, 0]); + y[0] -= 1; + assert_eq!(y, [0, 1]); } #[test] fn test_generic_operations() { fn test_dim(d: &D) { let mut x = d.clone(); - x += 1; + x[0] += 1; assert_eq!(x[0], 3); x += d; assert_eq!(x[0], 5); From 3d24f791d5219fae032e0ac5ab425ec657f6de05 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 22:28:38 +0100 Subject: [PATCH 071/107] dimension: Remove Deref and use explicit private accessors --- src/dimension.rs | 88 ++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/src/dimension.rs b/src/dimension.rs index 70d5ffbc2..f039a04a0 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -591,14 +591,14 @@ macro_rules! tuple_to_array { type Output = usize; #[inline(always)] fn index(&self, index: usize) -> &Self::Output { - &(**self)[index] + &self.ix()[index] } } impl IndexMut for Dim<[Ix; $n]> { #[inline(always)] fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut (**self)[index] + &mut self.ixm()[index] } } @@ -625,15 +625,13 @@ unsafe impl Dimension for Ix0 { #[inline] fn ndim(&self) -> usize { 0 } #[inline] - fn slice(&self) -> &[Ix] { &**self } + fn slice(&self) -> &[Ix] { &[] } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } + fn slice_mut(&mut self) -> &mut [Ix] { &mut [] } #[inline] fn _fastest_varying_stride_order(&self) -> Self { Ix0() } #[inline] - fn into_pattern(self) -> Self::Pattern { - self.convert() - } + fn into_pattern(self) -> Self::Pattern { } #[inline] fn next_for(&self, _index: Self) -> Option { None @@ -643,7 +641,10 @@ unsafe impl Dimension for Ix0 { /// Indexing macro for Dim<[usize; N]> this /// gets the index at `$i` in the underlying array macro_rules! get { - ($dim:expr, $i:expr) => { (**$dim)[$i] } + ($dim:expr, $i:expr) => { $dim.ix()[$i] } +} +macro_rules! getm { + ($dim:expr, $i:expr) => { $dim.ixm()[$i] } } unsafe impl Dimension for Ix1 { @@ -652,16 +653,16 @@ unsafe impl Dimension for Ix1 { #[inline] fn ndim(&self) -> usize { 1 } #[inline] - fn slice(&self) -> &[Ix] { &**self } + fn slice(&self) -> &[Ix] { self.ix() } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } #[inline] fn into_pattern(self) -> Self::Pattern { get!(&self, 0) } #[inline] fn next_for(&self, mut index: Self) -> Option { - get!(&mut index, 0) += 1; + getm!(index, 0) += 1; if get!(&index, 0) < get!(self, 0) { Some(index) } else { @@ -722,12 +723,12 @@ unsafe impl Dimension for Ix2 { fn ndim(&self) -> usize { 2 } #[inline] fn into_pattern(self) -> Self::Pattern { - self.convert() + self.ix().convert() } #[inline] - fn slice(&self) -> &[Ix] { &**self } + fn slice(&self) -> &[Ix] { self.ix() } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } #[inline] fn next_for(&self, index: Self) -> Option { let mut i = get!(&index, 0); @@ -762,12 +763,12 @@ unsafe impl Dimension for Ix2 { #[inline] fn last_elem(&self) -> usize { - (**self)[1] + get!(self, 1) } #[inline] fn set_last_elem(&mut self, i: usize) { - (**self)[1] = i; + getm!(self, 1) = i; } #[inline] @@ -856,12 +857,12 @@ unsafe impl Dimension for Ix3 { fn ndim(&self) -> usize { 3 } #[inline] fn into_pattern(self) -> Self::Pattern { - self.convert() + self.ix().convert() } #[inline] - fn slice(&self) -> &[Ix] { &**self } + fn slice(&self) -> &[Ix] { self.ix() } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } #[inline] fn size(&self) -> usize { @@ -914,7 +915,7 @@ unsafe impl Dimension for Ix3 { ($stride:expr, $order:expr, $x:expr, $y:expr) => { if $stride[$x] > $stride[$y] { $stride.swap($x, $y); - $order.swap($x, $y); + $order.ixm().swap($x, $y); } } } @@ -938,12 +939,12 @@ macro_rules! large_dim { fn ndim(&self) -> usize { $n } #[inline] fn into_pattern(self) -> Self::Pattern { - self.convert() + self.ix().convert() } #[inline] - fn slice(&self) -> &[Ix] { &**self } + fn slice(&self) -> &[Ix] { self.ix() } #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut **self } + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } } ) } @@ -958,9 +959,9 @@ unsafe impl Dimension for IxDyn { type SliceArg = [Si]; type Pattern = Self; - fn ndim(&self) -> usize { self.len() } - fn slice(&self) -> &[Ix] { self } - fn slice_mut(&mut self) -> &mut [Ix] { self } + fn ndim(&self) -> usize { self.ix().len() } + fn slice(&self) -> &[Ix] { self.ix() } + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } #[inline] fn into_pattern(self) -> Self::Pattern { self @@ -972,7 +973,7 @@ impl Index for Dim> { type Output = as Index>::Output; fn index(&self, index: J) -> &Self::Output { - &(**self)[index] + &self.ix()[index] } } @@ -980,7 +981,7 @@ impl IndexMut for Dim> where Vec: IndexMut, { fn index_mut(&mut self, index: J) -> &mut Self::Output { - &mut (**self)[index] + &mut self.ixm()[index] } } @@ -1044,7 +1045,7 @@ impl RemoveAxis for Dim> { type Smaller = Self; fn remove_axis(&self, axis: Axis) -> Self { let mut res = self.clone(); - res.remove(axis.axis()); + res.ixm().remove(axis.axis()); res } } @@ -1132,7 +1133,7 @@ unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { } #[inline] fn index_unchecked(&self, strides: &Ix4) -> isize { - zip(&**strides, &*self.into_dimension()).map(|(&s, &i)| stride_offset(i, s)).sum() + zip(strides.ix(), self.into_dimension().ix()).map(|(&s, &i)| stride_offset(i, s)).sum() } } unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { @@ -1142,7 +1143,7 @@ unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { } #[inline] fn index_unchecked(&self, strides: &Ix5) -> isize { - zip(&**strides, &*self.into_dimension()).map(|(&s, &i)| stride_offset(i, s)).sum() + zip(strides.ix(), self.into_dimension().ix()).map(|(&s, &i)| stride_offset(i, s)).sum() } } @@ -1190,7 +1191,7 @@ unsafe impl<'a> NdIndex for &'a [Ix] { Some(offset) } fn index_unchecked(&self, strides: &IxDyn) -> isize { - zip(&**strides, *self).map(|(&s, &i)| stride_offset(i, s)).sum() + zip(strides.ix(), *self).map(|(&s, &i)| stride_offset(i, s)).sum() } } @@ -1206,7 +1207,7 @@ unsafe impl NdIndex for Vec { Some(offset) } fn index_unchecked(&self, strides: &IxDyn) -> isize { - zip(&**strides, self).map(|(&s, &i)| stride_offset(i, s)).sum() + zip(strides.ix(), self).map(|(&s, &i)| stride_offset(i, s)).sum() } } @@ -1279,14 +1280,16 @@ derive_cmp!{PartialEq for Axis, eq -> bool} derive_cmp!{PartialOrd for Axis, partial_cmp -> Option} clone_from_copy!{Axis} -trait DimNew { +trait DimPrivate { fn new(index: I) -> Self; + fn ix(&self) -> &I; + fn ixm(&mut self) -> &mut I; } pub use self::dim::*; pub mod dim { use super::IntoDimension; - use super::DimNew; + use super::DimPrivate; use super::Dimension; use Ix; @@ -1297,12 +1300,14 @@ pub mod dim { index: I, } - impl DimNew for Dim { + impl DimPrivate for Dim { fn new(index: I) -> Dim { Dim { index: index, } } + fn ix(&self) -> &I { &self.index } + fn ixm(&mut self) -> &mut I { &mut self.index } } /// Create a new dimension value. @@ -1321,17 +1326,6 @@ pub mod dim { } } - use std::ops::{Deref, DerefMut}; - - impl Deref for Dim { - type Target = I; - fn deref(&self) -> &I { &self.index } - } - impl DerefMut for Dim - { - fn deref_mut(&mut self) -> &mut I { &mut self.index } - } - use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; macro_rules! impl_op { From 1af5f01f60432c8ee615362fc7671518ffdd13e4 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 22:33:04 +0100 Subject: [PATCH 072/107] Add doc for Dim --- src/dimension.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dimension.rs b/src/dimension.rs index f039a04a0..7a0fef01f 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -1295,6 +1295,10 @@ pub mod dim { use itertools::zip; + /// Dimension description. + /// + /// `Dim` describes the number of axes and the length of each axis + /// in an array. It is also used as an index type. #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] pub struct Dim { index: I, From 60e9c58ea66c7afb035b7bea0fa08f818f1aa018 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 22:47:05 +0100 Subject: [PATCH 073/107] Simplify the Ix0-Ix6 functions --- src/aliases.rs | 19 ++++++++++++------- src/dimension.rs | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index b07d9d10d..9f5cd3252 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -3,35 +3,40 @@ use ::{Ix, Array, ArrayView, ArrayViewMut}; use ::dimension::Dim; +use dimension::DimPrivate; /// Create a zero-dimensional index #[allow(non_snake_case)] #[inline(always)] -pub fn Ix0() -> Ix0 { Dim([]) } +pub fn Ix0() -> Ix0 { Dim::new([]) } /// Create a one-dimensional index #[allow(non_snake_case)] #[inline(always)] -pub fn Ix1(i0: Ix) -> Ix1 { Dim([i0]) } +pub fn Ix1(i0: Ix) -> Ix1 { Dim::new([i0]) } /// Create a two-dimensional index #[allow(non_snake_case)] #[inline(always)] -pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { Dim([i0, i1]) } +pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { Dim::new([i0, i1]) } /// Create a three-dimensional index #[allow(non_snake_case)] #[inline(always)] -pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 { Dim([i0, i1, i2]) } +pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 { Dim::new([i0, i1, i2]) } /// Create a four-dimensional index #[allow(non_snake_case)] #[inline(always)] -pub fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 { Dim([i0, i1, i2, i3]) } +pub fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 { Dim::new([i0, i1, i2, i3]) } /// Create a five-dimensional index #[allow(non_snake_case)] #[inline(always)] -pub fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 { Dim([i0, i1, i2, i3, i4]) } +pub fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 { + Dim::new([i0, i1, i2, i3, i4]) +} /// Create a six-dimensional index #[allow(non_snake_case)] #[inline(always)] -pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 { Dim([i0, i1, i2, i3, i4, i5]) } +pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 { + Dim::new([i0, i1, i2, i3, i4, i5]) +} /// zero-dimensionial pub type Ix0 = Dim<[Ix; 0]>; diff --git a/src/dimension.rs b/src/dimension.rs index 7a0fef01f..afc857550 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -1280,7 +1280,7 @@ derive_cmp!{PartialEq for Axis, eq -> bool} derive_cmp!{PartialOrd for Axis, partial_cmp -> Option} clone_from_copy!{Axis} -trait DimPrivate { +pub trait DimPrivate { fn new(index: I) -> Self; fn ix(&self) -> &I; fn ixm(&mut self) -> &mut I; From 4ac8078cad2278ac07eef09feb0da54b20899cbd Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 22:49:35 +0100 Subject: [PATCH 074/107] Prepare to split the dimension module --- src/{dimension.rs => dimension/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{dimension.rs => dimension/mod.rs} (100%) diff --git a/src/dimension.rs b/src/dimension/mod.rs similarity index 100% rename from src/dimension.rs rename to src/dimension/mod.rs From f24aa934195449911a48ad0224e119e7e121abc1 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 22:54:14 +0100 Subject: [PATCH 075/107] Split out Axis and Dim --- src/dimension/axis.rs | 49 +++++++++++ src/dimension/dim.rs | 152 ++++++++++++++++++++++++++++++++ src/dimension/mod.rs | 197 ++---------------------------------------- 3 files changed, 207 insertions(+), 191 deletions(-) create mode 100644 src/dimension/axis.rs create mode 100644 src/dimension/dim.rs diff --git a/src/dimension/axis.rs b/src/dimension/axis.rs new file mode 100644 index 000000000..214693078 --- /dev/null +++ b/src/dimension/axis.rs @@ -0,0 +1,49 @@ +// Copyright 2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp::Ordering; + +/// An axis index. +/// +/// An axis one of an array’s “dimensions”; an *n*-dimensional array has *n* axes. +/// Axis *0* is the array’s outermost axis and *n*-1 is the innermost. +/// +/// All array axis arguments use this type to make the code easier to write +/// correctly and easier to understand. +#[derive(Copy, Eq, Ord, Hash, Debug)] +pub struct Axis(pub usize); + +impl Axis { + #[inline(always)] + pub fn axis(&self) -> usize { self.0 } +} + +macro_rules! clone_from_copy { + ($typename:ident) => { + impl Clone for $typename { + #[inline] + fn clone(&self) -> Self { *self } + } + } +} + +macro_rules! derive_cmp { + ($traitname:ident for $typename:ident, $method:ident -> $ret:ty) => { + impl $traitname for $typename { + #[inline(always)] + fn $method(&self, rhs: &Self) -> $ret { + (self.0).$method(&rhs.0) + } + } + } +} + +derive_cmp!{PartialEq for Axis, eq -> bool} +derive_cmp!{PartialOrd for Axis, partial_cmp -> Option} +clone_from_copy!{Axis} + diff --git a/src/dimension/dim.rs b/src/dimension/dim.rs new file mode 100644 index 000000000..196baee25 --- /dev/null +++ b/src/dimension/dim.rs @@ -0,0 +1,152 @@ +// Copyright 2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::IntoDimension; +use super::Dimension; +use Ix; + +use itertools::zip; + +/// Private constructor and accessors for Dim +pub trait DimPrivate { + fn new(index: I) -> Self; + fn ix(&self) -> &I; + fn ixm(&mut self) -> &mut I; +} + +/// Dimension description. +/// +/// `Dim` describes the number of axes and the length of each axis +/// in an array. It is also used as an index type. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] +pub struct Dim { + index: I, +} + +impl DimPrivate for Dim { + fn new(index: I) -> Dim { + Dim { + index: index, + } + } + fn ix(&self) -> &I { &self.index } + fn ixm(&mut self) -> &mut I { &mut self.index } +} + +/// Create a new dimension value. +#[allow(non_snake_case)] +pub fn Dim(index: T) -> T::Dim + where T: IntoDimension +{ + index.into_dimension() +} + +impl PartialEq for Dim + where I: PartialEq, +{ + fn eq(&self, rhs: &I) -> bool { + self.index == *rhs + } +} + +use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; + +macro_rules! impl_op { + ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { + impl $op for Dim + where Dim: Dimension, + { + type Output = Self; + fn $op_m(mut self, rhs: Self) -> Self { + $expr!(self, &rhs); + self + } + } + + impl $opassign for Dim + where Dim: Dimension, + { + fn $opassign_m(&mut self, rhs: Self) { + $expr!(*self, &rhs); + } + } + + impl<'a, I> $opassign<&'a Dim> for Dim + where Dim: Dimension, + { + fn $opassign_m(&mut self, rhs: &Self) { + for (x, &y) in zip(self.slice_mut(), rhs.slice()) { + $expr!(*x, y); + } + } + } + + } +} + +macro_rules! impl_single_op { + ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { + impl $op for Dim<[Ix; 1]> + { + type Output = Self; + #[inline] + fn $op_m(mut self, rhs: Ix) -> Self { + $expr!(self, rhs); + self + } + } + + impl $opassign for Dim<[Ix; 1]> { + #[inline] + fn $opassign_m(&mut self, rhs: Ix) { + $expr!((*self)[0], rhs); + } + } + }; +} + +macro_rules! impl_scalar_op { + ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { + impl $op for Dim + where Dim: Dimension, + { + type Output = Self; + fn $op_m(mut self, rhs: Ix) -> Self { + $expr!(self, rhs); + self + } + } + + impl $opassign for Dim + where Dim: Dimension, + { + fn $opassign_m(&mut self, rhs: Ix) { + for x in self.slice_mut() { + $expr!(*x, rhs); + } + } + } + }; +} + +macro_rules! add { + ($x:expr, $y:expr) => { $x += $y; } +} +macro_rules! sub { + ($x:expr, $y:expr) => { $x -= $y; } +} +macro_rules! mul { + ($x:expr, $y:expr) => { $x *= $y; } +} +impl_op!(Add, add, AddAssign, add_assign, add); +impl_single_op!(Add, add, AddAssign, add_assign, add); +impl_op!(Sub, sub, SubAssign, sub_assign, sub); +impl_single_op!(Sub, sub, SubAssign, sub_assign, sub); +impl_op!(Mul, mul, MulAssign, mul_assign, mul); +impl_scalar_op!(Mul, mul, MulAssign, mul_assign, mul); + diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index afc857550..9c4fa1e5b 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -5,7 +5,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cmp::Ordering; use std::fmt::Debug; use std::ops::{Index, IndexMut}; @@ -19,6 +18,12 @@ use ZipExt; use {Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn}; use {ArrayView1, ArrayViewMut1}; +pub use self::dim::*; +pub use self::axis::Axis; + +pub mod dim; +mod axis; + /// Calculate offset from `Ix` stride converting sign properly #[inline(always)] pub fn stride_offset(n: Ix, stride: Ix) -> isize { @@ -1241,193 +1246,3 @@ mod test { } } -/// An axis index. -/// -/// An axis one of an array’s “dimensions”; an *n*-dimensional array has *n* axes. -/// Axis *0* is the array’s outermost axis and *n*-1 is the innermost. -/// -/// All array axis arguments use this type to make the code easier to write -/// correctly and easier to understand. -#[derive(Copy, Eq, Ord, Hash, Debug)] -pub struct Axis(pub usize); - -impl Axis { - #[inline(always)] - pub fn axis(&self) -> usize { self.0 } -} - -macro_rules! clone_from_copy { - ($typename:ident) => { - impl Clone for $typename { - #[inline] - fn clone(&self) -> Self { *self } - } - } -} - -macro_rules! derive_cmp { - ($traitname:ident for $typename:ident, $method:ident -> $ret:ty) => { - impl $traitname for $typename { - #[inline(always)] - fn $method(&self, rhs: &Self) -> $ret { - (self.0).$method(&rhs.0) - } - } - } -} - -derive_cmp!{PartialEq for Axis, eq -> bool} -derive_cmp!{PartialOrd for Axis, partial_cmp -> Option} -clone_from_copy!{Axis} - -pub trait DimPrivate { - fn new(index: I) -> Self; - fn ix(&self) -> &I; - fn ixm(&mut self) -> &mut I; -} - -pub use self::dim::*; -pub mod dim { - use super::IntoDimension; - use super::DimPrivate; - use super::Dimension; - use Ix; - - use itertools::zip; - - /// Dimension description. - /// - /// `Dim` describes the number of axes and the length of each axis - /// in an array. It is also used as an index type. - #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] - pub struct Dim { - index: I, - } - - impl DimPrivate for Dim { - fn new(index: I) -> Dim { - Dim { - index: index, - } - } - fn ix(&self) -> &I { &self.index } - fn ixm(&mut self) -> &mut I { &mut self.index } - } - - /// Create a new dimension value. - #[allow(non_snake_case)] - pub fn Dim(index: T) -> T::Dim - where T: IntoDimension - { - index.into_dimension() - } - - impl PartialEq for Dim - where I: PartialEq, - { - fn eq(&self, rhs: &I) -> bool { - self.index == *rhs - } - } - - use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; - - macro_rules! impl_op { - ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { - impl $op for Dim - where Dim: Dimension, - { - type Output = Self; - fn $op_m(mut self, rhs: Self) -> Self { - $expr!(self, &rhs); - self - } - } - - impl $opassign for Dim - where Dim: Dimension, - { - fn $opassign_m(&mut self, rhs: Self) { - $expr!(*self, &rhs); - } - } - - impl<'a, I> $opassign<&'a Dim> for Dim - where Dim: Dimension, - { - fn $opassign_m(&mut self, rhs: &Self) { - for (x, &y) in zip(self.slice_mut(), rhs.slice()) { - $expr!(*x, y); - } - } - } - - } - } - - macro_rules! impl_single_op { - ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { - impl $op for Dim<[Ix; 1]> - { - type Output = Self; - #[inline] - fn $op_m(mut self, rhs: Ix) -> Self { - $expr!(self, rhs); - self - } - } - - impl $opassign for Dim<[Ix; 1]> { - #[inline] - fn $opassign_m(&mut self, rhs: Ix) { - $expr!((*self)[0], rhs); - } - } - }; - } - - macro_rules! impl_scalar_op { - ($op:ident, $op_m:ident, $opassign:ident, $opassign_m:ident, $expr:ident) => { - impl $op for Dim - where Dim: Dimension, - { - type Output = Self; - fn $op_m(mut self, rhs: Ix) -> Self { - $expr!(self, rhs); - self - } - } - - impl $opassign for Dim - where Dim: Dimension, - { - fn $opassign_m(&mut self, rhs: Ix) { - for x in self.slice_mut() { - $expr!(*x, rhs); - } - } - } - }; - } - - macro_rules! add { - ($x:expr, $y:expr) => { $x += $y; } - } - macro_rules! sub { - ($x:expr, $y:expr) => { $x -= $y; } - } - macro_rules! mul { - ($x:expr, $y:expr) => { $x *= $y; } - } - impl_op!(Add, add, AddAssign, add_assign, add); - impl_single_op!(Add, add, AddAssign, add_assign, add); - impl_op!(Sub, sub, SubAssign, sub_assign, sub); - impl_single_op!(Sub, sub, SubAssign, sub_assign, sub); - impl_op!(Mul, mul, MulAssign, mul_assign, mul); - impl_scalar_op!(Mul, mul, MulAssign, mul_assign, mul); -} - - -#[test] -fn test_dim() { -} From 5fdb0afd77e5a0c25a3c054dd7fa03761e6d0221 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:03:32 +0100 Subject: [PATCH 076/107] split out ndindex --- src/dimension/macros.rs | 9 +++ src/dimension/mod.rs | 171 +-------------------------------------- src/dimension/ndindex.rs | 170 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+), 168 deletions(-) create mode 100644 src/dimension/macros.rs create mode 100644 src/dimension/ndindex.rs diff --git a/src/dimension/macros.rs b/src/dimension/macros.rs new file mode 100644 index 000000000..fa5f9ca34 --- /dev/null +++ b/src/dimension/macros.rs @@ -0,0 +1,9 @@ + +/// Indexing macro for Dim<[usize; N]> this +/// gets the index at `$i` in the underlying array +macro_rules! get { + ($dim:expr, $i:expr) => { $dim.ix()[$i] } +} +macro_rules! getm { + ($dim:expr, $i:expr) => { $dim.ixm()[$i] } +} diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index 9c4fa1e5b..ad8df0b82 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -20,9 +20,12 @@ use {ArrayView1, ArrayViewMut1}; pub use self::dim::*; pub use self::axis::Axis; +pub use self::ndindex::NdIndex; pub mod dim; +#[macro_use] mod macros; mod axis; +mod ndindex; /// Calculate offset from `Ix` stride converting sign properly #[inline(always)] @@ -643,14 +646,6 @@ unsafe impl Dimension for Ix0 { } } -/// Indexing macro for Dim<[usize; N]> this -/// gets the index at `$i` in the underlying array -macro_rules! get { - ($dim:expr, $i:expr) => { $dim.ix()[$i] } -} -macro_rules! getm { - ($dim:expr, $i:expr) => { $dim.ixm()[$i] } -} unsafe impl Dimension for Ix1 { type SliceArg = [Si; 1]; @@ -1055,166 +1050,6 @@ impl RemoveAxis for Dim> { } } -/// Tuple or fixed size arrays that can be used to index an array. -/// -/// ``` -/// use ndarray::arr2; -/// -/// let mut a = arr2(&[[0, 1], [0, 0]]); -/// a[[1, 1]] = 1; -/// assert_eq!(a[[0, 1]], 1); -/// assert_eq!(a[[1, 1]], 1); -/// ``` -/// -/// **Note** that `NdIndex` is implemented for all `D where D: Dimension`. -pub unsafe trait NdIndex : Debug { - #[doc(hidden)] - fn index_checked(&self, dim: &E, strides: &E) -> Option; - fn index_unchecked(&self, strides: &E) -> isize; -} - -unsafe impl NdIndex for D - where D: Dimension -{ - fn index_checked(&self, dim: &D, strides: &D) -> Option { - dim.stride_offset_checked(strides, self) - } - fn index_unchecked(&self, strides: &D) -> isize { - D::stride_offset(self, strides) - } -} - -unsafe impl NdIndex for () { - #[inline] - fn index_checked(&self, dim: &Ix0, strides: &Ix0) -> Option { - dim.stride_offset_checked(strides, &Ix0()) - } - #[inline(always)] - fn index_unchecked(&self, _strides: &Ix0) -> isize { - 0 - } -} - -unsafe impl NdIndex for Ix { - #[inline] - fn index_checked(&self, dim: &Ix1, strides: &Ix1) -> Option { - dim.stride_offset_checked(strides, &Ix1(*self)) - } - #[inline(always)] - fn index_unchecked(&self, strides: &Ix1) -> isize { - stride_offset(*self, get!(strides, 0)) - } -} - -unsafe impl NdIndex for (Ix, Ix) { - #[inline] - fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { - dim.stride_offset_checked(strides, &Ix2(self.0, self.1)) - } - #[inline] - fn index_unchecked(&self, strides: &Ix2) -> isize { - stride_offset(self.0, get!(strides, 0)) + - stride_offset(self.1, get!(strides, 1)) - } -} -unsafe impl NdIndex for (Ix, Ix, Ix) { - #[inline] - fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { - dim.stride_offset_checked(strides, &self.into_dimension()) - } - - #[inline] - fn index_unchecked(&self, strides: &Ix3) -> isize { - stride_offset(self.0, get!(strides, 0)) + - stride_offset(self.1, get!(strides, 1)) + - stride_offset(self.2, get!(strides, 2)) - } -} - -unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { - #[inline] - fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option { - dim.stride_offset_checked(strides, &self.into_dimension()) - } - #[inline] - fn index_unchecked(&self, strides: &Ix4) -> isize { - zip(strides.ix(), self.into_dimension().ix()).map(|(&s, &i)| stride_offset(i, s)).sum() - } -} -unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { - #[inline] - fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option { - dim.stride_offset_checked(strides, &self.into_dimension()) - } - #[inline] - fn index_unchecked(&self, strides: &Ix5) -> isize { - zip(strides.ix(), self.into_dimension().ix()).map(|(&s, &i)| stride_offset(i, s)).sum() - } -} - -unsafe impl NdIndex for [Ix; 2] { - #[inline] - fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { - dim.stride_offset_checked(strides, &Ix2(self[0], self[1])) - } - #[inline] - fn index_unchecked(&self, strides: &Ix2) -> isize { - stride_offset(self[0], get!(strides, 0)) + - stride_offset(self[1], get!(strides, 1)) - } -} - -unsafe impl NdIndex for [Ix; 3] { - #[inline] - fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { - dim.stride_offset_checked(strides, &Ix3(self[0], self[1], self[2])) - } - #[inline] - fn index_unchecked(&self, strides: &Ix3) -> isize { - stride_offset(self[0], get!(strides, 0)) + - stride_offset(self[1], get!(strides, 1)) + - stride_offset(self[2], get!(strides, 2)) - } -} - -impl<'a> IntoDimension for &'a [Ix] { - type Dim = Dim>; - fn into_dimension(self) -> Self::Dim { - Dim(self.to_vec()) - } -} - -unsafe impl<'a> NdIndex for &'a [Ix] { - fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { - let mut offset = 0; - for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { - if i >= d { - return None; - } - offset += stride_offset(i, s); - } - Some(offset) - } - fn index_unchecked(&self, strides: &IxDyn) -> isize { - zip(strides.ix(), *self).map(|(&s, &i)| stride_offset(i, s)).sum() - } -} - -unsafe impl NdIndex for Vec { - fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { - let mut offset = 0; - for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { - if i >= d { - return None; - } - offset += stride_offset(i, s); - } - Some(offset) - } - fn index_unchecked(&self, strides: &IxDyn) -> isize { - zip(strides.ix(), self).map(|(&s, &i)| stride_offset(i, s)).sum() - } -} // NOTE: These tests are not compiled & tested #[cfg(test)] diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs new file mode 100644 index 000000000..408f3ecbb --- /dev/null +++ b/src/dimension/ndindex.rs @@ -0,0 +1,170 @@ + +use std::fmt::Debug; + +use itertools::zip; + +use {Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, IxDyn, Dim, Dimension, IntoDimension}; +use {zipsl, ZipExt}; +use super::{stride_offset}; +use super::DimPrivate; + +/// Tuple or fixed size arrays that can be used to index an array. +/// +/// ``` +/// use ndarray::arr2; +/// +/// let mut a = arr2(&[[0, 1], [0, 0]]); +/// a[[1, 1]] = 1; +/// assert_eq!(a[[0, 1]], 1); +/// assert_eq!(a[[1, 1]], 1); +/// ``` +/// +/// **Note** that `NdIndex` is implemented for all `D where D: Dimension`. +pub unsafe trait NdIndex : Debug { + #[doc(hidden)] + fn index_checked(&self, dim: &E, strides: &E) -> Option; + fn index_unchecked(&self, strides: &E) -> isize; +} + +unsafe impl NdIndex for D + where D: Dimension +{ + fn index_checked(&self, dim: &D, strides: &D) -> Option { + dim.stride_offset_checked(strides, self) + } + fn index_unchecked(&self, strides: &D) -> isize { + D::stride_offset(self, strides) + } +} + +unsafe impl NdIndex for () { + #[inline] + fn index_checked(&self, dim: &Ix0, strides: &Ix0) -> Option { + dim.stride_offset_checked(strides, &Ix0()) + } + #[inline(always)] + fn index_unchecked(&self, _strides: &Ix0) -> isize { + 0 + } +} + +unsafe impl NdIndex for Ix { + #[inline] + fn index_checked(&self, dim: &Ix1, strides: &Ix1) -> Option { + dim.stride_offset_checked(strides, &Ix1(*self)) + } + #[inline(always)] + fn index_unchecked(&self, strides: &Ix1) -> isize { + stride_offset(*self, get!(strides, 0)) + } +} + +unsafe impl NdIndex for (Ix, Ix) { + #[inline] + fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { + dim.stride_offset_checked(strides, &Ix2(self.0, self.1)) + } + #[inline] + fn index_unchecked(&self, strides: &Ix2) -> isize { + stride_offset(self.0, get!(strides, 0)) + + stride_offset(self.1, get!(strides, 1)) + } +} +unsafe impl NdIndex for (Ix, Ix, Ix) { + #[inline] + fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { + dim.stride_offset_checked(strides, &self.into_dimension()) + } + + #[inline] + fn index_unchecked(&self, strides: &Ix3) -> isize { + stride_offset(self.0, get!(strides, 0)) + + stride_offset(self.1, get!(strides, 1)) + + stride_offset(self.2, get!(strides, 2)) + } +} + +unsafe impl NdIndex for (Ix, Ix, Ix, Ix) { + #[inline] + fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option { + dim.stride_offset_checked(strides, &self.into_dimension()) + } + #[inline] + fn index_unchecked(&self, strides: &Ix4) -> isize { + zip(strides.ix(), self.into_dimension().ix()).map(|(&s, &i)| stride_offset(i, s)).sum() + } +} +unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { + #[inline] + fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option { + dim.stride_offset_checked(strides, &self.into_dimension()) + } + #[inline] + fn index_unchecked(&self, strides: &Ix5) -> isize { + zip(strides.ix(), self.into_dimension().ix()).map(|(&s, &i)| stride_offset(i, s)).sum() + } +} + +unsafe impl NdIndex for [Ix; 2] { + #[inline] + fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { + dim.stride_offset_checked(strides, &Ix2(self[0], self[1])) + } + #[inline] + fn index_unchecked(&self, strides: &Ix2) -> isize { + stride_offset(self[0], get!(strides, 0)) + + stride_offset(self[1], get!(strides, 1)) + } +} + +unsafe impl NdIndex for [Ix; 3] { + #[inline] + fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { + dim.stride_offset_checked(strides, &Ix3(self[0], self[1], self[2])) + } + #[inline] + fn index_unchecked(&self, strides: &Ix3) -> isize { + stride_offset(self[0], get!(strides, 0)) + + stride_offset(self[1], get!(strides, 1)) + + stride_offset(self[2], get!(strides, 2)) + } +} + +impl<'a> IntoDimension for &'a [Ix] { + type Dim = Dim>; + fn into_dimension(self) -> Self::Dim { + Dim(self.to_vec()) + } +} + +unsafe impl<'a> NdIndex for &'a [Ix] { + fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { + let mut offset = 0; + for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { + if i >= d { + return None; + } + offset += stride_offset(i, s); + } + Some(offset) + } + fn index_unchecked(&self, strides: &IxDyn) -> isize { + zip(strides.ix(), *self).map(|(&s, &i)| stride_offset(i, s)).sum() + } +} + +unsafe impl NdIndex for Vec { + fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { + let mut offset = 0; + for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { + if i >= d { + return None; + } + offset += stride_offset(i, s); + } + Some(offset) + } + fn index_unchecked(&self, strides: &IxDyn) -> isize { + zip(strides.ix(), self).map(|(&s, &i)| stride_offset(i, s)).sum() + } +} From 5ed5a2ca75af4152ba7ff494d250eab4d3ee465a Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:08:33 +0100 Subject: [PATCH 077/107] Move dimension conversions to separate file --- src/dimension/conversion.rs | 153 ++++++++++++++++++++++++++++++++++++ src/dimension/mod.rs | 143 +-------------------------------- 2 files changed, 156 insertions(+), 140 deletions(-) create mode 100644 src/dimension/conversion.rs diff --git a/src/dimension/conversion.rs b/src/dimension/conversion.rs new file mode 100644 index 000000000..9ef29d22c --- /dev/null +++ b/src/dimension/conversion.rs @@ -0,0 +1,153 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Tuple to array conversion, IntoDimension, and related things + +use std::ops::{Index, IndexMut}; +use libnum::Zero; + +use {Ix, Ix1, IxDyn, Dimension, Dim}; +use super::DimPrivate; + +/// $m: macro callback +/// $m is called with $arg and then the indices corresponding to the size argument +macro_rules! index { + ($m:ident $arg:tt 0) => ($m!($arg)); + ($m:ident $arg:tt 1) => ($m!($arg 0)); + ($m:ident $arg:tt 2) => ($m!($arg 0 1)); + ($m:ident $arg:tt 3) => ($m!($arg 0 1 2)); + ($m:ident $arg:tt 4) => ($m!($arg 0 1 2 3)); + ($m:ident $arg:tt 5) => ($m!($arg 0 1 2 3 4)); + ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5)); + ($m:ident $arg:tt 7) => ($m!($arg 0 1 2 3 4 5 6)); +} + +macro_rules! index_item { + ($m:ident $arg:tt 0) => (); + ($m:ident $arg:tt 1) => ($m!($arg 0);); + ($m:ident $arg:tt 2) => ($m!($arg 0 1);); + ($m:ident $arg:tt 3) => ($m!($arg 0 1 2);); + ($m:ident $arg:tt 4) => ($m!($arg 0 1 2 3);); + ($m:ident $arg:tt 5) => ($m!($arg 0 1 2 3 4);); + ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5);); + ($m:ident $arg:tt 7) => ($m!($arg 0 1 2 3 4 5 6);); +} + +/// Convert a value into a dimension. +pub trait IntoDimension { + type Dim: Dimension; + fn into_dimension(self) -> Self::Dim; +} + +impl IntoDimension for Ix { + type Dim = Ix1; + #[inline(always)] + fn into_dimension(self) -> Ix1 { Ix1(self) } +} + +impl IntoDimension for D where D: Dimension { + type Dim = D; + #[inline(always)] + fn into_dimension(self) -> Self { self } +} + +impl IntoDimension for Vec { + type Dim = IxDyn; + #[inline(always)] + fn into_dimension(self) -> Self::Dim { Dim::new(self) } +} + +pub trait Convert { + type To; + fn convert(self) -> Self::To; +} + +macro_rules! sub { + ($_x:tt $y:tt) => ($y); +} + +macro_rules! tuple_type { + ([$T:ident] $($index:tt)*) => ( + ( $(sub!($index $T), )* ) + ) +} + +macro_rules! tuple_expr { + ([$self_:expr] $($index:tt)*) => ( + ( $($self_[$index], )* ) + ) +} + +macro_rules! array_expr { + ([$self_:expr] $($index:tt)*) => ( + [$($self_ . $index, )*] + ) +} + +macro_rules! array_zero { + ([] $($index:tt)*) => ( + [$(sub!($index 0), )*] + ) +} + +macro_rules! tuple_to_array { + ([] $($n:tt)*) => { + $( + impl Convert for [Ix; $n] { + type To = index!(tuple_type [Ix] $n); + fn convert(self) -> Self::To { + index!(tuple_expr [self] $n) + } + } + + impl IntoDimension for [Ix; $n] { + type Dim = Dim<[Ix; $n]>; + #[inline(always)] + fn into_dimension(self) -> Self::Dim { + Dim::new(self) + } + } + + impl IntoDimension for index!(tuple_type [Ix] $n) { + type Dim = Dim<[Ix; $n]>; + #[inline(always)] + fn into_dimension(self) -> Self::Dim { + Dim::new(index!(array_expr [self] $n)) + } + } + + impl Index for Dim<[Ix; $n]> { + type Output = usize; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + &self.ix()[index] + } + } + + impl IndexMut for Dim<[Ix; $n]> { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.ixm()[index] + } + } + + impl Zero for Dim<[Ix; $n]> { + #[inline] + fn zero() -> Self { + Dim::new(index!(array_zero [] $n)) + } + fn is_zero(&self) -> bool { + self.slice().iter().all(|x| *x == 0) + } + } + + )* + } +} + +index_item!(tuple_to_array [] 7); diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index ad8df0b82..e1b14704d 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -9,7 +9,6 @@ use std::fmt::Debug; use std::ops::{Index, IndexMut}; use itertools::{enumerate, zip}; -use libnum::Zero; use super::{Si, Ix, Ixs}; use super::{zipsl, zipsl_mut}; @@ -21,10 +20,13 @@ use {ArrayView1, ArrayViewMut1}; pub use self::dim::*; pub use self::axis::Axis; pub use self::ndindex::NdIndex; +pub use self::conversion::IntoDimension; +use self::conversion::Convert; pub mod dim; #[macro_use] mod macros; mod axis; +mod conversion; mod ndindex; /// Calculate offset from `Ix` stride converting sign properly @@ -486,145 +488,6 @@ pub fn do_sub(dims: &mut D, ptr: &mut *mut A, strides: &D, } } -// Tuple to array conversion - -/// $m: macro callback -/// $m is called with $arg and then the indices corresponding to the size argument -macro_rules! index { - ($m:ident $arg:tt 0) => ($m!($arg)); - ($m:ident $arg:tt 1) => ($m!($arg 0)); - ($m:ident $arg:tt 2) => ($m!($arg 0 1)); - ($m:ident $arg:tt 3) => ($m!($arg 0 1 2)); - ($m:ident $arg:tt 4) => ($m!($arg 0 1 2 3)); - ($m:ident $arg:tt 5) => ($m!($arg 0 1 2 3 4)); - ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5)); - ($m:ident $arg:tt 7) => ($m!($arg 0 1 2 3 4 5 6)); -} - -macro_rules! index_item { - ($m:ident $arg:tt 0) => (); - ($m:ident $arg:tt 1) => ($m!($arg 0);); - ($m:ident $arg:tt 2) => ($m!($arg 0 1);); - ($m:ident $arg:tt 3) => ($m!($arg 0 1 2);); - ($m:ident $arg:tt 4) => ($m!($arg 0 1 2 3);); - ($m:ident $arg:tt 5) => ($m!($arg 0 1 2 3 4);); - ($m:ident $arg:tt 6) => ($m!($arg 0 1 2 3 4 5);); - ($m:ident $arg:tt 7) => ($m!($arg 0 1 2 3 4 5 6);); -} - -/// Convert a value into a dimension. -pub trait IntoDimension { - type Dim: Dimension; - fn into_dimension(self) -> Self::Dim; -} - -impl IntoDimension for Ix { - type Dim = Ix1; - #[inline(always)] - fn into_dimension(self) -> Ix1 { Ix1(self) } -} - -impl IntoDimension for D where D: Dimension { - type Dim = D; - #[inline(always)] - fn into_dimension(self) -> Self { self } -} - -impl IntoDimension for Vec { - type Dim = IxDyn; - #[inline(always)] - fn into_dimension(self) -> Self::Dim { Dim::new(self) } -} - -trait Convert { - type To; - fn convert(self) -> Self::To; -} - -macro_rules! sub { - ($_x:tt $y:tt) => ($y); -} - -macro_rules! tuple_type { - ([$T:ident] $($index:tt)*) => ( - ( $(sub!($index $T), )* ) - ) -} - -macro_rules! tuple_expr { - ([$self_:expr] $($index:tt)*) => ( - ( $($self_[$index], )* ) - ) -} - -macro_rules! array_expr { - ([$self_:expr] $($index:tt)*) => ( - [$($self_ . $index, )*] - ) -} - -macro_rules! array_zero { - ([] $($index:tt)*) => ( - [$(sub!($index 0), )*] - ) -} - -macro_rules! tuple_to_array { - ([] $($n:tt)*) => { - $( - impl Convert for [Ix; $n] { - type To = index!(tuple_type [Ix] $n); - fn convert(self) -> Self::To { - index!(tuple_expr [self] $n) - } - } - - impl IntoDimension for [Ix; $n] { - type Dim = Dim<[Ix; $n]>; - #[inline(always)] - fn into_dimension(self) -> Self::Dim { - Dim::new(self) - } - } - - impl IntoDimension for index!(tuple_type [Ix] $n) { - type Dim = Dim<[Ix; $n]>; - #[inline(always)] - fn into_dimension(self) -> Self::Dim { - Dim::new(index!(array_expr [self] $n)) - } - } - - impl Index for Dim<[Ix; $n]> { - type Output = usize; - #[inline(always)] - fn index(&self, index: usize) -> &Self::Output { - &self.ix()[index] - } - } - - impl IndexMut for Dim<[Ix; $n]> { - #[inline(always)] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.ixm()[index] - } - } - - impl Zero for Dim<[Ix; $n]> { - #[inline] - fn zero() -> Self { - Dim::new(index!(array_zero [] $n)) - } - fn is_zero(&self) -> bool { - self.slice().iter().all(|x| *x == 0) - } - } - - )* - } -} - -index_item!(tuple_to_array [] 7); unsafe impl Dimension for Ix0 { type SliceArg = [Si; 0]; From fe206331e726ac82d5eeef5ae4ee024a2a28a19f Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:11:50 +0100 Subject: [PATCH 078/107] Split out RemoveAxis --- src/dimension/mod.rs | 67 +------------------------------ src/dimension/remove_axis.rs | 77 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 65 deletions(-) create mode 100644 src/dimension/remove_axis.rs diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index e1b14704d..b5accd8da 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -22,12 +22,14 @@ pub use self::axis::Axis; pub use self::ndindex::NdIndex; pub use self::conversion::IntoDimension; use self::conversion::Convert; +pub use self::remove_axis::RemoveAxis; pub mod dim; #[macro_use] mod macros; mod axis; mod conversion; mod ndindex; +mod remove_axis; /// Calculate offset from `Ix` stride converting sign properly #[inline(always)] @@ -848,71 +850,6 @@ impl IndexMut for Dim> } } -/// Array shape with a next smaller dimension. -/// -/// `RemoveAxis` defines a larger-than relation for array shapes: -/// removing one axis from *Self* gives smaller dimension *Smaller*. -pub trait RemoveAxis : Dimension { - type Smaller: Dimension; - fn remove_axis(&self, axis: Axis) -> Self::Smaller; -} - -impl RemoveAxis for Dim<[Ix; 1]> { - type Smaller = Ix0; - #[inline] - fn remove_axis(&self, _: Axis) -> Ix0 { Ix0() } -} - -impl RemoveAxis for Dim<[Ix; 2]> { - type Smaller = Ix1; - #[inline] - fn remove_axis(&self, axis: Axis) -> Ix1 { - let axis = axis.axis(); - debug_assert!(axis < self.ndim()); - if axis == 0 { Ix1(get!(self, 1)) } else { Ix1(get!(self, 0)) } - } -} - -macro_rules! impl_remove_axis_array( - ($($n:expr),*) => ( - $( - impl RemoveAxis for Dim<[Ix; $n]> - { - type Smaller = Dim<[Ix; $n - 1]>; - #[inline] - fn remove_axis(&self, axis: Axis) -> Self::Smaller { - let mut tup = Dim([0; $n - 1]); - { - let mut it = tup.slice_mut().iter_mut(); - for (i, &d) in self.slice().iter().enumerate() { - if i == axis.axis() { - continue; - } - for rr in it.by_ref() { - *rr = d; - break - } - } - } - tup - } - } - )* - ); -); - -impl_remove_axis_array!(3, 4, 5, 6); - - -impl RemoveAxis for Dim> { - type Smaller = Self; - fn remove_axis(&self, axis: Axis) -> Self { - let mut res = self.clone(); - res.ixm().remove(axis.axis()); - res - } -} - // NOTE: These tests are not compiled & tested #[cfg(test)] diff --git a/src/dimension/remove_axis.rs b/src/dimension/remove_axis.rs new file mode 100644 index 000000000..9b26056c3 --- /dev/null +++ b/src/dimension/remove_axis.rs @@ -0,0 +1,77 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use {Ix, Ix0, Ix1, Dimension, Dim, Axis}; +use super::DimPrivate; + +/// Array shape with a next smaller dimension. +/// +/// `RemoveAxis` defines a larger-than relation for array shapes: +/// removing one axis from *Self* gives smaller dimension *Smaller*. +pub trait RemoveAxis : Dimension { + type Smaller: Dimension; + fn remove_axis(&self, axis: Axis) -> Self::Smaller; +} + +impl RemoveAxis for Dim<[Ix; 1]> { + type Smaller = Ix0; + #[inline] + fn remove_axis(&self, _: Axis) -> Ix0 { Ix0() } +} + +impl RemoveAxis for Dim<[Ix; 2]> { + type Smaller = Ix1; + #[inline] + fn remove_axis(&self, axis: Axis) -> Ix1 { + let axis = axis.axis(); + debug_assert!(axis < self.ndim()); + if axis == 0 { Ix1(get!(self, 1)) } else { Ix1(get!(self, 0)) } + } +} + +macro_rules! impl_remove_axis_array( + ($($n:expr),*) => ( + $( + impl RemoveAxis for Dim<[Ix; $n]> + { + type Smaller = Dim<[Ix; $n - 1]>; + #[inline] + fn remove_axis(&self, axis: Axis) -> Self::Smaller { + let mut tup = Dim([0; $n - 1]); + { + let mut it = tup.slice_mut().iter_mut(); + for (i, &d) in self.slice().iter().enumerate() { + if i == axis.axis() { + continue; + } + for rr in it.by_ref() { + *rr = d; + break + } + } + } + tup + } + } + )* + ); +); + +impl_remove_axis_array!(3, 4, 5, 6); + + +impl RemoveAxis for Dim> { + type Smaller = Self; + fn remove_axis(&self, axis: Axis) -> Self { + let mut res = self.clone(); + res.ixm().remove(axis.axis()); + res + } +} + From fd2826811b851a9bb7e9f465622093fa9b927bc4 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:17:31 +0100 Subject: [PATCH 079/107] dimension: adjust get/getm macros --- src/dimension/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dimension/macros.rs b/src/dimension/macros.rs index fa5f9ca34..9f5f681e7 100644 --- a/src/dimension/macros.rs +++ b/src/dimension/macros.rs @@ -2,8 +2,8 @@ /// Indexing macro for Dim<[usize; N]> this /// gets the index at `$i` in the underlying array macro_rules! get { - ($dim:expr, $i:expr) => { $dim.ix()[$i] } + ($dim:expr, $i:expr) => { (*$dim.ix())[$i] } } macro_rules! getm { - ($dim:expr, $i:expr) => { $dim.ixm()[$i] } + ($dim:expr, $i:expr) => { (*$dim.ixm())[$i] } } From 8d98ae630276dfe699f3709bdf0b987c95ed3065 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:24:48 +0100 Subject: [PATCH 080/107] Split out the Dimension trait --- src/dimension/dimension_trait.rs | 681 +++++++++++++++++++++++++++++++ src/dimension/mod.rs | 669 +----------------------------- 2 files changed, 687 insertions(+), 663 deletions(-) create mode 100644 src/dimension/dimension_trait.rs diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs new file mode 100644 index 000000000..74154ee2e --- /dev/null +++ b/src/dimension/dimension_trait.rs @@ -0,0 +1,681 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use std::fmt::Debug; +use std::ops::{Index, IndexMut}; +use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; + +use itertools::{enumerate, zip}; + +use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Si}; +use IntoDimension; +use {ArrayView1, ArrayViewMut1}; +use {zipsl, zipsl_mut, ZipExt}; +use super::{ + stride_offset, + DimPrivate, +}; +use super::conversion::Convert; + +/// Array shape and index trait. +/// +/// `unsafe` because of the assumptions in the default methods. +/// +/// ***Don't implement this trait, it will evolve at will.*** +pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + + IndexMut + + Add + + AddAssign + for<'x> AddAssign<&'x Self> + + Sub + + SubAssign + for<'x> SubAssign<&'x Self> + + Mul + Mul + + MulAssign + for<'x> MulAssign<&'x Self> + MulAssign + +{ + /// `SliceArg` is the type which is used to specify slicing for this + /// dimension. + /// + /// For the fixed size dimensions it is a fixed size array of the correct + /// size, which you pass by reference. For the `Vec` dimension it is + /// a slice. + /// + /// - For `Ix1`: `[Si; 1]` + /// - For `Ix2`: `[Si; 2]` + /// - and so on.. + /// - For `Vec`: `[Si]` + /// + /// The easiest way to create a `&SliceArg` is using the macro + /// [`s![]`](macro.s!.html). + type SliceArg: ?Sized + AsRef<[Si]>; + /// Pattern matching friendly form of the dimension value. + /// + /// - For `Ix1`: `usize`, + /// - For `Ix2`: `(usize, usize)` + /// - and so on.. + /// - For `Vec`: `Vec`, + type Pattern: IntoDimension; + #[doc(hidden)] + fn ndim(&self) -> usize; + + /// Convert the dimension into a pattern matching friendly value. + fn into_pattern(self) -> Self::Pattern; + + /// Compute the size of the dimension (number of elements) + fn size(&self) -> usize { + self.slice().iter().fold(1, |s, &a| s * a as usize) + } + + /// Compute the size while checking for overflow. + fn size_checked(&self) -> Option { + self.slice().iter().fold(Some(1), |s, &a| s.and_then(|s_| s_.checked_mul(a))) + } + + #[doc(hidden)] + fn slice(&self) -> &[Ix]; + + #[doc(hidden)] + fn slice_mut(&mut self) -> &mut [Ix]; + + /// Borrow as a read-only array view. + fn as_array_view(&self) -> ArrayView1 { + ArrayView1::from(self.slice()) + } + + /// Borrow as a read-write array view. + fn as_array_view_mut(&mut self) -> ArrayViewMut1 { + ArrayViewMut1::from(self.slice_mut()) + } + + #[doc(hidden)] + fn equal(&self, rhs: &Self) -> bool { + self.slice() == rhs.slice() + } + + #[doc(hidden)] + fn default_strides(&self) -> Self { + // Compute default array strides + // Shape (a, b, c) => Give strides (b * c, c, 1) + let mut strides = self.clone(); + { + let mut it = strides.slice_mut().iter_mut().rev(); + // Set first element to 1 + for rs in it.by_ref() { + *rs = 1; + break; + } + let mut cum_prod = 1; + for (rs, dim) in it.zip(self.slice().iter().rev()) { + cum_prod *= *dim; + *rs = cum_prod; + } + } + strides + } + + #[doc(hidden)] + fn fortran_strides(&self) -> Self { + // Compute fortran array strides + // Shape (a, b, c) => Give strides (1, a, a * b) + let mut strides = self.clone(); + { + let mut it = strides.slice_mut().iter_mut(); + // Set first element to 1 + for rs in it.by_ref() { + *rs = 1; + break; + } + let mut cum_prod = 1; + for (rs, dim) in it.zip(self.slice().iter()) { + cum_prod *= *dim; + *rs = cum_prod; + } + } + strides + } + + #[doc(hidden)] + #[inline] + fn first_index(&self) -> Option { + for ax in self.slice().iter() { + if *ax == 0 { + return None; + } + } + let mut index = self.clone(); + for rr in index.slice_mut().iter_mut() { + *rr = 0; + } + Some(index) + } + + #[doc(hidden)] + /// Iteration -- Use self as size, and return next index after `index` + /// or None if there are no more. + // FIXME: use &Self for index or even &mut? + #[inline] + fn next_for(&self, index: Self) -> Option { + let mut index = index; + let mut done = false; + for (&dim, ix) in zip(self.slice(), index.slice_mut()).rev() { + *ix += 1; + if *ix == dim { + *ix = 0; + } else { + done = true; + break; + } + } + if done { + Some(index) + } else { + None + } + } + + #[doc(hidden)] + /// Return stride offset for index. + fn stride_offset(index: &Self, strides: &Self) -> isize { + let mut offset = 0; + for (&i, &s) in zipsl(index.slice(), strides.slice()) { + offset += stride_offset(i, s); + } + offset + } + + #[doc(hidden)] + /// Return stride offset for this dimension and index. + fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option { + let mut offset = 0; + for (&d, &i, &s) in zipsl(self.slice(), index.slice()).zip_cons(strides.slice()) + { + if i >= d { + return None; + } + offset += stride_offset(i, s); + } + Some(offset) + } + + #[doc(hidden)] + fn last_elem(&self) -> usize { + if self.ndim() == 0 { 0 } else { self.slice()[self.ndim() - 1] } + } + + #[doc(hidden)] + fn set_last_elem(&mut self, i: usize) { + let nd = self.ndim(); + self.slice_mut()[nd - 1] = i; + } + + #[doc(hidden)] + /// Modify dimension, strides and return data pointer offset + /// + /// **Panics** if `slices` does not correspond to the number of axes, + /// if any stride is 0, or if any index is out of bounds. + fn do_slices(dim: &mut Self, strides: &mut Self, slices: &Self::SliceArg) -> isize { + let slices = slices.as_ref(); + let mut offset = 0; + assert!(slices.len() == dim.slice().len()); + for (dr, sr, &slc) in zipsl_mut(dim.slice_mut(), strides.slice_mut()).zip_cons(slices) + { + let m = *dr; + let mi = m as Ixs; + let Si(b1, opt_e1, s1) = slc; + let e1 = opt_e1.unwrap_or(mi); + + let b1 = abs_index(mi, b1); + let mut e1 = abs_index(mi, e1); + if e1 < b1 { e1 = b1; } + + assert!(b1 <= m); + assert!(e1 <= m); + + let m = e1 - b1; + // stride + let s = (*sr) as Ixs; + + // Data pointer offset + offset += stride_offset(b1, *sr); + // Adjust for strides + assert!(s1 != 0); + // How to implement negative strides: + // + // Increase start pointer by + // old stride * (old dim - 1) + // to put the pointer completely in the other end + if s1 < 0 { + offset += stride_offset(m - 1, *sr); + } + + let s_prim = s * s1; + + let d = m / s1.abs() as Ix; + let r = m % s1.abs() as Ix; + let m_prim = d + if r > 0 { 1 } else { 0 }; + + // Update dimension and stride coordinate + *dr = m_prim; + *sr = s_prim as Ix; + } + offset + } + + #[doc(hidden)] + fn is_contiguous(dim: &Self, strides: &Self) -> bool { + let defaults = dim.default_strides(); + if strides.equal(&defaults) { + return true; + } + if dim.ndim() == 1 { return false; } + let order = strides._fastest_varying_stride_order(); + let strides = strides.slice(); + + // FIXME: Negative strides + let dim_slice = dim.slice(); + let mut cstride = 1; + for &i in order.slice() { + // a dimension of length 1 can have unequal strides + if dim_slice[i] != 1 && strides[i] != cstride { + return false; + } + cstride *= dim_slice[i]; + } + true + } + + /// Return the axis ordering corresponding to the fastest variation + /// (in ascending order). + /// + /// Assumes that no stride value appears twice. This cannot yield the correct + /// result the strides are not positive. + #[doc(hidden)] + fn _fastest_varying_stride_order(&self) -> Self { + let mut indices = self.clone(); + for (i, elt) in enumerate(indices.slice_mut()) { + *elt = i; + } + let strides = self.slice(); + indices.slice_mut().sort_by_key(|&i| strides[i]); + indices + } +} + +// utility functions + +#[inline] +fn abs_index(len: Ixs, index: Ixs) -> Ix { + if index < 0 { + (len + index) as Ix + } else { + index as Ix + } +} + + +// Dimension impls + + +unsafe impl Dimension for Ix0 { + type SliceArg = [Si; 0]; + type Pattern = (); + // empty product is 1 -> size is 1 + #[inline] + fn ndim(&self) -> usize { 0 } + #[inline] + fn slice(&self) -> &[Ix] { &[] } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { &mut [] } + #[inline] + fn _fastest_varying_stride_order(&self) -> Self { Ix0() } + #[inline] + fn into_pattern(self) -> Self::Pattern { } + #[inline] + fn next_for(&self, _index: Self) -> Option { + None + } +} + + +unsafe impl Dimension for Ix1 { + type SliceArg = [Si; 1]; + type Pattern = Ix; + #[inline] + fn ndim(&self) -> usize { 1 } + #[inline] + fn slice(&self) -> &[Ix] { self.ix() } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } + #[inline] + fn into_pattern(self) -> Self::Pattern { + get!(&self, 0) + } + #[inline] + fn next_for(&self, mut index: Self) -> Option { + getm!(index, 0) += 1; + if get!(&index, 0) < get!(self, 0) { + Some(index) + } else { + None + } + } + + #[inline] + fn equal(&self, rhs: &Self) -> bool { + get!(self, 0) == get!(rhs, 0) + } + + #[inline] + fn size(&self) -> usize { get!(self, 0) } + #[inline] + fn size_checked(&self) -> Option { Some(get!(self, 0)) } + + #[inline] + fn default_strides(&self) -> Self { + Ix1(1) + } + + #[inline] + fn _fastest_varying_stride_order(&self) -> Self { + Ix1(0) + } + + #[inline] + fn first_index(&self) -> Option { + if get!(self, 0) != 0 { + Some(Ix1(0)) + } else { + None + } + } + + /// Self is an index, return the stride offset + #[inline(always)] + fn stride_offset(index: &Self, stride: &Self) -> isize { + stride_offset(get!(index, 0), get!(stride, 0)) + } + + /// Return stride offset for this dimension and index. + #[inline] + fn stride_offset_checked(&self, stride: &Self, index: &Self) -> Option { + if get!(index, 0) < get!(self, 0) { + Some(stride_offset(get!(index, 0), get!(stride, 0))) + } else { + None + } + } +} + +unsafe impl Dimension for Ix2 { + type SliceArg = [Si; 2]; + type Pattern = (Ix, Ix); + #[inline] + fn ndim(&self) -> usize { 2 } + #[inline] + fn into_pattern(self) -> Self::Pattern { + self.ix().convert() + } + #[inline] + fn slice(&self) -> &[Ix] { self.ix() } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } + #[inline] + fn next_for(&self, index: Self) -> Option { + let mut i = get!(&index, 0); + let mut j = get!(&index, 1); + let imax = get!(self, 0); + let jmax = get!(self, 1); + j += 1; + if j >= jmax { + j = 0; + i += 1; + if i >= imax { + return None; + } + } + Some(Ix2(i, j)) + } + + #[inline] + fn equal(&self, rhs: &Self) -> bool { + get!(self, 0) == get!(rhs, 0) && get!(self, 1) == get!(rhs, 1) + } + + #[inline] + fn size(&self) -> usize { get!(self, 0) * get!(self, 1) } + + #[inline] + fn size_checked(&self) -> Option { + let m = get!(self, 0); + let n = get!(self, 1); + (m as usize).checked_mul(n as usize) + } + + #[inline] + fn last_elem(&self) -> usize { + get!(self, 1) + } + + #[inline] + fn set_last_elem(&mut self, i: usize) { + getm!(self, 1) = i; + } + + #[inline] + fn default_strides(&self) -> Self { + // Compute default array strides + // Shape (a, b, c) => Give strides (b * c, c, 1) + Ix2(get!(self, 1), 1) + } + #[inline] + fn fortran_strides(&self) -> Self { + Ix2(1, get!(self, 0)) + } + + #[inline] + fn _fastest_varying_stride_order(&self) -> Self { + if get!(self, 0) as Ixs <= get!(self, 1) as Ixs { Ix2(0, 1) } else { Ix2(1, 0) } + } + + #[inline] + fn is_contiguous(dim: &Self, strides: &Self) -> bool { + let defaults = dim.default_strides(); + if strides.equal(&defaults) { + return true; + } + + if dim.ndim() == 1 { return false; } + let order = strides._fastest_varying_stride_order(); + let strides = strides.slice(); + + // FIXME: Negative strides + let dim_slice = dim.slice(); + let mut cstride = 1; + for &i in order.slice() { + // a dimension of length 1 can have unequal strides + if dim_slice[i] != 1 && strides[i] != cstride { + return false; + } + cstride *= dim_slice[i]; + } + true + } + + #[inline] + fn first_index(&self) -> Option { + let m = get!(self, 0); + let n = get!(self, 1); + if m != 0 && n != 0 { + Some(Ix2(0, 0)) + } else { + None + } + } + + /// Self is an index, return the stride offset + #[inline(always)] + fn stride_offset(index: &Self, strides: &Self) -> isize { + let i = get!(index, 0); + let j = get!(index, 1); + let s = get!(strides, 0); + let t = get!(strides, 1); + stride_offset(i, s) + stride_offset(j, t) + } + + /// Return stride offset for this dimension and index. + #[inline] + fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option + { + let m = get!(self, 0); + let n = get!(self, 1); + let i = get!(index, 0); + let j = get!(index, 1); + let s = get!(strides, 0); + let t = get!(strides, 1); + if i < m && j < n { + Some(stride_offset(i, s) + stride_offset(j, t)) + } else { + None + } + } +} + +unsafe impl Dimension for Ix3 { + type SliceArg = [Si; 3]; + type Pattern = (Ix, Ix, Ix); + #[inline] + fn ndim(&self) -> usize { 3 } + #[inline] + fn into_pattern(self) -> Self::Pattern { + self.ix().convert() + } + #[inline] + fn slice(&self) -> &[Ix] { self.ix() } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } + + #[inline] + fn size(&self) -> usize { + let m = get!(self, 0); + let n = get!(self, 1); + let o = get!(self, 2); + m as usize * n as usize * o as usize + } + + #[inline] + fn next_for(&self, index: Self) -> Option { + let mut i = get!(&index, 0); + let mut j = get!(&index, 1); + let mut k = get!(&index, 2); + let imax = get!(self, 0); + let jmax = get!(self, 1); + let kmax = get!(self, 2); + k += 1; + if k == kmax { + k = 0; + j += 1; + if j == jmax { + j = 0; + i += 1; + if i == imax { + return None; + } + } + } + Some(Ix3(i, j, k)) + } + + /// Self is an index, return the stride offset + #[inline] + fn stride_offset(index: &Self, strides: &Self) -> isize { + let i = get!(index, 0); + let j = get!(index, 1); + let k = get!(index, 2); + let s = get!(strides, 0); + let t = get!(strides, 1); + let u = get!(strides, 2); + stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u) + } + + #[inline] + fn _fastest_varying_stride_order(&self) -> Self { + let mut stride = *self; + let mut order = Ix3(0, 1, 2); + macro_rules! swap { + ($stride:expr, $order:expr, $x:expr, $y:expr) => { + if $stride[$x] > $stride[$y] { + $stride.swap($x, $y); + $order.ixm().swap($x, $y); + } + } + } + { + // stable sorting network for 3 elements + let strides = stride.slice_mut(); + swap![strides, order, 1, 2]; + swap![strides, order, 0, 1]; + swap![strides, order, 1, 2]; + } + order + } +} + +macro_rules! large_dim { + ($n:expr, $name:ident, $($ix:ident),+) => ( + unsafe impl Dimension for $name { + type SliceArg = [Si; $n]; + type Pattern = ($($ix,)*); + #[inline] + fn ndim(&self) -> usize { $n } + #[inline] + fn into_pattern(self) -> Self::Pattern { + self.ix().convert() + } + #[inline] + fn slice(&self) -> &[Ix] { self.ix() } + #[inline] + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } + } + ) +} + +large_dim!(4, Ix4, Ix, Ix, Ix, Ix); +large_dim!(5, Ix5, Ix, Ix, Ix, Ix, Ix); +large_dim!(6, Ix6, Ix, Ix, Ix, Ix, Ix, Ix); + +/// Vec is a "dynamic" index, pretty hard to use when indexing, +/// and memory wasteful, but it allows an arbitrary and dynamic number of axes. +unsafe impl Dimension for IxDyn +{ + type SliceArg = [Si]; + type Pattern = Self; + fn ndim(&self) -> usize { self.ix().len() } + fn slice(&self) -> &[Ix] { self.ix() } + fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } + #[inline] + fn into_pattern(self) -> Self::Pattern { + self + } +} + +impl Index for Dim> + where Vec: Index, +{ + type Output = as Index>::Output; + fn index(&self, index: J) -> &Self::Output { + &self.ix()[index] + } +} + +impl IndexMut for Dim> + where Vec: IndexMut, +{ + fn index_mut(&mut self, index: J) -> &mut Self::Output { + &mut self.ixm()[index] + } +} diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index b5accd8da..85f2e54ab 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -5,29 +5,23 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::fmt::Debug; -use std::ops::{Index, IndexMut}; -use itertools::{enumerate, zip}; - -use super::{Si, Ix, Ixs}; -use super::{zipsl, zipsl_mut}; +use {Ix, Ixs}; use error::{from_kind, ErrorKind, ShapeError}; -use ZipExt; -use {Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn}; -use {ArrayView1, ArrayViewMut1}; +use {zipsl, ZipExt}; pub use self::dim::*; pub use self::axis::Axis; -pub use self::ndindex::NdIndex; pub use self::conversion::IntoDimension; -use self::conversion::Convert; +pub use self::dimension_trait::Dimension; +pub use self::ndindex::NdIndex; pub use self::remove_axis::RemoveAxis; -pub mod dim; #[macro_use] mod macros; mod axis; mod conversion; +pub mod dim; +mod dimension_trait; mod ndindex; mod remove_axis; @@ -135,290 +129,6 @@ fn stride_offset_checked_arithmetic(dim: &D, strides: &D, index: &D) Some(offset) } -use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; - -/// Array shape and index trait. -/// -/// `unsafe` because of the assumptions in the default methods. -/// -/// ***Don't implement this trait, it will evolve at will.*** -pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + - IndexMut + - Add + - AddAssign + for<'x> AddAssign<&'x Self> + - Sub + - SubAssign + for<'x> SubAssign<&'x Self> + - Mul + Mul + - MulAssign + for<'x> MulAssign<&'x Self> + MulAssign - -{ - /// `SliceArg` is the type which is used to specify slicing for this - /// dimension. - /// - /// For the fixed size dimensions it is a fixed size array of the correct - /// size, which you pass by reference. For the `Vec` dimension it is - /// a slice. - /// - /// - For `Ix1`: `[Si; 1]` - /// - For `Ix2`: `[Si; 2]` - /// - and so on.. - /// - For `Vec`: `[Si]` - /// - /// The easiest way to create a `&SliceArg` is using the macro - /// [`s![]`](macro.s!.html). - type SliceArg: ?Sized + AsRef<[Si]>; - /// Pattern matching friendly form of the dimension value. - /// - /// - For `Ix1`: `usize`, - /// - For `Ix2`: `(usize, usize)` - /// - and so on.. - /// - For `Vec`: `Vec`, - type Pattern: IntoDimension; - #[doc(hidden)] - fn ndim(&self) -> usize; - - /// Convert the dimension into a pattern matching friendly value. - fn into_pattern(self) -> Self::Pattern; - - /// Compute the size of the dimension (number of elements) - fn size(&self) -> usize { - self.slice().iter().fold(1, |s, &a| s * a as usize) - } - - /// Compute the size while checking for overflow. - fn size_checked(&self) -> Option { - self.slice().iter().fold(Some(1), |s, &a| s.and_then(|s_| s_.checked_mul(a))) - } - - #[doc(hidden)] - fn slice(&self) -> &[Ix]; - - #[doc(hidden)] - fn slice_mut(&mut self) -> &mut [Ix]; - - /// Borrow as a read-only array view. - fn as_array_view(&self) -> ArrayView1 { - ArrayView1::from(self.slice()) - } - - /// Borrow as a read-write array view. - fn as_array_view_mut(&mut self) -> ArrayViewMut1 { - ArrayViewMut1::from(self.slice_mut()) - } - - #[doc(hidden)] - fn equal(&self, rhs: &Self) -> bool { - self.slice() == rhs.slice() - } - - #[doc(hidden)] - fn default_strides(&self) -> Self { - // Compute default array strides - // Shape (a, b, c) => Give strides (b * c, c, 1) - let mut strides = self.clone(); - { - let mut it = strides.slice_mut().iter_mut().rev(); - // Set first element to 1 - for rs in it.by_ref() { - *rs = 1; - break; - } - let mut cum_prod = 1; - for (rs, dim) in it.zip(self.slice().iter().rev()) { - cum_prod *= *dim; - *rs = cum_prod; - } - } - strides - } - - #[doc(hidden)] - fn fortran_strides(&self) -> Self { - // Compute fortran array strides - // Shape (a, b, c) => Give strides (1, a, a * b) - let mut strides = self.clone(); - { - let mut it = strides.slice_mut().iter_mut(); - // Set first element to 1 - for rs in it.by_ref() { - *rs = 1; - break; - } - let mut cum_prod = 1; - for (rs, dim) in it.zip(self.slice().iter()) { - cum_prod *= *dim; - *rs = cum_prod; - } - } - strides - } - - #[doc(hidden)] - #[inline] - fn first_index(&self) -> Option { - for ax in self.slice().iter() { - if *ax == 0 { - return None; - } - } - let mut index = self.clone(); - for rr in index.slice_mut().iter_mut() { - *rr = 0; - } - Some(index) - } - - #[doc(hidden)] - /// Iteration -- Use self as size, and return next index after `index` - /// or None if there are no more. - // FIXME: use &Self for index or even &mut? - #[inline] - fn next_for(&self, index: Self) -> Option { - let mut index = index; - let mut done = false; - for (&dim, ix) in zip(self.slice(), index.slice_mut()).rev() { - *ix += 1; - if *ix == dim { - *ix = 0; - } else { - done = true; - break; - } - } - if done { - Some(index) - } else { - None - } - } - - #[doc(hidden)] - /// Return stride offset for index. - fn stride_offset(index: &Self, strides: &Self) -> isize { - let mut offset = 0; - for (&i, &s) in zipsl(index.slice(), strides.slice()) { - offset += stride_offset(i, s); - } - offset - } - - #[doc(hidden)] - /// Return stride offset for this dimension and index. - fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option { - let mut offset = 0; - for (&d, &i, &s) in zipsl(self.slice(), index.slice()).zip_cons(strides.slice()) - { - if i >= d { - return None; - } - offset += stride_offset(i, s); - } - Some(offset) - } - - #[doc(hidden)] - fn last_elem(&self) -> usize { - if self.ndim() == 0 { 0 } else { self.slice()[self.ndim() - 1] } - } - - #[doc(hidden)] - fn set_last_elem(&mut self, i: usize) { - let nd = self.ndim(); - self.slice_mut()[nd - 1] = i; - } - - #[doc(hidden)] - /// Modify dimension, strides and return data pointer offset - /// - /// **Panics** if `slices` does not correspond to the number of axes, - /// if any stride is 0, or if any index is out of bounds. - fn do_slices(dim: &mut Self, strides: &mut Self, slices: &Self::SliceArg) -> isize { - let slices = slices.as_ref(); - let mut offset = 0; - assert!(slices.len() == dim.slice().len()); - for (dr, sr, &slc) in zipsl_mut(dim.slice_mut(), strides.slice_mut()).zip_cons(slices) - { - let m = *dr; - let mi = m as Ixs; - let Si(b1, opt_e1, s1) = slc; - let e1 = opt_e1.unwrap_or(mi); - - let b1 = abs_index(mi, b1); - let mut e1 = abs_index(mi, e1); - if e1 < b1 { e1 = b1; } - - assert!(b1 <= m); - assert!(e1 <= m); - - let m = e1 - b1; - // stride - let s = (*sr) as Ixs; - - // Data pointer offset - offset += stride_offset(b1, *sr); - // Adjust for strides - assert!(s1 != 0); - // How to implement negative strides: - // - // Increase start pointer by - // old stride * (old dim - 1) - // to put the pointer completely in the other end - if s1 < 0 { - offset += stride_offset(m - 1, *sr); - } - - let s_prim = s * s1; - - let d = m / s1.abs() as Ix; - let r = m % s1.abs() as Ix; - let m_prim = d + if r > 0 { 1 } else { 0 }; - - // Update dimension and stride coordinate - *dr = m_prim; - *sr = s_prim as Ix; - } - offset - } - - #[doc(hidden)] - fn is_contiguous(dim: &Self, strides: &Self) -> bool { - let defaults = dim.default_strides(); - if strides.equal(&defaults) { - return true; - } - if dim.ndim() == 1 { return false; } - let order = strides._fastest_varying_stride_order(); - let strides = strides.slice(); - - // FIXME: Negative strides - let dim_slice = dim.slice(); - let mut cstride = 1; - for &i in order.slice() { - // a dimension of length 1 can have unequal strides - if dim_slice[i] != 1 && strides[i] != cstride { - return false; - } - cstride *= dim_slice[i]; - } - true - } - - /// Return the axis ordering corresponding to the fastest variation - /// (in ascending order). - /// - /// Assumes that no stride value appears twice. This cannot yield the correct - /// result the strides are not positive. - #[doc(hidden)] - fn _fastest_varying_stride_order(&self) -> Self { - let mut indices = self.clone(); - for (i, elt) in enumerate(indices.slice_mut()) { - *elt = i; - } - let strides = self.slice(); - indices.slice_mut().sort_by_key(|&i| strides[i]); - indices - } -} /// Implementation-specific extensions to `Dimension` pub trait DimensionExt { @@ -464,15 +174,6 @@ impl<'a> DimensionExt for [Ix] } } -#[inline] -fn abs_index(len: Ixs, index: Ixs) -> Ix { - if index < 0 { - (len + index) as Ix - } else { - index as Ix - } -} - /// Collapse axis `axis` and shift so that only subarray `index` is /// available. /// @@ -491,364 +192,6 @@ pub fn do_sub(dims: &mut D, ptr: &mut *mut A, strides: &D, } -unsafe impl Dimension for Ix0 { - type SliceArg = [Si; 0]; - type Pattern = (); - // empty product is 1 -> size is 1 - #[inline] - fn ndim(&self) -> usize { 0 } - #[inline] - fn slice(&self) -> &[Ix] { &[] } - #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { &mut [] } - #[inline] - fn _fastest_varying_stride_order(&self) -> Self { Ix0() } - #[inline] - fn into_pattern(self) -> Self::Pattern { } - #[inline] - fn next_for(&self, _index: Self) -> Option { - None - } -} - - -unsafe impl Dimension for Ix1 { - type SliceArg = [Si; 1]; - type Pattern = Ix; - #[inline] - fn ndim(&self) -> usize { 1 } - #[inline] - fn slice(&self) -> &[Ix] { self.ix() } - #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } - #[inline] - fn into_pattern(self) -> Self::Pattern { - get!(&self, 0) - } - #[inline] - fn next_for(&self, mut index: Self) -> Option { - getm!(index, 0) += 1; - if get!(&index, 0) < get!(self, 0) { - Some(index) - } else { - None - } - } - - #[inline] - fn equal(&self, rhs: &Self) -> bool { - get!(self, 0) == get!(rhs, 0) - } - - #[inline] - fn size(&self) -> usize { get!(self, 0) } - #[inline] - fn size_checked(&self) -> Option { Some(get!(self, 0)) } - - #[inline] - fn default_strides(&self) -> Self { - Ix1(1) - } - - #[inline] - fn _fastest_varying_stride_order(&self) -> Self { - Ix1(0) - } - - #[inline] - fn first_index(&self) -> Option { - if get!(self, 0) != 0 { - Some(Ix1(0)) - } else { - None - } - } - - /// Self is an index, return the stride offset - #[inline(always)] - fn stride_offset(index: &Self, stride: &Self) -> isize { - stride_offset(get!(index, 0), get!(stride, 0)) - } - - /// Return stride offset for this dimension and index. - #[inline] - fn stride_offset_checked(&self, stride: &Self, index: &Self) -> Option { - if get!(index, 0) < get!(self, 0) { - Some(stride_offset(get!(index, 0), get!(stride, 0))) - } else { - None - } - } -} - -unsafe impl Dimension for Ix2 { - type SliceArg = [Si; 2]; - type Pattern = (Ix, Ix); - #[inline] - fn ndim(&self) -> usize { 2 } - #[inline] - fn into_pattern(self) -> Self::Pattern { - self.ix().convert() - } - #[inline] - fn slice(&self) -> &[Ix] { self.ix() } - #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } - #[inline] - fn next_for(&self, index: Self) -> Option { - let mut i = get!(&index, 0); - let mut j = get!(&index, 1); - let imax = get!(self, 0); - let jmax = get!(self, 1); - j += 1; - if j >= jmax { - j = 0; - i += 1; - if i >= imax { - return None; - } - } - Some(Ix2(i, j)) - } - - #[inline] - fn equal(&self, rhs: &Self) -> bool { - get!(self, 0) == get!(rhs, 0) && get!(self, 1) == get!(rhs, 1) - } - - #[inline] - fn size(&self) -> usize { get!(self, 0) * get!(self, 1) } - - #[inline] - fn size_checked(&self) -> Option { - let m = get!(self, 0); - let n = get!(self, 1); - (m as usize).checked_mul(n as usize) - } - - #[inline] - fn last_elem(&self) -> usize { - get!(self, 1) - } - - #[inline] - fn set_last_elem(&mut self, i: usize) { - getm!(self, 1) = i; - } - - #[inline] - fn default_strides(&self) -> Self { - // Compute default array strides - // Shape (a, b, c) => Give strides (b * c, c, 1) - Ix2(get!(self, 1), 1) - } - #[inline] - fn fortran_strides(&self) -> Self { - Ix2(1, get!(self, 0)) - } - - #[inline] - fn _fastest_varying_stride_order(&self) -> Self { - if get!(self, 0) as Ixs <= get!(self, 1) as Ixs { Ix2(0, 1) } else { Ix2(1, 0) } - } - - #[inline] - fn is_contiguous(dim: &Self, strides: &Self) -> bool { - let defaults = dim.default_strides(); - if strides.equal(&defaults) { - return true; - } - - if dim.ndim() == 1 { return false; } - let order = strides._fastest_varying_stride_order(); - let strides = strides.slice(); - - // FIXME: Negative strides - let dim_slice = dim.slice(); - let mut cstride = 1; - for &i in order.slice() { - // a dimension of length 1 can have unequal strides - if dim_slice[i] != 1 && strides[i] != cstride { - return false; - } - cstride *= dim_slice[i]; - } - true - } - - #[inline] - fn first_index(&self) -> Option { - let m = get!(self, 0); - let n = get!(self, 1); - if m != 0 && n != 0 { - Some(Ix2(0, 0)) - } else { - None - } - } - - /// Self is an index, return the stride offset - #[inline(always)] - fn stride_offset(index: &Self, strides: &Self) -> isize { - let i = get!(index, 0); - let j = get!(index, 1); - let s = get!(strides, 0); - let t = get!(strides, 1); - stride_offset(i, s) + stride_offset(j, t) - } - - /// Return stride offset for this dimension and index. - #[inline] - fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option - { - let m = get!(self, 0); - let n = get!(self, 1); - let i = get!(index, 0); - let j = get!(index, 1); - let s = get!(strides, 0); - let t = get!(strides, 1); - if i < m && j < n { - Some(stride_offset(i, s) + stride_offset(j, t)) - } else { - None - } - } -} - -unsafe impl Dimension for Ix3 { - type SliceArg = [Si; 3]; - type Pattern = (Ix, Ix, Ix); - #[inline] - fn ndim(&self) -> usize { 3 } - #[inline] - fn into_pattern(self) -> Self::Pattern { - self.ix().convert() - } - #[inline] - fn slice(&self) -> &[Ix] { self.ix() } - #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } - - #[inline] - fn size(&self) -> usize { - let m = get!(self, 0); - let n = get!(self, 1); - let o = get!(self, 2); - m as usize * n as usize * o as usize - } - - #[inline] - fn next_for(&self, index: Self) -> Option { - let mut i = get!(&index, 0); - let mut j = get!(&index, 1); - let mut k = get!(&index, 2); - let imax = get!(self, 0); - let jmax = get!(self, 1); - let kmax = get!(self, 2); - k += 1; - if k == kmax { - k = 0; - j += 1; - if j == jmax { - j = 0; - i += 1; - if i == imax { - return None; - } - } - } - Some(Ix3(i, j, k)) - } - - /// Self is an index, return the stride offset - #[inline] - fn stride_offset(index: &Self, strides: &Self) -> isize { - let i = get!(index, 0); - let j = get!(index, 1); - let k = get!(index, 2); - let s = get!(strides, 0); - let t = get!(strides, 1); - let u = get!(strides, 2); - stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u) - } - - #[inline] - fn _fastest_varying_stride_order(&self) -> Self { - let mut stride = *self; - let mut order = Ix3(0, 1, 2); - macro_rules! swap { - ($stride:expr, $order:expr, $x:expr, $y:expr) => { - if $stride[$x] > $stride[$y] { - $stride.swap($x, $y); - $order.ixm().swap($x, $y); - } - } - } - { - // stable sorting network for 3 elements - let strides = stride.slice_mut(); - swap![strides, order, 1, 2]; - swap![strides, order, 0, 1]; - swap![strides, order, 1, 2]; - } - order - } -} - -macro_rules! large_dim { - ($n:expr, $name:ident, $($ix:ident),+) => ( - unsafe impl Dimension for $name { - type SliceArg = [Si; $n]; - type Pattern = ($($ix,)*); - #[inline] - fn ndim(&self) -> usize { $n } - #[inline] - fn into_pattern(self) -> Self::Pattern { - self.ix().convert() - } - #[inline] - fn slice(&self) -> &[Ix] { self.ix() } - #[inline] - fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } - } - ) -} - -large_dim!(4, Ix4, Ix, Ix, Ix, Ix); -large_dim!(5, Ix5, Ix, Ix, Ix, Ix, Ix); -large_dim!(6, Ix6, Ix, Ix, Ix, Ix, Ix, Ix); - -/// Vec is a "dynamic" index, pretty hard to use when indexing, -/// and memory wasteful, but it allows an arbitrary and dynamic number of axes. -unsafe impl Dimension for IxDyn -{ - type SliceArg = [Si]; - type Pattern = Self; - fn ndim(&self) -> usize { self.ix().len() } - fn slice(&self) -> &[Ix] { self.ix() } - fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } - #[inline] - fn into_pattern(self) -> Self::Pattern { - self - } -} - -impl Index for Dim> - where Vec: Index, -{ - type Output = as Index>::Output; - fn index(&self, index: J) -> &Self::Output { - &self.ix()[index] - } -} - -impl IndexMut for Dim> - where Vec: IndexMut, -{ - fn index_mut(&mut self, index: J) -> &mut Self::Output { - &mut self.ixm()[index] - } -} // NOTE: These tests are not compiled & tested From a3b9ab60783b0c4228c8442651ffebf4e0f88da8 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:45:08 +0100 Subject: [PATCH 081/107] Edit docs for Dim --- src/dimension/dim.rs | 18 ++++++++++++++++++ src/dimension/mod.rs | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/dimension/dim.rs b/src/dimension/dim.rs index 196baee25..42012e6fc 100644 --- a/src/dimension/dim.rs +++ b/src/dimension/dim.rs @@ -23,6 +23,24 @@ pub trait DimPrivate { /// /// `Dim` describes the number of axes and the length of each axis /// in an array. It is also used as an index type. +/// +/// The commonly you want to use the methods of the `Dimension` trait. See its +/// documentation for more information. +/// +/// # Examples +/// +/// To create an array with a particular dimension, you'd just pass +/// a tuple (in this example (3, 2) is used), which is converted to +/// `Dim` by the array constructor. +/// +/// ``` +/// use ndarray::Array2; +/// use ndarray::Dim; +/// +/// let mut array = Array2::zeros((3, 2)); +/// array[[0, 0]] = 1.; +/// assert_eq!(array.dim(), Dim([3, 2])); +/// ``` #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] pub struct Dim { index: I, diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index 85f2e54ab..4f75a551b 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -10,7 +10,7 @@ use {Ix, Ixs}; use error::{from_kind, ErrorKind, ShapeError}; use {zipsl, ZipExt}; -pub use self::dim::*; +pub use self::dim::{Dim, DimPrivate}; pub use self::axis::Axis; pub use self::conversion::IntoDimension; pub use self::dimension_trait::Dimension; From 7bfb6b4c538b5d77a64f62e6be910c594b549c98 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:46:54 +0100 Subject: [PATCH 082/107] s![] and ops macros: ast coercion is obsolete, we can drop it! --- src/impl_ops.rs | 10 +++------- src/si.rs | 5 ++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/impl_ops.rs b/src/impl_ops.rs index b8b763ba8..7bba676a8 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -47,10 +47,6 @@ impl ScalarOperand for f64 { } impl ScalarOperand for Complex { } impl ScalarOperand for Complex { } -macro_rules! as_expr( - ($e:expr) => ($e) -); - macro_rules! impl_binary_op( ($trt:ident, $operator:tt, $mth:ident, $iop:tt, $doc:expr) => ( /// Perform elementwise @@ -96,7 +92,7 @@ impl<'a, A, S, S2, D, E> $trt<&'a ArrayBase> for ArrayBase fn $mth(mut self, rhs: &ArrayBase) -> ArrayBase { self.zip_mut_with(rhs, |x, y| { - *x = as_expr!(x.clone() $operator y.clone()); + *x = x.clone() $operator y.clone(); }); self } @@ -139,7 +135,7 @@ impl $trt for ArrayBase type Output = ArrayBase; fn $mth(mut self, x: B) -> ArrayBase { self.unordered_foreach_mut(move |elt| { - *elt = as_expr!(elt.clone() $operator x.clone()); + *elt = elt.clone() $operator x.clone(); }); self } @@ -188,7 +184,7 @@ impl $trt> for $scalar } or {{ let mut rhs = rhs; rhs.unordered_foreach_mut(move |elt| { - *elt = as_expr!(self $operator *elt); + *elt = self $operator *elt; }); rhs }}) diff --git a/src/si.rs b/src/si.rs index bc67874e8..560b075db 100644 --- a/src/si.rs +++ b/src/si.rs @@ -121,14 +121,13 @@ pub const S: Si = Si(0, None, 1); /// ``` #[macro_export] macro_rules! s( - (@as_expr $e:expr) => ($e); // convert a..b;c into @step(a..b, c), final item (@parse [$($stack:tt)*] $r:expr;$s:expr) => { - s![@as_expr &[$($stack)* s!(@step $r, $s)]] + &[$($stack)* s!(@step $r, $s)] }; // convert a..b into @step(a..b, 1), final item (@parse [$($stack:tt)*] $r:expr) => { - s![@as_expr &[$($stack)* s!(@step $r, 1)]] + &[$($stack)* s!(@step $r, 1)] }; // convert a..b;c into @step(a..b, c) (@parse [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => { From a271e0286feddc51ff39fe7eb3b94a6dde48d855 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:52:28 +0100 Subject: [PATCH 083/107] Add RcArray1, RcArray2 aliases --- src/aliases.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/aliases.rs b/src/aliases.rs index 9f5cd3252..302c6f853 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -1,7 +1,7 @@ //! Type aliases for common array sizes //! -use ::{Ix, Array, ArrayView, ArrayViewMut}; +use ::{Ix, Array, ArrayView, ArrayViewMut, RcArray}; use ::dimension::Dim; use dimension::DimPrivate; @@ -105,3 +105,8 @@ pub type ArrayViewMut5<'a, A> = ArrayViewMut<'a, A, Ix5>; pub type ArrayViewMut6<'a, A> = ArrayViewMut<'a, A, Ix6>; /// dynamic-dimensional read-write array view pub type ArrayViewMutD<'a, A> = ArrayViewMut<'a, A, IxDyn>; + +/// one-dimensional shared ownership array +pub type RcArray1 = RcArray; +/// two-dimensional shared ownership array +pub type RcArray2 = RcArray; From 5305953c2343b5bbe4f3e6b395426a2a1f8a1fb1 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 6 Nov 2016 23:57:04 +0100 Subject: [PATCH 084/107] Change one-dimensional constructors to use `A` type parameter. This makes the docs more consistent and easier to read. --- src/impl_constructors.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index ff58d00ff..a3ab97343 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -24,8 +24,8 @@ use iterators::{to_vec, to_vec_mapped}; /// /// Note that the constructor methods apply to `Array` and `RcArray`, /// the two array types that have owned storage. -impl ArrayBase - where S: DataOwned +impl ArrayBase + where S: DataOwned, { /// Create a one-dimensional array from a vector (no copying needed). /// @@ -34,7 +34,7 @@ impl ArrayBase /// /// let array = Array::from_vec(vec![1., 2., 3., 4.]); /// ``` - pub fn from_vec(v: Vec) -> Self { + pub fn from_vec(v: Vec) -> Self { unsafe { Self::from_shape_vec_unchecked(v.len() as Ix, v) } } @@ -47,13 +47,13 @@ impl ArrayBase /// assert!(array == arr1(&[0, 1, 4, 9, 16])) /// ``` pub fn from_iter(iterable: I) -> Self - where I: IntoIterator + where I: IntoIterator { Self::from_vec(iterable.into_iter().collect()) } /// Create a one-dimensional array from the inclusive interval - /// `[start, end]` with `n` elements. `F` must be a floating point type. + /// `[start, end]` with `n` elements. `A` must be a floating point type. /// /// ```rust /// use ndarray::{Array, arr1}; @@ -61,15 +61,15 @@ impl ArrayBase /// let array = Array::linspace(0., 1., 5); /// assert!(array == arr1(&[0.0, 0.25, 0.5, 0.75, 1.0])) /// ``` - pub fn linspace(start: F, end: F, n: usize) -> Self - where S: Data, - F: Float, + pub fn linspace(start: A, end: A, n: usize) -> Self + where A: Float, { Self::from_vec(to_vec(linspace::linspace(start, end, n))) } /// Create a one-dimensional array from the half-open interval - /// `[start, end)` with elements spaced by `step`. `F` must be a floating point type. + /// `[start, end)` with elements spaced by `step`. `A` must be a floating + /// point type. /// /// ```rust /// use ndarray::{Array, arr1}; @@ -77,9 +77,8 @@ impl ArrayBase /// let array = Array::range(0., 5., 1.); /// assert!(array == arr1(&[0., 1., 2., 3., 4.])) /// ``` - pub fn range(start: F, end: F, step: F) -> Self - where S: Data, - F: Float, + pub fn range(start: A, end: A, step: A) -> Self + where A: Float, { Self::from_vec(to_vec(linspace::range(start, end, step))) } From 3ba15b565f593ef16d72a3959881e14d3bc5f6c5 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 00:08:11 +0100 Subject: [PATCH 085/107] Edit doc headings --- src/impl_constructors.rs | 2 ++ src/impl_methods.rs | 1 + src/impl_views.rs | 2 +- src/lib.rs | 5 +++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index a3ab97343..4fb74a094 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -20,6 +20,8 @@ use error::{self, ShapeError, ErrorKind}; use Indexes; use iterators::{to_vec, to_vec_mapped}; +/// # Constructor Methods for Owned Arrays +/// /// Constructor methods for one-dimensional arrays. /// /// Note that the constructor methods apply to `Array` and `RcArray`, diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 3466fd3e4..c912d2791 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -37,6 +37,7 @@ use { }; use stacking::stack; +/// # Methods For All Array Types impl ArrayBase where S: Data, D: Dimension { /// Return the total number of elements in the array. diff --git a/src/impl_views.rs b/src/impl_views.rs index 7a0577cce..a4743848a 100644 --- a/src/impl_views.rs +++ b/src/impl_views.rs @@ -12,7 +12,7 @@ use error::ShapeError; use StrideShape; -/// # Methods for Array Views +/// # Methods Specific to Array Views /// /// Methods for read-only array views `ArrayView<'a, A, D>` /// diff --git a/src/lib.rs b/src/lib.rs index 12c4ad3d2..e38688dbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,8 +198,9 @@ pub type Ixs = isize; /// + [Subviews](#subviews) /// + [Arithmetic Operations](#arithmetic-operations) /// + [Broadcasting](#broadcasting) -/// + [Methods](#methods) -/// + [Methods for Array Views](#methods-for-array-views) +/// + [Constructor Methods for Owned Arrays](#constructor-methods-for-owned-arrays) +/// + [Methods For All Array Types](#methods-for-all-array-types) +/// + [Methods Specific to Array Views](#methods-specific-to-array-views) /// /// ## `Array` and `RcArray` /// From ee623b988ee731c8237922b9ac0834fbb16b4939 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 00:10:02 +0100 Subject: [PATCH 086/107] Update split_at.svg --- docgen/images/split_at.svg | 166 +++++++++++++++++++++++-------------- 1 file changed, 105 insertions(+), 61 deletions(-) diff --git a/docgen/images/split_at.svg b/docgen/images/split_at.svg index 4e68f1157..57c429546 100644 --- a/docgen/images/split_at.svg +++ b/docgen/images/split_at.svg @@ -125,7 +125,7 @@ + style="opacity:0.95;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:0.95;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:0.95;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:0.95;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:1;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:1;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:0.95;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:0.95;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:0.95;fill:#006eaf;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.62353659;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + transform="matrix(0.62353657,0,0,0.62353657,546.73664,101.89416)" + style="fill:#006eaf;fill-opacity:1"> + transform="matrix(0.46312941,-0.46312941,0,1.000596,-151.14269,-102.52316)" + style="fill:#006eaf;fill-opacity:1"> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#008aff;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + style="opacity:1;fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + height="100%" + style="fill:#006eaf;fill-opacity:1" /> + style="opacity:1;fill:#006eaf;fill-opacity:1" /> + style="opacity:1;fill:#006eaf;fill-opacity:1" /> + style="opacity:1;fill:#006eaf;fill-opacity:1" /> Output shapes: (3, 5, 2) and (3, 5, 3) Date: Mon, 7 Nov 2016 00:16:50 +0100 Subject: [PATCH 087/107] use explicit imports in Array::from_shape_vec method --- src/impl_constructors.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 4fb74a094..c27ed3855 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -205,13 +205,15 @@ impl ArrayBase /// **Errors** if strides allow multiple indices to point to the same element. /// /// ``` - /// use ndarray::prelude::*; + /// use ndarray::Array; + /// use ndarray::ShapeBuilder; // Needed for .strides() method + /// use ndarray::arr2; /// /// let a = Array::from_shape_vec((2, 2), vec![1., 2., 3., 4.]); /// assert!(a.is_ok()); /// /// let b = Array::from_shape_vec((2, 2).strides((1, 2)), - /// vec![1., 2., 3., 4.]).unwrap(); + /// vec![1., 2., 3., 4.]).unwrap(); /// assert!( /// b == arr2(&[[1., 3.], /// [2., 4.]]) From 77a4f38c2688823091dc71c9cbe0130d74a0c0c6 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 00:29:00 +0100 Subject: [PATCH 088/107] Edit example for ndindex --- src/dimension/ndindex.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs index 408f3ecbb..a5e746fe7 100644 --- a/src/dimension/ndindex.rs +++ b/src/dimension/ndindex.rs @@ -13,10 +13,12 @@ use super::DimPrivate; /// ``` /// use ndarray::arr2; /// -/// let mut a = arr2(&[[0, 1], [0, 0]]); -/// a[[1, 1]] = 1; +/// let mut a = arr2(&[[0, 1], +/// [2, 3]]); /// assert_eq!(a[[0, 1]], 1); -/// assert_eq!(a[[1, 1]], 1); +/// assert_eq!(a[[1, 1]], 3); +/// a[[1, 1]] += 1; +/// assert_eq!(a[(1, 1)], 4); /// ``` /// /// **Note** that `NdIndex` is implemented for all `D where D: Dimension`. From b17f95a2031261056aac0dc779a26751160dad4b Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 00:30:56 +0100 Subject: [PATCH 089/107] Add missing NdIndex impls --- src/dimension/ndindex.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs index a5e746fe7..1fa77b923 100644 --- a/src/dimension/ndindex.rs +++ b/src/dimension/ndindex.rs @@ -132,6 +132,37 @@ unsafe impl NdIndex for [Ix; 3] { } } +unsafe impl NdIndex for [Ix; 4] { + #[inline] + fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option { + dim.stride_offset_checked(strides, &self.into_dimension()) + } + #[inline] + fn index_unchecked(&self, strides: &Ix4) -> isize { + stride_offset(self[0], get!(strides, 0)) + + stride_offset(self[1], get!(strides, 1)) + + stride_offset(self[2], get!(strides, 2)) + + stride_offset(self[3], get!(strides, 3)) + + 0 + } +} + +unsafe impl NdIndex for [Ix; 5] { + #[inline] + fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option { + dim.stride_offset_checked(strides, &self.into_dimension()) + } + #[inline] + fn index_unchecked(&self, strides: &Ix5) -> isize { + stride_offset(self[0], get!(strides, 0)) + + stride_offset(self[1], get!(strides, 1)) + + stride_offset(self[2], get!(strides, 2)) + + stride_offset(self[3], get!(strides, 3)) + + stride_offset(self[4], get!(strides, 4)) + + 0 + } +} + impl<'a> IntoDimension for &'a [Ix] { type Dim = Dim>; fn into_dimension(self) -> Self::Dim { From 2bb7b64a242e27ab4c1ac876b6596f794225c6e6 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 00:41:33 +0100 Subject: [PATCH 090/107] Reenable a dimension test --- tests/dimension.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/dimension.rs b/tests/dimension.rs index 53409f99f..f57fbda2c 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -23,11 +23,8 @@ fn remove_axis() let a = RcArray::::zeros((4,5)); a.subview(Axis(1), 0); - /* let a = RcArray::::zeros(vec![4,5,6]); let _b = a.into_subview(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]); - */ - } #[test] From 819011394c452a9b0ce457599a78d03a6872a1af Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 01:05:24 +0100 Subject: [PATCH 091/107] Implement NdIndex consistently. Allow indexing in ArrayD using arrays This dramatically increases usability of dynamic-dimension arrays by allowing indexing like a[[i, j]] for them. --- src/dimension/dimension_trait.rs | 11 +- src/dimension/mod.rs | 15 +++ src/dimension/ndindex.rs | 167 ++++++++++++++++++------------- tests/ixdyn.rs | 60 +++++++++++ 4 files changed, 175 insertions(+), 78 deletions(-) create mode 100644 tests/ixdyn.rs diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 74154ee2e..f4107676c 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -19,6 +19,7 @@ use {ArrayView1, ArrayViewMut1}; use {zipsl, zipsl_mut, ZipExt}; use super::{ stride_offset, + stride_offset_checked, DimPrivate, }; use super::conversion::Convert; @@ -191,15 +192,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + #[doc(hidden)] /// Return stride offset for this dimension and index. fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option { - let mut offset = 0; - for (&d, &i, &s) in zipsl(self.slice(), index.slice()).zip_cons(strides.slice()) - { - if i >= d { - return None; - } - offset += stride_offset(i, s); - } - Some(offset) + stride_offset_checked(self.slice(), strides.slice(), index.slice()) } #[doc(hidden)] diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index 4f75a551b..cf14d1801 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -129,6 +129,21 @@ fn stride_offset_checked_arithmetic(dim: &D, strides: &D, index: &D) Some(offset) } +/// Stride offset checked general version (slices) +pub fn stride_offset_checked(dim: &[Ix], strides: &[Ix], index: &[Ix]) -> Option { + if index.len() != dim.len() { + return None; + } + let mut offset = 0; + for (&d, &i, &s) in zipsl(dim, index).zip_cons(strides) + { + if i >= d { + return None; + } + offset += stride_offset(i, s); + } + Some(offset) +} /// Implementation-specific extensions to `Dimension` pub trait DimensionExt { diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs index 1fa77b923..65096d171 100644 --- a/src/dimension/ndindex.rs +++ b/src/dimension/ndindex.rs @@ -3,9 +3,8 @@ use std::fmt::Debug; use itertools::zip; -use {Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, IxDyn, Dim, Dimension, IntoDimension}; -use {zipsl, ZipExt}; -use super::{stride_offset}; +use {Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Dimension, IntoDimension}; +use super::{stride_offset, stride_offset_checked}; use super::DimPrivate; /// Tuple or fixed size arrays that can be used to index an array. @@ -50,17 +49,6 @@ unsafe impl NdIndex for () { } } -unsafe impl NdIndex for Ix { - #[inline] - fn index_checked(&self, dim: &Ix1, strides: &Ix1) -> Option { - dim.stride_offset_checked(strides, &Ix1(*self)) - } - #[inline(always)] - fn index_unchecked(&self, strides: &Ix1) -> isize { - stride_offset(*self, get!(strides, 0)) - } -} - unsafe impl NdIndex for (Ix, Ix) { #[inline] fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { @@ -107,60 +95,115 @@ unsafe impl NdIndex for (Ix, Ix, Ix, Ix, Ix) { } } -unsafe impl NdIndex for [Ix; 2] { +unsafe impl NdIndex for Ix { #[inline] - fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option { - dim.stride_offset_checked(strides, &Ix2(self[0], self[1])) + fn index_checked(&self, dim: &Ix1, strides: &Ix1) -> Option { + dim.stride_offset_checked(strides, &Ix1(*self)) } - #[inline] - fn index_unchecked(&self, strides: &Ix2) -> isize { - stride_offset(self[0], get!(strides, 0)) + - stride_offset(self[1], get!(strides, 1)) + #[inline(always)] + fn index_unchecked(&self, strides: &Ix1) -> isize { + stride_offset(*self, get!(strides, 0)) } } -unsafe impl NdIndex for [Ix; 3] { +unsafe impl NdIndex for Ix { #[inline] - fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option { - dim.stride_offset_checked(strides, &Ix3(self[0], self[1], self[2])) + fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { + debug_assert_eq!(dim.ndim(), 1); + stride_offset_checked(dim.ix(), strides.ix(), &[*self]) } - #[inline] - fn index_unchecked(&self, strides: &Ix3) -> isize { - stride_offset(self[0], get!(strides, 0)) + - stride_offset(self[1], get!(strides, 1)) + - stride_offset(self[2], get!(strides, 2)) + #[inline(always)] + fn index_unchecked(&self, strides: &IxDyn) -> isize { + debug_assert_eq!(strides.ndim(), 1); + stride_offset(*self, get!(strides, 0)) } } -unsafe impl NdIndex for [Ix; 4] { +unsafe impl NdIndex for Ix1 { #[inline] - fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option { - dim.stride_offset_checked(strides, &self.into_dimension()) + fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { + debug_assert_eq!(dim.ndim(), 1); + stride_offset_checked(dim.ix(), strides.ix(), self.ix()) } - #[inline] - fn index_unchecked(&self, strides: &Ix4) -> isize { - stride_offset(self[0], get!(strides, 0)) + - stride_offset(self[1], get!(strides, 1)) + - stride_offset(self[2], get!(strides, 2)) + - stride_offset(self[3], get!(strides, 3)) + - 0 + #[inline(always)] + fn index_unchecked(&self, strides: &IxDyn) -> isize { + debug_assert_eq!(strides.ndim(), 1); + stride_offset(get!(self, 0), get!(strides, 0)) } } -unsafe impl NdIndex for [Ix; 5] { - #[inline] - fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option { - dim.stride_offset_checked(strides, &self.into_dimension()) - } - #[inline] - fn index_unchecked(&self, strides: &Ix5) -> isize { - stride_offset(self[0], get!(strides, 0)) + - stride_offset(self[1], get!(strides, 1)) + - stride_offset(self[2], get!(strides, 2)) + - stride_offset(self[3], get!(strides, 3)) + - stride_offset(self[4], get!(strides, 4)) + - 0 - } +macro_rules! ndindex_with_array { + ($([$n:expr, $ix_n:ident $($index:tt)*])+) => { + $( + // implement NdIndex for [Ix; 2] and so on + unsafe impl NdIndex<$ix_n> for [Ix; $n] { + #[inline] + fn index_checked(&self, dim: &$ix_n, strides: &$ix_n) -> Option { + dim.stride_offset_checked(strides, &self.into_dimension()) + } + + #[inline] + fn index_unchecked(&self, strides: &$ix_n) -> isize { + $( + stride_offset(self[$index], get!(strides, $index)) + + )+ + 0 + } + } + + // implement NdIndex for Dim<[Ix; 2]> and so on + unsafe impl NdIndex for Dim<[Ix; $n]> { + #[inline] + fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { + debug_assert!(strides.ndim() == $n, + "Attempted to index with {:?} in array with {} axes", + self, strides.ndim()); + stride_offset_checked(dim.ix(), strides.ix(), self.ix()) + } + + #[inline] + fn index_unchecked(&self, strides: &IxDyn) -> isize { + debug_assert!(strides.ndim() == $n, + "Attempted to index with {:?} in array with {} axes", + self, strides.ndim()); + $( + stride_offset(get!(self, $index), get!(strides, $index)) + + )+ + 0 + } + } + + // implement NdIndex for [Ix; 2] and so on + unsafe impl NdIndex for [Ix; $n] { + #[inline] + fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { + debug_assert!(strides.ndim() == $n, + "Attempted to index with {:?} in array with {} axes", + self, strides.ndim()); + stride_offset_checked(dim.ix(), strides.ix(), self) + } + + #[inline] + fn index_unchecked(&self, strides: &IxDyn) -> isize { + debug_assert!(strides.ndim() == $n, + "Attempted to index with {:?} in array with {} axes", + self, strides.ndim()); + $( + stride_offset(self[$index], get!(strides, $index)) + + )+ + 0 + } + } + )+ + }; +} + +ndindex_with_array!{ + [2, Ix2 0 1] + [3, Ix3 0 1 2] + [4, Ix4 0 1 2 3] + [5, Ix5 0 1 2 3 4] + [6, Ix6 0 1 2 3 4 5] } impl<'a> IntoDimension for &'a [Ix] { @@ -172,14 +215,7 @@ impl<'a> IntoDimension for &'a [Ix] { unsafe impl<'a> NdIndex for &'a [Ix] { fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { - let mut offset = 0; - for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { - if i >= d { - return None; - } - offset += stride_offset(i, s); - } - Some(offset) + stride_offset_checked(dim.ix(), strides.ix(), *self) } fn index_unchecked(&self, strides: &IxDyn) -> isize { zip(strides.ix(), *self).map(|(&s, &i)| stride_offset(i, s)).sum() @@ -188,14 +224,7 @@ unsafe impl<'a> NdIndex for &'a [Ix] { unsafe impl NdIndex for Vec { fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { - let mut offset = 0; - for (&d, &i, &s) in zipsl(&dim[..], &self[..]).zip_cons(strides.slice()) { - if i >= d { - return None; - } - offset += stride_offset(i, s); - } - Some(offset) + stride_offset_checked(dim.ix(), strides.ix(), self) } fn index_unchecked(&self, strides: &IxDyn) -> isize { zip(strides.ix(), self).map(|(&s, &i)| stride_offset(i, s)).sum() diff --git a/tests/ixdyn.rs b/tests/ixdyn.rs new file mode 100644 index 000000000..b6d388867 --- /dev/null +++ b/tests/ixdyn.rs @@ -0,0 +1,60 @@ + +extern crate ndarray; + +use ndarray::Array; +use ndarray::Ix3; + +#[test] +fn test_ixdyn() { + // check that we can use fixed size arrays for indexing + let mut a = Array::zeros(vec![2, 3, 4]); + a[[1, 1, 1]] = 1.; + assert_eq!(a[[1, 1, 1]], 1.); +} + +#[should_panic] +#[test] +fn test_ixdyn_wrong_dim() { + // check that we can use but it panics at runtime, if number of axes is wrong + let mut a = Array::zeros(vec![2, 3, 4]); + a[[1, 1, 1]] = 1.; + + let _ = a[[0, 0]]; +} + +#[test] +fn test_ixdyn_out_of_bounds() { + // check that we are out of bounds + let a = Array::::zeros(vec![2, 3, 4]); + let res = a.get([0, 3, 0]); + assert_eq!(res, None); +} + +#[test] +fn test_ixdyn_uget() { + // check that we are out of bounds + let mut a = Array::::zeros(vec![2, 3, 4]); + + a[[1, 2, 0]] = 1.; + a[[1, 2, 1]] = 2.; + a[[1, 2, 3]] = 7.; + + let mut x = Ix3(1, 2, 0); + let step = Ix3(0, 0, 1); + let mut sum = 0.; + while let Some(&v) = a.get(x) { + sum += v; + x += step; + } + assert_eq!(sum, 10.); + + let mut x = Ix3(1, 2, 0); + let mut sum = 0.; + unsafe { + for _ in 0..4 { + sum += *a.uget(x); + x += step; + } + } + assert_eq!(sum, 10.); +} From da52cdb01484f95bffa7c8da3e5d56bd2203369f Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 01:17:09 +0100 Subject: [PATCH 092/107] Use simpler Debug impl for Dim --- src/dimension/dim.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/dimension/dim.rs b/src/dimension/dim.rs index 42012e6fc..63969b8dd 100644 --- a/src/dimension/dim.rs +++ b/src/dimension/dim.rs @@ -6,12 +6,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt; +use itertools::zip; + use super::IntoDimension; use super::Dimension; use Ix; -use itertools::zip; - /// Private constructor and accessors for Dim pub trait DimPrivate { fn new(index: I) -> Self; @@ -41,7 +42,7 @@ pub trait DimPrivate { /// array[[0, 0]] = 1.; /// assert_eq!(array.dim(), Dim([3, 2])); /// ``` -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Default)] pub struct Dim { index: I, } @@ -72,6 +73,14 @@ impl PartialEq for Dim } } +impl fmt::Debug for Dim + where I: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.index) + } +} + use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; macro_rules! impl_op { From 3d90cc285bb116214051ff6baf4f1401fa62bd2e Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 01:22:26 +0100 Subject: [PATCH 093/107] .travis: Test only beta for now (Requires Rust 1.13) --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index eee94920e..d7bef6db8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,6 @@ sudo: required dist: trusty matrix: include: - - rust: stable - env: - - FEATURES='test' - rust: beta env: - FEATURES='test' From 45faa492e8e13afc3ab59c4d50fb7b68e4ccd11f Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 01:42:24 +0100 Subject: [PATCH 094/107] Fix serde support for Dim migration --- src/array_serde.rs | 26 +++++++++++++++++++++++++- tests/serialize.rs | 25 +++++++++++++------------ 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/array_serde.rs b/src/array_serde.rs index 8aef08d6a..89adcd9d2 100644 --- a/src/array_serde.rs +++ b/src/array_serde.rs @@ -7,12 +7,36 @@ // except according to those terms. use serde::{self, Serialize, Deserialize}; +use std::marker::PhantomData; + use imp_prelude::*; use super::arraytraits::ARRAY_FORMAT_VERSION; use super::Elements; +use Dim; +use dimension::DimPrivate; -use std::marker::PhantomData; +/// **Requires crate feature `"serde"`** +impl Serialize for Dim + where I: Serialize, +{ + fn serialize(&self, serializer: &mut Se) -> Result<(), Se::Error> + where Se: serde::Serializer + { + self.ix().serialize(serializer) + } +} + +/// **Requires crate feature `"serde"`** +impl Deserialize for Dim + where I: Deserialize, +{ + fn deserialize(deserializer: &mut D) -> Result + where D: serde::de::Deserializer + { + I::deserialize(deserializer).map(Dim::new) + } +} /// **Requires crate feature `"serde"`** impl Serialize for ArrayBase diff --git a/tests/serialize.rs b/tests/serialize.rs index 0b5153654..92494f1d4 100644 --- a/tests/serialize.rs +++ b/tests/serialize.rs @@ -1,7 +1,8 @@ #![cfg(any(feature = "rustc-serialize", feature = "serde"))] #[cfg(feature = "rustc-serialize")] extern crate rustc_serialize as serialize; -extern crate ndarray; + +#[macro_use] extern crate ndarray; #[cfg(feature = "serde")] extern crate serde; @@ -12,7 +13,7 @@ extern crate serde_json; #[cfg(feature = "rustc-serialize")] use serialize::json; -use ndarray::{arr0, arr1, arr2, RcArray, Ix, S, Si}; +use ndarray::{arr0, arr1, arr2, RcArray, RcArray1, RcArray2}; #[cfg(feature = "rustc-serialize")] #[test] @@ -44,7 +45,7 @@ fn serial_many_dim() println!("{:?}", res); assert_eq!(a, res.unwrap()); let text = r##"{"v":1,"dim":[2,3],"data":[3,1,2.2,3.1,4,7]}"##; - let b = json::decode::>(text); + let b = json::decode::>(text); assert_eq!(a, b.unwrap()); } @@ -52,7 +53,7 @@ fn serial_many_dim() { // Test a sliced array. let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4)); - a.islice(&[Si(0, None, -1), S, S, Si(0, Some(2), 1)]); + a.islice(s![..;-1, .., .., ..2]); let serial = json::encode(&a).unwrap(); println!("Encode {:?} => {:?}", a, serial); let res = json::decode::>(&serial); @@ -67,13 +68,13 @@ fn serial_wrong_count() { // one element too few let text = r##"{"v":1,"dim":[2,3],"data":[3,1,2.2,3.1,4]}"##; - let arr = json::decode::>(text); + let arr = json::decode::>(text); println!("{:?}", arr); assert!(arr.is_err()); // future version let text = r##"{"v":200,"dim":[2,3],"data":[3,1,2.2,3.1,4,7]}"##; - let arr = json::decode::>(text); + let arr = json::decode::>(text); println!("{:?}", arr); assert!(arr.is_err()); } @@ -95,7 +96,7 @@ fn serial_many_dim_serde() let a = arr1::(&[2.72, 1., 2.]); let serial = serde_json::to_string(&a).unwrap(); println!("Serde encode {:?} => {:?}", a, serial); - let res = serde_json::from_str::>(&serial); + let res = serde_json::from_str::>(&serial); println!("{:?}", res); assert_eq!(a, res.unwrap()); } @@ -104,18 +105,18 @@ fn serial_many_dim_serde() let a = arr2(&[[3., 1., 2.2], [3.1, 4., 7.]]); let serial = serde_json::to_string(&a).unwrap(); println!("Serde encode {:?} => {:?}", a, serial); - let res = serde_json::from_str::>(&serial); + let res = serde_json::from_str::>(&serial); println!("{:?}", res); assert_eq!(a, res.unwrap()); let text = r##"{"v":1,"dim":[2,3],"data":[3,1,2.2,3.1,4,7]}"##; - let b = serde_json::from_str::>(text); + let b = serde_json::from_str::>(text); assert_eq!(a, b.unwrap()); } { // Test a sliced array. let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4)); - a.islice(&[Si(0, None, -1), S, S, Si(0, Some(2), 1)]); + a.islice(s![..;-1, .., .., ..2]); let serial = serde_json::to_string(&a).unwrap(); println!("Encode {:?} => {:?}", a, serial); let res = serde_json::from_str::>(&serial); @@ -130,13 +131,13 @@ fn serial_wrong_count_serde() { // one element too few let text = r##"{"v":1,"dim":[2,3],"data":[3,1,2.2,3.1,4]}"##; - let arr = serde_json::from_str::>(text); + let arr = serde_json::from_str::>(text); println!("{:?}", arr); assert!(arr.is_err()); // future version let text = r##"{"v":200,"dim":[2,3],"data":[3,1,2.2,3.1,4,7]}"##; - let arr = serde_json::from_str::>(text); + let arr = serde_json::from_str::>(text); println!("{:?}", arr); assert!(arr.is_err()); } From 73f1ec8ce47688c1bf315f1391db2db09a0083c2 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 01:57:39 +0100 Subject: [PATCH 095/107] Fix rustc-serialize support for Dim migration --- src/array_serialize.rs | 23 ++++++++++++++++++++++- tests/serialize.rs | 6 ++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/array_serialize.rs b/src/array_serialize.rs index 600039347..5f0676ea4 100644 --- a/src/array_serialize.rs +++ b/src/array_serialize.rs @@ -11,6 +11,27 @@ use super::arraytraits::ARRAY_FORMAT_VERSION; use imp_prelude::*; +use Dim; +use dimension::DimPrivate; + +/// **Requires crate feature `"rustc-serialize"`** +impl Encodable for Dim + where I: Encodable, +{ + fn encode(&self, s: &mut E) -> Result<(), E::Error> { + self.ix().encode(s) + } +} + +/// **Requires crate feature `"rustc-serialize"`** +impl Decodable for Dim + where I: Decodable, +{ + fn decode(d: &mut E) -> Result { + I::decode(d).map(Dim::new) + } +} + /// **Requires crate feature `"rustc-serialize"`** impl Encodable for ArrayBase where A: Encodable, @@ -43,7 +64,7 @@ impl Decodable for ArrayBase D: Dimension + Decodable, S: DataOwned { - fn decode(d: &mut E) -> Result, E::Error> { + fn decode(d: &mut E) -> Result { d.read_struct("Array", 3, |d| { let version: u8 = try!(d.read_struct_field("v", 0, Decodable::decode)); if version > ARRAY_FORMAT_VERSION { diff --git a/tests/serialize.rs b/tests/serialize.rs index 92494f1d4..155b25951 100644 --- a/tests/serialize.rs +++ b/tests/serialize.rs @@ -19,6 +19,7 @@ use ndarray::{arr0, arr1, arr2, RcArray, RcArray1, RcArray2}; #[test] fn serial_many_dim() { + /* rustc-serialize does not support serializing [T; 0] { let a = arr0::(2.72); let serial = json::encode(&a).unwrap(); @@ -27,12 +28,13 @@ fn serial_many_dim() println!("{:?}", res); assert_eq!(a, res.unwrap()); } + */ { let a = arr1::(&[2.72, 1., 2.]); let serial = json::encode(&a).unwrap(); println!("Encode {:?} => {:?}", a, serial); - let res = json::decode::>(&serial); + let res = json::decode::>(&serial); println!("{:?}", res); assert_eq!(a, res.unwrap()); } @@ -41,7 +43,7 @@ fn serial_many_dim() let a = arr2(&[[3., 1., 2.2], [3.1, 4., 7.]]); let serial = json::encode(&a).unwrap(); println!("Encode {:?} => {:?}", a, serial); - let res = json::decode::>(&serial); + let res = json::decode::>(&serial); println!("{:?}", res); assert_eq!(a, res.unwrap()); let text = r##"{"v":1,"dim":[2,3],"data":[3,1,2.2,3.1,4,7]}"##; From c96693b896355151e9d515bd8e0f2688124a69d1 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 04:25:08 +0100 Subject: [PATCH 096/107] Ensure DimPrivate is not exported --- src/dimension/dim.rs | 8 +------- src/dimension/mod.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/dimension/dim.rs b/src/dimension/dim.rs index 63969b8dd..051ff53a0 100644 --- a/src/dimension/dim.rs +++ b/src/dimension/dim.rs @@ -11,15 +11,9 @@ use itertools::zip; use super::IntoDimension; use super::Dimension; +use super::DimPrivate; use Ix; -/// Private constructor and accessors for Dim -pub trait DimPrivate { - fn new(index: I) -> Self; - fn ix(&self) -> &I; - fn ixm(&mut self) -> &mut I; -} - /// Dimension description. /// /// `Dim` describes the number of axes and the length of each axis diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index cf14d1801..a80651335 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -10,7 +10,7 @@ use {Ix, Ixs}; use error::{from_kind, ErrorKind, ShapeError}; use {zipsl, ZipExt}; -pub use self::dim::{Dim, DimPrivate}; +pub use self::dim::*; pub use self::axis::Axis; pub use self::conversion::IntoDimension; pub use self::dimension_trait::Dimension; @@ -25,6 +25,13 @@ mod dimension_trait; mod ndindex; mod remove_axis; +/// Private constructor and accessors for Dim +pub trait DimPrivate { + fn new(index: I) -> Self; + fn ix(&self) -> &I; + fn ixm(&mut self) -> &mut I; +} + /// Calculate offset from `Ix` stride converting sign properly #[inline(always)] pub fn stride_offset(n: Ix, stride: Ix) -> isize { From 238784b62ffca7bd14a8d432c11ac1f326b04078 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 04:38:51 +0100 Subject: [PATCH 097/107] Fix unused import warning --- tests/oper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/oper.rs b/tests/oper.rs index 2c00110d3..fbf36cce4 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -6,7 +6,7 @@ use ndarray::{arr0, rcarr1, rcarr2}; use ndarray::{LinalgScalar, Data}; use ndarray::linalg::general_mat_mul; use ndarray::Array2; -use ndarray::{Ix1, Ix2}; +use ndarray::Ix2; use std::fmt; use num_traits::Float; From d02606701bcfd546e50d74f1aa96a32f5b1b1d77 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 11:29:40 +0100 Subject: [PATCH 098/107] Edit link to array view methods --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e38688dbf..2a86dca14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -437,7 +437,7 @@ pub type OwnedArray = ArrayBase, D>; /// /// Array views have all the methods of an array (see [`ArrayBase`][ab]). /// -/// See also specific [**Methods for Array Views**](struct.ArrayBase.html#methods-for-array-views). +/// See also [**Methods Specific To Array Views**](struct.ArrayBase.html#methods-specific-to-array-views) /// /// [ab]: struct.ArrayBase.html pub type ArrayView<'a, A, D> = ArrayBase, D>; @@ -448,7 +448,7 @@ pub type ArrayView<'a, A, D> = ArrayBase, D>; /// /// Array views have all the methods of an array (see [`ArrayBase`][ab]). /// -/// See also specific [**Methods for Array Views**](struct.ArrayBase.html#methods-for-array-views). +/// See also [**Methods Specific To Array Views**](struct.ArrayBase.html#methods-specific-to-array-views) /// /// [ab]: struct.ArrayBase.html pub type ArrayViewMut<'a, A, D> = ArrayBase, D>; From 4f8847e527c7c4039fdc4b06255efab9de166657 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 12:59:09 +0100 Subject: [PATCH 099/107] Simplify DimensionExt --- src/dimension/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index a80651335..86339e7cb 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -174,12 +174,12 @@ impl DimensionExt for D { #[inline] fn axis(&self, axis: Axis) -> Ix { - self.slice()[axis.axis()] + self[axis.axis()] } #[inline] fn set_axis(&mut self, axis: Axis, value: Ix) { - self.slice_mut()[axis.axis()] = value; + self[axis.axis()] = value; } } From 9832287ffc638d0af437633a3f0d1ea93f7ff34b Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 12:29:43 +0100 Subject: [PATCH 100/107] Edit dimension docs --- src/lib.rs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2a86dca14..f4f69a0bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -217,29 +217,36 @@ pub type Ixs = isize; /// /// ## Indexing and Dimension /// -/// Array indexes are represented by the types `Ix` and `Ixs` (signed). -/// /// The dimensionality of the array determines the number of *axes*, for example /// a 2D array has two axes. These are listed in “big endian” order, so that /// the greatest dimension is listed first, the lowest dimension with the most /// rapidly varying index is the last. /// -/// In a 2D array the index of each element is `(row, column)` -/// as seen in this 3 × 3 example: +/// In a 2D array the index of each element is `[row, column]` as seen in this +/// 4 × 3 example: /// /// ```ignore -/// [[ (0, 0), (0, 1), (0, 2)], // row 0 -/// [ (1, 0), (1, 1), (1, 2)], // row 1 -/// [ (2, 0), (2, 1), (2, 2)]] // row 2 +/// [[ [0, 0], [0, 1], [0, 2] ], // row 0 +/// [ [1, 0], [1, 1], [1, 2] ], // row 1 +/// [ [2, 0], [2, 1], [2, 2] ], // row 2 +/// [ [3, 0], [3, 1], [3, 2] ]] // row 3 /// // \ \ \ /// // column 0 \ column 2 /// // column 1 /// ``` /// -/// The number of axes for an array is fixed by the `D` parameter: `Ix` for -/// a 1D array, `(Ix, Ix)` for a 2D array etc. The `D` type is also used -/// for element indices in `.get()` and `array[index]`. The dimension type `Vec` -/// allows a dynamic number of axes. +/// The number of axes for an array is fixed by its `D` type parameter: `Ix1` +/// for a 1D array, `Ix2` for a 2D array etc. The dimension type `IxDyn` allows +/// a dynamic number of axes. +/// +/// An array of the corresponding dimensionality is used to index the array, +/// making the syntax `array[[` i, j, ...`]]` +/// +/// ``` +/// use ndarray::Array2; +/// let mut array = Array2::zeros((4, 3)); +/// array[[1, 1]] = 7; +/// ``` /// /// The default memory order of an array is *row major* order (a.k.a “c” order), /// where each row is contiguous in memory. From 4dc8aa213565fed75b159d7c21e353921d6508b9 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 13:42:14 +0100 Subject: [PATCH 101/107] Edit docs --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f4f69a0bc..84051cd1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,8 +239,8 @@ pub type Ixs = isize; /// for a 1D array, `Ix2` for a 2D array etc. The dimension type `IxDyn` allows /// a dynamic number of axes. /// -/// An array of the corresponding dimensionality is used to index the array, -/// making the syntax `array[[` i, j, ...`]]` +/// A fixed size array (`[usize; N]`) of the corresponding dimensionality is +/// used to index the `Array`, making the syntax `array[[` i, j, ...`]]` /// /// ``` /// use ndarray::Array2; From 1120b5653d917207c5f2af51426e3fcf1f55ad16 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 13:55:09 +0100 Subject: [PATCH 102/107] Improve basic docs for array, array views --- src/lib.rs | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 84051cd1a..418c121b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,7 +192,9 @@ pub type Ixs = isize; /// /// ## Contents /// -/// + [Array and RcArray](#ownedarray-and-rcarray) +/// + [Array](#array) +/// + [RcArray](#rcarray) +/// + [Array Views](#array-views) /// + [Indexing and Dimension](#indexing-and-dimension) /// + [Slicing](#slicing) /// + [Subviews](#subviews) @@ -202,16 +204,51 @@ pub type Ixs = isize; /// + [Methods For All Array Types](#methods-for-all-array-types) /// + [Methods Specific to Array Views](#methods-specific-to-array-views) /// -/// ## `Array` and `RcArray` /// -/// `Array` owns the underlying array elements directly (just like -/// a `Vec`), while [`RcArray`](type.RcArray.html) is a an array with reference -/// counted data. `RcArray` can act both as an owner or as a view in that regard. +/// +/// +/// ## `Array` +/// +/// [`Array`](type.Array.html) is an owned array that ows the underlying array +/// elements directly (just like a `Vec`) and it is the default way to create and +/// store n-dimensional data. `Array` has two type parameters: `A` for +/// the element type, and `D` for the dimensionality. A particular +/// dimensionality's type alias like `Array3` just has the type parameter +/// `A` for element type. +/// +/// An example: +/// +/// ``` +/// // Create a three-dimensional f64 array, initialized with zeros +/// use ndarray::Array3; +/// let mut temperature = Array3::::zeros((3, 4, 5)); +/// // Increase the temperature in this location +/// temperature[[2, 2, 2]] += 0.5; +/// ``` +/// +/// ## `RcArray` +/// +/// [`RcArray`](type.RcArray.html) is an owned array with reference counted +/// data (shared ownership). /// Sharing requires that it uses copy-on-write for mutable operations. /// Calling a method for mutating elements on `RcArray`, for example /// [`view_mut()`](#method.view_mut) or [`get_mut()`](#method.get_mut), /// will break sharing and require a clone of the data (if it is not uniquely held). /// +/// ## Array Views +/// +/// `ArrayView` and `ArrayViewMut` are read-only and read-write array views +/// respectively. They use dimensionality, indexing, and almost all other +/// methods the same was as the other array types. +/// +/// A view is created from an array using `.view()`, `.view_mut()`, using +/// slicing (`.slice()`, `.slice_mut()`) or from one of the many iterators +/// that yield array views. +/// +/// You can also create an array view from a regular slice of data not +/// allocated with `Array` — see [Methods Specific to Array +/// Views](#methods-specific-to-array-views). +/// /// Note that all `ArrayBase` variants can change their view (slicing) of the /// data freely, even when their data can’t be mutated. /// From 6afabb0966b6984e374344dec7966c69dcc7b97d Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 15:44:46 +0100 Subject: [PATCH 103/107] Improve docs for indexing / Dimension --- src/dimension/dim.rs | 4 ++-- src/dimension/dimension_trait.rs | 5 +++-- src/lib.rs | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/dimension/dim.rs b/src/dimension/dim.rs index 051ff53a0..fb8b9b47c 100644 --- a/src/dimension/dim.rs +++ b/src/dimension/dim.rs @@ -19,8 +19,8 @@ use Ix; /// `Dim` describes the number of axes and the length of each axis /// in an array. It is also used as an index type. /// -/// The commonly you want to use the methods of the `Dimension` trait. See its -/// documentation for more information. +/// See also the [`Dimension` trait](Dimension.t.html) for its methods and +/// operations. /// /// # Examples /// diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index f4107676c..3c75ff0c3 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -26,9 +26,10 @@ use super::conversion::Convert; /// Array shape and index trait. /// -/// `unsafe` because of the assumptions in the default methods. +/// This trait defines a number of methods and operations that can be used on +/// dimensions and indices. /// -/// ***Don't implement this trait, it will evolve at will.*** +/// ***Note:*** *Don't implement this trait.* pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + IndexMut + Add + diff --git a/src/lib.rs b/src/lib.rs index 418c121b2..eb5e25267 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -285,6 +285,20 @@ pub type Ixs = isize; /// array[[1, 1]] = 7; /// ``` /// +/// Important traits and types for dimension and indexing: +/// +/// - A [`Dim`](Dim.t.html) value represents a dimensionality or index. +/// - Trait [`Dimension`](Dimension.t.html) is implemented by all +/// dimensionalities. It defines many operations for dimensions and indices. +/// - Trait [`IntoDimension`](IntoDimension.t.html) is used to convert into a +/// `Dim` value. +/// - Trait [`ShapeBuilder`](ShapeBuilder.t.html) is an extension of +/// `IntoDimension` and is used when constructing an array. A shape describes +/// not just the extent of each axis but also their strides. +/// - Trait [`NdIndex`](NdIndex.t.html) is an extension of `Dimension` and is +/// for values that can be used with indexing syntax. +/// +/// /// The default memory order of an array is *row major* order (a.k.a “c” order), /// where each row is contiguous in memory. /// A *column major* (a.k.a. “f” or fortran) memory order array has From 0929ea515796699824c4ed45c78e0ae182c1e74d Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 22:40:52 +0100 Subject: [PATCH 104/107] Update axis_iter image --- docgen/images/axis_iter.svg | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docgen/images/axis_iter.svg b/docgen/images/axis_iter.svg index ecb73209f..ea4157b0e 100644 --- a/docgen/images/axis_iter.svg +++ b/docgen/images/axis_iter.svg @@ -96,7 +96,7 @@ image/svg+xml - + @@ -737,11 +737,11 @@ sodipodi:role="line" x="602.84332" y="185.57912" - id="tspan8614-6">Input shape: (3, 5, 5)Input shape: (3, 4, 5)Output shapes: (3, 5) + id="tspan8640">Output shapes: (3, 4) 4 + From d8f756ed77c779c089409abfa9ecc8788a5d79ef Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 7 Nov 2016 22:43:01 +0100 Subject: [PATCH 105/107] Use 3 x 4 x 5 axis_iter illustration --- src/impl_methods.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index c912d2791..1c117870d 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -524,9 +524,9 @@ impl ArrayBase where S: Data, D: Dimension /// Return an iterator that traverses over `axis` /// and yields each subview along it. /// - /// For example, in a 3 × 5 × 5 array, with `axis` equal to `Axis(2)`, + /// For example, in a 3 × 4 × 5 array, with `axis` equal to `Axis(2)`, /// the iterator element - /// is a 3 × 5 subview (and there are 5 in total), as shown + /// is a 3 × 4 subview (and there are 5 in total), as shown /// in the picture below. /// /// Iterator element is `ArrayView` (read-only array view). @@ -535,7 +535,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if `axis` is out of bounds. /// - /// + /// pub fn axis_iter(&self, axis: Axis) -> AxisIter where D: RemoveAxis, { From db152464d362e56f06289a9be3aad95af63a68d1 Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 8 Nov 2016 01:09:32 +0100 Subject: [PATCH 106/107] Avoid using macros in type position --- src/dimension/conversion.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/dimension/conversion.rs b/src/dimension/conversion.rs index 9ef29d22c..9da9f34a1 100644 --- a/src/dimension/conversion.rs +++ b/src/dimension/conversion.rs @@ -27,8 +27,19 @@ macro_rules! index { ($m:ident $arg:tt 7) => ($m!($arg 0 1 2 3 4 5 6)); } +macro_rules! index_item_ix { + ($m:ident $arg:tt 0) => ($m!($arg);); + ($m:ident $arg:tt 1) => ($m!($arg Ix);); + ($m:ident $arg:tt 2) => ($m!($arg Ix Ix);); + ($m:ident $arg:tt 3) => ($m!($arg Ix Ix Ix);); + ($m:ident $arg:tt 4) => ($m!($arg Ix Ix Ix Ix);); + ($m:ident $arg:tt 5) => ($m!($arg Ix Ix Ix Ix Ix);); + ($m:ident $arg:tt 6) => ($m!($arg Ix Ix Ix Ix Ix Ix);); + ($m:ident $arg:tt 7) => ($m!($arg Ix Ix Ix Ix Ix Ix Ix);); +} + macro_rules! index_item { - ($m:ident $arg:tt 0) => (); + ($m:ident $arg:tt 0) => ($m!($arg);); ($m:ident $arg:tt 1) => ($m!($arg 0);); ($m:ident $arg:tt 2) => ($m!($arg 0 1);); ($m:ident $arg:tt 3) => ($m!($arg 0 1 2);); @@ -98,8 +109,14 @@ macro_rules! array_zero { macro_rules! tuple_to_array { ([] $($n:tt)*) => { $( + index_item_ix!(impl_tuple_to_array [$n] $n); + )* + } +} +macro_rules! impl_tuple_to_array { + ([$n:tt] $($ix:tt)*) => { impl Convert for [Ix; $n] { - type To = index!(tuple_type [Ix] $n); + type To = ($($ix ,)*); fn convert(self) -> Self::To { index!(tuple_expr [self] $n) } @@ -113,7 +130,7 @@ macro_rules! tuple_to_array { } } - impl IntoDimension for index!(tuple_type [Ix] $n) { + impl IntoDimension for ($($ix ,)*) { type Dim = Dim<[Ix; $n]>; #[inline(always)] fn into_dimension(self) -> Self::Dim { @@ -145,8 +162,6 @@ macro_rules! tuple_to_array { self.slice().iter().all(|x| *x == 0) } } - - )* } } From e5f4986919543b83af5d4ec746880b6fb371fb4b Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 8 Nov 2016 01:10:24 +0100 Subject: [PATCH 107/107] .travis: Test stable again --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index d7bef6db8..eee94920e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,9 @@ sudo: required dist: trusty matrix: include: + - rust: stable + env: + - FEATURES='test' - rust: beta env: - FEATURES='test'