Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/scipy/sparse/_bsr.py: 15%

312 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-23 06:43 +0000

1"""Compressed Block Sparse Row format""" 

2 

3__docformat__ = "restructuredtext en" 

4 

5__all__ = ['bsr_array', 'bsr_matrix', 'isspmatrix_bsr'] 

6 

7from warnings import warn 

8 

9import numpy as np 

10 

11from ._matrix import spmatrix 

12from ._data import _data_matrix, _minmax_mixin 

13from ._compressed import _cs_matrix 

14from ._base import issparse, _formats, _spbase, sparray 

15from ._sputils import (isshape, getdtype, getdata, to_native, upcast, 

16 check_shape) 

17from . import _sparsetools 

18from ._sparsetools import (bsr_matvec, bsr_matvecs, csr_matmat_maxnnz, 

19 bsr_matmat, bsr_transpose, bsr_sort_indices, 

20 bsr_tocsr) 

21 

22 

23class _bsr_base(_cs_matrix, _minmax_mixin): 

24 _format = 'bsr' 

25 

26 def __init__(self, arg1, shape=None, dtype=None, copy=False, blocksize=None): 

27 _data_matrix.__init__(self) 

28 

29 if issparse(arg1): 

30 if arg1.format == self.format and copy: 

31 arg1 = arg1.copy() 

32 else: 

33 arg1 = arg1.tobsr(blocksize=blocksize) 

34 self._set_self(arg1) 

35 

36 elif isinstance(arg1,tuple): 

37 if isshape(arg1): 

38 # it's a tuple of matrix dimensions (M,N) 

39 self._shape = check_shape(arg1) 

40 M,N = self.shape 

41 # process blocksize 

42 if blocksize is None: 

43 blocksize = (1,1) 

44 else: 

45 if not isshape(blocksize): 

46 raise ValueError('invalid blocksize=%s' % blocksize) 

47 blocksize = tuple(blocksize) 

48 self.data = np.zeros((0,) + blocksize, getdtype(dtype, default=float)) 

49 

50 R,C = blocksize 

51 if (M % R) != 0 or (N % C) != 0: 

52 raise ValueError('shape must be multiple of blocksize') 

53 

54 # Select index dtype large enough to pass array and 

55 # scalar parameters to sparsetools 

56 idx_dtype = self._get_index_dtype(maxval=max(M//R, N//C, R, C)) 

57 self.indices = np.zeros(0, dtype=idx_dtype) 

58 self.indptr = np.zeros(M//R + 1, dtype=idx_dtype) 

59 

60 elif len(arg1) == 2: 

61 # (data,(row,col)) format 

62 self._set_self( 

63 self._coo_container(arg1, dtype=dtype, shape=shape).tobsr( 

64 blocksize=blocksize 

65 ) 

66 ) 

67 

68 elif len(arg1) == 3: 

69 # (data,indices,indptr) format 

70 (data, indices, indptr) = arg1 

71 

72 # Select index dtype large enough to pass array and 

73 # scalar parameters to sparsetools 

74 maxval = 1 

75 if shape is not None: 

76 maxval = max(shape) 

77 if blocksize is not None: 

78 maxval = max(maxval, max(blocksize)) 

79 idx_dtype = self._get_index_dtype((indices, indptr), maxval=maxval, 

80 check_contents=True) 

81 self.indices = np.array(indices, copy=copy, dtype=idx_dtype) 

82 self.indptr = np.array(indptr, copy=copy, dtype=idx_dtype) 

83 self.data = getdata(data, copy=copy, dtype=dtype) 

84 if self.data.ndim != 3: 

85 raise ValueError( 

86 'BSR data must be 3-dimensional, got shape={}'.format( 

87 self.data.shape,)) 

88 if blocksize is not None: 

89 if not isshape(blocksize): 

90 raise ValueError(f'invalid blocksize={blocksize}') 

91 if tuple(blocksize) != self.data.shape[1:]: 

92 raise ValueError('mismatching blocksize={} vs {}'.format( 

93 blocksize, self.data.shape[1:])) 

94 else: 

95 raise ValueError('unrecognized bsr_array constructor usage') 

96 else: 

97 # must be dense 

98 try: 

99 arg1 = np.asarray(arg1) 

100 except Exception as e: 

101 raise ValueError("unrecognized form for" 

102 " %s_matrix constructor" % self.format) from e 

103 arg1 = self._coo_container( 

104 arg1, dtype=dtype 

105 ).tobsr(blocksize=blocksize) 

106 self._set_self(arg1) 

107 

108 if shape is not None: 

109 self._shape = check_shape(shape) 

110 else: 

111 if self.shape is None: 

112 # shape not already set, try to infer dimensions 

113 try: 

114 M = len(self.indptr) - 1 

115 N = self.indices.max() + 1 

116 except Exception as e: 

117 raise ValueError('unable to infer matrix dimensions') from e 

118 else: 

119 R,C = self.blocksize 

120 self._shape = check_shape((M*R,N*C)) 

121 

122 if self.shape is None: 

123 if shape is None: 

124 # TODO infer shape here 

125 raise ValueError('need to infer shape') 

126 else: 

127 self._shape = check_shape(shape) 

128 

129 if dtype is not None: 

130 self.data = self.data.astype(dtype, copy=False) 

131 

132 self.check_format(full_check=False) 

133 

134 def check_format(self, full_check=True): 

135 """Check whether the array/matrix respects the BSR format. 

136 

137 Parameters 

138 ---------- 

139 full_check : bool, optional 

140 If `True`, run rigorous check, scanning arrays for valid values. 

141 Note that activating those check might copy arrays for casting, 

142 modifying indices and index pointers' inplace. 

143 If `False`, run basic checks on attributes. O(1) operations. 

144 Default is `True`. 

145 """ 

146 M,N = self.shape 

147 R,C = self.blocksize 

148 

149 # index arrays should have integer data types 

150 if self.indptr.dtype.kind != 'i': 

151 warn("indptr array has non-integer dtype (%s)" 

152 % self.indptr.dtype.name) 

153 if self.indices.dtype.kind != 'i': 

154 warn("indices array has non-integer dtype (%s)" 

155 % self.indices.dtype.name) 

156 

157 # check array shapes 

158 if self.indices.ndim != 1 or self.indptr.ndim != 1: 

159 raise ValueError("indices, and indptr should be 1-D") 

160 if self.data.ndim != 3: 

161 raise ValueError("data should be 3-D") 

162 

163 # check index pointer 

164 if (len(self.indptr) != M//R + 1): 

165 raise ValueError("index pointer size (%d) should be (%d)" % 

166 (len(self.indptr), M//R + 1)) 

167 if (self.indptr[0] != 0): 

168 raise ValueError("index pointer should start with 0") 

169 

170 # check index and data arrays 

171 if (len(self.indices) != len(self.data)): 

172 raise ValueError("indices and data should have the same size") 

173 if (self.indptr[-1] > len(self.indices)): 

174 raise ValueError("Last value of index pointer should be less than " 

175 "the size of index and data arrays") 

176 

177 self.prune() 

178 

179 if full_check: 

180 # check format validity (more expensive) 

181 if self.nnz > 0: 

182 if self.indices.max() >= N//C: 

183 raise ValueError("column index values must be < %d (now max %d)" % (N//C, self.indices.max())) 

184 if self.indices.min() < 0: 

185 raise ValueError("column index values must be >= 0") 

186 if np.diff(self.indptr).min() < 0: 

187 raise ValueError("index pointer values must form a " 

188 "non-decreasing sequence") 

189 

190 idx_dtype = self._get_index_dtype((self.indices, self.indptr)) 

191 self.indptr = np.asarray(self.indptr, dtype=idx_dtype) 

192 self.indices = np.asarray(self.indices, dtype=idx_dtype) 

193 self.data = to_native(self.data) 

194 # if not self.has_sorted_indices(): 

195 # warn('Indices were not in sorted order. Sorting indices.') 

196 # self.sort_indices(check_first=False) 

197 

198 @property 

199 def blocksize(self) -> tuple: 

200 """Block size of the matrix.""" 

201 return self.data.shape[1:] 

202 

203 def _getnnz(self, axis=None): 

204 if axis is not None: 

205 raise NotImplementedError("_getnnz over an axis is not implemented " 

206 "for BSR format") 

207 R,C = self.blocksize 

208 return int(self.indptr[-1] * R * C) 

209 

210 _getnnz.__doc__ = _spbase._getnnz.__doc__ 

211 

212 def __repr__(self): 

213 format = _formats[self.format][1] 

214 return ("<%dx%d sparse matrix of type '%s'\n" 

215 "\twith %d stored elements (blocksize = %dx%d) in %s format>" % 

216 (self.shape + (self.dtype.type, self.nnz) + self.blocksize + 

217 (format,))) 

218 

219 def diagonal(self, k=0): 

220 rows, cols = self.shape 

221 if k <= -rows or k >= cols: 

222 return np.empty(0, dtype=self.data.dtype) 

223 R, C = self.blocksize 

224 y = np.zeros(min(rows + min(k, 0), cols - max(k, 0)), 

225 dtype=upcast(self.dtype)) 

226 _sparsetools.bsr_diagonal(k, rows // R, cols // C, R, C, 

227 self.indptr, self.indices, 

228 np.ravel(self.data), y) 

229 return y 

230 

231 diagonal.__doc__ = _spbase.diagonal.__doc__ 

232 

233 ########################## 

234 # NotImplemented methods # 

235 ########################## 

236 

237 def __getitem__(self,key): 

238 raise NotImplementedError 

239 

240 def __setitem__(self,key,val): 

241 raise NotImplementedError 

242 

243 ###################### 

244 # Arithmetic methods # 

245 ###################### 

246 

247 def _add_dense(self, other): 

248 return self.tocoo(copy=False)._add_dense(other) 

249 

250 def _mul_vector(self, other): 

251 M,N = self.shape 

252 R,C = self.blocksize 

253 

254 result = np.zeros(self.shape[0], dtype=upcast(self.dtype, other.dtype)) 

255 

256 bsr_matvec(M//R, N//C, R, C, 

257 self.indptr, self.indices, self.data.ravel(), 

258 other, result) 

259 

260 return result 

261 

262 def _mul_multivector(self,other): 

263 R,C = self.blocksize 

264 M,N = self.shape 

265 n_vecs = other.shape[1] # number of column vectors 

266 

267 result = np.zeros((M,n_vecs), dtype=upcast(self.dtype,other.dtype)) 

268 

269 bsr_matvecs(M//R, N//C, n_vecs, R, C, 

270 self.indptr, self.indices, self.data.ravel(), 

271 other.ravel(), result.ravel()) 

272 

273 return result 

274 

275 def _mul_sparse_matrix(self, other): 

276 M, K1 = self.shape 

277 K2, N = other.shape 

278 

279 R,n = self.blocksize 

280 

281 # convert to this format 

282 if other.format == "bsr": 

283 C = other.blocksize[1] 

284 else: 

285 C = 1 

286 

287 if other.format == "csr" and n == 1: 

288 other = other.tobsr(blocksize=(n,C), copy=False) # lightweight conversion 

289 else: 

290 other = other.tobsr(blocksize=(n,C)) 

291 

292 idx_dtype = self._get_index_dtype((self.indptr, self.indices, 

293 other.indptr, other.indices)) 

294 

295 bnnz = csr_matmat_maxnnz(M//R, N//C, 

296 self.indptr.astype(idx_dtype), 

297 self.indices.astype(idx_dtype), 

298 other.indptr.astype(idx_dtype), 

299 other.indices.astype(idx_dtype)) 

300 

301 idx_dtype = self._get_index_dtype((self.indptr, self.indices, 

302 other.indptr, other.indices), 

303 maxval=bnnz) 

304 indptr = np.empty(self.indptr.shape, dtype=idx_dtype) 

305 indices = np.empty(bnnz, dtype=idx_dtype) 

306 data = np.empty(R*C*bnnz, dtype=upcast(self.dtype,other.dtype)) 

307 

308 bsr_matmat(bnnz, M//R, N//C, R, C, n, 

309 self.indptr.astype(idx_dtype), 

310 self.indices.astype(idx_dtype), 

311 np.ravel(self.data), 

312 other.indptr.astype(idx_dtype), 

313 other.indices.astype(idx_dtype), 

314 np.ravel(other.data), 

315 indptr, 

316 indices, 

317 data) 

318 

319 data = data.reshape(-1,R,C) 

320 

321 # TODO eliminate zeros 

322 

323 return self._bsr_container( 

324 (data, indices, indptr), shape=(M, N), blocksize=(R, C) 

325 ) 

326 

327 ###################### 

328 # Conversion methods # 

329 ###################### 

330 

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

332 """Convert this array/matrix into Block Sparse Row Format. 

333 

334 With copy=False, the data/indices may be shared between this 

335 array/matrix and the resultant bsr_array/bsr_matrix. 

336 

337 If blocksize=(R, C) is provided, it will be used for determining 

338 block size of the bsr_array/bsr_matrix. 

339 """ 

340 if blocksize not in [None, self.blocksize]: 

341 return self.tocsr().tobsr(blocksize=blocksize) 

342 if copy: 

343 return self.copy() 

344 else: 

345 return self 

346 

347 def tocsr(self, copy=False): 

348 M, N = self.shape 

349 R, C = self.blocksize 

350 nnz = self.nnz 

351 idx_dtype = self._get_index_dtype((self.indptr, self.indices), 

352 maxval=max(nnz, N)) 

353 indptr = np.empty(M + 1, dtype=idx_dtype) 

354 indices = np.empty(nnz, dtype=idx_dtype) 

355 data = np.empty(nnz, dtype=upcast(self.dtype)) 

356 

357 bsr_tocsr(M // R, # n_brow 

358 N // C, # n_bcol 

359 R, C, 

360 self.indptr.astype(idx_dtype, copy=False), 

361 self.indices.astype(idx_dtype, copy=False), 

362 self.data, 

363 indptr, 

364 indices, 

365 data) 

366 return self._csr_container((data, indices, indptr), shape=self.shape) 

367 

368 tocsr.__doc__ = _spbase.tocsr.__doc__ 

369 

370 def tocsc(self, copy=False): 

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

372 

373 tocsc.__doc__ = _spbase.tocsc.__doc__ 

374 

375 def tocoo(self, copy=True): 

376 """Convert this array/matrix to COOrdinate format. 

377 

378 When copy=False the data array will be shared between 

379 this array/matrix and the resultant coo_array/coo_matrix. 

380 """ 

381 

382 M,N = self.shape 

383 R,C = self.blocksize 

384 

385 indptr_diff = np.diff(self.indptr) 

386 if indptr_diff.dtype.itemsize > np.dtype(np.intp).itemsize: 

387 # Check for potential overflow 

388 indptr_diff_limited = indptr_diff.astype(np.intp) 

389 if np.any(indptr_diff_limited != indptr_diff): 

390 raise ValueError("Matrix too big to convert") 

391 indptr_diff = indptr_diff_limited 

392 

393 idx_dtype = self._get_index_dtype(maxval=max(M, N)) 

394 row = (R * np.arange(M//R, dtype=idx_dtype)).repeat(indptr_diff) 

395 row = row.repeat(R*C).reshape(-1,R,C) 

396 row += np.tile(np.arange(R, dtype=idx_dtype).reshape(-1,1), (1,C)) 

397 row = row.reshape(-1) 

398 

399 col = (C * self.indices).astype(idx_dtype, copy=False).repeat(R*C).reshape(-1,R,C) 

400 col += np.tile(np.arange(C, dtype=idx_dtype), (R,1)) 

401 col = col.reshape(-1) 

402 

403 data = self.data.reshape(-1) 

404 

405 if copy: 

406 data = data.copy() 

407 

408 return self._coo_container( 

409 (data, (row, col)), shape=self.shape 

410 ) 

411 

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

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

414 

415 toarray.__doc__ = _spbase.toarray.__doc__ 

416 

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

418 if axes is not None and axes != (1, 0): 

419 raise ValueError("Sparse matrices do not support " 

420 "an 'axes' parameter because swapping " 

421 "dimensions is the only logical permutation.") 

422 

423 R, C = self.blocksize 

424 M, N = self.shape 

425 NBLK = self.nnz//(R*C) 

426 

427 if self.nnz == 0: 

428 return self._bsr_container((N, M), blocksize=(C, R), 

429 dtype=self.dtype, copy=copy) 

430 

431 indptr = np.empty(N//C + 1, dtype=self.indptr.dtype) 

432 indices = np.empty(NBLK, dtype=self.indices.dtype) 

433 data = np.empty((NBLK, C, R), dtype=self.data.dtype) 

434 

435 bsr_transpose(M//R, N//C, R, C, 

436 self.indptr, self.indices, self.data.ravel(), 

437 indptr, indices, data.ravel()) 

438 

439 return self._bsr_container((data, indices, indptr), 

440 shape=(N, M), copy=copy) 

441 

442 transpose.__doc__ = _spbase.transpose.__doc__ 

443 

444 ############################################################## 

445 # methods that examine or modify the internal data structure # 

446 ############################################################## 

447 

448 def eliminate_zeros(self): 

449 """Remove zero elements in-place.""" 

450 

451 if not self.nnz: 

452 return # nothing to do 

453 

454 R,C = self.blocksize 

455 M,N = self.shape 

456 

457 mask = (self.data != 0).reshape(-1,R*C).sum(axis=1) # nonzero blocks 

458 

459 nonzero_blocks = mask.nonzero()[0] 

460 

461 self.data[:len(nonzero_blocks)] = self.data[nonzero_blocks] 

462 

463 # modifies self.indptr and self.indices *in place* 

464 _sparsetools.csr_eliminate_zeros(M//R, N//C, self.indptr, 

465 self.indices, mask) 

466 self.prune() 

467 

468 def sum_duplicates(self): 

469 """Eliminate duplicate array/matrix entries by adding them together 

470 

471 The is an *in place* operation 

472 """ 

473 if self.has_canonical_format: 

474 return 

475 self.sort_indices() 

476 R, C = self.blocksize 

477 M, N = self.shape 

478 

479 # port of _sparsetools.csr_sum_duplicates 

480 n_row = M // R 

481 nnz = 0 

482 row_end = 0 

483 for i in range(n_row): 

484 jj = row_end 

485 row_end = self.indptr[i+1] 

486 while jj < row_end: 

487 j = self.indices[jj] 

488 x = self.data[jj] 

489 jj += 1 

490 while jj < row_end and self.indices[jj] == j: 

491 x += self.data[jj] 

492 jj += 1 

493 self.indices[nnz] = j 

494 self.data[nnz] = x 

495 nnz += 1 

496 self.indptr[i+1] = nnz 

497 

498 self.prune() # nnz may have changed 

499 self.has_canonical_format = True 

500 

501 def sort_indices(self): 

502 """Sort the indices of this array/matrix *in place* 

503 """ 

504 if self.has_sorted_indices: 

505 return 

506 

507 R,C = self.blocksize 

508 M,N = self.shape 

509 

510 bsr_sort_indices(M//R, N//C, R, C, self.indptr, self.indices, self.data.ravel()) 

511 

512 self.has_sorted_indices = True 

513 

514 def prune(self): 

515 """Remove empty space after all non-zero elements. 

516 """ 

517 

518 R,C = self.blocksize 

519 M,N = self.shape 

520 

521 if len(self.indptr) != M//R + 1: 

522 raise ValueError("index pointer has invalid length") 

523 

524 bnnz = self.indptr[-1] 

525 

526 if len(self.indices) < bnnz: 

527 raise ValueError("indices array has too few elements") 

528 if len(self.data) < bnnz: 

529 raise ValueError("data array has too few elements") 

530 

531 self.data = self.data[:bnnz] 

532 self.indices = self.indices[:bnnz] 

533 

534 # utility functions 

535 def _binopt(self, other, op, in_shape=None, out_shape=None): 

536 """Apply the binary operation fn to two sparse matrices.""" 

537 

538 # Ideally we'd take the GCDs of the blocksize dimensions 

539 # and explode self and other to match. 

540 other = self.__class__(other, blocksize=self.blocksize) 

541 

542 # e.g. bsr_plus_bsr, etc. 

543 fn = getattr(_sparsetools, self.format + op + self.format) 

544 

545 R,C = self.blocksize 

546 

547 max_bnnz = len(self.data) + len(other.data) 

548 idx_dtype = self._get_index_dtype((self.indptr, self.indices, 

549 other.indptr, other.indices), 

550 maxval=max_bnnz) 

551 indptr = np.empty(self.indptr.shape, dtype=idx_dtype) 

552 indices = np.empty(max_bnnz, dtype=idx_dtype) 

553 

554 bool_ops = ['_ne_', '_lt_', '_gt_', '_le_', '_ge_'] 

555 if op in bool_ops: 

556 data = np.empty(R*C*max_bnnz, dtype=np.bool_) 

557 else: 

558 data = np.empty(R*C*max_bnnz, dtype=upcast(self.dtype,other.dtype)) 

559 

560 fn(self.shape[0]//R, self.shape[1]//C, R, C, 

561 self.indptr.astype(idx_dtype), 

562 self.indices.astype(idx_dtype), 

563 self.data, 

564 other.indptr.astype(idx_dtype), 

565 other.indices.astype(idx_dtype), 

566 np.ravel(other.data), 

567 indptr, 

568 indices, 

569 data) 

570 

571 actual_bnnz = indptr[-1] 

572 indices = indices[:actual_bnnz] 

573 data = data[:R*C*actual_bnnz] 

574 

575 if actual_bnnz < max_bnnz/2: 

576 indices = indices.copy() 

577 data = data.copy() 

578 

579 data = data.reshape(-1,R,C) 

580 

581 return self.__class__((data, indices, indptr), shape=self.shape) 

582 

583 # needed by _data_matrix 

584 def _with_data(self,data,copy=True): 

585 """Returns a matrix with the same sparsity structure as self, 

586 but with different data. By default the structure arrays 

587 (i.e. .indptr and .indices) are copied. 

588 """ 

589 if copy: 

590 return self.__class__((data,self.indices.copy(),self.indptr.copy()), 

591 shape=self.shape,dtype=data.dtype) 

592 else: 

593 return self.__class__((data,self.indices,self.indptr), 

594 shape=self.shape,dtype=data.dtype) 

595 

596# # these functions are used by the parent class 

597# # to remove redudancy between bsc_matrix and bsr_matrix 

598# def _swap(self,x): 

599# """swap the members of x if this is a column-oriented matrix 

600# """ 

601# return (x[0],x[1]) 

602 

603 

604def isspmatrix_bsr(x): 

605 """Is `x` of a bsr_matrix type? 

606 

607 Parameters 

608 ---------- 

609 x 

610 object to check for being a bsr matrix 

611 

612 Returns 

613 ------- 

614 bool 

615 True if `x` is a bsr matrix, False otherwise 

616 

617 Examples 

618 -------- 

619 >>> from scipy.sparse import bsr_array, bsr_matrix, csr_matrix, isspmatrix_bsr 

620 >>> isspmatrix_bsr(bsr_matrix([[5]])) 

621 True 

622 >>> isspmatrix_bsr(bsr_array([[5]])) 

623 False 

624 >>> isspmatrix_bsr(csr_matrix([[5]])) 

625 False 

626 """ 

627 return isinstance(x, bsr_matrix) 

628 

629 

630# This namespace class separates array from matrix with isinstance 

631class bsr_array(_bsr_base, sparray): 

632 """ 

633 Block Sparse Row format sparse array. 

634 

635 This can be instantiated in several ways: 

636 bsr_array(D, [blocksize=(R,C)]) 

637 where D is a 2-D ndarray. 

638 

639 bsr_array(S, [blocksize=(R,C)]) 

640 with another sparse array or matrix S (equivalent to S.tobsr()) 

641 

642 bsr_array((M, N), [blocksize=(R,C), dtype]) 

643 to construct an empty sparse array with shape (M, N) 

644 dtype is optional, defaulting to dtype='d'. 

645 

646 bsr_array((data, ij), [blocksize=(R,C), shape=(M, N)]) 

647 where ``data`` and ``ij`` satisfy ``a[ij[0, k], ij[1, k]] = data[k]`` 

648 

649 bsr_array((data, indices, indptr), [shape=(M, N)]) 

650 is the standard BSR representation where the block column 

651 indices for row i are stored in ``indices[indptr[i]:indptr[i+1]]`` 

652 and their corresponding block values are stored in 

653 ``data[ indptr[i]: indptr[i+1] ]``. If the shape parameter is not 

654 supplied, the array dimensions are inferred from the index arrays. 

655 

656 Attributes 

657 ---------- 

658 dtype : dtype 

659 Data type of the array 

660 shape : 2-tuple 

661 Shape of the array 

662 ndim : int 

663 Number of dimensions (this is always 2) 

664 nnz 

665 size 

666 data 

667 BSR format data array of the array 

668 indices 

669 BSR format index array of the array 

670 indptr 

671 BSR format index pointer array of the array 

672 blocksize 

673 Block size 

674 has_sorted_indices : bool 

675 Whether indices are sorted 

676 has_canonical_format : bool 

677 T 

678 

679 Notes 

680 ----- 

681 Sparse arrays can be used in arithmetic operations: they support 

682 addition, subtraction, multiplication, division, and matrix power. 

683 

684 **Summary of BSR format** 

685 

686 The Block Sparse Row (BSR) format is very similar to the Compressed 

687 Sparse Row (CSR) format. BSR is appropriate for sparse matrices with dense 

688 sub matrices like the last example below. Such sparse block matrices often 

689 arise in vector-valued finite element discretizations. In such cases, BSR is 

690 considerably more efficient than CSR and CSC for many sparse arithmetic 

691 operations. 

692 

693 **Blocksize** 

694 

695 The blocksize (R,C) must evenly divide the shape of the sparse array (M,N). 

696 That is, R and C must satisfy the relationship ``M % R = 0`` and 

697 ``N % C = 0``. 

698 

699 If no blocksize is specified, a simple heuristic is applied to determine 

700 an appropriate blocksize. 

701 

702 **Canonical Format** 

703 

704 In canonical format, there are no duplicate blocks and indices are sorted 

705 per row. 

706 

707 Examples 

708 -------- 

709 >>> import numpy as np 

710 >>> from scipy.sparse import bsr_array 

711 >>> bsr_array((3, 4), dtype=np.int8).toarray() 

712 array([[0, 0, 0, 0], 

713 [0, 0, 0, 0], 

714 [0, 0, 0, 0]], dtype=int8) 

715 

716 >>> row = np.array([0, 0, 1, 2, 2, 2]) 

717 >>> col = np.array([0, 2, 2, 0, 1, 2]) 

718 >>> data = np.array([1, 2, 3 ,4, 5, 6]) 

719 >>> bsr_array((data, (row, col)), shape=(3, 3)).toarray() 

720 array([[1, 0, 2], 

721 [0, 0, 3], 

722 [4, 5, 6]]) 

723 

724 >>> indptr = np.array([0, 2, 3, 6]) 

725 >>> indices = np.array([0, 2, 2, 0, 1, 2]) 

726 >>> data = np.array([1, 2, 3, 4, 5, 6]).repeat(4).reshape(6, 2, 2) 

727 >>> bsr_array((data,indices,indptr), shape=(6, 6)).toarray() 

728 array([[1, 1, 0, 0, 2, 2], 

729 [1, 1, 0, 0, 2, 2], 

730 [0, 0, 0, 0, 3, 3], 

731 [0, 0, 0, 0, 3, 3], 

732 [4, 4, 5, 5, 6, 6], 

733 [4, 4, 5, 5, 6, 6]]) 

734 

735 """ 

736 

737 

738class bsr_matrix(spmatrix, _bsr_base): 

739 """ 

740 Block Sparse Row format sparse matrix. 

741 

742 This can be instantiated in several ways: 

743 bsr_matrix(D, [blocksize=(R,C)]) 

744 where D is a 2-D ndarray. 

745 

746 bsr_matrix(S, [blocksize=(R,C)]) 

747 with another sparse array or matrix S (equivalent to S.tobsr()) 

748 

749 bsr_matrix((M, N), [blocksize=(R,C), dtype]) 

750 to construct an empty sparse matrix with shape (M, N) 

751 dtype is optional, defaulting to dtype='d'. 

752 

753 bsr_matrix((data, ij), [blocksize=(R,C), shape=(M, N)]) 

754 where ``data`` and ``ij`` satisfy ``a[ij[0, k], ij[1, k]] = data[k]`` 

755 

756 bsr_matrix((data, indices, indptr), [shape=(M, N)]) 

757 is the standard BSR representation where the block column 

758 indices for row i are stored in ``indices[indptr[i]:indptr[i+1]]`` 

759 and their corresponding block values are stored in 

760 ``data[ indptr[i]: indptr[i+1] ]``. If the shape parameter is not 

761 supplied, the matrix dimensions are inferred from the index arrays. 

762 

763 Attributes 

764 ---------- 

765 dtype : dtype 

766 Data type of the matrix 

767 shape : 2-tuple 

768 Shape of the matrix 

769 ndim : int 

770 Number of dimensions (this is always 2) 

771 nnz 

772 size 

773 data 

774 BSR format data array of the matrix 

775 indices 

776 BSR format index array of the matrix 

777 indptr 

778 BSR format index pointer array of the matrix 

779 blocksize 

780 Block size 

781 has_sorted_indices : bool 

782 Whether indices are sorted 

783 has_canonical_format : bool 

784 T 

785 

786 Notes 

787 ----- 

788 Sparse matrices can be used in arithmetic operations: they support 

789 addition, subtraction, multiplication, division, and matrix power. 

790 

791 **Summary of BSR format** 

792 

793 The Block Sparse Row (BSR) format is very similar to the Compressed 

794 Sparse Row (CSR) format. BSR is appropriate for sparse matrices with dense 

795 sub matrices like the last example below. Such sparse block matrices often 

796 arise in vector-valued finite element discretizations. In such cases, BSR is 

797 considerably more efficient than CSR and CSC for many sparse arithmetic 

798 operations. 

799 

800 **Blocksize** 

801 

802 The blocksize (R,C) must evenly divide the shape of the sparse matrix (M,N). 

803 That is, R and C must satisfy the relationship ``M % R = 0`` and 

804 ``N % C = 0``. 

805 

806 If no blocksize is specified, a simple heuristic is applied to determine 

807 an appropriate blocksize. 

808 

809 **Canonical Format** 

810 

811 In canonical format, there are no duplicate blocks and indices are sorted 

812 per row. 

813 

814 Examples 

815 -------- 

816 >>> import numpy as np 

817 >>> from scipy.sparse import bsr_matrix 

818 >>> bsr_matrix((3, 4), dtype=np.int8).toarray() 

819 array([[0, 0, 0, 0], 

820 [0, 0, 0, 0], 

821 [0, 0, 0, 0]], dtype=int8) 

822 

823 >>> row = np.array([0, 0, 1, 2, 2, 2]) 

824 >>> col = np.array([0, 2, 2, 0, 1, 2]) 

825 >>> data = np.array([1, 2, 3 ,4, 5, 6]) 

826 >>> bsr_matrix((data, (row, col)), shape=(3, 3)).toarray() 

827 array([[1, 0, 2], 

828 [0, 0, 3], 

829 [4, 5, 6]]) 

830 

831 >>> indptr = np.array([0, 2, 3, 6]) 

832 >>> indices = np.array([0, 2, 2, 0, 1, 2]) 

833 >>> data = np.array([1, 2, 3, 4, 5, 6]).repeat(4).reshape(6, 2, 2) 

834 >>> bsr_matrix((data,indices,indptr), shape=(6, 6)).toarray() 

835 array([[1, 1, 0, 0, 2, 2], 

836 [1, 1, 0, 0, 2, 2], 

837 [0, 0, 0, 0, 3, 3], 

838 [0, 0, 0, 0, 3, 3], 

839 [4, 4, 5, 5, 6, 6], 

840 [4, 4, 5, 5, 6, 6]]) 

841 

842 """ 

843