determinant.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. from types import FunctionType
  2. from sympy.core.numbers import Float, Integer
  3. from sympy.core.singleton import S
  4. from sympy.core.symbol import uniquely_named_symbol
  5. from sympy.core.mul import Mul
  6. from sympy.polys import PurePoly, cancel
  7. from sympy.simplify.simplify import (simplify as _simplify,
  8. dotprodsimp as _dotprodsimp)
  9. from sympy.core.sympify import sympify
  10. from sympy.functions.combinatorial.numbers import nC
  11. from sympy.polys.matrices.domainmatrix import DomainMatrix
  12. from .common import NonSquareMatrixError
  13. from .utilities import (
  14. _get_intermediate_simp, _get_intermediate_simp_bool,
  15. _iszero, _is_zero_after_expand_mul)
  16. def _find_reasonable_pivot(col, iszerofunc=_iszero, simpfunc=_simplify):
  17. """ Find the lowest index of an item in ``col`` that is
  18. suitable for a pivot. If ``col`` consists only of
  19. Floats, the pivot with the largest norm is returned.
  20. Otherwise, the first element where ``iszerofunc`` returns
  21. False is used. If ``iszerofunc`` doesn't return false,
  22. items are simplified and retested until a suitable
  23. pivot is found.
  24. Returns a 4-tuple
  25. (pivot_offset, pivot_val, assumed_nonzero, newly_determined)
  26. where pivot_offset is the index of the pivot, pivot_val is
  27. the (possibly simplified) value of the pivot, assumed_nonzero
  28. is True if an assumption that the pivot was non-zero
  29. was made without being proved, and newly_determined are
  30. elements that were simplified during the process of pivot
  31. finding."""
  32. newly_determined = []
  33. col = list(col)
  34. # a column that contains a mix of floats and integers
  35. # but at least one float is considered a numerical
  36. # column, and so we do partial pivoting
  37. if all(isinstance(x, (Float, Integer)) for x in col) and any(
  38. isinstance(x, Float) for x in col):
  39. col_abs = [abs(x) for x in col]
  40. max_value = max(col_abs)
  41. if iszerofunc(max_value):
  42. # just because iszerofunc returned True, doesn't
  43. # mean the value is numerically zero. Make sure
  44. # to replace all entries with numerical zeros
  45. if max_value != 0:
  46. newly_determined = [(i, 0) for i, x in enumerate(col) if x != 0]
  47. return (None, None, False, newly_determined)
  48. index = col_abs.index(max_value)
  49. return (index, col[index], False, newly_determined)
  50. # PASS 1 (iszerofunc directly)
  51. possible_zeros = []
  52. for i, x in enumerate(col):
  53. is_zero = iszerofunc(x)
  54. # is someone wrote a custom iszerofunc, it may return
  55. # BooleanFalse or BooleanTrue instead of True or False,
  56. # so use == for comparison instead of `is`
  57. if is_zero == False:
  58. # we found something that is definitely not zero
  59. return (i, x, False, newly_determined)
  60. possible_zeros.append(is_zero)
  61. # by this point, we've found no certain non-zeros
  62. if all(possible_zeros):
  63. # if everything is definitely zero, we have
  64. # no pivot
  65. return (None, None, False, newly_determined)
  66. # PASS 2 (iszerofunc after simplify)
  67. # we haven't found any for-sure non-zeros, so
  68. # go through the elements iszerofunc couldn't
  69. # make a determination about and opportunistically
  70. # simplify to see if we find something
  71. for i, x in enumerate(col):
  72. if possible_zeros[i] is not None:
  73. continue
  74. simped = simpfunc(x)
  75. is_zero = iszerofunc(simped)
  76. if is_zero in (True, False):
  77. newly_determined.append((i, simped))
  78. if is_zero == False:
  79. return (i, simped, False, newly_determined)
  80. possible_zeros[i] = is_zero
  81. # after simplifying, some things that were recognized
  82. # as zeros might be zeros
  83. if all(possible_zeros):
  84. # if everything is definitely zero, we have
  85. # no pivot
  86. return (None, None, False, newly_determined)
  87. # PASS 3 (.equals(0))
  88. # some expressions fail to simplify to zero, but
  89. # ``.equals(0)`` evaluates to True. As a last-ditch
  90. # attempt, apply ``.equals`` to these expressions
  91. for i, x in enumerate(col):
  92. if possible_zeros[i] is not None:
  93. continue
  94. if x.equals(S.Zero):
  95. # ``.iszero`` may return False with
  96. # an implicit assumption (e.g., ``x.equals(0)``
  97. # when ``x`` is a symbol), so only treat it
  98. # as proved when ``.equals(0)`` returns True
  99. possible_zeros[i] = True
  100. newly_determined.append((i, S.Zero))
  101. if all(possible_zeros):
  102. return (None, None, False, newly_determined)
  103. # at this point there is nothing that could definitely
  104. # be a pivot. To maintain compatibility with existing
  105. # behavior, we'll assume that an illdetermined thing is
  106. # non-zero. We should probably raise a warning in this case
  107. i = possible_zeros.index(None)
  108. return (i, col[i], True, newly_determined)
  109. def _find_reasonable_pivot_naive(col, iszerofunc=_iszero, simpfunc=None):
  110. """
  111. Helper that computes the pivot value and location from a
  112. sequence of contiguous matrix column elements. As a side effect
  113. of the pivot search, this function may simplify some of the elements
  114. of the input column. A list of these simplified entries and their
  115. indices are also returned.
  116. This function mimics the behavior of _find_reasonable_pivot(),
  117. but does less work trying to determine if an indeterminate candidate
  118. pivot simplifies to zero. This more naive approach can be much faster,
  119. with the trade-off that it may erroneously return a pivot that is zero.
  120. ``col`` is a sequence of contiguous column entries to be searched for
  121. a suitable pivot.
  122. ``iszerofunc`` is a callable that returns a Boolean that indicates
  123. if its input is zero, or None if no such determination can be made.
  124. ``simpfunc`` is a callable that simplifies its input. It must return
  125. its input if it does not simplify its input. Passing in
  126. ``simpfunc=None`` indicates that the pivot search should not attempt
  127. to simplify any candidate pivots.
  128. Returns a 4-tuple:
  129. (pivot_offset, pivot_val, assumed_nonzero, newly_determined)
  130. ``pivot_offset`` is the sequence index of the pivot.
  131. ``pivot_val`` is the value of the pivot.
  132. pivot_val and col[pivot_index] are equivalent, but will be different
  133. when col[pivot_index] was simplified during the pivot search.
  134. ``assumed_nonzero`` is a boolean indicating if the pivot cannot be
  135. guaranteed to be zero. If assumed_nonzero is true, then the pivot
  136. may or may not be non-zero. If assumed_nonzero is false, then
  137. the pivot is non-zero.
  138. ``newly_determined`` is a list of index-value pairs of pivot candidates
  139. that were simplified during the pivot search.
  140. """
  141. # indeterminates holds the index-value pairs of each pivot candidate
  142. # that is neither zero or non-zero, as determined by iszerofunc().
  143. # If iszerofunc() indicates that a candidate pivot is guaranteed
  144. # non-zero, or that every candidate pivot is zero then the contents
  145. # of indeterminates are unused.
  146. # Otherwise, the only viable candidate pivots are symbolic.
  147. # In this case, indeterminates will have at least one entry,
  148. # and all but the first entry are ignored when simpfunc is None.
  149. indeterminates = []
  150. for i, col_val in enumerate(col):
  151. col_val_is_zero = iszerofunc(col_val)
  152. if col_val_is_zero == False:
  153. # This pivot candidate is non-zero.
  154. return i, col_val, False, []
  155. elif col_val_is_zero is None:
  156. # The candidate pivot's comparison with zero
  157. # is indeterminate.
  158. indeterminates.append((i, col_val))
  159. if len(indeterminates) == 0:
  160. # All candidate pivots are guaranteed to be zero, i.e. there is
  161. # no pivot.
  162. return None, None, False, []
  163. if simpfunc is None:
  164. # Caller did not pass in a simplification function that might
  165. # determine if an indeterminate pivot candidate is guaranteed
  166. # to be nonzero, so assume the first indeterminate candidate
  167. # is non-zero.
  168. return indeterminates[0][0], indeterminates[0][1], True, []
  169. # newly_determined holds index-value pairs of candidate pivots
  170. # that were simplified during the search for a non-zero pivot.
  171. newly_determined = []
  172. for i, col_val in indeterminates:
  173. tmp_col_val = simpfunc(col_val)
  174. if id(col_val) != id(tmp_col_val):
  175. # simpfunc() simplified this candidate pivot.
  176. newly_determined.append((i, tmp_col_val))
  177. if iszerofunc(tmp_col_val) == False:
  178. # Candidate pivot simplified to a guaranteed non-zero value.
  179. return i, tmp_col_val, False, newly_determined
  180. return indeterminates[0][0], indeterminates[0][1], True, newly_determined
  181. # This functions is a candidate for caching if it gets implemented for matrices.
  182. def _berkowitz_toeplitz_matrix(M):
  183. """Return (A,T) where T the Toeplitz matrix used in the Berkowitz algorithm
  184. corresponding to ``M`` and A is the first principal submatrix.
  185. """
  186. # the 0 x 0 case is trivial
  187. if M.rows == 0 and M.cols == 0:
  188. return M._new(1,1, [M.one])
  189. #
  190. # Partition M = [ a_11 R ]
  191. # [ C A ]
  192. #
  193. a, R = M[0,0], M[0, 1:]
  194. C, A = M[1:, 0], M[1:,1:]
  195. #
  196. # The Toeplitz matrix looks like
  197. #
  198. # [ 1 ]
  199. # [ -a 1 ]
  200. # [ -RC -a 1 ]
  201. # [ -RAC -RC -a 1 ]
  202. # [ -RA**2C -RAC -RC -a 1 ]
  203. # etc.
  204. # Compute the diagonal entries.
  205. # Because multiplying matrix times vector is so much
  206. # more efficient than matrix times matrix, recursively
  207. # compute -R * A**n * C.
  208. diags = [C]
  209. for i in range(M.rows - 2):
  210. diags.append(A.multiply(diags[i], dotprodsimp=None))
  211. diags = [(-R).multiply(d, dotprodsimp=None)[0, 0] for d in diags]
  212. diags = [M.one, -a] + diags
  213. def entry(i,j):
  214. if j > i:
  215. return M.zero
  216. return diags[i - j]
  217. toeplitz = M._new(M.cols + 1, M.rows, entry)
  218. return (A, toeplitz)
  219. # This functions is a candidate for caching if it gets implemented for matrices.
  220. def _berkowitz_vector(M):
  221. """ Run the Berkowitz algorithm and return a vector whose entries
  222. are the coefficients of the characteristic polynomial of ``M``.
  223. Given N x N matrix, efficiently compute
  224. coefficients of characteristic polynomials of ``M``
  225. without division in the ground domain.
  226. This method is particularly useful for computing determinant,
  227. principal minors and characteristic polynomial when ``M``
  228. has complicated coefficients e.g. polynomials. Semi-direct
  229. usage of this algorithm is also important in computing
  230. efficiently sub-resultant PRS.
  231. Assuming that M is a square matrix of dimension N x N and
  232. I is N x N identity matrix, then the Berkowitz vector is
  233. an N x 1 vector whose entries are coefficients of the
  234. polynomial
  235. charpoly(M) = det(t*I - M)
  236. As a consequence, all polynomials generated by Berkowitz
  237. algorithm are monic.
  238. For more information on the implemented algorithm refer to:
  239. [1] S.J. Berkowitz, On computing the determinant in small
  240. parallel time using a small number of processors, ACM,
  241. Information Processing Letters 18, 1984, pp. 147-150
  242. [2] M. Keber, Division-Free computation of sub-resultants
  243. using Bezout matrices, Tech. Report MPI-I-2006-1-006,
  244. Saarbrucken, 2006
  245. """
  246. # handle the trivial cases
  247. if M.rows == 0 and M.cols == 0:
  248. return M._new(1, 1, [M.one])
  249. elif M.rows == 1 and M.cols == 1:
  250. return M._new(2, 1, [M.one, -M[0,0]])
  251. submat, toeplitz = _berkowitz_toeplitz_matrix(M)
  252. return toeplitz.multiply(_berkowitz_vector(submat), dotprodsimp=None)
  253. def _adjugate(M, method="berkowitz"):
  254. """Returns the adjugate, or classical adjoint, of
  255. a matrix. That is, the transpose of the matrix of cofactors.
  256. https://en.wikipedia.org/wiki/Adjugate
  257. Parameters
  258. ==========
  259. method : string, optional
  260. Method to use to find the cofactors, can be "bareiss", "berkowitz" or
  261. "lu".
  262. Examples
  263. ========
  264. >>> from sympy import Matrix
  265. >>> M = Matrix([[1, 2], [3, 4]])
  266. >>> M.adjugate()
  267. Matrix([
  268. [ 4, -2],
  269. [-3, 1]])
  270. See Also
  271. ========
  272. cofactor_matrix
  273. sympy.matrices.common.MatrixCommon.transpose
  274. """
  275. return M.cofactor_matrix(method=method).transpose()
  276. # This functions is a candidate for caching if it gets implemented for matrices.
  277. def _charpoly(M, x='lambda', simplify=_simplify):
  278. """Computes characteristic polynomial det(x*I - M) where I is
  279. the identity matrix.
  280. A PurePoly is returned, so using different variables for ``x`` does
  281. not affect the comparison or the polynomials:
  282. Parameters
  283. ==========
  284. x : string, optional
  285. Name for the "lambda" variable, defaults to "lambda".
  286. simplify : function, optional
  287. Simplification function to use on the characteristic polynomial
  288. calculated. Defaults to ``simplify``.
  289. Examples
  290. ========
  291. >>> from sympy import Matrix
  292. >>> from sympy.abc import x, y
  293. >>> M = Matrix([[1, 3], [2, 0]])
  294. >>> M.charpoly()
  295. PurePoly(lambda**2 - lambda - 6, lambda, domain='ZZ')
  296. >>> M.charpoly(x) == M.charpoly(y)
  297. True
  298. >>> M.charpoly(x) == M.charpoly(y)
  299. True
  300. Specifying ``x`` is optional; a symbol named ``lambda`` is used by
  301. default (which looks good when pretty-printed in unicode):
  302. >>> M.charpoly().as_expr()
  303. lambda**2 - lambda - 6
  304. And if ``x`` clashes with an existing symbol, underscores will
  305. be prepended to the name to make it unique:
  306. >>> M = Matrix([[1, 2], [x, 0]])
  307. >>> M.charpoly(x).as_expr()
  308. _x**2 - _x - 2*x
  309. Whether you pass a symbol or not, the generator can be obtained
  310. with the gen attribute since it may not be the same as the symbol
  311. that was passed:
  312. >>> M.charpoly(x).gen
  313. _x
  314. >>> M.charpoly(x).gen == x
  315. False
  316. Notes
  317. =====
  318. The Samuelson-Berkowitz algorithm is used to compute
  319. the characteristic polynomial efficiently and without any
  320. division operations. Thus the characteristic polynomial over any
  321. commutative ring without zero divisors can be computed.
  322. If the determinant det(x*I - M) can be found out easily as
  323. in the case of an upper or a lower triangular matrix, then
  324. instead of Samuelson-Berkowitz algorithm, eigenvalues are computed
  325. and the characteristic polynomial with their help.
  326. See Also
  327. ========
  328. det
  329. """
  330. if not M.is_square:
  331. raise NonSquareMatrixError()
  332. if M.is_lower or M.is_upper:
  333. diagonal_elements = M.diagonal()
  334. x = uniquely_named_symbol(x, diagonal_elements, modify=lambda s: '_' + s)
  335. m = 1
  336. for i in diagonal_elements:
  337. m = m * (x - simplify(i))
  338. return PurePoly(m, x)
  339. berk_vector = _berkowitz_vector(M)
  340. x = uniquely_named_symbol(x, berk_vector, modify=lambda s: '_' + s)
  341. return PurePoly([simplify(a) for a in berk_vector], x)
  342. def _cofactor(M, i, j, method="berkowitz"):
  343. """Calculate the cofactor of an element.
  344. Parameters
  345. ==========
  346. method : string, optional
  347. Method to use to find the cofactors, can be "bareiss", "berkowitz" or
  348. "lu".
  349. Examples
  350. ========
  351. >>> from sympy import Matrix
  352. >>> M = Matrix([[1, 2], [3, 4]])
  353. >>> M.cofactor(0, 1)
  354. -3
  355. See Also
  356. ========
  357. cofactor_matrix
  358. minor
  359. minor_submatrix
  360. """
  361. if not M.is_square or M.rows < 1:
  362. raise NonSquareMatrixError()
  363. return S.NegativeOne**((i + j) % 2) * M.minor(i, j, method)
  364. def _cofactor_matrix(M, method="berkowitz"):
  365. """Return a matrix containing the cofactor of each element.
  366. Parameters
  367. ==========
  368. method : string, optional
  369. Method to use to find the cofactors, can be "bareiss", "berkowitz" or
  370. "lu".
  371. Examples
  372. ========
  373. >>> from sympy import Matrix
  374. >>> M = Matrix([[1, 2], [3, 4]])
  375. >>> M.cofactor_matrix()
  376. Matrix([
  377. [ 4, -3],
  378. [-2, 1]])
  379. See Also
  380. ========
  381. cofactor
  382. minor
  383. minor_submatrix
  384. """
  385. if not M.is_square or M.rows < 1:
  386. raise NonSquareMatrixError()
  387. return M._new(M.rows, M.cols,
  388. lambda i, j: M.cofactor(i, j, method))
  389. def _per(M):
  390. """Returns the permanent of a matrix. Unlike determinant,
  391. permanent is defined for both square and non-square matrices.
  392. For an m x n matrix, with m less than or equal to n,
  393. it is given as the sum over the permutations s of size
  394. less than or equal to m on [1, 2, . . . n] of the product
  395. from i = 1 to m of M[i, s[i]]. Taking the transpose will
  396. not affect the value of the permanent.
  397. In the case of a square matrix, this is the same as the permutation
  398. definition of the determinant, but it does not take the sign of the
  399. permutation into account. Computing the permanent with this definition
  400. is quite inefficient, so here the Ryser formula is used.
  401. Examples
  402. ========
  403. >>> from sympy import Matrix
  404. >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  405. >>> M.per()
  406. 450
  407. >>> M = Matrix([1, 5, 7])
  408. >>> M.per()
  409. 13
  410. References
  411. ==========
  412. .. [1] Prof. Frank Ben's notes: https://math.berkeley.edu/~bernd/ban275.pdf
  413. .. [2] Wikipedia article on Permanent: https://en.wikipedia.org/wiki/Permanent_(mathematics)
  414. .. [3] https://reference.wolfram.com/language/ref/Permanent.html
  415. .. [4] Permanent of a rectangular matrix : https://arxiv.org/pdf/0904.3251.pdf
  416. """
  417. import itertools
  418. m, n = M.shape
  419. if m > n:
  420. M = M.T
  421. m, n = n, m
  422. s = list(range(n))
  423. subsets = []
  424. for i in range(1, m + 1):
  425. subsets += list(map(list, itertools.combinations(s, i)))
  426. perm = 0
  427. for subset in subsets:
  428. prod = 1
  429. sub_len = len(subset)
  430. for i in range(m):
  431. prod *= sum([M[i, j] for j in subset])
  432. perm += prod * S.NegativeOne**sub_len * nC(n - sub_len, m - sub_len)
  433. perm *= S.NegativeOne**m
  434. perm = sympify(perm)
  435. return perm.simplify()
  436. def _det_DOM(M):
  437. DOM = DomainMatrix.from_Matrix(M, field=True, extension=True)
  438. K = DOM.domain
  439. return K.to_sympy(DOM.det())
  440. # This functions is a candidate for caching if it gets implemented for matrices.
  441. def _det(M, method="bareiss", iszerofunc=None):
  442. """Computes the determinant of a matrix if ``M`` is a concrete matrix object
  443. otherwise return an expressions ``Determinant(M)`` if ``M`` is a
  444. ``MatrixSymbol`` or other expression.
  445. Parameters
  446. ==========
  447. method : string, optional
  448. Specifies the algorithm used for computing the matrix determinant.
  449. If the matrix is at most 3x3, a hard-coded formula is used and the
  450. specified method is ignored. Otherwise, it defaults to
  451. ``'bareiss'``.
  452. Also, if the matrix is an upper or a lower triangular matrix, determinant
  453. is computed by simple multiplication of diagonal elements, and the
  454. specified method is ignored.
  455. If it is set to ``'domain-ge'``, then Gaussian elimination method will
  456. be used via using DomainMatrix.
  457. If it is set to ``'bareiss'``, Bareiss' fraction-free algorithm will
  458. be used.
  459. If it is set to ``'berkowitz'``, Berkowitz' algorithm will be used.
  460. Otherwise, if it is set to ``'lu'``, LU decomposition will be used.
  461. .. note::
  462. For backward compatibility, legacy keys like "bareis" and
  463. "det_lu" can still be used to indicate the corresponding
  464. methods.
  465. And the keys are also case-insensitive for now. However, it is
  466. suggested to use the precise keys for specifying the method.
  467. iszerofunc : FunctionType or None, optional
  468. If it is set to ``None``, it will be defaulted to ``_iszero`` if the
  469. method is set to ``'bareiss'``, and ``_is_zero_after_expand_mul`` if
  470. the method is set to ``'lu'``.
  471. It can also accept any user-specified zero testing function, if it
  472. is formatted as a function which accepts a single symbolic argument
  473. and returns ``True`` if it is tested as zero and ``False`` if it
  474. tested as non-zero, and also ``None`` if it is undecidable.
  475. Returns
  476. =======
  477. det : Basic
  478. Result of determinant.
  479. Raises
  480. ======
  481. ValueError
  482. If unrecognized keys are given for ``method`` or ``iszerofunc``.
  483. NonSquareMatrixError
  484. If attempted to calculate determinant from a non-square matrix.
  485. Examples
  486. ========
  487. >>> from sympy import Matrix, eye, det
  488. >>> I3 = eye(3)
  489. >>> det(I3)
  490. 1
  491. >>> M = Matrix([[1, 2], [3, 4]])
  492. >>> det(M)
  493. -2
  494. >>> det(M) == M.det()
  495. True
  496. >>> M.det(method="domain-ge")
  497. -2
  498. """
  499. # sanitize `method`
  500. method = method.lower()
  501. if method == "bareis":
  502. method = "bareiss"
  503. elif method == "det_lu":
  504. method = "lu"
  505. if method not in ("bareiss", "berkowitz", "lu", "domain-ge"):
  506. raise ValueError("Determinant method '%s' unrecognized" % method)
  507. if iszerofunc is None:
  508. if method == "bareiss":
  509. iszerofunc = _is_zero_after_expand_mul
  510. elif method == "lu":
  511. iszerofunc = _iszero
  512. elif not isinstance(iszerofunc, FunctionType):
  513. raise ValueError("Zero testing method '%s' unrecognized" % iszerofunc)
  514. n = M.rows
  515. if n == M.cols: # square check is done in individual method functions
  516. if n == 0:
  517. return M.one
  518. elif n == 1:
  519. return M[0, 0]
  520. elif n == 2:
  521. m = M[0, 0] * M[1, 1] - M[0, 1] * M[1, 0]
  522. return _get_intermediate_simp(_dotprodsimp)(m)
  523. elif n == 3:
  524. m = (M[0, 0] * M[1, 1] * M[2, 2]
  525. + M[0, 1] * M[1, 2] * M[2, 0]
  526. + M[0, 2] * M[1, 0] * M[2, 1]
  527. - M[0, 2] * M[1, 1] * M[2, 0]
  528. - M[0, 0] * M[1, 2] * M[2, 1]
  529. - M[0, 1] * M[1, 0] * M[2, 2])
  530. return _get_intermediate_simp(_dotprodsimp)(m)
  531. dets = []
  532. for b in M.strongly_connected_components():
  533. if method == "domain-ge": # uses DomainMatrix to evalute determinant
  534. det = _det_DOM(M[b, b])
  535. elif method == "bareiss":
  536. det = M[b, b]._eval_det_bareiss(iszerofunc=iszerofunc)
  537. elif method == "berkowitz":
  538. det = M[b, b]._eval_det_berkowitz()
  539. elif method == "lu":
  540. det = M[b, b]._eval_det_lu(iszerofunc=iszerofunc)
  541. dets.append(det)
  542. return Mul(*dets)
  543. # This functions is a candidate for caching if it gets implemented for matrices.
  544. def _det_bareiss(M, iszerofunc=_is_zero_after_expand_mul):
  545. """Compute matrix determinant using Bareiss' fraction-free
  546. algorithm which is an extension of the well known Gaussian
  547. elimination method. This approach is best suited for dense
  548. symbolic matrices and will result in a determinant with
  549. minimal number of fractions. It means that less term
  550. rewriting is needed on resulting formulae.
  551. Parameters
  552. ==========
  553. iszerofunc : function, optional
  554. The function to use to determine zeros when doing an LU decomposition.
  555. Defaults to ``lambda x: x.is_zero``.
  556. TODO: Implement algorithm for sparse matrices (SFF),
  557. http://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps.
  558. """
  559. # Recursively implemented Bareiss' algorithm as per Deanna Richelle Leggett's
  560. # thesis http://www.math.usm.edu/perry/Research/Thesis_DRL.pdf
  561. def bareiss(mat, cumm=1):
  562. if mat.rows == 0:
  563. return mat.one
  564. elif mat.rows == 1:
  565. return mat[0, 0]
  566. # find a pivot and extract the remaining matrix
  567. # With the default iszerofunc, _find_reasonable_pivot slows down
  568. # the computation by the factor of 2.5 in one test.
  569. # Relevant issues: #10279 and #13877.
  570. pivot_pos, pivot_val, _, _ = _find_reasonable_pivot(mat[:, 0], iszerofunc=iszerofunc)
  571. if pivot_pos is None:
  572. return mat.zero
  573. # if we have a valid pivot, we'll do a "row swap", so keep the
  574. # sign of the det
  575. sign = (-1) ** (pivot_pos % 2)
  576. # we want every row but the pivot row and every column
  577. rows = list(i for i in range(mat.rows) if i != pivot_pos)
  578. cols = list(range(mat.cols))
  579. tmp_mat = mat.extract(rows, cols)
  580. def entry(i, j):
  581. ret = (pivot_val*tmp_mat[i, j + 1] - mat[pivot_pos, j + 1]*tmp_mat[i, 0]) / cumm
  582. if _get_intermediate_simp_bool(True):
  583. return _dotprodsimp(ret)
  584. elif not ret.is_Atom:
  585. return cancel(ret)
  586. return ret
  587. return sign*bareiss(M._new(mat.rows - 1, mat.cols - 1, entry), pivot_val)
  588. if not M.is_square:
  589. raise NonSquareMatrixError()
  590. if M.rows == 0:
  591. return M.one
  592. # sympy/matrices/tests/test_matrices.py contains a test that
  593. # suggests that the determinant of a 0 x 0 matrix is one, by
  594. # convention.
  595. return bareiss(M)
  596. def _det_berkowitz(M):
  597. """ Use the Berkowitz algorithm to compute the determinant."""
  598. if not M.is_square:
  599. raise NonSquareMatrixError()
  600. if M.rows == 0:
  601. return M.one
  602. # sympy/matrices/tests/test_matrices.py contains a test that
  603. # suggests that the determinant of a 0 x 0 matrix is one, by
  604. # convention.
  605. berk_vector = _berkowitz_vector(M)
  606. return (-1)**(len(berk_vector) - 1) * berk_vector[-1]
  607. # This functions is a candidate for caching if it gets implemented for matrices.
  608. def _det_LU(M, iszerofunc=_iszero, simpfunc=None):
  609. """ Computes the determinant of a matrix from its LU decomposition.
  610. This function uses the LU decomposition computed by
  611. LUDecomposition_Simple().
  612. The keyword arguments iszerofunc and simpfunc are passed to
  613. LUDecomposition_Simple().
  614. iszerofunc is a callable that returns a boolean indicating if its
  615. input is zero, or None if it cannot make the determination.
  616. simpfunc is a callable that simplifies its input.
  617. The default is simpfunc=None, which indicate that the pivot search
  618. algorithm should not attempt to simplify any candidate pivots.
  619. If simpfunc fails to simplify its input, then it must return its input
  620. instead of a copy.
  621. Parameters
  622. ==========
  623. iszerofunc : function, optional
  624. The function to use to determine zeros when doing an LU decomposition.
  625. Defaults to ``lambda x: x.is_zero``.
  626. simpfunc : function, optional
  627. The simplification function to use when looking for zeros for pivots.
  628. """
  629. if not M.is_square:
  630. raise NonSquareMatrixError()
  631. if M.rows == 0:
  632. return M.one
  633. # sympy/matrices/tests/test_matrices.py contains a test that
  634. # suggests that the determinant of a 0 x 0 matrix is one, by
  635. # convention.
  636. lu, row_swaps = M.LUdecomposition_Simple(iszerofunc=iszerofunc,
  637. simpfunc=simpfunc)
  638. # P*A = L*U => det(A) = det(L)*det(U)/det(P) = det(P)*det(U).
  639. # Lower triangular factor L encoded in lu has unit diagonal => det(L) = 1.
  640. # P is a permutation matrix => det(P) in {-1, 1} => 1/det(P) = det(P).
  641. # LUdecomposition_Simple() returns a list of row exchange index pairs, rather
  642. # than a permutation matrix, but det(P) = (-1)**len(row_swaps).
  643. # Avoid forming the potentially time consuming product of U's diagonal entries
  644. # if the product is zero.
  645. # Bottom right entry of U is 0 => det(A) = 0.
  646. # It may be impossible to determine if this entry of U is zero when it is symbolic.
  647. if iszerofunc(lu[lu.rows-1, lu.rows-1]):
  648. return M.zero
  649. # Compute det(P)
  650. det = -M.one if len(row_swaps)%2 else M.one
  651. # Compute det(U) by calculating the product of U's diagonal entries.
  652. # The upper triangular portion of lu is the upper triangular portion of the
  653. # U factor in the LU decomposition.
  654. for k in range(lu.rows):
  655. det *= lu[k, k]
  656. # return det(P)*det(U)
  657. return det
  658. def _minor(M, i, j, method="berkowitz"):
  659. """Return the (i,j) minor of ``M``. That is,
  660. return the determinant of the matrix obtained by deleting
  661. the `i`th row and `j`th column from ``M``.
  662. Parameters
  663. ==========
  664. i, j : int
  665. The row and column to exclude to obtain the submatrix.
  666. method : string, optional
  667. Method to use to find the determinant of the submatrix, can be
  668. "bareiss", "berkowitz" or "lu".
  669. Examples
  670. ========
  671. >>> from sympy import Matrix
  672. >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  673. >>> M.minor(1, 1)
  674. -12
  675. See Also
  676. ========
  677. minor_submatrix
  678. cofactor
  679. det
  680. """
  681. if not M.is_square:
  682. raise NonSquareMatrixError()
  683. return M.minor_submatrix(i, j).det(method=method)
  684. def _minor_submatrix(M, i, j):
  685. """Return the submatrix obtained by removing the `i`th row
  686. and `j`th column from ``M`` (works with Pythonic negative indices).
  687. Parameters
  688. ==========
  689. i, j : int
  690. The row and column to exclude to obtain the submatrix.
  691. Examples
  692. ========
  693. >>> from sympy import Matrix
  694. >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  695. >>> M.minor_submatrix(1, 1)
  696. Matrix([
  697. [1, 3],
  698. [7, 9]])
  699. See Also
  700. ========
  701. minor
  702. cofactor
  703. """
  704. if i < 0:
  705. i += M.rows
  706. if j < 0:
  707. j += M.cols
  708. if not 0 <= i < M.rows or not 0 <= j < M.cols:
  709. raise ValueError("`i` and `j` must satisfy 0 <= i < ``M.rows`` "
  710. "(%d)" % M.rows + "and 0 <= j < ``M.cols`` (%d)." % M.cols)
  711. rows = [a for a in range(M.rows) if a != i]
  712. cols = [a for a in range(M.cols) if a != j]
  713. return M.extract(rows, cols)