Skip to content

Commit 1ed4545

Browse files
authoredDec 31, 2016
Merge pull request #19690 from Sacha0/sparsevechof
sparse vectors join the higher order function party
2 parents 827de2f + 2786db2 commit 1ed4545

File tree

8 files changed

+1125
-1006
lines changed

8 files changed

+1125
-1006
lines changed
 

‎base/sparse/abstractsparse.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ issparse{T, A<:AbstractSparseMatrix}(S::LinAlg.UnitLowerTriangular{T, A}) = true
2020
issparse{T, A<:AbstractSparseMatrix}(S::UpperTriangular{T, A}) = true
2121
issparse{T, A<:AbstractSparseMatrix}(S::LinAlg.UnitUpperTriangular{T, A}) = true
2222

23-
indtype{Tv,Ti}(S::AbstractSparseArray{Tv,Ti}) = Ti
23+
indtype{Tv,Ti}(S::AbstractSparseArray{Tv,Ti}) = (Base.@_pure_meta; Ti)

‎base/sparse/higherorderfns.jl

+850
Large diffs are not rendered by default.

‎base/sparse/sparse.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import Base: @get!, acos, acosd, acot, acotd, acsch, asech, asin, asind, asinh,
2626
rotl90, rotr90, round, scale!, setindex!, similar, size, transpose, tril,
2727
triu, vec, permute!, map, map!
2828

29-
import Base.Broadcast: _broadcast_type, broadcast_indices
29+
import Base.Broadcast: broadcast_indices
3030

3131
export AbstractSparseArray, AbstractSparseMatrix, AbstractSparseVector,
3232
SparseMatrixCSC, SparseVector, blkdiag, dense, droptol!, dropzeros!, dropzeros,
@@ -36,6 +36,7 @@ export AbstractSparseArray, AbstractSparseMatrix, AbstractSparseVector,
3636
include("abstractsparse.jl")
3737
include("sparsematrix.jl")
3838
include("sparsevector.jl")
39+
include("higherorderfns.jl")
3940

4041
include("linalg.jl")
4142
if Base.USE_GPL_LIBS

‎base/sparse/sparsematrix.jl

-761
Large diffs are not rendered by default.

‎test/choosetests.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ function choosetests(choices = [])
103103
end
104104

105105

106-
sparsetests = ["sparse/sparse", "sparse/sparsevector"]
106+
sparsetests = ["sparse/sparse", "sparse/sparsevector", "sparse/higherorderfns"]
107107
if Base.USE_GPL_LIBS
108108
append!(sparsetests, ["sparse/umfpack", "sparse/cholmod", "sparse/spqr"])
109109
end

‎test/sparse/higherorderfns.jl

+270
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
# This file is a part of Julia. License is MIT: http://julialang.org/license
2+
#
3+
# These tests cover the higher order functions specialized for sparse arrays defined in
4+
# base/sparse/higherorderfns.jl, particularly map[!]/broadcast[!] for SparseVectors and
5+
# SparseMatrixCSCs at present.
6+
7+
@testset "map[!] implementation specialized for a single (input) sparse vector/matrix" begin
8+
N, M = 10, 12
9+
# (also the implementation for broadcast[!] over a single (input) sparse vector/matrix)
10+
for shapeA in ((N,), (N, M))
11+
A = sprand(shapeA..., 0.4); fA = Array(A)
12+
# --> test map entry point
13+
@test map(sin, A) == sparse(map(sin, fA))
14+
@test map(cos, A) == sparse(map(cos, fA))
15+
# --> test map! entry point
16+
fX = copy(fA); X = sparse(fX)
17+
map!(sin, X, A); X = sparse(fX) # warmup for @allocated
18+
@test (@allocated map!(sin, X, A)) == 0
19+
@test map!(sin, X, A) == sparse(map!(sin, fX, fA))
20+
@test map!(cos, X, A) == sparse(map!(cos, fX, fA))
21+
@test_throws DimensionMismatch map!(sin, X, spzeros((shapeA .- 1)...))
22+
end
23+
end
24+
25+
@testset "map[!] implementation specialized for a pair of (input) sparse vectors/matrices" begin
26+
N, M = 10, 12
27+
f(x, y) = x + y + 1
28+
for shapeA in ((N,), (N, M))
29+
A, Bo = sprand(shapeA..., 0.3), sprand(shapeA..., 0.3)
30+
B = ndims(Bo) == 1 ? SparseVector{Float32, Int32}(Bo) : SparseMatrixCSC{Float32,Int32}(Bo)
31+
# use different types to check internal type stability via allocation tests below
32+
fA, fB = map(Array, (A, B))
33+
# --> test map entry point
34+
@test map(+, A, B) == sparse(map(+, fA, fB))
35+
@test map(*, A, B) == sparse(map(*, fA, fB))
36+
@test map(f, A, B) == sparse(map(f, fA, fB))
37+
@test_throws DimensionMismatch map(+, A, spzeros((shapeA .- 1)...))
38+
# --> test map! entry point
39+
fX = map(+, fA, fB); X = sparse(fX)
40+
map!(+, X, A, B); X = sparse(fX) # warmup for @allocated
41+
@test (@allocated map!(+, X, A, B)) == 0
42+
@test map!(+, X, A, B) == sparse(map!(+, fX, fA, fB))
43+
fX = map(*, fA, fB); X = sparse(fX)
44+
map!(*, X, A, B); X = sparse(fX) # warmup for @allocated
45+
@test (@allocated map!(*, X, A, B)) == 0
46+
@test map!(*, X, A, B) == sparse(map!(*, fX, fA, fB))
47+
@test map!(f, X, A, B) == sparse(map!(f, fX, fA, fB))
48+
@test_throws DimensionMismatch map!(f, X, A, spzeros((shapeA .- 1)...))
49+
end
50+
end
51+
52+
@testset "map[!] implementation capable of handling >2 (input) sparse vectors/matrices" begin
53+
N, M = 10, 12
54+
f(x, y, z) = x + y + z + 1
55+
for shapeA in ((N,), (N, M))
56+
A, B, Co = sprand(shapeA..., 0.2), sprand(shapeA..., 0.2), sprand(shapeA..., 0.2)
57+
C = ndims(Co) == 1 ? SparseVector{Float32,Int32}(Co) : SparseMatrixCSC{Float32,Int32}(Co)
58+
# use different types to check internal type stability via allocation tests below
59+
fA, fB, fC = map(Array, (A, B, C))
60+
# --> test map entry point
61+
@test map(+, A, B, C) == sparse(map(+, fA, fB, fC))
62+
@test map(*, A, B, C) == sparse(map(*, fA, fB, fC))
63+
@test map(f, A, B, C) == sparse(map(f, fA, fB, fC))
64+
@test_throws DimensionMismatch map(+, A, B, spzeros(N, M - 1))
65+
# --> test map! entry point
66+
fX = map(+, fA, fB, fC); X = sparse(fX)
67+
map!(+, X, A, B, C); X = sparse(fX) # warmup for @allocated
68+
@test (@allocated map!(+, X, A, B, C)) == 0
69+
@test map!(+, X, A, B, C) == sparse(map!(+, fX, fA, fB, fC))
70+
fX = map(*, fA, fB, fC); X = sparse(fX)
71+
map!(*, X, A, B, C); X = sparse(fX) # warmup for @allocated
72+
@test (@allocated map!(*, X, A, B, C)) == 0
73+
@test map!(*, X, A, B, C) == sparse(map!(*, fX, fA, fB, fC))
74+
@test map!(f, X, A, B, C) == sparse(map!(f, fX, fA, fB, fC))
75+
@test_throws DimensionMismatch map!(f, X, A, B, spzeros((shapeA .- 1)...))
76+
end
77+
end
78+
79+
@testset "broadcast[!] implementation specialized for a single (input) sparse vector/matrix" begin
80+
# broadcast[!] for a single sparse vector/matrix falls back to map[!], tested extensively
81+
# above. here we simply lightly exercise the relevant broadcast[!] entry points.
82+
N, M, p = 10, 12, 0.4
83+
a, A = sprand(N, p), sprand(N, M, p)
84+
fa, fA = Array(a), Array(A)
85+
@test broadcast(sin, a) == sparse(broadcast(sin, fa))
86+
@test broadcast(sin, A) == sparse(broadcast(sin, fA))
87+
@test broadcast!(sin, copy(a), a) == sparse(broadcast!(sin, copy(fa), fa))
88+
@test broadcast!(sin, copy(A), A) == sparse(broadcast!(sin, copy(fA), fA))
89+
end
90+
91+
@testset "broadcast[!] implementation specialized for pairs of (input) sparse vectors/matrices" begin
92+
N, M, p = 10, 12, 0.3
93+
f(x, y) = x + y + 1
94+
mats = (sprand(N, M, p), sprand(N, 1, p), sprand(1, M, p), sprand(1, 1, 1.0), spzeros(1, 1))
95+
vecs = (sprand(N, p), sprand(1, 1.0), spzeros(1))
96+
tens = (mats..., vecs...)
97+
for Xo in tens
98+
X = ndims(Xo) == 1 ? SparseVector{Float32,Int32}(Xo) : SparseMatrixCSC{Float32,Int32}(Xo)
99+
# use different types to check internal type stability via allocation tests below
100+
shapeX, fX = size(X), Array(X)
101+
for Y in tens
102+
fY = Array(Y)
103+
# --> test broadcast entry point
104+
@test broadcast(+, X, Y) == sparse(broadcast(+, fX, fY))
105+
@test broadcast(*, X, Y) == sparse(broadcast(*, fX, fY))
106+
@test broadcast(f, X, Y) == sparse(broadcast(f, fX, fY))
107+
# TODO strengthen this test, avoiding dependence on checking whether
108+
# broadcast_indices throws to determine whether sparse broadcast should throw
109+
try
110+
Base.Broadcast.broadcast_indices(spzeros((shapeX .- 1)...), Y)
111+
catch
112+
@test_throws DimensionMismatch broadcast(+, spzeros((shapeX .- 1)...), Y)
113+
end
114+
# --> test broadcast! entry point / +-like zero-preserving op
115+
fZ = broadcast(+, fX, fY); Z = sparse(fZ)
116+
broadcast!(+, Z, X, Y); Z = sparse(fZ) # warmup for @allocated
117+
@test (@allocated broadcast!(+, Z, X, Y)) == 0
118+
@test broadcast!(+, Z, X, Y) == sparse(broadcast!(+, fZ, fX, fY))
119+
# --> test broadcast! entry point / *-like zero-preserving op
120+
fZ = broadcast(*, fX, fY); Z = sparse(fZ)
121+
broadcast!(*, Z, X, Y); Z = sparse(fZ) # warmup for @allocated
122+
@test (@allocated broadcast!(*, Z, X, Y)) == 0
123+
@test broadcast!(*, Z, X, Y) == sparse(broadcast!(*, fZ, fX, fY))
124+
# --> test broadcast! entry point / not zero-preserving op
125+
fZ = broadcast(f, fX, fY); Z = sparse(fZ)
126+
broadcast!(f, Z, X, Y); Z = sparse(fZ) # warmup for @allocated
127+
@test (@allocated broadcast!(f, Z, X, Y)) == 0
128+
@test broadcast!(f, Z, X, Y) == sparse(broadcast!(f, fZ, fX, fY))
129+
# --> test shape checks for both broadcast and broadcast! entry points
130+
# TODO strengthen this test, avoiding dependence on checking whether
131+
# broadcast_indices throws to determine whether sparse broadcast should throw
132+
try
133+
Base.Broadcast.check_broadcast_indices(indices(Z), spzeros((shapeX .- 1)...), Y)
134+
catch
135+
@test_throws DimensionMismatch broadcast!(f, Z, spzeros((shapeX .- 1)...), Y)
136+
end
137+
end
138+
end
139+
end
140+
141+
@testset "broadcast[!] implementation capable of handling >2 (input) sparse vectors/matrices" begin
142+
N, M, p = 10, 12, 0.3
143+
f(x, y, z) = x + y + z + 1
144+
mats = (sprand(N, M, p), sprand(N, 1, p), sprand(1, M, p), sprand(1, 1, 1.0), spzeros(1, 1))
145+
vecs = (sprand(N, p), sprand(1, 1.0), spzeros(1))
146+
tens = (mats..., vecs...)
147+
for Xo in tens
148+
X = ndims(Xo) == 1 ? SparseVector{Float32,Int32}(Xo) : SparseMatrixCSC{Float32,Int32}(Xo)
149+
# use different types to check internal type stability via allocation tests below
150+
shapeX, fX = size(X), Array(X)
151+
for Y in tens, Z in tens
152+
fY, fZ = Array(Y), Array(Z)
153+
# --> test broadcast entry point
154+
@test broadcast(+, X, Y, Z) == sparse(broadcast(+, fX, fY, fZ))
155+
@test broadcast(*, X, Y, Z) == sparse(broadcast(*, fX, fY, fZ))
156+
@test broadcast(f, X, Y, Z) == sparse(broadcast(f, fX, fY, fZ))
157+
# TODO strengthen this test, avoiding dependence on checking whether
158+
# broadcast_indices throws to determine whether sparse broadcast should throw
159+
try
160+
Base.Broadcast.broadcast_indices(spzeros((shapeX .- 1)...), Y, Z)
161+
catch
162+
@test_throws DimensionMismatch broadcast(+, spzeros((shapeX .- 1)...), Y, Z)
163+
end
164+
# --> test broadcast! entry point / +-like zero-preserving op
165+
fQ = broadcast(+, fX, fY, fZ); Q = sparse(fQ)
166+
broadcast!(+, Q, X, Y, Z); Q = sparse(fQ) # warmup for @allocated
167+
@test (@allocated broadcast!(+, Q, X, Y, Z)) == 0
168+
@test broadcast!(+, Q, X, Y, Z) == sparse(broadcast!(+, fQ, fX, fY, fZ))
169+
# --> test broadcast! entry point / *-like zero-preserving op
170+
fQ = broadcast(*, fX, fY, fZ); Q = sparse(fQ)
171+
broadcast!(*, Q, X, Y, Z); Q = sparse(fQ) # warmup for @allocated
172+
@test (@allocated broadcast!(*, Q, X, Y, Z)) == 0
173+
@test broadcast!(*, Q, X, Y, Z) == sparse(broadcast!(*, fQ, fX, fY, fZ))
174+
# --> test broadcast! entry point / not zero-preserving op
175+
fQ = broadcast(f, fX, fY, fZ); Q = sparse(fQ)
176+
broadcast!(f, Q, X, Y, Z); Q = sparse(fQ) # warmup for @allocated
177+
@test_broken (@allocated broadcast!(f, Q, X, Y, Z)) == 0
178+
# the preceding test allocates 16 bytes in the entry point for broadcast!, but
179+
# none of the earlier tests of the same code path allocate. no allocation shows
180+
# up with --track-allocation=user. allocation shows up on the first line of the
181+
# entry point for broadcast! with --track-allocation=all, but that first line
182+
# almost certainly should not allocate. so not certain what's going on.
183+
@test broadcast!(f, Q, X, Y, Z) == sparse(broadcast!(f, fQ, fX, fY, fZ))
184+
# --> test shape checks for both broadcast and broadcast! entry points
185+
# TODO strengthen this test, avoiding dependence on checking whether
186+
# broadcast_indices throws to determine whether sparse broadcast should throw
187+
try
188+
Base.Broadcast.check_broadcast_indices(indices(Q), spzeros((shapeX .- 1)...), Y, Z)
189+
catch
190+
@test_throws DimensionMismatch broadcast!(f, Q, spzeros((shapeX .- 1)...), Y, Z)
191+
end
192+
end
193+
end
194+
end
195+
196+
# Older tests of sparse broadcast, now largely covered by the tests above
197+
@testset "assorted tests of sparse broadcast over two input arguments" begin
198+
N, p = 10, 0.3
199+
A, B, CF = sprand(N, N, p), sprand(N, N, p), rand(N, N)
200+
AF, BF, C = Array(A), Array(B), sparse(CF)
201+
202+
@test A .* B == AF .* BF
203+
@test A[1,:] .* B == AF[1,:] .* BF
204+
@test A[:,1] .* B == AF[:,1] .* BF
205+
@test A .* B[1,:] == AF .* BF[1,:]
206+
@test A .* B[:,1] == AF .* BF[:,1]
207+
208+
@test A .* B == AF .* BF
209+
@test A[1,:] .* BF == AF[1,:] .* BF
210+
@test A[:,1] .* BF == AF[:,1] .* BF
211+
@test A .* BF[1,:] == AF .* BF[1,:]
212+
@test A .* BF[:,1] == AF .* BF[:,1]
213+
214+
@test A .* B == AF .* BF
215+
@test AF[1,:] .* B == AF[1,:] .* BF
216+
@test AF[:,1] .* B == AF[:,1] .* BF
217+
@test AF .* B[1,:] == AF .* BF[1,:]
218+
@test AF .* B[:,1] == AF .* BF[:,1]
219+
220+
@test A .* B == AF .* BF
221+
@test A[1,:] .* B == AF[1,:] .* BF
222+
@test A[:,1] .* B == AF[:,1] .* BF
223+
@test A .* B[1,:] == AF .* BF[1,:]
224+
@test A .* B[:,1] == AF .* BF[:,1]
225+
226+
@test A .* 3 == AF .* 3
227+
@test 3 .* A == 3 .* AF
228+
@test A[1,:] .* 3 == AF[1,:] .* 3
229+
@test A[:,1] .* 3 == AF[:,1] .* 3
230+
231+
@test A .- 3 == AF .- 3
232+
@test 3 .- A == 3 .- AF
233+
@test A .- B == AF .- BF
234+
@test A - AF == zeros(AF)
235+
@test AF - A == zeros(AF)
236+
@test A[1,:] .- B == AF[1,:] .- BF
237+
@test A[:,1] .- B == AF[:,1] .- BF
238+
@test A .- B[1,:] == AF .- BF[1,:]
239+
@test A .- B[:,1] == AF .- BF[:,1]
240+
241+
@test A .+ 3 == AF .+ 3
242+
@test 3 .+ A == 3 .+ AF
243+
@test A .+ B == AF .+ BF
244+
@test A + AF == AF + A
245+
@test (A .< B) == (AF .< BF)
246+
@test (A .!= B) == (AF .!= BF)
247+
248+
@test A ./ 3 == AF ./ 3
249+
@test A .\ 3 == AF .\ 3
250+
@test 3 ./ A == 3 ./ AF
251+
@test 3 .\ A == 3 .\ AF
252+
@test A .\ C == AF .\ CF
253+
@test A ./ C == AF ./ CF
254+
@test A ./ CF[:,1] == AF ./ CF[:,1]
255+
@test A .\ CF[:,1] == AF .\ CF[:,1]
256+
@test BF ./ C == BF ./ CF
257+
@test BF .\ C == BF .\ CF
258+
259+
@test A .^ 3 == AF .^ 3
260+
@test 3 .^ A == 3 .^ AF
261+
@test A .^ BF[:,1] == AF .^ BF[:,1]
262+
@test BF[:,1] .^ A == BF[:,1] .^ AF
263+
264+
@test spzeros(0,0) + spzeros(0,0) == zeros(0,0)
265+
@test spzeros(0,0) * spzeros(0,0) == zeros(0,0)
266+
@test spzeros(1,0) .+ spzeros(2,1) == zeros(2,0)
267+
@test spzeros(1,0) .* spzeros(2,1) == zeros(2,0)
268+
@test spzeros(1,2) .+ spzeros(0,1) == zeros(0,2)
269+
@test spzeros(1,2) .* spzeros(0,1) == zeros(0,2)
270+
end

‎test/sparse/sparse.jl

-239
Original file line numberDiff line numberDiff line change
@@ -1170,89 +1170,6 @@ end
11701170
@test spdiagm(([1,2],[3.5],[4+5im]), (0,1,-1), 2,2) == [1 3.5; 4+5im 2]
11711171
end
11721172

1173-
@testset "sparse matrix broadcasting" begin
1174-
A = sprand(10,10,0.3)
1175-
B = sprand(10,10,0.3)
1176-
CF = rand(10,10)
1177-
AF = Array(A)
1178-
BF = Array(B)
1179-
C = sparse(CF)
1180-
@test A .* B == AF .* BF
1181-
@test A[1,:] .* B == AF[1,:] .* BF
1182-
@test A[:,1] .* B == AF[:,1] .* BF
1183-
@test A .* B[1,:] == AF .* BF[1,:]
1184-
@test A .* B[:,1] == AF .* BF[:,1]
1185-
1186-
@test A .* B == AF .* BF
1187-
@test A[1,:] .* BF == AF[1,:] .* BF
1188-
@test A[:,1] .* BF == AF[:,1] .* BF
1189-
@test A .* BF[1,:] == AF .* BF[1,:]
1190-
@test A .* BF[:,1] == AF .* BF[:,1]
1191-
1192-
@test A .* B == AF .* BF
1193-
@test AF[1,:] .* B == AF[1,:] .* BF
1194-
@test AF[:,1] .* B == AF[:,1] .* BF
1195-
@test AF .* B[1,:] == AF .* BF[1,:]
1196-
@test AF .* B[:,1] == AF .* BF[:,1]
1197-
1198-
@test A .* B == AF .* BF
1199-
@test A[1,:] .* B == AF[1,:] .* BF
1200-
@test A[:,1] .* B == AF[:,1] .* BF
1201-
@test A .* B[1,:] == AF .* BF[1,:]
1202-
@test A .* B[:,1] == AF .* BF[:,1]
1203-
1204-
@test A .* 3 == AF .* 3
1205-
@test 3 .* A == 3 .* AF
1206-
#@test A[1,:] .* 3 == AF[1,:] .* 3
1207-
@test all(A[1,:] .* 3 .== AF[1,:] .* 3)
1208-
#@test A[:,1] .* 3 == AF[:,1] .* 3
1209-
@test all(A[:,1] .* 3 .== AF[:,1] .* 3)
1210-
#TODO: simple comparation with == returns false because the left side is a (two-dimensional) SparseMatrixCSC
1211-
# while the right side is a Vector
1212-
1213-
@test A .- 3 == AF .- 3
1214-
@test 3 .- A == 3 .- AF
1215-
@test A .- B == AF .- BF
1216-
@test A - AF == zeros(AF)
1217-
@test AF - A == zeros(AF)
1218-
@test A[1,:] .- B == AF[1,:] .- BF
1219-
@test A[:,1] .- B == AF[:,1] .- BF
1220-
@test A .- B[1,:] == AF .- BF[1,:]
1221-
@test A .- B[:,1] == AF .- BF[:,1]
1222-
1223-
@test A .+ 3 == AF .+ 3
1224-
@test 3 .+ A == 3 .+ AF
1225-
@test A .+ B == AF .+ BF
1226-
@test A + AF == AF + A
1227-
@test (A .< B) == (AF .< BF)
1228-
@test (A .!= B) == (AF .!= BF)
1229-
1230-
@test A ./ 3 == AF ./ 3
1231-
@test A .\ 3 == AF .\ 3
1232-
@test 3 ./ A == 3 ./ AF
1233-
@test 3 .\ A == 3 .\ AF
1234-
@test A .\ C == AF .\ CF
1235-
@test A ./ C == AF ./ CF
1236-
@test A ./ CF[:,1] == AF ./ CF[:,1]
1237-
@test A .\ CF[:,1] == AF .\ CF[:,1]
1238-
@test BF ./ C == BF ./ CF
1239-
@test BF .\ C == BF .\ CF
1240-
1241-
@test A .^ 3 == AF .^ 3
1242-
@test 3 .^ A == 3 .^ AF
1243-
@test A .^ BF[:,1] == AF .^ BF[:,1]
1244-
@test BF[:,1] .^ A == BF[:,1] .^ AF
1245-
end
1246-
1247-
@testset "empty matrix broadcasting" begin
1248-
@test spzeros(0,0) + spzeros(0,0) == zeros(0,0)
1249-
@test spzeros(0,0) * spzeros(0,0) == zeros(0,0)
1250-
@test spzeros(1,0) .+ spzeros(2,1) == zeros(2,0)
1251-
@test spzeros(1,0) .* spzeros(2,1) == zeros(2,0)
1252-
@test spzeros(1,2) .+ spzeros(0,1) == zeros(0,2)
1253-
@test spzeros(1,2) .* spzeros(0,1) == zeros(0,2)
1254-
end
1255-
12561173
@testset "error conditions for reinterpret, reshape, and squeeze" begin
12571174
A = sprand(Bool, 5,5,0.2)
12581175
@test_throws ArgumentError reinterpret(Complex128,A)
@@ -1772,31 +1689,6 @@ end
17721689
@inferred hcat(sparse(rand(2,1)), eye(2,2))
17731690
end
17741691

1775-
# Test that broadcast[!](f, [C::SparseMatrixCSC], A::SparseMatrixCSC, B::SparseMatrixCSC)
1776-
# returns the correct (densely populated) result when f(zero(eltype(A)), zero(eltype(B))) != 0
1777-
@testset "check that broadcast[!](f, ... yields the correct (densely populated) result when f does not preserve zeros" begin
1778-
N = 5
1779-
sparsesqrmat = sprand(N, N, 0.5)
1780-
sparsesqrmat2 = sprand(N, N, 0.5)
1781-
sparserowmat = sprand(1, N, 0.5)
1782-
sparsecolmat = sprand(N, 1, 0.5)
1783-
sparse1x1matz = spzeros(1, 1)
1784-
sparse1x1mato = spones(sparse1x1matz)
1785-
zeroscourge = (x, y) -> x + y + 1
1786-
# test case where the matrices have the same shape and no singleton dimensions
1787-
@test broadcast(zeroscourge, sparsesqrmat, sparsesqrmat2) ==
1788-
broadcast(zeroscourge, Matrix(sparsesqrmat), Matrix(sparsesqrmat2))
1789-
# test combinations where either or both matrices have one or more singleton dimensions
1790-
sparsemats = (sparsesqrmat, sparserowmat, sparsecolmat, sparse1x1matz, sparse1x1mato)
1791-
densemats = map(Matrix, sparsemats)
1792-
for (sparseA, denseA) in zip(sparsemats, densemats)
1793-
for (sparseB, denseB) in zip(sparsemats, densemats)
1794-
@test broadcast(zeroscourge, sparseA, sparseB) ==
1795-
broadcast(zeroscourge, denseA, denseB)
1796-
end
1797-
end
1798-
end
1799-
18001692
# Check that `broadcast` methods specialized for unary operations over
18011693
# `SparseMatrixCSC`s determine a reasonable return type.
18021694
@testset "issue #18974" begin
@@ -1807,134 +1699,3 @@ end
18071699
@testset "issue #19503" begin
18081700
@test which(-, (SparseMatrixCSC,)).module == Base.SparseArrays
18091701
end
1810-
1811-
@testset "map[!] over sparse matrices" begin
1812-
N, M = 10, 12
1813-
# test map/map! implementation specialized for a single (input) sparse matrix
1814-
# (also tested through broadcast/broadcast! over a single (input) sparse matrix)
1815-
# --> test map entry point
1816-
A = sprand(N, M, 0.4)
1817-
fA = Array(A)
1818-
@test map(sin, A) == sparse(map(sin, fA))
1819-
@test map(cos, A) == sparse(map(cos, fA))
1820-
# --> test map! entry point
1821-
fX = copy(fA); X = sparse(fX)
1822-
map!(sin, X, A); X = sparse(fX) # warmup for @allocated
1823-
@test (@allocated map!(sin, X, A)) == 0
1824-
@test map!(sin, X, A) == sparse(map!(sin, fX, fA))
1825-
@test map!(cos, X, A) == sparse(map!(cos, fX, fA))
1826-
@test_throws DimensionMismatch map!(sin, X, spzeros(N, M - 1))
1827-
# test map/map! implementation specialized for a pair of (input) sparse matrices
1828-
f(x, y) = x + y + 1
1829-
A = sprand(N, M, 0.3)
1830-
B = convert(SparseMatrixCSC{Float32,Int32}, sprand(N, M, 0.3))
1831-
# use different types to check internal type stability via allocation tests below
1832-
fA, fB = map(Array, (A, B))
1833-
# --> test map entry point
1834-
@test map(+, A, B) == sparse(map(+, fA, fB))
1835-
@test map(*, A, B) == sparse(map(*, fA, fB))
1836-
@test map(f, A, B) == sparse(map(f, fA, fB))
1837-
@test_throws DimensionMismatch map(+, A, spzeros(N, M - 1))
1838-
# --> test map! entry point
1839-
fX = fA .+ fB; X = sparse(fX)
1840-
map!(+, X, A, B); X = sparse(fX) # warmup for @allocated
1841-
@test (@allocated map!(+, X, A, B)) == 0
1842-
@test map!(+, X, A, B) == sparse(map!(+, fX, fA, fB))
1843-
fX = fA .* fB; X = sparse(fX)
1844-
map!(*, X, A, B); X = sparse(fX) # warmup for @allocated
1845-
@test (@allocated map!(*, X, A, B)) == 0
1846-
@test map!(*, X, A, B) == sparse(map!(*, fX, fA, fB))
1847-
@test map!(f, X, A, B) == sparse(map!(f, fX, fA, fB))
1848-
@test_throws DimensionMismatch map!(f, X, A, spzeros(N, M - 1))
1849-
# test map/map! implementation for an arbitrary number of (input) sparse matrices
1850-
f(x, y, z) = x + y + z + 1
1851-
A = sprand(N, M, 0.2)
1852-
B = sprand(N, M, 0.2)
1853-
C = convert(SparseMatrixCSC{Float32,Int32}, sprand(N, M, 0.2))
1854-
# use different types to check internal type stability via allocation tests below
1855-
fA, fB, fC = map(Array, (A, B, C))
1856-
# --> test map entry point
1857-
@test map(+, A, B, C) == sparse(map(+, fA, fB, fC))
1858-
@test map(*, A, B, C) == sparse(map(*, fA, fB, fC))
1859-
@test map(f, A, B, C) == sparse(map(f, fA, fB, fC))
1860-
@test_throws DimensionMismatch map(+, A, B, spzeros(N, M - 1))
1861-
# --> test map! entry point
1862-
fX = fA .+ fB .+ fC; X = sparse(fX)
1863-
map!(+, X, A, B, C); X = sparse(fX) # warmup for @allocated
1864-
@test (@allocated map!(+, X, A, B, C)) == 0
1865-
@test map!(+, X, A, B, C) == sparse(map!(+, fX, fA, fB, fC))
1866-
fX = fA .* fB .* fC; X = sparse(fX)
1867-
map!(*, X, A, B, C); X = sparse(fX) # warmup for @allocated
1868-
@test (@allocated map!(*, X, A, B, C)) == 0
1869-
@test map!(*, X, A, B, C) == sparse(map!(*, fX, fA, fB, fC))
1870-
@test map!(f, X, A, B, C) == sparse(map!(f, fX, fA, fB, fC))
1871-
@test_throws DimensionMismatch map!(f, X, A, B, spzeros(N, M - 1))
1872-
end
1873-
1874-
@testset "test that broadcast! does not allocate unnecessarily" begin
1875-
# broadcast! over a single sparse matrix falls back to map!, tested above
1876-
N, M = 10, 12
1877-
# test broadcast! implementation specialized for a pair of (input) sparse matrices
1878-
f(x, y) = x + y + 1
1879-
A = sprand(N, M, 0.3)
1880-
B = convert(SparseMatrixCSC{Float32,Int32}, sprand(N, 1, 0.3))
1881-
# use different types to check internal type stability via allocation tests below
1882-
X = sparse(Array(A) .+ Array(B))
1883-
broadcast!(+, copy(X), A, B) # warmup for @allocated
1884-
@test (@allocated broadcast!(+, X, A, B)) == 0
1885-
X = sparse(Array(A) .* Array(B))
1886-
broadcast!(*, copy(X), A, B) # warmup for @allocated
1887-
@test (@allocated broadcast!(*, X, A, B)) == 0
1888-
X = sparse(broadcast(f, Array(A), Array(B)))
1889-
broadcast!(f, copy(X), A, B) # warmup for @allocated
1890-
@test (@allocated broadcast!(f, X, A, B)) == 0
1891-
# test broadcast! implementation for an arbitrary number of (input) sparse matrices
1892-
f(x, y, z) = x + y + z + 1
1893-
A = sprand(N, M, 0.2)
1894-
B = sprand(N, 1, 0.2)
1895-
C = convert(SparseMatrixCSC{Float32,Int32}, sprand(1, M, 0.2))
1896-
# use different types to check internal type stability via allocation tests below
1897-
X = sparse(Array(A) .+ Array(B) .+ Array(C))
1898-
broadcast!(+, copy(X), A, B, C) # warmup for @allocated
1899-
@test (@allocated broadcast!(+, X, A, B, C)) == 0
1900-
X = sparse(Array(A) .* Array(B) .* Array(C))
1901-
broadcast!(*, copy(X), A, B, C) # warmup for @allocated
1902-
@test (@allocated broadcast!(*, X, A, B, C)) == 0
1903-
X = sparse(broadcast(f, Array(A), Array(B), Array(C)))
1904-
broadcast!(f, copy(X), A, B, C) # warmup for @allocated
1905-
@test_broken (@allocated broadcast!(f, X, A, B, C)) == 0
1906-
# this last test allocates 16 bytes in the entry point for broadcast!, but none of the
1907-
# earlier tests of the same code path allocate. no allocation shows up with
1908-
# --track-allocation=user. allocation shows up on the first line of the entry point
1909-
# for broadcast! with --track-allocation=all, but that first line almost certainly
1910-
# should not allocate. so not certain what's going on.
1911-
end
1912-
1913-
@testset "test basic correctness of broadcast/broadcast! implementation for more than two (input) sparse matrices" begin
1914-
N, M = 10, 12
1915-
f(xs...) = sum(xs) + 1
1916-
A = sprand(N, M, 0.2)
1917-
B = sprand(N, 1, 0.2)
1918-
C = sprand(1, M, 0.2)
1919-
D = sprand(1, 1, 1.0)
1920-
E = spzeros(1, 1)
1921-
fA, fB, fC, fD, fE = map(Array, (A, B, C, D, E))
1922-
fX, fY = ones(fA), ones(fB)
1923-
X, Y = sparse(fX), sparse(fY)
1924-
for op in (+, *, f)
1925-
# horizontal expansion only
1926-
@test broadcast(op, A, B, B) == sparse(broadcast(op, fA, fB, fB))
1927-
@test broadcast!(op, X, A, B, B) == sparse(broadcast!(op, fX, fA, fB, fB))
1928-
# vertical expansion only
1929-
@test broadcast(op, B, D, E) == sparse(broadcast(op, fB, fD, fE))
1930-
@test broadcast!(op, Y, B, D, E) == sparse(broadcast!(op, fY, fB, fD, fE))
1931-
# separate horizontal and vertical expansion
1932-
@test broadcast(op, A, B, C) == sparse(broadcast(op, fA, fB, fC))
1933-
@test broadcast!(op, X, A, B, C) == sparse(broadcast!(op, fX, fA, fB, fC))
1934-
# simultaneous horizontal and vertical expansion
1935-
@test broadcast(op, A, B, C, D) == sparse(broadcast(op, fA, fB, fC, D))
1936-
@test broadcast!(op, X, A, B, C, D) == sparse(broadcast!(op, fX, fA, fB, fC, fD))
1937-
end
1938-
@test_throws DimensionMismatch broadcast(+, A, B, speye(N))
1939-
@test_throws DimensionMismatch broadcast!(+, X, A, B, speye(N))
1940-
end

‎test/sparse/sparsevector.jl

+1-3
Original file line numberDiff line numberDiff line change
@@ -609,9 +609,7 @@ let x = spv_x1, x2 = spv_x2
609609

610610
# multiplies
611611
xm = SparseVector(8, [2, 6], [5.0, -19.25])
612-
let y=x # workaround for broadcast not preserving sparsity in general
613-
@test exact_equal(x .* y, abs2(x))
614-
end
612+
@test exact_equal(x .* x, abs2(x))
615613
@test exact_equal(x .* x2, xm)
616614
@test exact_equal(x2 .* x, xm)
617615

0 commit comments

Comments
 (0)
Please sign in to comment.