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

354 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-03-22 06:44 +0000

1"""Functions to construct sparse matrices and arrays 

2""" 

3 

4__docformat__ = "restructuredtext en" 

5 

6__all__ = ['spdiags', 'eye', 'identity', 'kron', 'kronsum', 

7 'hstack', 'vstack', 'bmat', 'rand', 'random', 'diags', 'block_diag', 

8 'diags_array', 'block_array', 'eye_array', 'random_array'] 

9 

10import numbers 

11import math 

12import numpy as np 

13 

14from scipy._lib._util import check_random_state, rng_integers 

15from ._sputils import upcast, get_index_dtype, isscalarlike 

16 

17from ._sparsetools import csr_hstack 

18from ._bsr import bsr_matrix, bsr_array 

19from ._coo import coo_matrix, coo_array 

20from ._csc import csc_matrix, csc_array 

21from ._csr import csr_matrix, csr_array 

22from ._dia import dia_matrix, dia_array 

23 

24from ._base import issparse, sparray 

25 

26 

27def spdiags(data, diags, m=None, n=None, format=None): 

28 """ 

29 Return a sparse matrix from diagonals. 

30 

31 Parameters 

32 ---------- 

33 data : array_like 

34 Matrix diagonals stored row-wise 

35 diags : sequence of int or an int 

36 Diagonals to set: 

37 

38 * k = 0 the main diagonal 

39 * k > 0 the kth upper diagonal 

40 * k < 0 the kth lower diagonal 

41 m, n : int, tuple, optional 

42 Shape of the result. If `n` is None and `m` is a given tuple, 

43 the shape is this tuple. If omitted, the matrix is square and 

44 its shape is len(data[0]). 

45 format : str, optional 

46 Format of the result. By default (format=None) an appropriate sparse 

47 matrix format is returned. This choice is subject to change. 

48 

49 .. warning:: 

50 

51 This function returns a sparse matrix -- not a sparse array. 

52 You are encouraged to use ``diags_array`` to take advantage 

53 of the sparse array functionality. 

54 

55 See Also 

56 -------- 

57 diags_array : more convenient form of this function 

58 diags : matrix version of diags_array 

59 dia_matrix : the sparse DIAgonal format. 

60 

61 Examples 

62 -------- 

63 >>> import numpy as np 

64 >>> from scipy.sparse import spdiags 

65 >>> data = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]) 

66 >>> diags = np.array([0, -1, 2]) 

67 >>> spdiags(data, diags, 4, 4).toarray() 

68 array([[1, 0, 3, 0], 

69 [1, 2, 0, 4], 

70 [0, 2, 3, 0], 

71 [0, 0, 3, 4]]) 

72 

73 """ 

74 if m is None and n is None: 

75 m = n = len(data[0]) 

76 elif n is None: 

77 m, n = m 

78 return dia_matrix((data, diags), shape=(m, n)).asformat(format) 

79 

80 

81def diags_array(diagonals, /, *, offsets=0, shape=None, format=None, dtype=None): 

82 """ 

83 Construct a sparse array from diagonals. 

84 

85 Parameters 

86 ---------- 

87 diagonals : sequence of array_like 

88 Sequence of arrays containing the array diagonals, 

89 corresponding to `offsets`. 

90 offsets : sequence of int or an int, optional 

91 Diagonals to set: 

92 - k = 0 the main diagonal (default) 

93 - k > 0 the kth upper diagonal 

94 - k < 0 the kth lower diagonal 

95 shape : tuple of int, optional 

96 Shape of the result. If omitted, a square array large enough 

97 to contain the diagonals is returned. 

98 format : {"dia", "csr", "csc", "lil", ...}, optional 

99 Matrix format of the result. By default (format=None) an 

100 appropriate sparse array format is returned. This choice is 

101 subject to change. 

102 dtype : dtype, optional 

103 Data type of the array. 

104 

105 Notes 

106 ----- 

107 The result from `diags_array` is the sparse equivalent of:: 

108 

109 np.diag(diagonals[0], offsets[0]) 

110 + ... 

111 + np.diag(diagonals[k], offsets[k]) 

112 

113 Repeated diagonal offsets are disallowed. 

114 

115 .. versionadded:: 1.11 

116 

117 Examples 

118 -------- 

119 >>> from scipy.sparse import diags_array 

120 >>> diagonals = [[1, 2, 3, 4], [1, 2, 3], [1, 2]] 

121 >>> diags_array(diagonals, offsets=[0, -1, 2]).toarray() 

122 array([[1, 0, 1, 0], 

123 [1, 2, 0, 2], 

124 [0, 2, 3, 0], 

125 [0, 0, 3, 4]]) 

126 

127 Broadcasting of scalars is supported (but shape needs to be 

128 specified): 

129 

130 >>> diags_array([1, -2, 1], offsets=[-1, 0, 1], shape=(4, 4)).toarray() 

131 array([[-2., 1., 0., 0.], 

132 [ 1., -2., 1., 0.], 

133 [ 0., 1., -2., 1.], 

134 [ 0., 0., 1., -2.]]) 

135 

136 

137 If only one diagonal is wanted (as in `numpy.diag`), the following 

138 works as well: 

139 

140 >>> diags_array([1, 2, 3], offsets=1).toarray() 

141 array([[ 0., 1., 0., 0.], 

142 [ 0., 0., 2., 0.], 

143 [ 0., 0., 0., 3.], 

144 [ 0., 0., 0., 0.]]) 

145 """ 

146 # if offsets is not a sequence, assume that there's only one diagonal 

147 if isscalarlike(offsets): 

148 # now check that there's actually only one diagonal 

149 if len(diagonals) == 0 or isscalarlike(diagonals[0]): 

150 diagonals = [np.atleast_1d(diagonals)] 

151 else: 

152 raise ValueError("Different number of diagonals and offsets.") 

153 else: 

154 diagonals = list(map(np.atleast_1d, diagonals)) 

155 

156 offsets = np.atleast_1d(offsets) 

157 

158 # Basic check 

159 if len(diagonals) != len(offsets): 

160 raise ValueError("Different number of diagonals and offsets.") 

161 

162 # Determine shape, if omitted 

163 if shape is None: 

164 m = len(diagonals[0]) + abs(int(offsets[0])) 

165 shape = (m, m) 

166 

167 # Determine data type, if omitted 

168 if dtype is None: 

169 dtype = np.common_type(*diagonals) 

170 

171 # Construct data array 

172 m, n = shape 

173 

174 M = max([min(m + offset, n - offset) + max(0, offset) 

175 for offset in offsets]) 

176 M = max(0, M) 

177 data_arr = np.zeros((len(offsets), M), dtype=dtype) 

178 

179 K = min(m, n) 

180 

181 for j, diagonal in enumerate(diagonals): 

182 offset = offsets[j] 

183 k = max(0, offset) 

184 length = min(m + offset, n - offset, K) 

185 if length < 0: 

186 raise ValueError("Offset %d (index %d) out of bounds" % (offset, j)) 

187 try: 

188 data_arr[j, k:k+length] = diagonal[...,:length] 

189 except ValueError as e: 

190 if len(diagonal) != length and len(diagonal) != 1: 

191 raise ValueError( 

192 "Diagonal length (index %d: %d at offset %d) does not " 

193 "agree with array size (%d, %d)." % ( 

194 j, len(diagonal), offset, m, n)) from e 

195 raise 

196 

197 return dia_array((data_arr, offsets), shape=(m, n)).asformat(format) 

198 

199 

200def diags(diagonals, offsets=0, shape=None, format=None, dtype=None): 

201 """ 

202 Construct a sparse matrix from diagonals. 

203 

204 .. warning:: 

205 

206 This function returns a sparse matrix -- not a sparse array. 

207 You are encouraged to use ``diags_array`` to take advantage 

208 of the sparse array functionality. 

209 

210 Parameters 

211 ---------- 

212 diagonals : sequence of array_like 

213 Sequence of arrays containing the matrix diagonals, 

214 corresponding to `offsets`. 

215 offsets : sequence of int or an int, optional 

216 Diagonals to set: 

217 - k = 0 the main diagonal (default) 

218 - k > 0 the kth upper diagonal 

219 - k < 0 the kth lower diagonal 

220 shape : tuple of int, optional 

221 Shape of the result. If omitted, a square matrix large enough 

222 to contain the diagonals is returned. 

223 format : {"dia", "csr", "csc", "lil", ...}, optional 

224 Matrix format of the result. By default (format=None) an 

225 appropriate sparse matrix format is returned. This choice is 

226 subject to change. 

227 dtype : dtype, optional 

228 Data type of the matrix. 

229 

230 See Also 

231 -------- 

232 spdiags : construct matrix from diagonals 

233 diags_array : construct sparse array instead of sparse matrix 

234 

235 Notes 

236 ----- 

237 This function differs from `spdiags` in the way it handles 

238 off-diagonals. 

239 

240 The result from `diags` is the sparse equivalent of:: 

241 

242 np.diag(diagonals[0], offsets[0]) 

243 + ... 

244 + np.diag(diagonals[k], offsets[k]) 

245 

246 Repeated diagonal offsets are disallowed. 

247 

248 .. versionadded:: 0.11 

249 

250 Examples 

251 -------- 

252 >>> from scipy.sparse import diags 

253 >>> diagonals = [[1, 2, 3, 4], [1, 2, 3], [1, 2]] 

254 >>> diags(diagonals, [0, -1, 2]).toarray() 

255 array([[1, 0, 1, 0], 

256 [1, 2, 0, 2], 

257 [0, 2, 3, 0], 

258 [0, 0, 3, 4]]) 

259 

260 Broadcasting of scalars is supported (but shape needs to be 

261 specified): 

262 

263 >>> diags([1, -2, 1], [-1, 0, 1], shape=(4, 4)).toarray() 

264 array([[-2., 1., 0., 0.], 

265 [ 1., -2., 1., 0.], 

266 [ 0., 1., -2., 1.], 

267 [ 0., 0., 1., -2.]]) 

268 

269 

270 If only one diagonal is wanted (as in `numpy.diag`), the following 

271 works as well: 

272 

273 >>> diags([1, 2, 3], 1).toarray() 

274 array([[ 0., 1., 0., 0.], 

275 [ 0., 0., 2., 0.], 

276 [ 0., 0., 0., 3.], 

277 [ 0., 0., 0., 0.]]) 

278 """ 

279 A = diags_array(diagonals, offsets=offsets, shape=shape, dtype=dtype) 

280 return dia_matrix(A).asformat(format) 

281 

282 

283def identity(n, dtype='d', format=None): 

284 """Identity matrix in sparse format 

285 

286 Returns an identity matrix with shape (n,n) using a given 

287 sparse format and dtype. This differs from `eye_array` in 

288 that it has a square shape with ones only on the main diagonal. 

289 It is thus the multiplicative identity. `eye_array` allows 

290 rectangular shapes and the diagonal can be offset from the main one. 

291 

292 .. warning:: 

293 

294 This function returns a sparse matrix -- not a sparse array. 

295 You are encouraged to use ``eye_array`` to take advantage 

296 of the sparse array functionality. 

297 

298 Parameters 

299 ---------- 

300 n : int 

301 Shape of the identity matrix. 

302 dtype : dtype, optional 

303 Data type of the matrix 

304 format : str, optional 

305 Sparse format of the result, e.g., format="csr", etc. 

306 

307 Examples 

308 -------- 

309 >>> import scipy as sp 

310 >>> sp.sparse.identity(3).toarray() 

311 array([[ 1., 0., 0.], 

312 [ 0., 1., 0.], 

313 [ 0., 0., 1.]]) 

314 >>> sp.sparse.identity(3, dtype='int8', format='dia') 

315 <3x3 sparse matrix of type '<class 'numpy.int8'>' 

316 with 3 stored elements (1 diagonals) in DIAgonal format> 

317 >>> sp.sparse.eye_array(3, dtype='int8', format='dia') 

318 <3x3 sparse array of type '<class 'numpy.int8'>' 

319 with 3 stored elements (1 diagonals) in DIAgonal format> 

320 

321 """ 

322 return eye(n, n, dtype=dtype, format=format) 

323 

324 

325def eye_array(m, n=None, *, k=0, dtype=float, format=None): 

326 """Identity matrix in sparse array format 

327 

328 Return a sparse array with ones on diagonal. 

329 Specifically a sparse array (m x n) where the kth diagonal 

330 is all ones and everything else is zeros. 

331 

332 Parameters 

333 ---------- 

334 m : int or tuple of ints 

335 Number of rows requested. 

336 n : int, optional 

337 Number of columns. Default: `m`. 

338 k : int, optional 

339 Diagonal to place ones on. Default: 0 (main diagonal). 

340 dtype : dtype, optional 

341 Data type of the array 

342 format : str, optional (default: "dia") 

343 Sparse format of the result, e.g., format="csr", etc. 

344 

345 Examples 

346 -------- 

347 >>> import numpy as np 

348 >>> import scipy as sp 

349 >>> sp.sparse.eye_array(3).toarray() 

350 array([[ 1., 0., 0.], 

351 [ 0., 1., 0.], 

352 [ 0., 0., 1.]]) 

353 >>> sp.sparse.eye_array(3, dtype=np.int8) 

354 <3x3 sparse array of type '<class 'numpy.int8'>' 

355 with 3 stored elements (1 diagonals) in DIAgonal format> 

356 

357 """ 

358 # TODO: delete next 15 lines [combine with _eye()] once spmatrix removed 

359 return _eye(m, n, k, dtype, format) 

360 

361 

362def _eye(m, n, k, dtype, format, as_sparray=True): 

363 if as_sparray: 

364 csr_sparse = csr_array 

365 csc_sparse = csc_array 

366 coo_sparse = coo_array 

367 diags_sparse = diags_array 

368 else: 

369 csr_sparse = csr_matrix 

370 csc_sparse = csc_matrix 

371 coo_sparse = coo_matrix 

372 diags_sparse = diags 

373 

374 if n is None: 

375 n = m 

376 m, n = int(m), int(n) 

377 

378 if m == n and k == 0: 

379 # fast branch for special formats 

380 if format in ['csr', 'csc']: 

381 idx_dtype = get_index_dtype(maxval=n) 

382 indptr = np.arange(n+1, dtype=idx_dtype) 

383 indices = np.arange(n, dtype=idx_dtype) 

384 data = np.ones(n, dtype=dtype) 

385 cls = {'csr': csr_sparse, 'csc': csc_sparse}[format] 

386 return cls((data, indices, indptr), (n, n)) 

387 

388 elif format == 'coo': 

389 idx_dtype = get_index_dtype(maxval=n) 

390 row = np.arange(n, dtype=idx_dtype) 

391 col = np.arange(n, dtype=idx_dtype) 

392 data = np.ones(n, dtype=dtype) 

393 return coo_sparse((data, (row, col)), (n, n)) 

394 

395 data = np.ones((1, max(0, min(m + k, n))), dtype=dtype) 

396 return diags_sparse(data, offsets=[k], shape=(m, n), dtype=dtype).asformat(format) 

397 

398 

399def eye(m, n=None, k=0, dtype=float, format=None): 

400 """Sparse matrix with ones on diagonal 

401 

402 Returns a sparse matrix (m x n) where the kth diagonal 

403 is all ones and everything else is zeros. 

404 

405 Parameters 

406 ---------- 

407 m : int 

408 Number of rows in the matrix. 

409 n : int, optional 

410 Number of columns. Default: `m`. 

411 k : int, optional 

412 Diagonal to place ones on. Default: 0 (main diagonal). 

413 dtype : dtype, optional 

414 Data type of the matrix. 

415 format : str, optional 

416 Sparse format of the result, e.g., format="csr", etc. 

417 

418 .. warning:: 

419 

420 This function returns a sparse matrix -- not a sparse array. 

421 You are encouraged to use ``eye_array`` to take advantage 

422 of the sparse array functionality. 

423 

424 Examples 

425 -------- 

426 >>> import numpy as np 

427 >>> import scipy as sp 

428 >>> sp.sparse.eye(3).toarray() 

429 array([[ 1., 0., 0.], 

430 [ 0., 1., 0.], 

431 [ 0., 0., 1.]]) 

432 >>> sp.sparse.eye(3, dtype=np.int8) 

433 <3x3 sparse matrix of type '<class 'numpy.int8'>' 

434 with 3 stored elements (1 diagonals) in DIAgonal format> 

435 

436 """ 

437 return _eye(m, n, k, dtype, format, False) 

438 

439 

440def kron(A, B, format=None): 

441 """kronecker product of sparse matrices A and B 

442 

443 Parameters 

444 ---------- 

445 A : sparse or dense matrix 

446 first matrix of the product 

447 B : sparse or dense matrix 

448 second matrix of the product 

449 format : str, optional (default: 'bsr' or 'coo') 

450 format of the result (e.g. "csr") 

451 If None, choose 'bsr' for relatively dense array and 'coo' for others 

452 

453 Returns 

454 ------- 

455 kronecker product in a sparse format. 

456 Returns a sparse matrix unless either A or B is a 

457 sparse array in which case returns a sparse array. 

458 

459 Examples 

460 -------- 

461 >>> import numpy as np 

462 >>> import scipy as sp 

463 >>> A = sp.sparse.csr_array(np.array([[0, 2], [5, 0]])) 

464 >>> B = sp.sparse.csr_array(np.array([[1, 2], [3, 4]])) 

465 >>> sp.sparse.kron(A, B).toarray() 

466 array([[ 0, 0, 2, 4], 

467 [ 0, 0, 6, 8], 

468 [ 5, 10, 0, 0], 

469 [15, 20, 0, 0]]) 

470 

471 >>> sp.sparse.kron(A, [[1, 2], [3, 4]]).toarray() 

472 array([[ 0, 0, 2, 4], 

473 [ 0, 0, 6, 8], 

474 [ 5, 10, 0, 0], 

475 [15, 20, 0, 0]]) 

476 

477 """ 

478 # TODO: delete next 10 lines and replace _sparse with _array when spmatrix removed 

479 if isinstance(A, sparray) or isinstance(B, sparray): 

480 # convert to local variables 

481 bsr_sparse = bsr_array 

482 csr_sparse = csr_array 

483 coo_sparse = coo_array 

484 else: # use spmatrix 

485 bsr_sparse = bsr_matrix 

486 csr_sparse = csr_matrix 

487 coo_sparse = coo_matrix 

488 

489 B = coo_sparse(B) 

490 

491 # B is fairly dense, use BSR 

492 if (format is None or format == "bsr") and 2*B.nnz >= B.shape[0] * B.shape[1]: 

493 A = csr_sparse(A,copy=True) 

494 output_shape = (A.shape[0]*B.shape[0], A.shape[1]*B.shape[1]) 

495 

496 if A.nnz == 0 or B.nnz == 0: 

497 # kronecker product is the zero matrix 

498 return coo_sparse(output_shape).asformat(format) 

499 

500 B = B.toarray() 

501 data = A.data.repeat(B.size).reshape(-1,B.shape[0],B.shape[1]) 

502 data = data * B 

503 

504 return bsr_sparse((data,A.indices,A.indptr), shape=output_shape) 

505 else: 

506 # use COO 

507 A = coo_sparse(A) 

508 output_shape = (A.shape[0]*B.shape[0], A.shape[1]*B.shape[1]) 

509 

510 if A.nnz == 0 or B.nnz == 0: 

511 # kronecker product is the zero matrix 

512 return coo_sparse(output_shape).asformat(format) 

513 

514 # expand entries of a into blocks 

515 row = A.row.repeat(B.nnz) 

516 col = A.col.repeat(B.nnz) 

517 data = A.data.repeat(B.nnz) 

518 

519 if max(A.shape[0]*B.shape[0], A.shape[1]*B.shape[1]) > np.iinfo('int32').max: 

520 row = row.astype(np.int64) 

521 col = col.astype(np.int64) 

522 

523 row *= B.shape[0] 

524 col *= B.shape[1] 

525 

526 # increment block indices 

527 row,col = row.reshape(-1,B.nnz),col.reshape(-1,B.nnz) 

528 row += B.row 

529 col += B.col 

530 row,col = row.reshape(-1),col.reshape(-1) 

531 

532 # compute block entries 

533 data = data.reshape(-1,B.nnz) * B.data 

534 data = data.reshape(-1) 

535 

536 return coo_sparse((data,(row,col)), shape=output_shape).asformat(format) 

537 

538 

539def kronsum(A, B, format=None): 

540 """kronecker sum of square sparse matrices A and B 

541 

542 Kronecker sum of two sparse matrices is a sum of two Kronecker 

543 products kron(I_n,A) + kron(B,I_m) where A has shape (m,m) 

544 and B has shape (n,n) and I_m and I_n are identity matrices 

545 of shape (m,m) and (n,n), respectively. 

546 

547 Parameters 

548 ---------- 

549 A 

550 square matrix 

551 B 

552 square matrix 

553 format : str 

554 format of the result (e.g. "csr") 

555 

556 Returns 

557 ------- 

558 kronecker sum in a sparse matrix format 

559 

560 """ 

561 # TODO: delete next 8 lines and replace _sparse with _array when spmatrix removed 

562 if isinstance(A, sparray) or isinstance(B, sparray): 

563 # convert to local variables 

564 coo_sparse = coo_array 

565 identity_sparse = eye_array 

566 else: 

567 coo_sparse = coo_matrix 

568 identity_sparse = identity 

569 

570 A = coo_sparse(A) 

571 B = coo_sparse(B) 

572 

573 if A.shape[0] != A.shape[1]: 

574 raise ValueError('A is not square') 

575 

576 if B.shape[0] != B.shape[1]: 

577 raise ValueError('B is not square') 

578 

579 dtype = upcast(A.dtype, B.dtype) 

580 

581 I_n = identity_sparse(A.shape[0], dtype=dtype) 

582 I_m = identity_sparse(B.shape[0], dtype=dtype) 

583 L = kron(I_m, A, format='coo') 

584 R = kron(B, I_n, format='coo') 

585 

586 return (L + R).asformat(format) 

587 

588 

589def _compressed_sparse_stack(blocks, axis, return_spmatrix): 

590 """ 

591 Stacking fast path for CSR/CSC matrices or arrays 

592 (i) vstack for CSR, (ii) hstack for CSC. 

593 """ 

594 other_axis = 1 if axis == 0 else 0 

595 data = np.concatenate([b.data for b in blocks]) 

596 constant_dim = blocks[0].shape[other_axis] 

597 idx_dtype = get_index_dtype(arrays=[b.indptr for b in blocks], 

598 maxval=max(data.size, constant_dim)) 

599 indices = np.empty(data.size, dtype=idx_dtype) 

600 indptr = np.empty(sum(b.shape[axis] for b in blocks) + 1, dtype=idx_dtype) 

601 last_indptr = idx_dtype(0) 

602 sum_dim = 0 

603 sum_indices = 0 

604 for b in blocks: 

605 if b.shape[other_axis] != constant_dim: 

606 raise ValueError(f'incompatible dimensions for axis {other_axis}') 

607 indices[sum_indices:sum_indices+b.indices.size] = b.indices 

608 sum_indices += b.indices.size 

609 idxs = slice(sum_dim, sum_dim + b.shape[axis]) 

610 indptr[idxs] = b.indptr[:-1] 

611 indptr[idxs] += last_indptr 

612 sum_dim += b.shape[axis] 

613 last_indptr += b.indptr[-1] 

614 indptr[-1] = last_indptr 

615 # TODO remove this if-structure when sparse matrices removed 

616 if return_spmatrix: 

617 if axis == 0: 

618 return csr_matrix((data, indices, indptr), 

619 shape=(sum_dim, constant_dim)) 

620 else: 

621 return csc_matrix((data, indices, indptr), 

622 shape=(constant_dim, sum_dim)) 

623 

624 if axis == 0: 

625 return csr_array((data, indices, indptr), 

626 shape=(sum_dim, constant_dim)) 

627 else: 

628 return csc_array((data, indices, indptr), 

629 shape=(constant_dim, sum_dim)) 

630 

631 

632def _stack_along_minor_axis(blocks, axis): 

633 """ 

634 Stacking fast path for CSR/CSC matrices along the minor axis 

635 (i) hstack for CSR, (ii) vstack for CSC. 

636 """ 

637 n_blocks = len(blocks) 

638 if n_blocks == 0: 

639 raise ValueError('Missing block matrices') 

640 

641 if n_blocks == 1: 

642 return blocks[0] 

643 

644 # check for incompatible dimensions 

645 other_axis = 1 if axis == 0 else 0 

646 other_axis_dims = {b.shape[other_axis] for b in blocks} 

647 if len(other_axis_dims) > 1: 

648 raise ValueError(f'Mismatching dimensions along axis {other_axis}: ' 

649 f'{other_axis_dims}') 

650 constant_dim, = other_axis_dims 

651 

652 # Do the stacking 

653 indptr_list = [b.indptr for b in blocks] 

654 data_cat = np.concatenate([b.data for b in blocks]) 

655 

656 # Need to check if any indices/indptr, would be too large post- 

657 # concatenation for np.int32: 

658 # - The max value of indices is the output array's stacking-axis length - 1 

659 # - The max value in indptr is the number of non-zero entries. This is 

660 # exceedingly unlikely to require int64, but is checked out of an 

661 # abundance of caution. 

662 sum_dim = sum(b.shape[axis] for b in blocks) 

663 nnz = sum(len(b.indices) for b in blocks) 

664 idx_dtype = get_index_dtype(maxval=max(sum_dim - 1, nnz)) 

665 stack_dim_cat = np.array([b.shape[axis] for b in blocks], dtype=idx_dtype) 

666 if data_cat.size > 0: 

667 indptr_cat = np.concatenate(indptr_list).astype(idx_dtype) 

668 indices_cat = (np.concatenate([b.indices for b in blocks]) 

669 .astype(idx_dtype)) 

670 indptr = np.empty(constant_dim + 1, dtype=idx_dtype) 

671 indices = np.empty_like(indices_cat) 

672 data = np.empty_like(data_cat) 

673 csr_hstack(n_blocks, constant_dim, stack_dim_cat, 

674 indptr_cat, indices_cat, data_cat, 

675 indptr, indices, data) 

676 else: 

677 indptr = np.zeros(constant_dim + 1, dtype=idx_dtype) 

678 indices = np.empty(0, dtype=idx_dtype) 

679 data = np.empty(0, dtype=data_cat.dtype) 

680 

681 if axis == 0: 

682 return blocks[0]._csc_container((data, indices, indptr), 

683 shape=(sum_dim, constant_dim)) 

684 else: 

685 return blocks[0]._csr_container((data, indices, indptr), 

686 shape=(constant_dim, sum_dim)) 

687 

688 

689def hstack(blocks, format=None, dtype=None): 

690 """ 

691 Stack sparse matrices horizontally (column wise) 

692 

693 Parameters 

694 ---------- 

695 blocks 

696 sequence of sparse matrices with compatible shapes 

697 format : str 

698 sparse format of the result (e.g., "csr") 

699 by default an appropriate sparse matrix format is returned. 

700 This choice is subject to change. 

701 dtype : dtype, optional 

702 The data-type of the output matrix. If not given, the dtype is 

703 determined from that of `blocks`. 

704 

705 Returns 

706 ------- 

707 new_array : sparse matrix or array 

708 If any block in blocks is a sparse array, return a sparse array. 

709 Otherwise return a sparse matrix. 

710 

711 If you want a sparse array built from blocks that are not sparse 

712 arrays, use `block(hstack(blocks))` or convert one block 

713 e.g. `blocks[0] = csr_array(blocks[0])`. 

714 

715 See Also 

716 -------- 

717 vstack : stack sparse matrices vertically (row wise) 

718 

719 Examples 

720 -------- 

721 >>> from scipy.sparse import coo_matrix, hstack 

722 >>> A = coo_matrix([[1, 2], [3, 4]]) 

723 >>> B = coo_matrix([[5], [6]]) 

724 >>> hstack([A,B]).toarray() 

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

726 [3, 4, 6]]) 

727 

728 """ 

729 blocks = np.asarray(blocks, dtype='object') 

730 if any(isinstance(b, sparray) for b in blocks.flat): 

731 return _block([blocks], format, dtype) 

732 else: 

733 return _block([blocks], format, dtype, return_spmatrix=True) 

734 

735 

736def vstack(blocks, format=None, dtype=None): 

737 """ 

738 Stack sparse arrays vertically (row wise) 

739 

740 Parameters 

741 ---------- 

742 blocks 

743 sequence of sparse arrays with compatible shapes 

744 format : str, optional 

745 sparse format of the result (e.g., "csr") 

746 by default an appropriate sparse array format is returned. 

747 This choice is subject to change. 

748 dtype : dtype, optional 

749 The data-type of the output array. If not given, the dtype is 

750 determined from that of `blocks`. 

751 

752 Returns 

753 ------- 

754 new_array : sparse matrix or array 

755 If any block in blocks is a sparse array, return a sparse array. 

756 Otherwise return a sparse matrix. 

757 

758 If you want a sparse array built from blocks that are not sparse 

759 arrays, use `block(vstack(blocks))` or convert one block 

760 e.g. `blocks[0] = csr_array(blocks[0])`. 

761 

762 See Also 

763 -------- 

764 hstack : stack sparse matrices horizontally (column wise) 

765 

766 Examples 

767 -------- 

768 >>> from scipy.sparse import coo_array, vstack 

769 >>> A = coo_array([[1, 2], [3, 4]]) 

770 >>> B = coo_array([[5, 6]]) 

771 >>> vstack([A, B]).toarray() 

772 array([[1, 2], 

773 [3, 4], 

774 [5, 6]]) 

775 

776 """ 

777 blocks = np.asarray(blocks, dtype='object') 

778 if any(isinstance(b, sparray) for b in blocks.flat): 

779 return _block([[b] for b in blocks], format, dtype) 

780 else: 

781 return _block([[b] for b in blocks], format, dtype, return_spmatrix=True) 

782 

783 

784def bmat(blocks, format=None, dtype=None): 

785 """ 

786 Build a sparse array or matrix from sparse sub-blocks 

787 

788 Note: `block_array` is preferred over `bmat`. They are the same function 

789 except that `bmat` can return a deprecated sparse matrix. 

790 `bmat` returns a coo_matrix if none of the inputs are a sparse array. 

791 

792 .. warning:: 

793 

794 This function returns a sparse matrix -- not a sparse array. 

795 You are encouraged to use ``block_array`` to take advantage 

796 of the sparse array functionality. 

797 

798 Parameters 

799 ---------- 

800 blocks : array_like 

801 Grid of sparse matrices with compatible shapes. 

802 An entry of None implies an all-zero matrix. 

803 format : {'bsr', 'coo', 'csc', 'csr', 'dia', 'dok', 'lil'}, optional 

804 The sparse format of the result (e.g. "csr"). By default an 

805 appropriate sparse matrix format is returned. 

806 This choice is subject to change. 

807 dtype : dtype, optional 

808 The data-type of the output matrix. If not given, the dtype is 

809 determined from that of `blocks`. 

810 

811 Returns 

812 ------- 

813 bmat : sparse matrix or array 

814 If any block in blocks is a sparse array, return a sparse array. 

815 Otherwise return a sparse matrix. 

816 

817 If you want a sparse array built from blocks that are not sparse 

818 arrays, use `block_array()`. 

819 

820 See Also 

821 -------- 

822 block_array 

823 

824 Examples 

825 -------- 

826 >>> from scipy.sparse import coo_array, bmat 

827 >>> A = coo_array([[1, 2], [3, 4]]) 

828 >>> B = coo_array([[5], [6]]) 

829 >>> C = coo_array([[7]]) 

830 >>> bmat([[A, B], [None, C]]).toarray() 

831 array([[1, 2, 5], 

832 [3, 4, 6], 

833 [0, 0, 7]]) 

834 

835 >>> bmat([[A, None], [None, C]]).toarray() 

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

837 [3, 4, 0], 

838 [0, 0, 7]]) 

839 

840 """ 

841 blocks = np.asarray(blocks, dtype='object') 

842 if any(isinstance(b, sparray) for b in blocks.flat): 

843 return _block(blocks, format, dtype) 

844 else: 

845 return _block(blocks, format, dtype, return_spmatrix=True) 

846 

847 

848def block_array(blocks, *, format=None, dtype=None): 

849 """ 

850 Build a sparse array from sparse sub-blocks 

851 

852 Parameters 

853 ---------- 

854 blocks : array_like 

855 Grid of sparse arrays with compatible shapes. 

856 An entry of None implies an all-zero array. 

857 format : {'bsr', 'coo', 'csc', 'csr', 'dia', 'dok', 'lil'}, optional 

858 The sparse format of the result (e.g. "csr"). By default an 

859 appropriate sparse array format is returned. 

860 This choice is subject to change. 

861 dtype : dtype, optional 

862 The data-type of the output array. If not given, the dtype is 

863 determined from that of `blocks`. 

864 

865 Returns 

866 ------- 

867 block : sparse array 

868 

869 See Also 

870 -------- 

871 block_diag : specify blocks along the main diagonals 

872 diags : specify (possibly offset) diagonals 

873 

874 Examples 

875 -------- 

876 >>> from scipy.sparse import coo_array, block_array 

877 >>> A = coo_array([[1, 2], [3, 4]]) 

878 >>> B = coo_array([[5], [6]]) 

879 >>> C = coo_array([[7]]) 

880 >>> block_array([[A, B], [None, C]]).toarray() 

881 array([[1, 2, 5], 

882 [3, 4, 6], 

883 [0, 0, 7]]) 

884 

885 >>> block_array([[A, None], [None, C]]).toarray() 

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

887 [3, 4, 0], 

888 [0, 0, 7]]) 

889 

890 """ 

891 return _block(blocks, format, dtype) 

892 

893 

894def _block(blocks, format, dtype, return_spmatrix=False): 

895 blocks = np.asarray(blocks, dtype='object') 

896 

897 if blocks.ndim != 2: 

898 raise ValueError('blocks must be 2-D') 

899 

900 M,N = blocks.shape 

901 

902 # check for fast path cases 

903 if (format in (None, 'csr') and 

904 all(issparse(b) and b.format == 'csr' for b in blocks.flat) 

905 ): 

906 if N > 1: 

907 # stack along columns (axis 1): must have shape (M, 1) 

908 blocks = [[_stack_along_minor_axis(blocks[b, :], 1)] for b in range(M)] 

909 blocks = np.asarray(blocks, dtype='object') 

910 

911 # stack along rows (axis 0): 

912 A = _compressed_sparse_stack(blocks[:, 0], 0, return_spmatrix) 

913 if dtype is not None: 

914 A = A.astype(dtype) 

915 return A 

916 elif (format in (None, 'csc') and 

917 all(issparse(b) and b.format == 'csc' for b in blocks.flat) 

918 ): 

919 if M > 1: 

920 # stack along rows (axis 0): must have shape (1, N) 

921 blocks = [[_stack_along_minor_axis(blocks[:, b], 0) for b in range(N)]] 

922 blocks = np.asarray(blocks, dtype='object') 

923 

924 # stack along columns (axis 1): 

925 A = _compressed_sparse_stack(blocks[0, :], 1, return_spmatrix) 

926 if dtype is not None: 

927 A = A.astype(dtype) 

928 return A 

929 

930 block_mask = np.zeros(blocks.shape, dtype=bool) 

931 brow_lengths = np.zeros(M, dtype=np.int64) 

932 bcol_lengths = np.zeros(N, dtype=np.int64) 

933 

934 # convert everything to COO format 

935 for i in range(M): 

936 for j in range(N): 

937 if blocks[i,j] is not None: 

938 A = coo_array(blocks[i,j]) 

939 blocks[i,j] = A 

940 block_mask[i,j] = True 

941 

942 if brow_lengths[i] == 0: 

943 brow_lengths[i] = A.shape[0] 

944 elif brow_lengths[i] != A.shape[0]: 

945 msg = (f'blocks[{i},:] has incompatible row dimensions. ' 

946 f'Got blocks[{i},{j}].shape[0] == {A.shape[0]}, ' 

947 f'expected {brow_lengths[i]}.') 

948 raise ValueError(msg) 

949 

950 if bcol_lengths[j] == 0: 

951 bcol_lengths[j] = A.shape[1] 

952 elif bcol_lengths[j] != A.shape[1]: 

953 msg = (f'blocks[:,{j}] has incompatible column ' 

954 f'dimensions. ' 

955 f'Got blocks[{i},{j}].shape[1] == {A.shape[1]}, ' 

956 f'expected {bcol_lengths[j]}.') 

957 raise ValueError(msg) 

958 

959 nnz = sum(block.nnz for block in blocks[block_mask]) 

960 if dtype is None: 

961 all_dtypes = [blk.dtype for blk in blocks[block_mask]] 

962 dtype = upcast(*all_dtypes) if all_dtypes else None 

963 

964 row_offsets = np.append(0, np.cumsum(brow_lengths)) 

965 col_offsets = np.append(0, np.cumsum(bcol_lengths)) 

966 

967 shape = (row_offsets[-1], col_offsets[-1]) 

968 

969 data = np.empty(nnz, dtype=dtype) 

970 idx_dtype = get_index_dtype(maxval=max(shape)) 

971 row = np.empty(nnz, dtype=idx_dtype) 

972 col = np.empty(nnz, dtype=idx_dtype) 

973 

974 nnz = 0 

975 ii, jj = np.nonzero(block_mask) 

976 for i, j in zip(ii, jj): 

977 B = blocks[i, j] 

978 idx = slice(nnz, nnz + B.nnz) 

979 data[idx] = B.data 

980 np.add(B.row, row_offsets[i], out=row[idx], dtype=idx_dtype) 

981 np.add(B.col, col_offsets[j], out=col[idx], dtype=idx_dtype) 

982 nnz += B.nnz 

983 

984 if return_spmatrix: 

985 return coo_matrix((data, (row, col)), shape=shape).asformat(format) 

986 return coo_array((data, (row, col)), shape=shape).asformat(format) 

987 

988 

989def block_diag(mats, format=None, dtype=None): 

990 """ 

991 Build a block diagonal sparse matrix or array from provided matrices. 

992 

993 Parameters 

994 ---------- 

995 mats : sequence of matrices or arrays 

996 Input matrices or arrays. 

997 format : str, optional 

998 The sparse format of the result (e.g., "csr"). If not given, the result 

999 is returned in "coo" format. 

1000 dtype : dtype specifier, optional 

1001 The data-type of the output. If not given, the dtype is 

1002 determined from that of `blocks`. 

1003 

1004 Returns 

1005 ------- 

1006 res : sparse matrix or array 

1007 If at least one input is a sparse array, the output is a sparse array. 

1008 Otherwise the output is a sparse matrix. 

1009 

1010 Notes 

1011 ----- 

1012 

1013 .. versionadded:: 0.11.0 

1014 

1015 See Also 

1016 -------- 

1017 block_array 

1018 diags_array 

1019 

1020 Examples 

1021 -------- 

1022 >>> from scipy.sparse import coo_array, block_diag 

1023 >>> A = coo_array([[1, 2], [3, 4]]) 

1024 >>> B = coo_array([[5], [6]]) 

1025 >>> C = coo_array([[7]]) 

1026 >>> block_diag((A, B, C)).toarray() 

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

1028 [3, 4, 0, 0], 

1029 [0, 0, 5, 0], 

1030 [0, 0, 6, 0], 

1031 [0, 0, 0, 7]]) 

1032 

1033 """ 

1034 if any(isinstance(a, sparray) for a in mats): 

1035 container = coo_array 

1036 else: 

1037 container = coo_matrix 

1038 

1039 row = [] 

1040 col = [] 

1041 data = [] 

1042 r_idx = 0 

1043 c_idx = 0 

1044 for a in mats: 

1045 if isinstance(a, (list, numbers.Number)): 

1046 a = coo_array(np.atleast_2d(a)) 

1047 if issparse(a): 

1048 a = a.tocoo() 

1049 nrows, ncols = a._shape_as_2d 

1050 row.append(a.row + r_idx) 

1051 col.append(a.col + c_idx) 

1052 data.append(a.data) 

1053 else: 

1054 nrows, ncols = a.shape 

1055 a_row, a_col = np.divmod(np.arange(nrows*ncols), ncols) 

1056 row.append(a_row + r_idx) 

1057 col.append(a_col + c_idx) 

1058 data.append(a.ravel()) 

1059 r_idx += nrows 

1060 c_idx += ncols 

1061 row = np.concatenate(row) 

1062 col = np.concatenate(col) 

1063 data = np.concatenate(data) 

1064 return container((data, (row, col)), 

1065 shape=(r_idx, c_idx), 

1066 dtype=dtype).asformat(format) 

1067 

1068 

1069def random_array(shape, *, density=0.01, format='coo', dtype=None, 

1070 random_state=None, data_sampler=None): 

1071 """Return a sparse array of uniformly random numbers in [0, 1) 

1072 

1073 Returns a sparse array with the given shape and density 

1074 where values are generated uniformly randomly in the range [0, 1). 

1075 

1076 .. warning:: 

1077 

1078 Since numpy 1.17, passing a ``np.random.Generator`` (e.g. 

1079 ``np.random.default_rng``) for ``random_state`` will lead to much 

1080 faster execution times. 

1081 

1082 A much slower implementation is used by default for backwards 

1083 compatibility. 

1084 

1085 Parameters 

1086 ---------- 

1087 shape : int or tuple of ints 

1088 shape of the array 

1089 density : real, optional (default: 0.01) 

1090 density of the generated matrix: density equal to one means a full 

1091 matrix, density of 0 means a matrix with no non-zero items. 

1092 format : str, optional (default: 'coo') 

1093 sparse matrix format. 

1094 dtype : dtype, optional (default: np.float64) 

1095 type of the returned matrix values. 

1096 random_state : {None, int, `Generator`, `RandomState`}, optional 

1097 A random number generator to determine nonzero structure. We recommend using 

1098 a `numpy.random.Generator` manually provided for every call as it is much 

1099 faster than RandomState. 

1100 

1101 - If `None` (or `np.random`), the `numpy.random.RandomState` 

1102 singleton is used. 

1103 - If an int, a new ``Generator`` instance is used, 

1104 seeded with the int. 

1105 - If a ``Generator`` or ``RandomState`` instance then 

1106 that instance is used. 

1107 

1108 This random state will be used for sampling `indices` (the sparsity 

1109 structure), and by default for the data values too (see `data_sampler`). 

1110 

1111 data_sampler : callable, optional (default depends on dtype) 

1112 Sampler of random data values with keyword arg `size`. 

1113 This function should take a single keyword argument `size` specifying 

1114 the length of its returned ndarray. It is used to generate the nonzero 

1115 values in the matrix after the locations of those values are chosen. 

1116 By default, uniform [0, 1) random values are used unless `dtype` is 

1117 an integer (default uniform integers from that dtype) or 

1118 complex (default uniform over the unit square in the complex plane). 

1119 For these, the `random_state` rng is used e.g. `rng.uniform(size=size)`. 

1120 

1121 Returns 

1122 ------- 

1123 res : sparse array 

1124 

1125 Examples 

1126 -------- 

1127 

1128 Passing a ``np.random.Generator`` instance for better performance: 

1129 

1130 >>> import numpy as np 

1131 >>> import scipy as sp 

1132 >>> rng = np.random.default_rng() 

1133 

1134 Default sampling uniformly from [0, 1): 

1135 

1136 >>> S = sp.sparse.random_array((3, 4), density=0.25, random_state=rng) 

1137 

1138 Providing a sampler for the values: 

1139 

1140 >>> rvs = sp.stats.poisson(25, loc=10).rvs 

1141 >>> S = sp.sparse.random_array((3, 4), density=0.25, 

1142 ... random_state=rng, data_sampler=rvs) 

1143 >>> S.toarray() 

1144 array([[ 36., 0., 33., 0.], # random 

1145 [ 0., 0., 0., 0.], 

1146 [ 0., 0., 36., 0.]]) 

1147 

1148 Building a custom distribution. 

1149 This example builds a squared normal from np.random: 

1150 

1151 >>> def np_normal_squared(size=None, random_state=rng): 

1152 ... return random_state.standard_normal(size) ** 2 

1153 >>> S = sp.sparse.random_array((3, 4), density=0.25, random_state=rng, 

1154 ... data_sampler=np_normal_squared) 

1155 

1156 Or we can build it from sp.stats style rvs functions: 

1157 

1158 >>> def sp_stats_normal_squared(size=None, random_state=rng): 

1159 ... std_normal = sp.stats.distributions.norm_gen().rvs 

1160 ... return std_normal(size=size, random_state=random_state) ** 2 

1161 >>> S = sp.sparse.random_array((3, 4), density=0.25, random_state=rng, 

1162 ... data_sampler=sp_stats_normal_squared) 

1163 

1164 Or we can subclass sp.stats rv_continous or rv_discrete: 

1165 

1166 >>> class NormalSquared(sp.stats.rv_continuous): 

1167 ... def _rvs(self, size=None, random_state=rng): 

1168 ... return random_state.standard_normal(size) ** 2 

1169 >>> X = NormalSquared() 

1170 >>> Y = X().rvs 

1171 >>> S = sp.sparse.random_array((3, 4), density=0.25, 

1172 ... random_state=rng, data_sampler=Y) 

1173 """ 

1174 # Use the more efficient RNG by default. 

1175 if random_state is None: 

1176 random_state = np.random.default_rng() 

1177 data, ind = _random(shape, density, format, dtype, random_state, data_sampler) 

1178 return coo_array((data, ind), shape=shape).asformat(format) 

1179 

1180 

1181def _random(shape, density=0.01, format=None, dtype=None, 

1182 random_state=None, data_sampler=None): 

1183 if density < 0 or density > 1: 

1184 raise ValueError("density expected to be 0 <= density <= 1") 

1185 

1186 tot_prod = math.prod(shape) # use `math` for when prod is >= 2**64 

1187 

1188 # Number of non zero values 

1189 size = int(round(density * tot_prod)) 

1190 

1191 rng = check_random_state(random_state) 

1192 

1193 if data_sampler is None: 

1194 if np.issubdtype(dtype, np.integer): 

1195 def data_sampler(size): 

1196 return rng_integers(rng, 

1197 np.iinfo(dtype).min, 

1198 np.iinfo(dtype).max, 

1199 size, 

1200 dtype=dtype) 

1201 elif np.issubdtype(dtype, np.complexfloating): 

1202 def data_sampler(size): 

1203 return (rng.uniform(size=size) + 

1204 rng.uniform(size=size) * 1j) 

1205 else: 

1206 data_sampler = rng.uniform 

1207 

1208 # rng.choice uses int64 if first arg is an int 

1209 if tot_prod < np.iinfo(np.int64).max: 

1210 raveled_ind = rng.choice(tot_prod, size=size, replace=False) 

1211 ind = np.unravel_index(raveled_ind, shape=shape) 

1212 else: 

1213 # for ravel indices bigger than dtype max, use sets to remove duplicates 

1214 ndim = len(shape) 

1215 seen = set() 

1216 while len(seen) < size: 

1217 dsize = size - len(seen) 

1218 seen.update(map(tuple, rng_integers(rng, shape, size=(dsize, ndim)))) 

1219 ind = tuple(np.array(list(seen)).T) 

1220 

1221 # size kwarg allows eg data_sampler=partial(np.random.poisson, lam=5) 

1222 vals = data_sampler(size=size).astype(dtype, copy=False) 

1223 return vals, ind 

1224 

1225 

1226def random(m, n, density=0.01, format='coo', dtype=None, 

1227 random_state=None, data_rvs=None): 

1228 """Generate a sparse matrix of the given shape and density with randomly 

1229 distributed values. 

1230 

1231 .. warning:: 

1232 

1233 Since numpy 1.17, passing a ``np.random.Generator`` (e.g. 

1234 ``np.random.default_rng``) for ``random_state`` will lead to much 

1235 faster execution times. 

1236 

1237 A much slower implementation is used by default for backwards 

1238 compatibility. 

1239 

1240 .. warning:: 

1241 

1242 This function returns a sparse matrix -- not a sparse array. 

1243 You are encouraged to use ``random_array`` to take advantage of the 

1244 sparse array functionality. 

1245 

1246 Parameters 

1247 ---------- 

1248 m, n : int 

1249 shape of the matrix 

1250 density : real, optional 

1251 density of the generated matrix: density equal to one means a full 

1252 matrix, density of 0 means a matrix with no non-zero items. 

1253 format : str, optional 

1254 sparse matrix format. 

1255 dtype : dtype, optional 

1256 type of the returned matrix values. 

1257 random_state : {None, int, `numpy.random.Generator`, 

1258 `numpy.random.RandomState`}, optional 

1259 

1260 - If `seed` is None (or `np.random`), the `numpy.random.RandomState` 

1261 singleton is used. 

1262 - If `seed` is an int, a new ``RandomState`` instance is used, 

1263 seeded with `seed`. 

1264 - If `seed` is already a ``Generator`` or ``RandomState`` instance then 

1265 that instance is used. 

1266 

1267 This random state will be used for sampling the sparsity structure, but 

1268 not necessarily for sampling the values of the structurally nonzero 

1269 entries of the matrix. 

1270 data_rvs : callable, optional 

1271 Samples a requested number of random values. 

1272 This function should take a single argument specifying the length 

1273 of the ndarray that it will return. The structurally nonzero entries 

1274 of the sparse random matrix will be taken from the array sampled 

1275 by this function. By default, uniform [0, 1) random values will be 

1276 sampled using the same random state as is used for sampling 

1277 the sparsity structure. 

1278 

1279 Returns 

1280 ------- 

1281 res : sparse matrix 

1282 

1283 See Also 

1284 -------- 

1285 random_array : constructs sparse arrays instead of sparse matrices 

1286 

1287 Examples 

1288 -------- 

1289 

1290 Passing a ``np.random.Generator`` instance for better performance: 

1291 

1292 >>> import scipy as sp 

1293 >>> import numpy as np 

1294 >>> rng = np.random.default_rng() 

1295 >>> S = sp.sparse.random(3, 4, density=0.25, random_state=rng) 

1296 

1297 Providing a sampler for the values: 

1298 

1299 >>> rvs = sp.stats.poisson(25, loc=10).rvs 

1300 >>> S = sp.sparse.random(3, 4, density=0.25, random_state=rng, data_rvs=rvs) 

1301 >>> S.toarray() 

1302 array([[ 36., 0., 33., 0.], # random 

1303 [ 0., 0., 0., 0.], 

1304 [ 0., 0., 36., 0.]]) 

1305 

1306 Building a custom distribution. 

1307 This example builds a squared normal from np.random: 

1308 

1309 >>> def np_normal_squared(size=None, random_state=rng): 

1310 ... return random_state.standard_normal(size) ** 2 

1311 >>> S = sp.sparse.random(3, 4, density=0.25, random_state=rng, 

1312 ... data_rvs=np_normal_squared) 

1313 

1314 Or we can build it from sp.stats style rvs functions: 

1315 

1316 >>> def sp_stats_normal_squared(size=None, random_state=rng): 

1317 ... std_normal = sp.stats.distributions.norm_gen().rvs 

1318 ... return std_normal(size=size, random_state=random_state) ** 2 

1319 >>> S = sp.sparse.random(3, 4, density=0.25, random_state=rng, 

1320 ... data_rvs=sp_stats_normal_squared) 

1321 

1322 Or we can subclass sp.stats rv_continous or rv_discrete: 

1323 

1324 >>> class NormalSquared(sp.stats.rv_continuous): 

1325 ... def _rvs(self, size=None, random_state=rng): 

1326 ... return random_state.standard_normal(size) ** 2 

1327 >>> X = NormalSquared() 

1328 >>> Y = X() # get a frozen version of the distribution 

1329 >>> S = sp.sparse.random(3, 4, density=0.25, random_state=rng, data_rvs=Y.rvs) 

1330 """ 

1331 if n is None: 

1332 n = m 

1333 m, n = int(m), int(n) 

1334 # make keyword syntax work for data_rvs e.g. data_rvs(size=7) 

1335 if data_rvs is not None: 

1336 def data_rvs_kw(size): 

1337 return data_rvs(size) 

1338 else: 

1339 data_rvs_kw = None 

1340 vals, ind = _random((m, n), density, format, dtype, random_state, data_rvs_kw) 

1341 return coo_matrix((vals, ind), shape=(m, n)).asformat(format) 

1342 

1343 

1344def rand(m, n, density=0.01, format="coo", dtype=None, random_state=None): 

1345 """Generate a sparse matrix of the given shape and density with uniformly 

1346 distributed values. 

1347 

1348 .. warning:: 

1349 

1350 This function returns a sparse matrix -- not a sparse array. 

1351 You are encouraged to use ``random_array`` to take advantage 

1352 of the sparse array functionality. 

1353 

1354 Parameters 

1355 ---------- 

1356 m, n : int 

1357 shape of the matrix 

1358 density : real, optional 

1359 density of the generated matrix: density equal to one means a full 

1360 matrix, density of 0 means a matrix with no non-zero items. 

1361 format : str, optional 

1362 sparse matrix format. 

1363 dtype : dtype, optional 

1364 type of the returned matrix values. 

1365 random_state : {None, int, `numpy.random.Generator`, 

1366 `numpy.random.RandomState`}, optional 

1367 

1368 If `seed` is None (or `np.random`), the `numpy.random.RandomState` 

1369 singleton is used. 

1370 If `seed` is an int, a new ``RandomState`` instance is used, 

1371 seeded with `seed`. 

1372 If `seed` is already a ``Generator`` or ``RandomState`` instance then 

1373 that instance is used. 

1374 

1375 Returns 

1376 ------- 

1377 res : sparse matrix 

1378 

1379 Notes 

1380 ----- 

1381 Only float types are supported for now. 

1382 

1383 See Also 

1384 -------- 

1385 random : Similar function allowing a custom random data sampler 

1386 random_array : Similar to random() but returns a sparse array 

1387 

1388 Examples 

1389 -------- 

1390 >>> from scipy.sparse import rand 

1391 >>> matrix = rand(3, 4, density=0.25, format="csr", random_state=42) 

1392 >>> matrix 

1393 <3x4 sparse matrix of type '<class 'numpy.float64'>' 

1394 with 3 stored elements in Compressed Sparse Row format> 

1395 >>> matrix.toarray() 

1396 array([[0.05641158, 0. , 0. , 0.65088847], # random 

1397 [0. , 0. , 0. , 0.14286682], 

1398 [0. , 0. , 0. , 0. ]]) 

1399 

1400 """ 

1401 return random(m, n, density, format, dtype, random_state)