You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It's a natural idea, but it's not easily realizable because taking subviews changes the number of of axes, which changes the type of the array (D type parameter), unless the array is a dynamically dimensioned array (D is Vec<Ix>, and this mode is not properly supported either).
Some major type hackery would be needed for the slice method to support this, but another macro might be able to do it.
We have a fundamental tension in our choice to have explicit type-level axis counts in ndarray. Ix is different from (Ix, Ix) and so on. This could all be dynamic (more like python), but with the detriment that low-level arrays and array views become much more heavyweight. Consider that a ndarray class instance in numpy in Python is kilobytes of data. We've chosen to not go that route.
I'd really like this feature, too. I put together a proof-of-concept of one possible strategy: jturner314/ndarray@7b41f5f
Basically, what I did is:
Use an enum Si2 to represent either a range or a single index. (Note that it could alternatively be defined as enum Si2 { Range(Ixs, Option<Ixs>, Ixs), Subview(Ixs)) to get rid of Si.)
Add a new macro s2! that is basically the same as s! with two differences:
It allows isize in addition to range elements. (You can do s2![1..5, 3, 4..;2], for example.)
It returns the correct output dimension type in addition to the indexing information.
Add a new method ArrayBase::slice2 that takes the indexing information and output dimension type as arguments. I didn't write the implementation, but it should be doable because the output dimension is now known.
The code needs some refinement but shows that this feature is possible with basically the same API as the existing slicing functionality. What do you think?
After working on this a little more, I think I prefer an alternative approach: jturner314/ndarray@1987787
This is a summary:
Add an islice_axis() method to ArrayBase that slices along the specified axis.
Add a trait IntoSliceAxisOrIntoSubview that calls islice_axis() or into_subview() based on whether the argument is a range or index, and add a trait IntoSliceAxisOrIntoSubviewNextAxis that determines the next axis index.
Add slice!, into_slice!, and slice_mut! macros that make calls to view(), view_mut(), and into_slice_axis_or_into_subview() as necessary.
Note that it would also be possible to add an islice! macro if desired.
The implementation is simpler, and the usage is more concise (e.g. slice!(arr[1..4, 3, 2..6;3]) instead of arr.slice(s![1..4, 3, 2..6;3])).
It's worth pointing out that it would be feasible to provide slicing without any macros in the API, if that's desired. You could do it like this:
Implement From<T> for Si where T is Range<Ixs>, RangeFrom<Ixs>, RangeTo<Ixs>, RangeFull, (Range<Ixs>, Ixs), (RangeFrom<Ixs>, Ixs), (RangeTo<Ixs>, Ixs), and (RangeFull, Ixs).
Implement ArrayBase::slice(T) where T is a tuple of ranges (possibly with steps) and indices. For example, the user could call arr.slice((2..5, 7, (..4, 3), 8, 3)), where the corresponding implementation is impl<R1: Into<Si>, R2: Into<Si>> Slice<(R1, Ixs, R2, Ixs, Ixs)> for ArrayBase<S, Ix5> { type Output = ArrayBase<S, Ix2>; ... }
The implementation side is the complex part of this approach, because you'd have to provide an implementation for all possible tuple inputs. It's still feasible, though, (with use of macros or code generation to write the implementation) because there are only 2^6 = 64 possibilities for the largest fixed dimension (Ix6).
My preference is the approach in my previous comment (slice!, slice_mut!, etc., macros) just for simplicity of implementation and its ability to generalize to higher dimensions without an exponentially increasing number of trait implementations.
If you like the slice!, slice_mut!, etc., approach (or the one I proposed before that), I can finish the implementation and submit a PR.
Activity
bluss commentedon Aug 19, 2016
It's a natural idea, but it's not easily realizable because taking subviews changes the number of of axes, which changes the type of the array (D type parameter), unless the array is a dynamically dimensioned array (
DisVec<Ix>, and this mode is not properly supported either).Some major type hackery would be needed for the slice method to support this, but another macro might be able to do it.
bluss commentedon Aug 19, 2016
We have a fundamental tension in our choice to have explicit type-level axis counts in ndarray.
Ixis different from(Ix, Ix)and so on. This could all be dynamic (more like python), but with the detriment that low-level arrays and array views become much more heavyweight. Consider that a ndarray class instance in numpy in Python is kilobytes of data. We've chosen to not go that route.bluss commentedon Apr 3, 2017
This can be implemented for dynamic dimension arrays. Needs a design that shows how, though :)
jturner314 commentedon Oct 16, 2017
I'd really like this feature, too. I put together a proof-of-concept of one possible strategy: jturner314/ndarray@7b41f5f
Basically, what I did is:
Si2to represent either a range or a single index. (Note that it could alternatively be defined asenum Si2 { Range(Ixs, Option<Ixs>, Ixs), Subview(Ixs))to get rid ofSi.)s2!that is basically the same ass!with two differences:isizein addition to range elements. (You can dos2![1..5, 3, 4..;2], for example.)ArrayBase::slice2that takes the indexing information and output dimension type as arguments. I didn't write the implementation, but it should be doable because the output dimension is now known.The code needs some refinement but shows that this feature is possible with basically the same API as the existing slicing functionality. What do you think?
bluss commentedon Oct 16, 2017
Looks absolutely promising, happy you're keeping the compile time checking that the number of indices matches up.
bluss commentedon Oct 16, 2017
Having the cryptic and short name
Siis a remnant from before the s![] macro, so Si is short and cryptic since you'd need to use it once per axis.jturner314 commentedon Oct 17, 2017
After working on this a little more, I think I prefer an alternative approach: jturner314/ndarray@1987787
This is a summary:
islice_axis()method toArrayBasethat slices along the specified axis.IntoSliceAxisOrIntoSubviewthat callsislice_axis()orinto_subview()based on whether the argument is a range or index, and add a traitIntoSliceAxisOrIntoSubviewNextAxisthat determines the next axis index.slice!,into_slice!, andslice_mut!macros that make calls toview(),view_mut(), andinto_slice_axis_or_into_subview()as necessary.Note that it would also be possible to add an
islice!macro if desired.The implementation is simpler, and the usage is more concise (e.g.
slice!(arr[1..4, 3, 2..6;3])instead ofarr.slice(s![1..4, 3, 2..6;3])).What do you think?
jturner314 commentedon Oct 17, 2017
It's worth pointing out that it would be feasible to provide slicing without any macros in the API, if that's desired. You could do it like this:
From<T>forSiwhereTisRange<Ixs>,RangeFrom<Ixs>,RangeTo<Ixs>,RangeFull,(Range<Ixs>, Ixs),(RangeFrom<Ixs>, Ixs),(RangeTo<Ixs>, Ixs), and(RangeFull, Ixs).ArrayBase::slice(T)whereTis a tuple of ranges (possibly with steps) and indices. For example, the user could callarr.slice((2..5, 7, (..4, 3), 8, 3)), where the corresponding implementation isimpl<R1: Into<Si>, R2: Into<Si>> Slice<(R1, Ixs, R2, Ixs, Ixs)> for ArrayBase<S, Ix5> { type Output = ArrayBase<S, Ix2>; ... }The implementation side is the complex part of this approach, because you'd have to provide an implementation for all possible tuple inputs. It's still feasible, though, (with use of macros or code generation to write the implementation) because there are only 2^6 = 64 possibilities for the largest fixed dimension (
Ix6).My preference is the approach in my previous comment (
slice!,slice_mut!, etc., macros) just for simplicity of implementation and its ability to generalize to higher dimensions without an exponentially increasing number of trait implementations.If you like the
slice!,slice_mut!, etc., approach (or the one I proposed before that), I can finish the implementation and submit a PR.