svg_path_editor.math ==================== .. py:module:: svg_path_editor.math Attributes ---------- .. autoapisummary:: svg_path_editor.math.Number svg_path_editor.math.Symbol svg_path_editor.math.Expr svg_path_editor.math.Poly svg_path_editor.math.Boolean Classes ------- .. autoapisummary:: svg_path_editor.math.Precision Functions --------- .. autoapisummary:: svg_path_editor.math.canonical_decimal svg_path_editor.math.dec_to_rat svg_path_editor.math.rat_to_dec svg_path_editor.math.as_bool svg_path_editor.math.are_equal svg_path_editor.math.eq svg_path_editor.math.le svg_path_editor.math.ge svg_path_editor.math.lt svg_path_editor.math.gt svg_path_editor.math.is_zero svg_path_editor.math.subs svg_path_editor.math.evalf svg_path_editor.math._as_real_poly svg_path_editor.math.cutoff_tiny svg_path_editor.math.quadratic_roots svg_path_editor.math.cubic_roots svg_path_editor.math.quartic_roots svg_path_editor.math.polynomial_roots svg_path_editor.math._sylvester_matrix svg_path_editor.math.resultant svg_path_editor.math.expand Module Contents --------------- .. py:data:: Number .. py:type:: Symbol :canonical: 'sp.Symbol' .. py:type:: Expr :canonical: 'sp.Expr' .. py:type:: Poly :canonical: 'sp.Poly' .. py:type:: Boolean :canonical: 'sp.logic.boolalg.Boolean' .. py:class:: Precision Control numerical precision for mixed symbolic/numeric operations. ``baseline`` defines the primary target precision, while ``additional`` can be used to carry extra guard digits during intermediate computations. :ivar baseline: Baseline number of significant digits. :ivar additional: Additional guard digits to be used internally. .. py:attribute:: baseline :type: int .. py:attribute:: additional :type: int .. py:property:: full :type: int Full number of significant digits to use. :return: ``baseline + additional``. .. py:function:: canonical_decimal(x) Normalize a :class:`~decimal.Decimal` to a canonical form. :return: ``Decimal(0)`` for any zero value, otherwise ``x.normalize()``. .. py:function:: dec_to_rat(x) Convert a :class:`~decimal.Decimal` to a SymPy :class:`sympy.Rational`. The conversion is exact with respect to the decimal representation: the :class:`~decimal.Decimal` is first converted to a string and then passed to :class:`sympy.Rational`. .. py:function:: rat_to_dec(x) Convert a SymPy expression to :class:`~decimal.Decimal` with current precision. The expression is evaluated numerically using :meth:`sympy.Expr.evalf` with ``n = getcontext().prec`` and then converted to :class:`~decimal.Decimal`. The result is normalized via :func:`canonical_decimal`. .. py:function:: as_bool(r) Coerce a SymPy Boolean to builtin :class:`bool`. :raises ValueError: If ``r`` cannot be simplified to a definite Boolean. .. py:function:: are_equal(a, b) Test symbolic equality :math:`a = b` using SymPy. :return: ``True`` if SymPy proves ``a`` and ``b`` equal, otherwise ``False``. :raises ValueError: If the equality cannot be decided symbolically. .. py:function:: eq(a, b, *, n = None) Construct an (optionally relaxed) equality constraint :math:`a = b`. If ``n`` is ``None``, an exact symbolic equality :class:`sympy.Eq` is returned. Otherwise a relaxed inequality :math:`|a - b| < 10^{-\texttt{baseline}}` is constructed. .. py:function:: le(a, b, *, n = None) Construct an (optionally relaxed) inequality :math:`a ≤ b`. If ``n`` is ``None``, returns :class:`sympy.LessThan(a, b)`. Otherwise compares ``a`` with :math:`b + 10^{-\texttt{baseline}}`. .. py:function:: ge(a, b, *, n = None) Construct an (optionally relaxed) inequality :math:`a \ge b`. See :func:`le` for details. .. py:function:: lt(a, b, *, n = None) Construct an (optionally relaxed) strict inequality :math:`a < b`. If ``n`` is ``None``, returns :class:`sympy.StrictLessThan(a, b)`. Otherwise compares ``a`` with :math:`b + 10^{-\texttt{baseline}}`. .. py:function:: gt(a, b, *, n = None) Construct an (optionally relaxed) strict inequality :math:`a > b`. See :func:`lt` for details. .. py:function:: is_zero(expr, *, n = None) Test whether an expression is zero. If ``n`` is ``None``, use exact symbolic comparison ``expr == 0``. Otherwise, evaluate numerically to ``n.full`` significant digits and test :math:`|\mathtt{expr}| ≤ 10^{-\texttt{baseline}}`. :return: ``True`` if ``expr`` is considered zero, otherwise ``False``. :raises ValueError: If the exact symbolic comparison cannot be decided. .. py:function:: subs(expr, subs, *, n = None) Substitute symbols in an expression, optionally with numeric evaluation. If the expression contains floating-point numbers and ``n`` is not ``None``, :meth:`sympy.Expr.evalf` is used with the given precision and substitutions. Otherwise, standard symbolic substitution via :meth:`sympy.Expr.subs` is performed. :param expr: Expression in which to perform substitutions. :param subs: Mapping from symbols to replacement expressions. :param n: Optional precision for numerical evaluation. .. py:function:: evalf(expr, *, n) Optionally evaluate an expression numerically. If ``n`` is ``None``, return ``expr`` unchanged. Otherwise, return ``expr.evalf(n=n.full)``; if the imaginary part is at most :math:`10^{-\texttt{baseline}}`, the real part is returned. .. py:function:: _as_real_poly(poly, x) Try to interpret ``poly`` as a univariate real polynomial in ``x``. :return: A :class:`sympy.Poly` over a real domain, or ``None`` if this is not possible. .. py:function:: cutoff_tiny(v, n = None) Replace numerically tiny floating values by exact zero. If ``v`` is a :class:`sympy.Float` and ``is_zero(v, n=n)`` holds, :data:`sympy.S.Zero` is returned, otherwise ``v`` is returned unchanged. .. py:function:: quadratic_roots(a1, a0, *, real_only = True, n = None) Solve the monic quadratic equation .. math:: z^2 + a_1 z + a_0 = 0 and return only the real roots if ``real_only=True`` (default). The function implements the standard quadratic formula. :param a1: Coefficient :math:`a_1` of :math:`z`. :param a0: Constant term :math:`a_0`. :param real_only: If ``True``, discard non-real roots. :param n: Optional precision used when classifying the discriminant as positive/non-negative via :func:`cutoff_tiny` and :func:`ge`. :return: A list of roots of :math:`z^2 + a_1 z + a_0 = 0` sorted in nondecreasing order (if they are real). .. py:function:: cubic_roots(a2, a1, a0, *, real_only = True, n = None) Solve the monic cubic equation .. math:: z^3 + a_2 z^2 + a_1 z + a_0 = 0 using the algorithm from https://quarticequations.com/Selected_Algorithms.pdf. Only the real roots are returned if ``real_only=True``. The algorithm follows the two main cases in the reference: * Case 1 (:math:`r^2 + q^3 > 0`): one real root. * Case 2 (:math:`r^2 + q^3 ≤ 0`): three real roots (Viète’s trigonometric form). :param a2: Coefficient :math:`a_2` of :math:`z^2`. :param a1: Coefficient :math:`a_1` of :math:`z`. :param a0: Constant term :math:`a_0`. :param real_only: If ``True``, return only the real roots; otherwise all three (possibly complex) roots are returned. :param n: Optional precision used in :func:`is_zero`, :func:`gt`, :func:`eq`, and trigonometric evaluations. :return: A list of roots of :math:`z^3 + a_2 z^2 + a_1 z + a_0 = 0` sorted in nondecreasing order (if they are real). .. py:function:: quartic_roots(a3, a2, a1, a0, *, real_only = True, n = None) Solve the monic quartic equation .. math:: z^4 + a_3 z^3 + a_2 z^2 + a_1 z + a_0 = 0 using the modified Euler algorithm of Wolters, as described in https://quarticequations.com/Selected_Algorithms.pdf. Only real roots are returned if ``real_only=True``. The method uses the resolvent cubic .. math:: r^3 + \frac{b_2}{2}\,r^2 + \frac{b_2^2-4 b_0}{16}\,r - \frac{b_1^2}{64}=0, whose three solutions :math:`r_1,r_2,r_3` are obtained via :func:`cubic_roots`. The greatest real solution :math:`r_1` with :math:`r_1 ≥ 0` is then used to compute the four quartic roots. :param a3: Coefficient :math:`a_3` of :math:`z^3`. :param a2: Coefficient :math:`a_2` of :math:`z^2`. :param a1: Coefficient :math:`a_1` of :math:`z`. :param a0: Constant term :math:`a_0`. :param real_only: If ``True``, discard complex roots derived from negative radicands. :param n: Optional precision used in the classification of real radicands via :func:`ge` and in cubic root computation. :return: A list of real roots of :math:`z^4 + a_3 z^3 + a_2 z^2 + a_1 z + a_0 = 0`. .. py:function:: polynomial_roots(poly, x, *, real_only = True, n = None) Compute roots of a univariate polynomial up to degree 4. The input expression is converted to :class:`sympy.Poly` in ``x`` and dispatched to the appropriate specialized solver: * degree 4: :func:`quartic_roots` * degree 3: :func:`cubic_roots` * degree 2: :func:`quadratic_roots` * degree 1: explicit linear solution * degree 0: either no solution or infinitely many solutions The returned dictionary maps each root to its multiplicity using :class:`collections.Counter`. :param poly: Polynomial expression in the variable ``x``. :param x: Polynomial variable. :param real_only: If ``True``, only real roots are produced by the specialized solvers. :param n: Optional precision forwarded to the root solvers. :return: A mapping ``{root: multiplicity}``. :raises ValueError: If the polynomial degree is greater than 4 or for the identically zero polynomial (infinitely many solutions). .. py:function:: _sylvester_matrix(p, q) Construct the Sylvester matrix of two polynomials :math:`p(x), q(x)`. The input polynomials must be in the same variable and given as :class:`sympy.Poly` instances. The resulting square matrix has size :math:`(\deg(p) + \deg(q)) × (\deg(p) + \deg(q))` and is constructed from shifted coefficient rows. .. py:function:: resultant(f, g, x, y, n = None) Resultant :math:`\operatorname{res}_y(f, g)`. Eliminates variable :math:`y` from the system :math:`f(x, y) = 0`, :math:`g(x, y) = 0`. If both expressions are real polynomials in :math:`y`, the resultant is computed as the determinant of the Sylvester matrix, then numerically evaluated with :func:`evalf` using precision ``n``. Coefficients that are numerically zero (according to :func:`is_zero` with precision ``n``) are normalized to exact zero. Otherwise, :func:`sympy.resultant` is used. .. py:function:: expand(expr) Algebraically expand a SymPy expression. Thin wrapper around :func:`sympy.expand`.