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

315 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-14 06:37 +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 f'BSR data must be 3-dimensional, got shape={self.data.shape}' 

87 ) 

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(f"indptr array has non-integer dtype ({self.indptr.dtype.name})", 

152 stacklevel=2) 

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

154 warn(f"indices array has non-integer dtype ({self.indices.dtype.name})", 

155 stacklevel=2) 

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)" 

184 % (N//C, self.indices.max())) 

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

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

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

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

189 "non-decreasing sequence") 

190 

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

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

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

194 self.data = to_native(self.data) 

195 # if not self.has_sorted_indices(): 

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

197 # self.sort_indices(check_first=False) 

198 

199 @property 

200 def blocksize(self) -> tuple: 

201 """Block size of the matrix.""" 

202 return self.data.shape[1:] 

203 

204 def _getnnz(self, axis=None): 

205 if axis is not None: 

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

207 "for BSR format") 

208 R,C = self.blocksize 

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

210 

211 _getnnz.__doc__ = _spbase._getnnz.__doc__ 

212 

213 def __repr__(self): 

214 _, fmt = _formats[self.format] 

215 sparse_cls = 'array' if isinstance(self, sparray) else 'matrix' 

216 shape_str = 'x'.join(str(x) for x in self.shape) 

217 blksz = 'x'.join(str(x) for x in self.blocksize) 

218 return ( 

219 f"<{shape_str} sparse {sparse_cls} of type '{self.dtype.type}'\n" 

220 f"\twith {self.nnz} stored elements (blocksize = {blksz}) in {fmt} format>" 

221 ) 

222 

223 def diagonal(self, k=0): 

224 rows, cols = self.shape 

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

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

227 R, C = self.blocksize 

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

229 dtype=upcast(self.dtype)) 

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

231 self.indptr, self.indices, 

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

233 return y 

234 

235 diagonal.__doc__ = _spbase.diagonal.__doc__ 

236 

237 ########################## 

238 # NotImplemented methods # 

239 ########################## 

240 

241 def __getitem__(self,key): 

242 raise NotImplementedError 

243 

244 def __setitem__(self,key,val): 

245 raise NotImplementedError 

246 

247 ###################### 

248 # Arithmetic methods # 

249 ###################### 

250 

251 def _add_dense(self, other): 

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

253 

254 def _matmul_vector(self, other): 

255 M,N = self.shape 

256 R,C = self.blocksize 

257 

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

259 

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

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

262 other, result) 

263 

264 return result 

265 

266 def _matmul_multivector(self,other): 

267 R,C = self.blocksize 

268 M,N = self.shape 

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

270 

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

272 

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

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

275 other.ravel(), result.ravel()) 

276 

277 return result 

278 

279 def _matmul_sparse(self, other): 

280 M, K1 = self.shape 

281 K2, N = other.shape 

282 

283 R,n = self.blocksize 

284 

285 # convert to this format 

286 if other.format == "bsr": 

287 C = other.blocksize[1] 

288 else: 

289 C = 1 

290 

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

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

293 else: 

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

295 

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

297 other.indptr, other.indices)) 

298 

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

300 self.indptr.astype(idx_dtype), 

301 self.indices.astype(idx_dtype), 

302 other.indptr.astype(idx_dtype), 

303 other.indices.astype(idx_dtype)) 

304 

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

306 other.indptr, other.indices), 

307 maxval=bnnz) 

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

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

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

311 

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

313 self.indptr.astype(idx_dtype), 

314 self.indices.astype(idx_dtype), 

315 np.ravel(self.data), 

316 other.indptr.astype(idx_dtype), 

317 other.indices.astype(idx_dtype), 

318 np.ravel(other.data), 

319 indptr, 

320 indices, 

321 data) 

322 

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

324 

325 # TODO eliminate zeros 

326 

327 return self._bsr_container( 

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

329 ) 

330 

331 ###################### 

332 # Conversion methods # 

333 ###################### 

334 

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

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

337 

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

339 array/matrix and the resultant bsr_array/bsr_matrix. 

340 

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

342 block size of the bsr_array/bsr_matrix. 

343 """ 

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

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

346 if copy: 

347 return self.copy() 

348 else: 

349 return self 

350 

351 def tocsr(self, copy=False): 

352 M, N = self.shape 

353 R, C = self.blocksize 

354 nnz = self.nnz 

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

356 maxval=max(nnz, N)) 

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

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

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

360 

361 bsr_tocsr(M // R, # n_brow 

362 N // C, # n_bcol 

363 R, C, 

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

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

366 self.data, 

367 indptr, 

368 indices, 

369 data) 

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

371 

372 tocsr.__doc__ = _spbase.tocsr.__doc__ 

373 

374 def tocsc(self, copy=False): 

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

376 

377 tocsc.__doc__ = _spbase.tocsc.__doc__ 

378 

379 def tocoo(self, copy=True): 

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

381 

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

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

384 """ 

385 

386 M,N = self.shape 

387 R,C = self.blocksize 

388 

389 indptr_diff = np.diff(self.indptr) 

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

391 # Check for potential overflow 

392 indptr_diff_limited = indptr_diff.astype(np.intp) 

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

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

395 indptr_diff = indptr_diff_limited 

396 

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

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

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

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

401 row = row.reshape(-1) 

402 

403 col = ((C * self.indices).astype(idx_dtype, copy=False) 

404 .repeat(R*C).reshape(-1,R,C)) 

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

406 col = col.reshape(-1) 

407 

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

409 

410 if copy: 

411 data = data.copy() 

412 

413 return self._coo_container( 

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

415 ) 

416 

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

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

419 

420 toarray.__doc__ = _spbase.toarray.__doc__ 

421 

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

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

424 raise ValueError("Sparse matrices do not support " 

425 "an 'axes' parameter because swapping " 

426 "dimensions is the only logical permutation.") 

427 

428 R, C = self.blocksize 

429 M, N = self.shape 

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

431 

432 if self.nnz == 0: 

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

434 dtype=self.dtype, copy=copy) 

435 

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

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

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

439 

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

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

442 indptr, indices, data.ravel()) 

443 

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

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

446 

447 transpose.__doc__ = _spbase.transpose.__doc__ 

448 

449 ############################################################## 

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

451 ############################################################## 

452 

453 def eliminate_zeros(self): 

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

455 

456 if not self.nnz: 

457 return # nothing to do 

458 

459 R,C = self.blocksize 

460 M,N = self.shape 

461 

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

463 

464 nonzero_blocks = mask.nonzero()[0] 

465 

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

467 

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

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

470 self.indices, mask) 

471 self.prune() 

472 

473 def sum_duplicates(self): 

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

475 

476 The is an *in place* operation 

477 """ 

478 if self.has_canonical_format: 

479 return 

480 self.sort_indices() 

481 R, C = self.blocksize 

482 M, N = self.shape 

483 

484 # port of _sparsetools.csr_sum_duplicates 

485 n_row = M // R 

486 nnz = 0 

487 row_end = 0 

488 for i in range(n_row): 

489 jj = row_end 

490 row_end = self.indptr[i+1] 

491 while jj < row_end: 

492 j = self.indices[jj] 

493 x = self.data[jj] 

494 jj += 1 

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

496 x += self.data[jj] 

497 jj += 1 

498 self.indices[nnz] = j 

499 self.data[nnz] = x 

500 nnz += 1 

501 self.indptr[i+1] = nnz 

502 

503 self.prune() # nnz may have changed 

504 self.has_canonical_format = True 

505 

506 def sort_indices(self): 

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

508 """ 

509 if self.has_sorted_indices: 

510 return 

511 

512 R,C = self.blocksize 

513 M,N = self.shape 

514 

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

516 

517 self.has_sorted_indices = True 

518 

519 def prune(self): 

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

521 """ 

522 

523 R,C = self.blocksize 

524 M,N = self.shape 

525 

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

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

528 

529 bnnz = self.indptr[-1] 

530 

531 if len(self.indices) < bnnz: 

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

533 if len(self.data) < bnnz: 

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

535 

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

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

538 

539 # utility functions 

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

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

542 

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

544 # and explode self and other to match. 

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

546 

547 # e.g. bsr_plus_bsr, etc. 

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

549 

550 R,C = self.blocksize 

551 

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

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

554 other.indptr, other.indices), 

555 maxval=max_bnnz) 

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

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

558 

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

560 if op in bool_ops: 

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

562 else: 

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

564 

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

566 self.indptr.astype(idx_dtype), 

567 self.indices.astype(idx_dtype), 

568 self.data, 

569 other.indptr.astype(idx_dtype), 

570 other.indices.astype(idx_dtype), 

571 np.ravel(other.data), 

572 indptr, 

573 indices, 

574 data) 

575 

576 actual_bnnz = indptr[-1] 

577 indices = indices[:actual_bnnz] 

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

579 

580 if actual_bnnz < max_bnnz/2: 

581 indices = indices.copy() 

582 data = data.copy() 

583 

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

585 

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

587 

588 # needed by _data_matrix 

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

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

591 but with different data. By default the structure arrays 

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

593 """ 

594 if copy: 

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

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

597 else: 

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

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

600 

601# # these functions are used by the parent class 

602# # to remove redundancy between bsc_matrix and bsr_matrix 

603# def _swap(self,x): 

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

605# """ 

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

607 

608 

609def isspmatrix_bsr(x): 

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

611 

612 Parameters 

613 ---------- 

614 x 

615 object to check for being a bsr matrix 

616 

617 Returns 

618 ------- 

619 bool 

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

621 

622 Examples 

623 -------- 

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

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

626 True 

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

628 False 

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

630 False 

631 """ 

632 return isinstance(x, bsr_matrix) 

633 

634 

635# This namespace class separates array from matrix with isinstance 

636class bsr_array(_bsr_base, sparray): 

637 """ 

638 Block Sparse Row format sparse array. 

639 

640 This can be instantiated in several ways: 

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

642 where D is a 2-D ndarray. 

643 

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

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

646 

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

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

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

650 

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

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

653 

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

655 is the standard BSR representation where the block column 

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

657 and their corresponding block values are stored in 

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

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

660 

661 Attributes 

662 ---------- 

663 dtype : dtype 

664 Data type of the array 

665 shape : 2-tuple 

666 Shape of the array 

667 ndim : int 

668 Number of dimensions (this is always 2) 

669 nnz 

670 size 

671 data 

672 BSR format data array of the array 

673 indices 

674 BSR format index array of the array 

675 indptr 

676 BSR format index pointer array of the array 

677 blocksize 

678 Block size 

679 has_sorted_indices : bool 

680 Whether indices are sorted 

681 has_canonical_format : bool 

682 T 

683 

684 Notes 

685 ----- 

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

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

688 

689 **Summary of BSR format** 

690 

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

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

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

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

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

696 operations. 

697 

698 **Blocksize** 

699 

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

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

702 ``N % C = 0``. 

703 

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

705 an appropriate blocksize. 

706 

707 **Canonical Format** 

708 

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

710 per row. 

711 

712 Examples 

713 -------- 

714 >>> import numpy as np 

715 >>> from scipy.sparse import bsr_array 

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

717 array([[0, 0, 0, 0], 

718 [0, 0, 0, 0], 

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

720 

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

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

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

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

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

726 [0, 0, 3], 

727 [4, 5, 6]]) 

728 

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

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

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

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

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

734 [1, 1, 0, 0, 2, 2], 

735 [0, 0, 0, 0, 3, 3], 

736 [0, 0, 0, 0, 3, 3], 

737 [4, 4, 5, 5, 6, 6], 

738 [4, 4, 5, 5, 6, 6]]) 

739 

740 """ 

741 

742 

743class bsr_matrix(spmatrix, _bsr_base): 

744 """ 

745 Block Sparse Row format sparse matrix. 

746 

747 This can be instantiated in several ways: 

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

749 where D is a 2-D ndarray. 

750 

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

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

753 

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

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

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

757 

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

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

760 

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

762 is the standard BSR representation where the block column 

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

764 and their corresponding block values are stored in 

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

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

767 

768 Attributes 

769 ---------- 

770 dtype : dtype 

771 Data type of the matrix 

772 shape : 2-tuple 

773 Shape of the matrix 

774 ndim : int 

775 Number of dimensions (this is always 2) 

776 nnz 

777 size 

778 data 

779 BSR format data array of the matrix 

780 indices 

781 BSR format index array of the matrix 

782 indptr 

783 BSR format index pointer array of the matrix 

784 blocksize 

785 Block size 

786 has_sorted_indices : bool 

787 Whether indices are sorted 

788 has_canonical_format : bool 

789 T 

790 

791 Notes 

792 ----- 

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

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

795 

796 **Summary of BSR format** 

797 

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

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

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

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

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

803 operations. 

804 

805 **Blocksize** 

806 

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

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

809 ``N % C = 0``. 

810 

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

812 an appropriate blocksize. 

813 

814 **Canonical Format** 

815 

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

817 per row. 

818 

819 Examples 

820 -------- 

821 >>> import numpy as np 

822 >>> from scipy.sparse import bsr_matrix 

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

824 array([[0, 0, 0, 0], 

825 [0, 0, 0, 0], 

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

827 

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

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

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

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

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

833 [0, 0, 3], 

834 [4, 5, 6]]) 

835 

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

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

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

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

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

841 [1, 1, 0, 0, 2, 2], 

842 [0, 0, 0, 0, 3, 3], 

843 [0, 0, 0, 0, 3, 3], 

844 [4, 4, 5, 5, 6, 6], 

845 [4, 4, 5, 5, 6, 6]]) 

846 

847 """ 

848