Julia v0.6 - adding tuples in parallel for loop


#1

Hi,

I have some problems adding tuples in a parallel for-loop since an update from v0.5 to v0.6.
I define the addition of tuples in the following way …

#defining a function that adds up two tuples a and b of arbitrary length N and element type
addtup{N}(a::NTuple{N,Any},b::NTuple{N,Any}) = ntuple(i-> a[i]+b[i],Val{N}) 

and this function seems to work well both in v0.5 and v0.6 of Julia. E.g., defining a simple tuple of three entries (a scalar, vector and matrix) all composed of ones

mytuple = (1,[1,1,1],[1 1;1 1])
addtup(mytuple,mytuple)   # => (2,[2,2,2],[2 2;2 2])

leads to the correct result (the addition of all tuple elements).
Now I am trying to use this addition operator in a parallel for-loop, that is

  result = @parallel (addtup) for n=1:100
        (1,[1,1,1],[1 1;1 1])
  end

(in reality the parallel loop includes a function that returns a tuple, but the above minimal example should be sufficient). This should evaluate to

result = (100,[100,100,100],[100 100;100 100])

and works fine with Julia v0.5 (in parallel with different workers), and also in v.0.6 if I execute the above loop without starting multiple workers (i.e., starting Julia w/o the “-p” option). However, trying to parallelize it in v.0.6 leads to an error

ERROR: Error deserializing a remote exception from worker 2
Remote(original) exception of type TypeError
Remote stacktrace :
deserialize at ./serialize.jl:776
deserialize_typename at ./serialize.jl:938
deserialize at ./distributed/clusterserialize.jl:52
#99 at ./event.jl:73
Stacktrace:
 [1] collect(::Base.Generator{Array{Task,1},Base.#wait}) at ./array.jl:441
 [2] preduce(::Function, ::Function, ::UnitRange{Int64}) at ./distributed/macros.jl:148

If, in contrast, I replace the addition function by the less universal version (specifying directly the number of tuple elements to be 3)

addtup(a,b) = ntuple(i-> a[i]+b[i],3)

then everything works fine also in v0.6.
Does anyone have an idea what I am doing wrong or how this should be adjusted to work in v0.6 as well?
Many Thanks!


#2

Perhaps not a direct solution, but fyi in 0.6 this is exactly what broadcasted add over tuples does, i.e.

julia> (1,[1,1,1],[1 1;1 1]) .+ (1,[1,1,1],[1 1;1 1])
(2, [2, 2, 2], [2 2; 2 2])

and you can do this with a parallel for-loop as well,

julia> @parallel ((a,b)->broadcast(+,a,b)) for n=1:100
           (1,[1,1,1],[1 1;1 1])
       end
(100, [100, 100, 100], [100 100; 100 100])

#3

Thanks Marius, that’s really helpful. I have not been aware of that new possibility to add tuples. It works well on v0.6 and in parallel, just a bit unfortunate it’s not really compatible to v0.5 (I have still some computers running on that version too).


#4

Actually I didn’t realize this before but it works on 0.5 too (at least 0.5.2 that I’ve checked), just without the “dot” notation. I.e.

julia> broadcast(+,(1,[1,1,1],[1 1;1 1]),(1,[1,1,1],[1 1;1 1]))
(2, [2, 2, 2], [2 2; 2 2])

The for loop version works the same.


#5

It does not work for me in v0.5 (neither in v0.5.2 nor v0.5.0), i.e., throws a “MethodError” independent of if I use the notation “.+” or “broadcast(+,~,~)”. That’s very mysterious …


#6

What exactly is the error?


#7

The error is the following …

julia> broadcast(+,(1,[1,1,1],[1 1;1 1]),(1,[1,1,1],[1 1;1 1]))
ERROR: MethodError: Cannot `convert` an object of type Tuple{Int64,Array{Int64,1
},Array{Int64,2}} to an object of type CartesianRange{I<:CartesianIndex}
This may have arisen from a call to the constructor CartesianRange{I<:CartesianI
ndex}(...),
since type constructors fall back to convert methods.
 in CartesianRange{I<:CartesianIndex}(::Tuple{Int64,Array{Int64,1},Array{Int64,2
}}) at .\sysimg.jl:53
 in broadcast_t(::Function, ::Type{Any}, ::Tuple{Int64,Array{Int64,1},Array{Int6
4,2}}, ::Vararg{Tuple{Int64,Array{Int64,1},Array{Int64,2}},N}) at .\broadcast.jl
:214
 in broadcast(::Function, ::Tuple{Int64,Array{Int64,1},Array{Int64,2}}, ::Tuple{
Int64,Array{Int64,1},Array{Int64,2}}) at .\broadcast.jl:230