Skip to content

Rework subview methods and other related methods #537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 19, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/axis_ops.rs
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ fn main() {
}
a.swap_axes(0, 1);
a.swap_axes(0, 2);
a.slice_inplace(s![.., ..;-1, ..]);
a.slice_collapse(s![.., ..;-1, ..]);
regularize(&mut a).ok();

let mut b = Array::<u8, _>::zeros((2, 3, 4));
@@ -64,6 +64,6 @@ fn main() {
for (i, elt) in (0..).zip(&mut a) {
*elt = i;
}
a.slice_inplace(s![..;-1, ..;2, ..]);
a.slice_collapse(s![..;-1, ..;2, ..]);
regularize(&mut a).ok();
}
4 changes: 2 additions & 2 deletions examples/sort-axis.rs
Original file line number Diff line number Diff line change
@@ -109,8 +109,8 @@ impl<A, D> PermuteArray for Array<A, D>
result = Array::from_shape_vec_unchecked(self.dim(), v);
for i in 0..axis_len {
let perm_i = perm.indices[i];
Zip::from(result.subview_mut(axis, perm_i))
.and(self.subview(axis, i))
Zip::from(result.index_axis_mut(axis, perm_i))
.and(self.index_axis(axis, i))
.apply(|to, from| {
copy_nonoverlapping(from, to, 1)
});
8 changes: 4 additions & 4 deletions serialization-tests/tests/serialize.rs
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ fn serial_many_dim()
{
// Test a sliced array.
let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
a.slice_inplace(s![..;-1, .., .., ..2]);
a.slice_collapse(s![..;-1, .., .., ..2]);
let serial = json::encode(&a).unwrap();
println!("Encode {:?} => {:?}", a, serial);
let res = json::decode::<RcArray<f32, _>>(&serial);
@@ -114,7 +114,7 @@ fn serial_many_dim_serde()
{
// Test a sliced array.
let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
a.slice_inplace(s![..;-1, .., .., ..2]);
a.slice_collapse(s![..;-1, .., .., ..2]);
let serial = serde_json::to_string(&a).unwrap();
println!("Encode {:?} => {:?}", a, serial);
let res = serde_json::from_str::<RcArray<f32, _>>(&serial);
@@ -221,7 +221,7 @@ fn serial_many_dim_serde_msgpack()
{
// Test a sliced array.
let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
a.slice_inplace(s![..;-1, .., .., ..2]);
a.slice_collapse(s![..;-1, .., .., ..2]);

let mut buf = Vec::new();
serde::Serialize::serialize(&a, &mut rmp_serde::Serializer::new(&mut buf)).ok().unwrap();
@@ -273,7 +273,7 @@ fn serial_many_dim_ron()
{
// Test a sliced array.
let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
a.slice_inplace(s![..;-1, .., .., ..2]);
a.slice_collapse(s![..;-1, .., .., ..2]);

let a_s = ron_serialize(&a).unwrap();

13 changes: 9 additions & 4 deletions src/dimension/mod.rs
Original file line number Diff line number Diff line change
@@ -197,13 +197,18 @@ impl<'a> DimensionExt for [Ix]
///
/// **Panics** if `index` is larger than the size of the axis
// FIXME: Move to Dimension trait
pub fn do_sub<A, D: Dimension>(dims: &mut D, ptr: &mut *mut A, strides: &D,
axis: usize, index: Ix) {
pub fn do_collapse_axis<A, D: Dimension>(
dims: &mut D,
ptr: &mut *mut A,
strides: &D,
axis: usize,
index: usize,
) {
let dim = dims.slice()[axis];
let stride = strides.slice()[axis];
ndassert!(index < dim,
concat!("subview: Index {} must be less than axis length {} ",
"for array with shape {:?}"),
"collapse_axis: Index {} must be less than axis length {} for \
array with shape {:?}",
index, dim, *dims);
dims.slice_mut()[axis] = 1;
let off = stride_offset(index, stride);
8 changes: 4 additions & 4 deletions src/doc/ndarray_for_numpy_users/mod.rs
Original file line number Diff line number Diff line change
@@ -229,7 +229,7 @@
//! Only the non-mutable methods that take the array by reference are listed in
//! this table. For example, [`.slice()`][.slice()] also has corresponding
//! methods [`.slice_mut()`][.slice_mut()], [`.slice_move()`][.slice_move()], and
//! [`.slice_inplace()`][.slice_inplace()].
//! [`.slice_collapse()`][.slice_collapse()].
//!
//! * The behavior of slicing is slightly different from NumPy for slices with
//! `step < -1`. See the docs for the [`s![]` macro][s!] for more details.
@@ -238,7 +238,7 @@
//! ------|-----------|------
//! `a[-1]` | [`a[a.len() - 1]`][.index()] | access the last element in 1-D array `a`
//! `a[1, 4]` | [`a[[1, 4]]`][.index()] | access the element in row 1, column 4
//! `a[1]` or `a[1, :, :]` | [`a.slice(s![1, .., ..])`][.slice()] or [`a.subview(Axis(0), 1)`][.subview()] | get a 2-D subview of a 3-D array at index 1 of axis 0
//! `a[1]` or `a[1, :, :]` | [`a.slice(s![1, .., ..])`][.slice()] or [`a.index_axis(Axis(0), 1)`][.index_axis()] | get a 2-D subview of a 3-D array at index 1 of axis 0
//! `a[0:5]` or `a[:5]` or `a[0:5, :]` | [`a.slice(s![0..5, ..])`][.slice()] or [`a.slice(s![..5, ..])`][.slice()] or [`a.slice_axis(Axis(0), Slice::from(0..5))`][.slice_axis()] | get the first 5 rows of a 2-D array
//! `a[-5:]` or `a[-5:, :]` | [`a.slice(s![-5.., ..])`][.slice()] or [`a.slice_axis(Axis(0), Slice::from(-5..))`][.slice_axis()] | get the last 5 rows of a 2-D array
//! `a[:3, 4:9]` | [`a.slice(s![..3, 4..9])`][.slice()] | columns 4, 5, 6, 7, and 8 of the first 3 rows
@@ -618,14 +618,14 @@
//! [.sum()]: ../../struct.ArrayBase.html#method.sum
//! [.slice()]: ../../struct.ArrayBase.html#method.slice
//! [.slice_axis()]: ../../struct.ArrayBase.html#method.slice_axis
//! [.slice_inplace()]: ../../struct.ArrayBase.html#method.slice_inplace
//! [.slice_collapse()]: ../../struct.ArrayBase.html#method.slice_collapse
//! [.slice_move()]: ../../struct.ArrayBase.html#method.slice_move
//! [.slice_mut()]: ../../struct.ArrayBase.html#method.slice_mut
//! [.shape()]: ../../struct.ArrayBase.html#method.shape
//! [stack!]: ../../macro.stack.html
//! [stack()]: ../../fn.stack.html
//! [.strides()]: ../../struct.ArrayBase.html#method.strides
//! [.subview()]: ../../struct.ArrayBase.html#method.subview
//! [.index_axis()]: ../../struct.ArrayBase.html#method.index_axis
//! [.sum_axis()]: ../../struct.ArrayBase.html#method.sum_axis
//! [.t()]: ../../struct.ArrayBase.html#method.t
//! [::uninitialized()]: ../../struct.ArrayBase.html#method.uninitialized
8 changes: 4 additions & 4 deletions src/impl_2d.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ impl<A, S> ArrayBase<S, Ix2>
/// **Panics** if `index` is out of bounds.
pub fn row(&self, index: Ix) -> ArrayView1<A>
{
self.subview(Axis(0), index)
self.index_axis(Axis(0), index)
}

/// Return a mutable array view of row `index`.
@@ -28,7 +28,7 @@ impl<A, S> ArrayBase<S, Ix2>
pub fn row_mut(&mut self, index: Ix) -> ArrayViewMut1<A>
where S: DataMut
{
self.subview_mut(Axis(0), index)
self.index_axis_mut(Axis(0), index)
}

/// Return the number of rows (length of `Axis(0)`) in the two-dimensional array.
@@ -41,7 +41,7 @@ impl<A, S> ArrayBase<S, Ix2>
/// **Panics** if `index` is out of bounds.
pub fn column(&self, index: Ix) -> ArrayView1<A>
{
self.subview(Axis(1), index)
self.index_axis(Axis(1), index)
}

/// Return a mutable array view of column `index`.
@@ -50,7 +50,7 @@ impl<A, S> ArrayBase<S, Ix2>
pub fn column_mut(&mut self, index: Ix) -> ArrayViewMut1<A>
where S: DataMut
{
self.subview_mut(Axis(1), index)
self.index_axis_mut(Axis(1), index)
}

/// Return the number of columns (length of `Axis(1)`) in the two-dimensional array.
58 changes: 58 additions & 0 deletions src/impl_dyn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2018 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Methods for dynamic-dimensional arrays.
use imp_prelude::*;

/// # Methods for Dynamic-Dimensional Arrays
impl<A, S> ArrayBase<S, IxDyn>
where
S: Data<Elem = A>,
{
/// Insert new array axis of length 1 at `axis`, modifying the shape and
/// strides in-place.
///
/// **Panics** if the axis is out of bounds.
///
/// ```
/// use ndarray::{Axis, arr2, arr3};
///
/// let mut a = arr2(&[[1, 2, 3], [4, 5, 6]]).into_dyn();
/// assert_eq!(a.shape(), &[2, 3]);
///
/// a.insert_axis_inplace(Axis(1));
/// assert_eq!(a, arr3(&[[[1, 2, 3]], [[4, 5, 6]]]).into_dyn());
/// assert_eq!(a.shape(), &[2, 1, 3]);
/// ```
pub fn insert_axis_inplace(&mut self, axis: Axis) {
assert!(axis.index() <= self.ndim());
self.dim = self.dim.insert_axis(axis);
self.strides = self.strides.insert_axis(axis);
}

/// Collapses the array to `index` along the axis and removes the axis,
/// modifying the shape and strides in-place.
///
/// **Panics** if `axis` or `index` is out of bounds.
///
/// ```
/// use ndarray::{Axis, arr1, arr2};
///
/// let mut a = arr2(&[[1, 2, 3], [4, 5, 6]]).into_dyn();
/// assert_eq!(a.shape(), &[2, 3]);
///
/// a.index_axis_inplace(Axis(1), 1);
/// assert_eq!(a, arr1(&[2, 5]).into_dyn());
/// assert_eq!(a.shape(), &[2]);
/// ```
pub fn index_axis_inplace(&mut self, axis: Axis, index: usize) {
self.collapse_axis(axis, index);
self.dim = self.dim.remove_axis(axis);
self.strides = self.strides.remove_axis(axis);
}
}
126 changes: 92 additions & 34 deletions src/impl_methods.rs
Original file line number Diff line number Diff line change
@@ -310,8 +310,8 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
where
Do: Dimension,
{
// Slice and subview in-place without changing the number of dimensions.
self.slice_inplace(&*info);
// Slice and collapse in-place without changing the number of dimensions.
self.slice_collapse(&*info);

let indices: &[SliceOrIndex] = (**info).as_ref();

@@ -352,7 +352,7 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
///
/// **Panics** if an index is out of bounds or step size is zero.<br>
/// (**Panics** if `D` is `IxDyn` and `indices` does not match the number of array axes.)
pub fn slice_inplace(&mut self, indices: &D::SliceArg) {
pub fn slice_collapse(&mut self, indices: &D::SliceArg) {
let indices: &[SliceOrIndex] = indices.as_ref();
assert_eq!(indices.len(), self.ndim());
indices
@@ -364,11 +364,20 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
}
&SliceOrIndex::Index(index) => {
let i_usize = abs_index(self.len_of(Axis(axis)), index);
self.subview_inplace(Axis(axis), i_usize)
self.collapse_axis(Axis(axis), i_usize)
}
});
}

/// Slice the array in place without changing the number of dimensions.
///
/// **Panics** if an index is out of bounds or step size is zero.<br>
/// (**Panics** if `D` is `IxDyn` and `indices` does not match the number of array axes.)
#[deprecated(note="renamed to `slice_collapse`", since="0.12.1")]
pub fn slice_inplace(&mut self, indices: &D::SliceArg) {
self.slice_collapse(indices)
}

/// Return a view of the array, sliced along the specified axis.
///
/// **Panics** if an index is out of bounds or step size is zero.<br>
@@ -542,8 +551,8 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
}
}

/// Along `axis`, select the subview `index` and return a
/// view with that axis removed.
/// Returns a view restricted to `index` along the axis, with the axis
/// removed.
///
/// See [*Subviews*](#subviews) for full documentation.
///
@@ -559,18 +568,19 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
/// // . axis 1, column 1
/// // axis 1, column 0
/// assert!(
/// a.subview(Axis(0), 1) == ArrayView::from(&[3., 4.]) &&
/// a.subview(Axis(1), 1) == ArrayView::from(&[2., 4., 6.])
/// a.index_axis(Axis(0), 1) == ArrayView::from(&[3., 4.]) &&
/// a.index_axis(Axis(1), 1) == ArrayView::from(&[2., 4., 6.])
/// );
/// ```
pub fn subview(&self, axis: Axis, index: Ix) -> ArrayView<A, D::Smaller>
where D: RemoveAxis,
pub fn index_axis(&self, axis: Axis, index: usize) -> ArrayView<A, D::Smaller>
where
D: RemoveAxis,
{
self.view().into_subview(axis, index)
self.view().index_axis_move(axis, index)
}

/// Along `axis`, select the subview `index` and return a read-write view
/// with the axis removed.
/// Returns a mutable view restricted to `index` along the axis, with the
/// axis removed.
///
/// **Panics** if `axis` or `index` is out of bounds.
///
@@ -584,7 +594,7 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
/// // axis 1, column 0
///
/// {
/// let mut column1 = a.subview_mut(Axis(1), 1);
/// let mut column1 = a.index_axis_mut(Axis(1), 1);
/// column1 += 10.;
/// }
///
@@ -593,32 +603,87 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
/// [3., 14.]])
/// );
/// ```
pub fn index_axis_mut(&mut self, axis: Axis, index: usize) -> ArrayViewMut<A, D::Smaller>
where
S: DataMut,
D: RemoveAxis,
{
self.view_mut().index_axis_move(axis, index)
}

/// Collapses the array to `index` along the axis and removes the axis.
///
/// See [`.index_axis()`](#method.index_axis) and [*Subviews*](#subviews) for full documentation.
///
/// **Panics** if `axis` or `index` is out of bounds.
pub fn index_axis_move(mut self, axis: Axis, index: usize) -> ArrayBase<S, D::Smaller>
where
D: RemoveAxis,
{
self.collapse_axis(axis, index);
let dim = self.dim.remove_axis(axis);
let strides = self.strides.remove_axis(axis);
ArrayBase {
ptr: self.ptr,
data: self.data,
dim,
strides,
}
}

/// Selects `index` along the axis, collapsing the axis into length one.
///
/// **Panics** if `axis` or `index` is out of bounds.
pub fn collapse_axis(&mut self, axis: Axis, index: usize) {
dimension::do_collapse_axis(
&mut self.dim,
&mut self.ptr,
&self.strides,
axis.index(),
index,
)
}

/// Along `axis`, select the subview `index` and return a
/// view with that axis removed.
///
/// **Panics** if `axis` or `index` is out of bounds.
#[deprecated(note="renamed to `index_axis`", since="0.12.1")]
pub fn subview(&self, axis: Axis, index: Ix) -> ArrayView<A, D::Smaller>
where D: RemoveAxis,
{
self.index_axis(axis, index)
}

/// Along `axis`, select the subview `index` and return a read-write view
/// with the axis removed.
///
/// **Panics** if `axis` or `index` is out of bounds.
#[deprecated(note="renamed to `index_axis_mut`", since="0.12.1")]
pub fn subview_mut(&mut self, axis: Axis, index: Ix)
-> ArrayViewMut<A, D::Smaller>
where S: DataMut,
D: RemoveAxis,
{
self.view_mut().into_subview(axis, index)
self.index_axis_mut(axis, index)
}

/// Collapse dimension `axis` into length one,
/// and select the subview of `index` along that axis.
///
/// **Panics** if `index` is past the length of the axis.
#[deprecated(note="renamed to `collapse_axis`", since="0.12.1")]
pub fn subview_inplace(&mut self, axis: Axis, index: Ix) {
dimension::do_sub(&mut self.dim, &mut self.ptr, &self.strides,
axis.index(), index)
self.collapse_axis(axis, index)
}

/// Along `axis`, select the subview `index` and return `self`
/// with that axis removed.
///
/// See [`.subview()`](#method.subview) and [*Subviews*](#subviews) for full documentation.
pub fn into_subview(mut self, axis: Axis, index: Ix) -> ArrayBase<S, D::Smaller>
#[deprecated(note="renamed to `index_axis_move`", since="0.12.1")]
pub fn into_subview(self, axis: Axis, index: Ix) -> ArrayBase<S, D::Smaller>
where D: RemoveAxis,
{
self.subview_inplace(axis, index);
self.remove_axis(axis)
self.index_axis_move(axis, index)
}

/// Along `axis`, select arbitrary subviews corresponding to `indices`
@@ -648,7 +713,7 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
{
let mut subs = vec![self.view(); indices.len()];
for (&i, sub) in zip(indices, &mut subs[..]) {
sub.subview_inplace(axis, i);
sub.collapse_axis(axis, i);
}
if subs.is_empty() {
let mut dim = self.raw_dim();
@@ -1528,18 +1593,11 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
/// Remove array axis `axis` and return the result.
///
/// **Panics** if the axis is out of bounds or its length is zero.
#[deprecated(note="use `.index_axis_move(Axis(_), 0)` instead", since="0.12.1")]
pub fn remove_axis(self, axis: Axis) -> ArrayBase<S, D::Smaller>
where D: RemoveAxis,
{
assert_ne!(self.len_of(axis), 0, "Length of removed axis must be nonzero.");
let d = self.dim.remove_axis(axis);
let s = self.strides.remove_axis(axis);
ArrayBase {
ptr: self.ptr,
data: self.data,
dim: d,
strides: s,
}
self.index_axis_move(axis, 0)
}

fn pointer_is_inbounds(&self) -> bool {
@@ -1857,7 +1915,7 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
let view_stride = self.strides.axis(axis);
// use the 0th subview as a map to each 1d array view extended from
// the 0th element.
self.subview(axis, 0).map(|first_elt| {
self.index_axis(axis, 0).map(|first_elt| {
unsafe {
mapping(ArrayView::new_(first_elt, Ix1(view_len), Ix1(view_stride)))
}
@@ -1885,7 +1943,7 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
let view_stride = self.strides.axis(axis);
// use the 0th subview as a map to each 1d array view extended from
// the 0th element.
self.subview_mut(axis, 0).map_mut(|first_elt: &mut A| {
self.index_axis_mut(axis, 0).map_mut(|first_elt: &mut A| {
unsafe {
mapping(ArrayViewMut::new_(first_elt, Ix1(view_len), Ix1(view_stride)))
}
67 changes: 38 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -242,6 +242,7 @@ pub type Ixs = isize;
/// + [Methods For All Array Types](#methods-for-all-array-types)
/// + [Methods For 1-D Arrays](#methods-for-1-d-arrays)
/// + [Methods For 2-D Arrays](#methods-for-2-d-arrays)
/// + [Methods for Dynamic-Dimensional Arrays](#methods-for-dynamic-dimensional-arrays)
/// + [Numerical Methods for Arrays](#numerical-methods-for-arrays)
///
/// ## `Array`
@@ -444,23 +445,24 @@ pub type Ixs = isize;
///
/// You can use slicing to create a view of a subset of the data in
/// the array. Slicing methods include [`.slice()`], [`.slice_mut()`],
/// [`.slice_move()`], and [`.slice_inplace()`].
/// [`.slice_move()`], and [`.slice_collapse()`].
///
/// The slicing argument can be passed using the macro [`s![]`](macro.s!.html),
/// which will be used in all examples. (The explicit form is an instance of
/// [`&SliceInfo`]; see its docs for more information.)
///
/// [`&SliceInfo`]: struct.SliceInfo.html
///
/// If a range is used, the axis is preserved. If an index is used, a subview
/// is taken with respect to the axis. See [*Subviews*](#subviews) for more
/// information about subviews. Note that [`.slice_inplace()`] behaves like
/// [`.subview_inplace()`] by preserving the number of dimensions.
/// If a range is used, the axis is preserved. If an index is used, that index
/// is selected and the axis is removed; this selects a subview. See
/// [*Subviews*](#subviews) for more information about subviews. Note that
/// [`.slice_collapse()`] behaves like [`.collapse_axis()`] by preserving
/// the number of dimensions.
///
/// [`.slice()`]: #method.slice
/// [`.slice_mut()`]: #method.slice_mut
/// [`.slice_move()`]: #method.slice_move
/// [`.slice_inplace()`]: #method.slice_inplace
/// [`.slice_collapse()`]: #method.slice_collapse
///
/// ```
/// // import the s![] macro
@@ -504,7 +506,7 @@ pub type Ixs = isize;
/// assert_eq!(d, e);
/// assert_eq!(d.shape(), &[2, 1, 3]);
///
/// // Let’s create a slice while taking a subview with
/// // Let’s create a slice while selecting a subview with
/// //
/// // - Both submatrices of the greatest dimension: `..`
/// // - The last row in each submatrix, removing that axis: `-1`
@@ -520,17 +522,31 @@ pub type Ixs = isize;
/// ## Subviews
///
/// Subview methods allow you to restrict the array view while removing one
/// axis from the array. Subview methods include [`.subview()`],
/// [`.subview_mut()`], [`.into_subview()`], and [`.subview_inplace()`]. You
/// can also take a subview by using a single index instead of a range when
/// slicing.
///
/// Subview takes two arguments: `axis` and `index`.
///
/// [`.subview()`]: #method.subview
/// [`.subview_mut()`]: #method.subview_mut
/// [`.into_subview()`]: #method.into_subview
/// [`.subview_inplace()`]: #method.subview_inplace
/// axis from the array. Methods for selecting individual subviews include
/// [`.index_axis()`], [`.index_axis_mut()`], [`.index_axis_move()`], and
/// [`.index_axis_inplace()`]. You can also select a subview by using a single
/// index instead of a range when slicing. Some other methods, such as
/// [`.fold_axis()`], [`.axis_iter()`], [`.axis_iter_mut()`],
/// [`.outer_iter()`], and [`.outer_iter_mut()`] operate on all the subviews
/// along an axis.
///
/// A related method is [`.collapse_axis()`], which modifies the view in the
/// same way as [`.index_axis()`] except for removing the collapsed axis, since
/// it operates *in place*. The length of the axis becomes 1.
///
/// Methods for selecting an individual subview take two arguments: `axis` and
/// `index`.
///
/// [`.axis_iter()`]: #method.axis_iter
/// [`.axis_iter_mut()`]: #method.axis_iter_mut
/// [`.fold_axis()`]: #method.fold_axis
/// [`.index_axis()`]: #method.index_axis
/// [`.index_axis_inplace()`]: #method.index_axis_inplace
/// [`.index_axis_mut()`]: #method.index_axis_mut
/// [`.index_axis_move()`]: #method.index_axis_move
/// [`.collapse_axis()`]: #method.collapse_axis
/// [`.outer_iter()`]: #method.outer_iter
/// [`.outer_iter_mut()`]: #method.outer_iter_mut
///
/// ```
/// #[macro_use(s)] extern crate ndarray;
@@ -553,8 +569,8 @@ pub type Ixs = isize;
/// // Let’s take a subview along the greatest dimension (axis 0),
/// // taking submatrix 0, then submatrix 1
///
/// let sub_0 = a.subview(Axis(0), 0);
/// let sub_1 = a.subview(Axis(0), 1);
/// let sub_0 = a.index_axis(Axis(0), 0);
/// let sub_1 = a.index_axis(Axis(0), 1);
///
/// assert_eq!(sub_0, aview2(&[[ 1, 2, 3],
/// [ 4, 5, 6]]));
@@ -563,7 +579,7 @@ pub type Ixs = isize;
/// assert_eq!(sub_0.shape(), &[2, 3]);
///
/// // This is the subview picking only axis 2, column 0
/// let sub_col = a.subview(Axis(2), 0);
/// let sub_col = a.index_axis(Axis(2), 0);
///
/// assert_eq!(sub_col, aview2(&[[ 1, 4],
/// [ 7, 10]]));
@@ -574,14 +590,6 @@ pub type Ixs = isize;
/// # }
/// ```
///
/// [`.subview_inplace()`] modifies the view in the same way as [`.subview()`],
/// but since it is *in place*, it cannot remove the collapsed axis. It becomes
/// an axis of length 1.
///
/// `.outer_iter()` is an iterator of every subview along the zeroth (outer)
/// axis, while `.axis_iter()` is an iterator of every subview along a
/// specific axis.
///
/// ## Arithmetic Operations
///
/// Arrays support all arithmetic operations the same way: they apply elementwise.
@@ -1144,6 +1152,7 @@ impl<A, S, D> ArrayBase<S, D>

mod impl_1d;
mod impl_2d;
mod impl_dyn;

mod numeric;

4 changes: 2 additions & 2 deletions src/numeric/impl_numeric.rs
Original file line number Diff line number Diff line change
@@ -107,11 +107,11 @@ impl<A, S, D> ArrayBase<S, D>
// contiguous along the axis we are summing
let ax = axis.index();
for (i, elt) in enumerate(&mut res) {
*elt = self.subview(Axis(1 - ax), i).sum();
*elt = self.index_axis(Axis(1 - ax), i).sum();
}
} else {
for i in 0..n {
let view = self.subview(axis, i);
let view = self.index_axis(axis, i);
res = res + &view;
}
}
16 changes: 9 additions & 7 deletions src/slice.rs
Original file line number Diff line number Diff line change
@@ -465,12 +465,14 @@ impl_slicenextdim_larger!((), Slice);
/// The syntax is `s![` *[ axis-slice-or-index [, axis-slice-or-index [ , ... ]
/// ] ]* `]`, where *axis-slice-or-index* is any of the following:
///
/// * *index*: an index to use for taking a subview with respect to that axis
/// * *range*: a range with step size 1 to use for slicing that axis
/// * *range* `;` *step*: a range with step size *step* to use for slicing that axis
/// * *slice*: a [`Slice`] instance to use for slicing that axis
/// * *index*: an index to use for taking a subview with respect to that axis.
/// (The index is selected. The axis is removed except with
/// [`.slice_collapse()`].)
/// * *range*: a range with step size 1 to use for slicing that axis.
/// * *range* `;` *step*: a range with step size *step* to use for slicing that axis.
/// * *slice*: a [`Slice`] instance to use for slicing that axis.
/// * *slice* `;` *step*: a range constructed from the start and end of a [`Slice`]
/// instance, with new step size *step*, to use for slicing that axis
/// instance, with new step size *step*, to use for slicing that axis.
///
/// [`Slice`]: struct.Slice.html
///
@@ -486,12 +488,12 @@ impl_slicenextdim_larger!((), Slice);
/// the third axis for 1..5 with default step size 1. The input array must have
/// 3 dimensions. The resulting slice would have shape `[2, 4]` for
/// [`.slice()`], [`.slice_mut()`], and [`.slice_move()`], and shape
/// `[2, 1, 4]` for [`.slice_inplace()`].
/// `[2, 1, 4]` for [`.slice_collapse()`].
///
/// [`.slice()`]: struct.ArrayBase.html#method.slice
/// [`.slice_mut()`]: struct.ArrayBase.html#method.slice_mut
/// [`.slice_move()`]: struct.ArrayBase.html#method.slice_move
/// [`.slice_inplace()`]: struct.ArrayBase.html#method.slice_inplace
/// [`.slice_collapse()`]: struct.ArrayBase.html#method.slice_collapse
///
/// See also [*Slicing*](struct.ArrayBase.html#slicing).
///
78 changes: 39 additions & 39 deletions tests/array.rs
Original file line number Diff line number Diff line change
@@ -173,7 +173,7 @@ fn test_slice_array_fixed() {
arr.slice(info);
arr.slice_mut(info);
arr.view().slice_move(info);
arr.view().slice_inplace(info);
arr.view().slice_collapse(info);
}

#[test]
@@ -183,7 +183,7 @@ fn test_slice_dyninput_array_fixed() {
arr.slice(info);
arr.slice_mut(info);
arr.view().slice_move(info);
arr.view().slice_inplace(info.as_ref());
arr.view().slice_collapse(info.as_ref());
}

#[test]
@@ -197,7 +197,7 @@ fn test_slice_array_dyn() {
arr.slice(info);
arr.slice_mut(info);
arr.view().slice_move(info);
arr.view().slice_inplace(info);
arr.view().slice_collapse(info);
}

#[test]
@@ -211,7 +211,7 @@ fn test_slice_dyninput_array_dyn() {
arr.slice(info);
arr.slice_mut(info);
arr.view().slice_move(info);
arr.view().slice_inplace(info.as_ref());
arr.view().slice_collapse(info.as_ref());
}

#[test]
@@ -225,7 +225,7 @@ fn test_slice_dyninput_vec_fixed() {
arr.slice(info.as_ref());
arr.slice_mut(info.as_ref());
arr.view().slice_move(info.as_ref());
arr.view().slice_inplace(info.as_ref());
arr.view().slice_collapse(info.as_ref());
}

#[test]
@@ -239,7 +239,7 @@ fn test_slice_dyninput_vec_dyn() {
arr.slice(info.as_ref());
arr.slice_mut(info.as_ref());
arr.view().slice_move(info.as_ref());
arr.view().slice_inplace(info.as_ref());
arr.view().slice_collapse(info.as_ref());
}

#[test]
@@ -253,7 +253,7 @@ fn test_slice_with_subview() {
assert_eq!(vi.shape(), &[2, 2]);
assert!(
vi.iter()
.zip(arr.subview(Axis(1), 2).slice(s![1.., ..;2]).iter())
.zip(arr.index_axis(Axis(1), 2).slice(s![1.., ..;2]).iter())
.all(|(a, b)| a == b)
);

@@ -262,8 +262,8 @@ fn test_slice_with_subview() {
assert!(
vi.iter()
.zip(
arr.subview(Axis(0), 1)
.subview(Axis(0), 2)
arr.index_axis(Axis(0), 1)
.index_axis(Axis(0), 2)
.slice(s![..;2])
.iter()
)
@@ -276,15 +276,15 @@ fn test_slice_with_subview() {
}

#[test]
fn test_slice_inplace_with_subview_inplace() {
fn test_slice_collapse_with_indices() {
let mut arr = RcArray::<usize, _>::zeros((3, 5, 4));
for (i, elt) in arr.iter_mut().enumerate() {
*elt = i;
}

{
let mut vi = arr.view();
vi.slice_inplace(s![1.., 2, ..;2]);
vi.slice_collapse(s![1.., 2, ..;2]);
assert_eq!(vi.shape(), &[2, 1, 2]);
assert!(
vi.iter()
@@ -293,7 +293,7 @@ fn test_slice_inplace_with_subview_inplace() {
);

let mut vi = arr.view();
vi.slice_inplace(s![1, 2, ..;2]);
vi.slice_collapse(s![1, 2, ..;2]);
assert_eq!(vi.shape(), &[1, 1, 2]);
assert!(
vi.iter()
@@ -302,15 +302,15 @@ fn test_slice_inplace_with_subview_inplace() {
);

let mut vi = arr.view();
vi.slice_inplace(s![1, 2, 3]);
vi.slice_collapse(s![1, 2, 3]);
assert_eq!(vi.shape(), &[1, 1, 1]);
assert_eq!(vi, Array3::from_elem((1, 1, 1), arr[(1, 2, 3)]));
}

// Do it to the RcArray itself
let elem = arr[(1, 2, 3)];
let mut vi = arr;
vi.slice_inplace(s![1, 2, 3]);
vi.slice_collapse(s![1, 2, 3]);
assert_eq!(vi.shape(), &[1, 1, 1]);
assert_eq!(vi, Array3::from_elem((1, 1, 1), elem));
}
@@ -458,7 +458,7 @@ fn test_cow()
assert_eq!(n[[0, 1]], 0);
assert_eq!(n.get((0, 1)), Some(&0));
let mut rev = mat.reshape(4);
rev.slice_inplace(s![..;-1]);
rev.slice_collapse(s![..;-1]);
assert_eq!(rev[0], 4);
assert_eq!(rev[1], 3);
assert_eq!(rev[2], 2);
@@ -483,7 +483,7 @@ fn test_cow_shrink()
// mutation shrinks the array and gives it different strides
//
let mut mat = RcArray::zeros((2, 3));
//mat.slice_inplace(s![.., ..;2]);
//mat.slice_collapse(s![.., ..;2]);
mat[[0, 0]] = 1;
let n = mat.clone();
mat[[0, 1]] = 2;
@@ -498,7 +498,7 @@ fn test_cow_shrink()
assert_eq!(n.get((0, 1)), Some(&0));
// small has non-C strides this way
let mut small = mat.reshape(6);
small.slice_inplace(s![4..;-1]);
small.slice_collapse(s![4..;-1]);
assert_eq!(small[0], 6);
assert_eq!(small[1], 5);
let before = small.clone();
@@ -515,21 +515,21 @@ fn test_cow_shrink()
fn test_sub()
{
let mat = RcArray::linspace(0., 15., 16).reshape((2, 4, 2));
let s1 = mat.subview(Axis(0), 0);
let s2 = mat.subview(Axis(0), 1);
let s1 = mat.index_axis(Axis(0), 0);
let s2 = mat.index_axis(Axis(0), 1);
assert_eq!(s1.shape(), &[4, 2]);
assert_eq!(s2.shape(), &[4, 2]);
let n = RcArray::linspace(8., 15., 8).reshape((4,2));
assert_eq!(n, s2);
let m = RcArray::from_vec(vec![2., 3., 10., 11.]).reshape((2, 2));
assert_eq!(m, mat.subview(Axis(1), 1));
assert_eq!(m, mat.index_axis(Axis(1), 1));
}

#[should_panic]
#[test]
fn test_sub_oob_1() {
let mat = RcArray::linspace(0., 15., 16).reshape((2, 4, 2));
mat.subview(Axis(0), 2);
mat.index_axis(Axis(0), 2);
}


@@ -590,7 +590,7 @@ fn swapaxes()
#[test]
fn permuted_axes()
{
let a = array![1].into_subview(Axis(0), 0);
let a = array![1].index_axis_move(Axis(0), 0);
let permuted = a.view().permuted_axes([]);
assert_eq!(a, permuted);

@@ -652,9 +652,9 @@ fn standard_layout()
assert!(!a.is_standard_layout());
a.swap_axes(0, 1);
assert!(a.is_standard_layout());
let x1 = a.subview(Axis(0), 0);
let x1 = a.index_axis(Axis(0), 0);
assert!(x1.is_standard_layout());
let x2 = a.subview(Axis(1), 0);
let x2 = a.index_axis(Axis(1), 0);
assert!(!x2.is_standard_layout());
}

@@ -678,7 +678,7 @@ fn assign()
let mut a = arr2(&[[1, 2], [3, 4]]);
{
let mut v = a.view_mut();
v.slice_inplace(s![..1, ..]);
v.slice_collapse(s![..1, ..]);
v.fill(0);
}
assert_eq!(a, arr2(&[[0, 0], [3, 4]]));
@@ -887,7 +887,7 @@ fn zero_axes()
println!("{:?}\n{:?}", b.shape(), b);

// we can even get a subarray of b
let bsub = b.subview(Axis(0), 2);
let bsub = b.index_axis(Axis(0), 2);
assert_eq!(bsub.dim(), 0);
}

@@ -932,14 +932,14 @@ fn as_slice_memory_order()
fn array0_into_scalar() {
// With this kind of setup, the `Array`'s pointer is not the same as the
// underlying `Vec`'s pointer.
let a: Array0<i32> = array![4, 5, 6, 7].into_subview(Axis(0), 2);
let a: Array0<i32> = array![4, 5, 6, 7].index_axis_move(Axis(0), 2);
assert_ne!(a.as_ptr(), a.into_raw_vec().as_ptr());
// `.into_scalar()` should still work correctly.
let a: Array0<i32> = array![4, 5, 6, 7].into_subview(Axis(0), 2);
let a: Array0<i32> = array![4, 5, 6, 7].index_axis_move(Axis(0), 2);
assert_eq!(a.into_scalar(), 6);

// It should work for zero-size elements too.
let a: Array0<()> = array![(), (), (), ()].into_subview(Axis(0), 2);
let a: Array0<()> = array![(), (), (), ()].index_axis_move(Axis(0), 2);
assert_eq!(a.into_scalar(), ());
}

@@ -1010,7 +1010,7 @@ fn owned_array_discontiguous_drop() {
let v: Vec<_> = (0..12).map(|x| InsertOnDrop(set.clone(), Some(x))).collect();
let mut a = Array::from_shape_vec((2, 6), v).unwrap();
// discontiguous and non-zero offset
a.slice_inplace(s![.., 1..]);
a.slice_collapse(s![.., 1..]);
}
// each item was dropped exactly once
itertools::assert_equal(set.borrow().iter().cloned(), 0..12);
@@ -1400,9 +1400,9 @@ fn insert_axis_f() {
fn insert_axis_view() {
let a = array![[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]];

assert_eq!(a.subview(Axis(1), 0).insert_axis(Axis(0)), array![[[1, 2], [5, 6], [9, 10]]]);
assert_eq!(a.subview(Axis(1), 0).insert_axis(Axis(1)), array![[[1, 2]], [[5, 6]], [[9, 10]]]);
assert_eq!(a.subview(Axis(1), 0).insert_axis(Axis(2)), array![[[1], [2]], [[5], [6]], [[9], [10]]]);
assert_eq!(a.index_axis(Axis(1), 0).insert_axis(Axis(0)), array![[[1, 2], [5, 6], [9, 10]]]);
assert_eq!(a.index_axis(Axis(1), 0).insert_axis(Axis(1)), array![[[1, 2]], [[5, 6]], [[9, 10]]]);
assert_eq!(a.index_axis(Axis(1), 0).insert_axis(Axis(2)), array![[[1], [2]], [[5], [6]], [[9], [10]]]);
}

#[test]
@@ -1420,7 +1420,7 @@ fn char_array()
{
// test compilation & basics of non-numerical array
let cc = RcArray::from_iter("alphabet".chars()).reshape((4, 2));
assert!(cc.subview(Axis(1), 0) == RcArray::from_iter("apae".chars()));
assert!(cc.index_axis(Axis(1), 0) == RcArray::from_iter("apae".chars()));
}

#[test]
@@ -1576,7 +1576,7 @@ fn to_owned_memory_order() {
fn to_owned_neg_stride() {
let mut c = arr2(&[[1, 2, 3],
[4, 5, 6]]);
c.slice_inplace(s![.., ..;-1]);
c.slice_collapse(s![.., ..;-1]);
let co = c.to_owned();
assert_eq!(c, co);
}
@@ -1585,7 +1585,7 @@ fn to_owned_neg_stride() {
fn discontiguous_owned_to_owned() {
let mut c = arr2(&[[1, 2, 3],
[4, 5, 6]]);
c.slice_inplace(s![.., ..;2]);
c.slice_collapse(s![.., ..;2]);

let co = c.to_owned();
assert_eq!(c.strides(), &[3, 2]);
@@ -1753,10 +1753,10 @@ fn test_to_vec() {
[7, 8, 9],
[10,11,12]]);

a.slice_inplace(s![..;-1, ..]);
a.slice_collapse(s![..;-1, ..]);
assert_eq!(a.row(3).to_vec(), vec![1, 2, 3]);
assert_eq!(a.column(2).to_vec(), vec![12, 9, 6, 3]);
a.slice_inplace(s![.., ..;-1]);
a.slice_collapse(s![.., ..;-1]);
assert_eq!(a.row(3).to_vec(), vec![3, 2, 1]);
}

@@ -1772,7 +1772,7 @@ fn test_array_clone_unalias() {
#[test]
fn test_array_clone_same_view() {
let mut a = Array::from_iter(0..9).into_shape((3, 3)).unwrap();
a.slice_inplace(s![..;-1, ..;-1]);
a.slice_collapse(s![..;-1, ..;-1]);
let b = a.clone();
assert_eq!(a, b);
}
4 changes: 2 additions & 2 deletions tests/dimension.rs
Original file line number Diff line number Diff line change
@@ -53,10 +53,10 @@ fn remove_axis()
assert_eq!(Dim(vec![4, 5, 6]).remove_axis(Axis(1)), Dim(vec![4, 6]));

let a = RcArray::<f32, _>::zeros((4,5));
a.subview(Axis(1), 0);
a.index_axis(Axis(1), 0);

let a = RcArray::<f32, _>::zeros(vec![4,5,6]);
let _b = a.into_subview(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]);
let _b = a.index_axis_move(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]);
}

#[test]
20 changes: 10 additions & 10 deletions tests/iterators.rs
Original file line number Diff line number Diff line change
@@ -92,12 +92,12 @@ fn as_slice() {
let a = a.reshape((2, 4));
assert_slice_correct(&a);

assert!(a.view().subview(Axis(1), 0).as_slice().is_none());
assert!(a.view().index_axis(Axis(1), 0).as_slice().is_none());

let v = a.view();
assert_slice_correct(&v);
assert_slice_correct(&v.subview(Axis(0), 0));
assert_slice_correct(&v.subview(Axis(0), 1));
assert_slice_correct(&v.index_axis(Axis(0), 0));
assert_slice_correct(&v.index_axis(Axis(0), 1));

assert!(v.slice(s![.., ..1]).as_slice().is_none());
println!("{:?}", v.slice(s![..1;2, ..]));
@@ -180,12 +180,12 @@ fn outer_iter() {
// [8, 9],
// ...
assert_equal(a.outer_iter(),
vec![a.subview(Axis(0), 0), a.subview(Axis(0), 1)]);
vec![a.index_axis(Axis(0), 0), a.index_axis(Axis(0), 1)]);
let mut b = RcArray::zeros((2, 3, 2));
b.swap_axes(0, 2);
b.assign(&a);
assert_equal(b.outer_iter(),
vec![a.subview(Axis(0), 0), a.subview(Axis(0), 1)]);
vec![a.index_axis(Axis(0), 0), a.index_axis(Axis(0), 1)]);

let mut found_rows = Vec::new();
for sub in b.outer_iter() {
@@ -210,7 +210,7 @@ fn outer_iter() {
cv.assign(&a);
assert_eq!(&a, &cv);
assert_equal(cv.outer_iter(),
vec![a.subview(Axis(0), 0), a.subview(Axis(0), 1)]);
vec![a.index_axis(Axis(0), 0), a.index_axis(Axis(0), 1)]);

let mut found_rows = Vec::new();
for sub in cv.outer_iter() {
@@ -233,9 +233,9 @@ fn axis_iter() {
// [8, 9],
// ...
assert_equal(a.axis_iter(Axis(1)),
vec![a.subview(Axis(1), 0),
a.subview(Axis(1), 1),
a.subview(Axis(1), 2)]);
vec![a.index_axis(Axis(1), 0),
a.index_axis(Axis(1), 1),
a.index_axis(Axis(1), 2)]);
}

#[test]
@@ -264,7 +264,7 @@ fn outer_iter_mut() {
b.swap_axes(0, 2);
b.assign(&a);
assert_equal(b.outer_iter_mut(),
vec![a.subview(Axis(0), 0), a.subview(Axis(0), 1)]);
vec![a.index_axis(Axis(0), 0), a.index_axis(Axis(0), 1)]);

let mut found_rows = Vec::new();
for sub in b.outer_iter_mut() {