@@ -1390,31 +1390,19 @@ function one{T}(S::SparseMatrixCSC{T})
1390
1390
speye (T, m)
1391
1391
end
1392
1392
1393
- # # Unary arithmetic and boolean operators
1394
1393
1395
- """
1396
- Helper macro for the unary broadcast definitions below. Takes parent method `fp` and a set
1397
- of desired child methods `fcs`, and builds an expression defining each of the child methods
1398
- such that `broadcast(::typeof(fc), A::SparseMatrixCSC) = fp(fc, A)`.
1399
- """
1400
- macro _enumerate_childmethods (fp, fcs... )
1401
- fcexps = Expr (:block )
1402
- for fc in fcs
1403
- push! (fcexps. args, :( $ (esc (:broadcast ))(:: typeof ($ (esc (fc))), A:: SparseMatrixCSC ) = $ (esc (fp))($ (esc (fc)), A) ) )
1404
- end
1405
- return fcexps
1406
- end
1394
+ # # Broadcast operations involving a single sparse matrix and possibly broadcast scalars
1407
1395
1408
- # Operations that map zeros to zeros and may map nonzeros to zeros, yielding a sparse matrix
1409
- """
1410
- Takes unary function `f` that maps zeros to zeros and may map nonzeros to zeros, and returns
1411
- a new `SparseMatrixCSC{TiA,TvB}` `B` generated by applying `f` to each nonzero entry in
1412
- `A` and retaining only the resulting nonzeros.
1413
- "" "
1414
- function _broadcast_unary_nz2z_z2z_T {TvA,TiA,TvB } (f:: Function , A:: SparseMatrixCSC{TvA,TiA} , :: Type{TvB} )
1415
- Bcolptr = Array {TiA} ( A. n + 1 )
1416
- Browval = Array {TiA} ( nnz (A))
1417
- Bnzval = Array {TvB} ( nnz (A))
1396
+ function broadcast {Tf} (f :: Tf , A :: SparseMatrixCSC )
1397
+ fofzero = f ( zero ( eltype (A)))
1398
+ fpreszero = fofzero == zero (fofzero)
1399
+ return fpreszero ? _broadcast_zeropres (f, A) : _broadcast_notzeropres (f, A)
1400
+ end
1401
+ " Returns a `SparseMatrixCSC` storing only the nonzero entries of `broadcast(f, Matrix(A))`. "
1402
+ function _broadcast_zeropres {Tf } (f:: Tf , A:: SparseMatrixCSC )
1403
+ Bcolptr = similar (A . colptr, A. n + 1 )
1404
+ Browval = similar (A . rowval, nnz (A))
1405
+ Bnzval = similar (A . nzval, promote_eltype_op (f, A), nnz (A))
1418
1406
Bk = 1
1419
1407
@inbounds for j in 1 : A. n
1420
1408
Bcolptr[j] = Bk
@@ -1432,69 +1420,59 @@ function _broadcast_unary_nz2z_z2z_T{TvA,TiA,TvB}(f::Function, A::SparseMatrixCS
1432
1420
resize! (Bnzval, Bk - 1 )
1433
1421
return SparseMatrixCSC (A. m, A. n, Bcolptr, Browval, Bnzval)
1434
1422
end
1435
- function _broadcast_unary_nz2z_z2z {Tv} (f:: Function , A:: SparseMatrixCSC{Tv} )
1436
- _broadcast_unary_nz2z_z2z_T (f, A, Tv)
1437
- end
1438
- @_enumerate_childmethods (_broadcast_unary_nz2z_z2z,
1439
- sin, sinh, sind, asin, asinh, asind,
1440
- tan, tanh, tand, atan, atanh, atand,
1441
- sinpi, cosc, ceil, floor, trunc, round)
1442
- broadcast (:: typeof (real), A:: SparseMatrixCSC ) = copy (A)
1443
- broadcast {Tv,Ti} (:: typeof (imag), A:: SparseMatrixCSC{Tv,Ti} ) = spzeros (Tv, Ti, A. m, A. n)
1444
- broadcast {TTv} (:: typeof (real), A:: SparseMatrixCSC{Complex{TTv}} ) = _broadcast_unary_nz2z_z2z_T (real, A, TTv)
1445
- broadcast {TTv} (:: typeof (imag), A:: SparseMatrixCSC{Complex{TTv}} ) = _broadcast_unary_nz2z_z2z_T (imag, A, TTv)
1446
- ceil {To} (:: Type{To} , A:: SparseMatrixCSC ) = _broadcast_unary_nz2z_z2z_T (ceil, A, To)
1447
- floor {To} (:: Type{To} , A:: SparseMatrixCSC ) = _broadcast_unary_nz2z_z2z_T (floor, A, To)
1448
- trunc {To} (:: Type{To} , A:: SparseMatrixCSC ) = _broadcast_unary_nz2z_z2z_T (trunc, A, To)
1449
- round {To} (:: Type{To} , A:: SparseMatrixCSC ) = _broadcast_unary_nz2z_z2z_T (round, A, To)
1450
-
1451
- # Operations that map zeros to zeros and map nonzeros to nonzeros, yielding a sparse matrix
1452
- """
1453
- Takes unary function `f` that maps zeros to zeros and nonzeros to nonzeros, and returns a
1454
- new `SparseMatrixCSC{TiA,TvB}` `B` generated by applying `f` to each nonzero entry in `A`.
1455
- """
1456
- function _broadcast_unary_nz2nz_z2z {TvA,TiA,Tf<:Function} (f:: Tf , A:: SparseMatrixCSC{TvA,TiA} )
1457
- Bcolptr = Vector {TiA} (A. n + 1 )
1458
- Browval = Vector {TiA} (nnz (A))
1459
- copy! (Bcolptr, 1 , A. colptr, 1 , A. n + 1 )
1460
- copy! (Browval, 1 , A. rowval, 1 , nnz (A))
1461
- Bnzval = broadcast (f, A. nzval)
1462
- resize! (Bnzval, nnz (A))
1463
- return SparseMatrixCSC (A. m, A. n, Bcolptr, Browval, Bnzval)
1464
- end
1465
- @_enumerate_childmethods (_broadcast_unary_nz2nz_z2z,
1466
- log1p, expm1, abs, abs2, conj)
1467
- function conj! (A:: SparseMatrixCSC )
1468
- @inbounds @simd for k in 1 : nnz (A)
1469
- A. nzval[k] = conj (A. nzval[k])
1470
- end
1471
- return A
1472
- end
1473
-
1474
- # Operations that map both zeros and nonzeros to zeros, yielding a dense matrix
1475
1423
"""
1476
- Takes unary function `f` that maps both zeros and nonzeros to nonzeros, constructs a new
1477
- `Matrix{TvB}` `B`, populates all entries of `B` with the result of a single `f(one(zero(Tv)))`
1478
- call, and then, for each stored entry in `A`, calls `f` on the entry's value and stores the
1479
- result in the corresponding location in `B`.
1424
+ Returns a (dense) `SparseMatrixCSC` with `f(zero(eltype(A)))` stored in place of each
1425
+ unstored entry in `A` and `f(A[i,j])` stored in place of each stored entry `A[i,j]` in `A`.
1480
1426
"""
1481
- function _broadcast_unary_nz2nz_z2nz {Tv} (f:: Function , A:: SparseMatrixCSC{Tv} )
1482
- B = fill (f (zero (Tv)), size (A))
1483
- @inbounds for j in 1 : A. n
1484
- for k in nzrange (A, j)
1485
- i = A. rowval[k]
1486
- x = A. nzval[k]
1487
- B[i,j] = f (x)
1488
- end
1427
+ function _broadcast_notzeropres {Tf} (f:: Tf , A:: SparseMatrixCSC )
1428
+ nnzB = A. m * A. n
1429
+ # Build structure
1430
+ Bcolptr = similar (A. colptr, A. n + 1 )
1431
+ copy! (Bcolptr, 1 : A. m: (nnzB + 1 ))
1432
+ Browval = similar (A. rowval, nnzB)
1433
+ for k in 1 : A. m: (nnzB - A. m + 1 )
1434
+ copy! (Browval, k, 1 : A. m)
1435
+ end
1436
+ # Populate values
1437
+ Bnzval = fill (f (zero (eltype (A))), nnzB)
1438
+ @inbounds for (j, jo) in zip (1 : A. n, 0 : A. m: (nnzB - 1 )), k in nzrange (A, j)
1439
+ Bnzval[jo + A. rowval[k]] = f (A. nzval[k])
1489
1440
end
1490
- return B
1441
+ # NOTE: Combining the fill call into the loop above to avoid multiple sweeps over /
1442
+ # nonsequential access of Bnzval does not appear to improve performance
1443
+ return SparseMatrixCSC (A. m, A. n, Bcolptr, Browval, Bnzval)
1491
1444
end
1492
- @_enumerate_childmethods (_broadcast_unary_nz2nz_z2nz,
1493
- log, log2, log10, exp, exp2, exp10, sinc, cospi,
1494
- cos, cosh, cosd, acos, acosd,
1495
- cot, coth, cotd, acot, acotd,
1496
- sec, sech, secd, asech,
1497
- csc, csch, cscd, acsch)
1445
+
1446
+ # Cover common broadcast operations involving a single sparse matrix and one or more
1447
+ # broadcast scalars.
1448
+ #
1449
+ # TODO : The minimal snippet below is not satisfying: A better solution would achieve
1450
+ # the same for (1) all broadcast scalar types (Base.Broadcast.containertype(x) == Any?) and
1451
+ # (2) any combination (number, order, type mixture) of broadcast scalars. One might achieve
1452
+ # (2) via a generated function. But how one might simultaneously and gracefully achieve (1)
1453
+ # eludes me. Thoughts much appreciated.
1454
+ #
1455
+ broadcast {Tf} (f:: Tf , x:: Union{Number,Bool} , A:: SparseMatrixCSC ) = broadcast (y -> f (x, y), A)
1456
+ broadcast {Tf} (f:: Tf , A:: SparseMatrixCSC , y:: Union{Number,Bool} ) = broadcast (x -> f (x, y), A)
1457
+ # NOTE: The following two method definitions work around #19096. These definitions should
1458
+ # be folded into the two preceding definitions on resolution of #19096.
1459
+ broadcast {Tf,T} (f:: Tf , :: Type{T} , A:: SparseMatrixCSC ) = broadcast (y -> f (T, y), A)
1460
+ broadcast {Tf,T} (f:: Tf , A:: SparseMatrixCSC , :: Type{T} ) = broadcast (x -> f (x, T), A)
1461
+
1462
+ # TODO : The following definitions should be deprecated.
1463
+ ceil {To} (:: Type{To} , A:: SparseMatrixCSC ) = ceil .(To, A)
1464
+ floor {To} (:: Type{To} , A:: SparseMatrixCSC ) = floor .(To, A)
1465
+ trunc {To} (:: Type{To} , A:: SparseMatrixCSC ) = trunc .(To, A)
1466
+ round {To} (:: Type{To} , A:: SparseMatrixCSC ) = round .(To, A)
1467
+
1468
+ # TODO : Nix these two specializations, or keep them around?
1469
+ broadcast {Tf<:typeof(real)} (:: Tf , A:: SparseMatrixCSC ) = copy (A)
1470
+ broadcast {Tf<:typeof(imag),Tv,Ti} (:: Tf , A:: SparseMatrixCSC{Tv,Ti} ) = spzeros (Tv, Ti, A. m, A. n)
1471
+ # NOTE: Avoiding ambiguities with the general method (broadcast{Tf}(f::Tf, A::SparseMatrixCSC))
1472
+ # necessitates the less-than-graceful Tf<:typeof(fn) type parameters in the above definitions
1473
+
1474
+ # TODO : More appropriate location?
1475
+ conj! (A:: SparseMatrixCSC ) = (broadcast! (conj, A. nzval); A)
1498
1476
1499
1477
1500
1478
# # Broadcasting kernels specialized for returning a SparseMatrixCSC
0 commit comments