-
Notifications
You must be signed in to change notification settings - Fork 12
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
Simplify indexing #10
Conversation
Codecov Report
@@ Coverage Diff @@
## master #10 +/- ##
============================================
- Coverage 100.00% 70.37% -29.63%
============================================
Files 1 1
Lines 18 27 +9
============================================
+ Hits 18 19 +1
- Misses 0 8 +8
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
One behaviour changed by this PR is:
So linear indexing will cover the whole matrix, not just the first column. It still has |
Thanks for the pull request! Here are some performance results from me. Before:
After:
Linear indexing of linear arrays didn't change, 2D-indexing of matrices got a lot faster just as you reported and no longer does a lot of allocations, but linear indexing of matrices has gotten slower. All these results can be reproduced for larger arrays (200×200 elements accessed) and more dimensions. Linear indexing of a higher-dimensional array is consistently about 3 times slower with the PR than without for 2D arrays, 4 times slower with 3D arrays and 6 times slower with 4D arrays. Before:
After:
Linear indexing of the array has so far been undocumented behaviour, so changing the behaviour doesn't seem to be much of a problem to me, I agree with the new behaviour a lot more. However, the slowdown getting worse the more dimensions the array has is worrying. That should probably be addressed. Adding |
If I had to guess, this slowdown may be caused by the linear indexing special case being removed, making linear and multi-dimensional indexing use the same method. In the old version, the special case for linear indexing did not use a splatting operator Furthermore, I discovered that the arrays no longer error on indexing with bad dimensions: Before:
After:
|
I'm not sure we should call the change in time for linear indexing of a matrix a slowdown, as it's doing a different operation. Instead of accessing the first column repeatedly, it reads out all the data, and either your calculation wants one or it wants the other. But I am not surprised that reading all the data takes longer, I'd point to thinks fitting in registers or cache or something like that. And, to go from Cartesian to Linear indices is just multiplication, but the reverse involves
The old behaviour didn't pay this cost, because it fixed all indices but the leftmost one to 1. What is still weird about linear indexing is that the algorithm from Base it's using to convert to Cartesian seems not to behave well with negative numbers.
Before was even weirder, I think:
|
Oh I didn't see that variant. I saw this one, and added a test:
I'm not sure how weird this is, given that ordinary arrays do handle things like this:
But if you like I'll restore the error. |
But when the underlying array supports fast linear indexing, then there's no need to go via Cartesian. So the latest commit speeds this up:
and avoids some weirdness:
and adds a bounds check to restore the error on too few indices. But breaks one offset array test, not sure why yet. |
Of course, I didn't think about that. However, re-adding the specialized method did fix it.
It pretty much just delegated the getindex call to the inner array, if you look at the error trace it mentions the Base.getindex in array.jl being the one that errors, as normal arrays don't support non-matching indices. This behaviour should probably be kept for consistency.
Thank you for adding the special cases back! The slowdown is indeed resolved. Although, you should not use the |
I don't think this is true, it should specialise here. The two weird cases are
I was concerned about things like |
In the past, I have had bad experiences with using abstract types in method signatures unless absolutely necessary, making julia unable to specialize the method for subtypes. |
Base is confusing... there are indeed more |
Thank you for the adjustments. I guess what's left is to figure out why it breaks with CartesianIndex. I already confirmed it has nothing to do with OffsetArrays.
|
That's progress. Via
I suspect that |
I don't think having to implement |
Yes I don't like it at all. What I expected to work was overloading But in fact this case goes to |
I thought I saw a way, but now I invented some more evil test cases and it fails. |
src/CircularArrays.jl
Outdated
@@ -50,6 +69,14 @@ CircularArray(def::T, size) where T = CircularArray(fill(def, size)) | |||
CircularVector(data::AbstractArray{T, 1}) where T = CircularVector{T}(data) | |||
CircularVector(def::T, size::Int) where T = CircularVector{T}(fill(def, size)) | |||
|
|||
Base.IndexStyle(::Type{CircularArray{T,N,A}}) where {T,N,A} = IndexStyle(A) |
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.
The question came to me why this line would be needed. Wouldn't the issues with CartesianIndex be resolved if the IndexStyle defaulted to IndexCartesian
for anyhting but CircularVector? That would result in the calls with CartesianIndex parameters to run through the second implementation of getindex
instead of the first. Then all the hacks into to_indices could also be removed. I would be very interested to see your "more evil test cases" and see if they work with this, because all the current tests pass like 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.
I thought this was necessary for speed, although it's entirely possible I have got lost in all the versions now. It causes eachindex(A)
to prefer linear indexing, which can drop straight through to the underlying memory, whereas iterating CartesianIndices
involves some multiplications by strides... necessary when the underlying array is transposed, say.
I've pushed what I had lying around.
With my changes, all tests appear to pass, even your new ones, and I cannot find any noticeable slowdown in any of the benchmarks listed in this issue thread, at least with standard arrays. Perhaps you can try the proposed changes, if something turns out to have broken I will revert them. |
Since I heard no more feedback on this, I'll merge it. It seems to be working fine. |
Sorry about vanishing. I forgot all the details now but if it passes those tests it must be working pretty well! |
Before:
After: