/sympy/matrices/densesolve.py

https://github.com/ArchKaine/sympy
Python | 448 lines | 277 code | 35 blank | 136 comment | 14 complexity | 7df1d6e67b456a0d0eac418637537afd MD5 | raw file
  1. """
  2. Solution of equations using dense matrices.
  3. The dense matrix is stored as a list of lists.
  4. """
  5. import copy
  6. from sympy.core.power import isqrt
  7. from sympy.core.symbol import symbols
  8. from sympy.matrices.densetools import (
  9. augment, col, conjugate_transpose, eye, rowadd, rowmul)
  10. from sympy.utilities.exceptions import SymPyDeprecationWarning
  11. SymPyDeprecationWarning(
  12. feature="densesolve",
  13. issue=12695,
  14. deprecated_since_version="1.1").warn()
  15. def row_echelon(matlist, K):
  16. """
  17. Returns the row echelon form of a matrix with diagonal elements
  18. reduced to 1.
  19. Examples
  20. ========
  21. >>> from sympy.matrices.densesolve import row_echelon
  22. >>> from sympy import QQ
  23. >>> a = [
  24. ... [QQ(3), QQ(7), QQ(4)],
  25. ... [QQ(2), QQ(4), QQ(5)],
  26. ... [QQ(6), QQ(2), QQ(3)]]
  27. >>> row_echelon(a, QQ)
  28. [[1, 7/3, 4/3], [0, 1, -7/2], [0, 0, 1]]
  29. See Also
  30. ========
  31. rref
  32. """
  33. result_matlist = copy.deepcopy(matlist)
  34. nrow = len(result_matlist)
  35. for i in range(nrow):
  36. if (result_matlist[i][i] != 1 and result_matlist[i][i] != 0):
  37. rowmul(result_matlist, i, 1/result_matlist[i][i], K)
  38. for j in range(i + 1, nrow):
  39. if (result_matlist[j][i] != 0):
  40. rowadd(result_matlist, j, i, -result_matlist[j][i], K)
  41. return result_matlist
  42. def rref(matlist, K):
  43. """
  44. Returns the reduced row echelon form of a Matrix.
  45. Examples
  46. ========
  47. >>> from sympy.matrices.densesolve import rref
  48. >>> from sympy import QQ
  49. >>> a = [
  50. ... [QQ(1), QQ(2), QQ(1)],
  51. ... [QQ(-2), QQ(-3), QQ(1)],
  52. ... [QQ(3), QQ(5), QQ(0)]]
  53. >>> rref(a, QQ)
  54. [[1, 0, -5], [0, 1, 3], [0, 0, 0]]
  55. See Also
  56. ========
  57. row_echelon
  58. """
  59. result_matlist = copy.deepcopy(matlist)
  60. result_matlist = row_echelon(result_matlist, K)
  61. nrow = len(result_matlist)
  62. for i in range(nrow):
  63. if result_matlist[i][i] == 1:
  64. for j in range(i):
  65. rowadd(result_matlist, j, i, -result_matlist[j][i], K)
  66. return result_matlist
  67. def LU(matlist, K, reverse = 0):
  68. """
  69. It computes the LU decomposition of a matrix and returns L and U
  70. matrices.
  71. Examples
  72. ========
  73. >>> from sympy.matrices.densesolve import LU
  74. >>> from sympy import QQ
  75. >>> a = [
  76. ... [QQ(1), QQ(2), QQ(3)],
  77. ... [QQ(2), QQ(-4), QQ(6)],
  78. ... [QQ(3), QQ(-9), QQ(-3)]]
  79. >>> LU(a, QQ)
  80. ([[1, 0, 0], [2, 1, 0], [3, 15/8, 1]], [[1, 2, 3], [0, -8, 0], [0, 0, -12]])
  81. See Also
  82. ========
  83. upper_triangle
  84. lower_triangle
  85. """
  86. nrow = len(matlist)
  87. new_matlist1, new_matlist2 = eye(nrow, K), copy.deepcopy(matlist)
  88. for i in range(nrow):
  89. for j in range(i + 1, nrow):
  90. if (new_matlist2[j][i] != 0):
  91. new_matlist1[j][i] = new_matlist2[j][i]/new_matlist2[i][i]
  92. rowadd(new_matlist2, j, i, -new_matlist2[j][i]/new_matlist2[i][i], K)
  93. return new_matlist1, new_matlist2
  94. def cholesky(matlist, K):
  95. """
  96. Performs the cholesky decomposition of a Hermitian matrix and
  97. returns L and it's conjugate transpose.
  98. Examples
  99. ========
  100. >>> from sympy.matrices.densesolve import cholesky
  101. >>> from sympy import QQ
  102. >>> cholesky([[QQ(25), QQ(15), QQ(-5)], [QQ(15), QQ(18), QQ(0)], [QQ(-5), QQ(0), QQ(11)]], QQ)
  103. ([[5, 0, 0], [3, 3, 0], [-1, 1, 3]], [[5, 3, -1], [0, 3, 1], [0, 0, 3]])
  104. See Also
  105. ========
  106. cholesky_solve
  107. """
  108. new_matlist = copy.deepcopy(matlist)
  109. nrow = len(new_matlist)
  110. L = eye(nrow, K)
  111. for i in range(nrow):
  112. for j in range(i + 1):
  113. a = K.zero
  114. for k in range(j):
  115. a += L[i][k]*L[j][k]
  116. if i == j:
  117. L[i][j] = isqrt(new_matlist[i][j] - a)
  118. else:
  119. L[i][j] = (new_matlist[i][j] - a)/L[j][j]
  120. return L, conjugate_transpose(L, K)
  121. def LDL(matlist, K):
  122. """
  123. Performs the LDL decomposition of a hermitian matrix and returns L, D and
  124. transpose of L. Only applicable to rational entries.
  125. Examples
  126. ========
  127. >>> from sympy.matrices.densesolve import LDL
  128. >>> from sympy import QQ
  129. >>> a = [
  130. ... [QQ(4), QQ(12), QQ(-16)],
  131. ... [QQ(12), QQ(37), QQ(-43)],
  132. ... [QQ(-16), QQ(-43), QQ(98)]]
  133. >>> LDL(a, QQ)
  134. ([[1, 0, 0], [3, 1, 0], [-4, 5, 1]], [[4, 0, 0], [0, 1, 0], [0, 0, 9]], [[1, 3, -4], [0, 1, 5], [0, 0, 1]])
  135. """
  136. new_matlist = copy.deepcopy(matlist)
  137. nrow = len(new_matlist)
  138. L, D = eye(nrow, K), eye(nrow, K)
  139. for i in range(nrow):
  140. for j in range(i + 1):
  141. a = K.zero
  142. for k in range(j):
  143. a += L[i][k]*L[j][k]*D[k][k]
  144. if i == j:
  145. D[j][j] = new_matlist[j][j] - a
  146. else:
  147. L[i][j] = (new_matlist[i][j] - a)/D[j][j]
  148. return L, D, conjugate_transpose(L, K)
  149. def upper_triangle(matlist, K):
  150. """
  151. Transforms a given matrix to an upper triangle matrix by performing
  152. row operations on it.
  153. Examples
  154. ========
  155. >>> from sympy.matrices.densesolve import upper_triangle
  156. >>> from sympy import QQ
  157. >>> a = [
  158. ... [QQ(4,1), QQ(12,1), QQ(-16,1)],
  159. ... [QQ(12,1), QQ(37,1), QQ(-43,1)],
  160. ... [QQ(-16,1), QQ(-43,1), QQ(98,1)]]
  161. >>> upper_triangle(a, QQ)
  162. [[4, 12, -16], [0, 1, 5], [0, 0, 9]]
  163. See Also
  164. ========
  165. LU
  166. """
  167. copy_matlist = copy.deepcopy(matlist)
  168. lower_triangle, upper_triangle = LU(copy_matlist, K)
  169. return upper_triangle
  170. def lower_triangle(matlist, K):
  171. """
  172. Transforms a given matrix to a lower triangle matrix by performing
  173. row operations on it.
  174. Examples
  175. ========
  176. >>> from sympy.matrices.densesolve import lower_triangle
  177. >>> from sympy import QQ
  178. >>> a = [
  179. ... [QQ(4,1), QQ(12,1), QQ(-16)],
  180. ... [QQ(12,1), QQ(37,1), QQ(-43,1)],
  181. ... [QQ(-16,1), QQ(-43,1), QQ(98,1)]]
  182. >>> lower_triangle(a, QQ)
  183. [[1, 0, 0], [3, 1, 0], [-4, 5, 1]]
  184. See Also
  185. ========
  186. LU
  187. """
  188. copy_matlist = copy.deepcopy(matlist)
  189. lower_triangle, upper_triangle = LU(copy_matlist, K, reverse = 1)
  190. return lower_triangle
  191. def rref_solve(matlist, variable, constant, K):
  192. """
  193. Solves a system of equations using reduced row echelon form given
  194. a matrix of coefficients, a vector of variables and a vector of constants.
  195. Examples
  196. ========
  197. >>> from sympy.matrices.densesolve import rref_solve
  198. >>> from sympy import QQ
  199. >>> from sympy import Dummy
  200. >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z')
  201. >>> coefficients = [
  202. ... [QQ(25), QQ(15), QQ(-5)],
  203. ... [QQ(15), QQ(18), QQ(0)],
  204. ... [QQ(-5), QQ(0), QQ(11)]]
  205. >>> constants = [
  206. ... [QQ(2)],
  207. ... [QQ(3)],
  208. ... [QQ(1)]]
  209. >>> variables = [
  210. ... [x],
  211. ... [y],
  212. ... [z]]
  213. >>> rref_solve(coefficients, variables, constants, QQ)
  214. [[-1/225], [23/135], [4/45]]
  215. See Also
  216. ========
  217. row_echelon
  218. augment
  219. """
  220. new_matlist = copy.deepcopy(matlist)
  221. augmented = augment(new_matlist, constant, K)
  222. solution = rref(augmented, K)
  223. return col(solution, -1)
  224. def LU_solve(matlist, variable, constant, K):
  225. """
  226. Solves a system of equations using LU decomposition given a matrix
  227. of coefficients, a vector of variables and a vector of constants.
  228. Examples
  229. ========
  230. >>> from sympy.matrices.densesolve import LU_solve
  231. >>> from sympy import QQ
  232. >>> from sympy import Dummy
  233. >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z')
  234. >>> coefficients = [
  235. ... [QQ(2), QQ(-1), QQ(-2)],
  236. ... [QQ(-4), QQ(6), QQ(3)],
  237. ... [QQ(-4), QQ(-2), QQ(8)]]
  238. >>> variables = [
  239. ... [x],
  240. ... [y],
  241. ... [z]]
  242. >>> constants = [
  243. ... [QQ(-1)],
  244. ... [QQ(13)],
  245. ... [QQ(-6)]]
  246. >>> LU_solve(coefficients, variables, constants, QQ)
  247. [[2], [3], [1]]
  248. See Also
  249. ========
  250. LU
  251. forward_substitution
  252. backward_substitution
  253. """
  254. new_matlist = copy.deepcopy(matlist)
  255. nrow = len(new_matlist)
  256. L, U = LU(new_matlist, K)
  257. y = [[i] for i in symbols('y:%i' % nrow)]
  258. forward_substitution(L, y, constant, K)
  259. backward_substitution(U, variable, y, K)
  260. return variable
  261. def cholesky_solve(matlist, variable, constant, K):
  262. """
  263. Solves a system of equations using Cholesky decomposition given
  264. a matrix of coefficients, a vector of variables and a vector of constants.
  265. Examples
  266. ========
  267. >>> from sympy.matrices.densesolve import cholesky_solve
  268. >>> from sympy import QQ
  269. >>> from sympy import Dummy
  270. >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z')
  271. >>> coefficients = [
  272. ... [QQ(25), QQ(15), QQ(-5)],
  273. ... [QQ(15), QQ(18), QQ(0)],
  274. ... [QQ(-5), QQ(0), QQ(11)]]
  275. >>> variables = [
  276. ... [x],
  277. ... [y],
  278. ... [z]]
  279. >>> coefficients = [
  280. ... [QQ(2)],
  281. ... [QQ(3)],
  282. ... [QQ(1)]]
  283. >>> cholesky_solve([[QQ(25), QQ(15), QQ(-5)], [QQ(15), QQ(18), QQ(0)], [QQ(-5), QQ(0), QQ(11)]], [[x], [y], [z]], [[QQ(2)], [QQ(3)], [QQ(1)]], QQ)
  284. [[-1/225], [23/135], [4/45]]
  285. See Also
  286. ========
  287. cholesky
  288. forward_substitution
  289. backward_substitution
  290. """
  291. new_matlist = copy.deepcopy(matlist)
  292. nrow = len(new_matlist)
  293. L, Lstar = cholesky(new_matlist, K)
  294. y = [[i] for i in symbols('y:%i' % nrow)]
  295. forward_substitution(L, y, constant, K)
  296. backward_substitution(Lstar, variable, y, K)
  297. return variable
  298. def forward_substitution(lower_triangle, variable, constant, K):
  299. """
  300. Performs forward substitution given a lower triangular matrix, a
  301. vector of variables and a vector of constants.
  302. Examples
  303. ========
  304. >>> from sympy.matrices.densesolve import forward_substitution
  305. >>> from sympy import QQ
  306. >>> from sympy import Dummy
  307. >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z')
  308. >>> a = [
  309. ... [QQ(1), QQ(0), QQ(0)],
  310. ... [QQ(-2), QQ(1), QQ(0)],
  311. ... [QQ(-2), QQ(-1), QQ(1)]]
  312. >>> variables = [
  313. ... [x],
  314. ... [y],
  315. ... [z]]
  316. >>> constants = [
  317. ... [QQ(-1)],
  318. ... [QQ(13)],
  319. ... [QQ(-6)]]
  320. >>> forward_substitution(a, variables, constants, QQ)
  321. [[-1], [11], [3]]
  322. See Also
  323. ========
  324. LU_solve
  325. cholesky_solve
  326. """
  327. copy_lower_triangle = copy.deepcopy(lower_triangle)
  328. nrow = len(copy_lower_triangle)
  329. for i in range(nrow):
  330. a = K.zero
  331. for j in range(i):
  332. a += copy_lower_triangle[i][j]*variable[j][0]
  333. variable[i][0] = (constant[i][0] - a)/copy_lower_triangle[i][i]
  334. return variable
  335. def backward_substitution(upper_triangle, variable, constant, K):
  336. """
  337. Performs forward substitution given a lower triangular matrix,
  338. a vector of variables and a vector constants.
  339. Examples
  340. ========
  341. >>> from sympy.matrices.densesolve import backward_substitution
  342. >>> from sympy import QQ
  343. >>> from sympy import Dummy
  344. >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z')
  345. >>> a = [
  346. ... [QQ(2), QQ(-1), QQ(-2)],
  347. ... [QQ(0), QQ(4), QQ(-1)],
  348. ... [QQ(0), QQ(0), QQ(3)]]
  349. >>> variables = [
  350. ... [x],
  351. ... [y],
  352. ... [z]]
  353. >>> constants = [
  354. ... [QQ(-1)],
  355. ... [QQ(11)],
  356. ... [QQ(3)]]
  357. >>> backward_substitution(a, variables, constants, QQ)
  358. [[2], [3], [1]]
  359. See Also
  360. ========
  361. LU_solve
  362. cholesky_solve
  363. """
  364. copy_upper_triangle = copy.deepcopy(upper_triangle)
  365. nrow = len(copy_upper_triangle)
  366. for i in reversed(range(nrow)):
  367. a = K.zero
  368. for j in reversed(range(i + 1, nrow)):
  369. a += copy_upper_triangle[i][j]*variable[j][0]
  370. variable[i][0] = (constant[i][0] - a)/copy_upper_triangle[i][i]
  371. return variable