Skip to content

Commit 1bb60ca

Browse files
committed
CSR: ~3x faster creation from scipy CSR. added tocsr_scipy() export method
1 parent 6af2664 commit 1bb60ca

2 files changed

Lines changed: 48 additions & 4 deletions

File tree

scikits/cuda/cusparse.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -937,17 +937,30 @@ def __init__(self, handle, descr, csrVal, csrRowPtr, csrColInd, shape):
937937
# alternative constructor from dense ndarray, gpuarray or cuSPARSE matrix
938938
@classmethod
939939
def to_CSR(cls, A, handle):
940-
""" convert dense any scipy.sparse matrix formats to cuSPARSE CSR.
940+
""" convert dense numpy or gpuarray matrices as well as any
941+
scipy.sparse matrix formats to cuSPARSE CSR.
941942
"""
942943
if has_scipy and isinstance(A, scipy.sparse.spmatrix):
943944
"""Convert scipy.sparse CSR, COO, BSR, etc to cuSPARSE CSR"""
944945
# converting BSR, COO, etc to CSR
946+
if A.dtype.char not in ['f', 'd', 'F', 'D']:
947+
raise ValueError("unsupported numpy dtype {}".format(A.dtype))
948+
945949
if not isinstance(A, scipy.sparse.csr_matrix):
946950
A = A.tocsr()
947951

948-
csrRowPtr = gpuarray.to_gpu(A.indptr.astype(np.int32))
949-
csrColInd = gpuarray.to_gpu(A.indices.astype(np.int32))
950-
csrVal = gpuarray.to_gpu(A.data.astype(A.dtype))
952+
# avoid .astype() calls if possible for speed
953+
if A.indptr.dtype != np.int32:
954+
csrRowPtr = gpuarray.to_gpu(A.indptr.astype(np.int32))
955+
else:
956+
csrRowPtr = gpuarray.to_gpu(A.indptr)
957+
958+
if A.indices.dtype != np.int32:
959+
csrColInd = gpuarray.to_gpu(A.indices.astype(np.int32))
960+
else:
961+
csrColInd = gpuarray.to_gpu(A.indices)
962+
963+
csrVal = gpuarray.to_gpu(A.data)
951964
descr = cusparseCreateMatDescr()
952965
cusparseSetMatType(descr, CUSPARSE_MATRIX_TYPE_GENERAL)
953966
cusparseSetMatIndexBase(descr, CUSPARSE_INDEX_BASE_ZERO)
@@ -1031,6 +1044,14 @@ def getnnz(self):
10311044
""" return number of non-zeros"""
10321045
return self.nnz
10331046

1047+
def tocsr_scipy(self):
1048+
""" return as scipy csr_matrix in host memory """
1049+
from scipy.sparse import csr_matrix
1050+
return csr_matrix((self.data.get(),
1051+
self.indices.get(),
1052+
self.indptr.get()),
1053+
shape=self.shape)
1054+
10341055
def todense(self, lda=None, to_cpu=False, handle=None, stream=None,
10351056
autosync=True):
10361057
""" return dense gpuarray if to_cpu=False, numpy ndarray if to_cpu=True

tests/test_cusparse.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,29 @@ def test_CSR_todense():
872872
cusparseDestroy(h)
873873

874874

875+
def test_CSR_tocsr_scipy():
876+
n = 64
877+
h = cusparseCreate()
878+
try:
879+
dtype = np.float32
880+
A = 2*np.eye(n)
881+
882+
# generate a CSR matrix from a dense numpy array
883+
A_CSR = CSR.to_CSR(A.astype(dtype), h)
884+
885+
# convert cusparseCSR back to a dense matrix
886+
csr_scipy = A_CSR.tocsr_scipy()
887+
# assert_equal(A_CSR.data.get(), csr_scipy.data)
888+
# assert_equal(A_CSR.indices.get(), csr_scipy.indices)
889+
# assert_equal(A_CSR.indptr.get(), csr_scipy.indptr)
890+
891+
assert_equal(csr_scipy.indptr, scipy.sparse.csr_matrix(A).indptr)
892+
assert_equal(csr_scipy.indices, scipy.sparse.csr_matrix(A).indices)
893+
assert_equal(csr_scipy.data, scipy.sparse.csr_matrix(A).data)
894+
finally:
895+
cusparseDestroy(h)
896+
897+
875898
def test_CSR_mv():
876899
n = 64
877900
h = cusparseCreate()

0 commit comments

Comments
 (0)