diff --git a/src/SparseArrays.jl b/src/SparseArrays.jl index 04c8cf3b..f70d7a2f 100644 --- a/src/SparseArrays.jl +++ b/src/SparseArrays.jl @@ -160,9 +160,10 @@ const SparseMatrixCSCSubArray{Tv,Ti} = SubArray{Tv,2,<:AbstractSparseMatrixCSC{T const SparseMatrixCSCOrSubArray{Tv,Ti} = Union{AbstractSparseMatrixCSC{Tv,Ti}, SparseMatrixCSCSubArray{Tv,Ti}} # Whole-column views of sparse matrices and whole views of sparse vectors share the -# sparse vector interface. +# sparse vector interface. The length of a `SparseVector` has its index type, so a whole +# view of one slices a `OneTo{Ti}`. const SparseColumnView{Tv,Ti} = SubArray{Tv,1,<:AbstractSparseMatrixCSC{Tv,Ti},Tuple{Base.Slice{Base.OneTo{Int}},Int},false} -const SparseVectorView{Tv,Ti} = SubArray{Tv,1,<:AbstractSparseVector{Tv,Ti},Tuple{Base.Slice{Base.OneTo{Int}}},false} +const SparseVectorView{Tv,Ti} = SubArray{Tv,1,<:AbstractSparseVector{Tv,Ti},<:Tuple{Base.Slice{<:Base.OneTo}},false} const SparseVectorOrView{Tv,Ti} = Union{AbstractCompressedVector{Tv,Ti}, SparseColumnView{Tv,Ti}, SparseVectorView{Tv,Ti}} const AdjOrTransSparseVectorOrView{Tv,Ti} = AdjOrTrans{Tv, <:SparseVectorOrView{Tv,Ti}} # view of a unit range of a sparse vector's indices diff --git a/src/sparsevector.jl b/src/sparsevector.jl index 5d8f997a..6e9e65bf 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -63,8 +63,8 @@ length(x::FixedSparseVector) = getfield(x, :n) size(x::SparseVector) = (getfield(x, :n),) size(x::FixedSparseVector) = (getfield(x, :n),) -function Base._simple_count(f, x::AbstractCompressedVector, init::T) where T - init + T(count(f, nonzeros(x)) + f(zero(eltype(x)))*(length(x) - nnz(x))) +function Base._simple_count(f, x::Union{SparseVectorOrView,SparseVectorPartialView}, init::T) where T + init + T(count(f, nonzeros(x)) + f(_densezero(x))*(length(x) - nnz(x))) end # implement the nnz - nzrange - nonzeros - rowvals interface for sparse vectors @@ -555,6 +555,7 @@ sparsevec(a::AbstractVector{T}) where {T} = SparseVector{T, Int}(a) sparsevec(a::AbstractArray) = sparsevec(vec(a)) sparsevec(a::AbstractSparseMatrixCSC) = a[:] sparsevec(a::AbstractSparseVector) = vec(a) +sparsevec(a::Union{SparseColumnView,SparseVectorView}) = SparseVector(a) sparse(a::AbstractVector) = sparsevec(a) function _dense2indval!(nzind::Vector{Ti}, nzval::Vector{Tv}, s::AbstractArray) where {Tv,Ti} @@ -595,9 +596,9 @@ SparseVector{Tv}(s::AbstractVector) where {Tv} = SparseVector{Tv,Int}(s) SparseVector(s::AbstractVector{Tv}) where {Tv} = SparseVector{Tv,Int}(s) # copy-constructors -SparseVector(s::AbstractCompressedVector{Tv,Ti}) where {Tv,Ti} = SparseVector{Tv,Ti}(s) -SparseVector{Tv}(s::AbstractCompressedVector{<:Any,Ti}) where {Tv,Ti} = SparseVector{Tv,Ti}(s) -function SparseVector{Tv,Ti}(s::AbstractCompressedVector) where {Tv,Ti} +SparseVector(s::SparseVectorOrView{Tv,Ti}) where {Tv,Ti} = SparseVector{Tv,Ti}(s) +SparseVector{Tv}(s::SparseVectorOrView{<:Any,Ti}) where {Tv,Ti} = SparseVector{Tv,Ti}(s) +function SparseVector{Tv,Ti}(s::SparseVectorOrView) where {Tv,Ti} copyind = Vector{Ti}(nonzeroinds(s)) copynz = Vector{Tv}(nonzeros(s)) SparseVector{Tv,Ti}(length(s), copyind, copynz) diff --git a/test/sparsevector.jl b/test/sparsevector.jl index 303195a4..68e22784 100644 --- a/test/sparsevector.jl +++ b/test/sparsevector.jl @@ -1791,9 +1791,9 @@ end @test ((1 + im) * v)::T == (1 + im) * d @test copy(v)::T == d end - # the full-column and full-vector views scale in place through the parent's storage - # (`view(x, :)` is a `SparseVectorView` only when the parent's axes are `Int`-sized) - for v in (view(A, :, 1), (Ti === Int ? (view(x, :),) : ())...), a in (1.0 + im,) + # the full-column and full-vector views scale in place through the parent's storage, + # also when the parent's axes are not `Int` + for v in (view(A, :, 1), view(x, :), view(SparseVector{ComplexF64,Int128}(x), :)), a in (1.0 + im,) @test which(*, (typeof(v), typeof(a))).module === SparseArrays @test which(*, (typeof(a), typeof(v))).module === SparseArrays @test which(/, (typeof(v), typeof(a))).module === SparseArrays @@ -1817,6 +1817,15 @@ end @test @allocated(f(v)) < 10^4 end end + # `count` calls `f` on the stored entries and on one zero + calls = Ref(0) + @test count(z -> (calls[] += 1; !iszero(z)), view(SparseVector{ComplexF64,Int32}(y), :)) == 2 && calls[] == 3 + # a whole view converts with the parent's index type and stored zeros + z = SparseVector{ComplexF64,Int32}(x) + C = SparseMatrixCSC{ComplexF64,Int32}(A) + for (v, u) in ((view(z, :), z), (view(C, :, 1), C[:, 1])), f in (SparseVector, sparse, w -> vcat(w, w), w -> kron(w, z)) + @test exact_equal(f(v), f(u)) + end end end