Add support for inserting new axes while slicing#570
Add support for inserting new axes while slicing#570bluss merged 28 commits intorust-ndarray:masterfrom
Conversation
d075e2e to
1e978ca
Compare
|
Exciting! I'll look closer later |
1e978ca to
7e67f4a
Compare
|
I got to thinking – instead of having separate trait SliceArg {
// Number of dimensions that this slicing argument consumes in the input array.
type InDim: Dimension;
// Number of dimensions that this slicing argument produces in the output array.
type OutDim: Dimension;
fn next_in_dim<D>(&self, _: PhantomData<D>) -> PhantomData<D::Out>
where
D: Dimension + DimAdd<Self::InDim>,
{
PhantomData
}
fn next_out_dim<D>(&self, _: PhantomData<D>) -> PhantomData<D::Out>
where
D: Dimension + DimAdd<Self::OutDim>,
{
PhantomData
}
}
impl SliceArg for usize {
type InDim = Ix1;
type OutDim = Ix0;
}
impl SliceArg for NewAxis {
type InDim = Ix0;
type OutDim = Ix1;
}
impl SliceArg for Range<usize> {
type InDim = Ix1;
type OutDim = Ix1;
}
// ...
trait DimAdd<D: Dimension>: Dimension {
type Out: Dimension;
}
// ...
impl DimAdd<Ix2> for Ix3 {
type Out = Ix5;
}
// ...
impl DimAdd<IxDyn> for Ix3 {
type Out = IxDyn;
}
// ...
impl<D: Dimension> DimAdd<D> for IxDyn {
type Out = IxDyn;
}
// In s![] macro, to determine next input dimension use:
$crate::SliceArg::next_in_dim(&r, $in_dim)
// and to determine next output dimension use:
$crate::SliceArg::next_out_dim(&r, $out_dim)This has a couple of advantages:
|
|
@jturner314 DimAdd looks like a fine idea |
blas-tests/tests/oper.rs
Outdated
| { | ||
| let mut av = a.slice_mut(s![..;s1, ..;s2]); | ||
| let c = c.slice(SliceInfo::<_, IxDyn>::new(cslice).unwrap().as_ref()); | ||
| let c = c.slice(&SliceInfo::<_, IxDyn, IxDyn>::new(cslice).unwrap()); |
There was a problem hiding this comment.
This needs to be fixed (in this PR or another), we can't design a library where SliceInfo::<_, IxDyn, IxDyn>::new(cslice).unwrap() is a normal thing to say.
I don't keep up with IxDyn, since I don't use it much.
There was a problem hiding this comment.
We could add
impl SliceInfo<Vec<AxisSliceInfo>, IxDyn, IxDyn> {
pub fn from_vec(indices: Vec<AxisSliceInfo>) -> Result<Self, ShapeError> {
SliceInfo::new(indices)
}
}or
impl<T> SliceInfo<T, IxDyn, IxDyn>
where
T: AsRef<[AxisSliceInfo]>,
{
pub fn new_dyn(indices: T) -> Result<Self, ShapeError> {
SliceInfo::new(indices)
}
}I don't really expect anyone to create a SliceInfo instance directly, though, when they can just use the s![] macro or call .slice_axis()/.index_axis()/.insert_axis() on individual axes. Once we add support for Ellipsis (i.e. ...) in the s![] macro, there are even fewer use cases for creating SliceInfo directly.
There was a problem hiding this comment.
I just pushed a better solution. If we implement CanSlice<IxDyn> for [AxisSliceInfo], then there's no need for the user to create a SliceInfo instance here; they can just write &*cslice. (Optionally, we could also implement CanSlice<IxDyn> for Vec<AxisSliceInfo> to avoid the need for the *.)
We could also consider implementing CanSlice<IxDyn> for [Slice] and CanSlice<Dim<[usize; N]>> for [Slice; N], although that would require modifying the CanSlice trait somewhat (since it currently requires AsRef<[AxisSliceInfo]>) and the slicing method implementations.
I do think this test is better written by slicing individual axes with .slice_axis*() rather than combining the slicing information and calling .slice().
|
We have existing and new concepts and the dimensionality of each:
1D concepts are for a single axis and nD concepts pertain to the whole array. NewAxis already has the perfect name, so it's fine. We again need to bring some order to this and give them the best names. I'll come back to this. |
|
I'm sorry that I haven't come back to this, and the PR doesn't need to wait for me. |
4162aa5 to
da27047
Compare
|
I've rebased this off the latest The name |
6f441c8 to
c1afbbf
Compare
|
Rebased again to resolve conflict in |
|
Docs is a good reason to make CanSlice visible in the docs. Users depend on clicking on it to understand what it is. (MultiSlice should be visible by the same logic). Now, we don't have much of a module hierarchy in this crate. We're starting to miss it just to hide away lesser used things - suggestions welcome (with that said, I like the mostly-flat namespace). |
This isn't much more code and simplifies the logic somewhat.
This makes it visible in the docs, but the private marker trick prevents other crates from implementing it.
This makes it visible in the docs, but the private marker trick prevents other crates from implementing it.
This reduces how often an explicit `DimAdd` bound is necessary.
This reverts commit 3815462.
|
Thanks a lot 🎉 |
|
With this done, it's time to release 0.15. Just need to know if there are any last-minute cleanups needed or necessary. |
This is equivalent to NumPy's
np.newaxisfeature.A few notes:
CanSlicetrait has the additional benefit that.as_ref()is no longer needed when slicing dynamic-dimensional arrays. (See Calling slice on a dynamic size array #501.)CanSlicepublic because I don't see any reason (except for docs) to expose it._instead of an expression that evaluates toNewAxisto signal a new axis in thes![]macro.Fixes #895