123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947 |
- """Functions to construct sparse matrices
- """
- __docformat__ = "restructuredtext en"
- __all__ = ['spdiags', 'eye', 'identity', 'kron', 'kronsum',
- 'hstack', 'vstack', 'bmat', 'rand', 'random', 'diags', 'block_diag']
- import numbers
- from functools import partial
- import numpy as np
- from scipy._lib._util import check_random_state, rng_integers
- from ._sputils import upcast, get_index_dtype, isscalarlike
- from ._sparsetools import csr_hstack
- from ._csr import csr_matrix
- from ._csc import csc_matrix
- from ._bsr import bsr_matrix
- from ._coo import coo_matrix
- from ._dia import dia_matrix
- from ._base import issparse
- def spdiags(data, diags, m=None, n=None, format=None):
- """
- Return a sparse matrix from diagonals.
- Parameters
- ----------
- data : array_like
- Matrix diagonals stored row-wise
- diags : sequence of int or an int
- Diagonals to set:
- * k = 0 the main diagonal
- * k > 0 the kth upper diagonal
- * k < 0 the kth lower diagonal
- m, n : int, tuple, optional
- Shape of the result. If `n` is None and `m` is a given tuple,
- the shape is this tuple. If omitted, the matrix is square and
- its shape is len(data[0]).
- format : str, optional
- Format of the result. By default (format=None) an appropriate sparse
- matrix format is returned. This choice is subject to change.
- See Also
- --------
- diags : more convenient form of this function
- dia_matrix : the sparse DIAgonal format.
- Examples
- --------
- >>> import numpy as np
- >>> from scipy.sparse import spdiags
- >>> data = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])
- >>> diags = np.array([0, -1, 2])
- >>> spdiags(data, diags, 4, 4).toarray()
- array([[1, 0, 3, 0],
- [1, 2, 0, 4],
- [0, 2, 3, 0],
- [0, 0, 3, 4]])
- """
- if m is None and n is None:
- m = n = len(data[0])
- elif n is None:
- m, n = m
- return dia_matrix((data, diags), shape=(m, n)).asformat(format)
- def diags(diagonals, offsets=0, shape=None, format=None, dtype=None):
- """
- Construct a sparse matrix from diagonals.
- Parameters
- ----------
- diagonals : sequence of array_like
- Sequence of arrays containing the matrix diagonals,
- corresponding to `offsets`.
- offsets : sequence of int or an int, optional
- Diagonals to set:
- - k = 0 the main diagonal (default)
- - k > 0 the kth upper diagonal
- - k < 0 the kth lower diagonal
- shape : tuple of int, optional
- Shape of the result. If omitted, a square matrix large enough
- to contain the diagonals is returned.
- format : {"dia", "csr", "csc", "lil", ...}, optional
- Matrix format of the result. By default (format=None) an
- appropriate sparse matrix format is returned. This choice is
- subject to change.
- dtype : dtype, optional
- Data type of the matrix.
- See Also
- --------
- spdiags : construct matrix from diagonals
- Notes
- -----
- This function differs from `spdiags` in the way it handles
- off-diagonals.
- The result from `diags` is the sparse equivalent of::
- np.diag(diagonals[0], offsets[0])
- + ...
- + np.diag(diagonals[k], offsets[k])
- Repeated diagonal offsets are disallowed.
- .. versionadded:: 0.11
- Examples
- --------
- >>> from scipy.sparse import diags
- >>> diagonals = [[1, 2, 3, 4], [1, 2, 3], [1, 2]]
- >>> diags(diagonals, [0, -1, 2]).toarray()
- array([[1, 0, 1, 0],
- [1, 2, 0, 2],
- [0, 2, 3, 0],
- [0, 0, 3, 4]])
- Broadcasting of scalars is supported (but shape needs to be
- specified):
- >>> diags([1, -2, 1], [-1, 0, 1], shape=(4, 4)).toarray()
- array([[-2., 1., 0., 0.],
- [ 1., -2., 1., 0.],
- [ 0., 1., -2., 1.],
- [ 0., 0., 1., -2.]])
- If only one diagonal is wanted (as in `numpy.diag`), the following
- works as well:
- >>> diags([1, 2, 3], 1).toarray()
- array([[ 0., 1., 0., 0.],
- [ 0., 0., 2., 0.],
- [ 0., 0., 0., 3.],
- [ 0., 0., 0., 0.]])
- """
- # if offsets is not a sequence, assume that there's only one diagonal
- if isscalarlike(offsets):
- # now check that there's actually only one diagonal
- if len(diagonals) == 0 or isscalarlike(diagonals[0]):
- diagonals = [np.atleast_1d(diagonals)]
- else:
- raise ValueError("Different number of diagonals and offsets.")
- else:
- diagonals = list(map(np.atleast_1d, diagonals))
- offsets = np.atleast_1d(offsets)
- # Basic check
- if len(diagonals) != len(offsets):
- raise ValueError("Different number of diagonals and offsets.")
- # Determine shape, if omitted
- if shape is None:
- m = len(diagonals[0]) + abs(int(offsets[0]))
- shape = (m, m)
- # Determine data type, if omitted
- if dtype is None:
- dtype = np.common_type(*diagonals)
- # Construct data array
- m, n = shape
- M = max([min(m + offset, n - offset) + max(0, offset)
- for offset in offsets])
- M = max(0, M)
- data_arr = np.zeros((len(offsets), M), dtype=dtype)
- K = min(m, n)
- for j, diagonal in enumerate(diagonals):
- offset = offsets[j]
- k = max(0, offset)
- length = min(m + offset, n - offset, K)
- if length < 0:
- raise ValueError("Offset %d (index %d) out of bounds" % (offset, j))
- try:
- data_arr[j, k:k+length] = diagonal[...,:length]
- except ValueError as e:
- if len(diagonal) != length and len(diagonal) != 1:
- raise ValueError(
- "Diagonal length (index %d: %d at offset %d) does not "
- "agree with matrix size (%d, %d)." % (
- j, len(diagonal), offset, m, n)) from e
- raise
- return dia_matrix((data_arr, offsets), shape=(m, n)).asformat(format)
- def identity(n, dtype='d', format=None):
- """Identity matrix in sparse format
- Returns an identity matrix with shape (n,n) using a given
- sparse format and dtype.
- Parameters
- ----------
- n : int
- Shape of the identity matrix.
- dtype : dtype, optional
- Data type of the matrix
- format : str, optional
- Sparse format of the result, e.g., format="csr", etc.
- Examples
- --------
- >>> from scipy.sparse import identity
- >>> identity(3).toarray()
- array([[ 1., 0., 0.],
- [ 0., 1., 0.],
- [ 0., 0., 1.]])
- >>> identity(3, dtype='int8', format='dia')
- <3x3 sparse matrix of type '<class 'numpy.int8'>'
- with 3 stored elements (1 diagonals) in DIAgonal format>
- """
- return eye(n, n, dtype=dtype, format=format)
- def eye(m, n=None, k=0, dtype=float, format=None):
- """Sparse matrix with ones on diagonal
- Returns a sparse (m x n) matrix where the kth diagonal
- is all ones and everything else is zeros.
- Parameters
- ----------
- m : int
- Number of rows in the matrix.
- n : int, optional
- Number of columns. Default: `m`.
- k : int, optional
- Diagonal to place ones on. Default: 0 (main diagonal).
- dtype : dtype, optional
- Data type of the matrix.
- format : str, optional
- Sparse format of the result, e.g., format="csr", etc.
- Examples
- --------
- >>> import numpy as np
- >>> from scipy import sparse
- >>> sparse.eye(3).toarray()
- array([[ 1., 0., 0.],
- [ 0., 1., 0.],
- [ 0., 0., 1.]])
- >>> sparse.eye(3, dtype=np.int8)
- <3x3 sparse matrix of type '<class 'numpy.int8'>'
- with 3 stored elements (1 diagonals) in DIAgonal format>
- """
- if n is None:
- n = m
- m,n = int(m),int(n)
- if m == n and k == 0:
- # fast branch for special formats
- if format in ['csr', 'csc']:
- idx_dtype = get_index_dtype(maxval=n)
- indptr = np.arange(n+1, dtype=idx_dtype)
- indices = np.arange(n, dtype=idx_dtype)
- data = np.ones(n, dtype=dtype)
- cls = {'csr': csr_matrix, 'csc': csc_matrix}[format]
- return cls((data,indices,indptr),(n,n))
- elif format == 'coo':
- idx_dtype = get_index_dtype(maxval=n)
- row = np.arange(n, dtype=idx_dtype)
- col = np.arange(n, dtype=idx_dtype)
- data = np.ones(n, dtype=dtype)
- return coo_matrix((data, (row, col)), (n, n))
- diags = np.ones((1, max(0, min(m + k, n))), dtype=dtype)
- return spdiags(diags, k, m, n).asformat(format)
- def kron(A, B, format=None):
- """kronecker product of sparse matrices A and B
- Parameters
- ----------
- A : sparse or dense matrix
- first matrix of the product
- B : sparse or dense matrix
- second matrix of the product
- format : str, optional
- format of the result (e.g. "csr")
- Returns
- -------
- kronecker product in a sparse matrix format
- Examples
- --------
- >>> import numpy as np
- >>> from scipy import sparse
- >>> A = sparse.csr_matrix(np.array([[0, 2], [5, 0]]))
- >>> B = sparse.csr_matrix(np.array([[1, 2], [3, 4]]))
- >>> sparse.kron(A, B).toarray()
- array([[ 0, 0, 2, 4],
- [ 0, 0, 6, 8],
- [ 5, 10, 0, 0],
- [15, 20, 0, 0]])
- >>> sparse.kron(A, [[1, 2], [3, 4]]).toarray()
- array([[ 0, 0, 2, 4],
- [ 0, 0, 6, 8],
- [ 5, 10, 0, 0],
- [15, 20, 0, 0]])
- """
- B = coo_matrix(B)
- if (format is None or format == "bsr") and 2*B.nnz >= B.shape[0] * B.shape[1]:
- # B is fairly dense, use BSR
- A = csr_matrix(A,copy=True)
- output_shape = (A.shape[0]*B.shape[0], A.shape[1]*B.shape[1])
- if A.nnz == 0 or B.nnz == 0:
- # kronecker product is the zero matrix
- return coo_matrix(output_shape).asformat(format)
- B = B.toarray()
- data = A.data.repeat(B.size).reshape(-1,B.shape[0],B.shape[1])
- data = data * B
- return bsr_matrix((data,A.indices,A.indptr), shape=output_shape)
- else:
- # use COO
- A = coo_matrix(A)
- output_shape = (A.shape[0]*B.shape[0], A.shape[1]*B.shape[1])
- if A.nnz == 0 or B.nnz == 0:
- # kronecker product is the zero matrix
- return coo_matrix(output_shape).asformat(format)
- # expand entries of a into blocks
- row = A.row.repeat(B.nnz)
- col = A.col.repeat(B.nnz)
- data = A.data.repeat(B.nnz)
- if max(A.shape[0]*B.shape[0], A.shape[1]*B.shape[1]) > np.iinfo('int32').max:
- row = row.astype(np.int64)
- col = col.astype(np.int64)
- row *= B.shape[0]
- col *= B.shape[1]
- # increment block indices
- row,col = row.reshape(-1,B.nnz),col.reshape(-1,B.nnz)
- row += B.row
- col += B.col
- row,col = row.reshape(-1),col.reshape(-1)
- # compute block entries
- data = data.reshape(-1,B.nnz) * B.data
- data = data.reshape(-1)
- return coo_matrix((data,(row,col)), shape=output_shape).asformat(format)
- def kronsum(A, B, format=None):
- """kronecker sum of sparse matrices A and B
- Kronecker sum of two sparse matrices is a sum of two Kronecker
- products kron(I_n,A) + kron(B,I_m) where A has shape (m,m)
- and B has shape (n,n) and I_m and I_n are identity matrices
- of shape (m,m) and (n,n), respectively.
- Parameters
- ----------
- A
- square matrix
- B
- square matrix
- format : str
- format of the result (e.g. "csr")
- Returns
- -------
- kronecker sum in a sparse matrix format
- Examples
- --------
- """
- A = coo_matrix(A)
- B = coo_matrix(B)
- if A.shape[0] != A.shape[1]:
- raise ValueError('A is not square')
- if B.shape[0] != B.shape[1]:
- raise ValueError('B is not square')
- dtype = upcast(A.dtype, B.dtype)
- L = kron(eye(B.shape[0],dtype=dtype), A, format=format)
- R = kron(B, eye(A.shape[0],dtype=dtype), format=format)
- return (L+R).asformat(format) # since L + R is not always same format
- def _compressed_sparse_stack(blocks, axis):
- """
- Stacking fast path for CSR/CSC matrices
- (i) vstack for CSR, (ii) hstack for CSC.
- """
- other_axis = 1 if axis == 0 else 0
- data = np.concatenate([b.data for b in blocks])
- constant_dim = blocks[0].shape[other_axis]
- idx_dtype = get_index_dtype(arrays=[b.indptr for b in blocks],
- maxval=max(data.size, constant_dim))
- indices = np.empty(data.size, dtype=idx_dtype)
- indptr = np.empty(sum(b.shape[axis] for b in blocks) + 1, dtype=idx_dtype)
- last_indptr = idx_dtype(0)
- sum_dim = 0
- sum_indices = 0
- for b in blocks:
- if b.shape[other_axis] != constant_dim:
- raise ValueError(f'incompatible dimensions for axis {other_axis}')
- indices[sum_indices:sum_indices+b.indices.size] = b.indices
- sum_indices += b.indices.size
- idxs = slice(sum_dim, sum_dim + b.shape[axis])
- indptr[idxs] = b.indptr[:-1]
- indptr[idxs] += last_indptr
- sum_dim += b.shape[axis]
- last_indptr += b.indptr[-1]
- indptr[-1] = last_indptr
- if axis == 0:
- return csr_matrix((data, indices, indptr),
- shape=(sum_dim, constant_dim))
- else:
- return csc_matrix((data, indices, indptr),
- shape=(constant_dim, sum_dim))
- def _stack_along_minor_axis(blocks, axis):
- """
- Stacking fast path for CSR/CSC matrices along the minor axis
- (i) hstack for CSR, (ii) vstack for CSC.
- """
- n_blocks = len(blocks)
- if n_blocks == 0:
- raise ValueError('Missing block matrices')
- if n_blocks == 1:
- return blocks[0]
- # check for incompatible dimensions
- other_axis = 1 if axis == 0 else 0
- other_axis_dims = set(b.shape[other_axis] for b in blocks)
- if len(other_axis_dims) > 1:
- raise ValueError(f'Mismatching dimensions along axis {other_axis}: '
- f'{other_axis_dims}')
- constant_dim, = other_axis_dims
- # Do the stacking
- indptr_list = [b.indptr for b in blocks]
- data_cat = np.concatenate([b.data for b in blocks])
- # Need to check if any indices/indptr, would be too large post-
- # concatenation for np.int32:
- # - The max value of indices is the output array's stacking-axis length - 1
- # - The max value in indptr is the number of non-zero entries. This is
- # exceedingly unlikely to require int64, but is checked out of an
- # abundance of caution.
- sum_dim = sum(b.shape[axis] for b in blocks)
- nnz = sum(len(b.indices) for b in blocks)
- idx_dtype = get_index_dtype(maxval=max(sum_dim - 1, nnz))
- stack_dim_cat = np.array([b.shape[axis] for b in blocks], dtype=idx_dtype)
- if data_cat.size > 0:
- indptr_cat = np.concatenate(indptr_list).astype(idx_dtype)
- indices_cat = (np.concatenate([b.indices for b in blocks])
- .astype(idx_dtype))
- indptr = np.empty(constant_dim + 1, dtype=idx_dtype)
- indices = np.empty_like(indices_cat)
- data = np.empty_like(data_cat)
- csr_hstack(n_blocks, constant_dim, stack_dim_cat,
- indptr_cat, indices_cat, data_cat,
- indptr, indices, data)
- else:
- indptr = np.zeros(constant_dim + 1, dtype=idx_dtype)
- indices = np.empty(0, dtype=idx_dtype)
- data = np.empty(0, dtype=data_cat.dtype)
- if axis == 0:
- return csc_matrix((data, indices, indptr),
- shape=(sum_dim, constant_dim))
- else:
- return csr_matrix((data, indices, indptr),
- shape=(constant_dim, sum_dim))
- def hstack(blocks, format=None, dtype=None):
- """
- Stack sparse matrices horizontally (column wise)
- Parameters
- ----------
- blocks
- sequence of sparse matrices with compatible shapes
- format : str
- sparse format of the result (e.g., "csr")
- by default an appropriate sparse matrix format is returned.
- This choice is subject to change.
- dtype : dtype, optional
- The data-type of the output matrix. If not given, the dtype is
- determined from that of `blocks`.
- See Also
- --------
- vstack : stack sparse matrices vertically (row wise)
- Examples
- --------
- >>> from scipy.sparse import coo_matrix, hstack
- >>> A = coo_matrix([[1, 2], [3, 4]])
- >>> B = coo_matrix([[5], [6]])
- >>> hstack([A,B]).toarray()
- array([[1, 2, 5],
- [3, 4, 6]])
- """
- return bmat([blocks], format=format, dtype=dtype)
- def vstack(blocks, format=None, dtype=None):
- """
- Stack sparse matrices vertically (row wise)
- Parameters
- ----------
- blocks
- sequence of sparse matrices with compatible shapes
- format : str, optional
- sparse format of the result (e.g., "csr")
- by default an appropriate sparse matrix format is returned.
- This choice is subject to change.
- dtype : dtype, optional
- The data-type of the output matrix. If not given, the dtype is
- determined from that of `blocks`.
- See Also
- --------
- hstack : stack sparse matrices horizontally (column wise)
- Examples
- --------
- >>> from scipy.sparse import coo_matrix, vstack
- >>> A = coo_matrix([[1, 2], [3, 4]])
- >>> B = coo_matrix([[5, 6]])
- >>> vstack([A, B]).toarray()
- array([[1, 2],
- [3, 4],
- [5, 6]])
- """
- return bmat([[b] for b in blocks], format=format, dtype=dtype)
- def bmat(blocks, format=None, dtype=None):
- """
- Build a sparse matrix from sparse sub-blocks
- Parameters
- ----------
- blocks : array_like
- Grid of sparse matrices with compatible shapes.
- An entry of None implies an all-zero matrix.
- format : {'bsr', 'coo', 'csc', 'csr', 'dia', 'dok', 'lil'}, optional
- The sparse format of the result (e.g. "csr"). By default an
- appropriate sparse matrix format is returned.
- This choice is subject to change.
- dtype : dtype, optional
- The data-type of the output matrix. If not given, the dtype is
- determined from that of `blocks`.
- Returns
- -------
- bmat : sparse matrix
- See Also
- --------
- block_diag, diags
- Examples
- --------
- >>> from scipy.sparse import coo_matrix, bmat
- >>> A = coo_matrix([[1, 2], [3, 4]])
- >>> B = coo_matrix([[5], [6]])
- >>> C = coo_matrix([[7]])
- >>> bmat([[A, B], [None, C]]).toarray()
- array([[1, 2, 5],
- [3, 4, 6],
- [0, 0, 7]])
- >>> bmat([[A, None], [None, C]]).toarray()
- array([[1, 2, 0],
- [3, 4, 0],
- [0, 0, 7]])
- """
- blocks = np.asarray(blocks, dtype='object')
- if blocks.ndim != 2:
- raise ValueError('blocks must be 2-D')
- M,N = blocks.shape
- # check for fast path cases
- if (format in (None, 'csr') and all(isinstance(b, csr_matrix)
- for b in blocks.flat)):
- if N > 1:
- # stack along columns (axis 1):
- blocks = [[_stack_along_minor_axis(blocks[b, :], 1)]
- for b in range(M)] # must have shape: (M, 1)
- blocks = np.asarray(blocks, dtype='object')
- # stack along rows (axis 0):
- A = _compressed_sparse_stack(blocks[:, 0], 0)
- if dtype is not None:
- A = A.astype(dtype)
- return A
- elif (format in (None, 'csc') and all(isinstance(b, csc_matrix)
- for b in blocks.flat)):
- if M > 1:
- # stack along rows (axis 0):
- blocks = [[_stack_along_minor_axis(blocks[:, b], 0)
- for b in range(N)]] # must have shape: (1, N)
- blocks = np.asarray(blocks, dtype='object')
- # stack along columns (axis 1):
- A = _compressed_sparse_stack(blocks[0, :], 1)
- if dtype is not None:
- A = A.astype(dtype)
- return A
- block_mask = np.zeros(blocks.shape, dtype=bool)
- brow_lengths = np.zeros(M, dtype=np.int64)
- bcol_lengths = np.zeros(N, dtype=np.int64)
- # convert everything to COO format
- for i in range(M):
- for j in range(N):
- if blocks[i,j] is not None:
- A = coo_matrix(blocks[i,j])
- blocks[i,j] = A
- block_mask[i,j] = True
- if brow_lengths[i] == 0:
- brow_lengths[i] = A.shape[0]
- elif brow_lengths[i] != A.shape[0]:
- msg = (f'blocks[{i},:] has incompatible row dimensions. '
- f'Got blocks[{i},{j}].shape[0] == {A.shape[0]}, '
- f'expected {brow_lengths[i]}.')
- raise ValueError(msg)
- if bcol_lengths[j] == 0:
- bcol_lengths[j] = A.shape[1]
- elif bcol_lengths[j] != A.shape[1]:
- msg = (f'blocks[:,{j}] has incompatible column '
- f'dimensions. '
- f'Got blocks[{i},{j}].shape[1] == {A.shape[1]}, '
- f'expected {bcol_lengths[j]}.')
- raise ValueError(msg)
- nnz = sum(block.nnz for block in blocks[block_mask])
- if dtype is None:
- all_dtypes = [blk.dtype for blk in blocks[block_mask]]
- dtype = upcast(*all_dtypes) if all_dtypes else None
- row_offsets = np.append(0, np.cumsum(brow_lengths))
- col_offsets = np.append(0, np.cumsum(bcol_lengths))
- shape = (row_offsets[-1], col_offsets[-1])
- data = np.empty(nnz, dtype=dtype)
- idx_dtype = get_index_dtype(maxval=max(shape))
- row = np.empty(nnz, dtype=idx_dtype)
- col = np.empty(nnz, dtype=idx_dtype)
- nnz = 0
- ii, jj = np.nonzero(block_mask)
- for i, j in zip(ii, jj):
- B = blocks[i, j]
- idx = slice(nnz, nnz + B.nnz)
- data[idx] = B.data
- np.add(B.row, row_offsets[i], out=row[idx], dtype=idx_dtype)
- np.add(B.col, col_offsets[j], out=col[idx], dtype=idx_dtype)
- nnz += B.nnz
- return coo_matrix((data, (row, col)), shape=shape).asformat(format)
- def block_diag(mats, format=None, dtype=None):
- """
- Build a block diagonal sparse matrix from provided matrices.
- Parameters
- ----------
- mats : sequence of matrices
- Input matrices.
- format : str, optional
- The sparse format of the result (e.g., "csr"). If not given, the matrix
- is returned in "coo" format.
- dtype : dtype specifier, optional
- The data-type of the output matrix. If not given, the dtype is
- determined from that of `blocks`.
- Returns
- -------
- res : sparse matrix
- Notes
- -----
- .. versionadded:: 0.11.0
- See Also
- --------
- bmat, diags
- Examples
- --------
- >>> from scipy.sparse import coo_matrix, block_diag
- >>> A = coo_matrix([[1, 2], [3, 4]])
- >>> B = coo_matrix([[5], [6]])
- >>> C = coo_matrix([[7]])
- >>> block_diag((A, B, C)).toarray()
- array([[1, 2, 0, 0],
- [3, 4, 0, 0],
- [0, 0, 5, 0],
- [0, 0, 6, 0],
- [0, 0, 0, 7]])
- """
- row = []
- col = []
- data = []
- r_idx = 0
- c_idx = 0
- for a in mats:
- if isinstance(a, (list, numbers.Number)):
- a = coo_matrix(a)
- nrows, ncols = a.shape
- if issparse(a):
- a = a.tocoo()
- row.append(a.row + r_idx)
- col.append(a.col + c_idx)
- data.append(a.data)
- else:
- a_row, a_col = np.divmod(np.arange(nrows*ncols), ncols)
- row.append(a_row + r_idx)
- col.append(a_col + c_idx)
- data.append(a.ravel())
- r_idx += nrows
- c_idx += ncols
- row = np.concatenate(row)
- col = np.concatenate(col)
- data = np.concatenate(data)
- return coo_matrix((data, (row, col)),
- shape=(r_idx, c_idx),
- dtype=dtype).asformat(format)
- def random(m, n, density=0.01, format='coo', dtype=None,
- random_state=None, data_rvs=None):
- """Generate a sparse matrix of the given shape and density with randomly
- distributed values.
- Parameters
- ----------
- m, n : int
- shape of the matrix
- density : real, optional
- density of the generated matrix: density equal to one means a full
- matrix, density of 0 means a matrix with no non-zero items.
- format : str, optional
- sparse matrix format.
- dtype : dtype, optional
- type of the returned matrix values.
- random_state : {None, int, `numpy.random.Generator`,
- `numpy.random.RandomState`}, optional
- If `seed` is None (or `np.random`), the `numpy.random.RandomState`
- singleton is used.
- If `seed` is an int, a new ``RandomState`` instance is used,
- seeded with `seed`.
- If `seed` is already a ``Generator`` or ``RandomState`` instance then
- that instance is used.
- This random state will be used
- for sampling the sparsity structure, but not necessarily for sampling
- the values of the structurally nonzero entries of the matrix.
- data_rvs : callable, optional
- Samples a requested number of random values.
- This function should take a single argument specifying the length
- of the ndarray that it will return. The structurally nonzero entries
- of the sparse random matrix will be taken from the array sampled
- by this function. By default, uniform [0, 1) random values will be
- sampled using the same random state as is used for sampling
- the sparsity structure.
- Returns
- -------
- res : sparse matrix
- Notes
- -----
- Only float types are supported for now.
- Examples
- --------
- >>> from scipy.sparse import random
- >>> from scipy import stats
- >>> from numpy.random import default_rng
- >>> rng = default_rng()
- >>> rvs = stats.poisson(25, loc=10).rvs
- >>> S = random(3, 4, density=0.25, random_state=rng, data_rvs=rvs)
- >>> S.A
- array([[ 36., 0., 33., 0.], # random
- [ 0., 0., 0., 0.],
- [ 0., 0., 36., 0.]])
- >>> from scipy.sparse import random
- >>> from scipy.stats import rv_continuous
- >>> class CustomDistribution(rv_continuous):
- ... def _rvs(self, size=None, random_state=None):
- ... return random_state.standard_normal(size)
- >>> X = CustomDistribution(seed=rng)
- >>> Y = X() # get a frozen version of the distribution
- >>> S = random(3, 4, density=0.25, random_state=rng, data_rvs=Y.rvs)
- >>> S.A
- array([[ 0. , 0. , 0. , 0. ], # random
- [ 0.13569738, 1.9467163 , -0.81205367, 0. ],
- [ 0. , 0. , 0. , 0. ]])
- """
- if density < 0 or density > 1:
- raise ValueError("density expected to be 0 <= density <= 1")
- dtype = np.dtype(dtype)
- mn = m * n
- tp = np.intc
- if mn > np.iinfo(tp).max:
- tp = np.int64
- if mn > np.iinfo(tp).max:
- msg = """\
- Trying to generate a random sparse matrix such as the product of dimensions is
- greater than %d - this is not supported on this machine
- """
- raise ValueError(msg % np.iinfo(tp).max)
- # Number of non zero values
- k = int(round(density * m * n))
- random_state = check_random_state(random_state)
- if data_rvs is None:
- if np.issubdtype(dtype, np.integer):
- def data_rvs(n):
- return rng_integers(random_state,
- np.iinfo(dtype).min,
- np.iinfo(dtype).max,
- n,
- dtype=dtype)
- elif np.issubdtype(dtype, np.complexfloating):
- def data_rvs(n):
- return (random_state.uniform(size=n) +
- random_state.uniform(size=n) * 1j)
- else:
- data_rvs = partial(random_state.uniform, 0., 1.)
- ind = random_state.choice(mn, size=k, replace=False)
- j = np.floor(ind * 1. / m).astype(tp, copy=False)
- i = (ind - j * m).astype(tp, copy=False)
- vals = data_rvs(k).astype(dtype, copy=False)
- return coo_matrix((vals, (i, j)), shape=(m, n)).asformat(format,
- copy=False)
- def rand(m, n, density=0.01, format="coo", dtype=None, random_state=None):
- """Generate a sparse matrix of the given shape and density with uniformly
- distributed values.
- Parameters
- ----------
- m, n : int
- shape of the matrix
- density : real, optional
- density of the generated matrix: density equal to one means a full
- matrix, density of 0 means a matrix with no non-zero items.
- format : str, optional
- sparse matrix format.
- dtype : dtype, optional
- type of the returned matrix values.
- random_state : {None, int, `numpy.random.Generator`,
- `numpy.random.RandomState`}, optional
- If `seed` is None (or `np.random`), the `numpy.random.RandomState`
- singleton is used.
- If `seed` is an int, a new ``RandomState`` instance is used,
- seeded with `seed`.
- If `seed` is already a ``Generator`` or ``RandomState`` instance then
- that instance is used.
- Returns
- -------
- res : sparse matrix
- Notes
- -----
- Only float types are supported for now.
- See Also
- --------
- scipy.sparse.random : Similar function that allows a user-specified random
- data source.
- Examples
- --------
- >>> from scipy.sparse import rand
- >>> matrix = rand(3, 4, density=0.25, format="csr", random_state=42)
- >>> matrix
- <3x4 sparse matrix of type '<class 'numpy.float64'>'
- with 3 stored elements in Compressed Sparse Row format>
- >>> matrix.toarray()
- array([[0.05641158, 0. , 0. , 0.65088847],
- [0. , 0. , 0. , 0.14286682],
- [0. , 0. , 0. , 0. ]])
- """
- return random(m, n, density, format, dtype, random_state)
|