-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
add StepRange support for CartesianIndices #37829
Conversation
8b0879b
to
133f07f
Compare
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.
I think this is a good change. But the biggest worry about this is that a lot of code written for CartesianIndices has formerly assumed that the step size would always be 1, and that will no longer be true. Sort of like the transition to indexing starting at something other than 1, this could trigger a bigger shakeup across the ecosystem. It's probably the right thing to do, but be aware that this change may have a "tail" that could last for years. (It's probably a lot less disruptive than the 1-indexing change, though.)
One thing we can probably do to ease the transition is define
const UnitCartesianIndices{N,R<:NTuple{N,AbstractUnitRange{Int}}} = CartesianIndices{N,R}
and encourage people to use it when they want to enforce a step size of 1. (Not sure whether to export this, though, probably not.)
Codecov Report
@@ Coverage Diff @@
## master #37829 +/- ##
==========================================
- Coverage 87.64% 87.58% -0.07%
==========================================
Files 368 368
Lines 73053 73038 -15
==========================================
- Hits 64030 63968 -62
- Misses 9023 9070 +47
Continue to review full report at Codecov.
|
133f07f
to
7e1b9aa
Compare
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.
Where should the new test goes, test/cartesian.jl
?
dd28e3d
to
33ab8e7
Compare
* correct overflow checks * correct broadcasting
6efb112
to
b5d4036
Compare
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.
A very impressive PR! Solving #9080 alone is amazing, but doing so while cleaning up implementations, adding more flexibility, testing more thoroughly is a tour de force.
Subject to fixing the test errors this seems basically ready from what I can tell, pending how you want to resolve the LinearIndices situation. To be clear, I think that could be a separate PR, if you want to go with the errorring version here first and get it out in the wild.
base/multidimensional.jl
Outdated
indices = map(ind->convert(AbstractUnitRange, ind), indices) | ||
LinearIndices{N, typeof(indices)}(indices) | ||
else | ||
throw(ArgumentError("LinearIndices for $typeof(inds) with non-1 step size is not supported.")) |
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.
Actually, thinking about this more, maybe we can handle this? After all, the definition of LinearIndices
is
struct LinearIndices{N,R<:NTuple{N,AbstractUnitRange{Int}}} <: AbstractArray{Int,N}
indices::R
end
and so some of the same tricks you're using here could be used there too. You might have to reset the integer at the end of each "column," perhaps by maintaining a hybrid linear/cartesian iterator:
julia> inds = LinearIndices((1:3, 1:4))
3×4 LinearIndices{2, Tuple{UnitRange{Int64}, UnitRange{Int64}}}:
1 4 7 10
2 5 8 11
3 6 9 12
julia> inds[1:2:3,:] # can't just increase by a constant
2×4 Matrix{Int64}:
1 4 7 10
3 6 9 12
Only, of course, when it's a StepRange.
Keep in mind that converting Cartesian to Linear is pretty fast (multiply and add); it's the opposite transition, Linear to Cartesian, that requires div
and hence is dirt-slow. (That's why Cartesian is the fallback.)
Does |
To keep consistent with the StepRange behavior
Let's find out if generalizing this type causes package problems: @nanosoldier |
Your package evaluation job has completed - possible new issues were detected. A full report can be found here. cc @maleadt |
I think that's due to https://github.com/JuliaArrays/TiledIteration.jl/blob/master/src/TiledIteration.jl#L102 and is fixable. |
Good. That seems like the only real one I've seen. I think we can merge this. |
Thank you @johnnychen94! 🎆 |
My very first newsworthy PR 🎉 |
This avoids the boundary check due to a change in the implementation of iteration using `CartecianIndices` in PR JuliaLang#37829. This is a workaround on the caller side and does not change the iteration mechanism itself.
This avoids the boundary check due to a change in the implementation of iteration using `CartecianIndices` in PR JuliaLang#37829. This is a workaround on the caller side and does not change the iteration mechanism itself.
) * Fix performance regression in broadcasting with CartesianIndices This avoids the boundary check due to a change in the implementation of iteration using `CartecianIndices` in PR #37829. This is a workaround on the caller side and does not change the iteration mechanism itself. Co-authored-by: Matt Bauman <[email protected]> Co-authored-by: thofma <[email protected]>
) * Fix performance regression in broadcasting with CartesianIndices This avoids the boundary check due to a change in the implementation of iteration using `CartecianIndices` in PR #37829. This is a workaround on the caller side and does not change the iteration mechanism itself. Co-authored-by: Matt Bauman <[email protected]> Co-authored-by: thofma <[email protected]> (cherry picked from commit a4cd68c)
) * Fix performance regression in broadcasting with CartesianIndices This avoids the boundary check due to a change in the implementation of iteration using `CartecianIndices` in PR #37829. This is a workaround on the caller side and does not change the iteration mechanism itself. Co-authored-by: Matt Bauman <[email protected]> Co-authored-by: thofma <[email protected]> (cherry picked from commit a4cd68c)
…iaLang#39333) * Fix performance regression in broadcasting with CartesianIndices This avoids the boundary check due to a change in the implementation of iteration using `CartecianIndices` in PR JuliaLang#37829. This is a workaround on the caller side and does not change the iteration mechanism itself. Co-authored-by: Matt Bauman <[email protected]> Co-authored-by: thofma <[email protected]>
…iaLang#39333) * Fix performance regression in broadcasting with CartesianIndices This avoids the boundary check due to a change in the implementation of iteration using `CartecianIndices` in PR JuliaLang#37829. This is a workaround on the caller side and does not change the iteration mechanism itself. Co-authored-by: Matt Bauman <[email protected]> Co-authored-by: thofma <[email protected]>
) * Fix performance regression in broadcasting with CartesianIndices This avoids the boundary check due to a change in the implementation of iteration using `CartecianIndices` in PR #37829. This is a workaround on the caller side and does not change the iteration mechanism itself. Co-authored-by: Matt Bauman <[email protected]> Co-authored-by: thofma <[email protected]> (cherry picked from commit a4cd68c)
This PR intended to only add StepRange support for CartesianIndices, but more things are added here as I was working on it.
Three major changes are involved here:
StepRange CartesianIndices
The biggest change here is to make it possible to pass a
step
to CartesianIndices so that more flexible loop behavior can be doneAnother new thing introduced by this PR is that
step(::CartesianIndices)
now returns aCartesianIndex
, this enables us to treat CartesianIndices as a multidimensional range type.Reduce CartesianIndices overhead
By reworking the iterating part, the overhead issue #9080 is accidentally fixed.
So 🎉 looping over
CartesianIndices
is marginally faster than a manual loop.There's still some overhead for StepRange:
but that's more difficult to deal with because (IIUC)
step
can be either positive or negative. I'm not very familiar with this kind of low-level optimization...tests and bug fixes
A lot of tests are spread in other files, I tried to collect most of the test patterns into
test/cartesian.jl
so it is easier to first check ifinclude("test/cartesian.jl")
works before triggering the whole heavymake test
workflow.A bug is found and fixed (see also #37928) :
New tests are added to test common operations and properties. Old tests are still kept so as to not break anything unexpectedly.
There is still something I want to tackle, but I'm a bit running out of my spare time to keep working on this, which I'll leave them as future work:
cc: @timholy @mbauman
closes #37577
closes #9080