@@ -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,26 +1464,33 @@ _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
1493
+ nzval === C. nzval || (C = SparseMatrixCSC (C. m, C. n, C. colptr, C. rowval, nzval))
1487
1494
_trimstorage! (C, Ck - 1 )
1488
1495
return C
1489
1496
end
@@ -1496,13 +1503,14 @@ function _map_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::SparseMa
1496
1503
_densestructure! (C)
1497
1504
# Populate values
1498
1505
fill! (C. nzval, fillvalue)
1506
+ nzval = C. nzval
1499
1507
@inbounds for (j, jo) in zip (1 : C. n, 0 : C. m: (C. m* C. n - 1 )), Ak in nzrange (A, j)
1500
1508
Cx = f (A. nzval[Ak])
1501
- Cx != fillvalue && (C . nzval[ jo + A. rowval[Ak]] = Cx )
1509
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + A. rowval[Ak], Cx) )
1502
1510
end
1503
1511
# NOTE: Combining the fill! above into the loop above to avoid multiple sweeps over /
1504
1512
# nonsequential access of C.nzval does not appear to improve performance.
1505
- return C
1513
+ return nzval === C . nzval ? C : SparseMatrixCSC (C . m, C . n, C . colptr, C . rowval, nzval)
1506
1514
end
1507
1515
# helper functions for these methods and some of those below
1508
1516
function _expandstorage! (X:: SparseMatrixCSC , maxstored)
@@ -1533,6 +1541,7 @@ function _map_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC, B::Sp
1533
1541
spaceC = min (length (C. rowval), length (C. nzval))
1534
1542
rowsentinelA = convert (eltype (A. rowval), C. m + 1 )
1535
1543
rowsentinelB = convert (eltype (B. rowval), C. m + 1 )
1544
+ nzval = C. nzval
1536
1545
Ck = 1
1537
1546
@inbounds for j in 1 : C. n
1538
1547
C. colptr[j] = Ck
@@ -1562,12 +1571,13 @@ function _map_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC, B::Sp
1562
1571
if Cx != zero (eltype (C))
1563
1572
Ck > spaceC && (spaceC = _expandstorage! (C, Ck + (nnz (A) - (Ak - 1 )) + (nnz (B) - (Bk - 1 ))))
1564
1573
C. rowval[Ck] = Ci
1565
- C . nzval[Ck] = Cx
1574
+ nzval = _update_nzval! (nzval, Ck, Cx)
1566
1575
Ck += 1
1567
1576
end
1568
1577
end
1569
1578
end
1570
1579
@inbounds C. colptr[C. n + 1 ] = Ck
1580
+ nzval === C. nzval || (C = SparseMatrixCSC (C. m, C. n, C. colptr, C. rowval, nzval))
1571
1581
_trimstorage! (C, Ck - 1 )
1572
1582
return C
1573
1583
end
@@ -1578,6 +1588,7 @@ function _map_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::SparseMa
1578
1588
fill! (C. nzval, fillvalue)
1579
1589
# NOTE: Combining this fill! into the loop below to avoid multiple sweeps over /
1580
1590
# nonsequential access of C.nzval does not appear to improve performance.
1591
+ nzval = C. nzval
1581
1592
rowsentinelA = convert (eltype (A. rowval), C. m + 1 )
1582
1593
rowsentinelB = convert (eltype (B. rowval), C. m + 1 )
1583
1594
@inbounds for (j, jo) in zip (1 : C. n, 0 : C. m: (C. m* C. n - 1 ))
@@ -1598,17 +1609,18 @@ function _map_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::SparseMa
1598
1609
Cx, Ci = f (zero (eltype (A)), B. nzval[Bk]), Bi
1599
1610
Bk += one (Bk); Bi = Bk < stopBk ? B. rowval[Bk] : rowsentinelB
1600
1611
end
1601
- Cx != fillvalue && (C . nzval[ jo + Ci] = Cx )
1612
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + Ci, Cx) )
1602
1613
end
1603
1614
end
1604
- return C
1615
+ return nzval === C . nzval ? C : SparseMatrixCSC (C . m, C . n, C . colptr, C . rowval, nzval)
1605
1616
end
1606
1617
# _broadcast_zeropres!/_broadcast_notzeropres! specialized for a pair of (input) sparse matrices
1607
1618
function _broadcast_zeropres! {Tf} (f:: Tf , C:: SparseMatrixCSC , A:: SparseMatrixCSC , B:: SparseMatrixCSC )
1608
1619
isempty (C) && (fill! (C. colptr, 1 ); return C)
1609
1620
spaceC = min (length (C. rowval), length (C. nzval))
1610
1621
rowsentinelA = convert (eltype (A. rowval), C. m + 1 )
1611
1622
rowsentinelB = convert (eltype (B. rowval), C. m + 1 )
1623
+ nzval = C. nzval
1612
1624
# A and B cannot have the same shape, as we directed that case to map in broadcast's
1613
1625
# entry point; here we need efficiently handle only heterogeneous combinations of matrices
1614
1626
# with no singleton dimensions ("matrices" hereafter), one singleton dimension ("columns"
@@ -1663,7 +1675,7 @@ function _broadcast_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC,
1663
1675
if Cx != zero (eltype (C))
1664
1676
Ck > spaceC && (spaceC = _expandstorage! (C, _unchecked_maxnnzbcres (C. m, C. n, A, B)))
1665
1677
C. rowval[Ck] = Ci
1666
- C . nzval[Ck] = Cx
1678
+ nzval = _update_nzval! (nzval, Ck, Cx)
1667
1679
Ck += 1
1668
1680
end
1669
1681
end
@@ -1685,7 +1697,7 @@ function _broadcast_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC,
1685
1697
if Cx != zero (eltype (C))
1686
1698
Ck > spaceC && (spaceC = _expandstorage! (C, _unchecked_maxnnzbcres (C. m, C. n, A, B)))
1687
1699
C. rowval[Ck] = B. rowval[Bk]
1688
- C . nzval[Ck] = Cx
1700
+ nzval = _update_nzval! (nzval, Ck, Cx)
1689
1701
Ck += 1
1690
1702
end
1691
1703
Bk += one (Bk)
@@ -1704,7 +1716,7 @@ function _broadcast_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC,
1704
1716
if Cx != zero (eltype (C))
1705
1717
Ck > spaceC && (spaceC = _expandstorage! (C, _unchecked_maxnnzbcres (C. m, C. n, A, B)))
1706
1718
C. rowval[Ck] = Ci
1707
- C . nzval[Ck] = Cx
1719
+ nzval = _update_nzval! (nzval, Ck, Cx)
1708
1720
Ck += 1
1709
1721
end
1710
1722
end
@@ -1726,7 +1738,7 @@ function _broadcast_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC,
1726
1738
if Cx != zero (eltype (C))
1727
1739
Ck > spaceC && (spaceC = _expandstorage! (C, _unchecked_maxnnzbcres (C. m, C. n, A, B)))
1728
1740
C. rowval[Ck] = A. rowval[Ak]
1729
- C . nzval[Ck] = Cx
1741
+ nzval = _update_nzval! (nzval, Ck, Cx)
1730
1742
Ck += 1
1731
1743
end
1732
1744
Ak += one (Ak)
@@ -1745,14 +1757,15 @@ function _broadcast_zeropres!{Tf}(f::Tf, C::SparseMatrixCSC, A::SparseMatrixCSC,
1745
1757
if Cx != zero (eltype (C))
1746
1758
Ck > spaceC && (spaceC = _expandstorage! (C, _unchecked_maxnnzbcres (C. m, C. n, A, B)))
1747
1759
C. rowval[Ck] = Ci
1748
- C . nzval[Ck] = Cx
1760
+ nzval = _update_nzval! (nzval, Ck, Cx)
1749
1761
Ck += 1
1750
1762
end
1751
1763
end
1752
1764
end
1753
1765
end
1754
1766
end
1755
1767
@inbounds C. colptr[C. n + 1 ] = Ck
1768
+ nzval === C. nzval || (C = SparseMatrixCSC (C. m, C. n, C. colptr, C. rowval, nzval))
1756
1769
_trimstorage! (C, Ck - 1 )
1757
1770
return C
1758
1771
end
@@ -1764,6 +1777,7 @@ function _broadcast_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::Sp
1764
1777
fill! (C. nzval, fillvalue)
1765
1778
rowsentinelA = convert (eltype (A. rowval), C. m + 1 )
1766
1779
rowsentinelB = convert (eltype (B. rowval), C. m + 1 )
1780
+ nzval = C. nzval
1767
1781
# Cases without vertical expansion
1768
1782
if A. m == B. m
1769
1783
@inbounds for (j, jo) in zip (1 : C. n, 0 : C. m: (C. m* C. n - 1 ))
@@ -1785,7 +1799,7 @@ function _broadcast_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::Sp
1785
1799
Ak += one (Ak); Ai = Ak < stopAk ? A. rowval[Ak] : rowsentinelA
1786
1800
Bk += one (Bk); Bi = Bk < stopBk ? B. rowval[Bk] : rowsentinelB
1787
1801
end
1788
- Cx != fillvalue && (C . nzval[ jo + Ci] = Cx )
1802
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + Ci, Cx) )
1789
1803
end
1790
1804
end
1791
1805
# Cases with vertical expansion
@@ -1798,7 +1812,7 @@ function _broadcast_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::Sp
1798
1812
if fvAzB == zero (eltype (C))
1799
1813
while Bk < stopBk
1800
1814
Cx = f (Ax, B. nzval[Bk])
1801
- Cx != fillvalue && (C . nzval[ jo + B. rowval[Bk]] = Cx )
1815
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + B. rowval[Bk], Cx) )
1802
1816
Bk += one (Bk)
1803
1817
end
1804
1818
else
@@ -1810,7 +1824,7 @@ function _broadcast_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::Sp
1810
1824
else
1811
1825
Cx = fvAzB
1812
1826
end
1813
- Cx != fillvalue && (C . nzval[ jo + Ci] = Cx )
1827
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + Ci, Cx) )
1814
1828
end
1815
1829
end
1816
1830
end
@@ -1823,7 +1837,7 @@ function _broadcast_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::Sp
1823
1837
if fzAvB == zero (eltype (C))
1824
1838
while Ak < stopAk
1825
1839
Cx = f (A. nzval[Ak], Bx)
1826
- Cx != fillvalue && (C . nzval[ jo + A. rowval[Ak]] = Cx )
1840
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + A. rowval[Ak], Cx) )
1827
1841
Ak += one (Ak)
1828
1842
end
1829
1843
else
@@ -1835,12 +1849,12 @@ function _broadcast_notzeropres!{Tf}(f::Tf, fillvalue, C::SparseMatrixCSC, A::Sp
1835
1849
else
1836
1850
Cx = fzAvB
1837
1851
end
1838
- Cx != fillvalue && (C . nzval[ jo + Ci] = Cx )
1852
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + Ci, Cx) )
1839
1853
end
1840
1854
end
1841
1855
end
1842
1856
end
1843
- return C
1857
+ return nzval === C . nzval ? C : SparseMatrixCSC (C . m, C . n, C . colptr, C . rowval, nzval)
1844
1858
end
1845
1859
1846
1860
# _map_zeropres!/_map_notzeropres! for more than two sparse matrices
@@ -1849,6 +1863,7 @@ function _map_zeropres!{Tf,N}(f::Tf, C::SparseMatrixCSC, As::Vararg{SparseMatrix
1849
1863
rowsentinel = C. m + 1
1850
1864
Ck = 1
1851
1865
stopks = _indforcol_all (1 , As)
1866
+ nzval = C. nzval
1852
1867
@inbounds for j in 1 : C. n
1853
1868
C. colptr[j] = Ck
1854
1869
ks = stopks
@@ -1865,13 +1880,14 @@ function _map_zeropres!{Tf,N}(f::Tf, C::SparseMatrixCSC, As::Vararg{SparseMatrix
1865
1880
if Cx != zero (eltype (C))
1866
1881
Ck > spaceC && (spaceC = _expandstorage! (C, Ck + min (length (C), _sumnnzs (As... )) - (sum (ks) - N)))
1867
1882
C. rowval[Ck] = activerow
1868
- C . nzval[Ck] = Cx
1883
+ _update_nzval! ( nzval, Ck, Cx)
1869
1884
Ck += 1
1870
1885
end
1871
1886
activerow = min (rows... )
1872
1887
end
1873
1888
end
1874
1889
@inbounds C. colptr[C. n + 1 ] = Ck
1890
+ nzval === C. nzval || (C = SparseMatrixCSC (C. m, C. n, C. colptr, C. rowval, nzval))
1875
1891
_trimstorage! (C, Ck - 1 )
1876
1892
return C
1877
1893
end
@@ -1884,6 +1900,7 @@ function _map_notzeropres!{Tf,N}(f::Tf, fillvalue, C::SparseMatrixCSC, As::Varar
1884
1900
# nonsequential access of C.nzval does not appear to improve performance.
1885
1901
rowsentinel = C. m + 1
1886
1902
stopks = _indforcol_all (1 , As)
1903
+ nzval = C. nzval
1887
1904
@inbounds for (j, jo) in zip (1 : C. n, 0 : C. m: (C. m* C. n - 1 ))
1888
1905
ks = stopks
1889
1906
stopks = _indforcol_all (j + 1 , As)
@@ -1896,7 +1913,7 @@ function _map_notzeropres!{Tf,N}(f::Tf, fillvalue, C::SparseMatrixCSC, As::Varar
1896
1913
# rows = _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As)
1897
1914
vals, ks, rows = _fusedupdate_all (rowsentinel, activerow, rows, ks, stopks, As)
1898
1915
Cx = f (vals... )
1899
- Cx != fillvalue && (C . nzval[ jo + activerow] = Cx )
1916
+ Cx != fillvalue && (_update_nzval! ( nzval, jo + activerow, Cx) )
1900
1917
activerow = min (rows... )
1901
1918
end
1902
1919
end
@@ -1962,6 +1979,7 @@ function _broadcast_zeropres!{Tf,N}(f::Tf, C::SparseMatrixCSC, As::Vararg{Sparse
1962
1979
expandsverts = _expandsvert_all (C, As)
1963
1980
expandshorzs = _expandshorz_all (C, As)
1964
1981
rowsentinel = C. m + 1
1982
+ nzval = C. nzval
1965
1983
Ck = 1
1966
1984
@inbounds for j in 1 : C. n
1967
1985
C. colptr[j] = Ck
@@ -1985,7 +2003,7 @@ function _broadcast_zeropres!{Tf,N}(f::Tf, C::SparseMatrixCSC, As::Vararg{Sparse
1985
2003
if Cx != zero (eltype (C))
1986
2004
Ck > spaceC && (spaceC = _expandstorage! (C, _unchecked_maxnnzbcres (C. m, C. n, As)))
1987
2005
C. rowval[Ck] = activerow
1988
- C . nzval[Ck] = Cx
2006
+ nzval = _update_nzval! (nzval, Ck, Cx)
1989
2007
Ck += 1
1990
2008
end
1991
2009
activerow = min (rows... )
@@ -2006,13 +2024,14 @@ function _broadcast_zeropres!{Tf,N}(f::Tf, C::SparseMatrixCSC, As::Vararg{Sparse
2006
2024
if Cx != zero (eltype (C))
2007
2025
Ck > spaceC && (spaceC = _expandstorage! (C, _unchecked_maxnnzbcres (C. m, C. n, As)))
2008
2026
C. rowval[Ck] = Ci
2009
- C . nzval[Ck] = Cx
2027
+ nzval = _update_nzval! (nzval, Ck, Cx)
2010
2028
Ck += 1
2011
2029
end
2012
2030
end
2013
2031
end
2014
2032
end
2015
2033
@inbounds C. colptr[C. n + 1 ] = Ck
2034
+ nzval === C. nzval || (C = SparseMatrixCSC (C. m, C. n, C. colptr, C. rowval, nzval))
2016
2035
_trimstorage! (C, Ck - 1 )
2017
2036
return C
2018
2037
end
@@ -2022,6 +2041,7 @@ function _broadcast_notzeropres!{Tf,N}(f::Tf, fillvalue, C::SparseMatrixCSC, As:
2022
2041
_densestructure! (C)
2023
2042
# Populate values
2024
2043
fill! (C. nzval, fillvalue)
2044
+ nzval = C. nzval
2025
2045
expandsverts = _expandsvert_all (C, As)
2026
2046
expandshorzs = _expandshorz_all (C, As)
2027
2047
rowsentinel = C. m + 1
@@ -2043,7 +2063,7 @@ function _broadcast_notzeropres!{Tf,N}(f::Tf, fillvalue, C::SparseMatrixCSC, As:
2043
2063
# rows = _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As)
2044
2064
args, ks, rows = _fusedupdatebc_all (rowsentinel, activerow, rows, defargs, ks, stopks, As)
2045
2065
Cx = f (args... )
2046
- Cx != fillvalue && (C . nzval[ jo + activerow] = Cx )
2066
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + activerow, Cx) )
2047
2067
activerow = min (rows... )
2048
2068
end
2049
2069
else # fillvalue-non-preserving column scan
@@ -2059,11 +2079,11 @@ function _broadcast_notzeropres!{Tf,N}(f::Tf, fillvalue, C::SparseMatrixCSC, As:
2059
2079
else
2060
2080
Cx = defaultCx
2061
2081
end
2062
- Cx != fillvalue && (C . nzval[ jo + Ci] = Cx )
2082
+ Cx != fillvalue && (nzval = _update_nzval! (nzval, jo + Ci, Cx) )
2063
2083
end
2064
2084
end
2065
2085
end
2066
- return C
2086
+ return nzval === C . nzval ? C : SparseMatrixCSC (C . m, C . n, C . colptr, C . rowval, nzval)
2067
2087
end
2068
2088
# helper method for broadcast/broadcast! methods just above
2069
2089
@inline _expandsvert (C, A) = A. m != C. m
0 commit comments