Skip to content

Commit a9df0fd

Browse files
authored
shift csc calls to sparsetools csr. remove sparsetools csc. (scipy#22169)
1 parent b8d03e0 commit a9df0fd

File tree

4 files changed

+48
-214
lines changed

4 files changed

+48
-214
lines changed

scipy/sparse/_compressed.py

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
from . import _sparsetools
1414
from ._sparsetools import (get_csr_submatrix, csr_sample_offsets, csr_todense,
1515
csr_sample_values, csr_row_index, csr_row_slice,
16-
csr_column_index1, csr_column_index2)
16+
csr_column_index1, csr_column_index2, csr_diagonal,
17+
expandptr, csr_has_canonical_format, csr_eliminate_zeros,
18+
csr_sum_duplicates, csr_has_sorted_indices, csr_sort_indices,
19+
csr_matmat_maxnnz, csr_matmat)
1720
from ._index import IndexMixin
1821
from ._sputils import (upcast, upcast_char, to_native, isdense, isshape,
1922
getdtype, isscalarlike, isintlike, downcast_intp_index,
@@ -560,39 +563,40 @@ def _matmul_sparse(self, other):
560563
new_shape += (N,)
561564
faux_shape = (M if self.ndim == 2 else 1, N if o_ndim == 2 else 1)
562565

563-
major_dim = self._swap((M, N))[0]
564566
other = self.__class__(other) # convert to this format
567+
index_arrays = (self.indptr, self.indices, other.indptr, other.indices)
565568

566-
idx_dtype = self._get_index_dtype((self.indptr, self.indices,
567-
other.indptr, other.indices))
568-
569-
fn = getattr(_sparsetools, self.format + '_matmat_maxnnz')
570-
nnz = fn(M, N,
571-
np.asarray(self.indptr, dtype=idx_dtype),
572-
np.asarray(self.indices, dtype=idx_dtype),
573-
np.asarray(other.indptr, dtype=idx_dtype),
574-
np.asarray(other.indices, dtype=idx_dtype))
569+
M, N = self._swap((M, N))
570+
s, o = self._swap((self, other))
571+
572+
idx_dtype = self._get_index_dtype(index_arrays)
573+
s_indptr = np.asarray(s.indptr, dtype=idx_dtype)
574+
s_indices = np.asarray(s.indices, dtype=idx_dtype)
575+
o_indptr = np.asarray(o.indptr, dtype=idx_dtype)
576+
o_indices = np.asarray(o.indices, dtype=idx_dtype)
577+
578+
nnz = csr_matmat_maxnnz(M, N, s_indptr, s_indices, o_indptr, o_indices)
575579
if nnz == 0:
576580
if new_shape == ():
577581
return np.array(0, dtype=upcast(self.dtype, other.dtype))
578582
return self.__class__(new_shape, dtype=upcast(self.dtype, other.dtype))
579583

580-
idx_dtype = self._get_index_dtype((self.indptr, self.indices,
581-
other.indptr, other.indices),
582-
maxval=nnz)
584+
new_idx_dtype = self._get_index_dtype(index_arrays, maxval=nnz)
585+
if new_idx_dtype != idx_dtype:
586+
idx_dtype = new_idx_dtype
587+
s_indptr = np.asarray(s.indptr, dtype=idx_dtype)
588+
s_indices = np.asarray(s.indices, dtype=idx_dtype)
589+
o_indptr = np.asarray(o.indptr, dtype=idx_dtype)
590+
o_indices = np.asarray(o.indices, dtype=idx_dtype)
583591

584-
indptr = np.empty(major_dim + 1, dtype=idx_dtype)
592+
indptr = np.empty(M + 1, dtype=idx_dtype)
585593
indices = np.empty(nnz, dtype=idx_dtype)
586594
data = np.empty(nnz, dtype=upcast(self.dtype, other.dtype))
587595

588-
fn = getattr(_sparsetools, self.format + '_matmat')
589-
fn(M, N, np.asarray(self.indptr, dtype=idx_dtype),
590-
np.asarray(self.indices, dtype=idx_dtype),
591-
self.data,
592-
np.asarray(other.indptr, dtype=idx_dtype),
593-
np.asarray(other.indices, dtype=idx_dtype),
594-
other.data,
595-
indptr, indices, data)
596+
csr_matmat(M, N,
597+
s_indptr, s_indices, s.data,
598+
o_indptr, o_indices, o.data,
599+
indptr, indices, data)
596600

597601
if new_shape == ():
598602
return np.array(data[0])
@@ -604,14 +608,13 @@ def _matmul_sparse(self, other):
604608
return res
605609

606610
def diagonal(self, k=0):
607-
rows, cols = self.shape
608-
if k <= -rows or k >= cols:
611+
M, N = self._swap(self.shape)
612+
k, _ = self._swap((k, -k))
613+
614+
if k <= -M or k >= N:
609615
return np.empty(0, dtype=self.data.dtype)
610-
fn = getattr(_sparsetools, self.format + "_diagonal")
611-
y = np.empty(min(rows + min(k, 0), cols - max(k, 0)),
612-
dtype=upcast(self.dtype))
613-
fn(k, self.shape[0], self.shape[1], self.indptr, self.indices,
614-
self.data, y)
616+
y = np.empty(min(M + min(k, 0), N - max(k, 0)), dtype=upcast(self.dtype))
617+
csr_diagonal(k, M, N, self.indptr, self.indices, self.data, y)
615618
return y
616619

617620
diagonal.__doc__ = _spbase.diagonal.__doc__
@@ -1151,7 +1154,7 @@ def tocoo(self, copy=True):
11511154
major_dim, minor_dim = self._swap(self.shape)
11521155
minor_indices = self.indices
11531156
major_indices = np.empty(len(minor_indices), dtype=self.indices.dtype)
1154-
_sparsetools.expandptr(major_dim, self.indptr, major_indices)
1157+
expandptr(major_dim, self.indptr, major_indices)
11551158
coords = self._swap((major_indices, minor_indices))
11561159

11571160
return self._coo_container(
@@ -1189,7 +1192,7 @@ def eliminate_zeros(self):
11891192
This is an *in place* operation.
11901193
"""
11911194
M, N = self._swap(self._shape_as_2d)
1192-
_sparsetools.csr_eliminate_zeros(M, N, self.indptr, self.indices, self.data)
1195+
csr_eliminate_zeros(M, N, self.indptr, self.indices, self.data)
11931196
self.prune() # nnz may have changed
11941197

11951198
@property
@@ -1209,10 +1212,10 @@ def has_canonical_format(self) -> bool:
12091212
# not sorted => not canonical
12101213
self._has_canonical_format = False
12111214
elif not hasattr(self, '_has_canonical_format'):
1215+
M = len(self.indptr) - 1
12121216
self.has_canonical_format = bool(
1213-
_sparsetools.csr_has_canonical_format(
1214-
len(self.indptr) - 1, self.indptr, self.indices)
1215-
)
1217+
csr_has_canonical_format(M, self.indptr, self.indices)
1218+
)
12161219
return self._has_canonical_format
12171220

12181221
@has_canonical_format.setter
@@ -1231,7 +1234,7 @@ def sum_duplicates(self):
12311234
self.sort_indices()
12321235

12331236
M, N = self._swap(self._shape_as_2d)
1234-
_sparsetools.csr_sum_duplicates(M, N, self.indptr, self.indices, self.data)
1237+
csr_sum_duplicates(M, N, self.indptr, self.indices, self.data)
12351238

12361239
self.prune() # nnz may have changed
12371240
self.has_canonical_format = True
@@ -1246,10 +1249,10 @@ def has_sorted_indices(self) -> bool:
12461249
"""
12471250
# first check to see if result was cached
12481251
if not hasattr(self, '_has_sorted_indices'):
1252+
M = len(self.indptr) - 1
12491253
self._has_sorted_indices = bool(
1250-
_sparsetools.csr_has_sorted_indices(
1251-
len(self.indptr) - 1, self.indptr, self.indices)
1252-
)
1254+
csr_has_sorted_indices(M, self.indptr, self.indices)
1255+
)
12531256
return self._has_sorted_indices
12541257

12551258
@has_sorted_indices.setter
@@ -1271,10 +1274,9 @@ def sorted_indices(self):
12711274
def sort_indices(self):
12721275
"""Sort the indices of this array/matrix *in place*
12731276
"""
1274-
12751277
if not self.has_sorted_indices:
1276-
_sparsetools.csr_sort_indices(len(self.indptr) - 1, self.indptr,
1277-
self.indices, self.data)
1278+
M = len(self.indptr) - 1
1279+
csr_sort_indices(M, self.indptr, self.indices, self.data)
12781280
self.has_sorted_indices = True
12791281

12801282
def prune(self):
@@ -1353,7 +1355,7 @@ def _binopt(self, other, op):
13531355
other = self.__class__(other)
13541356

13551357
# e.g. csr_plus_csr, csr_minus_csr, etc.
1356-
fn = getattr(_sparsetools, self.format + op + self.format)
1358+
fn = getattr(_sparsetools, "csr" + op + "csr")
13571359

13581360
maxnnz = self.nnz + other.nnz
13591361
idx_dtype = self._get_index_dtype((self.indptr, self.indices,
@@ -1368,7 +1370,7 @@ def _binopt(self, other, op):
13681370
else:
13691371
data = np.empty(maxnnz, dtype=upcast(self.dtype, other.dtype))
13701372

1371-
M, N = self._shape_as_2d
1373+
M, N = self._swap(self._shape_as_2d)
13721374
fn(M, N,
13731375
np.asarray(self.indptr, dtype=idx_dtype),
13741376
np.asarray(self.indices, dtype=idx_dtype),

scipy/sparse/_csc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from ._matrix import spmatrix
1010
from ._base import _spbase, sparray
11-
from ._sparsetools import csc_tocsr, expandptr
11+
from ._sparsetools import csr_tocsc, expandptr
1212
from ._sputils import upcast
1313

1414
from ._compressed import _cs_matrix
@@ -49,7 +49,7 @@ def tocsr(self, copy=False):
4949
indices = np.empty(self.nnz, dtype=idx_dtype)
5050
data = np.empty(self.nnz, dtype=upcast(self.dtype))
5151

52-
csc_tocsr(M, N,
52+
csr_tocsc(N, M,
5353
self.indptr.astype(idx_dtype),
5454
self.indices.astype(idx_dtype),
5555
self.data,

scipy/sparse/_generate_sparsetools.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,8 @@
5656

5757
# csc.h
5858
CSC_ROUTINES = """
59-
csc_diagonal v iiiIIT*T
60-
csc_tocsr v iiIIT*I*I*T
61-
csc_matmat_maxnnz l iiIIII
62-
csc_matmat v iiIITIIT*I*I*T
6359
csc_matvec v iiIITT*T
6460
csc_matvecs v iiiIITT*T
65-
csc_elmul_csc v iiIITIIT*I*I*T
66-
csc_eldiv_csc v iiIITIIT*I*I*T
67-
csc_plus_csc v iiIITIIT*I*I*T
68-
csc_minus_csc v iiIITIIT*I*I*T
69-
csc_maximum_csc v iiIITIIT*I*I*T
70-
csc_minimum_csc v iiIITIIT*I*I*T
71-
csc_ne_csc v iiIITIIT*I*I*B
72-
csc_lt_csc v iiIITIIT*I*I*B
73-
csc_gt_csc v iiIITIIT*I*I*B
74-
csc_le_csc v iiIITIIT*I*I*B
75-
csc_ge_csc v iiIITIIT*I*I*B
7661
"""
7762

7863
# csr.h

scipy/sparse/sparsetools/csc.h

Lines changed: 0 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -83,157 +83,4 @@ void csc_matvecs(const I n_row,
8383
}
8484
}
8585

86-
87-
88-
89-
/*
90-
* Derived methods
91-
*/
92-
template <class I, class T>
93-
void csc_diagonal(const I k,
94-
const I n_row,
95-
const I n_col,
96-
const I Ap[],
97-
const I Aj[],
98-
const T Ax[],
99-
T Yx[])
100-
{ csr_diagonal(-k, n_col, n_row, Ap, Aj, Ax, Yx); }
101-
102-
103-
template <class I, class T>
104-
void csc_tocsr(const I n_row,
105-
const I n_col,
106-
const I Ap[],
107-
const I Ai[],
108-
const T Ax[],
109-
I Bp[],
110-
I Bj[],
111-
T Bx[])
112-
{ csr_tocsc<I,T>(n_col, n_row, Ap, Ai, Ax, Bp, Bj, Bx); }
113-
114-
template <class I>
115-
npy_intp csc_matmat_maxnnz(const I n_row,
116-
const I n_col,
117-
const I Ap[],
118-
const I Ai[],
119-
const I Bp[],
120-
const I Bi[])
121-
{ return csr_matmat_maxnnz(n_col, n_row, Bp, Bi, Ap, Ai); }
122-
123-
template <class I, class T>
124-
void csc_matmat(const I n_row,
125-
const I n_col,
126-
const I Ap[],
127-
const I Ai[],
128-
const T Ax[],
129-
const I Bp[],
130-
const I Bi[],
131-
const T Bx[],
132-
I Cp[],
133-
I Ci[],
134-
T Cx[])
135-
{ csr_matmat(n_col, n_row, Bp, Bi, Bx, Ap, Ai, Ax, Cp, Ci, Cx); }
136-
137-
template <class I, class T, class T2>
138-
void csc_ne_csc(const I n_row, const I n_col,
139-
const I Ap[], const I Ai[], const T Ax[],
140-
const I Bp[], const I Bi[], const T Bx[],
141-
I Cp[], I Ci[], T2 Cx[])
142-
{
143-
csr_ne_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
144-
}
145-
146-
template <class I, class T, class T2>
147-
void csc_lt_csc(const I n_row, const I n_col,
148-
const I Ap[], const I Ai[], const T Ax[],
149-
const I Bp[], const I Bi[], const T Bx[],
150-
I Cp[], I Ci[], T2 Cx[])
151-
{
152-
csr_lt_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
153-
}
154-
155-
template <class I, class T, class T2>
156-
void csc_gt_csc(const I n_row, const I n_col,
157-
const I Ap[], const I Ai[], const T Ax[],
158-
const I Bp[], const I Bi[], const T Bx[],
159-
I Cp[], I Ci[], T2 Cx[])
160-
{
161-
csr_gt_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
162-
}
163-
164-
template <class I, class T, class T2>
165-
void csc_le_csc(const I n_row, const I n_col,
166-
const I Ap[], const I Ai[], const T Ax[],
167-
const I Bp[], const I Bi[], const T Bx[],
168-
I Cp[], I Ci[], T2 Cx[])
169-
{
170-
csr_le_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
171-
}
172-
173-
template <class I, class T, class T2>
174-
void csc_ge_csc(const I n_row, const I n_col,
175-
const I Ap[], const I Ai[], const T Ax[],
176-
const I Bp[], const I Bi[], const T Bx[],
177-
I Cp[], I Ci[], T2 Cx[])
178-
{
179-
csr_ge_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
180-
}
181-
182-
template <class I, class T>
183-
void csc_elmul_csc(const I n_row, const I n_col,
184-
const I Ap[], const I Ai[], const T Ax[],
185-
const I Bp[], const I Bi[], const T Bx[],
186-
I Cp[], I Ci[], T Cx[])
187-
{
188-
csr_elmul_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
189-
}
190-
191-
template <class I, class T>
192-
void csc_eldiv_csc(const I n_row, const I n_col,
193-
const I Ap[], const I Ai[], const T Ax[],
194-
const I Bp[], const I Bi[], const T Bx[],
195-
I Cp[], I Ci[], T Cx[])
196-
{
197-
csr_eldiv_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
198-
}
199-
200-
201-
template <class I, class T>
202-
void csc_plus_csc(const I n_row, const I n_col,
203-
const I Ap[], const I Ai[], const T Ax[],
204-
const I Bp[], const I Bi[], const T Bx[],
205-
I Cp[], I Ci[], T Cx[])
206-
{
207-
csr_plus_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
208-
}
209-
210-
template <class I, class T>
211-
void csc_minus_csc(const I n_row, const I n_col,
212-
const I Ap[], const I Ai[], const T Ax[],
213-
const I Bp[], const I Bi[], const T Bx[],
214-
I Cp[], I Ci[], T Cx[])
215-
{
216-
csr_minus_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
217-
}
218-
219-
220-
template <class I, class T>
221-
void csc_maximum_csc(const I n_row, const I n_col,
222-
const I Ap[], const I Ai[], const T Ax[],
223-
const I Bp[], const I Bi[], const T Bx[],
224-
I Cp[], I Ci[], T Cx[])
225-
{
226-
csr_maximum_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
227-
}
228-
229-
template <class I, class T>
230-
void csc_minimum_csc(const I n_row, const I n_col,
231-
const I Ap[], const I Ai[], const T Ax[],
232-
const I Bp[], const I Bi[], const T Bx[],
233-
I Cp[], I Ci[], T Cx[])
234-
{
235-
csr_minimum_csr(n_col, n_row, Ap, Ai, Ax, Bp, Bi, Bx, Cp, Ci, Cx);
236-
}
237-
238-
23986
#endif

0 commit comments

Comments
 (0)