test_domainmatrix.py 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383
  1. from sympy.external.gmpy import GROUND_TYPES
  2. from sympy import Integer, Rational, S, sqrt, Matrix, symbols
  3. from sympy import FF, ZZ, QQ, QQ_I, EXRAW
  4. from sympy.polys.matrices.domainmatrix import DomainMatrix, DomainScalar, DM
  5. from sympy.polys.matrices.exceptions import (
  6. DMBadInputError, DMDomainError, DMShapeError, DMFormatError, DMNotAField,
  7. DMNonSquareMatrixError, DMNonInvertibleMatrixError,
  8. )
  9. from sympy.polys.matrices.ddm import DDM
  10. from sympy.polys.matrices.sdm import SDM
  11. from sympy.testing.pytest import raises
  12. def test_DM():
  13. ddm = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  14. A = DM([[1, 2], [3, 4]], ZZ)
  15. if GROUND_TYPES != 'flint':
  16. assert A.rep == ddm
  17. else:
  18. assert A.rep == ddm.to_dfm()
  19. assert A.shape == (2, 2)
  20. assert A.domain == ZZ
  21. def test_DomainMatrix_init():
  22. lol = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]]
  23. dod = {0: {0: ZZ(1), 1:ZZ(2)}, 1: {0:ZZ(3), 1:ZZ(4)}}
  24. ddm = DDM(lol, (2, 2), ZZ)
  25. sdm = SDM(dod, (2, 2), ZZ)
  26. A = DomainMatrix(lol, (2, 2), ZZ)
  27. if GROUND_TYPES != 'flint':
  28. assert A.rep == ddm
  29. else:
  30. assert A.rep == ddm.to_dfm()
  31. assert A.shape == (2, 2)
  32. assert A.domain == ZZ
  33. A = DomainMatrix(dod, (2, 2), ZZ)
  34. assert A.rep == sdm
  35. assert A.shape == (2, 2)
  36. assert A.domain == ZZ
  37. raises(TypeError, lambda: DomainMatrix(ddm, (2, 2), ZZ))
  38. raises(TypeError, lambda: DomainMatrix(sdm, (2, 2), ZZ))
  39. raises(TypeError, lambda: DomainMatrix(Matrix([[1]]), (1, 1), ZZ))
  40. for fmt, rep in [('sparse', sdm), ('dense', ddm)]:
  41. if fmt == 'dense' and GROUND_TYPES == 'flint':
  42. rep = rep.to_dfm()
  43. A = DomainMatrix(lol, (2, 2), ZZ, fmt=fmt)
  44. assert A.rep == rep
  45. A = DomainMatrix(dod, (2, 2), ZZ, fmt=fmt)
  46. assert A.rep == rep
  47. raises(ValueError, lambda: DomainMatrix(lol, (2, 2), ZZ, fmt='invalid'))
  48. raises(DMBadInputError, lambda: DomainMatrix([[ZZ(1), ZZ(2)]], (2, 2), ZZ))
  49. # uses copy
  50. was = [i.copy() for i in lol]
  51. A[0,0] = ZZ(42)
  52. assert was == lol
  53. def test_DomainMatrix_from_rep():
  54. ddm = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  55. A = DomainMatrix.from_rep(ddm)
  56. # XXX: Should from_rep convert to DFM?
  57. assert A.rep == ddm
  58. assert A.shape == (2, 2)
  59. assert A.domain == ZZ
  60. sdm = SDM({0: {0: ZZ(1), 1:ZZ(2)}, 1: {0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
  61. A = DomainMatrix.from_rep(sdm)
  62. assert A.rep == sdm
  63. assert A.shape == (2, 2)
  64. assert A.domain == ZZ
  65. A = DomainMatrix([[ZZ(1)]], (1, 1), ZZ)
  66. raises(TypeError, lambda: DomainMatrix.from_rep(A))
  67. def test_DomainMatrix_from_list():
  68. ddm = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  69. A = DomainMatrix.from_list([[1, 2], [3, 4]], ZZ)
  70. if GROUND_TYPES != 'flint':
  71. assert A.rep == ddm
  72. else:
  73. assert A.rep == ddm.to_dfm()
  74. assert A.shape == (2, 2)
  75. assert A.domain == ZZ
  76. dom = FF(7)
  77. ddm = DDM([[dom(1), dom(2)], [dom(3), dom(4)]], (2, 2), dom)
  78. A = DomainMatrix.from_list([[1, 2], [3, 4]], dom)
  79. if GROUND_TYPES != 'flint':
  80. assert A.rep == ddm
  81. else:
  82. assert A.rep == ddm.to_dfm()
  83. assert A.shape == (2, 2)
  84. assert A.domain == dom
  85. dom = FF(2**127-1)
  86. ddm = DDM([[dom(1), dom(2)], [dom(3), dom(4)]], (2, 2), dom)
  87. A = DomainMatrix.from_list([[1, 2], [3, 4]], dom)
  88. if GROUND_TYPES != 'flint':
  89. assert A.rep == ddm
  90. else:
  91. assert A.rep == ddm.to_dfm()
  92. assert A.shape == (2, 2)
  93. assert A.domain == dom
  94. ddm = DDM([[QQ(1, 2), QQ(3, 1)], [QQ(1, 4), QQ(5, 1)]], (2, 2), QQ)
  95. A = DomainMatrix.from_list([[(1, 2), (3, 1)], [(1, 4), (5, 1)]], QQ)
  96. if GROUND_TYPES != 'flint':
  97. assert A.rep == ddm
  98. else:
  99. assert A.rep == ddm.to_dfm()
  100. assert A.shape == (2, 2)
  101. assert A.domain == QQ
  102. def test_DomainMatrix_from_list_sympy():
  103. ddm = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  104. A = DomainMatrix.from_list_sympy(2, 2, [[1, 2], [3, 4]])
  105. if GROUND_TYPES != 'flint':
  106. assert A.rep == ddm
  107. else:
  108. assert A.rep == ddm.to_dfm()
  109. assert A.shape == (2, 2)
  110. assert A.domain == ZZ
  111. K = QQ.algebraic_field(sqrt(2))
  112. ddm = DDM(
  113. [[K.convert(1 + sqrt(2)), K.convert(2 + sqrt(2))],
  114. [K.convert(3 + sqrt(2)), K.convert(4 + sqrt(2))]],
  115. (2, 2),
  116. K
  117. )
  118. A = DomainMatrix.from_list_sympy(
  119. 2, 2, [[1 + sqrt(2), 2 + sqrt(2)], [3 + sqrt(2), 4 + sqrt(2)]],
  120. extension=True)
  121. assert A.rep == ddm
  122. assert A.shape == (2, 2)
  123. assert A.domain == K
  124. def test_DomainMatrix_from_dict_sympy():
  125. sdm = SDM({0: {0: QQ(1, 2)}, 1: {1: QQ(2, 3)}}, (2, 2), QQ)
  126. sympy_dict = {0: {0: Rational(1, 2)}, 1: {1: Rational(2, 3)}}
  127. A = DomainMatrix.from_dict_sympy(2, 2, sympy_dict)
  128. assert A.rep == sdm
  129. assert A.shape == (2, 2)
  130. assert A.domain == QQ
  131. fds = DomainMatrix.from_dict_sympy
  132. raises(DMBadInputError, lambda: fds(2, 2, {3: {0: Rational(1, 2)}}))
  133. raises(DMBadInputError, lambda: fds(2, 2, {0: {3: Rational(1, 2)}}))
  134. def test_DomainMatrix_from_Matrix():
  135. sdm = SDM({0: {0: ZZ(1), 1: ZZ(2)}, 1: {0: ZZ(3), 1: ZZ(4)}}, (2, 2), ZZ)
  136. A = DomainMatrix.from_Matrix(Matrix([[1, 2], [3, 4]]))
  137. assert A.rep == sdm
  138. assert A.shape == (2, 2)
  139. assert A.domain == ZZ
  140. K = QQ.algebraic_field(sqrt(2))
  141. sdm = SDM(
  142. {0: {0: K.convert(1 + sqrt(2)), 1: K.convert(2 + sqrt(2))},
  143. 1: {0: K.convert(3 + sqrt(2)), 1: K.convert(4 + sqrt(2))}},
  144. (2, 2),
  145. K
  146. )
  147. A = DomainMatrix.from_Matrix(
  148. Matrix([[1 + sqrt(2), 2 + sqrt(2)], [3 + sqrt(2), 4 + sqrt(2)]]),
  149. extension=True)
  150. assert A.rep == sdm
  151. assert A.shape == (2, 2)
  152. assert A.domain == K
  153. A = DomainMatrix.from_Matrix(Matrix([[QQ(1, 2), QQ(3, 4)], [QQ(0, 1), QQ(0, 1)]]), fmt='dense')
  154. ddm = DDM([[QQ(1, 2), QQ(3, 4)], [QQ(0, 1), QQ(0, 1)]], (2, 2), QQ)
  155. if GROUND_TYPES != 'flint':
  156. assert A.rep == ddm
  157. else:
  158. assert A.rep == ddm.to_dfm()
  159. assert A.shape == (2, 2)
  160. assert A.domain == QQ
  161. def test_DomainMatrix_eq():
  162. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  163. assert A == A
  164. B = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(1)]], (2, 2), ZZ)
  165. assert A != B
  166. C = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]]
  167. assert A != C
  168. def test_DomainMatrix_unify_eq():
  169. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  170. B1 = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  171. B2 = DomainMatrix([[QQ(1), QQ(3)], [QQ(3), QQ(4)]], (2, 2), QQ)
  172. B3 = DomainMatrix([[ZZ(1)]], (1, 1), ZZ)
  173. assert A.unify_eq(B1) is True
  174. assert A.unify_eq(B2) is False
  175. assert A.unify_eq(B3) is False
  176. def test_DomainMatrix_get_domain():
  177. K, items = DomainMatrix.get_domain([1, 2, 3, 4])
  178. assert items == [ZZ(1), ZZ(2), ZZ(3), ZZ(4)]
  179. assert K == ZZ
  180. K, items = DomainMatrix.get_domain([1, 2, 3, Rational(1, 2)])
  181. assert items == [QQ(1), QQ(2), QQ(3), QQ(1, 2)]
  182. assert K == QQ
  183. def test_DomainMatrix_convert_to():
  184. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  185. Aq = A.convert_to(QQ)
  186. assert Aq == DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  187. def test_DomainMatrix_choose_domain():
  188. A = [[1, 2], [3, 0]]
  189. assert DM(A, QQ).choose_domain() == DM(A, ZZ)
  190. assert DM(A, QQ).choose_domain(field=True) == DM(A, QQ)
  191. assert DM(A, ZZ).choose_domain(field=True) == DM(A, QQ)
  192. x = symbols('x')
  193. B = [[1, x], [x**2, x**3]]
  194. assert DM(B, QQ[x]).choose_domain(field=True) == DM(B, ZZ.frac_field(x))
  195. def test_DomainMatrix_to_flat_nz():
  196. Adm = DM([[1, 2], [3, 0]], ZZ)
  197. Addm = Adm.rep.to_ddm()
  198. Asdm = Adm.rep.to_sdm()
  199. for A in [Adm, Addm, Asdm]:
  200. elems, data = A.to_flat_nz()
  201. assert A.from_flat_nz(elems, data, A.domain) == A
  202. elemsq = [QQ(e) for e in elems]
  203. assert A.from_flat_nz(elemsq, data, QQ) == A.convert_to(QQ)
  204. elems2 = [2*e for e in elems]
  205. assert A.from_flat_nz(elems2, data, A.domain) == 2*A
  206. def test_DomainMatrix_to_sympy():
  207. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  208. assert A.to_sympy() == A.convert_to(EXRAW)
  209. def test_DomainMatrix_to_field():
  210. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  211. Aq = A.to_field()
  212. assert Aq == DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  213. def test_DomainMatrix_to_sparse():
  214. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  215. A_sparse = A.to_sparse()
  216. assert A_sparse.rep == {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}
  217. def test_DomainMatrix_to_dense():
  218. A = DomainMatrix({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ)
  219. A_dense = A.to_dense()
  220. ddm = DDM([[1, 2], [3, 4]], (2, 2), ZZ)
  221. if GROUND_TYPES != 'flint':
  222. assert A_dense.rep == ddm
  223. else:
  224. assert A_dense.rep == ddm.to_dfm()
  225. def test_DomainMatrix_unify():
  226. Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  227. Aq = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  228. assert Az.unify(Az) == (Az, Az)
  229. assert Az.unify(Aq) == (Aq, Aq)
  230. assert Aq.unify(Az) == (Aq, Aq)
  231. assert Aq.unify(Aq) == (Aq, Aq)
  232. As = DomainMatrix({0: {1: ZZ(1)}, 1:{0:ZZ(2)}}, (2, 2), ZZ)
  233. Ad = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  234. assert As.unify(As) == (As, As)
  235. assert Ad.unify(Ad) == (Ad, Ad)
  236. Bs, Bd = As.unify(Ad, fmt='dense')
  237. assert Bs.rep == DDM([[0, 1], [2, 0]], (2, 2), ZZ).to_dfm_or_ddm()
  238. assert Bd.rep == DDM([[1, 2],[3, 4]], (2, 2), ZZ).to_dfm_or_ddm()
  239. Bs, Bd = As.unify(Ad, fmt='sparse')
  240. assert Bs.rep == SDM({0: {1: 1}, 1: {0: 2}}, (2, 2), ZZ)
  241. assert Bd.rep == SDM({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ)
  242. raises(ValueError, lambda: As.unify(Ad, fmt='invalid'))
  243. def test_DomainMatrix_to_Matrix():
  244. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  245. A_Matrix = Matrix([[1, 2], [3, 4]])
  246. assert A.to_Matrix() == A_Matrix
  247. assert A.to_sparse().to_Matrix() == A_Matrix
  248. assert A.convert_to(QQ).to_Matrix() == A_Matrix
  249. assert A.convert_to(QQ.algebraic_field(sqrt(2))).to_Matrix() == A_Matrix
  250. def test_DomainMatrix_to_list():
  251. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  252. assert A.to_list() == [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]]
  253. def test_DomainMatrix_to_list_flat():
  254. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  255. assert A.to_list_flat() == [ZZ(1), ZZ(2), ZZ(3), ZZ(4)]
  256. def test_DomainMatrix_flat():
  257. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  258. assert A.flat() == [ZZ(1), ZZ(2), ZZ(3), ZZ(4)]
  259. def test_DomainMatrix_from_list_flat():
  260. nums = [ZZ(1), ZZ(2), ZZ(3), ZZ(4)]
  261. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  262. assert DomainMatrix.from_list_flat(nums, (2, 2), ZZ) == A
  263. assert DDM.from_list_flat(nums, (2, 2), ZZ) == A.rep.to_ddm()
  264. assert SDM.from_list_flat(nums, (2, 2), ZZ) == A.rep.to_sdm()
  265. assert A == A.from_list_flat(A.to_list_flat(), A.shape, A.domain)
  266. raises(DMBadInputError, DomainMatrix.from_list_flat, nums, (2, 3), ZZ)
  267. raises(DMBadInputError, DDM.from_list_flat, nums, (2, 3), ZZ)
  268. raises(DMBadInputError, SDM.from_list_flat, nums, (2, 3), ZZ)
  269. def test_DomainMatrix_to_dod():
  270. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  271. assert A.to_dod() == {0: {0: ZZ(1), 1:ZZ(2)}, 1: {0:ZZ(3), 1:ZZ(4)}}
  272. A = DomainMatrix([[ZZ(1), ZZ(0)], [ZZ(0), ZZ(4)]], (2, 2), ZZ)
  273. assert A.to_dod() == {0: {0: ZZ(1)}, 1: {1: ZZ(4)}}
  274. def test_DomainMatrix_from_dod():
  275. items = {0: {0: ZZ(1), 1:ZZ(2)}, 1: {0:ZZ(3), 1:ZZ(4)}}
  276. A = DM([[1, 2], [3, 4]], ZZ)
  277. assert DomainMatrix.from_dod(items, (2, 2), ZZ) == A.to_sparse()
  278. assert A.from_dod_like(items) == A
  279. assert A.from_dod_like(items, QQ) == A.convert_to(QQ)
  280. def test_DomainMatrix_to_dok():
  281. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  282. assert A.to_dok() == {(0, 0):ZZ(1), (0, 1):ZZ(2), (1, 0):ZZ(3), (1, 1):ZZ(4)}
  283. A = DomainMatrix([[ZZ(1), ZZ(0)], [ZZ(0), ZZ(4)]], (2, 2), ZZ)
  284. dok = {(0, 0):ZZ(1), (1, 1):ZZ(4)}
  285. assert A.to_dok() == dok
  286. assert A.to_dense().to_dok() == dok
  287. assert A.to_sparse().to_dok() == dok
  288. assert A.rep.to_ddm().to_dok() == dok
  289. assert A.rep.to_sdm().to_dok() == dok
  290. def test_DomainMatrix_from_dok():
  291. items = {(0, 0): ZZ(1), (1, 1): ZZ(2)}
  292. A = DM([[1, 0], [0, 2]], ZZ)
  293. assert DomainMatrix.from_dok(items, (2, 2), ZZ) == A.to_sparse()
  294. assert DDM.from_dok(items, (2, 2), ZZ) == A.rep.to_ddm()
  295. assert SDM.from_dok(items, (2, 2), ZZ) == A.rep.to_sdm()
  296. def test_DomainMatrix_repr():
  297. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  298. assert repr(A) == 'DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)'
  299. def test_DomainMatrix_transpose():
  300. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  301. AT = DomainMatrix([[ZZ(1), ZZ(3)], [ZZ(2), ZZ(4)]], (2, 2), ZZ)
  302. assert A.transpose() == AT
  303. def test_DomainMatrix_is_zero_matrix():
  304. A = DomainMatrix([[ZZ(1)]], (1, 1), ZZ)
  305. B = DomainMatrix([[ZZ(0)]], (1, 1), ZZ)
  306. assert A.is_zero_matrix is False
  307. assert B.is_zero_matrix is True
  308. def test_DomainMatrix_is_upper():
  309. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(0), ZZ(4)]], (2, 2), ZZ)
  310. B = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  311. assert A.is_upper is True
  312. assert B.is_upper is False
  313. def test_DomainMatrix_is_lower():
  314. A = DomainMatrix([[ZZ(1), ZZ(0)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  315. B = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  316. assert A.is_lower is True
  317. assert B.is_lower is False
  318. def test_DomainMatrix_is_diagonal():
  319. A = DM([[1, 0], [0, 4]], ZZ)
  320. B = DM([[1, 2], [3, 4]], ZZ)
  321. assert A.is_diagonal is A.to_sparse().is_diagonal is True
  322. assert B.is_diagonal is B.to_sparse().is_diagonal is False
  323. def test_DomainMatrix_is_square():
  324. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  325. B = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)], [ZZ(5), ZZ(6)]], (3, 2), ZZ)
  326. assert A.is_square is True
  327. assert B.is_square is False
  328. def test_DomainMatrix_diagonal():
  329. A = DM([[1, 2], [3, 4]], ZZ)
  330. assert A.diagonal() == A.to_sparse().diagonal() == [ZZ(1), ZZ(4)]
  331. A = DM([[1, 2], [3, 4], [5, 6]], ZZ)
  332. assert A.diagonal() == A.to_sparse().diagonal() == [ZZ(1), ZZ(4)]
  333. A = DM([[1, 2, 3], [4, 5, 6]], ZZ)
  334. assert A.diagonal() == A.to_sparse().diagonal() == [ZZ(1), ZZ(5)]
  335. def test_DomainMatrix_rank():
  336. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(6), QQ(8)]], (3, 2), QQ)
  337. assert A.rank() == 2
  338. def test_DomainMatrix_add():
  339. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  340. B = DomainMatrix([[ZZ(2), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ)
  341. assert A + A == A.add(A) == B
  342. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  343. L = [[2, 3], [3, 4]]
  344. raises(TypeError, lambda: A + L)
  345. raises(TypeError, lambda: L + A)
  346. A1 = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  347. A2 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  348. raises(DMShapeError, lambda: A1 + A2)
  349. raises(DMShapeError, lambda: A2 + A1)
  350. raises(DMShapeError, lambda: A1.add(A2))
  351. raises(DMShapeError, lambda: A2.add(A1))
  352. Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  353. Aq = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  354. Asum = DomainMatrix([[QQ(2), QQ(4)], [QQ(6), QQ(8)]], (2, 2), QQ)
  355. assert Az + Aq == Asum
  356. assert Aq + Az == Asum
  357. raises(DMDomainError, lambda: Az.add(Aq))
  358. raises(DMDomainError, lambda: Aq.add(Az))
  359. As = DomainMatrix({0: {1: ZZ(1)}, 1: {0: ZZ(2)}}, (2, 2), ZZ)
  360. Ad = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  361. Asd = As + Ad
  362. Ads = Ad + As
  363. assert Asd == DomainMatrix([[1, 3], [5, 4]], (2, 2), ZZ)
  364. assert Asd.rep == DDM([[1, 3], [5, 4]], (2, 2), ZZ).to_dfm_or_ddm()
  365. assert Ads == DomainMatrix([[1, 3], [5, 4]], (2, 2), ZZ)
  366. assert Ads.rep == DDM([[1, 3], [5, 4]], (2, 2), ZZ).to_dfm_or_ddm()
  367. raises(DMFormatError, lambda: As.add(Ad))
  368. def test_DomainMatrix_sub():
  369. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  370. B = DomainMatrix([[ZZ(0), ZZ(0)], [ZZ(0), ZZ(0)]], (2, 2), ZZ)
  371. assert A - A == A.sub(A) == B
  372. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  373. L = [[2, 3], [3, 4]]
  374. raises(TypeError, lambda: A - L)
  375. raises(TypeError, lambda: L - A)
  376. A1 = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  377. A2 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  378. raises(DMShapeError, lambda: A1 - A2)
  379. raises(DMShapeError, lambda: A2 - A1)
  380. raises(DMShapeError, lambda: A1.sub(A2))
  381. raises(DMShapeError, lambda: A2.sub(A1))
  382. Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  383. Aq = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  384. Adiff = DomainMatrix([[QQ(0), QQ(0)], [QQ(0), QQ(0)]], (2, 2), QQ)
  385. assert Az - Aq == Adiff
  386. assert Aq - Az == Adiff
  387. raises(DMDomainError, lambda: Az.sub(Aq))
  388. raises(DMDomainError, lambda: Aq.sub(Az))
  389. As = DomainMatrix({0: {1: ZZ(1)}, 1: {0: ZZ(2)}}, (2, 2), ZZ)
  390. Ad = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  391. Asd = As - Ad
  392. Ads = Ad - As
  393. assert Asd == DomainMatrix([[-1, -1], [-1, -4]], (2, 2), ZZ)
  394. assert Asd.rep == DDM([[-1, -1], [-1, -4]], (2, 2), ZZ).to_dfm_or_ddm()
  395. assert Asd == -Ads
  396. assert Asd.rep == -Ads.rep
  397. def test_DomainMatrix_neg():
  398. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  399. Aneg = DomainMatrix([[ZZ(-1), ZZ(-2)], [ZZ(-3), ZZ(-4)]], (2, 2), ZZ)
  400. assert -A == A.neg() == Aneg
  401. def test_DomainMatrix_mul():
  402. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  403. A2 = DomainMatrix([[ZZ(7), ZZ(10)], [ZZ(15), ZZ(22)]], (2, 2), ZZ)
  404. assert A*A == A.matmul(A) == A2
  405. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  406. L = [[1, 2], [3, 4]]
  407. raises(TypeError, lambda: A * L)
  408. raises(TypeError, lambda: L * A)
  409. Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  410. Aq = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  411. Aprod = DomainMatrix([[QQ(7), QQ(10)], [QQ(15), QQ(22)]], (2, 2), QQ)
  412. assert Az * Aq == Aprod
  413. assert Aq * Az == Aprod
  414. raises(DMDomainError, lambda: Az.matmul(Aq))
  415. raises(DMDomainError, lambda: Aq.matmul(Az))
  416. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  417. AA = DomainMatrix([[ZZ(2), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ)
  418. x = ZZ(2)
  419. assert A * x == x * A == A.mul(x) == AA
  420. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  421. AA = DomainMatrix.zeros((2, 2), ZZ)
  422. x = ZZ(0)
  423. assert A * x == x * A == A.mul(x).to_sparse() == AA
  424. As = DomainMatrix({0: {1: ZZ(1)}, 1: {0: ZZ(2)}}, (2, 2), ZZ)
  425. Ad = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  426. Asd = As * Ad
  427. Ads = Ad * As
  428. assert Asd == DomainMatrix([[3, 4], [2, 4]], (2, 2), ZZ)
  429. assert Asd.rep == DDM([[3, 4], [2, 4]], (2, 2), ZZ).to_dfm_or_ddm()
  430. assert Ads == DomainMatrix([[4, 1], [8, 3]], (2, 2), ZZ)
  431. assert Ads.rep == DDM([[4, 1], [8, 3]], (2, 2), ZZ).to_dfm_or_ddm()
  432. def test_DomainMatrix_mul_elementwise():
  433. A = DomainMatrix([[ZZ(2), ZZ(2)], [ZZ(0), ZZ(0)]], (2, 2), ZZ)
  434. B = DomainMatrix([[ZZ(4), ZZ(0)], [ZZ(3), ZZ(0)]], (2, 2), ZZ)
  435. C = DomainMatrix([[ZZ(8), ZZ(0)], [ZZ(0), ZZ(0)]], (2, 2), ZZ)
  436. assert A.mul_elementwise(B) == C
  437. assert B.mul_elementwise(A) == C
  438. def test_DomainMatrix_pow():
  439. eye = DomainMatrix.eye(2, ZZ)
  440. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  441. A2 = DomainMatrix([[ZZ(7), ZZ(10)], [ZZ(15), ZZ(22)]], (2, 2), ZZ)
  442. A3 = DomainMatrix([[ZZ(37), ZZ(54)], [ZZ(81), ZZ(118)]], (2, 2), ZZ)
  443. assert A**0 == A.pow(0) == eye
  444. assert A**1 == A.pow(1) == A
  445. assert A**2 == A.pow(2) == A2
  446. assert A**3 == A.pow(3) == A3
  447. raises(TypeError, lambda: A ** Rational(1, 2))
  448. raises(NotImplementedError, lambda: A ** -1)
  449. raises(NotImplementedError, lambda: A.pow(-1))
  450. A = DomainMatrix.zeros((2, 1), ZZ)
  451. raises(DMNonSquareMatrixError, lambda: A ** 1)
  452. def test_DomainMatrix_clear_denoms():
  453. A = DM([[(1,2),(1,3)],[(1,4),(1,5)]], QQ)
  454. den_Z = DomainScalar(ZZ(60), ZZ)
  455. Anum_Z = DM([[30, 20], [15, 12]], ZZ)
  456. Anum_Q = Anum_Z.convert_to(QQ)
  457. assert A.clear_denoms() == (den_Z, Anum_Q)
  458. assert A.clear_denoms(convert=True) == (den_Z, Anum_Z)
  459. assert A * den_Z == Anum_Q
  460. assert A == Anum_Q / den_Z
  461. def test_DomainMatrix_clear_denoms_rowwise():
  462. A = DM([[(1,2),(1,3)],[(1,4),(1,5)]], QQ)
  463. den_Z = DM([[6, 0], [0, 20]], ZZ).to_sparse()
  464. Anum_Z = DM([[3, 2], [5, 4]], ZZ)
  465. Anum_Q = DM([[3, 2], [5, 4]], QQ)
  466. assert A.clear_denoms_rowwise() == (den_Z, Anum_Q)
  467. assert A.clear_denoms_rowwise(convert=True) == (den_Z, Anum_Z)
  468. assert den_Z * A == Anum_Q
  469. assert A == den_Z.to_field().inv() * Anum_Q
  470. A = DM([[(1,2),(1,3),0,0],[0,0,0,0], [(1,4),(1,5),(1,6),(1,7)]], QQ)
  471. den_Z = DM([[6, 0, 0], [0, 1, 0], [0, 0, 420]], ZZ).to_sparse()
  472. Anum_Z = DM([[3, 2, 0, 0], [0, 0, 0, 0], [105, 84, 70, 60]], ZZ)
  473. Anum_Q = Anum_Z.convert_to(QQ)
  474. assert A.clear_denoms_rowwise() == (den_Z, Anum_Q)
  475. assert A.clear_denoms_rowwise(convert=True) == (den_Z, Anum_Z)
  476. assert den_Z * A == Anum_Q
  477. assert A == den_Z.to_field().inv() * Anum_Q
  478. def test_DomainMatrix_cancel_denom():
  479. A = DM([[2, 4], [6, 8]], ZZ)
  480. assert A.cancel_denom(ZZ(1)) == (DM([[2, 4], [6, 8]], ZZ), ZZ(1))
  481. assert A.cancel_denom(ZZ(3)) == (DM([[2, 4], [6, 8]], ZZ), ZZ(3))
  482. assert A.cancel_denom(ZZ(4)) == (DM([[1, 2], [3, 4]], ZZ), ZZ(2))
  483. A = DM([[1, 2], [3, 4]], ZZ)
  484. assert A.cancel_denom(ZZ(2)) == (A, ZZ(2))
  485. assert A.cancel_denom(ZZ(-2)) == (-A, ZZ(2))
  486. # Test canonicalization of denominator over Gaussian rationals.
  487. A = DM([[1, 2], [3, 4]], QQ_I)
  488. assert A.cancel_denom(QQ_I(0,2)) == (QQ_I(0,-1)*A, QQ_I(2))
  489. raises(ZeroDivisionError, lambda: A.cancel_denom(ZZ(0)))
  490. def test_DomainMatrix_cancel_denom_elementwise():
  491. A = DM([[2, 4], [6, 8]], ZZ)
  492. numers, denoms = A.cancel_denom_elementwise(ZZ(1))
  493. assert numers == DM([[2, 4], [6, 8]], ZZ)
  494. assert denoms == DM([[1, 1], [1, 1]], ZZ)
  495. numers, denoms = A.cancel_denom_elementwise(ZZ(4))
  496. assert numers == DM([[1, 1], [3, 2]], ZZ)
  497. assert denoms == DM([[2, 1], [2, 1]], ZZ)
  498. raises(ZeroDivisionError, lambda: A.cancel_denom_elementwise(ZZ(0)))
  499. def test_DomainMatrix_content_primitive():
  500. A = DM([[2, 4], [6, 8]], ZZ)
  501. A_primitive = DM([[1, 2], [3, 4]], ZZ)
  502. A_content = ZZ(2)
  503. assert A.content() == A_content
  504. assert A.primitive() == (A_content, A_primitive)
  505. def test_DomainMatrix_scc():
  506. Ad = DomainMatrix([[ZZ(1), ZZ(2), ZZ(3)],
  507. [ZZ(0), ZZ(1), ZZ(0)],
  508. [ZZ(2), ZZ(0), ZZ(4)]], (3, 3), ZZ)
  509. As = Ad.to_sparse()
  510. Addm = Ad.rep
  511. Asdm = As.rep
  512. for A in [Ad, As, Addm, Asdm]:
  513. assert Ad.scc() == [[1], [0, 2]]
  514. A = DM([[ZZ(1), ZZ(2), ZZ(3)]], ZZ)
  515. raises(DMNonSquareMatrixError, lambda: A.scc())
  516. def test_DomainMatrix_rref():
  517. # More tests in test_rref.py
  518. A = DomainMatrix([], (0, 1), QQ)
  519. assert A.rref() == (A, ())
  520. A = DomainMatrix([[QQ(1)]], (1, 1), QQ)
  521. assert A.rref() == (A, (0,))
  522. A = DomainMatrix([[QQ(0)]], (1, 1), QQ)
  523. assert A.rref() == (A, ())
  524. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  525. Ar, pivots = A.rref()
  526. assert Ar == DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ)
  527. assert pivots == (0, 1)
  528. A = DomainMatrix([[QQ(0), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  529. Ar, pivots = A.rref()
  530. assert Ar == DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ)
  531. assert pivots == (0, 1)
  532. A = DomainMatrix([[QQ(0), QQ(2)], [QQ(0), QQ(4)]], (2, 2), QQ)
  533. Ar, pivots = A.rref()
  534. assert Ar == DomainMatrix([[QQ(0), QQ(1)], [QQ(0), QQ(0)]], (2, 2), QQ)
  535. assert pivots == (1,)
  536. Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  537. Ar, pivots = Az.rref()
  538. assert Ar == DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ)
  539. assert pivots == (0, 1)
  540. methods = ('auto', 'GJ', 'FF', 'CD', 'GJ_dense', 'FF_dense', 'CD_dense')
  541. Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  542. for method in methods:
  543. Ar, pivots = Az.rref(method=method)
  544. assert Ar == DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ)
  545. assert pivots == (0, 1)
  546. raises(ValueError, lambda: Az.rref(method='foo'))
  547. raises(ValueError, lambda: Az.rref_den(method='foo'))
  548. def test_DomainMatrix_columnspace():
  549. A = DomainMatrix([[QQ(1), QQ(-1), QQ(1)], [QQ(2), QQ(-2), QQ(3)]], (2, 3), QQ)
  550. Acol = DomainMatrix([[QQ(1), QQ(1)], [QQ(2), QQ(3)]], (2, 2), QQ)
  551. assert A.columnspace() == Acol
  552. Az = DomainMatrix([[ZZ(1), ZZ(-1), ZZ(1)], [ZZ(2), ZZ(-2), ZZ(3)]], (2, 3), ZZ)
  553. raises(DMNotAField, lambda: Az.columnspace())
  554. A = DomainMatrix([[QQ(1), QQ(-1), QQ(1)], [QQ(2), QQ(-2), QQ(3)]], (2, 3), QQ, fmt='sparse')
  555. Acol = DomainMatrix({0: {0: QQ(1), 1: QQ(1)}, 1: {0: QQ(2), 1: QQ(3)}}, (2, 2), QQ)
  556. assert A.columnspace() == Acol
  557. def test_DomainMatrix_rowspace():
  558. A = DomainMatrix([[QQ(1), QQ(-1), QQ(1)], [QQ(2), QQ(-2), QQ(3)]], (2, 3), QQ)
  559. assert A.rowspace() == A
  560. Az = DomainMatrix([[ZZ(1), ZZ(-1), ZZ(1)], [ZZ(2), ZZ(-2), ZZ(3)]], (2, 3), ZZ)
  561. raises(DMNotAField, lambda: Az.rowspace())
  562. A = DomainMatrix([[QQ(1), QQ(-1), QQ(1)], [QQ(2), QQ(-2), QQ(3)]], (2, 3), QQ, fmt='sparse')
  563. assert A.rowspace() == A
  564. def test_DomainMatrix_nullspace():
  565. A = DomainMatrix([[QQ(1), QQ(1)], [QQ(1), QQ(1)]], (2, 2), QQ)
  566. Anull = DomainMatrix([[QQ(-1), QQ(1)]], (1, 2), QQ)
  567. assert A.nullspace() == Anull
  568. A = DomainMatrix([[ZZ(1), ZZ(1)], [ZZ(1), ZZ(1)]], (2, 2), ZZ)
  569. Anull = DomainMatrix([[ZZ(-1), ZZ(1)]], (1, 2), ZZ)
  570. assert A.nullspace() == Anull
  571. raises(DMNotAField, lambda: A.nullspace(divide_last=True))
  572. A = DomainMatrix([[ZZ(2), ZZ(2)], [ZZ(2), ZZ(2)]], (2, 2), ZZ)
  573. Anull = DomainMatrix([[ZZ(-2), ZZ(2)]], (1, 2), ZZ)
  574. Arref, den, pivots = A.rref_den()
  575. assert den == ZZ(2)
  576. assert Arref.nullspace_from_rref() == Anull
  577. assert Arref.nullspace_from_rref(pivots) == Anull
  578. assert Arref.to_sparse().nullspace_from_rref() == Anull.to_sparse()
  579. assert Arref.to_sparse().nullspace_from_rref(pivots) == Anull.to_sparse()
  580. def test_DomainMatrix_solve():
  581. # XXX: Maybe the _solve method should be changed...
  582. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(2), QQ(4)]], (2, 2), QQ)
  583. b = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  584. particular = DomainMatrix([[1, 0]], (1, 2), QQ)
  585. nullspace = DomainMatrix([[-2, 1]], (1, 2), QQ)
  586. assert A._solve(b) == (particular, nullspace)
  587. b3 = DomainMatrix([[QQ(1)], [QQ(1)], [QQ(1)]], (3, 1), QQ)
  588. raises(DMShapeError, lambda: A._solve(b3))
  589. bz = DomainMatrix([[ZZ(1)], [ZZ(1)]], (2, 1), ZZ)
  590. raises(DMNotAField, lambda: A._solve(bz))
  591. def test_DomainMatrix_inv():
  592. A = DomainMatrix([], (0, 0), QQ)
  593. assert A.inv() == A
  594. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  595. Ainv = DomainMatrix([[QQ(-2), QQ(1)], [QQ(3, 2), QQ(-1, 2)]], (2, 2), QQ)
  596. assert A.inv() == Ainv
  597. Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  598. raises(DMNotAField, lambda: Az.inv())
  599. Ans = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ)
  600. raises(DMNonSquareMatrixError, lambda: Ans.inv())
  601. Aninv = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(6)]], (2, 2), QQ)
  602. raises(DMNonInvertibleMatrixError, lambda: Aninv.inv())
  603. Z3 = FF(3)
  604. assert DM([[1, 2], [3, 4]], Z3).inv() == DM([[1, 1], [0, 1]], Z3)
  605. Z6 = FF(6)
  606. raises(DMNotAField, lambda: DM([[1, 2], [3, 4]], Z6).inv())
  607. def test_DomainMatrix_det():
  608. A = DomainMatrix([], (0, 0), ZZ)
  609. assert A.det() == 1
  610. A = DomainMatrix([[1]], (1, 1), ZZ)
  611. assert A.det() == 1
  612. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  613. assert A.det() == ZZ(-2)
  614. A = DomainMatrix([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(3), ZZ(5)]], (3, 3), ZZ)
  615. assert A.det() == ZZ(-1)
  616. A = DomainMatrix([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(2), ZZ(5)]], (3, 3), ZZ)
  617. assert A.det() == ZZ(0)
  618. Ans = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ)
  619. raises(DMNonSquareMatrixError, lambda: Ans.det())
  620. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  621. assert A.det() == QQ(-2)
  622. def test_DomainMatrix_eval_poly():
  623. dM = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  624. p = [ZZ(1), ZZ(2), ZZ(3)]
  625. result = DomainMatrix([[ZZ(12), ZZ(14)], [ZZ(21), ZZ(33)]], (2, 2), ZZ)
  626. assert dM.eval_poly(p) == result == p[0]*dM**2 + p[1]*dM + p[2]*dM**0
  627. assert dM.eval_poly([]) == dM.zeros(dM.shape, dM.domain)
  628. assert dM.eval_poly([ZZ(2)]) == 2*dM.eye(2, dM.domain)
  629. dM2 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  630. raises(DMNonSquareMatrixError, lambda: dM2.eval_poly([ZZ(1)]))
  631. def test_DomainMatrix_eval_poly_mul():
  632. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  633. b = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
  634. p = [ZZ(1), ZZ(2), ZZ(3)]
  635. result = DomainMatrix([[ZZ(40)], [ZZ(87)]], (2, 1), ZZ)
  636. assert A.eval_poly_mul(p, b) == result == p[0]*A**2*b + p[1]*A*b + p[2]*b
  637. dM = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  638. dM1 = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
  639. raises(DMNonSquareMatrixError, lambda: dM1.eval_poly_mul([ZZ(1)], b))
  640. b1 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  641. raises(DMShapeError, lambda: dM.eval_poly_mul([ZZ(1)], b1))
  642. bq = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  643. raises(DMDomainError, lambda: dM.eval_poly_mul([ZZ(1)], bq))
  644. def _check_solve_den(A, b, xnum, xden):
  645. # Examples for solve_den, solve_den_charpoly, solve_den_rref should use
  646. # this so that all methods and types are tested.
  647. case1 = (A, xnum, b)
  648. case2 = (A.to_sparse(), xnum.to_sparse(), b.to_sparse())
  649. for Ai, xnum_i, b_i in [case1, case2]:
  650. # The key invariant for solve_den:
  651. assert Ai*xnum_i == xden*b_i
  652. # solve_den_rref can differ at least by a minus sign
  653. answers = [(xnum_i, xden), (-xnum_i, -xden)]
  654. assert Ai.solve_den(b) in answers
  655. assert Ai.solve_den(b, method='rref') in answers
  656. assert Ai.solve_den_rref(b) in answers
  657. # charpoly can only be used if A is square and guarantees to return the
  658. # actual determinant as a denominator.
  659. m, n = Ai.shape
  660. if m == n:
  661. assert Ai.solve_den(b_i, method='charpoly') == (xnum_i, xden)
  662. assert Ai.solve_den_charpoly(b_i) == (xnum_i, xden)
  663. else:
  664. raises(DMNonSquareMatrixError, lambda: Ai.solve_den_charpoly(b))
  665. raises(DMNonSquareMatrixError, lambda: Ai.solve_den(b, method='charpoly'))
  666. def test_DomainMatrix_solve_den():
  667. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  668. b = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
  669. result = DomainMatrix([[ZZ(0)], [ZZ(-1)]], (2, 1), ZZ)
  670. den = ZZ(-2)
  671. _check_solve_den(A, b, result, den)
  672. A = DomainMatrix([
  673. [ZZ(1), ZZ(2), ZZ(3)],
  674. [ZZ(1), ZZ(2), ZZ(4)],
  675. [ZZ(1), ZZ(3), ZZ(5)]], (3, 3), ZZ)
  676. b = DomainMatrix([[ZZ(1)], [ZZ(2)], [ZZ(3)]], (3, 1), ZZ)
  677. result = DomainMatrix([[ZZ(2)], [ZZ(0)], [ZZ(-1)]], (3, 1), ZZ)
  678. den = ZZ(-1)
  679. _check_solve_den(A, b, result, den)
  680. A = DomainMatrix([[ZZ(2)], [ZZ(2)]], (2, 1), ZZ)
  681. b = DomainMatrix([[ZZ(3)], [ZZ(3)]], (2, 1), ZZ)
  682. result = DomainMatrix([[ZZ(3)]], (1, 1), ZZ)
  683. den = ZZ(2)
  684. _check_solve_den(A, b, result, den)
  685. def test_DomainMatrix_solve_den_charpoly():
  686. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  687. b = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
  688. A1 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  689. raises(DMNonSquareMatrixError, lambda: A1.solve_den_charpoly(b))
  690. b1 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  691. raises(DMShapeError, lambda: A.solve_den_charpoly(b1))
  692. bq = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  693. raises(DMDomainError, lambda: A.solve_den_charpoly(bq))
  694. def test_DomainMatrix_solve_den_charpoly_check():
  695. # Test check
  696. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(2), ZZ(4)]], (2, 2), ZZ)
  697. b = DomainMatrix([[ZZ(1)], [ZZ(3)]], (2, 1), ZZ)
  698. raises(DMNonInvertibleMatrixError, lambda: A.solve_den_charpoly(b))
  699. adjAb = DomainMatrix([[ZZ(-2)], [ZZ(1)]], (2, 1), ZZ)
  700. assert A.adjugate() * b == adjAb
  701. assert A.solve_den_charpoly(b, check=False) == (adjAb, ZZ(0))
  702. def test_DomainMatrix_solve_den_errors():
  703. A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  704. b = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
  705. raises(DMShapeError, lambda: A.solve_den(b))
  706. raises(DMShapeError, lambda: A.solve_den_rref(b))
  707. A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  708. b = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  709. raises(DMShapeError, lambda: A.solve_den(b))
  710. raises(DMShapeError, lambda: A.solve_den_rref(b))
  711. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  712. b1 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  713. raises(DMShapeError, lambda: A.solve_den(b1))
  714. A = DomainMatrix([[ZZ(2)]], (1, 1), ZZ)
  715. b = DomainMatrix([[ZZ(2)]], (1, 1), ZZ)
  716. raises(DMBadInputError, lambda: A.solve_den(b1, method='invalid'))
  717. A = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
  718. b = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
  719. raises(DMNonSquareMatrixError, lambda: A.solve_den_charpoly(b))
  720. def test_DomainMatrix_solve_den_rref_underdetermined():
  721. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(1), ZZ(2)]], (2, 2), ZZ)
  722. b = DomainMatrix([[ZZ(1)], [ZZ(1)]], (2, 1), ZZ)
  723. raises(DMNonInvertibleMatrixError, lambda: A.solve_den(b))
  724. raises(DMNonInvertibleMatrixError, lambda: A.solve_den_rref(b))
  725. def test_DomainMatrix_adj_poly_det():
  726. A = DM([[ZZ(1), ZZ(2), ZZ(3)],
  727. [ZZ(4), ZZ(5), ZZ(6)],
  728. [ZZ(7), ZZ(8), ZZ(9)]], ZZ)
  729. p, detA = A.adj_poly_det()
  730. assert p == [ZZ(1), ZZ(-15), ZZ(-18)]
  731. assert A.adjugate() == p[0]*A**2 + p[1]*A**1 + p[2]*A**0 == A.eval_poly(p)
  732. assert A.det() == detA
  733. A = DM([[ZZ(1), ZZ(2), ZZ(3)],
  734. [ZZ(7), ZZ(8), ZZ(9)]], ZZ)
  735. raises(DMNonSquareMatrixError, lambda: A.adj_poly_det())
  736. def test_DomainMatrix_inv_den():
  737. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  738. den = ZZ(-2)
  739. result = DomainMatrix([[ZZ(4), ZZ(-2)], [ZZ(-3), ZZ(1)]], (2, 2), ZZ)
  740. assert A.inv_den() == (result, den)
  741. def test_DomainMatrix_adjugate():
  742. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  743. result = DomainMatrix([[ZZ(4), ZZ(-2)], [ZZ(-3), ZZ(1)]], (2, 2), ZZ)
  744. assert A.adjugate() == result
  745. def test_DomainMatrix_adj_det():
  746. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  747. adjA = DomainMatrix([[ZZ(4), ZZ(-2)], [ZZ(-3), ZZ(1)]], (2, 2), ZZ)
  748. assert A.adj_det() == (adjA, ZZ(-2))
  749. def test_DomainMatrix_lu():
  750. A = DomainMatrix([], (0, 0), QQ)
  751. assert A.lu() == (A, A, [])
  752. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  753. L = DomainMatrix([[QQ(1), QQ(0)], [QQ(3), QQ(1)]], (2, 2), QQ)
  754. U = DomainMatrix([[QQ(1), QQ(2)], [QQ(0), QQ(-2)]], (2, 2), QQ)
  755. swaps = []
  756. assert A.lu() == (L, U, swaps)
  757. A = DomainMatrix([[QQ(0), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  758. L = DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ)
  759. U = DomainMatrix([[QQ(3), QQ(4)], [QQ(0), QQ(2)]], (2, 2), QQ)
  760. swaps = [(0, 1)]
  761. assert A.lu() == (L, U, swaps)
  762. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(2), QQ(4)]], (2, 2), QQ)
  763. L = DomainMatrix([[QQ(1), QQ(0)], [QQ(2), QQ(1)]], (2, 2), QQ)
  764. U = DomainMatrix([[QQ(1), QQ(2)], [QQ(0), QQ(0)]], (2, 2), QQ)
  765. swaps = []
  766. assert A.lu() == (L, U, swaps)
  767. A = DomainMatrix([[QQ(0), QQ(2)], [QQ(0), QQ(4)]], (2, 2), QQ)
  768. L = DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ)
  769. U = DomainMatrix([[QQ(0), QQ(2)], [QQ(0), QQ(4)]], (2, 2), QQ)
  770. swaps = []
  771. assert A.lu() == (L, U, swaps)
  772. A = DomainMatrix([[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]], (2, 3), QQ)
  773. L = DomainMatrix([[QQ(1), QQ(0)], [QQ(4), QQ(1)]], (2, 2), QQ)
  774. U = DomainMatrix([[QQ(1), QQ(2), QQ(3)], [QQ(0), QQ(-3), QQ(-6)]], (2, 3), QQ)
  775. swaps = []
  776. assert A.lu() == (L, U, swaps)
  777. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ)
  778. L = DomainMatrix([
  779. [QQ(1), QQ(0), QQ(0)],
  780. [QQ(3), QQ(1), QQ(0)],
  781. [QQ(5), QQ(2), QQ(1)]], (3, 3), QQ)
  782. U = DomainMatrix([[QQ(1), QQ(2)], [QQ(0), QQ(-2)], [QQ(0), QQ(0)]], (3, 2), QQ)
  783. swaps = []
  784. assert A.lu() == (L, U, swaps)
  785. A = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 2]]
  786. L = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 1, 1]]
  787. U = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]
  788. to_dom = lambda rows, dom: [[dom(e) for e in row] for row in rows]
  789. A = DomainMatrix(to_dom(A, QQ), (4, 4), QQ)
  790. L = DomainMatrix(to_dom(L, QQ), (4, 4), QQ)
  791. U = DomainMatrix(to_dom(U, QQ), (4, 4), QQ)
  792. assert A.lu() == (L, U, [])
  793. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  794. raises(DMNotAField, lambda: A.lu())
  795. def test_DomainMatrix_lu_solve():
  796. # Base case
  797. A = b = x = DomainMatrix([], (0, 0), QQ)
  798. assert A.lu_solve(b) == x
  799. # Basic example
  800. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  801. b = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  802. x = DomainMatrix([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
  803. assert A.lu_solve(b) == x
  804. # Example with swaps
  805. A = DomainMatrix([[QQ(0), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  806. b = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  807. x = DomainMatrix([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
  808. assert A.lu_solve(b) == x
  809. # Non-invertible
  810. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(2), QQ(4)]], (2, 2), QQ)
  811. b = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  812. raises(DMNonInvertibleMatrixError, lambda: A.lu_solve(b))
  813. # Overdetermined, consistent
  814. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ)
  815. b = DomainMatrix([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ)
  816. x = DomainMatrix([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
  817. assert A.lu_solve(b) == x
  818. # Overdetermined, inconsistent
  819. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ)
  820. b = DomainMatrix([[QQ(1)], [QQ(2)], [QQ(4)]], (3, 1), QQ)
  821. raises(DMNonInvertibleMatrixError, lambda: A.lu_solve(b))
  822. # Underdetermined
  823. A = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ)
  824. b = DomainMatrix([[QQ(1)]], (1, 1), QQ)
  825. raises(NotImplementedError, lambda: A.lu_solve(b))
  826. # Non-field
  827. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  828. b = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
  829. raises(DMNotAField, lambda: A.lu_solve(b))
  830. # Shape mismatch
  831. A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
  832. b = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ)
  833. raises(DMShapeError, lambda: A.lu_solve(b))
  834. def test_DomainMatrix_charpoly():
  835. A = DomainMatrix([], (0, 0), ZZ)
  836. p = [ZZ(1)]
  837. assert A.charpoly() == p
  838. assert A.to_sparse().charpoly() == p
  839. A = DomainMatrix([[1]], (1, 1), ZZ)
  840. p = [ZZ(1), ZZ(-1)]
  841. assert A.charpoly() == p
  842. assert A.to_sparse().charpoly() == p
  843. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  844. p = [ZZ(1), ZZ(-5), ZZ(-2)]
  845. assert A.charpoly() == p
  846. assert A.to_sparse().charpoly() == p
  847. A = DomainMatrix([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ)
  848. p = [ZZ(1), ZZ(-15), ZZ(-18), ZZ(0)]
  849. assert A.charpoly() == p
  850. assert A.to_sparse().charpoly() == p
  851. A = DomainMatrix([[ZZ(0), ZZ(1), ZZ(0)],
  852. [ZZ(1), ZZ(0), ZZ(1)],
  853. [ZZ(0), ZZ(1), ZZ(0)]], (3, 3), ZZ)
  854. p = [ZZ(1), ZZ(0), ZZ(-2), ZZ(0)]
  855. assert A.charpoly() == p
  856. assert A.to_sparse().charpoly() == p
  857. A = DM([[17, 0, 30, 0, 0, 0, 0, 0, 0, 0],
  858. [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  859. [69, 0, 0, 0, 0, 86, 0, 0, 0, 0],
  860. [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  861. [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  862. [ 0, 0, 0, 13, 0, 0, 0, 0, 0, 0],
  863. [ 0, 0, 0, 0, 0, 0, 0, 32, 0, 0],
  864. [ 0, 0, 0, 0, 37, 67, 0, 0, 0, 0],
  865. [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  866. [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], ZZ)
  867. p = ZZ.map([1, -17, -2070, 0, -771420, 0, 0, 0, 0, 0, 0])
  868. assert A.charpoly() == p
  869. assert A.to_sparse().charpoly() == p
  870. Ans = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ)
  871. raises(DMNonSquareMatrixError, lambda: Ans.charpoly())
  872. def test_DomainMatrix_charpoly_factor_list():
  873. A = DomainMatrix([], (0, 0), ZZ)
  874. assert A.charpoly_factor_list() == []
  875. A = DM([[1]], ZZ)
  876. assert A.charpoly_factor_list() == [
  877. ([ZZ(1), ZZ(-1)], 1)
  878. ]
  879. A = DM([[1, 2], [3, 4]], ZZ)
  880. assert A.charpoly_factor_list() == [
  881. ([ZZ(1), ZZ(-5), ZZ(-2)], 1)
  882. ]
  883. A = DM([[1, 2, 0], [3, 4, 0], [0, 0, 1]], ZZ)
  884. assert A.charpoly_factor_list() == [
  885. ([ZZ(1), ZZ(-1)], 1),
  886. ([ZZ(1), ZZ(-5), ZZ(-2)], 1)
  887. ]
  888. def test_DomainMatrix_eye():
  889. A = DomainMatrix.eye(3, QQ)
  890. assert A.rep == SDM.eye((3, 3), QQ)
  891. assert A.shape == (3, 3)
  892. assert A.domain == QQ
  893. def test_DomainMatrix_zeros():
  894. A = DomainMatrix.zeros((1, 2), QQ)
  895. assert A.rep == SDM.zeros((1, 2), QQ)
  896. assert A.shape == (1, 2)
  897. assert A.domain == QQ
  898. def test_DomainMatrix_ones():
  899. A = DomainMatrix.ones((2, 3), QQ)
  900. if GROUND_TYPES != 'flint':
  901. assert A.rep == DDM.ones((2, 3), QQ)
  902. else:
  903. assert A.rep == SDM.ones((2, 3), QQ).to_dfm()
  904. assert A.shape == (2, 3)
  905. assert A.domain == QQ
  906. def test_DomainMatrix_diag():
  907. A = DomainMatrix({0:{0:ZZ(2)}, 1:{1:ZZ(3)}}, (2, 2), ZZ)
  908. assert DomainMatrix.diag([ZZ(2), ZZ(3)], ZZ) == A
  909. A = DomainMatrix({0:{0:ZZ(2)}, 1:{1:ZZ(3)}}, (3, 4), ZZ)
  910. assert DomainMatrix.diag([ZZ(2), ZZ(3)], ZZ, (3, 4)) == A
  911. def test_DomainMatrix_hstack():
  912. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  913. B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ)
  914. C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ)
  915. AB = DomainMatrix([
  916. [ZZ(1), ZZ(2), ZZ(5), ZZ(6)],
  917. [ZZ(3), ZZ(4), ZZ(7), ZZ(8)]], (2, 4), ZZ)
  918. ABC = DomainMatrix([
  919. [ZZ(1), ZZ(2), ZZ(5), ZZ(6), ZZ(9), ZZ(10)],
  920. [ZZ(3), ZZ(4), ZZ(7), ZZ(8), ZZ(11), ZZ(12)]], (2, 6), ZZ)
  921. assert A.hstack(B) == AB
  922. assert A.hstack(B, C) == ABC
  923. def test_DomainMatrix_vstack():
  924. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  925. B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ)
  926. C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ)
  927. AB = DomainMatrix([
  928. [ZZ(1), ZZ(2)],
  929. [ZZ(3), ZZ(4)],
  930. [ZZ(5), ZZ(6)],
  931. [ZZ(7), ZZ(8)]], (4, 2), ZZ)
  932. ABC = DomainMatrix([
  933. [ZZ(1), ZZ(2)],
  934. [ZZ(3), ZZ(4)],
  935. [ZZ(5), ZZ(6)],
  936. [ZZ(7), ZZ(8)],
  937. [ZZ(9), ZZ(10)],
  938. [ZZ(11), ZZ(12)]], (6, 2), ZZ)
  939. assert A.vstack(B) == AB
  940. assert A.vstack(B, C) == ABC
  941. def test_DomainMatrix_applyfunc():
  942. A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  943. B = DomainMatrix([[ZZ(2), ZZ(4)]], (1, 2), ZZ)
  944. assert A.applyfunc(lambda x: 2*x) == B
  945. def test_DomainMatrix_scalarmul():
  946. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  947. lamda = DomainScalar(QQ(3)/QQ(2), QQ)
  948. assert A * lamda == DomainMatrix([[QQ(3, 2), QQ(3)], [QQ(9, 2), QQ(6)]], (2, 2), QQ)
  949. assert A * 2 == DomainMatrix([[ZZ(2), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ)
  950. assert 2 * A == DomainMatrix([[ZZ(2), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ)
  951. assert A * DomainScalar(ZZ(0), ZZ) == DomainMatrix({}, (2, 2), ZZ)
  952. assert A * DomainScalar(ZZ(1), ZZ) == A
  953. raises(TypeError, lambda: A * 1.5)
  954. def test_DomainMatrix_truediv():
  955. A = DomainMatrix.from_Matrix(Matrix([[1, 2], [3, 4]]))
  956. lamda = DomainScalar(QQ(3)/QQ(2), QQ)
  957. assert A / lamda == DomainMatrix({0: {0: QQ(2, 3), 1: QQ(4, 3)}, 1: {0: QQ(2), 1: QQ(8, 3)}}, (2, 2), QQ)
  958. b = DomainScalar(ZZ(1), ZZ)
  959. assert A / b == DomainMatrix({0: {0: QQ(1), 1: QQ(2)}, 1: {0: QQ(3), 1: QQ(4)}}, (2, 2), QQ)
  960. assert A / 1 == DomainMatrix({0: {0: QQ(1), 1: QQ(2)}, 1: {0: QQ(3), 1: QQ(4)}}, (2, 2), QQ)
  961. assert A / 2 == DomainMatrix({0: {0: QQ(1, 2), 1: QQ(1)}, 1: {0: QQ(3, 2), 1: QQ(2)}}, (2, 2), QQ)
  962. raises(ZeroDivisionError, lambda: A / 0)
  963. raises(TypeError, lambda: A / 1.5)
  964. raises(ZeroDivisionError, lambda: A / DomainScalar(ZZ(0), ZZ))
  965. A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  966. assert A.to_field() / 2 == DomainMatrix([[QQ(1, 2), QQ(1)], [QQ(3, 2), QQ(2)]], (2, 2), QQ)
  967. assert A / 2 == DomainMatrix([[QQ(1, 2), QQ(1)], [QQ(3, 2), QQ(2)]], (2, 2), QQ)
  968. assert A.to_field() / QQ(2,3) == DomainMatrix([[QQ(3, 2), QQ(3)], [QQ(9, 2), QQ(6)]], (2, 2), QQ)
  969. def test_DomainMatrix_getitem():
  970. dM = DomainMatrix([
  971. [ZZ(1), ZZ(2), ZZ(3)],
  972. [ZZ(4), ZZ(5), ZZ(6)],
  973. [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ)
  974. assert dM[1:,:-2] == DomainMatrix([[ZZ(4)], [ZZ(7)]], (2, 1), ZZ)
  975. assert dM[2,:-2] == DomainMatrix([[ZZ(7)]], (1, 1), ZZ)
  976. assert dM[:-2,:-2] == DomainMatrix([[ZZ(1)]], (1, 1), ZZ)
  977. assert dM[:-1,0:2] == DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(4), ZZ(5)]], (2, 2), ZZ)
  978. assert dM[:, -1] == DomainMatrix([[ZZ(3)], [ZZ(6)], [ZZ(9)]], (3, 1), ZZ)
  979. assert dM[-1, :] == DomainMatrix([[ZZ(7), ZZ(8), ZZ(9)]], (1, 3), ZZ)
  980. assert dM[::-1, :] == DomainMatrix([
  981. [ZZ(7), ZZ(8), ZZ(9)],
  982. [ZZ(4), ZZ(5), ZZ(6)],
  983. [ZZ(1), ZZ(2), ZZ(3)]], (3, 3), ZZ)
  984. raises(IndexError, lambda: dM[4, :-2])
  985. raises(IndexError, lambda: dM[:-2, 4])
  986. assert dM[1, 2] == DomainScalar(ZZ(6), ZZ)
  987. assert dM[-2, 2] == DomainScalar(ZZ(6), ZZ)
  988. assert dM[1, -2] == DomainScalar(ZZ(5), ZZ)
  989. assert dM[-1, -3] == DomainScalar(ZZ(7), ZZ)
  990. raises(IndexError, lambda: dM[3, 3])
  991. raises(IndexError, lambda: dM[1, 4])
  992. raises(IndexError, lambda: dM[-1, -4])
  993. dM = DomainMatrix({0: {0: ZZ(1)}}, (10, 10), ZZ)
  994. assert dM[5, 5] == DomainScalar(ZZ(0), ZZ)
  995. assert dM[0, 0] == DomainScalar(ZZ(1), ZZ)
  996. dM = DomainMatrix({1: {0: 1}}, (2,1), ZZ)
  997. assert dM[0:, 0] == DomainMatrix({1: {0: 1}}, (2, 1), ZZ)
  998. raises(IndexError, lambda: dM[3, 0])
  999. dM = DomainMatrix({2: {2: ZZ(1)}, 4: {4: ZZ(1)}}, (5, 5), ZZ)
  1000. assert dM[:2,:2] == DomainMatrix({}, (2, 2), ZZ)
  1001. assert dM[2:,2:] == DomainMatrix({0: {0: 1}, 2: {2: 1}}, (3, 3), ZZ)
  1002. assert dM[3:,3:] == DomainMatrix({1: {1: 1}}, (2, 2), ZZ)
  1003. assert dM[2:, 6:] == DomainMatrix({}, (3, 0), ZZ)
  1004. def test_DomainMatrix_getitem_sympy():
  1005. dM = DomainMatrix({2: {2: ZZ(2)}, 4: {4: ZZ(1)}}, (5, 5), ZZ)
  1006. val1 = dM.getitem_sympy(0, 0)
  1007. assert val1 is S.Zero
  1008. val2 = dM.getitem_sympy(2, 2)
  1009. assert val2 == 2 and isinstance(val2, Integer)
  1010. def test_DomainMatrix_extract():
  1011. dM1 = DomainMatrix([
  1012. [ZZ(1), ZZ(2), ZZ(3)],
  1013. [ZZ(4), ZZ(5), ZZ(6)],
  1014. [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ)
  1015. dM2 = DomainMatrix([
  1016. [ZZ(1), ZZ(3)],
  1017. [ZZ(7), ZZ(9)]], (2, 2), ZZ)
  1018. assert dM1.extract([0, 2], [0, 2]) == dM2
  1019. assert dM1.to_sparse().extract([0, 2], [0, 2]) == dM2.to_sparse()
  1020. assert dM1.extract([0, -1], [0, -1]) == dM2
  1021. assert dM1.to_sparse().extract([0, -1], [0, -1]) == dM2.to_sparse()
  1022. dM3 = DomainMatrix([
  1023. [ZZ(1), ZZ(2), ZZ(2)],
  1024. [ZZ(4), ZZ(5), ZZ(5)],
  1025. [ZZ(4), ZZ(5), ZZ(5)]], (3, 3), ZZ)
  1026. assert dM1.extract([0, 1, 1], [0, 1, 1]) == dM3
  1027. assert dM1.to_sparse().extract([0, 1, 1], [0, 1, 1]) == dM3.to_sparse()
  1028. empty = [
  1029. ([], [], (0, 0)),
  1030. ([1], [], (1, 0)),
  1031. ([], [1], (0, 1)),
  1032. ]
  1033. for rows, cols, size in empty:
  1034. assert dM1.extract(rows, cols) == DomainMatrix.zeros(size, ZZ).to_dense()
  1035. assert dM1.to_sparse().extract(rows, cols) == DomainMatrix.zeros(size, ZZ)
  1036. dM = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1037. bad_indices = [([2], [0]), ([0], [2]), ([-3], [0]), ([0], [-3])]
  1038. for rows, cols in bad_indices:
  1039. raises(IndexError, lambda: dM.extract(rows, cols))
  1040. raises(IndexError, lambda: dM.to_sparse().extract(rows, cols))
  1041. def test_DomainMatrix_setitem():
  1042. dM = DomainMatrix({2: {2: ZZ(1)}, 4: {4: ZZ(1)}}, (5, 5), ZZ)
  1043. dM[2, 2] = ZZ(2)
  1044. assert dM == DomainMatrix({2: {2: ZZ(2)}, 4: {4: ZZ(1)}}, (5, 5), ZZ)
  1045. def setitem(i, j, val):
  1046. dM[i, j] = val
  1047. raises(TypeError, lambda: setitem(2, 2, QQ(1, 2)))
  1048. raises(NotImplementedError, lambda: setitem(slice(1, 2), 2, ZZ(1)))
  1049. def test_DomainMatrix_pickling():
  1050. import pickle
  1051. dM = DomainMatrix({2: {2: ZZ(1)}, 4: {4: ZZ(1)}}, (5, 5), ZZ)
  1052. assert pickle.loads(pickle.dumps(dM)) == dM
  1053. dM = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
  1054. assert pickle.loads(pickle.dumps(dM)) == dM
  1055. def test_DomainMatrix_fflu():
  1056. A = DM([[1, 2], [3, 4]], ZZ)
  1057. P, L, D, U = A.fflu()
  1058. assert P.shape == A.shape
  1059. assert L.shape == A.shape
  1060. assert D.shape == A.shape
  1061. assert U.shape == A.shape
  1062. assert P == DM([[1, 0], [0, 1]], ZZ)
  1063. assert L == DM([[1, 0], [3, -2]], ZZ)
  1064. assert D == DM([[1, 0], [0, -2]], ZZ)
  1065. assert U == DM([[1, 2], [0, -2]], ZZ)
  1066. di, d = D.inv_den()
  1067. assert P.matmul(A).rmul(d) == L.matmul(di).matmul(U)