test_dense.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. from sympy.testing.pytest import raises
  2. from sympy.polys import ZZ, QQ
  3. from sympy.polys.matrices.ddm import DDM
  4. from sympy.polys.matrices.dense import (
  5. ddm_transpose,
  6. ddm_iadd, ddm_isub, ddm_ineg, ddm_imatmul, ddm_imul, ddm_irref,
  7. ddm_idet, ddm_iinv, ddm_ilu, ddm_ilu_split, ddm_ilu_solve, ddm_berk)
  8. from sympy.polys.matrices.exceptions import (
  9. DMShapeError, DMNonInvertibleMatrixError, DMNonSquareMatrixError)
  10. def test_ddm_transpose():
  11. a = [[1, 2], [3, 4]]
  12. assert ddm_transpose(a) == [[1, 3], [2, 4]]
  13. def test_ddm_iadd():
  14. a = [[1, 2], [3, 4]]
  15. b = [[5, 6], [7, 8]]
  16. ddm_iadd(a, b)
  17. assert a == [[6, 8], [10, 12]]
  18. def test_ddm_isub():
  19. a = [[1, 2], [3, 4]]
  20. b = [[5, 6], [7, 8]]
  21. ddm_isub(a, b)
  22. assert a == [[-4, -4], [-4, -4]]
  23. def test_ddm_ineg():
  24. a = [[1, 2], [3, 4]]
  25. ddm_ineg(a)
  26. assert a == [[-1, -2], [-3, -4]]
  27. def test_ddm_matmul():
  28. a = [[1, 2], [3, 4]]
  29. ddm_imul(a, 2)
  30. assert a == [[2, 4], [6, 8]]
  31. a = [[1, 2], [3, 4]]
  32. ddm_imul(a, 0)
  33. assert a == [[0, 0], [0, 0]]
  34. def test_ddm_imatmul():
  35. a = [[1, 2, 3], [4, 5, 6]]
  36. b = [[1, 2], [3, 4], [5, 6]]
  37. c1 = [[0, 0], [0, 0]]
  38. ddm_imatmul(c1, a, b)
  39. assert c1 == [[22, 28], [49, 64]]
  40. c2 = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
  41. ddm_imatmul(c2, b, a)
  42. assert c2 == [[9, 12, 15], [19, 26, 33], [29, 40, 51]]
  43. b3 = [[1], [2], [3]]
  44. c3 = [[0], [0]]
  45. ddm_imatmul(c3, a, b3)
  46. assert c3 == [[14], [32]]
  47. def test_ddm_irref():
  48. # Empty matrix
  49. A = []
  50. Ar = []
  51. pivots = []
  52. assert ddm_irref(A) == pivots
  53. assert A == Ar
  54. # Standard square case
  55. A = [[QQ(0), QQ(1)], [QQ(1), QQ(1)]]
  56. Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]]
  57. pivots = [0, 1]
  58. assert ddm_irref(A) == pivots
  59. assert A == Ar
  60. # m < n case
  61. A = [[QQ(1), QQ(2), QQ(1)], [QQ(3), QQ(4), QQ(1)]]
  62. Ar = [[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]]
  63. pivots = [0, 1]
  64. assert ddm_irref(A) == pivots
  65. assert A == Ar
  66. # same m < n but reversed
  67. A = [[QQ(3), QQ(4), QQ(1)], [QQ(1), QQ(2), QQ(1)]]
  68. Ar = [[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]]
  69. pivots = [0, 1]
  70. assert ddm_irref(A) == pivots
  71. assert A == Ar
  72. # m > n case
  73. A = [[QQ(1), QQ(0)], [QQ(1), QQ(3)], [QQ(0), QQ(1)]]
  74. Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)], [QQ(0), QQ(0)]]
  75. pivots = [0, 1]
  76. assert ddm_irref(A) == pivots
  77. assert A == Ar
  78. # Example with missing pivot
  79. A = [[QQ(1), QQ(0), QQ(1)], [QQ(3), QQ(0), QQ(1)]]
  80. Ar = [[QQ(1), QQ(0), QQ(0)], [QQ(0), QQ(0), QQ(1)]]
  81. pivots = [0, 2]
  82. assert ddm_irref(A) == pivots
  83. assert A == Ar
  84. # Example with missing pivot and no replacement
  85. A = [[QQ(0), QQ(1)], [QQ(0), QQ(2)], [QQ(1), QQ(0)]]
  86. Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)], [QQ(0), QQ(0)]]
  87. pivots = [0, 1]
  88. assert ddm_irref(A) == pivots
  89. assert A == Ar
  90. def test_ddm_idet():
  91. A = []
  92. assert ddm_idet(A, ZZ) == ZZ(1)
  93. A = [[ZZ(2)]]
  94. assert ddm_idet(A, ZZ) == ZZ(2)
  95. A = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]]
  96. assert ddm_idet(A, ZZ) == ZZ(-2)
  97. A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(3), ZZ(5)]]
  98. assert ddm_idet(A, ZZ) == ZZ(-1)
  99. A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(2), ZZ(5)]]
  100. assert ddm_idet(A, ZZ) == ZZ(0)
  101. A = [[QQ(1, 2), QQ(1, 2)], [QQ(1, 3), QQ(1, 4)]]
  102. assert ddm_idet(A, QQ) == QQ(-1, 24)
  103. def test_ddm_inv():
  104. A = []
  105. Ainv = []
  106. ddm_iinv(Ainv, A, QQ)
  107. assert Ainv == A
  108. A = []
  109. Ainv = []
  110. raises(ValueError, lambda: ddm_iinv(Ainv, A, ZZ))
  111. A = [[QQ(1), QQ(2)]]
  112. Ainv = [[QQ(0), QQ(0)]]
  113. raises(DMNonSquareMatrixError, lambda: ddm_iinv(Ainv, A, QQ))
  114. A = [[QQ(1, 1), QQ(2, 1)], [QQ(3, 1), QQ(4, 1)]]
  115. Ainv = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]]
  116. Ainv_expected = [[QQ(-2, 1), QQ(1, 1)], [QQ(3, 2), QQ(-1, 2)]]
  117. ddm_iinv(Ainv, A, QQ)
  118. assert Ainv == Ainv_expected
  119. A = [[QQ(1, 1), QQ(2, 1)], [QQ(2, 1), QQ(4, 1)]]
  120. Ainv = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]]
  121. raises(DMNonInvertibleMatrixError, lambda: ddm_iinv(Ainv, A, QQ))
  122. def test_ddm_ilu():
  123. A = []
  124. Alu = []
  125. swaps = ddm_ilu(A)
  126. assert A == Alu
  127. assert swaps == []
  128. A = [[]]
  129. Alu = [[]]
  130. swaps = ddm_ilu(A)
  131. assert A == Alu
  132. assert swaps == []
  133. A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
  134. Alu = [[QQ(1), QQ(2)], [QQ(3), QQ(-2)]]
  135. swaps = ddm_ilu(A)
  136. assert A == Alu
  137. assert swaps == []
  138. A = [[QQ(0), QQ(2)], [QQ(3), QQ(4)]]
  139. Alu = [[QQ(3), QQ(4)], [QQ(0), QQ(2)]]
  140. swaps = ddm_ilu(A)
  141. assert A == Alu
  142. assert swaps == [(0, 1)]
  143. A = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)], [QQ(7), QQ(8), QQ(9)]]
  144. Alu = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(-3), QQ(-6)], [QQ(7), QQ(2), QQ(0)]]
  145. swaps = ddm_ilu(A)
  146. assert A == Alu
  147. assert swaps == []
  148. A = [[QQ(0), QQ(1), QQ(2)], [QQ(0), QQ(1), QQ(3)], [QQ(1), QQ(1), QQ(2)]]
  149. Alu = [[QQ(1), QQ(1), QQ(2)], [QQ(0), QQ(1), QQ(3)], [QQ(0), QQ(1), QQ(-1)]]
  150. swaps = ddm_ilu(A)
  151. assert A == Alu
  152. assert swaps == [(0, 2)]
  153. A = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]]
  154. Alu = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(-3), QQ(-6)]]
  155. swaps = ddm_ilu(A)
  156. assert A == Alu
  157. assert swaps == []
  158. A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]]
  159. Alu = [[QQ(1), QQ(2)], [QQ(3), QQ(-2)], [QQ(5), QQ(2)]]
  160. swaps = ddm_ilu(A)
  161. assert A == Alu
  162. assert swaps == []
  163. def test_ddm_ilu_split():
  164. U = []
  165. L = []
  166. Uexp = []
  167. Lexp = []
  168. swaps = ddm_ilu_split(L, U, QQ)
  169. assert U == Uexp
  170. assert L == Lexp
  171. assert swaps == []
  172. U = [[]]
  173. L = [[QQ(1)]]
  174. Uexp = [[]]
  175. Lexp = [[QQ(1)]]
  176. swaps = ddm_ilu_split(L, U, QQ)
  177. assert U == Uexp
  178. assert L == Lexp
  179. assert swaps == []
  180. U = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
  181. L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]]
  182. Uexp = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)]]
  183. Lexp = [[QQ(1), QQ(0)], [QQ(3), QQ(1)]]
  184. swaps = ddm_ilu_split(L, U, QQ)
  185. assert U == Uexp
  186. assert L == Lexp
  187. assert swaps == []
  188. U = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]]
  189. L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]]
  190. Uexp = [[QQ(1), QQ(2), QQ(3)], [QQ(0), QQ(-3), QQ(-6)]]
  191. Lexp = [[QQ(1), QQ(0)], [QQ(4), QQ(1)]]
  192. swaps = ddm_ilu_split(L, U, QQ)
  193. assert U == Uexp
  194. assert L == Lexp
  195. assert swaps == []
  196. U = [[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]]
  197. L = [[QQ(1), QQ(0), QQ(0)], [QQ(0), QQ(1), QQ(0)], [QQ(0), QQ(0), QQ(1)]]
  198. Uexp = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)], [QQ(0), QQ(0)]]
  199. Lexp = [[QQ(1), QQ(0), QQ(0)], [QQ(3), QQ(1), QQ(0)], [QQ(5), QQ(2), QQ(1)]]
  200. swaps = ddm_ilu_split(L, U, QQ)
  201. assert U == Uexp
  202. assert L == Lexp
  203. assert swaps == []
  204. def test_ddm_ilu_solve():
  205. # Basic example
  206. # A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
  207. U = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)]]
  208. L = [[QQ(1), QQ(0)], [QQ(3), QQ(1)]]
  209. swaps = []
  210. b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  211. x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ)
  212. xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
  213. ddm_ilu_solve(x, L, U, swaps, b)
  214. assert x == xexp
  215. # Example with swaps
  216. # A = [[QQ(0), QQ(2)], [QQ(3), QQ(4)]]
  217. U = [[QQ(3), QQ(4)], [QQ(0), QQ(2)]]
  218. L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]]
  219. swaps = [(0, 1)]
  220. b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  221. x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ)
  222. xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
  223. ddm_ilu_solve(x, L, U, swaps, b)
  224. assert x == xexp
  225. # Overdetermined, consistent
  226. # A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ)
  227. U = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)], [QQ(0), QQ(0)]]
  228. L = [[QQ(1), QQ(0), QQ(0)], [QQ(3), QQ(1), QQ(0)], [QQ(5), QQ(2), QQ(1)]]
  229. swaps = []
  230. b = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ)
  231. x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ)
  232. xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
  233. ddm_ilu_solve(x, L, U, swaps, b)
  234. assert x == xexp
  235. # Overdetermined, inconsistent
  236. b = DDM([[QQ(1)], [QQ(2)], [QQ(4)]], (3, 1), QQ)
  237. raises(DMNonInvertibleMatrixError, lambda: ddm_ilu_solve(x, L, U, swaps, b))
  238. # Square, noninvertible
  239. # A = DDM([[QQ(1), QQ(2)], [QQ(1), QQ(2)]], (2, 2), QQ)
  240. U = [[QQ(1), QQ(2)], [QQ(0), QQ(0)]]
  241. L = [[QQ(1), QQ(0)], [QQ(1), QQ(1)]]
  242. swaps = []
  243. b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
  244. raises(DMNonInvertibleMatrixError, lambda: ddm_ilu_solve(x, L, U, swaps, b))
  245. # Underdetermined
  246. # A = DDM([[QQ(1), QQ(2)]], (1, 2), QQ)
  247. U = [[QQ(1), QQ(2)]]
  248. L = [[QQ(1)]]
  249. swaps = []
  250. b = DDM([[QQ(3)]], (1, 1), QQ)
  251. raises(NotImplementedError, lambda: ddm_ilu_solve(x, L, U, swaps, b))
  252. # Shape mismatch
  253. b3 = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ)
  254. raises(DMShapeError, lambda: ddm_ilu_solve(x, L, U, swaps, b3))
  255. # Empty shape mismatch
  256. U = [[QQ(1)]]
  257. L = [[QQ(1)]]
  258. swaps = []
  259. x = [[QQ(1)]]
  260. b = []
  261. raises(DMShapeError, lambda: ddm_ilu_solve(x, L, U, swaps, b))
  262. # Empty system
  263. U = []
  264. L = []
  265. swaps = []
  266. b = []
  267. x = []
  268. ddm_ilu_solve(x, L, U, swaps, b)
  269. assert x == []
  270. def test_ddm_charpoly():
  271. A = []
  272. assert ddm_berk(A, ZZ) == [[ZZ(1)]]
  273. A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]]
  274. Avec = [[ZZ(1)], [ZZ(-15)], [ZZ(-18)], [ZZ(0)]]
  275. assert ddm_berk(A, ZZ) == Avec
  276. A = DDM([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
  277. raises(DMShapeError, lambda: ddm_berk(A, ZZ))