dense.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. """
  2. Module for the ddm_* routines for operating on a matrix in list of lists
  3. matrix representation.
  4. These routines are used internally by the DDM class which also provides a
  5. friendlier interface for them. The idea here is to implement core matrix
  6. routines in a way that can be applied to any simple list representation
  7. without the need to use any particular matrix class. For example we can
  8. compute the RREF of a matrix like:
  9. >>> from sympy.polys.matrices.dense import ddm_irref
  10. >>> M = [[1, 2, 3], [4, 5, 6]]
  11. >>> pivots = ddm_irref(M)
  12. >>> M
  13. [[1.0, 0.0, -1.0], [0, 1.0, 2.0]]
  14. These are lower-level routines that work mostly in place.The routines at this
  15. level should not need to know what the domain of the elements is but should
  16. ideally document what operations they will use and what functions they need to
  17. be provided with.
  18. The next-level up is the DDM class which uses these routines but wraps them up
  19. with an interface that handles copying etc and keeps track of the Domain of
  20. the elements of the matrix:
  21. >>> from sympy.polys.domains import QQ
  22. >>> from sympy.polys.matrices.ddm import DDM
  23. >>> M = DDM([[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]], (2, 3), QQ)
  24. >>> M
  25. [[1, 2, 3], [4, 5, 6]]
  26. >>> Mrref, pivots = M.rref()
  27. >>> Mrref
  28. [[1, 0, -1], [0, 1, 2]]
  29. """
  30. from __future__ import annotations
  31. from operator import mul
  32. from .exceptions import (
  33. DMShapeError,
  34. DMDomainError,
  35. DMNonInvertibleMatrixError,
  36. DMNonSquareMatrixError,
  37. )
  38. from typing import Sequence, TypeVar
  39. from sympy.polys.matrices._typing import RingElement
  40. #: Type variable for the elements of the matrix
  41. T = TypeVar('T')
  42. #: Type variable for the elements of the matrix that are in a ring
  43. R = TypeVar('R', bound=RingElement)
  44. def ddm_transpose(matrix: Sequence[Sequence[T]]) -> list[list[T]]:
  45. """matrix transpose"""
  46. return list(map(list, zip(*matrix)))
  47. def ddm_iadd(a: list[list[R]], b: Sequence[Sequence[R]]) -> None:
  48. """a += b"""
  49. for ai, bi in zip(a, b):
  50. for j, bij in enumerate(bi):
  51. ai[j] += bij
  52. def ddm_isub(a: list[list[R]], b: Sequence[Sequence[R]]) -> None:
  53. """a -= b"""
  54. for ai, bi in zip(a, b):
  55. for j, bij in enumerate(bi):
  56. ai[j] -= bij
  57. def ddm_ineg(a: list[list[R]]) -> None:
  58. """a <-- -a"""
  59. for ai in a:
  60. for j, aij in enumerate(ai):
  61. ai[j] = -aij
  62. def ddm_imul(a: list[list[R]], b: R) -> None:
  63. """a <-- a*b"""
  64. for ai in a:
  65. for j, aij in enumerate(ai):
  66. ai[j] = aij * b
  67. def ddm_irmul(a: list[list[R]], b: R) -> None:
  68. """a <-- b*a"""
  69. for ai in a:
  70. for j, aij in enumerate(ai):
  71. ai[j] = b * aij
  72. def ddm_imatmul(
  73. a: list[list[R]], b: Sequence[Sequence[R]], c: Sequence[Sequence[R]]
  74. ) -> None:
  75. """a += b @ c"""
  76. cT = list(zip(*c))
  77. for bi, ai in zip(b, a):
  78. for j, cTj in enumerate(cT):
  79. ai[j] = sum(map(mul, bi, cTj), ai[j])
  80. def ddm_irref(a, _partial_pivot=False):
  81. """In-place reduced row echelon form of a matrix.
  82. Compute the reduced row echelon form of $a$. Modifies $a$ in place and
  83. returns a list of the pivot columns.
  84. Uses naive Gauss-Jordan elimination in the ground domain which must be a
  85. field.
  86. This routine is only really suitable for use with simple field domains like
  87. :ref:`GF(p)`, :ref:`QQ` and :ref:`QQ(a)` although even for :ref:`QQ` with
  88. larger matrices it is possibly more efficient to use fraction free
  89. approaches.
  90. This method is not suitable for use with rational function fields
  91. (:ref:`K(x)`) because the elements will blowup leading to costly gcd
  92. operations. In this case clearing denominators and using fraction free
  93. approaches is likely to be more efficient.
  94. For inexact numeric domains like :ref:`RR` and :ref:`CC` pass
  95. ``_partial_pivot=True`` to use partial pivoting to control rounding errors.
  96. Examples
  97. ========
  98. >>> from sympy.polys.matrices.dense import ddm_irref
  99. >>> from sympy import QQ
  100. >>> M = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]]
  101. >>> pivots = ddm_irref(M)
  102. >>> M
  103. [[1, 0, -1], [0, 1, 2]]
  104. >>> pivots
  105. [0, 1]
  106. See Also
  107. ========
  108. sympy.polys.matrices.domainmatrix.DomainMatrix.rref
  109. Higher level interface to this routine.
  110. ddm_irref_den
  111. The fraction free version of this routine.
  112. sdm_irref
  113. A sparse version of this routine.
  114. References
  115. ==========
  116. .. [1] https://en.wikipedia.org/wiki/Row_echelon_form#Reduced_row_echelon_form
  117. """
  118. # We compute aij**-1 below and then use multiplication instead of division
  119. # in the innermost loop. The domain here is a field so either operation is
  120. # defined. There are significant performance differences for some domains
  121. # though. In the case of e.g. QQ or QQ(x) inversion is free but
  122. # multiplication and division have the same cost so it makes no difference.
  123. # In cases like GF(p), QQ<sqrt(2)>, RR or CC though multiplication is
  124. # faster than division so reusing a precomputed inverse for many
  125. # multiplications can be a lot faster. The biggest win is QQ<a> when
  126. # deg(minpoly(a)) is large.
  127. #
  128. # With domains like QQ(x) this can perform badly for other reasons.
  129. # Typically the initial matrix has simple denominators and the
  130. # fraction-free approach with exquo (ddm_irref_den) will preserve that
  131. # property throughout. The method here causes denominator blowup leading to
  132. # expensive gcd reductions in the intermediate expressions. With many
  133. # generators like QQ(x,y,z,...) this is extremely bad.
  134. #
  135. # TODO: Use a nontrivial pivoting strategy to control intermediate
  136. # expression growth. Rearranging rows and/or columns could defer the most
  137. # complicated elements until the end. If the first pivot is a
  138. # complicated/large element then the first round of reduction will
  139. # immediately introduce expression blowup across the whole matrix.
  140. # a is (m x n)
  141. m = len(a)
  142. if not m:
  143. return []
  144. n = len(a[0])
  145. i = 0
  146. pivots = []
  147. for j in range(n):
  148. # Proper pivoting should be used for all domains for performance
  149. # reasons but it is only strictly needed for RR and CC (and possibly
  150. # other domains like RR(x)). This path is used by DDM.rref() if the
  151. # domain is RR or CC. It uses partial (row) pivoting based on the
  152. # absolute value of the pivot candidates.
  153. if _partial_pivot:
  154. ip = max(range(i, m), key=lambda ip: abs(a[ip][j]))
  155. a[i], a[ip] = a[ip], a[i]
  156. # pivot
  157. aij = a[i][j]
  158. # zero-pivot
  159. if not aij:
  160. for ip in range(i+1, m):
  161. aij = a[ip][j]
  162. # row-swap
  163. if aij:
  164. a[i], a[ip] = a[ip], a[i]
  165. break
  166. else:
  167. # next column
  168. continue
  169. # normalise row
  170. ai = a[i]
  171. aijinv = aij**-1
  172. for l in range(j, n):
  173. ai[l] *= aijinv # ai[j] = one
  174. # eliminate above and below to the right
  175. for k, ak in enumerate(a):
  176. if k == i or not ak[j]:
  177. continue
  178. akj = ak[j]
  179. ak[j] -= akj # ak[j] = zero
  180. for l in range(j+1, n):
  181. ak[l] -= akj * ai[l]
  182. # next row
  183. pivots.append(j)
  184. i += 1
  185. # no more rows?
  186. if i >= m:
  187. break
  188. return pivots
  189. def ddm_irref_den(a, K):
  190. """a <-- rref(a); return (den, pivots)
  191. Compute the fraction-free reduced row echelon form (RREF) of $a$. Modifies
  192. $a$ in place and returns a tuple containing the denominator of the RREF and
  193. a list of the pivot columns.
  194. Explanation
  195. ===========
  196. The algorithm used is the fraction-free version of Gauss-Jordan elimination
  197. described as FFGJ in [1]_. Here it is modified to handle zero or missing
  198. pivots and to avoid redundant arithmetic.
  199. The domain $K$ must support exact division (``K.exquo``) but does not need
  200. to be a field. This method is suitable for most exact rings and fields like
  201. :ref:`ZZ`, :ref:`QQ` and :ref:`QQ(a)`. In the case of :ref:`QQ` or
  202. :ref:`K(x)` it might be more efficient to clear denominators and use
  203. :ref:`ZZ` or :ref:`K[x]` instead.
  204. For inexact domains like :ref:`RR` and :ref:`CC` use ``ddm_irref`` instead.
  205. Examples
  206. ========
  207. >>> from sympy.polys.matrices.dense import ddm_irref_den
  208. >>> from sympy import ZZ, Matrix
  209. >>> M = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)]]
  210. >>> den, pivots = ddm_irref_den(M, ZZ)
  211. >>> M
  212. [[-3, 0, 3], [0, -3, -6]]
  213. >>> den
  214. -3
  215. >>> pivots
  216. [0, 1]
  217. >>> Matrix(M).rref()[0]
  218. Matrix([
  219. [1, 0, -1],
  220. [0, 1, 2]])
  221. See Also
  222. ========
  223. ddm_irref
  224. A version of this routine that uses field division.
  225. sdm_irref
  226. A sparse version of :func:`ddm_irref`.
  227. sdm_rref_den
  228. A sparse version of :func:`ddm_irref_den`.
  229. sympy.polys.matrices.domainmatrix.DomainMatrix.rref_den
  230. Higher level interface.
  231. References
  232. ==========
  233. .. [1] Fraction-free algorithms for linear and polynomial equations.
  234. George C. Nakos , Peter R. Turner , Robert M. Williams.
  235. https://dl.acm.org/doi/10.1145/271130.271133
  236. """
  237. #
  238. # A simpler presentation of this algorithm is given in [1]:
  239. #
  240. # Given an n x n matrix A and n x 1 matrix b:
  241. #
  242. # for i in range(n):
  243. # if i != 0:
  244. # d = a[i-1][i-1]
  245. # for j in range(n):
  246. # if j == i:
  247. # continue
  248. # b[j] = a[i][i]*b[j] - a[j][i]*b[i]
  249. # for k in range(n):
  250. # a[j][k] = a[i][i]*a[j][k] - a[j][i]*a[i][k]
  251. # if i != 0:
  252. # a[j][k] /= d
  253. #
  254. # Our version here is a bit more complicated because:
  255. #
  256. # 1. We use row-swaps to avoid zero pivots.
  257. # 2. We allow for some columns to be missing pivots.
  258. # 3. We avoid a lot of redundant arithmetic.
  259. #
  260. # TODO: Use a non-trivial pivoting strategy. Even just row swapping makes a
  261. # big difference to performance if e.g. the upper-left entry of the matrix
  262. # is a huge polynomial.
  263. # a is (m x n)
  264. m = len(a)
  265. if not m:
  266. return K.one, []
  267. n = len(a[0])
  268. d = None
  269. pivots = []
  270. no_pivots = []
  271. # i, j will be the row and column indices of the current pivot
  272. i = 0
  273. for j in range(n):
  274. # next pivot?
  275. aij = a[i][j]
  276. # swap rows if zero
  277. if not aij:
  278. for ip in range(i+1, m):
  279. aij = a[ip][j]
  280. # row-swap
  281. if aij:
  282. a[i], a[ip] = a[ip], a[i]
  283. break
  284. else:
  285. # go to next column
  286. no_pivots.append(j)
  287. continue
  288. # Now aij is the pivot and i,j are the row and column. We need to clear
  289. # the column above and below but we also need to keep track of the
  290. # denominator of the RREF which means also multiplying everything above
  291. # and to the left by the current pivot aij and dividing by d (which we
  292. # multiplied everything by in the previous iteration so this is an
  293. # exact division).
  294. #
  295. # First handle the upper left corner which is usually already diagonal
  296. # with all diagonal entries equal to the current denominator but there
  297. # can be other non-zero entries in any column that has no pivot.
  298. # Update previous pivots in the matrix
  299. if pivots:
  300. pivot_val = aij * a[0][pivots[0]]
  301. # Divide out the common factor
  302. if d is not None:
  303. pivot_val = K.exquo(pivot_val, d)
  304. # Could defer this until the end but it is pretty cheap and
  305. # helps when debugging.
  306. for ip, jp in enumerate(pivots):
  307. a[ip][jp] = pivot_val
  308. # Update columns without pivots
  309. for jnp in no_pivots:
  310. for ip in range(i):
  311. aijp = a[ip][jnp]
  312. if aijp:
  313. aijp *= aij
  314. if d is not None:
  315. aijp = K.exquo(aijp, d)
  316. a[ip][jnp] = aijp
  317. # Eliminate above, below and to the right as in ordinary division free
  318. # Gauss-Jordan elmination except also dividing out d from every entry.
  319. for jp, aj in enumerate(a):
  320. # Skip the current row
  321. if jp == i:
  322. continue
  323. # Eliminate to the right in all rows
  324. for kp in range(j+1, n):
  325. ajk = aij * aj[kp] - aj[j] * a[i][kp]
  326. if d is not None:
  327. ajk = K.exquo(ajk, d)
  328. aj[kp] = ajk
  329. # Set to zero above and below the pivot
  330. aj[j] = K.zero
  331. # next row
  332. pivots.append(j)
  333. i += 1
  334. # no more rows left?
  335. if i >= m:
  336. break
  337. if not K.is_one(aij):
  338. d = aij
  339. else:
  340. d = None
  341. if not pivots:
  342. denom = K.one
  343. else:
  344. denom = a[0][pivots[0]]
  345. return denom, pivots
  346. def ddm_idet(a, K):
  347. """a <-- echelon(a); return det
  348. Explanation
  349. ===========
  350. Compute the determinant of $a$ using the Bareiss fraction-free algorithm.
  351. The matrix $a$ is modified in place. Its diagonal elements are the
  352. determinants of the leading principal minors. The determinant of $a$ is
  353. returned.
  354. The domain $K$ must support exact division (``K.exquo``). This method is
  355. suitable for most exact rings and fields like :ref:`ZZ`, :ref:`QQ` and
  356. :ref:`QQ(a)` but not for inexact domains like :ref:`RR` and :ref:`CC`.
  357. Examples
  358. ========
  359. >>> from sympy import ZZ
  360. >>> from sympy.polys.matrices.ddm import ddm_idet
  361. >>> a = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]]
  362. >>> a
  363. [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
  364. >>> ddm_idet(a, ZZ)
  365. 0
  366. >>> a
  367. [[1, 2, 3], [4, -3, -6], [7, -6, 0]]
  368. >>> [a[i][i] for i in range(len(a))]
  369. [1, -3, 0]
  370. See Also
  371. ========
  372. sympy.polys.matrices.domainmatrix.DomainMatrix.det
  373. References
  374. ==========
  375. .. [1] https://en.wikipedia.org/wiki/Bareiss_algorithm
  376. .. [2] https://www.math.usm.edu/perry/Research/Thesis_DRL.pdf
  377. """
  378. # Bareiss algorithm
  379. # https://www.math.usm.edu/perry/Research/Thesis_DRL.pdf
  380. # a is (m x n)
  381. m = len(a)
  382. if not m:
  383. return K.one
  384. n = len(a[0])
  385. exquo = K.exquo
  386. # uf keeps track of the sign change from row swaps
  387. uf = K.one
  388. for k in range(n-1):
  389. if not a[k][k]:
  390. for i in range(k+1, n):
  391. if a[i][k]:
  392. a[k], a[i] = a[i], a[k]
  393. uf = -uf
  394. break
  395. else:
  396. return K.zero
  397. akkm1 = a[k-1][k-1] if k else K.one
  398. for i in range(k+1, n):
  399. for j in range(k+1, n):
  400. a[i][j] = exquo(a[i][j]*a[k][k] - a[i][k]*a[k][j], akkm1)
  401. return uf * a[-1][-1]
  402. def ddm_iinv(ainv, a, K):
  403. """ainv <-- inv(a)
  404. Compute the inverse of a matrix $a$ over a field $K$ using Gauss-Jordan
  405. elimination. The result is stored in $ainv$.
  406. Uses division in the ground domain which should be an exact field.
  407. Examples
  408. ========
  409. >>> from sympy.polys.matrices.ddm import ddm_iinv, ddm_imatmul
  410. >>> from sympy import QQ
  411. >>> a = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
  412. >>> ainv = [[None, None], [None, None]]
  413. >>> ddm_iinv(ainv, a, QQ)
  414. >>> ainv
  415. [[-2, 1], [3/2, -1/2]]
  416. >>> result = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]]
  417. >>> ddm_imatmul(result, a, ainv)
  418. >>> result
  419. [[1, 0], [0, 1]]
  420. See Also
  421. ========
  422. ddm_irref: the underlying routine.
  423. """
  424. if not K.is_Field:
  425. raise DMDomainError('Not a field')
  426. # a is (m x n)
  427. m = len(a)
  428. if not m:
  429. return
  430. n = len(a[0])
  431. if m != n:
  432. raise DMNonSquareMatrixError
  433. eye = [[K.one if i==j else K.zero for j in range(n)] for i in range(n)]
  434. Aaug = [row + eyerow for row, eyerow in zip(a, eye)]
  435. pivots = ddm_irref(Aaug)
  436. if pivots != list(range(n)):
  437. raise DMNonInvertibleMatrixError('Matrix det == 0; not invertible.')
  438. ainv[:] = [row[n:] for row in Aaug]
  439. def ddm_ilu_split(L, U, K):
  440. """L, U <-- LU(U)
  441. Compute the LU decomposition of a matrix $L$ in place and store the lower
  442. and upper triangular matrices in $L$ and $U$, respectively. Returns a list
  443. of row swaps that were performed.
  444. Uses division in the ground domain which should be an exact field.
  445. Examples
  446. ========
  447. >>> from sympy.polys.matrices.ddm import ddm_ilu_split
  448. >>> from sympy import QQ
  449. >>> L = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]]
  450. >>> U = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
  451. >>> swaps = ddm_ilu_split(L, U, QQ)
  452. >>> swaps
  453. []
  454. >>> L
  455. [[0, 0], [3, 0]]
  456. >>> U
  457. [[1, 2], [0, -2]]
  458. See Also
  459. ========
  460. ddm_ilu
  461. ddm_ilu_solve
  462. """
  463. m = len(U)
  464. if not m:
  465. return []
  466. n = len(U[0])
  467. swaps = ddm_ilu(U)
  468. zeros = [K.zero] * min(m, n)
  469. for i in range(1, m):
  470. j = min(i, n)
  471. L[i][:j] = U[i][:j]
  472. U[i][:j] = zeros[:j]
  473. return swaps
  474. def ddm_ilu(a):
  475. """a <-- LU(a)
  476. Computes the LU decomposition of a matrix in place. Returns a list of
  477. row swaps that were performed.
  478. Uses division in the ground domain which should be an exact field.
  479. This is only suitable for domains like :ref:`GF(p)`, :ref:`QQ`, :ref:`QQ_I`
  480. and :ref:`QQ(a)`. With a rational function field like :ref:`K(x)` it is
  481. better to clear denominators and use division-free algorithms. Pivoting is
  482. used to avoid exact zeros but not for floating point accuracy so :ref:`RR`
  483. and :ref:`CC` are not suitable (use :func:`ddm_irref` instead).
  484. Examples
  485. ========
  486. >>> from sympy.polys.matrices.dense import ddm_ilu
  487. >>> from sympy import QQ
  488. >>> a = [[QQ(1, 2), QQ(1, 3)], [QQ(1, 4), QQ(1, 5)]]
  489. >>> swaps = ddm_ilu(a)
  490. >>> swaps
  491. []
  492. >>> a
  493. [[1/2, 1/3], [1/2, 1/30]]
  494. The same example using ``Matrix``:
  495. >>> from sympy import Matrix, S
  496. >>> M = Matrix([[S(1)/2, S(1)/3], [S(1)/4, S(1)/5]])
  497. >>> L, U, swaps = M.LUdecomposition()
  498. >>> L
  499. Matrix([
  500. [ 1, 0],
  501. [1/2, 1]])
  502. >>> U
  503. Matrix([
  504. [1/2, 1/3],
  505. [ 0, 1/30]])
  506. >>> swaps
  507. []
  508. See Also
  509. ========
  510. ddm_irref
  511. ddm_ilu_solve
  512. sympy.matrices.matrixbase.MatrixBase.LUdecomposition
  513. """
  514. m = len(a)
  515. if not m:
  516. return []
  517. n = len(a[0])
  518. swaps = []
  519. for i in range(min(m, n)):
  520. if not a[i][i]:
  521. for ip in range(i+1, m):
  522. if a[ip][i]:
  523. swaps.append((i, ip))
  524. a[i], a[ip] = a[ip], a[i]
  525. break
  526. else:
  527. # M = Matrix([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 2]])
  528. continue
  529. for j in range(i+1, m):
  530. l_ji = a[j][i] / a[i][i]
  531. a[j][i] = l_ji
  532. for k in range(i+1, n):
  533. a[j][k] -= l_ji * a[i][k]
  534. return swaps
  535. def ddm_ilu_solve(x, L, U, swaps, b):
  536. """x <-- solve(L*U*x = swaps(b))
  537. Solve a linear system, $A*x = b$, given an LU factorization of $A$.
  538. Uses division in the ground domain which must be a field.
  539. Modifies $x$ in place.
  540. Examples
  541. ========
  542. Compute the LU decomposition of $A$ (in place):
  543. >>> from sympy import QQ
  544. >>> from sympy.polys.matrices.dense import ddm_ilu, ddm_ilu_solve
  545. >>> A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
  546. >>> swaps = ddm_ilu(A)
  547. >>> A
  548. [[1, 2], [3, -2]]
  549. >>> L = U = A
  550. Solve the linear system:
  551. >>> b = [[QQ(5)], [QQ(6)]]
  552. >>> x = [[None], [None]]
  553. >>> ddm_ilu_solve(x, L, U, swaps, b)
  554. >>> x
  555. [[-4], [9/2]]
  556. See Also
  557. ========
  558. ddm_ilu
  559. Compute the LU decomposition of a matrix in place.
  560. ddm_ilu_split
  561. Compute the LU decomposition of a matrix and separate $L$ and $U$.
  562. sympy.polys.matrices.domainmatrix.DomainMatrix.lu_solve
  563. Higher level interface to this function.
  564. """
  565. m = len(U)
  566. if not m:
  567. return
  568. n = len(U[0])
  569. m2 = len(b)
  570. if not m2:
  571. raise DMShapeError("Shape mismtch")
  572. o = len(b[0])
  573. if m != m2:
  574. raise DMShapeError("Shape mismtch")
  575. if m < n:
  576. raise NotImplementedError("Underdetermined")
  577. if swaps:
  578. b = [row[:] for row in b]
  579. for i1, i2 in swaps:
  580. b[i1], b[i2] = b[i2], b[i1]
  581. # solve Ly = b
  582. y = [[None] * o for _ in range(m)]
  583. for k in range(o):
  584. for i in range(m):
  585. rhs = b[i][k]
  586. for j in range(i):
  587. rhs -= L[i][j] * y[j][k]
  588. y[i][k] = rhs
  589. if m > n:
  590. for i in range(n, m):
  591. for j in range(o):
  592. if y[i][j]:
  593. raise DMNonInvertibleMatrixError
  594. # Solve Ux = y
  595. for k in range(o):
  596. for i in reversed(range(n)):
  597. if not U[i][i]:
  598. raise DMNonInvertibleMatrixError
  599. rhs = y[i][k]
  600. for j in range(i+1, n):
  601. rhs -= U[i][j] * x[j][k]
  602. x[i][k] = rhs / U[i][i]
  603. def ddm_berk(M, K):
  604. """
  605. Berkowitz algorithm for computing the characteristic polynomial.
  606. Explanation
  607. ===========
  608. The Berkowitz algorithm is a division-free algorithm for computing the
  609. characteristic polynomial of a matrix over any commutative ring using only
  610. arithmetic in the coefficient ring.
  611. Examples
  612. ========
  613. >>> from sympy import Matrix
  614. >>> from sympy.polys.matrices.dense import ddm_berk
  615. >>> from sympy.polys.domains import ZZ
  616. >>> M = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]]
  617. >>> ddm_berk(M, ZZ)
  618. [[1], [-5], [-2]]
  619. >>> Matrix(M).charpoly()
  620. PurePoly(lambda**2 - 5*lambda - 2, lambda, domain='ZZ')
  621. See Also
  622. ========
  623. sympy.polys.matrices.domainmatrix.DomainMatrix.charpoly
  624. The high-level interface to this function.
  625. References
  626. ==========
  627. .. [1] https://en.wikipedia.org/wiki/Samuelson%E2%80%93Berkowitz_algorithm
  628. """
  629. m = len(M)
  630. if not m:
  631. return [[K.one]]
  632. n = len(M[0])
  633. if m != n:
  634. raise DMShapeError("Not square")
  635. if n == 1:
  636. return [[K.one], [-M[0][0]]]
  637. a = M[0][0]
  638. R = [M[0][1:]]
  639. C = [[row[0]] for row in M[1:]]
  640. A = [row[1:] for row in M[1:]]
  641. q = ddm_berk(A, K)
  642. T = [[K.zero] * n for _ in range(n+1)]
  643. for i in range(n):
  644. T[i][i] = K.one
  645. T[i+1][i] = -a
  646. for i in range(2, n+1):
  647. if i == 2:
  648. AnC = C
  649. else:
  650. C = AnC
  651. AnC = [[K.zero] for row in C]
  652. ddm_imatmul(AnC, A, C)
  653. RAnC = [[K.zero]]
  654. ddm_imatmul(RAnC, R, AnC)
  655. for j in range(0, n+1-i):
  656. T[i+j][j] = -RAnC[0][0]
  657. qout = [[K.zero] for _ in range(n+1)]
  658. ddm_imatmul(qout, T, q)
  659. return qout