ZhengyangZhang commited on
Commit
417133e
·
verified ·
1 Parent(s): d7ff3e2

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/sympy/matrices/__init__.py +72 -0
  2. lib/python3.12/site-packages/sympy/matrices/decompositions.py +1621 -0
  3. lib/python3.12/site-packages/sympy/matrices/eigen.py +1346 -0
  4. lib/python3.12/site-packages/sympy/matrices/graph.py +279 -0
  5. lib/python3.12/site-packages/sympy/matrices/immutable.py +196 -0
  6. lib/python3.12/site-packages/sympy/matrices/matrices.py +687 -0
  7. lib/python3.12/site-packages/sympy/matrices/solvers.py +942 -0
  8. lib/python3.12/site-packages/sympy/matrices/sparse.py +473 -0
  9. lib/python3.12/site-packages/sympy/matrices/subspaces.py +174 -0
  10. lib/python3.12/site-packages/sympy/polys/__pycache__/__init__.cpython-312.pyc +0 -0
  11. lib/python3.12/site-packages/sympy/polys/__pycache__/appellseqs.cpython-312.pyc +0 -0
  12. lib/python3.12/site-packages/sympy/polys/__pycache__/constructor.cpython-312.pyc +0 -0
  13. lib/python3.12/site-packages/sympy/polys/__pycache__/densearith.cpython-312.pyc +0 -0
  14. lib/python3.12/site-packages/sympy/polys/__pycache__/densebasic.cpython-312.pyc +0 -0
  15. lib/python3.12/site-packages/sympy/polys/__pycache__/densetools.cpython-312.pyc +0 -0
  16. lib/python3.12/site-packages/sympy/polys/__pycache__/dispersion.cpython-312.pyc +0 -0
  17. lib/python3.12/site-packages/sympy/polys/__pycache__/distributedmodules.cpython-312.pyc +0 -0
  18. lib/python3.12/site-packages/sympy/polys/__pycache__/domainmatrix.cpython-312.pyc +0 -0
  19. lib/python3.12/site-packages/sympy/polys/__pycache__/euclidtools.cpython-312.pyc +0 -0
  20. lib/python3.12/site-packages/sympy/polys/__pycache__/factortools.cpython-312.pyc +0 -0
  21. lib/python3.12/site-packages/sympy/polys/__pycache__/fglmtools.cpython-312.pyc +0 -0
  22. lib/python3.12/site-packages/sympy/polys/__pycache__/fields.cpython-312.pyc +0 -0
  23. lib/python3.12/site-packages/sympy/polys/__pycache__/galoistools.cpython-312.pyc +0 -0
  24. lib/python3.12/site-packages/sympy/polys/__pycache__/groebnertools.cpython-312.pyc +0 -0
  25. lib/python3.12/site-packages/sympy/polys/__pycache__/heuristicgcd.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/sympy/polys/__pycache__/modulargcd.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/sympy/polys/__pycache__/monomials.cpython-312.pyc +0 -0
  28. lib/python3.12/site-packages/sympy/polys/__pycache__/multivariate_resultants.cpython-312.pyc +0 -0
  29. lib/python3.12/site-packages/sympy/polys/__pycache__/orderings.cpython-312.pyc +0 -0
  30. lib/python3.12/site-packages/sympy/polys/__pycache__/orthopolys.cpython-312.pyc +0 -0
  31. lib/python3.12/site-packages/sympy/polys/__pycache__/partfrac.cpython-312.pyc +0 -0
  32. lib/python3.12/site-packages/sympy/polys/__pycache__/polyconfig.cpython-312.pyc +0 -0
  33. lib/python3.12/site-packages/sympy/polys/__pycache__/polyerrors.cpython-312.pyc +0 -0
  34. lib/python3.12/site-packages/sympy/polys/__pycache__/polyfuncs.cpython-312.pyc +0 -0
  35. lib/python3.12/site-packages/sympy/polys/__pycache__/polymatrix.cpython-312.pyc +0 -0
  36. lib/python3.12/site-packages/sympy/polys/__pycache__/polyoptions.cpython-312.pyc +0 -0
  37. lib/python3.12/site-packages/sympy/polys/__pycache__/polyroots.cpython-312.pyc +0 -0
  38. lib/python3.12/site-packages/sympy/polys/__pycache__/polyutils.cpython-312.pyc +0 -0
  39. lib/python3.12/site-packages/sympy/polys/__pycache__/rationaltools.cpython-312.pyc +0 -0
  40. lib/python3.12/site-packages/sympy/polys/__pycache__/ring_series.cpython-312.pyc +0 -0
  41. lib/python3.12/site-packages/sympy/polys/__pycache__/rootisolation.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/sympy/polys/__pycache__/rootoftools.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/sympy/polys/__pycache__/solvers.cpython-312.pyc +0 -0
  44. lib/python3.12/site-packages/sympy/polys/__pycache__/specialpolys.cpython-312.pyc +0 -0
  45. lib/python3.12/site-packages/sympy/polys/__pycache__/sqfreetools.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/sympy/polys/__pycache__/subresultants_qq_zz.cpython-312.pyc +0 -0
  47. lib/python3.12/site-packages/sympy/polys/agca/__init__.py +5 -0
  48. lib/python3.12/site-packages/sympy/polys/agca/__pycache__/__init__.cpython-312.pyc +0 -0
  49. lib/python3.12/site-packages/sympy/polys/agca/__pycache__/extensions.cpython-312.pyc +0 -0
  50. lib/python3.12/site-packages/sympy/polys/agca/__pycache__/homomorphisms.cpython-312.pyc +0 -0
lib/python3.12/site-packages/sympy/matrices/__init__.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """A module that handles matrices.
2
+
3
+ Includes functions for fast creating matrices like zero, one/eye, random
4
+ matrix, etc.
5
+ """
6
+ from .exceptions import ShapeError, NonSquareMatrixError
7
+ from .kind import MatrixKind
8
+ from .dense import (
9
+ GramSchmidt, casoratian, diag, eye, hessian, jordan_cell,
10
+ list2numpy, matrix2numpy, matrix_multiply_elementwise, ones,
11
+ randMatrix, rot_axis1, rot_axis2, rot_axis3, rot_ccw_axis1,
12
+ rot_ccw_axis2, rot_ccw_axis3, rot_givens,
13
+ symarray, wronskian, zeros)
14
+ from .dense import MutableDenseMatrix
15
+ from .matrixbase import DeferredVector, MatrixBase
16
+
17
+ MutableMatrix = MutableDenseMatrix
18
+ Matrix = MutableMatrix
19
+
20
+ from .sparse import MutableSparseMatrix
21
+ from .sparsetools import banded
22
+ from .immutable import ImmutableDenseMatrix, ImmutableSparseMatrix
23
+
24
+ ImmutableMatrix = ImmutableDenseMatrix
25
+ SparseMatrix = MutableSparseMatrix
26
+
27
+ from .expressions import (
28
+ MatrixSlice, BlockDiagMatrix, BlockMatrix, FunctionMatrix, Identity,
29
+ Inverse, MatAdd, MatMul, MatPow, MatrixExpr, MatrixSymbol, Trace,
30
+ Transpose, ZeroMatrix, OneMatrix, blockcut, block_collapse, matrix_symbols, Adjoint,
31
+ hadamard_product, HadamardProduct, HadamardPower, Determinant, det,
32
+ diagonalize_vector, DiagMatrix, DiagonalMatrix, DiagonalOf, trace,
33
+ DotProduct, kronecker_product, KroneckerProduct,
34
+ PermutationMatrix, MatrixPermute, MatrixSet, Permanent, per)
35
+
36
+ from .utilities import dotprodsimp
37
+
38
+ __all__ = [
39
+ 'ShapeError', 'NonSquareMatrixError', 'MatrixKind',
40
+
41
+ 'GramSchmidt', 'casoratian', 'diag', 'eye', 'hessian', 'jordan_cell',
42
+ 'list2numpy', 'matrix2numpy', 'matrix_multiply_elementwise', 'ones',
43
+ 'randMatrix', 'rot_axis1', 'rot_axis2', 'rot_axis3', 'symarray',
44
+ 'wronskian', 'zeros', 'rot_ccw_axis1', 'rot_ccw_axis2', 'rot_ccw_axis3',
45
+ 'rot_givens',
46
+
47
+ 'MutableDenseMatrix',
48
+
49
+ 'DeferredVector', 'MatrixBase',
50
+
51
+ 'Matrix', 'MutableMatrix',
52
+
53
+ 'MutableSparseMatrix',
54
+
55
+ 'banded',
56
+
57
+ 'ImmutableDenseMatrix', 'ImmutableSparseMatrix',
58
+
59
+ 'ImmutableMatrix', 'SparseMatrix',
60
+
61
+ 'MatrixSlice', 'BlockDiagMatrix', 'BlockMatrix', 'FunctionMatrix',
62
+ 'Identity', 'Inverse', 'MatAdd', 'MatMul', 'MatPow', 'MatrixExpr',
63
+ 'MatrixSymbol', 'Trace', 'Transpose', 'ZeroMatrix', 'OneMatrix',
64
+ 'blockcut', 'block_collapse', 'matrix_symbols', 'Adjoint',
65
+ 'hadamard_product', 'HadamardProduct', 'HadamardPower', 'Determinant',
66
+ 'det', 'diagonalize_vector', 'DiagMatrix', 'DiagonalMatrix',
67
+ 'DiagonalOf', 'trace', 'DotProduct', 'kronecker_product',
68
+ 'KroneckerProduct', 'PermutationMatrix', 'MatrixPermute', 'MatrixSet',
69
+ 'Permanent', 'per',
70
+
71
+ 'dotprodsimp',
72
+ ]
lib/python3.12/site-packages/sympy/matrices/decompositions.py ADDED
@@ -0,0 +1,1621 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+
3
+ from sympy.core import S
4
+ from sympy.core.function import expand_mul
5
+ from sympy.functions.elementary.miscellaneous import Min, sqrt
6
+ from sympy.functions.elementary.complexes import sign
7
+
8
+ from .exceptions import NonSquareMatrixError, NonPositiveDefiniteMatrixError
9
+ from .utilities import _get_intermediate_simp, _iszero
10
+ from .determinant import _find_reasonable_pivot_naive
11
+
12
+
13
+ def _rank_decomposition(M, iszerofunc=_iszero, simplify=False):
14
+ r"""Returns a pair of matrices (`C`, `F`) with matching rank
15
+ such that `A = C F`.
16
+
17
+ Parameters
18
+ ==========
19
+
20
+ iszerofunc : Function, optional
21
+ A function used for detecting whether an element can
22
+ act as a pivot. ``lambda x: x.is_zero`` is used by default.
23
+
24
+ simplify : Bool or Function, optional
25
+ A function used to simplify elements when looking for a
26
+ pivot. By default SymPy's ``simplify`` is used.
27
+
28
+ Returns
29
+ =======
30
+
31
+ (C, F) : Matrices
32
+ `C` and `F` are full-rank matrices with rank as same as `A`,
33
+ whose product gives `A`.
34
+
35
+ See Notes for additional mathematical details.
36
+
37
+ Examples
38
+ ========
39
+
40
+ >>> from sympy import Matrix
41
+ >>> A = Matrix([
42
+ ... [1, 3, 1, 4],
43
+ ... [2, 7, 3, 9],
44
+ ... [1, 5, 3, 1],
45
+ ... [1, 2, 0, 8]
46
+ ... ])
47
+ >>> C, F = A.rank_decomposition()
48
+ >>> C
49
+ Matrix([
50
+ [1, 3, 4],
51
+ [2, 7, 9],
52
+ [1, 5, 1],
53
+ [1, 2, 8]])
54
+ >>> F
55
+ Matrix([
56
+ [1, 0, -2, 0],
57
+ [0, 1, 1, 0],
58
+ [0, 0, 0, 1]])
59
+ >>> C * F == A
60
+ True
61
+
62
+ Notes
63
+ =====
64
+
65
+ Obtaining `F`, an RREF of `A`, is equivalent to creating a
66
+ product
67
+
68
+ .. math::
69
+ E_n E_{n-1} ... E_1 A = F
70
+
71
+ where `E_n, E_{n-1}, \dots, E_1` are the elimination matrices or
72
+ permutation matrices equivalent to each row-reduction step.
73
+
74
+ The inverse of the same product of elimination matrices gives
75
+ `C`:
76
+
77
+ .. math::
78
+ C = \left(E_n E_{n-1} \dots E_1\right)^{-1}
79
+
80
+ It is not necessary, however, to actually compute the inverse:
81
+ the columns of `C` are those from the original matrix with the
82
+ same column indices as the indices of the pivot columns of `F`.
83
+
84
+ References
85
+ ==========
86
+
87
+ .. [1] https://en.wikipedia.org/wiki/Rank_factorization
88
+
89
+ .. [2] Piziak, R.; Odell, P. L. (1 June 1999).
90
+ "Full Rank Factorization of Matrices".
91
+ Mathematics Magazine. 72 (3): 193. doi:10.2307/2690882
92
+
93
+ See Also
94
+ ========
95
+
96
+ sympy.matrices.matrixbase.MatrixBase.rref
97
+ """
98
+
99
+ F, pivot_cols = M.rref(simplify=simplify, iszerofunc=iszerofunc,
100
+ pivots=True)
101
+ rank = len(pivot_cols)
102
+
103
+ C = M.extract(range(M.rows), pivot_cols)
104
+ F = F[:rank, :]
105
+
106
+ return C, F
107
+
108
+
109
+ def _liupc(M):
110
+ """Liu's algorithm, for pre-determination of the Elimination Tree of
111
+ the given matrix, used in row-based symbolic Cholesky factorization.
112
+
113
+ Examples
114
+ ========
115
+
116
+ >>> from sympy import SparseMatrix
117
+ >>> S = SparseMatrix([
118
+ ... [1, 0, 3, 2],
119
+ ... [0, 0, 1, 0],
120
+ ... [4, 0, 0, 5],
121
+ ... [0, 6, 7, 0]])
122
+ >>> S.liupc()
123
+ ([[0], [], [0], [1, 2]], [4, 3, 4, 4])
124
+
125
+ References
126
+ ==========
127
+
128
+ .. [1] Symbolic Sparse Cholesky Factorization using Elimination Trees,
129
+ Jeroen Van Grondelle (1999)
130
+ https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.7582
131
+ """
132
+ # Algorithm 2.4, p 17 of reference
133
+
134
+ # get the indices of the elements that are non-zero on or below diag
135
+ R = [[] for r in range(M.rows)]
136
+
137
+ for r, c, _ in M.row_list():
138
+ if c <= r:
139
+ R[r].append(c)
140
+
141
+ inf = len(R) # nothing will be this large
142
+ parent = [inf]*M.rows
143
+ virtual = [inf]*M.rows
144
+
145
+ for r in range(M.rows):
146
+ for c in R[r][:-1]:
147
+ while virtual[c] < r:
148
+ t = virtual[c]
149
+ virtual[c] = r
150
+ c = t
151
+
152
+ if virtual[c] == inf:
153
+ parent[c] = virtual[c] = r
154
+
155
+ return R, parent
156
+
157
+ def _row_structure_symbolic_cholesky(M):
158
+ """Symbolic cholesky factorization, for pre-determination of the
159
+ non-zero structure of the Cholesky factororization.
160
+
161
+ Examples
162
+ ========
163
+
164
+ >>> from sympy import SparseMatrix
165
+ >>> S = SparseMatrix([
166
+ ... [1, 0, 3, 2],
167
+ ... [0, 0, 1, 0],
168
+ ... [4, 0, 0, 5],
169
+ ... [0, 6, 7, 0]])
170
+ >>> S.row_structure_symbolic_cholesky()
171
+ [[0], [], [0], [1, 2]]
172
+
173
+ References
174
+ ==========
175
+
176
+ .. [1] Symbolic Sparse Cholesky Factorization using Elimination Trees,
177
+ Jeroen Van Grondelle (1999)
178
+ https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.7582
179
+ """
180
+
181
+ R, parent = M.liupc()
182
+ inf = len(R) # this acts as infinity
183
+ Lrow = copy.deepcopy(R)
184
+
185
+ for k in range(M.rows):
186
+ for j in R[k]:
187
+ while j != inf and j != k:
188
+ Lrow[k].append(j)
189
+ j = parent[j]
190
+
191
+ Lrow[k] = sorted(set(Lrow[k]))
192
+
193
+ return Lrow
194
+
195
+
196
+ def _cholesky(M, hermitian=True):
197
+ """Returns the Cholesky-type decomposition L of a matrix A
198
+ such that L * L.H == A if hermitian flag is True,
199
+ or L * L.T == A if hermitian is False.
200
+
201
+ A must be a Hermitian positive-definite matrix if hermitian is True,
202
+ or a symmetric matrix if it is False.
203
+
204
+ Examples
205
+ ========
206
+
207
+ >>> from sympy import Matrix
208
+ >>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11)))
209
+ >>> A.cholesky()
210
+ Matrix([
211
+ [ 5, 0, 0],
212
+ [ 3, 3, 0],
213
+ [-1, 1, 3]])
214
+ >>> A.cholesky() * A.cholesky().T
215
+ Matrix([
216
+ [25, 15, -5],
217
+ [15, 18, 0],
218
+ [-5, 0, 11]])
219
+
220
+ The matrix can have complex entries:
221
+
222
+ >>> from sympy import I
223
+ >>> A = Matrix(((9, 3*I), (-3*I, 5)))
224
+ >>> A.cholesky()
225
+ Matrix([
226
+ [ 3, 0],
227
+ [-I, 2]])
228
+ >>> A.cholesky() * A.cholesky().H
229
+ Matrix([
230
+ [ 9, 3*I],
231
+ [-3*I, 5]])
232
+
233
+ Non-hermitian Cholesky-type decomposition may be useful when the
234
+ matrix is not positive-definite.
235
+
236
+ >>> A = Matrix([[1, 2], [2, 1]])
237
+ >>> L = A.cholesky(hermitian=False)
238
+ >>> L
239
+ Matrix([
240
+ [1, 0],
241
+ [2, sqrt(3)*I]])
242
+ >>> L*L.T == A
243
+ True
244
+
245
+ See Also
246
+ ========
247
+
248
+ sympy.matrices.dense.DenseMatrix.LDLdecomposition
249
+ sympy.matrices.matrixbase.MatrixBase.LUdecomposition
250
+ QRdecomposition
251
+ """
252
+
253
+ from .dense import MutableDenseMatrix
254
+
255
+ if not M.is_square:
256
+ raise NonSquareMatrixError("Matrix must be square.")
257
+ if hermitian and not M.is_hermitian:
258
+ raise ValueError("Matrix must be Hermitian.")
259
+ if not hermitian and not M.is_symmetric():
260
+ raise ValueError("Matrix must be symmetric.")
261
+
262
+ L = MutableDenseMatrix.zeros(M.rows, M.rows)
263
+
264
+ if hermitian:
265
+ for i in range(M.rows):
266
+ for j in range(i):
267
+ L[i, j] = ((1 / L[j, j])*(M[i, j] -
268
+ sum(L[i, k]*L[j, k].conjugate() for k in range(j))))
269
+
270
+ Lii2 = (M[i, i] -
271
+ sum(L[i, k]*L[i, k].conjugate() for k in range(i)))
272
+
273
+ if Lii2.is_positive is False:
274
+ raise NonPositiveDefiniteMatrixError(
275
+ "Matrix must be positive-definite")
276
+
277
+ L[i, i] = sqrt(Lii2)
278
+
279
+ else:
280
+ for i in range(M.rows):
281
+ for j in range(i):
282
+ L[i, j] = ((1 / L[j, j])*(M[i, j] -
283
+ sum(L[i, k]*L[j, k] for k in range(j))))
284
+
285
+ L[i, i] = sqrt(M[i, i] -
286
+ sum(L[i, k]**2 for k in range(i)))
287
+
288
+ return M._new(L)
289
+
290
+ def _cholesky_sparse(M, hermitian=True):
291
+ """
292
+ Returns the Cholesky decomposition L of a matrix A
293
+ such that L * L.T = A
294
+
295
+ A must be a square, symmetric, positive-definite
296
+ and non-singular matrix
297
+
298
+ Examples
299
+ ========
300
+
301
+ >>> from sympy import SparseMatrix
302
+ >>> A = SparseMatrix(((25,15,-5),(15,18,0),(-5,0,11)))
303
+ >>> A.cholesky()
304
+ Matrix([
305
+ [ 5, 0, 0],
306
+ [ 3, 3, 0],
307
+ [-1, 1, 3]])
308
+ >>> A.cholesky() * A.cholesky().T == A
309
+ True
310
+
311
+ The matrix can have complex entries:
312
+
313
+ >>> from sympy import I
314
+ >>> A = SparseMatrix(((9, 3*I), (-3*I, 5)))
315
+ >>> A.cholesky()
316
+ Matrix([
317
+ [ 3, 0],
318
+ [-I, 2]])
319
+ >>> A.cholesky() * A.cholesky().H
320
+ Matrix([
321
+ [ 9, 3*I],
322
+ [-3*I, 5]])
323
+
324
+ Non-hermitian Cholesky-type decomposition may be useful when the
325
+ matrix is not positive-definite.
326
+
327
+ >>> A = SparseMatrix([[1, 2], [2, 1]])
328
+ >>> L = A.cholesky(hermitian=False)
329
+ >>> L
330
+ Matrix([
331
+ [1, 0],
332
+ [2, sqrt(3)*I]])
333
+ >>> L*L.T == A
334
+ True
335
+
336
+ See Also
337
+ ========
338
+
339
+ sympy.matrices.sparse.SparseMatrix.LDLdecomposition
340
+ sympy.matrices.matrixbase.MatrixBase.LUdecomposition
341
+ QRdecomposition
342
+ """
343
+
344
+ from .dense import MutableDenseMatrix
345
+
346
+ if not M.is_square:
347
+ raise NonSquareMatrixError("Matrix must be square.")
348
+ if hermitian and not M.is_hermitian:
349
+ raise ValueError("Matrix must be Hermitian.")
350
+ if not hermitian and not M.is_symmetric():
351
+ raise ValueError("Matrix must be symmetric.")
352
+
353
+ dps = _get_intermediate_simp(expand_mul, expand_mul)
354
+ Crowstruc = M.row_structure_symbolic_cholesky()
355
+ C = MutableDenseMatrix.zeros(M.rows)
356
+
357
+ for i in range(len(Crowstruc)):
358
+ for j in Crowstruc[i]:
359
+ if i != j:
360
+ C[i, j] = M[i, j]
361
+ summ = 0
362
+
363
+ for p1 in Crowstruc[i]:
364
+ if p1 < j:
365
+ for p2 in Crowstruc[j]:
366
+ if p2 < j:
367
+ if p1 == p2:
368
+ if hermitian:
369
+ summ += C[i, p1]*C[j, p1].conjugate()
370
+ else:
371
+ summ += C[i, p1]*C[j, p1]
372
+ else:
373
+ break
374
+ else:
375
+ break
376
+
377
+ C[i, j] = dps((C[i, j] - summ) / C[j, j])
378
+
379
+ else: # i == j
380
+ C[j, j] = M[j, j]
381
+ summ = 0
382
+
383
+ for k in Crowstruc[j]:
384
+ if k < j:
385
+ if hermitian:
386
+ summ += C[j, k]*C[j, k].conjugate()
387
+ else:
388
+ summ += C[j, k]**2
389
+ else:
390
+ break
391
+
392
+ Cjj2 = dps(C[j, j] - summ)
393
+
394
+ if hermitian and Cjj2.is_positive is False:
395
+ raise NonPositiveDefiniteMatrixError(
396
+ "Matrix must be positive-definite")
397
+
398
+ C[j, j] = sqrt(Cjj2)
399
+
400
+ return M._new(C)
401
+
402
+
403
+ def _LDLdecomposition(M, hermitian=True):
404
+ """Returns the LDL Decomposition (L, D) of matrix A,
405
+ such that L * D * L.H == A if hermitian flag is True, or
406
+ L * D * L.T == A if hermitian is False.
407
+ This method eliminates the use of square root.
408
+ Further this ensures that all the diagonal entries of L are 1.
409
+ A must be a Hermitian positive-definite matrix if hermitian is True,
410
+ or a symmetric matrix otherwise.
411
+
412
+ Examples
413
+ ========
414
+
415
+ >>> from sympy import Matrix, eye
416
+ >>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11)))
417
+ >>> L, D = A.LDLdecomposition()
418
+ >>> L
419
+ Matrix([
420
+ [ 1, 0, 0],
421
+ [ 3/5, 1, 0],
422
+ [-1/5, 1/3, 1]])
423
+ >>> D
424
+ Matrix([
425
+ [25, 0, 0],
426
+ [ 0, 9, 0],
427
+ [ 0, 0, 9]])
428
+ >>> L * D * L.T * A.inv() == eye(A.rows)
429
+ True
430
+
431
+ The matrix can have complex entries:
432
+
433
+ >>> from sympy import I
434
+ >>> A = Matrix(((9, 3*I), (-3*I, 5)))
435
+ >>> L, D = A.LDLdecomposition()
436
+ >>> L
437
+ Matrix([
438
+ [ 1, 0],
439
+ [-I/3, 1]])
440
+ >>> D
441
+ Matrix([
442
+ [9, 0],
443
+ [0, 4]])
444
+ >>> L*D*L.H == A
445
+ True
446
+
447
+ See Also
448
+ ========
449
+
450
+ sympy.matrices.dense.DenseMatrix.cholesky
451
+ sympy.matrices.matrixbase.MatrixBase.LUdecomposition
452
+ QRdecomposition
453
+ """
454
+
455
+ from .dense import MutableDenseMatrix
456
+
457
+ if not M.is_square:
458
+ raise NonSquareMatrixError("Matrix must be square.")
459
+ if hermitian and not M.is_hermitian:
460
+ raise ValueError("Matrix must be Hermitian.")
461
+ if not hermitian and not M.is_symmetric():
462
+ raise ValueError("Matrix must be symmetric.")
463
+
464
+ D = MutableDenseMatrix.zeros(M.rows, M.rows)
465
+ L = MutableDenseMatrix.eye(M.rows)
466
+
467
+ if hermitian:
468
+ for i in range(M.rows):
469
+ for j in range(i):
470
+ L[i, j] = (1 / D[j, j])*(M[i, j] - sum(
471
+ L[i, k]*L[j, k].conjugate()*D[k, k] for k in range(j)))
472
+
473
+ D[i, i] = (M[i, i] -
474
+ sum(L[i, k]*L[i, k].conjugate()*D[k, k] for k in range(i)))
475
+
476
+ if D[i, i].is_positive is False:
477
+ raise NonPositiveDefiniteMatrixError(
478
+ "Matrix must be positive-definite")
479
+
480
+ else:
481
+ for i in range(M.rows):
482
+ for j in range(i):
483
+ L[i, j] = (1 / D[j, j])*(M[i, j] - sum(
484
+ L[i, k]*L[j, k]*D[k, k] for k in range(j)))
485
+
486
+ D[i, i] = M[i, i] - sum(L[i, k]**2*D[k, k] for k in range(i))
487
+
488
+ return M._new(L), M._new(D)
489
+
490
+ def _LDLdecomposition_sparse(M, hermitian=True):
491
+ """
492
+ Returns the LDL Decomposition (matrices ``L`` and ``D``) of matrix
493
+ ``A``, such that ``L * D * L.T == A``. ``A`` must be a square,
494
+ symmetric, positive-definite and non-singular.
495
+
496
+ This method eliminates the use of square root and ensures that all
497
+ the diagonal entries of L are 1.
498
+
499
+ Examples
500
+ ========
501
+
502
+ >>> from sympy import SparseMatrix
503
+ >>> A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11)))
504
+ >>> L, D = A.LDLdecomposition()
505
+ >>> L
506
+ Matrix([
507
+ [ 1, 0, 0],
508
+ [ 3/5, 1, 0],
509
+ [-1/5, 1/3, 1]])
510
+ >>> D
511
+ Matrix([
512
+ [25, 0, 0],
513
+ [ 0, 9, 0],
514
+ [ 0, 0, 9]])
515
+ >>> L * D * L.T == A
516
+ True
517
+
518
+ """
519
+
520
+ from .dense import MutableDenseMatrix
521
+
522
+ if not M.is_square:
523
+ raise NonSquareMatrixError("Matrix must be square.")
524
+ if hermitian and not M.is_hermitian:
525
+ raise ValueError("Matrix must be Hermitian.")
526
+ if not hermitian and not M.is_symmetric():
527
+ raise ValueError("Matrix must be symmetric.")
528
+
529
+ dps = _get_intermediate_simp(expand_mul, expand_mul)
530
+ Lrowstruc = M.row_structure_symbolic_cholesky()
531
+ L = MutableDenseMatrix.eye(M.rows)
532
+ D = MutableDenseMatrix.zeros(M.rows, M.cols)
533
+
534
+ for i in range(len(Lrowstruc)):
535
+ for j in Lrowstruc[i]:
536
+ if i != j:
537
+ L[i, j] = M[i, j]
538
+ summ = 0
539
+
540
+ for p1 in Lrowstruc[i]:
541
+ if p1 < j:
542
+ for p2 in Lrowstruc[j]:
543
+ if p2 < j:
544
+ if p1 == p2:
545
+ if hermitian:
546
+ summ += L[i, p1]*L[j, p1].conjugate()*D[p1, p1]
547
+ else:
548
+ summ += L[i, p1]*L[j, p1]*D[p1, p1]
549
+ else:
550
+ break
551
+ else:
552
+ break
553
+
554
+ L[i, j] = dps((L[i, j] - summ) / D[j, j])
555
+
556
+ else: # i == j
557
+ D[i, i] = M[i, i]
558
+ summ = 0
559
+
560
+ for k in Lrowstruc[i]:
561
+ if k < i:
562
+ if hermitian:
563
+ summ += L[i, k]*L[i, k].conjugate()*D[k, k]
564
+ else:
565
+ summ += L[i, k]**2*D[k, k]
566
+ else:
567
+ break
568
+
569
+ D[i, i] = dps(D[i, i] - summ)
570
+
571
+ if hermitian and D[i, i].is_positive is False:
572
+ raise NonPositiveDefiniteMatrixError(
573
+ "Matrix must be positive-definite")
574
+
575
+ return M._new(L), M._new(D)
576
+
577
+
578
+ def _LUdecomposition(M, iszerofunc=_iszero, simpfunc=None, rankcheck=False):
579
+ """Returns (L, U, perm) where L is a lower triangular matrix with unit
580
+ diagonal, U is an upper triangular matrix, and perm is a list of row
581
+ swap index pairs. If A is the original matrix, then
582
+ ``A = (L*U).permuteBkwd(perm)``, and the row permutation matrix P such
583
+ that $P A = L U$ can be computed by ``P = eye(A.rows).permuteFwd(perm)``.
584
+
585
+ See documentation for LUCombined for details about the keyword argument
586
+ rankcheck, iszerofunc, and simpfunc.
587
+
588
+ Parameters
589
+ ==========
590
+
591
+ rankcheck : bool, optional
592
+ Determines if this function should detect the rank
593
+ deficiency of the matrixis and should raise a
594
+ ``ValueError``.
595
+
596
+ iszerofunc : function, optional
597
+ A function which determines if a given expression is zero.
598
+
599
+ The function should be a callable that takes a single
600
+ SymPy expression and returns a 3-valued boolean value
601
+ ``True``, ``False``, or ``None``.
602
+
603
+ It is internally used by the pivot searching algorithm.
604
+ See the notes section for a more information about the
605
+ pivot searching algorithm.
606
+
607
+ simpfunc : function or None, optional
608
+ A function that simplifies the input.
609
+
610
+ If this is specified as a function, this function should be
611
+ a callable that takes a single SymPy expression and returns
612
+ an another SymPy expression that is algebraically
613
+ equivalent.
614
+
615
+ If ``None``, it indicates that the pivot search algorithm
616
+ should not attempt to simplify any candidate pivots.
617
+
618
+ It is internally used by the pivot searching algorithm.
619
+ See the notes section for a more information about the
620
+ pivot searching algorithm.
621
+
622
+ Examples
623
+ ========
624
+
625
+ >>> from sympy import Matrix
626
+ >>> a = Matrix([[4, 3], [6, 3]])
627
+ >>> L, U, _ = a.LUdecomposition()
628
+ >>> L
629
+ Matrix([
630
+ [ 1, 0],
631
+ [3/2, 1]])
632
+ >>> U
633
+ Matrix([
634
+ [4, 3],
635
+ [0, -3/2]])
636
+
637
+ See Also
638
+ ========
639
+
640
+ sympy.matrices.dense.DenseMatrix.cholesky
641
+ sympy.matrices.dense.DenseMatrix.LDLdecomposition
642
+ QRdecomposition
643
+ LUdecomposition_Simple
644
+ LUdecompositionFF
645
+ LUsolve
646
+ """
647
+
648
+ combined, p = M.LUdecomposition_Simple(iszerofunc=iszerofunc,
649
+ simpfunc=simpfunc, rankcheck=rankcheck)
650
+
651
+ # L is lower triangular ``M.rows x M.rows``
652
+ # U is upper triangular ``M.rows x M.cols``
653
+ # L has unit diagonal. For each column in combined, the subcolumn
654
+ # below the diagonal of combined is shared by L.
655
+ # If L has more columns than combined, then the remaining subcolumns
656
+ # below the diagonal of L are zero.
657
+ # The upper triangular portion of L and combined are equal.
658
+ def entry_L(i, j):
659
+ if i < j:
660
+ # Super diagonal entry
661
+ return M.zero
662
+ elif i == j:
663
+ return M.one
664
+ elif j < combined.cols:
665
+ return combined[i, j]
666
+
667
+ # Subdiagonal entry of L with no corresponding
668
+ # entry in combined
669
+ return M.zero
670
+
671
+ def entry_U(i, j):
672
+ return M.zero if i > j else combined[i, j]
673
+
674
+ L = M._new(combined.rows, combined.rows, entry_L)
675
+ U = M._new(combined.rows, combined.cols, entry_U)
676
+
677
+ return L, U, p
678
+
679
+ def _LUdecomposition_Simple(M, iszerofunc=_iszero, simpfunc=None,
680
+ rankcheck=False):
681
+ r"""Compute the PLU decomposition of the matrix.
682
+
683
+ Parameters
684
+ ==========
685
+
686
+ rankcheck : bool, optional
687
+ Determines if this function should detect the rank
688
+ deficiency of the matrixis and should raise a
689
+ ``ValueError``.
690
+
691
+ iszerofunc : function, optional
692
+ A function which determines if a given expression is zero.
693
+
694
+ The function should be a callable that takes a single
695
+ SymPy expression and returns a 3-valued boolean value
696
+ ``True``, ``False``, or ``None``.
697
+
698
+ It is internally used by the pivot searching algorithm.
699
+ See the notes section for a more information about the
700
+ pivot searching algorithm.
701
+
702
+ simpfunc : function or None, optional
703
+ A function that simplifies the input.
704
+
705
+ If this is specified as a function, this function should be
706
+ a callable that takes a single SymPy expression and returns
707
+ an another SymPy expression that is algebraically
708
+ equivalent.
709
+
710
+ If ``None``, it indicates that the pivot search algorithm
711
+ should not attempt to simplify any candidate pivots.
712
+
713
+ It is internally used by the pivot searching algorithm.
714
+ See the notes section for a more information about the
715
+ pivot searching algorithm.
716
+
717
+ Returns
718
+ =======
719
+
720
+ (lu, row_swaps) : (Matrix, list)
721
+ If the original matrix is a $m, n$ matrix:
722
+
723
+ *lu* is a $m, n$ matrix, which contains result of the
724
+ decomposition in a compressed form. See the notes section
725
+ to see how the matrix is compressed.
726
+
727
+ *row_swaps* is a $m$-element list where each element is a
728
+ pair of row exchange indices.
729
+
730
+ ``A = (L*U).permute_backward(perm)``, and the row
731
+ permutation matrix $P$ from the formula $P A = L U$ can be
732
+ computed by ``P=eye(A.row).permute_forward(perm)``.
733
+
734
+ Raises
735
+ ======
736
+
737
+ ValueError
738
+ Raised if ``rankcheck=True`` and the matrix is found to
739
+ be rank deficient during the computation.
740
+
741
+ Notes
742
+ =====
743
+
744
+ About the PLU decomposition:
745
+
746
+ PLU decomposition is a generalization of a LU decomposition
747
+ which can be extended for rank-deficient matrices.
748
+
749
+ It can further be generalized for non-square matrices, and this
750
+ is the notation that SymPy is using.
751
+
752
+ PLU decomposition is a decomposition of a $m, n$ matrix $A$ in
753
+ the form of $P A = L U$ where
754
+
755
+ * $L$ is a $m, m$ lower triangular matrix with unit diagonal
756
+ entries.
757
+ * $U$ is a $m, n$ upper triangular matrix.
758
+ * $P$ is a $m, m$ permutation matrix.
759
+
760
+ So, for a square matrix, the decomposition would look like:
761
+
762
+ .. math::
763
+ L = \begin{bmatrix}
764
+ 1 & 0 & 0 & \cdots & 0 \\
765
+ L_{1, 0} & 1 & 0 & \cdots & 0 \\
766
+ L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 \\
767
+ \vdots & \vdots & \vdots & \ddots & \vdots \\
768
+ L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & 1
769
+ \end{bmatrix}
770
+
771
+ .. math::
772
+ U = \begin{bmatrix}
773
+ U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\
774
+ 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\
775
+ 0 & 0 & U_{2, 2} & \cdots & U_{2, n-1} \\
776
+ \vdots & \vdots & \vdots & \ddots & \vdots \\
777
+ 0 & 0 & 0 & \cdots & U_{n-1, n-1}
778
+ \end{bmatrix}
779
+
780
+ And for a matrix with more rows than the columns,
781
+ the decomposition would look like:
782
+
783
+ .. math::
784
+ L = \begin{bmatrix}
785
+ 1 & 0 & 0 & \cdots & 0 & 0 & \cdots & 0 \\
786
+ L_{1, 0} & 1 & 0 & \cdots & 0 & 0 & \cdots & 0 \\
787
+ L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 & 0 & \cdots & 0 \\
788
+ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots
789
+ & \vdots \\
790
+ L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & 1 & 0
791
+ & \cdots & 0 \\
792
+ L_{n, 0} & L_{n, 1} & L_{n, 2} & \cdots & L_{n, n-1} & 1
793
+ & \cdots & 0 \\
794
+ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots
795
+ & \ddots & \vdots \\
796
+ L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & L_{m-1, n-1}
797
+ & 0 & \cdots & 1 \\
798
+ \end{bmatrix}
799
+
800
+ .. math::
801
+ U = \begin{bmatrix}
802
+ U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\
803
+ 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\
804
+ 0 & 0 & U_{2, 2} & \cdots & U_{2, n-1} \\
805
+ \vdots & \vdots & \vdots & \ddots & \vdots \\
806
+ 0 & 0 & 0 & \cdots & U_{n-1, n-1} \\
807
+ 0 & 0 & 0 & \cdots & 0 \\
808
+ \vdots & \vdots & \vdots & \ddots & \vdots \\
809
+ 0 & 0 & 0 & \cdots & 0
810
+ \end{bmatrix}
811
+
812
+ Finally, for a matrix with more columns than the rows, the
813
+ decomposition would look like:
814
+
815
+ .. math::
816
+ L = \begin{bmatrix}
817
+ 1 & 0 & 0 & \cdots & 0 \\
818
+ L_{1, 0} & 1 & 0 & \cdots & 0 \\
819
+ L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 \\
820
+ \vdots & \vdots & \vdots & \ddots & \vdots \\
821
+ L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & 1
822
+ \end{bmatrix}
823
+
824
+ .. math::
825
+ U = \begin{bmatrix}
826
+ U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, m-1}
827
+ & \cdots & U_{0, n-1} \\
828
+ 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, m-1}
829
+ & \cdots & U_{1, n-1} \\
830
+ 0 & 0 & U_{2, 2} & \cdots & U_{2, m-1}
831
+ & \cdots & U_{2, n-1} \\
832
+ \vdots & \vdots & \vdots & \ddots & \vdots
833
+ & \cdots & \vdots \\
834
+ 0 & 0 & 0 & \cdots & U_{m-1, m-1}
835
+ & \cdots & U_{m-1, n-1} \\
836
+ \end{bmatrix}
837
+
838
+ About the compressed LU storage:
839
+
840
+ The results of the decomposition are often stored in compressed
841
+ forms rather than returning $L$ and $U$ matrices individually.
842
+
843
+ It may be less intiuitive, but it is commonly used for a lot of
844
+ numeric libraries because of the efficiency.
845
+
846
+ The storage matrix is defined as following for this specific
847
+ method:
848
+
849
+ * The subdiagonal elements of $L$ are stored in the subdiagonal
850
+ portion of $LU$, that is $LU_{i, j} = L_{i, j}$ whenever
851
+ $i > j$.
852
+ * The elements on the diagonal of $L$ are all 1, and are not
853
+ explicitly stored.
854
+ * $U$ is stored in the upper triangular portion of $LU$, that is
855
+ $LU_{i, j} = U_{i, j}$ whenever $i <= j$.
856
+ * For a case of $m > n$, the right side of the $L$ matrix is
857
+ trivial to store.
858
+ * For a case of $m < n$, the below side of the $U$ matrix is
859
+ trivial to store.
860
+
861
+ So, for a square matrix, the compressed output matrix would be:
862
+
863
+ .. math::
864
+ LU = \begin{bmatrix}
865
+ U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\
866
+ L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\
867
+ L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, n-1} \\
868
+ \vdots & \vdots & \vdots & \ddots & \vdots \\
869
+ L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & U_{n-1, n-1}
870
+ \end{bmatrix}
871
+
872
+ For a matrix with more rows than the columns, the compressed
873
+ output matrix would be:
874
+
875
+ .. math::
876
+ LU = \begin{bmatrix}
877
+ U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\
878
+ L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\
879
+ L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, n-1} \\
880
+ \vdots & \vdots & \vdots & \ddots & \vdots \\
881
+ L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots
882
+ & U_{n-1, n-1} \\
883
+ \vdots & \vdots & \vdots & \ddots & \vdots \\
884
+ L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots
885
+ & L_{m-1, n-1} \\
886
+ \end{bmatrix}
887
+
888
+ For a matrix with more columns than the rows, the compressed
889
+ output matrix would be:
890
+
891
+ .. math::
892
+ LU = \begin{bmatrix}
893
+ U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, m-1}
894
+ & \cdots & U_{0, n-1} \\
895
+ L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, m-1}
896
+ & \cdots & U_{1, n-1} \\
897
+ L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, m-1}
898
+ & \cdots & U_{2, n-1} \\
899
+ \vdots & \vdots & \vdots & \ddots & \vdots
900
+ & \cdots & \vdots \\
901
+ L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & U_{m-1, m-1}
902
+ & \cdots & U_{m-1, n-1} \\
903
+ \end{bmatrix}
904
+
905
+ About the pivot searching algorithm:
906
+
907
+ When a matrix contains symbolic entries, the pivot search algorithm
908
+ differs from the case where every entry can be categorized as zero or
909
+ nonzero.
910
+ The algorithm searches column by column through the submatrix whose
911
+ top left entry coincides with the pivot position.
912
+ If it exists, the pivot is the first entry in the current search
913
+ column that iszerofunc guarantees is nonzero.
914
+ If no such candidate exists, then each candidate pivot is simplified
915
+ if simpfunc is not None.
916
+ The search is repeated, with the difference that a candidate may be
917
+ the pivot if ``iszerofunc()`` cannot guarantee that it is nonzero.
918
+ In the second search the pivot is the first candidate that
919
+ iszerofunc can guarantee is nonzero.
920
+ If no such candidate exists, then the pivot is the first candidate
921
+ for which iszerofunc returns None.
922
+ If no such candidate exists, then the search is repeated in the next
923
+ column to the right.
924
+ The pivot search algorithm differs from the one in ``rref()``, which
925
+ relies on ``_find_reasonable_pivot()``.
926
+ Future versions of ``LUdecomposition_simple()`` may use
927
+ ``_find_reasonable_pivot()``.
928
+
929
+ See Also
930
+ ========
931
+
932
+ sympy.matrices.matrixbase.MatrixBase.LUdecomposition
933
+ LUdecompositionFF
934
+ LUsolve
935
+ """
936
+
937
+ if rankcheck:
938
+ # https://github.com/sympy/sympy/issues/9796
939
+ pass
940
+
941
+ if S.Zero in M.shape:
942
+ # Define LU decomposition of a matrix with no entries as a matrix
943
+ # of the same dimensions with all zero entries.
944
+ return M.zeros(M.rows, M.cols), []
945
+
946
+ dps = _get_intermediate_simp()
947
+ lu = M.as_mutable()
948
+ row_swaps = []
949
+
950
+ pivot_col = 0
951
+
952
+ for pivot_row in range(0, lu.rows - 1):
953
+ # Search for pivot. Prefer entry that iszeropivot determines
954
+ # is nonzero, over entry that iszeropivot cannot guarantee
955
+ # is zero.
956
+ # XXX ``_find_reasonable_pivot`` uses slow zero testing. Blocked by bug #10279
957
+ # Future versions of LUdecomposition_simple can pass iszerofunc and simpfunc
958
+ # to _find_reasonable_pivot().
959
+ # In pass 3 of _find_reasonable_pivot(), the predicate in ``if x.equals(S.Zero):``
960
+ # calls sympy.simplify(), and not the simplification function passed in via
961
+ # the keyword argument simpfunc.
962
+ iszeropivot = True
963
+
964
+ while pivot_col != M.cols and iszeropivot:
965
+ sub_col = (lu[r, pivot_col] for r in range(pivot_row, M.rows))
966
+
967
+ pivot_row_offset, pivot_value, is_assumed_non_zero, ind_simplified_pairs =\
968
+ _find_reasonable_pivot_naive(sub_col, iszerofunc, simpfunc)
969
+
970
+ iszeropivot = pivot_value is None
971
+
972
+ if iszeropivot:
973
+ # All candidate pivots in this column are zero.
974
+ # Proceed to next column.
975
+ pivot_col += 1
976
+
977
+ if rankcheck and pivot_col != pivot_row:
978
+ # All entries including and below the pivot position are
979
+ # zero, which indicates that the rank of the matrix is
980
+ # strictly less than min(num rows, num cols)
981
+ # Mimic behavior of previous implementation, by throwing a
982
+ # ValueError.
983
+ raise ValueError("Rank of matrix is strictly less than"
984
+ " number of rows or columns."
985
+ " Pass keyword argument"
986
+ " rankcheck=False to compute"
987
+ " the LU decomposition of this matrix.")
988
+
989
+ candidate_pivot_row = None if pivot_row_offset is None else pivot_row + pivot_row_offset
990
+
991
+ if candidate_pivot_row is None and iszeropivot:
992
+ # If candidate_pivot_row is None and iszeropivot is True
993
+ # after pivot search has completed, then the submatrix
994
+ # below and to the right of (pivot_row, pivot_col) is
995
+ # all zeros, indicating that Gaussian elimination is
996
+ # complete.
997
+ return lu, row_swaps
998
+
999
+ # Update entries simplified during pivot search.
1000
+ for offset, val in ind_simplified_pairs:
1001
+ lu[pivot_row + offset, pivot_col] = val
1002
+
1003
+ if pivot_row != candidate_pivot_row:
1004
+ # Row swap book keeping:
1005
+ # Record which rows were swapped.
1006
+ # Update stored portion of L factor by multiplying L on the
1007
+ # left and right with the current permutation.
1008
+ # Swap rows of U.
1009
+ row_swaps.append([pivot_row, candidate_pivot_row])
1010
+
1011
+ # Update L.
1012
+ lu[pivot_row, 0:pivot_row], lu[candidate_pivot_row, 0:pivot_row] = \
1013
+ lu[candidate_pivot_row, 0:pivot_row], lu[pivot_row, 0:pivot_row]
1014
+
1015
+ # Swap pivot row of U with candidate pivot row.
1016
+ lu[pivot_row, pivot_col:lu.cols], lu[candidate_pivot_row, pivot_col:lu.cols] = \
1017
+ lu[candidate_pivot_row, pivot_col:lu.cols], lu[pivot_row, pivot_col:lu.cols]
1018
+
1019
+ # Introduce zeros below the pivot by adding a multiple of the
1020
+ # pivot row to a row under it, and store the result in the
1021
+ # row under it.
1022
+ # Only entries in the target row whose index is greater than
1023
+ # start_col may be nonzero.
1024
+ start_col = pivot_col + 1
1025
+
1026
+ for row in range(pivot_row + 1, lu.rows):
1027
+ # Store factors of L in the subcolumn below
1028
+ # (pivot_row, pivot_row).
1029
+ lu[row, pivot_row] = \
1030
+ dps(lu[row, pivot_col]/lu[pivot_row, pivot_col])
1031
+
1032
+ # Form the linear combination of the pivot row and the current
1033
+ # row below the pivot row that zeros the entries below the pivot.
1034
+ # Employing slicing instead of a loop here raises
1035
+ # NotImplementedError: Cannot add Zero to MutableSparseMatrix
1036
+ # in sympy/matrices/tests/test_sparse.py.
1037
+ # c = pivot_row + 1 if pivot_row == pivot_col else pivot_col
1038
+ for c in range(start_col, lu.cols):
1039
+ lu[row, c] = dps(lu[row, c] - lu[row, pivot_row]*lu[pivot_row, c])
1040
+
1041
+ if pivot_row != pivot_col:
1042
+ # matrix rank < min(num rows, num cols),
1043
+ # so factors of L are not stored directly below the pivot.
1044
+ # These entries are zero by construction, so don't bother
1045
+ # computing them.
1046
+ for row in range(pivot_row + 1, lu.rows):
1047
+ lu[row, pivot_col] = M.zero
1048
+
1049
+ pivot_col += 1
1050
+
1051
+ if pivot_col == lu.cols:
1052
+ # All candidate pivots are zero implies that Gaussian
1053
+ # elimination is complete.
1054
+ return lu, row_swaps
1055
+
1056
+ if rankcheck:
1057
+ if iszerofunc(
1058
+ lu[Min(lu.rows, lu.cols) - 1, Min(lu.rows, lu.cols) - 1]):
1059
+ raise ValueError("Rank of matrix is strictly less than"
1060
+ " number of rows or columns."
1061
+ " Pass keyword argument"
1062
+ " rankcheck=False to compute"
1063
+ " the LU decomposition of this matrix.")
1064
+
1065
+ return lu, row_swaps
1066
+
1067
+ def _LUdecompositionFF(M):
1068
+ """Compute a fraction-free LU decomposition.
1069
+
1070
+ Returns 4 matrices P, L, D, U such that PA = L D**-1 U.
1071
+ If the elements of the matrix belong to some integral domain I, then all
1072
+ elements of L, D and U are guaranteed to belong to I.
1073
+
1074
+ See Also
1075
+ ========
1076
+
1077
+ sympy.matrices.matrixbase.MatrixBase.LUdecomposition
1078
+ LUdecomposition_Simple
1079
+ LUsolve
1080
+
1081
+ References
1082
+ ==========
1083
+
1084
+ .. [1] W. Zhou & D.J. Jeffrey, "Fraction-free matrix factors: new forms
1085
+ for LU and QR factors". Frontiers in Computer Science in China,
1086
+ Vol 2, no. 1, pp. 67-80, 2008.
1087
+ """
1088
+
1089
+ from sympy.matrices import SparseMatrix
1090
+
1091
+ zeros = SparseMatrix.zeros
1092
+ eye = SparseMatrix.eye
1093
+ n, m = M.rows, M.cols
1094
+ U, L, P = M.as_mutable(), eye(n), eye(n)
1095
+ DD = zeros(n, n)
1096
+ oldpivot = 1
1097
+
1098
+ for k in range(n - 1):
1099
+ if U[k, k] == 0:
1100
+ for kpivot in range(k + 1, n):
1101
+ if U[kpivot, k]:
1102
+ break
1103
+ else:
1104
+ raise ValueError("Matrix is not full rank")
1105
+
1106
+ U[k, k:], U[kpivot, k:] = U[kpivot, k:], U[k, k:]
1107
+ L[k, :k], L[kpivot, :k] = L[kpivot, :k], L[k, :k]
1108
+ P[k, :], P[kpivot, :] = P[kpivot, :], P[k, :]
1109
+
1110
+ L [k, k] = Ukk = U[k, k]
1111
+ DD[k, k] = oldpivot * Ukk
1112
+
1113
+ for i in range(k + 1, n):
1114
+ L[i, k] = Uik = U[i, k]
1115
+
1116
+ for j in range(k + 1, m):
1117
+ U[i, j] = (Ukk * U[i, j] - U[k, j] * Uik) / oldpivot
1118
+
1119
+ U[i, k] = 0
1120
+
1121
+ oldpivot = Ukk
1122
+
1123
+ DD[n - 1, n - 1] = oldpivot
1124
+
1125
+ return P, L, DD, U
1126
+
1127
+ def _singular_value_decomposition(A):
1128
+ r"""Returns a Condensed Singular Value decomposition.
1129
+
1130
+ Explanation
1131
+ ===========
1132
+
1133
+ A Singular Value decomposition is a decomposition in the form $A = U \Sigma V^H$
1134
+ where
1135
+
1136
+ - $U, V$ are column orthogonal matrix.
1137
+ - $\Sigma$ is a diagonal matrix, where the main diagonal contains singular
1138
+ values of matrix A.
1139
+
1140
+ A column orthogonal matrix satisfies
1141
+ $\mathbb{I} = U^H U$ while a full orthogonal matrix satisfies
1142
+ relation $\mathbb{I} = U U^H = U^H U$ where $\mathbb{I}$ is an identity
1143
+ matrix with matching dimensions.
1144
+
1145
+ For matrices which are not square or are rank-deficient, it is
1146
+ sufficient to return a column orthogonal matrix because augmenting
1147
+ them may introduce redundant computations.
1148
+ In condensed Singular Value Decomposition we only return column orthogonal
1149
+ matrices because of this reason
1150
+
1151
+ If you want to augment the results to return a full orthogonal
1152
+ decomposition, you should use the following procedures.
1153
+
1154
+ - Augment the $U, V$ matrices with columns that are orthogonal to every
1155
+ other columns and make it square.
1156
+ - Augment the $\Sigma$ matrix with zero rows to make it have the same
1157
+ shape as the original matrix.
1158
+
1159
+ The procedure will be illustrated in the examples section.
1160
+
1161
+ Examples
1162
+ ========
1163
+
1164
+ we take a full rank matrix first:
1165
+
1166
+ >>> from sympy import Matrix
1167
+ >>> A = Matrix([[1, 2],[2,1]])
1168
+ >>> U, S, V = A.singular_value_decomposition()
1169
+ >>> U
1170
+ Matrix([
1171
+ [ sqrt(2)/2, sqrt(2)/2],
1172
+ [-sqrt(2)/2, sqrt(2)/2]])
1173
+ >>> S
1174
+ Matrix([
1175
+ [1, 0],
1176
+ [0, 3]])
1177
+ >>> V
1178
+ Matrix([
1179
+ [-sqrt(2)/2, sqrt(2)/2],
1180
+ [ sqrt(2)/2, sqrt(2)/2]])
1181
+
1182
+ If a matrix if square and full rank both U, V
1183
+ are orthogonal in both directions
1184
+
1185
+ >>> U * U.H
1186
+ Matrix([
1187
+ [1, 0],
1188
+ [0, 1]])
1189
+ >>> U.H * U
1190
+ Matrix([
1191
+ [1, 0],
1192
+ [0, 1]])
1193
+
1194
+ >>> V * V.H
1195
+ Matrix([
1196
+ [1, 0],
1197
+ [0, 1]])
1198
+ >>> V.H * V
1199
+ Matrix([
1200
+ [1, 0],
1201
+ [0, 1]])
1202
+ >>> A == U * S * V.H
1203
+ True
1204
+
1205
+ >>> C = Matrix([
1206
+ ... [1, 0, 0, 0, 2],
1207
+ ... [0, 0, 3, 0, 0],
1208
+ ... [0, 0, 0, 0, 0],
1209
+ ... [0, 2, 0, 0, 0],
1210
+ ... ])
1211
+ >>> U, S, V = C.singular_value_decomposition()
1212
+
1213
+ >>> V.H * V
1214
+ Matrix([
1215
+ [1, 0, 0],
1216
+ [0, 1, 0],
1217
+ [0, 0, 1]])
1218
+ >>> V * V.H
1219
+ Matrix([
1220
+ [1/5, 0, 0, 0, 2/5],
1221
+ [ 0, 1, 0, 0, 0],
1222
+ [ 0, 0, 1, 0, 0],
1223
+ [ 0, 0, 0, 0, 0],
1224
+ [2/5, 0, 0, 0, 4/5]])
1225
+
1226
+ If you want to augment the results to be a full orthogonal
1227
+ decomposition, you should augment $V$ with an another orthogonal
1228
+ column.
1229
+
1230
+ You are able to append an arbitrary standard basis that are linearly
1231
+ independent to every other columns and you can run the Gram-Schmidt
1232
+ process to make them augmented as orthogonal basis.
1233
+
1234
+ >>> V_aug = V.row_join(Matrix([[0,0,0,0,1],
1235
+ ... [0,0,0,1,0]]).H)
1236
+ >>> V_aug = V_aug.QRdecomposition()[0]
1237
+ >>> V_aug
1238
+ Matrix([
1239
+ [0, sqrt(5)/5, 0, -2*sqrt(5)/5, 0],
1240
+ [1, 0, 0, 0, 0],
1241
+ [0, 0, 1, 0, 0],
1242
+ [0, 0, 0, 0, 1],
1243
+ [0, 2*sqrt(5)/5, 0, sqrt(5)/5, 0]])
1244
+ >>> V_aug.H * V_aug
1245
+ Matrix([
1246
+ [1, 0, 0, 0, 0],
1247
+ [0, 1, 0, 0, 0],
1248
+ [0, 0, 1, 0, 0],
1249
+ [0, 0, 0, 1, 0],
1250
+ [0, 0, 0, 0, 1]])
1251
+ >>> V_aug * V_aug.H
1252
+ Matrix([
1253
+ [1, 0, 0, 0, 0],
1254
+ [0, 1, 0, 0, 0],
1255
+ [0, 0, 1, 0, 0],
1256
+ [0, 0, 0, 1, 0],
1257
+ [0, 0, 0, 0, 1]])
1258
+
1259
+ Similarly we augment U
1260
+
1261
+ >>> U_aug = U.row_join(Matrix([0,0,1,0]))
1262
+ >>> U_aug = U_aug.QRdecomposition()[0]
1263
+ >>> U_aug
1264
+ Matrix([
1265
+ [0, 1, 0, 0],
1266
+ [0, 0, 1, 0],
1267
+ [0, 0, 0, 1],
1268
+ [1, 0, 0, 0]])
1269
+
1270
+ >>> U_aug.H * U_aug
1271
+ Matrix([
1272
+ [1, 0, 0, 0],
1273
+ [0, 1, 0, 0],
1274
+ [0, 0, 1, 0],
1275
+ [0, 0, 0, 1]])
1276
+ >>> U_aug * U_aug.H
1277
+ Matrix([
1278
+ [1, 0, 0, 0],
1279
+ [0, 1, 0, 0],
1280
+ [0, 0, 1, 0],
1281
+ [0, 0, 0, 1]])
1282
+
1283
+ We add 2 zero columns and one row to S
1284
+
1285
+ >>> S_aug = S.col_join(Matrix([[0,0,0]]))
1286
+ >>> S_aug = S_aug.row_join(Matrix([[0,0,0,0],
1287
+ ... [0,0,0,0]]).H)
1288
+ >>> S_aug
1289
+ Matrix([
1290
+ [2, 0, 0, 0, 0],
1291
+ [0, sqrt(5), 0, 0, 0],
1292
+ [0, 0, 3, 0, 0],
1293
+ [0, 0, 0, 0, 0]])
1294
+
1295
+
1296
+
1297
+ >>> U_aug * S_aug * V_aug.H == C
1298
+ True
1299
+
1300
+ """
1301
+
1302
+ AH = A.H
1303
+ m, n = A.shape
1304
+ if m >= n:
1305
+ V, S = (AH * A).diagonalize()
1306
+
1307
+ ranked = []
1308
+ for i, x in enumerate(S.diagonal()):
1309
+ if not x.is_zero:
1310
+ ranked.append(i)
1311
+
1312
+ V = V[:, ranked]
1313
+
1314
+ Singular_vals = [sqrt(S[i, i]) for i in range(S.rows) if i in ranked]
1315
+
1316
+ S = S.diag(*Singular_vals)
1317
+ V, _ = V.QRdecomposition()
1318
+ U = A * V * S.inv()
1319
+ else:
1320
+ U, S = (A * AH).diagonalize()
1321
+
1322
+ ranked = []
1323
+ for i, x in enumerate(S.diagonal()):
1324
+ if not x.is_zero:
1325
+ ranked.append(i)
1326
+
1327
+ U = U[:, ranked]
1328
+ Singular_vals = [sqrt(S[i, i]) for i in range(S.rows) if i in ranked]
1329
+
1330
+ S = S.diag(*Singular_vals)
1331
+ U, _ = U.QRdecomposition()
1332
+ V = AH * U * S.inv()
1333
+
1334
+ return U, S, V
1335
+
1336
+ def _QRdecomposition_optional(M, normalize=True):
1337
+ def dot(u, v):
1338
+ return u.dot(v, hermitian=True)
1339
+
1340
+ dps = _get_intermediate_simp(expand_mul, expand_mul)
1341
+
1342
+ A = M.as_mutable()
1343
+ ranked = []
1344
+
1345
+ Q = A
1346
+ R = A.zeros(A.cols)
1347
+
1348
+ for j in range(A.cols):
1349
+ for i in range(j):
1350
+ if Q[:, i].is_zero_matrix:
1351
+ continue
1352
+
1353
+ R[i, j] = dot(Q[:, i], Q[:, j]) / dot(Q[:, i], Q[:, i])
1354
+ R[i, j] = dps(R[i, j])
1355
+ Q[:, j] -= Q[:, i] * R[i, j]
1356
+
1357
+ Q[:, j] = dps(Q[:, j])
1358
+ if Q[:, j].is_zero_matrix is not True:
1359
+ ranked.append(j)
1360
+ R[j, j] = M.one
1361
+
1362
+ Q = Q.extract(range(Q.rows), ranked)
1363
+ R = R.extract(ranked, range(R.cols))
1364
+
1365
+ if normalize:
1366
+ # Normalization
1367
+ for i in range(Q.cols):
1368
+ norm = Q[:, i].norm()
1369
+ Q[:, i] /= norm
1370
+ R[i, :] *= norm
1371
+
1372
+ return M.__class__(Q), M.__class__(R)
1373
+
1374
+
1375
+ def _QRdecomposition(M):
1376
+ r"""Returns a QR decomposition.
1377
+
1378
+ Explanation
1379
+ ===========
1380
+
1381
+ A QR decomposition is a decomposition in the form $A = Q R$
1382
+ where
1383
+
1384
+ - $Q$ is a column orthogonal matrix.
1385
+ - $R$ is a upper triangular (trapezoidal) matrix.
1386
+
1387
+ A column orthogonal matrix satisfies
1388
+ $\mathbb{I} = Q^H Q$ while a full orthogonal matrix satisfies
1389
+ relation $\mathbb{I} = Q Q^H = Q^H Q$ where $I$ is an identity
1390
+ matrix with matching dimensions.
1391
+
1392
+ For matrices which are not square or are rank-deficient, it is
1393
+ sufficient to return a column orthogonal matrix because augmenting
1394
+ them may introduce redundant computations.
1395
+ And an another advantage of this is that you can easily inspect the
1396
+ matrix rank by counting the number of columns of $Q$.
1397
+
1398
+ If you want to augment the results to return a full orthogonal
1399
+ decomposition, you should use the following procedures.
1400
+
1401
+ - Augment the $Q$ matrix with columns that are orthogonal to every
1402
+ other columns and make it square.
1403
+ - Augment the $R$ matrix with zero rows to make it have the same
1404
+ shape as the original matrix.
1405
+
1406
+ The procedure will be illustrated in the examples section.
1407
+
1408
+ Examples
1409
+ ========
1410
+
1411
+ A full rank matrix example:
1412
+
1413
+ >>> from sympy import Matrix
1414
+ >>> A = Matrix([[12, -51, 4], [6, 167, -68], [-4, 24, -41]])
1415
+ >>> Q, R = A.QRdecomposition()
1416
+ >>> Q
1417
+ Matrix([
1418
+ [ 6/7, -69/175, -58/175],
1419
+ [ 3/7, 158/175, 6/175],
1420
+ [-2/7, 6/35, -33/35]])
1421
+ >>> R
1422
+ Matrix([
1423
+ [14, 21, -14],
1424
+ [ 0, 175, -70],
1425
+ [ 0, 0, 35]])
1426
+
1427
+ If the matrix is square and full rank, the $Q$ matrix becomes
1428
+ orthogonal in both directions, and needs no augmentation.
1429
+
1430
+ >>> Q * Q.H
1431
+ Matrix([
1432
+ [1, 0, 0],
1433
+ [0, 1, 0],
1434
+ [0, 0, 1]])
1435
+ >>> Q.H * Q
1436
+ Matrix([
1437
+ [1, 0, 0],
1438
+ [0, 1, 0],
1439
+ [0, 0, 1]])
1440
+
1441
+ >>> A == Q*R
1442
+ True
1443
+
1444
+ A rank deficient matrix example:
1445
+
1446
+ >>> A = Matrix([[12, -51, 0], [6, 167, 0], [-4, 24, 0]])
1447
+ >>> Q, R = A.QRdecomposition()
1448
+ >>> Q
1449
+ Matrix([
1450
+ [ 6/7, -69/175],
1451
+ [ 3/7, 158/175],
1452
+ [-2/7, 6/35]])
1453
+ >>> R
1454
+ Matrix([
1455
+ [14, 21, 0],
1456
+ [ 0, 175, 0]])
1457
+
1458
+ QRdecomposition might return a matrix Q that is rectangular.
1459
+ In this case the orthogonality condition might be satisfied as
1460
+ $\mathbb{I} = Q.H*Q$ but not in the reversed product
1461
+ $\mathbb{I} = Q * Q.H$.
1462
+
1463
+ >>> Q.H * Q
1464
+ Matrix([
1465
+ [1, 0],
1466
+ [0, 1]])
1467
+ >>> Q * Q.H
1468
+ Matrix([
1469
+ [27261/30625, 348/30625, -1914/6125],
1470
+ [ 348/30625, 30589/30625, 198/6125],
1471
+ [ -1914/6125, 198/6125, 136/1225]])
1472
+
1473
+ If you want to augment the results to be a full orthogonal
1474
+ decomposition, you should augment $Q$ with an another orthogonal
1475
+ column.
1476
+
1477
+ You are able to append an identity matrix,
1478
+ and you can run the Gram-Schmidt
1479
+ process to make them augmented as orthogonal basis.
1480
+
1481
+ >>> Q_aug = Q.row_join(Matrix.eye(3))
1482
+ >>> Q_aug = Q_aug.QRdecomposition()[0]
1483
+ >>> Q_aug
1484
+ Matrix([
1485
+ [ 6/7, -69/175, 58/175],
1486
+ [ 3/7, 158/175, -6/175],
1487
+ [-2/7, 6/35, 33/35]])
1488
+ >>> Q_aug.H * Q_aug
1489
+ Matrix([
1490
+ [1, 0, 0],
1491
+ [0, 1, 0],
1492
+ [0, 0, 1]])
1493
+ >>> Q_aug * Q_aug.H
1494
+ Matrix([
1495
+ [1, 0, 0],
1496
+ [0, 1, 0],
1497
+ [0, 0, 1]])
1498
+
1499
+ Augmenting the $R$ matrix with zero row is straightforward.
1500
+
1501
+ >>> R_aug = R.col_join(Matrix([[0, 0, 0]]))
1502
+ >>> R_aug
1503
+ Matrix([
1504
+ [14, 21, 0],
1505
+ [ 0, 175, 0],
1506
+ [ 0, 0, 0]])
1507
+ >>> Q_aug * R_aug == A
1508
+ True
1509
+
1510
+ A zero matrix example:
1511
+
1512
+ >>> from sympy import Matrix
1513
+ >>> A = Matrix.zeros(3, 4)
1514
+ >>> Q, R = A.QRdecomposition()
1515
+
1516
+ They may return matrices with zero rows and columns.
1517
+
1518
+ >>> Q
1519
+ Matrix(3, 0, [])
1520
+ >>> R
1521
+ Matrix(0, 4, [])
1522
+ >>> Q*R
1523
+ Matrix([
1524
+ [0, 0, 0, 0],
1525
+ [0, 0, 0, 0],
1526
+ [0, 0, 0, 0]])
1527
+
1528
+ As the same augmentation rule described above, $Q$ can be augmented
1529
+ with columns of an identity matrix and $R$ can be augmented with
1530
+ rows of a zero matrix.
1531
+
1532
+ >>> Q_aug = Q.row_join(Matrix.eye(3))
1533
+ >>> R_aug = R.col_join(Matrix.zeros(3, 4))
1534
+ >>> Q_aug * Q_aug.T
1535
+ Matrix([
1536
+ [1, 0, 0],
1537
+ [0, 1, 0],
1538
+ [0, 0, 1]])
1539
+ >>> R_aug
1540
+ Matrix([
1541
+ [0, 0, 0, 0],
1542
+ [0, 0, 0, 0],
1543
+ [0, 0, 0, 0]])
1544
+ >>> Q_aug * R_aug == A
1545
+ True
1546
+
1547
+ See Also
1548
+ ========
1549
+
1550
+ sympy.matrices.dense.DenseMatrix.cholesky
1551
+ sympy.matrices.dense.DenseMatrix.LDLdecomposition
1552
+ sympy.matrices.matrixbase.MatrixBase.LUdecomposition
1553
+ QRsolve
1554
+ """
1555
+ return _QRdecomposition_optional(M, normalize=True)
1556
+
1557
+ def _upper_hessenberg_decomposition(A):
1558
+ """Converts a matrix into Hessenberg matrix H.
1559
+
1560
+ Returns 2 matrices H, P s.t.
1561
+ $P H P^{T} = A$, where H is an upper hessenberg matrix
1562
+ and P is an orthogonal matrix
1563
+
1564
+ Examples
1565
+ ========
1566
+
1567
+ >>> from sympy import Matrix
1568
+ >>> A = Matrix([
1569
+ ... [1,2,3],
1570
+ ... [-3,5,6],
1571
+ ... [4,-8,9],
1572
+ ... ])
1573
+ >>> H, P = A.upper_hessenberg_decomposition()
1574
+ >>> H
1575
+ Matrix([
1576
+ [1, 6/5, 17/5],
1577
+ [5, 213/25, -134/25],
1578
+ [0, 216/25, 137/25]])
1579
+ >>> P
1580
+ Matrix([
1581
+ [1, 0, 0],
1582
+ [0, -3/5, 4/5],
1583
+ [0, 4/5, 3/5]])
1584
+ >>> P * H * P.H == A
1585
+ True
1586
+
1587
+
1588
+ References
1589
+ ==========
1590
+
1591
+ .. [#] https://mathworld.wolfram.com/HessenbergDecomposition.html
1592
+ """
1593
+
1594
+ M = A.as_mutable()
1595
+
1596
+ if not M.is_square:
1597
+ raise NonSquareMatrixError("Matrix must be square.")
1598
+
1599
+ n = M.cols
1600
+ P = M.eye(n)
1601
+ H = M
1602
+
1603
+ for j in range(n - 2):
1604
+
1605
+ u = H[j + 1:, j]
1606
+
1607
+ if u[1:, :].is_zero_matrix:
1608
+ continue
1609
+
1610
+ if sign(u[0]) != 0:
1611
+ u[0] = u[0] + sign(u[0]) * u.norm()
1612
+ else:
1613
+ u[0] = u[0] + u.norm()
1614
+
1615
+ v = u / u.norm()
1616
+
1617
+ H[j + 1:, :] = H[j + 1:, :] - 2 * v * (v.H * H[j + 1:, :])
1618
+ H[:, j + 1:] = H[:, j + 1:] - (H[:, j + 1:] * (2 * v)) * v.H
1619
+ P[:, j + 1:] = P[:, j + 1:] - (P[:, j + 1:] * (2 * v)) * v.H
1620
+
1621
+ return H, P
lib/python3.12/site-packages/sympy/matrices/eigen.py ADDED
@@ -0,0 +1,1346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from types import FunctionType
2
+ from collections import Counter
3
+
4
+ from mpmath import mp, workprec
5
+ from mpmath.libmp.libmpf import prec_to_dps
6
+
7
+ from sympy.core.sorting import default_sort_key
8
+ from sympy.core.evalf import DEFAULT_MAXPREC, PrecisionExhausted
9
+ from sympy.core.logic import fuzzy_and, fuzzy_or
10
+ from sympy.core.numbers import Float
11
+ from sympy.core.sympify import _sympify
12
+ from sympy.functions.elementary.miscellaneous import sqrt
13
+ from sympy.polys import roots, CRootOf, ZZ, QQ, EX
14
+ from sympy.polys.matrices import DomainMatrix
15
+ from sympy.polys.matrices.eigen import dom_eigenvects, dom_eigenvects_to_sympy
16
+ from sympy.polys.polytools import gcd
17
+
18
+ from .exceptions import MatrixError, NonSquareMatrixError
19
+ from .determinant import _find_reasonable_pivot
20
+
21
+ from .utilities import _iszero, _simplify
22
+
23
+
24
+ __doctest_requires__ = {
25
+ ('_is_indefinite',
26
+ '_is_negative_definite',
27
+ '_is_negative_semidefinite',
28
+ '_is_positive_definite',
29
+ '_is_positive_semidefinite'): ['matplotlib'],
30
+ }
31
+
32
+
33
+ def _eigenvals_eigenvects_mpmath(M):
34
+ norm2 = lambda v: mp.sqrt(sum(i**2 for i in v))
35
+
36
+ v1 = None
37
+ prec = max(x._prec for x in M.atoms(Float))
38
+ eps = 2**-prec
39
+
40
+ while prec < DEFAULT_MAXPREC:
41
+ with workprec(prec):
42
+ A = mp.matrix(M.evalf(n=prec_to_dps(prec)))
43
+ E, ER = mp.eig(A)
44
+ v2 = norm2([i for e in E for i in (mp.re(e), mp.im(e))])
45
+ if v1 is not None and mp.fabs(v1 - v2) < eps:
46
+ return E, ER
47
+ v1 = v2
48
+ prec *= 2
49
+
50
+ # we get here because the next step would have taken us
51
+ # past MAXPREC or because we never took a step; in case
52
+ # of the latter, we refuse to send back a solution since
53
+ # it would not have been verified; we also resist taking
54
+ # a small step to arrive exactly at MAXPREC since then
55
+ # the two calculations might be artificially close.
56
+ raise PrecisionExhausted
57
+
58
+
59
+ def _eigenvals_mpmath(M, multiple=False):
60
+ """Compute eigenvalues using mpmath"""
61
+ E, _ = _eigenvals_eigenvects_mpmath(M)
62
+ result = [_sympify(x) for x in E]
63
+ if multiple:
64
+ return result
65
+ return dict(Counter(result))
66
+
67
+
68
+ def _eigenvects_mpmath(M):
69
+ E, ER = _eigenvals_eigenvects_mpmath(M)
70
+ result = []
71
+ for i in range(M.rows):
72
+ eigenval = _sympify(E[i])
73
+ eigenvect = _sympify(ER[:, i])
74
+ result.append((eigenval, 1, [eigenvect]))
75
+
76
+ return result
77
+
78
+
79
+ # This function is a candidate for caching if it gets implemented for matrices.
80
+ def _eigenvals(
81
+ M, error_when_incomplete=True, *, simplify=False, multiple=False,
82
+ rational=False, **flags):
83
+ r"""Compute eigenvalues of the matrix.
84
+
85
+ Parameters
86
+ ==========
87
+
88
+ error_when_incomplete : bool, optional
89
+ If it is set to ``True``, it will raise an error if not all
90
+ eigenvalues are computed. This is caused by ``roots`` not returning
91
+ a full list of eigenvalues.
92
+
93
+ simplify : bool or function, optional
94
+ If it is set to ``True``, it attempts to return the most
95
+ simplified form of expressions returned by applying default
96
+ simplification method in every routine.
97
+
98
+ If it is set to ``False``, it will skip simplification in this
99
+ particular routine to save computation resources.
100
+
101
+ If a function is passed to, it will attempt to apply
102
+ the particular function as simplification method.
103
+
104
+ rational : bool, optional
105
+ If it is set to ``True``, every floating point numbers would be
106
+ replaced with rationals before computation. It can solve some
107
+ issues of ``roots`` routine not working well with floats.
108
+
109
+ multiple : bool, optional
110
+ If it is set to ``True``, the result will be in the form of a
111
+ list.
112
+
113
+ If it is set to ``False``, the result will be in the form of a
114
+ dictionary.
115
+
116
+ Returns
117
+ =======
118
+
119
+ eigs : list or dict
120
+ Eigenvalues of a matrix. The return format would be specified by
121
+ the key ``multiple``.
122
+
123
+ Raises
124
+ ======
125
+
126
+ MatrixError
127
+ If not enough roots had got computed.
128
+
129
+ NonSquareMatrixError
130
+ If attempted to compute eigenvalues from a non-square matrix.
131
+
132
+ Examples
133
+ ========
134
+
135
+ >>> from sympy import Matrix
136
+ >>> M = Matrix(3, 3, [0, 1, 1, 1, 0, 0, 1, 1, 1])
137
+ >>> M.eigenvals()
138
+ {-1: 1, 0: 1, 2: 1}
139
+
140
+ See Also
141
+ ========
142
+
143
+ MatrixBase.charpoly
144
+ eigenvects
145
+
146
+ Notes
147
+ =====
148
+
149
+ Eigenvalues of a matrix $A$ can be computed by solving a matrix
150
+ equation $\det(A - \lambda I) = 0$
151
+
152
+ It's not always possible to return radical solutions for
153
+ eigenvalues for matrices larger than $4, 4$ shape due to
154
+ Abel-Ruffini theorem.
155
+
156
+ If there is no radical solution is found for the eigenvalue,
157
+ it may return eigenvalues in the form of
158
+ :class:`sympy.polys.rootoftools.ComplexRootOf`.
159
+ """
160
+ if not M:
161
+ if multiple:
162
+ return []
163
+ return {}
164
+
165
+ if not M.is_square:
166
+ raise NonSquareMatrixError("{} must be a square matrix.".format(M))
167
+
168
+ if M._rep.domain not in (ZZ, QQ):
169
+ # Skip this check for ZZ/QQ because it can be slow
170
+ if all(x.is_number for x in M) and M.has(Float):
171
+ return _eigenvals_mpmath(M, multiple=multiple)
172
+
173
+ if rational:
174
+ from sympy.simplify import nsimplify
175
+ M = M.applyfunc(
176
+ lambda x: nsimplify(x, rational=True) if x.has(Float) else x)
177
+
178
+ if multiple:
179
+ return _eigenvals_list(
180
+ M, error_when_incomplete=error_when_incomplete, simplify=simplify,
181
+ **flags)
182
+ return _eigenvals_dict(
183
+ M, error_when_incomplete=error_when_incomplete, simplify=simplify,
184
+ **flags)
185
+
186
+
187
+ eigenvals_error_message = \
188
+ "It is not always possible to express the eigenvalues of a matrix " + \
189
+ "of size 5x5 or higher in radicals. " + \
190
+ "We have CRootOf, but domains other than the rationals are not " + \
191
+ "currently supported. " + \
192
+ "If there are no symbols in the matrix, " + \
193
+ "it should still be possible to compute numeric approximations " + \
194
+ "of the eigenvalues using " + \
195
+ "M.evalf().eigenvals() or M.charpoly().nroots()."
196
+
197
+
198
+ def _eigenvals_list(
199
+ M, error_when_incomplete=True, simplify=False, **flags):
200
+ iblocks = M.strongly_connected_components()
201
+ all_eigs = []
202
+ is_dom = M._rep.domain in (ZZ, QQ)
203
+ for b in iblocks:
204
+
205
+ # Fast path for a 1x1 block:
206
+ if is_dom and len(b) == 1:
207
+ index = b[0]
208
+ val = M[index, index]
209
+ all_eigs.append(val)
210
+ continue
211
+
212
+ block = M[b, b]
213
+
214
+ if isinstance(simplify, FunctionType):
215
+ charpoly = block.charpoly(simplify=simplify)
216
+ else:
217
+ charpoly = block.charpoly()
218
+
219
+ eigs = roots(charpoly, multiple=True, **flags)
220
+
221
+ if len(eigs) != block.rows:
222
+ try:
223
+ eigs = charpoly.all_roots(multiple=True)
224
+ except NotImplementedError:
225
+ if error_when_incomplete:
226
+ raise MatrixError(eigenvals_error_message)
227
+ else:
228
+ eigs = []
229
+
230
+ all_eigs += eigs
231
+
232
+ if not simplify:
233
+ return all_eigs
234
+ if not isinstance(simplify, FunctionType):
235
+ simplify = _simplify
236
+ return [simplify(value) for value in all_eigs]
237
+
238
+
239
+ def _eigenvals_dict(
240
+ M, error_when_incomplete=True, simplify=False, **flags):
241
+ iblocks = M.strongly_connected_components()
242
+ all_eigs = {}
243
+ is_dom = M._rep.domain in (ZZ, QQ)
244
+ for b in iblocks:
245
+
246
+ # Fast path for a 1x1 block:
247
+ if is_dom and len(b) == 1:
248
+ index = b[0]
249
+ val = M[index, index]
250
+ all_eigs[val] = all_eigs.get(val, 0) + 1
251
+ continue
252
+
253
+ block = M[b, b]
254
+
255
+ if isinstance(simplify, FunctionType):
256
+ charpoly = block.charpoly(simplify=simplify)
257
+ else:
258
+ charpoly = block.charpoly()
259
+
260
+ eigs = roots(charpoly, multiple=False, **flags)
261
+
262
+ if sum(eigs.values()) != block.rows:
263
+ try:
264
+ eigs = dict(charpoly.all_roots(multiple=False))
265
+ except NotImplementedError:
266
+ if error_when_incomplete:
267
+ raise MatrixError(eigenvals_error_message)
268
+ else:
269
+ eigs = {}
270
+
271
+ for k, v in eigs.items():
272
+ if k in all_eigs:
273
+ all_eigs[k] += v
274
+ else:
275
+ all_eigs[k] = v
276
+
277
+ if not simplify:
278
+ return all_eigs
279
+ if not isinstance(simplify, FunctionType):
280
+ simplify = _simplify
281
+ return {simplify(key): value for key, value in all_eigs.items()}
282
+
283
+
284
+ def _eigenspace(M, eigenval, iszerofunc=_iszero, simplify=False):
285
+ """Get a basis for the eigenspace for a particular eigenvalue"""
286
+ m = M - M.eye(M.rows) * eigenval
287
+ ret = m.nullspace(iszerofunc=iszerofunc)
288
+
289
+ # The nullspace for a real eigenvalue should be non-trivial.
290
+ # If we didn't find an eigenvector, try once more a little harder
291
+ if len(ret) == 0 and simplify:
292
+ ret = m.nullspace(iszerofunc=iszerofunc, simplify=True)
293
+ if len(ret) == 0:
294
+ raise NotImplementedError(
295
+ "Can't evaluate eigenvector for eigenvalue {}".format(eigenval))
296
+ return ret
297
+
298
+
299
+ def _eigenvects_DOM(M, **kwargs):
300
+ DOM = DomainMatrix.from_Matrix(M, field=True, extension=True)
301
+ DOM = DOM.to_dense()
302
+
303
+ if DOM.domain != EX:
304
+ rational, algebraic = dom_eigenvects(DOM)
305
+ eigenvects = dom_eigenvects_to_sympy(
306
+ rational, algebraic, M.__class__, **kwargs)
307
+ eigenvects = sorted(eigenvects, key=lambda x: default_sort_key(x[0]))
308
+
309
+ return eigenvects
310
+ return None
311
+
312
+
313
+ def _eigenvects_sympy(M, iszerofunc, simplify=True, **flags):
314
+ eigenvals = M.eigenvals(rational=False, **flags)
315
+
316
+ # Make sure that we have all roots in radical form
317
+ for x in eigenvals:
318
+ if x.has(CRootOf):
319
+ raise MatrixError(
320
+ "Eigenvector computation is not implemented if the matrix have "
321
+ "eigenvalues in CRootOf form")
322
+
323
+ eigenvals = sorted(eigenvals.items(), key=default_sort_key)
324
+ ret = []
325
+ for val, mult in eigenvals:
326
+ vects = _eigenspace(M, val, iszerofunc=iszerofunc, simplify=simplify)
327
+ ret.append((val, mult, vects))
328
+ return ret
329
+
330
+
331
+ # This functions is a candidate for caching if it gets implemented for matrices.
332
+ def _eigenvects(M, error_when_incomplete=True, iszerofunc=_iszero, *, chop=False, **flags):
333
+ """Compute eigenvectors of the matrix.
334
+
335
+ Parameters
336
+ ==========
337
+
338
+ error_when_incomplete : bool, optional
339
+ Raise an error when not all eigenvalues are computed. This is
340
+ caused by ``roots`` not returning a full list of eigenvalues.
341
+
342
+ iszerofunc : function, optional
343
+ Specifies a zero testing function to be used in ``rref``.
344
+
345
+ Default value is ``_iszero``, which uses SymPy's naive and fast
346
+ default assumption handler.
347
+
348
+ It can also accept any user-specified zero testing function, if it
349
+ is formatted as a function which accepts a single symbolic argument
350
+ and returns ``True`` if it is tested as zero and ``False`` if it
351
+ is tested as non-zero, and ``None`` if it is undecidable.
352
+
353
+ simplify : bool or function, optional
354
+ If ``True``, ``as_content_primitive()`` will be used to tidy up
355
+ normalization artifacts.
356
+
357
+ It will also be used by the ``nullspace`` routine.
358
+
359
+ chop : bool or positive number, optional
360
+ If the matrix contains any Floats, they will be changed to Rationals
361
+ for computation purposes, but the answers will be returned after
362
+ being evaluated with evalf. The ``chop`` flag is passed to ``evalf``.
363
+ When ``chop=True`` a default precision will be used; a number will
364
+ be interpreted as the desired level of precision.
365
+
366
+ Returns
367
+ =======
368
+
369
+ ret : [(eigenval, multiplicity, eigenspace), ...]
370
+ A ragged list containing tuples of data obtained by ``eigenvals``
371
+ and ``nullspace``.
372
+
373
+ ``eigenspace`` is a list containing the ``eigenvector`` for each
374
+ eigenvalue.
375
+
376
+ ``eigenvector`` is a vector in the form of a ``Matrix``. e.g.
377
+ a vector of length 3 is returned as ``Matrix([a_1, a_2, a_3])``.
378
+
379
+ Raises
380
+ ======
381
+
382
+ NotImplementedError
383
+ If failed to compute nullspace.
384
+
385
+ Examples
386
+ ========
387
+
388
+ >>> from sympy import Matrix
389
+ >>> M = Matrix(3, 3, [0, 1, 1, 1, 0, 0, 1, 1, 1])
390
+ >>> M.eigenvects()
391
+ [(-1, 1, [Matrix([
392
+ [-1],
393
+ [ 1],
394
+ [ 0]])]), (0, 1, [Matrix([
395
+ [ 0],
396
+ [-1],
397
+ [ 1]])]), (2, 1, [Matrix([
398
+ [2/3],
399
+ [1/3],
400
+ [ 1]])])]
401
+
402
+ See Also
403
+ ========
404
+
405
+ eigenvals
406
+ MatrixBase.nullspace
407
+ """
408
+ simplify = flags.get('simplify', True)
409
+ primitive = flags.get('simplify', False)
410
+ flags.pop('simplify', None) # remove this if it's there
411
+ flags.pop('multiple', None) # remove this if it's there
412
+
413
+ if not isinstance(simplify, FunctionType):
414
+ simpfunc = _simplify if simplify else lambda x: x
415
+
416
+ has_floats = M.has(Float)
417
+ if has_floats:
418
+ if all(x.is_number for x in M):
419
+ return _eigenvects_mpmath(M)
420
+ from sympy.simplify import nsimplify
421
+ M = M.applyfunc(lambda x: nsimplify(x, rational=True))
422
+
423
+ ret = _eigenvects_DOM(M)
424
+ if ret is None:
425
+ ret = _eigenvects_sympy(M, iszerofunc, simplify=simplify, **flags)
426
+
427
+ if primitive:
428
+ # if the primitive flag is set, get rid of any common
429
+ # integer denominators
430
+ def denom_clean(l):
431
+ return [(v / gcd(list(v))).applyfunc(simpfunc) for v in l]
432
+
433
+ ret = [(val, mult, denom_clean(es)) for val, mult, es in ret]
434
+
435
+ if has_floats:
436
+ # if we had floats to start with, turn the eigenvectors to floats
437
+ ret = [(val.evalf(chop=chop), mult, [v.evalf(chop=chop) for v in es])
438
+ for val, mult, es in ret]
439
+
440
+ return ret
441
+
442
+
443
+ def _is_diagonalizable_with_eigen(M, reals_only=False):
444
+ """See _is_diagonalizable. This function returns the bool along with the
445
+ eigenvectors to avoid calculating them again in functions like
446
+ ``diagonalize``."""
447
+
448
+ if not M.is_square:
449
+ return False, []
450
+
451
+ eigenvecs = M.eigenvects(simplify=True)
452
+
453
+ for val, mult, basis in eigenvecs:
454
+ if reals_only and not val.is_real: # if we have a complex eigenvalue
455
+ return False, eigenvecs
456
+
457
+ if mult != len(basis): # if the geometric multiplicity doesn't equal the algebraic
458
+ return False, eigenvecs
459
+
460
+ return True, eigenvecs
461
+
462
+ def _is_diagonalizable(M, reals_only=False, **kwargs):
463
+ """Returns ``True`` if a matrix is diagonalizable.
464
+
465
+ Parameters
466
+ ==========
467
+
468
+ reals_only : bool, optional
469
+ If ``True``, it tests whether the matrix can be diagonalized
470
+ to contain only real numbers on the diagonal.
471
+
472
+
473
+ If ``False``, it tests whether the matrix can be diagonalized
474
+ at all, even with numbers that may not be real.
475
+
476
+ Examples
477
+ ========
478
+
479
+ Example of a diagonalizable matrix:
480
+
481
+ >>> from sympy import Matrix
482
+ >>> M = Matrix([[1, 2, 0], [0, 3, 0], [2, -4, 2]])
483
+ >>> M.is_diagonalizable()
484
+ True
485
+
486
+ Example of a non-diagonalizable matrix:
487
+
488
+ >>> M = Matrix([[0, 1], [0, 0]])
489
+ >>> M.is_diagonalizable()
490
+ False
491
+
492
+ Example of a matrix that is diagonalized in terms of non-real entries:
493
+
494
+ >>> M = Matrix([[0, 1], [-1, 0]])
495
+ >>> M.is_diagonalizable(reals_only=False)
496
+ True
497
+ >>> M.is_diagonalizable(reals_only=True)
498
+ False
499
+
500
+ See Also
501
+ ========
502
+
503
+ sympy.matrices.matrixbase.MatrixBase.is_diagonal
504
+ diagonalize
505
+ """
506
+ if not M.is_square:
507
+ return False
508
+
509
+ if all(e.is_real for e in M) and M.is_symmetric():
510
+ return True
511
+
512
+ if all(e.is_complex for e in M) and M.is_hermitian:
513
+ return True
514
+
515
+ return _is_diagonalizable_with_eigen(M, reals_only=reals_only)[0]
516
+
517
+
518
+ #G&VL, Matrix Computations, Algo 5.4.2
519
+ def _householder_vector(x):
520
+ if not x.cols == 1:
521
+ raise ValueError("Input must be a column matrix")
522
+ v = x.copy()
523
+ v_plus = x.copy()
524
+ v_minus = x.copy()
525
+ q = x[0, 0] / abs(x[0, 0])
526
+ norm_x = x.norm()
527
+ v_plus[0, 0] = x[0, 0] + q * norm_x
528
+ v_minus[0, 0] = x[0, 0] - q * norm_x
529
+ if x[1:, 0].norm() == 0:
530
+ bet = 0
531
+ v[0, 0] = 1
532
+ else:
533
+ if v_plus.norm() <= v_minus.norm():
534
+ v = v_plus
535
+ else:
536
+ v = v_minus
537
+ v = v / v[0]
538
+ bet = 2 / (v.norm() ** 2)
539
+ return v, bet
540
+
541
+
542
+ def _bidiagonal_decmp_hholder(M):
543
+ m = M.rows
544
+ n = M.cols
545
+ A = M.as_mutable()
546
+ U, V = A.eye(m), A.eye(n)
547
+ for i in range(min(m, n)):
548
+ v, bet = _householder_vector(A[i:, i])
549
+ hh_mat = A.eye(m - i) - bet * v * v.H
550
+ A[i:, i:] = hh_mat * A[i:, i:]
551
+ temp = A.eye(m)
552
+ temp[i:, i:] = hh_mat
553
+ U = U * temp
554
+ if i + 1 <= n - 2:
555
+ v, bet = _householder_vector(A[i, i+1:].T)
556
+ hh_mat = A.eye(n - i - 1) - bet * v * v.H
557
+ A[i:, i+1:] = A[i:, i+1:] * hh_mat
558
+ temp = A.eye(n)
559
+ temp[i+1:, i+1:] = hh_mat
560
+ V = temp * V
561
+ return U, A, V
562
+
563
+
564
+ def _eval_bidiag_hholder(M):
565
+ m = M.rows
566
+ n = M.cols
567
+ A = M.as_mutable()
568
+ for i in range(min(m, n)):
569
+ v, bet = _householder_vector(A[i:, i])
570
+ hh_mat = A.eye(m-i) - bet * v * v.H
571
+ A[i:, i:] = hh_mat * A[i:, i:]
572
+ if i + 1 <= n - 2:
573
+ v, bet = _householder_vector(A[i, i+1:].T)
574
+ hh_mat = A.eye(n - i - 1) - bet * v * v.H
575
+ A[i:, i+1:] = A[i:, i+1:] * hh_mat
576
+ return A
577
+
578
+
579
+ def _bidiagonal_decomposition(M, upper=True):
580
+ """
581
+ Returns $(U,B,V.H)$ for
582
+
583
+ $$A = UBV^{H}$$
584
+
585
+ where $A$ is the input matrix, and $B$ is its Bidiagonalized form
586
+
587
+ Note: Bidiagonal Computation can hang for symbolic matrices.
588
+
589
+ Parameters
590
+ ==========
591
+
592
+ upper : bool. Whether to do upper bidiagnalization or lower.
593
+ True for upper and False for lower.
594
+
595
+ References
596
+ ==========
597
+
598
+ .. [1] Algorithm 5.4.2, Matrix computations by Golub and Van Loan, 4th edition
599
+ .. [2] Complex Matrix Bidiagonalization, https://github.com/vslobody/Householder-Bidiagonalization
600
+
601
+ """
602
+
603
+ if not isinstance(upper, bool):
604
+ raise ValueError("upper must be a boolean")
605
+
606
+ if upper:
607
+ return _bidiagonal_decmp_hholder(M)
608
+
609
+ X = _bidiagonal_decmp_hholder(M.H)
610
+ return X[2].H, X[1].H, X[0].H
611
+
612
+
613
+ def _bidiagonalize(M, upper=True):
614
+ """
615
+ Returns $B$, the Bidiagonalized form of the input matrix.
616
+
617
+ Note: Bidiagonal Computation can hang for symbolic matrices.
618
+
619
+ Parameters
620
+ ==========
621
+
622
+ upper : bool. Whether to do upper bidiagnalization or lower.
623
+ True for upper and False for lower.
624
+
625
+ References
626
+ ==========
627
+
628
+ .. [1] Algorithm 5.4.2, Matrix computations by Golub and Van Loan, 4th edition
629
+ .. [2] Complex Matrix Bidiagonalization : https://github.com/vslobody/Householder-Bidiagonalization
630
+
631
+ """
632
+
633
+ if not isinstance(upper, bool):
634
+ raise ValueError("upper must be a boolean")
635
+
636
+ if upper:
637
+ return _eval_bidiag_hholder(M)
638
+ return _eval_bidiag_hholder(M.H).H
639
+
640
+
641
+ def _diagonalize(M, reals_only=False, sort=False, normalize=False):
642
+ """
643
+ Return (P, D), where D is diagonal and
644
+
645
+ D = P^-1 * M * P
646
+
647
+ where M is current matrix.
648
+
649
+ Parameters
650
+ ==========
651
+
652
+ reals_only : bool. Whether to throw an error if complex numbers are need
653
+ to diagonalize. (Default: False)
654
+
655
+ sort : bool. Sort the eigenvalues along the diagonal. (Default: False)
656
+
657
+ normalize : bool. If True, normalize the columns of P. (Default: False)
658
+
659
+ Examples
660
+ ========
661
+
662
+ >>> from sympy import Matrix
663
+ >>> M = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2])
664
+ >>> M
665
+ Matrix([
666
+ [1, 2, 0],
667
+ [0, 3, 0],
668
+ [2, -4, 2]])
669
+ >>> (P, D) = M.diagonalize()
670
+ >>> D
671
+ Matrix([
672
+ [1, 0, 0],
673
+ [0, 2, 0],
674
+ [0, 0, 3]])
675
+ >>> P
676
+ Matrix([
677
+ [-1, 0, -1],
678
+ [ 0, 0, -1],
679
+ [ 2, 1, 2]])
680
+ >>> P.inv() * M * P
681
+ Matrix([
682
+ [1, 0, 0],
683
+ [0, 2, 0],
684
+ [0, 0, 3]])
685
+
686
+ See Also
687
+ ========
688
+
689
+ sympy.matrices.matrixbase.MatrixBase.is_diagonal
690
+ is_diagonalizable
691
+ """
692
+
693
+ if not M.is_square:
694
+ raise NonSquareMatrixError()
695
+
696
+ is_diagonalizable, eigenvecs = _is_diagonalizable_with_eigen(M,
697
+ reals_only=reals_only)
698
+
699
+ if not is_diagonalizable:
700
+ raise MatrixError("Matrix is not diagonalizable")
701
+
702
+ if sort:
703
+ eigenvecs = sorted(eigenvecs, key=default_sort_key)
704
+
705
+ p_cols, diag = [], []
706
+
707
+ for val, mult, basis in eigenvecs:
708
+ diag += [val] * mult
709
+ p_cols += basis
710
+
711
+ if normalize:
712
+ p_cols = [v / v.norm() for v in p_cols]
713
+
714
+ return M.hstack(*p_cols), M.diag(*diag)
715
+
716
+
717
+ def _fuzzy_positive_definite(M):
718
+ positive_diagonals = M._has_positive_diagonals()
719
+ if positive_diagonals is False:
720
+ return False
721
+
722
+ if positive_diagonals and M.is_strongly_diagonally_dominant:
723
+ return True
724
+
725
+ return None
726
+
727
+
728
+ def _fuzzy_positive_semidefinite(M):
729
+ nonnegative_diagonals = M._has_nonnegative_diagonals()
730
+ if nonnegative_diagonals is False:
731
+ return False
732
+
733
+ if nonnegative_diagonals and M.is_weakly_diagonally_dominant:
734
+ return True
735
+
736
+ return None
737
+
738
+
739
+ def _is_positive_definite(M):
740
+ if not M.is_hermitian:
741
+ if not M.is_square:
742
+ return False
743
+ M = M + M.H
744
+
745
+ fuzzy = _fuzzy_positive_definite(M)
746
+ if fuzzy is not None:
747
+ return fuzzy
748
+
749
+ return _is_positive_definite_GE(M)
750
+
751
+
752
+ def _is_positive_semidefinite(M):
753
+ if not M.is_hermitian:
754
+ if not M.is_square:
755
+ return False
756
+ M = M + M.H
757
+
758
+ fuzzy = _fuzzy_positive_semidefinite(M)
759
+ if fuzzy is not None:
760
+ return fuzzy
761
+
762
+ return _is_positive_semidefinite_cholesky(M)
763
+
764
+
765
+ def _is_negative_definite(M):
766
+ return _is_positive_definite(-M)
767
+
768
+
769
+ def _is_negative_semidefinite(M):
770
+ return _is_positive_semidefinite(-M)
771
+
772
+
773
+ def _is_indefinite(M):
774
+ if M.is_hermitian:
775
+ eigen = M.eigenvals()
776
+ args1 = [x.is_positive for x in eigen.keys()]
777
+ any_positive = fuzzy_or(args1)
778
+ args2 = [x.is_negative for x in eigen.keys()]
779
+ any_negative = fuzzy_or(args2)
780
+
781
+ return fuzzy_and([any_positive, any_negative])
782
+
783
+ elif M.is_square:
784
+ return (M + M.H).is_indefinite
785
+
786
+ return False
787
+
788
+
789
+ def _is_positive_definite_GE(M):
790
+ """A division-free gaussian elimination method for testing
791
+ positive-definiteness."""
792
+ M = M.as_mutable()
793
+ size = M.rows
794
+
795
+ for i in range(size):
796
+ is_positive = M[i, i].is_positive
797
+ if is_positive is not True:
798
+ return is_positive
799
+ for j in range(i+1, size):
800
+ M[j, i+1:] = M[i, i] * M[j, i+1:] - M[j, i] * M[i, i+1:]
801
+ return True
802
+
803
+
804
+ def _is_positive_semidefinite_cholesky(M):
805
+ """Uses Cholesky factorization with complete pivoting
806
+
807
+ References
808
+ ==========
809
+
810
+ .. [1] http://eprints.ma.man.ac.uk/1199/1/covered/MIMS_ep2008_116.pdf
811
+
812
+ .. [2] https://www.value-at-risk.net/cholesky-factorization/
813
+ """
814
+ M = M.as_mutable()
815
+ for k in range(M.rows):
816
+ diags = [M[i, i] for i in range(k, M.rows)]
817
+ pivot, pivot_val, nonzero, _ = _find_reasonable_pivot(diags)
818
+
819
+ if nonzero:
820
+ return None
821
+
822
+ if pivot is None:
823
+ for i in range(k+1, M.rows):
824
+ for j in range(k, M.cols):
825
+ iszero = M[i, j].is_zero
826
+ if iszero is None:
827
+ return None
828
+ elif iszero is False:
829
+ return False
830
+ return True
831
+
832
+ if M[k, k].is_negative or pivot_val.is_negative:
833
+ return False
834
+ elif not (M[k, k].is_nonnegative and pivot_val.is_nonnegative):
835
+ return None
836
+
837
+ if pivot > 0:
838
+ M.col_swap(k, k+pivot)
839
+ M.row_swap(k, k+pivot)
840
+
841
+ M[k, k] = sqrt(M[k, k])
842
+ M[k, k+1:] /= M[k, k]
843
+ M[k+1:, k+1:] -= M[k, k+1:].H * M[k, k+1:]
844
+
845
+ return M[-1, -1].is_nonnegative
846
+
847
+
848
+ _doc_positive_definite = \
849
+ r"""Finds out the definiteness of a matrix.
850
+
851
+ Explanation
852
+ ===========
853
+
854
+ A square real matrix $A$ is:
855
+
856
+ - A positive definite matrix if $x^T A x > 0$
857
+ for all non-zero real vectors $x$.
858
+ - A positive semidefinite matrix if $x^T A x \geq 0$
859
+ for all non-zero real vectors $x$.
860
+ - A negative definite matrix if $x^T A x < 0$
861
+ for all non-zero real vectors $x$.
862
+ - A negative semidefinite matrix if $x^T A x \leq 0$
863
+ for all non-zero real vectors $x$.
864
+ - An indefinite matrix if there exists non-zero real vectors
865
+ $x, y$ with $x^T A x > 0 > y^T A y$.
866
+
867
+ A square complex matrix $A$ is:
868
+
869
+ - A positive definite matrix if $\text{re}(x^H A x) > 0$
870
+ for all non-zero complex vectors $x$.
871
+ - A positive semidefinite matrix if $\text{re}(x^H A x) \geq 0$
872
+ for all non-zero complex vectors $x$.
873
+ - A negative definite matrix if $\text{re}(x^H A x) < 0$
874
+ for all non-zero complex vectors $x$.
875
+ - A negative semidefinite matrix if $\text{re}(x^H A x) \leq 0$
876
+ for all non-zero complex vectors $x$.
877
+ - An indefinite matrix if there exists non-zero complex vectors
878
+ $x, y$ with $\text{re}(x^H A x) > 0 > \text{re}(y^H A y)$.
879
+
880
+ A matrix need not be symmetric or hermitian to be positive definite.
881
+
882
+ - A real non-symmetric matrix is positive definite if and only if
883
+ $\frac{A + A^T}{2}$ is positive definite.
884
+ - A complex non-hermitian matrix is positive definite if and only if
885
+ $\frac{A + A^H}{2}$ is positive definite.
886
+
887
+ And this extension can apply for all the definitions above.
888
+
889
+ However, for complex cases, you can restrict the definition of
890
+ $\text{re}(x^H A x) > 0$ to $x^H A x > 0$ and require the matrix
891
+ to be hermitian.
892
+ But we do not present this restriction for computation because you
893
+ can check ``M.is_hermitian`` independently with this and use
894
+ the same procedure.
895
+
896
+ Examples
897
+ ========
898
+
899
+ An example of symmetric positive definite matrix:
900
+
901
+ .. plot::
902
+ :context: reset
903
+ :format: doctest
904
+ :include-source: True
905
+
906
+ >>> from sympy import Matrix, symbols
907
+ >>> from sympy.plotting import plot3d
908
+ >>> a, b = symbols('a b')
909
+ >>> x = Matrix([a, b])
910
+
911
+ >>> A = Matrix([[1, 0], [0, 1]])
912
+ >>> A.is_positive_definite
913
+ True
914
+ >>> A.is_positive_semidefinite
915
+ True
916
+
917
+ >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1))
918
+
919
+ An example of symmetric positive semidefinite matrix:
920
+
921
+ .. plot::
922
+ :context: close-figs
923
+ :format: doctest
924
+ :include-source: True
925
+
926
+ >>> A = Matrix([[1, -1], [-1, 1]])
927
+ >>> A.is_positive_definite
928
+ False
929
+ >>> A.is_positive_semidefinite
930
+ True
931
+
932
+ >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1))
933
+
934
+ An example of symmetric negative definite matrix:
935
+
936
+ .. plot::
937
+ :context: close-figs
938
+ :format: doctest
939
+ :include-source: True
940
+
941
+ >>> A = Matrix([[-1, 0], [0, -1]])
942
+ >>> A.is_negative_definite
943
+ True
944
+ >>> A.is_negative_semidefinite
945
+ True
946
+ >>> A.is_indefinite
947
+ False
948
+
949
+ >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1))
950
+
951
+ An example of symmetric indefinite matrix:
952
+
953
+ .. plot::
954
+ :context: close-figs
955
+ :format: doctest
956
+ :include-source: True
957
+
958
+ >>> A = Matrix([[1, 2], [2, -1]])
959
+ >>> A.is_indefinite
960
+ True
961
+
962
+ >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1))
963
+
964
+ An example of non-symmetric positive definite matrix.
965
+
966
+ .. plot::
967
+ :context: close-figs
968
+ :format: doctest
969
+ :include-source: True
970
+
971
+ >>> A = Matrix([[1, 2], [-2, 1]])
972
+ >>> A.is_positive_definite
973
+ True
974
+ >>> A.is_positive_semidefinite
975
+ True
976
+
977
+ >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1))
978
+
979
+ Notes
980
+ =====
981
+
982
+ Although some people trivialize the definition of positive definite
983
+ matrices only for symmetric or hermitian matrices, this restriction
984
+ is not correct because it does not classify all instances of
985
+ positive definite matrices from the definition $x^T A x > 0$ or
986
+ $\text{re}(x^H A x) > 0$.
987
+
988
+ For instance, ``Matrix([[1, 2], [-2, 1]])`` presented in
989
+ the example above is an example of real positive definite matrix
990
+ that is not symmetric.
991
+
992
+ However, since the following formula holds true;
993
+
994
+ .. math::
995
+ \text{re}(x^H A x) > 0 \iff
996
+ \text{re}(x^H \frac{A + A^H}{2} x) > 0
997
+
998
+ We can classify all positive definite matrices that may or may not
999
+ be symmetric or hermitian by transforming the matrix to
1000
+ $\frac{A + A^T}{2}$ or $\frac{A + A^H}{2}$
1001
+ (which is guaranteed to be always real symmetric or complex
1002
+ hermitian) and we can defer most of the studies to symmetric or
1003
+ hermitian positive definite matrices.
1004
+
1005
+ But it is a different problem for the existence of Cholesky
1006
+ decomposition. Because even though a non symmetric or a non
1007
+ hermitian matrix can be positive definite, Cholesky or LDL
1008
+ decomposition does not exist because the decompositions require the
1009
+ matrix to be symmetric or hermitian.
1010
+
1011
+ References
1012
+ ==========
1013
+
1014
+ .. [1] https://en.wikipedia.org/wiki/Definiteness_of_a_matrix#Eigenvalues
1015
+
1016
+ .. [2] https://mathworld.wolfram.com/PositiveDefiniteMatrix.html
1017
+
1018
+ .. [3] Johnson, C. R. "Positive Definite Matrices." Amer.
1019
+ Math. Monthly 77, 259-264 1970.
1020
+ """
1021
+
1022
+ _is_positive_definite.__doc__ = _doc_positive_definite
1023
+ _is_positive_semidefinite.__doc__ = _doc_positive_definite
1024
+ _is_negative_definite.__doc__ = _doc_positive_definite
1025
+ _is_negative_semidefinite.__doc__ = _doc_positive_definite
1026
+ _is_indefinite.__doc__ = _doc_positive_definite
1027
+
1028
+
1029
+ def _jordan_form(M, calc_transform=True, *, chop=False):
1030
+ """Return $(P, J)$ where $J$ is a Jordan block
1031
+ matrix and $P$ is a matrix such that $M = P J P^{-1}$
1032
+
1033
+ Parameters
1034
+ ==========
1035
+
1036
+ calc_transform : bool
1037
+ If ``False``, then only $J$ is returned.
1038
+
1039
+ chop : bool
1040
+ All matrices are converted to exact types when computing
1041
+ eigenvalues and eigenvectors. As a result, there may be
1042
+ approximation errors. If ``chop==True``, these errors
1043
+ will be truncated.
1044
+
1045
+ Examples
1046
+ ========
1047
+
1048
+ >>> from sympy import Matrix
1049
+ >>> M = Matrix([[ 6, 5, -2, -3], [-3, -1, 3, 3], [ 2, 1, -2, -3], [-1, 1, 5, 5]])
1050
+ >>> P, J = M.jordan_form()
1051
+ >>> J
1052
+ Matrix([
1053
+ [2, 1, 0, 0],
1054
+ [0, 2, 0, 0],
1055
+ [0, 0, 2, 1],
1056
+ [0, 0, 0, 2]])
1057
+
1058
+ See Also
1059
+ ========
1060
+
1061
+ jordan_block
1062
+ """
1063
+
1064
+ if not M.is_square:
1065
+ raise NonSquareMatrixError("Only square matrices have Jordan forms")
1066
+
1067
+ mat = M
1068
+ has_floats = M.has(Float)
1069
+
1070
+ if has_floats:
1071
+ try:
1072
+ max_prec = max(term._prec for term in M.values() if isinstance(term, Float))
1073
+ except ValueError:
1074
+ # if no term in the matrix is explicitly a Float calling max()
1075
+ # will throw a error so setting max_prec to default value of 53
1076
+ max_prec = 53
1077
+
1078
+ # setting minimum max_dps to 15 to prevent loss of precision in
1079
+ # matrix containing non evaluated expressions
1080
+ max_dps = max(prec_to_dps(max_prec), 15)
1081
+
1082
+ def restore_floats(*args):
1083
+ """If ``has_floats`` is `True`, cast all ``args`` as
1084
+ matrices of floats."""
1085
+
1086
+ if has_floats:
1087
+ args = [m.evalf(n=max_dps, chop=chop) for m in args]
1088
+ if len(args) == 1:
1089
+ return args[0]
1090
+
1091
+ return args
1092
+
1093
+ # cache calculations for some speedup
1094
+ mat_cache = {}
1095
+
1096
+ def eig_mat(val, pow):
1097
+ """Cache computations of ``(M - val*I)**pow`` for quick
1098
+ retrieval"""
1099
+
1100
+ if (val, pow) in mat_cache:
1101
+ return mat_cache[(val, pow)]
1102
+
1103
+ if (val, pow - 1) in mat_cache:
1104
+ mat_cache[(val, pow)] = mat_cache[(val, pow - 1)].multiply(
1105
+ mat_cache[(val, 1)], dotprodsimp=None)
1106
+ else:
1107
+ mat_cache[(val, pow)] = (mat - val*M.eye(M.rows)).pow(pow)
1108
+
1109
+ return mat_cache[(val, pow)]
1110
+
1111
+ # helper functions
1112
+ def nullity_chain(val, algebraic_multiplicity):
1113
+ """Calculate the sequence [0, nullity(E), nullity(E**2), ...]
1114
+ until it is constant where ``E = M - val*I``"""
1115
+
1116
+ # mat.rank() is faster than computing the null space,
1117
+ # so use the rank-nullity theorem
1118
+ cols = M.cols
1119
+ ret = [0]
1120
+ nullity = cols - eig_mat(val, 1).rank()
1121
+ i = 2
1122
+
1123
+ while nullity != ret[-1]:
1124
+ ret.append(nullity)
1125
+
1126
+ if nullity == algebraic_multiplicity:
1127
+ break
1128
+
1129
+ nullity = cols - eig_mat(val, i).rank()
1130
+ i += 1
1131
+
1132
+ # Due to issues like #7146 and #15872, SymPy sometimes
1133
+ # gives the wrong rank. In this case, raise an error
1134
+ # instead of returning an incorrect matrix
1135
+ if nullity < ret[-1] or nullity > algebraic_multiplicity:
1136
+ raise MatrixError(
1137
+ "SymPy had encountered an inconsistent "
1138
+ "result while computing Jordan block: "
1139
+ "{}".format(M))
1140
+
1141
+ return ret
1142
+
1143
+ def blocks_from_nullity_chain(d):
1144
+ """Return a list of the size of each Jordan block.
1145
+ If d_n is the nullity of E**n, then the number
1146
+ of Jordan blocks of size n is
1147
+
1148
+ 2*d_n - d_(n-1) - d_(n+1)"""
1149
+
1150
+ # d[0] is always the number of columns, so skip past it
1151
+ mid = [2*d[n] - d[n - 1] - d[n + 1] for n in range(1, len(d) - 1)]
1152
+ # d is assumed to plateau with "d[ len(d) ] == d[-1]", so
1153
+ # 2*d_n - d_(n-1) - d_(n+1) == d_n - d_(n-1)
1154
+ end = [d[-1] - d[-2]] if len(d) > 1 else [d[0]]
1155
+
1156
+ return mid + end
1157
+
1158
+ def pick_vec(small_basis, big_basis):
1159
+ """Picks a vector from big_basis that isn't in
1160
+ the subspace spanned by small_basis"""
1161
+
1162
+ if len(small_basis) == 0:
1163
+ return big_basis[0]
1164
+
1165
+ for v in big_basis:
1166
+ _, pivots = M.hstack(*(small_basis + [v])).echelon_form(
1167
+ with_pivots=True)
1168
+
1169
+ if pivots[-1] == len(small_basis):
1170
+ return v
1171
+
1172
+ # roots doesn't like Floats, so replace them with Rationals
1173
+ if has_floats:
1174
+ from sympy.simplify import nsimplify
1175
+ mat = mat.applyfunc(lambda x: nsimplify(x, rational=True))
1176
+
1177
+ # first calculate the jordan block structure
1178
+ eigs = mat.eigenvals()
1179
+
1180
+ # Make sure that we have all roots in radical form
1181
+ for x in eigs:
1182
+ if x.has(CRootOf):
1183
+ raise MatrixError(
1184
+ "Jordan normal form is not implemented if the matrix have "
1185
+ "eigenvalues in CRootOf form")
1186
+
1187
+ # most matrices have distinct eigenvalues
1188
+ # and so are diagonalizable. In this case, don't
1189
+ # do extra work!
1190
+ if len(eigs.keys()) == mat.cols:
1191
+ blocks = sorted(eigs.keys(), key=default_sort_key)
1192
+ jordan_mat = mat.diag(*blocks)
1193
+
1194
+ if not calc_transform:
1195
+ return restore_floats(jordan_mat)
1196
+
1197
+ jordan_basis = [eig_mat(eig, 1).nullspace()[0]
1198
+ for eig in blocks]
1199
+ basis_mat = mat.hstack(*jordan_basis)
1200
+
1201
+ return restore_floats(basis_mat, jordan_mat)
1202
+
1203
+ block_structure = []
1204
+
1205
+ for eig in sorted(eigs.keys(), key=default_sort_key):
1206
+ algebraic_multiplicity = eigs[eig]
1207
+ chain = nullity_chain(eig, algebraic_multiplicity)
1208
+ block_sizes = blocks_from_nullity_chain(chain)
1209
+
1210
+ # if block_sizes = = [a, b, c, ...], then the number of
1211
+ # Jordan blocks of size 1 is a, of size 2 is b, etc.
1212
+ # create an array that has (eig, block_size) with one
1213
+ # entry for each block
1214
+ size_nums = [(i+1, num) for i, num in enumerate(block_sizes)]
1215
+
1216
+ # we expect larger Jordan blocks to come earlier
1217
+ size_nums.reverse()
1218
+
1219
+ block_structure.extend(
1220
+ [(eig, size) for size, num in size_nums for _ in range(num)])
1221
+
1222
+ jordan_form_size = sum(size for eig, size in block_structure)
1223
+
1224
+ if jordan_form_size != M.rows:
1225
+ raise MatrixError(
1226
+ "SymPy had encountered an inconsistent result while "
1227
+ "computing Jordan block. : {}".format(M))
1228
+
1229
+ blocks = (mat.jordan_block(size=size, eigenvalue=eig) for eig, size in block_structure)
1230
+ jordan_mat = mat.diag(*blocks)
1231
+
1232
+ if not calc_transform:
1233
+ return restore_floats(jordan_mat)
1234
+
1235
+ # For each generalized eigenspace, calculate a basis.
1236
+ # We start by looking for a vector in null( (A - eig*I)**n )
1237
+ # which isn't in null( (A - eig*I)**(n-1) ) where n is
1238
+ # the size of the Jordan block
1239
+ #
1240
+ # Ideally we'd just loop through block_structure and
1241
+ # compute each generalized eigenspace. However, this
1242
+ # causes a lot of unneeded computation. Instead, we
1243
+ # go through the eigenvalues separately, since we know
1244
+ # their generalized eigenspaces must have bases that
1245
+ # are linearly independent.
1246
+ jordan_basis = []
1247
+
1248
+ for eig in sorted(eigs.keys(), key=default_sort_key):
1249
+ eig_basis = []
1250
+
1251
+ for block_eig, size in block_structure:
1252
+ if block_eig != eig:
1253
+ continue
1254
+
1255
+ null_big = (eig_mat(eig, size)).nullspace()
1256
+ null_small = (eig_mat(eig, size - 1)).nullspace()
1257
+
1258
+ # we want to pick something that is in the big basis
1259
+ # and not the small, but also something that is independent
1260
+ # of any other generalized eigenvectors from a different
1261
+ # generalized eigenspace sharing the same eigenvalue.
1262
+ vec = pick_vec(null_small + eig_basis, null_big)
1263
+ new_vecs = [eig_mat(eig, i).multiply(vec, dotprodsimp=None)
1264
+ for i in range(size)]
1265
+
1266
+ eig_basis.extend(new_vecs)
1267
+ jordan_basis.extend(reversed(new_vecs))
1268
+
1269
+ basis_mat = mat.hstack(*jordan_basis)
1270
+
1271
+ return restore_floats(basis_mat, jordan_mat)
1272
+
1273
+
1274
+ def _left_eigenvects(M, **flags):
1275
+ """Returns left eigenvectors and eigenvalues.
1276
+
1277
+ This function returns the list of triples (eigenval, multiplicity,
1278
+ basis) for the left eigenvectors. Options are the same as for
1279
+ eigenvects(), i.e. the ``**flags`` arguments gets passed directly to
1280
+ eigenvects().
1281
+
1282
+ Examples
1283
+ ========
1284
+
1285
+ >>> from sympy import Matrix
1286
+ >>> M = Matrix([[0, 1, 1], [1, 0, 0], [1, 1, 1]])
1287
+ >>> M.eigenvects()
1288
+ [(-1, 1, [Matrix([
1289
+ [-1],
1290
+ [ 1],
1291
+ [ 0]])]), (0, 1, [Matrix([
1292
+ [ 0],
1293
+ [-1],
1294
+ [ 1]])]), (2, 1, [Matrix([
1295
+ [2/3],
1296
+ [1/3],
1297
+ [ 1]])])]
1298
+ >>> M.left_eigenvects()
1299
+ [(-1, 1, [Matrix([[-2, 1, 1]])]), (0, 1, [Matrix([[-1, -1, 1]])]), (2,
1300
+ 1, [Matrix([[1, 1, 1]])])]
1301
+
1302
+ """
1303
+
1304
+ eigs = M.transpose().eigenvects(**flags)
1305
+
1306
+ return [(val, mult, [l.transpose() for l in basis]) for val, mult, basis in eigs]
1307
+
1308
+
1309
+ def _singular_values(M):
1310
+ """Compute the singular values of a Matrix
1311
+
1312
+ Examples
1313
+ ========
1314
+
1315
+ >>> from sympy import Matrix, Symbol
1316
+ >>> x = Symbol('x', real=True)
1317
+ >>> M = Matrix([[0, 1, 0], [0, x, 0], [-1, 0, 0]])
1318
+ >>> M.singular_values()
1319
+ [sqrt(x**2 + 1), 1, 0]
1320
+
1321
+ See Also
1322
+ ========
1323
+
1324
+ condition_number
1325
+ """
1326
+
1327
+ if M.rows >= M.cols:
1328
+ valmultpairs = M.H.multiply(M).eigenvals()
1329
+ else:
1330
+ valmultpairs = M.multiply(M.H).eigenvals()
1331
+
1332
+ # Expands result from eigenvals into a simple list
1333
+ vals = []
1334
+
1335
+ for k, v in valmultpairs.items():
1336
+ vals += [sqrt(k)] * v # dangerous! same k in several spots!
1337
+
1338
+ # Pad with zeros if singular values are computed in reverse way,
1339
+ # to give consistent format.
1340
+ if len(vals) < M.cols:
1341
+ vals += [M.zero] * (M.cols - len(vals))
1342
+
1343
+ # sort them in descending order
1344
+ vals.sort(reverse=True, key=default_sort_key)
1345
+
1346
+ return vals
lib/python3.12/site-packages/sympy/matrices/graph.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.utilities.iterables import \
2
+ flatten, connected_components, strongly_connected_components
3
+ from .exceptions import NonSquareMatrixError
4
+
5
+
6
+ def _connected_components(M):
7
+ """Returns the list of connected vertices of the graph when
8
+ a square matrix is viewed as a weighted graph.
9
+
10
+ Examples
11
+ ========
12
+
13
+ >>> from sympy import Matrix
14
+ >>> A = Matrix([
15
+ ... [66, 0, 0, 68, 0, 0, 0, 0, 67],
16
+ ... [0, 55, 0, 0, 0, 0, 54, 53, 0],
17
+ ... [0, 0, 0, 0, 1, 2, 0, 0, 0],
18
+ ... [86, 0, 0, 88, 0, 0, 0, 0, 87],
19
+ ... [0, 0, 10, 0, 11, 12, 0, 0, 0],
20
+ ... [0, 0, 20, 0, 21, 22, 0, 0, 0],
21
+ ... [0, 45, 0, 0, 0, 0, 44, 43, 0],
22
+ ... [0, 35, 0, 0, 0, 0, 34, 33, 0],
23
+ ... [76, 0, 0, 78, 0, 0, 0, 0, 77]])
24
+ >>> A.connected_components()
25
+ [[0, 3, 8], [1, 6, 7], [2, 4, 5]]
26
+
27
+ Notes
28
+ =====
29
+
30
+ Even if any symbolic elements of the matrix can be indeterminate
31
+ to be zero mathematically, this only takes the account of the
32
+ structural aspect of the matrix, so they will considered to be
33
+ nonzero.
34
+ """
35
+ if not M.is_square:
36
+ raise NonSquareMatrixError
37
+
38
+ V = range(M.rows)
39
+ E = sorted(M.todok().keys())
40
+ return connected_components((V, E))
41
+
42
+
43
+ def _strongly_connected_components(M):
44
+ """Returns the list of strongly connected vertices of the graph when
45
+ a square matrix is viewed as a weighted graph.
46
+
47
+ Examples
48
+ ========
49
+
50
+ >>> from sympy import Matrix
51
+ >>> A = Matrix([
52
+ ... [44, 0, 0, 0, 43, 0, 45, 0, 0],
53
+ ... [0, 66, 62, 61, 0, 68, 0, 60, 67],
54
+ ... [0, 0, 22, 21, 0, 0, 0, 20, 0],
55
+ ... [0, 0, 12, 11, 0, 0, 0, 10, 0],
56
+ ... [34, 0, 0, 0, 33, 0, 35, 0, 0],
57
+ ... [0, 86, 82, 81, 0, 88, 0, 80, 87],
58
+ ... [54, 0, 0, 0, 53, 0, 55, 0, 0],
59
+ ... [0, 0, 2, 1, 0, 0, 0, 0, 0],
60
+ ... [0, 76, 72, 71, 0, 78, 0, 70, 77]])
61
+ >>> A.strongly_connected_components()
62
+ [[0, 4, 6], [2, 3, 7], [1, 5, 8]]
63
+ """
64
+ if not M.is_square:
65
+ raise NonSquareMatrixError
66
+
67
+ # RepMatrix uses the more efficient DomainMatrix.scc() method
68
+ rep = getattr(M, '_rep', None)
69
+ if rep is not None:
70
+ return rep.scc()
71
+
72
+ V = range(M.rows)
73
+ E = sorted(M.todok().keys())
74
+ return strongly_connected_components((V, E))
75
+
76
+
77
+ def _connected_components_decomposition(M):
78
+ """Decomposes a square matrix into block diagonal form only
79
+ using the permutations.
80
+
81
+ Explanation
82
+ ===========
83
+
84
+ The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a
85
+ permutation matrix and $B$ is a block diagonal matrix.
86
+
87
+ Returns
88
+ =======
89
+
90
+ P, B : PermutationMatrix, BlockDiagMatrix
91
+ *P* is a permutation matrix for the similarity transform
92
+ as in the explanation. And *B* is the block diagonal matrix of
93
+ the result of the permutation.
94
+
95
+ If you would like to get the diagonal blocks from the
96
+ BlockDiagMatrix, see
97
+ :meth:`~sympy.matrices.expressions.blockmatrix.BlockDiagMatrix.get_diag_blocks`.
98
+
99
+ Examples
100
+ ========
101
+
102
+ >>> from sympy import Matrix, pprint
103
+ >>> A = Matrix([
104
+ ... [66, 0, 0, 68, 0, 0, 0, 0, 67],
105
+ ... [0, 55, 0, 0, 0, 0, 54, 53, 0],
106
+ ... [0, 0, 0, 0, 1, 2, 0, 0, 0],
107
+ ... [86, 0, 0, 88, 0, 0, 0, 0, 87],
108
+ ... [0, 0, 10, 0, 11, 12, 0, 0, 0],
109
+ ... [0, 0, 20, 0, 21, 22, 0, 0, 0],
110
+ ... [0, 45, 0, 0, 0, 0, 44, 43, 0],
111
+ ... [0, 35, 0, 0, 0, 0, 34, 33, 0],
112
+ ... [76, 0, 0, 78, 0, 0, 0, 0, 77]])
113
+
114
+ >>> P, B = A.connected_components_decomposition()
115
+ >>> pprint(P)
116
+ PermutationMatrix((1 3)(2 8 5 7 4 6))
117
+ >>> pprint(B)
118
+ [[66 68 67] ]
119
+ [[ ] ]
120
+ [[86 88 87] 0 0 ]
121
+ [[ ] ]
122
+ [[76 78 77] ]
123
+ [ ]
124
+ [ [55 54 53] ]
125
+ [ [ ] ]
126
+ [ 0 [45 44 43] 0 ]
127
+ [ [ ] ]
128
+ [ [35 34 33] ]
129
+ [ ]
130
+ [ [0 1 2 ]]
131
+ [ [ ]]
132
+ [ 0 0 [10 11 12]]
133
+ [ [ ]]
134
+ [ [20 21 22]]
135
+
136
+ >>> P = P.as_explicit()
137
+ >>> B = B.as_explicit()
138
+ >>> P.T*B*P == A
139
+ True
140
+
141
+ Notes
142
+ =====
143
+
144
+ This problem corresponds to the finding of the connected components
145
+ of a graph, when a matrix is viewed as a weighted graph.
146
+ """
147
+ from sympy.combinatorics.permutations import Permutation
148
+ from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix
149
+ from sympy.matrices.expressions.permutation import PermutationMatrix
150
+
151
+ iblocks = M.connected_components()
152
+
153
+ p = Permutation(flatten(iblocks))
154
+ P = PermutationMatrix(p)
155
+
156
+ blocks = []
157
+ for b in iblocks:
158
+ blocks.append(M[b, b])
159
+ B = BlockDiagMatrix(*blocks)
160
+ return P, B
161
+
162
+
163
+ def _strongly_connected_components_decomposition(M, lower=True):
164
+ """Decomposes a square matrix into block triangular form only
165
+ using the permutations.
166
+
167
+ Explanation
168
+ ===========
169
+
170
+ The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a
171
+ permutation matrix and $B$ is a block diagonal matrix.
172
+
173
+ Parameters
174
+ ==========
175
+
176
+ lower : bool
177
+ Makes $B$ lower block triangular when ``True``.
178
+ Otherwise, makes $B$ upper block triangular.
179
+
180
+ Returns
181
+ =======
182
+
183
+ P, B : PermutationMatrix, BlockMatrix
184
+ *P* is a permutation matrix for the similarity transform
185
+ as in the explanation. And *B* is the block triangular matrix of
186
+ the result of the permutation.
187
+
188
+ Examples
189
+ ========
190
+
191
+ >>> from sympy import Matrix, pprint
192
+ >>> A = Matrix([
193
+ ... [44, 0, 0, 0, 43, 0, 45, 0, 0],
194
+ ... [0, 66, 62, 61, 0, 68, 0, 60, 67],
195
+ ... [0, 0, 22, 21, 0, 0, 0, 20, 0],
196
+ ... [0, 0, 12, 11, 0, 0, 0, 10, 0],
197
+ ... [34, 0, 0, 0, 33, 0, 35, 0, 0],
198
+ ... [0, 86, 82, 81, 0, 88, 0, 80, 87],
199
+ ... [54, 0, 0, 0, 53, 0, 55, 0, 0],
200
+ ... [0, 0, 2, 1, 0, 0, 0, 0, 0],
201
+ ... [0, 76, 72, 71, 0, 78, 0, 70, 77]])
202
+
203
+ A lower block triangular decomposition:
204
+
205
+ >>> P, B = A.strongly_connected_components_decomposition()
206
+ >>> pprint(P)
207
+ PermutationMatrix((8)(1 4 3 2 6)(5 7))
208
+ >>> pprint(B)
209
+ [[44 43 45] [0 0 0] [0 0 0] ]
210
+ [[ ] [ ] [ ] ]
211
+ [[34 33 35] [0 0 0] [0 0 0] ]
212
+ [[ ] [ ] [ ] ]
213
+ [[54 53 55] [0 0 0] [0 0 0] ]
214
+ [ ]
215
+ [ [0 0 0] [22 21 20] [0 0 0] ]
216
+ [ [ ] [ ] [ ] ]
217
+ [ [0 0 0] [12 11 10] [0 0 0] ]
218
+ [ [ ] [ ] [ ] ]
219
+ [ [0 0 0] [2 1 0 ] [0 0 0] ]
220
+ [ ]
221
+ [ [0 0 0] [62 61 60] [66 68 67]]
222
+ [ [ ] [ ] [ ]]
223
+ [ [0 0 0] [82 81 80] [86 88 87]]
224
+ [ [ ] [ ] [ ]]
225
+ [ [0 0 0] [72 71 70] [76 78 77]]
226
+
227
+ >>> P = P.as_explicit()
228
+ >>> B = B.as_explicit()
229
+ >>> P.T * B * P == A
230
+ True
231
+
232
+ An upper block triangular decomposition:
233
+
234
+ >>> P, B = A.strongly_connected_components_decomposition(lower=False)
235
+ >>> pprint(P)
236
+ PermutationMatrix((0 1 5 7 4 3 2 8 6))
237
+ >>> pprint(B)
238
+ [[66 68 67] [62 61 60] [0 0 0] ]
239
+ [[ ] [ ] [ ] ]
240
+ [[86 88 87] [82 81 80] [0 0 0] ]
241
+ [[ ] [ ] [ ] ]
242
+ [[76 78 77] [72 71 70] [0 0 0] ]
243
+ [ ]
244
+ [ [0 0 0] [22 21 20] [0 0 0] ]
245
+ [ [ ] [ ] [ ] ]
246
+ [ [0 0 0] [12 11 10] [0 0 0] ]
247
+ [ [ ] [ ] [ ] ]
248
+ [ [0 0 0] [2 1 0 ] [0 0 0] ]
249
+ [ ]
250
+ [ [0 0 0] [0 0 0] [44 43 45]]
251
+ [ [ ] [ ] [ ]]
252
+ [ [0 0 0] [0 0 0] [34 33 35]]
253
+ [ [ ] [ ] [ ]]
254
+ [ [0 0 0] [0 0 0] [54 53 55]]
255
+
256
+ >>> P = P.as_explicit()
257
+ >>> B = B.as_explicit()
258
+ >>> P.T * B * P == A
259
+ True
260
+ """
261
+ from sympy.combinatorics.permutations import Permutation
262
+ from sympy.matrices.expressions.blockmatrix import BlockMatrix
263
+ from sympy.matrices.expressions.permutation import PermutationMatrix
264
+
265
+ iblocks = M.strongly_connected_components()
266
+ if not lower:
267
+ iblocks = list(reversed(iblocks))
268
+
269
+ p = Permutation(flatten(iblocks))
270
+ P = PermutationMatrix(p)
271
+
272
+ rows = []
273
+ for a in iblocks:
274
+ cols = []
275
+ for b in iblocks:
276
+ cols.append(M[a, b])
277
+ rows.append(cols)
278
+ B = BlockMatrix(rows)
279
+ return P, B
lib/python3.12/site-packages/sympy/matrices/immutable.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from mpmath.matrices.matrices import _matrix
2
+
3
+ from sympy.core import Basic, Dict, Tuple
4
+ from sympy.core.numbers import Integer
5
+ from sympy.core.cache import cacheit
6
+ from sympy.core.sympify import _sympy_converter as sympify_converter, _sympify
7
+ from sympy.matrices.dense import DenseMatrix
8
+ from sympy.matrices.expressions import MatrixExpr
9
+ from sympy.matrices.matrixbase import MatrixBase
10
+ from sympy.matrices.repmatrix import RepMatrix
11
+ from sympy.matrices.sparse import SparseRepMatrix
12
+ from sympy.multipledispatch import dispatch
13
+
14
+
15
+ def sympify_matrix(arg):
16
+ return arg.as_immutable()
17
+
18
+
19
+ sympify_converter[MatrixBase] = sympify_matrix
20
+
21
+
22
+ def sympify_mpmath_matrix(arg):
23
+ mat = [_sympify(x) for x in arg]
24
+ return ImmutableDenseMatrix(arg.rows, arg.cols, mat)
25
+
26
+
27
+ sympify_converter[_matrix] = sympify_mpmath_matrix
28
+
29
+
30
+ class ImmutableRepMatrix(RepMatrix, MatrixExpr): # type: ignore
31
+ """Immutable matrix based on RepMatrix
32
+
33
+ Uses DomainMAtrix as the internal representation.
34
+ """
35
+
36
+ #
37
+ # This is a subclass of RepMatrix that adds/overrides some methods to make
38
+ # the instances Basic and immutable. ImmutableRepMatrix is a superclass for
39
+ # both ImmutableDenseMatrix and ImmutableSparseMatrix.
40
+ #
41
+
42
+ def __new__(cls, *args, **kwargs):
43
+ return cls._new(*args, **kwargs)
44
+
45
+ __hash__ = MatrixExpr.__hash__
46
+
47
+ def copy(self):
48
+ return self
49
+
50
+ @property
51
+ def cols(self):
52
+ return self._cols
53
+
54
+ @property
55
+ def rows(self):
56
+ return self._rows
57
+
58
+ @property
59
+ def shape(self):
60
+ return self._rows, self._cols
61
+
62
+ def as_immutable(self):
63
+ return self
64
+
65
+ def _entry(self, i, j, **kwargs):
66
+ return self[i, j]
67
+
68
+ def __setitem__(self, *args):
69
+ raise TypeError("Cannot set values of {}".format(self.__class__))
70
+
71
+ def is_diagonalizable(self, reals_only=False, **kwargs):
72
+ return super().is_diagonalizable(
73
+ reals_only=reals_only, **kwargs)
74
+
75
+ is_diagonalizable.__doc__ = SparseRepMatrix.is_diagonalizable.__doc__
76
+ is_diagonalizable = cacheit(is_diagonalizable)
77
+
78
+ def analytic_func(self, f, x):
79
+ return self.as_mutable().analytic_func(f, x).as_immutable()
80
+
81
+
82
+ class ImmutableDenseMatrix(DenseMatrix, ImmutableRepMatrix): # type: ignore
83
+ """Create an immutable version of a matrix.
84
+
85
+ Examples
86
+ ========
87
+
88
+ >>> from sympy import eye, ImmutableMatrix
89
+ >>> ImmutableMatrix(eye(3))
90
+ Matrix([
91
+ [1, 0, 0],
92
+ [0, 1, 0],
93
+ [0, 0, 1]])
94
+ >>> _[0, 0] = 42
95
+ Traceback (most recent call last):
96
+ ...
97
+ TypeError: Cannot set values of ImmutableDenseMatrix
98
+ """
99
+
100
+ # MatrixExpr is set as NotIterable, but we want explicit matrices to be
101
+ # iterable
102
+ _iterable = True
103
+ _class_priority = 8
104
+ _op_priority = 10.001
105
+
106
+ @classmethod
107
+ def _new(cls, *args, **kwargs):
108
+ if len(args) == 1 and isinstance(args[0], ImmutableDenseMatrix):
109
+ return args[0]
110
+ if kwargs.get('copy', True) is False:
111
+ if len(args) != 3:
112
+ raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]")
113
+ rows, cols, flat_list = args
114
+ else:
115
+ rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs)
116
+ flat_list = list(flat_list) # create a shallow copy
117
+
118
+ rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list)
119
+
120
+ return cls._fromrep(rep)
121
+
122
+ @classmethod
123
+ def _fromrep(cls, rep):
124
+ rows, cols = rep.shape
125
+ flat_list = rep.to_sympy().to_list_flat()
126
+ obj = Basic.__new__(cls,
127
+ Integer(rows),
128
+ Integer(cols),
129
+ Tuple(*flat_list, sympify=False))
130
+ obj._rows = rows
131
+ obj._cols = cols
132
+ obj._rep = rep
133
+ return obj
134
+
135
+
136
+ # make sure ImmutableDenseMatrix is aliased as ImmutableMatrix
137
+ ImmutableMatrix = ImmutableDenseMatrix
138
+
139
+
140
+ class ImmutableSparseMatrix(SparseRepMatrix, ImmutableRepMatrix): # type:ignore
141
+ """Create an immutable version of a sparse matrix.
142
+
143
+ Examples
144
+ ========
145
+
146
+ >>> from sympy import eye, ImmutableSparseMatrix
147
+ >>> ImmutableSparseMatrix(1, 1, {})
148
+ Matrix([[0]])
149
+ >>> ImmutableSparseMatrix(eye(3))
150
+ Matrix([
151
+ [1, 0, 0],
152
+ [0, 1, 0],
153
+ [0, 0, 1]])
154
+ >>> _[0, 0] = 42
155
+ Traceback (most recent call last):
156
+ ...
157
+ TypeError: Cannot set values of ImmutableSparseMatrix
158
+ >>> _.shape
159
+ (3, 3)
160
+ """
161
+ is_Matrix = True
162
+ _class_priority = 9
163
+
164
+ @classmethod
165
+ def _new(cls, *args, **kwargs):
166
+ rows, cols, smat = cls._handle_creation_inputs(*args, **kwargs)
167
+
168
+ rep = cls._smat_to_DomainMatrix(rows, cols, smat)
169
+
170
+ return cls._fromrep(rep)
171
+
172
+ @classmethod
173
+ def _fromrep(cls, rep):
174
+ rows, cols = rep.shape
175
+ smat = rep.to_sympy().to_dok()
176
+ obj = Basic.__new__(cls, Integer(rows), Integer(cols), Dict(smat))
177
+ obj._rows = rows
178
+ obj._cols = cols
179
+ obj._rep = rep
180
+ return obj
181
+
182
+
183
+ @dispatch(ImmutableDenseMatrix, ImmutableDenseMatrix)
184
+ def _eval_is_eq(lhs, rhs): # noqa:F811
185
+ """Helper method for Equality with matrices.sympy.
186
+
187
+ Relational automatically converts matrices to ImmutableDenseMatrix
188
+ instances, so this method only applies here. Returns True if the
189
+ matrices are definitively the same, False if they are definitively
190
+ different, and None if undetermined (e.g. if they contain Symbols).
191
+ Returning None triggers default handling of Equalities.
192
+
193
+ """
194
+ if lhs.shape != rhs.shape:
195
+ return False
196
+ return (lhs - rhs).is_zero_matrix
lib/python3.12/site-packages/sympy/matrices/matrices.py ADDED
@@ -0,0 +1,687 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # A module consisting of deprecated matrix classes. New code should not be
3
+ # added here.
4
+ #
5
+ from sympy.core.basic import Basic
6
+ from sympy.core.symbol import Dummy
7
+
8
+ from .common import MatrixCommon
9
+
10
+ from .exceptions import NonSquareMatrixError
11
+
12
+ from .utilities import _iszero, _is_zero_after_expand_mul, _simplify
13
+
14
+ from .determinant import (
15
+ _find_reasonable_pivot, _find_reasonable_pivot_naive,
16
+ _adjugate, _charpoly, _cofactor, _cofactor_matrix, _per,
17
+ _det, _det_bareiss, _det_berkowitz, _det_bird, _det_laplace, _det_LU,
18
+ _minor, _minor_submatrix)
19
+
20
+ from .reductions import _is_echelon, _echelon_form, _rank, _rref
21
+ from .subspaces import _columnspace, _nullspace, _rowspace, _orthogonalize
22
+
23
+ from .eigen import (
24
+ _eigenvals, _eigenvects,
25
+ _bidiagonalize, _bidiagonal_decomposition,
26
+ _is_diagonalizable, _diagonalize,
27
+ _is_positive_definite, _is_positive_semidefinite,
28
+ _is_negative_definite, _is_negative_semidefinite, _is_indefinite,
29
+ _jordan_form, _left_eigenvects, _singular_values)
30
+
31
+
32
+ # This class was previously defined in this module, but was moved to
33
+ # sympy.matrices.matrixbase. We import it here for backwards compatibility in
34
+ # case someone was importing it from here.
35
+ from .matrixbase import MatrixBase
36
+
37
+
38
+ __doctest_requires__ = {
39
+ ('MatrixEigen.is_indefinite',
40
+ 'MatrixEigen.is_negative_definite',
41
+ 'MatrixEigen.is_negative_semidefinite',
42
+ 'MatrixEigen.is_positive_definite',
43
+ 'MatrixEigen.is_positive_semidefinite'): ['matplotlib'],
44
+ }
45
+
46
+
47
+ class MatrixDeterminant(MatrixCommon):
48
+ """Provides basic matrix determinant operations. Should not be instantiated
49
+ directly. See ``determinant.py`` for their implementations."""
50
+
51
+ def _eval_det_bareiss(self, iszerofunc=_is_zero_after_expand_mul):
52
+ return _det_bareiss(self, iszerofunc=iszerofunc)
53
+
54
+ def _eval_det_berkowitz(self):
55
+ return _det_berkowitz(self)
56
+
57
+ def _eval_det_lu(self, iszerofunc=_iszero, simpfunc=None):
58
+ return _det_LU(self, iszerofunc=iszerofunc, simpfunc=simpfunc)
59
+
60
+ def _eval_det_bird(self):
61
+ return _det_bird(self)
62
+
63
+ def _eval_det_laplace(self):
64
+ return _det_laplace(self)
65
+
66
+ def _eval_determinant(self): # for expressions.determinant.Determinant
67
+ return _det(self)
68
+
69
+ def adjugate(self, method="berkowitz"):
70
+ return _adjugate(self, method=method)
71
+
72
+ def charpoly(self, x='lambda', simplify=_simplify):
73
+ return _charpoly(self, x=x, simplify=simplify)
74
+
75
+ def cofactor(self, i, j, method="berkowitz"):
76
+ return _cofactor(self, i, j, method=method)
77
+
78
+ def cofactor_matrix(self, method="berkowitz"):
79
+ return _cofactor_matrix(self, method=method)
80
+
81
+ def det(self, method="bareiss", iszerofunc=None):
82
+ return _det(self, method=method, iszerofunc=iszerofunc)
83
+
84
+ def per(self):
85
+ return _per(self)
86
+
87
+ def minor(self, i, j, method="berkowitz"):
88
+ return _minor(self, i, j, method=method)
89
+
90
+ def minor_submatrix(self, i, j):
91
+ return _minor_submatrix(self, i, j)
92
+
93
+ _find_reasonable_pivot.__doc__ = _find_reasonable_pivot.__doc__
94
+ _find_reasonable_pivot_naive.__doc__ = _find_reasonable_pivot_naive.__doc__
95
+ _eval_det_bareiss.__doc__ = _det_bareiss.__doc__
96
+ _eval_det_berkowitz.__doc__ = _det_berkowitz.__doc__
97
+ _eval_det_bird.__doc__ = _det_bird.__doc__
98
+ _eval_det_laplace.__doc__ = _det_laplace.__doc__
99
+ _eval_det_lu.__doc__ = _det_LU.__doc__
100
+ _eval_determinant.__doc__ = _det.__doc__
101
+ adjugate.__doc__ = _adjugate.__doc__
102
+ charpoly.__doc__ = _charpoly.__doc__
103
+ cofactor.__doc__ = _cofactor.__doc__
104
+ cofactor_matrix.__doc__ = _cofactor_matrix.__doc__
105
+ det.__doc__ = _det.__doc__
106
+ per.__doc__ = _per.__doc__
107
+ minor.__doc__ = _minor.__doc__
108
+ minor_submatrix.__doc__ = _minor_submatrix.__doc__
109
+
110
+
111
+ class MatrixReductions(MatrixDeterminant):
112
+ """Provides basic matrix row/column operations. Should not be instantiated
113
+ directly. See ``reductions.py`` for some of their implementations."""
114
+
115
+ def echelon_form(self, iszerofunc=_iszero, simplify=False, with_pivots=False):
116
+ return _echelon_form(self, iszerofunc=iszerofunc, simplify=simplify,
117
+ with_pivots=with_pivots)
118
+
119
+ @property
120
+ def is_echelon(self):
121
+ return _is_echelon(self)
122
+
123
+ def rank(self, iszerofunc=_iszero, simplify=False):
124
+ return _rank(self, iszerofunc=iszerofunc, simplify=simplify)
125
+
126
+ def rref_rhs(self, rhs):
127
+ """Return reduced row-echelon form of matrix, matrix showing
128
+ rhs after reduction steps. ``rhs`` must have the same number
129
+ of rows as ``self``.
130
+
131
+ Examples
132
+ ========
133
+
134
+ >>> from sympy import Matrix, symbols
135
+ >>> r1, r2 = symbols('r1 r2')
136
+ >>> Matrix([[1, 1], [2, 1]]).rref_rhs(Matrix([r1, r2]))
137
+ (Matrix([
138
+ [1, 0],
139
+ [0, 1]]), Matrix([
140
+ [ -r1 + r2],
141
+ [2*r1 - r2]]))
142
+ """
143
+ r, _ = _rref(self.hstack(self, self.eye(self.rows), rhs))
144
+ return r[:, :self.cols], r[:, -rhs.cols:]
145
+
146
+ def rref(self, iszerofunc=_iszero, simplify=False, pivots=True,
147
+ normalize_last=True):
148
+ return _rref(self, iszerofunc=iszerofunc, simplify=simplify,
149
+ pivots=pivots, normalize_last=normalize_last)
150
+
151
+ echelon_form.__doc__ = _echelon_form.__doc__
152
+ is_echelon.__doc__ = _is_echelon.__doc__
153
+ rank.__doc__ = _rank.__doc__
154
+ rref.__doc__ = _rref.__doc__
155
+
156
+ def _normalize_op_args(self, op, col, k, col1, col2, error_str="col"):
157
+ """Validate the arguments for a row/column operation. ``error_str``
158
+ can be one of "row" or "col" depending on the arguments being parsed."""
159
+ if op not in ["n->kn", "n<->m", "n->n+km"]:
160
+ raise ValueError("Unknown {} operation '{}'. Valid col operations "
161
+ "are 'n->kn', 'n<->m', 'n->n+km'".format(error_str, op))
162
+
163
+ # define self_col according to error_str
164
+ self_cols = self.cols if error_str == 'col' else self.rows
165
+
166
+ # normalize and validate the arguments
167
+ if op == "n->kn":
168
+ col = col if col is not None else col1
169
+ if col is None or k is None:
170
+ raise ValueError("For a {0} operation 'n->kn' you must provide the "
171
+ "kwargs `{0}` and `k`".format(error_str))
172
+ if not 0 <= col < self_cols:
173
+ raise ValueError("This matrix does not have a {} '{}'".format(error_str, col))
174
+
175
+ elif op == "n<->m":
176
+ # we need two cols to swap. It does not matter
177
+ # how they were specified, so gather them together and
178
+ # remove `None`
179
+ cols = {col, k, col1, col2}.difference([None])
180
+ if len(cols) > 2:
181
+ # maybe the user left `k` by mistake?
182
+ cols = {col, col1, col2}.difference([None])
183
+ if len(cols) != 2:
184
+ raise ValueError("For a {0} operation 'n<->m' you must provide the "
185
+ "kwargs `{0}1` and `{0}2`".format(error_str))
186
+ col1, col2 = cols
187
+ if not 0 <= col1 < self_cols:
188
+ raise ValueError("This matrix does not have a {} '{}'".format(error_str, col1))
189
+ if not 0 <= col2 < self_cols:
190
+ raise ValueError("This matrix does not have a {} '{}'".format(error_str, col2))
191
+
192
+ elif op == "n->n+km":
193
+ col = col1 if col is None else col
194
+ col2 = col1 if col2 is None else col2
195
+ if col is None or col2 is None or k is None:
196
+ raise ValueError("For a {0} operation 'n->n+km' you must provide the "
197
+ "kwargs `{0}`, `k`, and `{0}2`".format(error_str))
198
+ if col == col2:
199
+ raise ValueError("For a {0} operation 'n->n+km' `{0}` and `{0}2` must "
200
+ "be different.".format(error_str))
201
+ if not 0 <= col < self_cols:
202
+ raise ValueError("This matrix does not have a {} '{}'".format(error_str, col))
203
+ if not 0 <= col2 < self_cols:
204
+ raise ValueError("This matrix does not have a {} '{}'".format(error_str, col2))
205
+
206
+ else:
207
+ raise ValueError('invalid operation %s' % repr(op))
208
+
209
+ return op, col, k, col1, col2
210
+
211
+ def _eval_col_op_multiply_col_by_const(self, col, k):
212
+ def entry(i, j):
213
+ if j == col:
214
+ return k * self[i, j]
215
+ return self[i, j]
216
+ return self._new(self.rows, self.cols, entry)
217
+
218
+ def _eval_col_op_swap(self, col1, col2):
219
+ def entry(i, j):
220
+ if j == col1:
221
+ return self[i, col2]
222
+ elif j == col2:
223
+ return self[i, col1]
224
+ return self[i, j]
225
+ return self._new(self.rows, self.cols, entry)
226
+
227
+ def _eval_col_op_add_multiple_to_other_col(self, col, k, col2):
228
+ def entry(i, j):
229
+ if j == col:
230
+ return self[i, j] + k * self[i, col2]
231
+ return self[i, j]
232
+ return self._new(self.rows, self.cols, entry)
233
+
234
+ def _eval_row_op_swap(self, row1, row2):
235
+ def entry(i, j):
236
+ if i == row1:
237
+ return self[row2, j]
238
+ elif i == row2:
239
+ return self[row1, j]
240
+ return self[i, j]
241
+ return self._new(self.rows, self.cols, entry)
242
+
243
+ def _eval_row_op_multiply_row_by_const(self, row, k):
244
+ def entry(i, j):
245
+ if i == row:
246
+ return k * self[i, j]
247
+ return self[i, j]
248
+ return self._new(self.rows, self.cols, entry)
249
+
250
+ def _eval_row_op_add_multiple_to_other_row(self, row, k, row2):
251
+ def entry(i, j):
252
+ if i == row:
253
+ return self[i, j] + k * self[row2, j]
254
+ return self[i, j]
255
+ return self._new(self.rows, self.cols, entry)
256
+
257
+ def elementary_col_op(self, op="n->kn", col=None, k=None, col1=None, col2=None):
258
+ """Performs the elementary column operation `op`.
259
+
260
+ `op` may be one of
261
+
262
+ * ``"n->kn"`` (column n goes to k*n)
263
+ * ``"n<->m"`` (swap column n and column m)
264
+ * ``"n->n+km"`` (column n goes to column n + k*column m)
265
+
266
+ Parameters
267
+ ==========
268
+
269
+ op : string; the elementary row operation
270
+ col : the column to apply the column operation
271
+ k : the multiple to apply in the column operation
272
+ col1 : one column of a column swap
273
+ col2 : second column of a column swap or column "m" in the column operation
274
+ "n->n+km"
275
+ """
276
+
277
+ op, col, k, col1, col2 = self._normalize_op_args(op, col, k, col1, col2, "col")
278
+
279
+ # now that we've validated, we're all good to dispatch
280
+ if op == "n->kn":
281
+ return self._eval_col_op_multiply_col_by_const(col, k)
282
+ if op == "n<->m":
283
+ return self._eval_col_op_swap(col1, col2)
284
+ if op == "n->n+km":
285
+ return self._eval_col_op_add_multiple_to_other_col(col, k, col2)
286
+
287
+ def elementary_row_op(self, op="n->kn", row=None, k=None, row1=None, row2=None):
288
+ """Performs the elementary row operation `op`.
289
+
290
+ `op` may be one of
291
+
292
+ * ``"n->kn"`` (row n goes to k*n)
293
+ * ``"n<->m"`` (swap row n and row m)
294
+ * ``"n->n+km"`` (row n goes to row n + k*row m)
295
+
296
+ Parameters
297
+ ==========
298
+
299
+ op : string; the elementary row operation
300
+ row : the row to apply the row operation
301
+ k : the multiple to apply in the row operation
302
+ row1 : one row of a row swap
303
+ row2 : second row of a row swap or row "m" in the row operation
304
+ "n->n+km"
305
+ """
306
+
307
+ op, row, k, row1, row2 = self._normalize_op_args(op, row, k, row1, row2, "row")
308
+
309
+ # now that we've validated, we're all good to dispatch
310
+ if op == "n->kn":
311
+ return self._eval_row_op_multiply_row_by_const(row, k)
312
+ if op == "n<->m":
313
+ return self._eval_row_op_swap(row1, row2)
314
+ if op == "n->n+km":
315
+ return self._eval_row_op_add_multiple_to_other_row(row, k, row2)
316
+
317
+
318
+ class MatrixSubspaces(MatrixReductions):
319
+ """Provides methods relating to the fundamental subspaces of a matrix.
320
+ Should not be instantiated directly. See ``subspaces.py`` for their
321
+ implementations."""
322
+
323
+ def columnspace(self, simplify=False):
324
+ return _columnspace(self, simplify=simplify)
325
+
326
+ def nullspace(self, simplify=False, iszerofunc=_iszero):
327
+ return _nullspace(self, simplify=simplify, iszerofunc=iszerofunc)
328
+
329
+ def rowspace(self, simplify=False):
330
+ return _rowspace(self, simplify=simplify)
331
+
332
+ # This is a classmethod but is converted to such later in order to allow
333
+ # assignment of __doc__ since that does not work for already wrapped
334
+ # classmethods in Python 3.6.
335
+ def orthogonalize(cls, *vecs, **kwargs):
336
+ return _orthogonalize(cls, *vecs, **kwargs)
337
+
338
+ columnspace.__doc__ = _columnspace.__doc__
339
+ nullspace.__doc__ = _nullspace.__doc__
340
+ rowspace.__doc__ = _rowspace.__doc__
341
+ orthogonalize.__doc__ = _orthogonalize.__doc__
342
+
343
+ orthogonalize = classmethod(orthogonalize) # type:ignore
344
+
345
+
346
+ class MatrixEigen(MatrixSubspaces):
347
+ """Provides basic matrix eigenvalue/vector operations.
348
+ Should not be instantiated directly. See ``eigen.py`` for their
349
+ implementations."""
350
+
351
+ def eigenvals(self, error_when_incomplete=True, **flags):
352
+ return _eigenvals(self, error_when_incomplete=error_when_incomplete, **flags)
353
+
354
+ def eigenvects(self, error_when_incomplete=True, iszerofunc=_iszero, **flags):
355
+ return _eigenvects(self, error_when_incomplete=error_when_incomplete,
356
+ iszerofunc=iszerofunc, **flags)
357
+
358
+ def is_diagonalizable(self, reals_only=False, **kwargs):
359
+ return _is_diagonalizable(self, reals_only=reals_only, **kwargs)
360
+
361
+ def diagonalize(self, reals_only=False, sort=False, normalize=False):
362
+ return _diagonalize(self, reals_only=reals_only, sort=sort,
363
+ normalize=normalize)
364
+
365
+ def bidiagonalize(self, upper=True):
366
+ return _bidiagonalize(self, upper=upper)
367
+
368
+ def bidiagonal_decomposition(self, upper=True):
369
+ return _bidiagonal_decomposition(self, upper=upper)
370
+
371
+ @property
372
+ def is_positive_definite(self):
373
+ return _is_positive_definite(self)
374
+
375
+ @property
376
+ def is_positive_semidefinite(self):
377
+ return _is_positive_semidefinite(self)
378
+
379
+ @property
380
+ def is_negative_definite(self):
381
+ return _is_negative_definite(self)
382
+
383
+ @property
384
+ def is_negative_semidefinite(self):
385
+ return _is_negative_semidefinite(self)
386
+
387
+ @property
388
+ def is_indefinite(self):
389
+ return _is_indefinite(self)
390
+
391
+ def jordan_form(self, calc_transform=True, **kwargs):
392
+ return _jordan_form(self, calc_transform=calc_transform, **kwargs)
393
+
394
+ def left_eigenvects(self, **flags):
395
+ return _left_eigenvects(self, **flags)
396
+
397
+ def singular_values(self):
398
+ return _singular_values(self)
399
+
400
+ eigenvals.__doc__ = _eigenvals.__doc__
401
+ eigenvects.__doc__ = _eigenvects.__doc__
402
+ is_diagonalizable.__doc__ = _is_diagonalizable.__doc__
403
+ diagonalize.__doc__ = _diagonalize.__doc__
404
+ is_positive_definite.__doc__ = _is_positive_definite.__doc__
405
+ is_positive_semidefinite.__doc__ = _is_positive_semidefinite.__doc__
406
+ is_negative_definite.__doc__ = _is_negative_definite.__doc__
407
+ is_negative_semidefinite.__doc__ = _is_negative_semidefinite.__doc__
408
+ is_indefinite.__doc__ = _is_indefinite.__doc__
409
+ jordan_form.__doc__ = _jordan_form.__doc__
410
+ left_eigenvects.__doc__ = _left_eigenvects.__doc__
411
+ singular_values.__doc__ = _singular_values.__doc__
412
+ bidiagonalize.__doc__ = _bidiagonalize.__doc__
413
+ bidiagonal_decomposition.__doc__ = _bidiagonal_decomposition.__doc__
414
+
415
+
416
+ class MatrixCalculus(MatrixCommon):
417
+ """Provides calculus-related matrix operations."""
418
+
419
+ def diff(self, *args, evaluate=True, **kwargs):
420
+ """Calculate the derivative of each element in the matrix.
421
+
422
+ Examples
423
+ ========
424
+
425
+ >>> from sympy import Matrix
426
+ >>> from sympy.abc import x, y
427
+ >>> M = Matrix([[x, y], [1, 0]])
428
+ >>> M.diff(x)
429
+ Matrix([
430
+ [1, 0],
431
+ [0, 0]])
432
+
433
+ See Also
434
+ ========
435
+
436
+ integrate
437
+ limit
438
+ """
439
+ # XXX this should be handled here rather than in Derivative
440
+ from sympy.tensor.array.array_derivatives import ArrayDerivative
441
+ deriv = ArrayDerivative(self, *args, evaluate=evaluate)
442
+ # XXX This can rather changed to always return immutable matrix
443
+ if not isinstance(self, Basic) and evaluate:
444
+ return deriv.as_mutable()
445
+ return deriv
446
+
447
+ def _eval_derivative(self, arg):
448
+ return self.applyfunc(lambda x: x.diff(arg))
449
+
450
+ def integrate(self, *args, **kwargs):
451
+ """Integrate each element of the matrix. ``args`` will
452
+ be passed to the ``integrate`` function.
453
+
454
+ Examples
455
+ ========
456
+
457
+ >>> from sympy import Matrix
458
+ >>> from sympy.abc import x, y
459
+ >>> M = Matrix([[x, y], [1, 0]])
460
+ >>> M.integrate((x, ))
461
+ Matrix([
462
+ [x**2/2, x*y],
463
+ [ x, 0]])
464
+ >>> M.integrate((x, 0, 2))
465
+ Matrix([
466
+ [2, 2*y],
467
+ [2, 0]])
468
+
469
+ See Also
470
+ ========
471
+
472
+ limit
473
+ diff
474
+ """
475
+ return self.applyfunc(lambda x: x.integrate(*args, **kwargs))
476
+
477
+ def jacobian(self, X):
478
+ """Calculates the Jacobian matrix (derivative of a vector-valued function).
479
+
480
+ Parameters
481
+ ==========
482
+
483
+ ``self`` : vector of expressions representing functions f_i(x_1, ..., x_n).
484
+ X : set of x_i's in order, it can be a list or a Matrix
485
+
486
+ Both ``self`` and X can be a row or a column matrix in any order
487
+ (i.e., jacobian() should always work).
488
+
489
+ Examples
490
+ ========
491
+
492
+ >>> from sympy import sin, cos, Matrix
493
+ >>> from sympy.abc import rho, phi
494
+ >>> X = Matrix([rho*cos(phi), rho*sin(phi), rho**2])
495
+ >>> Y = Matrix([rho, phi])
496
+ >>> X.jacobian(Y)
497
+ Matrix([
498
+ [cos(phi), -rho*sin(phi)],
499
+ [sin(phi), rho*cos(phi)],
500
+ [ 2*rho, 0]])
501
+ >>> X = Matrix([rho*cos(phi), rho*sin(phi)])
502
+ >>> X.jacobian(Y)
503
+ Matrix([
504
+ [cos(phi), -rho*sin(phi)],
505
+ [sin(phi), rho*cos(phi)]])
506
+
507
+ See Also
508
+ ========
509
+
510
+ hessian
511
+ wronskian
512
+ """
513
+ if not isinstance(X, MatrixBase):
514
+ X = self._new(X)
515
+ # Both X and ``self`` can be a row or a column matrix, so we need to make
516
+ # sure all valid combinations work, but everything else fails:
517
+ if self.shape[0] == 1:
518
+ m = self.shape[1]
519
+ elif self.shape[1] == 1:
520
+ m = self.shape[0]
521
+ else:
522
+ raise TypeError("``self`` must be a row or a column matrix")
523
+ if X.shape[0] == 1:
524
+ n = X.shape[1]
525
+ elif X.shape[1] == 1:
526
+ n = X.shape[0]
527
+ else:
528
+ raise TypeError("X must be a row or a column matrix")
529
+
530
+ # m is the number of functions and n is the number of variables
531
+ # computing the Jacobian is now easy:
532
+ return self._new(m, n, lambda j, i: self[j].diff(X[i]))
533
+
534
+ def limit(self, *args):
535
+ """Calculate the limit of each element in the matrix.
536
+ ``args`` will be passed to the ``limit`` function.
537
+
538
+ Examples
539
+ ========
540
+
541
+ >>> from sympy import Matrix
542
+ >>> from sympy.abc import x, y
543
+ >>> M = Matrix([[x, y], [1, 0]])
544
+ >>> M.limit(x, 2)
545
+ Matrix([
546
+ [2, y],
547
+ [1, 0]])
548
+
549
+ See Also
550
+ ========
551
+
552
+ integrate
553
+ diff
554
+ """
555
+ return self.applyfunc(lambda x: x.limit(*args))
556
+
557
+
558
+ # https://github.com/sympy/sympy/pull/12854
559
+ class MatrixDeprecated(MatrixCommon):
560
+ """A class to house deprecated matrix methods."""
561
+ def berkowitz_charpoly(self, x=Dummy('lambda'), simplify=_simplify):
562
+ return self.charpoly(x=x)
563
+
564
+ def berkowitz_det(self):
565
+ """Computes determinant using Berkowitz method.
566
+
567
+ See Also
568
+ ========
569
+
570
+ det
571
+ berkowitz
572
+ """
573
+ return self.det(method='berkowitz')
574
+
575
+ def berkowitz_eigenvals(self, **flags):
576
+ """Computes eigenvalues of a Matrix using Berkowitz method.
577
+
578
+ See Also
579
+ ========
580
+
581
+ berkowitz
582
+ """
583
+ return self.eigenvals(**flags)
584
+
585
+ def berkowitz_minors(self):
586
+ """Computes principal minors using Berkowitz method.
587
+
588
+ See Also
589
+ ========
590
+
591
+ berkowitz
592
+ """
593
+ sign, minors = self.one, []
594
+
595
+ for poly in self.berkowitz():
596
+ minors.append(sign * poly[-1])
597
+ sign = -sign
598
+
599
+ return tuple(minors)
600
+
601
+ def berkowitz(self):
602
+ from sympy.matrices import zeros
603
+ berk = ((1,),)
604
+ if not self:
605
+ return berk
606
+
607
+ if not self.is_square:
608
+ raise NonSquareMatrixError()
609
+
610
+ A, N = self, self.rows
611
+ transforms = [0] * (N - 1)
612
+
613
+ for n in range(N, 1, -1):
614
+ T, k = zeros(n + 1, n), n - 1
615
+
616
+ R, C = -A[k, :k], A[:k, k]
617
+ A, a = A[:k, :k], -A[k, k]
618
+
619
+ items = [C]
620
+
621
+ for i in range(0, n - 2):
622
+ items.append(A * items[i])
623
+
624
+ for i, B in enumerate(items):
625
+ items[i] = (R * B)[0, 0]
626
+
627
+ items = [self.one, a] + items
628
+
629
+ for i in range(n):
630
+ T[i:, i] = items[:n - i + 1]
631
+
632
+ transforms[k - 1] = T
633
+
634
+ polys = [self._new([self.one, -A[0, 0]])]
635
+
636
+ for i, T in enumerate(transforms):
637
+ polys.append(T * polys[i])
638
+
639
+ return berk + tuple(map(tuple, polys))
640
+
641
+ def cofactorMatrix(self, method="berkowitz"):
642
+ return self.cofactor_matrix(method=method)
643
+
644
+ def det_bareis(self):
645
+ return _det_bareiss(self)
646
+
647
+ def det_LU_decomposition(self):
648
+ """Compute matrix determinant using LU decomposition.
649
+
650
+
651
+ Note that this method fails if the LU decomposition itself
652
+ fails. In particular, if the matrix has no inverse this method
653
+ will fail.
654
+
655
+ TODO: Implement algorithm for sparse matrices (SFF),
656
+ https://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps
657
+
658
+ See Also
659
+ ========
660
+
661
+
662
+ det
663
+ det_bareiss
664
+ berkowitz_det
665
+ """
666
+ return self.det(method='lu')
667
+
668
+ def jordan_cell(self, eigenval, n):
669
+ return self.jordan_block(size=n, eigenvalue=eigenval)
670
+
671
+ def jordan_cells(self, calc_transformation=True):
672
+ P, J = self.jordan_form()
673
+ return P, J.get_diag_blocks()
674
+
675
+ def minorEntry(self, i, j, method="berkowitz"):
676
+ return self.minor(i, j, method=method)
677
+
678
+ def minorMatrix(self, i, j):
679
+ return self.minor_submatrix(i, j)
680
+
681
+ def permuteBkwd(self, perm):
682
+ """Permute the rows of the matrix with the given permutation in reverse."""
683
+ return self.permute_rows(perm, direction='backward')
684
+
685
+ def permuteFwd(self, perm):
686
+ """Permute the rows of the matrix with the given permutation."""
687
+ return self.permute_rows(perm, direction='forward')
lib/python3.12/site-packages/sympy/matrices/solvers.py ADDED
@@ -0,0 +1,942 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.function import expand_mul
2
+ from sympy.core.symbol import Dummy, uniquely_named_symbol, symbols
3
+ from sympy.utilities.iterables import numbered_symbols
4
+
5
+ from .exceptions import ShapeError, NonSquareMatrixError, NonInvertibleMatrixError
6
+ from .eigen import _fuzzy_positive_definite
7
+ from .utilities import _get_intermediate_simp, _iszero
8
+
9
+
10
+ def _diagonal_solve(M, rhs):
11
+ """Solves ``Ax = B`` efficiently, where A is a diagonal Matrix,
12
+ with non-zero diagonal entries.
13
+
14
+ Examples
15
+ ========
16
+
17
+ >>> from sympy import Matrix, eye
18
+ >>> A = eye(2)*2
19
+ >>> B = Matrix([[1, 2], [3, 4]])
20
+ >>> A.diagonal_solve(B) == B/2
21
+ True
22
+
23
+ See Also
24
+ ========
25
+
26
+ sympy.matrices.dense.DenseMatrix.lower_triangular_solve
27
+ sympy.matrices.dense.DenseMatrix.upper_triangular_solve
28
+ gauss_jordan_solve
29
+ cholesky_solve
30
+ LDLsolve
31
+ LUsolve
32
+ QRsolve
33
+ pinv_solve
34
+ cramer_solve
35
+ """
36
+
37
+ if not M.is_diagonal():
38
+ raise TypeError("Matrix should be diagonal")
39
+ if rhs.rows != M.rows:
40
+ raise TypeError("Size mismatch")
41
+
42
+ return M._new(
43
+ rhs.rows, rhs.cols, lambda i, j: rhs[i, j] / M[i, i])
44
+
45
+
46
+ def _lower_triangular_solve(M, rhs):
47
+ """Solves ``Ax = B``, where A is a lower triangular matrix.
48
+
49
+ See Also
50
+ ========
51
+
52
+ upper_triangular_solve
53
+ gauss_jordan_solve
54
+ cholesky_solve
55
+ diagonal_solve
56
+ LDLsolve
57
+ LUsolve
58
+ QRsolve
59
+ pinv_solve
60
+ cramer_solve
61
+ """
62
+
63
+ from .dense import MutableDenseMatrix
64
+
65
+ if not M.is_square:
66
+ raise NonSquareMatrixError("Matrix must be square.")
67
+ if rhs.rows != M.rows:
68
+ raise ShapeError("Matrices size mismatch.")
69
+ if not M.is_lower:
70
+ raise ValueError("Matrix must be lower triangular.")
71
+
72
+ dps = _get_intermediate_simp()
73
+ X = MutableDenseMatrix.zeros(M.rows, rhs.cols)
74
+
75
+ for j in range(rhs.cols):
76
+ for i in range(M.rows):
77
+ if M[i, i] == 0:
78
+ raise TypeError("Matrix must be non-singular.")
79
+
80
+ X[i, j] = dps((rhs[i, j] - sum(M[i, k]*X[k, j]
81
+ for k in range(i))) / M[i, i])
82
+
83
+ return M._new(X)
84
+
85
+ def _lower_triangular_solve_sparse(M, rhs):
86
+ """Solves ``Ax = B``, where A is a lower triangular matrix.
87
+
88
+ See Also
89
+ ========
90
+
91
+ upper_triangular_solve
92
+ gauss_jordan_solve
93
+ cholesky_solve
94
+ diagonal_solve
95
+ LDLsolve
96
+ LUsolve
97
+ QRsolve
98
+ pinv_solve
99
+ cramer_solve
100
+ """
101
+
102
+ if not M.is_square:
103
+ raise NonSquareMatrixError("Matrix must be square.")
104
+ if rhs.rows != M.rows:
105
+ raise ShapeError("Matrices size mismatch.")
106
+ if not M.is_lower:
107
+ raise ValueError("Matrix must be lower triangular.")
108
+
109
+ dps = _get_intermediate_simp()
110
+ rows = [[] for i in range(M.rows)]
111
+
112
+ for i, j, v in M.row_list():
113
+ if i > j:
114
+ rows[i].append((j, v))
115
+
116
+ X = rhs.as_mutable()
117
+
118
+ for j in range(rhs.cols):
119
+ for i in range(rhs.rows):
120
+ for u, v in rows[i]:
121
+ X[i, j] -= v*X[u, j]
122
+
123
+ X[i, j] = dps(X[i, j] / M[i, i])
124
+
125
+ return M._new(X)
126
+
127
+
128
+ def _upper_triangular_solve(M, rhs):
129
+ """Solves ``Ax = B``, where A is an upper triangular matrix.
130
+
131
+ See Also
132
+ ========
133
+
134
+ lower_triangular_solve
135
+ gauss_jordan_solve
136
+ cholesky_solve
137
+ diagonal_solve
138
+ LDLsolve
139
+ LUsolve
140
+ QRsolve
141
+ pinv_solve
142
+ cramer_solve
143
+ """
144
+
145
+ from .dense import MutableDenseMatrix
146
+
147
+ if not M.is_square:
148
+ raise NonSquareMatrixError("Matrix must be square.")
149
+ if rhs.rows != M.rows:
150
+ raise ShapeError("Matrix size mismatch.")
151
+ if not M.is_upper:
152
+ raise TypeError("Matrix is not upper triangular.")
153
+
154
+ dps = _get_intermediate_simp()
155
+ X = MutableDenseMatrix.zeros(M.rows, rhs.cols)
156
+
157
+ for j in range(rhs.cols):
158
+ for i in reversed(range(M.rows)):
159
+ if M[i, i] == 0:
160
+ raise ValueError("Matrix must be non-singular.")
161
+
162
+ X[i, j] = dps((rhs[i, j] - sum(M[i, k]*X[k, j]
163
+ for k in range(i + 1, M.rows))) / M[i, i])
164
+
165
+ return M._new(X)
166
+
167
+ def _upper_triangular_solve_sparse(M, rhs):
168
+ """Solves ``Ax = B``, where A is an upper triangular matrix.
169
+
170
+ See Also
171
+ ========
172
+
173
+ lower_triangular_solve
174
+ gauss_jordan_solve
175
+ cholesky_solve
176
+ diagonal_solve
177
+ LDLsolve
178
+ LUsolve
179
+ QRsolve
180
+ pinv_solve
181
+ cramer_solve
182
+ """
183
+
184
+ if not M.is_square:
185
+ raise NonSquareMatrixError("Matrix must be square.")
186
+ if rhs.rows != M.rows:
187
+ raise ShapeError("Matrix size mismatch.")
188
+ if not M.is_upper:
189
+ raise TypeError("Matrix is not upper triangular.")
190
+
191
+ dps = _get_intermediate_simp()
192
+ rows = [[] for i in range(M.rows)]
193
+
194
+ for i, j, v in M.row_list():
195
+ if i < j:
196
+ rows[i].append((j, v))
197
+
198
+ X = rhs.as_mutable()
199
+
200
+ for j in range(rhs.cols):
201
+ for i in reversed(range(rhs.rows)):
202
+ for u, v in reversed(rows[i]):
203
+ X[i, j] -= v*X[u, j]
204
+
205
+ X[i, j] = dps(X[i, j] / M[i, i])
206
+
207
+ return M._new(X)
208
+
209
+
210
+ def _cholesky_solve(M, rhs):
211
+ """Solves ``Ax = B`` using Cholesky decomposition,
212
+ for a general square non-singular matrix.
213
+ For a non-square matrix with rows > cols,
214
+ the least squares solution is returned.
215
+
216
+ See Also
217
+ ========
218
+
219
+ sympy.matrices.dense.DenseMatrix.lower_triangular_solve
220
+ sympy.matrices.dense.DenseMatrix.upper_triangular_solve
221
+ gauss_jordan_solve
222
+ diagonal_solve
223
+ LDLsolve
224
+ LUsolve
225
+ QRsolve
226
+ pinv_solve
227
+ cramer_solve
228
+ """
229
+
230
+ if M.rows < M.cols:
231
+ raise NotImplementedError(
232
+ 'Under-determined System. Try M.gauss_jordan_solve(rhs)')
233
+
234
+ hermitian = True
235
+ reform = False
236
+
237
+ if M.is_symmetric():
238
+ hermitian = False
239
+ elif not M.is_hermitian:
240
+ reform = True
241
+
242
+ if reform or _fuzzy_positive_definite(M) is False:
243
+ H = M.H
244
+ M = H.multiply(M)
245
+ rhs = H.multiply(rhs)
246
+ hermitian = not M.is_symmetric()
247
+
248
+ L = M.cholesky(hermitian=hermitian)
249
+ Y = L.lower_triangular_solve(rhs)
250
+
251
+ if hermitian:
252
+ return (L.H).upper_triangular_solve(Y)
253
+ else:
254
+ return (L.T).upper_triangular_solve(Y)
255
+
256
+
257
+ def _LDLsolve(M, rhs):
258
+ """Solves ``Ax = B`` using LDL decomposition,
259
+ for a general square and non-singular matrix.
260
+
261
+ For a non-square matrix with rows > cols,
262
+ the least squares solution is returned.
263
+
264
+ Examples
265
+ ========
266
+
267
+ >>> from sympy import Matrix, eye
268
+ >>> A = eye(2)*2
269
+ >>> B = Matrix([[1, 2], [3, 4]])
270
+ >>> A.LDLsolve(B) == B/2
271
+ True
272
+
273
+ See Also
274
+ ========
275
+
276
+ sympy.matrices.dense.DenseMatrix.LDLdecomposition
277
+ sympy.matrices.dense.DenseMatrix.lower_triangular_solve
278
+ sympy.matrices.dense.DenseMatrix.upper_triangular_solve
279
+ gauss_jordan_solve
280
+ cholesky_solve
281
+ diagonal_solve
282
+ LUsolve
283
+ QRsolve
284
+ pinv_solve
285
+ cramer_solve
286
+ """
287
+
288
+ if M.rows < M.cols:
289
+ raise NotImplementedError(
290
+ 'Under-determined System. Try M.gauss_jordan_solve(rhs)')
291
+
292
+ hermitian = True
293
+ reform = False
294
+
295
+ if M.is_symmetric():
296
+ hermitian = False
297
+ elif not M.is_hermitian:
298
+ reform = True
299
+
300
+ if reform or _fuzzy_positive_definite(M) is False:
301
+ H = M.H
302
+ M = H.multiply(M)
303
+ rhs = H.multiply(rhs)
304
+ hermitian = not M.is_symmetric()
305
+
306
+ L, D = M.LDLdecomposition(hermitian=hermitian)
307
+ Y = L.lower_triangular_solve(rhs)
308
+ Z = D.diagonal_solve(Y)
309
+
310
+ if hermitian:
311
+ return (L.H).upper_triangular_solve(Z)
312
+ else:
313
+ return (L.T).upper_triangular_solve(Z)
314
+
315
+
316
+ def _LUsolve(M, rhs, iszerofunc=_iszero):
317
+ """Solve the linear system ``Ax = rhs`` for ``x`` where ``A = M``.
318
+
319
+ This is for symbolic matrices, for real or complex ones use
320
+ mpmath.lu_solve or mpmath.qr_solve.
321
+
322
+ See Also
323
+ ========
324
+
325
+ sympy.matrices.dense.DenseMatrix.lower_triangular_solve
326
+ sympy.matrices.dense.DenseMatrix.upper_triangular_solve
327
+ gauss_jordan_solve
328
+ cholesky_solve
329
+ diagonal_solve
330
+ LDLsolve
331
+ QRsolve
332
+ pinv_solve
333
+ LUdecomposition
334
+ cramer_solve
335
+ """
336
+
337
+ if rhs.rows != M.rows:
338
+ raise ShapeError(
339
+ "``M`` and ``rhs`` must have the same number of rows.")
340
+
341
+ m = M.rows
342
+ n = M.cols
343
+
344
+ if m < n:
345
+ raise NotImplementedError("Underdetermined systems not supported.")
346
+
347
+ try:
348
+ A, perm = M.LUdecomposition_Simple(
349
+ iszerofunc=iszerofunc, rankcheck=True)
350
+ except ValueError:
351
+ raise NonInvertibleMatrixError("Matrix det == 0; not invertible.")
352
+
353
+ dps = _get_intermediate_simp()
354
+ b = rhs.permute_rows(perm).as_mutable()
355
+
356
+ # forward substitution, all diag entries are scaled to 1
357
+ for i in range(m):
358
+ for j in range(min(i, n)):
359
+ scale = A[i, j]
360
+ b.zip_row_op(i, j, lambda x, y: dps(x - y * scale))
361
+
362
+ # consistency check for overdetermined systems
363
+ if m > n:
364
+ for i in range(n, m):
365
+ for j in range(b.cols):
366
+ if not iszerofunc(b[i, j]):
367
+ raise ValueError("The system is inconsistent.")
368
+
369
+ b = b[0:n, :] # truncate zero rows if consistent
370
+
371
+ # backward substitution
372
+ for i in range(n - 1, -1, -1):
373
+ for j in range(i + 1, n):
374
+ scale = A[i, j]
375
+ b.zip_row_op(i, j, lambda x, y: dps(x - y * scale))
376
+
377
+ scale = A[i, i]
378
+ b.row_op(i, lambda x, _: dps(x / scale))
379
+
380
+ return rhs.__class__(b)
381
+
382
+
383
+ def _QRsolve(M, b):
384
+ """Solve the linear system ``Ax = b``.
385
+
386
+ ``M`` is the matrix ``A``, the method argument is the vector
387
+ ``b``. The method returns the solution vector ``x``. If ``b`` is a
388
+ matrix, the system is solved for each column of ``b`` and the
389
+ return value is a matrix of the same shape as ``b``.
390
+
391
+ This method is slower (approximately by a factor of 2) but
392
+ more stable for floating-point arithmetic than the LUsolve method.
393
+ However, LUsolve usually uses an exact arithmetic, so you do not need
394
+ to use QRsolve.
395
+
396
+ This is mainly for educational purposes and symbolic matrices, for real
397
+ (or complex) matrices use mpmath.qr_solve.
398
+
399
+ See Also
400
+ ========
401
+
402
+ sympy.matrices.dense.DenseMatrix.lower_triangular_solve
403
+ sympy.matrices.dense.DenseMatrix.upper_triangular_solve
404
+ gauss_jordan_solve
405
+ cholesky_solve
406
+ diagonal_solve
407
+ LDLsolve
408
+ LUsolve
409
+ pinv_solve
410
+ QRdecomposition
411
+ cramer_solve
412
+ """
413
+
414
+ dps = _get_intermediate_simp(expand_mul, expand_mul)
415
+ Q, R = M.QRdecomposition()
416
+ y = Q.T * b
417
+
418
+ # back substitution to solve R*x = y:
419
+ # We build up the result "backwards" in the vector 'x' and reverse it
420
+ # only in the end.
421
+ x = []
422
+ n = R.rows
423
+
424
+ for j in range(n - 1, -1, -1):
425
+ tmp = y[j, :]
426
+
427
+ for k in range(j + 1, n):
428
+ tmp -= R[j, k] * x[n - 1 - k]
429
+
430
+ tmp = dps(tmp)
431
+
432
+ x.append(tmp / R[j, j])
433
+
434
+ return M.vstack(*x[::-1])
435
+
436
+
437
+ def _gauss_jordan_solve(M, B, freevar=False):
438
+ """
439
+ Solves ``Ax = B`` using Gauss Jordan elimination.
440
+
441
+ There may be zero, one, or infinite solutions. If one solution
442
+ exists, it will be returned. If infinite solutions exist, it will
443
+ be returned parametrically. If no solutions exist, It will throw
444
+ ValueError.
445
+
446
+ Parameters
447
+ ==========
448
+
449
+ B : Matrix
450
+ The right hand side of the equation to be solved for. Must have
451
+ the same number of rows as matrix A.
452
+
453
+ freevar : boolean, optional
454
+ Flag, when set to `True` will return the indices of the free
455
+ variables in the solutions (column Matrix), for a system that is
456
+ undetermined (e.g. A has more columns than rows), for which
457
+ infinite solutions are possible, in terms of arbitrary
458
+ values of free variables. Default `False`.
459
+
460
+ Returns
461
+ =======
462
+
463
+ x : Matrix
464
+ The matrix that will satisfy ``Ax = B``. Will have as many rows as
465
+ matrix A has columns, and as many columns as matrix B.
466
+
467
+ params : Matrix
468
+ If the system is underdetermined (e.g. A has more columns than
469
+ rows), infinite solutions are possible, in terms of arbitrary
470
+ parameters. These arbitrary parameters are returned as params
471
+ Matrix.
472
+
473
+ free_var_index : List, optional
474
+ If the system is underdetermined (e.g. A has more columns than
475
+ rows), infinite solutions are possible, in terms of arbitrary
476
+ values of free variables. Then the indices of the free variables
477
+ in the solutions (column Matrix) are returned by free_var_index,
478
+ if the flag `freevar` is set to `True`.
479
+
480
+ Examples
481
+ ========
482
+
483
+ >>> from sympy import Matrix
484
+ >>> A = Matrix([[1, 2, 1, 1], [1, 2, 2, -1], [2, 4, 0, 6]])
485
+ >>> B = Matrix([7, 12, 4])
486
+ >>> sol, params = A.gauss_jordan_solve(B)
487
+ >>> sol
488
+ Matrix([
489
+ [-2*tau0 - 3*tau1 + 2],
490
+ [ tau0],
491
+ [ 2*tau1 + 5],
492
+ [ tau1]])
493
+ >>> params
494
+ Matrix([
495
+ [tau0],
496
+ [tau1]])
497
+ >>> taus_zeroes = { tau:0 for tau in params }
498
+ >>> sol_unique = sol.xreplace(taus_zeroes)
499
+ >>> sol_unique
500
+ Matrix([
501
+ [2],
502
+ [0],
503
+ [5],
504
+ [0]])
505
+
506
+
507
+ >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]])
508
+ >>> B = Matrix([3, 6, 9])
509
+ >>> sol, params = A.gauss_jordan_solve(B)
510
+ >>> sol
511
+ Matrix([
512
+ [-1],
513
+ [ 2],
514
+ [ 0]])
515
+ >>> params
516
+ Matrix(0, 1, [])
517
+
518
+ >>> A = Matrix([[2, -7], [-1, 4]])
519
+ >>> B = Matrix([[-21, 3], [12, -2]])
520
+ >>> sol, params = A.gauss_jordan_solve(B)
521
+ >>> sol
522
+ Matrix([
523
+ [0, -2],
524
+ [3, -1]])
525
+ >>> params
526
+ Matrix(0, 2, [])
527
+
528
+
529
+ >>> from sympy import Matrix
530
+ >>> A = Matrix([[1, 2, 1, 1], [1, 2, 2, -1], [2, 4, 0, 6]])
531
+ >>> B = Matrix([7, 12, 4])
532
+ >>> sol, params, freevars = A.gauss_jordan_solve(B, freevar=True)
533
+ >>> sol
534
+ Matrix([
535
+ [-2*tau0 - 3*tau1 + 2],
536
+ [ tau0],
537
+ [ 2*tau1 + 5],
538
+ [ tau1]])
539
+ >>> params
540
+ Matrix([
541
+ [tau0],
542
+ [tau1]])
543
+ >>> freevars
544
+ [1, 3]
545
+
546
+
547
+ See Also
548
+ ========
549
+
550
+ sympy.matrices.dense.DenseMatrix.lower_triangular_solve
551
+ sympy.matrices.dense.DenseMatrix.upper_triangular_solve
552
+ cholesky_solve
553
+ diagonal_solve
554
+ LDLsolve
555
+ LUsolve
556
+ QRsolve
557
+ pinv
558
+
559
+ References
560
+ ==========
561
+
562
+ .. [1] https://en.wikipedia.org/wiki/Gaussian_elimination
563
+
564
+ """
565
+
566
+ from sympy.matrices import Matrix, zeros
567
+
568
+ cls = M.__class__
569
+ aug = M.hstack(M.copy(), B.copy())
570
+ B_cols = B.cols
571
+ row, col = aug[:, :-B_cols].shape
572
+
573
+ # solve by reduced row echelon form
574
+ A, pivots = aug.rref(simplify=True)
575
+ A, v = A[:, :-B_cols], A[:, -B_cols:]
576
+ pivots = list(filter(lambda p: p < col, pivots))
577
+ rank = len(pivots)
578
+
579
+ # Get index of free symbols (free parameters)
580
+ # non-pivots columns are free variables
581
+ free_var_index = [c for c in range(A.cols) if c not in pivots]
582
+
583
+ # Bring to block form
584
+ permutation = Matrix(pivots + free_var_index).T
585
+
586
+ # check for existence of solutions
587
+ # rank of aug Matrix should be equal to rank of coefficient matrix
588
+ if not v[rank:, :].is_zero_matrix:
589
+ raise ValueError("Linear system has no solution")
590
+
591
+ # Free parameters
592
+ # what are current unnumbered free symbol names?
593
+ name = uniquely_named_symbol('tau', [aug],
594
+ compare=lambda i: str(i).rstrip('1234567890'),
595
+ modify=lambda s: '_' + s).name
596
+ gen = numbered_symbols(name)
597
+ tau = Matrix([next(gen) for k in range((col - rank)*B_cols)]).reshape(
598
+ col - rank, B_cols)
599
+
600
+ # Full parametric solution
601
+ V = A[:rank, free_var_index]
602
+ vt = v[:rank, :]
603
+ free_sol = tau.vstack(vt - V * tau, tau)
604
+
605
+ # Undo permutation
606
+ sol = zeros(col, B_cols)
607
+
608
+ for k in range(col):
609
+ sol[permutation[k], :] = free_sol[k,:]
610
+
611
+ sol, tau = cls(sol), cls(tau)
612
+
613
+ if freevar:
614
+ return sol, tau, free_var_index
615
+ else:
616
+ return sol, tau
617
+
618
+
619
+ def _pinv_solve(M, B, arbitrary_matrix=None):
620
+ """Solve ``Ax = B`` using the Moore-Penrose pseudoinverse.
621
+
622
+ There may be zero, one, or infinite solutions. If one solution
623
+ exists, it will be returned. If infinite solutions exist, one will
624
+ be returned based on the value of arbitrary_matrix. If no solutions
625
+ exist, the least-squares solution is returned.
626
+
627
+ Parameters
628
+ ==========
629
+
630
+ B : Matrix
631
+ The right hand side of the equation to be solved for. Must have
632
+ the same number of rows as matrix A.
633
+ arbitrary_matrix : Matrix
634
+ If the system is underdetermined (e.g. A has more columns than
635
+ rows), infinite solutions are possible, in terms of an arbitrary
636
+ matrix. This parameter may be set to a specific matrix to use
637
+ for that purpose; if so, it must be the same shape as x, with as
638
+ many rows as matrix A has columns, and as many columns as matrix
639
+ B. If left as None, an appropriate matrix containing dummy
640
+ symbols in the form of ``wn_m`` will be used, with n and m being
641
+ row and column position of each symbol.
642
+
643
+ Returns
644
+ =======
645
+
646
+ x : Matrix
647
+ The matrix that will satisfy ``Ax = B``. Will have as many rows as
648
+ matrix A has columns, and as many columns as matrix B.
649
+
650
+ Examples
651
+ ========
652
+
653
+ >>> from sympy import Matrix
654
+ >>> A = Matrix([[1, 2, 3], [4, 5, 6]])
655
+ >>> B = Matrix([7, 8])
656
+ >>> A.pinv_solve(B)
657
+ Matrix([
658
+ [ _w0_0/6 - _w1_0/3 + _w2_0/6 - 55/18],
659
+ [-_w0_0/3 + 2*_w1_0/3 - _w2_0/3 + 1/9],
660
+ [ _w0_0/6 - _w1_0/3 + _w2_0/6 + 59/18]])
661
+ >>> A.pinv_solve(B, arbitrary_matrix=Matrix([0, 0, 0]))
662
+ Matrix([
663
+ [-55/18],
664
+ [ 1/9],
665
+ [ 59/18]])
666
+
667
+ See Also
668
+ ========
669
+
670
+ sympy.matrices.dense.DenseMatrix.lower_triangular_solve
671
+ sympy.matrices.dense.DenseMatrix.upper_triangular_solve
672
+ gauss_jordan_solve
673
+ cholesky_solve
674
+ diagonal_solve
675
+ LDLsolve
676
+ LUsolve
677
+ QRsolve
678
+ pinv
679
+
680
+ Notes
681
+ =====
682
+
683
+ This may return either exact solutions or least squares solutions.
684
+ To determine which, check ``A * A.pinv() * B == B``. It will be
685
+ True if exact solutions exist, and False if only a least-squares
686
+ solution exists. Be aware that the left hand side of that equation
687
+ may need to be simplified to correctly compare to the right hand
688
+ side.
689
+
690
+ References
691
+ ==========
692
+
693
+ .. [1] https://en.wikipedia.org/wiki/Moore-Penrose_pseudoinverse#Obtaining_all_solutions_of_a_linear_system
694
+
695
+ """
696
+
697
+ from sympy.matrices import eye
698
+
699
+ A = M
700
+ A_pinv = M.pinv()
701
+
702
+ if arbitrary_matrix is None:
703
+ rows, cols = A.cols, B.cols
704
+ w = symbols('w:{}_:{}'.format(rows, cols), cls=Dummy)
705
+ arbitrary_matrix = M.__class__(cols, rows, w).T
706
+
707
+ return A_pinv.multiply(B) + (eye(A.cols) -
708
+ A_pinv.multiply(A)).multiply(arbitrary_matrix)
709
+
710
+
711
+ def _cramer_solve(M, rhs, det_method="laplace"):
712
+ """Solves system of linear equations using Cramer's rule.
713
+
714
+ This method is relatively inefficient compared to other methods.
715
+ However it only uses a single division, assuming a division-free determinant
716
+ method is provided. This is helpful to minimize the chance of divide-by-zero
717
+ cases in symbolic solutions to linear systems.
718
+
719
+ Parameters
720
+ ==========
721
+ M : Matrix
722
+ The matrix representing the left hand side of the equation.
723
+ rhs : Matrix
724
+ The matrix representing the right hand side of the equation.
725
+ det_method : str or callable
726
+ The method to use to calculate the determinant of the matrix.
727
+ The default is ``'laplace'``. If a callable is passed, it should take a
728
+ single argument, the matrix, and return the determinant of the matrix.
729
+
730
+ Returns
731
+ =======
732
+ x : Matrix
733
+ The matrix that will satisfy ``Ax = B``. Will have as many rows as
734
+ matrix A has columns, and as many columns as matrix B.
735
+
736
+ Examples
737
+ ========
738
+
739
+ >>> from sympy import Matrix
740
+ >>> A = Matrix([[0, -6, 1], [0, -6, -1], [-5, -2, 3]])
741
+ >>> B = Matrix([[-30, -9], [-18, -27], [-26, 46]])
742
+ >>> x = A.cramer_solve(B)
743
+ >>> x
744
+ Matrix([
745
+ [ 0, -5],
746
+ [ 4, 3],
747
+ [-6, 9]])
748
+
749
+ References
750
+ ==========
751
+
752
+ .. [1] https://en.wikipedia.org/wiki/Cramer%27s_rule#Explicit_formulas_for_small_systems
753
+
754
+ """
755
+ from .dense import zeros
756
+
757
+ def entry(i, j):
758
+ return rhs[i, sol] if j == col else M[i, j]
759
+
760
+ if det_method == "bird":
761
+ from .determinant import _det_bird
762
+ det = _det_bird
763
+ elif det_method == "laplace":
764
+ from .determinant import _det_laplace
765
+ det = _det_laplace
766
+ elif isinstance(det_method, str):
767
+ det = lambda matrix: matrix.det(method=det_method)
768
+ else:
769
+ det = det_method
770
+ det_M = det(M)
771
+ x = zeros(*rhs.shape)
772
+ for sol in range(rhs.shape[1]):
773
+ for col in range(rhs.shape[0]):
774
+ x[col, sol] = det(M.__class__(*M.shape, entry)) / det_M
775
+ return M.__class__(x)
776
+
777
+
778
+ def _solve(M, rhs, method='GJ'):
779
+ """Solves linear equation where the unique solution exists.
780
+
781
+ Parameters
782
+ ==========
783
+
784
+ rhs : Matrix
785
+ Vector representing the right hand side of the linear equation.
786
+
787
+ method : string, optional
788
+ If set to ``'GJ'`` or ``'GE'``, the Gauss-Jordan elimination will be
789
+ used, which is implemented in the routine ``gauss_jordan_solve``.
790
+
791
+ If set to ``'LU'``, ``LUsolve`` routine will be used.
792
+
793
+ If set to ``'QR'``, ``QRsolve`` routine will be used.
794
+
795
+ If set to ``'PINV'``, ``pinv_solve`` routine will be used.
796
+
797
+ If set to ``'CRAMER'``, ``cramer_solve`` routine will be used.
798
+
799
+ It also supports the methods available for special linear systems
800
+
801
+ For positive definite systems:
802
+
803
+ If set to ``'CH'``, ``cholesky_solve`` routine will be used.
804
+
805
+ If set to ``'LDL'``, ``LDLsolve`` routine will be used.
806
+
807
+ To use a different method and to compute the solution via the
808
+ inverse, use a method defined in the .inv() docstring.
809
+
810
+ Returns
811
+ =======
812
+
813
+ solutions : Matrix
814
+ Vector representing the solution.
815
+
816
+ Raises
817
+ ======
818
+
819
+ ValueError
820
+ If there is not a unique solution then a ``ValueError`` will be
821
+ raised.
822
+
823
+ If ``M`` is not square, a ``ValueError`` and a different routine
824
+ for solving the system will be suggested.
825
+ """
826
+
827
+ if method in ('GJ', 'GE'):
828
+ try:
829
+ soln, param = M.gauss_jordan_solve(rhs)
830
+
831
+ if param:
832
+ raise NonInvertibleMatrixError("Matrix det == 0; not invertible. "
833
+ "Try ``M.gauss_jordan_solve(rhs)`` to obtain a parametric solution.")
834
+
835
+ except ValueError:
836
+ raise NonInvertibleMatrixError("Matrix det == 0; not invertible.")
837
+
838
+ return soln
839
+
840
+ elif method == 'LU':
841
+ return M.LUsolve(rhs)
842
+ elif method == 'CH':
843
+ return M.cholesky_solve(rhs)
844
+ elif method == 'QR':
845
+ return M.QRsolve(rhs)
846
+ elif method == 'LDL':
847
+ return M.LDLsolve(rhs)
848
+ elif method == 'PINV':
849
+ return M.pinv_solve(rhs)
850
+ elif method == 'CRAMER':
851
+ return M.cramer_solve(rhs)
852
+ else:
853
+ return M.inv(method=method).multiply(rhs)
854
+
855
+
856
+ def _solve_least_squares(M, rhs, method='CH'):
857
+ """Return the least-square fit to the data.
858
+
859
+ Parameters
860
+ ==========
861
+
862
+ rhs : Matrix
863
+ Vector representing the right hand side of the linear equation.
864
+
865
+ method : string or boolean, optional
866
+ If set to ``'CH'``, ``cholesky_solve`` routine will be used.
867
+
868
+ If set to ``'LDL'``, ``LDLsolve`` routine will be used.
869
+
870
+ If set to ``'QR'``, ``QRsolve`` routine will be used.
871
+
872
+ If set to ``'PINV'``, ``pinv_solve`` routine will be used.
873
+
874
+ Otherwise, the conjugate of ``M`` will be used to create a system
875
+ of equations that is passed to ``solve`` along with the hint
876
+ defined by ``method``.
877
+
878
+ Returns
879
+ =======
880
+
881
+ solutions : Matrix
882
+ Vector representing the solution.
883
+
884
+ Examples
885
+ ========
886
+
887
+ >>> from sympy import Matrix, ones
888
+ >>> A = Matrix([1, 2, 3])
889
+ >>> B = Matrix([2, 3, 4])
890
+ >>> S = Matrix(A.row_join(B))
891
+ >>> S
892
+ Matrix([
893
+ [1, 2],
894
+ [2, 3],
895
+ [3, 4]])
896
+
897
+ If each line of S represent coefficients of Ax + By
898
+ and x and y are [2, 3] then S*xy is:
899
+
900
+ >>> r = S*Matrix([2, 3]); r
901
+ Matrix([
902
+ [ 8],
903
+ [13],
904
+ [18]])
905
+
906
+ But let's add 1 to the middle value and then solve for the
907
+ least-squares value of xy:
908
+
909
+ >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy
910
+ Matrix([
911
+ [ 5/3],
912
+ [10/3]])
913
+
914
+ The error is given by S*xy - r:
915
+
916
+ >>> S*xy - r
917
+ Matrix([
918
+ [1/3],
919
+ [1/3],
920
+ [1/3]])
921
+ >>> _.norm().n(2)
922
+ 0.58
923
+
924
+ If a different xy is used, the norm will be higher:
925
+
926
+ >>> xy += ones(2, 1)/10
927
+ >>> (S*xy - r).norm().n(2)
928
+ 1.5
929
+
930
+ """
931
+
932
+ if method == 'CH':
933
+ return M.cholesky_solve(rhs)
934
+ elif method == 'QR':
935
+ return M.QRsolve(rhs)
936
+ elif method == 'LDL':
937
+ return M.LDLsolve(rhs)
938
+ elif method == 'PINV':
939
+ return M.pinv_solve(rhs)
940
+ else:
941
+ t = M.H
942
+ return (t * M).solve(t * rhs, method=method)
lib/python3.12/site-packages/sympy/matrices/sparse.py ADDED
@@ -0,0 +1,473 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections.abc import Callable
2
+
3
+ from sympy.core.containers import Dict
4
+ from sympy.utilities.exceptions import sympy_deprecation_warning
5
+ from sympy.utilities.iterables import is_sequence
6
+ from sympy.utilities.misc import as_int
7
+
8
+ from .matrixbase import MatrixBase
9
+ from .repmatrix import MutableRepMatrix, RepMatrix
10
+
11
+ from .utilities import _iszero
12
+
13
+ from .decompositions import (
14
+ _liupc, _row_structure_symbolic_cholesky, _cholesky_sparse,
15
+ _LDLdecomposition_sparse)
16
+
17
+ from .solvers import (
18
+ _lower_triangular_solve_sparse, _upper_triangular_solve_sparse)
19
+
20
+
21
+ class SparseRepMatrix(RepMatrix):
22
+ """
23
+ A sparse matrix (a matrix with a large number of zero elements).
24
+
25
+ Examples
26
+ ========
27
+
28
+ >>> from sympy import SparseMatrix, ones
29
+ >>> SparseMatrix(2, 2, range(4))
30
+ Matrix([
31
+ [0, 1],
32
+ [2, 3]])
33
+ >>> SparseMatrix(2, 2, {(1, 1): 2})
34
+ Matrix([
35
+ [0, 0],
36
+ [0, 2]])
37
+
38
+ A SparseMatrix can be instantiated from a ragged list of lists:
39
+
40
+ >>> SparseMatrix([[1, 2, 3], [1, 2], [1]])
41
+ Matrix([
42
+ [1, 2, 3],
43
+ [1, 2, 0],
44
+ [1, 0, 0]])
45
+
46
+ For safety, one may include the expected size and then an error
47
+ will be raised if the indices of any element are out of range or
48
+ (for a flat list) if the total number of elements does not match
49
+ the expected shape:
50
+
51
+ >>> SparseMatrix(2, 2, [1, 2])
52
+ Traceback (most recent call last):
53
+ ...
54
+ ValueError: List length (2) != rows*columns (4)
55
+
56
+ Here, an error is not raised because the list is not flat and no
57
+ element is out of range:
58
+
59
+ >>> SparseMatrix(2, 2, [[1, 2]])
60
+ Matrix([
61
+ [1, 2],
62
+ [0, 0]])
63
+
64
+ But adding another element to the first (and only) row will cause
65
+ an error to be raised:
66
+
67
+ >>> SparseMatrix(2, 2, [[1, 2, 3]])
68
+ Traceback (most recent call last):
69
+ ...
70
+ ValueError: The location (0, 2) is out of designated range: (1, 1)
71
+
72
+ To autosize the matrix, pass None for rows:
73
+
74
+ >>> SparseMatrix(None, [[1, 2, 3]])
75
+ Matrix([[1, 2, 3]])
76
+ >>> SparseMatrix(None, {(1, 1): 1, (3, 3): 3})
77
+ Matrix([
78
+ [0, 0, 0, 0],
79
+ [0, 1, 0, 0],
80
+ [0, 0, 0, 0],
81
+ [0, 0, 0, 3]])
82
+
83
+ Values that are themselves a Matrix are automatically expanded:
84
+
85
+ >>> SparseMatrix(4, 4, {(1, 1): ones(2)})
86
+ Matrix([
87
+ [0, 0, 0, 0],
88
+ [0, 1, 1, 0],
89
+ [0, 1, 1, 0],
90
+ [0, 0, 0, 0]])
91
+
92
+ A ValueError is raised if the expanding matrix tries to overwrite
93
+ a different element already present:
94
+
95
+ >>> SparseMatrix(3, 3, {(0, 0): ones(2), (1, 1): 2})
96
+ Traceback (most recent call last):
97
+ ...
98
+ ValueError: collision at (1, 1)
99
+
100
+ See Also
101
+ ========
102
+ DenseMatrix
103
+ MutableSparseMatrix
104
+ ImmutableSparseMatrix
105
+ """
106
+
107
+ @classmethod
108
+ def _handle_creation_inputs(cls, *args, **kwargs):
109
+ if len(args) == 1 and isinstance(args[0], MatrixBase):
110
+ rows = args[0].rows
111
+ cols = args[0].cols
112
+ smat = args[0].todok()
113
+ return rows, cols, smat
114
+
115
+ smat = {}
116
+ # autosizing
117
+ if len(args) == 2 and args[0] is None:
118
+ args = [None, None, args[1]]
119
+
120
+ if len(args) == 3:
121
+ r, c = args[:2]
122
+ if r is c is None:
123
+ rows = cols = None
124
+ elif None in (r, c):
125
+ raise ValueError(
126
+ 'Pass rows=None and no cols for autosizing.')
127
+ else:
128
+ rows, cols = as_int(args[0]), as_int(args[1])
129
+
130
+ if isinstance(args[2], Callable):
131
+ op = args[2]
132
+
133
+ if None in (rows, cols):
134
+ raise ValueError(
135
+ "{} and {} must be integers for this "
136
+ "specification.".format(rows, cols))
137
+
138
+ row_indices = [cls._sympify(i) for i in range(rows)]
139
+ col_indices = [cls._sympify(j) for j in range(cols)]
140
+
141
+ for i in row_indices:
142
+ for j in col_indices:
143
+ value = cls._sympify(op(i, j))
144
+ if value != cls.zero:
145
+ smat[i, j] = value
146
+
147
+ return rows, cols, smat
148
+
149
+ elif isinstance(args[2], (dict, Dict)):
150
+ def update(i, j, v):
151
+ # update smat and make sure there are no collisions
152
+ if v:
153
+ if (i, j) in smat and v != smat[i, j]:
154
+ raise ValueError(
155
+ "There is a collision at {} for {} and {}."
156
+ .format((i, j), v, smat[i, j])
157
+ )
158
+ smat[i, j] = v
159
+
160
+ # manual copy, copy.deepcopy() doesn't work
161
+ for (r, c), v in args[2].items():
162
+ if isinstance(v, MatrixBase):
163
+ for (i, j), vv in v.todok().items():
164
+ update(r + i, c + j, vv)
165
+ elif isinstance(v, (list, tuple)):
166
+ _, _, smat = cls._handle_creation_inputs(v, **kwargs)
167
+ for i, j in smat:
168
+ update(r + i, c + j, smat[i, j])
169
+ else:
170
+ v = cls._sympify(v)
171
+ update(r, c, cls._sympify(v))
172
+
173
+ elif is_sequence(args[2]):
174
+ flat = not any(is_sequence(i) for i in args[2])
175
+ if not flat:
176
+ _, _, smat = \
177
+ cls._handle_creation_inputs(args[2], **kwargs)
178
+ else:
179
+ flat_list = args[2]
180
+ if len(flat_list) != rows * cols:
181
+ raise ValueError(
182
+ "The length of the flat list ({}) does not "
183
+ "match the specified size ({} * {})."
184
+ .format(len(flat_list), rows, cols)
185
+ )
186
+
187
+ for i in range(rows):
188
+ for j in range(cols):
189
+ value = flat_list[i*cols + j]
190
+ value = cls._sympify(value)
191
+ if value != cls.zero:
192
+ smat[i, j] = value
193
+
194
+ if rows is None: # autosizing
195
+ keys = smat.keys()
196
+ rows = max(r for r, _ in keys) + 1 if keys else 0
197
+ cols = max(c for _, c in keys) + 1 if keys else 0
198
+
199
+ else:
200
+ for i, j in smat.keys():
201
+ if i and i >= rows or j and j >= cols:
202
+ raise ValueError(
203
+ "The location {} is out of the designated range"
204
+ "[{}, {}]x[{}, {}]"
205
+ .format((i, j), 0, rows - 1, 0, cols - 1)
206
+ )
207
+
208
+ return rows, cols, smat
209
+
210
+ elif len(args) == 1 and isinstance(args[0], (list, tuple)):
211
+ # list of values or lists
212
+ v = args[0]
213
+ c = 0
214
+ for i, row in enumerate(v):
215
+ if not isinstance(row, (list, tuple)):
216
+ row = [row]
217
+ for j, vv in enumerate(row):
218
+ if vv != cls.zero:
219
+ smat[i, j] = cls._sympify(vv)
220
+ c = max(c, len(row))
221
+ rows = len(v) if c else 0
222
+ cols = c
223
+ return rows, cols, smat
224
+
225
+ else:
226
+ # handle full matrix forms with _handle_creation_inputs
227
+ rows, cols, mat = super()._handle_creation_inputs(*args)
228
+ for i in range(rows):
229
+ for j in range(cols):
230
+ value = mat[cols*i + j]
231
+ if value != cls.zero:
232
+ smat[i, j] = value
233
+
234
+ return rows, cols, smat
235
+
236
+ @property
237
+ def _smat(self):
238
+
239
+ sympy_deprecation_warning(
240
+ """
241
+ The private _smat attribute of SparseMatrix is deprecated. Use the
242
+ .todok() method instead.
243
+ """,
244
+ deprecated_since_version="1.9",
245
+ active_deprecations_target="deprecated-private-matrix-attributes"
246
+ )
247
+
248
+ return self.todok()
249
+
250
+ def _eval_inverse(self, **kwargs):
251
+ return self.inv(method=kwargs.get('method', 'LDL'),
252
+ iszerofunc=kwargs.get('iszerofunc', _iszero),
253
+ try_block_diag=kwargs.get('try_block_diag', False))
254
+
255
+ def applyfunc(self, f):
256
+ """Apply a function to each element of the matrix.
257
+
258
+ Examples
259
+ ========
260
+
261
+ >>> from sympy import SparseMatrix
262
+ >>> m = SparseMatrix(2, 2, lambda i, j: i*2+j)
263
+ >>> m
264
+ Matrix([
265
+ [0, 1],
266
+ [2, 3]])
267
+ >>> m.applyfunc(lambda i: 2*i)
268
+ Matrix([
269
+ [0, 2],
270
+ [4, 6]])
271
+
272
+ """
273
+ if not callable(f):
274
+ raise TypeError("`f` must be callable.")
275
+
276
+ # XXX: This only applies the function to the nonzero elements of the
277
+ # matrix so is inconsistent with DenseMatrix.applyfunc e.g.
278
+ # zeros(2, 2).applyfunc(lambda x: x + 1)
279
+ dok = {}
280
+ for k, v in self.todok().items():
281
+ fv = f(v)
282
+ if fv != 0:
283
+ dok[k] = fv
284
+
285
+ return self._new(self.rows, self.cols, dok)
286
+
287
+ def as_immutable(self):
288
+ """Returns an Immutable version of this Matrix."""
289
+ from .immutable import ImmutableSparseMatrix
290
+ return ImmutableSparseMatrix(self)
291
+
292
+ def as_mutable(self):
293
+ """Returns a mutable version of this matrix.
294
+
295
+ Examples
296
+ ========
297
+
298
+ >>> from sympy import ImmutableMatrix
299
+ >>> X = ImmutableMatrix([[1, 2], [3, 4]])
300
+ >>> Y = X.as_mutable()
301
+ >>> Y[1, 1] = 5 # Can set values in Y
302
+ >>> Y
303
+ Matrix([
304
+ [1, 2],
305
+ [3, 5]])
306
+ """
307
+ return MutableSparseMatrix(self)
308
+
309
+ def col_list(self):
310
+ """Returns a column-sorted list of non-zero elements of the matrix.
311
+
312
+ Examples
313
+ ========
314
+
315
+ >>> from sympy import SparseMatrix
316
+ >>> a=SparseMatrix(((1, 2), (3, 4)))
317
+ >>> a
318
+ Matrix([
319
+ [1, 2],
320
+ [3, 4]])
321
+ >>> a.CL
322
+ [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)]
323
+
324
+ See Also
325
+ ========
326
+
327
+ sympy.matrices.sparse.SparseMatrix.row_list
328
+ """
329
+ return [tuple(k + (self[k],)) for k in sorted(self.todok().keys(), key=lambda k: list(reversed(k)))]
330
+
331
+ def nnz(self):
332
+ """Returns the number of non-zero elements in Matrix."""
333
+ return len(self.todok())
334
+
335
+ def row_list(self):
336
+ """Returns a row-sorted list of non-zero elements of the matrix.
337
+
338
+ Examples
339
+ ========
340
+
341
+ >>> from sympy import SparseMatrix
342
+ >>> a = SparseMatrix(((1, 2), (3, 4)))
343
+ >>> a
344
+ Matrix([
345
+ [1, 2],
346
+ [3, 4]])
347
+ >>> a.RL
348
+ [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)]
349
+
350
+ See Also
351
+ ========
352
+
353
+ sympy.matrices.sparse.SparseMatrix.col_list
354
+ """
355
+ return [tuple(k + (self[k],)) for k in
356
+ sorted(self.todok().keys(), key=list)]
357
+
358
+ def scalar_multiply(self, scalar):
359
+ "Scalar element-wise multiplication"
360
+ return scalar * self
361
+
362
+ def solve_least_squares(self, rhs, method='LDL'):
363
+ """Return the least-square fit to the data.
364
+
365
+ By default the cholesky_solve routine is used (method='CH'); other
366
+ methods of matrix inversion can be used. To find out which are
367
+ available, see the docstring of the .inv() method.
368
+
369
+ Examples
370
+ ========
371
+
372
+ >>> from sympy import SparseMatrix, Matrix, ones
373
+ >>> A = Matrix([1, 2, 3])
374
+ >>> B = Matrix([2, 3, 4])
375
+ >>> S = SparseMatrix(A.row_join(B))
376
+ >>> S
377
+ Matrix([
378
+ [1, 2],
379
+ [2, 3],
380
+ [3, 4]])
381
+
382
+ If each line of S represent coefficients of Ax + By
383
+ and x and y are [2, 3] then S*xy is:
384
+
385
+ >>> r = S*Matrix([2, 3]); r
386
+ Matrix([
387
+ [ 8],
388
+ [13],
389
+ [18]])
390
+
391
+ But let's add 1 to the middle value and then solve for the
392
+ least-squares value of xy:
393
+
394
+ >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy
395
+ Matrix([
396
+ [ 5/3],
397
+ [10/3]])
398
+
399
+ The error is given by S*xy - r:
400
+
401
+ >>> S*xy - r
402
+ Matrix([
403
+ [1/3],
404
+ [1/3],
405
+ [1/3]])
406
+ >>> _.norm().n(2)
407
+ 0.58
408
+
409
+ If a different xy is used, the norm will be higher:
410
+
411
+ >>> xy += ones(2, 1)/10
412
+ >>> (S*xy - r).norm().n(2)
413
+ 1.5
414
+
415
+ """
416
+ t = self.T
417
+ return (t*self).inv(method=method)*t*rhs
418
+
419
+ def solve(self, rhs, method='LDL'):
420
+ """Return solution to self*soln = rhs using given inversion method.
421
+
422
+ For a list of possible inversion methods, see the .inv() docstring.
423
+ """
424
+ if not self.is_square:
425
+ if self.rows < self.cols:
426
+ raise ValueError('Under-determined system.')
427
+ elif self.rows > self.cols:
428
+ raise ValueError('For over-determined system, M, having '
429
+ 'more rows than columns, try M.solve_least_squares(rhs).')
430
+ else:
431
+ return self.inv(method=method).multiply(rhs)
432
+
433
+ RL = property(row_list, None, None, "Alternate faster representation")
434
+ CL = property(col_list, None, None, "Alternate faster representation")
435
+
436
+ def liupc(self):
437
+ return _liupc(self)
438
+
439
+ def row_structure_symbolic_cholesky(self):
440
+ return _row_structure_symbolic_cholesky(self)
441
+
442
+ def cholesky(self, hermitian=True):
443
+ return _cholesky_sparse(self, hermitian=hermitian)
444
+
445
+ def LDLdecomposition(self, hermitian=True):
446
+ return _LDLdecomposition_sparse(self, hermitian=hermitian)
447
+
448
+ def lower_triangular_solve(self, rhs):
449
+ return _lower_triangular_solve_sparse(self, rhs)
450
+
451
+ def upper_triangular_solve(self, rhs):
452
+ return _upper_triangular_solve_sparse(self, rhs)
453
+
454
+ liupc.__doc__ = _liupc.__doc__
455
+ row_structure_symbolic_cholesky.__doc__ = _row_structure_symbolic_cholesky.__doc__
456
+ cholesky.__doc__ = _cholesky_sparse.__doc__
457
+ LDLdecomposition.__doc__ = _LDLdecomposition_sparse.__doc__
458
+ lower_triangular_solve.__doc__ = lower_triangular_solve.__doc__
459
+ upper_triangular_solve.__doc__ = upper_triangular_solve.__doc__
460
+
461
+
462
+ class MutableSparseMatrix(SparseRepMatrix, MutableRepMatrix):
463
+
464
+ @classmethod
465
+ def _new(cls, *args, **kwargs):
466
+ rows, cols, smat = cls._handle_creation_inputs(*args, **kwargs)
467
+
468
+ rep = cls._smat_to_DomainMatrix(rows, cols, smat)
469
+
470
+ return cls._fromrep(rep)
471
+
472
+
473
+ SparseMatrix = MutableSparseMatrix
lib/python3.12/site-packages/sympy/matrices/subspaces.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .utilities import _iszero
2
+
3
+
4
+ def _columnspace(M, simplify=False):
5
+ """Returns a list of vectors (Matrix objects) that span columnspace of ``M``
6
+
7
+ Examples
8
+ ========
9
+
10
+ >>> from sympy import Matrix
11
+ >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6])
12
+ >>> M
13
+ Matrix([
14
+ [ 1, 3, 0],
15
+ [-2, -6, 0],
16
+ [ 3, 9, 6]])
17
+ >>> M.columnspace()
18
+ [Matrix([
19
+ [ 1],
20
+ [-2],
21
+ [ 3]]), Matrix([
22
+ [0],
23
+ [0],
24
+ [6]])]
25
+
26
+ See Also
27
+ ========
28
+
29
+ nullspace
30
+ rowspace
31
+ """
32
+
33
+ reduced, pivots = M.echelon_form(simplify=simplify, with_pivots=True)
34
+
35
+ return [M.col(i) for i in pivots]
36
+
37
+
38
+ def _nullspace(M, simplify=False, iszerofunc=_iszero):
39
+ """Returns list of vectors (Matrix objects) that span nullspace of ``M``
40
+
41
+ Examples
42
+ ========
43
+
44
+ >>> from sympy import Matrix
45
+ >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6])
46
+ >>> M
47
+ Matrix([
48
+ [ 1, 3, 0],
49
+ [-2, -6, 0],
50
+ [ 3, 9, 6]])
51
+ >>> M.nullspace()
52
+ [Matrix([
53
+ [-3],
54
+ [ 1],
55
+ [ 0]])]
56
+
57
+ See Also
58
+ ========
59
+
60
+ columnspace
61
+ rowspace
62
+ """
63
+
64
+ reduced, pivots = M.rref(iszerofunc=iszerofunc, simplify=simplify)
65
+
66
+ free_vars = [i for i in range(M.cols) if i not in pivots]
67
+ basis = []
68
+
69
+ for free_var in free_vars:
70
+ # for each free variable, we will set it to 1 and all others
71
+ # to 0. Then, we will use back substitution to solve the system
72
+ vec = [M.zero] * M.cols
73
+ vec[free_var] = M.one
74
+
75
+ for piv_row, piv_col in enumerate(pivots):
76
+ vec[piv_col] -= reduced[piv_row, free_var]
77
+
78
+ basis.append(vec)
79
+
80
+ return [M._new(M.cols, 1, b) for b in basis]
81
+
82
+
83
+ def _rowspace(M, simplify=False):
84
+ """Returns a list of vectors that span the row space of ``M``.
85
+
86
+ Examples
87
+ ========
88
+
89
+ >>> from sympy import Matrix
90
+ >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6])
91
+ >>> M
92
+ Matrix([
93
+ [ 1, 3, 0],
94
+ [-2, -6, 0],
95
+ [ 3, 9, 6]])
96
+ >>> M.rowspace()
97
+ [Matrix([[1, 3, 0]]), Matrix([[0, 0, 6]])]
98
+ """
99
+
100
+ reduced, pivots = M.echelon_form(simplify=simplify, with_pivots=True)
101
+
102
+ return [reduced.row(i) for i in range(len(pivots))]
103
+
104
+
105
+ def _orthogonalize(cls, *vecs, normalize=False, rankcheck=False):
106
+ """Apply the Gram-Schmidt orthogonalization procedure
107
+ to vectors supplied in ``vecs``.
108
+
109
+ Parameters
110
+ ==========
111
+
112
+ vecs
113
+ vectors to be made orthogonal
114
+
115
+ normalize : bool
116
+ If ``True``, return an orthonormal basis.
117
+
118
+ rankcheck : bool
119
+ If ``True``, the computation does not stop when encountering
120
+ linearly dependent vectors.
121
+
122
+ If ``False``, it will raise ``ValueError`` when any zero
123
+ or linearly dependent vectors are found.
124
+
125
+ Returns
126
+ =======
127
+
128
+ list
129
+ List of orthogonal (or orthonormal) basis vectors.
130
+
131
+ Examples
132
+ ========
133
+
134
+ >>> from sympy import I, Matrix
135
+ >>> v = [Matrix([1, I]), Matrix([1, -I])]
136
+ >>> Matrix.orthogonalize(*v)
137
+ [Matrix([
138
+ [1],
139
+ [I]]), Matrix([
140
+ [ 1],
141
+ [-I]])]
142
+
143
+ See Also
144
+ ========
145
+
146
+ MatrixBase.QRdecomposition
147
+
148
+ References
149
+ ==========
150
+
151
+ .. [1] https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process
152
+ """
153
+ from .decompositions import _QRdecomposition_optional
154
+
155
+ if not vecs:
156
+ return []
157
+
158
+ all_row_vecs = (vecs[0].rows == 1)
159
+
160
+ vecs = [x.vec() for x in vecs]
161
+ M = cls.hstack(*vecs)
162
+ Q, R = _QRdecomposition_optional(M, normalize=normalize)
163
+
164
+ if rankcheck and Q.cols < len(vecs):
165
+ raise ValueError("GramSchmidt: vector set not linearly independent")
166
+
167
+ ret = []
168
+ for i in range(Q.cols):
169
+ if all_row_vecs:
170
+ col = cls(Q[:, i].T)
171
+ else:
172
+ col = cls(Q[:, i])
173
+ ret.append(col)
174
+ return ret
lib/python3.12/site-packages/sympy/polys/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (5.57 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/appellseqs.cpython-312.pyc ADDED
Binary file (10.4 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/constructor.cpython-312.pyc ADDED
Binary file (13.9 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/densearith.cpython-312.pyc ADDED
Binary file (45.1 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/densebasic.cpython-312.pyc ADDED
Binary file (50.5 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/densetools.cpython-312.pyc ADDED
Binary file (37.2 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/dispersion.cpython-312.pyc ADDED
Binary file (6.24 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/distributedmodules.cpython-312.pyc ADDED
Binary file (27.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/domainmatrix.cpython-312.pyc ADDED
Binary file (532 Bytes). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/euclidtools.cpython-312.pyc ADDED
Binary file (54.1 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/factortools.cpython-312.pyc ADDED
Binary file (57.2 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/fglmtools.cpython-312.pyc ADDED
Binary file (9.65 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/fields.cpython-312.pyc ADDED
Binary file (36 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/galoistools.cpython-312.pyc ADDED
Binary file (74.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/groebnertools.cpython-312.pyc ADDED
Binary file (33.5 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/heuristicgcd.cpython-312.pyc ADDED
Binary file (5 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/modulargcd.cpython-312.pyc ADDED
Binary file (73.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/monomials.cpython-312.pyc ADDED
Binary file (26.3 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/multivariate_resultants.cpython-312.pyc ADDED
Binary file (21.2 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/orderings.cpython-312.pyc ADDED
Binary file (14.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/orthopolys.cpython-312.pyc ADDED
Binary file (15.5 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/partfrac.cpython-312.pyc ADDED
Binary file (17.9 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/polyconfig.cpython-312.pyc ADDED
Binary file (2.24 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/polyerrors.cpython-312.pyc ADDED
Binary file (9.76 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/polyfuncs.cpython-312.pyc ADDED
Binary file (11.9 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/polymatrix.cpython-312.pyc ADDED
Binary file (17.4 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/polyoptions.cpython-312.pyc ADDED
Binary file (32.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/polyroots.cpython-312.pyc ADDED
Binary file (49.6 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/polyutils.cpython-312.pyc ADDED
Binary file (24.4 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/rationaltools.cpython-312.pyc ADDED
Binary file (3.63 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/ring_series.cpython-312.pyc ADDED
Binary file (72.4 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/rootisolation.cpython-312.pyc ADDED
Binary file (80.3 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/rootoftools.cpython-312.pyc ADDED
Binary file (52.5 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/solvers.cpython-312.pyc ADDED
Binary file (16.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/specialpolys.cpython-312.pyc ADDED
Binary file (29.9 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/sqfreetools.cpython-312.pyc ADDED
Binary file (24.2 kB). View file
 
lib/python3.12/site-packages/sympy/polys/__pycache__/subresultants_qq_zz.cpython-312.pyc ADDED
Binary file (90.4 kB). View file
 
lib/python3.12/site-packages/sympy/polys/agca/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ """Module for algebraic geometry and commutative algebra."""
2
+
3
+ from .homomorphisms import homomorphism
4
+
5
+ __all__ = ['homomorphism']
lib/python3.12/site-packages/sympy/polys/agca/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (348 Bytes). View file
 
lib/python3.12/site-packages/sympy/polys/agca/__pycache__/extensions.cpython-312.pyc ADDED
Binary file (16.7 kB). View file
 
lib/python3.12/site-packages/sympy/polys/agca/__pycache__/homomorphisms.cpython-312.pyc ADDED
Binary file (31.7 kB). View file