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
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-23 06:43 +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 '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)
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("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)
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)" % (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")
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)
198 @property
199 def blocksize(self) -> tuple:
200 """Block size of the matrix."""
201 return self.data.shape[1:]
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)
210 _getnnz.__doc__ = _spbase._getnnz.__doc__
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,)))
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
231 diagonal.__doc__ = _spbase.diagonal.__doc__
233 ##########################
234 # NotImplemented methods #
235 ##########################
237 def __getitem__(self,key):
238 raise NotImplementedError
240 def __setitem__(self,key,val):
241 raise NotImplementedError
243 ######################
244 # Arithmetic methods #
245 ######################
247 def _add_dense(self, other):
248 return self.tocoo(copy=False)._add_dense(other)
250 def _mul_vector(self, other):
251 M,N = self.shape
252 R,C = self.blocksize
254 result = np.zeros(self.shape[0], dtype=upcast(self.dtype, other.dtype))
256 bsr_matvec(M//R, N//C, R, C,
257 self.indptr, self.indices, self.data.ravel(),
258 other, result)
260 return result
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
267 result = np.zeros((M,n_vecs), dtype=upcast(self.dtype,other.dtype))
269 bsr_matvecs(M//R, N//C, n_vecs, R, C,
270 self.indptr, self.indices, self.data.ravel(),
271 other.ravel(), result.ravel())
273 return result
275 def _mul_sparse_matrix(self, other):
276 M, K1 = self.shape
277 K2, N = other.shape
279 R,n = self.blocksize
281 # convert to this format
282 if other.format == "bsr":
283 C = other.blocksize[1]
284 else:
285 C = 1
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))
292 idx_dtype = self._get_index_dtype((self.indptr, self.indices,
293 other.indptr, other.indices))
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))
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))
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)
319 data = data.reshape(-1,R,C)
321 # TODO eliminate zeros
323 return self._bsr_container(
324 (data, indices, indptr), shape=(M, N), blocksize=(R, C)
325 )
327 ######################
328 # Conversion methods #
329 ######################
331 def tobsr(self, blocksize=None, copy=False):
332 """Convert this array/matrix into Block Sparse Row Format.
334 With copy=False, the data/indices may be shared between this
335 array/matrix and the resultant bsr_array/bsr_matrix.
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
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))
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)
368 tocsr.__doc__ = _spbase.tocsr.__doc__
370 def tocsc(self, copy=False):
371 return self.tocsr(copy=False).tocsc(copy=copy)
373 tocsc.__doc__ = _spbase.tocsc.__doc__
375 def tocoo(self, copy=True):
376 """Convert this array/matrix to COOrdinate format.
378 When copy=False the data array will be shared between
379 this array/matrix and the resultant coo_array/coo_matrix.
380 """
382 M,N = self.shape
383 R,C = self.blocksize
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
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)
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)
403 data = self.data.reshape(-1)
405 if copy:
406 data = data.copy()
408 return self._coo_container(
409 (data, (row, col)), shape=self.shape
410 )
412 def toarray(self, order=None, out=None):
413 return self.tocoo(copy=False).toarray(order=order, out=out)
415 toarray.__doc__ = _spbase.toarray.__doc__
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.")
423 R, C = self.blocksize
424 M, N = self.shape
425 NBLK = self.nnz//(R*C)
427 if self.nnz == 0:
428 return self._bsr_container((N, M), blocksize=(C, R),
429 dtype=self.dtype, copy=copy)
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)
435 bsr_transpose(M//R, N//C, R, C,
436 self.indptr, self.indices, self.data.ravel(),
437 indptr, indices, data.ravel())
439 return self._bsr_container((data, indices, indptr),
440 shape=(N, M), copy=copy)
442 transpose.__doc__ = _spbase.transpose.__doc__
444 ##############################################################
445 # methods that examine or modify the internal data structure #
446 ##############################################################
448 def eliminate_zeros(self):
449 """Remove zero elements in-place."""
451 if not self.nnz:
452 return # nothing to do
454 R,C = self.blocksize
455 M,N = self.shape
457 mask = (self.data != 0).reshape(-1,R*C).sum(axis=1) # nonzero blocks
459 nonzero_blocks = mask.nonzero()[0]
461 self.data[:len(nonzero_blocks)] = self.data[nonzero_blocks]
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()
468 def sum_duplicates(self):
469 """Eliminate duplicate array/matrix entries by adding them together
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
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
498 self.prune() # nnz may have changed
499 self.has_canonical_format = True
501 def sort_indices(self):
502 """Sort the indices of this array/matrix *in place*
503 """
504 if self.has_sorted_indices:
505 return
507 R,C = self.blocksize
508 M,N = self.shape
510 bsr_sort_indices(M//R, N//C, R, C, self.indptr, self.indices, self.data.ravel())
512 self.has_sorted_indices = True
514 def prune(self):
515 """Remove empty space after all non-zero elements.
516 """
518 R,C = self.blocksize
519 M,N = self.shape
521 if len(self.indptr) != M//R + 1:
522 raise ValueError("index pointer has invalid length")
524 bnnz = self.indptr[-1]
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")
531 self.data = self.data[:bnnz]
532 self.indices = self.indices[:bnnz]
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."""
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)
542 # e.g. bsr_plus_bsr, etc.
543 fn = getattr(_sparsetools, self.format + op + self.format)
545 R,C = self.blocksize
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)
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))
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)
571 actual_bnnz = indptr[-1]
572 indices = indices[:actual_bnnz]
573 data = data[:R*C*actual_bnnz]
575 if actual_bnnz < max_bnnz/2:
576 indices = indices.copy()
577 data = data.copy()
579 data = data.reshape(-1,R,C)
581 return self.__class__((data, indices, indptr), shape=self.shape)
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)
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])
604def isspmatrix_bsr(x):
605 """Is `x` of a bsr_matrix type?
607 Parameters
608 ----------
609 x
610 object to check for being a bsr matrix
612 Returns
613 -------
614 bool
615 True if `x` is a bsr matrix, False otherwise
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)
630# This namespace class separates array from matrix with isinstance
631class bsr_array(_bsr_base, sparray):
632 """
633 Block Sparse Row format sparse array.
635 This can be instantiated in several ways:
636 bsr_array(D, [blocksize=(R,C)])
637 where D is a 2-D ndarray.
639 bsr_array(S, [blocksize=(R,C)])
640 with another sparse array or matrix S (equivalent to S.tobsr())
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'.
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]``
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.
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
679 Notes
680 -----
681 Sparse arrays can be used in arithmetic operations: they support
682 addition, subtraction, multiplication, division, and matrix power.
684 **Summary of BSR format**
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.
693 **Blocksize**
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``.
699 If no blocksize is specified, a simple heuristic is applied to determine
700 an appropriate blocksize.
702 **Canonical Format**
704 In canonical format, there are no duplicate blocks and indices are sorted
705 per row.
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)
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]])
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]])
735 """
738class bsr_matrix(spmatrix, _bsr_base):
739 """
740 Block Sparse Row format sparse matrix.
742 This can be instantiated in several ways:
743 bsr_matrix(D, [blocksize=(R,C)])
744 where D is a 2-D ndarray.
746 bsr_matrix(S, [blocksize=(R,C)])
747 with another sparse array or matrix S (equivalent to S.tobsr())
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'.
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]``
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.
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
786 Notes
787 -----
788 Sparse matrices can be used in arithmetic operations: they support
789 addition, subtraction, multiplication, division, and matrix power.
791 **Summary of BSR format**
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.
800 **Blocksize**
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``.
806 If no blocksize is specified, a simple heuristic is applied to determine
807 an appropriate blocksize.
809 **Canonical Format**
811 In canonical format, there are no duplicate blocks and indices are sorted
812 per row.
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)
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]])
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]])
842 """