def ratint_logpart(f, g, x, t=None): """Lazard-Rioboo-Trager algorithm. Given a field K and polynomials f and g in K[x], such that f and g are coprime, deg(f) < deg(g) and g is square-free, returns a list of tuples (s_i, q_i) of polynomials, for i = 1..n, such that s_i in K[t, x] and q_i in K[t], and: ___ ___ d f d \ ` \ ` -- - = -- ) ) a log(s_i(a, x)) dx g dx /__, /__, i=1..n a | q_i(a) = 0 """ f, g = Poly(f, x), Poly(g, x) t = t or Symbol('t', dummy=True) a, b = g, f - g.diff().mul_term(t) res, R = poly_subresultants(a, b) Q = poly_sqf(Poly(res, t)) R_map, H, i = {}, [], 1 for r in R: R_map[r.degree] = r for q in Q: if q.degree > 0: _, q = q.as_primitive() if g.degree == i: H.append((g, q)) else: h = R_map[i] A = poly_sqf(h.LC, t) for j in xrange(0, len(A)): T = poly_gcd(A[j], q)**(j+1) h = poly_div(h, Poly(T, x))[0] # NOTE: h.LC is always invertible in K[t] inv, coeffs = Poly(h.LC, t).invert(q), [S(1)] for coeff in h.coeffs[1:]: T = poly_div(inv*coeff, q)[1] coeffs.append(T.as_basic()) h = Poly(zip(coeffs, h.monoms), x) H.append((h, q)) i += 1 return H
def poly_sturm(f, *symbols): """Computes the Sturm sequence of a given polynomial. Given an univariate, square-free polynomial f(x) returns an associated Sturm sequence f_0(x), ..., f_n(x) defined by: f_0(x), f_1(x) = f(x), f'(x) f_n = -rem(f_{n-2}(x), f_{n-1}(x)) For more information on the implemented algorithm refer to: [1] J.H. Davenport, Y. Siret, E. Tournier, Computer Algebra Systems and Algorithms for Algebraic Computation, Academic Press, London, 1988, pp. 124-128 """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") if f.is_multivariate: raise MultivariatePolyError(f) else: f = f.as_squarefree() sturm = [f, f.diff()] while not sturm[-1].is_zero: sturm.append(-poly_div(sturm[-2], sturm[-1])[1]) return sturm[:-1]
def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.length == 1: if f.is_constant: return [] else: return [S(0)] * f.degree if f.length == 2: if f.degree == 1: return roots_linear(f) else: return roots_binomial(f) x, result = f.symbols[0], [] for i in [S(-1), S(1)]: if f(i).expand().is_zero: f = poly_div(f, x - i)[0] result.append(i) break n = f.degree if n == 1: result += roots_linear(f) elif n == 2: result += roots_quadratic(f) elif n == 3 and flags.get('cubics', True): result += roots_cubic(f) elif n == 4 and flags.get('quartics', False): result += roots_quartic(f) return result
def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.length == 1: if f.is_constant: return [] else: return [S(0)] * f.degree if f.length == 2: if f.degree == 1: return roots_linear(f) else: return roots_binomial(f) x, result = f.symbols[0], [] for i in [S(-1), S(1)]: if f(i).expand().is_zero: f = poly_div(f, x - i)[0] result.append(i) break n = f.degree if n == 1: result += roots_linear(f) elif n == 2: result += roots_quadratic(f) elif n == 3 and flags.get("cubics", True): result += roots_cubic(f) elif n == 4 and flags.get("quartics", False): result += roots_quartic(f) return result
def roots_trivial(g): if g.length == 1: if g.is_constant: return [] else: return [S.Zero] * g.degree (k,), g = g.as_reduced() if k == 0: zeros = [] else: zeros = [S.Zero] * k if g.length == 2: zeros += roots_binomial(g) else: x = g.symbols[0] for i in [S.NegativeOne, S.One]: if g(i).expand() is S.Zero: g = poly_div(g, x - i)[0] zeros.append(i) break n = g.degree if n == 1: zeros += roots_linear(g) elif n == 2: zeros += roots_quadratic(g) elif n == 3: if flags.get("cubics", False): # TODO: now we can used factor() not only # for cubic polynomials. See #1158 try: _, factors = poly_factors(g) if len(factors) == 1: raise PolynomialError for factor, k in factors: zeros += roots(factor, multiple=True) * k except PolynomialError: zeros += roots_cubic(g) elif n == 4: if flags.get("quartics", False): zeros += roots_quartic(g) return zeros
def roots_trivial(g): if g.length == 1: if g.is_constant: return [] else: return [S.Zero] * g.degree (k, ), g = g.as_reduced() if k == 0: zeros = [] else: zeros = [S.Zero] * k if g.length == 2: zeros += roots_binomial(g) else: x = g.symbols[0] for i in [S.NegativeOne, S.One]: if g(i).expand() is S.Zero: g = poly_div(g, x - i)[0] zeros.append(i) break n = g.degree if n == 1: zeros += roots_linear(g) elif n == 2: zeros += roots_quadratic(g) elif n == 3: if flags.get('cubics', False): # TODO: now we can used factor() not only # for cubic polynomials. See #1158 try: _, factors = poly_factors(g) if len(factors) == 1: raise PolynomialError for factor, k in factors: zeros += roots(factor, multiple=True) * k except PolynomialError: zeros += roots_cubic(g) elif n == 4: if flags.get('quartics', False): zeros += roots_quartic(g) return zeros
def ratint_ratpart(f, g, x): """Horowitz-Ostrogradsky algorithm. Given a field K and polynomials f and g in K[x], such that f and g are coprime and deg(f) < deg(g), returns fractions A and B in K(x), such that f/g = A' + B and B has square-free denominator. """ f, g = Poly(f, x), Poly(g, x) u = poly_gcd(g, g.diff()) v = poly_div(g, u)[0] n = u.degree - 1 m = v.degree - 1 d = g.degree A_coeff = [ Symbol('a' + str(n-i), dummy=True) for i in xrange(0, n+1) ] B_coeff = [ Symbol('b' + str(m-i), dummy=True) for i in xrange(0, m+1) ] symbols = A_coeff + B_coeff A = Poly(zip(A_coeff, xrange(n, -1, -1)), x) B = Poly(zip(B_coeff, xrange(m, -1, -1)), x) H = f - A.diff()*v + A*poly_div(u.diff()*v, u)[0] - B*u result = solve(H.coeffs, symbols) A = A.subs(result) B = B.subs(result) rat_part = Poly.cancel((A, u), x) log_part = Poly.cancel((B, v), x) return rat_part, log_part
def poly_root_factors(f, *symbols, **flags): """Returns all factors of a univariate polynomial. >>> from sympy.polys.rootfinding import poly_root_factors >>> from sympy.abc import x, y >>> factors = poly_root_factors(x**2-y, x) >>> set(f.as_basic() for f in factors) set([x + y**(1/2), x - y**(1/2)]) """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") if f.is_multivariate: raise MultivariatePolyError(f) else: x = f.symbols[0] if 'multiple' in flags: del flags['multiple'] zeros = roots(f, **flags) if not zeros: return [f] else: factors, N = [], 0 for r, n in zeros.iteritems(): h = Poly([(S.One, 1), (-r, 0)], x) factors, N = factors + [h]*n, N + n if N < f.degree: g = reduce(lambda p,q: p*q, factors) factors.append(poly_div(f, g)[0]) return factors
def poly_root_factors(f, *symbols, **flags): """Returns all factors of an univariate polynomial. >>> from sympy import * >>> x,y = symbols('xy') >>> factors = poly_root_factors(x**2-y, x) >>> set(f.as_basic() for f in factors) set([x + y**(1/2), x - y**(1/2)]) """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") if f.is_multivariate: raise MultivariatePolyError(f) else: x = f.symbols[0] if flags.has_key('multiple'): del flags['multiple'] zeros = roots(f, **flags) if not zeros: return [f] else: factors, N = [], 0 for r, n in zeros.iteritems(): h = Poly([(S.One, 1), (-r, 0)], x) factors, N = factors + [h] * n, N + n if N < f.degree: g = reduce(lambda p, q: p * q, factors) factors.append(poly_div(f, g)[0]) return factors
def log_to_atan(f, g): """Convert complex logarithms to real arctangents. Given a real field K and polynomials f and g in K[x], with g != 0, returns a sum h of arctangents of polynomials in K[x], such that: df d f + I g -- = -- I log( ------- ) dx dx f - I g """ if f.degree < g.degree: f, g = -g, f p, q = poly_div(f, g) if q.is_zero: return 2*atan(p.as_basic()) else: s, t, h = poly_gcdex(g, -f) A = 2*atan(quo(f*s+g*t, h)) return A + log_to_atan(s, t)
def ratint(f, x, **flags): """Performs indefinite integration of rational functions. Given a field K and a rational function f = p/q, where p and q are polynomials in K[x], returns a function g such that f = g'. >>> from sympy.integrals.rationaltools import ratint >>> from sympy.abc import x >>> ratint(36/(x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2), x) -4*log(1 + x) + 4*log(-2 + x) - (6 + 12*x)/(1 - x**2) References ========== .. [Bro05] M. Bronstein, Symbolic Integration I: Transcendental Functions, Second Edition, Springer-Verlag, 2005, pp. 35-70 """ if type(f) is not tuple: p, q = f.as_numer_denom() else: p, q = f p, q = Poly(p, x), Poly(q, x) g = poly_gcd(p, q) p = poly_div(p, g)[0] q = poly_div(q, g)[0] result, p = poly_div(p, q) result = result.integrate(x).as_basic() if p.is_zero: return result g, h = ratint_ratpart(p, q, x) P, Q = h.as_numer_denom() q, r = poly_div(P, Q, x) result += g + q.integrate(x).as_basic() if not r.is_zero: symbol = flags.get('symbol', 't') if not isinstance(symbol, Symbol): t = Symbol(symbol, dummy=True) else: t = symbol L = ratint_logpart(r, Q, x, t) real = flags.get('real') if real is None: if type(f) is not tuple: atoms = f.atoms() else: p, q = f atoms = p.atoms() \ | q.atoms() for elt in atoms - set([x]): if not elt.is_real: real = False break else: real = True eps = S(0) if not real: for h, q in L: eps += RootSum(Lambda(t, t*log(h.as_basic())), q) else: for h, q in L: R = log_to_real(h, q, x, t) if R is not None: eps += R else: eps += RootSum(Lambda(t, t*log(h.as_basic())), q) result += eps return result
def test_poly_div(): f = Poly(x**3-12*x**2-42, x) g = Poly(x**2+x-3, x) h = poly_div(f, g) assert h[0] == Poly(x-13, x) assert h[1] == Poly(16*x-81, x) assert h[0].as_basic() == x-13 assert h[1].as_basic() == 16*x-81 assert f / g == Poly(x-13, x) assert f % g == Poly(16*x-81, x) assert divmod(f, g) == (Poly(x-13, x), Poly(16*x-81, x)) assert f / x == Poly(x**2-12*x, x) assert f % x == Poly(-42, x) assert divmod(f, x) == (Poly(x**2-12*x, x), Poly(-42, x)) assert f / sin(x) == f.as_basic() / sin(x) assert f % sin(x) == 0 assert divmod(f, sin(x)) == (f.as_basic() / sin(x), 0) assert poly_div(4*x**2*y-2*x*y-2*y+4*x+8, 2, x, y) == \ (Poly(2*x**2*y-x*y-y+2*x+4, x, y), Poly((), x, y)) assert poly_div(4*x**2*y-2*x*y-2*y+4*x+8, 2*y, x, y) == \ (Poly(2*x**2-x-1, x, y), Poly(4*x+8, x, y)) assert poly_div(x-1, y-1, x, y) == (Poly((), x, y), Poly(x-1, x, y)) assert poly_div(x**3-12*x**2-42, x-3, x) == \ (Poly(x**2-9*x-27, x), Poly(-123, x)) assert poly_div(2+2*x+x**2, 1, x) == (Poly(2+2*x+x**2, x), Poly(0, x)) assert poly_div(2+2*x+x**2, 2, x) == (Poly(1+x+x**2/2, x), Poly(0, x)) assert poly_div(3*x**3, x**2, x) == (Poly(3*x, x), Poly(0, x)) assert poly_div(1, x, x) == (Poly(0, x), Poly(1, x)) assert poly_div(x*y+2*x+y,x,x) == (Poly(2+y, x), Poly(y, x)) assert poly_div(x*y**2 + 1, [x*y+1, y+1], x, y) == \ ([Poly(y, x, y), Poly(-1, x, y)], Poly(2, x, y)) assert poly_div(x**2*y+x*y**2+y**2, [x*y-1, y**2-1], x, y) == \ ([Poly(x+y, x, y), Poly(1, x, y)], Poly(1+x+y, x, y)) assert poly_div(x**2*y+x*y**2+y**2, [y**2-1, x*y-1], x, y) == \ ([Poly(1+x, x, y), Poly(x, x, y)], Poly(1+2*x, x, y)) f, g = 3*x**3 + x**2 + x + 5, 5*x**2 - 3*x + 1 q = Poly(Rational(3,5)*x + Rational(14, 25), x) r = Poly(Rational(52, 25)*x + Rational(111, 25), x) assert poly_div(f, g, x) == (q, r) assert poly_div(Poly(f, x), Poly(g, x)) == (q, r) q = Poly(15*x + 14, x) r = Poly(52*x + 111, x) assert poly_pdiv(f, g, x) == (q, r) assert poly_pdiv(Poly(f, x), Poly(g, x)) == (q, r)
def ratint(f, x, **flags): """Performs indefinite integration of rational functions. Given a field K and a rational function f = p/q, where p and q are polynomials in K[x], returns a function g such that f = g'. >>> from sympy import * >>> x = Symbol('x') >>> ratint(36/(x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2), x) -4*log(1 + x) + 4*log(-2 + x) - (6 + 12*x)/(1 - x**2) References ========== .. [Bro05] M. Bronstein, Symbolic Integration I: Transcendental Functions, Second Edition, Springer-Verlang, 2005, pp. 35-70 """ if type(f) is not tuple: p, q = f.as_numer_denom() else: p, q = f p, q = Poly(p, x), Poly(q, x) g = poly_gcd(p, q) p = poly_div(p, g)[0] q = poly_div(q, g)[0] result, p = poly_div(p, q) result = result.integrate(x).as_basic() if p.is_zero: return result g, h = ratint_ratpart(p, q, x) P, Q = h.as_numer_denom() q, r = poly_div(P, Q, x) result += g + q.integrate(x).as_basic() if not r.is_zero: symbol = flags.get('symbol', 't') if not isinstance(symbol, Symbol): t = Symbol(symbol, dummy=True) else: t = symbol L = ratint_logpart(r, Q, x, t) real = flags.get('real') if real is None: if type(f) is not tuple: atoms = f.atoms() else: p, q = f atoms = p.atoms() \ | q.atoms() for elt in atoms - set([x]): if not elt.is_real: real = False break else: real = True eps = S(0) if not real: for h, q in L: eps += RootSum(Lambda(t, t*log(h.as_basic())), q) else: for h, q in L: R = log_to_real(h, q, x, t) if R is not None: eps += R else: eps += RootSum(Lambda(t, t*log(h.as_basic())), q) result += eps return result