test_decompositions.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. from sympy.core.function import expand_mul
  2. from sympy.core.numbers import I, Rational
  3. from sympy.core.singleton import S
  4. from sympy.core.symbol import Symbol
  5. from sympy.functions.elementary.miscellaneous import sqrt
  6. from sympy.functions.elementary.complexes import Abs
  7. from sympy.simplify.simplify import simplify
  8. from sympy.matrices.matrices import NonSquareMatrixError
  9. from sympy.matrices import Matrix, zeros, eye, SparseMatrix
  10. from sympy.abc import x, y, z
  11. from sympy.testing.pytest import raises, slow
  12. from sympy.testing.matrices import allclose
  13. def test_LUdecomp():
  14. testmat = Matrix([[0, 2, 5, 3],
  15. [3, 3, 7, 4],
  16. [8, 4, 0, 2],
  17. [-2, 6, 3, 4]])
  18. L, U, p = testmat.LUdecomposition()
  19. assert L.is_lower
  20. assert U.is_upper
  21. assert (L*U).permute_rows(p, 'backward') - testmat == zeros(4)
  22. testmat = Matrix([[6, -2, 7, 4],
  23. [0, 3, 6, 7],
  24. [1, -2, 7, 4],
  25. [-9, 2, 6, 3]])
  26. L, U, p = testmat.LUdecomposition()
  27. assert L.is_lower
  28. assert U.is_upper
  29. assert (L*U).permute_rows(p, 'backward') - testmat == zeros(4)
  30. # non-square
  31. testmat = Matrix([[1, 2, 3],
  32. [4, 5, 6],
  33. [7, 8, 9],
  34. [10, 11, 12]])
  35. L, U, p = testmat.LUdecomposition(rankcheck=False)
  36. assert L.is_lower
  37. assert U.is_upper
  38. assert (L*U).permute_rows(p, 'backward') - testmat == zeros(4, 3)
  39. # square and singular
  40. testmat = Matrix([[1, 2, 3],
  41. [2, 4, 6],
  42. [4, 5, 6]])
  43. L, U, p = testmat.LUdecomposition(rankcheck=False)
  44. assert L.is_lower
  45. assert U.is_upper
  46. assert (L*U).permute_rows(p, 'backward') - testmat == zeros(3)
  47. M = Matrix(((1, x, 1), (2, y, 0), (y, 0, z)))
  48. L, U, p = M.LUdecomposition()
  49. assert L.is_lower
  50. assert U.is_upper
  51. assert (L*U).permute_rows(p, 'backward') - M == zeros(3)
  52. mL = Matrix((
  53. (1, 0, 0),
  54. (2, 3, 0),
  55. ))
  56. assert mL.is_lower is True
  57. assert mL.is_upper is False
  58. mU = Matrix((
  59. (1, 2, 3),
  60. (0, 4, 5),
  61. ))
  62. assert mU.is_lower is False
  63. assert mU.is_upper is True
  64. # test FF LUdecomp
  65. M = Matrix([[1, 3, 3],
  66. [3, 2, 6],
  67. [3, 2, 2]])
  68. P, L, Dee, U = M.LUdecompositionFF()
  69. assert P*M == L*Dee.inv()*U
  70. M = Matrix([[1, 2, 3, 4],
  71. [3, -1, 2, 3],
  72. [3, 1, 3, -2],
  73. [6, -1, 0, 2]])
  74. P, L, Dee, U = M.LUdecompositionFF()
  75. assert P*M == L*Dee.inv()*U
  76. M = Matrix([[0, 0, 1],
  77. [2, 3, 0],
  78. [3, 1, 4]])
  79. P, L, Dee, U = M.LUdecompositionFF()
  80. assert P*M == L*Dee.inv()*U
  81. # issue 15794
  82. M = Matrix(
  83. [[1, 2, 3],
  84. [4, 5, 6],
  85. [7, 8, 9]]
  86. )
  87. raises(ValueError, lambda : M.LUdecomposition_Simple(rankcheck=True))
  88. def test_singular_value_decompositionD():
  89. A = Matrix([[1, 2], [2, 1]])
  90. U, S, V = A.singular_value_decomposition()
  91. assert U * S * V.T == A
  92. assert U.T * U == eye(U.cols)
  93. assert V.T * V == eye(V.cols)
  94. B = Matrix([[1, 2]])
  95. U, S, V = B.singular_value_decomposition()
  96. assert U * S * V.T == B
  97. assert U.T * U == eye(U.cols)
  98. assert V.T * V == eye(V.cols)
  99. C = Matrix([
  100. [1, 0, 0, 0, 2],
  101. [0, 0, 3, 0, 0],
  102. [0, 0, 0, 0, 0],
  103. [0, 2, 0, 0, 0],
  104. ])
  105. U, S, V = C.singular_value_decomposition()
  106. assert U * S * V.T == C
  107. assert U.T * U == eye(U.cols)
  108. assert V.T * V == eye(V.cols)
  109. D = Matrix([[Rational(1, 3), sqrt(2)], [0, Rational(1, 4)]])
  110. U, S, V = D.singular_value_decomposition()
  111. assert simplify(U.T * U) == eye(U.cols)
  112. assert simplify(V.T * V) == eye(V.cols)
  113. assert simplify(U * S * V.T) == D
  114. def test_QR():
  115. A = Matrix([[1, 2], [2, 3]])
  116. Q, S = A.QRdecomposition()
  117. R = Rational
  118. assert Q == Matrix([
  119. [ 5**R(-1, 2), (R(2)/5)*(R(1)/5)**R(-1, 2)],
  120. [2*5**R(-1, 2), (-R(1)/5)*(R(1)/5)**R(-1, 2)]])
  121. assert S == Matrix([[5**R(1, 2), 8*5**R(-1, 2)], [0, (R(1)/5)**R(1, 2)]])
  122. assert Q*S == A
  123. assert Q.T * Q == eye(2)
  124. A = Matrix([[1, 1, 1], [1, 1, 3], [2, 3, 4]])
  125. Q, R = A.QRdecomposition()
  126. assert Q.T * Q == eye(Q.cols)
  127. assert R.is_upper
  128. assert A == Q*R
  129. A = Matrix([[12, 0, -51], [6, 0, 167], [-4, 0, 24]])
  130. Q, R = A.QRdecomposition()
  131. assert Q.T * Q == eye(Q.cols)
  132. assert R.is_upper
  133. assert A == Q*R
  134. x = Symbol('x')
  135. A = Matrix([x])
  136. Q, R = A.QRdecomposition()
  137. assert Q == Matrix([x / Abs(x)])
  138. assert R == Matrix([Abs(x)])
  139. A = Matrix([[x, 0], [0, x]])
  140. Q, R = A.QRdecomposition()
  141. assert Q == x / Abs(x) * Matrix([[1, 0], [0, 1]])
  142. assert R == Abs(x) * Matrix([[1, 0], [0, 1]])
  143. def test_QR_non_square():
  144. # Narrow (cols < rows) matrices
  145. A = Matrix([[9, 0, 26], [12, 0, -7], [0, 4, 4], [0, -3, -3]])
  146. Q, R = A.QRdecomposition()
  147. assert Q.T * Q == eye(Q.cols)
  148. assert R.is_upper
  149. assert A == Q*R
  150. A = Matrix([[1, -1, 4], [1, 4, -2], [1, 4, 2], [1, -1, 0]])
  151. Q, R = A.QRdecomposition()
  152. assert Q.T * Q == eye(Q.cols)
  153. assert R.is_upper
  154. assert A == Q*R
  155. A = Matrix(2, 1, [1, 2])
  156. Q, R = A.QRdecomposition()
  157. assert Q.T * Q == eye(Q.cols)
  158. assert R.is_upper
  159. assert A == Q*R
  160. # Wide (cols > rows) matrices
  161. A = Matrix([[1, 2, 3], [4, 5, 6]])
  162. Q, R = A.QRdecomposition()
  163. assert Q.T * Q == eye(Q.cols)
  164. assert R.is_upper
  165. assert A == Q*R
  166. A = Matrix([[1, 2, 3, 4], [1, 4, 9, 16], [1, 8, 27, 64]])
  167. Q, R = A.QRdecomposition()
  168. assert Q.T * Q == eye(Q.cols)
  169. assert R.is_upper
  170. assert A == Q*R
  171. A = Matrix(1, 2, [1, 2])
  172. Q, R = A.QRdecomposition()
  173. assert Q.T * Q == eye(Q.cols)
  174. assert R.is_upper
  175. assert A == Q*R
  176. def test_QR_trivial():
  177. # Rank deficient matrices
  178. A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  179. Q, R = A.QRdecomposition()
  180. assert Q.T * Q == eye(Q.cols)
  181. assert R.is_upper
  182. assert A == Q*R
  183. A = Matrix([[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]])
  184. Q, R = A.QRdecomposition()
  185. assert Q.T * Q == eye(Q.cols)
  186. assert R.is_upper
  187. assert A == Q*R
  188. A = Matrix([[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]).T
  189. Q, R = A.QRdecomposition()
  190. assert Q.T * Q == eye(Q.cols)
  191. assert R.is_upper
  192. assert A == Q*R
  193. # Zero rank matrices
  194. A = Matrix([[0, 0, 0]])
  195. Q, R = A.QRdecomposition()
  196. assert Q.T * Q == eye(Q.cols)
  197. assert R.is_upper
  198. assert A == Q*R
  199. A = Matrix([[0, 0, 0]]).T
  200. Q, R = A.QRdecomposition()
  201. assert Q.T * Q == eye(Q.cols)
  202. assert R.is_upper
  203. assert A == Q*R
  204. A = Matrix([[0, 0, 0], [0, 0, 0]])
  205. Q, R = A.QRdecomposition()
  206. assert Q.T * Q == eye(Q.cols)
  207. assert R.is_upper
  208. assert A == Q*R
  209. A = Matrix([[0, 0, 0], [0, 0, 0]]).T
  210. Q, R = A.QRdecomposition()
  211. assert Q.T * Q == eye(Q.cols)
  212. assert R.is_upper
  213. assert A == Q*R
  214. # Rank deficient matrices with zero norm from beginning columns
  215. A = Matrix([[0, 0, 0], [1, 2, 3]]).T
  216. Q, R = A.QRdecomposition()
  217. assert Q.T * Q == eye(Q.cols)
  218. assert R.is_upper
  219. assert A == Q*R
  220. A = Matrix([[0, 0, 0, 0], [1, 2, 3, 4], [0, 0, 0, 0]]).T
  221. Q, R = A.QRdecomposition()
  222. assert Q.T * Q == eye(Q.cols)
  223. assert R.is_upper
  224. assert A == Q*R
  225. A = Matrix([[0, 0, 0, 0], [1, 2, 3, 4], [0, 0, 0, 0], [2, 4, 6, 8]]).T
  226. Q, R = A.QRdecomposition()
  227. assert Q.T * Q == eye(Q.cols)
  228. assert R.is_upper
  229. assert A == Q*R
  230. A = Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0], [1, 2, 3]]).T
  231. Q, R = A.QRdecomposition()
  232. assert Q.T * Q == eye(Q.cols)
  233. assert R.is_upper
  234. assert A == Q*R
  235. def test_QR_float():
  236. A = Matrix([[1, 1], [1, 1.01]])
  237. Q, R = A.QRdecomposition()
  238. assert allclose(Q * R, A)
  239. assert allclose(Q * Q.T, Matrix.eye(2))
  240. assert allclose(Q.T * Q, Matrix.eye(2))
  241. A = Matrix([[1, 1], [1, 1.001]])
  242. Q, R = A.QRdecomposition()
  243. assert allclose(Q * R, A)
  244. assert allclose(Q * Q.T, Matrix.eye(2))
  245. assert allclose(Q.T * Q, Matrix.eye(2))
  246. def test_LUdecomposition_Simple_iszerofunc():
  247. # Test if callable passed to matrices.LUdecomposition_Simple() as iszerofunc keyword argument is used inside
  248. # matrices.LUdecomposition_Simple()
  249. magic_string = "I got passed in!"
  250. def goofyiszero(value):
  251. raise ValueError(magic_string)
  252. try:
  253. lu, p = Matrix([[1, 0], [0, 1]]).LUdecomposition_Simple(iszerofunc=goofyiszero)
  254. except ValueError as err:
  255. assert magic_string == err.args[0]
  256. return
  257. assert False
  258. def test_LUdecomposition_iszerofunc():
  259. # Test if callable passed to matrices.LUdecomposition() as iszerofunc keyword argument is used inside
  260. # matrices.LUdecomposition_Simple()
  261. magic_string = "I got passed in!"
  262. def goofyiszero(value):
  263. raise ValueError(magic_string)
  264. try:
  265. l, u, p = Matrix([[1, 0], [0, 1]]).LUdecomposition(iszerofunc=goofyiszero)
  266. except ValueError as err:
  267. assert magic_string == err.args[0]
  268. return
  269. assert False
  270. def test_LDLdecomposition():
  271. raises(NonSquareMatrixError, lambda: Matrix((1, 2)).LDLdecomposition())
  272. raises(ValueError, lambda: Matrix(((1, 2), (3, 4))).LDLdecomposition())
  273. raises(ValueError, lambda: Matrix(((5 + I, 0), (0, 1))).LDLdecomposition())
  274. raises(ValueError, lambda: Matrix(((1, 5), (5, 1))).LDLdecomposition())
  275. raises(ValueError, lambda: Matrix(((1, 2), (3, 4))).LDLdecomposition(hermitian=False))
  276. A = Matrix(((1, 5), (5, 1)))
  277. L, D = A.LDLdecomposition(hermitian=False)
  278. assert L * D * L.T == A
  279. A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11)))
  280. L, D = A.LDLdecomposition()
  281. assert L * D * L.T == A
  282. assert L.is_lower
  283. assert L == Matrix([[1, 0, 0], [ Rational(3, 5), 1, 0], [Rational(-1, 5), Rational(1, 3), 1]])
  284. assert D.is_diagonal()
  285. assert D == Matrix([[25, 0, 0], [0, 9, 0], [0, 0, 9]])
  286. A = Matrix(((4, -2*I, 2 + 2*I), (2*I, 2, -1 + I), (2 - 2*I, -1 - I, 11)))
  287. L, D = A.LDLdecomposition()
  288. assert expand_mul(L * D * L.H) == A
  289. assert L.expand() == Matrix([[1, 0, 0], [I/2, 1, 0], [S.Half - I/2, 0, 1]])
  290. assert D.expand() == Matrix(((4, 0, 0), (0, 1, 0), (0, 0, 9)))
  291. raises(NonSquareMatrixError, lambda: SparseMatrix((1, 2)).LDLdecomposition())
  292. raises(ValueError, lambda: SparseMatrix(((1, 2), (3, 4))).LDLdecomposition())
  293. raises(ValueError, lambda: SparseMatrix(((5 + I, 0), (0, 1))).LDLdecomposition())
  294. raises(ValueError, lambda: SparseMatrix(((1, 5), (5, 1))).LDLdecomposition())
  295. raises(ValueError, lambda: SparseMatrix(((1, 2), (3, 4))).LDLdecomposition(hermitian=False))
  296. A = SparseMatrix(((1, 5), (5, 1)))
  297. L, D = A.LDLdecomposition(hermitian=False)
  298. assert L * D * L.T == A
  299. A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11)))
  300. L, D = A.LDLdecomposition()
  301. assert L * D * L.T == A
  302. assert L.is_lower
  303. assert L == Matrix([[1, 0, 0], [ Rational(3, 5), 1, 0], [Rational(-1, 5), Rational(1, 3), 1]])
  304. assert D.is_diagonal()
  305. assert D == Matrix([[25, 0, 0], [0, 9, 0], [0, 0, 9]])
  306. A = SparseMatrix(((4, -2*I, 2 + 2*I), (2*I, 2, -1 + I), (2 - 2*I, -1 - I, 11)))
  307. L, D = A.LDLdecomposition()
  308. assert expand_mul(L * D * L.H) == A
  309. assert L == Matrix(((1, 0, 0), (I/2, 1, 0), (S.Half - I/2, 0, 1)))
  310. assert D == Matrix(((4, 0, 0), (0, 1, 0), (0, 0, 9)))
  311. def test_pinv_succeeds_with_rank_decomposition_method():
  312. # Test rank decomposition method of pseudoinverse succeeding
  313. As = [Matrix([
  314. [61, 89, 55, 20, 71, 0],
  315. [62, 96, 85, 85, 16, 0],
  316. [69, 56, 17, 4, 54, 0],
  317. [10, 54, 91, 41, 71, 0],
  318. [ 7, 30, 10, 48, 90, 0],
  319. [0,0,0,0,0,0]])]
  320. for A in As:
  321. A_pinv = A.pinv(method="RD")
  322. AAp = A * A_pinv
  323. ApA = A_pinv * A
  324. assert simplify(AAp * A) == A
  325. assert simplify(ApA * A_pinv) == A_pinv
  326. assert AAp.H == AAp
  327. assert ApA.H == ApA
  328. def test_rank_decomposition():
  329. a = Matrix(0, 0, [])
  330. c, f = a.rank_decomposition()
  331. assert f.is_echelon
  332. assert c.cols == f.rows == a.rank()
  333. assert c * f == a
  334. a = Matrix(1, 1, [5])
  335. c, f = a.rank_decomposition()
  336. assert f.is_echelon
  337. assert c.cols == f.rows == a.rank()
  338. assert c * f == a
  339. a = Matrix(3, 3, [1, 2, 3, 1, 2, 3, 1, 2, 3])
  340. c, f = a.rank_decomposition()
  341. assert f.is_echelon
  342. assert c.cols == f.rows == a.rank()
  343. assert c * f == a
  344. a = Matrix([
  345. [0, 0, 1, 2, 2, -5, 3],
  346. [-1, 5, 2, 2, 1, -7, 5],
  347. [0, 0, -2, -3, -3, 8, -5],
  348. [-1, 5, 0, -1, -2, 1, 0]])
  349. c, f = a.rank_decomposition()
  350. assert f.is_echelon
  351. assert c.cols == f.rows == a.rank()
  352. assert c * f == a
  353. @slow
  354. def test_upper_hessenberg_decomposition():
  355. A = Matrix([
  356. [1, 0, sqrt(3)],
  357. [sqrt(2), Rational(1, 2), 2],
  358. [1, Rational(1, 4), 3],
  359. ])
  360. H, P = A.upper_hessenberg_decomposition()
  361. assert simplify(P * P.H) == eye(P.cols)
  362. assert simplify(P.H * P) == eye(P.cols)
  363. assert H.is_upper_hessenberg
  364. assert (simplify(P * H * P.H)) == A
  365. B = Matrix([
  366. [1, 2, 10],
  367. [8, 2, 5],
  368. [3, 12, 34],
  369. ])
  370. H, P = B.upper_hessenberg_decomposition()
  371. assert simplify(P * P.H) == eye(P.cols)
  372. assert simplify(P.H * P) == eye(P.cols)
  373. assert H.is_upper_hessenberg
  374. assert simplify(P * H * P.H) == B
  375. C = Matrix([
  376. [1, sqrt(2), 2, 3],
  377. [0, 5, 3, 4],
  378. [1, 1, 4, sqrt(5)],
  379. [0, 2, 2, 3]
  380. ])
  381. H, P = C.upper_hessenberg_decomposition()
  382. assert simplify(P * P.H) == eye(P.cols)
  383. assert simplify(P.H * P) == eye(P.cols)
  384. assert H.is_upper_hessenberg
  385. assert simplify(P * H * P.H) == C
  386. D = Matrix([
  387. [1, 2, 3],
  388. [-3, 5, 6],
  389. [4, -8, 9],
  390. ])
  391. H, P = D.upper_hessenberg_decomposition()
  392. assert simplify(P * P.H) == eye(P.cols)
  393. assert simplify(P.H * P) == eye(P.cols)
  394. assert H.is_upper_hessenberg
  395. assert simplify(P * H * P.H) == D
  396. E = Matrix([
  397. [1, 0, 0, 0],
  398. [0, 1, 0, 0],
  399. [1, 1, 0, 1],
  400. [1, 1, 1, 0]
  401. ])
  402. H, P = E.upper_hessenberg_decomposition()
  403. assert simplify(P * P.H) == eye(P.cols)
  404. assert simplify(P.H * P) == eye(P.cols)
  405. assert H.is_upper_hessenberg
  406. assert simplify(P * H * P.H) == E