Skip to content
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

fix for loop for array indexing #15497

Merged
merged 1 commit into from
Mar 26, 2016
Merged

fix for loop for array indexing #15497

merged 1 commit into from
Mar 26, 2016

Conversation

meggart
Copy link
Contributor

@meggart meggart commented Mar 14, 2016

This is the iteration fixes for the files abstractarray.jl ... arraymath.jl, see issue #15434

There were quite a few cases where the fix was not obviuos because of one of these reasons:

  • there was an offset in the iteration e.g. (for i=2:length(A))
  • iteration was done over certain dimensions of a matrix
  • changes were too non-trivial for this PR, I did not want to touch (and possibly mess up) map_n! and map_to_n!

However, #Fixme iter and #Fixme comp comments were added in these cases.

@@ -833,7 +833,7 @@ end
function indcopy(sz::Dims, I::Vector)
n = length(I)
s = sz[n]
for i = n+1:length(sz)
for i = n+1:length(sz) #Fixme iter, might be unnecessary, because it is not exported
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is OK here since I is restricted to Vector (as opposed to AbstractVector).

@nalimilan
Copy link
Member

Thanks! I think most of the FIXMEs can be fixed easily, though some of them require more though/work/features.

@meggart
Copy link
Contributor Author

meggart commented Mar 14, 2016

Thanks for the review. I have removed some FIXME comments and updated some type signatures according to your remarks.

@IainNZ
Copy link
Member

IainNZ commented Mar 14, 2016

Does all this ziping slow down the code at all for plain-old-arrrays?

@nalimilan
Copy link
Member

Does all this ziping slow down the code at all for plain-old-arrrays?

It doesn't (well, currently almost not, and with a special iterator type not at all): #15356 (comment)

@@ -179,8 +180,8 @@ end

function ipermutedims(A::AbstractArray,perm)
iperm = Array(Int,length(perm))
for i = 1:length(perm)
iperm[perm[i]] = i
for (i,j) = zip(1:length(perm),eachindex(perm))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the same as enumerate(eachindex(perm)) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, would the enumerate version be preferred?

@meggart
Copy link
Contributor Author

meggart commented Mar 17, 2016

PR is updated according to the comments.

@meggart
Copy link
Contributor Author

meggart commented Mar 17, 2016

Sorry for the confusion, changes were still local...

for i = 1:length(A)
if testf(A[i])
for (i,j) = enumerate(eachindex(A))
if testf(A[j])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the enumerate(eachindex(A)) preferable over the straightforward i=1:length(A)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because some package might implement a non-standard Fortran-style indexing, where indices have an offset and don't start at 1.
Also Linear indexing might be slow if A is a SubArray.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, although makes the code kinda ugly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to use enumerate(A) directly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact the code seems to have a bug as written. It should be something like

for (i, a) in enumerate(A)
    if testf(a)

(In other words, a = A[i].)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, one doesn't need the index of A at all, I will update. But just out of curiosity: is this a bug? The code worked for me, are there cases where it doesn't?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

julia> A = rand(5)
5-element Array{Float64,1}:
 0.819467
 0.980514
 0.190881
 0.936337
 0.882508

julia> for (i, j) in enumerate(A)
           @show A[j]
       end
WARNING: Indexing with non-Integer Reals is deprecated.  It may be that your index arose from an integer division of the form i/j, in which case you should consider using i÷j or div(i,j) instead.
 in depwarn at deprecated.jl:73
 in to_index at deprecated.jl:447
 in getindex at array.jl:282
 [inlined code] from show.jl:127
 in anonymous at no file:0
while loading no file, in expression starting on line 0
ERROR: InexactError()
 in to_index at deprecated.jl:448
 in getindex at array.jl:282
 [inlined code] from show.jl:127
 in anonymous at no file:0

julia> for (i, a) in enumerate(A)
           @show a
       end
a = 0.8194665233152139
a = 0.9805141257931855
a = 0.19088128894552314
a = 0.9363374114892509
a = 0.8825084643072016

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (i, j) in enumerate(A) is not @meggart wrote. He wrote for (i, j) in enumerate(eachindex(A)) which seems like it would work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I was reading too fast. OK, then this wasn't a bug, just a style point.

@@ -179,8 +180,8 @@ end

function ipermutedims(A::AbstractArray,perm)
iperm = Array(Int,length(perm))
for i = 1:length(perm)
iperm[perm[i]] = i
for (i,j) = enumerate(eachindex(perm))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(i,p) = enumerate(perm) ?

@meggart
Copy link
Contributor Author

meggart commented Mar 21, 2016

Is this ok now?

@timholy
Copy link
Member

timholy commented Mar 21, 2016

LGTM. Maybe I should wait for someone else to take a second look 😉.

@meggart
Copy link
Contributor Author

meggart commented Mar 24, 2016

Another option would be to wait until #15459 gets merged and then revisit some of the FIXMEs.

@timholy
Copy link
Member

timholy commented Mar 24, 2016

Sorry for the delay here, @meggart. This is some nice work, exhibiting a clear understanding of the goals and strategies in #15434. I'm guessing #15459 is the beginning, but not end, of a thread of ideas, so I'd rather not hold this hostage to future improvements.

I see this got another thumbs up, so at least one set of eyeballs besides mine has checked this. To satisfy @KristofferC's excellent point in #15564 (comment), let's runbenchmarks("array", vs = "JuliaLang/julia:master").

@@ -1261,14 +1261,14 @@ end

## 2 argument
function map!{F}(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray)
for i = 1:length(A)
dest[i] = f(A[i], B[i])
for (i,j,k) = zip(eachindex(dest),eachindex(A),eachindex(B))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to in to be consistent with the rest?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, spaces after commas are the most frequent convention.

@pao
Copy link
Member

pao commented Mar 24, 2016

Something weird going on with nanosoldier? cc @jrevels

@jrevels
Copy link
Member

jrevels commented Mar 24, 2016

It seems that the build failed due to some issue with threading. Do the other CI services not enable the JULIA_THREADS flag? I enable it for benchmark builds (if the Julia version is high enough) so that the threading benchmarks are available. I could disable that flag, if the problem is indeed unrelated to this PR.

Here's the last couple lines of the build log, if anybody's curious:

⋮
From worker 2:      CC src/signal-handling.o
From worker 2:      CC src/simplevector.o
From worker 2:      CC src/APInt-C.o
From worker 2:      CC src/runtime_intrinsics.o
From worker 2:      CC src/runtime_ccall.o
From worker 2:      CC src/threadgroup.o
From worker 2:      CC src/threading.o
/.../src/threading.c: In function ‘jl_threading_run’:
/.../src/threading.c:394:5: error: too many arguments to function ‘jl_get_specialization1’
jl_lambda_info_t *li = jl_get_specialization1(argtypes, NULL);
^
In file included from /.../src/threading.c:23:0:
/.../src/julia_internal.h:266:19: note: declared here
jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types);
           ^
make[1]: *** [threading.o] Error 1
make[1]: *** Waiting for unfinished jobs....
In file included from /.../src/APInt-C.cpp:9:0:
/.../src/julia.h: In function ‘void jl_lock_frame_push(void (*)())’:
/.../src/julia.h:1374:32: warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object [-Wpedantic]
locks->items[len] = (void*)unlock_func;
                        ^
/.../src/julia.h: In function ‘void jl_eh_restore_state(jl_handler_t*)’:
/.../src/julia.h:1388:47: warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object [-Wpedantic]
     ((void(*)(void))locks->items[i - 1])();
                                       ^
In file included from /.../src/runtime_ccall.cpp:7:0:
/.../src/julia.h: In function ‘void jl_lock_frame_push(void (*)())’:
/.../src/julia.h:1374:32: warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object [-Wpedantic]
locks->items[len] = (void*)unlock_func;
                        ^
/.../src/julia.h: In function ‘void jl_eh_restore_state(jl_handler_t*)’:
/.../src/julia.h:1388:47: warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object [-Wpedantic]
     ((void(*)(void))locks->items[i - 1])();
                                       ^
make: *** [julia-src-release] Error 2

@pao
Copy link
Member

pao commented Mar 24, 2016

It seems that the build failed due to some issue with threading.

#15608

@timholy
Copy link
Member

timholy commented Mar 24, 2016

I also have the impression that threading performance may have been broken for a while, so I'm not certain that the threading benchmarks are worth much now, unless one compares against a much older julia-0.5.

@jrevels
Copy link
Member

jrevels commented Mar 24, 2016

I'll go ahead and disable the flag then. I'll retrigger the benchmarks here once I've made the change.

@jrevels
Copy link
Member

jrevels commented Mar 24, 2016

runbenchmarks("array", vs = "JuliaLang/julia:master")

@meggart
Copy link
Contributor Author

meggart commented Mar 24, 2016

I updated lines 1039 and 1264 according to comments. Looks like this interrupted the perfomance tests? Sorry for this...

@@ -362,8 +362,8 @@ function ctransposeblock!(B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offs
return B
end
function ccopy!(B, A)
for i = 1:length(A)
B[i] = ctranspose(A[i])
for (i,j) = zip(eachindex(B),eachindex(A))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here use in

@jrevels
Copy link
Member

jrevels commented Mar 24, 2016

. Looks like this interrupted the performance tests? Sorry for this...

Don't be! The performance tests are still running on the version of the PR that they were triggered on, it's just that GitHub's UI only shows the status of the latest version.

@nanosoldier
Copy link
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels

@timholy
Copy link
Member

timholy commented Mar 25, 2016

Nice! @meggart, there often seem to be a few tests that get reported as regressions due to noise (there are hundreds of tests run, and so even a p < 0.01 statistical criterion would report a few false alarms). I would recommend checking the sum_each and possibly simd benchmark, but the other one looks like certain noise. The benchmarks are here. I don't think there's a convenient way to re-run specific cases (see https://github.com/JuliaCI/BenchmarkTrackers.jl/issues/16), so what I do is grep for the test and then copy/paste and run similar code locally.

If you need any help, give a shout!

@KristofferC
Copy link
Member

The SIMD benchmarks are currently quite noisy.

@timholy
Copy link
Member

timholy commented Mar 25, 2016

I've definitely seen false reports on the sum_each benchmark too, so I'd give this a 95% chance of being fine. I'm therefore happy to merge this as-is, without further evidence that this doesn't hurt performance. Any objections?

@timholy timholy merged commit 6bf9e98 into JuliaLang:master Mar 26, 2016
@timholy
Copy link
Member

timholy commented Mar 26, 2016

Thanks very much, @meggart!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants