From 7e573a20810817ec66f501cbe797c8edff7cbeee Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 01/35] Fix warnings in tests for Zip --- tests/azip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/azip.rs b/tests/azip.rs index 4586f1a2d..b0364a475 100644 --- a/tests/azip.rs +++ b/tests/azip.rs @@ -86,7 +86,7 @@ fn test_broadcast() { let e = Array::from_elem((), 2.); { - let mut z = Zip::from(a.view_mut()) + let z = Zip::from(a.view_mut()) .and_broadcast(&b) .and_broadcast(&d) .and_broadcast(&e); From 153c66680e9b58b7fe69ed1ec047183f488cd71c Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 02/35] ndproducer: Generalize Ptr and Offset --- src/iterators/macros.rs | 3 +- src/iterators/mod.rs | 18 +++++----- src/zip/mod.rs | 73 ++++++++++++++++++++++++----------------- 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/iterators/macros.rs b/src/iterators/macros.rs index bcc5bb4f2..dcd4ee753 100644 --- a/src/iterators/macros.rs +++ b/src/iterators/macros.rs @@ -38,7 +38,8 @@ macro_rules! impl_ndproducer { } }) => { impl<$($typarm)*> NdProducer for $fulltype { - type Elem = A; + type Ptr = *mut A; + type Stride = isize; $( type $atyn = $atyv; )* diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 80c2a9a07..3498f811f 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -793,7 +793,8 @@ impl<'a, A, D> NdProducer for AxisIter<'a, A, D> { type Item = ::Item; type Dim = Ix1; - type Elem = A; + type Ptr = *mut A; + type Stride = isize; #[doc(hidden)] fn layout(&self) -> ::Layout { @@ -804,7 +805,7 @@ impl<'a, A, D> NdProducer for AxisIter<'a, A, D> Ix1(self.len()) } #[doc(hidden)] - fn as_ptr(&self) -> *mut Self::Elem { + fn as_ptr(&self) -> Self::Ptr { self.iter.ptr } @@ -813,13 +814,13 @@ impl<'a, A, D> NdProducer for AxisIter<'a, A, D> } #[doc(hidden)] - unsafe fn as_ref(&self, ptr: *mut Self::Elem) -> Self::Item { + unsafe fn as_ref(&self, ptr: Self::Ptr) -> Self::Item { ArrayView::new_(ptr, self.iter.inner_dim.clone(), self.iter.inner_strides.clone()) } #[doc(hidden)] - unsafe fn uget_ptr(&self, i: &Self::Dim) -> *mut Self::Elem { + unsafe fn uget_ptr(&self, i: &Self::Dim) -> Self::Ptr { self.iter.ptr.offset(self.iter.stride * i[0] as isize) } @@ -840,7 +841,8 @@ impl<'a, A, D> NdProducer for AxisIterMut<'a, A, D> { type Item = ::Item; type Dim = Ix1; - type Elem = A; + type Ptr = *mut A; + type Stride = isize; #[doc(hidden)] fn layout(&self) -> ::Layout { @@ -851,7 +853,7 @@ impl<'a, A, D> NdProducer for AxisIterMut<'a, A, D> Ix1(self.len()) } #[doc(hidden)] - fn as_ptr(&self) -> *mut Self::Elem { + fn as_ptr(&self) -> Self::Ptr { self.iter.ptr } @@ -860,13 +862,13 @@ impl<'a, A, D> NdProducer for AxisIterMut<'a, A, D> } #[doc(hidden)] - unsafe fn as_ref(&self, ptr: *mut Self::Elem) -> Self::Item { + unsafe fn as_ref(&self, ptr: Self::Ptr) -> Self::Item { ArrayViewMut::new_(ptr, self.iter.inner_dim.clone(), self.iter.inner_strides.clone()) } #[doc(hidden)] - unsafe fn uget_ptr(&self, i: &Self::Dim) -> *mut Self::Elem { + unsafe fn uget_ptr(&self, i: &Self::Dim) -> Self::Ptr { self.iter.ptr.offset(self.iter.stride * i[0] as isize) } diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 0aedfd0fb..9b249ec7c 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -142,10 +142,11 @@ pub trait NdProducer { /// The element produced per iteration. type Item; // Internal use / Pointee type - #[doc(hidden)] - type Elem; /// Dimension type type Dim: Dimension; + type Ptr: Offset; + type Stride: Copy; + #[doc(hidden)] fn layout(&self) -> Layout; #[doc(hidden)] @@ -155,23 +156,35 @@ pub trait NdProducer { self.raw_dim() == *dim } #[doc(hidden)] - fn as_ptr(&self) -> *mut Self::Elem; + fn as_ptr(&self) -> Self::Ptr; #[doc(hidden)] - unsafe fn as_ref(&self, *mut Self::Elem) -> Self::Item; + unsafe fn as_ref(&self, Self::Ptr) -> Self::Item; #[doc(hidden)] - unsafe fn uget_ptr(&self, i: &Self::Dim) -> *mut Self::Elem; + unsafe fn uget_ptr(&self, i: &Self::Dim) -> Self::Ptr; #[doc(hidden)] - fn stride_of(&self, axis: Axis) -> isize; + fn stride_of(&self, axis: Axis) -> ::Stride; #[doc(hidden)] #[inline(always)] - fn contiguous_stride(&self) -> isize { - 1 - } + fn contiguous_stride(&self) -> Self::Stride; #[doc(hidden)] fn split_at(self, axis: Axis, index: usize) -> (Self, Self) where Self: Sized; private_decl!{} } +pub trait Offset : Copy { + type Stride: Copy; + unsafe fn stride_offset(self, s: Self::Stride, index: usize) -> Self; + private_decl!{} +} + +impl Offset for *mut T { + type Stride = isize; + unsafe fn stride_offset(self, s: Self::Stride, index: usize) -> Self { + self.offset(s * (index as isize)) + } + private_impl!{} +} + trait ZippableTuple : Sized { type Item; type Ptr: OffsetTuple + Copy; @@ -258,7 +271,8 @@ impl<'a, A, D> NdProducer for ArrayView<'a, A, D> { type Item = &'a A; type Dim = D; - type Elem = A; + type Ptr = *mut A; + type Stride = isize; private_impl!{} #[doc(hidden)] @@ -295,6 +309,9 @@ impl<'a, A, D> NdProducer for ArrayView<'a, A, D> fn stride_of(&self, axis: Axis) -> isize { self.strides()[axis.index()] } + + #[inline(always)] + fn contiguous_stride(&self) -> Self::Stride { 1 } #[doc(hidden)] fn split_at(self, axis: Axis, index: usize) -> (Self, Self) { @@ -307,7 +324,8 @@ impl<'a, A, D> NdProducer for ArrayViewMut<'a, A, D> { type Item = &'a mut A; type Dim = D; - type Elem = A; + type Ptr = *mut A; + type Stride = isize; private_impl!{} #[doc(hidden)] @@ -345,6 +363,9 @@ impl<'a, A, D> NdProducer for ArrayViewMut<'a, A, D> self.strides()[axis.index()] } + #[inline(always)] + fn contiguous_stride(&self) -> Self::Stride { 1 } + #[doc(hidden)] fn split_at(self, axis: Axis, index: usize) -> (Self, Self) { self.split_at(axis, index) @@ -490,7 +511,7 @@ impl Zip let inner_strides = self.parts.contiguous_stride(); for i in 0..size { unsafe { - let ptr_i = ptrs.stride_offset(i, inner_strides); + let ptr_i = ptrs.stride_offset(inner_strides, i); acc = fold_while![function(acc, self.parts.as_ref(ptr_i))]; } } @@ -515,7 +536,7 @@ impl Zip unsafe { let ptr = self.parts.uget_ptr(&index); for i in 0..inner_len { - let p = ptr.stride_offset(i, inner_strides); + let p = ptr.stride_offset(inner_strides, i); acc = fold_while!(function(acc, self.parts.as_ref(p))); } } @@ -527,6 +548,7 @@ impl Zip } } +/* trait Offset : Copy { unsafe fn offset(self, off: isize) -> Self; unsafe fn stride_offset(self, index: usize, stride: isize) -> Self { @@ -539,21 +561,17 @@ impl Offset for *mut T { self.offset(off) } } +*/ trait OffsetTuple { type Args; - unsafe fn offset(self, off: isize) -> Self; - unsafe fn stride_offset(self, index: usize, stride: Self::Args) -> Self; + unsafe fn stride_offset(self, stride: Self::Args, index: usize) -> Self; } impl OffsetTuple for *mut T { type Args = isize; - unsafe fn offset(self, off: isize) -> Self { - self.offset(off) - } - - unsafe fn stride_offset(self, index: usize, stride: isize) -> Self { + unsafe fn stride_offset(self, stride: Self::Args, index: usize) -> Self { self.offset(index as isize * stride) } } @@ -568,16 +586,11 @@ macro_rules! offset_impl { $( #[allow(non_snake_case)] impl<$($param: Offset),*> OffsetTuple for ($($param, )*) { - type Args = ($(sub!($param [isize]),)*); - unsafe fn offset(self, off: isize) -> Self { - let ($($param, )*) = self; - ($($param . offset(off),)*) - } - - unsafe fn stride_offset(self, index: usize, stride: Self::Args) -> Self { + type Args = ($($param::Stride,)*); + unsafe fn stride_offset(self, stride: Self::Args, index: usize) -> Self { let ($($param, )*) = self; let ($($q, )*) = stride; - ($(Offset::stride_offset($param, index, $q),)*) + ($(Offset::stride_offset($param, $q, index),)*) } } )+ @@ -599,9 +612,9 @@ macro_rules! zipt_impl { #[allow(non_snake_case)] impl),*> ZippableTuple for ($($p, )*) { type Item = ($($p::Item, )*); - type Ptr = ($(*mut $p::Elem, )*); + type Ptr = ($($p::Ptr, )*); type Dim = Dim; - type Stride = ($(sub!($p [isize]),)* ); + type Stride = ($($p::Stride,)* ); fn stride_of(&self, index: usize) -> Self::Stride { let ($(ref $p,)*) = *self; From 2d2cb5c6ea99f6fbf886295a00d0f96497fb23c8 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 03/35] indices: Implement an indices producer --- src/indexes.rs | 139 +++++++++++++++++++++++++++++++++++++++++-- src/iterators/mod.rs | 4 +- src/lib.rs | 1 + src/zip/mod.rs | 22 ++++++- 4 files changed, 156 insertions(+), 10 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index 030e0d3ab..fd18f885d 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -8,12 +8,16 @@ use {ArrayBase, Data}; use super::Dimension; use dimension::IntoDimension; +use Axis; +use Layout; +use NdProducer; +use zip::{Offset, Splittable}; /// An iterator over the indexes of an array shape. /// /// Iterator element type is `D`. #[derive(Clone)] -pub struct Indices { +pub struct IndicesIter { dim: D, index: Option, } @@ -22,11 +26,11 @@ pub struct Indices { /// /// *Note:* prefer higher order methods, arithmetic operations and /// non-indexed iteration before using indices. -pub fn indices(shape: E) -> Indices +pub fn indices(shape: E) -> IndicesIter where E: IntoDimension, { let dim = shape.into_dimension(); - Indices { + IndicesIter { index: dim.first_index(), dim: dim, } @@ -36,13 +40,13 @@ pub fn indices(shape: E) -> Indices /// /// *Note:* prefer higher order methods, arithmetic operations and /// non-indexed iteration before using indices. -pub fn indices_of(array: &ArrayBase) -> Indices +pub fn indices_of(array: &ArrayBase) -> IndicesIter where S: Data, D: Dimension, { indices(array.dim()) } -impl Iterator for Indices +impl Iterator for IndicesIter where D: Dimension, { type Item = D::Pattern; @@ -73,6 +77,129 @@ impl Iterator for Indices } } -impl ExactSizeIterator for Indices +impl ExactSizeIterator for IndicesIter where D: Dimension {} + +impl IntoIterator for Indices + where D: Dimension +{ + type Item = D::Pattern; + type IntoIter = IndicesIter; + fn into_iter(self) -> Self::IntoIter { + let sz = self.dim.size(); + let index = if sz != 0 { Some(self.start) } else { None }; + IndicesIter { + index: index, + dim: self.dim, + } + } +} + +#[derive(Copy, Clone, Debug)] +pub struct Indices + where D: Dimension +{ + start: D, + dim: D, +} + +pub fn indices_new(dim: D) -> Indices { + Indices { + start: D::default(), + dim: dim, + } +} + +#[derive(Copy, Clone, Debug)] +pub struct IndexPtr { + index: D, +} + +impl Offset for IndexPtr + where D: Dimension + Copy, +{ + // stride: The axis to increment + type Stride = usize; + + unsafe fn stride_offset(mut self, stride: Self::Stride, index: usize) -> Self { + self.index[stride] += index; + self + } + private_impl!{} +} + +impl NdProducer for Indices + where D: Dimension, + D: Copy, +{ + type Item = D::Pattern; + type Dim = D; + type Ptr = IndexPtr; + type Stride = usize; + + private_impl!{} + + #[doc(hidden)] + fn raw_dim(&self) -> Self::Dim { + self.dim.clone() + } + + #[doc(hidden)] + fn equal_dim(&self, dim: &Self::Dim) -> bool { + self.dim.equal(dim) + } + + #[doc(hidden)] + fn as_ptr(&self) -> Self::Ptr { + IndexPtr { + index: self.start, + } + } + + #[doc(hidden)] + fn layout(&self) -> Layout { + if self.dim.ndim() <= 1 { + Layout::one_dimensional() + } else { + Layout::none() + } + } + + #[doc(hidden)] + unsafe fn as_ref(&self, ptr: Self::Ptr) -> Self::Item { + ptr.index.into_pattern() + } + + #[doc(hidden)] + unsafe fn uget_ptr(&self, i: &Self::Dim) -> Self::Ptr { + let mut index = *i; + index += &self.start; + IndexPtr { index: index } + } + + #[doc(hidden)] + fn stride_of(&self, axis: Axis) -> Self::Stride { + axis.index() + } + + #[inline(always)] + fn contiguous_stride(&self) -> Self::Stride { 0 } + + #[doc(hidden)] + fn split_at(self, axis: Axis, index: usize) -> (Self, Self) { + let start_a = self.start; + let mut start_b = start_a; + let (a, b) = self.dim.split_at(axis, index); + start_b[axis.index()] += index; + (Indices { + start: start_a, + dim: a, + }, + Indices { + start: start_b, + dim: b, + }) + } +} + diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 3498f811f..6b9b7ecc9 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1077,7 +1077,7 @@ pub unsafe trait TrustedIterator { } use std::slice; use std::iter; use linspace::Linspace; -use indexes::Indices; +use IndicesIter; unsafe impl TrustedIterator for Linspace { } unsafe impl<'a, A, D> TrustedIterator for Iter<'a, A, D> { } @@ -1085,7 +1085,7 @@ unsafe impl TrustedIterator for iter::Map where I: TrustedIterator { } unsafe impl<'a, A> TrustedIterator for slice::Iter<'a, A> { } unsafe impl TrustedIterator for ::std::ops::Range { } -unsafe impl TrustedIterator for Indices where D: Dimension { } +unsafe impl TrustedIterator for IndicesIter where D: Dimension { } /// Like Iterator::collect, but only for trusted length iterators diff --git a/src/lib.rs b/src/lib.rs index 5b9f97453..c9c28eb13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,6 +97,7 @@ pub use dimension::dim::*; pub use dimension::NdIndex; pub use dimension::IxDynImpl; pub use indexes::Indices; +pub use indexes::{IndicesIter}; pub use indexes::{indices, indices_of}; pub use error::{ShapeError, ErrorKind}; pub use si::{Si, S}; diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 9b249ec7c..925d6a2fc 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -15,6 +15,7 @@ use Layout; use layout::{CORDER, FORDER}; use layout::LayoutPriv; +use indexes::{Indices, indices_new}; /// Return if the expression is a break value. macro_rules! fold_while { @@ -96,7 +97,7 @@ impl<'a, A, D, E> Broadcast for ArrayView<'a, A, D> private_impl!{} } -trait Splittable : Sized { +pub trait Splittable : Sized { fn split_at(self, Axis, Ix) -> (Self, Self); } @@ -373,7 +374,6 @@ impl<'a, A, D> NdProducer for ArrayViewMut<'a, A, D> } - /// Lock step function application across several arrays or other producers. /// /// Zip allows matching several arrays to each other elementwise and applying @@ -447,6 +447,24 @@ impl Zip<(P, ), D> } } } +impl Zip<(Indices, P), D> + where D: Dimension + Copy, + P: NdProducer, +{ + /// Create a new `Zip` with an index producer and the producer `p`. + /// + /// The Zip will take the exact dimension of `p` and all inputs + /// must have the same dimensions (or be broadcast to them). + /// + /// *Note:* Indexed zip has significant overhead. + pub fn indexed(p: IP) -> Self + where IP: IntoNdProducer + { + let array = p.into_producer(); + let dim = array.raw_dim(); + Zip::from(indices_new(dim)).and(array) + } +} impl Zip where D: Dimension, From b38d673ba71ad9d87ea4833d347af825a8e11008 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 04/35] indices: Test for index producer --- tests/azip.rs | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tests/azip.rs b/tests/azip.rs index b0364a475..4f13b90e1 100644 --- a/tests/azip.rs +++ b/tests/azip.rs @@ -149,3 +149,96 @@ fn test_clone() { i += 1; }); } + +#[test] +fn test_indices_1() { + let mut a1 = Array::default(12); + for (i, elt) in a1.indexed_iter_mut() { + *elt = i; + } + + let mut count = 0; + Zip::indexed(&a1) + .apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, a1.len()); + + let mut count = 0; + let len = a1.len(); + let (x, y) = Zip::indexed(&mut a1).split(); + + x.apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, len / 2); + y.apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, len); +} + +#[test] +fn test_indices_2() { + let mut a1 = Array::default((10, 12)); + for (i, elt) in a1.indexed_iter_mut() { + *elt = i; + } + + let mut count = 0; + Zip::indexed(&a1) + .apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, a1.len()); + + let mut count = 0; + let len = a1.len(); + let (x, y) = Zip::indexed(&mut a1).split(); + + x.apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, len / 2); + y.apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, len); +} + +#[test] +fn test_indices_3() { + let mut a1 = Array::default((4, 5, 6)); + for (i, elt) in a1.indexed_iter_mut() { + *elt = i; + } + + let mut count = 0; + Zip::indexed(&a1) + .apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, a1.len()); + + let mut count = 0; + let len = a1.len(); + let (x, y) = Zip::indexed(&mut a1).split(); + + x.apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, len / 2); + y.apply(|i, elt| { + count += 1; + assert_eq!(*elt, i); + }); + assert_eq!(count, len); +} From bc2f8e4d335df69ce51fcd50681bc0a40fccda85 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 05/35] indices: Example for index + zip --- examples/zip_many.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/zip_many.rs b/examples/zip_many.rs index e7a0166c2..02916d3ee 100644 --- a/examples/zip_many.rs +++ b/examples/zip_many.rs @@ -3,6 +3,7 @@ extern crate ndarray; use ndarray::prelude::*; +use ndarray::Zip; fn main() { let n = 16; @@ -34,4 +35,18 @@ fn main() { let nchunks = (n / chunk_sz.0, n / chunk_sz.1); let mut sums = Array::zeros(nchunks); azip!(mut sums, ref a (a.whole_chunks(chunk_sz)) in { *sums = a.scalar_sum() }); + + + // Let's imagine we split to parallelize + { + let (x, y) = Zip::indexed(&mut a).split(); + x.apply(|(_, j), elt| { + *elt = elt.powi(j as i32); + }); + + y.apply(|(_, j), elt| { + *elt = elt.powi(j as i32); + }); + } + println!("{:8.3?}", a); } From fbc9b7c5c54f4fea9c54ad18aed07541362add05 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 06/35] indices: benchmarks --- benches/iter.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/benches/iter.rs b/benches/iter.rs index 106bb245c..06570b3d4 100644 --- a/benches/iter.rs +++ b/benches/iter.rs @@ -2,6 +2,7 @@ extern crate test; use test::Bencher; +use test::black_box; #[macro_use(s, azip)] extern crate ndarray; @@ -205,6 +206,70 @@ fn vector_sum_3_zip_unchecked(bench: &mut Bencher) // index iterator size const ISZ: usize = 16; +const I2DSZ: usize = 64; + +#[bench] +fn indexed_iter_1d_ix1(bench: &mut Bencher) { + let mut a = Array::::zeros(I2DSZ * I2DSZ); + for (i, elt) in a.indexed_iter_mut() { + *elt = i as _; + } + + bench.iter(|| { + for (i, &_elt) in a.indexed_iter() { + //assert!(a[i] == elt); + black_box(i); + } + }) +} + +#[bench] +fn indexed_zip_1d_ix1(bench: &mut Bencher) { + let mut a = Array::::zeros(I2DSZ * I2DSZ); + for (i, elt) in a.indexed_iter_mut() { + *elt = i as _; + } + + bench.iter(|| { + Zip::indexed(&a) + .apply(|i, &_elt| { + black_box(i); + //assert!(a[i] == elt); + }); + }) +} + +#[bench] +fn indexed_iter_2d_ix2(bench: &mut Bencher) { + let mut a = Array::::zeros((I2DSZ, I2DSZ)); + for ((i, j), elt) in a.indexed_iter_mut() { + *elt = (i + 100 * j) as _; + } + + bench.iter(|| { + for (i, &_elt) in a.indexed_iter() { + //assert!(a[i] == elt); + black_box(i); + } + }) +} +#[bench] +fn indexed_zip_2d_ix2(bench: &mut Bencher) { + let mut a = Array::::zeros((I2DSZ, I2DSZ)); + for ((i, j), elt) in a.indexed_iter_mut() { + *elt = (i + 100 * j) as _; + } + + bench.iter(|| { + Zip::indexed(&a) + .apply(|i, &_elt| { + black_box(i); + //assert!(a[i] == elt); + }); + }) +} + + #[bench] fn indexed_iter_3d_ix3(bench: &mut Bencher) { @@ -214,12 +279,29 @@ fn indexed_iter_3d_ix3(bench: &mut Bencher) { } bench.iter(|| { - for (i, &elt) in a.indexed_iter() { - assert!(a[i] == elt); + for (i, &_elt) in a.indexed_iter() { + //assert!(a[i] == elt); + black_box(i); } }) } +#[bench] +fn indexed_zip_3d_ix3(bench: &mut Bencher) { + let mut a = Array::::zeros((ISZ, ISZ, ISZ)); + for ((i, j, k), elt) in a.indexed_iter_mut() { + *elt = (i + 100 * j + 10000 * k) as _; + } + + bench.iter(|| { + Zip::indexed(&a) + .apply(|i, &_elt| { + black_box(i); + //assert!(a[i] == elt); + }); + }) +} + #[bench] fn indexed_iter_3d_dyn(bench: &mut Bencher) { let mut a = Array::::zeros((ISZ, ISZ, ISZ)); @@ -229,8 +311,9 @@ fn indexed_iter_3d_dyn(bench: &mut Bencher) { let a = a.into_shape(&[ISZ; 3][..]).unwrap(); bench.iter(|| { - for (i, &elt) in a.indexed_iter() { - assert!(a[i] == elt); + for (i, &_elt) in a.indexed_iter() { + //assert!(a[i] == elt); + black_box(i); } }) } From fe73cbba91413c735952d7cc068ac4694ffda94a Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 07/35] Move iterators to the iter submodule --- src/arraytraits.rs | 4 +- src/impl_methods.rs | 11 +++-- src/iterators/iter.rs | 29 ++++++++++++ src/iterators/mod.rs | 107 ++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 85 ++++----------------------------- 5 files changed, 149 insertions(+), 87 deletions(-) create mode 100644 src/iterators/iter.rs diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 4968c63be..354b2b691 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -15,9 +15,11 @@ use std::ops::{ }; use imp_prelude::*; -use { +use iter::{ Iter, IterMut, +}; +use { NdIndex, }; diff --git a/src/impl_methods.rs b/src/impl_methods.rs index ae4a6563a..e8fecdb6f 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -27,25 +27,28 @@ use iterators::{ new_inners_mut, whole_chunks_of, whole_chunks_mut_of, - Inners, - InnersMut, }; use zip::Zip; use { NdIndex, +}; +use iter::{ AxisChunksIter, AxisChunksIterMut, Iter, IterMut, IndexedIter, IndexedIterMut, + Inners, + InnersMut, AxisIter, AxisIterMut, WholeChunks, WholeChunksMut, }; use stacking::stack; +use PrivateNew; /// # Methods For All Array Types impl ArrayBase where S: Data, D: Dimension @@ -181,7 +184,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// Iterator element type is `(D::Pattern, &A)`. pub fn indexed_iter(&self) -> IndexedIter { - IndexedIter(self.view().into_elements_base()) + IndexedIter::new(self.view().into_elements_base()) } /// Return an iterator of indexes and mutable references to the elements of the array. @@ -193,7 +196,7 @@ impl ArrayBase where S: Data, D: Dimension pub fn indexed_iter_mut(&mut self) -> IndexedIterMut where S: DataMut, { - IndexedIterMut(self.view_mut().into_elements_base()) + IndexedIterMut::new(self.view_mut().into_elements_base()) } diff --git a/src/iterators/iter.rs b/src/iterators/iter.rs new file mode 100644 index 000000000..9d1b3fd05 --- /dev/null +++ b/src/iterators/iter.rs @@ -0,0 +1,29 @@ + +//! Producers, iterables and iterators. +//! +//! This module collects all concrete producer, iterable and iterator +//! implementation structs. + + +pub use indexes::{ + Indices, + IndicesIter, +}; +pub use iterators::{ + Iter, + IterMut, + IndexedIter, + IndexedIterMut, + Inners, + InnersMut, + InnerIter, + InnerIterMut, + AxisIter, + AxisIterMut, + AxisChunksIter, + AxisChunksIterMut, + WholeChunks, + WholeChunksIter, + WholeChunksMut, + WholeChunksIterMut, +}; diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 6b9b7ecc9..339533772 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -10,14 +10,16 @@ #[macro_use] mod macros; mod chunks; mod inners; +pub mod iter; use std::marker::PhantomData; use std::ptr; use Ix1; +use PrivateNew; + use super::{Dimension, Ix, Ixs}; -use super::{Iter, ElementsRepr, ElementsBase, ElementsBaseMut, IterMut, IndexedIter, IndexedIterMut}; use super::{ ArrayBase, Data, @@ -43,6 +45,8 @@ pub use self::inners::{ InnersMut, }; +use std::slice::{self, Iter as SliceIter, IterMut as SliceIterMut}; + /// Base for array iterators /// /// Iterator element type is `&'a A`. @@ -254,6 +258,100 @@ clone_bounds!( } ); +impl<'a, A, D> PrivateNew> for Iter<'a, A, D> + where D: Dimension +{ + fn new(self_: ArrayView<'a, A, D>) -> Self { + Iter { + inner: if let Some(slc) = self_.into_slice() { + ElementsRepr::Slice(slc.iter()) + } else { + ElementsRepr::Counted(self_.into_elements_base()) + }, + } + } +} + + + +impl<'a, A, D> PrivateNew> for IterMut<'a, A, D> + where D: Dimension +{ + fn new(self_: ArrayViewMut<'a, A, D>) -> Self { + IterMut { + inner: + match self_.into_slice_() { + Ok(x) => ElementsRepr::Slice(x.into_iter()), + Err(self_) => ElementsRepr::Counted(self_.into_elements_base()), + } + } + } +} + +#[derive(Clone)] +pub enum ElementsRepr { + Slice(S), + Counted(C), +} + +/// An iterator over the elements of an array. +/// +/// Iterator element type is `&'a A`. +/// +/// See [`.iter()`](struct.ArrayBase.html#method.iter) for more information. +pub struct Iter<'a, A: 'a, D> { + inner: ElementsRepr, ElementsBase<'a, A, D>>, +} + +/// Counted read only iterator +pub struct ElementsBase<'a, A: 'a, D> { + pub inner: Baseiter<'a, A, D>, +} + +/// An iterator over the elements of an array (mutable). +/// +/// Iterator element type is `&'a mut A`. +/// +/// See [`.iter_mut()`](struct.ArrayBase.html#method.iter_mut) for more information. +pub struct IterMut<'a, A: 'a, D> { + inner: ElementsRepr, ElementsBaseMut<'a, A, D>>, +} + +/// An iterator over the elements of an array. +/// +/// Iterator element type is `&'a mut A`. +pub struct ElementsBaseMut<'a, A: 'a, D> { + pub inner: Baseiter<'a, A, D>, +} + + +/// An iterator over the indexes and elements of an array. +/// +/// See [`.indexed_iter()`](struct.ArrayBase.html#method.indexed_iter) for more information. +#[derive(Clone)] +pub struct IndexedIter<'a, A: 'a, D>(ElementsBase<'a, A, D>); +/// An iterator over the indexes and elements of an array (mutable). +/// +/// See [`.indexed_iter_mut()`](struct.ArrayBase.html#method.indexed_iter_mut) for more information. +pub struct IndexedIterMut<'a, A: 'a, D>(ElementsBaseMut<'a, A, D>); + +impl<'a, A, D> PrivateNew> for IndexedIter<'a, A, D> + where D: Dimension +{ + fn new(x: ElementsBase<'a, A, D>) -> Self { + IndexedIter(x) + } +} + +impl<'a, A, D> PrivateNew> for IndexedIterMut<'a, A, D> + where D: Dimension +{ + fn new(x: ElementsBaseMut<'a, A, D>) -> Self { + IndexedIterMut(x) + } +} + + impl<'a, A, D: Dimension> Iterator for Iter<'a, A, D> { type Item = &'a A; #[inline] @@ -1074,14 +1172,13 @@ send_sync_read_write!(ElementsBaseMut); /// to deliver exactly as many items as it said it would. pub unsafe trait TrustedIterator { } -use std::slice; -use std::iter; +use std; use linspace::Linspace; -use IndicesIter; +use iter::IndicesIter; unsafe impl TrustedIterator for Linspace { } unsafe impl<'a, A, D> TrustedIterator for Iter<'a, A, D> { } -unsafe impl TrustedIterator for iter::Map +unsafe impl TrustedIterator for std::iter::Map where I: TrustedIterator { } unsafe impl<'a, A> TrustedIterator for slice::Iter<'a, A> { } unsafe impl TrustedIterator for ::std::ops::Range { } diff --git a/src/lib.rs b/src/lib.rs index c9c28eb13..b71c3e4d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,27 +96,12 @@ pub use dimension::dim::*; pub use dimension::NdIndex; pub use dimension::IxDynImpl; -pub use indexes::Indices; -pub use indexes::{IndicesIter}; pub use indexes::{indices, indices_of}; pub use error::{ShapeError, ErrorKind}; pub use si::{Si, S}; use iterators::Baseiter; -pub use iterators::{ - Inners, - InnersMut, - InnerIter, - InnerIterMut, - AxisIter, - AxisIterMut, - AxisChunksIter, - AxisChunksIterMut, - WholeChunks, - WholeChunksIter, - WholeChunksMut, - WholeChunksIterMut, -}; +use iterators::{ElementsBase, ElementsBaseMut, Iter, IterMut}; pub use arraytraits::AsArray; pub use linalg_traits::{LinalgScalar, NdFloat}; @@ -149,6 +134,7 @@ mod dimension; mod free_functions; pub use free_functions::*; +pub use iterators::iter; mod layout; mod indexes; @@ -747,19 +733,13 @@ impl<'a, A, D> ArrayBase, D> } fn into_iter_(self) -> Iter<'a, A, D> { - Iter { - inner: if let Some(slc) = self.into_slice() { - ElementsRepr::Slice(slc.iter()) - } else { - ElementsRepr::Counted(self.into_elements_base()) - }, - } + Iter::new(self) } /// Return an outer iterator for this view. #[doc(hidden)] // not official #[deprecated(note="This method will be replaced.")] - pub fn into_outer_iter(self) -> AxisIter<'a, A, D::Smaller> + pub fn into_outer_iter(self) -> iter::AxisIter<'a, A, D::Smaller> where D: RemoveAxis, { iterators::new_outer_iter(self) @@ -813,66 +793,23 @@ impl<'a, A, D> ArrayBase, D> } fn into_iter_(self) -> IterMut<'a, A, D> { - IterMut { - inner: - match self.into_slice_() { - Ok(x) => ElementsRepr::Slice(x.into_iter()), - Err(self_) => ElementsRepr::Counted(self_.into_elements_base()), - } - } + IterMut::new(self) } /// Return an outer iterator for this view. #[doc(hidden)] // not official #[deprecated(note="This method will be replaced.")] - pub fn into_outer_iter(self) -> AxisIterMut<'a, A, D::Smaller> + pub fn into_outer_iter(self) -> iter::AxisIterMut<'a, A, D::Smaller> where D: RemoveAxis, { iterators::new_outer_iter_mut(self) } } - -/// An iterator over the elements of an array. -/// -/// Iterator element type is `&'a A`. -/// -/// See [`.iter()`](struct.ArrayBase.html#method.iter) for more information. -pub struct Iter<'a, A: 'a, D> { - inner: ElementsRepr, ElementsBase<'a, A, D>>, -} - -/// Counted read only iterator -struct ElementsBase<'a, A: 'a, D> { - inner: Baseiter<'a, A, D>, +trait PrivateNew { + fn new(x: T) -> Self; } -/// An iterator over the elements of an array (mutable). -/// -/// Iterator element type is `&'a mut A`. -/// -/// See [`.iter_mut()`](struct.ArrayBase.html#method.iter_mut) for more information. -pub struct IterMut<'a, A: 'a, D> { - inner: ElementsRepr, ElementsBaseMut<'a, A, D>>, -} - -/// An iterator over the elements of an array. -/// -/// Iterator element type is `&'a mut A`. -struct ElementsBaseMut<'a, A: 'a, D> { - inner: Baseiter<'a, A, D>, -} - -/// An iterator over the indexes and elements of an array. -/// -/// See [`.indexed_iter()`](struct.ArrayBase.html#method.indexed_iter) for more information. -#[derive(Clone)] -pub struct IndexedIter<'a, A: 'a, D>(ElementsBase<'a, A, D>); -/// An iterator over the indexes and elements of an array (mutable). -/// -/// See [`.indexed_iter_mut()`](struct.ArrayBase.html#method.indexed_iter_mut) for more information. -pub struct IndexedIterMut<'a, A: 'a, D>(ElementsBaseMut<'a, A, D>); - fn zipsl<'a, 'b, A, B>(t: &'a [A], u: &'b [B]) -> ZipIter, SliceIter<'b, B>> { t.iter().zip(u) @@ -895,12 +832,6 @@ trait ZipExt : Iterator { impl ZipExt for I where I: Iterator { } -#[derive(Clone)] -enum ElementsRepr { - Slice(S), - Counted(C), -} - /// A contiguous array shape of n dimensions. /// From a62837320b490f41e50f1869e37bdf2b12442f43 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 08/35] =?UTF-8?q?Rename=20.whole=5Fchunks()=20=E2=86=92=20?= =?UTF-8?q?.exact=5Fchunks()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/impl_methods.rs | 39 ++++++++++++++++++------- src/iterators/chunks.rs | 62 ++++++++++++++++++++-------------------- src/iterators/iter.rs | 8 +++--- src/iterators/mod.rs | 12 ++++---- tests/azip.rs | 2 +- tests/iterator_chunks.rs | 18 ++++++------ 6 files changed, 79 insertions(+), 62 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index e8fecdb6f..ca274f449 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -25,8 +25,8 @@ use dimension::{axes_of, Axes, merge_axes, stride_offset}; use iterators::{ new_inners, new_inners_mut, - whole_chunks_of, - whole_chunks_mut_of, + exact_chunks_of, + exact_chunks_mut_of, }; use zip::Zip; @@ -44,8 +44,8 @@ use iter::{ InnersMut, AxisIter, AxisIterMut, - WholeChunks, - WholeChunksMut, + ExactChunks, + ExactChunksMut, }; use stacking::stack; use PrivateNew; @@ -694,7 +694,7 @@ impl ArrayBase where S: Data, D: Dimension iterators::new_chunk_iter_mut(self.view_mut(), axis.index(), size) } - /// Return a whole chunks producer (and iterable). + /// Return an exact chunks producer (and iterable). /// /// It produces the whole chunks of a given n-dimensional chunk size, /// skipping the remainder along each dimension that doesn't fit evenly. @@ -705,13 +705,21 @@ impl ArrayBase where S: Data, D: Dimension /// **Panics** if any dimension of `chunk_size` is zero
/// (**Panics** if `D` is `IxDyn` and `chunk_size` does not match the /// number of array axes.) - pub fn whole_chunks(&self, chunk_size: E) -> WholeChunks + pub fn exact_chunks(&self, chunk_size: E) -> ExactChunks where E: IntoDimension, { - whole_chunks_of(self.view(), chunk_size) + exact_chunks_of(self.view(), chunk_size) } - /// Return a whole chunks producer (and iterable). + #[doc(hidden)] + #[deprecated(note="Renamed to exact_chunks")] + pub fn whole_chunks(&self, chunk_size: E) -> ExactChunks + where E: IntoDimension, + { + self.exact_chunks(chunk_size) + } + + /// Return an exact chunks producer (and iterable). /// /// It produces the whole chunks of a given n-dimensional chunk size, /// skipping the remainder along each dimension that doesn't fit evenly. @@ -729,7 +737,7 @@ impl ArrayBase where S: Data, D: Dimension /// let mut a = Array::zeros((6, 7)); /// /// // Fill each 2 × 2 chunk with the index of where it appeared in iteration - /// for (i, mut chunk) in a.whole_chunks_mut((2, 2)).into_iter().enumerate() { + /// for (i, mut chunk) in a.exact_chunks_mut((2, 2)).into_iter().enumerate() { /// chunk.fill(i); /// } /// @@ -743,11 +751,20 @@ impl ArrayBase where S: Data, D: Dimension /// [6, 6, 7, 7, 8, 8, 0], /// [6, 6, 7, 7, 8, 8, 0]])); /// ``` - pub fn whole_chunks_mut(&mut self, chunk_size: E) -> WholeChunksMut + pub fn exact_chunks_mut(&mut self, chunk_size: E) -> ExactChunksMut + where E: IntoDimension, + S: DataMut + { + exact_chunks_mut_of(self.view_mut(), chunk_size) + } + + #[doc(hidden)] + #[deprecated(note="Renamed to exact_chunks_mut")] + pub fn whole_chunks_mut(&mut self, chunk_size: E) -> ExactChunksMut where E: IntoDimension, S: DataMut { - whole_chunks_mut_of(self.view_mut(), chunk_size) + self.exact_chunks_mut(chunk_size) } // Return (length, stride) for diagonal diff --git a/src/iterators/chunks.rs b/src/iterators/chunks.rs index 04ca80431..2a11697fd 100644 --- a/src/iterators/chunks.rs +++ b/src/iterators/chunks.rs @@ -8,12 +8,12 @@ use ::ElementsBaseMut; impl_ndproducer! { ['a, A, D: Dimension] [Clone => 'a, A, D: Clone ] - WholeChunks { + ExactChunks { base, chunk, inner_strides, } - WholeChunks<'a, A, D> { + ExactChunks<'a, A, D> { type Dim = D; type Item = ArrayView<'a, A, D>; @@ -27,19 +27,19 @@ impl_ndproducer! { type BaseProducerRef<'a, A, D> = ArrayView<'a, A, D>; type BaseProducerMut<'a, A, D> = ArrayViewMut<'a, A, D>; -/// Whole chunks producer and iterable. +/// Exact chunks producer and iterable. /// -/// See [`.whole_chunks()`](struct.ArrayBase.html#method.whole_chunks) for more +/// See [`.exact_chunks()`](struct.ArrayBase.html#method.exact_chunks) for more /// information. //#[derive(Debug)] -pub struct WholeChunks<'a, A: 'a, D> { +pub struct ExactChunks<'a, A: 'a, D> { base: BaseProducerRef<'a, A, D>, chunk: D, inner_strides: D, } /// **Panics** if any chunk dimension is zero
-pub fn whole_chunks_of(mut a: ArrayView, chunk: E) -> WholeChunks +pub fn exact_chunks_of(mut a: ArrayView, chunk: E) -> ExactChunks where D: Dimension, E: IntoDimension, { @@ -54,21 +54,21 @@ pub fn whole_chunks_of(mut a: ArrayView, chunk: E) -> WholeChunks let inner_strides = a.raw_strides(); a.strides *= &chunk; - WholeChunks { + ExactChunks { base: a, chunk: chunk, inner_strides: inner_strides, } } -impl<'a, A, D> IntoIterator for WholeChunks<'a, A, D> +impl<'a, A, D> IntoIterator for ExactChunks<'a, A, D> where D: Dimension, A: 'a, { type Item = ::Item; - type IntoIter = WholeChunksIter<'a, A, D>; + type IntoIter = ExactChunksIter<'a, A, D>; fn into_iter(self) -> Self::IntoIter { - WholeChunksIter { + ExactChunksIter { iter: self.base.into_elements_base(), chunk: self.chunk, inner_strides: self.inner_strides, @@ -76,11 +76,11 @@ impl<'a, A, D> IntoIterator for WholeChunks<'a, A, D> } } -/// Whole chunks iterator. +/// Exact chunks iterator. /// -/// See [`.whole_chunks()`](struct.ArrayBase.html#method.whole_chunks) for more +/// See [`.exact_chunks()`](struct.ArrayBase.html#method.exact_chunks) for more /// information. -pub struct WholeChunksIter<'a, A: 'a, D> { +pub struct ExactChunksIter<'a, A: 'a, D> { iter: ElementsBase<'a, A, D>, chunk: D, inner_strides: D, @@ -89,12 +89,12 @@ pub struct WholeChunksIter<'a, A: 'a, D> { impl_ndproducer! { ['a, A, D: Dimension] [Clone => ] - WholeChunksMut { + ExactChunksMut { base, chunk, inner_strides, } - WholeChunksMut<'a, A, D> { + ExactChunksMut<'a, A, D> { type Dim = D; type Item = ArrayViewMut<'a, A, D>; @@ -106,20 +106,20 @@ impl_ndproducer! { } } -/// Whole chunks producer and iterable. +/// Exact chunks producer and iterable. /// -/// See [`.whole_chunks_mut()`](struct.ArrayBase.html#method.whole_chunks_mut) +/// See [`.exact_chunks_mut()`](struct.ArrayBase.html#method.exact_chunks_mut) /// for more information. //#[derive(Debug)] -pub struct WholeChunksMut<'a, A: 'a, D> { +pub struct ExactChunksMut<'a, A: 'a, D> { base: BaseProducerMut<'a, A, D>, chunk: D, inner_strides: D, } /// **Panics** if any chunk dimension is zero
-pub fn whole_chunks_mut_of(mut a: ArrayViewMut, chunk: E) - -> WholeChunksMut +pub fn exact_chunks_mut_of(mut a: ArrayViewMut, chunk: E) + -> ExactChunksMut where D: Dimension, E: IntoDimension, { @@ -134,21 +134,21 @@ pub fn whole_chunks_mut_of(mut a: ArrayViewMut, chunk: E) let inner_strides = a.raw_strides(); a.strides *= &chunk; - WholeChunksMut { + ExactChunksMut { base: a, chunk: chunk, inner_strides: inner_strides, } } -impl<'a, A, D> IntoIterator for WholeChunksMut<'a, A, D> +impl<'a, A, D> IntoIterator for ExactChunksMut<'a, A, D> where D: Dimension, A: 'a, { type Item = ::Item; - type IntoIter = WholeChunksIterMut<'a, A, D>; + type IntoIter = ExactChunksIterMut<'a, A, D>; fn into_iter(self) -> Self::IntoIter { - WholeChunksIterMut { + ExactChunksIterMut { iter: self.base.into_elements_base(), chunk: self.chunk, inner_strides: self.inner_strides, @@ -206,12 +206,12 @@ macro_rules! impl_iterator { impl_iterator!{ ['a, A, D: Dimension] [Clone => 'a, A, D: Clone] - WholeChunksIter { + ExactChunksIter { iter, chunk, inner_strides, } - WholeChunksIter<'a, A, D> { + ExactChunksIter<'a, A, D> { type Item = ArrayView<'a, A, D>; fn item(&mut self, elt) { @@ -228,12 +228,12 @@ impl_iterator!{ impl_iterator!{ ['a, A, D: Dimension] [Clone => ] - WholeChunksIterMut { + ExactChunksIterMut { iter, chunk, inner_strides, } - WholeChunksIterMut<'a, A, D> { + ExactChunksIterMut<'a, A, D> { type Item = ArrayViewMut<'a, A, D>; fn item(&mut self, elt) { @@ -247,11 +247,11 @@ impl_iterator!{ } } -/// Whole chunks iterator. +/// Exact chunks iterator. /// -/// See [`.whole_chunks_mut()`](struct.ArrayBase.html#method.whole_chunks_mut) +/// See [`.exact_chunks_mut()`](struct.ArrayBase.html#method.exact_chunks_mut) /// for more information. -pub struct WholeChunksIterMut<'a, A: 'a, D> { +pub struct ExactChunksIterMut<'a, A: 'a, D> { iter: ElementsBaseMut<'a, A, D>, chunk: D, inner_strides: D, diff --git a/src/iterators/iter.rs b/src/iterators/iter.rs index 9d1b3fd05..e99ac6ad0 100644 --- a/src/iterators/iter.rs +++ b/src/iterators/iter.rs @@ -22,8 +22,8 @@ pub use iterators::{ AxisIterMut, AxisChunksIter, AxisChunksIterMut, - WholeChunks, - WholeChunksIter, - WholeChunksMut, - WholeChunksIterMut, + ExactChunks, + ExactChunksIter, + ExactChunksMut, + ExactChunksIterMut, }; diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 339533772..0c6d93bf6 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -31,12 +31,12 @@ use super::{ }; pub use self::chunks::{ - WholeChunks, - WholeChunksIter, - whole_chunks_of, - WholeChunksMut, - WholeChunksIterMut, - whole_chunks_mut_of, + ExactChunks, + ExactChunksIter, + exact_chunks_of, + ExactChunksMut, + ExactChunksIterMut, + exact_chunks_mut_of, }; pub use self::inners::{ new_inners, diff --git a/tests/azip.rs b/tests/azip.rs index 4f13b90e1..ffcc7f1b5 100644 --- a/tests/azip.rs +++ b/tests/azip.rs @@ -137,7 +137,7 @@ fn test_contiguous_but_not_c_or_f() { fn test_clone() { let a = Array::from_iter(0..27).into_shape((3, 3, 3)).unwrap(); - let z = Zip::from(&a).and(a.whole_chunks((1, 1, 1))); + let z = Zip::from(&a).and(a.exact_chunks((1, 1, 1))); let w = z.clone(); let mut result = Vec::new(); z.apply(|x, y| { diff --git a/tests/iterator_chunks.rs b/tests/iterator_chunks.rs index 286d643d5..65202fa42 100644 --- a/tests/iterator_chunks.rs +++ b/tests/iterator_chunks.rs @@ -12,7 +12,7 @@ fn chunks() { let (m, n) = a.dim(); for i in 1..m + 1 { for j in 1..n + 1 { - let c = a.whole_chunks((i, j)); + let c = a.exact_chunks((i, j)); let ly = n / j; for (index, elt) in c.into_iter().enumerate() { @@ -22,16 +22,16 @@ fn chunks() { let cy = (cindex.1 * j) as isize; assert_eq!(elt, a.slice(s![cx.., cy..]).slice(s![..i as isize, ..j as isize])); } - let c = a.whole_chunks((i, j)); + let c = a.exact_chunks((i, j)); assert_eq!(c.into_iter().count(), (m / i) * (n / j)); - let c = a.whole_chunks((i, j)); + let c = a.exact_chunks((i, j)); let (c1, c2) = c.split_at(Axis(0), (m / i) / 2); assert_eq!(c1.into_iter().count(), ((m / i) / 2) * (n / j)); assert_eq!(c2.into_iter().count(), (m / i - (m / i) / 2) * (n / j)); } } - let c = a.whole_chunks((m + 1, n)); + let c = a.exact_chunks((m + 1, n)); assert_eq!(c.raw_dim().size(), 0); assert_eq!(c.into_iter().count(), 0); } @@ -40,7 +40,7 @@ fn chunks() { #[test] fn chunks_different_size_1() { let a = Array::::zeros(vec![2, 3]); - a.whole_chunks(vec![2]); + a.exact_chunks(vec![2]); } #[test] @@ -48,7 +48,7 @@ fn chunks_ok_size() { let mut a = Array::::zeros(vec![2, 3]); a.fill(1.); let mut c = 0; - for elt in a.whole_chunks(vec![2, 1]) { + for elt in a.exact_chunks(vec![2, 1]) { assert!(elt.iter().all(|&x| x == 1.)); assert_eq!(elt.shape(), &[2, 1]); c += 1; @@ -60,13 +60,13 @@ fn chunks_ok_size() { #[test] fn chunks_different_size_2() { let a = Array::::zeros(vec![2, 3]); - a.whole_chunks(vec![2, 3, 4]); + a.exact_chunks(vec![2, 3, 4]); } #[test] fn chunks_mut() { let mut a = Array::zeros((7, 8)); - for (i, mut chunk) in a.whole_chunks_mut((2, 3)).into_iter().enumerate() { + for (i, mut chunk) in a.exact_chunks_mut((2, 3)).into_iter().enumerate() { chunk.fill(i); } println!("{:?}", a); @@ -85,5 +85,5 @@ fn chunks_mut() { #[test] fn chunks_different_size_3() { let mut a = Array::::zeros(vec![2, 3]); - a.whole_chunks_mut(vec![2, 3, 4]); + a.exact_chunks_mut(vec![2, 3, 4]); } From dcda7436be152c5a7c64891f11804391ae6ae6e2 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 09/35] Update tests for whole chunks rename --- examples/zip_many.rs | 2 +- tests/iterators.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/zip_many.rs b/examples/zip_many.rs index 02916d3ee..778f4bffa 100644 --- a/examples/zip_many.rs +++ b/examples/zip_many.rs @@ -34,7 +34,7 @@ fn main() { let chunk_sz = (2, 2); let nchunks = (n / chunk_sz.0, n / chunk_sz.1); let mut sums = Array::zeros(nchunks); - azip!(mut sums, ref a (a.whole_chunks(chunk_sz)) in { *sums = a.scalar_sum() }); + azip!(mut sums, ref a (a.exact_chunks(chunk_sz)) in { *sums = a.scalar_sum() }); // Let's imagine we split to parallelize diff --git a/tests/iterators.rs b/tests/iterators.rs index 8333d07b2..a75eefbb8 100644 --- a/tests/iterators.rs +++ b/tests/iterators.rs @@ -480,10 +480,10 @@ fn iterators_are_send_sync() { _send_sync(&a.axis_chunks_iter(Axis(1), 1)); _send_sync(&a.axis_chunks_iter_mut(Axis(1), 1)); _send_sync(&indices(a.dim())); - _send_sync(&a.whole_chunks((1, 1, 1))); - _send_sync(&a.whole_chunks_mut((1, 1, 1))); - _send_sync(&a.whole_chunks((1, 1, 1)).into_iter()); - _send_sync(&a.whole_chunks_mut((1, 1, 1)).into_iter()); + _send_sync(&a.exact_chunks((1, 1, 1))); + _send_sync(&a.exact_chunks_mut((1, 1, 1))); + _send_sync(&a.exact_chunks((1, 1, 1)).into_iter()); + _send_sync(&a.exact_chunks_mut((1, 1, 1)).into_iter()); } #[test] From 950f475df7351fa26efc06922b8b1aede861858e Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 10/35] Move inners below genrows() --- src/impl_methods.rs | 85 +++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index ca274f449..176cbbcc4 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -461,48 +461,6 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Return a producer and iterable that traverses over all lanes - /// pointing in the direction of `axis`. - /// - /// For example, in a 2 × 2 × 3 array, the iterator element - /// is a row of 3 elements (and there are 2 × 2 = 4 rows in total). - /// - /// Iterator element is `ArrayView1` (1D array view); note that it is - /// always 1D. - /// - /// ``` - /// use ndarray::{arr3, aview1, Axis}; - /// - /// let a = arr3(&[[[ 0, 1, 2], - /// [ 3, 4, 5]], - /// [[ 6, 7, 8], - /// [ 9, 10, 11]]]); - /// - /// let inner0 = a.inners(Axis(0)); - /// let inner1 = a.inners(Axis(1)); - /// let inner2 = a.inners(Axis(2)); - /// - /// // The first lane for axis 0 is [0, 6] - /// assert_eq!(inner0.into_iter().next().unwrap(), aview1(&[0, 6])); - /// // The first lane for axis 1 is [0, 3] - /// assert_eq!(inner1.into_iter().next().unwrap(), aview1(&[0, 3])); - /// // The first lane for axis 2 is [0, 1, 2] - /// assert_eq!(inner2.into_iter().next().unwrap(), aview1(&[0, 1, 2])); - /// ``` - pub fn inners(&self, axis: Axis) -> Inners { - new_inners(self.view(), axis) - } - - /// Return a producer and iterable that traverses over all axes but the - /// selected axis. - /// - /// Iterator element is `ArrayViewMut1` (1D read-write array view). - pub fn inners_mut(&mut self, axis: Axis) -> InnersMut - where S: DataMut - { - new_inners_mut(self.view_mut(), axis) - } - /// Return a producer and iterable that traverses over the *generalized* /// rows of the array. For a 2D array these are the regular rows. /// @@ -587,6 +545,49 @@ impl ArrayBase where S: Data, D: Dimension new_inners_mut(self.view_mut(), Axis(0)) } + /// Return a producer and iterable that traverses over all lanes + /// pointing in the direction of `axis`. + /// + /// For example, in a 2 × 2 × 3 array, the iterator element + /// is a row of 3 elements (and there are 2 × 2 = 4 rows in total). + /// + /// Iterator element is `ArrayView1` (1D array view); note that it is + /// always 1D. + /// + /// ``` + /// use ndarray::{arr3, aview1, Axis}; + /// + /// let a = arr3(&[[[ 0, 1, 2], + /// [ 3, 4, 5]], + /// [[ 6, 7, 8], + /// [ 9, 10, 11]]]); + /// + /// let inner0 = a.inners(Axis(0)); + /// let inner1 = a.inners(Axis(1)); + /// let inner2 = a.inners(Axis(2)); + /// + /// // The first lane for axis 0 is [0, 6] + /// assert_eq!(inner0.into_iter().next().unwrap(), aview1(&[0, 6])); + /// // The first lane for axis 1 is [0, 3] + /// assert_eq!(inner1.into_iter().next().unwrap(), aview1(&[0, 3])); + /// // The first lane for axis 2 is [0, 1, 2] + /// assert_eq!(inner2.into_iter().next().unwrap(), aview1(&[0, 1, 2])); + /// ``` + pub fn inners(&self, axis: Axis) -> Inners { + new_inners(self.view(), axis) + } + + /// Return a producer and iterable that traverses over all axes but the + /// selected axis. + /// + /// Iterator element is `ArrayViewMut1` (1D read-write array view). + pub fn inners_mut(&mut self, axis: Axis) -> InnersMut + where S: DataMut + { + new_inners_mut(self.view_mut(), axis) + } + + /// Return an iterator that traverses over the outermost dimension /// and yields each subview. /// From d271b405c41a65fc52fe27ffb662532e6fb61302 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 11/35] Update inners doc --- src/impl_methods.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 176cbbcc4..a7dfc889f 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -545,12 +545,9 @@ impl ArrayBase where S: Data, D: Dimension new_inners_mut(self.view_mut(), Axis(0)) } - /// Return a producer and iterable that traverses over all lanes + /// Return a producer and iterable that traverses over all 1D lanes /// pointing in the direction of `axis`. /// - /// For example, in a 2 × 2 × 3 array, the iterator element - /// is a row of 3 elements (and there are 2 × 2 = 4 rows in total). - /// /// Iterator element is `ArrayView1` (1D array view); note that it is /// always 1D. /// @@ -577,8 +574,8 @@ impl ArrayBase where S: Data, D: Dimension new_inners(self.view(), axis) } - /// Return a producer and iterable that traverses over all axes but the - /// selected axis. + /// Return a producer and iterable that traverses over all 1D lanes + /// pointing in the direction of `axis`. /// /// Iterator element is `ArrayViewMut1` (1D read-write array view). pub fn inners_mut(&mut self, axis: Axis) -> InnersMut From d080a58e0de0e744955c7566566ab64a33b93ebd Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 12/35] fold while: Add .is_done() --- src/zip/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 925d6a2fc..0534ae760 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -803,4 +803,12 @@ impl FoldWhile { FoldWhile::Continue(x) | FoldWhile::Done(x) => x } } + + /// Return true if it is `Done`, false if `Continue + pub fn is_done(&self) -> bool { + match *self { + FoldWhile::Continue(_) => false, + FoldWhile::Done(_) => true, + } + } } From d5dcff3403f88f063ed3ae5f344f3bd18880b110 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 13/35] Use is_done() --- src/numeric/impl_numeric.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/numeric/impl_numeric.rs b/src/numeric/impl_numeric.rs index 4f23ab0a4..3892991f7 100644 --- a/src/numeric/impl_numeric.rs +++ b/src/numeric/impl_numeric.rs @@ -126,8 +126,7 @@ impl ArrayBase S2: Data, E: Dimension, { - let result = - Zip::from(self) + !Zip::from(self) .and(rhs.broadcast_unwrap(self.raw_dim())) .fold_while((), |_, x, y| { if (*x - *y).abs() <= tol { @@ -135,11 +134,7 @@ impl ArrayBase } else { FoldWhile::Done(()) } - }); - match result { - FoldWhile::Continue(_) => true, - FoldWhile::Done(_) => false, - } + }).is_done() } } From 5620afbee5266474da9eeb2a264b9175abc07c60 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 14/35] DOC: Doc for Indices --- src/indexes.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/indexes.rs b/src/indexes.rs index fd18f885d..3c4388311 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -96,6 +96,9 @@ impl IntoIterator for Indices } } +/// Indices producer and iterable. +/// +/// `Indices` is an `NdProducer` that produces the indices of an array shape. #[derive(Copy, Clone, Debug)] pub struct Indices where D: Dimension From 38439405069eaddb77c7c917c35bbf72cc2bebcb Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 15/35] Remove example file linalg.rs --- examples/linalg.rs | 293 --------------------------------------------- 1 file changed, 293 deletions(-) delete mode 100644 examples/linalg.rs diff --git a/examples/linalg.rs b/examples/linalg.rs deleted file mode 100644 index ec864809b..000000000 --- a/examples/linalg.rs +++ /dev/null @@ -1,293 +0,0 @@ -#![allow(non_snake_case)] - -//! A few linear algebra operations on two-dimensional arrays, just for demo -//! purposes. - -extern crate ndarray; -extern crate num_traits; -extern crate num_complex; - -use num_traits::{Num, Zero, One}; -use num_traits::Float; -use num_complex::Complex; -use std::ops::{Add, Sub, Mul, Div}; - -use ndarray::{RcArray, Ix1, Ix2}; -use ndarray::{rcarr1, rcarr2}; -use ndarray::LinalgScalar; - -/// Column vector. -pub type Col = RcArray; -/// Rectangular matrix. -pub type Mat = RcArray; - -/// Trait union for a ring with 1. -pub trait Ring : Clone + Zero + Add + Sub - + One + Mul { } -impl + Sub + One + Mul> Ring for A { } - -/// Trait union for a field. -pub trait Field : Ring + Div { } -impl> Field for A { } - -/// A real or complex number. -pub trait ComplexField : LinalgScalar -{ - #[inline] - fn conjugate(self) -> Self { self } - fn sqrt_real(self) -> Self; - #[inline] - fn is_complex() -> bool { false } -} - -impl ComplexField for f32 -{ - #[inline] - fn sqrt_real(self) -> f32 { self.sqrt() } -} - -impl ComplexField for f64 -{ - #[inline] - fn sqrt_real(self) -> f64 { self.sqrt() } -} - -impl ComplexField for Complex -{ - #[inline] - fn conjugate(self) -> Complex { self.conj() } - fn sqrt_real(self) -> Complex { Complex::new(self.re.sqrt(), A::zero()) } - #[inline] - fn is_complex() -> bool { true } -} - -// Some examples. -fn main() { - chol(); - subst(); - lst_squares(); -} - -fn chol() -{ - let _ = rcarr2(&[[1., 2.], [3., 4.]]); // not pos. def. - let a = rcarr2(&[[10., 14.], [14., 20.]]); // aT a is pos def - - let chol = cholesky(a); - let ans = - rcarr2(&[[3.16227770, 0.00000000], - [4.42718887, 0.63245525]]); - - assert!(ans.all_close(&chol, 0.001)); - - // Compute bT b for a pos def matrix - let b = RcArray::linspace(0f32, 8., 9).reshape((3, 3)); - let mut bt = b.clone(); - bt.swap_axes(0, 1); - let bpd = bt.dot(&b).into_shared(); - println!("bpd=\n{:?}", bpd); - let chol = cholesky(bpd); - println!("chol=\n{:.8?}", chol); - - let ans = - rcarr2(&[[6.70820379, 0.00000000, 0.00000000], - [8.04984474, 1.09544373, 0.00000000], - [9.39148617, 2.19088745, 0.00000000]]); - assert!(ans.all_close(&chol, 0.001)); - - let a = - rcarr2(&[[ 0.05201001, 0.22982409, 0.1014132 ], - [ 0.22982409, 1.105822 , 0.37946544], - [ 0.1014132 , 0.37946544, 1.16199134]]); - let chol = cholesky(a); - - let ans = - rcarr2(&[[ 0.22805704, 0. , 0. ], - [ 1.00774829, 0.30044197, 0. ], - [ 0.44468348, -0.2285419 , 0.95499557]]); - assert!(ans.all_close(&chol, 0.001)); -} - -fn subst() -{ - let lll = - rcarr2(&[[ 0.22805704, 0. , 0. ], - [ 1.00774829, 0.30044197, 0. ], - [ 0.44468348, -0.2285419 , 0.95499557]]); - let ans = rcarr1::(&[4.384868, -8.050947, -0.827078]); - - assert!(ans.all_close(&subst_fw(&lll, &rcarr1(&[1., 2., 3.])), - 0.001)); -} - -fn lst_squares() -{ - let xs = - rcarr2(&[[ 2., 3.], - [-2., -1.], - [ 1., 5.], - [-1., 2.]]); - let b = rcarr1(&[1., -1., 2., 1.]); - let x_lstsq = least_squares(&xs, &b); - let ans = rcarr1(&[0.070632, 0.390335]); - assert!(x_lstsq.all_close(&ans, 0.001)); -} - -/// Solve *a x = b* with linear least squares approximation. -/// -/// It is used to find the best fit for an overdetermined system, -/// i.e. the number of rows in *a* is larger than the number of -/// unknowns *x*. -/// -/// Return best fit for *x*. -pub fn least_squares(a: &Mat, b: &Col) -> Col -{ - // Using transpose: a.T a x = a.T b; - // a.T a being square gives naive solution - // x_lstsq = inv(a.T a) a.T b - // - // Solve using cholesky decomposition - // aT a x = aT b - // - // Factor aT a into L L.T - // - // L L.T x = aT b - // - // => L z = aT b - // fw subst for z - // => L.T x = z - // bw subst for x estimate - // - let mut aT = a.clone(); - aT.swap_axes(0, 1); - if ::is_complex() { - // conjugate transpose - for elt in aT.iter_mut() { - *elt = elt.conjugate(); - } - } - - let aT_a = aT.dot(a).into_shared(); - let mut L = cholesky(aT_a); - let rhs = aT.dot(b).into_shared(); - - // Solve L z = aT b - let z = subst_fw(&L, &rhs); - - // Solve L.T x = z - if ::is_complex() { - // conjugate transpose - // only elements below the diagonal have imag part - let (m, _) = L.dim(); - for i in 1..m { - for j in 0..i { - let elt = &mut L[[i, j]]; - *elt = elt.conjugate(); - } - } - } - L.swap_axes(0, 1); - - // => x_lstsq - subst_bw(&L, &z) -} - -/// Factor *a = L LT*. -/// -/// *a* should be a square matrix, hermitian and positive definite. -/// -/// https://en.wikipedia.org/wiki/Cholesky_decomposition -/// -/// “The Cholesky decomposition is mainly used for the numerical solution of -/// linear equations Ax = b. -/// -/// If A is symmetric and positive definite, then we can solve Ax = b by first -/// computing the Cholesky decomposition A = LL*, then solving Ly = b for y by -/// forward substitution, and finally solving L*x = y for x by back -/// substitution.” -/// -/// Return L. -pub fn cholesky(a: Mat) -> Mat -{ - let z = A::zero(); - let (m, n) = a.dim(); - assert!(m == n); - // Perform the operation in-place on `a` - let mut L = a; - for i in 0..m { - // Entries 0 .. i before the diagonal - for j in 0..i { - // A = ( - // L²_1,1 - // L_2,1 L_1,1 L²_2,1 + L²_2,2 - // L_3,1 L_1,1 L_3,1 L_2,1 + L_3,2 L_2,2 L²_3,1 + L²_3,2 + L²_3,3 - // .. ) - let mut lik_ljk_sum = z; - { - // L_ik for k = 0 .. j - // L_jk for k = 0 .. j - let Lik = L.row(i).into_iter(); - let Ljk = L.row(j).into_iter(); - for (&lik, &ljk) in Lik.zip(Ljk).take(j as usize) { - lik_ljk_sum = lik_ljk_sum + lik * ljk.conjugate(); - } - } - - // L_ij = [ A_ij - Sum(k = 1 .. j) L_ik L_jk ] / L_jj - L[[i, j]] = (L[[i, j]] - lik_ljk_sum) / L[[j, j]]; - } - - // Diagonal where i == j - // L_jj = Sqrt[ A_jj - Sum(k = 1 .. j) L_jk L_jk ] - let j = i; - let mut ljk_sum = z; - // L_jk for k = 0 .. j - for &ljk in L.row(j).into_iter().take(j as usize) { - ljk_sum = ljk_sum + ljk * ljk.conjugate(); - } - L[[j, j]] = (L[[j, j]] - ljk_sum).sqrt_real(); - - // After the diagonal - // L_ij = 0 for j > i - for j in i + 1..n { - L[[i, j]] = z; - } - } - L -} - -/// 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(); - assert!(m == n); - 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 - let mut b_lx_sum = b[i]; - for j in 0..i { - b_lx_sum = b_lx_sum - l[[i, j]] * x[j]; - } - x[i] = b_lx_sum / l[[i, i]]; - } - x -} - -/// 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(); - assert!(m == n); - 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 - let mut b_ux_sum = b[i]; - for j in i..m { - b_ux_sum = b_ux_sum - u[[i, j]] * x[j]; - } - x[i] = b_ux_sum / u[[i, i]]; - } - x -} From 49b23f881f8f1841621db18ed8e35b71a787b1e2 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 16/35] dimension: Add method .zero_index() --- src/dimension/dimension_trait.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index f2e7b5fe1..3612c1066 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -146,6 +146,12 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + strides } + #[doc(hidden)] + // Return an index of same dimensionality + fn zero_index(&self) -> Self { + Self::default() + } + #[doc(hidden)] #[inline] fn first_index(&self) -> Option { @@ -758,6 +764,17 @@ impl Dimension for IxDyn fn into_pattern(self) -> Self::Pattern { self } + + fn zero_index(&self) -> Self { + const ZEROS: &'static [usize] = &[0; 4]; + let n = self.ndim(); + if n <= ZEROS.len() { + Dim(&ZEROS[..n]) + } else { + Dim(vec![0; n]) + } + } + #[inline] fn try_remove_axis(&self, axis: Axis) -> Self::Smaller { if self.ndim() > 0 { From 07622590d7736c18d582d897de4f233359b014df Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 17/35] Return Indices (NdProducer + IntoIterator) from indices/indices_of --- src/impl_constructors.rs | 2 +- src/indexes.rs | 12 ++++++------ tests/array.rs | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 624bfc11d..6d44c2452 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -185,7 +185,7 @@ impl ArrayBase F: FnMut(D::Pattern) -> A, { let shape = shape.into_shape(); - let v = to_vec_mapped(indices(shape.dim.clone()), f); + let v = to_vec_mapped(indices(shape.dim.clone()).into_iter(), f); unsafe { Self::from_shape_vec_unchecked(shape, v) } } diff --git a/src/indexes.rs b/src/indexes.rs index 3c4388311..c742bab24 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -22,25 +22,25 @@ pub struct IndicesIter { index: Option, } -/// Create an iterator over the array shape `shape`. +/// Create an iterable of the array shape `shape`. /// /// *Note:* prefer higher order methods, arithmetic operations and /// non-indexed iteration before using indices. -pub fn indices(shape: E) -> IndicesIter +pub fn indices(shape: E) -> Indices where E: IntoDimension, { let dim = shape.into_dimension(); - IndicesIter { - index: dim.first_index(), + Indices { + start: dim.zero_index(), dim: dim, } } -/// Create an iterator over the indices of the passed-in array. +/// Return an iterable of the indices of the passed-in array. /// /// *Note:* prefer higher order methods, arithmetic operations and /// non-indexed iteration before using indices. -pub fn indices_of(array: &ArrayBase) -> IndicesIter +pub fn indices_of(array: &ArrayBase) -> Indices where S: Data, D: Dimension, { indices(array.dim()) diff --git a/tests/array.rs b/tests/array.rs index ec614238b..5b850916c 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -11,7 +11,7 @@ use ndarray::{ arr3, }; use ndarray::indices; -use itertools::free::enumerate; +use itertools::{enumerate, zip}; #[test] fn test_matmul_rcarray() @@ -96,13 +96,13 @@ fn test_index() *elt = i; } - for ((i, j), a) in indices((2, 3)).zip(A.iter()) { + for ((i, j), a) in zip(indices((2, 3)), &A) { assert_eq!(*a, A[[i, j]]); } let vi = A.slice(&[Si(1, None, 1), Si(0, None, 2)]); let mut it = vi.iter(); - for ((i, j), x) in indices((1, 2)).zip(it.by_ref()) { + for ((i, j), x) in zip(indices((1, 2)), &mut it) { assert_eq!(*x, vi[[i, j]]); } assert!(it.next().is_none()); From 76573c30bdfa958f32b0d158a73005850666d880 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 18/35] Add test for indices_of + IxDyn --- tests/indices.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/indices.rs diff --git a/tests/indices.rs b/tests/indices.rs new file mode 100644 index 000000000..9e47075a4 --- /dev/null +++ b/tests/indices.rs @@ -0,0 +1,25 @@ +extern crate ndarray; + +use ndarray::prelude::*; +use ndarray::indices_of; + +#[test] +fn test_ixdyn_index_iterate() { + for &rev in &[false, true] { + let mut a = Array::zeros((2, 3, 4).set_f(rev)); + let dim = a.shape().to_vec(); + for ((i, j, k), elt) in a.indexed_iter_mut() { + *elt = i + 10 * j + 100 * k; + } + let a = a.into_shape(dim).unwrap(); + println!("{:?}", a.dim()); + let mut c = 0; + for i in indices_of(&a) { + let ans = i[0] + 10 * i[1] + 100 * i[2]; + println!("{:?}", i); + assert_eq!(a[i], ans); + c += 1; + } + assert_eq!(c, a.len()); + } +} From a1b62987ecd3130275d3bb9e21dd4904198965e5 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 19/35] Use indices function for zip --- src/indexes.rs | 7 ------- src/zip/mod.rs | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index c742bab24..29e7ee23d 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -107,13 +107,6 @@ pub struct Indices dim: D, } -pub fn indices_new(dim: D) -> Indices { - Indices { - start: D::default(), - dim: dim, - } -} - #[derive(Copy, Clone, Debug)] pub struct IndexPtr { index: D, diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 0534ae760..5a36fbeda 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -15,7 +15,7 @@ use Layout; use layout::{CORDER, FORDER}; use layout::LayoutPriv; -use indexes::{Indices, indices_new}; +use indexes::{Indices, indices}; /// Return if the expression is a break value. macro_rules! fold_while { @@ -462,7 +462,7 @@ impl Zip<(Indices, P), D> { let array = p.into_producer(); let dim = array.raw_dim(); - Zip::from(indices_new(dim)).and(array) + Zip::from(indices(dim)).and(array) } } From a9ec2bedf0d22d5d5cc3785fda9dbf026bc72a33 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 20/35] DOC: Update NdProducer --- src/zip/mod.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 5a36fbeda..b04c3f982 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -139,13 +139,36 @@ impl

IntoNdProducer for P where P: NdProducer { /// that yields chunks. /// /// Producers are used as a arguments to `Zip` and `azip!()`. +/// +/// # Comparison to `IntoIterator` +/// +/// Most `NdProducers` are *iterable* (implement `IntoIterator`) but not directly +/// iterators. This separation is needed because the producer represents +/// a multidimensional set of items, it can be split along a particular axis for +/// parallelization, and it has no fixed correspondance to a sequence. +/// +/// The natural exception is one dimensional producers, like `AxisIter`, which +/// implement `Iterator` directly +/// (`AxisIter` traverses a one dimensional sequence, along an axis, while +/// *producing* multidimensional items). +/// +/// See also [`IntoNdProducer`](trait.IntoNdProducer.html) pub trait NdProducer { /// The element produced per iteration. type Item; // Internal use / Pointee type /// Dimension type type Dim: Dimension; + + // The pointer Ptr is used by an array view to simply point to the + // current element. It doesn't have to be a pointer (see Indices). + // Its main function is that it can be incremented with a particular + // stride (= along a particular axis) + #[doc(hidden)] + /// Pointer or stand-in for pointer type Ptr: Offset; + #[doc(hidden)] + /// Pointer stride type Stride: Copy; #[doc(hidden)] From ad6fd5239b9f49e843599101cf0c7b401dcc02c5 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 21/35] Align impl style across NdProducers This makes the implementor list easier to read --- src/indexes.rs | 5 +---- src/iterators/iter.rs | 3 +++ src/iterators/mod.rs | 6 ++---- src/zip/mod.rs | 7 ++----- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index 29e7ee23d..b03e8a906 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -125,10 +125,7 @@ impl Offset for IndexPtr private_impl!{} } -impl NdProducer for Indices - where D: Dimension, - D: Copy, -{ +impl NdProducer for Indices { type Item = D::Pattern; type Dim = D; type Ptr = IndexPtr; diff --git a/src/iterators/iter.rs b/src/iterators/iter.rs index e99ac6ad0..254090296 100644 --- a/src/iterators/iter.rs +++ b/src/iterators/iter.rs @@ -3,6 +3,9 @@ //! //! This module collects all concrete producer, iterable and iterator //! implementation structs. +//! +//! +//! See also [`NdProducer`](../trait.NdProducer.html). pub use indexes::{ diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 0c6d93bf6..04497068d 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -886,8 +886,7 @@ pub fn new_axis_iter_mut(v: ArrayViewMut, axis: usize) } } -impl<'a, A, D> NdProducer for AxisIter<'a, A, D> - where D: Dimension +impl<'a, A, D: Dimension> NdProducer for AxisIter<'a, A, D> { type Item = ::Item; type Dim = Ix1; @@ -934,8 +933,7 @@ impl<'a, A, D> NdProducer for AxisIter<'a, A, D> private_impl!{} } -impl<'a, A, D> NdProducer for AxisIterMut<'a, A, D> - where D: Dimension +impl<'a, A, D: Dimension> NdProducer for AxisIterMut<'a, A, D> { type Item = ::Item; type Dim = Ix1; diff --git a/src/zip/mod.rs b/src/zip/mod.rs index b04c3f982..13b509727 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -290,8 +290,7 @@ impl<'a, A: 'a> IntoNdProducer for &'a mut Vec { } } -impl<'a, A, D> NdProducer for ArrayView<'a, A, D> - where D: Dimension, +impl<'a, A, D: Dimension> NdProducer for ArrayView<'a, A, D> { type Item = &'a A; type Dim = D; @@ -343,9 +342,7 @@ impl<'a, A, D> NdProducer for ArrayView<'a, A, D> } } -impl<'a, A, D> NdProducer for ArrayViewMut<'a, A, D> - where D: Dimension, -{ +impl<'a, A, D: Dimension> NdProducer for ArrayViewMut<'a, A, D> { type Item = &'a mut A; type Dim = D; type Ptr = *mut A; From d7f2032da3aae58118ed80e5b57024a45f1b9e5f Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 22/35] Update to itertools 0.6.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d5f02a648..f16f30577 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ version = "0.1.32" default-features = false [dependencies.itertools] -version = "0.5.0" +version = "0.6.0" [dependencies.rustc-serialize] version = "0.3.20" From 8a70dc58fe678e5d2677148bd5747322f2f958d9 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 23/35] DOC: Update method links for moved iterators --- src/iterators/chunks.rs | 8 ++++---- src/iterators/inners.rs | 4 ++-- src/iterators/mod.rs | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/iterators/chunks.rs b/src/iterators/chunks.rs index 2a11697fd..5c7471db6 100644 --- a/src/iterators/chunks.rs +++ b/src/iterators/chunks.rs @@ -29,7 +29,7 @@ type BaseProducerMut<'a, A, D> = ArrayViewMut<'a, A, D>; /// Exact chunks producer and iterable. /// -/// See [`.exact_chunks()`](struct.ArrayBase.html#method.exact_chunks) for more +/// See [`.exact_chunks()`](../struct.ArrayBase.html#method.exact_chunks) for more /// information. //#[derive(Debug)] pub struct ExactChunks<'a, A: 'a, D> { @@ -78,7 +78,7 @@ impl<'a, A, D> IntoIterator for ExactChunks<'a, A, D> /// Exact chunks iterator. /// -/// See [`.exact_chunks()`](struct.ArrayBase.html#method.exact_chunks) for more +/// See [`.exact_chunks()`](../struct.ArrayBase.html#method.exact_chunks) for more /// information. pub struct ExactChunksIter<'a, A: 'a, D> { iter: ElementsBase<'a, A, D>, @@ -108,7 +108,7 @@ impl_ndproducer! { /// Exact chunks producer and iterable. /// -/// See [`.exact_chunks_mut()`](struct.ArrayBase.html#method.exact_chunks_mut) +/// See [`.exact_chunks_mut()`](../struct.ArrayBase.html#method.exact_chunks_mut) /// for more information. //#[derive(Debug)] pub struct ExactChunksMut<'a, A: 'a, D> { @@ -249,7 +249,7 @@ impl_iterator!{ /// Exact chunks iterator. /// -/// See [`.exact_chunks_mut()`](struct.ArrayBase.html#method.exact_chunks_mut) +/// See [`.exact_chunks_mut()`](../struct.ArrayBase.html#method.exact_chunks_mut) /// for more information. pub struct ExactChunksIterMut<'a, A: 'a, D> { iter: ElementsBaseMut<'a, A, D>, diff --git a/src/iterators/inners.rs b/src/iterators/inners.rs index 7513d558b..53955a3fe 100644 --- a/src/iterators/inners.rs +++ b/src/iterators/inners.rs @@ -22,7 +22,7 @@ impl_ndproducer! { } } -/// See [`.inners()`](struct.ArrayBase.html#method.inners) +/// See [`.inners()`](../struct.ArrayBase.html#method.inners) /// for more information. pub struct Inners<'a, A: 'a, D> { base: ArrayView<'a, A, D>, @@ -88,7 +88,7 @@ impl<'a, A, D> IntoIterator for Inners<'a, A, D> } } -/// See [`.inners_mut()`](struct.ArrayBase.html#method.inners_mut) +/// See [`.inners_mut()`](../struct.ArrayBase.html#method.inners_mut) /// for more information. pub struct InnersMut<'a, A: 'a, D> { base: ArrayViewMut<'a, A, D>, diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 04497068d..d44b0a7a0 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -298,7 +298,7 @@ pub enum ElementsRepr { /// /// Iterator element type is `&'a A`. /// -/// See [`.iter()`](struct.ArrayBase.html#method.iter) for more information. +/// See [`.iter()`](../struct.ArrayBase.html#method.iter) for more information. pub struct Iter<'a, A: 'a, D> { inner: ElementsRepr, ElementsBase<'a, A, D>>, } @@ -312,7 +312,7 @@ pub struct ElementsBase<'a, A: 'a, D> { /// /// Iterator element type is `&'a mut A`. /// -/// See [`.iter_mut()`](struct.ArrayBase.html#method.iter_mut) for more information. +/// See [`.iter_mut()`](../struct.ArrayBase.html#method.iter_mut) for more information. pub struct IterMut<'a, A: 'a, D> { inner: ElementsRepr, ElementsBaseMut<'a, A, D>>, } @@ -327,12 +327,12 @@ pub struct ElementsBaseMut<'a, A: 'a, D> { /// An iterator over the indexes and elements of an array. /// -/// See [`.indexed_iter()`](struct.ArrayBase.html#method.indexed_iter) for more information. +/// See [`.indexed_iter()`](../struct.ArrayBase.html#method.indexed_iter) for more information. #[derive(Clone)] pub struct IndexedIter<'a, A: 'a, D>(ElementsBase<'a, A, D>); /// An iterator over the indexes and elements of an array (mutable). /// -/// See [`.indexed_iter_mut()`](struct.ArrayBase.html#method.indexed_iter_mut) for more information. +/// See [`.indexed_iter_mut()`](../struct.ArrayBase.html#method.indexed_iter_mut) for more information. pub struct IndexedIterMut<'a, A: 'a, D>(ElementsBaseMut<'a, A, D>); impl<'a, A, D> PrivateNew> for IndexedIter<'a, A, D> @@ -515,7 +515,7 @@ impl<'a, A, D> ExactSizeIterator for IndexedIterMut<'a, A, D> /// An iterator that traverses over all dimensions but the innermost, /// and yields each inner row. /// -/// See [`.inners()`](struct.ArrayBase.html#method.inners) for more information. +/// See [`.inners()`](../struct.ArrayBase.html#method.inners) for more information. pub struct InnerIter<'a, A: 'a, D> { inner_len: Ix, inner_stride: Ixs, @@ -552,7 +552,7 @@ impl<'a, A, D> ExactSizeIterator for InnerIter<'a, A, D> /// An iterator that traverses over all dimensions but the innermost, /// and yields each inner row (mutable). /// -/// See [`.inners_mut()`](struct.ArrayBase.html#method.inners_mut) +/// See [`.inners_mut()`](../struct.ArrayBase.html#method.inners_mut) /// for more information. pub struct InnerIterMut<'a, A: 'a, D> { inner_len: Ix, @@ -682,8 +682,8 @@ impl DoubleEndedIterator for OuterIterCore /// /// Iterator element type is `ArrayView<'a, A, D>`. /// -/// See [`.outer_iter()`](struct.ArrayBase.html#method.outer_iter) -/// or [`.axis_iter()`](struct.ArrayBase.html#method.axis_iter) +/// See [`.outer_iter()`](../struct.ArrayBase.html#method.outer_iter) +/// or [`.axis_iter()`](../struct.ArrayBase.html#method.axis_iter) /// for more information. #[derive(Debug)] pub struct AxisIter<'a, A: 'a, D> { @@ -819,8 +819,8 @@ pub fn new_axis_iter(v: ArrayView, axis: usize) /// /// Iterator element type is `ArrayViewMut<'a, A, D>`. /// -/// See [`.outer_iter_mut()`](struct.ArrayBase.html#method.outer_iter_mut) -/// or [`.axis_iter_mut()`](struct.ArrayBase.html#method.axis_iter_mut) +/// See [`.outer_iter_mut()`](../struct.ArrayBase.html#method.outer_iter_mut) +/// or [`.axis_iter_mut()`](../struct.ArrayBase.html#method.axis_iter_mut) /// for more information. pub struct AxisIterMut<'a, A: 'a, D> { iter: OuterIterCore, @@ -989,7 +989,7 @@ impl<'a, A, D: Dimension> NdProducer for AxisIterMut<'a, A, D> /// /// Iterator element type is `ArrayView<'a, A, D>`. /// -/// See [`.axis_chunks_iter()`](struct.ArrayBase.html#method.axis_chunks_iter) for more information. +/// See [`.axis_chunks_iter()`](../struct.ArrayBase.html#method.axis_chunks_iter) for more information. pub struct AxisChunksIter<'a, A: 'a, D> { iter: OuterIterCore, last_ptr: *mut A, @@ -1125,7 +1125,7 @@ macro_rules! chunk_iter_impl { /// /// Iterator element type is `ArrayViewMut<'a, A, D>`. /// -/// See [`.axis_chunks_iter_mut()`](struct.ArrayBase.html#method.axis_chunks_iter_mut) +/// See [`.axis_chunks_iter_mut()`](../struct.ArrayBase.html#method.axis_chunks_iter_mut) /// for more information. pub struct AxisChunksIterMut<'a, A: 'a, D> { iter: OuterIterCore, From 24541e117ac4c688a7bd8695ba20038d26ba8eaa Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 24/35] Remove deprecated Axis::axis() --- src/dimension/axes.rs | 2 +- src/dimension/axis.rs | 3 --- src/iterators/iter.rs | 3 +++ src/lib.rs | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/dimension/axes.rs b/src/dimension/axes.rs index 4b2913d22..2877600bd 100644 --- a/src/dimension/axes.rs +++ b/src/dimension/axes.rs @@ -15,7 +15,7 @@ pub fn axes_of<'a, D>(d: &'a D, strides: &'a D) -> Axes<'a, D> /// An iterator over the length and stride of each axis of an array. /// -/// See [`.axes()`](struct.ArrayBase.html#method.axes) for more information. +/// See [`.axes()`](../struct.ArrayBase.html#method.axes) for more information. /// /// Iterator element type is `AxisDescription`. /// diff --git a/src/dimension/axis.rs b/src/dimension/axis.rs index e222912f3..f09ee95d8 100644 --- a/src/dimension/axis.rs +++ b/src/dimension/axis.rs @@ -22,9 +22,6 @@ impl Axis { /// Return the index of the axis. #[inline(always)] pub fn index(&self) -> usize { self.0 } - #[deprecated(note = "Renamed to .index()")] - #[inline(always)] - pub fn axis(&self) -> usize { self.0 } } copy_and_clone!{Axis} diff --git a/src/iterators/iter.rs b/src/iterators/iter.rs index 254090296..5f8837db6 100644 --- a/src/iterators/iter.rs +++ b/src/iterators/iter.rs @@ -8,6 +8,9 @@ //! See also [`NdProducer`](../trait.NdProducer.html). +pub use dimension::{ + Axes, +}; pub use indexes::{ Indices, IndicesIter, diff --git a/src/lib.rs b/src/lib.rs index b71c3e4d3..dab9b1e39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,6 @@ pub use dimension::{ IntoDimension, RemoveAxis, Axis, - Axes, AxisDescription, }; pub use dimension::dim::*; From e6092d8119a92993b5128af4fdc1a27e21331c9b Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 25/35] Implement NdIndex for &IxDyn --- src/dimension/ndindex.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs index a33ac37e9..b95ae2df4 100644 --- a/src/dimension/ndindex.rs +++ b/src/dimension/ndindex.rs @@ -204,20 +204,20 @@ impl<'a> IntoDimension for &'a [Ix] { } } -unsafe impl<'a> NdIndex for &'a [Ix] { +unsafe impl<'a> NdIndex for &'a IxDyn { fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { - stride_offset_checked(dim.ix(), strides.ix(), *self) + (**self).index_checked(dim, strides) } fn index_unchecked(&self, strides: &IxDyn) -> isize { - zip(strides.ix(), *self).map(|(&s, &i)| stride_offset(i, s)).sum() + (**self).index_unchecked(strides) } } -unsafe impl NdIndex for IxDynImpl { +unsafe impl<'a> NdIndex for &'a [Ix] { fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option { - stride_offset_checked(dim.ix(), strides.ix(), self) + 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() + zip(strides.ix(), *self).map(|(&s, &i)| stride_offset(i, s)).sum() } } From 6263582d39d7f2fa69adf71104e8ddf848ca2e59 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 26/35] Fixup indexing test to actually test what we were after --- tests/dimension.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/dimension.rs b/tests/dimension.rs index ea2c527ea..ec1f312a1 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -213,10 +213,11 @@ macro_rules! ndindex { } let dim = a.shape().to_vec(); let b = a.broadcast(dim).unwrap(); - for (i, &elt) in a.indexed_iter() { + for (i, &elt) in b.indexed_iter() { let dim = i.into_dimension(); - assert_eq!(elt, b[dim]); assert_eq!(elt, b[dim.slice()]); + assert_eq!(elt, b[&dim]); + assert_eq!(elt, b[dim]); } } } From ac4ec282e4032b2ff1f9118002648c16d6dc60e7 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 27/35] DOC: Fix code indent in Zip doc --- src/zip/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 13b509727..19dbfba01 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -437,8 +437,8 @@ impl<'a, A, D: Dimension> NdProducer for ArrayViewMut<'a, A, D> { /// .and(&c) /// .and(&d) /// .apply(|w, &x, &y, &z| { -/// *w += x + y * z; -/// }); +/// *w += x + y * z; +/// }); /// ``` #[derive(Debug, Clone)] pub struct Zip { From 5bee21f9bf324acab3906bba1604f051873cc1f3 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 28/35] DOC: Change wording of indexed zip warning Let's just say it has overhead. Depending on application, it may not be significant. --- src/zip/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 19dbfba01..0bbc113f6 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -476,7 +476,7 @@ impl Zip<(Indices, P), D> /// The Zip will take the exact dimension of `p` and all inputs /// must have the same dimensions (or be broadcast to them). /// - /// *Note:* Indexed zip has significant overhead. + /// *Note:* Indexed zip has overhead. pub fn indexed(p: IP) -> Self where IP: IntoNdProducer { From 87514ecafc6f6d690b7daac542d03c5537318d84 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 29/35] =?UTF-8?q?Rename=20inners=20=E2=86=92=20lanes=20and?= =?UTF-8?q?=20so=20on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/impl_methods.rs | 14 +++++++------- src/iterators/iter.rs | 4 ++-- src/iterators/{inners.rs => lanes.rs} | 16 ++++++++-------- src/iterators/mod.rs | 26 +++++++++++++------------- 4 files changed, 30 insertions(+), 30 deletions(-) rename src/iterators/{inners.rs => lanes.rs} (90%) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index a7dfc889f..aeb259b8d 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -464,7 +464,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return a producer and iterable that traverses over the *generalized* /// rows of the array. For a 2D array these are the regular rows. /// - /// This is equivalent to `.inners(Axis(n - 1))` where *n* is `self.ndim()`. + /// This is equivalent to `.lanes(Axis(n - 1))` where *n* is `self.ndim()`. /// /// For an array of dimensions *a* × *b* × *c* × ... × *l* × *m* /// it has *a* × *b* × *c* × ... × *l* rows each of length *m*. @@ -508,7 +508,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return a producer and iterable that traverses over the *generalized* /// columns of the array. For a 2D array these are the regular columns. /// - /// This is equivalent to `.inners(Axis(0))`. + /// This is equivalent to `.lanes(Axis(0))`. /// /// For an array of dimensions *a* × *b* × *c* × ... × *l* × *m* /// it has *b* × *c* × ... × *l* × *m* columns each of length *a*. @@ -559,9 +559,9 @@ impl ArrayBase where S: Data, D: Dimension /// [[ 6, 7, 8], /// [ 9, 10, 11]]]); /// - /// let inner0 = a.inners(Axis(0)); - /// let inner1 = a.inners(Axis(1)); - /// let inner2 = a.inners(Axis(2)); + /// let inner0 = a.lanes(Axis(0)); + /// let inner1 = a.lanes(Axis(1)); + /// let inner2 = a.lanes(Axis(2)); /// /// // The first lane for axis 0 is [0, 6] /// assert_eq!(inner0.into_iter().next().unwrap(), aview1(&[0, 6])); @@ -570,7 +570,7 @@ impl ArrayBase where S: Data, D: Dimension /// // The first lane for axis 2 is [0, 1, 2] /// assert_eq!(inner2.into_iter().next().unwrap(), aview1(&[0, 1, 2])); /// ``` - pub fn inners(&self, axis: Axis) -> Inners { + pub fn lanes(&self, axis: Axis) -> Inners { new_inners(self.view(), axis) } @@ -578,7 +578,7 @@ impl ArrayBase where S: Data, D: Dimension /// pointing in the direction of `axis`. /// /// Iterator element is `ArrayViewMut1` (1D read-write array view). - pub fn inners_mut(&mut self, axis: Axis) -> InnersMut + pub fn lanes_mut(&mut self, axis: Axis) -> InnersMut where S: DataMut { new_inners_mut(self.view_mut(), axis) diff --git a/src/iterators/iter.rs b/src/iterators/iter.rs index 5f8837db6..2ca30b07b 100644 --- a/src/iterators/iter.rs +++ b/src/iterators/iter.rs @@ -22,8 +22,8 @@ pub use iterators::{ IndexedIterMut, Inners, InnersMut, - InnerIter, - InnerIterMut, + LaneIter, + LaneIterMut, AxisIter, AxisIterMut, AxisChunksIter, diff --git a/src/iterators/inners.rs b/src/iterators/lanes.rs similarity index 90% rename from src/iterators/inners.rs rename to src/iterators/lanes.rs index 53955a3fe..e8dd18792 100644 --- a/src/iterators/inners.rs +++ b/src/iterators/lanes.rs @@ -1,8 +1,8 @@ use imp_prelude::*; use {NdProducer, Layout}; -use super::InnerIter; -use super::InnerIterMut; +use super::LaneIter; +use super::LaneIterMut; impl_ndproducer! { ['a, A, D: Dimension] @@ -22,7 +22,7 @@ impl_ndproducer! { } } -/// See [`.inners()`](../struct.ArrayBase.html#method.inners) +/// See [`.lanes()`](../struct.ArrayBase.html#method.lanes) /// for more information. pub struct Inners<'a, A: 'a, D> { base: ArrayView<'a, A, D>, @@ -78,9 +78,9 @@ impl<'a, A, D> IntoIterator for Inners<'a, A, D> where D: Dimension, { type Item = ::Item; - type IntoIter = InnerIter<'a, A, D>; + type IntoIter = LaneIter<'a, A, D>; fn into_iter(self) -> Self::IntoIter { - InnerIter { + LaneIter { iter: self.base.into_base_iter(), inner_len: self.inner_len, inner_stride: self.inner_stride, @@ -88,7 +88,7 @@ impl<'a, A, D> IntoIterator for Inners<'a, A, D> } } -/// See [`.inners_mut()`](../struct.ArrayBase.html#method.inners_mut) +/// See [`.lanes_mut()`](../struct.ArrayBase.html#method.lanes_mut) /// for more information. pub struct InnersMut<'a, A: 'a, D> { base: ArrayViewMut<'a, A, D>, @@ -126,9 +126,9 @@ impl<'a, A, D> IntoIterator for InnersMut<'a, A, D> where D: Dimension, { type Item = ::Item; - type IntoIter = InnerIterMut<'a, A, D>; + type IntoIter = LaneIterMut<'a, A, D>; fn into_iter(self) -> Self::IntoIter { - InnerIterMut { + LaneIterMut { iter: self.base.into_base_iter(), inner_len: self.inner_len, inner_stride: self.inner_stride, diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index d44b0a7a0..917236299 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -9,7 +9,7 @@ #[macro_use] mod macros; mod chunks; -mod inners; +mod lanes; pub mod iter; use std::marker::PhantomData; @@ -38,7 +38,7 @@ pub use self::chunks::{ ExactChunksIterMut, exact_chunks_mut_of, }; -pub use self::inners::{ +pub use self::lanes::{ new_inners, new_inners_mut, Inners, @@ -515,14 +515,14 @@ impl<'a, A, D> ExactSizeIterator for IndexedIterMut<'a, A, D> /// An iterator that traverses over all dimensions but the innermost, /// and yields each inner row. /// -/// See [`.inners()`](../struct.ArrayBase.html#method.inners) for more information. -pub struct InnerIter<'a, A: 'a, D> { +/// See [`.lanes()`](../struct.ArrayBase.html#method.lanes) for more information. +pub struct LaneIter<'a, A: 'a, D> { inner_len: Ix, inner_stride: Ixs, iter: Baseiter<'a, A, D>, } -impl<'a, A, D> Iterator for InnerIter<'a, A, D> +impl<'a, A, D> Iterator for LaneIter<'a, A, D> where D: Dimension { type Item = ArrayView<'a, A, Ix1>; @@ -538,7 +538,7 @@ impl<'a, A, D> Iterator for InnerIter<'a, A, D> } } -impl<'a, A, D> ExactSizeIterator for InnerIter<'a, A, D> +impl<'a, A, D> ExactSizeIterator for LaneIter<'a, A, D> where D: Dimension { fn len(&self) -> usize { @@ -546,21 +546,21 @@ impl<'a, A, D> ExactSizeIterator for InnerIter<'a, A, D> } } -// NOTE: InnerIterMut is a mutable iterator and must not expose aliasing +// NOTE: LaneIterMut is a mutable iterator and must not expose aliasing // pointers. Due to this we use an empty slice for the raw data (it's unused // anyway). /// An iterator that traverses over all dimensions but the innermost, /// and yields each inner row (mutable). /// -/// See [`.inners_mut()`](../struct.ArrayBase.html#method.inners_mut) +/// See [`.lanes_mut()`](../struct.ArrayBase.html#method.lanes_mut) /// for more information. -pub struct InnerIterMut<'a, A: 'a, D> { +pub struct LaneIterMut<'a, A: 'a, D> { inner_len: Ix, inner_stride: Ixs, iter: Baseiter<'a, A, D>, } -impl<'a, A, D> Iterator for InnerIterMut<'a, A, D> +impl<'a, A, D> Iterator for LaneIterMut<'a, A, D> where D: Dimension, { type Item = ArrayViewMut<'a, A, Ix1>; @@ -578,7 +578,7 @@ impl<'a, A, D> Iterator for InnerIterMut<'a, A, D> } } -impl<'a, A, D> ExactSizeIterator for InnerIterMut<'a, A, D> +impl<'a, A, D> ExactSizeIterator for LaneIterMut<'a, A, D> where D: Dimension, { fn len(&self) -> usize { @@ -1154,14 +1154,14 @@ chunk_iter_impl!(AxisChunksIterMut, ArrayViewMut); send_sync_read_only!(Iter); send_sync_read_only!(IndexedIter); -send_sync_read_only!(InnerIter); +send_sync_read_only!(LaneIter); send_sync_read_only!(AxisIter); send_sync_read_only!(AxisChunksIter); send_sync_read_only!(ElementsBase); send_sync_read_write!(IterMut); send_sync_read_write!(IndexedIterMut); -send_sync_read_write!(InnerIterMut); +send_sync_read_write!(LaneIterMut); send_sync_read_write!(AxisIterMut); send_sync_read_write!(AxisChunksIterMut); send_sync_read_write!(ElementsBaseMut); From 92018db11e8b2625661de5e030fc2fe79459f666 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:43:04 +0200 Subject: [PATCH 30/35] DOC: Add section for iteration and looping --- src/lib.rs | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index dab9b1e39..a14b1449c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -204,6 +204,7 @@ pub type Ixs = isize; /// + [RcArray](#rcarray) /// + [Array Views](#array-views) /// + [Indexing and Dimension](#indexing-and-dimension) +/// + [Loops, Producers and Iterators](#loops-producers-and-iterators) /// + [Slicing](#slicing) /// + [Subviews](#subviews) /// + [Arithmetic Operations](#arithmetic-operations) @@ -316,6 +317,90 @@ pub type Ixs = isize; /// (the rightmost index is varying the fastest). /// The iterators `.iter(), .iter_mut()` always adhere to this order, for example. /// +/// ## Loops, Producers and Iterators +/// +/// Using [`Zip`](struct.Zip.html) is the most general way to apply a procedure +/// across one or several arrays or *producers*. +/// +/// [`NdProducer`](trait.NdProducer.html) is like an iterable but for +/// multidimensional data. All producers have dimensions and axes, like an +/// array view, and they can be split and used with parallelization using `Zip`. +/// +/// For example, `ArrayView` is a producer, it has the same dimensions +/// as the array view and for each iteration it produces a reference to +/// the array element (`&A` in this case). +/// +/// Another example, if we have a 10 × 10 array and use `.exact_chunks((2, 2))` +/// we get a producer of chunks which has the dimensions 5 × 5 (because +/// there are *10 / 2 = 5* chunks in either direction). The 5 × 5 chunks producer +/// can be paired with any other producers of the same dimension with `Zip`, for +/// example 5 × 5 arrays. +/// +/// ### `.iter()` and `.iter_mut()` +/// +/// These are the element iterators of arrays and they produce an element +/// sequence in the logical order of the array, that means that the elements +/// will be visited in the sequence that corresponds to increasing the +/// last index first: *0, ..., 0, 0*; *0, ..., 0, 1*; *0, ...0, 2* and so on. +/// +/// ### `.outer_iter()` and `.axis_iter()` +/// +/// These iterators produce array views of one smaller dimension. +/// +/// For example, for a 2D array, `.outer_iter()` will produce the 1D rows. +/// For a 3D array, `.outer_iter()` produces 2D subviews. +/// +/// `.axis_iter()` is like `outer_iter()` but allows you to pick which +/// axis to traverse. +/// +/// The `outer_iter` and `axis_iter` are one dimensional producers. +/// +/// ## `.genrows()`, `.gencolumns()` and `.lanes()` +/// +/// [`.genrows()`][gr] is a producer (and iterable) of all rows in an array. +/// +/// ``` +/// use ndarray::Array; +/// +/// // 1. Loop over the rows of a 2D array +/// let mut a = Array::zeros((10, 10)); +/// for mut row in a.genrows_mut() { +/// row.fill(1.); +/// } +/// +/// // 2. Use Zip to pair each row in 2D `a` with elements in 1D `b` +/// use ndarray::Zip; +/// let mut b = Array::zeros(a.rows()); +/// +/// Zip::from(a.genrows()) +/// .and(&mut b) +/// .apply(|a_row, b_elt| { +/// *b_elt = a_row[a.cols() - 1] - a_row[0]; +/// }); +/// ``` +/// +/// The *lanes* of an array are 1D segments along an axis and when pointed +/// along the last axis they are *rows*, when pointed along the first axis +/// they are *columns*. +/// +/// A *m* × *n* array has *m* rows each of length *n* and conversely +/// *n* columns each of length *m*. +/// +/// To generalize this, we say that an array of dimension *a* × *m* × *n* +/// has *a m* rows. It's composed of *a* times the previous array, so it +/// has *a* times as many rows. +/// +/// All methods: [`.genrows()`][gr], [`.genrows_mut()`][grm], +/// [`.gencolumns()`][gc], [`.gencolumns_mut()`][gcm], +/// [`.lanes(axis)`][l], [`.lanes_mut(axis)`][lm]. +/// +/// [gr]: #method.genrows +/// [grm]: #method.genrows_mut +/// [gc]: #method.gencolumns +/// [gcm]: #method.gencolumns_mut +/// [l]: #method.lanes +/// [lm]: #method.lanes_mut +/// /// ## Slicing /// /// You can use slicing to create a view of a subset of the data in From d1f87cbc7fcdf63042eba8ca41e0d25e916763bc Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 17:57:03 +0200 Subject: [PATCH 31/35] DOC: Update .lanes() --- src/impl_methods.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index aeb259b8d..17cc21b51 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -548,8 +548,11 @@ impl ArrayBase where S: Data, D: Dimension /// Return a producer and iterable that traverses over all 1D lanes /// pointing in the direction of `axis`. /// - /// Iterator element is `ArrayView1` (1D array view); note that it is - /// always 1D. + /// When the point in the direction of the first axis, they are *columns*, + /// in the direction of the last axis *rows*; in general they are all + /// *lanes* and are one dimensional. + /// + /// Iterator element is `ArrayView1` (1D array view). /// /// ``` /// use ndarray::{arr3, aview1, Axis}; From 8efffe49019383a0e9f4db2ffe72ddd22fbd9e66 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 18:01:53 +0200 Subject: [PATCH 32/35] parallel: Update for moved iterator structs --- parallel/src/par.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parallel/src/par.rs b/parallel/src/par.rs index 3efcc8119..0afa2d5b4 100644 --- a/parallel/src/par.rs +++ b/parallel/src/par.rs @@ -10,8 +10,8 @@ use rayon::par_iter::internal::Producer; use rayon::par_iter::internal::UnindexedProducer; use rayon::par_iter::internal::bridge_unindexed; -use ndarray::AxisIter; -use ndarray::AxisIterMut; +use ndarray::iter::AxisIter; +use ndarray::iter::AxisIterMut; use ndarray::{Dimension}; use ndarray::{ArrayView, ArrayViewMut}; From ec8aaab2b01c777a595884adb7cbe9b2bbe21f56 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 18:47:54 +0200 Subject: [PATCH 33/35] zip: Split by axis of len > 1, always This fixes a problem where it would repeatedly split an Indices producer along a zero-length axis. --- src/zip/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 0bbc113f6..2e4f6d835 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -515,11 +515,11 @@ impl Zip /// others. fn max_stride_axis(&self) -> Axis { let i = match self.layout.flag() { - CORDER => self.dimension.slice().iter() - .position(|&len| len > 1).unwrap_or(0), FORDER => self.dimension.slice().iter() .rposition(|&len| len > 1).unwrap_or(self.dimension.ndim() - 1), - _ => 0, + /* corder or default */ + _ => self.dimension.slice().iter() + .position(|&len| len > 1).unwrap_or(0), }; Axis(i) } From 5f70817a74218b075816de9907f298ed5734c805 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 19:42:04 +0200 Subject: [PATCH 34/35] zip: Add test for index split --- tests/azip.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/azip.rs b/tests/azip.rs index ffcc7f1b5..16d895e90 100644 --- a/tests/azip.rs +++ b/tests/azip.rs @@ -242,3 +242,32 @@ fn test_indices_3() { }); assert_eq!(count, len); } + +#[test] +fn test_indices_split_1() { + for m in (0..4).chain(10..12) { + for n in (0..4).chain(10..12) { + let a1 = Array::::default((m, n)); + let (a, b) = Zip::indexed(&a1).split(); + let mut seen = Vec::new(); + + let mut ac = 0; + a.apply(|i, _| { + ac += 1; + seen.push(i); + }); + let mut bc = 0; + b.apply(|i, _| { + bc += 1; + seen.push(i); + }); + + assert_eq!(a1.len(), ac + bc); + + seen.sort(); + assert_eq!(seen.len(), a1.len()); + seen.dedup(); + assert_eq!(seen.len(), a1.len()); + } + } +} From b44020d238fb49c62736410acb0b6ce8f205cee7 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 6 Apr 2017 20:16:47 +0200 Subject: [PATCH 35/35] zip: Debug assertions in split --- src/zip/mod.rs | 2 ++ tests/azip.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 2e4f6d835..91f666afd 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -778,6 +778,8 @@ macro_rules! map_impl { /// /// It will be split in the way that best preserves element locality. pub fn split(self) -> (Self, Self) { + debug_assert_ne!(self.size(), 0, "Attempt to split empty zip"); + debug_assert_ne!(self.size(), 1, "Attempt to split zip with 1 elem"); // Always split in a way that preserves layout (if any) let axis = self.max_stride_axis(); let index = self.len_of(axis) / 2; diff --git a/tests/azip.rs b/tests/azip.rs index 16d895e90..6e5cd300f 100644 --- a/tests/azip.rs +++ b/tests/azip.rs @@ -248,6 +248,9 @@ fn test_indices_split_1() { for m in (0..4).chain(10..12) { for n in (0..4).chain(10..12) { let a1 = Array::::default((m, n)); + if a1.len() <= 1 { + continue; + } let (a, b) = Zip::indexed(&a1).split(); let mut seen = Vec::new();