-
-
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
Rename LinearFast etc. and define an indexing enumerate(::IndexMethod, iter)
method
#16378
Conversation
+1, but needs docs. You should probably mention |
base/exports.jl
Outdated
@@ -981,6 +982,7 @@ export | |||
enumerate, | |||
next, | |||
start, | |||
visit, |
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 don't think we need to export both uppercase and lowercase any more. Let's stick with just one of them exported. Maybe only one of them defined at all.
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 basically agree with this. So the question is, do we want for (i, a) in enumerate(A)
or for (i, a) in Enumerate(A)
? I kind of prefer the lowercase version, and un-export the type.
As an alternative to a new exported name like However, here this alternative seems to have two problems:
Consequently, for the moment I suspect that exporting |
Most iterators seem to have lowercase functions, and if needed, they're backed by CamelCase types which hold the iterator state. To me, this feels like a good convention to stick to, although it has the usual downside of polluting the address space. (As an aside, I'm liking golang's convention of qualifying most functions with their (short) package name. Numerical computing in Python seems to be going a similar direction ( |
I'm just wondering why we export the "backing" type at all. Seems like the user-friendly constructor is enough. |
The name |
I called it indenumerate in AbstractTrees. |
In Scala, this is called |
|
Is this faster than |
Even though there's a correlation between
Since we already have |
Yes, considerably faster: julia> function itervisit(A)
s = zero(eltype(A))
n = 0
for (I, a) in visit(A)
s += a
n += I[1]>2
end
s, n
end
itervisit (generic function with 1 method)
julia> function iterzip(A)
s = zero(eltype(A))
n = 0
for (I, a) in zip(eachindex(A), A)
s += a
n += I[1]>2
end
s, n
end
iterzip (generic function with 1 method)
julia> A = rand(10000, 1000);
julia> B = sub(A, 1:size(A,1)-1, :);
julia> @benchmark itervisit(A)
================ Benchmark Results ========================
Time per evaluation: 13.47 ms [9.70 ms, 17.24 ms]
Proportion of time in GC: 0.00% [0.00%, 0.00%]
Memory allocated: 0.00 bytes
Number of allocations: 0 allocations
Number of samples: 100
Number of evaluations: 100
Time spent benchmarking: 1.67 s
julia> @benchmark iterzip(A)
================ Benchmark Results ========================
Time per evaluation: 19.27 ms [19.22 ms, 19.31 ms]
Proportion of time in GC: 0.00% [0.00%, 0.00%]
Memory allocated: 0.00 bytes
Number of allocations: 0 allocations
Number of samples: 100
Number of evaluations: 100
Time spent benchmarking: 2.22 s
julia> @benchmark itervisit(B)
================ Benchmark Results ========================
Time per evaluation: 33.56 ms [32.94 ms, 34.17 ms]
Proportion of time in GC: 0.00% [0.00%, 0.00%]
Memory allocated: 48.00 bytes
Number of allocations: 1 allocations
Number of samples: 100
Number of evaluations: 100
Time spent benchmarking: 3.63 s
julia> @benchmark iterzip(B)
================ Benchmark Results ========================
Time per evaluation: 52.60 ms [51.96 ms, 53.25 ms]
Proportion of time in GC: 0.00% [0.00%, 0.00%]
Memory allocated: 0.00 bytes
Number of allocations: 0 allocations
Number of samples: 100
Number of evaluations: 100
Time spent benchmarking: 5.57 s Interesting, though, that there's an allocation in |
I went with @kmsquire's suggestion of |
The AppVeyor looks like a new and very exciting (but unrelated) failure. Anyone seen that before? |
None of my business but I thought I would suggest |
@lstagner you should definitely feel free to make suggestions like this! I'm personally not wed to |
Is there intent to rebase this for 0.6, or 1.0? |
Since this got brought up again one last bit of bikeshedding. I still think this function should be called In the most general sense an array (or any iterable collection) can be thought of type of graph where each vertex has a label (index, key,...) and a value. This iterator then returns the label/value pairs of this graph in the most efficient way. Since the pairs have a special order, in this case efficient memory order, the collection of pairs is a traversal of the graph. Here is the definition of traversal
In principle this function could be generalized to any iterable collection. |
To me the fundamental obstacle is having both |
This is a pattern we have in other cases too, like for I suggest to use a general mechanism like |
Hmm, maybe in conjunction with a renaming (#20175 (comment)) this might be viable. Putting this up for consideration for 0.6. I saw that tomorrow is the stated deadline; I can't do it today, but I probably could tackle it by the end of the day tomorrow. I'll mark this now, and folks coordinating the 0.6 release can comment on whether they think it's important enough to squeeze in. |
One big problem, though, if we return instances rather than types: julia> CartesianIndex()
CartesianIndex{0}(()) But we don't actually want a 0-dimensional cartesian index, we want it to match the dimensionality of the input array. We have this: julia> CartesianIndex{3}()
CartesianIndex{3}((1, 1, 1)) but now I worry that this is less obviously a "trait" than it is a value. |
OK, review comments addressed with the exception of #16378 (comment). If we really want to close the feature/deprecation window today, I think it's too risky to try to fix something like this now, and we should just go with the improvement we have. It passes locally, but perhaps better to let it get through CI. |
shouldn't harm anything, but just in case @nanosoldier |
Yes, I think we'd have to move to a type-based system in order for I think it's too late in the release cycle to open all those cans of worms. This rename is already a huge win. I think that the difference in names can be attributed to the difference between how you index and what you index with… and I think that is defensible. |
deprecation maybe not working as it should? |
I would say it's completely orthogonal to the choice of merging
Well, I admit that passing |
Good catch, @tkelman. Should be fixed now. @nanosoldier |
@nalimilan Yes, sorry, I didn't make it clear my questions were rhetorical. Point is simply that I don't think the use of |
base/deprecated.jl
Outdated
@@ -1272,6 +1272,11 @@ for f in (:airyai, :airyaiprime, :airybi, :airybiprime, :airyaix, :airyaiprimex, | |||
end | |||
end | |||
|
|||
@deprecate_binding LinearIndexing IndexStyle |
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.
This macro will export the old bindings. The @deprecate
macro has an optional third argument to disable this behavior — perhaps you could add that to @deprecate_binding
, too.
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.
Good catch. Fixed (I hope).
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels |
`enumerate(A)` doesn't guarantee that the counter corresponds to the index; so when you need an index, call this method.
Should we think about exporting a short form for |
See discussion above. There seems to be a shortage of good names in the English language. |
…ing traits rename (JuliaLang#16378).
enumerate
lets you count along as you access elements of an iterator/array. This can be viewed as equivalent to key/value iteration, but this perspective basically assumes linear indexing. Sometimes you'd prefer it if the returned "key" is of the most efficient indexing type. Hence,visit
eachindexvalue
.I'm not wedded to the name, so let the bikeshedding begin. This was inspired by working on #16260 (which introduces another reason to be careful about the distinction between counting and indexing), but is sufficiently stand-alone that I thought it merited a separate PR.
I also noticed that
enumerate
doesn't inlinenext
forLinearSlow
arrays. On a quick benchmark, adding@inline
gave a 3x speed improvement. In that casevisit
is still 2x faster (it was 6x faster), but I haven't yet tried to figure out the reason for the remaining gap.