Skip to content

Commit 1a0a0b7

Browse files
authored
Merge pull request #16947 from Sacha0/exportdropzeros
Test, document, and export dropzeros[!]
2 parents fa7e6da + 9529b74 commit 1a0a0b7

File tree

7 files changed

+140
-21
lines changed

7 files changed

+140
-21
lines changed

base/exports.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,8 @@ export
707707

708708
# sparse
709709
full,
710+
dropzeros,
711+
dropzeros!,
710712

711713
# bitarrays
712714
falses,

base/sparse/sparse.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import Base: @get!, acos, acosd, acot, acotd, acsch, asech, asin, asind, asinh,
2929
import Base.Broadcast: eltype_plus, broadcast_shape
3030

3131
export AbstractSparseArray, AbstractSparseMatrix, AbstractSparseVector,
32-
SparseMatrixCSC, SparseVector, blkdiag, dense, droptol!, dropzeros!, etree,
32+
SparseMatrixCSC, SparseVector, blkdiag, dense, droptol!, dropzeros!, dropzeros, etree,
3333
issparse, nonzeros, nzrange, rowvals, sparse, sparsevec, spdiagm, speye, spones,
3434
sprand, sprandn, spzeros, symperm, nnz
3535

base/sparse/sparsematrix.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,24 @@ end
795795
droptol!(A::SparseMatrixCSC, tol, trim::Bool = true) =
796796
fkeep!(A, (i, j, x) -> abs(x) > tol, trim)
797797

798+
"""
799+
dropzeros!(A::SparseMatrixCSC, trim::Bool = true)
800+
801+
Removes stored numerical zeros from `A`, optionally trimming resulting excess space from
802+
`A.rowval` and `A.nzval` when `trim` is `true`.
803+
804+
For an out-of-place version, see [`dropzeros`](:func:`Base.SparseArrays.dropzeros`). For
805+
algorithmic information, see [`Base.SparseArrays.fkeep!`](:func:`Base.SparseArrays.fkeep!`).
806+
"""
798807
dropzeros!(A::SparseMatrixCSC, trim::Bool = true) = fkeep!(A, (i, j, x) -> x != 0, trim)
808+
"""
809+
dropzeros(A::SparseMatrixCSC, trim::Bool = true)
810+
811+
Generates a copy of `A` and removes stored numerical zeros from that copy, optionally
812+
trimming excess space from the result's `rowval` and `nzval` arrays when `trim` is `true`.
813+
814+
For an in-place version and algorithmic information, see [`dropzeros!`](:func:`Base.SparseArrays.dropzeros!`).
815+
"""
799816
dropzeros(A::SparseMatrixCSC, trim::Bool = true) = dropzeros!(copy(A), trim)
800817

801818

base/sparse/sparsevector.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,9 +1689,27 @@ end
16891689

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

1692+
"""
1693+
dropzeros!(x::SparseVector, trim::Bool = true)
1694+
1695+
Removes stored numerical zeros from `x`, optionally trimming resulting excess space from
1696+
`x.nzind` and `x.nzval` when `trim` is `true`.
1697+
1698+
For an out-of-place version, see [`dropzeros`](:func:`Base.SparseArrays.dropzeros`). For
1699+
algorithmic information, see [`Base.SparseArrays.fkeep!`](:func:`Base.SparseArrays.fkeep!`).
1700+
"""
16921701
dropzeros!(x::SparseVector, trim::Bool = true) = fkeep!(x, (i, x) -> x != 0, trim)
1702+
"""
1703+
dropzeros(x::SparseVector, trim::Bool = true)
1704+
1705+
Generates a copy of `x` and removes numerical zeros from that copy, optionally trimming
1706+
excess space from the result's `nzind` and `nzval` arrays when `trim` is `true`.
1707+
1708+
For an in-place version and algorithmic information, see [`dropzeros!`](:func:`Base.SparseArrays.dropzeros!`).
1709+
"""
16931710
dropzeros(x::SparseVector, trim::Bool = true) = dropzeros!(copy(x), trim)
16941711

1712+
16951713
function _fillnonzero!{Tv,Ti}(arr::SparseMatrixCSC{Tv, Ti}, val)
16961714
m, n = size(arr)
16971715
resize!(arr.colptr, n+1)

doc/stdlib/arrays.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,3 +1036,34 @@ dense counterparts. The following functions are specific to sparse arrays.
10361036
end
10371037
end
10381038
1039+
.. function:: dropzeros!(A::SparseMatrixCSC, trim::Bool = true)
1040+
1041+
.. Docstring generated from Julia source
1042+
1043+
Removes stored numerical zeros from ``A``\ , optionally trimming resulting excess space from ``A.rowval`` and ``A.nzval`` when ``trim`` is ``true``\ .
1044+
1045+
For an out-of-place version, see :func:`Base.SparseArrays.dropzeros`\ . For algorithmic information, see :func:`Base.SparseArrays.fkeep!`\ .
1046+
1047+
.. function:: dropzeros(A::SparseMatrixCSC, trim::Bool = true)
1048+
1049+
.. Docstring generated from Julia source
1050+
1051+
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``\ .
1052+
1053+
For an in-place version and algorithmic information, see :func:`Base.SparseArrays.dropzeros!`\ .
1054+
1055+
.. function:: dropzeros!(x::SparseVector, trim::Bool = true)
1056+
1057+
.. Docstring generated from Julia source
1058+
1059+
Removes stored numerical zeros from ``x``\ , optionally trimming resulting excess space from ``x.nzind`` and ``x.nzval`` when ``trim`` is ``true``\ .
1060+
1061+
For an out-of-place version, see :func:`Base.SparseArrays.dropzeros`\ . For algorithmic information, see :func:`Base.SparseArrays.fkeep!`\ .
1062+
1063+
.. function:: dropzeros(x::SparseVector, trim::Bool = true)
1064+
1065+
.. Docstring generated from Julia source
1066+
1067+
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``\ .
1068+
1069+
For an in-place version and algorithmic information, see :func:`Base.SparseArrays.dropzeros!`\ .

test/sparsedir/sparse.jl

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,6 @@ mfe22 = eye(Float64, 2)
365365
# issue #5190
366366
@test_throws ArgumentError sparsevec([3,5,7],[0.1,0.0,3.2],4)
367367

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

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

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

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

1066-
# dropzeros
1067-
A = sparse([1 2 3; 4 5 6; 7 8 9])
1068-
A.nzval[2] = A.nzval[6] = A.nzval[7] = 0
1069-
@test Base.dropzeros!(A).colptr == [1, 3, 5, 7]
1056+
# Test dropzeros[!]
1057+
let smalldim = 5, largedim = 10, nzprob = 0.4, targetnumposzeros = 5, targetnumnegzeros = 5
1058+
for (m, n) in ((largedim, largedim), (smalldim, largedim), (largedim, smalldim))
1059+
A = sprand(m, n, nzprob)
1060+
struczerosA = find(x -> x == 0, A)
1061+
poszerosinds = unique(rand(struczerosA, targetnumposzeros))
1062+
negzerosinds = unique(rand(struczerosA, targetnumnegzeros))
1063+
Aposzeros = setindex!(copy(A), 2, poszerosinds)
1064+
Anegzeros = setindex!(copy(A), -2, negzerosinds)
1065+
Abothsigns = setindex!(copy(Aposzeros), -2, negzerosinds)
1066+
map!(x -> x == 2 ? 0.0 : x, Aposzeros.nzval)
1067+
map!(x -> x == -2 ? -0.0 : x, Anegzeros.nzval)
1068+
map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, Abothsigns.nzval)
1069+
for Awithzeros in (Aposzeros, Anegzeros, Abothsigns)
1070+
# Basic functionality / dropzeros!
1071+
@test Base.dropzeros!(copy(Awithzeros)) == A
1072+
@test Base.dropzeros!(copy(Awithzeros), false) == A
1073+
# Basic functionality / dropzeros
1074+
@test Base.SparseArrays.dropzeros(Awithzeros) == A
1075+
@test Base.SparseArrays.dropzeros(Awithzeros, false) == A
1076+
# Check trimming works as expected
1077+
@test length(Base.dropzeros!(copy(Awithzeros)).nzval) == length(A.nzval)
1078+
@test length(Base.dropzeros!(copy(Awithzeros)).rowval) == length(A.rowval)
1079+
@test length(Base.dropzeros!(copy(Awithzeros), false).nzval) == length(Awithzeros.nzval)
1080+
@test length(Base.dropzeros!(copy(Awithzeros), false).rowval) == length(Awithzeros.rowval)
1081+
end
1082+
end
1083+
# original lone dropzeros test
1084+
A = sparse([1 2 3; 4 5 6; 7 8 9])
1085+
A.nzval[2] = A.nzval[6] = A.nzval[7] = 0
1086+
@test Base.dropzeros!(A).colptr == [1, 3, 5, 7]
1087+
# test for issue #5169, modified for new behavior following #15242/#14798
1088+
@test nnz(sparse([1, 1], [1, 2], [0.0, -0.0])) == 2
1089+
@test nnz(Base.SparseArrays.dropzeros!(sparse([1, 1], [1, 2], [0.0, -0.0]))) == 0
1090+
# test for issue #5437, modified for new behavior following #15242/#14798
1091+
@test nnz(sparse([1, 2, 3], [1, 2, 3], [0.0, 1.0, 2.0])) == 3
1092+
@test nnz(Base.SparseArrays.dropzeros!(sparse([1, 2, 3],[1, 2, 3],[0.0, 1.0, 2.0]))) == 2
1093+
end
10701094

10711095
#trace
10721096
@test_throws DimensionMismatch trace(sparse(ones(5,6)))

test/sparsedir/sparsevector.jl

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -903,19 +903,46 @@ let x = sparsevec(1:7, [3., 2., -1., 1., -2., -3., 3.], 7)
903903
Base.droptol!(xdrop, 3.)
904904
@test exact_equal(xdrop, SparseVector(7, Int[], Float64[]))
905905

906-
# dropzeros
907-
xdrop = copy(x)
908-
xdrop.nzval[[2, 4, 6]] = 0.0
909-
Base.SparseArrays.dropzeros!(xdrop)
910-
@test exact_equal(xdrop, SparseVector(7, [1, 3, 5, 7], [3, -1., -2., 3.]))
911-
912906
xdrop = copy(x)
913907
# This will keep index 1, 3, 4, 7 in xdrop
914908
f_drop(i, x) = (abs(x) == 1.) || (i in [1, 7])
915909
Base.SparseArrays.fkeep!(xdrop, f_drop)
916910
@test exact_equal(xdrop, SparseVector(7, [1, 3, 4, 7], [3., -1., 1., 3.]))
917911
end
918912

913+
# dropzeros[!]
914+
let testdims = (10, 20, 30), nzprob = 0.4, targetnumposzeros = 5, targetnumnegzeros = 5
915+
for m in testdims
916+
v = sprand(m, nzprob)
917+
struczerosv = find(x -> x == 0, v)
918+
poszerosinds = unique(rand(struczerosv, targetnumposzeros))
919+
negzerosinds = unique(rand(struczerosv, targetnumnegzeros))
920+
vposzeros = setindex!(copy(v), 2, poszerosinds)
921+
vnegzeros = setindex!(copy(v), -2, negzerosinds)
922+
vbothsigns = setindex!(copy(vposzeros), -2, negzerosinds)
923+
map!(x -> x == 2 ? 0.0 : x, vposzeros.nzval)
924+
map!(x -> x == -2 ? -0.0 : x, vnegzeros.nzval)
925+
map!(x -> x == 2 ? 0.0 : x == -2 ? -0.0 : x, vbothsigns.nzval)
926+
for vwithzeros in (vposzeros, vnegzeros, vbothsigns)
927+
# Basic functionality / dropzeros!
928+
@test dropzeros!(copy(vwithzeros)) == v
929+
@test dropzeros!(copy(vwithzeros), false) == v
930+
# Basic functionality / dropzeros
931+
@test dropzeros(vwithzeros) == v
932+
@test dropzeros(vwithzeros, false) == v
933+
# Check trimming works as expected
934+
@test length(dropzeros!(copy(vwithzeros)).nzval) == length(v.nzval)
935+
@test length(dropzeros!(copy(vwithzeros)).nzind) == length(v.nzind)
936+
@test length(dropzeros!(copy(vwithzeros), false).nzval) == length(vwithzeros.nzval)
937+
@test length(dropzeros!(copy(vwithzeros), false).nzind) == length(vwithzeros.nzind)
938+
end
939+
end
940+
# original dropzeros! test
941+
xdrop = sparsevec(1:7, [3., 2., -1., 1., -2., -3., 3.], 7)
942+
xdrop.nzval[[2, 4, 6]] = 0.0
943+
Base.SparseArrays.dropzeros!(xdrop)
944+
@test exact_equal(xdrop, SparseVector(7, [1, 3, 5, 7], [3, -1., -2., 3.]))
945+
end
919946

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

0 commit comments

Comments
 (0)