Skip to content

Commit

Permalink
Test, document, and export dropzeros[!] for both SparseMatrixCSCs a…
Browse files Browse the repository at this point in the history
…nd `SparseVector`s.
  • Loading branch information
Sacha0 committed Jun 16, 2016
1 parent 7ad5eee commit 9529b74
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 21 deletions.
2 changes: 2 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,8 @@ export

# sparse
full,
dropzeros,
dropzeros!,

# bitarrays
falses,
Expand Down
2 changes: 1 addition & 1 deletion base/sparse/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import Base: @get!, acos, acosd, acot, acotd, acsch, asech, asin, asind, asinh,
import Base.Broadcast: eltype_plus, broadcast_shape

export AbstractSparseArray, AbstractSparseMatrix, AbstractSparseVector,
SparseMatrixCSC, SparseVector, blkdiag, dense, droptol!, dropzeros!, etree,
SparseMatrixCSC, SparseVector, blkdiag, dense, droptol!, dropzeros!, dropzeros, etree,
issparse, nonzeros, nzrange, rowvals, sparse, sparsevec, spdiagm, speye, spones,
sprand, sprandn, spzeros, symperm, nnz

Expand Down
17 changes: 17 additions & 0 deletions base/sparse/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,24 @@ end
droptol!(A::SparseMatrixCSC, tol, trim::Bool = true) =
fkeep!(A, (i, j, x) -> abs(x) > tol, trim)

"""
dropzeros!(A::SparseMatrixCSC, trim::Bool = true)
Removes stored numerical zeros from `A`, optionally trimming resulting excess space from
`A.rowval` and `A.nzval` when `trim` is `true`.
For an out-of-place version, see [`dropzeros`](:func:`Base.SparseArrays.dropzeros`). For
algorithmic information, see [`Base.SparseArrays.fkeep!`](:func:`Base.SparseArrays.fkeep!`).
"""
dropzeros!(A::SparseMatrixCSC, trim::Bool = true) = fkeep!(A, (i, j, x) -> x != 0, trim)
"""
dropzeros(A::SparseMatrixCSC, trim::Bool = true)
Generates a copy of `A` and removes stored numerical zeros from that copy, optionally
trimming excess space from the result's `rowval` and `nzval` arrays when `trim` is `true`.
For an in-place version and algorithmic information, see [`dropzeros!`](:func:`Base.SparseArrays.dropzeros!`).
"""
dropzeros(A::SparseMatrixCSC, trim::Bool = true) = dropzeros!(copy(A), trim)


Expand Down
18 changes: 18 additions & 0 deletions base/sparse/sparsevector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1689,9 +1689,27 @@ end

droptol!(x::SparseVector, tol, trim::Bool = true) = fkeep!(x, (i, x) -> abs(x) > tol, trim)

"""
dropzeros!(x::SparseVector, trim::Bool = true)
Removes stored numerical zeros from `x`, optionally trimming resulting excess space from
`x.nzind` and `x.nzval` when `trim` is `true`.
For an out-of-place version, see [`dropzeros`](:func:`Base.SparseArrays.dropzeros`). For
algorithmic information, see [`Base.SparseArrays.fkeep!`](:func:`Base.SparseArrays.fkeep!`).
"""
dropzeros!(x::SparseVector, trim::Bool = true) = fkeep!(x, (i, x) -> x != 0, trim)
"""
dropzeros(x::SparseVector, trim::Bool = true)
Generates a copy of `x` and removes numerical zeros from that copy, optionally trimming
excess space from the result's `nzind` and `nzval` arrays when `trim` is `true`.
For an in-place version and algorithmic information, see [`dropzeros!`](:func:`Base.SparseArrays.dropzeros!`).
"""
dropzeros(x::SparseVector, trim::Bool = true) = dropzeros!(copy(x), trim)


function _fillnonzero!{Tv,Ti}(arr::SparseMatrixCSC{Tv, Ti}, val)
m, n = size(arr)
resize!(arr.colptr, n+1)
Expand Down
31 changes: 31 additions & 0 deletions doc/stdlib/arrays.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1036,3 +1036,34 @@ dense counterparts. The following functions are specific to sparse arrays.
end
end
.. function:: dropzeros!(A::SparseMatrixCSC, trim::Bool = true)

.. Docstring generated from Julia source
Removes stored numerical zeros from ``A``\ , optionally trimming resulting excess space from ``A.rowval`` and ``A.nzval`` when ``trim`` is ``true``\ .

For an out-of-place version, see :func:`Base.SparseArrays.dropzeros`\ . For algorithmic information, see :func:`Base.SparseArrays.fkeep!`\ .

.. function:: dropzeros(A::SparseMatrixCSC, trim::Bool = true)

.. Docstring generated from Julia source
Generates a copy of ``A`` and removes stored numerical zeros from that copy, optionally trimming excess space from the result's ``rowval`` and ``nzval`` arrays when ``trim`` is ``true``\ .

For an in-place version and algorithmic information, see :func:`Base.SparseArrays.dropzeros!`\ .

.. function:: dropzeros!(x::SparseVector, trim::Bool = true)

.. Docstring generated from Julia source
Removes stored numerical zeros from ``x``\ , optionally trimming resulting excess space from ``x.nzind`` and ``x.nzval`` when ``trim`` is ``true``\ .

For an out-of-place version, see :func:`Base.SparseArrays.dropzeros`\ . For algorithmic information, see :func:`Base.SparseArrays.fkeep!`\ .

.. function:: dropzeros(x::SparseVector, trim::Bool = true)

.. Docstring generated from Julia source
Generates a copy of ``x`` and removes numerical zeros from that copy, optionally trimming excess space from the result's ``nzind`` and ``nzval`` arrays when ``trim`` is ``true``\ .

For an in-place version and algorithmic information, see :func:`Base.SparseArrays.dropzeros!`\ .
52 changes: 38 additions & 14 deletions test/sparsedir/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,6 @@ mfe22 = eye(Float64, 2)
# issue #5190
@test_throws ArgumentError sparsevec([3,5,7],[0.1,0.0,3.2],4)

# issue #5169
@test nnz(sparse([1,1],[1,2],[0.0,-0.0])) == 2
@test nnz(Base.SparseArrays.dropzeros!(sparse([1,1],[1,2],[0.0,-0.0]))) == 0
# changed from `== 0` to `== 2` and added dropzeros! form in #14798,
# matching sparse()'s behavioral revision discussed in #12605, #9928, #9906, #6769

# issue #5386
K,J,V = findnz(SparseMatrixCSC(2,1,[1,3],[1,2],[1.0,0.0]))
Expand All @@ -379,11 +374,6 @@ K,J,V = findnz(SparseMatrixCSC(2,1,[1,3],[1,2],[1.0,0.0]))
A = speye(Bool, 5)
@test find(A) == find(x -> x == true, A) == find(full(A))

# issue #5437
@test nnz(sparse([1,2,3],[1,2,3],[0.0,1.0,2.0])) == 3
@test nnz(Base.SparseArrays.dropzeros!(sparse([1,2,3],[1,2,3],[0.0,1.0,2.0]))) == 2
# changed from `== 2` to `== 3` and added dropzeros! form in #14798,
# matching sparse()'s behavioral revision discussed in #12605, #9928, #9906, #6769

# issue #5824
@test sprand(4,5,0.5).^0 == sparse(ones(4,5))
Expand Down Expand Up @@ -1063,10 +1053,44 @@ perm = randperm(10)
@test Base.droptol!(A,0.01).colptr == [1,1,1,2,2,3,4,6,6,7,9]
@test isequal(Base.droptol!(sparse([1], [1], [1]), 1), SparseMatrixCSC(1,1,Int[1,1],Int[],Int[]))

# dropzeros
A = sparse([1 2 3; 4 5 6; 7 8 9])
A.nzval[2] = A.nzval[6] = A.nzval[7] = 0
@test Base.dropzeros!(A).colptr == [1, 3, 5, 7]
# Test dropzeros[!]
let smalldim = 5, largedim = 10, nzprob = 0.4, targetnumposzeros = 5, targetnumnegzeros = 5
for (m, n) in ((largedim, largedim), (smalldim, largedim), (largedim, smalldim))
A = sprand(m, n, nzprob)
struczerosA = find(x -> x == 0, A)
poszerosinds = unique(rand(struczerosA, targetnumposzeros))
negzerosinds = unique(rand(struczerosA, targetnumnegzeros))
Aposzeros = setindex!(copy(A), 2, poszerosinds)
Anegzeros = setindex!(copy(A), -2, negzerosinds)
Abothsigns = setindex!(copy(Aposzeros), -2, negzerosinds)
map!(x -> x == 2 ? 0.0 : x, Aposzeros.nzval)
map!(x -> x == -2 ? -0.0 : x, Anegzeros.nzval)
map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, Abothsigns.nzval)
for Awithzeros in (Aposzeros, Anegzeros, Abothsigns)
# Basic functionality / dropzeros!
@test Base.dropzeros!(copy(Awithzeros)) == A
@test Base.dropzeros!(copy(Awithzeros), false) == A
# Basic functionality / dropzeros
@test Base.SparseArrays.dropzeros(Awithzeros) == A
@test Base.SparseArrays.dropzeros(Awithzeros, false) == A
# Check trimming works as expected
@test length(Base.dropzeros!(copy(Awithzeros)).nzval) == length(A.nzval)
@test length(Base.dropzeros!(copy(Awithzeros)).rowval) == length(A.rowval)
@test length(Base.dropzeros!(copy(Awithzeros), false).nzval) == length(Awithzeros.nzval)
@test length(Base.dropzeros!(copy(Awithzeros), false).rowval) == length(Awithzeros.rowval)
end
end
# original lone dropzeros test
A = sparse([1 2 3; 4 5 6; 7 8 9])
A.nzval[2] = A.nzval[6] = A.nzval[7] = 0
@test Base.dropzeros!(A).colptr == [1, 3, 5, 7]
# test for issue #5169, modified for new behavior following #15242/#14798
@test nnz(sparse([1, 1], [1, 2], [0.0, -0.0])) == 2
@test nnz(Base.SparseArrays.dropzeros!(sparse([1, 1], [1, 2], [0.0, -0.0]))) == 0
# test for issue #5437, modified for new behavior following #15242/#14798
@test nnz(sparse([1, 2, 3], [1, 2, 3], [0.0, 1.0, 2.0])) == 3
@test nnz(Base.SparseArrays.dropzeros!(sparse([1, 2, 3],[1, 2, 3],[0.0, 1.0, 2.0]))) == 2
end

#trace
@test_throws DimensionMismatch trace(sparse(ones(5,6)))
Expand Down
39 changes: 33 additions & 6 deletions test/sparsedir/sparsevector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -903,19 +903,46 @@ let x = sparsevec(1:7, [3., 2., -1., 1., -2., -3., 3.], 7)
Base.droptol!(xdrop, 3.)
@test exact_equal(xdrop, SparseVector(7, Int[], Float64[]))

# dropzeros
xdrop = copy(x)
xdrop.nzval[[2, 4, 6]] = 0.0
Base.SparseArrays.dropzeros!(xdrop)
@test exact_equal(xdrop, SparseVector(7, [1, 3, 5, 7], [3, -1., -2., 3.]))

xdrop = copy(x)
# This will keep index 1, 3, 4, 7 in xdrop
f_drop(i, x) = (abs(x) == 1.) || (i in [1, 7])
Base.SparseArrays.fkeep!(xdrop, f_drop)
@test exact_equal(xdrop, SparseVector(7, [1, 3, 4, 7], [3., -1., 1., 3.]))
end

# dropzeros[!]
let testdims = (10, 20, 30), nzprob = 0.4, targetnumposzeros = 5, targetnumnegzeros = 5
for m in testdims
v = sprand(m, nzprob)
struczerosv = find(x -> x == 0, v)
poszerosinds = unique(rand(struczerosv, targetnumposzeros))
negzerosinds = unique(rand(struczerosv, targetnumnegzeros))
vposzeros = setindex!(copy(v), 2, poszerosinds)
vnegzeros = setindex!(copy(v), -2, negzerosinds)
vbothsigns = setindex!(copy(vposzeros), -2, negzerosinds)
map!(x -> x == 2 ? 0.0 : x, vposzeros.nzval)
map!(x -> x == -2 ? -0.0 : x, vnegzeros.nzval)
map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, vbothsigns.nzval)
for vwithzeros in (vposzeros, vnegzeros, vbothsigns)
# Basic functionality / dropzeros!
@test dropzeros!(copy(vwithzeros)) == v
@test dropzeros!(copy(vwithzeros), false) == v
# Basic functionality / dropzeros
@test dropzeros(vwithzeros) == v
@test dropzeros(vwithzeros, false) == v
# Check trimming works as expected
@test length(dropzeros!(copy(vwithzeros)).nzval) == length(v.nzval)
@test length(dropzeros!(copy(vwithzeros)).nzind) == length(v.nzind)
@test length(dropzeros!(copy(vwithzeros), false).nzval) == length(vwithzeros.nzval)
@test length(dropzeros!(copy(vwithzeros), false).nzind) == length(vwithzeros.nzind)
end
end
# original dropzeros! test
xdrop = sparsevec(1:7, [3., 2., -1., 1., -2., -3., 3.], 7)
xdrop.nzval[[2, 4, 6]] = 0.0
Base.SparseArrays.dropzeros!(xdrop)
@test exact_equal(xdrop, SparseVector(7, [1, 3, 5, 7], [3, -1., -2., 3.]))
end

# It's tempting to share data between a SparseVector and a SparseArrays,
# but if that's done, then modifications to one or the other will cause
Expand Down

0 comments on commit 9529b74

Please sign in to comment.