Coverage for /usr/lib/python3/dist-packages/sympy/matrices/common.py: 26%

1012 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1""" 

2Basic methods common to all matrices to be used 

3when creating more advanced matrices (e.g., matrices over rings, 

4etc.). 

5""" 

6 

7from collections import defaultdict 

8from collections.abc import Iterable 

9from inspect import isfunction 

10from functools import reduce 

11 

12from sympy.assumptions.refine import refine 

13from sympy.core import SympifyError, Add 

14from sympy.core.basic import Atom 

15from sympy.core.decorators import call_highest_priority 

16from sympy.core.kind import Kind, NumberKind 

17from sympy.core.logic import fuzzy_and, FuzzyBool 

18from sympy.core.mod import Mod 

19from sympy.core.singleton import S 

20from sympy.core.symbol import Symbol 

21from sympy.core.sympify import sympify 

22from sympy.functions.elementary.complexes import Abs, re, im 

23from .utilities import _dotprodsimp, _simplify 

24from sympy.polys.polytools import Poly 

25from sympy.utilities.iterables import flatten, is_sequence 

26from sympy.utilities.misc import as_int, filldedent 

27from sympy.tensor.array import NDimArray 

28 

29from .utilities import _get_intermediate_simp_bool 

30 

31 

32class MatrixError(Exception): 

33 pass 

34 

35 

36class ShapeError(ValueError, MatrixError): 

37 """Wrong matrix shape""" 

38 pass 

39 

40 

41class NonSquareMatrixError(ShapeError): 

42 pass 

43 

44 

45class NonInvertibleMatrixError(ValueError, MatrixError): 

46 """The matrix in not invertible (division by multidimensional zero error).""" 

47 pass 

48 

49 

50class NonPositiveDefiniteMatrixError(ValueError, MatrixError): 

51 """The matrix is not a positive-definite matrix.""" 

52 pass 

53 

54 

55class MatrixRequired: 

56 """All subclasses of matrix objects must implement the 

57 required matrix properties listed here.""" 

58 rows = None # type: int 

59 cols = None # type: int 

60 _simplify = None 

61 

62 @classmethod 

63 def _new(cls, *args, **kwargs): 

64 """`_new` must, at minimum, be callable as 

65 `_new(rows, cols, mat) where mat is a flat list of the 

66 elements of the matrix.""" 

67 raise NotImplementedError("Subclasses must implement this.") 

68 

69 def __eq__(self, other): 

70 raise NotImplementedError("Subclasses must implement this.") 

71 

72 def __getitem__(self, key): 

73 """Implementations of __getitem__ should accept ints, in which 

74 case the matrix is indexed as a flat list, tuples (i,j) in which 

75 case the (i,j) entry is returned, slices, or mixed tuples (a,b) 

76 where a and b are any combination of slices and integers.""" 

77 raise NotImplementedError("Subclasses must implement this.") 

78 

79 def __len__(self): 

80 """The total number of entries in the matrix.""" 

81 raise NotImplementedError("Subclasses must implement this.") 

82 

83 @property 

84 def shape(self): 

85 raise NotImplementedError("Subclasses must implement this.") 

86 

87 

88class MatrixShaping(MatrixRequired): 

89 """Provides basic matrix shaping and extracting of submatrices""" 

90 

91 def _eval_col_del(self, col): 

92 def entry(i, j): 

93 return self[i, j] if j < col else self[i, j + 1] 

94 return self._new(self.rows, self.cols - 1, entry) 

95 

96 def _eval_col_insert(self, pos, other): 

97 

98 def entry(i, j): 

99 if j < pos: 

100 return self[i, j] 

101 elif pos <= j < pos + other.cols: 

102 return other[i, j - pos] 

103 return self[i, j - other.cols] 

104 

105 return self._new(self.rows, self.cols + other.cols, entry) 

106 

107 def _eval_col_join(self, other): 

108 rows = self.rows 

109 

110 def entry(i, j): 

111 if i < rows: 

112 return self[i, j] 

113 return other[i - rows, j] 

114 

115 return classof(self, other)._new(self.rows + other.rows, self.cols, 

116 entry) 

117 

118 def _eval_extract(self, rowsList, colsList): 

119 mat = list(self) 

120 cols = self.cols 

121 indices = (i * cols + j for i in rowsList for j in colsList) 

122 return self._new(len(rowsList), len(colsList), 

123 [mat[i] for i in indices]) 

124 

125 def _eval_get_diag_blocks(self): 

126 sub_blocks = [] 

127 

128 def recurse_sub_blocks(M): 

129 i = 1 

130 while i <= M.shape[0]: 

131 if i == 1: 

132 to_the_right = M[0, i:] 

133 to_the_bottom = M[i:, 0] 

134 else: 

135 to_the_right = M[:i, i:] 

136 to_the_bottom = M[i:, :i] 

137 if any(to_the_right) or any(to_the_bottom): 

138 i += 1 

139 continue 

140 else: 

141 sub_blocks.append(M[:i, :i]) 

142 if M.shape == M[:i, :i].shape: 

143 return 

144 else: 

145 recurse_sub_blocks(M[i:, i:]) 

146 return 

147 

148 recurse_sub_blocks(self) 

149 return sub_blocks 

150 

151 def _eval_row_del(self, row): 

152 def entry(i, j): 

153 return self[i, j] if i < row else self[i + 1, j] 

154 return self._new(self.rows - 1, self.cols, entry) 

155 

156 def _eval_row_insert(self, pos, other): 

157 entries = list(self) 

158 insert_pos = pos * self.cols 

159 entries[insert_pos:insert_pos] = list(other) 

160 return self._new(self.rows + other.rows, self.cols, entries) 

161 

162 def _eval_row_join(self, other): 

163 cols = self.cols 

164 

165 def entry(i, j): 

166 if j < cols: 

167 return self[i, j] 

168 return other[i, j - cols] 

169 

170 return classof(self, other)._new(self.rows, self.cols + other.cols, 

171 entry) 

172 

173 def _eval_tolist(self): 

174 return [list(self[i,:]) for i in range(self.rows)] 

175 

176 def _eval_todok(self): 

177 dok = {} 

178 rows, cols = self.shape 

179 for i in range(rows): 

180 for j in range(cols): 

181 val = self[i, j] 

182 if val != self.zero: 

183 dok[i, j] = val 

184 return dok 

185 

186 def _eval_vec(self): 

187 rows = self.rows 

188 

189 def entry(n, _): 

190 # we want to read off the columns first 

191 j = n // rows 

192 i = n - j * rows 

193 return self[i, j] 

194 

195 return self._new(len(self), 1, entry) 

196 

197 def _eval_vech(self, diagonal): 

198 c = self.cols 

199 v = [] 

200 if diagonal: 

201 for j in range(c): 

202 for i in range(j, c): 

203 v.append(self[i, j]) 

204 else: 

205 for j in range(c): 

206 for i in range(j + 1, c): 

207 v.append(self[i, j]) 

208 return self._new(len(v), 1, v) 

209 

210 def col_del(self, col): 

211 """Delete the specified column.""" 

212 if col < 0: 

213 col += self.cols 

214 if not 0 <= col < self.cols: 

215 raise IndexError("Column {} is out of range.".format(col)) 

216 return self._eval_col_del(col) 

217 

218 def col_insert(self, pos, other): 

219 """Insert one or more columns at the given column position. 

220 

221 Examples 

222 ======== 

223 

224 >>> from sympy import zeros, ones 

225 >>> M = zeros(3) 

226 >>> V = ones(3, 1) 

227 >>> M.col_insert(1, V) 

228 Matrix([ 

229 [0, 1, 0, 0], 

230 [0, 1, 0, 0], 

231 [0, 1, 0, 0]]) 

232 

233 See Also 

234 ======== 

235 

236 col 

237 row_insert 

238 """ 

239 # Allows you to build a matrix even if it is null matrix 

240 if not self: 

241 return type(self)(other) 

242 

243 pos = as_int(pos) 

244 

245 if pos < 0: 

246 pos = self.cols + pos 

247 if pos < 0: 

248 pos = 0 

249 elif pos > self.cols: 

250 pos = self.cols 

251 

252 if self.rows != other.rows: 

253 raise ShapeError( 

254 "The matrices have incompatible number of rows ({} and {})" 

255 .format(self.rows, other.rows)) 

256 

257 return self._eval_col_insert(pos, other) 

258 

259 def col_join(self, other): 

260 """Concatenates two matrices along self's last and other's first row. 

261 

262 Examples 

263 ======== 

264 

265 >>> from sympy import zeros, ones 

266 >>> M = zeros(3) 

267 >>> V = ones(1, 3) 

268 >>> M.col_join(V) 

269 Matrix([ 

270 [0, 0, 0], 

271 [0, 0, 0], 

272 [0, 0, 0], 

273 [1, 1, 1]]) 

274 

275 See Also 

276 ======== 

277 

278 col 

279 row_join 

280 """ 

281 # A null matrix can always be stacked (see #10770) 

282 if self.rows == 0 and self.cols != other.cols: 

283 return self._new(0, other.cols, []).col_join(other) 

284 

285 if self.cols != other.cols: 

286 raise ShapeError( 

287 "The matrices have incompatible number of columns ({} and {})" 

288 .format(self.cols, other.cols)) 

289 return self._eval_col_join(other) 

290 

291 def col(self, j): 

292 """Elementary column selector. 

293 

294 Examples 

295 ======== 

296 

297 >>> from sympy import eye 

298 >>> eye(2).col(0) 

299 Matrix([ 

300 [1], 

301 [0]]) 

302 

303 See Also 

304 ======== 

305 

306 row 

307 col_del 

308 col_join 

309 col_insert 

310 """ 

311 return self[:, j] 

312 

313 def extract(self, rowsList, colsList): 

314 r"""Return a submatrix by specifying a list of rows and columns. 

315 Negative indices can be given. All indices must be in the range 

316 $-n \le i < n$ where $n$ is the number of rows or columns. 

317 

318 Examples 

319 ======== 

320 

321 >>> from sympy import Matrix 

322 >>> m = Matrix(4, 3, range(12)) 

323 >>> m 

324 Matrix([ 

325 [0, 1, 2], 

326 [3, 4, 5], 

327 [6, 7, 8], 

328 [9, 10, 11]]) 

329 >>> m.extract([0, 1, 3], [0, 1]) 

330 Matrix([ 

331 [0, 1], 

332 [3, 4], 

333 [9, 10]]) 

334 

335 Rows or columns can be repeated: 

336 

337 >>> m.extract([0, 0, 1], [-1]) 

338 Matrix([ 

339 [2], 

340 [2], 

341 [5]]) 

342 

343 Every other row can be taken by using range to provide the indices: 

344 

345 >>> m.extract(range(0, m.rows, 2), [-1]) 

346 Matrix([ 

347 [2], 

348 [8]]) 

349 

350 RowsList or colsList can also be a list of booleans, in which case 

351 the rows or columns corresponding to the True values will be selected: 

352 

353 >>> m.extract([0, 1, 2, 3], [True, False, True]) 

354 Matrix([ 

355 [0, 2], 

356 [3, 5], 

357 [6, 8], 

358 [9, 11]]) 

359 """ 

360 

361 if not is_sequence(rowsList) or not is_sequence(colsList): 

362 raise TypeError("rowsList and colsList must be iterable") 

363 # ensure rowsList and colsList are lists of integers 

364 if rowsList and all(isinstance(i, bool) for i in rowsList): 

365 rowsList = [index for index, item in enumerate(rowsList) if item] 

366 if colsList and all(isinstance(i, bool) for i in colsList): 

367 colsList = [index for index, item in enumerate(colsList) if item] 

368 

369 # ensure everything is in range 

370 rowsList = [a2idx(k, self.rows) for k in rowsList] 

371 colsList = [a2idx(k, self.cols) for k in colsList] 

372 

373 return self._eval_extract(rowsList, colsList) 

374 

375 def get_diag_blocks(self): 

376 """Obtains the square sub-matrices on the main diagonal of a square matrix. 

377 

378 Useful for inverting symbolic matrices or solving systems of 

379 linear equations which may be decoupled by having a block diagonal 

380 structure. 

381 

382 Examples 

383 ======== 

384 

385 >>> from sympy import Matrix 

386 >>> from sympy.abc import x, y, z 

387 >>> A = Matrix([[1, 3, 0, 0], [y, z*z, 0, 0], [0, 0, x, 0], [0, 0, 0, 0]]) 

388 >>> a1, a2, a3 = A.get_diag_blocks() 

389 >>> a1 

390 Matrix([ 

391 [1, 3], 

392 [y, z**2]]) 

393 >>> a2 

394 Matrix([[x]]) 

395 >>> a3 

396 Matrix([[0]]) 

397 

398 """ 

399 return self._eval_get_diag_blocks() 

400 

401 @classmethod 

402 def hstack(cls, *args): 

403 """Return a matrix formed by joining args horizontally (i.e. 

404 by repeated application of row_join). 

405 

406 Examples 

407 ======== 

408 

409 >>> from sympy import Matrix, eye 

410 >>> Matrix.hstack(eye(2), 2*eye(2)) 

411 Matrix([ 

412 [1, 0, 2, 0], 

413 [0, 1, 0, 2]]) 

414 """ 

415 if len(args) == 0: 

416 return cls._new() 

417 

418 kls = type(args[0]) 

419 return reduce(kls.row_join, args) 

420 

421 def reshape(self, rows, cols): 

422 """Reshape the matrix. Total number of elements must remain the same. 

423 

424 Examples 

425 ======== 

426 

427 >>> from sympy import Matrix 

428 >>> m = Matrix(2, 3, lambda i, j: 1) 

429 >>> m 

430 Matrix([ 

431 [1, 1, 1], 

432 [1, 1, 1]]) 

433 >>> m.reshape(1, 6) 

434 Matrix([[1, 1, 1, 1, 1, 1]]) 

435 >>> m.reshape(3, 2) 

436 Matrix([ 

437 [1, 1], 

438 [1, 1], 

439 [1, 1]]) 

440 

441 """ 

442 if self.rows * self.cols != rows * cols: 

443 raise ValueError("Invalid reshape parameters %d %d" % (rows, cols)) 

444 return self._new(rows, cols, lambda i, j: self[i * cols + j]) 

445 

446 def row_del(self, row): 

447 """Delete the specified row.""" 

448 if row < 0: 

449 row += self.rows 

450 if not 0 <= row < self.rows: 

451 raise IndexError("Row {} is out of range.".format(row)) 

452 

453 return self._eval_row_del(row) 

454 

455 def row_insert(self, pos, other): 

456 """Insert one or more rows at the given row position. 

457 

458 Examples 

459 ======== 

460 

461 >>> from sympy import zeros, ones 

462 >>> M = zeros(3) 

463 >>> V = ones(1, 3) 

464 >>> M.row_insert(1, V) 

465 Matrix([ 

466 [0, 0, 0], 

467 [1, 1, 1], 

468 [0, 0, 0], 

469 [0, 0, 0]]) 

470 

471 See Also 

472 ======== 

473 

474 row 

475 col_insert 

476 """ 

477 # Allows you to build a matrix even if it is null matrix 

478 if not self: 

479 return self._new(other) 

480 

481 pos = as_int(pos) 

482 

483 if pos < 0: 

484 pos = self.rows + pos 

485 if pos < 0: 

486 pos = 0 

487 elif pos > self.rows: 

488 pos = self.rows 

489 

490 if self.cols != other.cols: 

491 raise ShapeError( 

492 "The matrices have incompatible number of columns ({} and {})" 

493 .format(self.cols, other.cols)) 

494 

495 return self._eval_row_insert(pos, other) 

496 

497 def row_join(self, other): 

498 """Concatenates two matrices along self's last and rhs's first column 

499 

500 Examples 

501 ======== 

502 

503 >>> from sympy import zeros, ones 

504 >>> M = zeros(3) 

505 >>> V = ones(3, 1) 

506 >>> M.row_join(V) 

507 Matrix([ 

508 [0, 0, 0, 1], 

509 [0, 0, 0, 1], 

510 [0, 0, 0, 1]]) 

511 

512 See Also 

513 ======== 

514 

515 row 

516 col_join 

517 """ 

518 # A null matrix can always be stacked (see #10770) 

519 if self.cols == 0 and self.rows != other.rows: 

520 return self._new(other.rows, 0, []).row_join(other) 

521 

522 if self.rows != other.rows: 

523 raise ShapeError( 

524 "The matrices have incompatible number of rows ({} and {})" 

525 .format(self.rows, other.rows)) 

526 return self._eval_row_join(other) 

527 

528 def diagonal(self, k=0): 

529 """Returns the kth diagonal of self. The main diagonal 

530 corresponds to `k=0`; diagonals above and below correspond to 

531 `k > 0` and `k < 0`, respectively. The values of `self[i, j]` 

532 for which `j - i = k`, are returned in order of increasing 

533 `i + j`, starting with `i + j = |k|`. 

534 

535 Examples 

536 ======== 

537 

538 >>> from sympy import Matrix 

539 >>> m = Matrix(3, 3, lambda i, j: j - i); m 

540 Matrix([ 

541 [ 0, 1, 2], 

542 [-1, 0, 1], 

543 [-2, -1, 0]]) 

544 >>> _.diagonal() 

545 Matrix([[0, 0, 0]]) 

546 >>> m.diagonal(1) 

547 Matrix([[1, 1]]) 

548 >>> m.diagonal(-2) 

549 Matrix([[-2]]) 

550 

551 Even though the diagonal is returned as a Matrix, the element 

552 retrieval can be done with a single index: 

553 

554 >>> Matrix.diag(1, 2, 3).diagonal()[1] # instead of [0, 1] 

555 2 

556 

557 See Also 

558 ======== 

559 

560 diag 

561 """ 

562 rv = [] 

563 k = as_int(k) 

564 r = 0 if k > 0 else -k 

565 c = 0 if r else k 

566 while True: 

567 if r == self.rows or c == self.cols: 

568 break 

569 rv.append(self[r, c]) 

570 r += 1 

571 c += 1 

572 if not rv: 

573 raise ValueError(filldedent(''' 

574 The %s diagonal is out of range [%s, %s]''' % ( 

575 k, 1 - self.rows, self.cols - 1))) 

576 return self._new(1, len(rv), rv) 

577 

578 def row(self, i): 

579 """Elementary row selector. 

580 

581 Examples 

582 ======== 

583 

584 >>> from sympy import eye 

585 >>> eye(2).row(0) 

586 Matrix([[1, 0]]) 

587 

588 See Also 

589 ======== 

590 

591 col 

592 row_del 

593 row_join 

594 row_insert 

595 """ 

596 return self[i, :] 

597 

598 @property 

599 def shape(self): 

600 """The shape (dimensions) of the matrix as the 2-tuple (rows, cols). 

601 

602 Examples 

603 ======== 

604 

605 >>> from sympy import zeros 

606 >>> M = zeros(2, 3) 

607 >>> M.shape 

608 (2, 3) 

609 >>> M.rows 

610 2 

611 >>> M.cols 

612 3 

613 """ 

614 return (self.rows, self.cols) 

615 

616 def todok(self): 

617 """Return the matrix as dictionary of keys. 

618 

619 Examples 

620 ======== 

621 

622 >>> from sympy import Matrix 

623 >>> M = Matrix.eye(3) 

624 >>> M.todok() 

625 {(0, 0): 1, (1, 1): 1, (2, 2): 1} 

626 """ 

627 return self._eval_todok() 

628 

629 def tolist(self): 

630 """Return the Matrix as a nested Python list. 

631 

632 Examples 

633 ======== 

634 

635 >>> from sympy import Matrix, ones 

636 >>> m = Matrix(3, 3, range(9)) 

637 >>> m 

638 Matrix([ 

639 [0, 1, 2], 

640 [3, 4, 5], 

641 [6, 7, 8]]) 

642 >>> m.tolist() 

643 [[0, 1, 2], [3, 4, 5], [6, 7, 8]] 

644 >>> ones(3, 0).tolist() 

645 [[], [], []] 

646 

647 When there are no rows then it will not be possible to tell how 

648 many columns were in the original matrix: 

649 

650 >>> ones(0, 3).tolist() 

651 [] 

652 

653 """ 

654 if not self.rows: 

655 return [] 

656 if not self.cols: 

657 return [[] for i in range(self.rows)] 

658 return self._eval_tolist() 

659 

660 def todod(M): 

661 """Returns matrix as dict of dicts containing non-zero elements of the Matrix 

662 

663 Examples 

664 ======== 

665 

666 >>> from sympy import Matrix 

667 >>> A = Matrix([[0, 1],[0, 3]]) 

668 >>> A 

669 Matrix([ 

670 [0, 1], 

671 [0, 3]]) 

672 >>> A.todod() 

673 {0: {1: 1}, 1: {1: 3}} 

674 

675 

676 """ 

677 rowsdict = {} 

678 Mlol = M.tolist() 

679 for i, Mi in enumerate(Mlol): 

680 row = {j: Mij for j, Mij in enumerate(Mi) if Mij} 

681 if row: 

682 rowsdict[i] = row 

683 return rowsdict 

684 

685 def vec(self): 

686 """Return the Matrix converted into a one column matrix by stacking columns 

687 

688 Examples 

689 ======== 

690 

691 >>> from sympy import Matrix 

692 >>> m=Matrix([[1, 3], [2, 4]]) 

693 >>> m 

694 Matrix([ 

695 [1, 3], 

696 [2, 4]]) 

697 >>> m.vec() 

698 Matrix([ 

699 [1], 

700 [2], 

701 [3], 

702 [4]]) 

703 

704 See Also 

705 ======== 

706 

707 vech 

708 """ 

709 return self._eval_vec() 

710 

711 def vech(self, diagonal=True, check_symmetry=True): 

712 """Reshapes the matrix into a column vector by stacking the 

713 elements in the lower triangle. 

714 

715 Parameters 

716 ========== 

717 

718 diagonal : bool, optional 

719 If ``True``, it includes the diagonal elements. 

720 

721 check_symmetry : bool, optional 

722 If ``True``, it checks whether the matrix is symmetric. 

723 

724 Examples 

725 ======== 

726 

727 >>> from sympy import Matrix 

728 >>> m=Matrix([[1, 2], [2, 3]]) 

729 >>> m 

730 Matrix([ 

731 [1, 2], 

732 [2, 3]]) 

733 >>> m.vech() 

734 Matrix([ 

735 [1], 

736 [2], 

737 [3]]) 

738 >>> m.vech(diagonal=False) 

739 Matrix([[2]]) 

740 

741 Notes 

742 ===== 

743 

744 This should work for symmetric matrices and ``vech`` can 

745 represent symmetric matrices in vector form with less size than 

746 ``vec``. 

747 

748 See Also 

749 ======== 

750 

751 vec 

752 """ 

753 if not self.is_square: 

754 raise NonSquareMatrixError 

755 

756 if check_symmetry and not self.is_symmetric(): 

757 raise ValueError("The matrix is not symmetric.") 

758 

759 return self._eval_vech(diagonal) 

760 

761 @classmethod 

762 def vstack(cls, *args): 

763 """Return a matrix formed by joining args vertically (i.e. 

764 by repeated application of col_join). 

765 

766 Examples 

767 ======== 

768 

769 >>> from sympy import Matrix, eye 

770 >>> Matrix.vstack(eye(2), 2*eye(2)) 

771 Matrix([ 

772 [1, 0], 

773 [0, 1], 

774 [2, 0], 

775 [0, 2]]) 

776 """ 

777 if len(args) == 0: 

778 return cls._new() 

779 

780 kls = type(args[0]) 

781 return reduce(kls.col_join, args) 

782 

783 

784class MatrixSpecial(MatrixRequired): 

785 """Construction of special matrices""" 

786 

787 @classmethod 

788 def _eval_diag(cls, rows, cols, diag_dict): 

789 """diag_dict is a defaultdict containing 

790 all the entries of the diagonal matrix.""" 

791 def entry(i, j): 

792 return diag_dict[(i, j)] 

793 return cls._new(rows, cols, entry) 

794 

795 @classmethod 

796 def _eval_eye(cls, rows, cols): 

797 vals = [cls.zero]*(rows*cols) 

798 vals[::cols+1] = [cls.one]*min(rows, cols) 

799 return cls._new(rows, cols, vals, copy=False) 

800 

801 @classmethod 

802 def _eval_jordan_block(cls, size: int, eigenvalue, band='upper'): 

803 if band == 'lower': 

804 def entry(i, j): 

805 if i == j: 

806 return eigenvalue 

807 elif j + 1 == i: 

808 return cls.one 

809 return cls.zero 

810 else: 

811 def entry(i, j): 

812 if i == j: 

813 return eigenvalue 

814 elif i + 1 == j: 

815 return cls.one 

816 return cls.zero 

817 return cls._new(size, size, entry) 

818 

819 @classmethod 

820 def _eval_ones(cls, rows, cols): 

821 def entry(i, j): 

822 return cls.one 

823 return cls._new(rows, cols, entry) 

824 

825 @classmethod 

826 def _eval_zeros(cls, rows, cols): 

827 return cls._new(rows, cols, [cls.zero]*(rows*cols), copy=False) 

828 

829 @classmethod 

830 def _eval_wilkinson(cls, n): 

831 def entry(i, j): 

832 return cls.one if i + 1 == j else cls.zero 

833 

834 D = cls._new(2*n + 1, 2*n + 1, entry) 

835 

836 wminus = cls.diag(list(range(-n, n + 1)), unpack=True) + D + D.T 

837 wplus = abs(cls.diag(list(range(-n, n + 1)), unpack=True)) + D + D.T 

838 

839 return wminus, wplus 

840 

841 @classmethod 

842 def diag(kls, *args, strict=False, unpack=True, rows=None, cols=None, **kwargs): 

843 """Returns a matrix with the specified diagonal. 

844 If matrices are passed, a block-diagonal matrix 

845 is created (i.e. the "direct sum" of the matrices). 

846 

847 kwargs 

848 ====== 

849 

850 rows : rows of the resulting matrix; computed if 

851 not given. 

852 

853 cols : columns of the resulting matrix; computed if 

854 not given. 

855 

856 cls : class for the resulting matrix 

857 

858 unpack : bool which, when True (default), unpacks a single 

859 sequence rather than interpreting it as a Matrix. 

860 

861 strict : bool which, when False (default), allows Matrices to 

862 have variable-length rows. 

863 

864 Examples 

865 ======== 

866 

867 >>> from sympy import Matrix 

868 >>> Matrix.diag(1, 2, 3) 

869 Matrix([ 

870 [1, 0, 0], 

871 [0, 2, 0], 

872 [0, 0, 3]]) 

873 

874 The current default is to unpack a single sequence. If this is 

875 not desired, set `unpack=False` and it will be interpreted as 

876 a matrix. 

877 

878 >>> Matrix.diag([1, 2, 3]) == Matrix.diag(1, 2, 3) 

879 True 

880 

881 When more than one element is passed, each is interpreted as 

882 something to put on the diagonal. Lists are converted to 

883 matrices. Filling of the diagonal always continues from 

884 the bottom right hand corner of the previous item: this 

885 will create a block-diagonal matrix whether the matrices 

886 are square or not. 

887 

888 >>> col = [1, 2, 3] 

889 >>> row = [[4, 5]] 

890 >>> Matrix.diag(col, row) 

891 Matrix([ 

892 [1, 0, 0], 

893 [2, 0, 0], 

894 [3, 0, 0], 

895 [0, 4, 5]]) 

896 

897 When `unpack` is False, elements within a list need not all be 

898 of the same length. Setting `strict` to True would raise a 

899 ValueError for the following: 

900 

901 >>> Matrix.diag([[1, 2, 3], [4, 5], [6]], unpack=False) 

902 Matrix([ 

903 [1, 2, 3], 

904 [4, 5, 0], 

905 [6, 0, 0]]) 

906 

907 The type of the returned matrix can be set with the ``cls`` 

908 keyword. 

909 

910 >>> from sympy import ImmutableMatrix 

911 >>> from sympy.utilities.misc import func_name 

912 >>> func_name(Matrix.diag(1, cls=ImmutableMatrix)) 

913 'ImmutableDenseMatrix' 

914 

915 A zero dimension matrix can be used to position the start of 

916 the filling at the start of an arbitrary row or column: 

917 

918 >>> from sympy import ones 

919 >>> r2 = ones(0, 2) 

920 >>> Matrix.diag(r2, 1, 2) 

921 Matrix([ 

922 [0, 0, 1, 0], 

923 [0, 0, 0, 2]]) 

924 

925 See Also 

926 ======== 

927 eye 

928 diagonal 

929 .dense.diag 

930 .expressions.blockmatrix.BlockMatrix 

931 .sparsetools.banded 

932 """ 

933 from sympy.matrices.matrices import MatrixBase 

934 from sympy.matrices.dense import Matrix 

935 from sympy.matrices import SparseMatrix 

936 klass = kwargs.get('cls', kls) 

937 if unpack and len(args) == 1 and is_sequence(args[0]) and \ 

938 not isinstance(args[0], MatrixBase): 

939 args = args[0] 

940 

941 # fill a default dict with the diagonal entries 

942 diag_entries = defaultdict(int) 

943 rmax = cmax = 0 # keep track of the biggest index seen 

944 for m in args: 

945 if isinstance(m, list): 

946 if strict: 

947 # if malformed, Matrix will raise an error 

948 _ = Matrix(m) 

949 r, c = _.shape 

950 m = _.tolist() 

951 else: 

952 r, c, smat = SparseMatrix._handle_creation_inputs(m) 

953 for (i, j), _ in smat.items(): 

954 diag_entries[(i + rmax, j + cmax)] = _ 

955 m = [] # to skip process below 

956 elif hasattr(m, 'shape'): # a Matrix 

957 # convert to list of lists 

958 r, c = m.shape 

959 m = m.tolist() 

960 else: # in this case, we're a single value 

961 diag_entries[(rmax, cmax)] = m 

962 rmax += 1 

963 cmax += 1 

964 continue 

965 # process list of lists 

966 for i, mi in enumerate(m): 

967 for j, _ in enumerate(mi): 

968 diag_entries[(i + rmax, j + cmax)] = _ 

969 rmax += r 

970 cmax += c 

971 if rows is None: 

972 rows, cols = cols, rows 

973 if rows is None: 

974 rows, cols = rmax, cmax 

975 else: 

976 cols = rows if cols is None else cols 

977 if rows < rmax or cols < cmax: 

978 raise ValueError(filldedent(''' 

979 The constructed matrix is {} x {} but a size of {} x {} 

980 was specified.'''.format(rmax, cmax, rows, cols))) 

981 return klass._eval_diag(rows, cols, diag_entries) 

982 

983 @classmethod 

984 def eye(kls, rows, cols=None, **kwargs): 

985 """Returns an identity matrix. 

986 

987 Parameters 

988 ========== 

989 

990 rows : rows of the matrix 

991 cols : cols of the matrix (if None, cols=rows) 

992 

993 kwargs 

994 ====== 

995 cls : class of the returned matrix 

996 """ 

997 if cols is None: 

998 cols = rows 

999 if rows < 0 or cols < 0: 

1000 raise ValueError("Cannot create a {} x {} matrix. " 

1001 "Both dimensions must be positive".format(rows, cols)) 

1002 klass = kwargs.get('cls', kls) 

1003 rows, cols = as_int(rows), as_int(cols) 

1004 

1005 return klass._eval_eye(rows, cols) 

1006 

1007 @classmethod 

1008 def jordan_block(kls, size=None, eigenvalue=None, *, band='upper', **kwargs): 

1009 """Returns a Jordan block 

1010 

1011 Parameters 

1012 ========== 

1013 

1014 size : Integer, optional 

1015 Specifies the shape of the Jordan block matrix. 

1016 

1017 eigenvalue : Number or Symbol 

1018 Specifies the value for the main diagonal of the matrix. 

1019 

1020 .. note:: 

1021 The keyword ``eigenval`` is also specified as an alias 

1022 of this keyword, but it is not recommended to use. 

1023 

1024 We may deprecate the alias in later release. 

1025 

1026 band : 'upper' or 'lower', optional 

1027 Specifies the position of the off-diagonal to put `1` s on. 

1028 

1029 cls : Matrix, optional 

1030 Specifies the matrix class of the output form. 

1031 

1032 If it is not specified, the class type where the method is 

1033 being executed on will be returned. 

1034 

1035 Returns 

1036 ======= 

1037 

1038 Matrix 

1039 A Jordan block matrix. 

1040 

1041 Raises 

1042 ====== 

1043 

1044 ValueError 

1045 If insufficient arguments are given for matrix size 

1046 specification, or no eigenvalue is given. 

1047 

1048 Examples 

1049 ======== 

1050 

1051 Creating a default Jordan block: 

1052 

1053 >>> from sympy import Matrix 

1054 >>> from sympy.abc import x 

1055 >>> Matrix.jordan_block(4, x) 

1056 Matrix([ 

1057 [x, 1, 0, 0], 

1058 [0, x, 1, 0], 

1059 [0, 0, x, 1], 

1060 [0, 0, 0, x]]) 

1061 

1062 Creating an alternative Jordan block matrix where `1` is on 

1063 lower off-diagonal: 

1064 

1065 >>> Matrix.jordan_block(4, x, band='lower') 

1066 Matrix([ 

1067 [x, 0, 0, 0], 

1068 [1, x, 0, 0], 

1069 [0, 1, x, 0], 

1070 [0, 0, 1, x]]) 

1071 

1072 Creating a Jordan block with keyword arguments 

1073 

1074 >>> Matrix.jordan_block(size=4, eigenvalue=x) 

1075 Matrix([ 

1076 [x, 1, 0, 0], 

1077 [0, x, 1, 0], 

1078 [0, 0, x, 1], 

1079 [0, 0, 0, x]]) 

1080 

1081 References 

1082 ========== 

1083 

1084 .. [1] https://en.wikipedia.org/wiki/Jordan_matrix 

1085 """ 

1086 klass = kwargs.pop('cls', kls) 

1087 

1088 eigenval = kwargs.get('eigenval', None) 

1089 if eigenvalue is None and eigenval is None: 

1090 raise ValueError("Must supply an eigenvalue") 

1091 elif eigenvalue != eigenval and None not in (eigenval, eigenvalue): 

1092 raise ValueError( 

1093 "Inconsistent values are given: 'eigenval'={}, " 

1094 "'eigenvalue'={}".format(eigenval, eigenvalue)) 

1095 else: 

1096 if eigenval is not None: 

1097 eigenvalue = eigenval 

1098 

1099 if size is None: 

1100 raise ValueError("Must supply a matrix size") 

1101 

1102 size = as_int(size) 

1103 return klass._eval_jordan_block(size, eigenvalue, band) 

1104 

1105 @classmethod 

1106 def ones(kls, rows, cols=None, **kwargs): 

1107 """Returns a matrix of ones. 

1108 

1109 Parameters 

1110 ========== 

1111 

1112 rows : rows of the matrix 

1113 cols : cols of the matrix (if None, cols=rows) 

1114 

1115 kwargs 

1116 ====== 

1117 cls : class of the returned matrix 

1118 """ 

1119 if cols is None: 

1120 cols = rows 

1121 klass = kwargs.get('cls', kls) 

1122 rows, cols = as_int(rows), as_int(cols) 

1123 

1124 return klass._eval_ones(rows, cols) 

1125 

1126 @classmethod 

1127 def zeros(kls, rows, cols=None, **kwargs): 

1128 """Returns a matrix of zeros. 

1129 

1130 Parameters 

1131 ========== 

1132 

1133 rows : rows of the matrix 

1134 cols : cols of the matrix (if None, cols=rows) 

1135 

1136 kwargs 

1137 ====== 

1138 cls : class of the returned matrix 

1139 """ 

1140 if cols is None: 

1141 cols = rows 

1142 if rows < 0 or cols < 0: 

1143 raise ValueError("Cannot create a {} x {} matrix. " 

1144 "Both dimensions must be positive".format(rows, cols)) 

1145 klass = kwargs.get('cls', kls) 

1146 rows, cols = as_int(rows), as_int(cols) 

1147 

1148 return klass._eval_zeros(rows, cols) 

1149 

1150 @classmethod 

1151 def companion(kls, poly): 

1152 """Returns a companion matrix of a polynomial. 

1153 

1154 Examples 

1155 ======== 

1156 

1157 >>> from sympy import Matrix, Poly, Symbol, symbols 

1158 >>> x = Symbol('x') 

1159 >>> c0, c1, c2, c3, c4 = symbols('c0:5') 

1160 >>> p = Poly(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + x**5, x) 

1161 >>> Matrix.companion(p) 

1162 Matrix([ 

1163 [0, 0, 0, 0, -c0], 

1164 [1, 0, 0, 0, -c1], 

1165 [0, 1, 0, 0, -c2], 

1166 [0, 0, 1, 0, -c3], 

1167 [0, 0, 0, 1, -c4]]) 

1168 """ 

1169 poly = kls._sympify(poly) 

1170 if not isinstance(poly, Poly): 

1171 raise ValueError("{} must be a Poly instance.".format(poly)) 

1172 if not poly.is_monic: 

1173 raise ValueError("{} must be a monic polynomial.".format(poly)) 

1174 if not poly.is_univariate: 

1175 raise ValueError( 

1176 "{} must be a univariate polynomial.".format(poly)) 

1177 

1178 size = poly.degree() 

1179 if not size >= 1: 

1180 raise ValueError( 

1181 "{} must have degree not less than 1.".format(poly)) 

1182 

1183 coeffs = poly.all_coeffs() 

1184 def entry(i, j): 

1185 if j == size - 1: 

1186 return -coeffs[-1 - i] 

1187 elif i == j + 1: 

1188 return kls.one 

1189 return kls.zero 

1190 return kls._new(size, size, entry) 

1191 

1192 

1193 @classmethod 

1194 def wilkinson(kls, n, **kwargs): 

1195 """Returns two square Wilkinson Matrix of size 2*n + 1 

1196 $W_{2n + 1}^-, W_{2n + 1}^+ =$ Wilkinson(n) 

1197 

1198 Examples 

1199 ======== 

1200 

1201 >>> from sympy import Matrix 

1202 >>> wminus, wplus = Matrix.wilkinson(3) 

1203 >>> wminus 

1204 Matrix([ 

1205 [-3, 1, 0, 0, 0, 0, 0], 

1206 [ 1, -2, 1, 0, 0, 0, 0], 

1207 [ 0, 1, -1, 1, 0, 0, 0], 

1208 [ 0, 0, 1, 0, 1, 0, 0], 

1209 [ 0, 0, 0, 1, 1, 1, 0], 

1210 [ 0, 0, 0, 0, 1, 2, 1], 

1211 [ 0, 0, 0, 0, 0, 1, 3]]) 

1212 >>> wplus 

1213 Matrix([ 

1214 [3, 1, 0, 0, 0, 0, 0], 

1215 [1, 2, 1, 0, 0, 0, 0], 

1216 [0, 1, 1, 1, 0, 0, 0], 

1217 [0, 0, 1, 0, 1, 0, 0], 

1218 [0, 0, 0, 1, 1, 1, 0], 

1219 [0, 0, 0, 0, 1, 2, 1], 

1220 [0, 0, 0, 0, 0, 1, 3]]) 

1221 

1222 References 

1223 ========== 

1224 

1225 .. [1] https://blogs.mathworks.com/cleve/2013/04/15/wilkinsons-matrices-2/ 

1226 .. [2] J. H. Wilkinson, The Algebraic Eigenvalue Problem, Claredon Press, Oxford, 1965, 662 pp. 

1227 

1228 """ 

1229 klass = kwargs.get('cls', kls) 

1230 n = as_int(n) 

1231 return klass._eval_wilkinson(n) 

1232 

1233class MatrixProperties(MatrixRequired): 

1234 """Provides basic properties of a matrix.""" 

1235 

1236 def _eval_atoms(self, *types): 

1237 result = set() 

1238 for i in self: 

1239 result.update(i.atoms(*types)) 

1240 return result 

1241 

1242 def _eval_free_symbols(self): 

1243 return set().union(*(i.free_symbols for i in self if i)) 

1244 

1245 def _eval_has(self, *patterns): 

1246 return any(a.has(*patterns) for a in self) 

1247 

1248 def _eval_is_anti_symmetric(self, simpfunc): 

1249 if not all(simpfunc(self[i, j] + self[j, i]).is_zero for i in range(self.rows) for j in range(self.cols)): 

1250 return False 

1251 return True 

1252 

1253 def _eval_is_diagonal(self): 

1254 for i in range(self.rows): 

1255 for j in range(self.cols): 

1256 if i != j and self[i, j]: 

1257 return False 

1258 return True 

1259 

1260 # _eval_is_hermitian is called by some general SymPy 

1261 # routines and has a different *args signature. Make 

1262 # sure the names don't clash by adding `_matrix_` in name. 

1263 def _eval_is_matrix_hermitian(self, simpfunc): 

1264 mat = self._new(self.rows, self.cols, lambda i, j: simpfunc(self[i, j] - self[j, i].conjugate())) 

1265 return mat.is_zero_matrix 

1266 

1267 def _eval_is_Identity(self) -> FuzzyBool: 

1268 def dirac(i, j): 

1269 if i == j: 

1270 return 1 

1271 return 0 

1272 

1273 return all(self[i, j] == dirac(i, j) 

1274 for i in range(self.rows) 

1275 for j in range(self.cols)) 

1276 

1277 def _eval_is_lower_hessenberg(self): 

1278 return all(self[i, j].is_zero 

1279 for i in range(self.rows) 

1280 for j in range(i + 2, self.cols)) 

1281 

1282 def _eval_is_lower(self): 

1283 return all(self[i, j].is_zero 

1284 for i in range(self.rows) 

1285 for j in range(i + 1, self.cols)) 

1286 

1287 def _eval_is_symbolic(self): 

1288 return self.has(Symbol) 

1289 

1290 def _eval_is_symmetric(self, simpfunc): 

1291 mat = self._new(self.rows, self.cols, lambda i, j: simpfunc(self[i, j] - self[j, i])) 

1292 return mat.is_zero_matrix 

1293 

1294 def _eval_is_zero_matrix(self): 

1295 if any(i.is_zero == False for i in self): 

1296 return False 

1297 if any(i.is_zero is None for i in self): 

1298 return None 

1299 return True 

1300 

1301 def _eval_is_upper_hessenberg(self): 

1302 return all(self[i, j].is_zero 

1303 for i in range(2, self.rows) 

1304 for j in range(min(self.cols, (i - 1)))) 

1305 

1306 def _eval_values(self): 

1307 return [i for i in self if not i.is_zero] 

1308 

1309 def _has_positive_diagonals(self): 

1310 diagonal_entries = (self[i, i] for i in range(self.rows)) 

1311 return fuzzy_and(x.is_positive for x in diagonal_entries) 

1312 

1313 def _has_nonnegative_diagonals(self): 

1314 diagonal_entries = (self[i, i] for i in range(self.rows)) 

1315 return fuzzy_and(x.is_nonnegative for x in diagonal_entries) 

1316 

1317 def atoms(self, *types): 

1318 """Returns the atoms that form the current object. 

1319 

1320 Examples 

1321 ======== 

1322 

1323 >>> from sympy.abc import x, y 

1324 >>> from sympy import Matrix 

1325 >>> Matrix([[x]]) 

1326 Matrix([[x]]) 

1327 >>> _.atoms() 

1328 {x} 

1329 >>> Matrix([[x, y], [y, x]]) 

1330 Matrix([ 

1331 [x, y], 

1332 [y, x]]) 

1333 >>> _.atoms() 

1334 {x, y} 

1335 """ 

1336 

1337 types = tuple(t if isinstance(t, type) else type(t) for t in types) 

1338 if not types: 

1339 types = (Atom,) 

1340 return self._eval_atoms(*types) 

1341 

1342 @property 

1343 def free_symbols(self): 

1344 """Returns the free symbols within the matrix. 

1345 

1346 Examples 

1347 ======== 

1348 

1349 >>> from sympy.abc import x 

1350 >>> from sympy import Matrix 

1351 >>> Matrix([[x], [1]]).free_symbols 

1352 {x} 

1353 """ 

1354 return self._eval_free_symbols() 

1355 

1356 def has(self, *patterns): 

1357 """Test whether any subexpression matches any of the patterns. 

1358 

1359 Examples 

1360 ======== 

1361 

1362 >>> from sympy import Matrix, SparseMatrix, Float 

1363 >>> from sympy.abc import x, y 

1364 >>> A = Matrix(((1, x), (0.2, 3))) 

1365 >>> B = SparseMatrix(((1, x), (0.2, 3))) 

1366 >>> A.has(x) 

1367 True 

1368 >>> A.has(y) 

1369 False 

1370 >>> A.has(Float) 

1371 True 

1372 >>> B.has(x) 

1373 True 

1374 >>> B.has(y) 

1375 False 

1376 >>> B.has(Float) 

1377 True 

1378 """ 

1379 return self._eval_has(*patterns) 

1380 

1381 def is_anti_symmetric(self, simplify=True): 

1382 """Check if matrix M is an antisymmetric matrix, 

1383 that is, M is a square matrix with all M[i, j] == -M[j, i]. 

1384 

1385 When ``simplify=True`` (default), the sum M[i, j] + M[j, i] is 

1386 simplified before testing to see if it is zero. By default, 

1387 the SymPy simplify function is used. To use a custom function 

1388 set simplify to a function that accepts a single argument which 

1389 returns a simplified expression. To skip simplification, set 

1390 simplify to False but note that although this will be faster, 

1391 it may induce false negatives. 

1392 

1393 Examples 

1394 ======== 

1395 

1396 >>> from sympy import Matrix, symbols 

1397 >>> m = Matrix(2, 2, [0, 1, -1, 0]) 

1398 >>> m 

1399 Matrix([ 

1400 [ 0, 1], 

1401 [-1, 0]]) 

1402 >>> m.is_anti_symmetric() 

1403 True 

1404 >>> x, y = symbols('x y') 

1405 >>> m = Matrix(2, 3, [0, 0, x, -y, 0, 0]) 

1406 >>> m 

1407 Matrix([ 

1408 [ 0, 0, x], 

1409 [-y, 0, 0]]) 

1410 >>> m.is_anti_symmetric() 

1411 False 

1412 

1413 >>> from sympy.abc import x, y 

1414 >>> m = Matrix(3, 3, [0, x**2 + 2*x + 1, y, 

1415 ... -(x + 1)**2, 0, x*y, 

1416 ... -y, -x*y, 0]) 

1417 

1418 Simplification of matrix elements is done by default so even 

1419 though two elements which should be equal and opposite would not 

1420 pass an equality test, the matrix is still reported as 

1421 anti-symmetric: 

1422 

1423 >>> m[0, 1] == -m[1, 0] 

1424 False 

1425 >>> m.is_anti_symmetric() 

1426 True 

1427 

1428 If ``simplify=False`` is used for the case when a Matrix is already 

1429 simplified, this will speed things up. Here, we see that without 

1430 simplification the matrix does not appear anti-symmetric: 

1431 

1432 >>> m.is_anti_symmetric(simplify=False) 

1433 False 

1434 

1435 But if the matrix were already expanded, then it would appear 

1436 anti-symmetric and simplification in the is_anti_symmetric routine 

1437 is not needed: 

1438 

1439 >>> m = m.expand() 

1440 >>> m.is_anti_symmetric(simplify=False) 

1441 True 

1442 """ 

1443 # accept custom simplification 

1444 simpfunc = simplify 

1445 if not isfunction(simplify): 

1446 simpfunc = _simplify if simplify else lambda x: x 

1447 

1448 if not self.is_square: 

1449 return False 

1450 return self._eval_is_anti_symmetric(simpfunc) 

1451 

1452 def is_diagonal(self): 

1453 """Check if matrix is diagonal, 

1454 that is matrix in which the entries outside the main diagonal are all zero. 

1455 

1456 Examples 

1457 ======== 

1458 

1459 >>> from sympy import Matrix, diag 

1460 >>> m = Matrix(2, 2, [1, 0, 0, 2]) 

1461 >>> m 

1462 Matrix([ 

1463 [1, 0], 

1464 [0, 2]]) 

1465 >>> m.is_diagonal() 

1466 True 

1467 

1468 >>> m = Matrix(2, 2, [1, 1, 0, 2]) 

1469 >>> m 

1470 Matrix([ 

1471 [1, 1], 

1472 [0, 2]]) 

1473 >>> m.is_diagonal() 

1474 False 

1475 

1476 >>> m = diag(1, 2, 3) 

1477 >>> m 

1478 Matrix([ 

1479 [1, 0, 0], 

1480 [0, 2, 0], 

1481 [0, 0, 3]]) 

1482 >>> m.is_diagonal() 

1483 True 

1484 

1485 See Also 

1486 ======== 

1487 

1488 is_lower 

1489 is_upper 

1490 sympy.matrices.matrices.MatrixEigen.is_diagonalizable 

1491 diagonalize 

1492 """ 

1493 return self._eval_is_diagonal() 

1494 

1495 @property 

1496 def is_weakly_diagonally_dominant(self): 

1497 r"""Tests if the matrix is row weakly diagonally dominant. 

1498 

1499 Explanation 

1500 =========== 

1501 

1502 A $n, n$ matrix $A$ is row weakly diagonally dominant if 

1503 

1504 .. math:: 

1505 \left|A_{i, i}\right| \ge \sum_{j = 0, j \neq i}^{n-1} 

1506 \left|A_{i, j}\right| \quad {\text{for all }} 

1507 i \in \{ 0, ..., n-1 \} 

1508 

1509 Examples 

1510 ======== 

1511 

1512 >>> from sympy import Matrix 

1513 >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) 

1514 >>> A.is_weakly_diagonally_dominant 

1515 True 

1516 

1517 >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) 

1518 >>> A.is_weakly_diagonally_dominant 

1519 False 

1520 

1521 >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) 

1522 >>> A.is_weakly_diagonally_dominant 

1523 True 

1524 

1525 Notes 

1526 ===== 

1527 

1528 If you want to test whether a matrix is column diagonally 

1529 dominant, you can apply the test after transposing the matrix. 

1530 """ 

1531 if not self.is_square: 

1532 return False 

1533 

1534 rows, cols = self.shape 

1535 

1536 def test_row(i): 

1537 summation = self.zero 

1538 for j in range(cols): 

1539 if i != j: 

1540 summation += Abs(self[i, j]) 

1541 return (Abs(self[i, i]) - summation).is_nonnegative 

1542 

1543 return fuzzy_and(test_row(i) for i in range(rows)) 

1544 

1545 @property 

1546 def is_strongly_diagonally_dominant(self): 

1547 r"""Tests if the matrix is row strongly diagonally dominant. 

1548 

1549 Explanation 

1550 =========== 

1551 

1552 A $n, n$ matrix $A$ is row strongly diagonally dominant if 

1553 

1554 .. math:: 

1555 \left|A_{i, i}\right| > \sum_{j = 0, j \neq i}^{n-1} 

1556 \left|A_{i, j}\right| \quad {\text{for all }} 

1557 i \in \{ 0, ..., n-1 \} 

1558 

1559 Examples 

1560 ======== 

1561 

1562 >>> from sympy import Matrix 

1563 >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) 

1564 >>> A.is_strongly_diagonally_dominant 

1565 False 

1566 

1567 >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) 

1568 >>> A.is_strongly_diagonally_dominant 

1569 False 

1570 

1571 >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) 

1572 >>> A.is_strongly_diagonally_dominant 

1573 True 

1574 

1575 Notes 

1576 ===== 

1577 

1578 If you want to test whether a matrix is column diagonally 

1579 dominant, you can apply the test after transposing the matrix. 

1580 """ 

1581 if not self.is_square: 

1582 return False 

1583 

1584 rows, cols = self.shape 

1585 

1586 def test_row(i): 

1587 summation = self.zero 

1588 for j in range(cols): 

1589 if i != j: 

1590 summation += Abs(self[i, j]) 

1591 return (Abs(self[i, i]) - summation).is_positive 

1592 

1593 return fuzzy_and(test_row(i) for i in range(rows)) 

1594 

1595 @property 

1596 def is_hermitian(self): 

1597 """Checks if the matrix is Hermitian. 

1598 

1599 In a Hermitian matrix element i,j is the complex conjugate of 

1600 element j,i. 

1601 

1602 Examples 

1603 ======== 

1604 

1605 >>> from sympy import Matrix 

1606 >>> from sympy import I 

1607 >>> from sympy.abc import x 

1608 >>> a = Matrix([[1, I], [-I, 1]]) 

1609 >>> a 

1610 Matrix([ 

1611 [ 1, I], 

1612 [-I, 1]]) 

1613 >>> a.is_hermitian 

1614 True 

1615 >>> a[0, 0] = 2*I 

1616 >>> a.is_hermitian 

1617 False 

1618 >>> a[0, 0] = x 

1619 >>> a.is_hermitian 

1620 >>> a[0, 1] = a[1, 0]*I 

1621 >>> a.is_hermitian 

1622 False 

1623 """ 

1624 if not self.is_square: 

1625 return False 

1626 

1627 return self._eval_is_matrix_hermitian(_simplify) 

1628 

1629 @property 

1630 def is_Identity(self) -> FuzzyBool: 

1631 if not self.is_square: 

1632 return False 

1633 return self._eval_is_Identity() 

1634 

1635 @property 

1636 def is_lower_hessenberg(self): 

1637 r"""Checks if the matrix is in the lower-Hessenberg form. 

1638 

1639 The lower hessenberg matrix has zero entries 

1640 above the first superdiagonal. 

1641 

1642 Examples 

1643 ======== 

1644 

1645 >>> from sympy import Matrix 

1646 >>> a = Matrix([[1, 2, 0, 0], [5, 2, 3, 0], [3, 4, 3, 7], [5, 6, 1, 1]]) 

1647 >>> a 

1648 Matrix([ 

1649 [1, 2, 0, 0], 

1650 [5, 2, 3, 0], 

1651 [3, 4, 3, 7], 

1652 [5, 6, 1, 1]]) 

1653 >>> a.is_lower_hessenberg 

1654 True 

1655 

1656 See Also 

1657 ======== 

1658 

1659 is_upper_hessenberg 

1660 is_lower 

1661 """ 

1662 return self._eval_is_lower_hessenberg() 

1663 

1664 @property 

1665 def is_lower(self): 

1666 """Check if matrix is a lower triangular matrix. True can be returned 

1667 even if the matrix is not square. 

1668 

1669 Examples 

1670 ======== 

1671 

1672 >>> from sympy import Matrix 

1673 >>> m = Matrix(2, 2, [1, 0, 0, 1]) 

1674 >>> m 

1675 Matrix([ 

1676 [1, 0], 

1677 [0, 1]]) 

1678 >>> m.is_lower 

1679 True 

1680 

1681 >>> m = Matrix(4, 3, [0, 0, 0, 2, 0, 0, 1, 4, 0, 6, 6, 5]) 

1682 >>> m 

1683 Matrix([ 

1684 [0, 0, 0], 

1685 [2, 0, 0], 

1686 [1, 4, 0], 

1687 [6, 6, 5]]) 

1688 >>> m.is_lower 

1689 True 

1690 

1691 >>> from sympy.abc import x, y 

1692 >>> m = Matrix(2, 2, [x**2 + y, y**2 + x, 0, x + y]) 

1693 >>> m 

1694 Matrix([ 

1695 [x**2 + y, x + y**2], 

1696 [ 0, x + y]]) 

1697 >>> m.is_lower 

1698 False 

1699 

1700 See Also 

1701 ======== 

1702 

1703 is_upper 

1704 is_diagonal 

1705 is_lower_hessenberg 

1706 """ 

1707 return self._eval_is_lower() 

1708 

1709 @property 

1710 def is_square(self): 

1711 """Checks if a matrix is square. 

1712 

1713 A matrix is square if the number of rows equals the number of columns. 

1714 The empty matrix is square by definition, since the number of rows and 

1715 the number of columns are both zero. 

1716 

1717 Examples 

1718 ======== 

1719 

1720 >>> from sympy import Matrix 

1721 >>> a = Matrix([[1, 2, 3], [4, 5, 6]]) 

1722 >>> b = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 

1723 >>> c = Matrix([]) 

1724 >>> a.is_square 

1725 False 

1726 >>> b.is_square 

1727 True 

1728 >>> c.is_square 

1729 True 

1730 """ 

1731 return self.rows == self.cols 

1732 

1733 def is_symbolic(self): 

1734 """Checks if any elements contain Symbols. 

1735 

1736 Examples 

1737 ======== 

1738 

1739 >>> from sympy import Matrix 

1740 >>> from sympy.abc import x, y 

1741 >>> M = Matrix([[x, y], [1, 0]]) 

1742 >>> M.is_symbolic() 

1743 True 

1744 

1745 """ 

1746 return self._eval_is_symbolic() 

1747 

1748 def is_symmetric(self, simplify=True): 

1749 """Check if matrix is symmetric matrix, 

1750 that is square matrix and is equal to its transpose. 

1751 

1752 By default, simplifications occur before testing symmetry. 

1753 They can be skipped using 'simplify=False'; while speeding things a bit, 

1754 this may however induce false negatives. 

1755 

1756 Examples 

1757 ======== 

1758 

1759 >>> from sympy import Matrix 

1760 >>> m = Matrix(2, 2, [0, 1, 1, 2]) 

1761 >>> m 

1762 Matrix([ 

1763 [0, 1], 

1764 [1, 2]]) 

1765 >>> m.is_symmetric() 

1766 True 

1767 

1768 >>> m = Matrix(2, 2, [0, 1, 2, 0]) 

1769 >>> m 

1770 Matrix([ 

1771 [0, 1], 

1772 [2, 0]]) 

1773 >>> m.is_symmetric() 

1774 False 

1775 

1776 >>> m = Matrix(2, 3, [0, 0, 0, 0, 0, 0]) 

1777 >>> m 

1778 Matrix([ 

1779 [0, 0, 0], 

1780 [0, 0, 0]]) 

1781 >>> m.is_symmetric() 

1782 False 

1783 

1784 >>> from sympy.abc import x, y 

1785 >>> m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) 

1786 >>> m 

1787 Matrix([ 

1788 [ 1, x**2 + 2*x + 1, y], 

1789 [(x + 1)**2, 2, 0], 

1790 [ y, 0, 3]]) 

1791 >>> m.is_symmetric() 

1792 True 

1793 

1794 If the matrix is already simplified, you may speed-up is_symmetric() 

1795 test by using 'simplify=False'. 

1796 

1797 >>> bool(m.is_symmetric(simplify=False)) 

1798 False 

1799 >>> m1 = m.expand() 

1800 >>> m1.is_symmetric(simplify=False) 

1801 True 

1802 """ 

1803 simpfunc = simplify 

1804 if not isfunction(simplify): 

1805 simpfunc = _simplify if simplify else lambda x: x 

1806 

1807 if not self.is_square: 

1808 return False 

1809 

1810 return self._eval_is_symmetric(simpfunc) 

1811 

1812 @property 

1813 def is_upper_hessenberg(self): 

1814 """Checks if the matrix is the upper-Hessenberg form. 

1815 

1816 The upper hessenberg matrix has zero entries 

1817 below the first subdiagonal. 

1818 

1819 Examples 

1820 ======== 

1821 

1822 >>> from sympy import Matrix 

1823 >>> a = Matrix([[1, 4, 2, 3], [3, 4, 1, 7], [0, 2, 3, 4], [0, 0, 1, 3]]) 

1824 >>> a 

1825 Matrix([ 

1826 [1, 4, 2, 3], 

1827 [3, 4, 1, 7], 

1828 [0, 2, 3, 4], 

1829 [0, 0, 1, 3]]) 

1830 >>> a.is_upper_hessenberg 

1831 True 

1832 

1833 See Also 

1834 ======== 

1835 

1836 is_lower_hessenberg 

1837 is_upper 

1838 """ 

1839 return self._eval_is_upper_hessenberg() 

1840 

1841 @property 

1842 def is_upper(self): 

1843 """Check if matrix is an upper triangular matrix. True can be returned 

1844 even if the matrix is not square. 

1845 

1846 Examples 

1847 ======== 

1848 

1849 >>> from sympy import Matrix 

1850 >>> m = Matrix(2, 2, [1, 0, 0, 1]) 

1851 >>> m 

1852 Matrix([ 

1853 [1, 0], 

1854 [0, 1]]) 

1855 >>> m.is_upper 

1856 True 

1857 

1858 >>> m = Matrix(4, 3, [5, 1, 9, 0, 4, 6, 0, 0, 5, 0, 0, 0]) 

1859 >>> m 

1860 Matrix([ 

1861 [5, 1, 9], 

1862 [0, 4, 6], 

1863 [0, 0, 5], 

1864 [0, 0, 0]]) 

1865 >>> m.is_upper 

1866 True 

1867 

1868 >>> m = Matrix(2, 3, [4, 2, 5, 6, 1, 1]) 

1869 >>> m 

1870 Matrix([ 

1871 [4, 2, 5], 

1872 [6, 1, 1]]) 

1873 >>> m.is_upper 

1874 False 

1875 

1876 See Also 

1877 ======== 

1878 

1879 is_lower 

1880 is_diagonal 

1881 is_upper_hessenberg 

1882 """ 

1883 return all(self[i, j].is_zero 

1884 for i in range(1, self.rows) 

1885 for j in range(min(i, self.cols))) 

1886 

1887 @property 

1888 def is_zero_matrix(self): 

1889 """Checks if a matrix is a zero matrix. 

1890 

1891 A matrix is zero if every element is zero. A matrix need not be square 

1892 to be considered zero. The empty matrix is zero by the principle of 

1893 vacuous truth. For a matrix that may or may not be zero (e.g. 

1894 contains a symbol), this will be None 

1895 

1896 Examples 

1897 ======== 

1898 

1899 >>> from sympy import Matrix, zeros 

1900 >>> from sympy.abc import x 

1901 >>> a = Matrix([[0, 0], [0, 0]]) 

1902 >>> b = zeros(3, 4) 

1903 >>> c = Matrix([[0, 1], [0, 0]]) 

1904 >>> d = Matrix([]) 

1905 >>> e = Matrix([[x, 0], [0, 0]]) 

1906 >>> a.is_zero_matrix 

1907 True 

1908 >>> b.is_zero_matrix 

1909 True 

1910 >>> c.is_zero_matrix 

1911 False 

1912 >>> d.is_zero_matrix 

1913 True 

1914 >>> e.is_zero_matrix 

1915 """ 

1916 return self._eval_is_zero_matrix() 

1917 

1918 def values(self): 

1919 """Return non-zero values of self.""" 

1920 return self._eval_values() 

1921 

1922 

1923class MatrixOperations(MatrixRequired): 

1924 """Provides basic matrix shape and elementwise 

1925 operations. Should not be instantiated directly.""" 

1926 

1927 def _eval_adjoint(self): 

1928 return self.transpose().conjugate() 

1929 

1930 def _eval_applyfunc(self, f): 

1931 out = self._new(self.rows, self.cols, [f(x) for x in self]) 

1932 return out 

1933 

1934 def _eval_as_real_imag(self): # type: ignore 

1935 return (self.applyfunc(re), self.applyfunc(im)) 

1936 

1937 def _eval_conjugate(self): 

1938 return self.applyfunc(lambda x: x.conjugate()) 

1939 

1940 def _eval_permute_cols(self, perm): 

1941 # apply the permutation to a list 

1942 mapping = list(perm) 

1943 

1944 def entry(i, j): 

1945 return self[i, mapping[j]] 

1946 

1947 return self._new(self.rows, self.cols, entry) 

1948 

1949 def _eval_permute_rows(self, perm): 

1950 # apply the permutation to a list 

1951 mapping = list(perm) 

1952 

1953 def entry(i, j): 

1954 return self[mapping[i], j] 

1955 

1956 return self._new(self.rows, self.cols, entry) 

1957 

1958 def _eval_trace(self): 

1959 return sum(self[i, i] for i in range(self.rows)) 

1960 

1961 def _eval_transpose(self): 

1962 return self._new(self.cols, self.rows, lambda i, j: self[j, i]) 

1963 

1964 def adjoint(self): 

1965 """Conjugate transpose or Hermitian conjugation.""" 

1966 return self._eval_adjoint() 

1967 

1968 def applyfunc(self, f): 

1969 """Apply a function to each element of the matrix. 

1970 

1971 Examples 

1972 ======== 

1973 

1974 >>> from sympy import Matrix 

1975 >>> m = Matrix(2, 2, lambda i, j: i*2+j) 

1976 >>> m 

1977 Matrix([ 

1978 [0, 1], 

1979 [2, 3]]) 

1980 >>> m.applyfunc(lambda i: 2*i) 

1981 Matrix([ 

1982 [0, 2], 

1983 [4, 6]]) 

1984 

1985 """ 

1986 if not callable(f): 

1987 raise TypeError("`f` must be callable.") 

1988 

1989 return self._eval_applyfunc(f) 

1990 

1991 def as_real_imag(self, deep=True, **hints): 

1992 """Returns a tuple containing the (real, imaginary) part of matrix.""" 

1993 # XXX: Ignoring deep and hints... 

1994 return self._eval_as_real_imag() 

1995 

1996 def conjugate(self): 

1997 """Return the by-element conjugation. 

1998 

1999 Examples 

2000 ======== 

2001 

2002 >>> from sympy import SparseMatrix, I 

2003 >>> a = SparseMatrix(((1, 2 + I), (3, 4), (I, -I))) 

2004 >>> a 

2005 Matrix([ 

2006 [1, 2 + I], 

2007 [3, 4], 

2008 [I, -I]]) 

2009 >>> a.C 

2010 Matrix([ 

2011 [ 1, 2 - I], 

2012 [ 3, 4], 

2013 [-I, I]]) 

2014 

2015 See Also 

2016 ======== 

2017 

2018 transpose: Matrix transposition 

2019 H: Hermite conjugation 

2020 sympy.matrices.matrices.MatrixBase.D: Dirac conjugation 

2021 """ 

2022 return self._eval_conjugate() 

2023 

2024 def doit(self, **hints): 

2025 return self.applyfunc(lambda x: x.doit(**hints)) 

2026 

2027 def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): 

2028 """Apply evalf() to each element of self.""" 

2029 options = {'subs':subs, 'maxn':maxn, 'chop':chop, 'strict':strict, 

2030 'quad':quad, 'verbose':verbose} 

2031 return self.applyfunc(lambda i: i.evalf(n, **options)) 

2032 

2033 def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, 

2034 mul=True, log=True, multinomial=True, basic=True, **hints): 

2035 """Apply core.function.expand to each entry of the matrix. 

2036 

2037 Examples 

2038 ======== 

2039 

2040 >>> from sympy.abc import x 

2041 >>> from sympy import Matrix 

2042 >>> Matrix(1, 1, [x*(x+1)]) 

2043 Matrix([[x*(x + 1)]]) 

2044 >>> _.expand() 

2045 Matrix([[x**2 + x]]) 

2046 

2047 """ 

2048 return self.applyfunc(lambda x: x.expand( 

2049 deep, modulus, power_base, power_exp, mul, log, multinomial, basic, 

2050 **hints)) 

2051 

2052 @property 

2053 def H(self): 

2054 """Return Hermite conjugate. 

2055 

2056 Examples 

2057 ======== 

2058 

2059 >>> from sympy import Matrix, I 

2060 >>> m = Matrix((0, 1 + I, 2, 3)) 

2061 >>> m 

2062 Matrix([ 

2063 [ 0], 

2064 [1 + I], 

2065 [ 2], 

2066 [ 3]]) 

2067 >>> m.H 

2068 Matrix([[0, 1 - I, 2, 3]]) 

2069 

2070 See Also 

2071 ======== 

2072 

2073 conjugate: By-element conjugation 

2074 sympy.matrices.matrices.MatrixBase.D: Dirac conjugation 

2075 """ 

2076 return self.T.C 

2077 

2078 def permute(self, perm, orientation='rows', direction='forward'): 

2079 r"""Permute the rows or columns of a matrix by the given list of 

2080 swaps. 

2081 

2082 Parameters 

2083 ========== 

2084 

2085 perm : Permutation, list, or list of lists 

2086 A representation for the permutation. 

2087 

2088 If it is ``Permutation``, it is used directly with some 

2089 resizing with respect to the matrix size. 

2090 

2091 If it is specified as list of lists, 

2092 (e.g., ``[[0, 1], [0, 2]]``), then the permutation is formed 

2093 from applying the product of cycles. The direction how the 

2094 cyclic product is applied is described in below. 

2095 

2096 If it is specified as a list, the list should represent 

2097 an array form of a permutation. (e.g., ``[1, 2, 0]``) which 

2098 would would form the swapping function 

2099 `0 \mapsto 1, 1 \mapsto 2, 2\mapsto 0`. 

2100 

2101 orientation : 'rows', 'cols' 

2102 A flag to control whether to permute the rows or the columns 

2103 

2104 direction : 'forward', 'backward' 

2105 A flag to control whether to apply the permutations from 

2106 the start of the list first, or from the back of the list 

2107 first. 

2108 

2109 For example, if the permutation specification is 

2110 ``[[0, 1], [0, 2]]``, 

2111 

2112 If the flag is set to ``'forward'``, the cycle would be 

2113 formed as `0 \mapsto 2, 2 \mapsto 1, 1 \mapsto 0`. 

2114 

2115 If the flag is set to ``'backward'``, the cycle would be 

2116 formed as `0 \mapsto 1, 1 \mapsto 2, 2 \mapsto 0`. 

2117 

2118 If the argument ``perm`` is not in a form of list of lists, 

2119 this flag takes no effect. 

2120 

2121 Examples 

2122 ======== 

2123 

2124 >>> from sympy import eye 

2125 >>> M = eye(3) 

2126 >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='forward') 

2127 Matrix([ 

2128 [0, 0, 1], 

2129 [1, 0, 0], 

2130 [0, 1, 0]]) 

2131 

2132 >>> from sympy import eye 

2133 >>> M = eye(3) 

2134 >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='backward') 

2135 Matrix([ 

2136 [0, 1, 0], 

2137 [0, 0, 1], 

2138 [1, 0, 0]]) 

2139 

2140 Notes 

2141 ===== 

2142 

2143 If a bijective function 

2144 `\sigma : \mathbb{N}_0 \rightarrow \mathbb{N}_0` denotes the 

2145 permutation. 

2146 

2147 If the matrix `A` is the matrix to permute, represented as 

2148 a horizontal or a vertical stack of vectors: 

2149 

2150 .. math:: 

2151 A = 

2152 \begin{bmatrix} 

2153 a_0 \\ a_1 \\ \vdots \\ a_{n-1} 

2154 \end{bmatrix} = 

2155 \begin{bmatrix} 

2156 \alpha_0 & \alpha_1 & \cdots & \alpha_{n-1} 

2157 \end{bmatrix} 

2158 

2159 If the matrix `B` is the result, the permutation of matrix rows 

2160 is defined as: 

2161 

2162 .. math:: 

2163 B := \begin{bmatrix} 

2164 a_{\sigma(0)} \\ a_{\sigma(1)} \\ \vdots \\ a_{\sigma(n-1)} 

2165 \end{bmatrix} 

2166 

2167 And the permutation of matrix columns is defined as: 

2168 

2169 .. math:: 

2170 B := \begin{bmatrix} 

2171 \alpha_{\sigma(0)} & \alpha_{\sigma(1)} & 

2172 \cdots & \alpha_{\sigma(n-1)} 

2173 \end{bmatrix} 

2174 """ 

2175 from sympy.combinatorics import Permutation 

2176 

2177 # allow british variants and `columns` 

2178 if direction == 'forwards': 

2179 direction = 'forward' 

2180 if direction == 'backwards': 

2181 direction = 'backward' 

2182 if orientation == 'columns': 

2183 orientation = 'cols' 

2184 

2185 if direction not in ('forward', 'backward'): 

2186 raise TypeError("direction='{}' is an invalid kwarg. " 

2187 "Try 'forward' or 'backward'".format(direction)) 

2188 if orientation not in ('rows', 'cols'): 

2189 raise TypeError("orientation='{}' is an invalid kwarg. " 

2190 "Try 'rows' or 'cols'".format(orientation)) 

2191 

2192 if not isinstance(perm, (Permutation, Iterable)): 

2193 raise ValueError( 

2194 "{} must be a list, a list of lists, " 

2195 "or a SymPy permutation object.".format(perm)) 

2196 

2197 # ensure all swaps are in range 

2198 max_index = self.rows if orientation == 'rows' else self.cols 

2199 if not all(0 <= t <= max_index for t in flatten(list(perm))): 

2200 raise IndexError("`swap` indices out of range.") 

2201 

2202 if perm and not isinstance(perm, Permutation) and \ 

2203 isinstance(perm[0], Iterable): 

2204 if direction == 'forward': 

2205 perm = list(reversed(perm)) 

2206 perm = Permutation(perm, size=max_index+1) 

2207 else: 

2208 perm = Permutation(perm, size=max_index+1) 

2209 

2210 if orientation == 'rows': 

2211 return self._eval_permute_rows(perm) 

2212 if orientation == 'cols': 

2213 return self._eval_permute_cols(perm) 

2214 

2215 def permute_cols(self, swaps, direction='forward'): 

2216 """Alias for 

2217 ``self.permute(swaps, orientation='cols', direction=direction)`` 

2218 

2219 See Also 

2220 ======== 

2221 

2222 permute 

2223 """ 

2224 return self.permute(swaps, orientation='cols', direction=direction) 

2225 

2226 def permute_rows(self, swaps, direction='forward'): 

2227 """Alias for 

2228 ``self.permute(swaps, orientation='rows', direction=direction)`` 

2229 

2230 See Also 

2231 ======== 

2232 

2233 permute 

2234 """ 

2235 return self.permute(swaps, orientation='rows', direction=direction) 

2236 

2237 def refine(self, assumptions=True): 

2238 """Apply refine to each element of the matrix. 

2239 

2240 Examples 

2241 ======== 

2242 

2243 >>> from sympy import Symbol, Matrix, Abs, sqrt, Q 

2244 >>> x = Symbol('x') 

2245 >>> Matrix([[Abs(x)**2, sqrt(x**2)],[sqrt(x**2), Abs(x)**2]]) 

2246 Matrix([ 

2247 [ Abs(x)**2, sqrt(x**2)], 

2248 [sqrt(x**2), Abs(x)**2]]) 

2249 >>> _.refine(Q.real(x)) 

2250 Matrix([ 

2251 [ x**2, Abs(x)], 

2252 [Abs(x), x**2]]) 

2253 

2254 """ 

2255 return self.applyfunc(lambda x: refine(x, assumptions)) 

2256 

2257 def replace(self, F, G, map=False, simultaneous=True, exact=None): 

2258 """Replaces Function F in Matrix entries with Function G. 

2259 

2260 Examples 

2261 ======== 

2262 

2263 >>> from sympy import symbols, Function, Matrix 

2264 >>> F, G = symbols('F, G', cls=Function) 

2265 >>> M = Matrix(2, 2, lambda i, j: F(i+j)) ; M 

2266 Matrix([ 

2267 [F(0), F(1)], 

2268 [F(1), F(2)]]) 

2269 >>> N = M.replace(F,G) 

2270 >>> N 

2271 Matrix([ 

2272 [G(0), G(1)], 

2273 [G(1), G(2)]]) 

2274 """ 

2275 return self.applyfunc( 

2276 lambda x: x.replace(F, G, map=map, simultaneous=simultaneous, exact=exact)) 

2277 

2278 def rot90(self, k=1): 

2279 """Rotates Matrix by 90 degrees 

2280 

2281 Parameters 

2282 ========== 

2283 

2284 k : int 

2285 Specifies how many times the matrix is rotated by 90 degrees 

2286 (clockwise when positive, counter-clockwise when negative). 

2287 

2288 Examples 

2289 ======== 

2290 

2291 >>> from sympy import Matrix, symbols 

2292 >>> A = Matrix(2, 2, symbols('a:d')) 

2293 >>> A 

2294 Matrix([ 

2295 [a, b], 

2296 [c, d]]) 

2297 

2298 Rotating the matrix clockwise one time: 

2299 

2300 >>> A.rot90(1) 

2301 Matrix([ 

2302 [c, a], 

2303 [d, b]]) 

2304 

2305 Rotating the matrix anticlockwise two times: 

2306 

2307 >>> A.rot90(-2) 

2308 Matrix([ 

2309 [d, c], 

2310 [b, a]]) 

2311 """ 

2312 

2313 mod = k%4 

2314 if mod == 0: 

2315 return self 

2316 if mod == 1: 

2317 return self[::-1, ::].T 

2318 if mod == 2: 

2319 return self[::-1, ::-1] 

2320 if mod == 3: 

2321 return self[::, ::-1].T 

2322 

2323 def simplify(self, **kwargs): 

2324 """Apply simplify to each element of the matrix. 

2325 

2326 Examples 

2327 ======== 

2328 

2329 >>> from sympy.abc import x, y 

2330 >>> from sympy import SparseMatrix, sin, cos 

2331 >>> SparseMatrix(1, 1, [x*sin(y)**2 + x*cos(y)**2]) 

2332 Matrix([[x*sin(y)**2 + x*cos(y)**2]]) 

2333 >>> _.simplify() 

2334 Matrix([[x]]) 

2335 """ 

2336 return self.applyfunc(lambda x: x.simplify(**kwargs)) 

2337 

2338 def subs(self, *args, **kwargs): # should mirror core.basic.subs 

2339 """Return a new matrix with subs applied to each entry. 

2340 

2341 Examples 

2342 ======== 

2343 

2344 >>> from sympy.abc import x, y 

2345 >>> from sympy import SparseMatrix, Matrix 

2346 >>> SparseMatrix(1, 1, [x]) 

2347 Matrix([[x]]) 

2348 >>> _.subs(x, y) 

2349 Matrix([[y]]) 

2350 >>> Matrix(_).subs(y, x) 

2351 Matrix([[x]]) 

2352 """ 

2353 

2354 if len(args) == 1 and not isinstance(args[0], (dict, set)) and iter(args[0]) and not is_sequence(args[0]): 

2355 args = (list(args[0]),) 

2356 

2357 return self.applyfunc(lambda x: x.subs(*args, **kwargs)) 

2358 

2359 def trace(self): 

2360 """ 

2361 Returns the trace of a square matrix i.e. the sum of the 

2362 diagonal elements. 

2363 

2364 Examples 

2365 ======== 

2366 

2367 >>> from sympy import Matrix 

2368 >>> A = Matrix(2, 2, [1, 2, 3, 4]) 

2369 >>> A.trace() 

2370 5 

2371 

2372 """ 

2373 if self.rows != self.cols: 

2374 raise NonSquareMatrixError() 

2375 return self._eval_trace() 

2376 

2377 def transpose(self): 

2378 """ 

2379 Returns the transpose of the matrix. 

2380 

2381 Examples 

2382 ======== 

2383 

2384 >>> from sympy import Matrix 

2385 >>> A = Matrix(2, 2, [1, 2, 3, 4]) 

2386 >>> A.transpose() 

2387 Matrix([ 

2388 [1, 3], 

2389 [2, 4]]) 

2390 

2391 >>> from sympy import Matrix, I 

2392 >>> m=Matrix(((1, 2+I), (3, 4))) 

2393 >>> m 

2394 Matrix([ 

2395 [1, 2 + I], 

2396 [3, 4]]) 

2397 >>> m.transpose() 

2398 Matrix([ 

2399 [ 1, 3], 

2400 [2 + I, 4]]) 

2401 >>> m.T == m.transpose() 

2402 True 

2403 

2404 See Also 

2405 ======== 

2406 

2407 conjugate: By-element conjugation 

2408 

2409 """ 

2410 return self._eval_transpose() 

2411 

2412 @property 

2413 def T(self): 

2414 '''Matrix transposition''' 

2415 return self.transpose() 

2416 

2417 @property 

2418 def C(self): 

2419 '''By-element conjugation''' 

2420 return self.conjugate() 

2421 

2422 def n(self, *args, **kwargs): 

2423 """Apply evalf() to each element of self.""" 

2424 return self.evalf(*args, **kwargs) 

2425 

2426 def xreplace(self, rule): # should mirror core.basic.xreplace 

2427 """Return a new matrix with xreplace applied to each entry. 

2428 

2429 Examples 

2430 ======== 

2431 

2432 >>> from sympy.abc import x, y 

2433 >>> from sympy import SparseMatrix, Matrix 

2434 >>> SparseMatrix(1, 1, [x]) 

2435 Matrix([[x]]) 

2436 >>> _.xreplace({x: y}) 

2437 Matrix([[y]]) 

2438 >>> Matrix(_).xreplace({y: x}) 

2439 Matrix([[x]]) 

2440 """ 

2441 return self.applyfunc(lambda x: x.xreplace(rule)) 

2442 

2443 def _eval_simplify(self, **kwargs): 

2444 # XXX: We can't use self.simplify here as mutable subclasses will 

2445 # override simplify and have it return None 

2446 return MatrixOperations.simplify(self, **kwargs) 

2447 

2448 def _eval_trigsimp(self, **opts): 

2449 from sympy.simplify.trigsimp import trigsimp 

2450 return self.applyfunc(lambda x: trigsimp(x, **opts)) 

2451 

2452 def upper_triangular(self, k=0): 

2453 """Return the elements on and above the kth diagonal of a matrix. 

2454 If k is not specified then simply returns upper-triangular portion 

2455 of a matrix 

2456 

2457 Examples 

2458 ======== 

2459 

2460 >>> from sympy import ones 

2461 >>> A = ones(4) 

2462 >>> A.upper_triangular() 

2463 Matrix([ 

2464 [1, 1, 1, 1], 

2465 [0, 1, 1, 1], 

2466 [0, 0, 1, 1], 

2467 [0, 0, 0, 1]]) 

2468 

2469 >>> A.upper_triangular(2) 

2470 Matrix([ 

2471 [0, 0, 1, 1], 

2472 [0, 0, 0, 1], 

2473 [0, 0, 0, 0], 

2474 [0, 0, 0, 0]]) 

2475 

2476 >>> A.upper_triangular(-1) 

2477 Matrix([ 

2478 [1, 1, 1, 1], 

2479 [1, 1, 1, 1], 

2480 [0, 1, 1, 1], 

2481 [0, 0, 1, 1]]) 

2482 

2483 """ 

2484 

2485 def entry(i, j): 

2486 return self[i, j] if i + k <= j else self.zero 

2487 

2488 return self._new(self.rows, self.cols, entry) 

2489 

2490 

2491 def lower_triangular(self, k=0): 

2492 """Return the elements on and below the kth diagonal of a matrix. 

2493 If k is not specified then simply returns lower-triangular portion 

2494 of a matrix 

2495 

2496 Examples 

2497 ======== 

2498 

2499 >>> from sympy import ones 

2500 >>> A = ones(4) 

2501 >>> A.lower_triangular() 

2502 Matrix([ 

2503 [1, 0, 0, 0], 

2504 [1, 1, 0, 0], 

2505 [1, 1, 1, 0], 

2506 [1, 1, 1, 1]]) 

2507 

2508 >>> A.lower_triangular(-2) 

2509 Matrix([ 

2510 [0, 0, 0, 0], 

2511 [0, 0, 0, 0], 

2512 [1, 0, 0, 0], 

2513 [1, 1, 0, 0]]) 

2514 

2515 >>> A.lower_triangular(1) 

2516 Matrix([ 

2517 [1, 1, 0, 0], 

2518 [1, 1, 1, 0], 

2519 [1, 1, 1, 1], 

2520 [1, 1, 1, 1]]) 

2521 

2522 """ 

2523 

2524 def entry(i, j): 

2525 return self[i, j] if i + k >= j else self.zero 

2526 

2527 return self._new(self.rows, self.cols, entry) 

2528 

2529 

2530 

2531class MatrixArithmetic(MatrixRequired): 

2532 """Provides basic matrix arithmetic operations. 

2533 Should not be instantiated directly.""" 

2534 

2535 _op_priority = 10.01 

2536 

2537 def _eval_Abs(self): 

2538 return self._new(self.rows, self.cols, lambda i, j: Abs(self[i, j])) 

2539 

2540 def _eval_add(self, other): 

2541 return self._new(self.rows, self.cols, 

2542 lambda i, j: self[i, j] + other[i, j]) 

2543 

2544 def _eval_matrix_mul(self, other): 

2545 def entry(i, j): 

2546 vec = [self[i,k]*other[k,j] for k in range(self.cols)] 

2547 try: 

2548 return Add(*vec) 

2549 except (TypeError, SympifyError): 

2550 # Some matrices don't work with `sum` or `Add` 

2551 # They don't work with `sum` because `sum` tries to add `0` 

2552 # Fall back to a safe way to multiply if the `Add` fails. 

2553 return reduce(lambda a, b: a + b, vec) 

2554 

2555 return self._new(self.rows, other.cols, entry) 

2556 

2557 def _eval_matrix_mul_elementwise(self, other): 

2558 return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other[i,j]) 

2559 

2560 def _eval_matrix_rmul(self, other): 

2561 def entry(i, j): 

2562 return sum(other[i,k]*self[k,j] for k in range(other.cols)) 

2563 return self._new(other.rows, self.cols, entry) 

2564 

2565 def _eval_pow_by_recursion(self, num): 

2566 if num == 1: 

2567 return self 

2568 

2569 if num % 2 == 1: 

2570 a, b = self, self._eval_pow_by_recursion(num - 1) 

2571 else: 

2572 a = b = self._eval_pow_by_recursion(num // 2) 

2573 

2574 return a.multiply(b) 

2575 

2576 def _eval_pow_by_cayley(self, exp): 

2577 from sympy.discrete.recurrences import linrec_coeffs 

2578 row = self.shape[0] 

2579 p = self.charpoly() 

2580 

2581 coeffs = (-p).all_coeffs()[1:] 

2582 coeffs = linrec_coeffs(coeffs, exp) 

2583 new_mat = self.eye(row) 

2584 ans = self.zeros(row) 

2585 

2586 for i in range(row): 

2587 ans += coeffs[i]*new_mat 

2588 new_mat *= self 

2589 

2590 return ans 

2591 

2592 def _eval_pow_by_recursion_dotprodsimp(self, num, prevsimp=None): 

2593 if prevsimp is None: 

2594 prevsimp = [True]*len(self) 

2595 

2596 if num == 1: 

2597 return self 

2598 

2599 if num % 2 == 1: 

2600 a, b = self, self._eval_pow_by_recursion_dotprodsimp(num - 1, 

2601 prevsimp=prevsimp) 

2602 else: 

2603 a = b = self._eval_pow_by_recursion_dotprodsimp(num // 2, 

2604 prevsimp=prevsimp) 

2605 

2606 m = a.multiply(b, dotprodsimp=False) 

2607 lenm = len(m) 

2608 elems = [None]*lenm 

2609 

2610 for i in range(lenm): 

2611 if prevsimp[i]: 

2612 elems[i], prevsimp[i] = _dotprodsimp(m[i], withsimp=True) 

2613 else: 

2614 elems[i] = m[i] 

2615 

2616 return m._new(m.rows, m.cols, elems) 

2617 

2618 def _eval_scalar_mul(self, other): 

2619 return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other) 

2620 

2621 def _eval_scalar_rmul(self, other): 

2622 return self._new(self.rows, self.cols, lambda i, j: other*self[i,j]) 

2623 

2624 def _eval_Mod(self, other): 

2625 return self._new(self.rows, self.cols, lambda i, j: Mod(self[i, j], other)) 

2626 

2627 # Python arithmetic functions 

2628 def __abs__(self): 

2629 """Returns a new matrix with entry-wise absolute values.""" 

2630 return self._eval_Abs() 

2631 

2632 @call_highest_priority('__radd__') 

2633 def __add__(self, other): 

2634 """Return self + other, raising ShapeError if shapes do not match.""" 

2635 if isinstance(other, NDimArray): # Matrix and array addition is currently not implemented 

2636 return NotImplemented 

2637 other = _matrixify(other) 

2638 # matrix-like objects can have shapes. This is 

2639 # our first sanity check. 

2640 if hasattr(other, 'shape'): 

2641 if self.shape != other.shape: 

2642 raise ShapeError("Matrix size mismatch: %s + %s" % ( 

2643 self.shape, other.shape)) 

2644 

2645 # honest SymPy matrices defer to their class's routine 

2646 if getattr(other, 'is_Matrix', False): 

2647 # call the highest-priority class's _eval_add 

2648 a, b = self, other 

2649 if a.__class__ != classof(a, b): 

2650 b, a = a, b 

2651 return a._eval_add(b) 

2652 # Matrix-like objects can be passed to CommonMatrix routines directly. 

2653 if getattr(other, 'is_MatrixLike', False): 

2654 return MatrixArithmetic._eval_add(self, other) 

2655 

2656 raise TypeError('cannot add %s and %s' % (type(self), type(other))) 

2657 

2658 @call_highest_priority('__rtruediv__') 

2659 def __truediv__(self, other): 

2660 return self * (self.one / other) 

2661 

2662 @call_highest_priority('__rmatmul__') 

2663 def __matmul__(self, other): 

2664 other = _matrixify(other) 

2665 if not getattr(other, 'is_Matrix', False) and not getattr(other, 'is_MatrixLike', False): 

2666 return NotImplemented 

2667 

2668 return self.__mul__(other) 

2669 

2670 def __mod__(self, other): 

2671 return self.applyfunc(lambda x: x % other) 

2672 

2673 @call_highest_priority('__rmul__') 

2674 def __mul__(self, other): 

2675 """Return self*other where other is either a scalar or a matrix 

2676 of compatible dimensions. 

2677 

2678 Examples 

2679 ======== 

2680 

2681 >>> from sympy import Matrix 

2682 >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) 

2683 >>> 2*A == A*2 == Matrix([[2, 4, 6], [8, 10, 12]]) 

2684 True 

2685 >>> B = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 

2686 >>> A*B 

2687 Matrix([ 

2688 [30, 36, 42], 

2689 [66, 81, 96]]) 

2690 >>> B*A 

2691 Traceback (most recent call last): 

2692 ... 

2693 ShapeError: Matrices size mismatch. 

2694 >>> 

2695 

2696 See Also 

2697 ======== 

2698 

2699 matrix_multiply_elementwise 

2700 """ 

2701 

2702 return self.multiply(other) 

2703 

2704 def multiply(self, other, dotprodsimp=None): 

2705 """Same as __mul__() but with optional simplification. 

2706 

2707 Parameters 

2708 ========== 

2709 

2710 dotprodsimp : bool, optional 

2711 Specifies whether intermediate term algebraic simplification is used 

2712 during matrix multiplications to control expression blowup and thus 

2713 speed up calculation. Default is off. 

2714 """ 

2715 

2716 isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) 

2717 other = _matrixify(other) 

2718 # matrix-like objects can have shapes. This is 

2719 # our first sanity check. Double check other is not explicitly not a Matrix. 

2720 if (hasattr(other, 'shape') and len(other.shape) == 2 and 

2721 (getattr(other, 'is_Matrix', True) or 

2722 getattr(other, 'is_MatrixLike', True))): 

2723 if self.shape[1] != other.shape[0]: 

2724 raise ShapeError("Matrix size mismatch: %s * %s." % ( 

2725 self.shape, other.shape)) 

2726 

2727 # honest SymPy matrices defer to their class's routine 

2728 if getattr(other, 'is_Matrix', False): 

2729 m = self._eval_matrix_mul(other) 

2730 if isimpbool: 

2731 return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) 

2732 return m 

2733 

2734 # Matrix-like objects can be passed to CommonMatrix routines directly. 

2735 if getattr(other, 'is_MatrixLike', False): 

2736 return MatrixArithmetic._eval_matrix_mul(self, other) 

2737 

2738 # if 'other' is not iterable then scalar multiplication. 

2739 if not isinstance(other, Iterable): 

2740 try: 

2741 return self._eval_scalar_mul(other) 

2742 except TypeError: 

2743 pass 

2744 

2745 return NotImplemented 

2746 

2747 def multiply_elementwise(self, other): 

2748 """Return the Hadamard product (elementwise product) of A and B 

2749 

2750 Examples 

2751 ======== 

2752 

2753 >>> from sympy import Matrix 

2754 >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) 

2755 >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) 

2756 >>> A.multiply_elementwise(B) 

2757 Matrix([ 

2758 [ 0, 10, 200], 

2759 [300, 40, 5]]) 

2760 

2761 See Also 

2762 ======== 

2763 

2764 sympy.matrices.matrices.MatrixBase.cross 

2765 sympy.matrices.matrices.MatrixBase.dot 

2766 multiply 

2767 """ 

2768 if self.shape != other.shape: 

2769 raise ShapeError("Matrix shapes must agree {} != {}".format(self.shape, other.shape)) 

2770 

2771 return self._eval_matrix_mul_elementwise(other) 

2772 

2773 def __neg__(self): 

2774 return self._eval_scalar_mul(-1) 

2775 

2776 @call_highest_priority('__rpow__') 

2777 def __pow__(self, exp): 

2778 """Return self**exp a scalar or symbol.""" 

2779 

2780 return self.pow(exp) 

2781 

2782 

2783 def pow(self, exp, method=None): 

2784 r"""Return self**exp a scalar or symbol. 

2785 

2786 Parameters 

2787 ========== 

2788 

2789 method : multiply, mulsimp, jordan, cayley 

2790 If multiply then it returns exponentiation using recursion. 

2791 If jordan then Jordan form exponentiation will be used. 

2792 If cayley then the exponentiation is done using Cayley-Hamilton 

2793 theorem. 

2794 If mulsimp then the exponentiation is done using recursion 

2795 with dotprodsimp. This specifies whether intermediate term 

2796 algebraic simplification is used during naive matrix power to 

2797 control expression blowup and thus speed up calculation. 

2798 If None, then it heuristically decides which method to use. 

2799 

2800 """ 

2801 

2802 if method is not None and method not in ['multiply', 'mulsimp', 'jordan', 'cayley']: 

2803 raise TypeError('No such method') 

2804 if self.rows != self.cols: 

2805 raise NonSquareMatrixError() 

2806 a = self 

2807 jordan_pow = getattr(a, '_matrix_pow_by_jordan_blocks', None) 

2808 exp = sympify(exp) 

2809 

2810 if exp.is_zero: 

2811 return a._new(a.rows, a.cols, lambda i, j: int(i == j)) 

2812 if exp == 1: 

2813 return a 

2814 

2815 diagonal = getattr(a, 'is_diagonal', None) 

2816 if diagonal is not None and diagonal(): 

2817 return a._new(a.rows, a.cols, lambda i, j: a[i,j]**exp if i == j else 0) 

2818 

2819 if exp.is_Number and exp % 1 == 0: 

2820 if a.rows == 1: 

2821 return a._new([[a[0]**exp]]) 

2822 if exp < 0: 

2823 exp = -exp 

2824 a = a.inv() 

2825 # When certain conditions are met, 

2826 # Jordan block algorithm is faster than 

2827 # computation by recursion. 

2828 if method == 'jordan': 

2829 try: 

2830 return jordan_pow(exp) 

2831 except MatrixError: 

2832 if method == 'jordan': 

2833 raise 

2834 

2835 elif method == 'cayley': 

2836 if not exp.is_Number or exp % 1 != 0: 

2837 raise ValueError("cayley method is only valid for integer powers") 

2838 return a._eval_pow_by_cayley(exp) 

2839 

2840 elif method == "mulsimp": 

2841 if not exp.is_Number or exp % 1 != 0: 

2842 raise ValueError("mulsimp method is only valid for integer powers") 

2843 return a._eval_pow_by_recursion_dotprodsimp(exp) 

2844 

2845 elif method == "multiply": 

2846 if not exp.is_Number or exp % 1 != 0: 

2847 raise ValueError("multiply method is only valid for integer powers") 

2848 return a._eval_pow_by_recursion(exp) 

2849 

2850 elif method is None and exp.is_Number and exp % 1 == 0: 

2851 # Decide heuristically which method to apply 

2852 if a.rows == 2 and exp > 100000: 

2853 return jordan_pow(exp) 

2854 elif _get_intermediate_simp_bool(True, None): 

2855 return a._eval_pow_by_recursion_dotprodsimp(exp) 

2856 elif exp > 10000: 

2857 return a._eval_pow_by_cayley(exp) 

2858 else: 

2859 return a._eval_pow_by_recursion(exp) 

2860 

2861 if jordan_pow: 

2862 try: 

2863 return jordan_pow(exp) 

2864 except NonInvertibleMatrixError: 

2865 # Raised by jordan_pow on zero determinant matrix unless exp is 

2866 # definitely known to be a non-negative integer. 

2867 # Here we raise if n is definitely not a non-negative integer 

2868 # but otherwise we can leave this as an unevaluated MatPow. 

2869 if exp.is_integer is False or exp.is_nonnegative is False: 

2870 raise 

2871 

2872 from sympy.matrices.expressions import MatPow 

2873 return MatPow(a, exp) 

2874 

2875 @call_highest_priority('__add__') 

2876 def __radd__(self, other): 

2877 return self + other 

2878 

2879 @call_highest_priority('__matmul__') 

2880 def __rmatmul__(self, other): 

2881 other = _matrixify(other) 

2882 if not getattr(other, 'is_Matrix', False) and not getattr(other, 'is_MatrixLike', False): 

2883 return NotImplemented 

2884 

2885 return self.__rmul__(other) 

2886 

2887 @call_highest_priority('__mul__') 

2888 def __rmul__(self, other): 

2889 return self.rmultiply(other) 

2890 

2891 def rmultiply(self, other, dotprodsimp=None): 

2892 """Same as __rmul__() but with optional simplification. 

2893 

2894 Parameters 

2895 ========== 

2896 

2897 dotprodsimp : bool, optional 

2898 Specifies whether intermediate term algebraic simplification is used 

2899 during matrix multiplications to control expression blowup and thus 

2900 speed up calculation. Default is off. 

2901 """ 

2902 isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) 

2903 other = _matrixify(other) 

2904 # matrix-like objects can have shapes. This is 

2905 # our first sanity check. Double check other is not explicitly not a Matrix. 

2906 if (hasattr(other, 'shape') and len(other.shape) == 2 and 

2907 (getattr(other, 'is_Matrix', True) or 

2908 getattr(other, 'is_MatrixLike', True))): 

2909 if self.shape[0] != other.shape[1]: 

2910 raise ShapeError("Matrix size mismatch.") 

2911 

2912 # honest SymPy matrices defer to their class's routine 

2913 if getattr(other, 'is_Matrix', False): 

2914 m = self._eval_matrix_rmul(other) 

2915 if isimpbool: 

2916 return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) 

2917 return m 

2918 # Matrix-like objects can be passed to CommonMatrix routines directly. 

2919 if getattr(other, 'is_MatrixLike', False): 

2920 return MatrixArithmetic._eval_matrix_rmul(self, other) 

2921 

2922 # if 'other' is not iterable then scalar multiplication. 

2923 if not isinstance(other, Iterable): 

2924 try: 

2925 return self._eval_scalar_rmul(other) 

2926 except TypeError: 

2927 pass 

2928 

2929 return NotImplemented 

2930 

2931 @call_highest_priority('__sub__') 

2932 def __rsub__(self, a): 

2933 return (-self) + a 

2934 

2935 @call_highest_priority('__rsub__') 

2936 def __sub__(self, a): 

2937 return self + (-a) 

2938 

2939class MatrixCommon(MatrixArithmetic, MatrixOperations, MatrixProperties, 

2940 MatrixSpecial, MatrixShaping): 

2941 """All common matrix operations including basic arithmetic, shaping, 

2942 and special matrices like `zeros`, and `eye`.""" 

2943 _diff_wrt = True # type: bool 

2944 

2945 

2946class _MinimalMatrix: 

2947 """Class providing the minimum functionality 

2948 for a matrix-like object and implementing every method 

2949 required for a `MatrixRequired`. This class does not have everything 

2950 needed to become a full-fledged SymPy object, but it will satisfy the 

2951 requirements of anything inheriting from `MatrixRequired`. If you wish 

2952 to make a specialized matrix type, make sure to implement these 

2953 methods and properties with the exception of `__init__` and `__repr__` 

2954 which are included for convenience.""" 

2955 

2956 is_MatrixLike = True 

2957 _sympify = staticmethod(sympify) 

2958 _class_priority = 3 

2959 zero = S.Zero 

2960 one = S.One 

2961 

2962 is_Matrix = True 

2963 is_MatrixExpr = False 

2964 

2965 @classmethod 

2966 def _new(cls, *args, **kwargs): 

2967 return cls(*args, **kwargs) 

2968 

2969 def __init__(self, rows, cols=None, mat=None, copy=False): 

2970 if isfunction(mat): 

2971 # if we passed in a function, use that to populate the indices 

2972 mat = [mat(i, j) for i in range(rows) for j in range(cols)] 

2973 if cols is None and mat is None: 

2974 mat = rows 

2975 rows, cols = getattr(mat, 'shape', (rows, cols)) 

2976 try: 

2977 # if we passed in a list of lists, flatten it and set the size 

2978 if cols is None and mat is None: 

2979 mat = rows 

2980 cols = len(mat[0]) 

2981 rows = len(mat) 

2982 mat = [x for l in mat for x in l] 

2983 except (IndexError, TypeError): 

2984 pass 

2985 self.mat = tuple(self._sympify(x) for x in mat) 

2986 self.rows, self.cols = rows, cols 

2987 if self.rows is None or self.cols is None: 

2988 raise NotImplementedError("Cannot initialize matrix with given parameters") 

2989 

2990 def __getitem__(self, key): 

2991 def _normalize_slices(row_slice, col_slice): 

2992 """Ensure that row_slice and col_slice do not have 

2993 `None` in their arguments. Any integers are converted 

2994 to slices of length 1""" 

2995 if not isinstance(row_slice, slice): 

2996 row_slice = slice(row_slice, row_slice + 1, None) 

2997 row_slice = slice(*row_slice.indices(self.rows)) 

2998 

2999 if not isinstance(col_slice, slice): 

3000 col_slice = slice(col_slice, col_slice + 1, None) 

3001 col_slice = slice(*col_slice.indices(self.cols)) 

3002 

3003 return (row_slice, col_slice) 

3004 

3005 def _coord_to_index(i, j): 

3006 """Return the index in _mat corresponding 

3007 to the (i,j) position in the matrix. """ 

3008 return i * self.cols + j 

3009 

3010 if isinstance(key, tuple): 

3011 i, j = key 

3012 if isinstance(i, slice) or isinstance(j, slice): 

3013 # if the coordinates are not slices, make them so 

3014 # and expand the slices so they don't contain `None` 

3015 i, j = _normalize_slices(i, j) 

3016 

3017 rowsList, colsList = list(range(self.rows))[i], \ 

3018 list(range(self.cols))[j] 

3019 indices = (i * self.cols + j for i in rowsList for j in 

3020 colsList) 

3021 return self._new(len(rowsList), len(colsList), 

3022 [self.mat[i] for i in indices]) 

3023 

3024 # if the key is a tuple of ints, change 

3025 # it to an array index 

3026 key = _coord_to_index(i, j) 

3027 return self.mat[key] 

3028 

3029 def __eq__(self, other): 

3030 try: 

3031 classof(self, other) 

3032 except TypeError: 

3033 return False 

3034 return ( 

3035 self.shape == other.shape and list(self) == list(other)) 

3036 

3037 def __len__(self): 

3038 return self.rows*self.cols 

3039 

3040 def __repr__(self): 

3041 return "_MinimalMatrix({}, {}, {})".format(self.rows, self.cols, 

3042 self.mat) 

3043 

3044 @property 

3045 def shape(self): 

3046 return (self.rows, self.cols) 

3047 

3048 

3049class _CastableMatrix: # this is needed here ONLY FOR TESTS. 

3050 def as_mutable(self): 

3051 return self 

3052 

3053 def as_immutable(self): 

3054 return self 

3055 

3056 

3057class _MatrixWrapper: 

3058 """Wrapper class providing the minimum functionality for a matrix-like 

3059 object: .rows, .cols, .shape, indexability, and iterability. CommonMatrix 

3060 math operations should work on matrix-like objects. This one is intended for 

3061 matrix-like objects which use the same indexing format as SymPy with respect 

3062 to returning matrix elements instead of rows for non-tuple indexes. 

3063 """ 

3064 

3065 is_Matrix = False # needs to be here because of __getattr__ 

3066 is_MatrixLike = True 

3067 

3068 def __init__(self, mat, shape): 

3069 self.mat = mat 

3070 self.shape = shape 

3071 self.rows, self.cols = shape 

3072 

3073 def __getitem__(self, key): 

3074 if isinstance(key, tuple): 

3075 return sympify(self.mat.__getitem__(key)) 

3076 

3077 return sympify(self.mat.__getitem__((key // self.rows, key % self.cols))) 

3078 

3079 def __iter__(self): # supports numpy.matrix and numpy.array 

3080 mat = self.mat 

3081 cols = self.cols 

3082 

3083 return iter(sympify(mat[r, c]) for r in range(self.rows) for c in range(cols)) 

3084 

3085 

3086class MatrixKind(Kind): 

3087 """ 

3088 Kind for all matrices in SymPy. 

3089 

3090 Basic class for this kind is ``MatrixBase`` and ``MatrixExpr``, 

3091 but any expression representing the matrix can have this. 

3092 

3093 Parameters 

3094 ========== 

3095 

3096 element_kind : Kind 

3097 Kind of the element. Default is 

3098 :class:`sympy.core.kind.NumberKind`, 

3099 which means that the matrix contains only numbers. 

3100 

3101 Examples 

3102 ======== 

3103 

3104 Any instance of matrix class has ``MatrixKind``: 

3105 

3106 >>> from sympy import MatrixSymbol 

3107 >>> A = MatrixSymbol('A', 2,2) 

3108 >>> A.kind 

3109 MatrixKind(NumberKind) 

3110 

3111 Although expression representing a matrix may be not instance of 

3112 matrix class, it will have ``MatrixKind`` as well: 

3113 

3114 >>> from sympy import MatrixExpr, Integral 

3115 >>> from sympy.abc import x 

3116 >>> intM = Integral(A, x) 

3117 >>> isinstance(intM, MatrixExpr) 

3118 False 

3119 >>> intM.kind 

3120 MatrixKind(NumberKind) 

3121 

3122 Use ``isinstance()`` to check for ``MatrixKind`` without specifying 

3123 the element kind. Use ``is`` with specifying the element kind: 

3124 

3125 >>> from sympy import Matrix 

3126 >>> from sympy.core import NumberKind 

3127 >>> from sympy.matrices import MatrixKind 

3128 >>> M = Matrix([1, 2]) 

3129 >>> isinstance(M.kind, MatrixKind) 

3130 True 

3131 >>> M.kind is MatrixKind(NumberKind) 

3132 True 

3133 

3134 See Also 

3135 ======== 

3136 

3137 sympy.core.kind.NumberKind 

3138 sympy.core.kind.UndefinedKind 

3139 sympy.core.containers.TupleKind 

3140 sympy.sets.sets.SetKind 

3141 

3142 """ 

3143 def __new__(cls, element_kind=NumberKind): 

3144 obj = super().__new__(cls, element_kind) 

3145 obj.element_kind = element_kind 

3146 return obj 

3147 

3148 def __repr__(self): 

3149 return "MatrixKind(%s)" % self.element_kind 

3150 

3151 

3152def _matrixify(mat): 

3153 """If `mat` is a Matrix or is matrix-like, 

3154 return a Matrix or MatrixWrapper object. Otherwise 

3155 `mat` is passed through without modification.""" 

3156 

3157 if getattr(mat, 'is_Matrix', False) or getattr(mat, 'is_MatrixLike', False): 

3158 return mat 

3159 

3160 if not(getattr(mat, 'is_Matrix', True) or getattr(mat, 'is_MatrixLike', True)): 

3161 return mat 

3162 

3163 shape = None 

3164 

3165 if hasattr(mat, 'shape'): # numpy, scipy.sparse 

3166 if len(mat.shape) == 2: 

3167 shape = mat.shape 

3168 elif hasattr(mat, 'rows') and hasattr(mat, 'cols'): # mpmath 

3169 shape = (mat.rows, mat.cols) 

3170 

3171 if shape: 

3172 return _MatrixWrapper(mat, shape) 

3173 

3174 return mat 

3175 

3176 

3177def a2idx(j, n=None): 

3178 """Return integer after making positive and validating against n.""" 

3179 if not isinstance(j, int): 

3180 jindex = getattr(j, '__index__', None) 

3181 if jindex is not None: 

3182 j = jindex() 

3183 else: 

3184 raise IndexError("Invalid index a[%r]" % (j,)) 

3185 if n is not None: 

3186 if j < 0: 

3187 j += n 

3188 if not (j >= 0 and j < n): 

3189 raise IndexError("Index out of range: a[%s]" % (j,)) 

3190 return int(j) 

3191 

3192 

3193def classof(A, B): 

3194 """ 

3195 Get the type of the result when combining matrices of different types. 

3196 

3197 Currently the strategy is that immutability is contagious. 

3198 

3199 Examples 

3200 ======== 

3201 

3202 >>> from sympy import Matrix, ImmutableMatrix 

3203 >>> from sympy.matrices.common import classof 

3204 >>> M = Matrix([[1, 2], [3, 4]]) # a Mutable Matrix 

3205 >>> IM = ImmutableMatrix([[1, 2], [3, 4]]) 

3206 >>> classof(M, IM) 

3207 <class 'sympy.matrices.immutable.ImmutableDenseMatrix'> 

3208 """ 

3209 priority_A = getattr(A, '_class_priority', None) 

3210 priority_B = getattr(B, '_class_priority', None) 

3211 if None not in (priority_A, priority_B): 

3212 if A._class_priority > B._class_priority: 

3213 return A.__class__ 

3214 else: 

3215 return B.__class__ 

3216 

3217 try: 

3218 import numpy 

3219 except ImportError: 

3220 pass 

3221 else: 

3222 if isinstance(A, numpy.ndarray): 

3223 return B.__class__ 

3224 if isinstance(B, numpy.ndarray): 

3225 return A.__class__ 

3226 

3227 raise TypeError("Incompatible classes %s, %s" % (A.__class__, B.__class__))