def roots_cyclotomic(f, factor=False): """Compute roots of cyclotomic polynomials. """ L, U = _inv_totient_estimate(f.degree()) for n in range(L, U + 1): g = cyclotomic_poly(n, f.gen, polys=True) if f == g: break else: # pragma: no cover raise RuntimeError("failed to find index of a cyclotomic polynomial") roots = [] if not factor: # get the indices in the right order so the computed # roots will be sorted h = n//2 ks = [i for i in range(1, n + 1) if igcd(i, n) == 1] ks.sort(key=lambda x: (x, -1) if x <= h else (abs(x - n), 1)) d = 2*I*pi/n for k in reversed(ks): roots.append(exp(k*d).expand(complex=True)) else: g = Poly(f, extension=root(-1, n)) for h, _ in ordered(g.factor_list()[1]): roots.append(-h.TC()) return roots
def test_RootOf_all_roots(): assert Poly(x**5 + x + 1).all_roots() == [ RootOf(x**3 - x**2 + 1, 0), -Rational(1, 2) - sqrt(3) * I / 2, -Rational(1, 2) + sqrt(3) * I / 2, RootOf(x**3 - x**2 + 1, 1), RootOf(x**3 - x**2 + 1, 2), ] assert Poly(x**5 + x + 1).all_roots(radicals=False) == [ RootOf(x**3 - x**2 + 1, 0), RootOf(x**2 + x + 1, 0, radicals=False), RootOf(x**2 + x + 1, 1, radicals=False), RootOf(x**3 - x**2 + 1, 1), RootOf(x**3 - x**2 + 1, 2), ] r = Poly((x**3 + x + 20) * (x**3 + x + 21)).all_roots() assert r[0].is_real and r[1].is_real assert all(not _.is_real for _ in r[2:]) assert r == [ RootOf(x**3 + x + 21, 0), RootOf(x**3 + x + 20, 0), RootOf(x**3 + x + 20, 1), RootOf(x**3 + x + 20, 2), RootOf(x**3 + x + 21, 1), RootOf(x**3 + x + 21, 2) ]
def random_poly(x, n, inf, sup, domain=ZZ, polys=False): """Return a polynomial of degree ``n`` with coefficients in ``[inf, sup]``. """ poly = Poly(dup_random(n, inf, sup, domain), x, domain=domain) if not polys: return poly.as_expr() else: return poly
def _minimal_polynomial_sq(p, n, x): """ Returns the minimal polynomial for the ``nth-root`` of a sum of surds or ``None`` if it fails. Parameters ========== p : sum of surds n : positive integer x : variable of the returned polynomial Examples ======== >>> from diofant import sqrt >>> from diofant.abc import x >>> q = 1 + sqrt(2) + sqrt(3) >>> _minimal_polynomial_sq(q, 3, x) x**12 - 4*x**9 - 4*x**6 + 16*x**3 - 8 """ from diofant.simplify.simplify import _is_sum_surds p = sympify(p) n = sympify(n) r = _is_sum_surds(p) if not n.is_Integer or not n > 0 or not _is_sum_surds(p): return pn = p**Rational(1, n) # eliminate the square roots p -= x while 1: p1 = _separate_sq(p) if p1 is p: p = p1.subs({x: x**n}) break else: p = p1 # _separate_sq eliminates field extensions in a minimal way, so that # if n = 1 then `p = constant*(minimal_polynomial(p))` # if n > 1 it contains the minimal polynomial as a factor. if n == 1: p1 = Poly(p) if p.coeff(x**p1.degree(x)) < 0: p = -p p = p.primitive()[1] return p # by construction `p` has root `pn` # the minimal polynomial is the factor vanishing in x = pn factors = factor_list(p)[1] result = _choose_factor(factors, x, pn) return result
def _eval_sum_hyper(f, i, a): """ Returns (res, cond). Sums from a to oo. """ from diofant.functions import hyper from diofant.simplify import hyperexpand, hypersimp, fraction, simplify from diofant.polys.polytools import Poly, factor if a != 0: return _eval_sum_hyper(f.subs(i, i + a), i, 0) if f.subs(i, 0) == 0: if simplify(f.subs(i, Dummy('i', integer=True, positive=True))) == 0: return Integer(0), True return _eval_sum_hyper(f.subs(i, i + 1), i, 0) hs = hypersimp(f, i) if hs is None: return numer, denom = fraction(factor(hs)) top, topl = numer.as_coeff_mul(i) bot, botl = denom.as_coeff_mul(i) ab = [top, bot] factors = [topl, botl] params = [[], []] for k in range(2): for fac in factors[k]: mul = 1 if fac.is_Pow: mul = fac.exp fac = fac.base if not mul.is_Integer: return p = Poly(fac, i) if p.degree() != 1: return m, n = p.all_coeffs() ab[k] *= m**mul params[k] += [n / m] * mul # Add "1" to numerator parameters, to account for implicit n! in # hypergeometric series. ap = params[0] + [1] bq = params[1] x = ab[0] / ab[1] h = hyper(ap, bq, x) e = h try: e = hyperexpand(h) except PolynomialError: pass if e is S.NaN and h.convergence_statement: e = h return f.subs(i, 0) * e, h.convergence_statement
def _rational_case(cls, poly, func): """Handle the rational function case. """ roots = symbols('r:%d' % poly.degree()) var, expr = func.variables[0], func.expr f = sum(expr.subs(var, r) for r in roots) p, q = together(f).as_numer_denom() domain = QQ[roots] p = p.expand() q = q.expand() try: p = Poly(p, domain=domain, expand=False) except GeneratorsNeeded: p, p_coeff = None, (p, ) else: p_monom, p_coeff = zip(*p.terms()) try: q = Poly(q, domain=domain, expand=False) except GeneratorsNeeded: q, q_coeff = None, (q, ) else: q_monom, q_coeff = zip(*q.terms()) coeffs, mapping = symmetrize(p_coeff + q_coeff, formal=True) formulas, values = viete(poly, roots), [] for (sym, _), (_, val) in zip(mapping, formulas): values.append((sym, val)) for i, (coeff, _) in enumerate(coeffs): coeffs[i] = coeff.subs(values) n = len(p_coeff) p_coeff = coeffs[:n] q_coeff = coeffs[n:] if p is not None: p = Poly(dict(zip(p_monom, p_coeff)), *p.gens).as_expr() else: (p, ) = p_coeff if q is not None: q = Poly(dict(zip(q_monom, q_coeff)), *q.gens).as_expr() else: (q, ) = q_coeff return factor(p / q)
def _minpoly_pow(ex, pw, x, dom, mp=None): """ Returns ``minpoly(ex**pw, x)`` Parameters ========== ex : algebraic element pw : rational number x : indeterminate of the polynomial dom: ground domain mp : minimal polynomial of ``p`` Examples ======== >>> from diofant import sqrt, QQ, Rational >>> from diofant.abc import x, y >>> p = sqrt(1 + sqrt(2)) >>> _minpoly_pow(p, 2, x, QQ) x**2 - 2*x - 1 >>> minpoly(p**2, x) x**2 - 2*x - 1 >>> _minpoly_pow(y, Rational(1, 3), x, QQ.frac_field(y)) x**3 - y >>> minpoly(y**Rational(1, 3), x) x**3 - y """ pw = sympify(pw) if not mp: mp = _minpoly_compose(ex, x, dom) if not pw.is_rational: raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) if pw < 0: if mp == x: raise ZeroDivisionError('%s is zero' % ex) mp = _invertx(mp, x) if pw == -1: return mp pw = -pw ex = 1 / ex y = Dummy(str(x)) mp = mp.subs({x: y}) n, d = pw.as_numer_denom() res = Poly(resultant(mp, x**d - y**n, gens=[y]), x, domain=dom) _, factors = res.factor_list() res = _choose_factor(factors, x, ex**pw, dom) return res.as_expr()
def fateman_poly_F_3(n): """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ Y = [Symbol('y_' + str(i)) for i in range(0, n + 1)] y_0 = Y[0] u = Add(*[y**(n + 1) for y in Y[1:]]) H = Poly((y_0**(n + 1) + u + 1)**2, *Y) F = Poly((y_0**(n + 1) - u - 2)**2, *Y) G = Poly((y_0**(n + 1) + u + 2)**2, *Y) return H * F, H * G, H
def fateman_poly_F_2(n): """Fateman's GCD benchmark: linearly dense quartic inputs """ Y = [Symbol('y_' + str(i)) for i in range(0, n + 1)] y_0 = Y[0] u = Add(*[y for y in Y[1:]]) H = Poly((y_0 + u + 1)**2, *Y) F = Poly((y_0 - u - 2)**2, *Y) G = Poly((y_0 + u + 2)**2, *Y) return H * F, H * G, H
def test_RootOf_all_roots(): assert Poly(x**5 + x + 1).all_roots() == [ RootOf(x**3 - x**2 + 1, 0), -Rational(1, 2) - sqrt(3) * I / 2, -Rational(1, 2) + sqrt(3) * I / 2, RootOf(x**3 - x**2 + 1, 1), RootOf(x**3 - x**2 + 1, 2), ] assert Poly(x**5 + x + 1).all_roots(radicals=False) == [ RootOf(x**3 - x**2 + 1, 0), RootOf(x**2 + x + 1, 0, radicals=False), RootOf(x**2 + x + 1, 1, radicals=False), RootOf(x**3 - x**2 + 1, 1), RootOf(x**3 - x**2 + 1, 2), ]
def sdm_to_vector(f, gens, K, n=None): """ Convert sdm ``f`` into a list of polynomial expressions. The generators for the polynomial ring are specified via ``gens``. The rank of the module is guessed, or passed via ``n``. The ground field is assumed to be ``K``. Examples ======== >>> from diofant.abc import x, y, z >>> from diofant.polys import QQ, lex >>> f = [((1, 0, 0, 1), QQ(2)), ((0, 2, 0, 0), QQ(1)), ((0, 0, 2, 0), QQ(1))] >>> sdm_to_vector(f, [x, y, z], QQ) [x**2 + y**2, 2*z] """ dic = sdm_to_dict(f) dics = {} for k, v in dic.items(): dics.setdefault(k[0], []).append((k[1:], v)) n = n or len(dics) res = [] for k in range(n): if k in dics: res.append(Poly(dict(dics[k]), gens=gens, domain=K).as_expr()) else: res.append(S.Zero) return res
def root_factors(f, *gens, **args): """ Returns all factors of a univariate polynomial. Examples ======== >>> from diofant.abc import x, y >>> root_factors(x**2 - y, x) [x - sqrt(y), x + sqrt(y)] """ args = dict(args) filter = args.pop('filter', None) F = Poly(f, *gens, **args) if not F.is_Poly: return [f] if F.is_multivariate: raise ValueError('multivariate polynomials are not supported') x = F.gens[0] zeros = roots(F, filter=filter) if not zeros: factors = [F] else: factors, N = [], 0 for r, n in ordered(zeros.items()): factors, N = factors + [Poly(x - r, x)]*n, N + n if N < F.degree(): G = reduce(lambda p, q: p*q, factors) factors.append(F.quo(G)) if not isinstance(f, Poly): factors = [ f.as_expr() for f in factors ] return factors
def test_RootOf_attributes(): r = RootOf(x**3 + x + 3, 0) assert r.is_number assert r.free_symbols == set() # if the following assertion fails then multivariate polynomials # are apparently supported and the RootOf.free_symbols routine # should be changed to return whatever symbols would not be # the PurePoly dummy symbol pytest.raises(NotImplementedError, lambda: RootOf(Poly(x**3 + y * x + 1, x), 0))
def _roots_quartic_euler(p, q, r, a): """ Descartes-Euler solution of the quartic equation Parameters ========== p, q, r: coefficients of ``x**4 + p*x**2 + q*x + r`` a: shift of the roots Notes ===== This is a helper function for ``roots_quartic``. Look for solutions of the form :: ``x1 = sqrt(R) - sqrt(A + B*sqrt(R))`` ``x2 = -sqrt(R) - sqrt(A - B*sqrt(R))`` ``x3 = -sqrt(R) + sqrt(A - B*sqrt(R))`` ``x4 = sqrt(R) + sqrt(A + B*sqrt(R))`` To satisfy the quartic equation one must have ``p = -2*(R + A); q = -4*B*R; r = (R - A)**2 - B**2*R`` so that ``R`` must satisfy the Descartes-Euler resolvent equation ``64*R**3 + 32*p*R**2 + (4*p**2 - 16*r)*R - q**2 = 0`` If the resolvent does not have a rational solution, return None; in that case it is likely that the Ferrari method gives a simpler solution. Examples ======== >>> from diofant import Rational, Integer >>> p, q, r = -Rational(64, 5), -Rational(512, 125), -Rational(1024, 3125) >>> _roots_quartic_euler(p, q, r, Integer(0))[0] -sqrt(32*sqrt(5)/125 + 16/5) + 4*sqrt(5)/5 """ # solve the resolvent equation x = Symbol('x') eq = 64*x**3 + 32*p*x**2 + (4*p**2 - 16*r)*x - q**2 xsols = list(roots(Poly(eq, x), cubics=False).keys()) xsols = [sol for sol in xsols if sol.is_rational] if not xsols: return R = max(xsols) c1 = sqrt(R) B = -q*c1/(4*R) A = -R - p/2 c2 = sqrt(A + B) c3 = sqrt(A - B) return [c1 - c2 - a, -c1 - c3 - a, -c1 + c3 - a, c1 + c2 - a]
def field_isomorphism_pslq(a, b): """Construct field isomorphism using PSLQ algorithm. """ if not a.root.is_extended_real or not b.root.is_extended_real: raise NotImplementedError("PSLQ doesn't support complex coefficients") f = a.minpoly g = b.minpoly.replace(f.gen) n, m, prev = 100, b.minpoly.degree(), None for i in range(1, 5): A = a.root.evalf(n) B = b.root.evalf(n) basis = [1, B] + [B**i for i in range(2, m)] + [A] dps, mp.dps = mp.dps, n coeffs = pslq(basis, maxcoeff=int(1e10), maxsteps=1000) mp.dps = dps if coeffs is None: break if coeffs != prev: prev = coeffs else: break coeffs = [sympify(c) / coeffs[-1] for c in coeffs[:-1]] while not coeffs[-1]: coeffs.pop() coeffs = list(reversed(coeffs)) h = Poly(coeffs, f.gen, domain='QQ') if f.compose(h).rem(g).is_zero: d, approx = len(coeffs) - 1, 0 for i, coeff in enumerate(coeffs): approx += coeff * B**(d - i) if A * approx < 0: return [-c for c in coeffs] else: return coeffs elif f.compose(-h).rem(g).is_zero: return [-c for c in coeffs] else: n *= 2 return
def fateman_poly_F_1(n): """Fateman's GCD benchmark: trivial GCD """ Y = [Symbol('y_' + str(i)) for i in range(0, n + 1)] y_0, y_1 = Y[0], Y[1] u = y_0 + Add(*[y for y in Y[1:]]) v = y_0**2 + Add(*[y**2 for y in Y[1:]]) F = ((u + 1) * (u + 2)).as_poly(*Y) G = ((v + 1) * (-3 * y_1 * y_0**2 + y_1**2 - 1)).as_poly(*Y) H = Poly(1, *Y) return F, G, H
def legendre_poly(n, x=None, **args): """Generates Legendre polynomial of degree `n` in `x`. """ if n < 0: raise ValueError("can't generate Legendre polynomial of degree %s" % n) poly = DMP(dup_legendre(int(n), QQ), QQ) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) if not args.get('polys', False): return poly.as_expr() else: return poly
def symmetric_poly(n, *gens, **args): """Generates symmetric polynomial of order `n`. """ gens = _analyze_gens(gens) if n < 0 or n > len(gens) or not gens: raise ValueError( "can't generate symmetric polynomial of order %s for %s" % (n, gens)) elif not n: poly = S.One else: poly = Add(*[Mul(*s) for s in subsets(gens, int(n))]) if not args.get('polys', False): return poly else: return Poly(poly, *gens)
def cyclotomic_poly(n, x=None, **args): """Generates cyclotomic polynomial of order `n` in `x`. """ if n <= 0: raise ValueError("can't generate cyclotomic polynomial of order %s" % n) poly = DMP(dup_zz_cyclotomic_poly(int(n), ZZ), ZZ) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) if not args.get('polys', False): return poly.as_expr() else: return poly
def chebyshevt_poly(n, x=None, **args): """Generates Chebyshev polynomial of the first kind of degree `n` in `x`. """ if n < 0: raise ValueError( "can't generate 1st kind Chebyshev polynomial of degree %s" % n) poly = DMP(dup_chebyshevt(int(n), ZZ), ZZ) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) if not args.get('polys', False): return poly.as_expr() else: return poly
def test_RootOf_conjugate(): p = x**7 + x + 1 assert RootOf(p, 0).conjugate() == RootOf(p, 0) assert RootOf(p, 1).conjugate() == RootOf(p, 2) assert RootOf(p, 2).conjugate() == RootOf(p, 1) assert RootOf(p, 6).conjugate() == RootOf(p, 5) p2 = p * (x - 123) assert RootOf(p2, 0).conjugate() == RootOf(p2, 0) assert RootOf(p2, 1).conjugate() == RootOf(p2, 1) assert RootOf(p2, 2).conjugate() == RootOf(p2, 3) assert RootOf(p2, 3).conjugate() == RootOf(p2, 2) assert RootOf(p2, 7).conjugate() == RootOf(p2, 6) p3 = Poly(x**7 + x * y + 1, x) assert RootOf(p3, x, 0).conjugate() == conjugate(RootOf(p3, x, 0), evaluate=False)
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 jacobi_poly(n, a, b, x=None, **args): """Generates Jacobi polynomial of degree `n` in `x`. """ if n < 0: raise ValueError("can't generate Jacobi polynomial of degree %s" % n) K, v = construct_domain([a, b], field=True) poly = DMP(dup_jacobi(int(n), v[0], v[1], K), K) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) if not args.get('polys', False): return poly.as_expr() else: return poly
def gegenbauer_poly(n, a, x=None, **args): """Generates Gegenbauer polynomial of degree `n` in `x`. """ if n < 0: raise ValueError("can't generate Gegenbauer polynomial of degree %s" % n) K, a = construct_domain(a, field=True) poly = DMP(dup_gegenbauer(int(n), a, K), K) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) if not args.get('polys', False): return poly.as_expr() else: return poly
def spherical_bessel_fn(n, x=None, **args): """ Coefficients for the spherical Bessel functions. Those are only needed in the jn() function. The coefficients are calculated from: fn(0, z) = 1/z fn(1, z) = 1/z**2 fn(n-1, z) + fn(n+1, z) == (2*n+1)/z * fn(n, z) Examples ======== >>> from diofant import Symbol >>> z = Symbol("z") >>> spherical_bessel_fn(1, z) z**(-2) >>> spherical_bessel_fn(2, z) -1/z + 3/z**3 >>> spherical_bessel_fn(3, z) -6/z**2 + 15/z**4 >>> spherical_bessel_fn(4, z) 1/z - 45/z**3 + 105/z**5 """ if n < 0: dup = dup_spherical_bessel_fn_minus(-int(n), ZZ) else: dup = dup_spherical_bessel_fn(int(n), ZZ) poly = DMP(dup, ZZ) if x is not None: poly = Poly.new(poly, 1 / x) else: poly = PurePoly.new(poly, 1 / Dummy('x')) if not args.get('polys', False): return poly.as_expr() else: return poly
def laguerre_poly(n, x=None, alpha=None, **args): """Generates Laguerre polynomial of degree `n` in `x`. """ if n < 0: raise ValueError("can't generate Laguerre polynomial of degree %s" % n) if alpha is not None: K, alpha = construct_domain(alpha, field=True) # XXX: ground_field=True else: K, alpha = QQ, QQ(0) poly = DMP(dup_laguerre(int(n), alpha, K), K) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) if not args.get('polys', False): return poly.as_expr() else: return poly
def test_RootOf_conjugate(): p = x**7 + x + 1 assert RootOf(p, 0).conjugate() == RootOf(p, 0) assert RootOf(p, 1).conjugate() == RootOf(p, 2) assert RootOf(p, 2).conjugate() == RootOf(p, 1) assert RootOf(p, 6).conjugate() == RootOf(p, 5) p2 = p * (x - 123) assert RootOf(p2, 0).conjugate() == RootOf(p2, 0) assert RootOf(p2, 1).conjugate() == RootOf(p2, 1) assert RootOf(p2, 2).conjugate() == RootOf(p2, 3) assert RootOf(p2, 3).conjugate() == RootOf(p2, 2) assert RootOf(p2, 7).conjugate() == RootOf(p2, 6) p3 = Poly(x**7 + x * y + 1, x) assert RootOf(p3, x, 0).conjugate() == conjugate(RootOf(p3, x, 0), evaluate=False) p4 = x**12 - 4 * x**8 + 2 * x**6 + 4 * x**4 + 4 * x**2 + 1 r4 = RootOf(p4, 4) r5 = RootOf(p4, 5) assert r4.conjugate() == r5 assert r4.evalf() == -r5.evalf()
def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.is_ground: return [] if f.is_monomial: return [Integer(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
def test_sympyissue_15413(): assert Poly(sqrt(2) * x**3 + x, x).all_roots() == [0, -I * root(2, -4), I * root(2, -4)]
def test_sympyissue_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_sympyissue_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