In JuliaLang/julia#19518, broadcast for sparse matrices underwent a major revision, overall a move in the right direction, IMHO. But it also resulted in a regression (in my eyes) if type inference fails for the operation/element type combination. This issue is meant to continue the discussion started in JuliaLang/julia#19518 (comment).
There are three aspects here that make the problem more acute than for ordinary Arrays.
- For sparse matrices, even basic operations like
+ and - just invoke broadcast internally. OTOH, for Arrays, these do some special tricks for the result type, which helps for the empty case. However, getting the type right for the empty case may not be important enough to warrant such special-casing the be replicated.
- However,
broadcast for sparse matrices relies on inference to determine the output element type not only in the empty as in all-dimensions-zero case, but always also if no entries need to be stored (everything zero), making this case much more likely to occur.
- Once inference fails for an all-zero (or truely empty) case, the element type becomes
Any, which precludes all further operations as zero(::Any) is undefined.
E.g.:
julia> x = spzeros(Real, 2, 2)
2×2 sparse matrix with 0 Real nonzero entries
julia> x + x
2×2 sparse matrix with 0 Any nonzero entries
julia> x + x + x
ERROR: MethodError: no method matching zero(::Type{Any})
Edit: Similarly also
julia> speye(Real, 3) * 1 * 1
ERROR: MethodError: no method matching zero(::Type{Any})
The immediate fix I have in mind (but I find the sparse broadcast machinery too intimidating on first glance to try to implement properly) is the following: If the result of broadcast(op, a, b) would have element type Any (i.e. inference failed) and nzval is empty, use typeof(op(zero(eltype(a)), zero(eltype(b)))) as element type instead. (Likewise for one- and more-argument cases, of course.) For the example above, this would give an element type of Int which would be much more useful than Any.
In JuliaLang/julia#19518,
broadcastfor sparse matrices underwent a major revision, overall a move in the right direction, IMHO. But it also resulted in a regression (in my eyes) if type inference fails for the operation/element type combination. This issue is meant to continue the discussion started in JuliaLang/julia#19518 (comment).There are three aspects here that make the problem more acute than for ordinary
Arrays.+and-just invoke broadcast internally. OTOH, forArrays, these do some special tricks for the result type, which helps for the empty case. However, getting the type right for the empty case may not be important enough to warrant such special-casing the be replicated.broadcastfor sparse matrices relies on inference to determine the output element type not only in the empty as in all-dimensions-zero case, but alwaysalso if no entries need to be stored (everything zero), making this case much more likely to occur.Any, which precludes all further operations aszero(::Any)is undefined.E.g.:
Edit: Similarly also
The immediate fix I have in mind (but I find the sparse broadcast machinery too intimidating on first glance to try to implement properly) is the following: If the result of
broadcast(op, a, b)would have element typeAny(i.e. inference failed) andnzvalis empty, usetypeof(op(zero(eltype(a)), zero(eltype(b))))as element type instead. (Likewise for one- and more-argument cases, of course.) For the example above, this would give an element type ofIntwhich would be much more useful thanAny.