@@ -8,7 +8,7 @@ import Base: map, map!, broadcast, copy, copyto!, _extrema_dims, _extrema_itr
8
8
9
9
using Base: front, tail, to_shape
10
10
using .. SparseArrays: SparseVector, SparseMatrixCSC, AbstractSparseVector, AbstractSparseMatrixCSC,
11
- AbstractSparseMatrix, AbstractSparseArray, indtype, nnz, nzrange,
11
+ AbstractSparseMatrix, AbstractSparseArray, indtype, nnz, nzrange, spzeros,
12
12
SparseVectorUnion, AdjOrTransSparseVectorUnion, nonzeroinds, nonzeros, rowvals, getcolptr, widelength
13
13
using Base. Broadcast: BroadcastStyle, Broadcasted, flatten
14
14
using LinearAlgebra
@@ -132,12 +132,17 @@ function trimstorage!(A::SparseVecOrMat, maxstored)
132
132
resize! (storedvals (A), maxstored)
133
133
return maxstored
134
134
end
135
+
135
136
function expandstorage! (A:: SparseVecOrMat , maxstored)
136
- length (storedinds (A)) < maxstored && resize! (storedinds (A), maxstored)
137
- length (storedvals (A)) < maxstored && resize! (storedvals (A), maxstored)
137
+ if length (storedinds (A)) < maxstored
138
+ resize! (storedinds (A), maxstored)
139
+ resize! (storedvals (A), maxstored)
140
+ end
138
141
return maxstored
139
142
end
140
143
144
+ _checkbuffers (S:: SparseMatrixCSC ) = (@assert length (getcolptr (S)) == size (S, 2 ) + 1 && getcolptr (S)[end ] - 1 == length (rowvals (S)) == length (nonzeros (S)); S)
145
+ _checkbuffers (S:: SparseVector ) = (@assert length (storedvals (S)) == length (storedinds (S)); S)
141
146
142
147
# (2) map[!] entry points
143
148
map (f:: Tf , A:: SparseVector ) where {Tf} = _noshapecheck_map (f, A)
@@ -181,7 +186,7 @@ copy(bc::SpBroadcasted1) = _noshapecheck_map(bc.f, bc.args[1])
181
186
storedvals (C)[1 ] = fofnoargs
182
187
broadcast! (f, view (storedvals (C), 2 : length (storedvals (C))))
183
188
end
184
- return C
189
+ return _checkbuffers (C)
185
190
end
186
191
187
192
function _diffshape_broadcast (f:: Tf , A:: SparseVecOrMat , Bs:: Vararg{SparseVecOrMat,N} ) where {Tf,N}
@@ -224,22 +229,17 @@ _maxnnzfrom(shape::NTuple{2}, A::AbstractSparseMatrixCSC) = nnz(A) * div(shape[1
224
229
@inline _unchecked_maxnnzbcres (shape, As... ) = _unchecked_maxnnzbcres (shape, As)
225
230
@inline _checked_maxnnzbcres (shape:: NTuple{1} , As... ) = shape[1 ] != 0 ? _unchecked_maxnnzbcres (shape, As) : 0
226
231
@inline _checked_maxnnzbcres (shape:: NTuple{2} , As... ) = shape[1 ] != 0 && shape[2 ] != 0 ? _unchecked_maxnnzbcres (shape, As) : 0
227
- @inline function _allocres (shape:: NTuple{1} , indextype, entrytype, maxnnz)
228
- storedinds = Vector {indextype} (undef, maxnnz)
229
- storedvals = Vector {entrytype} (undef, maxnnz)
230
- return SparseVector (shape... , storedinds, storedvals)
231
- end
232
- @inline function _allocres (shape:: NTuple{2} , indextype, entrytype, maxnnz)
233
- pointers = ones (indextype, shape[2 ] + 1 )
234
- storedinds = Vector {indextype} (undef, maxnnz)
235
- storedvals = Vector {entrytype} (undef, maxnnz)
236
- return SparseMatrixCSC (shape... , pointers, storedinds, storedvals)
232
+ @inline function _allocres (shape:: Union{NTuple{1},NTuple{2}} , indextype, entrytype, maxnnz)
233
+ X = spzeros (entrytype, indextype, shape)
234
+ resize! (storedinds (X), maxnnz)
235
+ resize! (storedvals (X), maxnnz)
236
+ return X
237
237
end
238
238
239
239
# (4) _map_zeropres!/_map_notzeropres! specialized for a single sparse vector/matrix
240
240
" Stores only the nonzero entries of `map(f, Array(A))` in `C`."
241
241
function _map_zeropres! (f:: Tf , C:: SparseVecOrMat , A:: SparseVecOrMat ) where Tf
242
- spaceC:: Int = min ( length (storedinds (C)), length ( storedvals (C) ))
242
+ spaceC:: Int = length (nonzeros (C ))
243
243
Ck = 1
244
244
@inbounds for j in columns (C)
245
245
setcolptr! (C, j, Ck)
@@ -255,7 +255,7 @@ function _map_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat) where Tf
255
255
end
256
256
@inbounds setcolptr! (C, numcols (C) + 1 , Ck)
257
257
trimstorage! (C, Ck - 1 )
258
- return C
258
+ return _checkbuffers (C)
259
259
end
260
260
"""
261
261
Densifies `C`, storing `fillvalue` in place of each unstored entry in `A` and
@@ -274,7 +274,7 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseVecOrMa
274
274
end
275
275
# NOTE: Combining the fill! above into the loop above to avoid multiple sweeps over /
276
276
# nonsequential access of storedvals(C) does not appear to improve performance.
277
- return C
277
+ return _checkbuffers (C)
278
278
end
279
279
# helper functions for these methods and some of those below
280
280
@inline _densecoloffsets (A:: SparseVector ) = 0
297
297
298
298
# (5) _map_zeropres!/_map_notzeropres! specialized for a pair of sparse vectors/matrices
299
299
function _map_zeropres! (f:: Tf , C:: SparseVecOrMat , A:: SparseVecOrMat , B:: SparseVecOrMat ) where Tf
300
- spaceC:: Int = min ( length (storedinds (C)), length ( storedvals (C) ))
300
+ spaceC:: Int = length (nonzeros (C ))
301
301
rowsentinelA = convert (indtype (A), numrows (C) + 1 )
302
302
rowsentinelB = convert (indtype (B), numrows (C) + 1 )
303
303
Ck = 1
@@ -336,7 +336,7 @@ function _map_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat, B::SparseVe
336
336
end
337
337
@inbounds setcolptr! (C, numcols (C) + 1 , Ck)
338
338
trimstorage! (C, Ck - 1 )
339
- return C
339
+ return _checkbuffers (C)
340
340
end
341
341
function _map_notzeropres! (f:: Tf , fillvalue, C:: SparseVecOrMat , A:: SparseVecOrMat , B:: SparseVecOrMat ) where Tf
342
342
# Build dense matrix structure in C, expanding storage if necessary
@@ -368,13 +368,13 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseVecOrMa
368
368
Cx != fillvalue && (storedvals (C)[jo + Ci] = Cx)
369
369
end
370
370
end
371
- return C
371
+ return _checkbuffers (C)
372
372
end
373
373
374
374
375
375
# (6) _map_zeropres!/_map_notzeropres! for more than two sparse matrices / vectors
376
376
function _map_zeropres! (f:: Tf , C:: SparseVecOrMat , As:: Vararg{SparseVecOrMat,N} ) where {Tf,N}
377
- spaceC:: Int = min ( length (storedinds (C)), length ( storedvals (C) ))
377
+ spaceC:: Int = length (nonzeros (C ))
378
378
rowsentinel = numrows (C) + 1
379
379
Ck = 1
380
380
stopks = _colstartind_all (1 , As)
@@ -398,7 +398,7 @@ function _map_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMat,N})
398
398
end
399
399
@inbounds setcolptr! (C, numcols (C) + 1 , Ck)
400
400
trimstorage! (C, Ck - 1 )
401
- return C
401
+ return _checkbuffers (C)
402
402
end
403
403
function _map_notzeropres! (f:: Tf , fillvalue, C:: SparseVecOrMat , As:: Vararg{SparseVecOrMat,N} ) where {Tf,N}
404
404
# Build dense matrix structure in C, expanding storage if necessary
@@ -421,7 +421,7 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg{Spars
421
421
activerow = min (rows... )
422
422
end
423
423
end
424
- return C
424
+ return _checkbuffers (C)
425
425
end
426
426
427
427
# helper methods for map/map! methods just above
462
462
# (7) _broadcast_zeropres!/_broadcast_notzeropres! specialized for a single (input) sparse vector/matrix
463
463
function _broadcast_zeropres! (f:: Tf , C:: SparseVecOrMat , A:: SparseVecOrMat ) where Tf
464
464
isempty (C) && return _finishempty! (C)
465
- spaceC:: Int = min ( length (storedinds (C)), length ( storedvals (C) ))
465
+ spaceC:: Int = length (nonzeros (C ))
466
466
# C and A cannot have the same shape, as we directed that case to map in broadcast's
467
467
# entry point; here we need efficiently handle only heterogeneous C-A combinations where
468
468
# one or both of C and A has at least one singleton dimension.
@@ -509,7 +509,7 @@ function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat) where
509
509
end
510
510
@inbounds setcolptr! (C, numcols (C) + 1 , Ck)
511
511
trimstorage! (C, Ck - 1 )
512
- return C
512
+ return _checkbuffers (C)
513
513
end
514
514
function _broadcast_notzeropres! (f:: Tf , fillvalue, C:: SparseVecOrMat , A:: SparseVecOrMat ) where Tf
515
515
# For information on this code, see comments in similar code in _broadcast_zeropres! above
@@ -540,14 +540,14 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseV
540
540
end
541
541
end
542
542
end
543
- return C
543
+ return _checkbuffers (C)
544
544
end
545
545
546
546
547
547
# (8) _broadcast_zeropres!/_broadcast_notzeropres! specialized for a pair of (input) sparse vectors/matrices
548
548
function _broadcast_zeropres! (f:: Tf , C:: SparseVecOrMat , A:: SparseVecOrMat , B:: SparseVecOrMat ) where Tf
549
549
isempty (C) && return _finishempty! (C)
550
- spaceC:: Int = min ( length (storedinds (C)), length ( storedvals (C) ))
550
+ spaceC:: Int = length (nonzeros (C ))
551
551
rowsentinelA = convert (indtype (A), numrows (C) + 1 )
552
552
rowsentinelB = convert (indtype (B), numrows (C) + 1 )
553
553
# C, A, and B cannot all have the same shape, as we directed that case to map in broadcast's
@@ -711,7 +711,7 @@ function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat, B::Sp
711
711
end
712
712
@inbounds setcolptr! (C, numcols (C) + 1 , Ck)
713
713
trimstorage! (C, Ck - 1 )
714
- return C
714
+ return _checkbuffers (C)
715
715
end
716
716
function _broadcast_notzeropres! (f:: Tf , fillvalue, C:: SparseVecOrMat , A:: SparseVecOrMat , B:: SparseVecOrMat ) where Tf
717
717
# For information on this code, see comments in similar code in _broadcast_zeropres! above
@@ -810,7 +810,7 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseV
810
810
end
811
811
end
812
812
end
813
- return C
813
+ return _checkbuffers (C)
814
814
end
815
815
_finishempty! (C:: SparseVector ) = C
816
816
_finishempty! (C:: AbstractSparseMatrixCSC ) = (fill! (getcolptr (C), 1 ); C)
861
861
# (9) _broadcast_zeropres!/_broadcast_notzeropres! for more than two (input) sparse vectors/matrices
862
862
function _broadcast_zeropres! (f:: Tf , C:: SparseVecOrMat , As:: Vararg{SparseVecOrMat,N} ) where {Tf,N}
863
863
isempty (C) && return _finishempty! (C)
864
- spaceC:: Int = min ( length (storedinds (C)), length ( storedvals (C) ))
864
+ spaceC:: Int = length (nonzeros (C ))
865
865
expandsverts = _expandsvert_all (C, As)
866
866
expandshorzs = _expandshorz_all (C, As)
867
867
rowsentinel = numrows (C) + 1
@@ -909,7 +909,7 @@ function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMa
909
909
end
910
910
@inbounds setcolptr! (C, numcols (C) + 1 , Ck)
911
911
trimstorage! (C, Ck - 1 )
912
- return C
912
+ return _checkbuffers (C)
913
913
end
914
914
function _broadcast_notzeropres! (f:: Tf , fillvalue, C:: SparseVecOrMat , As:: Vararg{SparseVecOrMat,N} ) where {Tf,N}
915
915
isempty (C) && return _finishempty! (C)
@@ -950,7 +950,7 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg
950
950
end
951
951
end
952
952
end
953
- return C
953
+ return _checkbuffers (C)
954
954
end
955
955
956
956
# helper method for broadcast/broadcast! methods just above
0 commit comments