From 0fa79a52491b523cf8ef1ea309eb09161f588b81 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 01/12] ixdyn: Implement short-dimension optimization for IxDyn This means that low-dimensional IxDyn are stored inline and don't need an allocation for creation and cloning. --- src/aliases.rs | 11 +- src/dimension/conversion.rs | 10 +- src/dimension/dimension_trait.rs | 18 ++-- src/dimension/dynindeximpl.rs | 180 +++++++++++++++++++++++++++++++ src/dimension/mod.rs | 2 + src/dimension/ndindex.rs | 9 +- src/dimension/remove_axis.rs | 3 +- src/lib.rs | 1 + 8 files changed, 217 insertions(+), 17 deletions(-) create mode 100644 src/dimension/dynindeximpl.rs diff --git a/src/aliases.rs b/src/aliases.rs index 759b2039f..2651bcddf 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -1,7 +1,14 @@ //! Type aliases for common array sizes //! -use ::{Ix, Array, ArrayView, ArrayViewMut, RcArray}; +use ::{ + Ix, + Array, + ArrayView, + ArrayViewMut, + RcArray, + IxDynImpl, +}; use ::dimension::Dim; use dimension::DimPrivate; @@ -78,7 +85,7 @@ pub type Ix6 = Dim<[Ix; 6]>; /// // the same type `Array` a.k.a `ArrayD`: /// let arrays = vec![a, b]; /// ``` -pub type IxDyn = Dim>; +pub type IxDyn = Dim; /// zero-dimensional array pub type Array0 = Array; diff --git a/src/dimension/conversion.rs b/src/dimension/conversion.rs index edddf1e42..98f8e3bc8 100644 --- a/src/dimension/conversion.rs +++ b/src/dimension/conversion.rs @@ -11,7 +11,7 @@ use std::ops::{Index, IndexMut}; use libnum::Zero; -use {Ix, Ix1, IxDyn, Dimension, Dim}; +use {Ix, Ix1, IxDyn, Dimension, Dim, IxDynImpl}; use super::DimPrivate; /// $m: macro callback @@ -56,12 +56,18 @@ impl IntoDimension for D where D: Dimension { fn into_dimension(self) -> Self { self } } -impl IntoDimension for Vec { +impl IntoDimension for IxDynImpl { type Dim = IxDyn; #[inline(always)] fn into_dimension(self) -> Self::Dim { Dim::new(self) } } +impl IntoDimension for Vec { + type Dim = IxDyn; + #[inline(always)] + fn into_dimension(self) -> Self::Dim { Dim::new(IxDynImpl::from(self)) } +} + pub trait Convert { type To; fn convert(self) -> Self::To; diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index e3cdefe1b..0251f13e0 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -13,7 +13,7 @@ use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; use itertools::{enumerate, zip}; -use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, IxDyn, Dim, Si}; +use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, IxDyn, Dim, Si, IxDynImpl}; use IntoDimension; use RemoveAxis; use {ArrayView1, ArrayViewMut1}; @@ -53,7 +53,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + /// - For `Ix1`: `[Si; 1]` /// - For `Ix2`: `[Si; 2]` /// - and so on.. - /// - For `Vec`: `[Si]` + /// - For `IxDyn: `[Si]` /// /// The easiest way to create a `&SliceArg` is using the macro /// [`s![]`](macro.s!.html). @@ -63,7 +63,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default + /// - For `Ix1`: `usize`, /// - For `Ix2`: `(usize, usize)` /// - and so on.. - /// - For `Vec`: `Vec`, + /// - For `IxDyn: `IxDyn` type Pattern: IntoDimension; // Next smaller dimension (if it exists) #[doc(hidden)] @@ -734,7 +734,7 @@ 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, +/// IxDyn 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 { @@ -761,17 +761,17 @@ unsafe impl Dimension for IxDyn } } -impl Index for Dim> - where Vec: Index, +impl Index for Dim + where IxDynImpl: Index, { - type Output = as Index>::Output; + type Output = >::Output; fn index(&self, index: J) -> &Self::Output { &self.ix()[index] } } -impl IndexMut for Dim> - where Vec: IndexMut, +impl IndexMut for Dim + where IxDynImpl: IndexMut, { fn index_mut(&mut self, index: J) -> &mut Self::Output { &mut self.ixm()[index] diff --git a/src/dimension/dynindeximpl.rs b/src/dimension/dynindeximpl.rs new file mode 100644 index 000000000..0d71c0048 --- /dev/null +++ b/src/dimension/dynindeximpl.rs @@ -0,0 +1,180 @@ + +use std::ops::{ + Index, + IndexMut, + Deref, + DerefMut, +}; +use imp_prelude::*; + +const CAP: usize = 4; + +/// T is usize or isize +#[derive(Debug)] +enum IxDynRepr { + Inline(u32, [T; CAP]), + Alloc(Box<[T]>), +} + +impl Deref for IxDynRepr { + type Target = [T]; + fn deref(&self) -> &[T] { + match *self { + IxDynRepr::Inline(len, ref ar) => { + unsafe { + ar.get_unchecked(..len as usize) + } + } + IxDynRepr::Alloc(ref ar) => &*ar, + } + } +} + +impl DerefMut for IxDynRepr { + fn deref_mut(&mut self) -> &mut [T] { + match *self { + IxDynRepr::Inline(len, ref mut ar) => { + unsafe { + ar.get_unchecked_mut(..len as usize) + } + } + IxDynRepr::Alloc(ref mut ar) => &mut *ar, + } + } +} + +impl Default for IxDynRepr { + fn default() -> Self { + Self::copy_from(&[0]) + } +} + + +use ::libnum::Zero; + +impl IxDynRepr { + pub fn copy_from(x: &[T]) -> Self { + if x.len() <= CAP { + let mut arr = [T::zero(); CAP]; + for i in 0..x.len() { + arr[i] = x[i]; + } + IxDynRepr::Inline(x.len() as _, arr) + } else { + Self::from(x) + } + } +} + +impl IxDynRepr { + // make an Inline or Alloc version as appropriate + fn from_vec_auto(v: Vec) -> Self { + if v.len() <= CAP { + Self::copy_from(&v) + } else { + Self::from_vec(v) + } + } +} + +impl IxDynRepr { + fn from_vec(v: Vec) -> Self { + IxDynRepr::Alloc(v.into_boxed_slice()) + } + + fn from(x: &[T]) -> Self { + Self::from_vec(x.to_vec()) + } +} + +impl Clone for IxDynRepr { + fn clone(&self) -> Self { + match *self { + IxDynRepr::Inline(len, arr) => { + IxDynRepr::Inline(len, arr) + } + _ => Self::from(&self[..]) + } + } +} + +impl Eq for IxDynRepr { } + +impl PartialEq for IxDynRepr { + fn eq(&self, rhs: &Self) -> bool { + match (self, rhs) { + (&IxDynRepr::Inline(slen, ref sarr), &IxDynRepr::Inline(rlen, ref rarr)) => { + slen == rlen && + (0..CAP as usize).filter(|&i| i < slen as usize) + .all(|i| sarr[i] == rarr[i]) + } + _ => self[..] == rhs[..] + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct IxDynImpl(IxDynRepr); +unsafe impl Send for IxDynImpl {} +unsafe impl Sync for IxDynImpl {} + +impl IxDynImpl { + pub fn remove(&mut self, i: usize) { + unimplemented!() + } +} + +impl<'a> From<&'a [Ix]> for IxDynImpl { + #[inline] + fn from(ix: &'a [Ix]) -> Self { + IxDynImpl(IxDynRepr::copy_from(ix)) + } +} + +impl From> for IxDynImpl { + #[inline] + fn from(ix: Vec) -> Self { + IxDynImpl(IxDynRepr::from_vec_auto(ix)) + } +} + +impl Index for IxDynImpl + where [Ix]: Index, +{ + type Output = <[Ix] as Index>::Output; + fn index(&self, index: J) -> &Self::Output { + &self.0[index] + } +} + +impl IndexMut for IxDynImpl + where [Ix]: IndexMut, +{ + fn index_mut(&mut self, index: J) -> &mut Self::Output { + &mut self.0[index] + } +} + +impl Deref for IxDynImpl { + type Target = [Ix]; + #[inline] + fn deref(&self) -> &[Ix] { + &self.0 + } +} + +impl DerefMut for IxDynImpl { + #[inline] + fn deref_mut(&mut self) -> &mut [Ix] { + &mut self.0 + } +} + +impl<'a> IntoIterator for &'a IxDynImpl { + type Item = &'a Ix; + type IntoIter = <&'a [Ix] as IntoIterator>::IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + self[..].into_iter() + } +} diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index a7e16f87c..ed914e57a 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -17,12 +17,14 @@ pub use self::dimension_trait::Dimension; pub use self::ndindex::NdIndex; pub use self::remove_axis::RemoveAxis; pub use self::axes::{axes_of, Axes, AxisDescription}; +pub use self::dynindeximpl::IxDynImpl; #[macro_use] mod macros; mod axis; mod conversion; pub mod dim; mod dimension_trait; +mod dynindeximpl; mod ndindex; mod remove_axis; mod axes; diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs index eeea5b29a..82042f631 100644 --- a/src/dimension/ndindex.rs +++ b/src/dimension/ndindex.rs @@ -4,6 +4,9 @@ use std::fmt::Debug; use itertools::zip; use {Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Dimension, IntoDimension}; +use { + IxDynImpl, +}; use super::{stride_offset, stride_offset_checked}; use super::DimPrivate; @@ -194,9 +197,9 @@ ndindex_with_array!{ } impl<'a> IntoDimension for &'a [Ix] { - type Dim = Dim>; + type Dim = IxDyn; fn into_dimension(self) -> Self::Dim { - Dim(self.to_vec()) + Dim(IxDynImpl::from(self)) } } @@ -209,7 +212,7 @@ unsafe impl<'a> NdIndex for &'a [Ix] { } } -unsafe impl NdIndex for Vec { +unsafe impl NdIndex for IxDynImpl { fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { stride_offset_checked(dim.ix(), strides.ix(), self) } diff --git a/src/dimension/remove_axis.rs b/src/dimension/remove_axis.rs index 824c5b21a..5a6f57755 100644 --- a/src/dimension/remove_axis.rs +++ b/src/dimension/remove_axis.rs @@ -8,6 +8,7 @@ use {Ix, Ix0, Ix1, Dimension, Dim, Axis}; +use IxDyn; use super::DimPrivate; /// Array shape with a next smaller dimension. @@ -66,7 +67,7 @@ macro_rules! impl_remove_axis_array( impl_remove_axis_array!(3, 4, 5, 6); -impl RemoveAxis for Dim> { +impl RemoveAxis for IxDyn { type Smaller = Self; fn remove_axis(&self, axis: Axis) -> Self { let mut res = self.clone(); diff --git a/src/lib.rs b/src/lib.rs index 37c314663..7b1611792 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,6 +94,7 @@ pub use dimension::{ pub use dimension::dim::*; pub use dimension::NdIndex; +pub use dimension::IxDynImpl; pub use indexes::Indices; pub use indexes::{indices, indices_of}; pub use error::{ShapeError, ErrorKind}; From cefc3b763aebcd295d111a199b12da3200e24c40 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 02/12] ixdyn: Implement zero-dim indexing for IxDyn (Enables indexing a zero dimensional dynamic dimension array using array[[]], array[()], array[Ix0()]) --- src/dimension/ndindex.rs | 11 ++++----- tests/ixdyn.rs | 48 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs index 82042f631..a33ac37e9 100644 --- a/src/dimension/ndindex.rs +++ b/src/dimension/ndindex.rs @@ -132,10 +132,10 @@ macro_rules! ndindex_with_array { } #[inline] - fn index_unchecked(&self, strides: &$ix_n) -> isize { + fn index_unchecked(&self, _strides: &$ix_n) -> isize { $( - stride_offset(self[$index], get!(strides, $index)) + - )+ + stride_offset(self[$index], get!(_strides, $index)) + + )* 0 } } @@ -157,7 +157,7 @@ macro_rules! ndindex_with_array { self, strides.ndim()); $( stride_offset(get!(self, $index), get!(strides, $index)) + - )+ + )* 0 } } @@ -179,7 +179,7 @@ macro_rules! ndindex_with_array { self, strides.ndim()); $( stride_offset(self[$index], get!(strides, $index)) + - )+ + )* 0 } } @@ -188,6 +188,7 @@ macro_rules! ndindex_with_array { } ndindex_with_array!{ + [0, Ix0] [1, Ix1 0] [2, Ix2 0 1] [3, Ix3 0 1 2] diff --git a/tests/ixdyn.rs b/tests/ixdyn.rs index e293c7ab8..b6843d4fa 100644 --- a/tests/ixdyn.rs +++ b/tests/ixdyn.rs @@ -3,6 +3,7 @@ extern crate ndarray; use ndarray::Array; use ndarray::Ix3; +use ndarray::IntoDimension; use ndarray::ShapeBuilder; #[test] @@ -98,3 +99,50 @@ fn test_ixdyn_uget() { } assert_eq!(sum, 10.); } + +#[test] +fn test_0() { + let mut a = Array::zeros(vec![]); + let z = vec![].into_dimension(); + assert_eq!(a[z.clone()], 0.); + a[[]] = 1.; + assert_eq!(a[[]], 1.); + assert_eq!(a.len(), 1); + assert_eq!(a.as_slice().unwrap(), &[1.]); + + let mut a = Array::zeros(vec![].f()); + assert_eq!(a[[]], 0.); + a[[]] = 1.; + assert_eq!(a[[]], 1.); + assert_eq!(a.len(), 1); + assert_eq!(a.as_slice().unwrap(), &[1.]); +} + +#[test] +fn test_0_add() { + let mut a = Array::zeros(vec![]); + a += 1.; + assert_eq!(a[[]], 1.); + a += 2.; + assert_eq!(a[[]], 3.); +} + +#[test] +fn test_0_add_add() { + let mut a = Array::zeros(vec![]); + a += 1.; + let mut b = Array::zeros(vec![]); + b += 1.; + a += &b; + assert_eq!(a[[]], 2.); +} + +#[test] +fn test_0_add_broad() { + let mut b = Array::from_vec(vec![5., 6.]); + let mut a = Array::zeros(vec![]); + a += 1.; + b += &a; + assert_eq!(b[0], 6.); + assert_eq!(b[1], 7.); +} From c6379f5bd5ba4769af8ddc9202a6a4d0576ec23e Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 03/12] ixdyn: Doc for IxDynImpl --- src/dimension/dynindeximpl.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dimension/dynindeximpl.rs b/src/dimension/dynindeximpl.rs index 0d71c0048..57b6a9c4d 100644 --- a/src/dimension/dynindeximpl.rs +++ b/src/dimension/dynindeximpl.rs @@ -113,6 +113,11 @@ impl PartialEq for IxDynRepr { } } +/// Dynamic dimension or index type. +/// +/// Use `IxDyn` directly. This type implements a dynamic number of +/// dimensions or indices. Short dimensions are stored inline and don't need +/// any dynamic memory allocation. #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct IxDynImpl(IxDynRepr); unsafe impl Send for IxDynImpl {} From 8b66c514c000a89a5e79ffec44e32eebc912f0bd Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 04/12] Fixup tests/dimension.rs --- tests/dimension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dimension.rs b/tests/dimension.rs index 6f75ebbf0..b7250f86e 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -34,7 +34,7 @@ fn dyn_dimension() let a = arr2(&[[1., 2.], [3., 4.0]]).into_shape(vec![2, 2]).unwrap(); assert_eq!(&a - &a, Array::zeros(vec![2, 2])); assert_eq!(a[&[0, 0][..]], 1.); - assert_eq!(a[vec![0, 0]], 1.); + assert_eq!(a[[0, 0]], 1.); let mut dim = vec![1; 1024]; dim[16] = 4; From 60aa150634c567a2acc12009c719d590f5795156 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 05/12] Fixup tests/iterator_chunks.rs --- tests/iterator_chunks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/iterator_chunks.rs b/tests/iterator_chunks.rs index 965837fa4..286d643d5 100644 --- a/tests/iterator_chunks.rs +++ b/tests/iterator_chunks.rs @@ -50,7 +50,7 @@ fn chunks_ok_size() { let mut c = 0; for elt in a.whole_chunks(vec![2, 1]) { assert!(elt.iter().all(|&x| x == 1.)); - assert_eq!(elt.dim(), vec![2, 1]); + assert_eq!(elt.shape(), &[2, 1]); c += 1; } assert_eq!(c, 3); From 0540bd1abf86a9f2b58b50229817bbabd7ee061c Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 06/12] Add dev-dependency on defmac --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index e77ee98fa..d5f02a648 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,9 @@ matrixmultiply = { version = "0.1.13" } version = "0.9" optional = true +[dev-dependencies] +defmac = "0.1" + [features] blas = ["blas-sys"] From d680b90915f0c25e9f193bd351d36e9c6c436f6c Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 07/12] ixdyn: Implement .remove_axis() --- src/dimension/dynindeximpl.rs | 29 +++++++++++++++++++++++++++-- src/dimension/remove_axis.rs | 9 --------- tests/dimension.rs | 23 ++++++++++++++++++++++- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/dimension/dynindeximpl.rs b/src/dimension/dynindeximpl.rs index 57b6a9c4d..7e941adb4 100644 --- a/src/dimension/dynindeximpl.rs +++ b/src/dimension/dynindeximpl.rs @@ -6,6 +6,7 @@ use std::ops::{ DerefMut, }; use imp_prelude::*; +use dimension::DimPrivate; const CAP: usize = 4; @@ -124,8 +125,24 @@ unsafe impl Send for IxDynImpl {} unsafe impl Sync for IxDynImpl {} impl IxDynImpl { - pub fn remove(&mut self, i: usize) { - unimplemented!() + fn remove(&self, i: usize) -> Self { + IxDynImpl(match self.0 { + IxDynRepr::Inline(0, _) => IxDynRepr::Inline(0, [0; CAP]), + IxDynRepr::Inline(1, _) => IxDynRepr::Inline(0, [0; CAP]), + IxDynRepr::Inline(2, ref arr) => { + let mut out = [0; CAP]; + out[0] = arr[1 - i]; + IxDynRepr::Inline(1, out) + } + ref ixdyn => { + let len = ixdyn.len(); + let mut result = IxDynRepr::copy_from(&ixdyn[..len - 1]); + for j in i..len - 1 { + result[j] = ixdyn[j + 1] + } + result + } + }) } } @@ -183,3 +200,11 @@ impl<'a> IntoIterator for &'a IxDynImpl { self[..].into_iter() } } + +impl RemoveAxis for Dim { + type Smaller = Self; + fn remove_axis(&self, axis: Axis) -> Self { + debug_assert!(axis.index() < self.ndim()); + Dim::new(self.ix().remove(axis.index())) + } +} diff --git a/src/dimension/remove_axis.rs b/src/dimension/remove_axis.rs index 5a6f57755..83fa3b8b1 100644 --- a/src/dimension/remove_axis.rs +++ b/src/dimension/remove_axis.rs @@ -8,7 +8,6 @@ use {Ix, Ix0, Ix1, Dimension, Dim, Axis}; -use IxDyn; use super::DimPrivate; /// Array shape with a next smaller dimension. @@ -67,12 +66,4 @@ macro_rules! impl_remove_axis_array( impl_remove_axis_array!(3, 4, 5, 6); -impl RemoveAxis for IxDyn { - type Smaller = Self; - fn remove_axis(&self, axis: Axis) -> Self { - let mut res = self.clone(); - res.ixm().remove(axis.index()); - res - } -} diff --git a/tests/dimension.rs b/tests/dimension.rs index b7250f86e..ea2c527ea 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -1,4 +1,6 @@ extern crate ndarray; +#[macro_use] +extern crate defmac; use ndarray::{ RcArray, @@ -18,7 +20,7 @@ fn remove_axis() 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!(Dim(vec![1,2]).remove_axis(Axis(0)), Dim(vec![2])); + 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)); @@ -43,6 +45,25 @@ fn dyn_dimension() assert_eq!(z.shape(), &dim[..]); } +#[test] +fn dyn_remove() { + let mut v = vec![1, 2, 3, 4, 5, 6, 7]; + let mut dim = Dim(v.clone()); + defmac!(test_remove index => { + dim = dim.remove_axis(Axis(index)); + v.remove(index); + assert_eq!(dim.slice(), &v[..]); + }); + + test_remove!(1); + test_remove!(2); + test_remove!(3); + test_remove!(0); + test_remove!(2); + test_remove!(0); + test_remove!(0); +} + #[test] fn fastest_varying_order() { let strides = Dim([2, 8, 4, 1]); From 41255726cb052271ee9f36bcaaf72a4232ac7d9c Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 08/12] ixdyn: Add function IxDyn --- src/aliases.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/aliases.rs b/src/aliases.rs index 2651bcddf..ddcec3959 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -45,6 +45,13 @@ pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 { Dim::new([i0, i1, i2, i3, i4, i5]) } +/// Create a dynamic-dimensional index +#[allow(non_snake_case)] +#[inline(always)] +pub fn IxDyn(ix: &[Ix]) -> IxDyn { + Dim(ix) +} + /// zero-dimensionial pub type Ix0 = Dim<[Ix; 0]>; /// one-dimensional From 086993b32eb74716813e76554eed13bc99146800 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:07:51 +0200 Subject: [PATCH 09/12] ixdyn: Use IxDyn function for example --- src/aliases.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index ddcec3959..4f5ab945a 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -68,16 +68,18 @@ pub type Ix5 = Dim<[Ix; 5]>; pub type Ix6 = Dim<[Ix; 6]>; /// dynamic-dimensional /// -/// `Vec` and `&[usize]` implement `IntoDimension` to produce `IxDyn`; -/// use them to create arrays with a dynamic number of axes. +/// You can use the `IxDyn` function to create a dimension for an array with +/// dynamic number of dimensions. (`Vec` and `&[usize]` also implement +/// `IntoDimension` to produce `IxDyn`). /// /// ``` /// use ndarray::ArrayD; +/// use ndarray::IxDyn; /// /// // Create a 5 × 6 × 3 × 4 array using the dynamic dimension type -/// let mut a = ArrayD::::zeros(vec![5, 6, 3, 4]); +/// let mut a = ArrayD::::zeros(IxDyn(&[5, 6, 3, 4])); /// // Create a 1 × 3 × 4 array using the dynamic dimension type -/// let mut b = ArrayD::::zeros(vec![1, 3, 4]); +/// let mut b = ArrayD::::zeros(IxDyn(&[1, 3, 4])); /// /// // We can use broadcasting to add arrays of compatible shapes together: /// a += &b; From 93f09aa2b6bf5c253214211def403236483d474d Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:20:51 +0200 Subject: [PATCH 10/12] ixdyn: Document default --- src/dimension/dynindeximpl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dimension/dynindeximpl.rs b/src/dimension/dynindeximpl.rs index 7e941adb4..6f29d5782 100644 --- a/src/dimension/dynindeximpl.rs +++ b/src/dimension/dynindeximpl.rs @@ -44,6 +44,7 @@ impl DerefMut for IxDynRepr { } } +/// The default is equivalent to `Self::from(&[0])`. impl Default for IxDynRepr { fn default() -> Self { Self::copy_from(&[0]) From b1077d60aa3a7726b3db044400b5dbc9b3d5b492 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:22:29 +0200 Subject: [PATCH 11/12] ixdyn: Update Default for Array documentation for IxDyn change --- src/arraytraits.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/arraytraits.rs b/src/arraytraits.rs index ec069dbb2..4968c63be 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -304,9 +304,11 @@ impl<'a, A: 'a, D, T> AsArray<'a, A, D> for T /// /// The array is created with dimension `D::default()`, which results /// in for example dimensions `0` and `(0, 0)` with zero elements for the -/// one-dimensional and two-dimensional cases respectively, while for example -/// the zero dimensional case uses `()` (or `Vec::new()`) which -/// results in an array with one element. +/// one-dimensional and two-dimensional cases respectively. +/// +/// The default dimension for `IxDyn` is `IxDyn(&[0])` (array has zero +/// elements). And the default for the dimension `()` is `()` (array has +/// one element). /// /// Since arrays cannot grow, the intention is to use the default value as /// placeholder. From 204a150af3a53e2fc669181f12217c73f884faa9 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 3 Apr 2017 23:24:42 +0200 Subject: [PATCH 12/12] ixdyn: Add test for new Array::default() --- tests/array.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/array.rs b/tests/array.rs index acb1fe005..f0770aa5b 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -1072,6 +1072,14 @@ fn test_default() { assert_eq!(b, arr0(Foo::default())); } +#[test] +fn test_default_ixdyn() { + let a = as Default>::default(); + let b = >::zeros(IxDyn(&[0])); + assert_eq!(a, b); +} + + #[test] fn test_map_axis() { let a = arr2(&[[1, 2, 3],