@@ -1413,7 +1413,7 @@ function map{Tf,N}(f::Tf, A::SparseMatrixCSC, Bs::Vararg{SparseMatrixCSC,N})
1413
1413
fofzeros = f (_zeros_eltypes (A, Bs... )... )
1414
1414
fpreszeros = fofzeros == zero (fofzeros)
1415
1415
maxnnzC = fpreszeros ? min (length (A), _sumnnzs (A, Bs... )) : length (A)
1416
- entrytypeC = _broadcast_type (f, A, Bs ... )
1416
+ entrytypeC = typeof (fofzeros )
1417
1417
indextypeC = _promote_indtype (A, Bs... )
1418
1418
Ccolptr = Vector {indextypeC} (A. n + 1 )
1419
1419
Crowval = Vector {indextypeC} (maxnnzC)
@@ -1438,7 +1438,7 @@ function broadcast{Tf,N}(f::Tf, A::SparseMatrixCSC, Bs::Vararg{SparseMatrixCSC,N
1438
1438
fofzeros = f (_zeros_eltypes (A, Bs... )... )
1439
1439
fpreszeros = fofzeros == zero (fofzeros)
1440
1440
indextypeC = _promote_indtype (A, Bs... )
1441
- entrytypeC = _broadcast_type (f, A, Bs ... )
1441
+ entrytypeC = typeof (fofzeros )
1442
1442
Cm, Cn = Base. to_shape (Base. Broadcast. broadcast_indices (A, Bs... ))
1443
1443
maxnnzC = fpreszeros ? _checked_maxnnzbcres (Cm, Cn, A, Bs... ) : (Cm * Cn)
1444
1444
Ccolptr = Vector {indextypeC} (Cn + 1 )
@@ -1464,28 +1464,34 @@ _maxnnzfrom(Cm, Cn, A) = nnz(A) * div(Cm, A.m) * div(Cn, A.n)
1464
1464
@inline _maxnnzfrom_each (Cm, Cn, As) = (_maxnnzfrom (Cm, Cn, first (As)), _maxnnzfrom_each (Cm, Cn, tail (As))... )
1465
1465
@inline _unchecked_maxnnzbcres (Cm, Cn, As) = min (Cm * Cn, sum (_maxnnzfrom_each (Cm, Cn, As)))
1466
1466
@inline _checked_maxnnzbcres (Cm, Cn, As... ) = Cm != 0 && Cn != 0 ? _unchecked_maxnnzbcres (Cm, Cn, As) : 0
1467
- _broadcast_type (f, As... ) = Base. _promote_op (f, Base. Broadcast. typestuple (As... ))
1467
+ @inline _update_nzval! {T} (nzval:: Vector{T} , k, x:: T ) = (nzval[k] = x; nzval)
1468
+ @inline function _update_nzval! {T,Tx} (nzval:: Vector{T} , k, x:: Tx )
1469
+ nzval = convert (Vector{typejoin (Tx, T)}, nzval)
1470
+ nzval[k] = x
1471
+ return nzval
1472
+ end
1468
1473
1469
1474
# _map_zeropres!/_map_notzeropres! specialized for a single sparse matrix
1470
1475
" Stores only the nonzero entries of `map(f, Matrix(A))` in `C`."
1471
1476
function _map_zeropres! {Tf} (f:: Tf , C:: SparseMatrixCSC , A:: SparseMatrixCSC )
1472
1477
spaceC = min (length (C. rowval), length (C. nzval))
1473
1478
Ck = 1
1479
+ nzval = C. nzval
1474
1480
@inbounds for j in 1 : C. n
1475
1481
C. colptr[j] = Ck
1476
1482
for Ak in nzrange (A, j)
1477
1483
Cx = f (A. nzval[Ak])
1478
1484
if Cx != zero (eltype (C))
1479
1485
Ck > spaceC && (spaceC = _expandstorage! (C, Ck + nnz (A) - (Ak - 1 )))
1480
1486
C. rowval[Ck] = A. rowval[Ak]
1481
- C . nzval[Ck] = Cx
1487
+ nzval = _update_nzval! (nzval, Ck, Cx)
1482
1488
Ck += 1
1483
1489
end
1484
1490
end
1485
1491
end
1486
1492
@inbounds C. colptr[C. n + 1 ] = Ck
1487
1493
_trimstorage! (C, Ck - 1 )
1488
- return C
1494
+ return nzval === C . nzval ? C : SparseMatrixCSC (C . m, C . n, C . colptr, C . rowval, nzval)
1489
1495
end
1490
1496
"""
1491
1497
Densifies `C`, storing `fillvalue` in place of each unstored entry in `A` and
@@ -1496,13 +1502,14 @@ function _map_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::SparseMa
1496
1502
_densestructure! (C)
1497
1503
# Populate values
1498
1504
fill! (C. nzval, fillvalue)
1505
+ nzval = C. nzval
1499
1506
@inbounds for (j, jo) in zip (1 : C. n, 0 : C. m: (C. m* C. n - 1 )), Ak in nzrange (A, j)
1500
1507
Cx = f (A. nzval[Ak])
1501
- Cx != fillvalue && (C . nzval[ jo + A. rowval[Ak]] = Cx )
1508
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + A. rowval[Ak], Cx) )
1502
1509
end
1503
1510
# NOTE: Combining the fill! above into the loop above to avoid multiple sweeps over /
1504
1511
# nonsequential access of C.nzval does not appear to improve performance.
1505
- return C
1512
+ return nzval === C . nzval ? C : SparseMatrixCSC (C . m, C . n, C . colptr, C . rowval, nzval)
1506
1513
end
1507
1514
# helper functions for these methods and some of those below
1508
1515
function _expandstorage! (X:: SparseMatrixCSC , maxstored)
@@ -1533,6 +1540,7 @@ function _map_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC, B::Sp
1533
1540
spaceC = min (length (C. rowval), length (C. nzval))
1534
1541
rowsentinelA = convert (eltype (A. rowval), C. m + 1 )
1535
1542
rowsentinelB = convert (eltype (B. rowval), C. m + 1 )
1543
+ nzval = C. nzval
1536
1544
Ck = 1
1537
1545
@inbounds for j in 1 : C. n
1538
1546
C. colptr[j] = Ck
@@ -1562,12 +1570,13 @@ function _map_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC, B::Sp
1562
1570
if Cx != zero (eltype (C))
1563
1571
Ck > spaceC && (spaceC = _expandstorage! (C, Ck + (nnz (A) - (Ak - 1 )) + (nnz (B) - (Bk - 1 ))))
1564
1572
C. rowval[Ck] = Ci
1565
- C . nzval[Ck] = Cx
1573
+ nzval = _update_nzval! (nzval, Ck, Cx)
1566
1574
Ck += 1
1567
1575
end
1568
1576
end
1569
1577
end
1570
1578
@inbounds C. colptr[C. n + 1 ] = Ck
1579
+ nzval === C. nzval || (C = SparseMatrixCSC (C. m, C. n, C. colptr, C. rowval, nzval))
1571
1580
_trimstorage! (C, Ck - 1 )
1572
1581
return C
1573
1582
end
@@ -1578,6 +1587,7 @@ function _map_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::SparseMa
1578
1587
fill! (C. nzval, fillvalue)
1579
1588
# NOTE: Combining this fill! into the loop below to avoid multiple sweeps over /
1580
1589
# nonsequential access of C.nzval does not appear to improve performance.
1590
+ nzval = C. nzval
1581
1591
rowsentinelA = convert (eltype (A. rowval), C. m + 1 )
1582
1592
rowsentinelB = convert (eltype (B. rowval), C. m + 1 )
1583
1593
@inbounds for (j, jo) in zip (1 : C. n, 0 : C. m: (C. m* C. n - 1 ))
@@ -1598,10 +1608,10 @@ function _map_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::SparseMa
1598
1608
Cx, Ci = f (zero (eltype (A)), B. nzval[Bk]), Bi
1599
1609
Bk += one (Bk); Bi = Bk < stopBk ? B. rowval[Bk] : rowsentinelB
1600
1610
end
1601
- Cx != fillvalue && (C . nzval[ jo + Ci] = Cx )
1611
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + Ci, Cx) )
1602
1612
end
1603
1613
end
1604
- return C
1614
+ return nzval === C . nzval ? C : SparseMatrixCSC (C . m, C . n, C . colptr, C . rowval, nzval)
1605
1615
end
1606
1616
# _broadcast_zeropres!/_broadcast_notzeropres! specialized for a pair of (input) sparse matrices
1607
1617
function _broadcast_zeropres! {Tf} (f:: Tf , C:: SparseMatrixCSC , A:: SparseMatrixCSC , B:: SparseMatrixCSC )
0 commit comments