Skip to content

Add support for slicing with subviews #369

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

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
03a34a9
Add slicing with subviews
jturner314 Oct 19, 2017
5f1a18a
Remove redundant assert
jturner314 Oct 19, 2017
4d5e3c0
Fix slicing for Rust < 1.21.0
jturner314 Oct 19, 2017
0cd3563
Add type-checking of input size for islice()
jturner314 Oct 19, 2017
e71f636
Pass Si by value instead of by reference
jturner314 Oct 19, 2017
a84c384
Remove support for Rust < 1.21.0
jturner314 Oct 20, 2017
4d2d577
Implement From<Vec<SliceOrIndex>> for SliceInfo
jturner314 Oct 20, 2017
4ee8729
Remove Sized constraint on T in SliceInfo<T, D>
jturner314 Oct 20, 2017
98cdc24
Remove out_ndim member from SliceInfo
jturner314 Oct 20, 2017
b35a7b5
Remove T type parameter from slice*()
jturner314 Oct 20, 2017
27fe458
Make slice() work cleanly for SliceInfo<Vec<_>, _>
jturner314 Oct 20, 2017
23affed
Change transmute() to a pointer cast and deref
jturner314 Oct 21, 2017
66f464d
Add tests for SliceInfo types
jturner314 Oct 21, 2017
89ea1db
Support slicing with more SliceInfo types
jturner314 Oct 21, 2017
6775e41
Remove I: Borrow<_> from *slice*() methods
bluss Oct 24, 2017
9f13954
Remove visibility to SliceInfo.indices
jturner314 Oct 24, 2017
c927ac5
Change Borrow to AsRef
jturner314 Oct 24, 2017
c4f0bf3
Switch from deref + coerce to as_ref
jturner314 Oct 25, 2017
5cdd44c
Remove Si type and rename si module
jturner314 Oct 25, 2017
907d587
Reformat slice module
jturner314 Oct 25, 2017
a056f02
Change SliceInfo to repr(C)
jturner314 Oct 25, 2017
2053e17
Rename .i*() to .*_inplace()
jturner314 Oct 26, 2017
39371d3
Rename .slice_into() to .slice_move()
jturner314 Oct 26, 2017
1848f6b
Fix remaining calls to .islice()
jturner314 Oct 26, 2017
5bc5cd3
Rename .into_subview() to .subview_move()
jturner314 Oct 26, 2017
8c1fc99
Revert "Rename .into_subview() to .subview_move()"
jturner314 Oct 26, 2017
6561c22
Update documentation
jturner314 Oct 26, 2017
db9adfa
Update stride -> step size in docs
jturner314 Oct 26, 2017
6f44bac
Change isize -> Ixs in slice_axis*() signatures
jturner314 Oct 26, 2017
190ca34
Fix failing doc test
jturner314 Oct 26, 2017
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
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
182 changes: 112 additions & 70 deletions src/dimension/dimension_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
// except according to those terms.


use std::convert::AsRef;
use std::fmt::Debug;
use std::ops::{Index, IndexMut};
use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign};

use itertools::{enumerate, zip};

use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Si, 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 +42,24 @@ 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.
/// size. 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 @@ -240,65 +253,57 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
}

#[doc(hidden)]
/// Modify dimension, strides and return data pointer offset
/// Modify dimension, stride 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();
/// **Panics** if any stride is 0 or if any index is out of bounds.
fn do_slice(dim: &mut Ix, stride: &mut Ix, start: isize, end: Option<isize>, step: isize) -> isize {
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 dr = dim;
let sr = stride;

let m = *dr;
let mi = m as Ixs;
let (b1, opt_e1, s1) = (start, end, step);
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,
"Slice begin {} is past end of axis of length {}",
b1, m);
ndassert!(e1 <= m,
"Slice end {} is past end of axis of length {}",
e1, m);

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

// Data pointer offset
offset += stride_offset(b1, *sr);
// Adjust for strides
ndassert!(s1 != 0, "Slice stride must not be none");
// 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 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 };
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;

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

Expand Down Expand Up @@ -401,7 +406,7 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
// utility functions

#[inline]
fn abs_index(len: Ixs, index: Ixs) -> Ix {
pub fn abs_index(len: Ixs, index: Ixs) -> Ix {
if index < 0 {
(len + index) as Ix
} else {
Expand All @@ -425,7 +430,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 +447,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 +467,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 +483,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 +561,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 +577,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 +697,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 +721,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 +815,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 +831,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 +867,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 +888,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
2 changes: 1 addition & 1 deletion src/dimension/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use error::{from_kind, ErrorKind, ShapeError};
pub use self::dim::*;
pub use self::axis::Axis;
pub use self::conversion::IntoDimension;
pub use self::dimension_trait::Dimension;
pub use self::dimension_trait::{abs_index, Dimension};
pub use self::ndindex::NdIndex;
pub use self::remove_axis::RemoveAxis;
pub use self::axes::{axes_of, Axes, AxisDescription};
Expand Down
Loading