-
Notifications
You must be signed in to change notification settings - Fork 37
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
Cleaning up indexing and dimension mapping code. #181
Conversation
* Realized that a lot of things I had documented internally are now in the online docs, likely making them appear more stable and public than they are right now. * `argdims` was ambiguously documented and not used elsewhere so I split it into two separate/more useful methos: ndims_index and ndims_subset * Deleted/consolidated a bunch of indexing code
Codecov Report
@@ Coverage Diff @@
## master #181 +/- ##
==========================================
+ Coverage 83.57% 84.13% +0.55%
==========================================
Files 11 11
Lines 1644 1607 -37
==========================================
- Hits 1374 1352 -22
+ Misses 270 255 -15
Continue to review full report at Codecov.
|
* removed ndims_subset for now. * added canonicalize tests
We could potentially do something like this @inline function ndims_index(axs::Tuple{Vararg{Any,NA}}, inds::Tuple{I1,I2}) where {NA,I1,I2}
ndi = ndims_index(getfield(axs, 1), getfield(inds, 1))
if ndi === nothing
ndi = ndims_index(getfield(axs, NA), getfield(inds, 2))
return (ndi - static(NA), ndi)
else
_, axstail = Base.IteratorsMD.split(axs, Val(known(ndi)))
return (ndi, ndims_index(tail(axstail), (getfield(inds, 2),))...)
end
end
@inline function ndims_index(axs::Tuple{Vararg{Any,NA}}, inds::Tuple{Vararg{Any,NI}}) where {NA,NI}
ndi = ndims_index(getfield(axs, 1), getfield(inds, 1))
if ndi === nothing
ndi = ndims_index(getfield(axs, NA), getfield(inds, NI))
N = NA - ndi
if N < 0
return (ndims_index((), Base.front(inds))..., ndi)
else
_, axstail = Base.IteratorsMD.split(axs, Val())
return (ndims_index(axstail, Base.front(inds))..., ndi)
end
else
_, axstail = Base.IteratorsMD.split(axs, Val(known(ndi)))
return (ndi, ndims_index(tail(axstail), tail(inds))...)
end
end Which would allow
|
For now I think we should just keep index->dim mapping an internal design. I've been quite verbose here, so it should be pretty easy to come back and implement the real deal in the future. |
LoopVectorization also has code for handling this right now, but I hadn't gotten around to actually integrating it with EDIT: Although probably not worth trying to rebase it on top of this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
tldr; I was cleaning up indexing/dimension stuff and did the following:
end
andbegin
get lowered here, but the related issue of mapping each indexing argument to the appropriate dimension of an array can be accomplished here (reference:A[i, end]
assumes thati
indexes one dimension JuliaLang/julia#35681, Elipsis and [CartesianIndex()] not working SciML/EllipsisNotation.jl#26).Now for the IALR (is a long read). Mapping each indexing argument to the dimensions/axes of an indexed array involves finding out:
Int
-> 1,CartesianIndex{3}
-> 3)CartesianIndices{3}
-> 3,CartesianIndex{3}
-> 0).There are also indices that trail past the last dimension of the indexed array that are either dropped (
Int
) or result in final dimension that's one element long (OneTo(1)
,:
).Most of this is handled in
to_indices
right now, which I've found easily results in ambiguities (an example in the wild).Also,
to_indices
isn't as optimized as one might hope.I've found some success in the past with small improvements to the performance of
ArrayInterface.to_indices
(e.g., mostly performing a few basic operations prior to the recursiveto_indices
call).So the problems are:
to_indices(::MyArray, axes, inds::Tuple{IndexType,Vararg{Any}})
pattern is somewhat against the design patterns we're aiming for inArrayInterface.jl
because anything that wrapsMyArray
will lose this relationship withIndexType
.to_indices
has some performance draw backs (but it sounds like that will improve someday with more compiler work).If you look in the original comments about problems with
end
there's some dislike of going into the type domain.However, I think it's pretty reasonable (and useful) to require there is a way to map each index type to the dimensions of an array type.
In the current draft this is being done using
ndsim_index
.This is a pretty straightforward setup with the exception of accommodating things like
EllipsisNotation.jl
where the number of dimensions thatEllipsisNotation.Ellipsis
maps to is dependent on which dimensions all the other indices map to.The best solution I've come up with that permits contextual dimension mapping is using
LazyAxis
to keep track of the number of dimensions.The only other idea I have right now is using
axes_types
types so that users don't have to worry about usingLazyAxis
as a counter.I generally try to avoid forcing anyone to directly interact with
Tuple
to work with an interface.On the other hand, if someone isn't comfortable digging into that deep into the type system they probably shouldn't be changing something as fundamental as index to dimension mapping.
I'm going to sit on this for a day or two in hopes that I have an epiphany that solves this all perfectly (unless someone has a suggestion that does that for me).
Nothing here should be breaking BTW.
All the stuff I removed wasn't being used anywhere else yet.