domainmatrix.py 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693
  1. """
  2. Module for the DomainMatrix class.
  3. A DomainMatrix represents a matrix with elements that are in a particular
  4. Domain. Each DomainMatrix internally wraps a DDM which is used for the
  5. lower-level operations. The idea is that the DomainMatrix class provides the
  6. convenience routines for converting between Expr and the poly domains as well
  7. as unifying matrices with different domains.
  8. """
  9. from functools import reduce
  10. from typing import Union as tUnion, Tuple as tTuple
  11. from sympy.core.sympify import _sympify
  12. from ..domains import Domain
  13. from ..constructor import construct_domain
  14. from .exceptions import (DMNonSquareMatrixError, DMShapeError,
  15. DMDomainError, DMFormatError, DMBadInputError,
  16. DMNotAField)
  17. from .ddm import DDM
  18. from .sdm import SDM
  19. from .domainscalar import DomainScalar
  20. from sympy.polys.domains import ZZ, EXRAW
  21. def DM(rows, domain):
  22. """Convenient alias for DomainMatrix.from_list
  23. Examples
  24. =======
  25. >>> from sympy import ZZ
  26. >>> from sympy.polys.matrices import DM
  27. >>> DM([[1, 2], [3, 4]], ZZ)
  28. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  29. See also
  30. =======
  31. DomainMatrix.from_list
  32. """
  33. return DomainMatrix.from_list(rows, domain)
  34. class DomainMatrix:
  35. r"""
  36. Associate Matrix with :py:class:`~.Domain`
  37. Explanation
  38. ===========
  39. DomainMatrix uses :py:class:`~.Domain` for its internal representation
  40. which makes it more faster for many common operations
  41. than current SymPy Matrix class, but this advantage makes it not
  42. entirely compatible with Matrix.
  43. DomainMatrix could be found analogous to numpy arrays with "dtype".
  44. In the DomainMatrix, each matrix has a domain such as :ref:`ZZ`
  45. or :ref:`QQ(a)`.
  46. Examples
  47. ========
  48. Creating a DomainMatrix from the existing Matrix class:
  49. >>> from sympy import Matrix
  50. >>> from sympy.polys.matrices import DomainMatrix
  51. >>> Matrix1 = Matrix([
  52. ... [1, 2],
  53. ... [3, 4]])
  54. >>> A = DomainMatrix.from_Matrix(Matrix1)
  55. >>> A
  56. DomainMatrix({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ)
  57. Driectly forming a DomainMatrix:
  58. >>> from sympy import ZZ
  59. >>> from sympy.polys.matrices import DomainMatrix
  60. >>> A = DomainMatrix([
  61. ... [ZZ(1), ZZ(2)],
  62. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  63. >>> A
  64. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  65. See Also
  66. ========
  67. DDM
  68. SDM
  69. Domain
  70. Poly
  71. """
  72. rep: tUnion[SDM, DDM]
  73. shape: tTuple[int, int]
  74. domain: Domain
  75. def __new__(cls, rows, shape, domain, *, fmt=None):
  76. """
  77. Creates a :py:class:`~.DomainMatrix`.
  78. Parameters
  79. ==========
  80. rows : Represents elements of DomainMatrix as list of lists
  81. shape : Represents dimension of DomainMatrix
  82. domain : Represents :py:class:`~.Domain` of DomainMatrix
  83. Raises
  84. ======
  85. TypeError
  86. If any of rows, shape and domain are not provided
  87. """
  88. if isinstance(rows, (DDM, SDM)):
  89. raise TypeError("Use from_rep to initialise from SDM/DDM")
  90. elif isinstance(rows, list):
  91. rep = DDM(rows, shape, domain)
  92. elif isinstance(rows, dict):
  93. rep = SDM(rows, shape, domain)
  94. else:
  95. msg = "Input should be list-of-lists or dict-of-dicts"
  96. raise TypeError(msg)
  97. if fmt is not None:
  98. if fmt == 'sparse':
  99. rep = rep.to_sdm()
  100. elif fmt == 'dense':
  101. rep = rep.to_ddm()
  102. else:
  103. raise ValueError("fmt should be 'sparse' or 'dense'")
  104. return cls.from_rep(rep)
  105. def __getnewargs__(self):
  106. rep = self.rep
  107. if isinstance(rep, DDM):
  108. arg = list(rep)
  109. elif isinstance(rep, SDM):
  110. arg = dict(rep)
  111. else:
  112. raise RuntimeError # pragma: no cover
  113. return arg, self.shape, self.domain
  114. def __getitem__(self, key):
  115. i, j = key
  116. m, n = self.shape
  117. if not (isinstance(i, slice) or isinstance(j, slice)):
  118. return DomainScalar(self.rep.getitem(i, j), self.domain)
  119. if not isinstance(i, slice):
  120. if not -m <= i < m:
  121. raise IndexError("Row index out of range")
  122. i = i % m
  123. i = slice(i, i+1)
  124. if not isinstance(j, slice):
  125. if not -n <= j < n:
  126. raise IndexError("Column index out of range")
  127. j = j % n
  128. j = slice(j, j+1)
  129. return self.from_rep(self.rep.extract_slice(i, j))
  130. def getitem_sympy(self, i, j):
  131. return self.domain.to_sympy(self.rep.getitem(i, j))
  132. def extract(self, rowslist, colslist):
  133. return self.from_rep(self.rep.extract(rowslist, colslist))
  134. def __setitem__(self, key, value):
  135. i, j = key
  136. if not self.domain.of_type(value):
  137. raise TypeError
  138. if isinstance(i, int) and isinstance(j, int):
  139. self.rep.setitem(i, j, value)
  140. else:
  141. raise NotImplementedError
  142. @classmethod
  143. def from_rep(cls, rep):
  144. """Create a new DomainMatrix efficiently from DDM/SDM.
  145. Examples
  146. ========
  147. Create a :py:class:`~.DomainMatrix` with an dense internal
  148. representation as :py:class:`~.DDM`:
  149. >>> from sympy.polys.domains import ZZ
  150. >>> from sympy.polys.matrices import DomainMatrix
  151. >>> from sympy.polys.matrices.ddm import DDM
  152. >>> drep = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  153. >>> dM = DomainMatrix.from_rep(drep)
  154. >>> dM
  155. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  156. Create a :py:class:`~.DomainMatrix` with a sparse internal
  157. representation as :py:class:`~.SDM`:
  158. >>> from sympy.polys.matrices import DomainMatrix
  159. >>> from sympy.polys.matrices.sdm import SDM
  160. >>> from sympy import ZZ
  161. >>> drep = SDM({0:{1:ZZ(1)},1:{0:ZZ(2)}}, (2, 2), ZZ)
  162. >>> dM = DomainMatrix.from_rep(drep)
  163. >>> dM
  164. DomainMatrix({0: {1: 1}, 1: {0: 2}}, (2, 2), ZZ)
  165. Parameters
  166. ==========
  167. rep: SDM or DDM
  168. The internal sparse or dense representation of the matrix.
  169. Returns
  170. =======
  171. DomainMatrix
  172. A :py:class:`~.DomainMatrix` wrapping *rep*.
  173. Notes
  174. =====
  175. This takes ownership of rep as its internal representation. If rep is
  176. being mutated elsewhere then a copy should be provided to
  177. ``from_rep``. Only minimal verification or checking is done on *rep*
  178. as this is supposed to be an efficient internal routine.
  179. """
  180. if not isinstance(rep, (DDM, SDM)):
  181. raise TypeError("rep should be of type DDM or SDM")
  182. self = super().__new__(cls)
  183. self.rep = rep
  184. self.shape = rep.shape
  185. self.domain = rep.domain
  186. return self
  187. @classmethod
  188. def from_list(cls, rows, domain):
  189. r"""
  190. Convert a list of lists into a DomainMatrix
  191. Parameters
  192. ==========
  193. rows: list of lists
  194. Each element of the inner lists should be either the single arg,
  195. or tuple of args, that would be passed to the domain constructor
  196. in order to form an element of the domain. See examples.
  197. Returns
  198. =======
  199. DomainMatrix containing elements defined in rows
  200. Examples
  201. ========
  202. >>> from sympy.polys.matrices import DomainMatrix
  203. >>> from sympy import FF, QQ, ZZ
  204. >>> A = DomainMatrix.from_list([[1, 0, 1], [0, 0, 1]], ZZ)
  205. >>> A
  206. DomainMatrix([[1, 0, 1], [0, 0, 1]], (2, 3), ZZ)
  207. >>> B = DomainMatrix.from_list([[1, 0, 1], [0, 0, 1]], FF(7))
  208. >>> B
  209. DomainMatrix([[1 mod 7, 0 mod 7, 1 mod 7], [0 mod 7, 0 mod 7, 1 mod 7]], (2, 3), GF(7))
  210. >>> C = DomainMatrix.from_list([[(1, 2), (3, 1)], [(1, 4), (5, 1)]], QQ)
  211. >>> C
  212. DomainMatrix([[1/2, 3], [1/4, 5]], (2, 2), QQ)
  213. See Also
  214. ========
  215. from_list_sympy
  216. """
  217. nrows = len(rows)
  218. ncols = 0 if not nrows else len(rows[0])
  219. conv = lambda e: domain(*e) if isinstance(e, tuple) else domain(e)
  220. domain_rows = [[conv(e) for e in row] for row in rows]
  221. return DomainMatrix(domain_rows, (nrows, ncols), domain)
  222. @classmethod
  223. def from_list_sympy(cls, nrows, ncols, rows, **kwargs):
  224. r"""
  225. Convert a list of lists of Expr into a DomainMatrix using construct_domain
  226. Parameters
  227. ==========
  228. nrows: number of rows
  229. ncols: number of columns
  230. rows: list of lists
  231. Returns
  232. =======
  233. DomainMatrix containing elements of rows
  234. Examples
  235. ========
  236. >>> from sympy.polys.matrices import DomainMatrix
  237. >>> from sympy.abc import x, y, z
  238. >>> A = DomainMatrix.from_list_sympy(1, 3, [[x, y, z]])
  239. >>> A
  240. DomainMatrix([[x, y, z]], (1, 3), ZZ[x,y,z])
  241. See Also
  242. ========
  243. sympy.polys.constructor.construct_domain, from_dict_sympy
  244. """
  245. assert len(rows) == nrows
  246. assert all(len(row) == ncols for row in rows)
  247. items_sympy = [_sympify(item) for row in rows for item in row]
  248. domain, items_domain = cls.get_domain(items_sympy, **kwargs)
  249. domain_rows = [[items_domain[ncols*r + c] for c in range(ncols)] for r in range(nrows)]
  250. return DomainMatrix(domain_rows, (nrows, ncols), domain)
  251. @classmethod
  252. def from_dict_sympy(cls, nrows, ncols, elemsdict, **kwargs):
  253. """
  254. Parameters
  255. ==========
  256. nrows: number of rows
  257. ncols: number of cols
  258. elemsdict: dict of dicts containing non-zero elements of the DomainMatrix
  259. Returns
  260. =======
  261. DomainMatrix containing elements of elemsdict
  262. Examples
  263. ========
  264. >>> from sympy.polys.matrices import DomainMatrix
  265. >>> from sympy.abc import x,y,z
  266. >>> elemsdict = {0: {0:x}, 1:{1: y}, 2: {2: z}}
  267. >>> A = DomainMatrix.from_dict_sympy(3, 3, elemsdict)
  268. >>> A
  269. DomainMatrix({0: {0: x}, 1: {1: y}, 2: {2: z}}, (3, 3), ZZ[x,y,z])
  270. See Also
  271. ========
  272. from_list_sympy
  273. """
  274. if not all(0 <= r < nrows for r in elemsdict):
  275. raise DMBadInputError("Row out of range")
  276. if not all(0 <= c < ncols for row in elemsdict.values() for c in row):
  277. raise DMBadInputError("Column out of range")
  278. items_sympy = [_sympify(item) for row in elemsdict.values() for item in row.values()]
  279. domain, items_domain = cls.get_domain(items_sympy, **kwargs)
  280. idx = 0
  281. items_dict = {}
  282. for i, row in elemsdict.items():
  283. items_dict[i] = {}
  284. for j in row:
  285. items_dict[i][j] = items_domain[idx]
  286. idx += 1
  287. return DomainMatrix(items_dict, (nrows, ncols), domain)
  288. @classmethod
  289. def from_Matrix(cls, M, fmt='sparse',**kwargs):
  290. r"""
  291. Convert Matrix to DomainMatrix
  292. Parameters
  293. ==========
  294. M: Matrix
  295. Returns
  296. =======
  297. Returns DomainMatrix with identical elements as M
  298. Examples
  299. ========
  300. >>> from sympy import Matrix
  301. >>> from sympy.polys.matrices import DomainMatrix
  302. >>> M = Matrix([
  303. ... [1.0, 3.4],
  304. ... [2.4, 1]])
  305. >>> A = DomainMatrix.from_Matrix(M)
  306. >>> A
  307. DomainMatrix({0: {0: 1.0, 1: 3.4}, 1: {0: 2.4, 1: 1.0}}, (2, 2), RR)
  308. We can keep internal representation as ddm using fmt='dense'
  309. >>> from sympy import Matrix, QQ
  310. >>> from sympy.polys.matrices import DomainMatrix
  311. >>> A = DomainMatrix.from_Matrix(Matrix([[QQ(1, 2), QQ(3, 4)], [QQ(0, 1), QQ(0, 1)]]), fmt='dense')
  312. >>> A.rep
  313. [[1/2, 3/4], [0, 0]]
  314. See Also
  315. ========
  316. Matrix
  317. """
  318. if fmt == 'dense':
  319. return cls.from_list_sympy(*M.shape, M.tolist(), **kwargs)
  320. return cls.from_dict_sympy(*M.shape, M.todod(), **kwargs)
  321. @classmethod
  322. def get_domain(cls, items_sympy, **kwargs):
  323. K, items_K = construct_domain(items_sympy, **kwargs)
  324. return K, items_K
  325. def copy(self):
  326. return self.from_rep(self.rep.copy())
  327. def convert_to(self, K):
  328. r"""
  329. Change the domain of DomainMatrix to desired domain or field
  330. Parameters
  331. ==========
  332. K : Represents the desired domain or field.
  333. Alternatively, ``None`` may be passed, in which case this method
  334. just returns a copy of this DomainMatrix.
  335. Returns
  336. =======
  337. DomainMatrix
  338. DomainMatrix with the desired domain or field
  339. Examples
  340. ========
  341. >>> from sympy import ZZ, ZZ_I
  342. >>> from sympy.polys.matrices import DomainMatrix
  343. >>> A = DomainMatrix([
  344. ... [ZZ(1), ZZ(2)],
  345. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  346. >>> A.convert_to(ZZ_I)
  347. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ_I)
  348. """
  349. if K is None:
  350. return self.copy()
  351. return self.from_rep(self.rep.convert_to(K))
  352. def to_sympy(self):
  353. return self.convert_to(EXRAW)
  354. def to_field(self):
  355. r"""
  356. Returns a DomainMatrix with the appropriate field
  357. Returns
  358. =======
  359. DomainMatrix
  360. DomainMatrix with the appropriate field
  361. Examples
  362. ========
  363. >>> from sympy import ZZ
  364. >>> from sympy.polys.matrices import DomainMatrix
  365. >>> A = DomainMatrix([
  366. ... [ZZ(1), ZZ(2)],
  367. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  368. >>> A.to_field()
  369. DomainMatrix([[1, 2], [3, 4]], (2, 2), QQ)
  370. """
  371. K = self.domain.get_field()
  372. return self.convert_to(K)
  373. def to_sparse(self):
  374. """
  375. Return a sparse DomainMatrix representation of *self*.
  376. Examples
  377. ========
  378. >>> from sympy.polys.matrices import DomainMatrix
  379. >>> from sympy import QQ
  380. >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ)
  381. >>> A.rep
  382. [[1, 0], [0, 2]]
  383. >>> B = A.to_sparse()
  384. >>> B.rep
  385. {0: {0: 1}, 1: {1: 2}}
  386. """
  387. if self.rep.fmt == 'sparse':
  388. return self
  389. return self.from_rep(SDM.from_ddm(self.rep))
  390. def to_dense(self):
  391. """
  392. Return a dense DomainMatrix representation of *self*.
  393. Examples
  394. ========
  395. >>> from sympy.polys.matrices import DomainMatrix
  396. >>> from sympy import QQ
  397. >>> A = DomainMatrix({0: {0: 1}, 1: {1: 2}}, (2, 2), QQ)
  398. >>> A.rep
  399. {0: {0: 1}, 1: {1: 2}}
  400. >>> B = A.to_dense()
  401. >>> B.rep
  402. [[1, 0], [0, 2]]
  403. """
  404. if self.rep.fmt == 'dense':
  405. return self
  406. return self.from_rep(SDM.to_ddm(self.rep))
  407. @classmethod
  408. def _unify_domain(cls, *matrices):
  409. """Convert matrices to a common domain"""
  410. domains = {matrix.domain for matrix in matrices}
  411. if len(domains) == 1:
  412. return matrices
  413. domain = reduce(lambda x, y: x.unify(y), domains)
  414. return tuple(matrix.convert_to(domain) for matrix in matrices)
  415. @classmethod
  416. def _unify_fmt(cls, *matrices, fmt=None):
  417. """Convert matrices to the same format.
  418. If all matrices have the same format, then return unmodified.
  419. Otherwise convert both to the preferred format given as *fmt* which
  420. should be 'dense' or 'sparse'.
  421. """
  422. formats = {matrix.rep.fmt for matrix in matrices}
  423. if len(formats) == 1:
  424. return matrices
  425. if fmt == 'sparse':
  426. return tuple(matrix.to_sparse() for matrix in matrices)
  427. elif fmt == 'dense':
  428. return tuple(matrix.to_dense() for matrix in matrices)
  429. else:
  430. raise ValueError("fmt should be 'sparse' or 'dense'")
  431. def unify(self, *others, fmt=None):
  432. """
  433. Unifies the domains and the format of self and other
  434. matrices.
  435. Parameters
  436. ==========
  437. others : DomainMatrix
  438. fmt: string 'dense', 'sparse' or `None` (default)
  439. The preferred format to convert to if self and other are not
  440. already in the same format. If `None` or not specified then no
  441. conversion if performed.
  442. Returns
  443. =======
  444. Tuple[DomainMatrix]
  445. Matrices with unified domain and format
  446. Examples
  447. ========
  448. Unify the domain of DomainMatrix that have different domains:
  449. >>> from sympy import ZZ, QQ
  450. >>> from sympy.polys.matrices import DomainMatrix
  451. >>> A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  452. >>> B = DomainMatrix([[QQ(1, 2), QQ(2)]], (1, 2), QQ)
  453. >>> Aq, Bq = A.unify(B)
  454. >>> Aq
  455. DomainMatrix([[1, 2]], (1, 2), QQ)
  456. >>> Bq
  457. DomainMatrix([[1/2, 2]], (1, 2), QQ)
  458. Unify the format (dense or sparse):
  459. >>> A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  460. >>> B = DomainMatrix({0:{0: ZZ(1)}}, (2, 2), ZZ)
  461. >>> B.rep
  462. {0: {0: 1}}
  463. >>> A2, B2 = A.unify(B, fmt='dense')
  464. >>> B2.rep
  465. [[1, 0], [0, 0]]
  466. See Also
  467. ========
  468. convert_to, to_dense, to_sparse
  469. """
  470. matrices = (self,) + others
  471. matrices = DomainMatrix._unify_domain(*matrices)
  472. if fmt is not None:
  473. matrices = DomainMatrix._unify_fmt(*matrices, fmt=fmt)
  474. return matrices
  475. def to_Matrix(self):
  476. r"""
  477. Convert DomainMatrix to Matrix
  478. Returns
  479. =======
  480. Matrix
  481. MutableDenseMatrix for the DomainMatrix
  482. Examples
  483. ========
  484. >>> from sympy import ZZ
  485. >>> from sympy.polys.matrices import DomainMatrix
  486. >>> A = DomainMatrix([
  487. ... [ZZ(1), ZZ(2)],
  488. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  489. >>> A.to_Matrix()
  490. Matrix([
  491. [1, 2],
  492. [3, 4]])
  493. See Also
  494. ========
  495. from_Matrix
  496. """
  497. from sympy.matrices.dense import MutableDenseMatrix
  498. elemlist = self.rep.to_list()
  499. elements_sympy = [self.domain.to_sympy(e) for row in elemlist for e in row]
  500. return MutableDenseMatrix(*self.shape, elements_sympy)
  501. def to_list(self):
  502. return self.rep.to_list()
  503. def to_list_flat(self):
  504. return self.rep.to_list_flat()
  505. def to_dok(self):
  506. return self.rep.to_dok()
  507. def __repr__(self):
  508. return 'DomainMatrix(%s, %r, %r)' % (str(self.rep), self.shape, self.domain)
  509. def transpose(self):
  510. """Matrix transpose of ``self``"""
  511. return self.from_rep(self.rep.transpose())
  512. def flat(self):
  513. rows, cols = self.shape
  514. return [self[i,j].element for i in range(rows) for j in range(cols)]
  515. @property
  516. def is_zero_matrix(self):
  517. return self.rep.is_zero_matrix()
  518. @property
  519. def is_upper(self):
  520. """
  521. Says whether this matrix is upper-triangular. True can be returned
  522. even if the matrix is not square.
  523. """
  524. return self.rep.is_upper()
  525. @property
  526. def is_lower(self):
  527. """
  528. Says whether this matrix is lower-triangular. True can be returned
  529. even if the matrix is not square.
  530. """
  531. return self.rep.is_lower()
  532. @property
  533. def is_square(self):
  534. return self.shape[0] == self.shape[1]
  535. def rank(self):
  536. rref, pivots = self.rref()
  537. return len(pivots)
  538. def hstack(A, *B):
  539. r"""Horizontally stack the given matrices.
  540. Parameters
  541. ==========
  542. B: DomainMatrix
  543. Matrices to stack horizontally.
  544. Returns
  545. =======
  546. DomainMatrix
  547. DomainMatrix by stacking horizontally.
  548. Examples
  549. ========
  550. >>> from sympy import ZZ
  551. >>> from sympy.polys.matrices import DomainMatrix
  552. >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  553. >>> B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ)
  554. >>> A.hstack(B)
  555. DomainMatrix([[1, 2, 5, 6], [3, 4, 7, 8]], (2, 4), ZZ)
  556. >>> C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ)
  557. >>> A.hstack(B, C)
  558. DomainMatrix([[1, 2, 5, 6, 9, 10], [3, 4, 7, 8, 11, 12]], (2, 6), ZZ)
  559. See Also
  560. ========
  561. unify
  562. """
  563. A, *B = A.unify(*B, fmt='dense')
  564. return DomainMatrix.from_rep(A.rep.hstack(*(Bk.rep for Bk in B)))
  565. def vstack(A, *B):
  566. r"""Vertically stack the given matrices.
  567. Parameters
  568. ==========
  569. B: DomainMatrix
  570. Matrices to stack vertically.
  571. Returns
  572. =======
  573. DomainMatrix
  574. DomainMatrix by stacking vertically.
  575. Examples
  576. ========
  577. >>> from sympy import ZZ
  578. >>> from sympy.polys.matrices import DomainMatrix
  579. >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  580. >>> B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ)
  581. >>> A.vstack(B)
  582. DomainMatrix([[1, 2], [3, 4], [5, 6], [7, 8]], (4, 2), ZZ)
  583. >>> C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ)
  584. >>> A.vstack(B, C)
  585. DomainMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], (6, 2), ZZ)
  586. See Also
  587. ========
  588. unify
  589. """
  590. A, *B = A.unify(*B, fmt='dense')
  591. return DomainMatrix.from_rep(A.rep.vstack(*(Bk.rep for Bk in B)))
  592. def applyfunc(self, func, domain=None):
  593. if domain is None:
  594. domain = self.domain
  595. return self.from_rep(self.rep.applyfunc(func, domain))
  596. def __add__(A, B):
  597. if not isinstance(B, DomainMatrix):
  598. return NotImplemented
  599. A, B = A.unify(B, fmt='dense')
  600. return A.add(B)
  601. def __sub__(A, B):
  602. if not isinstance(B, DomainMatrix):
  603. return NotImplemented
  604. A, B = A.unify(B, fmt='dense')
  605. return A.sub(B)
  606. def __neg__(A):
  607. return A.neg()
  608. def __mul__(A, B):
  609. """A * B"""
  610. if isinstance(B, DomainMatrix):
  611. A, B = A.unify(B, fmt='dense')
  612. return A.matmul(B)
  613. elif B in A.domain:
  614. return A.scalarmul(B)
  615. elif isinstance(B, DomainScalar):
  616. A, B = A.unify(B)
  617. return A.scalarmul(B.element)
  618. else:
  619. return NotImplemented
  620. def __rmul__(A, B):
  621. if B in A.domain:
  622. return A.rscalarmul(B)
  623. elif isinstance(B, DomainScalar):
  624. A, B = A.unify(B)
  625. return A.rscalarmul(B.element)
  626. else:
  627. return NotImplemented
  628. def __pow__(A, n):
  629. """A ** n"""
  630. if not isinstance(n, int):
  631. return NotImplemented
  632. return A.pow(n)
  633. def _check(a, op, b, ashape, bshape):
  634. if a.domain != b.domain:
  635. msg = "Domain mismatch: %s %s %s" % (a.domain, op, b.domain)
  636. raise DMDomainError(msg)
  637. if ashape != bshape:
  638. msg = "Shape mismatch: %s %s %s" % (a.shape, op, b.shape)
  639. raise DMShapeError(msg)
  640. if a.rep.fmt != b.rep.fmt:
  641. msg = "Format mismatch: %s %s %s" % (a.rep.fmt, op, b.rep.fmt)
  642. raise DMFormatError(msg)
  643. def add(A, B):
  644. r"""
  645. Adds two DomainMatrix matrices of the same Domain
  646. Parameters
  647. ==========
  648. A, B: DomainMatrix
  649. matrices to add
  650. Returns
  651. =======
  652. DomainMatrix
  653. DomainMatrix after Addition
  654. Raises
  655. ======
  656. DMShapeError
  657. If the dimensions of the two DomainMatrix are not equal
  658. ValueError
  659. If the domain of the two DomainMatrix are not same
  660. Examples
  661. ========
  662. >>> from sympy import ZZ
  663. >>> from sympy.polys.matrices import DomainMatrix
  664. >>> A = DomainMatrix([
  665. ... [ZZ(1), ZZ(2)],
  666. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  667. >>> B = DomainMatrix([
  668. ... [ZZ(4), ZZ(3)],
  669. ... [ZZ(2), ZZ(1)]], (2, 2), ZZ)
  670. >>> A.add(B)
  671. DomainMatrix([[5, 5], [5, 5]], (2, 2), ZZ)
  672. See Also
  673. ========
  674. sub, matmul
  675. """
  676. A._check('+', B, A.shape, B.shape)
  677. return A.from_rep(A.rep.add(B.rep))
  678. def sub(A, B):
  679. r"""
  680. Subtracts two DomainMatrix matrices of the same Domain
  681. Parameters
  682. ==========
  683. A, B: DomainMatrix
  684. matrices to substract
  685. Returns
  686. =======
  687. DomainMatrix
  688. DomainMatrix after Substraction
  689. Raises
  690. ======
  691. DMShapeError
  692. If the dimensions of the two DomainMatrix are not equal
  693. ValueError
  694. If the domain of the two DomainMatrix are not same
  695. Examples
  696. ========
  697. >>> from sympy import ZZ
  698. >>> from sympy.polys.matrices import DomainMatrix
  699. >>> A = DomainMatrix([
  700. ... [ZZ(1), ZZ(2)],
  701. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  702. >>> B = DomainMatrix([
  703. ... [ZZ(4), ZZ(3)],
  704. ... [ZZ(2), ZZ(1)]], (2, 2), ZZ)
  705. >>> A.sub(B)
  706. DomainMatrix([[-3, -1], [1, 3]], (2, 2), ZZ)
  707. See Also
  708. ========
  709. add, matmul
  710. """
  711. A._check('-', B, A.shape, B.shape)
  712. return A.from_rep(A.rep.sub(B.rep))
  713. def neg(A):
  714. r"""
  715. Returns the negative of DomainMatrix
  716. Parameters
  717. ==========
  718. A : Represents a DomainMatrix
  719. Returns
  720. =======
  721. DomainMatrix
  722. DomainMatrix after Negation
  723. Examples
  724. ========
  725. >>> from sympy import ZZ
  726. >>> from sympy.polys.matrices import DomainMatrix
  727. >>> A = DomainMatrix([
  728. ... [ZZ(1), ZZ(2)],
  729. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  730. >>> A.neg()
  731. DomainMatrix([[-1, -2], [-3, -4]], (2, 2), ZZ)
  732. """
  733. return A.from_rep(A.rep.neg())
  734. def mul(A, b):
  735. r"""
  736. Performs term by term multiplication for the second DomainMatrix
  737. w.r.t first DomainMatrix. Returns a DomainMatrix whose rows are
  738. list of DomainMatrix matrices created after term by term multiplication.
  739. Parameters
  740. ==========
  741. A, B: DomainMatrix
  742. matrices to multiply term-wise
  743. Returns
  744. =======
  745. DomainMatrix
  746. DomainMatrix after term by term multiplication
  747. Examples
  748. ========
  749. >>> from sympy import ZZ
  750. >>> from sympy.polys.matrices import DomainMatrix
  751. >>> A = DomainMatrix([
  752. ... [ZZ(1), ZZ(2)],
  753. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  754. >>> B = DomainMatrix([
  755. ... [ZZ(1), ZZ(1)],
  756. ... [ZZ(0), ZZ(1)]], (2, 2), ZZ)
  757. >>> A.mul(B)
  758. DomainMatrix([[DomainMatrix([[1, 1], [0, 1]], (2, 2), ZZ),
  759. DomainMatrix([[2, 2], [0, 2]], (2, 2), ZZ)],
  760. [DomainMatrix([[3, 3], [0, 3]], (2, 2), ZZ),
  761. DomainMatrix([[4, 4], [0, 4]], (2, 2), ZZ)]], (2, 2), ZZ)
  762. See Also
  763. ========
  764. matmul
  765. """
  766. return A.from_rep(A.rep.mul(b))
  767. def rmul(A, b):
  768. return A.from_rep(A.rep.rmul(b))
  769. def matmul(A, B):
  770. r"""
  771. Performs matrix multiplication of two DomainMatrix matrices
  772. Parameters
  773. ==========
  774. A, B: DomainMatrix
  775. to multiply
  776. Returns
  777. =======
  778. DomainMatrix
  779. DomainMatrix after multiplication
  780. Examples
  781. ========
  782. >>> from sympy import ZZ
  783. >>> from sympy.polys.matrices import DomainMatrix
  784. >>> A = DomainMatrix([
  785. ... [ZZ(1), ZZ(2)],
  786. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  787. >>> B = DomainMatrix([
  788. ... [ZZ(1), ZZ(1)],
  789. ... [ZZ(0), ZZ(1)]], (2, 2), ZZ)
  790. >>> A.matmul(B)
  791. DomainMatrix([[1, 3], [3, 7]], (2, 2), ZZ)
  792. See Also
  793. ========
  794. mul, pow, add, sub
  795. """
  796. A._check('*', B, A.shape[1], B.shape[0])
  797. return A.from_rep(A.rep.matmul(B.rep))
  798. def _scalarmul(A, lamda, reverse):
  799. if lamda == A.domain.zero:
  800. return DomainMatrix.zeros(A.shape, A.domain)
  801. elif lamda == A.domain.one:
  802. return A.copy()
  803. elif reverse:
  804. return A.rmul(lamda)
  805. else:
  806. return A.mul(lamda)
  807. def scalarmul(A, lamda):
  808. return A._scalarmul(lamda, reverse=False)
  809. def rscalarmul(A, lamda):
  810. return A._scalarmul(lamda, reverse=True)
  811. def mul_elementwise(A, B):
  812. assert A.domain == B.domain
  813. return A.from_rep(A.rep.mul_elementwise(B.rep))
  814. def __truediv__(A, lamda):
  815. """ Method for Scalar Divison"""
  816. if isinstance(lamda, int) or ZZ.of_type(lamda):
  817. lamda = DomainScalar(ZZ(lamda), ZZ)
  818. if not isinstance(lamda, DomainScalar):
  819. return NotImplemented
  820. A, lamda = A.to_field().unify(lamda)
  821. if lamda.element == lamda.domain.zero:
  822. raise ZeroDivisionError
  823. if lamda.element == lamda.domain.one:
  824. return A.to_field()
  825. return A.mul(1 / lamda.element)
  826. def pow(A, n):
  827. r"""
  828. Computes A**n
  829. Parameters
  830. ==========
  831. A : DomainMatrix
  832. n : exponent for A
  833. Returns
  834. =======
  835. DomainMatrix
  836. DomainMatrix on computing A**n
  837. Raises
  838. ======
  839. NotImplementedError
  840. if n is negative.
  841. Examples
  842. ========
  843. >>> from sympy import ZZ
  844. >>> from sympy.polys.matrices import DomainMatrix
  845. >>> A = DomainMatrix([
  846. ... [ZZ(1), ZZ(1)],
  847. ... [ZZ(0), ZZ(1)]], (2, 2), ZZ)
  848. >>> A.pow(2)
  849. DomainMatrix([[1, 2], [0, 1]], (2, 2), ZZ)
  850. See Also
  851. ========
  852. matmul
  853. """
  854. nrows, ncols = A.shape
  855. if nrows != ncols:
  856. raise DMNonSquareMatrixError('Power of a nonsquare matrix')
  857. if n < 0:
  858. raise NotImplementedError('Negative powers')
  859. elif n == 0:
  860. return A.eye(nrows, A.domain)
  861. elif n == 1:
  862. return A
  863. elif n % 2 == 1:
  864. return A * A**(n - 1)
  865. else:
  866. sqrtAn = A ** (n // 2)
  867. return sqrtAn * sqrtAn
  868. def scc(self):
  869. """Compute the strongly connected components of a DomainMatrix
  870. Explanation
  871. ===========
  872. A square matrix can be considered as the adjacency matrix for a
  873. directed graph where the row and column indices are the vertices. In
  874. this graph if there is an edge from vertex ``i`` to vertex ``j`` if
  875. ``M[i, j]`` is nonzero. This routine computes the strongly connected
  876. components of that graph which are subsets of the rows and columns that
  877. are connected by some nonzero element of the matrix. The strongly
  878. connected components are useful because many operations such as the
  879. determinant can be computed by working with the submatrices
  880. corresponding to each component.
  881. Examples
  882. ========
  883. Find the strongly connected components of a matrix:
  884. >>> from sympy import ZZ
  885. >>> from sympy.polys.matrices import DomainMatrix
  886. >>> M = DomainMatrix([[ZZ(1), ZZ(0), ZZ(2)],
  887. ... [ZZ(0), ZZ(3), ZZ(0)],
  888. ... [ZZ(4), ZZ(6), ZZ(5)]], (3, 3), ZZ)
  889. >>> M.scc()
  890. [[1], [0, 2]]
  891. Compute the determinant from the components:
  892. >>> MM = M.to_Matrix()
  893. >>> MM
  894. Matrix([
  895. [1, 0, 2],
  896. [0, 3, 0],
  897. [4, 6, 5]])
  898. >>> MM[[1], [1]]
  899. Matrix([[3]])
  900. >>> MM[[0, 2], [0, 2]]
  901. Matrix([
  902. [1, 2],
  903. [4, 5]])
  904. >>> MM.det()
  905. -9
  906. >>> MM[[1], [1]].det() * MM[[0, 2], [0, 2]].det()
  907. -9
  908. The components are given in reverse topological order and represent a
  909. permutation of the rows and columns that will bring the matrix into
  910. block lower-triangular form:
  911. >>> MM[[1, 0, 2], [1, 0, 2]]
  912. Matrix([
  913. [3, 0, 0],
  914. [0, 1, 2],
  915. [6, 4, 5]])
  916. Returns
  917. =======
  918. List of lists of integers
  919. Each list represents a strongly connected component.
  920. See also
  921. ========
  922. sympy.matrices.matrices.MatrixBase.strongly_connected_components
  923. sympy.utilities.iterables.strongly_connected_components
  924. """
  925. rows, cols = self.shape
  926. assert rows == cols
  927. return self.rep.scc()
  928. def rref(self):
  929. r"""
  930. Returns reduced-row echelon form and list of pivots for the DomainMatrix
  931. Returns
  932. =======
  933. (DomainMatrix, list)
  934. reduced-row echelon form and list of pivots for the DomainMatrix
  935. Raises
  936. ======
  937. ValueError
  938. If the domain of DomainMatrix not a Field
  939. Examples
  940. ========
  941. >>> from sympy import QQ
  942. >>> from sympy.polys.matrices import DomainMatrix
  943. >>> A = DomainMatrix([
  944. ... [QQ(2), QQ(-1), QQ(0)],
  945. ... [QQ(-1), QQ(2), QQ(-1)],
  946. ... [QQ(0), QQ(0), QQ(2)]], (3, 3), QQ)
  947. >>> rref_matrix, rref_pivots = A.rref()
  948. >>> rref_matrix
  949. DomainMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]], (3, 3), QQ)
  950. >>> rref_pivots
  951. (0, 1, 2)
  952. See Also
  953. ========
  954. convert_to, lu
  955. """
  956. if not self.domain.is_Field:
  957. raise DMNotAField('Not a field')
  958. rref_ddm, pivots = self.rep.rref()
  959. return self.from_rep(rref_ddm), tuple(pivots)
  960. def columnspace(self):
  961. r"""
  962. Returns the columnspace for the DomainMatrix
  963. Returns
  964. =======
  965. DomainMatrix
  966. The columns of this matrix form a basis for the columnspace.
  967. Examples
  968. ========
  969. >>> from sympy import QQ
  970. >>> from sympy.polys.matrices import DomainMatrix
  971. >>> A = DomainMatrix([
  972. ... [QQ(1), QQ(-1)],
  973. ... [QQ(2), QQ(-2)]], (2, 2), QQ)
  974. >>> A.columnspace()
  975. DomainMatrix([[1], [2]], (2, 1), QQ)
  976. """
  977. if not self.domain.is_Field:
  978. raise DMNotAField('Not a field')
  979. rref, pivots = self.rref()
  980. rows, cols = self.shape
  981. return self.extract(range(rows), pivots)
  982. def rowspace(self):
  983. r"""
  984. Returns the rowspace for the DomainMatrix
  985. Returns
  986. =======
  987. DomainMatrix
  988. The rows of this matrix form a basis for the rowspace.
  989. Examples
  990. ========
  991. >>> from sympy import QQ
  992. >>> from sympy.polys.matrices import DomainMatrix
  993. >>> A = DomainMatrix([
  994. ... [QQ(1), QQ(-1)],
  995. ... [QQ(2), QQ(-2)]], (2, 2), QQ)
  996. >>> A.rowspace()
  997. DomainMatrix([[1, -1]], (1, 2), QQ)
  998. """
  999. if not self.domain.is_Field:
  1000. raise DMNotAField('Not a field')
  1001. rref, pivots = self.rref()
  1002. rows, cols = self.shape
  1003. return self.extract(range(len(pivots)), range(cols))
  1004. def nullspace(self):
  1005. r"""
  1006. Returns the nullspace for the DomainMatrix
  1007. Returns
  1008. =======
  1009. DomainMatrix
  1010. The rows of this matrix form a basis for the nullspace.
  1011. Examples
  1012. ========
  1013. >>> from sympy import QQ
  1014. >>> from sympy.polys.matrices import DomainMatrix
  1015. >>> A = DomainMatrix([
  1016. ... [QQ(1), QQ(-1)],
  1017. ... [QQ(2), QQ(-2)]], (2, 2), QQ)
  1018. >>> A.nullspace()
  1019. DomainMatrix([[1, 1]], (1, 2), QQ)
  1020. """
  1021. if not self.domain.is_Field:
  1022. raise DMNotAField('Not a field')
  1023. return self.from_rep(self.rep.nullspace()[0])
  1024. def inv(self):
  1025. r"""
  1026. Finds the inverse of the DomainMatrix if exists
  1027. Returns
  1028. =======
  1029. DomainMatrix
  1030. DomainMatrix after inverse
  1031. Raises
  1032. ======
  1033. ValueError
  1034. If the domain of DomainMatrix not a Field
  1035. DMNonSquareMatrixError
  1036. If the DomainMatrix is not a not Square DomainMatrix
  1037. Examples
  1038. ========
  1039. >>> from sympy import QQ
  1040. >>> from sympy.polys.matrices import DomainMatrix
  1041. >>> A = DomainMatrix([
  1042. ... [QQ(2), QQ(-1), QQ(0)],
  1043. ... [QQ(-1), QQ(2), QQ(-1)],
  1044. ... [QQ(0), QQ(0), QQ(2)]], (3, 3), QQ)
  1045. >>> A.inv()
  1046. DomainMatrix([[2/3, 1/3, 1/6], [1/3, 2/3, 1/3], [0, 0, 1/2]], (3, 3), QQ)
  1047. See Also
  1048. ========
  1049. neg
  1050. """
  1051. if not self.domain.is_Field:
  1052. raise DMNotAField('Not a field')
  1053. m, n = self.shape
  1054. if m != n:
  1055. raise DMNonSquareMatrixError
  1056. inv = self.rep.inv()
  1057. return self.from_rep(inv)
  1058. def det(self):
  1059. r"""
  1060. Returns the determinant of a Square DomainMatrix
  1061. Returns
  1062. =======
  1063. S.Complexes
  1064. determinant of Square DomainMatrix
  1065. Raises
  1066. ======
  1067. ValueError
  1068. If the domain of DomainMatrix not a Field
  1069. Examples
  1070. ========
  1071. >>> from sympy import ZZ
  1072. >>> from sympy.polys.matrices import DomainMatrix
  1073. >>> A = DomainMatrix([
  1074. ... [ZZ(1), ZZ(2)],
  1075. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1076. >>> A.det()
  1077. -2
  1078. """
  1079. m, n = self.shape
  1080. if m != n:
  1081. raise DMNonSquareMatrixError
  1082. return self.rep.det()
  1083. def lu(self):
  1084. r"""
  1085. Returns Lower and Upper decomposition of the DomainMatrix
  1086. Returns
  1087. =======
  1088. (L, U, exchange)
  1089. L, U are Lower and Upper decomposition of the DomainMatrix,
  1090. exchange is the list of indices of rows exchanged in the decomposition.
  1091. Raises
  1092. ======
  1093. ValueError
  1094. If the domain of DomainMatrix not a Field
  1095. Examples
  1096. ========
  1097. >>> from sympy import QQ
  1098. >>> from sympy.polys.matrices import DomainMatrix
  1099. >>> A = DomainMatrix([
  1100. ... [QQ(1), QQ(-1)],
  1101. ... [QQ(2), QQ(-2)]], (2, 2), QQ)
  1102. >>> A.lu()
  1103. (DomainMatrix([[1, 0], [2, 1]], (2, 2), QQ), DomainMatrix([[1, -1], [0, 0]], (2, 2), QQ), [])
  1104. See Also
  1105. ========
  1106. lu_solve
  1107. """
  1108. if not self.domain.is_Field:
  1109. raise DMNotAField('Not a field')
  1110. L, U, swaps = self.rep.lu()
  1111. return self.from_rep(L), self.from_rep(U), swaps
  1112. def lu_solve(self, rhs):
  1113. r"""
  1114. Solver for DomainMatrix x in the A*x = B
  1115. Parameters
  1116. ==========
  1117. rhs : DomainMatrix B
  1118. Returns
  1119. =======
  1120. DomainMatrix
  1121. x in A*x = B
  1122. Raises
  1123. ======
  1124. DMShapeError
  1125. If the DomainMatrix A and rhs have different number of rows
  1126. ValueError
  1127. If the domain of DomainMatrix A not a Field
  1128. Examples
  1129. ========
  1130. >>> from sympy import QQ
  1131. >>> from sympy.polys.matrices import DomainMatrix
  1132. >>> A = DomainMatrix([
  1133. ... [QQ(1), QQ(2)],
  1134. ... [QQ(3), QQ(4)]], (2, 2), QQ)
  1135. >>> B = DomainMatrix([
  1136. ... [QQ(1), QQ(1)],
  1137. ... [QQ(0), QQ(1)]], (2, 2), QQ)
  1138. >>> A.lu_solve(B)
  1139. DomainMatrix([[-2, -1], [3/2, 1]], (2, 2), QQ)
  1140. See Also
  1141. ========
  1142. lu
  1143. """
  1144. if self.shape[0] != rhs.shape[0]:
  1145. raise DMShapeError("Shape")
  1146. if not self.domain.is_Field:
  1147. raise DMNotAField('Not a field')
  1148. sol = self.rep.lu_solve(rhs.rep)
  1149. return self.from_rep(sol)
  1150. def _solve(A, b):
  1151. # XXX: Not sure about this method or its signature. It is just created
  1152. # because it is needed by the holonomic module.
  1153. if A.shape[0] != b.shape[0]:
  1154. raise DMShapeError("Shape")
  1155. if A.domain != b.domain or not A.domain.is_Field:
  1156. raise DMNotAField('Not a field')
  1157. Aaug = A.hstack(b)
  1158. Arref, pivots = Aaug.rref()
  1159. particular = Arref.from_rep(Arref.rep.particular())
  1160. nullspace_rep, nonpivots = Arref[:,:-1].rep.nullspace()
  1161. nullspace = Arref.from_rep(nullspace_rep)
  1162. return particular, nullspace
  1163. def charpoly(self):
  1164. r"""
  1165. Returns the coefficients of the characteristic polynomial
  1166. of the DomainMatrix. These elements will be domain elements.
  1167. The domain of the elements will be same as domain of the DomainMatrix.
  1168. Returns
  1169. =======
  1170. list
  1171. coefficients of the characteristic polynomial
  1172. Raises
  1173. ======
  1174. DMNonSquareMatrixError
  1175. If the DomainMatrix is not a not Square DomainMatrix
  1176. Examples
  1177. ========
  1178. >>> from sympy import ZZ
  1179. >>> from sympy.polys.matrices import DomainMatrix
  1180. >>> A = DomainMatrix([
  1181. ... [ZZ(1), ZZ(2)],
  1182. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1183. >>> A.charpoly()
  1184. [1, -5, -2]
  1185. """
  1186. m, n = self.shape
  1187. if m != n:
  1188. raise DMNonSquareMatrixError("not square")
  1189. return self.rep.charpoly()
  1190. @classmethod
  1191. def eye(cls, shape, domain):
  1192. r"""
  1193. Return identity matrix of size n
  1194. Examples
  1195. ========
  1196. >>> from sympy.polys.matrices import DomainMatrix
  1197. >>> from sympy import QQ
  1198. >>> DomainMatrix.eye(3, QQ)
  1199. DomainMatrix({0: {0: 1}, 1: {1: 1}, 2: {2: 1}}, (3, 3), QQ)
  1200. """
  1201. if isinstance(shape, int):
  1202. shape = (shape, shape)
  1203. return cls.from_rep(SDM.eye(shape, domain))
  1204. @classmethod
  1205. def diag(cls, diagonal, domain, shape=None):
  1206. r"""
  1207. Return diagonal matrix with entries from ``diagonal``.
  1208. Examples
  1209. ========
  1210. >>> from sympy.polys.matrices import DomainMatrix
  1211. >>> from sympy import ZZ
  1212. >>> DomainMatrix.diag([ZZ(5), ZZ(6)], ZZ)
  1213. DomainMatrix({0: {0: 5}, 1: {1: 6}}, (2, 2), ZZ)
  1214. """
  1215. if shape is None:
  1216. N = len(diagonal)
  1217. shape = (N, N)
  1218. return cls.from_rep(SDM.diag(diagonal, domain, shape))
  1219. @classmethod
  1220. def zeros(cls, shape, domain, *, fmt='sparse'):
  1221. """Returns a zero DomainMatrix of size shape, belonging to the specified domain
  1222. Examples
  1223. ========
  1224. >>> from sympy.polys.matrices import DomainMatrix
  1225. >>> from sympy import QQ
  1226. >>> DomainMatrix.zeros((2, 3), QQ)
  1227. DomainMatrix({}, (2, 3), QQ)
  1228. """
  1229. return cls.from_rep(SDM.zeros(shape, domain))
  1230. @classmethod
  1231. def ones(cls, shape, domain):
  1232. """Returns a DomainMatrix of 1s, of size shape, belonging to the specified domain
  1233. Examples
  1234. ========
  1235. >>> from sympy.polys.matrices import DomainMatrix
  1236. >>> from sympy import QQ
  1237. >>> DomainMatrix.ones((2,3), QQ)
  1238. DomainMatrix([[1, 1, 1], [1, 1, 1]], (2, 3), QQ)
  1239. """
  1240. return cls.from_rep(DDM.ones(shape, domain))
  1241. def __eq__(A, B):
  1242. r"""
  1243. Checks for two DomainMatrix matrices to be equal or not
  1244. Parameters
  1245. ==========
  1246. A, B: DomainMatrix
  1247. to check equality
  1248. Returns
  1249. =======
  1250. Boolean
  1251. True for equal, else False
  1252. Raises
  1253. ======
  1254. NotImplementedError
  1255. If B is not a DomainMatrix
  1256. Examples
  1257. ========
  1258. >>> from sympy import ZZ
  1259. >>> from sympy.polys.matrices import DomainMatrix
  1260. >>> A = DomainMatrix([
  1261. ... [ZZ(1), ZZ(2)],
  1262. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1263. >>> B = DomainMatrix([
  1264. ... [ZZ(1), ZZ(1)],
  1265. ... [ZZ(0), ZZ(1)]], (2, 2), ZZ)
  1266. >>> A.__eq__(A)
  1267. True
  1268. >>> A.__eq__(B)
  1269. False
  1270. """
  1271. if not isinstance(A, type(B)):
  1272. return NotImplemented
  1273. return A.domain == B.domain and A.rep == B.rep
  1274. def unify_eq(A, B):
  1275. if A.shape != B.shape:
  1276. return False
  1277. if A.domain != B.domain:
  1278. A, B = A.unify(B)
  1279. return A == B