class_docstr: Block Sparse Row matrix
  
  This can be instantiated in several ways:
      bsr_matrix(D, [blocksize=(R,C)])
          where D is a dense matrix or 2-D ndarray.
  
      bsr_matrix(S, [blocksize=(R,C)])
          with another sparse matrix S (equivalent to S.tobsr())
  
      bsr_matrix((M, N), [blocksize=(R,C), dtype])
          to construct an empty matrix with shape (M, N)
          dtype is optional, defaulting to dtype='d'.
  
      bsr_matrix((data, ij), [blocksize=(R,C), shape=(M, N)])
          where ``data`` and ``ij`` satisfy ``a[ij[0, k], ij[1, k]] = data[k]``
  
      bsr_matrix((data, indices, indptr), [shape=(M, N)])
          is the standard BSR representation where the block column
          indices for row i are stored in ``indices[indptr[i]:indptr[i+1]]``
          and their corresponding block values are stored in
          ``data[ indptr[i]: indptr[i+1] ]``.  If the shape parameter is not
          supplied, the matrix dimensions are inferred from the index arrays.
  
  Attributes
  ----------
  dtype : dtype
      Data type of the matrix
  shape : 2-tuple
      Shape of the matrix
  ndim : int
      Number of dimensions (this is always 2)
  nnz
      Number of nonzero elements
  data
      Data array of the matrix
  indices
      BSR format index array
  indptr
      BSR format index pointer array
  blocksize
      Block size of the matrix
  has_sorted_indices
      Whether indices are sorted
  
  Notes
  -----
  Sparse matrices can be used in arithmetic operations: they support
  addition, subtraction, multiplication, division, and matrix power.
  
  **Summary of BSR format**
  
  The Block Compressed Row (BSR) format is very similar to the Compressed
  Sparse Row (CSR) format.  BSR is appropriate for sparse matrices with dense
  sub matrices like the last example below.  Block matrices often arise in
  vector-valued finite element discretizations.  In such cases, BSR is
  considerably more efficient than CSR and CSC for many sparse arithmetic
  operations.
  
  **Blocksize**
  
  The blocksize (R,C) must evenly divide the shape of the matrix (M,N).
  That is, R and C must satisfy the relationship ``M % R = 0`` and
  ``N % C = 0``.
  
  If no blocksize is specified, a simple heuristic is applied to determine
  an appropriate blocksize.
  
  Examples
  --------
  >>> from scipy.sparse import bsr_matrix
  >>> bsr_matrix((3, 4), dtype=np.int8).toarray()
  array([[0, 0, 0, 0],
         [0, 0, 0, 0],
         [0, 0, 0, 0]], dtype=int8)
  
  >>> row = np.array([0, 0, 1, 2, 2, 2])
  >>> col = np.array([0, 2, 2, 0, 1, 2])
  >>> data = np.array([1, 2, 3 ,4, 5, 6])
  >>> bsr_matrix((data, (row, col)), shape=(3, 3)).toarray()
  array([[1, 0, 2],
         [0, 0, 3],
         [4, 5, 6]])
  
  >>> indptr = np.array([0, 2, 3, 6])
  >>> indices = np.array([0, 2, 2, 0, 1, 2])
  >>> data = np.array([1, 2, 3, 4, 5, 6]).repeat(4).reshape(6, 2, 2)
  >>> bsr_matrix((data,indices,indptr), shape=(6, 6)).toarray()
  array([[1, 1, 0, 0, 2, 2],
         [1, 1, 0, 0, 2, 2],
         [0, 0, 0, 0, 3, 3],
         [0, 0, 0, 0, 3, 3],
         [4, 4, 5, 5, 6, 6],
         [4, 4, 5, 5, 6, 6]])
code: def _mul_sparse_matrix(self, other):
      M, K1 = self.shape
      K2, N = other.shape
  
      R, n = self.blocksize
  
      # convert to this format
      if isspmatrix_bsr(other):
          C = other.blocksize[1]
      else:
          C = 1
  
      from .csr import isspmatrix_csr
  
      if isspmatrix_csr(other) and n == 1:
          other = other.tobsr(
              blocksize=(n, C), copy=False
          )  # lightweight conversion
      else:
          other = other.tobsr(blocksize=(n, C))
  
      idx_dtype = get_index_dtype(
          (self.indptr, self.indices, other.indptr, other.indices),
          maxval=(M // R) * (N // C),
      )
      indptr = np.empty(self.indptr.shape, dtype=idx_dtype)
  
      csr_matmat_pass1(
          M // R,
          N // C,
          self.indptr.astype(idx_dtype),
          self.indices.astype(idx_dtype),
          other.indptr.astype(idx_dtype),
          other.indices.astype(idx_dtype),
          indptr,
      )
  
      bnnz = indptr[-1]
  
      idx_dtype = get_index_dtype(
          (self.indptr, self.indices, other.indptr, other.indices),
          maxval=bnnz,
      )
      indptr = indptr.astype(idx_dtype)
      indices = np.empty(bnnz, dtype=idx_dtype)
      data = np.empty(
          R * C * bnnz, dtype=upcast(self.dtype, other.dtype)
      )
  
      bsr_matmat_pass2(
          M // R,
          N // C,
          R,
          C,
          n,
          self.indptr.astype(idx_dtype),
          self.indices.astype(idx_dtype),
          np.ravel(self.data),
          other.indptr.astype(idx_dtype),
          other.indices.astype(idx_dtype),
          np.ravel(other.data),
          indptr,
          indices,
          data,
      )
  
      data = data.reshape(-1, R, C)
  
      # TODO eliminate zeros
  
      return bsr_matrix(
          (data, indices, indptr), shape=(M, N), blocksize=(R, C)
      )
  
imports: from __future__ import division, print_function, absolute_import
  from warnings import warn
  import numpy
  from .data import _data_matrix, _minmax_mixin
  from .compressed import _cs_matrix
  from .base import isspmatrix, _formats, spmatrix
  from .sputils import isshape, getdtype, to_native, upcast, get_index_dtype, check_shape
  from .None import _sparsetools
  from ._sparsetools import bsr_matvec, bsr_matvecs, csr_matmat_pass1, bsr_matmat_pass2, bsr_transpose, bsr_sort_indices, bsr_tocsr
label_desc: Use image node_id 14 for calling the bsr_matrix obj's underlying member method code with example usage: obj._mul_sparse_matrix(other) and returns: bsr_matrix