Coverage for /usr/lib/python3/dist-packages/scipy/sparse/_base.py: 29%

534 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1"""Base class for sparse matrices""" 

2from warnings import warn 

3 

4import numpy as np 

5 

6from ._sputils import (asmatrix, check_reshape_kwargs, check_shape, 

7 get_sum_dtype, isdense, isscalarlike, 

8 matrix, validateaxis,) 

9 

10from ._matrix import spmatrix 

11 

12__all__ = ['isspmatrix', 'issparse', 'sparray', 

13 'SparseWarning', 'SparseEfficiencyWarning'] 

14 

15 

16class SparseWarning(Warning): 

17 pass 

18 

19 

20class SparseFormatWarning(SparseWarning): 

21 pass 

22 

23 

24class SparseEfficiencyWarning(SparseWarning): 

25 pass 

26 

27 

28# The formats that we might potentially understand. 

29_formats = {'csc': [0, "Compressed Sparse Column"], 

30 'csr': [1, "Compressed Sparse Row"], 

31 'dok': [2, "Dictionary Of Keys"], 

32 'lil': [3, "List of Lists"], 

33 'dod': [4, "Dictionary of Dictionaries"], 

34 'sss': [5, "Symmetric Sparse Skyline"], 

35 'coo': [6, "COOrdinate"], 

36 'lba': [7, "Linpack BAnded"], 

37 'egd': [8, "Ellpack-itpack Generalized Diagonal"], 

38 'dia': [9, "DIAgonal"], 

39 'bsr': [10, "Block Sparse Row"], 

40 'msr': [11, "Modified compressed Sparse Row"], 

41 'bsc': [12, "Block Sparse Column"], 

42 'msc': [13, "Modified compressed Sparse Column"], 

43 'ssk': [14, "Symmetric SKyline"], 

44 'nsk': [15, "Nonsymmetric SKyline"], 

45 'jad': [16, "JAgged Diagonal"], 

46 'uss': [17, "Unsymmetric Sparse Skyline"], 

47 'vbr': [18, "Variable Block Row"], 

48 'und': [19, "Undefined"] 

49 } 

50 

51 

52# These univariate ufuncs preserve zeros. 

53_ufuncs_with_fixed_point_at_zero = frozenset([ 

54 np.sin, np.tan, np.arcsin, np.arctan, np.sinh, np.tanh, np.arcsinh, 

55 np.arctanh, np.rint, np.sign, np.expm1, np.log1p, np.deg2rad, 

56 np.rad2deg, np.floor, np.ceil, np.trunc, np.sqrt]) 

57 

58 

59MAXPRINT = 50 

60 

61 

62class _spbase: 

63 """ This class provides a base class for all sparse arrays. It 

64 cannot be instantiated. Most of the work is provided by subclasses. 

65 """ 

66 

67 __array_priority__ = 10.1 

68 _format = 'und' # undefined 

69 ndim = 2 

70 

71 @property 

72 def _bsr_container(self): 

73 from ._bsr import bsr_array 

74 return bsr_array 

75 

76 @property 

77 def _coo_container(self): 

78 from ._coo import coo_array 

79 return coo_array 

80 

81 @property 

82 def _csc_container(self): 

83 from ._csc import csc_array 

84 return csc_array 

85 

86 @property 

87 def _csr_container(self): 

88 from ._csr import csr_array 

89 return csr_array 

90 

91 @property 

92 def _dia_container(self): 

93 from ._dia import dia_array 

94 return dia_array 

95 

96 @property 

97 def _dok_container(self): 

98 from ._dok import dok_array 

99 return dok_array 

100 

101 @property 

102 def _lil_container(self): 

103 from ._lil import lil_array 

104 return lil_array 

105 

106 _is_array = True 

107 

108 def __init__(self, maxprint=MAXPRINT): 

109 self._shape = None 

110 if self.__class__.__name__ == '_spbase': 

111 raise ValueError("This class is not intended" 

112 " to be instantiated directly.") 

113 self.maxprint = maxprint 

114 

115 # Use this in 1.13.0 and later: 

116 # 

117 # @property 

118 # def shape(self): 

119 # return self._shape 

120 

121 def reshape(self, *args, **kwargs): 

122 """reshape(self, shape, order='C', copy=False) 

123 

124 Gives a new shape to a sparse array without changing its data. 

125 

126 Parameters 

127 ---------- 

128 shape : length-2 tuple of ints 

129 The new shape should be compatible with the original shape. 

130 order : {'C', 'F'}, optional 

131 Read the elements using this index order. 'C' means to read and 

132 write the elements using C-like index order; e.g., read entire first 

133 row, then second row, etc. 'F' means to read and write the elements 

134 using Fortran-like index order; e.g., read entire first column, then 

135 second column, etc. 

136 copy : bool, optional 

137 Indicates whether or not attributes of self should be copied 

138 whenever possible. The degree to which attributes are copied varies 

139 depending on the type of sparse array being used. 

140 

141 Returns 

142 ------- 

143 reshaped : sparse array 

144 A sparse array with the given `shape`, not necessarily of the same 

145 format as the current object. 

146 

147 See Also 

148 -------- 

149 numpy.reshape : NumPy's implementation of 'reshape' for ndarrays 

150 """ 

151 # If the shape already matches, don't bother doing an actual reshape 

152 # Otherwise, the default is to convert to COO and use its reshape 

153 shape = check_shape(args, self.shape) 

154 order, copy = check_reshape_kwargs(kwargs) 

155 if shape == self.shape: 

156 if copy: 

157 return self.copy() 

158 else: 

159 return self 

160 

161 return self.tocoo(copy=copy).reshape(shape, order=order, copy=False) 

162 

163 def resize(self, shape): 

164 """Resize the array in-place to dimensions given by ``shape`` 

165 

166 Any elements that lie within the new shape will remain at the same 

167 indices, while non-zero elements lying outside the new shape are 

168 removed. 

169 

170 Parameters 

171 ---------- 

172 shape : (int, int) 

173 number of rows and columns in the new array 

174 

175 Notes 

176 ----- 

177 The semantics are not identical to `numpy.ndarray.resize` or 

178 `numpy.resize`. Here, the same data will be maintained at each index 

179 before and after reshape, if that index is within the new bounds. In 

180 numpy, resizing maintains contiguity of the array, moving elements 

181 around in the logical array but not within a flattened representation. 

182 

183 We give no guarantees about whether the underlying data attributes 

184 (arrays, etc.) will be modified in place or replaced with new objects. 

185 """ 

186 # As an inplace operation, this requires implementation in each format. 

187 raise NotImplementedError( 

188 f'{type(self).__name__}.resize is not implemented') 

189 

190 def astype(self, dtype, casting='unsafe', copy=True): 

191 """Cast the array elements to a specified type. 

192 

193 Parameters 

194 ---------- 

195 dtype : string or numpy dtype 

196 Typecode or data-type to which to cast the data. 

197 casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional 

198 Controls what kind of data casting may occur. 

199 Defaults to 'unsafe' for backwards compatibility. 

200 'no' means the data types should not be cast at all. 

201 'equiv' means only byte-order changes are allowed. 

202 'safe' means only casts which can preserve values are allowed. 

203 'same_kind' means only safe casts or casts within a kind, 

204 like float64 to float32, are allowed. 

205 'unsafe' means any data conversions may be done. 

206 copy : bool, optional 

207 If `copy` is `False`, the result might share some memory with this 

208 array. If `copy` is `True`, it is guaranteed that the result and 

209 this array do not share any memory. 

210 """ 

211 

212 dtype = np.dtype(dtype) 

213 if self.dtype != dtype: 

214 return self.tocsr().astype( 

215 dtype, casting=casting, copy=copy).asformat(self.format) 

216 elif copy: 

217 return self.copy() 

218 else: 

219 return self 

220 

221 @classmethod 

222 def _ascontainer(cls, X, **kwargs): 

223 if cls._is_array: 

224 return np.asarray(X, **kwargs) 

225 else: 

226 return asmatrix(X, **kwargs) 

227 

228 @classmethod 

229 def _container(cls, X, **kwargs): 

230 if cls._is_array: 

231 return np.array(X, **kwargs) 

232 else: 

233 return matrix(X, **kwargs) 

234 

235 def _asfptype(self): 

236 """Upcast array to a floating point format (if necessary)""" 

237 

238 fp_types = ['f', 'd', 'F', 'D'] 

239 

240 if self.dtype.char in fp_types: 

241 return self 

242 else: 

243 for fp_type in fp_types: 

244 if self.dtype <= np.dtype(fp_type): 

245 return self.astype(fp_type) 

246 

247 raise TypeError('cannot upcast [%s] to a floating ' 

248 'point format' % self.dtype.name) 

249 

250 def __iter__(self): 

251 for r in range(self.shape[0]): 

252 yield self[r, :] 

253 

254 def _getmaxprint(self): 

255 """Maximum number of elements to display when printed.""" 

256 return self.maxprint 

257 

258 def count_nonzero(self): 

259 """Number of non-zero entries, equivalent to 

260 

261 np.count_nonzero(a.toarray()) 

262 

263 Unlike the nnz property, which return the number of stored 

264 entries (the length of the data attribute), this method counts the 

265 actual number of non-zero entries in data. 

266 """ 

267 raise NotImplementedError("count_nonzero not implemented for %s." % 

268 self.__class__.__name__) 

269 

270 def _getnnz(self, axis=None): 

271 """Number of stored values, including explicit zeros. 

272 

273 Parameters 

274 ---------- 

275 axis : None, 0, or 1 

276 Select between the number of values across the whole array, in 

277 each column, or in each row. 

278 

279 See also 

280 -------- 

281 count_nonzero : Number of non-zero entries 

282 """ 

283 raise NotImplementedError("getnnz not implemented for %s." % 

284 self.__class__.__name__) 

285 

286 @property 

287 def nnz(self): 

288 """Number of stored values, including explicit zeros. 

289 

290 See also 

291 -------- 

292 count_nonzero : Number of non-zero entries 

293 """ 

294 return self._getnnz() 

295 

296 @property 

297 def format(self): 

298 return self._format 

299 

300 def __repr__(self): 

301 _, format_name = _formats[self.format] 

302 sparse_cls = 'array' if self._is_array else 'matrix' 

303 return f"<%dx%d sparse {sparse_cls} of type '%s'\n" \ 

304 "\twith %d stored elements in %s format>" % \ 

305 (self.shape + (self.dtype.type, self.nnz, format_name)) 

306 

307 def __str__(self): 

308 maxprint = self._getmaxprint() 

309 

310 A = self.tocoo() 

311 

312 # helper function, outputs "(i,j) v" 

313 def tostr(row, col, data): 

314 triples = zip(list(zip(row, col)), data) 

315 return '\n'.join([(' %s\t%s' % t) for t in triples]) 

316 

317 if self.nnz > maxprint: 

318 half = maxprint // 2 

319 out = tostr(A.row[:half], A.col[:half], A.data[:half]) 

320 out += "\n :\t:\n" 

321 half = maxprint - maxprint//2 

322 out += tostr(A.row[-half:], A.col[-half:], A.data[-half:]) 

323 else: 

324 out = tostr(A.row, A.col, A.data) 

325 

326 return out 

327 

328 def __bool__(self): # Simple -- other ideas? 

329 if self.shape == (1, 1): 

330 return self.nnz != 0 

331 else: 

332 raise ValueError("The truth value of an array with more than one " 

333 "element is ambiguous. Use a.any() or a.all().") 

334 __nonzero__ = __bool__ 

335 

336 # What should len(sparse) return? For consistency with dense matrices, 

337 # perhaps it should be the number of rows? But for some uses the number of 

338 # non-zeros is more important. For now, raise an exception! 

339 def __len__(self): 

340 raise TypeError("sparse array length is ambiguous; use getnnz()" 

341 " or shape[0]") 

342 

343 def asformat(self, format, copy=False): 

344 """Return this array in the passed format. 

345 

346 Parameters 

347 ---------- 

348 format : {str, None} 

349 The desired sparse format ("csr", "csc", "lil", "dok", "array", ...) 

350 or None for no conversion. 

351 copy : bool, optional 

352 If True, the result is guaranteed to not share data with self. 

353 

354 Returns 

355 ------- 

356 A : This array in the passed format. 

357 """ 

358 if format is None or format == self.format: 

359 if copy: 

360 return self.copy() 

361 else: 

362 return self 

363 else: 

364 try: 

365 convert_method = getattr(self, 'to' + format) 

366 except AttributeError as e: 

367 raise ValueError(f'Format {format} is unknown.') from e 

368 

369 # Forward the copy kwarg, if it's accepted. 

370 try: 

371 return convert_method(copy=copy) 

372 except TypeError: 

373 return convert_method() 

374 

375 ################################################################### 

376 # NOTE: All arithmetic operations use csr_matrix by default. 

377 # Therefore a new sparse array format just needs to define a 

378 # .tocsr() method to provide arithmetic support. Any of these 

379 # methods can be overridden for efficiency. 

380 #################################################################### 

381 

382 def multiply(self, other): 

383 """Point-wise multiplication by another array 

384 """ 

385 return self.tocsr().multiply(other) 

386 

387 def maximum(self, other): 

388 """Element-wise maximum between this and another array.""" 

389 return self.tocsr().maximum(other) 

390 

391 def minimum(self, other): 

392 """Element-wise minimum between this and another array.""" 

393 return self.tocsr().minimum(other) 

394 

395 def dot(self, other): 

396 """Ordinary dot product 

397 

398 Examples 

399 -------- 

400 >>> import numpy as np 

401 >>> from scipy.sparse import csr_array 

402 >>> A = csr_array([[1, 2, 0], [0, 0, 3], [4, 0, 5]]) 

403 >>> v = np.array([1, 0, -1]) 

404 >>> A.dot(v) 

405 array([ 1, -3, -1], dtype=int64) 

406 

407 """ 

408 if np.isscalar(other): 

409 return self * other 

410 else: 

411 return self @ other 

412 

413 def power(self, n, dtype=None): 

414 """Element-wise power.""" 

415 return self.tocsr().power(n, dtype=dtype) 

416 

417 def __eq__(self, other): 

418 return self.tocsr().__eq__(other) 

419 

420 def __ne__(self, other): 

421 return self.tocsr().__ne__(other) 

422 

423 def __lt__(self, other): 

424 return self.tocsr().__lt__(other) 

425 

426 def __gt__(self, other): 

427 return self.tocsr().__gt__(other) 

428 

429 def __le__(self, other): 

430 return self.tocsr().__le__(other) 

431 

432 def __ge__(self, other): 

433 return self.tocsr().__ge__(other) 

434 

435 def __abs__(self): 

436 return abs(self.tocsr()) 

437 

438 def __round__(self, ndigits=0): 

439 return round(self.tocsr(), ndigits=ndigits) 

440 

441 def _add_sparse(self, other): 

442 return self.tocsr()._add_sparse(other) 

443 

444 def _add_dense(self, other): 

445 return self.tocoo()._add_dense(other) 

446 

447 def _sub_sparse(self, other): 

448 return self.tocsr()._sub_sparse(other) 

449 

450 def _sub_dense(self, other): 

451 return self.todense() - other 

452 

453 def _rsub_dense(self, other): 

454 # note: this can't be replaced by other + (-self) for unsigned types 

455 return other - self.todense() 

456 

457 def __add__(self, other): # self + other 

458 if isscalarlike(other): 

459 if other == 0: 

460 return self.copy() 

461 # Now we would add this scalar to every element. 

462 raise NotImplementedError('adding a nonzero scalar to a ' 

463 'sparse array is not supported') 

464 elif issparse(other): 

465 if other.shape != self.shape: 

466 raise ValueError("inconsistent shapes") 

467 return self._add_sparse(other) 

468 elif isdense(other): 

469 other = np.broadcast_to(other, self.shape) 

470 return self._add_dense(other) 

471 else: 

472 return NotImplemented 

473 

474 def __radd__(self,other): # other + self 

475 return self.__add__(other) 

476 

477 def __sub__(self, other): # self - other 

478 if isscalarlike(other): 

479 if other == 0: 

480 return self.copy() 

481 raise NotImplementedError('subtracting a nonzero scalar from a ' 

482 'sparse array is not supported') 

483 elif issparse(other): 

484 if other.shape != self.shape: 

485 raise ValueError("inconsistent shapes") 

486 return self._sub_sparse(other) 

487 elif isdense(other): 

488 other = np.broadcast_to(other, self.shape) 

489 return self._sub_dense(other) 

490 else: 

491 return NotImplemented 

492 

493 def __rsub__(self,other): # other - self 

494 if isscalarlike(other): 

495 if other == 0: 

496 return -self.copy() 

497 raise NotImplementedError('subtracting a sparse array from a ' 

498 'nonzero scalar is not supported') 

499 elif isdense(other): 

500 other = np.broadcast_to(other, self.shape) 

501 return self._rsub_dense(other) 

502 else: 

503 return NotImplemented 

504 

505 def _mul_dispatch(self, other): 

506 """`np.matrix`-compatible mul, i.e. `dot` or `NotImplemented` 

507 

508 interpret other and call one of the following 

509 self._mul_scalar() 

510 self._mul_vector() 

511 self._mul_multivector() 

512 self._mul_sparse_matrix() 

513 """ 

514 # This method has to be different from `__matmul__` because it is also 

515 # called by sparse matrix classes. 

516 

517 M, N = self.shape 

518 

519 if other.__class__ is np.ndarray: 

520 # Fast path for the most common case 

521 if other.shape == (N,): 

522 return self._mul_vector(other) 

523 elif other.shape == (N, 1): 

524 return self._mul_vector(other.ravel()).reshape(M, 1) 

525 elif other.ndim == 2 and other.shape[0] == N: 

526 return self._mul_multivector(other) 

527 

528 if isscalarlike(other): 

529 # scalar value 

530 return self._mul_scalar(other) 

531 

532 if issparse(other): 

533 if self.shape[1] != other.shape[0]: 

534 raise ValueError('dimension mismatch') 

535 return self._mul_sparse_matrix(other) 

536 

537 # If it's a list or whatever, treat it like an array 

538 other_a = np.asanyarray(other) 

539 

540 if other_a.ndim == 0 and other_a.dtype == np.object_: 

541 # Not interpretable as an array; return NotImplemented so that 

542 # other's __rmul__ can kick in if that's implemented. 

543 return NotImplemented 

544 

545 try: 

546 other.shape 

547 except AttributeError: 

548 other = other_a 

549 

550 if other.ndim == 1 or other.ndim == 2 and other.shape[1] == 1: 

551 # dense row or column vector 

552 if other.shape != (N,) and other.shape != (N, 1): 

553 raise ValueError('dimension mismatch') 

554 

555 result = self._mul_vector(np.ravel(other)) 

556 

557 if isinstance(other, np.matrix): 

558 result = self._ascontainer(result) 

559 

560 if other.ndim == 2 and other.shape[1] == 1: 

561 # If 'other' was an (nx1) column vector, reshape the result 

562 result = result.reshape(-1, 1) 

563 

564 return result 

565 

566 elif other.ndim == 2: 

567 ## 

568 # dense 2D array or matrix ("multivector") 

569 

570 if other.shape[0] != self.shape[1]: 

571 raise ValueError('dimension mismatch') 

572 

573 result = self._mul_multivector(np.asarray(other)) 

574 

575 if isinstance(other, np.matrix): 

576 result = self._ascontainer(result) 

577 

578 return result 

579 

580 else: 

581 raise ValueError('could not interpret dimensions') 

582 

583 def __mul__(self, *args, **kwargs): 

584 return self.multiply(*args, **kwargs) 

585 

586 # by default, use CSR for __mul__ handlers 

587 def _mul_scalar(self, other): 

588 return self.tocsr()._mul_scalar(other) 

589 

590 def _mul_vector(self, other): 

591 return self.tocsr()._mul_vector(other) 

592 

593 def _mul_multivector(self, other): 

594 return self.tocsr()._mul_multivector(other) 

595 

596 def _mul_sparse_matrix(self, other): 

597 return self.tocsr()._mul_sparse_matrix(other) 

598 

599 def _rmul_dispatch(self, other): 

600 if isscalarlike(other): 

601 return self._mul_scalar(other) 

602 else: 

603 # Don't use asarray unless we have to 

604 try: 

605 tr = other.transpose() 

606 except AttributeError: 

607 tr = np.asarray(other).transpose() 

608 ret = self.transpose()._mul_dispatch(tr) 

609 if ret is NotImplemented: 

610 return NotImplemented 

611 return ret.transpose() 

612 

613 def __rmul__(self, *args, **kwargs): # other * self 

614 return self.multiply(*args, **kwargs) 

615 

616 ####################### 

617 # matmul (@) operator # 

618 ####################### 

619 

620 def __matmul__(self, other): 

621 if isscalarlike(other): 

622 raise ValueError("Scalar operands are not allowed, " 

623 "use '*' instead") 

624 return self._mul_dispatch(other) 

625 

626 def __rmatmul__(self, other): 

627 if isscalarlike(other): 

628 raise ValueError("Scalar operands are not allowed, " 

629 "use '*' instead") 

630 return self._rmul_dispatch(other) 

631 

632 #################### 

633 # Other Arithmetic # 

634 #################### 

635 

636 def _divide(self, other, true_divide=False, rdivide=False): 

637 if isscalarlike(other): 

638 if rdivide: 

639 if true_divide: 

640 return np.true_divide(other, self.todense()) 

641 else: 

642 return np.divide(other, self.todense()) 

643 

644 if true_divide and np.can_cast(self.dtype, np.float_): 

645 return self.astype(np.float_)._mul_scalar(1./other) 

646 else: 

647 r = self._mul_scalar(1./other) 

648 

649 scalar_dtype = np.asarray(other).dtype 

650 if (np.issubdtype(self.dtype, np.integer) and 

651 np.issubdtype(scalar_dtype, np.integer)): 

652 return r.astype(self.dtype) 

653 else: 

654 return r 

655 

656 elif isdense(other): 

657 if not rdivide: 

658 if true_divide: 

659 recip = np.true_divide(1., other) 

660 else: 

661 recip = np.divide(1., other) 

662 return self.multiply(recip) 

663 else: 

664 if true_divide: 

665 return np.true_divide(other, self.todense()) 

666 else: 

667 return np.divide(other, self.todense()) 

668 elif issparse(other): 

669 if rdivide: 

670 return other._divide(self, true_divide, rdivide=False) 

671 

672 self_csr = self.tocsr() 

673 if true_divide and np.can_cast(self.dtype, np.float_): 

674 return self_csr.astype(np.float_)._divide_sparse(other) 

675 else: 

676 return self_csr._divide_sparse(other) 

677 else: 

678 return NotImplemented 

679 

680 def __truediv__(self, other): 

681 return self._divide(other, true_divide=True) 

682 

683 def __div__(self, other): 

684 # Always do true division 

685 return self._divide(other, true_divide=True) 

686 

687 def __rtruediv__(self, other): 

688 # Implementing this as the inverse would be too magical -- bail out 

689 return NotImplemented 

690 

691 def __rdiv__(self, other): 

692 # Implementing this as the inverse would be too magical -- bail out 

693 return NotImplemented 

694 

695 def __neg__(self): 

696 return -self.tocsr() 

697 

698 def __iadd__(self, other): 

699 return NotImplemented 

700 

701 def __isub__(self, other): 

702 return NotImplemented 

703 

704 def __imul__(self, other): 

705 return NotImplemented 

706 

707 def __idiv__(self, other): 

708 return self.__itruediv__(other) 

709 

710 def __itruediv__(self, other): 

711 return NotImplemented 

712 

713 def __pow__(self, *args, **kwargs): 

714 return self.power(*args, **kwargs) 

715 

716 @property 

717 def A(self) -> np.ndarray: 

718 if self._is_array: 

719 warn(np.VisibleDeprecationWarning( 

720 "`.A` is deprecated and will be removed in v1.13.0. " 

721 "Use `.toarray()` instead." 

722 )) 

723 return self.toarray() 

724 

725 @property 

726 def T(self): 

727 return self.transpose() 

728 

729 @property 

730 def H(self): 

731 if self._is_array: 

732 warn(np.VisibleDeprecationWarning( 

733 "`.H` is deprecated and will be removed in v1.13.0. " 

734 "Please use `.T.conjugate()` instead." 

735 )) 

736 return self.T.conjugate() 

737 

738 @property 

739 def real(self): 

740 return self._real() 

741 

742 @property 

743 def imag(self): 

744 return self._imag() 

745 

746 @property 

747 def size(self): 

748 return self._getnnz() 

749 

750 def transpose(self, axes=None, copy=False): 

751 """ 

752 Reverses the dimensions of the sparse array. 

753 

754 Parameters 

755 ---------- 

756 axes : None, optional 

757 This argument is in the signature *solely* for NumPy 

758 compatibility reasons. Do not pass in anything except 

759 for the default value. 

760 copy : bool, optional 

761 Indicates whether or not attributes of `self` should be 

762 copied whenever possible. The degree to which attributes 

763 are copied varies depending on the type of sparse array 

764 being used. 

765 

766 Returns 

767 ------- 

768 p : `self` with the dimensions reversed. 

769 

770 See Also 

771 -------- 

772 numpy.transpose : NumPy's implementation of 'transpose' for ndarrays 

773 """ 

774 return self.tocsr(copy=copy).transpose(axes=axes, copy=False) 

775 

776 def conjugate(self, copy=True): 

777 """Element-wise complex conjugation. 

778 

779 If the array is of non-complex data type and `copy` is False, 

780 this method does nothing and the data is not copied. 

781 

782 Parameters 

783 ---------- 

784 copy : bool, optional 

785 If True, the result is guaranteed to not share data with self. 

786 

787 Returns 

788 ------- 

789 A : The element-wise complex conjugate. 

790 

791 """ 

792 if np.issubdtype(self.dtype, np.complexfloating): 

793 return self.tocsr(copy=copy).conjugate(copy=False) 

794 elif copy: 

795 return self.copy() 

796 else: 

797 return self 

798 

799 def conj(self, copy=True): 

800 return self.conjugate(copy=copy) 

801 

802 conj.__doc__ = conjugate.__doc__ 

803 

804 def _real(self): 

805 return self.tocsr()._real() 

806 

807 def _imag(self): 

808 return self.tocsr()._imag() 

809 

810 def nonzero(self): 

811 """nonzero indices 

812 

813 Returns a tuple of arrays (row,col) containing the indices 

814 of the non-zero elements of the array. 

815 

816 Examples 

817 -------- 

818 >>> from scipy.sparse import csr_array 

819 >>> A = csr_array([[1,2,0],[0,0,3],[4,0,5]]) 

820 >>> A.nonzero() 

821 (array([0, 0, 1, 2, 2]), array([0, 1, 2, 0, 2])) 

822 

823 """ 

824 

825 # convert to COOrdinate format 

826 A = self.tocoo() 

827 nz_mask = A.data != 0 

828 return (A.row[nz_mask], A.col[nz_mask]) 

829 

830 def _getcol(self, j): 

831 """Returns a copy of column j of the array, as an (m x 1) sparse 

832 array (column vector). 

833 """ 

834 # Subclasses should override this method for efficiency. 

835 # Post-multiply by a (n x 1) column vector 'a' containing all zeros 

836 # except for a_j = 1 

837 n = self.shape[1] 

838 if j < 0: 

839 j += n 

840 if j < 0 or j >= n: 

841 raise IndexError("index out of bounds") 

842 col_selector = self._csc_container(([1], [[j], [0]]), 

843 shape=(n, 1), dtype=self.dtype) 

844 return self @ col_selector 

845 

846 def _getrow(self, i): 

847 """Returns a copy of row i of the array, as a (1 x n) sparse 

848 array (row vector). 

849 """ 

850 # Subclasses should override this method for efficiency. 

851 # Pre-multiply by a (1 x m) row vector 'a' containing all zeros 

852 # except for a_i = 1 

853 m = self.shape[0] 

854 if i < 0: 

855 i += m 

856 if i < 0 or i >= m: 

857 raise IndexError("index out of bounds") 

858 row_selector = self._csr_container(([1], [[0], [i]]), 

859 shape=(1, m), dtype=self.dtype) 

860 return row_selector @ self 

861 

862 # The following dunder methods cannot be implemented. 

863 # 

864 # def __array__(self): 

865 # # Sparse matrices rely on NumPy wrapping them in object arrays under 

866 # # the hood to make unary ufuncs work on them. So we cannot raise 

867 # # TypeError here - which would be handy to not give users object 

868 # # arrays they probably don't want (they're looking for `.toarray()`). 

869 # # 

870 # # Conversion with `toarray()` would also break things because of the 

871 # # behavior discussed above, plus we want to avoid densification by 

872 # # accident because that can too easily blow up memory. 

873 # 

874 # def __array_ufunc__(self): 

875 # # We cannot implement __array_ufunc__ due to mismatching semantics. 

876 # # See gh-7707 and gh-7349 for details. 

877 # 

878 # def __array_function__(self): 

879 # # We cannot implement __array_function__ due to mismatching semantics. 

880 # # See gh-10362 for details. 

881 

882 def todense(self, order=None, out=None): 

883 """ 

884 Return a dense matrix representation of this sparse array. 

885 

886 Parameters 

887 ---------- 

888 order : {'C', 'F'}, optional 

889 Whether to store multi-dimensional data in C (row-major) 

890 or Fortran (column-major) order in memory. The default 

891 is 'None', which provides no ordering guarantees. 

892 Cannot be specified in conjunction with the `out` 

893 argument. 

894 

895 out : ndarray, 2-D, optional 

896 If specified, uses this array (or `numpy.matrix`) as the 

897 output buffer instead of allocating a new array to 

898 return. The provided array must have the same shape and 

899 dtype as the sparse array on which you are calling the 

900 method. 

901 

902 Returns 

903 ------- 

904 arr : numpy.matrix, 2-D 

905 A NumPy matrix object with the same shape and containing 

906 the same data represented by the sparse array, with the 

907 requested memory order. If `out` was passed and was an 

908 array (rather than a `numpy.matrix`), it will be filled 

909 with the appropriate values and returned wrapped in a 

910 `numpy.matrix` object that shares the same memory. 

911 """ 

912 return self._ascontainer(self.toarray(order=order, out=out)) 

913 

914 def toarray(self, order=None, out=None): 

915 """ 

916 Return a dense ndarray representation of this sparse array. 

917 

918 Parameters 

919 ---------- 

920 order : {'C', 'F'}, optional 

921 Whether to store multidimensional data in C (row-major) 

922 or Fortran (column-major) order in memory. The default 

923 is 'None', which provides no ordering guarantees. 

924 Cannot be specified in conjunction with the `out` 

925 argument. 

926 

927 out : ndarray, 2-D, optional 

928 If specified, uses this array as the output buffer 

929 instead of allocating a new array to return. The provided 

930 array must have the same shape and dtype as the sparse 

931 array on which you are calling the method. For most 

932 sparse types, `out` is required to be memory contiguous 

933 (either C or Fortran ordered). 

934 

935 Returns 

936 ------- 

937 arr : ndarray, 2-D 

938 An array with the same shape and containing the same 

939 data represented by the sparse array, with the requested 

940 memory order. If `out` was passed, the same object is 

941 returned after being modified in-place to contain the 

942 appropriate values. 

943 """ 

944 return self.tocoo(copy=False).toarray(order=order, out=out) 

945 

946 # Any sparse array format deriving from _spbase must define one of 

947 # tocsr or tocoo. The other conversion methods may be implemented for 

948 # efficiency, but are not required. 

949 def tocsr(self, copy=False): 

950 """Convert this array to Compressed Sparse Row format. 

951 

952 With copy=False, the data/indices may be shared between this array and 

953 the resultant csr_array. 

954 """ 

955 return self.tocoo(copy=copy).tocsr(copy=False) 

956 

957 def todok(self, copy=False): 

958 """Convert this array to Dictionary Of Keys format. 

959 

960 With copy=False, the data/indices may be shared between this array and 

961 the resultant dok_array. 

962 """ 

963 return self.tocoo(copy=copy).todok(copy=False) 

964 

965 def tocoo(self, copy=False): 

966 """Convert this array to COOrdinate format. 

967 

968 With copy=False, the data/indices may be shared between this array and 

969 the resultant coo_array. 

970 """ 

971 return self.tocsr(copy=False).tocoo(copy=copy) 

972 

973 def tolil(self, copy=False): 

974 """Convert this array to List of Lists format. 

975 

976 With copy=False, the data/indices may be shared between this array and 

977 the resultant lil_array. 

978 """ 

979 return self.tocsr(copy=False).tolil(copy=copy) 

980 

981 def todia(self, copy=False): 

982 """Convert this array to sparse DIAgonal format. 

983 

984 With copy=False, the data/indices may be shared between this array and 

985 the resultant dia_array. 

986 """ 

987 return self.tocoo(copy=copy).todia(copy=False) 

988 

989 def tobsr(self, blocksize=None, copy=False): 

990 """Convert this array to Block Sparse Row format. 

991 

992 With copy=False, the data/indices may be shared between this array and 

993 the resultant bsr_array. 

994 

995 When blocksize=(R, C) is provided, it will be used for construction of 

996 the bsr_array. 

997 """ 

998 return self.tocsr(copy=False).tobsr(blocksize=blocksize, copy=copy) 

999 

1000 def tocsc(self, copy=False): 

1001 """Convert this array to Compressed Sparse Column format. 

1002 

1003 With copy=False, the data/indices may be shared between this array and 

1004 the resultant csc_array. 

1005 """ 

1006 return self.tocsr(copy=copy).tocsc(copy=False) 

1007 

1008 def copy(self): 

1009 """Returns a copy of this array. 

1010 

1011 No data/indices will be shared between the returned value and current 

1012 array. 

1013 """ 

1014 return self.__class__(self, copy=True) 

1015 

1016 def sum(self, axis=None, dtype=None, out=None): 

1017 """ 

1018 Sum the array elements over a given axis. 

1019 

1020 Parameters 

1021 ---------- 

1022 axis : {-2, -1, 0, 1, None} optional 

1023 Axis along which the sum is computed. The default is to 

1024 compute the sum of all the array elements, returning a scalar 

1025 (i.e., `axis` = `None`). 

1026 dtype : dtype, optional 

1027 The type of the returned array and of the accumulator in which 

1028 the elements are summed. The dtype of `a` is used by default 

1029 unless `a` has an integer dtype of less precision than the default 

1030 platform integer. In that case, if `a` is signed then the platform 

1031 integer is used while if `a` is unsigned then an unsigned integer 

1032 of the same precision as the platform integer is used. 

1033 

1034 .. versionadded:: 0.18.0 

1035 

1036 out : np.matrix, optional 

1037 Alternative output matrix in which to place the result. It must 

1038 have the same shape as the expected output, but the type of the 

1039 output values will be cast if necessary. 

1040 

1041 .. versionadded:: 0.18.0 

1042 

1043 Returns 

1044 ------- 

1045 sum_along_axis : np.matrix 

1046 A matrix with the same shape as `self`, with the specified 

1047 axis removed. 

1048 

1049 See Also 

1050 -------- 

1051 numpy.matrix.sum : NumPy's implementation of 'sum' for matrices 

1052 

1053 """ 

1054 validateaxis(axis) 

1055 

1056 # We use multiplication by a matrix of ones to achieve this. 

1057 # For some sparse array formats more efficient methods are 

1058 # possible -- these should override this function. 

1059 m, n = self.shape 

1060 

1061 # Mimic numpy's casting. 

1062 res_dtype = get_sum_dtype(self.dtype) 

1063 

1064 if axis is None: 

1065 # sum over rows and columns 

1066 return ( 

1067 self @ self._ascontainer(np.ones((n, 1), dtype=res_dtype)) 

1068 ).sum(dtype=dtype, out=out) 

1069 

1070 if axis < 0: 

1071 axis += 2 

1072 

1073 # axis = 0 or 1 now 

1074 if axis == 0: 

1075 # sum over columns 

1076 ret = self._ascontainer( 

1077 np.ones((1, m), dtype=res_dtype) 

1078 ) @ self 

1079 else: 

1080 # sum over rows 

1081 ret = self @ self._ascontainer( 

1082 np.ones((n, 1), dtype=res_dtype) 

1083 ) 

1084 

1085 if out is not None and out.shape != ret.shape: 

1086 raise ValueError("dimensions do not match") 

1087 

1088 return ret.sum(axis=axis, dtype=dtype, out=out) 

1089 

1090 def mean(self, axis=None, dtype=None, out=None): 

1091 """ 

1092 Compute the arithmetic mean along the specified axis. 

1093 

1094 Returns the average of the array elements. The average is taken 

1095 over all elements in the array by default, otherwise over the 

1096 specified axis. `float64` intermediate and return values are used 

1097 for integer inputs. 

1098 

1099 Parameters 

1100 ---------- 

1101 axis : {-2, -1, 0, 1, None} optional 

1102 Axis along which the mean is computed. The default is to compute 

1103 the mean of all elements in the array (i.e., `axis` = `None`). 

1104 dtype : data-type, optional 

1105 Type to use in computing the mean. For integer inputs, the default 

1106 is `float64`; for floating point inputs, it is the same as the 

1107 input dtype. 

1108 

1109 .. versionadded:: 0.18.0 

1110 

1111 out : np.matrix, optional 

1112 Alternative output matrix in which to place the result. It must 

1113 have the same shape as the expected output, but the type of the 

1114 output values will be cast if necessary. 

1115 

1116 .. versionadded:: 0.18.0 

1117 

1118 Returns 

1119 ------- 

1120 m : np.matrix 

1121 

1122 See Also 

1123 -------- 

1124 numpy.matrix.mean : NumPy's implementation of 'mean' for matrices 

1125 

1126 """ 

1127 def _is_integral(dtype): 

1128 return (np.issubdtype(dtype, np.integer) or 

1129 np.issubdtype(dtype, np.bool_)) 

1130 

1131 validateaxis(axis) 

1132 

1133 res_dtype = self.dtype.type 

1134 integral = _is_integral(self.dtype) 

1135 

1136 # output dtype 

1137 if dtype is None: 

1138 if integral: 

1139 res_dtype = np.float64 

1140 else: 

1141 res_dtype = np.dtype(dtype).type 

1142 

1143 # intermediate dtype for summation 

1144 inter_dtype = np.float64 if integral else res_dtype 

1145 inter_self = self.astype(inter_dtype) 

1146 

1147 if axis is None: 

1148 return (inter_self / np.array( 

1149 self.shape[0] * self.shape[1]))\ 

1150 .sum(dtype=res_dtype, out=out) 

1151 

1152 if axis < 0: 

1153 axis += 2 

1154 

1155 # axis = 0 or 1 now 

1156 if axis == 0: 

1157 return (inter_self * (1.0 / self.shape[0])).sum( 

1158 axis=0, dtype=res_dtype, out=out) 

1159 else: 

1160 return (inter_self * (1.0 / self.shape[1])).sum( 

1161 axis=1, dtype=res_dtype, out=out) 

1162 

1163 def diagonal(self, k=0): 

1164 """Returns the kth diagonal of the array. 

1165 

1166 Parameters 

1167 ---------- 

1168 k : int, optional 

1169 Which diagonal to get, corresponding to elements a[i, i+k]. 

1170 Default: 0 (the main diagonal). 

1171 

1172 .. versionadded:: 1.0 

1173 

1174 See also 

1175 -------- 

1176 numpy.diagonal : Equivalent numpy function. 

1177 

1178 Examples 

1179 -------- 

1180 >>> from scipy.sparse import csr_array 

1181 >>> A = csr_array([[1, 2, 0], [0, 0, 3], [4, 0, 5]]) 

1182 >>> A.diagonal() 

1183 array([1, 0, 5]) 

1184 >>> A.diagonal(k=1) 

1185 array([2, 3]) 

1186 """ 

1187 return self.tocsr().diagonal(k=k) 

1188 

1189 def trace(self, offset=0): 

1190 """Returns the sum along diagonals of the sparse array. 

1191 

1192 Parameters 

1193 ---------- 

1194 offset : int, optional 

1195 Which diagonal to get, corresponding to elements a[i, i+offset]. 

1196 Default: 0 (the main diagonal). 

1197 

1198 """ 

1199 return self.diagonal(k=offset).sum() 

1200 

1201 def setdiag(self, values, k=0): 

1202 """ 

1203 Set diagonal or off-diagonal elements of the array. 

1204 

1205 Parameters 

1206 ---------- 

1207 values : array_like 

1208 New values of the diagonal elements. 

1209 

1210 Values may have any length. If the diagonal is longer than values, 

1211 then the remaining diagonal entries will not be set. If values are 

1212 longer than the diagonal, then the remaining values are ignored. 

1213 

1214 If a scalar value is given, all of the diagonal is set to it. 

1215 

1216 k : int, optional 

1217 Which off-diagonal to set, corresponding to elements a[i,i+k]. 

1218 Default: 0 (the main diagonal). 

1219 

1220 """ 

1221 M, N = self.shape 

1222 if (k > 0 and k >= N) or (k < 0 and -k >= M): 

1223 raise ValueError("k exceeds array dimensions") 

1224 self._setdiag(np.asarray(values), k) 

1225 

1226 def _setdiag(self, values, k): 

1227 """This part of the implementation gets overridden by the 

1228 different formats. 

1229 """ 

1230 M, N = self.shape 

1231 if k < 0: 

1232 if values.ndim == 0: 

1233 # broadcast 

1234 max_index = min(M+k, N) 

1235 for i in range(max_index): 

1236 self[i - k, i] = values 

1237 else: 

1238 max_index = min(M+k, N, len(values)) 

1239 if max_index <= 0: 

1240 return 

1241 for i, v in enumerate(values[:max_index]): 

1242 self[i - k, i] = v 

1243 else: 

1244 if values.ndim == 0: 

1245 # broadcast 

1246 max_index = min(M, N-k) 

1247 for i in range(max_index): 

1248 self[i, i + k] = values 

1249 else: 

1250 max_index = min(M, N-k, len(values)) 

1251 if max_index <= 0: 

1252 return 

1253 for i, v in enumerate(values[:max_index]): 

1254 self[i, i + k] = v 

1255 

1256 def _process_toarray_args(self, order, out): 

1257 if out is not None: 

1258 if order is not None: 

1259 raise ValueError('order cannot be specified if out ' 

1260 'is not None') 

1261 if out.shape != self.shape or out.dtype != self.dtype: 

1262 raise ValueError('out array must be same dtype and shape as ' 

1263 'sparse array') 

1264 out[...] = 0. 

1265 return out 

1266 else: 

1267 return np.zeros(self.shape, dtype=self.dtype, order=order) 

1268 

1269 def _get_index_dtype(self, arrays=(), maxval=None, check_contents=False): 

1270 """ 

1271 Determine index dtype for array. 

1272 

1273 This wraps _sputils.get_index_dtype, providing compatibility for both 

1274 array and matrix API sparse matrices. Matrix API sparse matrices would 

1275 attempt to downcast the indices - which can be computationally 

1276 expensive and undesirable for users. The array API changes this 

1277 behaviour. 

1278 

1279 See discussion: https://github.com/scipy/scipy/issues/16774 

1280 

1281 The get_index_dtype import is due to implementation details of the test 

1282 suite. It allows the decorator ``with_64bit_maxval_limit`` to mock a 

1283 lower int32 max value for checks on the matrix API's downcasting 

1284 behaviour. 

1285 """ 

1286 from ._sputils import get_index_dtype 

1287 

1288 # Don't check contents for array API 

1289 return get_index_dtype(arrays, maxval, (check_contents and not self._is_array)) 

1290 

1291 

1292 ## All methods below are deprecated and should be removed in 

1293 ## scipy 1.13.0 

1294 ## 

1295 ## Also uncomment the definition of shape above. 

1296 

1297 def get_shape(self): 

1298 """Get shape of a sparse array. 

1299 

1300 .. deprecated:: 1.11.0 

1301 This method will be removed in SciPy 1.13.0. 

1302 Use `X.shape` instead. 

1303 """ 

1304 msg = ( 

1305 "`get_shape` is deprecated and will be removed in v1.13.0; " 

1306 "use `X.shape` instead." 

1307 ) 

1308 warn(msg, DeprecationWarning, stacklevel=2) 

1309 

1310 return self._shape 

1311 

1312 def set_shape(self, shape): 

1313 """See `reshape`. 

1314 

1315 .. deprecated:: 1.11.0 

1316 This method will be removed in SciPy 1.13.0. 

1317 Use `X.reshape` instead. 

1318 """ 

1319 msg = ( 

1320 "Shape assignment is deprecated and will be removed in v1.13.0; " 

1321 "use `reshape` instead." 

1322 ) 

1323 warn(msg, DeprecationWarning, stacklevel=2) 

1324 

1325 # Make sure copy is False since this is in place 

1326 # Make sure format is unchanged because we are doing a __dict__ swap 

1327 new_self = self.reshape(shape, copy=False).asformat(self.format) 

1328 self.__dict__ = new_self.__dict__ 

1329 

1330 shape = property( 

1331 fget=lambda self: self._shape, 

1332 fset=set_shape, 

1333 doc="""The shape of the array. 

1334 

1335Note that, starting in SciPy 1.13.0, this property will no longer be 

1336settable. To change the array shape, use `X.reshape` instead. 

1337""" 

1338 ) # noqa: F811 

1339 

1340 def asfptype(self): 

1341 """Upcast array to a floating point format (if necessary) 

1342 

1343 .. deprecated:: 1.11.0 

1344 This method is for internal use only, and will be removed from the 

1345 public API in SciPy 1.13.0. 

1346 """ 

1347 msg = ( 

1348 "`asfptype` is an internal function, and is deprecated " 

1349 "as part of the public API. It will be removed in v1.13.0." 

1350 ) 

1351 warn(msg, DeprecationWarning, stacklevel=2) 

1352 return self._asfptype() 

1353 

1354 def getmaxprint(self): 

1355 """Maximum number of elements to display when printed. 

1356 

1357 .. deprecated:: 1.11.0 

1358 This method is for internal use only, and will be removed from the 

1359 public API in SciPy 1.13.0. 

1360 """ 

1361 msg = ( 

1362 "`getmaxprint` is an internal function, and is deprecated " 

1363 "as part of the public API. It will be removed in v1.13.0." 

1364 ) 

1365 warn(msg, DeprecationWarning, stacklevel=2) 

1366 return self._getmaxprint() 

1367 

1368 def getformat(self): 

1369 """Matrix storage format. 

1370 

1371 .. deprecated:: 1.11.0 

1372 This method will be removed in SciPy 1.13.0. 

1373 Use `X.format` instead. 

1374 """ 

1375 msg = ( 

1376 "`getformat` is deprecated and will be removed in v1.13.0; " 

1377 "use `X.format` instead." 

1378 ) 

1379 warn(msg, DeprecationWarning, stacklevel=2) 

1380 return self.format 

1381 

1382 def getnnz(self, axis=None): 

1383 """Number of stored values, including explicit zeros. 

1384 

1385 .. deprecated:: 1.11.0 

1386 This method will be removed in SciPy 1.13.0. Use `X.nnz` 

1387 instead. The `axis` argument will no longer be supported; 

1388 please let us know if you still need this functionality. 

1389 

1390 Parameters 

1391 ---------- 

1392 axis : None, 0, or 1 

1393 Select between the number of values across the whole array, in 

1394 each column, or in each row. 

1395 

1396 See also 

1397 -------- 

1398 count_nonzero : Number of non-zero entries 

1399 """ 

1400 msg = ( 

1401 "`getnnz` is deprecated and will be removed in v1.13.0; " 

1402 "use `X.nnz` instead." 

1403 ) 

1404 warn(msg, DeprecationWarning, stacklevel=2) 

1405 return self._getnnz(axis=axis) 

1406 

1407 def getH(self): 

1408 """Return the Hermitian transpose of this array. 

1409 

1410 .. deprecated:: 1.11.0 

1411 This method will be removed in SciPy 1.13.0. 

1412 Use `X.conj().T` instead. 

1413 """ 

1414 msg = ( 

1415 "`getH` is deprecated and will be removed in v1.13.0; " 

1416 "use `X.conj().T` instead." 

1417 ) 

1418 warn(msg, DeprecationWarning, stacklevel=2) 

1419 return self.conjugate().transpose() 

1420 

1421 def getcol(self, j): 

1422 """Returns a copy of column j of the array, as an (m x 1) sparse 

1423 array (column vector). 

1424 

1425 .. deprecated:: 1.11.0 

1426 This method will be removed in SciPy 1.13.0. 

1427 Use array indexing instead. 

1428 """ 

1429 msg = ( 

1430 "`getcol` is deprecated and will be removed in v1.13.0; " 

1431 f"use `X[:, [{j}]]` instead." 

1432 ) 

1433 warn(msg, DeprecationWarning, stacklevel=2) 

1434 return self._getcol(j) 

1435 

1436 def getrow(self, i): 

1437 """Returns a copy of row i of the array, as a (1 x n) sparse 

1438 array (row vector). 

1439 

1440 .. deprecated:: 1.11.0 

1441 This method will be removed in SciPy 1.13.0. 

1442 Use array indexing instead. 

1443 """ 

1444 msg = ( 

1445 "`getrow` is deprecated and will be removed in v1.13.0; " 

1446 f"use `X[[{i}]]` instead." 

1447 ) 

1448 warn(msg, DeprecationWarning, stacklevel=2) 

1449 return self._getrow(i) 

1450 

1451 ## End 1.13.0 deprecated methods 

1452 

1453 

1454class sparray: 

1455 """A namespace class to separate sparray from spmatrix""" 

1456 pass 

1457 

1458sparray.__doc__ = _spbase.__doc__ 

1459 

1460 

1461def issparse(x): 

1462 """Is `x` of a sparse array type? 

1463 

1464 Parameters 

1465 ---------- 

1466 x 

1467 object to check for being a sparse array 

1468 

1469 Returns 

1470 ------- 

1471 bool 

1472 True if `x` is a sparse array or a sparse matrix, False otherwise 

1473 

1474 Examples 

1475 -------- 

1476 >>> import numpy as np 

1477 >>> from scipy.sparse import csr_array, csr_matrix, issparse 

1478 >>> issparse(csr_matrix([[5]])) 

1479 True 

1480 >>> issparse(csr_array([[5]])) 

1481 True 

1482 >>> issparse(np.array([[5]])) 

1483 False 

1484 >>> issparse(5) 

1485 False 

1486 """ 

1487 return isinstance(x, _spbase) 

1488 

1489 

1490def isspmatrix(x): 

1491 """Is `x` of a sparse matrix type? 

1492 

1493 Parameters 

1494 ---------- 

1495 x 

1496 object to check for being a sparse matrix 

1497 

1498 Returns 

1499 ------- 

1500 bool 

1501 True if `x` is a sparse matrix, False otherwise 

1502 

1503 Examples 

1504 -------- 

1505 >>> import numpy as np 

1506 >>> from scipy.sparse import csr_array, csr_matrix, isspmatrix 

1507 >>> isspmatrix(csr_matrix([[5]])) 

1508 True 

1509 >>> isspmatrix(csr_array([[5]])) 

1510 False 

1511 >>> isspmatrix(np.array([[5]])) 

1512 False 

1513 >>> isspmatrix(5) 

1514 False 

1515 """ 

1516 return isinstance(x, spmatrix)