Skip to content

Commit

Permalink
Merge pull request rust-ndarray#377 from jturner314/slice-subview4
Browse files Browse the repository at this point in the history
Add support for slicing with subviews
  • Loading branch information
bluss authored Nov 20, 2017
2 parents 50679f3 + 79659c9 commit a380737
Show file tree
Hide file tree
Showing 12 changed files with 1,078 additions and 346 deletions.
3 changes: 0 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ sudo: required
dist: trusty
matrix:
include:
- rust: 1.18.0
env:
- FEATURES='test'
- rust: stable
env:
- FEATURES='test'
Expand Down
4 changes: 2 additions & 2 deletions examples/axis_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn main() {
}
a.swap_axes(0, 1);
a.swap_axes(0, 2);
a.islice(s![.., ..;-1, ..]);
a.slice_inplace(s![.., ..;-1, ..]);
regularize(&mut a).ok();

let mut b = Array::<u8, _>::zeros((2, 3, 4));
Expand All @@ -64,6 +64,6 @@ fn main() {
for (i, elt) in (0..).zip(&mut a) {
*elt = i;
}
a.islice(s![..;-1, ..;2, ..]);
a.slice_inplace(s![..;-1, ..;2, ..]);
regularize(&mut a).ok();
}
8 changes: 4 additions & 4 deletions serialization-tests/tests/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.islice(s![..;-1, .., .., ..2]);
a.slice_inplace(s![..;-1, .., .., ..2]);
let serial = json::encode(&a).unwrap();
println!("Encode {:?} => {:?}", a, serial);
let res = json::decode::<RcArray<f32, _>>(&serial);
Expand Down Expand Up @@ -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.islice(s![..;-1, .., .., ..2]);
a.slice_inplace(s![..;-1, .., .., ..2]);
let serial = serde_json::to_string(&a).unwrap();
println!("Encode {:?} => {:?}", a, serial);
let res = serde_json::from_str::<RcArray<f32, _>>(&serial);
Expand Down Expand Up @@ -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.islice(s![..;-1, .., .., ..2]);
a.slice_inplace(s![..;-1, .., .., ..2]);

let mut buf = Vec::new();
serde::Serialize::serialize(&a, &mut rmp_serde::Serializer::new(&mut buf)).ok().unwrap();
Expand Down Expand Up @@ -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.islice(s![..;-1, .., .., ..2]);
a.slice_inplace(s![..;-1, .., .., ..2]);

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

Expand Down
151 changes: 63 additions & 88 deletions src/dimension/dimension_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign};

use itertools::{enumerate, zip};

use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Si, IxDynImpl};
use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, SliceOrIndex, IxDynImpl};
use IntoDimension;
use RemoveAxis;
use {ArrayView1, ArrayViewMut1};
Expand Down Expand Up @@ -41,21 +41,25 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
MulAssign + for<'x> MulAssign<&'x Self> + MulAssign<usize>

{
/// For fixed-size dimension representations (e.g. `Ix2`), this should be
/// `Some(ndim)`, and for variable-size dimension representations (e.g.
/// `IxDyn`), this should be `None`.
const NDIM: Option<usize>;
/// `SliceArg` is the type which is used to specify slicing for this
/// dimension.
///
/// For the fixed size dimensions it is a fixed size array of the correct
/// size, which you pass by reference. For the dynamic dimension it is
/// a slice.
///
/// - For `Ix1`: `[Si; 1]`
/// - For `Ix2`: `[Si; 2]`
/// - For `Ix1`: `[SliceOrIndex; 1]`
/// - For `Ix2`: `[SliceOrIndex; 2]`
/// - and so on..
/// - For `IxDyn`: `[Si]`
/// - For `IxDyn`: `[SliceOrIndex]`
///
/// The easiest way to create a `&SliceArg` is using the macro
/// [`s![]`](macro.s!.html).
type SliceArg: ?Sized + AsRef<[Si]>;
/// The easiest way to create a `&SliceInfo<SliceArg, Do>` is using the
/// [`s![]`](macro.s!.html) macro.
type SliceArg: ?Sized + AsRef<[SliceOrIndex]>;
/// Pattern matching friendly form of the dimension value.
///
/// - For `Ix1`: `usize`,
Expand Down Expand Up @@ -152,6 +156,15 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
Self::default()
}

#[doc(hidden)]
/// Return an index of same type and with the specified dimensionality.
///
/// This method is useful for generalizing over fixed-size and
/// variable-size dimension representations.
///
/// **Panics** if `Self` has a fixed size that is not `ndim`.
fn zero_index_with_ndim(ndim: usize) -> Self;

#[doc(hidden)]
#[inline]
fn first_index(&self) -> Option<Self> {
Expand Down Expand Up @@ -239,69 +252,6 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
self.slice_mut()[nd - 1] = i;
}

#[doc(hidden)]
/// Modify dimension, strides and return data pointer offset
///
/// **Panics** if `slices` does not correspond to the number of axes,
/// if any stride is 0, or if any index is out of bounds.
fn do_slices(dim: &mut Self, strides: &mut Self, slices: &Self::SliceArg) -> isize {
let slices = slices.as_ref();
let mut offset = 0;
ndassert!(slices.len() == dim.slice().len(),
"SliceArg {:?}'s length does not match dimension {:?}",
slices, dim);
for (dr, sr, &slc) in izip!(dim.slice_mut(), strides.slice_mut(), slices) {
let m = *dr;
let mi = m as Ixs;
let Si(b1, opt_e1, s1) = slc;
let e1 = opt_e1.unwrap_or(mi);

let b1 = abs_index(mi, b1);
let mut e1 = abs_index(mi, e1);
if e1 < b1 { e1 = b1; }

ndassert!(b1 <= m,
concat!("Slice begin {} is past end of axis of length {}",
" (for SliceArg {:?})"),
b1, m, slices);
ndassert!(e1 <= m,
concat!("Slice end {} is past end of axis of length {}",
" (for SliceArg {:?})"),
e1, m, slices);

let m = e1 - b1;
// stride
let s = (*sr) as Ixs;

// Data pointer offset
offset += stride_offset(b1, *sr);
// Adjust for strides
ndassert!(s1 != 0,
concat!("Slice stride must not be none",
"(for SliceArg {:?})"),
slices);
// How to implement negative strides:
//
// Increase start pointer by
// old stride * (old dim - 1)
// to put the pointer completely in the other end
if s1 < 0 {
offset += stride_offset(m - 1, *sr);
}

let s_prim = s * s1;

let d = m / s1.abs() as Ix;
let r = m % s1.abs() as Ix;
let m_prim = d + if r > 0 { 1 } else { 0 };

// Update dimension and stride coordinate
*dr = m_prim;
*sr = s_prim as Ix;
}
offset
}

#[doc(hidden)]
fn is_contiguous(dim: &Self, strides: &Self) -> bool {
let defaults = dim.default_strides();
Expand Down Expand Up @@ -398,18 +348,6 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
private_decl!{}
}

// utility functions

#[inline]
fn abs_index(len: Ixs, index: Ixs) -> Ix {
if index < 0 {
(len + index) as Ix
} else {
index as Ix
}
}


// Dimension impls

macro_rules! impl_insert_axis_array(
Expand All @@ -425,7 +363,8 @@ macro_rules! impl_insert_axis_array(
);

impl Dimension for Dim<[Ix; 0]> {
type SliceArg = [Si; 0];
const NDIM: Option<usize> = Some(0);
type SliceArg = [SliceOrIndex; 0];
type Pattern = ();
type Smaller = Self;
type Larger = Ix1;
Expand All @@ -441,6 +380,11 @@ impl Dimension for Dim<[Ix; 0]> {
#[inline]
fn into_pattern(self) -> Self::Pattern { }
#[inline]
fn zero_index_with_ndim(ndim: usize) -> Self {
assert_eq!(ndim, 0);
Self::default()
}
#[inline]
fn next_for(&self, _index: Self) -> Option<Self> {
None
}
Expand All @@ -456,7 +400,8 @@ impl Dimension for Dim<[Ix; 0]> {


impl Dimension for Dim<[Ix; 1]> {
type SliceArg = [Si; 1];
const NDIM: Option<usize> = Some(1);
type SliceArg = [SliceOrIndex; 1];
type Pattern = Ix;
type Smaller = Ix0;
type Larger = Ix2;
Expand All @@ -471,6 +416,11 @@ impl Dimension for Dim<[Ix; 1]> {
get!(&self, 0)
}
#[inline]
fn zero_index_with_ndim(ndim: usize) -> Self {
assert_eq!(ndim, 1);
Self::default()
}
#[inline]
fn next_for(&self, mut index: Self) -> Option<Self> {
getm!(index, 0) += 1;
if get!(&index, 0) < get!(self, 0) {
Expand Down Expand Up @@ -544,7 +494,8 @@ impl Dimension for Dim<[Ix; 1]> {
}

impl Dimension for Dim<[Ix; 2]> {
type SliceArg = [Si; 2];
const NDIM: Option<usize> = Some(2);
type SliceArg = [SliceOrIndex; 2];
type Pattern = (Ix, Ix);
type Smaller = Ix1;
type Larger = Ix3;
Expand All @@ -559,6 +510,11 @@ impl Dimension for Dim<[Ix; 2]> {
#[inline]
fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() }
#[inline]
fn zero_index_with_ndim(ndim: usize) -> Self {
assert_eq!(ndim, 2);
Self::default()
}
#[inline]
fn next_for(&self, index: Self) -> Option<Self> {
let mut i = get!(&index, 0);
let mut j = get!(&index, 1);
Expand Down Expand Up @@ -674,7 +630,8 @@ impl Dimension for Dim<[Ix; 2]> {
}

impl Dimension for Dim<[Ix; 3]> {
type SliceArg = [Si; 3];
const NDIM: Option<usize> = Some(3);
type SliceArg = [SliceOrIndex; 3];
type Pattern = (Ix, Ix, Ix);
type Smaller = Ix2;
type Larger = Ix4;
Expand All @@ -697,6 +654,12 @@ impl Dimension for Dim<[Ix; 3]> {
m as usize * n as usize * o as usize
}

#[inline]
fn zero_index_with_ndim(ndim: usize) -> Self {
assert_eq!(ndim, 3);
Self::default()
}

#[inline]
fn next_for(&self, index: Self) -> Option<Self> {
let mut i = get!(&index, 0);
Expand Down Expand Up @@ -785,7 +748,8 @@ impl Dimension for Dim<[Ix; 3]> {
macro_rules! large_dim {
($n:expr, $name:ident, $pattern:ty, $larger:ty, { $($insert_axis:tt)* }) => (
impl Dimension for Dim<[Ix; $n]> {
type SliceArg = [Si; $n];
const NDIM: Option<usize> = Some($n);
type SliceArg = [SliceOrIndex; $n];
type Pattern = $pattern;
type Smaller = Dim<[Ix; $n - 1]>;
type Larger = $larger;
Expand All @@ -800,6 +764,11 @@ macro_rules! large_dim {
#[inline]
fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() }
#[inline]
fn zero_index_with_ndim(ndim: usize) -> Self {
assert_eq!(ndim, $n);
Self::default()
}
#[inline]
$($insert_axis)*
#[inline]
fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
Expand Down Expand Up @@ -831,7 +800,8 @@ large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, {
/// and memory wasteful, but it allows an arbitrary and dynamic number of axes.
impl Dimension for IxDyn
{
type SliceArg = [Si];
const NDIM: Option<usize> = None;
type SliceArg = [SliceOrIndex];
type Pattern = Self;
type Smaller = Self;
type Larger = Self;
Expand All @@ -851,6 +821,11 @@ impl Dimension for IxDyn
IxDyn::zeros(self.ndim())
}

#[inline]
fn zero_index_with_ndim(ndim: usize) -> Self {
IxDyn::zeros(ndim)
}

#[inline]
fn insert_axis(&self, axis: Axis) -> Self::Larger {
debug_assert!(axis.index() <= self.ndim());
Expand Down
Loading

0 comments on commit a380737

Please sign in to comment.