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

296 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-23 06:43 +0000

1""" A sparse matrix in COOrdinate or 'triplet' format""" 

2 

3__docformat__ = "restructuredtext en" 

4 

5__all__ = ['coo_array', 'coo_matrix', 'isspmatrix_coo'] 

6 

7from warnings import warn 

8 

9import numpy as np 

10 

11from ._matrix import spmatrix 

12from ._sparsetools import coo_tocsr, coo_todense, coo_matvec 

13from ._base import issparse, SparseEfficiencyWarning, _spbase, sparray 

14from ._data import _data_matrix, _minmax_mixin 

15from ._sputils import (upcast, upcast_char, to_native, isshape, getdtype, 

16 getdata, downcast_intp_index, 

17 check_shape, check_reshape_kwargs) 

18 

19import operator 

20 

21 

22class _coo_base(_data_matrix, _minmax_mixin): 

23 _format = 'coo' 

24 

25 def __init__(self, arg1, shape=None, dtype=None, copy=False): 

26 _data_matrix.__init__(self) 

27 

28 if isinstance(arg1, tuple): 

29 if isshape(arg1): 

30 M, N = arg1 

31 self._shape = check_shape((M, N)) 

32 idx_dtype = self._get_index_dtype(maxval=max(M, N)) 

33 data_dtype = getdtype(dtype, default=float) 

34 self.row = np.array([], dtype=idx_dtype) 

35 self.col = np.array([], dtype=idx_dtype) 

36 self.data = np.array([], dtype=data_dtype) 

37 self.has_canonical_format = True 

38 else: 

39 try: 

40 obj, (row, col) = arg1 

41 except (TypeError, ValueError) as e: 

42 raise TypeError('invalid input format') from e 

43 

44 if shape is None: 

45 if len(row) == 0 or len(col) == 0: 

46 raise ValueError('cannot infer dimensions from zero ' 

47 'sized index arrays') 

48 M = operator.index(np.max(row)) + 1 

49 N = operator.index(np.max(col)) + 1 

50 self._shape = check_shape((M, N)) 

51 else: 

52 # Use 2 steps to ensure shape has length 2. 

53 M, N = shape 

54 self._shape = check_shape((M, N)) 

55 

56 idx_dtype = self._get_index_dtype((row, col), maxval=max(self.shape), check_contents=True) 

57 self.row = np.array(row, copy=copy, dtype=idx_dtype) 

58 self.col = np.array(col, copy=copy, dtype=idx_dtype) 

59 self.data = getdata(obj, copy=copy, dtype=dtype) 

60 self.has_canonical_format = False 

61 else: 

62 if issparse(arg1): 

63 if arg1.format == self.format and copy: 

64 self.row = arg1.row.copy() 

65 self.col = arg1.col.copy() 

66 self.data = arg1.data.copy() 

67 self._shape = check_shape(arg1.shape) 

68 else: 

69 coo = arg1.tocoo() 

70 self.row = coo.row 

71 self.col = coo.col 

72 self.data = coo.data 

73 self._shape = check_shape(coo.shape) 

74 self.has_canonical_format = False 

75 else: 

76 #dense argument 

77 M = np.atleast_2d(np.asarray(arg1)) 

78 

79 if M.ndim != 2: 

80 raise TypeError('expected dimension <= 2 array or matrix') 

81 

82 self._shape = check_shape(M.shape) 

83 if shape is not None: 

84 if check_shape(shape) != self._shape: 

85 raise ValueError('inconsistent shapes: %s != %s' % 

86 (shape, self._shape)) 

87 index_dtype = self._get_index_dtype(maxval=max(self._shape)) 

88 row, col = M.nonzero() 

89 self.row = row.astype(index_dtype, copy=False) 

90 self.col = col.astype(index_dtype, copy=False) 

91 self.data = M[self.row, self.col] 

92 self.has_canonical_format = True 

93 

94 if dtype is not None: 

95 self.data = self.data.astype(dtype, copy=False) 

96 

97 self._check() 

98 

99 def reshape(self, *args, **kwargs): 

100 shape = check_shape(args, self.shape) 

101 order, copy = check_reshape_kwargs(kwargs) 

102 

103 # Return early if reshape is not required 

104 if shape == self.shape: 

105 if copy: 

106 return self.copy() 

107 else: 

108 return self 

109 

110 nrows, ncols = self.shape 

111 

112 if order == 'C': 

113 # Upcast to avoid overflows: the coo_array constructor 

114 # below will downcast the results to a smaller dtype, if 

115 # possible. 

116 dtype = self._get_index_dtype(maxval=(ncols * max(0, nrows - 1) + max(0, ncols - 1))) 

117 

118 flat_indices = np.multiply(ncols, self.row, dtype=dtype) + self.col 

119 new_row, new_col = divmod(flat_indices, shape[1]) 

120 elif order == 'F': 

121 dtype = self._get_index_dtype(maxval=(nrows * max(0, ncols - 1) + max(0, nrows - 1))) 

122 

123 flat_indices = np.multiply(nrows, self.col, dtype=dtype) + self.row 

124 new_col, new_row = divmod(flat_indices, shape[0]) 

125 else: 

126 raise ValueError("'order' must be 'C' or 'F'") 

127 

128 # Handle copy here rather than passing on to the constructor so that no 

129 # copy will be made of new_row and new_col regardless 

130 if copy: 

131 new_data = self.data.copy() 

132 else: 

133 new_data = self.data 

134 

135 return self.__class__((new_data, (new_row, new_col)), 

136 shape=shape, copy=False) 

137 

138 reshape.__doc__ = _spbase.reshape.__doc__ 

139 

140 def _getnnz(self, axis=None): 

141 if axis is None: 

142 nnz = len(self.data) 

143 if nnz != len(self.row) or nnz != len(self.col): 

144 raise ValueError('row, column, and data array must all be the ' 

145 'same length') 

146 

147 if self.data.ndim != 1 or self.row.ndim != 1 or \ 

148 self.col.ndim != 1: 

149 raise ValueError('row, column, and data arrays must be 1-D') 

150 

151 return int(nnz) 

152 

153 if axis < 0: 

154 axis += 2 

155 if axis == 0: 

156 return np.bincount(downcast_intp_index(self.col), 

157 minlength=self.shape[1]) 

158 elif axis == 1: 

159 return np.bincount(downcast_intp_index(self.row), 

160 minlength=self.shape[0]) 

161 else: 

162 raise ValueError('axis out of bounds') 

163 

164 _getnnz.__doc__ = _spbase._getnnz.__doc__ 

165 

166 def _check(self): 

167 """ Checks data structure for consistency """ 

168 

169 # index arrays should have integer data types 

170 if self.row.dtype.kind != 'i': 

171 warn("row index array has non-integer dtype (%s) " 

172 % self.row.dtype.name) 

173 if self.col.dtype.kind != 'i': 

174 warn("col index array has non-integer dtype (%s) " 

175 % self.col.dtype.name) 

176 

177 idx_dtype = self._get_index_dtype((self.row, self.col), maxval=max(self.shape)) 

178 self.row = np.asarray(self.row, dtype=idx_dtype) 

179 self.col = np.asarray(self.col, dtype=idx_dtype) 

180 self.data = to_native(self.data) 

181 

182 if self.nnz > 0: 

183 if self.row.max() >= self.shape[0]: 

184 raise ValueError('row index exceeds matrix dimensions') 

185 if self.col.max() >= self.shape[1]: 

186 raise ValueError('column index exceeds matrix dimensions') 

187 if self.row.min() < 0: 

188 raise ValueError('negative row index found') 

189 if self.col.min() < 0: 

190 raise ValueError('negative column index found') 

191 

192 def transpose(self, axes=None, copy=False): 

193 if axes is not None and axes != (1, 0): 

194 raise ValueError("Sparse array/matrices do not support " 

195 "an 'axes' parameter because swapping " 

196 "dimensions is the only logical permutation.") 

197 

198 M, N = self.shape 

199 return self.__class__((self.data, (self.col, self.row)), 

200 shape=(N, M), copy=copy) 

201 

202 transpose.__doc__ = _spbase.transpose.__doc__ 

203 

204 def resize(self, *shape): 

205 shape = check_shape(shape) 

206 new_M, new_N = shape 

207 M, N = self.shape 

208 

209 if new_M < M or new_N < N: 

210 mask = np.logical_and(self.row < new_M, self.col < new_N) 

211 if not mask.all(): 

212 self.row = self.row[mask] 

213 self.col = self.col[mask] 

214 self.data = self.data[mask] 

215 

216 self._shape = shape 

217 

218 resize.__doc__ = _spbase.resize.__doc__ 

219 

220 def toarray(self, order=None, out=None): 

221 B = self._process_toarray_args(order, out) 

222 fortran = int(B.flags.f_contiguous) 

223 if not fortran and not B.flags.c_contiguous: 

224 raise ValueError("Output array must be C or F contiguous") 

225 M,N = self.shape 

226 coo_todense(M, N, self.nnz, self.row, self.col, self.data, 

227 B.ravel('A'), fortran) 

228 return B 

229 

230 toarray.__doc__ = _spbase.toarray.__doc__ 

231 

232 def tocsc(self, copy=False): 

233 """Convert this array/matrix to Compressed Sparse Column format 

234 

235 Duplicate entries will be summed together. 

236 

237 Examples 

238 -------- 

239 >>> from numpy import array 

240 >>> from scipy.sparse import coo_array 

241 >>> row = array([0, 0, 1, 3, 1, 0, 0]) 

242 >>> col = array([0, 2, 1, 3, 1, 0, 0]) 

243 >>> data = array([1, 1, 1, 1, 1, 1, 1]) 

244 >>> A = coo_array((data, (row, col)), shape=(4, 4)).tocsc() 

245 >>> A.toarray() 

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

247 [0, 2, 0, 0], 

248 [0, 0, 0, 0], 

249 [0, 0, 0, 1]]) 

250 

251 """ 

252 if self.nnz == 0: 

253 return self._csc_container(self.shape, dtype=self.dtype) 

254 else: 

255 M,N = self.shape 

256 idx_dtype = self._get_index_dtype( 

257 (self.col, self.row), maxval=max(self.nnz, M) 

258 ) 

259 row = self.row.astype(idx_dtype, copy=False) 

260 col = self.col.astype(idx_dtype, copy=False) 

261 

262 indptr = np.empty(N + 1, dtype=idx_dtype) 

263 indices = np.empty_like(row, dtype=idx_dtype) 

264 data = np.empty_like(self.data, dtype=upcast(self.dtype)) 

265 

266 coo_tocsr(N, M, self.nnz, col, row, self.data, 

267 indptr, indices, data) 

268 

269 x = self._csc_container((data, indices, indptr), shape=self.shape) 

270 if not self.has_canonical_format: 

271 x.sum_duplicates() 

272 return x 

273 

274 def tocsr(self, copy=False): 

275 """Convert this array/matrix to Compressed Sparse Row format 

276 

277 Duplicate entries will be summed together. 

278 

279 Examples 

280 -------- 

281 >>> from numpy import array 

282 >>> from scipy.sparse import coo_array 

283 >>> row = array([0, 0, 1, 3, 1, 0, 0]) 

284 >>> col = array([0, 2, 1, 3, 1, 0, 0]) 

285 >>> data = array([1, 1, 1, 1, 1, 1, 1]) 

286 >>> A = coo_array((data, (row, col)), shape=(4, 4)).tocsr() 

287 >>> A.toarray() 

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

289 [0, 2, 0, 0], 

290 [0, 0, 0, 0], 

291 [0, 0, 0, 1]]) 

292 

293 """ 

294 if self.nnz == 0: 

295 return self._csr_container(self.shape, dtype=self.dtype) 

296 else: 

297 M,N = self.shape 

298 idx_dtype = self._get_index_dtype( 

299 (self.row, self.col), maxval=max(self.nnz, N) 

300 ) 

301 row = self.row.astype(idx_dtype, copy=False) 

302 col = self.col.astype(idx_dtype, copy=False) 

303 

304 indptr = np.empty(M + 1, dtype=idx_dtype) 

305 indices = np.empty_like(col, dtype=idx_dtype) 

306 data = np.empty_like(self.data, dtype=upcast(self.dtype)) 

307 

308 coo_tocsr(M, N, self.nnz, row, col, self.data, 

309 indptr, indices, data) 

310 

311 x = self._csr_container((data, indices, indptr), shape=self.shape) 

312 if not self.has_canonical_format: 

313 x.sum_duplicates() 

314 return x 

315 

316 def tocoo(self, copy=False): 

317 if copy: 

318 return self.copy() 

319 else: 

320 return self 

321 

322 tocoo.__doc__ = _spbase.tocoo.__doc__ 

323 

324 def todia(self, copy=False): 

325 self.sum_duplicates() 

326 ks = self.col - self.row # the diagonal for each nonzero 

327 diags, diag_idx = np.unique(ks, return_inverse=True) 

328 

329 if len(diags) > 100: 

330 # probably undesired, should todia() have a maxdiags parameter? 

331 warn("Constructing a DIA matrix with %d diagonals " 

332 "is inefficient" % len(diags), SparseEfficiencyWarning) 

333 

334 #initialize and fill in data array 

335 if self.data.size == 0: 

336 data = np.zeros((0, 0), dtype=self.dtype) 

337 else: 

338 data = np.zeros((len(diags), self.col.max()+1), dtype=self.dtype) 

339 data[diag_idx, self.col] = self.data 

340 

341 return self._dia_container((data, diags), shape=self.shape) 

342 

343 todia.__doc__ = _spbase.todia.__doc__ 

344 

345 def todok(self, copy=False): 

346 self.sum_duplicates() 

347 dok = self._dok_container((self.shape), dtype=self.dtype) 

348 dok._update(zip(zip(self.row,self.col),self.data)) 

349 

350 return dok 

351 

352 todok.__doc__ = _spbase.todok.__doc__ 

353 

354 def diagonal(self, k=0): 

355 rows, cols = self.shape 

356 if k <= -rows or k >= cols: 

357 return np.empty(0, dtype=self.data.dtype) 

358 diag = np.zeros(min(rows + min(k, 0), cols - max(k, 0)), 

359 dtype=self.dtype) 

360 diag_mask = (self.row + k) == self.col 

361 

362 if self.has_canonical_format: 

363 row = self.row[diag_mask] 

364 data = self.data[diag_mask] 

365 else: 

366 row, _, data = self._sum_duplicates(self.row[diag_mask], 

367 self.col[diag_mask], 

368 self.data[diag_mask]) 

369 diag[row + min(k, 0)] = data 

370 

371 return diag 

372 

373 diagonal.__doc__ = _data_matrix.diagonal.__doc__ 

374 

375 def _setdiag(self, values, k): 

376 M, N = self.shape 

377 if values.ndim and not len(values): 

378 return 

379 idx_dtype = self.row.dtype 

380 

381 # Determine which triples to keep and where to put the new ones. 

382 full_keep = self.col - self.row != k 

383 if k < 0: 

384 max_index = min(M+k, N) 

385 if values.ndim: 

386 max_index = min(max_index, len(values)) 

387 keep = np.logical_or(full_keep, self.col >= max_index) 

388 new_row = np.arange(-k, -k + max_index, dtype=idx_dtype) 

389 new_col = np.arange(max_index, dtype=idx_dtype) 

390 else: 

391 max_index = min(M, N-k) 

392 if values.ndim: 

393 max_index = min(max_index, len(values)) 

394 keep = np.logical_or(full_keep, self.row >= max_index) 

395 new_row = np.arange(max_index, dtype=idx_dtype) 

396 new_col = np.arange(k, k + max_index, dtype=idx_dtype) 

397 

398 # Define the array of data consisting of the entries to be added. 

399 if values.ndim: 

400 new_data = values[:max_index] 

401 else: 

402 new_data = np.empty(max_index, dtype=self.dtype) 

403 new_data[:] = values 

404 

405 # Update the internal structure. 

406 self.row = np.concatenate((self.row[keep], new_row)) 

407 self.col = np.concatenate((self.col[keep], new_col)) 

408 self.data = np.concatenate((self.data[keep], new_data)) 

409 self.has_canonical_format = False 

410 

411 # needed by _data_matrix 

412 def _with_data(self,data,copy=True): 

413 """Returns a matrix with the same sparsity structure as self, 

414 but with different data. By default the index arrays 

415 (i.e. .row and .col) are copied. 

416 """ 

417 if copy: 

418 return self.__class__((data, (self.row.copy(), self.col.copy())), 

419 shape=self.shape, dtype=data.dtype) 

420 else: 

421 return self.__class__((data, (self.row, self.col)), 

422 shape=self.shape, dtype=data.dtype) 

423 

424 def sum_duplicates(self): 

425 """Eliminate duplicate entries by adding them together 

426 

427 This is an *in place* operation 

428 """ 

429 if self.has_canonical_format: 

430 return 

431 summed = self._sum_duplicates(self.row, self.col, self.data) 

432 self.row, self.col, self.data = summed 

433 self.has_canonical_format = True 

434 

435 def _sum_duplicates(self, row, col, data): 

436 # Assumes (data, row, col) not in canonical format. 

437 if len(data) == 0: 

438 return row, col, data 

439 # Sort indices w.r.t. rows, then cols. This corresponds to C-order, 

440 # which we rely on for argmin/argmax to return the first index in the 

441 # same way that numpy does (in the case of ties). 

442 order = np.lexsort((col, row)) 

443 row = row[order] 

444 col = col[order] 

445 data = data[order] 

446 unique_mask = ((row[1:] != row[:-1]) | 

447 (col[1:] != col[:-1])) 

448 unique_mask = np.append(True, unique_mask) 

449 row = row[unique_mask] 

450 col = col[unique_mask] 

451 unique_inds, = np.nonzero(unique_mask) 

452 data = np.add.reduceat(data, unique_inds, dtype=self.dtype) 

453 return row, col, data 

454 

455 def eliminate_zeros(self): 

456 """Remove zero entries from the array/matrix 

457 

458 This is an *in place* operation 

459 """ 

460 mask = self.data != 0 

461 self.data = self.data[mask] 

462 self.row = self.row[mask] 

463 self.col = self.col[mask] 

464 

465 ####################### 

466 # Arithmetic handlers # 

467 ####################### 

468 

469 def _add_dense(self, other): 

470 if other.shape != self.shape: 

471 raise ValueError('Incompatible shapes ({} and {})' 

472 .format(self.shape, other.shape)) 

473 dtype = upcast_char(self.dtype.char, other.dtype.char) 

474 result = np.array(other, dtype=dtype, copy=True) 

475 fortran = int(result.flags.f_contiguous) 

476 M, N = self.shape 

477 coo_todense(M, N, self.nnz, self.row, self.col, self.data, 

478 result.ravel('A'), fortran) 

479 return self._container(result, copy=False) 

480 

481 def _mul_vector(self, other): 

482 #output array 

483 result = np.zeros(self.shape[0], dtype=upcast_char(self.dtype.char, 

484 other.dtype.char)) 

485 coo_matvec(self.nnz, self.row, self.col, self.data, other, result) 

486 return result 

487 

488 def _mul_multivector(self, other): 

489 result = np.zeros((other.shape[1], self.shape[0]), 

490 dtype=upcast_char(self.dtype.char, other.dtype.char)) 

491 for i, col in enumerate(other.T): 

492 coo_matvec(self.nnz, self.row, self.col, self.data, col, result[i]) 

493 return result.T.view(type=type(other)) 

494 

495 

496def isspmatrix_coo(x): 

497 """Is `x` of coo_matrix type? 

498 

499 Parameters 

500 ---------- 

501 x 

502 object to check for being a coo matrix 

503 

504 Returns 

505 ------- 

506 bool 

507 True if `x` is a coo matrix, False otherwise 

508 

509 Examples 

510 -------- 

511 >>> from scipy.sparse import coo_array, coo_matrix, csr_matrix, isspmatrix_coo 

512 >>> isspmatrix_coo(coo_matrix([[5]])) 

513 True 

514 >>> isspmatrix_coo(coo_array([[5]])) 

515 False 

516 >>> isspmatrix_coo(csr_matrix([[5]])) 

517 False 

518 """ 

519 return isinstance(x, coo_matrix) 

520 

521 

522# This namespace class separates array from matrix with isinstance 

523class coo_array(_coo_base, sparray): 

524 """ 

525 A sparse array in COOrdinate format. 

526 

527 Also known as the 'ijv' or 'triplet' format. 

528 

529 This can be instantiated in several ways: 

530 coo_array(D) 

531 where D is a 2-D ndarray 

532 

533 coo_array(S) 

534 with another sparse array or matrix S (equivalent to S.tocoo()) 

535 

536 coo_array((M, N), [dtype]) 

537 to construct an empty array with shape (M, N) 

538 dtype is optional, defaulting to dtype='d'. 

539 

540 coo_array((data, (i, j)), [shape=(M, N)]) 

541 to construct from three arrays: 

542 1. data[:] the entries of the array, in any order 

543 2. i[:] the row indices of the array entries 

544 3. j[:] the column indices of the array entries 

545 

546 Where ``A[i[k], j[k]] = data[k]``. When shape is not 

547 specified, it is inferred from the index arrays 

548 

549 Attributes 

550 ---------- 

551 dtype : dtype 

552 Data type of the array 

553 shape : 2-tuple 

554 Shape of the array 

555 ndim : int 

556 Number of dimensions (this is always 2) 

557 nnz 

558 size 

559 data 

560 COO format data array of the array 

561 row 

562 COO format row index array of the array 

563 col 

564 COO format column index array of the array 

565 has_canonical_format : bool 

566 Whether the matrix has sorted indices and no duplicates 

567 format 

568 T 

569 

570 Notes 

571 ----- 

572 

573 Sparse arrays can be used in arithmetic operations: they support 

574 addition, subtraction, multiplication, division, and matrix power. 

575 

576 Advantages of the COO format 

577 - facilitates fast conversion among sparse formats 

578 - permits duplicate entries (see example) 

579 - very fast conversion to and from CSR/CSC formats 

580 

581 Disadvantages of the COO format 

582 - does not directly support: 

583 + arithmetic operations 

584 + slicing 

585 

586 Intended Usage 

587 - COO is a fast format for constructing sparse arrays 

588 - Once a COO array has been constructed, convert to CSR or 

589 CSC format for fast arithmetic and matrix vector operations 

590 - By default when converting to CSR or CSC format, duplicate (i,j) 

591 entries will be summed together. This facilitates efficient 

592 construction of finite element matrices and the like. (see example) 

593 

594 Canonical format 

595 - Entries and indices sorted by row, then column. 

596 - There are no duplicate entries (i.e. duplicate (i,j) locations) 

597 - Data arrays MAY have explicit zeros. 

598 

599 Examples 

600 -------- 

601 

602 >>> # Constructing an empty array 

603 >>> import numpy as np 

604 >>> from scipy.sparse import coo_array 

605 >>> coo_array((3, 4), dtype=np.int8).toarray() 

606 array([[0, 0, 0, 0], 

607 [0, 0, 0, 0], 

608 [0, 0, 0, 0]], dtype=int8) 

609 

610 >>> # Constructing an array using ijv format 

611 >>> row = np.array([0, 3, 1, 0]) 

612 >>> col = np.array([0, 3, 1, 2]) 

613 >>> data = np.array([4, 5, 7, 9]) 

614 >>> coo_array((data, (row, col)), shape=(4, 4)).toarray() 

615 array([[4, 0, 9, 0], 

616 [0, 7, 0, 0], 

617 [0, 0, 0, 0], 

618 [0, 0, 0, 5]]) 

619 

620 >>> # Constructing an array with duplicate indices 

621 >>> row = np.array([0, 0, 1, 3, 1, 0, 0]) 

622 >>> col = np.array([0, 2, 1, 3, 1, 0, 0]) 

623 >>> data = np.array([1, 1, 1, 1, 1, 1, 1]) 

624 >>> coo = coo_array((data, (row, col)), shape=(4, 4)) 

625 >>> # Duplicate indices are maintained until implicitly or explicitly summed 

626 >>> np.max(coo.data) 

627 1 

628 >>> coo.toarray() 

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

630 [0, 2, 0, 0], 

631 [0, 0, 0, 0], 

632 [0, 0, 0, 1]]) 

633 

634 """ 

635 

636 

637class coo_matrix(spmatrix, _coo_base): 

638 """ 

639 A sparse matrix in COOrdinate format. 

640 

641 Also known as the 'ijv' or 'triplet' format. 

642 

643 This can be instantiated in several ways: 

644 coo_matrix(D) 

645 where D is a 2-D ndarray 

646 

647 coo_matrix(S) 

648 with another sparse array or matrix S (equivalent to S.tocoo()) 

649 

650 coo_matrix((M, N), [dtype]) 

651 to construct an empty matrix with shape (M, N) 

652 dtype is optional, defaulting to dtype='d'. 

653 

654 coo_matrix((data, (i, j)), [shape=(M, N)]) 

655 to construct from three arrays: 

656 1. data[:] the entries of the matrix, in any order 

657 2. i[:] the row indices of the matrix entries 

658 3. j[:] the column indices of the matrix entries 

659 

660 Where ``A[i[k], j[k]] = data[k]``. When shape is not 

661 specified, it is inferred from the index arrays 

662 

663 Attributes 

664 ---------- 

665 dtype : dtype 

666 Data type of the matrix 

667 shape : 2-tuple 

668 Shape of the matrix 

669 ndim : int 

670 Number of dimensions (this is always 2) 

671 nnz 

672 size 

673 data 

674 COO format data array of the matrix 

675 row 

676 COO format row index array of the matrix 

677 col 

678 COO format column index array of the matrix 

679 has_canonical_format : bool 

680 Whether the matrix has sorted indices and no duplicates 

681 format 

682 T 

683 

684 Notes 

685 ----- 

686 

687 Sparse matrices can be used in arithmetic operations: they support 

688 addition, subtraction, multiplication, division, and matrix power. 

689 

690 Advantages of the COO format 

691 - facilitates fast conversion among sparse formats 

692 - permits duplicate entries (see example) 

693 - very fast conversion to and from CSR/CSC formats 

694 

695 Disadvantages of the COO format 

696 - does not directly support: 

697 + arithmetic operations 

698 + slicing 

699 

700 Intended Usage 

701 - COO is a fast format for constructing sparse matrices 

702 - Once a COO matrix has been constructed, convert to CSR or 

703 CSC format for fast arithmetic and matrix vector operations 

704 - By default when converting to CSR or CSC format, duplicate (i,j) 

705 entries will be summed together. This facilitates efficient 

706 construction of finite element matrices and the like. (see example) 

707 

708 Canonical format 

709 - Entries and indices sorted by row, then column. 

710 - There are no duplicate entries (i.e. duplicate (i,j) locations) 

711 - Data arrays MAY have explicit zeros. 

712 

713 Examples 

714 -------- 

715 

716 >>> # Constructing an empty matrix 

717 >>> import numpy as np 

718 >>> from scipy.sparse import coo_matrix 

719 >>> coo_matrix((3, 4), dtype=np.int8).toarray() 

720 array([[0, 0, 0, 0], 

721 [0, 0, 0, 0], 

722 [0, 0, 0, 0]], dtype=int8) 

723 

724 >>> # Constructing a matrix using ijv format 

725 >>> row = np.array([0, 3, 1, 0]) 

726 >>> col = np.array([0, 3, 1, 2]) 

727 >>> data = np.array([4, 5, 7, 9]) 

728 >>> coo_matrix((data, (row, col)), shape=(4, 4)).toarray() 

729 array([[4, 0, 9, 0], 

730 [0, 7, 0, 0], 

731 [0, 0, 0, 0], 

732 [0, 0, 0, 5]]) 

733 

734 >>> # Constructing a matrix with duplicate indices 

735 >>> row = np.array([0, 0, 1, 3, 1, 0, 0]) 

736 >>> col = np.array([0, 2, 1, 3, 1, 0, 0]) 

737 >>> data = np.array([1, 1, 1, 1, 1, 1, 1]) 

738 >>> coo = coo_matrix((data, (row, col)), shape=(4, 4)) 

739 >>> # Duplicate indices are maintained until implicitly or explicitly summed 

740 >>> np.max(coo.data) 

741 1 

742 >>> coo.toarray() 

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

744 [0, 2, 0, 0], 

745 [0, 0, 0, 0], 

746 [0, 0, 0, 1]]) 

747 

748 """ 

749