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
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-14 06:37 +0000
1"""Compressed Block Sparse Row format"""
3__docformat__ = "restructuredtext en"
5__all__ = ['bsr_array', 'bsr_matrix', 'isspmatrix_bsr']
7from warnings import warn
9import numpy as np
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)
23class _bsr_base(_cs_matrix, _minmax_mixin):
24 _format = 'bsr'
26 def __init__(self, arg1, shape=None, dtype=None, copy=False, blocksize=None):
27 _data_matrix.__init__(self)
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)
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))
50 R,C = blocksize
51 if (M % R) != 0 or (N % C) != 0:
52 raise ValueError('shape must be multiple of blocksize')
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)
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 )
68 elif len(arg1) == 3:
69 # (data,indices,indptr) format
70 (data, indices, indptr) = arg1
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)
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))
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)
129 if dtype is not None:
130 self.data = self.data.astype(dtype, copy=False)
132 self.check_format(full_check=False)
134 def check_format(self, full_check=True):
135 """Check whether the array/matrix respects the BSR format.
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
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)
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")
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")
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")
177 self.prune()
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")
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)
199 @property
200 def blocksize(self) -> tuple:
201 """Block size of the matrix."""
202 return self.data.shape[1:]
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)
211 _getnnz.__doc__ = _spbase._getnnz.__doc__
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 )
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
235 diagonal.__doc__ = _spbase.diagonal.__doc__
237 ##########################
238 # NotImplemented methods #
239 ##########################
241 def __getitem__(self,key):
242 raise NotImplementedError
244 def __setitem__(self,key,val):
245 raise NotImplementedError
247 ######################
248 # Arithmetic methods #
249 ######################
251 def _add_dense(self, other):
252 return self.tocoo(copy=False)._add_dense(other)
254 def _matmul_vector(self, other):
255 M,N = self.shape
256 R,C = self.blocksize
258 result = np.zeros(self.shape[0], dtype=upcast(self.dtype, other.dtype))
260 bsr_matvec(M//R, N//C, R, C,
261 self.indptr, self.indices, self.data.ravel(),
262 other, result)
264 return result
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
271 result = np.zeros((M,n_vecs), dtype=upcast(self.dtype,other.dtype))
273 bsr_matvecs(M//R, N//C, n_vecs, R, C,
274 self.indptr, self.indices, self.data.ravel(),
275 other.ravel(), result.ravel())
277 return result
279 def _matmul_sparse(self, other):
280 M, K1 = self.shape
281 K2, N = other.shape
283 R,n = self.blocksize
285 # convert to this format
286 if other.format == "bsr":
287 C = other.blocksize[1]
288 else:
289 C = 1
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))
296 idx_dtype = self._get_index_dtype((self.indptr, self.indices,
297 other.indptr, other.indices))
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))
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))
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)
323 data = data.reshape(-1,R,C)
325 # TODO eliminate zeros
327 return self._bsr_container(
328 (data, indices, indptr), shape=(M, N), blocksize=(R, C)
329 )
331 ######################
332 # Conversion methods #
333 ######################
335 def tobsr(self, blocksize=None, copy=False):
336 """Convert this array/matrix into Block Sparse Row Format.
338 With copy=False, the data/indices may be shared between this
339 array/matrix and the resultant bsr_array/bsr_matrix.
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
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))
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)
372 tocsr.__doc__ = _spbase.tocsr.__doc__
374 def tocsc(self, copy=False):
375 return self.tocsr(copy=False).tocsc(copy=copy)
377 tocsc.__doc__ = _spbase.tocsc.__doc__
379 def tocoo(self, copy=True):
380 """Convert this array/matrix to COOrdinate format.
382 When copy=False the data array will be shared between
383 this array/matrix and the resultant coo_array/coo_matrix.
384 """
386 M,N = self.shape
387 R,C = self.blocksize
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
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)
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)
408 data = self.data.reshape(-1)
410 if copy:
411 data = data.copy()
413 return self._coo_container(
414 (data, (row, col)), shape=self.shape
415 )
417 def toarray(self, order=None, out=None):
418 return self.tocoo(copy=False).toarray(order=order, out=out)
420 toarray.__doc__ = _spbase.toarray.__doc__
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.")
428 R, C = self.blocksize
429 M, N = self.shape
430 NBLK = self.nnz//(R*C)
432 if self.nnz == 0:
433 return self._bsr_container((N, M), blocksize=(C, R),
434 dtype=self.dtype, copy=copy)
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)
440 bsr_transpose(M//R, N//C, R, C,
441 self.indptr, self.indices, self.data.ravel(),
442 indptr, indices, data.ravel())
444 return self._bsr_container((data, indices, indptr),
445 shape=(N, M), copy=copy)
447 transpose.__doc__ = _spbase.transpose.__doc__
449 ##############################################################
450 # methods that examine or modify the internal data structure #
451 ##############################################################
453 def eliminate_zeros(self):
454 """Remove zero elements in-place."""
456 if not self.nnz:
457 return # nothing to do
459 R,C = self.blocksize
460 M,N = self.shape
462 mask = (self.data != 0).reshape(-1,R*C).sum(axis=1) # nonzero blocks
464 nonzero_blocks = mask.nonzero()[0]
466 self.data[:len(nonzero_blocks)] = self.data[nonzero_blocks]
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()
473 def sum_duplicates(self):
474 """Eliminate duplicate array/matrix entries by adding them together
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
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
503 self.prune() # nnz may have changed
504 self.has_canonical_format = True
506 def sort_indices(self):
507 """Sort the indices of this array/matrix *in place*
508 """
509 if self.has_sorted_indices:
510 return
512 R,C = self.blocksize
513 M,N = self.shape
515 bsr_sort_indices(M//R, N//C, R, C, self.indptr, self.indices, self.data.ravel())
517 self.has_sorted_indices = True
519 def prune(self):
520 """Remove empty space after all non-zero elements.
521 """
523 R,C = self.blocksize
524 M,N = self.shape
526 if len(self.indptr) != M//R + 1:
527 raise ValueError("index pointer has invalid length")
529 bnnz = self.indptr[-1]
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")
536 self.data = self.data[:bnnz]
537 self.indices = self.indices[:bnnz]
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."""
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)
547 # e.g. bsr_plus_bsr, etc.
548 fn = getattr(_sparsetools, self.format + op + self.format)
550 R,C = self.blocksize
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)
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))
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)
576 actual_bnnz = indptr[-1]
577 indices = indices[:actual_bnnz]
578 data = data[:R*C*actual_bnnz]
580 if actual_bnnz < max_bnnz/2:
581 indices = indices.copy()
582 data = data.copy()
584 data = data.reshape(-1,R,C)
586 return self.__class__((data, indices, indptr), shape=self.shape)
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)
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])
609def isspmatrix_bsr(x):
610 """Is `x` of a bsr_matrix type?
612 Parameters
613 ----------
614 x
615 object to check for being a bsr matrix
617 Returns
618 -------
619 bool
620 True if `x` is a bsr matrix, False otherwise
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)
635# This namespace class separates array from matrix with isinstance
636class bsr_array(_bsr_base, sparray):
637 """
638 Block Sparse Row format sparse array.
640 This can be instantiated in several ways:
641 bsr_array(D, [blocksize=(R,C)])
642 where D is a 2-D ndarray.
644 bsr_array(S, [blocksize=(R,C)])
645 with another sparse array or matrix S (equivalent to S.tobsr())
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'.
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]``
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.
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
684 Notes
685 -----
686 Sparse arrays can be used in arithmetic operations: they support
687 addition, subtraction, multiplication, division, and matrix power.
689 **Summary of BSR format**
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.
698 **Blocksize**
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``.
704 If no blocksize is specified, a simple heuristic is applied to determine
705 an appropriate blocksize.
707 **Canonical Format**
709 In canonical format, there are no duplicate blocks and indices are sorted
710 per row.
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)
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]])
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]])
740 """
743class bsr_matrix(spmatrix, _bsr_base):
744 """
745 Block Sparse Row format sparse matrix.
747 This can be instantiated in several ways:
748 bsr_matrix(D, [blocksize=(R,C)])
749 where D is a 2-D ndarray.
751 bsr_matrix(S, [blocksize=(R,C)])
752 with another sparse array or matrix S (equivalent to S.tobsr())
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'.
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]``
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.
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
791 Notes
792 -----
793 Sparse matrices can be used in arithmetic operations: they support
794 addition, subtraction, multiplication, division, and matrix power.
796 **Summary of BSR format**
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.
805 **Blocksize**
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``.
811 If no blocksize is specified, a simple heuristic is applied to determine
812 an appropriate blocksize.
814 **Canonical Format**
816 In canonical format, there are no duplicate blocks and indices are sorted
817 per row.
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)
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]])
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]])
847 """