Buckets:
MisterAI/LocalAI_Demo_backends / cpu-diffusers.upgrade-tmp /venv /lib /python3.10 /site-packages /sympy /polys /solvers.py
| """Low-level linear systems solver. """ | |
| from sympy.utilities.exceptions import sympy_deprecation_warning | |
| from sympy.utilities.iterables import connected_components | |
| from sympy.core.sympify import sympify | |
| from sympy.core.numbers import Integer, Rational | |
| from sympy.matrices.dense import MutableDenseMatrix | |
| from sympy.polys.domains import ZZ, QQ | |
| from sympy.polys.domains import EX | |
| from sympy.polys.rings import sring | |
| from sympy.polys.polyerrors import NotInvertible | |
| from sympy.polys.domainmatrix import DomainMatrix | |
| class PolyNonlinearError(Exception): | |
| """Raised by solve_lin_sys for nonlinear equations""" | |
| pass | |
| class RawMatrix(MutableDenseMatrix): | |
| """ | |
| .. deprecated:: 1.9 | |
| This class fundamentally is broken by design. Use ``DomainMatrix`` if | |
| you want a matrix over the polys domains or ``Matrix`` for a matrix | |
| with ``Expr`` elements. The ``RawMatrix`` class will be removed/broken | |
| in future in order to reestablish the invariant that the elements of a | |
| Matrix should be of type ``Expr``. | |
| """ | |
| _sympify = staticmethod(lambda x, *args, **kwargs: x) | |
| def __init__(self, *args, **kwargs): | |
| sympy_deprecation_warning( | |
| """ | |
| The RawMatrix class is deprecated. Use either DomainMatrix or | |
| Matrix instead. | |
| """, | |
| deprecated_since_version="1.9", | |
| active_deprecations_target="deprecated-rawmatrix", | |
| ) | |
| domain = ZZ | |
| for i in range(self.rows): | |
| for j in range(self.cols): | |
| val = self[i,j] | |
| if getattr(val, 'is_Poly', False): | |
| K = val.domain[val.gens] | |
| val_sympy = val.as_expr() | |
| elif hasattr(val, 'parent'): | |
| K = val.parent() | |
| val_sympy = K.to_sympy(val) | |
| elif isinstance(val, (int, Integer)): | |
| K = ZZ | |
| val_sympy = sympify(val) | |
| elif isinstance(val, Rational): | |
| K = QQ | |
| val_sympy = val | |
| else: | |
| for K in ZZ, QQ: | |
| if K.of_type(val): | |
| val_sympy = K.to_sympy(val) | |
| break | |
| else: | |
| raise TypeError | |
| domain = domain.unify(K) | |
| self[i,j] = val_sympy | |
| self.ring = domain | |
| def eqs_to_matrix(eqs_coeffs, eqs_rhs, gens, domain): | |
| """Get matrix from linear equations in dict format. | |
| Explanation | |
| =========== | |
| Get the matrix representation of a system of linear equations represented | |
| as dicts with low-level DomainElement coefficients. This is an | |
| *internal* function that is used by solve_lin_sys. | |
| Parameters | |
| ========== | |
| eqs_coeffs: list[dict[Symbol, DomainElement]] | |
| The left hand sides of the equations as dicts mapping from symbols to | |
| coefficients where the coefficients are instances of | |
| DomainElement. | |
| eqs_rhs: list[DomainElements] | |
| The right hand sides of the equations as instances of | |
| DomainElement. | |
| gens: list[Symbol] | |
| The unknowns in the system of equations. | |
| domain: Domain | |
| The domain for coefficients of both lhs and rhs. | |
| Returns | |
| ======= | |
| The augmented matrix representation of the system as a DomainMatrix. | |
| Examples | |
| ======== | |
| >>> from sympy import symbols, ZZ | |
| >>> from sympy.polys.solvers import eqs_to_matrix | |
| >>> x, y = symbols('x, y') | |
| >>> eqs_coeff = [{x:ZZ(1), y:ZZ(1)}, {x:ZZ(1), y:ZZ(-1)}] | |
| >>> eqs_rhs = [ZZ(0), ZZ(-1)] | |
| >>> eqs_to_matrix(eqs_coeff, eqs_rhs, [x, y], ZZ) | |
| DomainMatrix([[1, 1, 0], [1, -1, 1]], (2, 3), ZZ) | |
| See also | |
| ======== | |
| solve_lin_sys: Uses :func:`~eqs_to_matrix` internally | |
| """ | |
| sym2index = {x: n for n, x in enumerate(gens)} | |
| nrows = len(eqs_coeffs) | |
| ncols = len(gens) + 1 | |
| rows = [[domain.zero] * ncols for _ in range(nrows)] | |
| for row, eq_coeff, eq_rhs in zip(rows, eqs_coeffs, eqs_rhs): | |
| for sym, coeff in eq_coeff.items(): | |
| row[sym2index[sym]] = domain.convert(coeff) | |
| row[-1] = -domain.convert(eq_rhs) | |
| return DomainMatrix(rows, (nrows, ncols), domain) | |
| def sympy_eqs_to_ring(eqs, symbols): | |
| """Convert a system of equations from Expr to a PolyRing | |
| Explanation | |
| =========== | |
| High-level functions like ``solve`` expect Expr as inputs but can use | |
| ``solve_lin_sys`` internally. This function converts equations from | |
| ``Expr`` to the low-level poly types used by the ``solve_lin_sys`` | |
| function. | |
| Parameters | |
| ========== | |
| eqs: List of Expr | |
| A list of equations as Expr instances | |
| symbols: List of Symbol | |
| A list of the symbols that are the unknowns in the system of | |
| equations. | |
| Returns | |
| ======= | |
| Tuple[List[PolyElement], Ring]: The equations as PolyElement instances | |
| and the ring of polynomials within which each equation is represented. | |
| Examples | |
| ======== | |
| >>> from sympy import symbols | |
| >>> from sympy.polys.solvers import sympy_eqs_to_ring | |
| >>> a, x, y = symbols('a, x, y') | |
| >>> eqs = [x-y, x+a*y] | |
| >>> eqs_ring, ring = sympy_eqs_to_ring(eqs, [x, y]) | |
| >>> eqs_ring | |
| [x - y, x + a*y] | |
| >>> type(eqs_ring[0]) | |
| <class 'sympy.polys.rings.PolyElement'> | |
| >>> ring | |
| ZZ(a)[x,y] | |
| With the equations in this form they can be passed to ``solve_lin_sys``: | |
| >>> from sympy.polys.solvers import solve_lin_sys | |
| >>> solve_lin_sys(eqs_ring, ring) | |
| {y: 0, x: 0} | |
| """ | |
| try: | |
| K, eqs_K = sring(eqs, symbols, field=True, extension=True) | |
| except NotInvertible: | |
| # https://github.com/sympy/sympy/issues/18874 | |
| K, eqs_K = sring(eqs, symbols, domain=EX) | |
| return eqs_K, K.to_domain() | |
| def solve_lin_sys(eqs, ring, _raw=True): | |
| """Solve a system of linear equations from a PolynomialRing | |
| Explanation | |
| =========== | |
| Solves a system of linear equations given as PolyElement instances of a | |
| PolynomialRing. The basic arithmetic is carried out using instance of | |
| DomainElement which is more efficient than :class:`~sympy.core.expr.Expr` | |
| for the most common inputs. | |
| While this is a public function it is intended primarily for internal use | |
| so its interface is not necessarily convenient. Users are suggested to use | |
| the :func:`sympy.solvers.solveset.linsolve` function (which uses this | |
| function internally) instead. | |
| Parameters | |
| ========== | |
| eqs: list[PolyElement] | |
| The linear equations to be solved as elements of a | |
| PolynomialRing (assumed equal to zero). | |
| ring: PolynomialRing | |
| The polynomial ring from which eqs are drawn. The generators of this | |
| ring are the unknowns to be solved for and the domain of the ring is | |
| the domain of the coefficients of the system of equations. | |
| _raw: bool | |
| If *_raw* is False, the keys and values in the returned dictionary | |
| will be of type Expr (and the unit of the field will be removed from | |
| the keys) otherwise the low-level polys types will be returned, e.g. | |
| PolyElement: PythonRational. | |
| Returns | |
| ======= | |
| ``None`` if the system has no solution. | |
| dict[Symbol, Expr] if _raw=False | |
| dict[Symbol, DomainElement] if _raw=True. | |
| Examples | |
| ======== | |
| >>> from sympy import symbols | |
| >>> from sympy.polys.solvers import solve_lin_sys, sympy_eqs_to_ring | |
| >>> x, y = symbols('x, y') | |
| >>> eqs = [x - y, x + y - 2] | |
| >>> eqs_ring, ring = sympy_eqs_to_ring(eqs, [x, y]) | |
| >>> solve_lin_sys(eqs_ring, ring) | |
| {y: 1, x: 1} | |
| Passing ``_raw=False`` returns the same result except that the keys are | |
| ``Expr`` rather than low-level poly types. | |
| >>> solve_lin_sys(eqs_ring, ring, _raw=False) | |
| {x: 1, y: 1} | |
| See also | |
| ======== | |
| sympy_eqs_to_ring: prepares the inputs to ``solve_lin_sys``. | |
| linsolve: ``linsolve`` uses ``solve_lin_sys`` internally. | |
| sympy.solvers.solvers.solve: ``solve`` uses ``solve_lin_sys`` internally. | |
| """ | |
| as_expr = not _raw | |
| assert ring.domain.is_Field | |
| eqs_dict = [dict(eq) for eq in eqs] | |
| one_monom = ring.one.monoms()[0] | |
| zero = ring.domain.zero | |
| eqs_rhs = [] | |
| eqs_coeffs = [] | |
| for eq_dict in eqs_dict: | |
| eq_rhs = eq_dict.pop(one_monom, zero) | |
| eq_coeffs = {} | |
| for monom, coeff in eq_dict.items(): | |
| if sum(monom) != 1: | |
| msg = "Nonlinear term encountered in solve_lin_sys" | |
| raise PolyNonlinearError(msg) | |
| eq_coeffs[ring.gens[monom.index(1)]] = coeff | |
| if not eq_coeffs: | |
| if not eq_rhs: | |
| continue | |
| else: | |
| return None | |
| eqs_rhs.append(eq_rhs) | |
| eqs_coeffs.append(eq_coeffs) | |
| result = _solve_lin_sys(eqs_coeffs, eqs_rhs, ring) | |
| if result is not None and as_expr: | |
| def to_sympy(x): | |
| as_expr = getattr(x, 'as_expr', None) | |
| if as_expr: | |
| return as_expr() | |
| else: | |
| return ring.domain.to_sympy(x) | |
| tresult = {to_sympy(sym): to_sympy(val) for sym, val in result.items()} | |
| # Remove 1.0x | |
| result = {} | |
| for k, v in tresult.items(): | |
| if k.is_Mul: | |
| c, s = k.as_coeff_Mul() | |
| result[s] = v/c | |
| else: | |
| result[k] = v | |
| return result | |
| def _solve_lin_sys(eqs_coeffs, eqs_rhs, ring): | |
| """Solve a linear system from dict of PolynomialRing coefficients | |
| Explanation | |
| =========== | |
| This is an **internal** function used by :func:`solve_lin_sys` after the | |
| equations have been preprocessed. The role of this function is to split | |
| the system into connected components and pass those to | |
| :func:`_solve_lin_sys_component`. | |
| Examples | |
| ======== | |
| Setup a system for $x-y=0$ and $x+y=2$ and solve: | |
| >>> from sympy import symbols, sring | |
| >>> from sympy.polys.solvers import _solve_lin_sys | |
| >>> x, y = symbols('x, y') | |
| >>> R, (xr, yr) = sring([x, y], [x, y]) | |
| >>> eqs = [{xr:R.one, yr:-R.one}, {xr:R.one, yr:R.one}] | |
| >>> eqs_rhs = [R.zero, -2*R.one] | |
| >>> _solve_lin_sys(eqs, eqs_rhs, R) | |
| {y: 1, x: 1} | |
| See also | |
| ======== | |
| solve_lin_sys: This function is used internally by :func:`solve_lin_sys`. | |
| """ | |
| V = ring.gens | |
| E = [] | |
| for eq_coeffs in eqs_coeffs: | |
| syms = list(eq_coeffs) | |
| E.extend(zip(syms[:-1], syms[1:])) | |
| G = V, E | |
| components = connected_components(G) | |
| sym2comp = {} | |
| for n, component in enumerate(components): | |
| for sym in component: | |
| sym2comp[sym] = n | |
| subsystems = [([], []) for _ in range(len(components))] | |
| for eq_coeff, eq_rhs in zip(eqs_coeffs, eqs_rhs): | |
| sym = next(iter(eq_coeff), None) | |
| sub_coeff, sub_rhs = subsystems[sym2comp[sym]] | |
| sub_coeff.append(eq_coeff) | |
| sub_rhs.append(eq_rhs) | |
| sol = {} | |
| for subsystem in subsystems: | |
| subsol = _solve_lin_sys_component(subsystem[0], subsystem[1], ring) | |
| if subsol is None: | |
| return None | |
| sol.update(subsol) | |
| return sol | |
| def _solve_lin_sys_component(eqs_coeffs, eqs_rhs, ring): | |
| """Solve a linear system from dict of PolynomialRing coefficients | |
| Explanation | |
| =========== | |
| This is an **internal** function used by :func:`solve_lin_sys` after the | |
| equations have been preprocessed. After :func:`_solve_lin_sys` splits the | |
| system into connected components this function is called for each | |
| component. The system of equations is solved using Gauss-Jordan | |
| elimination with division followed by back-substitution. | |
| Examples | |
| ======== | |
| Setup a system for $x-y=0$ and $x+y=2$ and solve: | |
| >>> from sympy import symbols, sring | |
| >>> from sympy.polys.solvers import _solve_lin_sys_component | |
| >>> x, y = symbols('x, y') | |
| >>> R, (xr, yr) = sring([x, y], [x, y]) | |
| >>> eqs = [{xr:R.one, yr:-R.one}, {xr:R.one, yr:R.one}] | |
| >>> eqs_rhs = [R.zero, -2*R.one] | |
| >>> _solve_lin_sys_component(eqs, eqs_rhs, R) | |
| {y: 1, x: 1} | |
| See also | |
| ======== | |
| solve_lin_sys: This function is used internally by :func:`solve_lin_sys`. | |
| """ | |
| # transform from equations to matrix form | |
| matrix = eqs_to_matrix(eqs_coeffs, eqs_rhs, ring.gens, ring.domain) | |
| # convert to a field for rref | |
| if not matrix.domain.is_Field: | |
| matrix = matrix.to_field() | |
| # solve by row-reduction | |
| echelon, pivots = matrix.rref() | |
| # construct the returnable form of the solutions | |
| keys = ring.gens | |
| if pivots and pivots[-1] == len(keys): | |
| return None | |
| if len(pivots) == len(keys): | |
| sol = [] | |
| for s in [row[-1] for row in echelon.rep.to_ddm()]: | |
| a = s | |
| sol.append(a) | |
| sols = dict(zip(keys, sol)) | |
| else: | |
| sols = {} | |
| g = ring.gens | |
| # Extract ground domain coefficients and convert to the ring: | |
| if hasattr(ring, 'ring'): | |
| convert = ring.ring.ground_new | |
| else: | |
| convert = ring.ground_new | |
| echelon = echelon.rep.to_ddm() | |
| vals_set = {v for row in echelon for v in row} | |
| vals_map = {v: convert(v) for v in vals_set} | |
| echelon = [[vals_map[eij] for eij in ei] for ei in echelon] | |
| for i, p in enumerate(pivots): | |
| v = echelon[i][-1] - sum(echelon[i][j]*g[j] for j in range(p+1, len(g)) if echelon[i][j]) | |
| sols[keys[p]] = v | |
| return sols | |
Xet Storage Details
- Size:
- 13.5 kB
- Xet hash:
- e360fa7f3098e3bf3570c25e7ed7f01af03c05b77c3bc138b5e4653afeef501b
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.