domainmatrix.py 113 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983
  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 __future__ import annotations
  10. from collections import Counter
  11. from functools import reduce
  12. from sympy.external.gmpy import GROUND_TYPES
  13. from sympy.utilities.decorator import doctest_depends_on
  14. from sympy.core.sympify import _sympify
  15. from ..domains import Domain
  16. from ..constructor import construct_domain
  17. from .exceptions import (
  18. DMFormatError,
  19. DMBadInputError,
  20. DMShapeError,
  21. DMDomainError,
  22. DMNotAField,
  23. DMNonSquareMatrixError,
  24. DMNonInvertibleMatrixError
  25. )
  26. from .domainscalar import DomainScalar
  27. from sympy.polys.domains import ZZ, EXRAW, QQ
  28. from sympy.polys.densearith import dup_mul
  29. from sympy.polys.densebasic import dup_convert
  30. from sympy.polys.densetools import (
  31. dup_mul_ground,
  32. dup_quo_ground,
  33. dup_content,
  34. dup_clear_denoms,
  35. dup_primitive,
  36. dup_transform,
  37. )
  38. from sympy.polys.factortools import dup_factor_list
  39. from sympy.polys.polyutils import _sort_factors
  40. from .ddm import DDM
  41. from .sdm import SDM
  42. from .dfm import DFM
  43. from .rref import _dm_rref, _dm_rref_den
  44. if GROUND_TYPES != 'flint':
  45. __doctest_skip__ = ['DomainMatrix.to_dfm', 'DomainMatrix.to_dfm_or_ddm']
  46. else:
  47. __doctest_skip__ = ['DomainMatrix.from_list']
  48. def DM(rows, domain):
  49. """Convenient alias for DomainMatrix.from_list
  50. Examples
  51. ========
  52. >>> from sympy import ZZ
  53. >>> from sympy.polys.matrices import DM
  54. >>> DM([[1, 2], [3, 4]], ZZ)
  55. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  56. See Also
  57. ========
  58. DomainMatrix.from_list
  59. """
  60. return DomainMatrix.from_list(rows, domain)
  61. class DomainMatrix:
  62. r"""
  63. Associate Matrix with :py:class:`~.Domain`
  64. Explanation
  65. ===========
  66. DomainMatrix uses :py:class:`~.Domain` for its internal representation
  67. which makes it faster than the SymPy Matrix class (currently) for many
  68. common operations, but this advantage makes it not entirely compatible
  69. with Matrix. DomainMatrix are analogous to numpy arrays with "dtype".
  70. In the DomainMatrix, each element has a domain such as :ref:`ZZ`
  71. or :ref:`QQ(a)`.
  72. Examples
  73. ========
  74. Creating a DomainMatrix from the existing Matrix class:
  75. >>> from sympy import Matrix
  76. >>> from sympy.polys.matrices import DomainMatrix
  77. >>> Matrix1 = Matrix([
  78. ... [1, 2],
  79. ... [3, 4]])
  80. >>> A = DomainMatrix.from_Matrix(Matrix1)
  81. >>> A
  82. DomainMatrix({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ)
  83. Directly forming a DomainMatrix:
  84. >>> from sympy import ZZ
  85. >>> from sympy.polys.matrices import DomainMatrix
  86. >>> A = DomainMatrix([
  87. ... [ZZ(1), ZZ(2)],
  88. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  89. >>> A
  90. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  91. See Also
  92. ========
  93. DDM
  94. SDM
  95. Domain
  96. Poly
  97. """
  98. rep: SDM | DDM | DFM
  99. shape: tuple[int, int]
  100. domain: Domain
  101. def __new__(cls, rows, shape, domain, *, fmt=None):
  102. """
  103. Creates a :py:class:`~.DomainMatrix`.
  104. Parameters
  105. ==========
  106. rows : Represents elements of DomainMatrix as list of lists
  107. shape : Represents dimension of DomainMatrix
  108. domain : Represents :py:class:`~.Domain` of DomainMatrix
  109. Raises
  110. ======
  111. TypeError
  112. If any of rows, shape and domain are not provided
  113. """
  114. if isinstance(rows, (DDM, SDM, DFM)):
  115. raise TypeError("Use from_rep to initialise from SDM/DDM")
  116. elif isinstance(rows, list):
  117. rep = DDM(rows, shape, domain)
  118. elif isinstance(rows, dict):
  119. rep = SDM(rows, shape, domain)
  120. else:
  121. msg = "Input should be list-of-lists or dict-of-dicts"
  122. raise TypeError(msg)
  123. if fmt is not None:
  124. if fmt == 'sparse':
  125. rep = rep.to_sdm()
  126. elif fmt == 'dense':
  127. rep = rep.to_ddm()
  128. else:
  129. raise ValueError("fmt should be 'sparse' or 'dense'")
  130. # Use python-flint for dense matrices if possible
  131. if rep.fmt == 'dense' and DFM._supports_domain(domain):
  132. rep = rep.to_dfm()
  133. return cls.from_rep(rep)
  134. def __reduce__(self):
  135. rep = self.rep
  136. if rep.fmt == 'dense':
  137. arg = self.to_list()
  138. elif rep.fmt == 'sparse':
  139. arg = dict(rep)
  140. else:
  141. raise RuntimeError # pragma: no cover
  142. args = (arg, rep.shape, rep.domain)
  143. return (self.__class__, args)
  144. def __getitem__(self, key):
  145. i, j = key
  146. m, n = self.shape
  147. if not (isinstance(i, slice) or isinstance(j, slice)):
  148. return DomainScalar(self.rep.getitem(i, j), self.domain)
  149. if not isinstance(i, slice):
  150. if not -m <= i < m:
  151. raise IndexError("Row index out of range")
  152. i = i % m
  153. i = slice(i, i+1)
  154. if not isinstance(j, slice):
  155. if not -n <= j < n:
  156. raise IndexError("Column index out of range")
  157. j = j % n
  158. j = slice(j, j+1)
  159. return self.from_rep(self.rep.extract_slice(i, j))
  160. def getitem_sympy(self, i, j):
  161. return self.domain.to_sympy(self.rep.getitem(i, j))
  162. def extract(self, rowslist, colslist):
  163. return self.from_rep(self.rep.extract(rowslist, colslist))
  164. def __setitem__(self, key, value):
  165. i, j = key
  166. if not self.domain.of_type(value):
  167. raise TypeError
  168. if isinstance(i, int) and isinstance(j, int):
  169. self.rep.setitem(i, j, value)
  170. else:
  171. raise NotImplementedError
  172. @classmethod
  173. def from_rep(cls, rep):
  174. """Create a new DomainMatrix efficiently from DDM/SDM.
  175. Examples
  176. ========
  177. Create a :py:class:`~.DomainMatrix` with an dense internal
  178. representation as :py:class:`~.DDM`:
  179. >>> from sympy.polys.domains import ZZ
  180. >>> from sympy.polys.matrices import DomainMatrix
  181. >>> from sympy.polys.matrices.ddm import DDM
  182. >>> drep = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  183. >>> dM = DomainMatrix.from_rep(drep)
  184. >>> dM
  185. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  186. Create a :py:class:`~.DomainMatrix` with a sparse internal
  187. representation as :py:class:`~.SDM`:
  188. >>> from sympy.polys.matrices import DomainMatrix
  189. >>> from sympy.polys.matrices.sdm import SDM
  190. >>> from sympy import ZZ
  191. >>> drep = SDM({0:{1:ZZ(1)},1:{0:ZZ(2)}}, (2, 2), ZZ)
  192. >>> dM = DomainMatrix.from_rep(drep)
  193. >>> dM
  194. DomainMatrix({0: {1: 1}, 1: {0: 2}}, (2, 2), ZZ)
  195. Parameters
  196. ==========
  197. rep: SDM or DDM
  198. The internal sparse or dense representation of the matrix.
  199. Returns
  200. =======
  201. DomainMatrix
  202. A :py:class:`~.DomainMatrix` wrapping *rep*.
  203. Notes
  204. =====
  205. This takes ownership of rep as its internal representation. If rep is
  206. being mutated elsewhere then a copy should be provided to
  207. ``from_rep``. Only minimal verification or checking is done on *rep*
  208. as this is supposed to be an efficient internal routine.
  209. """
  210. if not (isinstance(rep, (DDM, SDM)) or (DFM is not None and isinstance(rep, DFM))):
  211. raise TypeError("rep should be of type DDM or SDM")
  212. self = super().__new__(cls)
  213. self.rep = rep
  214. self.shape = rep.shape
  215. self.domain = rep.domain
  216. return self
  217. @classmethod
  218. @doctest_depends_on(ground_types=['python', 'gmpy'])
  219. def from_list(cls, rows, domain):
  220. r"""
  221. Convert a list of lists into a DomainMatrix
  222. Parameters
  223. ==========
  224. rows: list of lists
  225. Each element of the inner lists should be either the single arg,
  226. or tuple of args, that would be passed to the domain constructor
  227. in order to form an element of the domain. See examples.
  228. Returns
  229. =======
  230. DomainMatrix containing elements defined in rows
  231. Examples
  232. ========
  233. >>> from sympy.polys.matrices import DomainMatrix
  234. >>> from sympy import FF, QQ, ZZ
  235. >>> A = DomainMatrix.from_list([[1, 0, 1], [0, 0, 1]], ZZ)
  236. >>> A
  237. DomainMatrix([[1, 0, 1], [0, 0, 1]], (2, 3), ZZ)
  238. >>> B = DomainMatrix.from_list([[1, 0, 1], [0, 0, 1]], FF(7))
  239. >>> B
  240. DomainMatrix([[1 mod 7, 0 mod 7, 1 mod 7], [0 mod 7, 0 mod 7, 1 mod 7]], (2, 3), GF(7))
  241. >>> C = DomainMatrix.from_list([[(1, 2), (3, 1)], [(1, 4), (5, 1)]], QQ)
  242. >>> C
  243. DomainMatrix([[1/2, 3], [1/4, 5]], (2, 2), QQ)
  244. See Also
  245. ========
  246. from_list_sympy
  247. """
  248. nrows = len(rows)
  249. ncols = 0 if not nrows else len(rows[0])
  250. conv = lambda e: domain(*e) if isinstance(e, tuple) else domain(e)
  251. domain_rows = [[conv(e) for e in row] for row in rows]
  252. return DomainMatrix(domain_rows, (nrows, ncols), domain)
  253. @classmethod
  254. def from_list_sympy(cls, nrows, ncols, rows, **kwargs):
  255. r"""
  256. Convert a list of lists of Expr into a DomainMatrix using construct_domain
  257. Parameters
  258. ==========
  259. nrows: number of rows
  260. ncols: number of columns
  261. rows: list of lists
  262. Returns
  263. =======
  264. DomainMatrix containing elements of rows
  265. Examples
  266. ========
  267. >>> from sympy.polys.matrices import DomainMatrix
  268. >>> from sympy.abc import x, y, z
  269. >>> A = DomainMatrix.from_list_sympy(1, 3, [[x, y, z]])
  270. >>> A
  271. DomainMatrix([[x, y, z]], (1, 3), ZZ[x,y,z])
  272. See Also
  273. ========
  274. sympy.polys.constructor.construct_domain, from_dict_sympy
  275. """
  276. assert len(rows) == nrows
  277. assert all(len(row) == ncols for row in rows)
  278. items_sympy = [_sympify(item) for row in rows for item in row]
  279. domain, items_domain = cls.get_domain(items_sympy, **kwargs)
  280. domain_rows = [[items_domain[ncols*r + c] for c in range(ncols)] for r in range(nrows)]
  281. return DomainMatrix(domain_rows, (nrows, ncols), domain)
  282. @classmethod
  283. def from_dict_sympy(cls, nrows, ncols, elemsdict, **kwargs):
  284. """
  285. Parameters
  286. ==========
  287. nrows: number of rows
  288. ncols: number of cols
  289. elemsdict: dict of dicts containing non-zero elements of the DomainMatrix
  290. Returns
  291. =======
  292. DomainMatrix containing elements of elemsdict
  293. Examples
  294. ========
  295. >>> from sympy.polys.matrices import DomainMatrix
  296. >>> from sympy.abc import x,y,z
  297. >>> elemsdict = {0: {0:x}, 1:{1: y}, 2: {2: z}}
  298. >>> A = DomainMatrix.from_dict_sympy(3, 3, elemsdict)
  299. >>> A
  300. DomainMatrix({0: {0: x}, 1: {1: y}, 2: {2: z}}, (3, 3), ZZ[x,y,z])
  301. See Also
  302. ========
  303. from_list_sympy
  304. """
  305. if not all(0 <= r < nrows for r in elemsdict):
  306. raise DMBadInputError("Row out of range")
  307. if not all(0 <= c < ncols for row in elemsdict.values() for c in row):
  308. raise DMBadInputError("Column out of range")
  309. items_sympy = [_sympify(item) for row in elemsdict.values() for item in row.values()]
  310. domain, items_domain = cls.get_domain(items_sympy, **kwargs)
  311. idx = 0
  312. items_dict = {}
  313. for i, row in elemsdict.items():
  314. items_dict[i] = {}
  315. for j in row:
  316. items_dict[i][j] = items_domain[idx]
  317. idx += 1
  318. return DomainMatrix(items_dict, (nrows, ncols), domain)
  319. @classmethod
  320. def from_Matrix(cls, M, fmt='sparse',**kwargs):
  321. r"""
  322. Convert Matrix to DomainMatrix
  323. Parameters
  324. ==========
  325. M: Matrix
  326. Returns
  327. =======
  328. Returns DomainMatrix with identical elements as M
  329. Examples
  330. ========
  331. >>> from sympy import Matrix
  332. >>> from sympy.polys.matrices import DomainMatrix
  333. >>> M = Matrix([
  334. ... [1.0, 3.4],
  335. ... [2.4, 1]])
  336. >>> A = DomainMatrix.from_Matrix(M)
  337. >>> A
  338. DomainMatrix({0: {0: 1.0, 1: 3.4}, 1: {0: 2.4, 1: 1.0}}, (2, 2), RR)
  339. We can keep internal representation as ddm using fmt='dense'
  340. >>> from sympy import Matrix, QQ
  341. >>> from sympy.polys.matrices import DomainMatrix
  342. >>> A = DomainMatrix.from_Matrix(Matrix([[QQ(1, 2), QQ(3, 4)], [QQ(0, 1), QQ(0, 1)]]), fmt='dense')
  343. >>> A.rep
  344. [[1/2, 3/4], [0, 0]]
  345. See Also
  346. ========
  347. Matrix
  348. """
  349. if fmt == 'dense':
  350. return cls.from_list_sympy(*M.shape, M.tolist(), **kwargs)
  351. return cls.from_dict_sympy(*M.shape, M.todod(), **kwargs)
  352. @classmethod
  353. def get_domain(cls, items_sympy, **kwargs):
  354. K, items_K = construct_domain(items_sympy, **kwargs)
  355. return K, items_K
  356. def choose_domain(self, **opts):
  357. """Convert to a domain found by :func:`~.construct_domain`.
  358. Examples
  359. ========
  360. >>> from sympy import ZZ
  361. >>> from sympy.polys.matrices import DM
  362. >>> M = DM([[1, 2], [3, 4]], ZZ)
  363. >>> M
  364. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  365. >>> M.choose_domain(field=True)
  366. DomainMatrix([[1, 2], [3, 4]], (2, 2), QQ)
  367. >>> from sympy.abc import x
  368. >>> M = DM([[1, x], [x**2, x**3]], ZZ[x])
  369. >>> M.choose_domain(field=True).domain
  370. ZZ(x)
  371. Keyword arguments are passed to :func:`~.construct_domain`.
  372. See Also
  373. ========
  374. construct_domain
  375. convert_to
  376. """
  377. elements, data = self.to_sympy().to_flat_nz()
  378. dom, elements_dom = construct_domain(elements, **opts)
  379. return self.from_flat_nz(elements_dom, data, dom)
  380. def copy(self):
  381. return self.from_rep(self.rep.copy())
  382. def convert_to(self, K):
  383. r"""
  384. Change the domain of DomainMatrix to desired domain or field
  385. Parameters
  386. ==========
  387. K : Represents the desired domain or field.
  388. Alternatively, ``None`` may be passed, in which case this method
  389. just returns a copy of this DomainMatrix.
  390. Returns
  391. =======
  392. DomainMatrix
  393. DomainMatrix with the desired domain or field
  394. Examples
  395. ========
  396. >>> from sympy import ZZ, ZZ_I
  397. >>> from sympy.polys.matrices import DomainMatrix
  398. >>> A = DomainMatrix([
  399. ... [ZZ(1), ZZ(2)],
  400. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  401. >>> A.convert_to(ZZ_I)
  402. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ_I)
  403. """
  404. if K == self.domain:
  405. return self.copy()
  406. rep = self.rep
  407. # The DFM, DDM and SDM types do not do any implicit conversions so we
  408. # manage switching between DDM and DFM here.
  409. if rep.is_DFM and not DFM._supports_domain(K):
  410. rep_K = rep.to_ddm().convert_to(K)
  411. elif rep.is_DDM and DFM._supports_domain(K):
  412. rep_K = rep.convert_to(K).to_dfm()
  413. else:
  414. rep_K = rep.convert_to(K)
  415. return self.from_rep(rep_K)
  416. def to_sympy(self):
  417. return self.convert_to(EXRAW)
  418. def to_field(self):
  419. r"""
  420. Returns a DomainMatrix with the appropriate field
  421. Returns
  422. =======
  423. DomainMatrix
  424. DomainMatrix with the appropriate field
  425. Examples
  426. ========
  427. >>> from sympy import ZZ
  428. >>> from sympy.polys.matrices import DomainMatrix
  429. >>> A = DomainMatrix([
  430. ... [ZZ(1), ZZ(2)],
  431. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  432. >>> A.to_field()
  433. DomainMatrix([[1, 2], [3, 4]], (2, 2), QQ)
  434. """
  435. K = self.domain.get_field()
  436. return self.convert_to(K)
  437. def to_sparse(self):
  438. """
  439. Return a sparse DomainMatrix representation of *self*.
  440. Examples
  441. ========
  442. >>> from sympy.polys.matrices import DomainMatrix
  443. >>> from sympy import QQ
  444. >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ)
  445. >>> A.rep
  446. [[1, 0], [0, 2]]
  447. >>> B = A.to_sparse()
  448. >>> B.rep
  449. {0: {0: 1}, 1: {1: 2}}
  450. """
  451. if self.rep.fmt == 'sparse':
  452. return self
  453. return self.from_rep(self.rep.to_sdm())
  454. def to_dense(self):
  455. """
  456. Return a dense DomainMatrix representation of *self*.
  457. Examples
  458. ========
  459. >>> from sympy.polys.matrices import DomainMatrix
  460. >>> from sympy import QQ
  461. >>> A = DomainMatrix({0: {0: 1}, 1: {1: 2}}, (2, 2), QQ)
  462. >>> A.rep
  463. {0: {0: 1}, 1: {1: 2}}
  464. >>> B = A.to_dense()
  465. >>> B.rep
  466. [[1, 0], [0, 2]]
  467. """
  468. rep = self.rep
  469. if rep.fmt == 'dense':
  470. return self
  471. return self.from_rep(rep.to_dfm_or_ddm())
  472. def to_ddm(self):
  473. """
  474. Return a :class:`~.DDM` representation of *self*.
  475. Examples
  476. ========
  477. >>> from sympy.polys.matrices import DomainMatrix
  478. >>> from sympy import QQ
  479. >>> A = DomainMatrix({0: {0: 1}, 1: {1: 2}}, (2, 2), QQ)
  480. >>> ddm = A.to_ddm()
  481. >>> ddm
  482. [[1, 0], [0, 2]]
  483. >>> type(ddm)
  484. <class 'sympy.polys.matrices.ddm.DDM'>
  485. See Also
  486. ========
  487. to_sdm
  488. to_dense
  489. sympy.polys.matrices.ddm.DDM.to_sdm
  490. """
  491. return self.rep.to_ddm()
  492. def to_sdm(self):
  493. """
  494. Return a :class:`~.SDM` representation of *self*.
  495. Examples
  496. ========
  497. >>> from sympy.polys.matrices import DomainMatrix
  498. >>> from sympy import QQ
  499. >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ)
  500. >>> sdm = A.to_sdm()
  501. >>> sdm
  502. {0: {0: 1}, 1: {1: 2}}
  503. >>> type(sdm)
  504. <class 'sympy.polys.matrices.sdm.SDM'>
  505. See Also
  506. ========
  507. to_ddm
  508. to_sparse
  509. sympy.polys.matrices.sdm.SDM.to_ddm
  510. """
  511. return self.rep.to_sdm()
  512. @doctest_depends_on(ground_types=['flint'])
  513. def to_dfm(self):
  514. """
  515. Return a :class:`~.DFM` representation of *self*.
  516. Examples
  517. ========
  518. >>> from sympy.polys.matrices import DomainMatrix
  519. >>> from sympy import QQ
  520. >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ)
  521. >>> dfm = A.to_dfm()
  522. >>> dfm
  523. [[1, 0], [0, 2]]
  524. >>> type(dfm)
  525. <class 'sympy.polys.matrices._dfm.DFM'>
  526. See Also
  527. ========
  528. to_ddm
  529. to_dense
  530. DFM
  531. """
  532. return self.rep.to_dfm()
  533. @doctest_depends_on(ground_types=['flint'])
  534. def to_dfm_or_ddm(self):
  535. """
  536. Return a :class:`~.DFM` or :class:`~.DDM` representation of *self*.
  537. Explanation
  538. ===========
  539. The :class:`~.DFM` representation can only be used if the ground types
  540. are ``flint`` and the ground domain is supported by ``python-flint``.
  541. This method will return a :class:`~.DFM` representation if possible,
  542. but will return a :class:`~.DDM` representation otherwise.
  543. Examples
  544. ========
  545. >>> from sympy.polys.matrices import DomainMatrix
  546. >>> from sympy import QQ
  547. >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ)
  548. >>> dfm = A.to_dfm_or_ddm()
  549. >>> dfm
  550. [[1, 0], [0, 2]]
  551. >>> type(dfm) # Depends on the ground domain and ground types
  552. <class 'sympy.polys.matrices._dfm.DFM'>
  553. See Also
  554. ========
  555. to_ddm: Always return a :class:`~.DDM` representation.
  556. to_dfm: Returns a :class:`~.DFM` representation or raise an error.
  557. to_dense: Convert internally to a :class:`~.DFM` or :class:`~.DDM`
  558. DFM: The :class:`~.DFM` dense FLINT matrix representation.
  559. DDM: The Python :class:`~.DDM` dense domain matrix representation.
  560. """
  561. return self.rep.to_dfm_or_ddm()
  562. @classmethod
  563. def _unify_domain(cls, *matrices):
  564. """Convert matrices to a common domain"""
  565. domains = {matrix.domain for matrix in matrices}
  566. if len(domains) == 1:
  567. return matrices
  568. domain = reduce(lambda x, y: x.unify(y), domains)
  569. return tuple(matrix.convert_to(domain) for matrix in matrices)
  570. @classmethod
  571. def _unify_fmt(cls, *matrices, fmt=None):
  572. """Convert matrices to the same format.
  573. If all matrices have the same format, then return unmodified.
  574. Otherwise convert both to the preferred format given as *fmt* which
  575. should be 'dense' or 'sparse'.
  576. """
  577. formats = {matrix.rep.fmt for matrix in matrices}
  578. if len(formats) == 1:
  579. return matrices
  580. if fmt == 'sparse':
  581. return tuple(matrix.to_sparse() for matrix in matrices)
  582. elif fmt == 'dense':
  583. return tuple(matrix.to_dense() for matrix in matrices)
  584. else:
  585. raise ValueError("fmt should be 'sparse' or 'dense'")
  586. def unify(self, *others, fmt=None):
  587. """
  588. Unifies the domains and the format of self and other
  589. matrices.
  590. Parameters
  591. ==========
  592. others : DomainMatrix
  593. fmt: string 'dense', 'sparse' or `None` (default)
  594. The preferred format to convert to if self and other are not
  595. already in the same format. If `None` or not specified then no
  596. conversion if performed.
  597. Returns
  598. =======
  599. Tuple[DomainMatrix]
  600. Matrices with unified domain and format
  601. Examples
  602. ========
  603. Unify the domain of DomainMatrix that have different domains:
  604. >>> from sympy import ZZ, QQ
  605. >>> from sympy.polys.matrices import DomainMatrix
  606. >>> A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  607. >>> B = DomainMatrix([[QQ(1, 2), QQ(2)]], (1, 2), QQ)
  608. >>> Aq, Bq = A.unify(B)
  609. >>> Aq
  610. DomainMatrix([[1, 2]], (1, 2), QQ)
  611. >>> Bq
  612. DomainMatrix([[1/2, 2]], (1, 2), QQ)
  613. Unify the format (dense or sparse):
  614. >>> A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  615. >>> B = DomainMatrix({0:{0: ZZ(1)}}, (2, 2), ZZ)
  616. >>> B.rep
  617. {0: {0: 1}}
  618. >>> A2, B2 = A.unify(B, fmt='dense')
  619. >>> B2.rep
  620. [[1, 0], [0, 0]]
  621. See Also
  622. ========
  623. convert_to, to_dense, to_sparse
  624. """
  625. matrices = (self,) + others
  626. matrices = DomainMatrix._unify_domain(*matrices)
  627. if fmt is not None:
  628. matrices = DomainMatrix._unify_fmt(*matrices, fmt=fmt)
  629. return matrices
  630. def to_Matrix(self):
  631. r"""
  632. Convert DomainMatrix to Matrix
  633. Returns
  634. =======
  635. Matrix
  636. MutableDenseMatrix for the DomainMatrix
  637. Examples
  638. ========
  639. >>> from sympy import ZZ
  640. >>> from sympy.polys.matrices import DomainMatrix
  641. >>> A = DomainMatrix([
  642. ... [ZZ(1), ZZ(2)],
  643. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  644. >>> A.to_Matrix()
  645. Matrix([
  646. [1, 2],
  647. [3, 4]])
  648. See Also
  649. ========
  650. from_Matrix
  651. """
  652. from sympy.matrices.dense import MutableDenseMatrix
  653. # XXX: If the internal representation of RepMatrix changes then this
  654. # might need to be changed also.
  655. if self.domain in (ZZ, QQ, EXRAW):
  656. if self.rep.fmt == "sparse":
  657. rep = self.copy()
  658. else:
  659. rep = self.to_sparse()
  660. else:
  661. rep = self.convert_to(EXRAW).to_sparse()
  662. return MutableDenseMatrix._fromrep(rep)
  663. def to_list(self):
  664. """
  665. Convert :class:`DomainMatrix` to list of lists.
  666. See Also
  667. ========
  668. from_list
  669. to_list_flat
  670. to_flat_nz
  671. to_dok
  672. """
  673. return self.rep.to_list()
  674. def to_list_flat(self):
  675. """
  676. Convert :class:`DomainMatrix` to flat list.
  677. Examples
  678. ========
  679. >>> from sympy import ZZ
  680. >>> from sympy.polys.matrices import DomainMatrix
  681. >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  682. >>> A.to_list_flat()
  683. [1, 2, 3, 4]
  684. See Also
  685. ========
  686. from_list_flat
  687. to_list
  688. to_flat_nz
  689. to_dok
  690. """
  691. return self.rep.to_list_flat()
  692. @classmethod
  693. def from_list_flat(cls, elements, shape, domain):
  694. """
  695. Create :class:`DomainMatrix` from flat list.
  696. Examples
  697. ========
  698. >>> from sympy import ZZ
  699. >>> from sympy.polys.matrices import DomainMatrix
  700. >>> element_list = [ZZ(1), ZZ(2), ZZ(3), ZZ(4)]
  701. >>> A = DomainMatrix.from_list_flat(element_list, (2, 2), ZZ)
  702. >>> A
  703. DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  704. >>> A == A.from_list_flat(A.to_list_flat(), A.shape, A.domain)
  705. True
  706. See Also
  707. ========
  708. to_list_flat
  709. """
  710. ddm = DDM.from_list_flat(elements, shape, domain)
  711. return cls.from_rep(ddm.to_dfm_or_ddm())
  712. def to_flat_nz(self):
  713. """
  714. Convert :class:`DomainMatrix` to list of nonzero elements and data.
  715. Explanation
  716. ===========
  717. Returns a tuple ``(elements, data)`` where ``elements`` is a list of
  718. elements of the matrix with zeros possibly excluded. The matrix can be
  719. reconstructed by passing these to :meth:`from_flat_nz`. The idea is to
  720. be able to modify a flat list of the elements and then create a new
  721. matrix of the same shape with the modified elements in the same
  722. positions.
  723. The format of ``data`` differs depending on whether the underlying
  724. representation is dense or sparse but either way it represents the
  725. positions of the elements in the list in a way that
  726. :meth:`from_flat_nz` can use to reconstruct the matrix. The
  727. :meth:`from_flat_nz` method should be called on the same
  728. :class:`DomainMatrix` that was used to call :meth:`to_flat_nz`.
  729. Examples
  730. ========
  731. >>> from sympy import ZZ
  732. >>> from sympy.polys.matrices import DomainMatrix
  733. >>> A = DomainMatrix([
  734. ... [ZZ(1), ZZ(2)],
  735. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  736. >>> elements, data = A.to_flat_nz()
  737. >>> elements
  738. [1, 2, 3, 4]
  739. >>> A == A.from_flat_nz(elements, data, A.domain)
  740. True
  741. Create a matrix with the elements doubled:
  742. >>> elements_doubled = [2*x for x in elements]
  743. >>> A2 = A.from_flat_nz(elements_doubled, data, A.domain)
  744. >>> A2 == 2*A
  745. True
  746. See Also
  747. ========
  748. from_flat_nz
  749. """
  750. return self.rep.to_flat_nz()
  751. def from_flat_nz(self, elements, data, domain):
  752. """
  753. Reconstruct :class:`DomainMatrix` after calling :meth:`to_flat_nz`.
  754. See :meth:`to_flat_nz` for explanation.
  755. See Also
  756. ========
  757. to_flat_nz
  758. """
  759. rep = self.rep.from_flat_nz(elements, data, domain)
  760. return self.from_rep(rep)
  761. def to_dod(self):
  762. """
  763. Convert :class:`DomainMatrix` to dictionary of dictionaries (dod) format.
  764. Explanation
  765. ===========
  766. Returns a dictionary of dictionaries representing the matrix.
  767. Examples
  768. ========
  769. >>> from sympy import ZZ
  770. >>> from sympy.polys.matrices import DM
  771. >>> A = DM([[ZZ(1), ZZ(2), ZZ(0)], [ZZ(3), ZZ(0), ZZ(4)]], ZZ)
  772. >>> A.to_dod()
  773. {0: {0: 1, 1: 2}, 1: {0: 3, 2: 4}}
  774. >>> A.to_sparse() == A.from_dod(A.to_dod(), A.shape, A.domain)
  775. True
  776. >>> A == A.from_dod_like(A.to_dod())
  777. True
  778. See Also
  779. ========
  780. from_dod
  781. from_dod_like
  782. to_dok
  783. to_list
  784. to_list_flat
  785. to_flat_nz
  786. sympy.matrices.matrixbase.MatrixBase.todod
  787. """
  788. return self.rep.to_dod()
  789. @classmethod
  790. def from_dod(cls, dod, shape, domain):
  791. """
  792. Create sparse :class:`DomainMatrix` from dict of dict (dod) format.
  793. See :meth:`to_dod` for explanation.
  794. See Also
  795. ========
  796. to_dod
  797. from_dod_like
  798. """
  799. return cls.from_rep(SDM.from_dod(dod, shape, domain))
  800. def from_dod_like(self, dod, domain=None):
  801. """
  802. Create :class:`DomainMatrix` like ``self`` from dict of dict (dod) format.
  803. See :meth:`to_dod` for explanation.
  804. See Also
  805. ========
  806. to_dod
  807. from_dod
  808. """
  809. if domain is None:
  810. domain = self.domain
  811. return self.from_rep(self.rep.from_dod(dod, self.shape, domain))
  812. def to_dok(self):
  813. """
  814. Convert :class:`DomainMatrix` to dictionary of keys (dok) format.
  815. Examples
  816. ========
  817. >>> from sympy import ZZ
  818. >>> from sympy.polys.matrices import DomainMatrix
  819. >>> A = DomainMatrix([
  820. ... [ZZ(1), ZZ(0)],
  821. ... [ZZ(0), ZZ(4)]], (2, 2), ZZ)
  822. >>> A.to_dok()
  823. {(0, 0): 1, (1, 1): 4}
  824. The matrix can be reconstructed by calling :meth:`from_dok` although
  825. the reconstructed matrix will always be in sparse format:
  826. >>> A.to_sparse() == A.from_dok(A.to_dok(), A.shape, A.domain)
  827. True
  828. See Also
  829. ========
  830. from_dok
  831. to_list
  832. to_list_flat
  833. to_flat_nz
  834. """
  835. return self.rep.to_dok()
  836. @classmethod
  837. def from_dok(cls, dok, shape, domain):
  838. """
  839. Create :class:`DomainMatrix` from dictionary of keys (dok) format.
  840. See :meth:`to_dok` for explanation.
  841. See Also
  842. ========
  843. to_dok
  844. """
  845. return cls.from_rep(SDM.from_dok(dok, shape, domain))
  846. def iter_values(self):
  847. """
  848. Iterate over nonzero elements of the matrix.
  849. Examples
  850. ========
  851. >>> from sympy import ZZ
  852. >>> from sympy.polys.matrices import DomainMatrix
  853. >>> A = DomainMatrix([[ZZ(1), ZZ(0)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  854. >>> list(A.iter_values())
  855. [1, 3, 4]
  856. See Also
  857. ========
  858. iter_items
  859. to_list_flat
  860. sympy.matrices.matrixbase.MatrixBase.iter_values
  861. """
  862. return self.rep.iter_values()
  863. def iter_items(self):
  864. """
  865. Iterate over indices and values of nonzero elements of the matrix.
  866. Examples
  867. ========
  868. >>> from sympy import ZZ
  869. >>> from sympy.polys.matrices import DomainMatrix
  870. >>> A = DomainMatrix([[ZZ(1), ZZ(0)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  871. >>> list(A.iter_items())
  872. [((0, 0), 1), ((1, 0), 3), ((1, 1), 4)]
  873. See Also
  874. ========
  875. iter_values
  876. to_dok
  877. sympy.matrices.matrixbase.MatrixBase.iter_items
  878. """
  879. return self.rep.iter_items()
  880. def nnz(self):
  881. """
  882. Number of nonzero elements in the matrix.
  883. Examples
  884. ========
  885. >>> from sympy import ZZ
  886. >>> from sympy.polys.matrices import DM
  887. >>> A = DM([[1, 0], [0, 4]], ZZ)
  888. >>> A.nnz()
  889. 2
  890. """
  891. return self.rep.nnz()
  892. def __repr__(self):
  893. return 'DomainMatrix(%s, %r, %r)' % (str(self.rep), self.shape, self.domain)
  894. def transpose(self):
  895. """Matrix transpose of ``self``"""
  896. return self.from_rep(self.rep.transpose())
  897. def flat(self):
  898. rows, cols = self.shape
  899. return [self[i,j].element for i in range(rows) for j in range(cols)]
  900. @property
  901. def is_zero_matrix(self):
  902. return self.rep.is_zero_matrix()
  903. @property
  904. def is_upper(self):
  905. """
  906. Says whether this matrix is upper-triangular. True can be returned
  907. even if the matrix is not square.
  908. """
  909. return self.rep.is_upper()
  910. @property
  911. def is_lower(self):
  912. """
  913. Says whether this matrix is lower-triangular. True can be returned
  914. even if the matrix is not square.
  915. """
  916. return self.rep.is_lower()
  917. @property
  918. def is_diagonal(self):
  919. """
  920. True if the matrix is diagonal.
  921. Can return true for non-square matrices. A matrix is diagonal if
  922. ``M[i,j] == 0`` whenever ``i != j``.
  923. Examples
  924. ========
  925. >>> from sympy import ZZ
  926. >>> from sympy.polys.matrices import DM
  927. >>> M = DM([[ZZ(1), ZZ(0)], [ZZ(0), ZZ(1)]], ZZ)
  928. >>> M.is_diagonal
  929. True
  930. See Also
  931. ========
  932. is_upper
  933. is_lower
  934. is_square
  935. diagonal
  936. """
  937. return self.rep.is_diagonal()
  938. def diagonal(self):
  939. """
  940. Get the diagonal entries of the matrix as a list.
  941. Examples
  942. ========
  943. >>> from sympy import ZZ
  944. >>> from sympy.polys.matrices import DM
  945. >>> M = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ)
  946. >>> M.diagonal()
  947. [1, 4]
  948. See Also
  949. ========
  950. is_diagonal
  951. diag
  952. """
  953. return self.rep.diagonal()
  954. @property
  955. def is_square(self):
  956. """
  957. True if the matrix is square.
  958. """
  959. return self.shape[0] == self.shape[1]
  960. def rank(self):
  961. rref, pivots = self.rref()
  962. return len(pivots)
  963. def hstack(A, *B):
  964. r"""Horizontally stack the given matrices.
  965. Parameters
  966. ==========
  967. B: DomainMatrix
  968. Matrices to stack horizontally.
  969. Returns
  970. =======
  971. DomainMatrix
  972. DomainMatrix by stacking horizontally.
  973. Examples
  974. ========
  975. >>> from sympy import ZZ
  976. >>> from sympy.polys.matrices import DomainMatrix
  977. >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  978. >>> B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ)
  979. >>> A.hstack(B)
  980. DomainMatrix([[1, 2, 5, 6], [3, 4, 7, 8]], (2, 4), ZZ)
  981. >>> C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ)
  982. >>> A.hstack(B, C)
  983. DomainMatrix([[1, 2, 5, 6, 9, 10], [3, 4, 7, 8, 11, 12]], (2, 6), ZZ)
  984. See Also
  985. ========
  986. unify
  987. """
  988. A, *B = A.unify(*B, fmt=A.rep.fmt)
  989. return DomainMatrix.from_rep(A.rep.hstack(*(Bk.rep for Bk in B)))
  990. def vstack(A, *B):
  991. r"""Vertically stack the given matrices.
  992. Parameters
  993. ==========
  994. B: DomainMatrix
  995. Matrices to stack vertically.
  996. Returns
  997. =======
  998. DomainMatrix
  999. DomainMatrix by stacking vertically.
  1000. Examples
  1001. ========
  1002. >>> from sympy import ZZ
  1003. >>> from sympy.polys.matrices import DomainMatrix
  1004. >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1005. >>> B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ)
  1006. >>> A.vstack(B)
  1007. DomainMatrix([[1, 2], [3, 4], [5, 6], [7, 8]], (4, 2), ZZ)
  1008. >>> C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ)
  1009. >>> A.vstack(B, C)
  1010. DomainMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], (6, 2), ZZ)
  1011. See Also
  1012. ========
  1013. unify
  1014. """
  1015. A, *B = A.unify(*B, fmt='dense')
  1016. return DomainMatrix.from_rep(A.rep.vstack(*(Bk.rep for Bk in B)))
  1017. def applyfunc(self, func, domain=None):
  1018. if domain is None:
  1019. domain = self.domain
  1020. return self.from_rep(self.rep.applyfunc(func, domain))
  1021. def __add__(A, B):
  1022. if not isinstance(B, DomainMatrix):
  1023. return NotImplemented
  1024. A, B = A.unify(B, fmt='dense')
  1025. return A.add(B)
  1026. def __sub__(A, B):
  1027. if not isinstance(B, DomainMatrix):
  1028. return NotImplemented
  1029. A, B = A.unify(B, fmt='dense')
  1030. return A.sub(B)
  1031. def __neg__(A):
  1032. return A.neg()
  1033. def __mul__(A, B):
  1034. """A * B"""
  1035. if isinstance(B, DomainMatrix):
  1036. A, B = A.unify(B, fmt='dense')
  1037. return A.matmul(B)
  1038. elif B in A.domain:
  1039. return A.scalarmul(B)
  1040. elif isinstance(B, DomainScalar):
  1041. A, B = A.unify(B)
  1042. return A.scalarmul(B.element)
  1043. else:
  1044. return NotImplemented
  1045. def __rmul__(A, B):
  1046. if B in A.domain:
  1047. return A.rscalarmul(B)
  1048. elif isinstance(B, DomainScalar):
  1049. A, B = A.unify(B)
  1050. return A.rscalarmul(B.element)
  1051. else:
  1052. return NotImplemented
  1053. def __pow__(A, n):
  1054. """A ** n"""
  1055. if not isinstance(n, int):
  1056. return NotImplemented
  1057. return A.pow(n)
  1058. def _check(a, op, b, ashape, bshape):
  1059. if a.domain != b.domain:
  1060. msg = "Domain mismatch: %s %s %s" % (a.domain, op, b.domain)
  1061. raise DMDomainError(msg)
  1062. if ashape != bshape:
  1063. msg = "Shape mismatch: %s %s %s" % (a.shape, op, b.shape)
  1064. raise DMShapeError(msg)
  1065. if a.rep.fmt != b.rep.fmt:
  1066. msg = "Format mismatch: %s %s %s" % (a.rep.fmt, op, b.rep.fmt)
  1067. raise DMFormatError(msg)
  1068. if type(a.rep) != type(b.rep):
  1069. msg = "Type mismatch: %s %s %s" % (type(a.rep), op, type(b.rep))
  1070. raise DMFormatError(msg)
  1071. def add(A, B):
  1072. r"""
  1073. Adds two DomainMatrix matrices of the same Domain
  1074. Parameters
  1075. ==========
  1076. A, B: DomainMatrix
  1077. matrices to add
  1078. Returns
  1079. =======
  1080. DomainMatrix
  1081. DomainMatrix after Addition
  1082. Raises
  1083. ======
  1084. DMShapeError
  1085. If the dimensions of the two DomainMatrix are not equal
  1086. ValueError
  1087. If the domain of the two DomainMatrix are not same
  1088. Examples
  1089. ========
  1090. >>> from sympy import ZZ
  1091. >>> from sympy.polys.matrices import DomainMatrix
  1092. >>> A = DomainMatrix([
  1093. ... [ZZ(1), ZZ(2)],
  1094. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1095. >>> B = DomainMatrix([
  1096. ... [ZZ(4), ZZ(3)],
  1097. ... [ZZ(2), ZZ(1)]], (2, 2), ZZ)
  1098. >>> A.add(B)
  1099. DomainMatrix([[5, 5], [5, 5]], (2, 2), ZZ)
  1100. See Also
  1101. ========
  1102. sub, matmul
  1103. """
  1104. A._check('+', B, A.shape, B.shape)
  1105. return A.from_rep(A.rep.add(B.rep))
  1106. def sub(A, B):
  1107. r"""
  1108. Subtracts two DomainMatrix matrices of the same Domain
  1109. Parameters
  1110. ==========
  1111. A, B: DomainMatrix
  1112. matrices to subtract
  1113. Returns
  1114. =======
  1115. DomainMatrix
  1116. DomainMatrix after Subtraction
  1117. Raises
  1118. ======
  1119. DMShapeError
  1120. If the dimensions of the two DomainMatrix are not equal
  1121. ValueError
  1122. If the domain of the two DomainMatrix are not same
  1123. Examples
  1124. ========
  1125. >>> from sympy import ZZ
  1126. >>> from sympy.polys.matrices import DomainMatrix
  1127. >>> A = DomainMatrix([
  1128. ... [ZZ(1), ZZ(2)],
  1129. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1130. >>> B = DomainMatrix([
  1131. ... [ZZ(4), ZZ(3)],
  1132. ... [ZZ(2), ZZ(1)]], (2, 2), ZZ)
  1133. >>> A.sub(B)
  1134. DomainMatrix([[-3, -1], [1, 3]], (2, 2), ZZ)
  1135. See Also
  1136. ========
  1137. add, matmul
  1138. """
  1139. A._check('-', B, A.shape, B.shape)
  1140. return A.from_rep(A.rep.sub(B.rep))
  1141. def neg(A):
  1142. r"""
  1143. Returns the negative of DomainMatrix
  1144. Parameters
  1145. ==========
  1146. A : Represents a DomainMatrix
  1147. Returns
  1148. =======
  1149. DomainMatrix
  1150. DomainMatrix after Negation
  1151. Examples
  1152. ========
  1153. >>> from sympy import ZZ
  1154. >>> from sympy.polys.matrices import DomainMatrix
  1155. >>> A = DomainMatrix([
  1156. ... [ZZ(1), ZZ(2)],
  1157. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1158. >>> A.neg()
  1159. DomainMatrix([[-1, -2], [-3, -4]], (2, 2), ZZ)
  1160. """
  1161. return A.from_rep(A.rep.neg())
  1162. def mul(A, b):
  1163. r"""
  1164. Performs term by term multiplication for the second DomainMatrix
  1165. w.r.t first DomainMatrix. Returns a DomainMatrix whose rows are
  1166. list of DomainMatrix matrices created after term by term multiplication.
  1167. Parameters
  1168. ==========
  1169. A, B: DomainMatrix
  1170. matrices to multiply term-wise
  1171. Returns
  1172. =======
  1173. DomainMatrix
  1174. DomainMatrix after term by term multiplication
  1175. Examples
  1176. ========
  1177. >>> from sympy import ZZ
  1178. >>> from sympy.polys.matrices import DomainMatrix
  1179. >>> A = DomainMatrix([
  1180. ... [ZZ(1), ZZ(2)],
  1181. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1182. >>> b = ZZ(2)
  1183. >>> A.mul(b)
  1184. DomainMatrix([[2, 4], [6, 8]], (2, 2), ZZ)
  1185. See Also
  1186. ========
  1187. matmul
  1188. """
  1189. return A.from_rep(A.rep.mul(b))
  1190. def rmul(A, b):
  1191. return A.from_rep(A.rep.rmul(b))
  1192. def matmul(A, B):
  1193. r"""
  1194. Performs matrix multiplication of two DomainMatrix matrices
  1195. Parameters
  1196. ==========
  1197. A, B: DomainMatrix
  1198. to multiply
  1199. Returns
  1200. =======
  1201. DomainMatrix
  1202. DomainMatrix after multiplication
  1203. Examples
  1204. ========
  1205. >>> from sympy import ZZ
  1206. >>> from sympy.polys.matrices import DomainMatrix
  1207. >>> A = DomainMatrix([
  1208. ... [ZZ(1), ZZ(2)],
  1209. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1210. >>> B = DomainMatrix([
  1211. ... [ZZ(1), ZZ(1)],
  1212. ... [ZZ(0), ZZ(1)]], (2, 2), ZZ)
  1213. >>> A.matmul(B)
  1214. DomainMatrix([[1, 3], [3, 7]], (2, 2), ZZ)
  1215. See Also
  1216. ========
  1217. mul, pow, add, sub
  1218. """
  1219. A._check('*', B, A.shape[1], B.shape[0])
  1220. return A.from_rep(A.rep.matmul(B.rep))
  1221. def _scalarmul(A, lamda, reverse):
  1222. if lamda == A.domain.zero:
  1223. return DomainMatrix.zeros(A.shape, A.domain)
  1224. elif lamda == A.domain.one:
  1225. return A.copy()
  1226. elif reverse:
  1227. return A.rmul(lamda)
  1228. else:
  1229. return A.mul(lamda)
  1230. def scalarmul(A, lamda):
  1231. return A._scalarmul(lamda, reverse=False)
  1232. def rscalarmul(A, lamda):
  1233. return A._scalarmul(lamda, reverse=True)
  1234. def mul_elementwise(A, B):
  1235. assert A.domain == B.domain
  1236. return A.from_rep(A.rep.mul_elementwise(B.rep))
  1237. def __truediv__(A, lamda):
  1238. """ Method for Scalar Division"""
  1239. if isinstance(lamda, int) or ZZ.of_type(lamda):
  1240. lamda = DomainScalar(ZZ(lamda), ZZ)
  1241. elif A.domain.is_Field and lamda in A.domain:
  1242. K = A.domain
  1243. lamda = DomainScalar(K.convert(lamda), K)
  1244. if not isinstance(lamda, DomainScalar):
  1245. return NotImplemented
  1246. A, lamda = A.to_field().unify(lamda)
  1247. if lamda.element == lamda.domain.zero:
  1248. raise ZeroDivisionError
  1249. if lamda.element == lamda.domain.one:
  1250. return A
  1251. return A.mul(1 / lamda.element)
  1252. def pow(A, n):
  1253. r"""
  1254. Computes A**n
  1255. Parameters
  1256. ==========
  1257. A : DomainMatrix
  1258. n : exponent for A
  1259. Returns
  1260. =======
  1261. DomainMatrix
  1262. DomainMatrix on computing A**n
  1263. Raises
  1264. ======
  1265. NotImplementedError
  1266. if n is negative.
  1267. Examples
  1268. ========
  1269. >>> from sympy import ZZ
  1270. >>> from sympy.polys.matrices import DomainMatrix
  1271. >>> A = DomainMatrix([
  1272. ... [ZZ(1), ZZ(1)],
  1273. ... [ZZ(0), ZZ(1)]], (2, 2), ZZ)
  1274. >>> A.pow(2)
  1275. DomainMatrix([[1, 2], [0, 1]], (2, 2), ZZ)
  1276. See Also
  1277. ========
  1278. matmul
  1279. """
  1280. nrows, ncols = A.shape
  1281. if nrows != ncols:
  1282. raise DMNonSquareMatrixError('Power of a nonsquare matrix')
  1283. if n < 0:
  1284. raise NotImplementedError('Negative powers')
  1285. elif n == 0:
  1286. return A.eye(nrows, A.domain)
  1287. elif n == 1:
  1288. return A
  1289. elif n % 2 == 1:
  1290. return A * A**(n - 1)
  1291. else:
  1292. sqrtAn = A ** (n // 2)
  1293. return sqrtAn * sqrtAn
  1294. def scc(self):
  1295. """Compute the strongly connected components of a DomainMatrix
  1296. Explanation
  1297. ===========
  1298. A square matrix can be considered as the adjacency matrix for a
  1299. directed graph where the row and column indices are the vertices. In
  1300. this graph if there is an edge from vertex ``i`` to vertex ``j`` if
  1301. ``M[i, j]`` is nonzero. This routine computes the strongly connected
  1302. components of that graph which are subsets of the rows and columns that
  1303. are connected by some nonzero element of the matrix. The strongly
  1304. connected components are useful because many operations such as the
  1305. determinant can be computed by working with the submatrices
  1306. corresponding to each component.
  1307. Examples
  1308. ========
  1309. Find the strongly connected components of a matrix:
  1310. >>> from sympy import ZZ
  1311. >>> from sympy.polys.matrices import DomainMatrix
  1312. >>> M = DomainMatrix([[ZZ(1), ZZ(0), ZZ(2)],
  1313. ... [ZZ(0), ZZ(3), ZZ(0)],
  1314. ... [ZZ(4), ZZ(6), ZZ(5)]], (3, 3), ZZ)
  1315. >>> M.scc()
  1316. [[1], [0, 2]]
  1317. Compute the determinant from the components:
  1318. >>> MM = M.to_Matrix()
  1319. >>> MM
  1320. Matrix([
  1321. [1, 0, 2],
  1322. [0, 3, 0],
  1323. [4, 6, 5]])
  1324. >>> MM[[1], [1]]
  1325. Matrix([[3]])
  1326. >>> MM[[0, 2], [0, 2]]
  1327. Matrix([
  1328. [1, 2],
  1329. [4, 5]])
  1330. >>> MM.det()
  1331. -9
  1332. >>> MM[[1], [1]].det() * MM[[0, 2], [0, 2]].det()
  1333. -9
  1334. The components are given in reverse topological order and represent a
  1335. permutation of the rows and columns that will bring the matrix into
  1336. block lower-triangular form:
  1337. >>> MM[[1, 0, 2], [1, 0, 2]]
  1338. Matrix([
  1339. [3, 0, 0],
  1340. [0, 1, 2],
  1341. [6, 4, 5]])
  1342. Returns
  1343. =======
  1344. List of lists of integers
  1345. Each list represents a strongly connected component.
  1346. See also
  1347. ========
  1348. sympy.matrices.matrixbase.MatrixBase.strongly_connected_components
  1349. sympy.utilities.iterables.strongly_connected_components
  1350. """
  1351. if not self.is_square:
  1352. raise DMNonSquareMatrixError('Matrix must be square for scc')
  1353. return self.rep.scc()
  1354. def clear_denoms(self, convert=False):
  1355. """
  1356. Clear denominators, but keep the domain unchanged.
  1357. Examples
  1358. ========
  1359. >>> from sympy import QQ
  1360. >>> from sympy.polys.matrices import DM
  1361. >>> A = DM([[(1,2), (1,3)], [(1,4), (1,5)]], QQ)
  1362. >>> den, Anum = A.clear_denoms()
  1363. >>> den.to_sympy()
  1364. 60
  1365. >>> Anum.to_Matrix()
  1366. Matrix([
  1367. [30, 20],
  1368. [15, 12]])
  1369. >>> den * A == Anum
  1370. True
  1371. The numerator matrix will be in the same domain as the original matrix
  1372. unless ``convert`` is set to ``True``:
  1373. >>> A.clear_denoms()[1].domain
  1374. QQ
  1375. >>> A.clear_denoms(convert=True)[1].domain
  1376. ZZ
  1377. The denominator is always in the associated ring:
  1378. >>> A.clear_denoms()[0].domain
  1379. ZZ
  1380. >>> A.domain.get_ring()
  1381. ZZ
  1382. See Also
  1383. ========
  1384. sympy.polys.polytools.Poly.clear_denoms
  1385. clear_denoms_rowwise
  1386. """
  1387. elems0, data = self.to_flat_nz()
  1388. K0 = self.domain
  1389. K1 = K0.get_ring() if K0.has_assoc_Ring else K0
  1390. den, elems1 = dup_clear_denoms(elems0, K0, K1, convert=convert)
  1391. if convert:
  1392. Kden, Knum = K1, K1
  1393. else:
  1394. Kden, Knum = K1, K0
  1395. den = DomainScalar(den, Kden)
  1396. num = self.from_flat_nz(elems1, data, Knum)
  1397. return den, num
  1398. def clear_denoms_rowwise(self, convert=False):
  1399. """
  1400. Clear denominators from each row of the matrix.
  1401. Examples
  1402. ========
  1403. >>> from sympy import QQ
  1404. >>> from sympy.polys.matrices import DM
  1405. >>> A = DM([[(1,2), (1,3), (1,4)], [(1,5), (1,6), (1,7)]], QQ)
  1406. >>> den, Anum = A.clear_denoms_rowwise()
  1407. >>> den.to_Matrix()
  1408. Matrix([
  1409. [12, 0],
  1410. [ 0, 210]])
  1411. >>> Anum.to_Matrix()
  1412. Matrix([
  1413. [ 6, 4, 3],
  1414. [42, 35, 30]])
  1415. The denominator matrix is a diagonal matrix with the denominators of
  1416. each row on the diagonal. The invariants are:
  1417. >>> den * A == Anum
  1418. True
  1419. >>> A == den.to_field().inv() * Anum
  1420. True
  1421. The numerator matrix will be in the same domain as the original matrix
  1422. unless ``convert`` is set to ``True``:
  1423. >>> A.clear_denoms_rowwise()[1].domain
  1424. QQ
  1425. >>> A.clear_denoms_rowwise(convert=True)[1].domain
  1426. ZZ
  1427. The domain of the denominator matrix is the associated ring:
  1428. >>> A.clear_denoms_rowwise()[0].domain
  1429. ZZ
  1430. See Also
  1431. ========
  1432. sympy.polys.polytools.Poly.clear_denoms
  1433. clear_denoms
  1434. """
  1435. dod = self.to_dod()
  1436. K0 = self.domain
  1437. K1 = K0.get_ring() if K0.has_assoc_Ring else K0
  1438. diagonals = [K0.one] * self.shape[0]
  1439. dod_num = {}
  1440. for i, rowi in dod.items():
  1441. indices, elems = zip(*rowi.items())
  1442. den, elems_num = dup_clear_denoms(elems, K0, K1, convert=convert)
  1443. rowi_num = dict(zip(indices, elems_num))
  1444. diagonals[i] = den
  1445. dod_num[i] = rowi_num
  1446. if convert:
  1447. Kden, Knum = K1, K1
  1448. else:
  1449. Kden, Knum = K1, K0
  1450. den = self.diag(diagonals, Kden)
  1451. num = self.from_dod_like(dod_num, Knum)
  1452. return den, num
  1453. def cancel_denom(self, denom):
  1454. """
  1455. Cancel factors between a matrix and a denominator.
  1456. Returns a matrix and denominator on lowest terms.
  1457. Requires ``gcd`` in the ground domain.
  1458. Methods like :meth:`solve_den`, :meth:`inv_den` and :meth:`rref_den`
  1459. return a matrix and denominator but not necessarily on lowest terms.
  1460. Reduction to lowest terms without fractions can be performed with
  1461. :meth:`cancel_denom`.
  1462. Examples
  1463. ========
  1464. >>> from sympy.polys.matrices import DM
  1465. >>> from sympy import ZZ
  1466. >>> M = DM([[2, 2, 0],
  1467. ... [0, 2, 2],
  1468. ... [0, 0, 2]], ZZ)
  1469. >>> Minv, den = M.inv_den()
  1470. >>> Minv.to_Matrix()
  1471. Matrix([
  1472. [1, -1, 1],
  1473. [0, 1, -1],
  1474. [0, 0, 1]])
  1475. >>> den
  1476. 2
  1477. >>> Minv_reduced, den_reduced = Minv.cancel_denom(den)
  1478. >>> Minv_reduced.to_Matrix()
  1479. Matrix([
  1480. [1, -1, 1],
  1481. [0, 1, -1],
  1482. [0, 0, 1]])
  1483. >>> den_reduced
  1484. 2
  1485. >>> Minv_reduced.to_field() / den_reduced == Minv.to_field() / den
  1486. True
  1487. The denominator is made canonical with respect to units (e.g. a
  1488. negative denominator is made positive):
  1489. >>> M = DM([[2, 2, 0]], ZZ)
  1490. >>> den = ZZ(-4)
  1491. >>> M.cancel_denom(den)
  1492. (DomainMatrix([[-1, -1, 0]], (1, 3), ZZ), 2)
  1493. Any factor common to _all_ elements will be cancelled but there can
  1494. still be factors in common between _some_ elements of the matrix and
  1495. the denominator. To cancel factors between each element and the
  1496. denominator, use :meth:`cancel_denom_elementwise` or otherwise convert
  1497. to a field and use division:
  1498. >>> M = DM([[4, 6]], ZZ)
  1499. >>> den = ZZ(12)
  1500. >>> M.cancel_denom(den)
  1501. (DomainMatrix([[2, 3]], (1, 2), ZZ), 6)
  1502. >>> numers, denoms = M.cancel_denom_elementwise(den)
  1503. >>> numers
  1504. DomainMatrix([[1, 1]], (1, 2), ZZ)
  1505. >>> denoms
  1506. DomainMatrix([[3, 2]], (1, 2), ZZ)
  1507. >>> M.to_field() / den
  1508. DomainMatrix([[1/3, 1/2]], (1, 2), QQ)
  1509. See Also
  1510. ========
  1511. solve_den
  1512. inv_den
  1513. rref_den
  1514. cancel_denom_elementwise
  1515. """
  1516. M = self
  1517. K = self.domain
  1518. if K.is_zero(denom):
  1519. raise ZeroDivisionError('denominator is zero')
  1520. elif K.is_one(denom):
  1521. return (M.copy(), denom)
  1522. elements, data = M.to_flat_nz()
  1523. # First canonicalize the denominator (e.g. multiply by -1).
  1524. if K.is_negative(denom):
  1525. u = -K.one
  1526. else:
  1527. u = K.canonical_unit(denom)
  1528. # Often after e.g. solve_den the denominator will be much more
  1529. # complicated than the elements of the numerator. Hopefully it will be
  1530. # quicker to find the gcd of the numerator and if there is no content
  1531. # then we do not need to look at the denominator at all.
  1532. content = dup_content(elements, K)
  1533. common = K.gcd(content, denom)
  1534. if not K.is_one(content):
  1535. common = K.gcd(content, denom)
  1536. if not K.is_one(common):
  1537. elements = dup_quo_ground(elements, common, K)
  1538. denom = K.quo(denom, common)
  1539. if not K.is_one(u):
  1540. elements = dup_mul_ground(elements, u, K)
  1541. denom = u * denom
  1542. elif K.is_one(common):
  1543. return (M.copy(), denom)
  1544. M_cancelled = M.from_flat_nz(elements, data, K)
  1545. return M_cancelled, denom
  1546. def cancel_denom_elementwise(self, denom):
  1547. """
  1548. Cancel factors between the elements of a matrix and a denominator.
  1549. Returns a matrix of numerators and matrix of denominators.
  1550. Requires ``gcd`` in the ground domain.
  1551. Examples
  1552. ========
  1553. >>> from sympy.polys.matrices import DM
  1554. >>> from sympy import ZZ
  1555. >>> M = DM([[2, 3], [4, 12]], ZZ)
  1556. >>> denom = ZZ(6)
  1557. >>> numers, denoms = M.cancel_denom_elementwise(denom)
  1558. >>> numers.to_Matrix()
  1559. Matrix([
  1560. [1, 1],
  1561. [2, 2]])
  1562. >>> denoms.to_Matrix()
  1563. Matrix([
  1564. [3, 2],
  1565. [3, 1]])
  1566. >>> M_frac = (M.to_field() / denom).to_Matrix()
  1567. >>> M_frac
  1568. Matrix([
  1569. [1/3, 1/2],
  1570. [2/3, 2]])
  1571. >>> denoms_inverted = denoms.to_Matrix().applyfunc(lambda e: 1/e)
  1572. >>> numers.to_Matrix().multiply_elementwise(denoms_inverted) == M_frac
  1573. True
  1574. Use :meth:`cancel_denom` to cancel factors between the matrix and the
  1575. denominator while preserving the form of a matrix with a scalar
  1576. denominator.
  1577. See Also
  1578. ========
  1579. cancel_denom
  1580. """
  1581. K = self.domain
  1582. M = self
  1583. if K.is_zero(denom):
  1584. raise ZeroDivisionError('denominator is zero')
  1585. elif K.is_one(denom):
  1586. M_numers = M.copy()
  1587. M_denoms = M.ones(M.shape, M.domain)
  1588. return (M_numers, M_denoms)
  1589. elements, data = M.to_flat_nz()
  1590. cofactors = [K.cofactors(numer, denom) for numer in elements]
  1591. gcds, numers, denoms = zip(*cofactors)
  1592. M_numers = M.from_flat_nz(list(numers), data, K)
  1593. M_denoms = M.from_flat_nz(list(denoms), data, K)
  1594. return (M_numers, M_denoms)
  1595. def content(self):
  1596. """
  1597. Return the gcd of the elements of the matrix.
  1598. Requires ``gcd`` in the ground domain.
  1599. Examples
  1600. ========
  1601. >>> from sympy.polys.matrices import DM
  1602. >>> from sympy import ZZ
  1603. >>> M = DM([[2, 4], [4, 12]], ZZ)
  1604. >>> M.content()
  1605. 2
  1606. See Also
  1607. ========
  1608. primitive
  1609. cancel_denom
  1610. """
  1611. K = self.domain
  1612. elements, _ = self.to_flat_nz()
  1613. return dup_content(elements, K)
  1614. def primitive(self):
  1615. """
  1616. Factor out gcd of the elements of a matrix.
  1617. Requires ``gcd`` in the ground domain.
  1618. Examples
  1619. ========
  1620. >>> from sympy.polys.matrices import DM
  1621. >>> from sympy import ZZ
  1622. >>> M = DM([[2, 4], [4, 12]], ZZ)
  1623. >>> content, M_primitive = M.primitive()
  1624. >>> content
  1625. 2
  1626. >>> M_primitive
  1627. DomainMatrix([[1, 2], [2, 6]], (2, 2), ZZ)
  1628. >>> content * M_primitive == M
  1629. True
  1630. >>> M_primitive.content() == ZZ(1)
  1631. True
  1632. See Also
  1633. ========
  1634. content
  1635. cancel_denom
  1636. """
  1637. K = self.domain
  1638. elements, data = self.to_flat_nz()
  1639. content, prims = dup_primitive(elements, K)
  1640. M_primitive = self.from_flat_nz(prims, data, K)
  1641. return content, M_primitive
  1642. def rref(self, *, method='auto'):
  1643. r"""
  1644. Returns reduced-row echelon form (RREF) and list of pivots.
  1645. If the domain is not a field then it will be converted to a field. See
  1646. :meth:`rref_den` for the fraction-free version of this routine that
  1647. returns RREF with denominator instead.
  1648. The domain must either be a field or have an associated fraction field
  1649. (see :meth:`to_field`).
  1650. Examples
  1651. ========
  1652. >>> from sympy import QQ
  1653. >>> from sympy.polys.matrices import DomainMatrix
  1654. >>> A = DomainMatrix([
  1655. ... [QQ(2), QQ(-1), QQ(0)],
  1656. ... [QQ(-1), QQ(2), QQ(-1)],
  1657. ... [QQ(0), QQ(0), QQ(2)]], (3, 3), QQ)
  1658. >>> rref_matrix, rref_pivots = A.rref()
  1659. >>> rref_matrix
  1660. DomainMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]], (3, 3), QQ)
  1661. >>> rref_pivots
  1662. (0, 1, 2)
  1663. Parameters
  1664. ==========
  1665. method : str, optional (default: 'auto')
  1666. The method to use to compute the RREF. The default is ``'auto'``,
  1667. which will attempt to choose the fastest method. The other options
  1668. are:
  1669. - ``A.rref(method='GJ')`` uses Gauss-Jordan elimination with
  1670. division. If the domain is not a field then it will be converted
  1671. to a field with :meth:`to_field` first and RREF will be computed
  1672. by inverting the pivot elements in each row. This is most
  1673. efficient for very sparse matrices or for matrices whose elements
  1674. have complex denominators.
  1675. - ``A.rref(method='FF')`` uses fraction-free Gauss-Jordan
  1676. elimination. Elimination is performed using exact division
  1677. (``exquo``) to control the growth of the coefficients. In this
  1678. case the current domain is always used for elimination but if
  1679. the domain is not a field then it will be converted to a field
  1680. at the end and divided by the denominator. This is most efficient
  1681. for dense matrices or for matrices with simple denominators.
  1682. - ``A.rref(method='CD')`` clears the denominators before using
  1683. fraction-free Gauss-Jordan elimination in the associated ring.
  1684. This is most efficient for dense matrices with very simple
  1685. denominators.
  1686. - ``A.rref(method='GJ_dense')``, ``A.rref(method='FF_dense')``, and
  1687. ``A.rref(method='CD_dense')`` are the same as the above methods
  1688. except that the dense implementations of the algorithms are used.
  1689. By default ``A.rref(method='auto')`` will usually choose the
  1690. sparse implementations for RREF.
  1691. Regardless of which algorithm is used the returned matrix will
  1692. always have the same format (sparse or dense) as the input and its
  1693. domain will always be the field of fractions of the input domain.
  1694. Returns
  1695. =======
  1696. (DomainMatrix, list)
  1697. reduced-row echelon form and list of pivots for the DomainMatrix
  1698. See Also
  1699. ========
  1700. rref_den
  1701. RREF with denominator
  1702. sympy.polys.matrices.sdm.sdm_irref
  1703. Sparse implementation of ``method='GJ'``.
  1704. sympy.polys.matrices.sdm.sdm_rref_den
  1705. Sparse implementation of ``method='FF'`` and ``method='CD'``.
  1706. sympy.polys.matrices.dense.ddm_irref
  1707. Dense implementation of ``method='GJ'``.
  1708. sympy.polys.matrices.dense.ddm_irref_den
  1709. Dense implementation of ``method='FF'`` and ``method='CD'``.
  1710. clear_denoms
  1711. Clear denominators from a matrix, used by ``method='CD'`` and
  1712. by ``method='GJ'`` when the original domain is not a field.
  1713. """
  1714. return _dm_rref(self, method=method)
  1715. def rref_den(self, *, method='auto', keep_domain=True):
  1716. r"""
  1717. Returns reduced-row echelon form with denominator and list of pivots.
  1718. Requires exact division in the ground domain (``exquo``).
  1719. Examples
  1720. ========
  1721. >>> from sympy import ZZ, QQ
  1722. >>> from sympy.polys.matrices import DomainMatrix
  1723. >>> A = DomainMatrix([
  1724. ... [ZZ(2), ZZ(-1), ZZ(0)],
  1725. ... [ZZ(-1), ZZ(2), ZZ(-1)],
  1726. ... [ZZ(0), ZZ(0), ZZ(2)]], (3, 3), ZZ)
  1727. >>> A_rref, denom, pivots = A.rref_den()
  1728. >>> A_rref
  1729. DomainMatrix([[6, 0, 0], [0, 6, 0], [0, 0, 6]], (3, 3), ZZ)
  1730. >>> denom
  1731. 6
  1732. >>> pivots
  1733. (0, 1, 2)
  1734. >>> A_rref.to_field() / denom
  1735. DomainMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]], (3, 3), QQ)
  1736. >>> A_rref.to_field() / denom == A.convert_to(QQ).rref()[0]
  1737. True
  1738. Parameters
  1739. ==========
  1740. method : str, optional (default: 'auto')
  1741. The method to use to compute the RREF. The default is ``'auto'``,
  1742. which will attempt to choose the fastest method. The other options
  1743. are:
  1744. - ``A.rref(method='FF')`` uses fraction-free Gauss-Jordan
  1745. elimination. Elimination is performed using exact division
  1746. (``exquo``) to control the growth of the coefficients. In this
  1747. case the current domain is always used for elimination and the
  1748. result is always returned as a matrix over the current domain.
  1749. This is most efficient for dense matrices or for matrices with
  1750. simple denominators.
  1751. - ``A.rref(method='CD')`` clears denominators before using
  1752. fraction-free Gauss-Jordan elimination in the associated ring.
  1753. The result will be converted back to the original domain unless
  1754. ``keep_domain=False`` is passed in which case the result will be
  1755. over the ring used for elimination. This is most efficient for
  1756. dense matrices with very simple denominators.
  1757. - ``A.rref(method='GJ')`` uses Gauss-Jordan elimination with
  1758. division. If the domain is not a field then it will be converted
  1759. to a field with :meth:`to_field` first and RREF will be computed
  1760. by inverting the pivot elements in each row. The result is
  1761. converted back to the original domain by clearing denominators
  1762. unless ``keep_domain=False`` is passed in which case the result
  1763. will be over the field used for elimination. This is most
  1764. efficient for very sparse matrices or for matrices whose elements
  1765. have complex denominators.
  1766. - ``A.rref(method='GJ_dense')``, ``A.rref(method='FF_dense')``, and
  1767. ``A.rref(method='CD_dense')`` are the same as the above methods
  1768. except that the dense implementations of the algorithms are used.
  1769. By default ``A.rref(method='auto')`` will usually choose the
  1770. sparse implementations for RREF.
  1771. Regardless of which algorithm is used the returned matrix will
  1772. always have the same format (sparse or dense) as the input and if
  1773. ``keep_domain=True`` its domain will always be the same as the
  1774. input.
  1775. keep_domain : bool, optional
  1776. If True (the default), the domain of the returned matrix and
  1777. denominator are the same as the domain of the input matrix. If
  1778. False, the domain of the returned matrix might be changed to an
  1779. associated ring or field if the algorithm used a different domain.
  1780. This is useful for efficiency if the caller does not need the
  1781. result to be in the original domain e.g. it avoids clearing
  1782. denominators in the case of ``A.rref(method='GJ')``.
  1783. Returns
  1784. =======
  1785. (DomainMatrix, scalar, list)
  1786. Reduced-row echelon form, denominator and list of pivot indices.
  1787. See Also
  1788. ========
  1789. rref
  1790. RREF without denominator for field domains.
  1791. sympy.polys.matrices.sdm.sdm_irref
  1792. Sparse implementation of ``method='GJ'``.
  1793. sympy.polys.matrices.sdm.sdm_rref_den
  1794. Sparse implementation of ``method='FF'`` and ``method='CD'``.
  1795. sympy.polys.matrices.dense.ddm_irref
  1796. Dense implementation of ``method='GJ'``.
  1797. sympy.polys.matrices.dense.ddm_irref_den
  1798. Dense implementation of ``method='FF'`` and ``method='CD'``.
  1799. clear_denoms
  1800. Clear denominators from a matrix, used by ``method='CD'``.
  1801. """
  1802. return _dm_rref_den(self, method=method, keep_domain=keep_domain)
  1803. def columnspace(self):
  1804. r"""
  1805. Returns the columnspace for the DomainMatrix
  1806. Returns
  1807. =======
  1808. DomainMatrix
  1809. The columns of this matrix form a basis for the columnspace.
  1810. Examples
  1811. ========
  1812. >>> from sympy import QQ
  1813. >>> from sympy.polys.matrices import DomainMatrix
  1814. >>> A = DomainMatrix([
  1815. ... [QQ(1), QQ(-1)],
  1816. ... [QQ(2), QQ(-2)]], (2, 2), QQ)
  1817. >>> A.columnspace()
  1818. DomainMatrix([[1], [2]], (2, 1), QQ)
  1819. """
  1820. if not self.domain.is_Field:
  1821. raise DMNotAField('Not a field')
  1822. rref, pivots = self.rref()
  1823. rows, cols = self.shape
  1824. return self.extract(range(rows), pivots)
  1825. def rowspace(self):
  1826. r"""
  1827. Returns the rowspace for the DomainMatrix
  1828. Returns
  1829. =======
  1830. DomainMatrix
  1831. The rows of this matrix form a basis for the rowspace.
  1832. Examples
  1833. ========
  1834. >>> from sympy import QQ
  1835. >>> from sympy.polys.matrices import DomainMatrix
  1836. >>> A = DomainMatrix([
  1837. ... [QQ(1), QQ(-1)],
  1838. ... [QQ(2), QQ(-2)]], (2, 2), QQ)
  1839. >>> A.rowspace()
  1840. DomainMatrix([[1, -1]], (1, 2), QQ)
  1841. """
  1842. if not self.domain.is_Field:
  1843. raise DMNotAField('Not a field')
  1844. rref, pivots = self.rref()
  1845. rows, cols = self.shape
  1846. return self.extract(range(len(pivots)), range(cols))
  1847. def nullspace(self, divide_last=False):
  1848. r"""
  1849. Returns the nullspace for the DomainMatrix
  1850. Returns
  1851. =======
  1852. DomainMatrix
  1853. The rows of this matrix form a basis for the nullspace.
  1854. Examples
  1855. ========
  1856. >>> from sympy import QQ
  1857. >>> from sympy.polys.matrices import DM
  1858. >>> A = DM([
  1859. ... [QQ(2), QQ(-2)],
  1860. ... [QQ(4), QQ(-4)]], QQ)
  1861. >>> A.nullspace()
  1862. DomainMatrix([[1, 1]], (1, 2), QQ)
  1863. The returned matrix is a basis for the nullspace:
  1864. >>> A_null = A.nullspace().transpose()
  1865. >>> A * A_null
  1866. DomainMatrix([[0], [0]], (2, 1), QQ)
  1867. >>> rows, cols = A.shape
  1868. >>> nullity = rows - A.rank()
  1869. >>> A_null.shape == (cols, nullity)
  1870. True
  1871. Nullspace can also be computed for non-field rings. If the ring is not
  1872. a field then division is not used. Setting ``divide_last`` to True will
  1873. raise an error in this case:
  1874. >>> from sympy import ZZ
  1875. >>> B = DM([[6, -3],
  1876. ... [4, -2]], ZZ)
  1877. >>> B.nullspace()
  1878. DomainMatrix([[3, 6]], (1, 2), ZZ)
  1879. >>> B.nullspace(divide_last=True)
  1880. Traceback (most recent call last):
  1881. ...
  1882. DMNotAField: Cannot normalize vectors over a non-field
  1883. Over a ring with ``gcd`` defined the nullspace can potentially be
  1884. reduced with :meth:`primitive`:
  1885. >>> B.nullspace().primitive()
  1886. (3, DomainMatrix([[1, 2]], (1, 2), ZZ))
  1887. A matrix over a ring can often be normalized by converting it to a
  1888. field but it is often a bad idea to do so:
  1889. >>> from sympy.abc import a, b, c
  1890. >>> from sympy import Matrix
  1891. >>> M = Matrix([[ a*b, b + c, c],
  1892. ... [ a - b, b*c, c**2],
  1893. ... [a*b + a - b, b*c + b + c, c**2 + c]])
  1894. >>> M.to_DM().domain
  1895. ZZ[a,b,c]
  1896. >>> M.to_DM().nullspace().to_Matrix().transpose()
  1897. Matrix([
  1898. [ c**3],
  1899. [ -a*b*c**2 + a*c - b*c],
  1900. [a*b**2*c - a*b - a*c + b**2 + b*c]])
  1901. The unnormalized form here is nicer than the normalized form that
  1902. spreads a large denominator throughout the matrix:
  1903. >>> M.to_DM().to_field().nullspace(divide_last=True).to_Matrix().transpose()
  1904. Matrix([
  1905. [ c**3/(a*b**2*c - a*b - a*c + b**2 + b*c)],
  1906. [(-a*b*c**2 + a*c - b*c)/(a*b**2*c - a*b - a*c + b**2 + b*c)],
  1907. [ 1]])
  1908. Parameters
  1909. ==========
  1910. divide_last : bool, optional
  1911. If False (the default), the vectors are not normalized and the RREF
  1912. is computed using :meth:`rref_den` and the denominator is
  1913. discarded. If True, then each row is divided by its final element;
  1914. the domain must be a field in this case.
  1915. See Also
  1916. ========
  1917. nullspace_from_rref
  1918. rref
  1919. rref_den
  1920. rowspace
  1921. """
  1922. A = self
  1923. K = A.domain
  1924. if divide_last and not K.is_Field:
  1925. raise DMNotAField("Cannot normalize vectors over a non-field")
  1926. if divide_last:
  1927. A_rref, pivots = A.rref()
  1928. else:
  1929. A_rref, den, pivots = A.rref_den()
  1930. # Ensure that the sign is canonical before discarding the
  1931. # denominator. Then M.nullspace().primitive() is canonical.
  1932. u = K.canonical_unit(den)
  1933. if u != K.one:
  1934. A_rref *= u
  1935. A_null = A_rref.nullspace_from_rref(pivots)
  1936. return A_null
  1937. def nullspace_from_rref(self, pivots=None):
  1938. """
  1939. Compute nullspace from rref and pivots.
  1940. The domain of the matrix can be any domain.
  1941. The matrix must be in reduced row echelon form already. Otherwise the
  1942. result will be incorrect. Use :meth:`rref` or :meth:`rref_den` first
  1943. to get the reduced row echelon form or use :meth:`nullspace` instead.
  1944. See Also
  1945. ========
  1946. nullspace
  1947. rref
  1948. rref_den
  1949. sympy.polys.matrices.sdm.SDM.nullspace_from_rref
  1950. sympy.polys.matrices.ddm.DDM.nullspace_from_rref
  1951. """
  1952. null_rep, nonpivots = self.rep.nullspace_from_rref(pivots)
  1953. return self.from_rep(null_rep)
  1954. def inv(self):
  1955. r"""
  1956. Finds the inverse of the DomainMatrix if exists
  1957. Returns
  1958. =======
  1959. DomainMatrix
  1960. DomainMatrix after inverse
  1961. Raises
  1962. ======
  1963. ValueError
  1964. If the domain of DomainMatrix not a Field
  1965. DMNonSquareMatrixError
  1966. If the DomainMatrix is not a not Square DomainMatrix
  1967. Examples
  1968. ========
  1969. >>> from sympy import QQ
  1970. >>> from sympy.polys.matrices import DomainMatrix
  1971. >>> A = DomainMatrix([
  1972. ... [QQ(2), QQ(-1), QQ(0)],
  1973. ... [QQ(-1), QQ(2), QQ(-1)],
  1974. ... [QQ(0), QQ(0), QQ(2)]], (3, 3), QQ)
  1975. >>> A.inv()
  1976. DomainMatrix([[2/3, 1/3, 1/6], [1/3, 2/3, 1/3], [0, 0, 1/2]], (3, 3), QQ)
  1977. See Also
  1978. ========
  1979. neg
  1980. """
  1981. if not self.domain.is_Field:
  1982. raise DMNotAField('Not a field')
  1983. m, n = self.shape
  1984. if m != n:
  1985. raise DMNonSquareMatrixError
  1986. inv = self.rep.inv()
  1987. return self.from_rep(inv)
  1988. def det(self):
  1989. r"""
  1990. Returns the determinant of a square :class:`DomainMatrix`.
  1991. Returns
  1992. =======
  1993. determinant: DomainElement
  1994. Determinant of the matrix.
  1995. Raises
  1996. ======
  1997. ValueError
  1998. If the domain of DomainMatrix is not a Field
  1999. Examples
  2000. ========
  2001. >>> from sympy import ZZ
  2002. >>> from sympy.polys.matrices import DomainMatrix
  2003. >>> A = DomainMatrix([
  2004. ... [ZZ(1), ZZ(2)],
  2005. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  2006. >>> A.det()
  2007. -2
  2008. """
  2009. m, n = self.shape
  2010. if m != n:
  2011. raise DMNonSquareMatrixError
  2012. return self.rep.det()
  2013. def adj_det(self):
  2014. """
  2015. Adjugate and determinant of a square :class:`DomainMatrix`.
  2016. Returns
  2017. =======
  2018. (adjugate, determinant) : (DomainMatrix, DomainScalar)
  2019. The adjugate matrix and determinant of this matrix.
  2020. Examples
  2021. ========
  2022. >>> from sympy import ZZ
  2023. >>> from sympy.polys.matrices import DM
  2024. >>> A = DM([
  2025. ... [ZZ(1), ZZ(2)],
  2026. ... [ZZ(3), ZZ(4)]], ZZ)
  2027. >>> adjA, detA = A.adj_det()
  2028. >>> adjA
  2029. DomainMatrix([[4, -2], [-3, 1]], (2, 2), ZZ)
  2030. >>> detA
  2031. -2
  2032. See Also
  2033. ========
  2034. adjugate
  2035. Returns only the adjugate matrix.
  2036. det
  2037. Returns only the determinant.
  2038. inv_den
  2039. Returns a matrix/denominator pair representing the inverse matrix
  2040. but perhaps differing from the adjugate and determinant by a common
  2041. factor.
  2042. """
  2043. m, n = self.shape
  2044. I_m = self.eye((m, m), self.domain)
  2045. adjA, detA = self.solve_den_charpoly(I_m, check=False)
  2046. if self.rep.fmt == "dense":
  2047. adjA = adjA.to_dense()
  2048. return adjA, detA
  2049. def adjugate(self):
  2050. """
  2051. Adjugate of a square :class:`DomainMatrix`.
  2052. The adjugate matrix is the transpose of the cofactor matrix and is
  2053. related to the inverse by::
  2054. adj(A) = det(A) * A.inv()
  2055. Unlike the inverse matrix the adjugate matrix can be computed and
  2056. expressed without division or fractions in the ground domain.
  2057. Examples
  2058. ========
  2059. >>> from sympy import ZZ
  2060. >>> from sympy.polys.matrices import DM
  2061. >>> A = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ)
  2062. >>> A.adjugate()
  2063. DomainMatrix([[4, -2], [-3, 1]], (2, 2), ZZ)
  2064. Returns
  2065. =======
  2066. DomainMatrix
  2067. The adjugate matrix of this matrix with the same domain.
  2068. See Also
  2069. ========
  2070. adj_det
  2071. """
  2072. adjA, detA = self.adj_det()
  2073. return adjA
  2074. def inv_den(self, method=None):
  2075. """
  2076. Return the inverse as a :class:`DomainMatrix` with denominator.
  2077. Returns
  2078. =======
  2079. (inv, den) : (:class:`DomainMatrix`, :class:`~.DomainElement`)
  2080. The inverse matrix and its denominator.
  2081. This is more or less equivalent to :meth:`adj_det` except that ``inv``
  2082. and ``den`` are not guaranteed to be the adjugate and inverse. The
  2083. ratio ``inv/den`` is equivalent to ``adj/det`` but some factors
  2084. might be cancelled between ``inv`` and ``den``. In simple cases this
  2085. might just be a minus sign so that ``(inv, den) == (-adj, -det)`` but
  2086. factors more complicated than ``-1`` can also be cancelled.
  2087. Cancellation is not guaranteed to be complete so ``inv`` and ``den``
  2088. may not be on lowest terms. The denominator ``den`` will be zero if and
  2089. only if the determinant is zero.
  2090. If the actual adjugate and determinant are needed, use :meth:`adj_det`
  2091. instead. If the intention is to compute the inverse matrix or solve a
  2092. system of equations then :meth:`inv_den` is more efficient.
  2093. Examples
  2094. ========
  2095. >>> from sympy import ZZ
  2096. >>> from sympy.polys.matrices import DomainMatrix
  2097. >>> A = DomainMatrix([
  2098. ... [ZZ(2), ZZ(-1), ZZ(0)],
  2099. ... [ZZ(-1), ZZ(2), ZZ(-1)],
  2100. ... [ZZ(0), ZZ(0), ZZ(2)]], (3, 3), ZZ)
  2101. >>> Ainv, den = A.inv_den()
  2102. >>> den
  2103. 6
  2104. >>> Ainv
  2105. DomainMatrix([[4, 2, 1], [2, 4, 2], [0, 0, 3]], (3, 3), ZZ)
  2106. >>> A * Ainv == den * A.eye(A.shape, A.domain).to_dense()
  2107. True
  2108. Parameters
  2109. ==========
  2110. method : str, optional
  2111. The method to use to compute the inverse. Can be one of ``None``,
  2112. ``'rref'`` or ``'charpoly'``. If ``None`` then the method is
  2113. chosen automatically (see :meth:`solve_den` for details).
  2114. See Also
  2115. ========
  2116. inv
  2117. det
  2118. adj_det
  2119. solve_den
  2120. """
  2121. I = self.eye(self.shape, self.domain)
  2122. return self.solve_den(I, method=method)
  2123. def solve_den(self, b, method=None):
  2124. """
  2125. Solve matrix equation $Ax = b$ without fractions in the ground domain.
  2126. Examples
  2127. ========
  2128. Solve a matrix equation over the integers:
  2129. >>> from sympy import ZZ
  2130. >>> from sympy.polys.matrices import DM
  2131. >>> A = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ)
  2132. >>> b = DM([[ZZ(5)], [ZZ(6)]], ZZ)
  2133. >>> xnum, xden = A.solve_den(b)
  2134. >>> xden
  2135. -2
  2136. >>> xnum
  2137. DomainMatrix([[8], [-9]], (2, 1), ZZ)
  2138. >>> A * xnum == xden * b
  2139. True
  2140. Solve a matrix equation over a polynomial ring:
  2141. >>> from sympy import ZZ
  2142. >>> from sympy.abc import x, y, z, a, b
  2143. >>> R = ZZ[x, y, z, a, b]
  2144. >>> M = DM([[x*y, x*z], [y*z, x*z]], R)
  2145. >>> b = DM([[a], [b]], R)
  2146. >>> M.to_Matrix()
  2147. Matrix([
  2148. [x*y, x*z],
  2149. [y*z, x*z]])
  2150. >>> b.to_Matrix()
  2151. Matrix([
  2152. [a],
  2153. [b]])
  2154. >>> xnum, xden = M.solve_den(b)
  2155. >>> xden
  2156. x**2*y*z - x*y*z**2
  2157. >>> xnum.to_Matrix()
  2158. Matrix([
  2159. [ a*x*z - b*x*z],
  2160. [-a*y*z + b*x*y]])
  2161. >>> M * xnum == xden * b
  2162. True
  2163. The solution can be expressed over a fraction field which will cancel
  2164. gcds between the denominator and the elements of the numerator:
  2165. >>> xsol = xnum.to_field() / xden
  2166. >>> xsol.to_Matrix()
  2167. Matrix([
  2168. [ (a - b)/(x*y - y*z)],
  2169. [(-a*z + b*x)/(x**2*z - x*z**2)]])
  2170. >>> (M * xsol).to_Matrix() == b.to_Matrix()
  2171. True
  2172. When solving a large system of equations this cancellation step might
  2173. be a lot slower than :func:`solve_den` itself. The solution can also be
  2174. expressed as a ``Matrix`` without attempting any polynomial
  2175. cancellation between the numerator and denominator giving a less
  2176. simplified result more quickly:
  2177. >>> xsol_uncancelled = xnum.to_Matrix() / xnum.domain.to_sympy(xden)
  2178. >>> xsol_uncancelled
  2179. Matrix([
  2180. [ (a*x*z - b*x*z)/(x**2*y*z - x*y*z**2)],
  2181. [(-a*y*z + b*x*y)/(x**2*y*z - x*y*z**2)]])
  2182. >>> from sympy import cancel
  2183. >>> cancel(xsol_uncancelled) == xsol.to_Matrix()
  2184. True
  2185. Parameters
  2186. ==========
  2187. self : :class:`DomainMatrix`
  2188. The ``m x n`` matrix $A$ in the equation $Ax = b$. Underdetermined
  2189. systems are not supported so ``m >= n``: $A$ should be square or
  2190. have more rows than columns.
  2191. b : :class:`DomainMatrix`
  2192. The ``n x m`` matrix $b$ for the rhs.
  2193. cp : list of :class:`~.DomainElement`, optional
  2194. The characteristic polynomial of the matrix $A$. If not given, it
  2195. will be computed using :meth:`charpoly`.
  2196. method: str, optional
  2197. The method to use for solving the system. Can be one of ``None``,
  2198. ``'charpoly'`` or ``'rref'``. If ``None`` (the default) then the
  2199. method will be chosen automatically.
  2200. The ``charpoly`` method uses :meth:`solve_den_charpoly` and can
  2201. only be used if the matrix is square. This method is division free
  2202. and can be used with any domain.
  2203. The ``rref`` method is fraction free but requires exact division
  2204. in the ground domain (``exquo``). This is also suitable for most
  2205. domains. This method can be used with overdetermined systems (more
  2206. equations than unknowns) but not underdetermined systems as a
  2207. unique solution is sought.
  2208. Returns
  2209. =======
  2210. (xnum, xden) : (DomainMatrix, DomainElement)
  2211. The solution of the equation $Ax = b$ as a pair consisting of an
  2212. ``n x m`` matrix numerator ``xnum`` and a scalar denominator
  2213. ``xden``.
  2214. The solution $x$ is given by ``x = xnum / xden``. The division free
  2215. invariant is ``A * xnum == xden * b``. If $A$ is square then the
  2216. denominator ``xden`` will be a divisor of the determinant $det(A)$.
  2217. Raises
  2218. ======
  2219. DMNonInvertibleMatrixError
  2220. If the system $Ax = b$ does not have a unique solution.
  2221. See Also
  2222. ========
  2223. solve_den_charpoly
  2224. solve_den_rref
  2225. inv_den
  2226. """
  2227. m, n = self.shape
  2228. bm, bn = b.shape
  2229. if m != bm:
  2230. raise DMShapeError("Matrix equation shape mismatch.")
  2231. if method is None:
  2232. method = 'rref'
  2233. elif method == 'charpoly' and m != n:
  2234. raise DMNonSquareMatrixError("method='charpoly' requires a square matrix.")
  2235. if method == 'charpoly':
  2236. xnum, xden = self.solve_den_charpoly(b)
  2237. elif method == 'rref':
  2238. xnum, xden = self.solve_den_rref(b)
  2239. else:
  2240. raise DMBadInputError("method should be 'rref' or 'charpoly'")
  2241. return xnum, xden
  2242. def solve_den_rref(self, b):
  2243. """
  2244. Solve matrix equation $Ax = b$ using fraction-free RREF
  2245. Solves the matrix equation $Ax = b$ for $x$ and returns the solution
  2246. as a numerator/denominator pair.
  2247. Examples
  2248. ========
  2249. >>> from sympy import ZZ
  2250. >>> from sympy.polys.matrices import DM
  2251. >>> A = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ)
  2252. >>> b = DM([[ZZ(5)], [ZZ(6)]], ZZ)
  2253. >>> xnum, xden = A.solve_den_rref(b)
  2254. >>> xden
  2255. -2
  2256. >>> xnum
  2257. DomainMatrix([[8], [-9]], (2, 1), ZZ)
  2258. >>> A * xnum == xden * b
  2259. True
  2260. See Also
  2261. ========
  2262. solve_den
  2263. solve_den_charpoly
  2264. """
  2265. A = self
  2266. m, n = A.shape
  2267. bm, bn = b.shape
  2268. if m != bm:
  2269. raise DMShapeError("Matrix equation shape mismatch.")
  2270. if m < n:
  2271. raise DMShapeError("Underdetermined matrix equation.")
  2272. Aaug = A.hstack(b)
  2273. Aaug_rref, denom, pivots = Aaug.rref_den()
  2274. # XXX: We check here if there are pivots after the last column. If
  2275. # there were than it possibly means that rref_den performed some
  2276. # unnecessary elimination. It would be better if rref methods had a
  2277. # parameter indicating how many columns should be used for elimination.
  2278. if len(pivots) != n or pivots and pivots[-1] >= n:
  2279. raise DMNonInvertibleMatrixError("Non-unique solution.")
  2280. xnum = Aaug_rref[:n, n:]
  2281. xden = denom
  2282. return xnum, xden
  2283. def solve_den_charpoly(self, b, cp=None, check=True):
  2284. """
  2285. Solve matrix equation $Ax = b$ using the characteristic polynomial.
  2286. This method solves the square matrix equation $Ax = b$ for $x$ using
  2287. the characteristic polynomial without any division or fractions in the
  2288. ground domain.
  2289. Examples
  2290. ========
  2291. Solve a matrix equation over the integers:
  2292. >>> from sympy import ZZ
  2293. >>> from sympy.polys.matrices import DM
  2294. >>> A = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ)
  2295. >>> b = DM([[ZZ(5)], [ZZ(6)]], ZZ)
  2296. >>> xnum, detA = A.solve_den_charpoly(b)
  2297. >>> detA
  2298. -2
  2299. >>> xnum
  2300. DomainMatrix([[8], [-9]], (2, 1), ZZ)
  2301. >>> A * xnum == detA * b
  2302. True
  2303. Parameters
  2304. ==========
  2305. self : DomainMatrix
  2306. The ``n x n`` matrix `A` in the equation `Ax = b`. Must be square
  2307. and invertible.
  2308. b : DomainMatrix
  2309. The ``n x m`` matrix `b` for the rhs.
  2310. cp : list, optional
  2311. The characteristic polynomial of the matrix `A` if known. If not
  2312. given, it will be computed using :meth:`charpoly`.
  2313. check : bool, optional
  2314. If ``True`` (the default) check that the determinant is not zero
  2315. and raise an error if it is. If ``False`` then if the determinant
  2316. is zero the return value will be equal to ``(A.adjugate()*b, 0)``.
  2317. Returns
  2318. =======
  2319. (xnum, detA) : (DomainMatrix, DomainElement)
  2320. The solution of the equation `Ax = b` as a matrix numerator and
  2321. scalar denominator pair. The denominator is equal to the
  2322. determinant of `A` and the numerator is ``adj(A)*b``.
  2323. The solution $x$ is given by ``x = xnum / detA``. The division free
  2324. invariant is ``A * xnum == detA * b``.
  2325. If ``b`` is the identity matrix, then ``xnum`` is the adjugate matrix
  2326. and we have ``A * adj(A) == detA * I``.
  2327. See Also
  2328. ========
  2329. solve_den
  2330. Main frontend for solving matrix equations with denominator.
  2331. solve_den_rref
  2332. Solve matrix equations using fraction-free RREF.
  2333. inv_den
  2334. Invert a matrix using the characteristic polynomial.
  2335. """
  2336. A, b = self.unify(b)
  2337. m, n = self.shape
  2338. mb, nb = b.shape
  2339. if m != n:
  2340. raise DMNonSquareMatrixError("Matrix must be square")
  2341. if mb != m:
  2342. raise DMShapeError("Matrix and vector must have the same number of rows")
  2343. f, detA = self.adj_poly_det(cp=cp)
  2344. if check and not detA:
  2345. raise DMNonInvertibleMatrixError("Matrix is not invertible")
  2346. # Compute adj(A)*b = det(A)*inv(A)*b using Horner's method without
  2347. # constructing inv(A) explicitly.
  2348. adjA_b = self.eval_poly_mul(f, b)
  2349. return (adjA_b, detA)
  2350. def adj_poly_det(self, cp=None):
  2351. """
  2352. Return the polynomial $p$ such that $p(A) = adj(A)$ and also the
  2353. determinant of $A$.
  2354. Examples
  2355. ========
  2356. >>> from sympy import QQ
  2357. >>> from sympy.polys.matrices import DM
  2358. >>> A = DM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], QQ)
  2359. >>> p, detA = A.adj_poly_det()
  2360. >>> p
  2361. [-1, 5]
  2362. >>> p_A = A.eval_poly(p)
  2363. >>> p_A
  2364. DomainMatrix([[4, -2], [-3, 1]], (2, 2), QQ)
  2365. >>> p[0]*A**1 + p[1]*A**0 == p_A
  2366. True
  2367. >>> p_A == A.adjugate()
  2368. True
  2369. >>> A * A.adjugate() == detA * A.eye(A.shape, A.domain).to_dense()
  2370. True
  2371. See Also
  2372. ========
  2373. adjugate
  2374. eval_poly
  2375. adj_det
  2376. """
  2377. # Cayley-Hamilton says that a matrix satisfies its own minimal
  2378. # polynomial
  2379. #
  2380. # p[0]*A^n + p[1]*A^(n-1) + ... + p[n]*I = 0
  2381. #
  2382. # with p[0]=1 and p[n]=(-1)^n*det(A) or
  2383. #
  2384. # det(A)*I = -(-1)^n*(p[0]*A^(n-1) + p[1]*A^(n-2) + ... + p[n-1]*A).
  2385. #
  2386. # Define a new polynomial f with f[i] = -(-1)^n*p[i] for i=0..n-1. Then
  2387. #
  2388. # det(A)*I = f[0]*A^n + f[1]*A^(n-1) + ... + f[n-1]*A.
  2389. #
  2390. # Multiplying on the right by inv(A) gives
  2391. #
  2392. # det(A)*inv(A) = f[0]*A^(n-1) + f[1]*A^(n-2) + ... + f[n-1].
  2393. #
  2394. # So adj(A) = det(A)*inv(A) = f(A)
  2395. A = self
  2396. m, n = self.shape
  2397. if m != n:
  2398. raise DMNonSquareMatrixError("Matrix must be square")
  2399. if cp is None:
  2400. cp = A.charpoly()
  2401. if len(cp) % 2:
  2402. # n is even
  2403. detA = cp[-1]
  2404. f = [-cpi for cpi in cp[:-1]]
  2405. else:
  2406. # n is odd
  2407. detA = -cp[-1]
  2408. f = cp[:-1]
  2409. return f, detA
  2410. def eval_poly(self, p):
  2411. """
  2412. Evaluate polynomial function of a matrix $p(A)$.
  2413. Examples
  2414. ========
  2415. >>> from sympy import QQ
  2416. >>> from sympy.polys.matrices import DM
  2417. >>> A = DM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], QQ)
  2418. >>> p = [QQ(1), QQ(2), QQ(3)]
  2419. >>> p_A = A.eval_poly(p)
  2420. >>> p_A
  2421. DomainMatrix([[12, 14], [21, 33]], (2, 2), QQ)
  2422. >>> p_A == p[0]*A**2 + p[1]*A + p[2]*A**0
  2423. True
  2424. See Also
  2425. ========
  2426. eval_poly_mul
  2427. """
  2428. A = self
  2429. m, n = A.shape
  2430. if m != n:
  2431. raise DMNonSquareMatrixError("Matrix must be square")
  2432. if not p:
  2433. return self.zeros(self.shape, self.domain)
  2434. elif len(p) == 1:
  2435. return p[0] * self.eye(self.shape, self.domain)
  2436. # Evaluate p(A) using Horner's method:
  2437. # XXX: Use Paterson-Stockmeyer method?
  2438. I = A.eye(A.shape, A.domain)
  2439. p_A = p[0] * I
  2440. for pi in p[1:]:
  2441. p_A = A*p_A + pi*I
  2442. return p_A
  2443. def eval_poly_mul(self, p, B):
  2444. r"""
  2445. Evaluate polynomial matrix product $p(A) \times B$.
  2446. Evaluate the polynomial matrix product $p(A) \times B$ using Horner's
  2447. method without creating the matrix $p(A)$ explicitly. If $B$ is a
  2448. column matrix then this method will only use matrix-vector multiplies
  2449. and no matrix-matrix multiplies are needed.
  2450. If $B$ is square or wide or if $A$ can be represented in a simpler
  2451. domain than $B$ then it might be faster to evaluate $p(A)$ explicitly
  2452. (see :func:`eval_poly`) and then multiply with $B$.
  2453. Examples
  2454. ========
  2455. >>> from sympy import QQ
  2456. >>> from sympy.polys.matrices import DM
  2457. >>> A = DM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], QQ)
  2458. >>> b = DM([[QQ(5)], [QQ(6)]], QQ)
  2459. >>> p = [QQ(1), QQ(2), QQ(3)]
  2460. >>> p_A_b = A.eval_poly_mul(p, b)
  2461. >>> p_A_b
  2462. DomainMatrix([[144], [303]], (2, 1), QQ)
  2463. >>> p_A_b == p[0]*A**2*b + p[1]*A*b + p[2]*b
  2464. True
  2465. >>> A.eval_poly_mul(p, b) == A.eval_poly(p)*b
  2466. True
  2467. See Also
  2468. ========
  2469. eval_poly
  2470. solve_den_charpoly
  2471. """
  2472. A = self
  2473. m, n = A.shape
  2474. mb, nb = B.shape
  2475. if m != n:
  2476. raise DMNonSquareMatrixError("Matrix must be square")
  2477. if mb != n:
  2478. raise DMShapeError("Matrices are not aligned")
  2479. if A.domain != B.domain:
  2480. raise DMDomainError("Matrices must have the same domain")
  2481. # Given a polynomial p(x) = p[0]*x^n + p[1]*x^(n-1) + ... + p[n-1]
  2482. # and matrices A and B we want to find
  2483. #
  2484. # p(A)*B = p[0]*A^n*B + p[1]*A^(n-1)*B + ... + p[n-1]*B
  2485. #
  2486. # Factoring out A term by term we get
  2487. #
  2488. # p(A)*B = A*(...A*(A*(A*(p[0]*B) + p[1]*B) + p[2]*B) + ...) + p[n-1]*B
  2489. #
  2490. # where each pair of brackets represents one iteration of the loop
  2491. # below starting from the innermost p[0]*B. If B is a column matrix
  2492. # then products like A*(...) are matrix-vector multiplies and products
  2493. # like p[i]*B are scalar-vector multiplies so there are no
  2494. # matrix-matrix multiplies.
  2495. if not p:
  2496. return B.zeros(B.shape, B.domain, fmt=B.rep.fmt)
  2497. p_A_B = p[0]*B
  2498. for p_i in p[1:]:
  2499. p_A_B = A*p_A_B + p_i*B
  2500. return p_A_B
  2501. def lu(self):
  2502. r"""
  2503. Returns Lower and Upper decomposition of the DomainMatrix
  2504. Returns
  2505. =======
  2506. (L, U, exchange)
  2507. L, U are Lower and Upper decomposition of the DomainMatrix,
  2508. exchange is the list of indices of rows exchanged in the
  2509. decomposition.
  2510. Raises
  2511. ======
  2512. ValueError
  2513. If the domain of DomainMatrix not a Field
  2514. Examples
  2515. ========
  2516. >>> from sympy import QQ
  2517. >>> from sympy.polys.matrices import DomainMatrix
  2518. >>> A = DomainMatrix([
  2519. ... [QQ(1), QQ(-1)],
  2520. ... [QQ(2), QQ(-2)]], (2, 2), QQ)
  2521. >>> L, U, exchange = A.lu()
  2522. >>> L
  2523. DomainMatrix([[1, 0], [2, 1]], (2, 2), QQ)
  2524. >>> U
  2525. DomainMatrix([[1, -1], [0, 0]], (2, 2), QQ)
  2526. >>> exchange
  2527. []
  2528. See Also
  2529. ========
  2530. lu_solve
  2531. """
  2532. if not self.domain.is_Field:
  2533. raise DMNotAField('Not a field')
  2534. L, U, swaps = self.rep.lu()
  2535. return self.from_rep(L), self.from_rep(U), swaps
  2536. def qr(self):
  2537. r"""
  2538. QR decomposition of the DomainMatrix.
  2539. Explanation
  2540. ===========
  2541. The QR decomposition expresses a matrix as the product of an orthogonal
  2542. matrix (Q) and an upper triangular matrix (R). In this implementation,
  2543. Q is not orthonormal: its columns are orthogonal but not normalized to
  2544. unit vectors. This avoids unnecessary divisions and is particularly
  2545. suited for exact arithmetic domains.
  2546. Note
  2547. ====
  2548. This implementation is valid only for matrices over real domains. For
  2549. matrices over complex domains, a proper QR decomposition would require
  2550. handling conjugation to ensure orthogonality.
  2551. Returns
  2552. =======
  2553. (Q, R)
  2554. Q is the orthogonal matrix, and R is the upper triangular matrix
  2555. resulting from the QR decomposition of the DomainMatrix.
  2556. Raises
  2557. ======
  2558. DMDomainError
  2559. If the domain of the DomainMatrix is not a field (e.g., QQ).
  2560. Examples
  2561. ========
  2562. >>> from sympy import QQ
  2563. >>> from sympy.polys.matrices import DomainMatrix
  2564. >>> A = DomainMatrix([[1, 2], [3, 4], [5, 6]], (3, 2), QQ)
  2565. >>> Q, R = A.qr()
  2566. >>> Q
  2567. DomainMatrix([[1, 26/35], [3, 8/35], [5, -2/7]], (3, 2), QQ)
  2568. >>> R
  2569. DomainMatrix([[1, 44/35], [0, 1]], (2, 2), QQ)
  2570. >>> Q * R == A
  2571. True
  2572. >>> (Q.transpose() * Q).is_diagonal
  2573. True
  2574. >>> R.is_upper
  2575. True
  2576. See Also
  2577. ========
  2578. lu
  2579. """
  2580. ddm_q, ddm_r = self.rep.qr()
  2581. Q = self.from_rep(ddm_q)
  2582. R = self.from_rep(ddm_r)
  2583. return Q, R
  2584. def lu_solve(self, rhs):
  2585. r"""
  2586. Solver for DomainMatrix x in the A*x = B
  2587. Parameters
  2588. ==========
  2589. rhs : DomainMatrix B
  2590. Returns
  2591. =======
  2592. DomainMatrix
  2593. x in A*x = B
  2594. Raises
  2595. ======
  2596. DMShapeError
  2597. If the DomainMatrix A and rhs have different number of rows
  2598. ValueError
  2599. If the domain of DomainMatrix A not a Field
  2600. Examples
  2601. ========
  2602. >>> from sympy import QQ
  2603. >>> from sympy.polys.matrices import DomainMatrix
  2604. >>> A = DomainMatrix([
  2605. ... [QQ(1), QQ(2)],
  2606. ... [QQ(3), QQ(4)]], (2, 2), QQ)
  2607. >>> B = DomainMatrix([
  2608. ... [QQ(1), QQ(1)],
  2609. ... [QQ(0), QQ(1)]], (2, 2), QQ)
  2610. >>> A.lu_solve(B)
  2611. DomainMatrix([[-2, -1], [3/2, 1]], (2, 2), QQ)
  2612. See Also
  2613. ========
  2614. lu
  2615. """
  2616. if self.shape[0] != rhs.shape[0]:
  2617. raise DMShapeError("Shape")
  2618. if not self.domain.is_Field:
  2619. raise DMNotAField('Not a field')
  2620. sol = self.rep.lu_solve(rhs.rep)
  2621. return self.from_rep(sol)
  2622. def fflu(self):
  2623. """
  2624. Fraction-free LU decomposition of DomainMatrix.
  2625. Explanation
  2626. ===========
  2627. This method computes the PLDU decomposition
  2628. using Gauss-Bareiss elimination in a fraction-free manner,
  2629. it ensures that all intermediate results remain in
  2630. the domain of the input matrix. Unlike standard
  2631. LU decomposition, which introduces division, this approach
  2632. avoids fractions, making it particularly suitable
  2633. for exact arithmetic over integers or polynomials.
  2634. This method satisfies the invariant:
  2635. P * A = L * inv(D) * U
  2636. Returns
  2637. =======
  2638. (P, L, D, U)
  2639. - P (Permutation matrix)
  2640. - L (Lower triangular matrix)
  2641. - D (Diagonal matrix)
  2642. - U (Upper triangular matrix)
  2643. Examples
  2644. ========
  2645. >>> from sympy import ZZ
  2646. >>> from sympy.polys.matrices import DomainMatrix
  2647. >>> A = DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)
  2648. >>> P, L, D, U = A.fflu()
  2649. >>> P
  2650. DomainMatrix([[1, 0], [0, 1]], (2, 2), ZZ)
  2651. >>> L
  2652. DomainMatrix([[1, 0], [3, -2]], (2, 2), ZZ)
  2653. >>> D
  2654. DomainMatrix([[1, 0], [0, -2]], (2, 2), ZZ)
  2655. >>> U
  2656. DomainMatrix([[1, 2], [0, -2]], (2, 2), ZZ)
  2657. >>> L.is_lower and U.is_upper and D.is_diagonal
  2658. True
  2659. >>> L * D.to_field().inv() * U == P * A.to_field()
  2660. True
  2661. >>> I, d = D.inv_den()
  2662. >>> L * I * U == d * P * A
  2663. True
  2664. See Also
  2665. ========
  2666. sympy.polys.matrices.ddm.DDM.fflu
  2667. References
  2668. ==========
  2669. .. [1] Nakos, G. C., Turner, P. R., & Williams, R. M. (1997). Fraction-free
  2670. algorithms for linear and polynomial equations. ACM SIGSAM Bulletin,
  2671. 31(3), 11-19. https://doi.org/10.1145/271130.271133
  2672. .. [2] Middeke, J.; Jeffrey, D.J.; Koutschan, C. (2020), "Common Factors
  2673. in Fraction-Free Matrix Decompositions", Mathematics in Computer Science,
  2674. 15 (4): 589–608, arXiv:2005.12380, doi:10.1007/s11786-020-00495-9
  2675. .. [3] https://en.wikipedia.org/wiki/Bareiss_algorithm
  2676. """
  2677. from_rep = self.from_rep
  2678. P, L, D, U = self.rep.fflu()
  2679. return from_rep(P), from_rep(L), from_rep(D), from_rep(U)
  2680. def _solve(A, b):
  2681. # XXX: Not sure about this method or its signature. It is just created
  2682. # because it is needed by the holonomic module.
  2683. if A.shape[0] != b.shape[0]:
  2684. raise DMShapeError("Shape")
  2685. if A.domain != b.domain or not A.domain.is_Field:
  2686. raise DMNotAField('Not a field')
  2687. Aaug = A.hstack(b)
  2688. Arref, pivots = Aaug.rref()
  2689. particular = Arref.from_rep(Arref.rep.particular())
  2690. nullspace_rep, nonpivots = Arref[:,:-1].rep.nullspace()
  2691. nullspace = Arref.from_rep(nullspace_rep)
  2692. return particular, nullspace
  2693. def charpoly(self):
  2694. r"""
  2695. Characteristic polynomial of a square matrix.
  2696. Computes the characteristic polynomial in a fully expanded form using
  2697. division free arithmetic. If a factorization of the characteristic
  2698. polynomial is needed then it is more efficient to call
  2699. :meth:`charpoly_factor_list` than calling :meth:`charpoly` and then
  2700. factorizing the result.
  2701. Returns
  2702. =======
  2703. list: list of DomainElement
  2704. coefficients of the characteristic polynomial
  2705. Examples
  2706. ========
  2707. >>> from sympy import ZZ
  2708. >>> from sympy.polys.matrices import DomainMatrix
  2709. >>> A = DomainMatrix([
  2710. ... [ZZ(1), ZZ(2)],
  2711. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  2712. >>> A.charpoly()
  2713. [1, -5, -2]
  2714. See Also
  2715. ========
  2716. charpoly_factor_list
  2717. Compute the factorisation of the characteristic polynomial.
  2718. charpoly_factor_blocks
  2719. A partial factorisation of the characteristic polynomial that can
  2720. be computed more efficiently than either the full factorisation or
  2721. the fully expanded polynomial.
  2722. """
  2723. M = self
  2724. K = M.domain
  2725. factors = M.charpoly_factor_blocks()
  2726. cp = [K.one]
  2727. for f, mult in factors:
  2728. for _ in range(mult):
  2729. cp = dup_mul(cp, f, K)
  2730. return cp
  2731. def charpoly_factor_list(self):
  2732. """
  2733. Full factorization of the characteristic polynomial.
  2734. Examples
  2735. ========
  2736. >>> from sympy.polys.matrices import DM
  2737. >>> from sympy import ZZ
  2738. >>> M = DM([[6, -1, 0, 0],
  2739. ... [9, 12, 0, 0],
  2740. ... [0, 0, 1, 2],
  2741. ... [0, 0, 5, 6]], ZZ)
  2742. Compute the factorization of the characteristic polynomial:
  2743. >>> M.charpoly_factor_list()
  2744. [([1, -9], 2), ([1, -7, -4], 1)]
  2745. Use :meth:`charpoly` to get the unfactorized characteristic polynomial:
  2746. >>> M.charpoly()
  2747. [1, -25, 203, -495, -324]
  2748. The same calculations with ``Matrix``:
  2749. >>> M.to_Matrix().charpoly().as_expr()
  2750. lambda**4 - 25*lambda**3 + 203*lambda**2 - 495*lambda - 324
  2751. >>> M.to_Matrix().charpoly().as_expr().factor()
  2752. (lambda - 9)**2*(lambda**2 - 7*lambda - 4)
  2753. Returns
  2754. =======
  2755. list: list of pairs (factor, multiplicity)
  2756. A full factorization of the characteristic polynomial.
  2757. See Also
  2758. ========
  2759. charpoly
  2760. Expanded form of the characteristic polynomial.
  2761. charpoly_factor_blocks
  2762. A partial factorisation of the characteristic polynomial that can
  2763. be computed more efficiently.
  2764. """
  2765. M = self
  2766. K = M.domain
  2767. # It is more efficient to start from the partial factorization provided
  2768. # for free by M.charpoly_factor_blocks than the expanded M.charpoly.
  2769. factors = M.charpoly_factor_blocks()
  2770. factors_irreducible = []
  2771. for factor_i, mult_i in factors:
  2772. _, factors_list = dup_factor_list(factor_i, K)
  2773. for factor_j, mult_j in factors_list:
  2774. factors_irreducible.append((factor_j, mult_i * mult_j))
  2775. return _collect_factors(factors_irreducible)
  2776. def charpoly_factor_blocks(self):
  2777. """
  2778. Partial factorisation of the characteristic polynomial.
  2779. This factorisation arises from a block structure of the matrix (if any)
  2780. and so the factors are not guaranteed to be irreducible. The
  2781. :meth:`charpoly_factor_blocks` method is the most efficient way to get
  2782. a representation of the characteristic polynomial but the result is
  2783. neither fully expanded nor fully factored.
  2784. Examples
  2785. ========
  2786. >>> from sympy.polys.matrices import DM
  2787. >>> from sympy import ZZ
  2788. >>> M = DM([[6, -1, 0, 0],
  2789. ... [9, 12, 0, 0],
  2790. ... [0, 0, 1, 2],
  2791. ... [0, 0, 5, 6]], ZZ)
  2792. This computes a partial factorization using only the block structure of
  2793. the matrix to reveal factors:
  2794. >>> M.charpoly_factor_blocks()
  2795. [([1, -18, 81], 1), ([1, -7, -4], 1)]
  2796. These factors correspond to the two diagonal blocks in the matrix:
  2797. >>> DM([[6, -1], [9, 12]], ZZ).charpoly()
  2798. [1, -18, 81]
  2799. >>> DM([[1, 2], [5, 6]], ZZ).charpoly()
  2800. [1, -7, -4]
  2801. Use :meth:`charpoly_factor_list` to get a complete factorization into
  2802. irreducibles:
  2803. >>> M.charpoly_factor_list()
  2804. [([1, -9], 2), ([1, -7, -4], 1)]
  2805. Use :meth:`charpoly` to get the expanded characteristic polynomial:
  2806. >>> M.charpoly()
  2807. [1, -25, 203, -495, -324]
  2808. Returns
  2809. =======
  2810. list: list of pairs (factor, multiplicity)
  2811. A partial factorization of the characteristic polynomial.
  2812. See Also
  2813. ========
  2814. charpoly
  2815. Compute the fully expanded characteristic polynomial.
  2816. charpoly_factor_list
  2817. Compute a full factorization of the characteristic polynomial.
  2818. """
  2819. M = self
  2820. if not M.is_square:
  2821. raise DMNonSquareMatrixError("not square")
  2822. # scc returns indices that permute the matrix into block triangular
  2823. # form and can extract the diagonal blocks. M.charpoly() is equal to
  2824. # the product of the diagonal block charpolys.
  2825. components = M.scc()
  2826. block_factors = []
  2827. for indices in components:
  2828. block = M.extract(indices, indices)
  2829. block_factors.append((block.charpoly_base(), 1))
  2830. return _collect_factors(block_factors)
  2831. def charpoly_base(self):
  2832. """
  2833. Base case for :meth:`charpoly_factor_blocks` after block decomposition.
  2834. This method is used internally by :meth:`charpoly_factor_blocks` as the
  2835. base case for computing the characteristic polynomial of a block. It is
  2836. more efficient to call :meth:`charpoly_factor_blocks`, :meth:`charpoly`
  2837. or :meth:`charpoly_factor_list` rather than call this method directly.
  2838. This will use either the dense or the sparse implementation depending
  2839. on the sparsity of the matrix and will clear denominators if possible
  2840. before calling :meth:`charpoly_berk` to compute the characteristic
  2841. polynomial using the Berkowitz algorithm.
  2842. See Also
  2843. ========
  2844. charpoly
  2845. charpoly_factor_list
  2846. charpoly_factor_blocks
  2847. charpoly_berk
  2848. """
  2849. M = self
  2850. K = M.domain
  2851. # It seems that the sparse implementation is always faster for random
  2852. # matrices with fewer than 50% non-zero entries. This does not seem to
  2853. # depend on domain, size, bit count etc.
  2854. density = self.nnz() / self.shape[0]**2
  2855. if density < 0.5:
  2856. M = M.to_sparse()
  2857. else:
  2858. M = M.to_dense()
  2859. # Clearing denominators is always more efficient if it can be done.
  2860. # Doing it here after block decomposition is good because each block
  2861. # might have a smaller denominator. However it might be better for
  2862. # charpoly and charpoly_factor_list to restore the denominators only at
  2863. # the very end so that they can call e.g. dup_factor_list before
  2864. # restoring the denominators. The methods would need to be changed to
  2865. # return (poly, denom) pairs to make that work though.
  2866. clear_denoms = K.is_Field and K.has_assoc_Ring
  2867. if clear_denoms:
  2868. clear_denoms = True
  2869. d, M = M.clear_denoms(convert=True)
  2870. d = d.element
  2871. K_f = K
  2872. K_r = M.domain
  2873. # Berkowitz algorithm over K_r.
  2874. cp = M.charpoly_berk()
  2875. if clear_denoms:
  2876. # Restore the denominator in the charpoly over K_f.
  2877. #
  2878. # If M = N/d then p_M(x) = p_N(x*d)/d^n.
  2879. cp = dup_convert(cp, K_r, K_f)
  2880. p = [K_f.one, K_f.zero]
  2881. q = [K_f.one/d]
  2882. cp = dup_transform(cp, p, q, K_f)
  2883. return cp
  2884. def charpoly_berk(self):
  2885. """Compute the characteristic polynomial using the Berkowitz algorithm.
  2886. This method directly calls the underlying implementation of the
  2887. Berkowitz algorithm (:meth:`sympy.polys.matrices.dense.ddm_berk` or
  2888. :meth:`sympy.polys.matrices.sdm.sdm_berk`).
  2889. This is used by :meth:`charpoly` and other methods as the base case for
  2890. for computing the characteristic polynomial. However those methods will
  2891. apply other optimizations such as block decomposition, clearing
  2892. denominators and converting between dense and sparse representations
  2893. before calling this method. It is more efficient to call those methods
  2894. instead of this one but this method is provided for direct access to
  2895. the Berkowitz algorithm.
  2896. Examples
  2897. ========
  2898. >>> from sympy.polys.matrices import DM
  2899. >>> from sympy import QQ
  2900. >>> M = DM([[6, -1, 0, 0],
  2901. ... [9, 12, 0, 0],
  2902. ... [0, 0, 1, 2],
  2903. ... [0, 0, 5, 6]], QQ)
  2904. >>> M.charpoly_berk()
  2905. [1, -25, 203, -495, -324]
  2906. See Also
  2907. ========
  2908. charpoly
  2909. charpoly_base
  2910. charpoly_factor_list
  2911. charpoly_factor_blocks
  2912. sympy.polys.matrices.dense.ddm_berk
  2913. sympy.polys.matrices.sdm.sdm_berk
  2914. """
  2915. return self.rep.charpoly()
  2916. @classmethod
  2917. def eye(cls, shape, domain):
  2918. r"""
  2919. Return identity matrix of size n or shape (m, n).
  2920. Examples
  2921. ========
  2922. >>> from sympy.polys.matrices import DomainMatrix
  2923. >>> from sympy import QQ
  2924. >>> DomainMatrix.eye(3, QQ)
  2925. DomainMatrix({0: {0: 1}, 1: {1: 1}, 2: {2: 1}}, (3, 3), QQ)
  2926. """
  2927. if isinstance(shape, int):
  2928. shape = (shape, shape)
  2929. return cls.from_rep(SDM.eye(shape, domain))
  2930. @classmethod
  2931. def diag(cls, diagonal, domain, shape=None):
  2932. r"""
  2933. Return diagonal matrix with entries from ``diagonal``.
  2934. Examples
  2935. ========
  2936. >>> from sympy.polys.matrices import DomainMatrix
  2937. >>> from sympy import ZZ
  2938. >>> DomainMatrix.diag([ZZ(5), ZZ(6)], ZZ)
  2939. DomainMatrix({0: {0: 5}, 1: {1: 6}}, (2, 2), ZZ)
  2940. """
  2941. if shape is None:
  2942. N = len(diagonal)
  2943. shape = (N, N)
  2944. return cls.from_rep(SDM.diag(diagonal, domain, shape))
  2945. @classmethod
  2946. def zeros(cls, shape, domain, *, fmt='sparse'):
  2947. """Returns a zero DomainMatrix of size shape, belonging to the specified domain
  2948. Examples
  2949. ========
  2950. >>> from sympy.polys.matrices import DomainMatrix
  2951. >>> from sympy import QQ
  2952. >>> DomainMatrix.zeros((2, 3), QQ)
  2953. DomainMatrix({}, (2, 3), QQ)
  2954. """
  2955. return cls.from_rep(SDM.zeros(shape, domain))
  2956. @classmethod
  2957. def ones(cls, shape, domain):
  2958. """Returns a DomainMatrix of 1s, of size shape, belonging to the specified domain
  2959. Examples
  2960. ========
  2961. >>> from sympy.polys.matrices import DomainMatrix
  2962. >>> from sympy import QQ
  2963. >>> DomainMatrix.ones((2,3), QQ)
  2964. DomainMatrix([[1, 1, 1], [1, 1, 1]], (2, 3), QQ)
  2965. """
  2966. return cls.from_rep(DDM.ones(shape, domain).to_dfm_or_ddm())
  2967. def __eq__(A, B):
  2968. r"""
  2969. Checks for two DomainMatrix matrices to be equal or not
  2970. Parameters
  2971. ==========
  2972. A, B: DomainMatrix
  2973. to check equality
  2974. Returns
  2975. =======
  2976. Boolean
  2977. True for equal, else False
  2978. Raises
  2979. ======
  2980. NotImplementedError
  2981. If B is not a DomainMatrix
  2982. Examples
  2983. ========
  2984. >>> from sympy import ZZ
  2985. >>> from sympy.polys.matrices import DomainMatrix
  2986. >>> A = DomainMatrix([
  2987. ... [ZZ(1), ZZ(2)],
  2988. ... [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  2989. >>> B = DomainMatrix([
  2990. ... [ZZ(1), ZZ(1)],
  2991. ... [ZZ(0), ZZ(1)]], (2, 2), ZZ)
  2992. >>> A.__eq__(A)
  2993. True
  2994. >>> A.__eq__(B)
  2995. False
  2996. """
  2997. if not isinstance(A, type(B)):
  2998. return NotImplemented
  2999. return A.domain == B.domain and A.rep == B.rep
  3000. def unify_eq(A, B):
  3001. if A.shape != B.shape:
  3002. return False
  3003. if A.domain != B.domain:
  3004. A, B = A.unify(B)
  3005. return A == B
  3006. def lll(A, delta=QQ(3, 4)):
  3007. """
  3008. Performs the Lenstra–Lenstra–Lovász (LLL) basis reduction algorithm.
  3009. See [1]_ and [2]_.
  3010. Parameters
  3011. ==========
  3012. delta : QQ, optional
  3013. The Lovász parameter. Must be in the interval (0.25, 1), with larger
  3014. values producing a more reduced basis. The default is 0.75 for
  3015. historical reasons.
  3016. Returns
  3017. =======
  3018. The reduced basis as a DomainMatrix over ZZ.
  3019. Throws
  3020. ======
  3021. DMValueError: if delta is not in the range (0.25, 1)
  3022. DMShapeError: if the matrix is not of shape (m, n) with m <= n
  3023. DMDomainError: if the matrix domain is not ZZ
  3024. DMRankError: if the matrix contains linearly dependent rows
  3025. Examples
  3026. ========
  3027. >>> from sympy.polys.domains import ZZ, QQ
  3028. >>> from sympy.polys.matrices import DM
  3029. >>> x = DM([[1, 0, 0, 0, -20160],
  3030. ... [0, 1, 0, 0, 33768],
  3031. ... [0, 0, 1, 0, 39578],
  3032. ... [0, 0, 0, 1, 47757]], ZZ)
  3033. >>> y = DM([[10, -3, -2, 8, -4],
  3034. ... [3, -9, 8, 1, -11],
  3035. ... [-3, 13, -9, -3, -9],
  3036. ... [-12, -7, -11, 9, -1]], ZZ)
  3037. >>> assert x.lll(delta=QQ(5, 6)) == y
  3038. Notes
  3039. =====
  3040. The implementation is derived from the Maple code given in Figures 4.3
  3041. and 4.4 of [3]_ (pp.68-69). It uses the efficient method of only calculating
  3042. state updates as they are required.
  3043. See also
  3044. ========
  3045. lll_transform
  3046. References
  3047. ==========
  3048. .. [1] https://en.wikipedia.org/wiki/Lenstra%E2%80%93Lenstra%E2%80%93Lov%C3%A1sz_lattice_basis_reduction_algorithm
  3049. .. [2] https://web.archive.org/web/20221029115428/https://web.cs.elte.hu/~lovasz/scans/lll.pdf
  3050. .. [3] Murray R. Bremner, "Lattice Basis Reduction: An Introduction to the LLL Algorithm and Its Applications"
  3051. """
  3052. return DomainMatrix.from_rep(A.rep.lll(delta=delta))
  3053. def lll_transform(A, delta=QQ(3, 4)):
  3054. """
  3055. Performs the Lenstra–Lenstra–Lovász (LLL) basis reduction algorithm
  3056. and returns the reduced basis and transformation matrix.
  3057. Explanation
  3058. ===========
  3059. Parameters, algorithm and basis are the same as for :meth:`lll` except that
  3060. the return value is a tuple `(B, T)` with `B` the reduced basis and
  3061. `T` a transformation matrix. The original basis `A` is transformed to
  3062. `B` with `T*A == B`. If only `B` is needed then :meth:`lll` should be
  3063. used as it is a little faster.
  3064. Examples
  3065. ========
  3066. >>> from sympy.polys.domains import ZZ, QQ
  3067. >>> from sympy.polys.matrices import DM
  3068. >>> X = DM([[1, 0, 0, 0, -20160],
  3069. ... [0, 1, 0, 0, 33768],
  3070. ... [0, 0, 1, 0, 39578],
  3071. ... [0, 0, 0, 1, 47757]], ZZ)
  3072. >>> B, T = X.lll_transform(delta=QQ(5, 6))
  3073. >>> T * X == B
  3074. True
  3075. See also
  3076. ========
  3077. lll
  3078. """
  3079. reduced, transform = A.rep.lll_transform(delta=delta)
  3080. return DomainMatrix.from_rep(reduced), DomainMatrix.from_rep(transform)
  3081. def _collect_factors(factors_list):
  3082. """
  3083. Collect repeating factors and sort.
  3084. >>> from sympy.polys.matrices.domainmatrix import _collect_factors
  3085. >>> _collect_factors([([1, 2], 2), ([1, 4], 3), ([1, 2], 5)])
  3086. [([1, 4], 3), ([1, 2], 7)]
  3087. """
  3088. factors = Counter()
  3089. for factor, exponent in factors_list:
  3090. factors[tuple(factor)] += exponent
  3091. factors_list = [(list(f), e) for f, e in factors.items()]
  3092. return _sort_factors(factors_list)