def test_splitfactor(): p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 + (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t, field=True) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]}) assert splitfactor(p, DE) == (Poly(4*x**4*t**3 + (-8*x**3 - 4*x**4)*t**2 + (4*x**2 + 8*x**3)*t - 4*x**2, t, domain='ZZ(x)'), Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t, domain='ZZ(x)')) assert splitfactor(Poly(x, t), DE) == (Poly(x, t), Poly(1, t)) r = Poly(-4*x**4*z**2 + 4*x**6*z**2 - z*x**3 - 4*x**5*z**3 + 4*x**3*z**3 + x**4 + z*x**5 - x**6, t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) assert splitfactor(r, DE, coefficientD=True) == \ (Poly(x*z - x**2 - z*x**3 + x**4, t), Poly(-x**2 + 4*x**2*z**2, t)) assert splitfactor_sqf(r, DE, coefficientD=True) == \ (((Poly(x*z - x**2 - z*x**3 + x**4, t), 1),), ((Poly(-x**2 + 4*x**2*z**2, t), 1),)) assert splitfactor(Poly(0, t), DE) == (Poly(0, t), Poly(1, t)) assert splitfactor_sqf(Poly(0, t), DE) == (((Poly(0, t), 1),), ())
def roots_quintic(f): """ Calulate exact roots of a solvable quintic """ result = [] coeff_5, coeff_4, p, q, r, s = f.all_coeffs() # Eqn must be of the form x^5 + px^3 + qx^2 + rx + s if coeff_4: return result if coeff_5 != 1: l = [p / coeff_5, q / coeff_5, r / coeff_5, s / coeff_5] if not all(coeff.is_Rational for coeff in l): return result f = Poly(f / coeff_5) quintic = PolyQuintic(f) # Eqn standardized. Algo for solving starts here if not f.is_irreducible: return result f20 = quintic.f20 # Check if f20 has linear factors over domain Z if f20.is_irreducible: return result # Now, we know that f is solvable for _factor in f20.factor_list()[1]: if _factor[0].is_linear: theta = _factor[0].root(0) break d = discriminant(f) delta = sqrt(d) # zeta = a fifth root of unity zeta1, zeta2, zeta3, zeta4 = quintic.zeta T = quintic.T(theta, d) tol = S(1e-10) alpha = T[1] + T[2] * delta alpha_bar = T[1] - T[2] * delta beta = T[3] + T[4] * delta beta_bar = T[3] - T[4] * delta disc = alpha**2 - 4 * beta disc_bar = alpha_bar**2 - 4 * beta_bar l0 = quintic.l0(theta) l1 = _quintic_simplify((-alpha + sqrt(disc)) / S(2)) l4 = _quintic_simplify((-alpha - sqrt(disc)) / S(2)) l2 = _quintic_simplify((-alpha_bar + sqrt(disc_bar)) / S(2)) l3 = _quintic_simplify((-alpha_bar - sqrt(disc_bar)) / S(2)) order = quintic.order(theta, d) test = (order * delta.n()) - ((l1.n() - l4.n()) * (l2.n() - l3.n())) # Comparing floats # Problems importing on top from sympy.utilities.randtest import comp if not comp(test, 0, tol): l2, l3 = l3, l2 # Now we have correct order of l's R1 = l0 + l1 * zeta1 + l2 * zeta2 + l3 * zeta3 + l4 * zeta4 R2 = l0 + l3 * zeta1 + l1 * zeta2 + l4 * zeta3 + l2 * zeta4 R3 = l0 + l2 * zeta1 + l4 * zeta2 + l1 * zeta3 + l3 * zeta4 R4 = l0 + l4 * zeta1 + l3 * zeta2 + l2 * zeta3 + l1 * zeta4 Res = [None, [None] * 5, [None] * 5, [None] * 5, [None] * 5] Res_n = [None, [None] * 5, [None] * 5, [None] * 5, [None] * 5] sol = Symbol('sol') # Simplifying improves performace a lot for exact expressions R1 = _quintic_simplify(R1) R2 = _quintic_simplify(R2) R3 = _quintic_simplify(R3) R4 = _quintic_simplify(R4) # Solve imported here. Causing problems if imported as 'solve' # and hence the changed name from sympy.solvers.solvers import solve as _solve a, b = symbols('a b', cls=Dummy) _sol = _solve(sol**5 - a - I * b, sol) for i in range(5): _sol[i] = factor(_sol[i]) R1 = R1.as_real_imag() R2 = R2.as_real_imag() R3 = R3.as_real_imag() R4 = R4.as_real_imag() for i, root in enumerate(_sol): Res[1][i] = _quintic_simplify(root.subs({a: R1[0], b: R1[1]})) Res[2][i] = _quintic_simplify(root.subs({a: R2[0], b: R2[1]})) Res[3][i] = _quintic_simplify(root.subs({a: R3[0], b: R3[1]})) Res[4][i] = _quintic_simplify(root.subs({a: R4[0], b: R4[1]})) for i in range(1, 5): for j in range(5): Res_n[i][j] = Res[i][j].n() Res[i][j] = _quintic_simplify(Res[i][j]) r1 = Res[1][0] r1_n = Res_n[1][0] for i in range(5): if comp(im(r1_n * Res_n[4][i]), 0, tol): r4 = Res[4][i] break u, v = quintic.uv(theta, d) sqrt5 = math.sqrt(5) # Now we have various Res values. Each will be a list of five # values. We have to pick one r value from those five for each Res u, v = quintic.uv(theta, d) testplus = (u + v * delta * sqrt(5)).n() testminus = (u - v * delta * sqrt(5)).n() # Evaluated numbers suffixed with _n # We will use evaluated numbers for calculation. Much faster. r4_n = r4.n() r2 = r3 = None for i in range(5): r2temp_n = Res_n[2][i] for j in range(5): # Again storing away the exact number and using # evaluated numbers in computations r3temp_n = Res_n[3][j] if (comp(r1_n * r2temp_n**2 + r4_n * r3temp_n**2 - testplus, 0, tol) and comp( r3temp_n * r1_n**2 + r2temp_n * r4_n**2 - testminus, 0, tol)): r2 = Res[2][i] r3 = Res[3][j] break if r2: break # Now, we have r's so we can get roots x1 = (r1 + r2 + r3 + r4) / 5 x2 = (r1 * zeta4 + r2 * zeta3 + r3 * zeta2 + r4 * zeta1) / 5 x3 = (r1 * zeta3 + r2 * zeta1 + r3 * zeta4 + r4 * zeta2) / 5 x4 = (r1 * zeta2 + r2 * zeta4 + r3 * zeta1 + r4 * zeta3) / 5 x5 = (r1 * zeta1 + r2 * zeta2 + r3 * zeta3 + r4 * zeta4) / 5 result = [x1, x2, x3, x4, x5] # Now check if solutions are distinct saw = set() for r in result: r = r.n(2) if r in saw: # Roots were identical. Abort, return [] # and fall back to usual solve return [] saw.add(r) return result
def test_sympy__polys__polytools__Poly(): from sympy.polys.polytools import Poly assert _test_args(Poly(2, x, y))
def test_RootOf_real_roots(): assert Poly(x**5 + x + 1).real_roots() == [RootOf(x**3 - x**2 + 1, 0)] assert Poly(x**5 + x + 1).real_roots(radicals=False) == [RootOf(x**3 - x**2 + 1, 0)]
def test_issue_8316(): f = Poly(7 * x**8 - 9) assert len(f.all_roots()) == 8 f = Poly(7 * x**8 - 10) assert len(f.all_roots()) == 8
def test__imag_count(): from sympy.polys.rootoftools import _imag_count_of_factor def imag_count(p): return sum( [_imag_count_of_factor(f) * m for f, m in p.factor_list()[1]]) assert imag_count(Poly(x**6 + 10 * x**2 + 1)) == 2 assert imag_count(Poly(x**2)) == 0 assert imag_count(Poly([1] * 3 + [-1], x)) == 0 assert imag_count(Poly(x**3 + 1)) == 0 assert imag_count(Poly(x**2 + 1)) == 2 assert imag_count(Poly(x**2 - 1)) == 0 assert imag_count(Poly(x**4 - 1)) == 2 assert imag_count(Poly(x**4 + 1)) == 0 assert imag_count(Poly([1, 2, 3], x)) == 0 assert imag_count(Poly(x**3 + x + 1)) == 0 assert imag_count(Poly(x**4 + x + 1)) == 0 def q(r1, r2, p): return Poly(((x - r1) * (x - r2)).subs(x, x**p), x) assert imag_count(q(-1, -2, 2)) == 4 assert imag_count(q(-1, 2, 2)) == 2 assert imag_count(q(1, 2, 2)) == 0 assert imag_count(q(1, 2, 4)) == 4 assert imag_count(q(-1, 2, 4)) == 2 assert imag_count(q(-1, -2, 4)) == 0
def primitive_element(extension, x=None, **args): """Construct a common number field for all extensions. """ if not extension: raise ValueError("can't compute primitive element for empty extension") if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly if not args.get('ex', False): gen, coeffs = extension[0], [1] # XXX when minimal_polynomial is extended to work # with AlgebraicNumbers this test can be removed if isinstance(gen, AlgebraicNumber): g = gen.minpoly.replace(x) else: g = minimal_polynomial(gen, x, polys=True) for ext in extension[1:]: _, factors = factor_list(g, extension=ext) g = _choose_factor(factors, x, gen) s, _, g = g.sqf_norm() gen += s * ext coeffs.append(s) if not args.get('polys', False): return g.as_expr(), coeffs else: return cls(g), coeffs generator = numbered_symbols('y', cls=Dummy) F, Y = [], [] for ext in extension: y = next(generator) if ext.is_Poly: if ext.is_univariate: f = ext.as_expr(y) else: raise ValueError("expected minimal polynomial, got %s" % ext) else: f = minpoly(ext, y) F.append(f) Y.append(y) coeffs_generator = args.get('coeffs', _coeffs_generator) for coeffs in coeffs_generator(len(Y)): f = x - sum([c * y for c, y in zip(coeffs, Y)]) G = groebner(F + [f], Y + [x], order='lex', field=True) H, g = G[:-1], cls(G[-1], x, domain='QQ') for i, (h, y) in enumerate(zip(H, Y)): try: H[i] = Poly(y - h, x, domain='QQ').all_coeffs() # XXX: composite=False except CoercionFailed: # pragma: no cover break # G is not a triangular set else: break else: # pragma: no cover raise RuntimeError("run out of coefficient configurations") _, g = g.clear_denoms() if not args.get('polys', False): return g.as_expr(), coeffs, H else: return g, coeffs, H
def test_smith_normal_deprecated(): from sympy.polys.solvers import RawMatrix as Matrix with warns_deprecated_sympy(): m = Matrix([[12, 6, 4,8],[3,9,6,12],[2,16,14,28],[20,10,10,20]]) setattr(m, 'ring', ZZ) with warns_deprecated_sympy(): smf = Matrix([[1, 0, 0, 0], [0, 10, 0, 0], [0, 0, -30, 0], [0, 0, 0, 0]]) assert smith_normal_form(m) == smf x = Symbol('x') with warns_deprecated_sympy(): m = Matrix([[Poly(x-1), Poly(1, x),Poly(-1,x)], [0, Poly(x), Poly(-1,x)], [Poly(0,x),Poly(-1,x),Poly(x)]]) setattr(m, 'ring', QQ[x]) invs = (Poly(1, x, domain='QQ'), Poly(x - 1, domain='QQ'), Poly(x**2 - 1, domain='QQ')) assert invariant_factors(m) == invs with warns_deprecated_sympy(): m = Matrix([[2, 4]]) setattr(m, 'ring', ZZ) with warns_deprecated_sympy(): smf = Matrix([[2, 0]]) assert smith_normal_form(m) == smf
def _eval_scalar_mul(self, other): mat = [ Poly(a.as_expr() * other, *a.gens) if isinstance(a, Poly) else a * other for a in self._mat ] return self.__class__(self.rows, self.cols, mat, copy=False)
def _transform(cls, expr, x): """Transform an expression to a polynomial. """ poly = Poly(expr, x, greedy=False) return _rootof_preprocess(poly)
""" allowed_flags(args, []) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed, exc: return exc.expr form, gen = S.Zero, F.gen if F.is_univariate: for coeff in F.all_coeffs(): form = form * gen + coeff else: F, gens = Poly(F, gen), gens[1:] for coeff in F.all_coeffs(): form = form * gen + horner(coeff, *gens, **args) return form def interpolate(data, x): """ Construct an interpolating polynomial for the data points. Examples ======== >>> from sympy.polys.polyfuncs import interpolate
def __new__(cls, f, x=None, indices=None, radicals=True, expand=True): """Construct a new ``RootOf`` object for ``k``-th root of ``f``. """ if indices is None and (not isinstance(x, Basic) or x.is_Integer): x, indices = None, x poly = Poly(f, x, greedy=False, expand=expand) if not poly.is_univariate: raise PolynomialError("only univariate polynomials are allowed") degree = poly.degree() if degree <= 0: raise PolynomialError("can't construct RootOf object for %s" % f) if indices is not None and indices is not True: if hasattr(indices, '__iter__'): indices, iterable = list(indices), True else: indices, iterable = [indices], False indices = map(int, indices) for i, index in enumerate(indices): if index < -degree or index >= degree: raise IndexError( "root index out of [%d, %d] range, got %d" % (-degree, degree - 1, index)) elif index < 0: indices[i] += degree else: iterable = True if indices is True: indices = range(degree) dom = poly.get_domain() if not dom.is_Exact: poly = poly.to_exact() roots = roots_trivial(poly, radicals) if roots is not None: if indices is not None: result = [roots[index] for index in indices] else: result = [root for root in roots if root.is_real] else: coeff, poly = _rootof_preprocess(poly) dom = poly.get_domain() if not dom.is_ZZ: raise NotImplementedError("RootOf is not supported over %s" % dom) result = [] for data in _rootof_data(poly, indices): poly, index, pointer, conjugate = data roots = roots_trivial(poly, radicals) if roots is not None: result.append(coeff * roots[index]) else: result.append(coeff * cls._new(poly, index, pointer, conjugate)) if not iterable: return result[0] else: return result
def reduce_poly(self, f, gen=None): r""" Reduce a univariate :py:class:`~.Poly` *f*, or an :py:class:`~.Expr` expressing the same, modulo this :py:class:`~.PrimeIdeal`. Explanation =========== If our second generator $\alpha$ is zero, then we simply reduce the coefficients of *f* mod the rational prime $p$ lying under this ideal. Otherwise we first reduce *f* mod $\alpha$ (as a polynomial in the same variable as *f*), and then mod $p$. Examples ======== >>> from sympy import QQ, cyclotomic_poly, symbols >>> zeta = symbols('zeta') >>> Phi = cyclotomic_poly(7, zeta) >>> k = QQ.algebraic_field((Phi, zeta)) >>> P = k.primes_above(11) >>> frp = P[0] >>> B = k.integral_basis(fmt='sympy') >>> print([frp.reduce_poly(b, zeta) for b in B]) [1, zeta, zeta**2, -5*zeta**2 - 4*zeta + 1, -zeta**2 - zeta - 5, 4*zeta**2 - zeta - 1] Parameters ========== f : :py:class:`~.Poly`, :py:class:`~.Expr` The univariate polynomial to be reduced. gen : :py:class:`~.Symbol`, None, optional (default=None) Symbol to use as the variable in the polynomials. If *f* is a :py:class:`~.Poly` or a non-constant :py:class:`~.Expr`, this replaces its variable. If *f* is a constant :py:class:`~.Expr`, then *gen* must be supplied. Returns ======= :py:class:`~.Poly`, :py:class:`~.Expr` Type is same as that of given *f*. If returning a :py:class:`~.Poly`, its domain will be the finite field $\mathbb{F}_p$. Raises ====== GeneratorsNeeded If *f* is a constant :py:class:`~.Expr` and *gen* is ``None``. NotImplementedError If *f* is other than :py:class:`~.Poly` or :py:class:`~.Expr`, or is not univariate. """ if isinstance(f, Expr): try: g = Poly(f) except GeneratorsNeeded as e: if gen is None: raise e from None g = Poly(f, gen) return self.reduce_poly(g).as_expr() if isinstance(f, Poly) and f.is_univariate: a = self.alpha.poly(f.gen) if a != 0: f = f.rem(a) return f.set_modulus(self.p) raise NotImplementedError
def round_two(T, radicals=None): r""" Zassenhaus's "Round 2" algorithm. Explanation =========== Carry out Zassenhaus's "Round 2" algorithm on a monic irreducible polynomial *T* over :ref:`ZZ`. This computes an integral basis and the discriminant for the field $K = \mathbb{Q}[x]/(T(x))$. Alternatively, you may pass an :py:class:`~.AlgebraicField` instance, in place of the polynomial *T*, in which case the algorithm is applied to the minimal polynomial for the field's primitive element. Ordinarily this function need not be called directly, as one can instead access the :py:meth:`~.AlgebraicField.maximal_order`, :py:meth:`~.AlgebraicField.integral_basis`, and :py:meth:`~.AlgebraicField.discriminant` methods of an :py:class:`~.AlgebraicField`. Examples ======== Working through an AlgebraicField: >>> from sympy import Poly, QQ >>> from sympy.abc import x >>> T = Poly(x ** 3 + x ** 2 - 2 * x + 8) >>> K = QQ.alg_field_from_poly(T, "theta") >>> print(K.maximal_order()) Submodule[[2, 0, 0], [0, 2, 0], [0, 1, 1]]/2 >>> print(K.discriminant()) -503 >>> print(K.integral_basis(fmt='sympy')) [1, theta, theta/2 + theta**2/2] Calling directly: >>> from sympy import Poly >>> from sympy.abc import x >>> from sympy.polys.numberfields.basis import round_two >>> T = Poly(x ** 3 + x ** 2 - 2 * x + 8) >>> print(round_two(T)) (Submodule[[2, 0, 0], [0, 2, 0], [0, 1, 1]]/2, -503) The nilradicals mod $p$ that are sometimes computed during the Round Two algorithm may be useful in further calculations. Pass a dictionary under `radicals` to receive these: >>> T = Poly(x**3 + 3*x**2 + 5) >>> rad = {} >>> ZK, dK = round_two(T, radicals=rad) >>> print(rad) {3: Submodule[[-1, 1, 0], [-1, 0, 1]]} Parameters ========== T : :py:class:`~.Poly`, :py:class:`~.AlgebraicField` Either (1) the irreducible monic polynomial over :ref:`ZZ` defining the number field, or (2) an :py:class:`~.AlgebraicField` representing the number field itself. radicals : dict, optional This is a way for any $p$-radicals (if computed) to be returned by reference. If desired, pass an empty dictionary. If the algorithm reaches the point where it computes the nilradical mod $p$ of the ring of integers $Z_K$, then an $\mathbb{F}_p$-basis for this ideal will be stored in this dictionary under the key ``p``. This can be useful for other algorithms, such as prime decomposition. Returns ======= Pair ``(ZK, dK)``, where: ``ZK`` is a :py:class:`~sympy.polys.numberfields.modules.Submodule` representing the maximal order. ``dK`` is the discriminant of the field $K = \mathbb{Q}[x]/(T(x))$. See Also ======== .AlgebraicField.maximal_order .AlgebraicField.integral_basis .AlgebraicField.discriminant References ========== .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* """ K = None if isinstance(T, AlgebraicField): K, T = T, T.ext.minpoly_of_element() if T.domain == QQ: try: T = Poly(T, domain=ZZ) except CoercionFailed: pass # Let the error be raised by the next clause. if (not T.is_univariate or not T.is_irreducible or not T.is_monic or not T.domain == ZZ): raise ValueError( 'Round 2 requires a monic irreducible univariate polynomial over ZZ.' ) n = T.degree() D = T.discriminant() D_modulus = ZZ.from_sympy(abs(D)) # D must be 0 or 1 mod 4 (see Cohen Sec 4.4), which ensures we can write # it in the form D = D_0 * F**2, where D_0 is 1 or a fundamental discriminant. _, F = extract_fundamental_discriminant(D) Ztheta = PowerBasis(K or T) H = Ztheta.whole_submodule() nilrad = None while F: # Next prime: p, e = F.popitem() U_bar, m = _apply_Dedekind_criterion(T, p) if m == 0: continue # For a given prime p, the first enlargement of the order spanned by # the current basis can be done in a simple way: U = Ztheta.element_from_poly(Poly(U_bar, domain=ZZ)) # TODO: # Theory says only first m columns of the U//p*H term below are needed. # Could be slightly more efficient to use only those. Maybe `Submodule` # class should support a slice operator? H = H.add(U // p * H, hnf_modulus=D_modulus) if e <= m: continue # A second, and possibly more, enlargements for p will be needed. # These enlargements require a more involved procedure. q = p while q < n: q *= p H1, nilrad = _second_enlargement(H, p, q) while H1 != H: H = H1 H1, nilrad = _second_enlargement(H, p, q) # Note: We do not store all nilradicals mod p, only the very last. This is # because, unless computed against the entire integral basis, it might not # be accurate. (In other words, if H was not already equal to ZK when we # passed it to `_second_enlargement`, then we can't trust the nilradical # so computed.) Example: if T(x) = x ** 3 + 15 * x ** 2 - 9 * x + 13, then # F is divisible by 2, 3, and 7, and the nilradical mod 2 as computed above # will not be accurate for the full, maximal order ZK. if nilrad is not None and isinstance(radicals, dict): radicals[p] = nilrad ZK = H # Pre-set expensive boolean properties which we already know to be true: ZK._starts_with_unity = True ZK._is_sq_maxrank_HNF = True dK = (D * ZK.matrix.det()**2) // ZK.denom**(2 * n) return ZK, dK
def polytope_integrate(poly, expr=None, *, clockwise=False, max_degree=None): """Integrates polynomials over 2/3-Polytopes. Explanation =========== This function accepts the polytope in ``poly`` and the function in ``expr`` (uni/bi/trivariate polynomials are implemented) and returns the exact integral of ``expr`` over ``poly``. Parameters ========== poly : The input Polygon. expr : The input polynomial. clockwise : Binary value to sort input points of 2-Polytope clockwise.(Optional) max_degree : The maximum degree of any monomial of the input polynomial.(Optional) Examples ======== >>> from sympy.abc import x, y >>> from sympy import Point, Polygon >>> from sympy.integrals.intpoly import polytope_integrate >>> polygon = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)) >>> polys = [1, x, y, x*y, x**2*y, x*y**2] >>> expr = x*y >>> polytope_integrate(polygon, expr) 1/4 >>> polytope_integrate(polygon, polys, max_degree=3) {1: 1, x: 1/2, y: 1/2, x*y: 1/4, x*y**2: 1/6, x**2*y: 1/6} """ if clockwise: if isinstance(poly, Polygon): poly = Polygon(*point_sort(poly.vertices), evaluate=False) else: raise TypeError("clockwise=True works for only 2-Polytope" "V-representation input") if isinstance(poly, Polygon): # For Vertex Representation(2D case) hp_params = hyperplane_parameters(poly) facets = poly.sides elif len(poly[0]) == 2: # For Hyperplane Representation(2D case) plen = len(poly) if len(poly[0][0]) == 2: intersections = [ intersection(poly[(i - 1) % plen], poly[i], "plane2D") for i in range(0, plen) ] hp_params = poly lints = len(intersections) facets = [ Segment2D(intersections[i], intersections[(i + 1) % lints]) for i in range(0, lints) ] else: raise NotImplementedError("Integration for H-representation 3D" "case not implemented yet.") else: # For Vertex Representation(3D case) vertices = poly[0] facets = poly[1:] hp_params = hyperplane_parameters(facets, vertices) if max_degree is None: if expr is None: raise TypeError( 'Input expression must be a valid SymPy expression') return main_integrate3d(expr, facets, vertices, hp_params) if max_degree is not None: result = {} if expr is not None: f_expr = [] for e in expr: _ = decompose(e) if len(_) == 1 and not _.popitem()[0]: f_expr.append(e) elif Poly(e).total_degree() <= max_degree: f_expr.append(e) expr = f_expr if not isinstance(expr, list) and expr is not None: raise TypeError('Input polynomials must be list of expressions') if len(hp_params[0][0]) == 3: result_dict = main_integrate3d(0, facets, vertices, hp_params, max_degree) else: result_dict = main_integrate(0, facets, hp_params, max_degree) if expr is None: return result_dict for poly in expr: poly = _sympify(poly) if poly not in result: if poly.is_zero: result[S.Zero] = S.Zero continue integral_value = S.Zero monoms = decompose(poly, separate=True) for monom in monoms: monom = nsimplify(monom) coeff, m = strip(monom) integral_value += result_dict[m] * coeff result[poly] = integral_value return result if expr is None: raise TypeError('Input expression must be a valid SymPy expression') return main_integrate(expr, facets, hp_params)
def test_shape(): c0, c1, c2 = symbols('c0:3') x = Symbol('x') assert CompanionMatrix(Poly([1, c0], x)).shape == (1, 1) assert CompanionMatrix(Poly([1, c1, c0], x)).shape == (2, 2) assert CompanionMatrix(Poly([1, c2, c1, c0], x)).shape == (3, 3)
def bivariate_type(f, x, y, **kwargs): """Given an expression, f, 3 tests will be done to see what type of composite bivariate it might be, options for u(x, y) are:: x*y x+y x*y+x x*y+y If it matches one of these types, ``u(x, y)``, ``P(u)`` and dummy variable ``u`` will be returned. Solving ``P(u)`` for ``u`` and equating the solutions to ``u(x, y)`` and then solving for ``x`` or ``y`` is equivalent to solving the original expression for ``x`` or ``y``. If ``x`` and ``y`` represent two functions in the same variable, e.g. ``x = g(t)`` and ``y = h(t)``, then if ``u(x, y) - p`` can be solved for ``t`` then these represent the solutions to ``P(u) = 0`` when ``p`` are the solutions of ``P(u) = 0``. Only positive values of ``u`` are considered. Examples ======== >>> from sympy.solvers.solvers import solve >>> from sympy.solvers.bivariate import bivariate_type >>> from sympy.abc import x, y >>> eq = (x**2 - 3).subs(x, x + y) >>> bivariate_type(eq, x, y) (x + y, _u**2 - 3, _u) >>> uxy, pu, u = _ >>> usol = solve(pu, u); usol [sqrt(3)] >>> [solve(uxy - s) for s in solve(pu, u)] [[{x: -y + sqrt(3)}]] >>> all(eq.subs(s).equals(0) for sol in _ for s in sol) True """ u = Dummy('u', positive=True) if kwargs.pop('first', True): p = Poly(f, x, y) f = p.as_expr() _x = Dummy() _y = Dummy() rv = bivariate_type(Poly(f.subs({x: _x, y: _y}), _x, _y), _x, _y, first=False) if rv: reps = {_x: x, _y: y} return rv[0].xreplace(reps), rv[1].xreplace(reps), rv[2] return p = f f = p.as_expr() # f(x*y) args = Add.make_args(p.as_expr()) new = [] for a in args: a = _mexpand(a.subs(x, u/y)) free = a.free_symbols if x in free or y in free: break new.append(a) else: return x*y, Add(*new), u def ok(f, v, c): new = _mexpand(f.subs(v, c)) free = new.free_symbols return None if (x in free or y in free) else new # f(a*x + b*y) new = [] d = p.degree(x) if p.degree(y) == d: a = root(p.coeff_monomial(x**d), d) b = root(p.coeff_monomial(y**d), d) new = ok(f, x, (u - b*y)/a) if new is not None: return a*x + b*y, new, u # f(a*x*y + b*y) new = [] d = p.degree(x) if p.degree(y) == d: for itry in range(2): a = root(p.coeff_monomial(x**d*y**d), d) b = root(p.coeff_monomial(y**d), d) new = ok(f, x, (u - b*y)/a/y) if new is not None: return a*x*y + b*y, new, u x, y = y, x
def pole_zero_numerical_data(system): """ Returns the numerical data of poles and zeros of the system. It is internally used by ``pole_zero_plot`` to get the data for plotting poles and zeros. Users can use this data to further analyse the dynamics of the system or plot using a different backend/plotting-module. Parameters ========== system : SISOLinearTimeInvariant The system for which the pole-zero data is to be computed. Returns ======= tuple : (zeros, poles) zeros = Zeros of the system. NumPy array of complex numbers. poles = Poles of the system. NumPy array of complex numbers. Raises ====== NotImplementedError When a SISO LTI system is not passed. When time delay terms are present in the system. ValueError When more than one free symbol is present in the system. The only variable in the transfer function should be the variable of the Laplace transform. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import pole_zero_numerical_data >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) >>> pole_zero_numerical_data(tf1) # doctest: +SKIP ([-0.+1.j 0.-1.j], [-2. +0.j -0.5+0.8660254j -0.5-0.8660254j -1. +0.j ]) See Also ======== pole_zero_plot """ _check_system(system) system = system.doit() # Get the equivalent TransferFunction object. num_poly = Poly(system.num, system.var).all_coeffs() den_poly = Poly(system.den, system.var).all_coeffs() num_poly = np.array(num_poly, dtype=np.complex128) den_poly = np.array(den_poly, dtype=np.complex128) zeros = np.roots(num_poly) poles = np.roots(den_poly) return zeros, poles
def q(r1, r2, p): return Poly(((x - r1) * (x - r2)).subs(x, x**p), x)
def roots_quartic(f): r""" Returns a list of roots of a quartic polynomial. There are many references for solving quartic expressions available [1-5]. This reviewer has found that many of them require one to select from among 2 or more possible sets of solutions and that some solutions work when one is searching for real roots but don't work when searching for complex roots (though this is not always stated clearly). The following routine has been tested and found to be correct for 0, 2 or 4 complex roots. The quasisymmetric case solution [6] looks for quartics that have the form `x**4 + A*x**3 + B*x**2 + C*x + D = 0` where `(C/A)**2 = D`. Although there is a general solution, simpler results can be obtained for certain values of the coefficients. In all cases, 4 roots are returned: 1) `f = c + a*(a**2/8 - b/2) == 0` 2) `g = d - a*(a*(3*a**2/256 - b/16) + c/4) = 0` 3) if `f != 0` and `g != 0` and `p = -d + a*c/4 - b**2/12` then a) `p == 0` b) `p != 0` **Examples** >>> from sympy import Poly, symbols, I >>> from sympy.polys.polyroots import roots_quartic >>> r = roots_quartic(Poly('x**4-6*x**3+17*x**2-26*x+20')) >>> # 4 complex roots: 1+-I*sqrt(3), 2+-I >>> sorted(str(tmp.evalf(n=2)) for tmp in r) ['1.0 + 1.7*I', '1.0 - 1.7*I', '2.0 + I', '2.0 - 1.0*I'] **References** 1. http://mathforum.org/dr.math/faq/faq.cubic.equations.html 2. http://en.wikipedia.org/wiki/Quartic_function#Summary_of_Ferrari.27s_method 3. http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html 4. http://staff.bath.ac.uk/masjhd/JHD-CA.pdf 5. http://www.albmath.org/files/Math_5713.pdf 6. http://www.statemaster.com/encyclopedia/Quartic-equation """ _, a, b, c, d = f.monic().all_coeffs() if not d: return [S.Zero] + roots([1, a, b, c], multiple=True) elif (c / a)**2 == d: x, m = f.gen, c / a g = Poly(x**2 + a * x + b - 2 * m, x) z1, z2 = roots_quadratic(g) h1 = Poly(x**2 - z1 * x + m, x) h2 = Poly(x**2 - z2 * x + m, x) r1 = roots_quadratic(h1) r2 = roots_quadratic(h2) return r1 + r2 else: a2 = a**2 e = b - 3 * a2 / 8 f = c + a * (a2 / 8 - b / 2) g = d - a * (a * (3 * a2 / 256 - b / 16) + c / 4) aon4 = a / 4 ans = [] if f is S.Zero: y1, y2 = [tmp**S.Half for tmp in roots([1, e, g], multiple=True)] return [tmp - aon4 for tmp in [-y1, -y2, y1, y2]] if g is S.Zero: y = [S.Zero] + roots([1, 0, e, f], multiple=True) return [tmp - aon4 for tmp in y] else: p = -e**2 / 12 - g q = -e**3 / 108 + e * g / 3 - f**2 / 8 TH = Rational(1, 3) if p is S.Zero: y = -5 * e / 6 - q**TH else: # with p !=0 then u below is not 0 root = sqrt(q**2 / 4 + p**3 / 27) r = -q / 2 + root # or -q/2 - root u = r**TH # primary root of solve(x**3-r, x) y = -5 * e / 6 + u - p / u / 3 w = sqrt(e + 2 * y) arg1 = 3 * e + 2 * y arg2 = 2 * f / w for s in [-1, 1]: root = sqrt(-(arg1 + s * arg2)) for t in [-1, 1]: ans.append((s * w - t * root) / 2 - aon4) return ans
def test_RootOf___new__(): assert RootOf(x, 0) == 0 assert RootOf(x, -1) == 0 assert RootOf(x, S.Zero) == 0 assert RootOf(x - 1, 0) == 1 assert RootOf(x - 1, -1) == 1 assert RootOf(x + 1, 0) == -1 assert RootOf(x + 1, -1) == -1 assert RootOf(x**2 + 2 * x + 3, 0) == -1 - I * sqrt(2) assert RootOf(x**2 + 2 * x + 3, 1) == -1 + I * sqrt(2) assert RootOf(x**2 + 2 * x + 3, -1) == -1 + I * sqrt(2) assert RootOf(x**2 + 2 * x + 3, -2) == -1 - I * sqrt(2) r = RootOf(x**2 + 2 * x + 3, 0, radicals=False) assert isinstance(r, RootOf) is True r = RootOf(x**2 + 2 * x + 3, 1, radicals=False) assert isinstance(r, RootOf) is True r = RootOf(x**2 + 2 * x + 3, -1, radicals=False) assert isinstance(r, RootOf) is True r = RootOf(x**2 + 2 * x + 3, -2, radicals=False) assert isinstance(r, RootOf) is True assert RootOf((x - 1) * (x + 1), 0, radicals=False) == -1 assert RootOf((x - 1) * (x + 1), 1, radicals=False) == 1 assert RootOf((x - 1) * (x + 1), -1, radicals=False) == 1 assert RootOf((x - 1) * (x + 1), -2, radicals=False) == -1 assert RootOf((x - 1) * (x + 1), 0, radicals=True) == -1 assert RootOf((x - 1) * (x + 1), 1, radicals=True) == 1 assert RootOf((x - 1) * (x + 1), -1, radicals=True) == 1 assert RootOf((x - 1) * (x + 1), -2, radicals=True) == -1 assert RootOf((x - 1) * (x**3 + x + 3), 0) == RootOf(x**3 + x + 3, 0) assert RootOf((x - 1) * (x**3 + x + 3), 1) == 1 assert RootOf((x - 1) * (x**3 + x + 3), 2) == RootOf(x**3 + x + 3, 1) assert RootOf((x - 1) * (x**3 + x + 3), 3) == RootOf(x**3 + x + 3, 2) assert RootOf((x - 1) * (x**3 + x + 3), -1) == RootOf(x**3 + x + 3, 2) assert RootOf((x - 1) * (x**3 + x + 3), -2) == RootOf(x**3 + x + 3, 1) assert RootOf((x - 1) * (x**3 + x + 3), -3) == 1 assert RootOf((x - 1) * (x**3 + x + 3), -4) == RootOf(x**3 + x + 3, 0) assert RootOf(x**4 + 3 * x**3, 0) == -3 assert RootOf(x**4 + 3 * x**3, 1) == 0 assert RootOf(x**4 + 3 * x**3, 2) == 0 assert RootOf(x**4 + 3 * x**3, 3) == 0 raises(GeneratorsNeeded, lambda: RootOf(0, 0)) raises(GeneratorsNeeded, lambda: RootOf(1, 0)) raises(PolynomialError, lambda: RootOf(Poly(0, x), 0)) raises(PolynomialError, lambda: RootOf(Poly(1, x), 0)) raises(PolynomialError, lambda: RootOf(x - y, 0)) raises(NotImplementedError, lambda: RootOf(x**3 - x + sqrt(2), 0)) raises(NotImplementedError, lambda: RootOf(x**3 - x + I, 0)) raises(IndexError, lambda: RootOf(x**2 - 1, -4)) raises(IndexError, lambda: RootOf(x**2 - 1, -3)) raises(IndexError, lambda: RootOf(x**2 - 1, 2)) raises(IndexError, lambda: RootOf(x**2 - 1, 3)) raises(ValueError, lambda: RootOf(x**2 - 1, x)) assert RootOf(Poly(x - y, x), 0) == y assert RootOf(Poly(x**2 - y, x), 0) == -sqrt(y) assert RootOf(Poly(x**2 - y, x), 1) == sqrt(y) assert RootOf(Poly(x**3 - y, x), 0) == y**Rational(1, 3) assert RootOf(y * x**3 + y * x + 2 * y, x, 0) == -1 raises(NotImplementedError, lambda: RootOf(x**3 + x + 2 * y, x, 0)) assert RootOf(x**3 + x + 1, 0).is_commutative is True
def roots(f, *gens, **flags): """ Computes symbolic roots of a univariate polynomial. Given a univariate polynomial f with symbolic coefficients (or a list of the polynomial's coefficients), returns a dictionary with its roots and their multiplicities. Only roots expressible via radicals will be returned. To get a complete set of roots use RootOf class or numerical methods instead. By default cubic and quartic formulas are used in the algorithm. To disable them because of unreadable output set `cubics=False` or `quartics=False` respectively. To get roots from a specific domain set the `filter` flag with one of the following specifiers: Z, Q, R, I, C. By default all roots are returned (this is equivalent to setting `filter='C'`). By default a dictionary is returned giving a compact result in case of multiple roots. However to get a tuple containing all those roots set the `multiple` flag to True. **Examples** >>> from sympy import Poly, roots >>> from sympy.abc import x, y >>> roots(x**2 - 1, x) {1: 1, -1: 1} >>> p = Poly(x**2-1, x) >>> roots(p) {1: 1, -1: 1} >>> p = Poly(x**2-y, x, y) >>> roots(Poly(p, x)) {y**(1/2): 1, -y**(1/2): 1} >>> roots(x**2 - y, x) {y**(1/2): 1, -y**(1/2): 1} >>> roots([1, 0, -1]) {1: 1, -1: 1} """ flags = dict(flags) auto = flags.pop('auto', True) cubics = flags.pop('cubics', True) quartics = flags.pop('quartics', True) multiple = flags.pop('multiple', False) filter = flags.pop('filter', None) predicate = flags.pop('predicate', None) if isinstance(f, list): if gens: raise ValueError('redundant generators given') x = Dummy('x') poly, i = {}, len(f) - 1 for coeff in f: poly[i], i = sympify(coeff), i - 1 f = Poly(poly, x, field=True) else: try: f = Poly(f, *gens, **flags) except GeneratorsNeeded: if multiple: return [] else: return {} if f.is_multivariate: raise PolynomialError('multivariate polynomials are not supported') if auto and f.get_domain().has_Ring: f = f.to_field() x = f.gen def _update_dict(result, root, k): if root in result: result[root] += k else: result[root] = k def _try_decompose(f): """Find roots using functional decomposition. """ factors, roots = f.decompose(), [] for root in _try_heuristics(factors[0]): roots.append(root) for factor in factors[1:]: previous, roots = list(roots), [] for root in previous: g = factor - Poly(root, x) for root in _try_heuristics(g): roots.append(root) return roots def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.is_ground: return [] if f.is_monomial: return [S(0)] * f.degree() if f.length() == 2: if f.degree() == 1: return map(cancel, roots_linear(f)) else: return roots_binomial(f) result = [] for i in [-1, 1]: if not f.eval(i): f = f.exquo(Poly(x - i, x)) result.append(i) break n = f.degree() if n == 1: result += map(cancel, roots_linear(f)) elif n == 2: result += map(cancel, roots_quadratic(f)) elif n == 3 and cubics: result += roots_cubic(f) elif n == 4 and quartics: result += roots_quartic(f) return result if f.is_monomial == 1: if f.is_ground: if multiple: return [] else: return {} else: result = {S(0): f.degree()} else: (k, ), f = f.terms_gcd() if not k: zeros = {} else: zeros = {S(0): k} result = {} if f.degree() == 1: result[roots_linear(f)[0]] = 1 elif f.degree() == 2: for r in roots_quadratic(f): _update_dict(result, r, 1) elif f.length() == 2: for r in roots_binomial(f): _update_dict(result, r, 1) else: _, factors = Poly(f.as_expr()).factor_list() if len(factors) == 1 and factors[0][1] == 1: for root in _try_decompose(f): _update_dict(result, root, 1) else: for factor, k in factors: for r in _try_heuristics(Poly(factor, x, field=True)): _update_dict(result, r, k) result.update(zeros) if filter not in [None, 'C']: handlers = { 'Z': lambda r: r.is_Integer, 'Q': lambda r: r.is_Rational, 'R': lambda r: r.is_real, 'I': lambda r: r.is_imaginary, } try: query = handlers[filter] except KeyError: raise ValueError("Invalid filter: %s" % filter) for zero in dict(result).iterkeys(): if not query(zero): del result[zero] if predicate is not None: for zero in dict(result).iterkeys(): if not predicate(zero): del result[zero] if not multiple: return result else: zeros = [] for zero, k in result.iteritems(): zeros.extend([zero] * k) return zeros
def test_issue_7876(): l1 = Poly(x**6 - x + 1, x).all_roots() l2 = [RootOf(x**6 - x + 1, i) for i in range(6)] assert frozenset(l1) == frozenset(l2)
def test_solve_poly_inequality(): assert psolve(Poly(0, x), '==') == [S.Reals] assert psolve(Poly(1, x), '==') == [S.EmptySet] assert psolve(PurePoly(x + 1, x), ">") == [Interval(-1, oo, True, False)]
def roots_quartic(f): r""" Returns a list of roots of a quartic polynomial. There are many references for solving quartic expressions available [1-5]. This reviewer has found that many of them require one to select from among 2 or more possible sets of solutions and that some solutions work when one is searching for real roots but don't work when searching for complex roots (though this is not always stated clearly). The following routine has been tested and found to be correct for 0, 2 or 4 complex roots. The quasisymmetric case solution [6] looks for quartics that have the form `x**4 + A*x**3 + B*x**2 + C*x + D = 0` where `(C/A)**2 = D`. Although no general solution that is always applicable for all coefficients is known to this reviewer, certain conditions are tested to determine the simplest 4 expressions that can be returned: 1) `f = c + a*(a**2/8 - b/2) == 0` 2) `g = d - a*(a*(3*a**2/256 - b/16) + c/4) = 0` 3) if `f != 0` and `g != 0` and `p = -d + a*c/4 - b**2/12` then a) `p == 0` b) `p != 0` Examples ======== >>> from sympy import Poly, symbols, I >>> from sympy.polys.polyroots import roots_quartic >>> r = roots_quartic(Poly('x**4-6*x**3+17*x**2-26*x+20')) >>> # 4 complex roots: 1+-I*sqrt(3), 2+-I >>> sorted(str(tmp.evalf(n=2)) for tmp in r) ['1.0 + 1.7*I', '1.0 - 1.7*I', '2.0 + 1.0*I', '2.0 - 1.0*I'] References ========== 1. http://mathforum.org/dr.math/faq/faq.cubic.equations.html 2. http://en.wikipedia.org/wiki/Quartic_function#Summary_of_Ferrari.27s_method 3. http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html 4. http://staff.bath.ac.uk/masjhd/JHD-CA.pdf 5. http://www.albmath.org/files/Math_5713.pdf 6. http://www.statemaster.com/encyclopedia/Quartic-equation 7. eqworld.ipmnet.ru/en/solutions/ae/ae0108.pdf """ _, a, b, c, d = f.monic().all_coeffs() if not d: return [S.Zero] + roots([1, a, b, c], multiple=True) elif (c / a)**2 == d: x, m = f.gen, c / a g = Poly(x**2 + a * x + b - 2 * m, x) z1, z2 = roots_quadratic(g) h1 = Poly(x**2 - z1 * x + m, x) h2 = Poly(x**2 - z2 * x + m, x) r1 = roots_quadratic(h1) r2 = roots_quadratic(h2) return r1 + r2 else: a2 = a**2 e = b - 3 * a2 / 8 f = c + a * (a2 / 8 - b / 2) g = d - a * (a * (3 * a2 / 256 - b / 16) + c / 4) aon4 = a / 4 if f is S.Zero: y1, y2 = [sqrt(tmp) for tmp in roots([1, e, g], multiple=True)] return [tmp - aon4 for tmp in [-y1, -y2, y1, y2]] if g is S.Zero: y = [S.Zero] + roots([1, 0, e, f], multiple=True) return [tmp - aon4 for tmp in y] else: # Descartes-Euler method, see [7] sols = _roots_quartic_euler(e, f, g, aon4) if sols: return sols # Ferrari method, see [1, 2] a2 = a**2 e = b - 3 * a2 / 8 f = c + a * (a2 / 8 - b / 2) g = d - a * (a * (3 * a2 / 256 - b / 16) + c / 4) p = -e**2 / 12 - g q = -e**3 / 108 + e * g / 3 - f**2 / 8 TH = Rational(1, 3) def _ans(y): w = sqrt(e + 2 * y) arg1 = 3 * e + 2 * y arg2 = 2 * f / w ans = [] for s in [-1, 1]: root = sqrt(-(arg1 + s * arg2)) for t in [-1, 1]: ans.append((s * w - t * root) / 2 - aon4) return ans # p == 0 case y1 = -5 * e / 6 - q**TH if p.is_zero: return _ans(y1) # if p != 0 then u below is not 0 root = sqrt(q**2 / 4 + p**3 / 27) r = -q / 2 + root # or -q/2 - root u = r**TH # primary root of solve(x**3 - r, x) y2 = -5 * e / 6 + u - p / u / 3 if p.is_nonzero: return _ans(y2) # sort it out once they know the values of the coefficients return [ Piecewise((a1, Eq(p, 0)), (a2, True)) for a1, a2 in zip(_ans(y1), _ans(y2)) ]
def test_AlgebraicNumber(): minpoly, root = x**2 - 2, sqrt(2) a = AlgebraicNumber(root, gen=x) assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is False assert a.coeffs() == [S.One, S.Zero] assert a.native_coeffs() == [QQ(1), QQ(0)] a = AlgebraicNumber(root, gen=x, alias='y') assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias == Symbol('y') assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is True a = AlgebraicNumber(root, gen=x, alias=Symbol('y')) assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias == Symbol('y') assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is True assert AlgebraicNumber(sqrt(2), []).rep == DMP([], QQ) assert AlgebraicNumber(sqrt(2), ()).rep == DMP([], QQ) assert AlgebraicNumber(sqrt(2), (0, 0)).rep == DMP([], QQ) assert AlgebraicNumber(sqrt(2), [8]).rep == DMP([QQ(8)], QQ) assert AlgebraicNumber(sqrt(2), [Rational(8, 3)]).rep == DMP([QQ(8, 3)], QQ) assert AlgebraicNumber(sqrt(2), [7, 3]).rep == DMP([QQ(7), QQ(3)], QQ) assert AlgebraicNumber( sqrt(2), [Rational(7, 9), Rational(3, 2)]).rep == DMP([QQ(7, 9), QQ(3, 2)], QQ) assert AlgebraicNumber(sqrt(2), [1, 2, 3]).rep == DMP([QQ(2), QQ(5)], QQ) a = AlgebraicNumber(AlgebraicNumber(root, gen=x), [1, 2]) assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is False assert a.coeffs() == [S.One, S(2)] assert a.native_coeffs() == [QQ(1), QQ(2)] a = AlgebraicNumber((minpoly, root), [1, 2]) assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is False a = AlgebraicNumber((Poly(minpoly), root), [1, 2]) assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is False assert AlgebraicNumber( sqrt(3)).rep == DMP([ QQ(1), QQ(0)], QQ) assert AlgebraicNumber(-sqrt(3)).rep == DMP([ QQ(1), QQ(0)], QQ) a = AlgebraicNumber(sqrt(2)) b = AlgebraicNumber(sqrt(2)) assert a == b c = AlgebraicNumber(sqrt(2), gen=x) assert a == b assert a == c a = AlgebraicNumber(sqrt(2), [1, 2]) b = AlgebraicNumber(sqrt(2), [1, 3]) assert a != b and a != sqrt(2) + 3 assert (a == x) is False and (a != x) is True a = AlgebraicNumber(sqrt(2), [1, 0]) b = AlgebraicNumber(sqrt(2), [1, 0], alias=y) assert a.as_poly(x) == Poly(x, domain='QQ') assert b.as_poly() == Poly(y, domain='QQ') assert a.as_expr() == sqrt(2) assert a.as_expr(x) == x assert b.as_expr() == sqrt(2) assert b.as_expr(x) == x a = AlgebraicNumber(sqrt(2), [2, 3]) b = AlgebraicNumber(sqrt(2), [2, 3], alias=y) p = a.as_poly() assert p == Poly(2*p.gen + 3) assert a.as_poly(x) == Poly(2*x + 3, domain='QQ') assert b.as_poly() == Poly(2*y + 3, domain='QQ') assert a.as_expr() == 2*sqrt(2) + 3 assert a.as_expr(x) == 2*x + 3 assert b.as_expr() == 2*sqrt(2) + 3 assert b.as_expr(x) == 2*x + 3 a = AlgebraicNumber(sqrt(2)) b = to_number_field(sqrt(2)) assert a.args == b.args == (sqrt(2), Tuple(1, 0)) b = AlgebraicNumber(sqrt(2), alias='alpha') assert b.args == (sqrt(2), Tuple(1, 0), Symbol('alpha')) a = AlgebraicNumber(sqrt(2), [1, 2, 3]) assert a.args == (sqrt(2), Tuple(1, 2, 3)) a = AlgebraicNumber(sqrt(2), [1, 2], "alpha") b = AlgebraicNumber(a) c = AlgebraicNumber(a, alias="gamma") assert a == b assert c.alias.name == "gamma" a = AlgebraicNumber(sqrt(2) + sqrt(3), [S(1)/2, 0, S(-9)/2, 0]) b = AlgebraicNumber(a, [1, 0, 0]) assert b.root == a.root assert a.to_root() == sqrt(2) assert b.to_root() == 2 a = AlgebraicNumber(2) assert a.is_primitive_element is True
def roots(f, *gens, **flags): """ Computes symbolic roots of a univariate polynomial. Given a univariate polynomial f with symbolic coefficients (or a list of the polynomial's coefficients), returns a dictionary with its roots and their multiplicities. Only roots expressible via radicals will be returned. To get a complete set of roots use RootOf class or numerical methods instead. By default cubic and quartic formulas are used in the algorithm. To disable them because of unreadable output set ``cubics=False`` or ``quartics=False`` respectively. If cubic roots are real but are expressed in terms of complex numbers (casus irreducibilis [1]) the ``trig`` flag can be set to True to have the solutions returned in terms of cosine and inverse cosine functions. To get roots from a specific domain set the ``filter`` flag with one of the following specifiers: Z, Q, R, I, C. By default all roots are returned (this is equivalent to setting ``filter='C'``). By default a dictionary is returned giving a compact result in case of multiple roots. However to get a list containing all those roots set the ``multiple`` flag to True; the list will have identical roots appearing next to each other in the result. (For a given Poly, the all_roots method will give the roots in sorted numerical order.) Examples ======== >>> from sympy import Poly, roots >>> from sympy.abc import x, y >>> roots(x**2 - 1, x) {-1: 1, 1: 1} >>> p = Poly(x**2-1, x) >>> roots(p) {-1: 1, 1: 1} >>> p = Poly(x**2-y, x, y) >>> roots(Poly(p, x)) {-sqrt(y): 1, sqrt(y): 1} >>> roots(x**2 - y, x) {-sqrt(y): 1, sqrt(y): 1} >>> roots([1, 0, -1]) {-1: 1, 1: 1} References ========== 1. http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method """ from sympy.polys.polytools import to_rational_coeffs flags = dict(flags) auto = flags.pop('auto', True) cubics = flags.pop('cubics', True) trig = flags.pop('trig', False) quartics = flags.pop('quartics', True) quintics = flags.pop('quintics', False) multiple = flags.pop('multiple', False) filter = flags.pop('filter', None) predicate = flags.pop('predicate', None) if isinstance(f, list): if gens: raise ValueError('redundant generators given') x = Dummy('x') poly, i = {}, len(f) - 1 for coeff in f: poly[i], i = sympify(coeff), i - 1 f = Poly(poly, x, field=True) else: try: f = Poly(f, *gens, **flags) except GeneratorsNeeded: if multiple: return [] else: return {} if f.is_multivariate: raise PolynomialError('multivariate polynomials are not supported') def _update_dict(result, root, k): if root in result: result[root] += k else: result[root] = k def _try_decompose(f): """Find roots using functional decomposition. """ factors, roots = f.decompose(), [] for root in _try_heuristics(factors[0]): roots.append(root) for factor in factors[1:]: previous, roots = list(roots), [] for root in previous: g = factor - Poly(root, f.gen) for root in _try_heuristics(g): roots.append(root) return roots def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.is_ground: return [] if f.is_monomial: return [S(0)] * f.degree() if f.length() == 2: if f.degree() == 1: return list(map(cancel, roots_linear(f))) else: return roots_binomial(f) result = [] for i in [-1, 1]: if not f.eval(i): f = f.quo(Poly(f.gen - i, f.gen)) result.append(i) break n = f.degree() if n == 1: result += list(map(cancel, roots_linear(f))) elif n == 2: result += list(map(cancel, roots_quadratic(f))) elif f.is_cyclotomic: result += roots_cyclotomic(f) elif n == 3 and cubics: result += roots_cubic(f, trig=trig) elif n == 4 and quartics: result += roots_quartic(f) elif n == 5 and quintics: result += roots_quintic(f) return result (k, ), f = f.terms_gcd() if not k: zeros = {} else: zeros = {S(0): k} coeff, f = preprocess_roots(f) if auto and f.get_domain().has_Ring: f = f.to_field() rescale_x = None translate_x = None result = {} if not f.is_ground: if not f.get_domain().is_Exact: for r in f.nroots(): _update_dict(result, r, 1) elif f.degree() == 1: result[roots_linear(f)[0]] = 1 elif f.degree() == 2: for r in roots_quadratic(f): _update_dict(result, r, 1) elif f.length() == 2: for r in roots_binomial(f): _update_dict(result, r, 1) else: _, factors = Poly(f.as_expr()).factor_list() if len(factors) == 1 and factors[0][1] == 1: if f.get_domain().is_EX: res = to_rational_coeffs(f) if res: if res[0] is None: translate_x, f = res[2:] else: rescale_x, f = res[1], res[-1] result = roots(f) if not result: for root in _try_decompose(f): _update_dict(result, root, 1) else: for root in _try_decompose(f): _update_dict(result, root, 1) else: for factor, k in factors: for r in _try_heuristics(Poly(factor, f.gen, field=True)): _update_dict(result, r, k) if coeff is not S.One: _result, result, = result, {} for root, k in _result.items(): result[coeff * root] = k result.update(zeros) if filter not in [None, 'C']: handlers = { 'Z': lambda r: r.is_Integer, 'Q': lambda r: r.is_Rational, 'R': lambda r: r.is_real, 'I': lambda r: r.is_imaginary, } try: query = handlers[filter] except KeyError: raise ValueError("Invalid filter: %s" % filter) for zero in dict(result).keys(): if not query(zero): del result[zero] if predicate is not None: for zero in dict(result).keys(): if not predicate(zero): del result[zero] if rescale_x: result1 = {} for k, v in result.items(): result1[k * rescale_x] = v result = result1 if translate_x: result1 = {} for k, v in result.items(): result1[k + translate_x] = v result = result1 if not multiple: return result else: zeros = [] for zero in ordered(result): zeros.extend([zero] * result[zero]) return zeros
def roots(f, *gens, auto=True, cubics=True, trig=False, quartics=True, quintics=False, multiple=False, filter=None, predicate=None, **flags): """ Computes symbolic roots of a univariate polynomial. Given a univariate polynomial f with symbolic coefficients (or a list of the polynomial's coefficients), returns a dictionary with its roots and their multiplicities. Only roots expressible via radicals will be returned. To get a complete set of roots use RootOf class or numerical methods instead. By default cubic and quartic formulas are used in the algorithm. To disable them because of unreadable output set ``cubics=False`` or ``quartics=False`` respectively. If cubic roots are real but are expressed in terms of complex numbers (casus irreducibilis [1]) the ``trig`` flag can be set to True to have the solutions returned in terms of cosine and inverse cosine functions. To get roots from a specific domain set the ``filter`` flag with one of the following specifiers: Z, Q, R, I, C. By default all roots are returned (this is equivalent to setting ``filter='C'``). By default a dictionary is returned giving a compact result in case of multiple roots. However to get a list containing all those roots set the ``multiple`` flag to True; the list will have identical roots appearing next to each other in the result. (For a given Poly, the all_roots method will give the roots in sorted numerical order.) Examples ======== >>> from sympy import Poly, roots >>> from sympy.abc import x, y >>> roots(x**2 - 1, x) {-1: 1, 1: 1} >>> p = Poly(x**2-1, x) >>> roots(p) {-1: 1, 1: 1} >>> p = Poly(x**2-y, x, y) >>> roots(Poly(p, x)) {-sqrt(y): 1, sqrt(y): 1} >>> roots(x**2 - y, x) {-sqrt(y): 1, sqrt(y): 1} >>> roots([1, 0, -1]) {-1: 1, 1: 1} References ========== .. [1] https://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method """ from sympy.polys.polytools import to_rational_coeffs flags = dict(flags) if isinstance(f, list): if gens: raise ValueError('redundant generators given') x = Dummy('x') poly, i = {}, len(f) - 1 for coeff in f: poly[i], i = sympify(coeff), i - 1 f = Poly(poly, x, field=True) else: try: F = Poly(f, *gens, **flags) if not isinstance(f, Poly) and not F.gen.is_Symbol: raise PolynomialError("generator must be a Symbol") else: f = F if f.length == 2 and f.degree() != 1: # check for foo**n factors in the constant n = f.degree() npow_bases = [] others = [] expr = f.as_expr() con = expr.as_independent(*gens)[0] for p in Mul.make_args(con): if p.is_Pow and not p.exp % n: npow_bases.append(p.base**(p.exp / n)) else: others.append(p) if npow_bases: b = Mul(*npow_bases) B = Dummy() d = roots( Poly(expr - con + B**n * Mul(*others), *gens, **flags), *gens, **flags) rv = {} for k, v in d.items(): rv[k.subs(B, b)] = v return rv except GeneratorsNeeded: if multiple: return [] else: return {} if f.is_multivariate: raise PolynomialError('multivariate polynomials are not supported') def _update_dict(result, zeros, currentroot, k): if currentroot == S.Zero: if S.Zero in zeros: zeros[S.Zero] += k else: zeros[S.Zero] = k if currentroot in result: result[currentroot] += k else: result[currentroot] = k def _try_decompose(f): """Find roots using functional decomposition. """ factors, roots = f.decompose(), [] for currentroot in _try_heuristics(factors[0]): roots.append(currentroot) for currentfactor in factors[1:]: previous, roots = list(roots), [] for currentroot in previous: g = currentfactor - Poly(currentroot, f.gen) for currentroot in _try_heuristics(g): roots.append(currentroot) return roots def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.is_ground: return [] if f.is_monomial: return [S.Zero] * f.degree() if f.length() == 2: if f.degree() == 1: return list(map(cancel, roots_linear(f))) else: return roots_binomial(f) result = [] for i in [-1, 1]: if not f.eval(i): f = f.quo(Poly(f.gen - i, f.gen)) result.append(i) break n = f.degree() if n == 1: result += list(map(cancel, roots_linear(f))) elif n == 2: result += list(map(cancel, roots_quadratic(f))) elif f.is_cyclotomic: result += roots_cyclotomic(f) elif n == 3 and cubics: result += roots_cubic(f, trig=trig) elif n == 4 and quartics: result += roots_quartic(f) elif n == 5 and quintics: result += roots_quintic(f) return result # Convert the generators to symbols dumgens = symbols('x:%d' % len(f.gens), cls=Dummy) f = f.per(f.rep, dumgens) (k, ), f = f.terms_gcd() if not k: zeros = {} else: zeros = {S.Zero: k} coeff, f = preprocess_roots(f) if auto and f.get_domain().is_Ring: f = f.to_field() # Use EX instead of ZZ_I or QQ_I if f.get_domain().is_QQ_I: f = f.per(f.rep.convert(EX)) rescale_x = None translate_x = None result = {} if not f.is_ground: dom = f.get_domain() if not dom.is_Exact and dom.is_Numerical: for r in f.nroots(): _update_dict(result, zeros, r, 1) elif f.degree() == 1: _update_dict(result, zeros, roots_linear(f)[0], 1) elif f.length() == 2: roots_fun = roots_quadratic if f.degree() == 2 else roots_binomial for r in roots_fun(f): _update_dict(result, zeros, r, 1) else: _, factors = Poly(f.as_expr()).factor_list() if len(factors) == 1 and f.degree() == 2: for r in roots_quadratic(f): _update_dict(result, zeros, r, 1) else: if len(factors) == 1 and factors[0][1] == 1: if f.get_domain().is_EX: res = to_rational_coeffs(f) if res: if res[0] is None: translate_x, f = res[2:] else: rescale_x, f = res[1], res[-1] result = roots(f) if not result: for currentroot in _try_decompose(f): _update_dict(result, zeros, currentroot, 1) else: for r in _try_heuristics(f): _update_dict(result, zeros, r, 1) else: for currentroot in _try_decompose(f): _update_dict(result, zeros, currentroot, 1) else: for currentfactor, k in factors: for r in _try_heuristics( Poly(currentfactor, f.gen, field=True)): _update_dict(result, zeros, r, k) if coeff is not S.One: _result, result, = result, {} for currentroot, k in _result.items(): result[coeff * currentroot] = k if filter not in [None, 'C']: handlers = { 'Z': lambda r: r.is_Integer, 'Q': lambda r: r.is_Rational, 'R': lambda r: all(a.is_real for a in r.as_numer_denom()), 'I': lambda r: r.is_imaginary, } try: query = handlers[filter] except KeyError: raise ValueError("Invalid filter: %s" % filter) for zero in dict(result).keys(): if not query(zero): del result[zero] if predicate is not None: for zero in dict(result).keys(): if not predicate(zero): del result[zero] if rescale_x: result1 = {} for k, v in result.items(): result1[k * rescale_x] = v result = result1 if translate_x: result1 = {} for k, v in result.items(): result1[k + translate_x] = v result = result1 # adding zero roots after non-trivial roots have been translated result.update(zeros) if not multiple: return result else: zeros = [] for zero in ordered(result): zeros.extend([zero] * result[zero]) return zeros
def _minpoly_op_algebraic_element(op, ex1, ex2, x, dom, mp1=None, mp2=None): """ return the minimal polynomial for ``op(ex1, ex2)`` Parameters ========== op : operation ``Add`` or ``Mul`` ex1, ex2 : expressions for the algebraic elements x : indeterminate of the polynomials dom: ground domain mp1, mp2 : minimal polynomials for ``ex1`` and ``ex2`` or None Examples ======== >>> from sympy import sqrt, Add, Mul, QQ >>> from sympy.polys.numberfields import _minpoly_op_algebraic_element >>> from sympy.abc import x, y >>> p1 = sqrt(sqrt(2) + 1) >>> p2 = sqrt(sqrt(2) - 1) >>> _minpoly_op_algebraic_element(Mul, p1, p2, x, QQ) x - 1 >>> q1 = sqrt(y) >>> q2 = 1 / y >>> _minpoly_op_algebraic_element(Add, q1, q2, x, QQ.frac_field(y)) x**2*y**2 - 2*x*y - y**3 + 1 References ========== [1] http://en.wikipedia.org/wiki/Resultant [2] I.M. Isaacs, Proc. Amer. Math. Soc. 25 (1970), 638 "Degrees of sums in a separable field extension". """ y = Dummy(str(x)) if mp1 is None: mp1 = _minpoly_compose(ex1, x, dom) if mp2 is None: mp2 = _minpoly_compose(ex2, y, dom) else: mp2 = mp2.subs({x: y}) if op is Add: # mp1a = mp1.subs({x: x - y}) if dom == QQ: R, X = ring('X', QQ) p1 = R(dict_from_expr(mp1)[0]) p2 = R(dict_from_expr(mp2)[0]) else: (p1, p2), _ = parallel_poly_from_expr((mp1, x - y), x, y) r = p1.compose(p2) mp1a = r.as_expr() elif op is Mul: mp1a = _muly(mp1, x, y) else: raise NotImplementedError('option not available') if op is Mul or dom != QQ: r = resultant(mp1a, mp2, gens=[y, x]) else: r = rs_compose_add(p1, p2) r = expr_from_dict(r.as_expr_dict(), x) deg1 = degree(mp1, x) deg2 = degree(mp2, y) if op is Mul and deg1 == 1 or deg2 == 1: # if deg1 = 1, then mp1 = x - a; mp1a = x - y - a; # r = mp2(x - a), so that `r` is irreducible return r r = Poly(r, x, domain=dom) _, factors = r.factor_list() res = _choose_factor(factors, x, op(ex1, ex2), dom) return res.as_expr()
def test_DifferentialExtension_misc(): # Odd ends assert DifferentialExtension(sin(y)*exp(x), x)._important_attrs == \ (Poly(sin(y)*t0, t0, domain='ZZ[sin(y)]'), Poly(1, t0, domain='ZZ'), [Poly(1, x, domain='ZZ'), Poly(t0, t0, domain='ZZ')], [x, t0], [Lambda(i, exp(i))], [], [None, 'exp'], [None, x]) raises(NotImplementedError, lambda: DifferentialExtension(sin(x), x)) assert DifferentialExtension(10**x, x)._important_attrs == \ (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(log(10)*t0, t0)], [x, t0], [Lambda(i, exp(i*log(10)))], [(exp(x*log(10)), 10**x)], [None, 'exp'], [None, x*log(10)]) assert DifferentialExtension(log(x) + log(x**2), x)._important_attrs in [ (Poly(3*t0, t0), Poly(2, t0), [Poly(1, x), Poly(2/x, t0)], [x, t0], [Lambda(i, log(i**2))], [], [None, ], [], [1], [x**2]), (Poly(3*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], [Lambda(i, log(i))], [], [None, 'log'], [None, x])] assert DifferentialExtension(S.Zero, x)._important_attrs == \ (Poly(0, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None]) assert DifferentialExtension(tan(atan(x).rewrite(log)), x)._important_attrs == \ (Poly(x, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None])