On Julia 1.13 / SparseArrays 1.13.0, multiplying a sparse Float64 matrix that contains Inf (or NaN) by a BitVector returns NaN where earlier versions returned 0.0. The false entries of the BitVector no longer act as strong zeros.
Minimum working example
On Julia 1.12:
julia> VERSION
v"1.12.6"
julia> pkgversion(SparseArrays)
v"1.12.0"
julia> spdiagm([Inf]) * BitVector([false])
1-element Vector{Float64}:
0.0
julia> Inf * false
0.0
On Julia 1.13:
julia> VERSION
v"1.13.0-rc1"
julia> pkgversion(SparseArrays)
v"1.13.0"
julia> spdiagm([Inf]) * BitVector([false])
1-element Vector{Float64}:
NaN
julia> Inf * false
0.0
Cause
Possibly introduced by #666. The inner accumulation in _spmatmul! changed from += to muladd:
- C[rv[j], k] += nzv[j]*αxj
+ C[rvj, k] = muladd(nzv[j], αxj, C[rvj, k])
https://github.com/JuliaSparse/SparseArrays.jl/pull/666/changes#diff-c92a7388d7c72d7e5be3445ed18e898354d6c455b888839e303fe1e6d3a28e7aR172
With a Bool operand, αxj stays false::Bool, so the old code computed Inf * false == 0.0 (strong zero). muladd promotes the Bool to Float64 first, which loses the strong zero:
julia> muladd(Inf, false, 0.0)
NaN
julia> Inf * false + 0.0
0.0
On Julia 1.13 / SparseArrays 1.13.0, multiplying a sparse
Float64matrix that containsInf(orNaN) by aBitVectorreturnsNaNwhere earlier versions returned0.0. Thefalseentries of theBitVectorno longer act as strong zeros.Minimum working example
On Julia 1.12:
On Julia 1.13:
Cause
Possibly introduced by #666. The inner accumulation in
_spmatmul!changed from+=tomuladd:https://github.com/JuliaSparse/SparseArrays.jl/pull/666/changes#diff-c92a7388d7c72d7e5be3445ed18e898354d6c455b888839e303fe1e6d3a28e7aR172
With a
Booloperand,αxjstaysfalse::Bool, so the old code computedInf * false == 0.0(strong zero).muladdpromotes theBooltoFloat64first, which loses the strong zero: