repmatrix.py 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  1. from collections import defaultdict
  2. from operator import index as index_
  3. from sympy.core.expr import Expr
  4. from sympy.core.kind import Kind, NumberKind, UndefinedKind
  5. from sympy.core.numbers import Integer, Rational
  6. from sympy.core.sympify import _sympify, SympifyError
  7. from sympy.core.singleton import S
  8. from sympy.polys.domains import ZZ, QQ, GF, EXRAW
  9. from sympy.polys.matrices import DomainMatrix
  10. from sympy.polys.matrices.exceptions import DMNonInvertibleMatrixError
  11. from sympy.polys.polyerrors import CoercionFailed, NotInvertible
  12. from sympy.utilities.exceptions import sympy_deprecation_warning
  13. from sympy.utilities.iterables import is_sequence
  14. from sympy.utilities.misc import filldedent, as_int
  15. from .exceptions import ShapeError, NonSquareMatrixError, NonInvertibleMatrixError
  16. from .matrixbase import classof, MatrixBase
  17. from .kind import MatrixKind
  18. class RepMatrix(MatrixBase):
  19. """Matrix implementation based on DomainMatrix as an internal representation.
  20. The RepMatrix class is a superclass for Matrix, ImmutableMatrix,
  21. SparseMatrix and ImmutableSparseMatrix which are the main usable matrix
  22. classes in SymPy. Most methods on this class are simply forwarded to
  23. DomainMatrix.
  24. """
  25. #
  26. # MatrixBase is the common superclass for all of the usable explicit matrix
  27. # classes in SymPy. The idea is that MatrixBase is an abstract class though
  28. # and that subclasses will implement the lower-level methods.
  29. #
  30. # RepMatrix is a subclass of MatrixBase that uses DomainMatrix as an
  31. # internal representation and delegates lower-level methods to
  32. # DomainMatrix. All of SymPy's standard explicit matrix classes subclass
  33. # RepMatrix and so use DomainMatrix internally.
  34. #
  35. # A RepMatrix uses an internal DomainMatrix with the domain set to ZZ, QQ
  36. # or EXRAW. The EXRAW domain is equivalent to the previous implementation
  37. # of Matrix that used Expr for the elements. The ZZ and QQ domains are used
  38. # when applicable just because they are compatible with the previous
  39. # implementation but are much more efficient. Other domains such as QQ[x]
  40. # are not used because they differ from Expr in some way (e.g. automatic
  41. # expansion of powers and products).
  42. #
  43. _rep: DomainMatrix
  44. def __eq__(self, other):
  45. # Skip sympify for mutable matrices...
  46. if not isinstance(other, RepMatrix):
  47. try:
  48. other = _sympify(other)
  49. except SympifyError:
  50. return NotImplemented
  51. if not isinstance(other, RepMatrix):
  52. return NotImplemented
  53. return self._rep.unify_eq(other._rep)
  54. def to_DM(self, domain=None, **kwargs):
  55. """Convert to a :class:`~.DomainMatrix`.
  56. Examples
  57. ========
  58. >>> from sympy import Matrix
  59. >>> M = Matrix([[1, 2], [3, 4]])
  60. >>> M.to_DM()
  61. DomainMatrix({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ)
  62. The :meth:`DomainMatrix.to_Matrix` method can be used to convert back:
  63. >>> M.to_DM().to_Matrix() == M
  64. True
  65. The domain can be given explicitly or otherwise it will be chosen by
  66. :func:`construct_domain`. Any keyword arguments (besides ``domain``)
  67. are passed to :func:`construct_domain`:
  68. >>> from sympy import QQ, symbols
  69. >>> x = symbols('x')
  70. >>> M = Matrix([[x, 1], [1, x]])
  71. >>> M
  72. Matrix([
  73. [x, 1],
  74. [1, x]])
  75. >>> M.to_DM().domain
  76. ZZ[x]
  77. >>> M.to_DM(field=True).domain
  78. ZZ(x)
  79. >>> M.to_DM(domain=QQ[x]).domain
  80. QQ[x]
  81. See Also
  82. ========
  83. DomainMatrix
  84. DomainMatrix.to_Matrix
  85. DomainMatrix.convert_to
  86. DomainMatrix.choose_domain
  87. construct_domain
  88. """
  89. if domain is not None:
  90. if kwargs:
  91. raise TypeError("Options cannot be used with domain parameter")
  92. return self._rep.convert_to(domain)
  93. rep = self._rep
  94. dom = rep.domain
  95. # If the internal DomainMatrix is already ZZ or QQ then we can maybe
  96. # bypass calling construct_domain or performing any conversions. Some
  97. # kwargs might affect this though e.g. field=True (not sure if there
  98. # are others).
  99. if not kwargs:
  100. if dom.is_ZZ:
  101. return rep.copy()
  102. elif dom.is_QQ:
  103. # All elements might be integers
  104. try:
  105. return rep.convert_to(ZZ)
  106. except CoercionFailed:
  107. pass
  108. return rep.copy()
  109. # Let construct_domain choose a domain
  110. rep_dom = rep.choose_domain(**kwargs)
  111. # XXX: There should be an option to construct_domain to choose EXRAW
  112. # instead of EX. At least converting to EX does not initially trigger
  113. # EX.simplify which is what we want here but should probably be
  114. # considered a bug in EX. Perhaps also this could be handled in
  115. # DomainMatrix.choose_domain rather than here...
  116. if rep_dom.domain.is_EX:
  117. rep_dom = rep_dom.convert_to(EXRAW)
  118. return rep_dom
  119. @classmethod
  120. def _unify_element_sympy(cls, rep, element):
  121. domain = rep.domain
  122. element = _sympify(element)
  123. if domain != EXRAW:
  124. # The domain can only be ZZ, QQ or EXRAW
  125. if element.is_Integer:
  126. new_domain = domain
  127. elif element.is_Rational:
  128. new_domain = QQ
  129. else:
  130. new_domain = EXRAW
  131. # XXX: This converts the domain for all elements in the matrix
  132. # which can be slow. This happens e.g. if __setitem__ changes one
  133. # element to something that does not fit in the domain
  134. if new_domain != domain:
  135. rep = rep.convert_to(new_domain)
  136. domain = new_domain
  137. if domain != EXRAW:
  138. element = new_domain.from_sympy(element)
  139. if domain == EXRAW and not isinstance(element, Expr):
  140. sympy_deprecation_warning(
  141. """
  142. non-Expr objects in a Matrix is deprecated. Matrix represents
  143. a mathematical matrix. To represent a container of non-numeric
  144. entities, Use a list of lists, TableForm, NumPy array, or some
  145. other data structure instead.
  146. """,
  147. deprecated_since_version="1.9",
  148. active_deprecations_target="deprecated-non-expr-in-matrix",
  149. stacklevel=4,
  150. )
  151. return rep, element
  152. @classmethod
  153. def _dod_to_DomainMatrix(cls, rows, cols, dod, types):
  154. if not all(issubclass(typ, Expr) for typ in types):
  155. sympy_deprecation_warning(
  156. """
  157. non-Expr objects in a Matrix is deprecated. Matrix represents
  158. a mathematical matrix. To represent a container of non-numeric
  159. entities, Use a list of lists, TableForm, NumPy array, or some
  160. other data structure instead.
  161. """,
  162. deprecated_since_version="1.9",
  163. active_deprecations_target="deprecated-non-expr-in-matrix",
  164. stacklevel=6,
  165. )
  166. rep = DomainMatrix(dod, (rows, cols), EXRAW)
  167. if all(issubclass(typ, Rational) for typ in types):
  168. if all(issubclass(typ, Integer) for typ in types):
  169. rep = rep.convert_to(ZZ)
  170. else:
  171. rep = rep.convert_to(QQ)
  172. return rep
  173. @classmethod
  174. def _flat_list_to_DomainMatrix(cls, rows, cols, flat_list):
  175. elements_dod = defaultdict(dict)
  176. for n, element in enumerate(flat_list):
  177. if element != 0:
  178. i, j = divmod(n, cols)
  179. elements_dod[i][j] = element
  180. types = set(map(type, flat_list))
  181. rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types)
  182. return rep
  183. @classmethod
  184. def _smat_to_DomainMatrix(cls, rows, cols, smat):
  185. elements_dod = defaultdict(dict)
  186. for (i, j), element in smat.items():
  187. if element != 0:
  188. elements_dod[i][j] = element
  189. types = set(map(type, smat.values()))
  190. rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types)
  191. return rep
  192. def flat(self):
  193. return self._rep.to_sympy().to_list_flat()
  194. def _eval_tolist(self):
  195. return self._rep.to_sympy().to_list()
  196. def _eval_todok(self):
  197. return self._rep.to_sympy().to_dok()
  198. @classmethod
  199. def _eval_from_dok(cls, rows, cols, dok):
  200. return cls._fromrep(cls._smat_to_DomainMatrix(rows, cols, dok))
  201. def _eval_values(self):
  202. return list(self._eval_iter_values())
  203. def _eval_iter_values(self):
  204. rep = self._rep
  205. K = rep.domain
  206. values = rep.iter_values()
  207. if not K.is_EXRAW:
  208. values = map(K.to_sympy, values)
  209. return values
  210. def _eval_iter_items(self):
  211. rep = self._rep
  212. K = rep.domain
  213. to_sympy = K.to_sympy
  214. items = rep.iter_items()
  215. if not K.is_EXRAW:
  216. items = ((i, to_sympy(v)) for i, v in items)
  217. return items
  218. def copy(self):
  219. return self._fromrep(self._rep.copy())
  220. @property
  221. def kind(self) -> MatrixKind:
  222. domain = self._rep.domain
  223. element_kind: Kind
  224. if domain in (ZZ, QQ):
  225. element_kind = NumberKind
  226. elif domain == EXRAW:
  227. kinds = {e.kind for e in self.values()}
  228. if len(kinds) == 1:
  229. [element_kind] = kinds
  230. else:
  231. element_kind = UndefinedKind
  232. else: # pragma: no cover
  233. raise RuntimeError("Domain should only be ZZ, QQ or EXRAW")
  234. return MatrixKind(element_kind)
  235. def _eval_has(self, *patterns):
  236. # if the matrix has any zeros, see if S.Zero
  237. # has the pattern. If _smat is full length,
  238. # the matrix has no zeros.
  239. zhas = False
  240. dok = self.todok()
  241. if len(dok) != self.rows*self.cols:
  242. zhas = S.Zero.has(*patterns)
  243. return zhas or any(value.has(*patterns) for value in dok.values())
  244. def _eval_is_Identity(self):
  245. if not all(self[i, i] == 1 for i in range(self.rows)):
  246. return False
  247. return len(self.todok()) == self.rows
  248. def _eval_is_symmetric(self, simpfunc):
  249. diff = (self - self.T).applyfunc(simpfunc)
  250. return len(diff.values()) == 0
  251. def _eval_transpose(self):
  252. """Returns the transposed SparseMatrix of this SparseMatrix.
  253. Examples
  254. ========
  255. >>> from sympy import SparseMatrix
  256. >>> a = SparseMatrix(((1, 2), (3, 4)))
  257. >>> a
  258. Matrix([
  259. [1, 2],
  260. [3, 4]])
  261. >>> a.T
  262. Matrix([
  263. [1, 3],
  264. [2, 4]])
  265. """
  266. return self._fromrep(self._rep.transpose())
  267. def _eval_col_join(self, other):
  268. return self._fromrep(self._rep.vstack(other._rep))
  269. def _eval_row_join(self, other):
  270. return self._fromrep(self._rep.hstack(other._rep))
  271. def _eval_extract(self, rowsList, colsList):
  272. return self._fromrep(self._rep.extract(rowsList, colsList))
  273. def __getitem__(self, key):
  274. return _getitem_RepMatrix(self, key)
  275. @classmethod
  276. def _eval_zeros(cls, rows, cols):
  277. rep = DomainMatrix.zeros((rows, cols), ZZ)
  278. return cls._fromrep(rep)
  279. @classmethod
  280. def _eval_eye(cls, rows, cols):
  281. rep = DomainMatrix.eye((rows, cols), ZZ)
  282. return cls._fromrep(rep)
  283. def _eval_add(self, other):
  284. return classof(self, other)._fromrep(self._rep + other._rep)
  285. def _eval_matrix_mul(self, other):
  286. return classof(self, other)._fromrep(self._rep * other._rep)
  287. def _eval_matrix_mul_elementwise(self, other):
  288. selfrep, otherrep = self._rep.unify(other._rep)
  289. newrep = selfrep.mul_elementwise(otherrep)
  290. return classof(self, other)._fromrep(newrep)
  291. def _eval_scalar_mul(self, other):
  292. rep, other = self._unify_element_sympy(self._rep, other)
  293. return self._fromrep(rep.scalarmul(other))
  294. def _eval_scalar_rmul(self, other):
  295. rep, other = self._unify_element_sympy(self._rep, other)
  296. return self._fromrep(rep.rscalarmul(other))
  297. def _eval_Abs(self):
  298. return self._fromrep(self._rep.applyfunc(abs))
  299. def _eval_conjugate(self):
  300. rep = self._rep
  301. domain = rep.domain
  302. if domain in (ZZ, QQ):
  303. return self.copy()
  304. else:
  305. return self._fromrep(rep.applyfunc(lambda e: e.conjugate()))
  306. def equals(self, other, failing_expression=False):
  307. """Applies ``equals`` to corresponding elements of the matrices,
  308. trying to prove that the elements are equivalent, returning True
  309. if they are, False if any pair is not, and None (or the first
  310. failing expression if failing_expression is True) if it cannot
  311. be decided if the expressions are equivalent or not. This is, in
  312. general, an expensive operation.
  313. Examples
  314. ========
  315. >>> from sympy import Matrix
  316. >>> from sympy.abc import x
  317. >>> A = Matrix([x*(x - 1), 0])
  318. >>> B = Matrix([x**2 - x, 0])
  319. >>> A == B
  320. False
  321. >>> A.simplify() == B.simplify()
  322. True
  323. >>> A.equals(B)
  324. True
  325. >>> A.equals(2)
  326. False
  327. See Also
  328. ========
  329. sympy.core.expr.Expr.equals
  330. """
  331. if self.shape != getattr(other, 'shape', None):
  332. return False
  333. rv = True
  334. for i in range(self.rows):
  335. for j in range(self.cols):
  336. ans = self[i, j].equals(other[i, j], failing_expression)
  337. if ans is False:
  338. return False
  339. elif ans is not True and rv is True:
  340. rv = ans
  341. return rv
  342. def inv_mod(M, m):
  343. r"""
  344. Returns the inverse of the integer matrix ``M`` modulo ``m``.
  345. Examples
  346. ========
  347. >>> from sympy import Matrix
  348. >>> A = Matrix(2, 2, [1, 2, 3, 4])
  349. >>> A.inv_mod(5)
  350. Matrix([
  351. [3, 1],
  352. [4, 2]])
  353. >>> A.inv_mod(3)
  354. Matrix([
  355. [1, 1],
  356. [0, 1]])
  357. """
  358. if not M.is_square:
  359. raise NonSquareMatrixError()
  360. try:
  361. m = as_int(m)
  362. except ValueError:
  363. raise TypeError("inv_mod: modulus m must be an integer")
  364. K = GF(m, symmetric=False)
  365. try:
  366. dM = M.to_DM(K)
  367. except CoercionFailed:
  368. raise ValueError("inv_mod: matrix entries must be integers")
  369. if K.is_Field:
  370. try:
  371. dMi = dM.inv()
  372. except DMNonInvertibleMatrixError as exc:
  373. msg = f'Matrix is not invertible (mod {m})'
  374. raise NonInvertibleMatrixError(msg) from exc
  375. else:
  376. dMadj, det = dM.adj_det()
  377. try:
  378. detinv = 1 / det
  379. except NotInvertible:
  380. msg = f'Matrix is not invertible (mod {m})'
  381. raise NonInvertibleMatrixError(msg)
  382. dMi = dMadj * detinv
  383. return dMi.to_Matrix()
  384. def lll(self, delta=0.75):
  385. """LLL-reduced basis for the rowspace of a matrix of integers.
  386. Performs the Lenstra–Lenstra–Lovász (LLL) basis reduction algorithm.
  387. The implementation is provided by :class:`~DomainMatrix`. See
  388. :meth:`~DomainMatrix.lll` for more details.
  389. Examples
  390. ========
  391. >>> from sympy import Matrix
  392. >>> M = Matrix([[1, 0, 0, 0, -20160],
  393. ... [0, 1, 0, 0, 33768],
  394. ... [0, 0, 1, 0, 39578],
  395. ... [0, 0, 0, 1, 47757]])
  396. >>> M.lll()
  397. Matrix([
  398. [ 10, -3, -2, 8, -4],
  399. [ 3, -9, 8, 1, -11],
  400. [ -3, 13, -9, -3, -9],
  401. [-12, -7, -11, 9, -1]])
  402. See Also
  403. ========
  404. lll_transform
  405. sympy.polys.matrices.domainmatrix.DomainMatrix.lll
  406. """
  407. delta = QQ.from_sympy(_sympify(delta))
  408. dM = self._rep.convert_to(ZZ)
  409. basis = dM.lll(delta=delta)
  410. return self._fromrep(basis)
  411. def lll_transform(self, delta=0.75):
  412. """LLL-reduced basis and transformation matrix.
  413. Performs the Lenstra–Lenstra–Lovász (LLL) basis reduction algorithm.
  414. The implementation is provided by :class:`~DomainMatrix`. See
  415. :meth:`~DomainMatrix.lll_transform` for more details.
  416. Examples
  417. ========
  418. >>> from sympy import Matrix
  419. >>> M = Matrix([[1, 0, 0, 0, -20160],
  420. ... [0, 1, 0, 0, 33768],
  421. ... [0, 0, 1, 0, 39578],
  422. ... [0, 0, 0, 1, 47757]])
  423. >>> B, T = M.lll_transform()
  424. >>> B
  425. Matrix([
  426. [ 10, -3, -2, 8, -4],
  427. [ 3, -9, 8, 1, -11],
  428. [ -3, 13, -9, -3, -9],
  429. [-12, -7, -11, 9, -1]])
  430. >>> T
  431. Matrix([
  432. [ 10, -3, -2, 8],
  433. [ 3, -9, 8, 1],
  434. [ -3, 13, -9, -3],
  435. [-12, -7, -11, 9]])
  436. The transformation matrix maps the original basis to the LLL-reduced
  437. basis:
  438. >>> T * M == B
  439. True
  440. See Also
  441. ========
  442. lll
  443. sympy.polys.matrices.domainmatrix.DomainMatrix.lll_transform
  444. """
  445. delta = QQ.from_sympy(_sympify(delta))
  446. dM = self._rep.convert_to(ZZ)
  447. basis, transform = dM.lll_transform(delta=delta)
  448. B = self._fromrep(basis)
  449. T = self._fromrep(transform)
  450. return B, T
  451. class MutableRepMatrix(RepMatrix):
  452. """Mutable matrix based on DomainMatrix as the internal representation"""
  453. #
  454. # MutableRepMatrix is a subclass of RepMatrix that adds/overrides methods
  455. # to make the instances mutable. MutableRepMatrix is a superclass for both
  456. # MutableDenseMatrix and MutableSparseMatrix.
  457. #
  458. is_zero = False
  459. def __new__(cls, *args, **kwargs):
  460. return cls._new(*args, **kwargs)
  461. @classmethod
  462. def _new(cls, *args, copy=True, **kwargs):
  463. if copy is False:
  464. # The input was rows, cols, [list].
  465. # It should be used directly without creating a copy.
  466. if len(args) != 3:
  467. raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]")
  468. rows, cols, flat_list = args
  469. else:
  470. rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs)
  471. flat_list = list(flat_list) # create a shallow copy
  472. rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list)
  473. return cls._fromrep(rep)
  474. @classmethod
  475. def _fromrep(cls, rep):
  476. obj = super().__new__(cls)
  477. obj.rows, obj.cols = rep.shape
  478. obj._rep = rep
  479. return obj
  480. def copy(self):
  481. return self._fromrep(self._rep.copy())
  482. def as_mutable(self):
  483. return self.copy()
  484. def __setitem__(self, key, value):
  485. """
  486. Examples
  487. ========
  488. >>> from sympy import Matrix, I, zeros, ones
  489. >>> m = Matrix(((1, 2+I), (3, 4)))
  490. >>> m
  491. Matrix([
  492. [1, 2 + I],
  493. [3, 4]])
  494. >>> m[1, 0] = 9
  495. >>> m
  496. Matrix([
  497. [1, 2 + I],
  498. [9, 4]])
  499. >>> m[1, 0] = [[0, 1]]
  500. To replace row r you assign to position r*m where m
  501. is the number of columns:
  502. >>> M = zeros(4)
  503. >>> m = M.cols
  504. >>> M[3*m] = ones(1, m)*2; M
  505. Matrix([
  506. [0, 0, 0, 0],
  507. [0, 0, 0, 0],
  508. [0, 0, 0, 0],
  509. [2, 2, 2, 2]])
  510. And to replace column c you can assign to position c:
  511. >>> M[2] = ones(m, 1)*4; M
  512. Matrix([
  513. [0, 0, 4, 0],
  514. [0, 0, 4, 0],
  515. [0, 0, 4, 0],
  516. [2, 2, 4, 2]])
  517. """
  518. rv = self._setitem(key, value)
  519. if rv is not None:
  520. i, j, value = rv
  521. self._rep, value = self._unify_element_sympy(self._rep, value)
  522. self._rep.rep.setitem(i, j, value)
  523. def _eval_col_del(self, col):
  524. self._rep = DomainMatrix.hstack(self._rep[:,:col], self._rep[:,col+1:])
  525. self.cols -= 1
  526. def _eval_row_del(self, row):
  527. self._rep = DomainMatrix.vstack(self._rep[:row,:], self._rep[row+1:, :])
  528. self.rows -= 1
  529. def _eval_col_insert(self, col, other):
  530. other = self._new(other)
  531. return self.hstack(self[:,:col], other, self[:,col:])
  532. def _eval_row_insert(self, row, other):
  533. other = self._new(other)
  534. return self.vstack(self[:row,:], other, self[row:,:])
  535. def col_op(self, j, f):
  536. """In-place operation on col j using two-arg functor whose args are
  537. interpreted as (self[i, j], i).
  538. Examples
  539. ========
  540. >>> from sympy import eye
  541. >>> M = eye(3)
  542. >>> M.col_op(1, lambda v, i: v + 2*M[i, 0]); M
  543. Matrix([
  544. [1, 2, 0],
  545. [0, 1, 0],
  546. [0, 0, 1]])
  547. See Also
  548. ========
  549. col
  550. row_op
  551. """
  552. for i in range(self.rows):
  553. self[i, j] = f(self[i, j], i)
  554. def col_swap(self, i, j):
  555. """Swap the two given columns of the matrix in-place.
  556. Examples
  557. ========
  558. >>> from sympy import Matrix
  559. >>> M = Matrix([[1, 0], [1, 0]])
  560. >>> M
  561. Matrix([
  562. [1, 0],
  563. [1, 0]])
  564. >>> M.col_swap(0, 1)
  565. >>> M
  566. Matrix([
  567. [0, 1],
  568. [0, 1]])
  569. See Also
  570. ========
  571. col
  572. row_swap
  573. """
  574. for k in range(0, self.rows):
  575. self[k, i], self[k, j] = self[k, j], self[k, i]
  576. def row_op(self, i, f):
  577. """In-place operation on row ``i`` using two-arg functor whose args are
  578. interpreted as ``(self[i, j], j)``.
  579. Examples
  580. ========
  581. >>> from sympy import eye
  582. >>> M = eye(3)
  583. >>> M.row_op(1, lambda v, j: v + 2*M[0, j]); M
  584. Matrix([
  585. [1, 0, 0],
  586. [2, 1, 0],
  587. [0, 0, 1]])
  588. See Also
  589. ========
  590. row
  591. zip_row_op
  592. col_op
  593. """
  594. for j in range(self.cols):
  595. self[i, j] = f(self[i, j], j)
  596. #The next three methods give direct support for the most common row operations inplace.
  597. def row_mult(self,i,factor):
  598. """Multiply the given row by the given factor in-place.
  599. Examples
  600. ========
  601. >>> from sympy import eye
  602. >>> M = eye(3)
  603. >>> M.row_mult(1,7); M
  604. Matrix([
  605. [1, 0, 0],
  606. [0, 7, 0],
  607. [0, 0, 1]])
  608. """
  609. for j in range(self.cols):
  610. self[i,j] *= factor
  611. def row_add(self,s,t,k):
  612. """Add k times row s (source) to row t (target) in place.
  613. Examples
  614. ========
  615. >>> from sympy import eye
  616. >>> M = eye(3)
  617. >>> M.row_add(0, 2,3); M
  618. Matrix([
  619. [1, 0, 0],
  620. [0, 1, 0],
  621. [3, 0, 1]])
  622. """
  623. for j in range(self.cols):
  624. self[t,j] += k*self[s,j]
  625. def row_swap(self, i, j):
  626. """Swap the two given rows of the matrix in-place.
  627. Examples
  628. ========
  629. >>> from sympy import Matrix
  630. >>> M = Matrix([[0, 1], [1, 0]])
  631. >>> M
  632. Matrix([
  633. [0, 1],
  634. [1, 0]])
  635. >>> M.row_swap(0, 1)
  636. >>> M
  637. Matrix([
  638. [1, 0],
  639. [0, 1]])
  640. See Also
  641. ========
  642. row
  643. col_swap
  644. """
  645. for k in range(0, self.cols):
  646. self[i, k], self[j, k] = self[j, k], self[i, k]
  647. def zip_row_op(self, i, k, f):
  648. """In-place operation on row ``i`` using two-arg functor whose args are
  649. interpreted as ``(self[i, j], self[k, j])``.
  650. Examples
  651. ========
  652. >>> from sympy import eye
  653. >>> M = eye(3)
  654. >>> M.zip_row_op(1, 0, lambda v, u: v + 2*u); M
  655. Matrix([
  656. [1, 0, 0],
  657. [2, 1, 0],
  658. [0, 0, 1]])
  659. See Also
  660. ========
  661. row
  662. row_op
  663. col_op
  664. """
  665. for j in range(self.cols):
  666. self[i, j] = f(self[i, j], self[k, j])
  667. def copyin_list(self, key, value):
  668. """Copy in elements from a list.
  669. Parameters
  670. ==========
  671. key : slice
  672. The section of this matrix to replace.
  673. value : iterable
  674. The iterable to copy values from.
  675. Examples
  676. ========
  677. >>> from sympy import eye
  678. >>> I = eye(3)
  679. >>> I[:2, 0] = [1, 2] # col
  680. >>> I
  681. Matrix([
  682. [1, 0, 0],
  683. [2, 1, 0],
  684. [0, 0, 1]])
  685. >>> I[1, :2] = [[3, 4]]
  686. >>> I
  687. Matrix([
  688. [1, 0, 0],
  689. [3, 4, 0],
  690. [0, 0, 1]])
  691. See Also
  692. ========
  693. copyin_matrix
  694. """
  695. if not is_sequence(value):
  696. raise TypeError("`value` must be an ordered iterable, not %s." % type(value))
  697. return self.copyin_matrix(key, type(self)(value))
  698. def copyin_matrix(self, key, value):
  699. """Copy in values from a matrix into the given bounds.
  700. Parameters
  701. ==========
  702. key : slice
  703. The section of this matrix to replace.
  704. value : Matrix
  705. The matrix to copy values from.
  706. Examples
  707. ========
  708. >>> from sympy import Matrix, eye
  709. >>> M = Matrix([[0, 1], [2, 3], [4, 5]])
  710. >>> I = eye(3)
  711. >>> I[:3, :2] = M
  712. >>> I
  713. Matrix([
  714. [0, 1, 0],
  715. [2, 3, 0],
  716. [4, 5, 1]])
  717. >>> I[0, 1] = M
  718. >>> I
  719. Matrix([
  720. [0, 0, 1],
  721. [2, 2, 3],
  722. [4, 4, 5]])
  723. See Also
  724. ========
  725. copyin_list
  726. """
  727. rlo, rhi, clo, chi = self.key2bounds(key)
  728. shape = value.shape
  729. dr, dc = rhi - rlo, chi - clo
  730. if shape != (dr, dc):
  731. raise ShapeError(filldedent("The Matrix `value` doesn't have the "
  732. "same dimensions "
  733. "as the in sub-Matrix given by `key`."))
  734. for i in range(value.rows):
  735. for j in range(value.cols):
  736. self[i + rlo, j + clo] = value[i, j]
  737. def fill(self, value):
  738. """Fill self with the given value.
  739. Notes
  740. =====
  741. Unless many values are going to be deleted (i.e. set to zero)
  742. this will create a matrix that is slower than a dense matrix in
  743. operations.
  744. Examples
  745. ========
  746. >>> from sympy import SparseMatrix
  747. >>> M = SparseMatrix.zeros(3); M
  748. Matrix([
  749. [0, 0, 0],
  750. [0, 0, 0],
  751. [0, 0, 0]])
  752. >>> M.fill(1); M
  753. Matrix([
  754. [1, 1, 1],
  755. [1, 1, 1],
  756. [1, 1, 1]])
  757. See Also
  758. ========
  759. zeros
  760. ones
  761. """
  762. value = _sympify(value)
  763. if not value:
  764. self._rep = DomainMatrix.zeros(self.shape, EXRAW)
  765. else:
  766. elements_dod = {i: dict.fromkeys(range(self.cols), value) for i in range(self.rows)}
  767. self._rep = DomainMatrix(elements_dod, self.shape, EXRAW)
  768. def _getitem_RepMatrix(self, key):
  769. """Return portion of self defined by key. If the key involves a slice
  770. then a list will be returned (if key is a single slice) or a matrix
  771. (if key was a tuple involving a slice).
  772. Examples
  773. ========
  774. >>> from sympy import Matrix, I
  775. >>> m = Matrix([
  776. ... [1, 2 + I],
  777. ... [3, 4 ]])
  778. If the key is a tuple that does not involve a slice then that element
  779. is returned:
  780. >>> m[1, 0]
  781. 3
  782. When a tuple key involves a slice, a matrix is returned. Here, the
  783. first column is selected (all rows, column 0):
  784. >>> m[:, 0]
  785. Matrix([
  786. [1],
  787. [3]])
  788. If the slice is not a tuple then it selects from the underlying
  789. list of elements that are arranged in row order and a list is
  790. returned if a slice is involved:
  791. >>> m[0]
  792. 1
  793. >>> m[::2]
  794. [1, 3]
  795. """
  796. if isinstance(key, tuple):
  797. i, j = key
  798. try:
  799. return self._rep.getitem_sympy(index_(i), index_(j))
  800. except (TypeError, IndexError):
  801. if (isinstance(i, Expr) and not i.is_number) or (isinstance(j, Expr) and not j.is_number):
  802. if ((j < 0) is True) or ((j >= self.shape[1]) is True) or\
  803. ((i < 0) is True) or ((i >= self.shape[0]) is True):
  804. raise ValueError("index out of boundary")
  805. from sympy.matrices.expressions.matexpr import MatrixElement
  806. return MatrixElement(self, i, j)
  807. if isinstance(i, slice):
  808. i = range(self.rows)[i]
  809. elif is_sequence(i):
  810. pass
  811. else:
  812. i = [i]
  813. if isinstance(j, slice):
  814. j = range(self.cols)[j]
  815. elif is_sequence(j):
  816. pass
  817. else:
  818. j = [j]
  819. return self.extract(i, j)
  820. else:
  821. # Index/slice like a flattened list
  822. rows, cols = self.shape
  823. # Raise the appropriate exception:
  824. if not rows * cols:
  825. return [][key]
  826. rep = self._rep.rep
  827. domain = rep.domain
  828. is_slice = isinstance(key, slice)
  829. if is_slice:
  830. values = [rep.getitem(*divmod(n, cols)) for n in range(rows * cols)[key]]
  831. else:
  832. values = [rep.getitem(*divmod(index_(key), cols))]
  833. if domain != EXRAW:
  834. to_sympy = domain.to_sympy
  835. values = [to_sympy(val) for val in values]
  836. if is_slice:
  837. return values
  838. else:
  839. return values[0]