-
-
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
type-instability in sum (and other reductions) #6069
Comments
That seems like the correct solution. |
What about types for which |
If the container isn't empty, we should use the first element to start this. Returning |
What about if the container has only one element and |
Hmm. Yes, that's a bit of a problem. We can use |
Maybe we should only use the |
Is there any summable type |
It's a little disturbing that it so hard to make a simple function like |
Well, the flip side in a statically typed system is that it's hard to even have a generic sum function – because it would have such a complicated type signature. Of course, this could all be made simpler by making the sum of two values of the same type always be of that type, but I'm not convinced that's a good idea yet – and it's a rather different question. |
I found a counterexample: julia> A=Matrix[randn(1,1), randn(2,2)]
2-element Array{Array{T,2},1}:
[1.76797]
[-0.0870554 0.307046
1.15972 -0.36789]
julia> reduce(.*, A)
2x2 Array{Float64,2}:
-0.153911 0.542849
2.05035 -0.650418
julia> zero(A[1]).*zero(A[2])
2x2 Array{Float64,2}:
0.0 0.0
0.0 0.0
julia> T = eltype(A)
Array{T,2}
julia> zero(T)
ERROR: no method convert(Type{Array{T,2}}, Int64)
in zero at abstractarray.jl:225 |
@jiahao, what about for sum? Type-stability in reduce is much harder, I agree. |
I found an example which is type stable but for which julia> using Color; A=[LCHuv(rand(3)...) for i=1:10];
julia> sum(A)
LCHuv(3.9230728595082516,5.225114269676179,5.640624576230978)
julia> zero(eltype(A))
ERROR: no method convert(Type{LCHuv}, Int64)
in zero at operators.jl:146 |
Arguably, this is just a case of a missing |
Here is a more insidious one: julia> A=[Bidiagonal(rand(5), rand(4), randbool()) for i=1:10] #Generate random lower and upper bidiagonals
10-element Array{Bidiagonal{Float64},1}:
5x5 Bidiagonal{Float64}:
diag: 0.859519 0.195208 0.300049 0.783655 0.584966
sub: 0.825225 0.562332 0.149394 0.177572
5x5 Bidiagonal{Float64}:
diag: 0.0359303 0.721596 0.17091 0.924345 0.96887
super: 0.288528 0.138715 0.960179 0.75766
...
julia> eltype(A)
Bidiagonal{Float64} (constructor with 1 method)
julia> sum(A)
5x5 Tridiagonal{Float64}:
5.05453 2.20272 0.0 0.0 0.0
3.36481 5.43659 2.00832 0.0 0.0
0.0 2.56735 5.3427 3.2014 0.0
0.0 0.0 2.60014 5.09088 3.53915
0.0 0.0 0.0 2.21059 5.00687
julia> zero(eltype(A)) #Lower or upper bidiagonal?
ERROR: no method convert(Type{Bidiagonal{Float64}}, Int64)
in zero at operators.jl:146 |
You only need zero(::T), not zero(T), for summing non empty collections.
|
Perhaps the goal should be to have One option might be this:
|
I've pushed a possible fix (stevengj@7f553ff) to a branch. |
cross-reference discussion in #5588 |
+1 for |
@lindahua, my latest version turns out not to need |
The
sum
function is extremely slow for several types because of a type instability whenevertypeof(zero(T)+zero(T)) != T
. For example, the following implementation is almost 100x faster thansum
for anArray{Int8}
:Also, the
sum
function is type-unstable for the same reason, e.g.:Recommendation: use
typeof(zero(T)+zero(T))
for the accumulation insum
and friends, and returnzero(T)+zero(T)
for sums of empty arrays rather thanzero(T)
. (Or is there some other way to infer the type of arithmetic results that is faster/cleaner thanzero(T)+zero(T)
?)The same problem shows up in other reductions, e.g.
typeof(reduce(+, Int8[1,2])) != typeof(reduce(+, Int8[1]))
.cc: @jiahao
The text was updated successfully, but these errors were encountered: