Skip to content

Commit 1565bc0

Browse files
tkluckKristofferC
authored andcommitted
SparseArrays: specialize zero(...) so result has nnz(...) = 0 (#34209)
Before this commit, the result of zero(x::AbstractSparseArray) is filled with stored zeros exactly where `x` has a stored value. That is a wasteful artifact of the default fallback implementation for `AbstractArray`. After this commit, we return a sparse array of the same dimensions as `x` without any stored values. This change is backwards incompatible where it relates to object identity. Before this commit, for mutable objects, every stored zero has the same identity. Example: julia> using SparseArrays julia> y = zero(BigInt[1,2,3]); y[1] === y[2] true julia> y = zero(sparse(BigInt[1,2,3])); y[1] === y[2] true julia> Base.zero(a::AbstractSparseArray) = spzeros(eltype(a), size(a)...) julia> y = zero(sparse(BigInt[1,2,3])); y[1] === y[2] false But this behaviour should be classified as a performance bug and can therefore be fixed in a minor (but not a patch) release.
1 parent 46124ba commit 1565bc0

File tree

3 files changed

+8
-1
lines changed

3 files changed

+8
-1
lines changed

NEWS.md

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ Standard library changes
9999

100100
#### SparseArrays
101101

102+
* The return value of `zero(x::AbstractSparseArray)` has no stored zeros anymore ([#31835]).
103+
Previously, it would have stored zeros wherever `x` had them. This makes the operation
104+
constant time instead of `O(<number of stored values>)`.
105+
102106
#### Dates
103107

104108
#### Statistics

stdlib/SparseArrays/src/SparseArrays.jl

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ using Base: ReshapedArray, promote_op, setindex_shape_check, to_shape, tail,
1010
using Base.Sort: Forward
1111
using LinearAlgebra
1212

13-
import Base: +, -, *, \, /, &, |, xor, ==
13+
import Base: +, -, *, \, /, &, |, xor, ==, zero
1414
import LinearAlgebra: mul!, ldiv!, rdiv!, cholesky, adjoint!, diag, eigen, dot,
1515
issymmetric, istril, istriu, lu, tr, transpose!, tril!, triu!,
1616
cond, diagm, factorize, ishermitian, norm, opnorm, lmul!, rmul!, tril, triu, matprod
@@ -52,6 +52,8 @@ similar(D::Diagonal, ::Type{T}, dims::Union{Dims{1},Dims{2}}) where {T} = spzero
5252
similar(S::SymTridiagonal, ::Type{T}, dims::Union{Dims{1},Dims{2}}) where {T} = spzeros(T, dims...)
5353
similar(M::Tridiagonal, ::Type{T}, dims::Union{Dims{1},Dims{2}}) where {T} = spzeros(T, dims...)
5454

55+
zero(a::AbstractSparseArray) = spzeros(eltype(a), size(a)...)
56+
5557
const BiTriSym = Union{Bidiagonal,SymTridiagonal,Tridiagonal}
5658
function *(A::BiTriSym, B::BiTriSym)
5759
TS = promote_op(matprod, eltype(A), eltype(B))

stdlib/SparseArrays/test/sparse.jl

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ end
3636
@testset "issparse" begin
3737
@test issparse(sparse(fill(1,5,5)))
3838
@test !issparse(fill(1,5,5))
39+
@test nnz(zero(sparse(fill(1,5,5)))) == 0
3940
end
4041

4142
@testset "iszero specialization for SparseMatrixCSC" begin

0 commit comments

Comments
 (0)