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 = Poly(f, x) g = Poly(g, x) u, v, _ = g.cofactors(g.diff()) n = u.degree() m = v.degree() d = g.degree() A_coeffs = [ Dummy('a' + str(n-i)) for i in xrange(0, n) ] B_coeffs = [ Dummy('b' + str(m-i)) for i in xrange(0, m) ] C_coeffs = A_coeffs + B_coeffs A = Poly(A_coeffs, x, domain=ZZ[C_coeffs]) B = Poly(B_coeffs, x, domain=ZZ[C_coeffs]) H = f - A.diff()*v + A*(u.diff()*v).exquo(u) - B*u result = solve(H.coeffs(), C_coeffs) A = A.as_basic().subs(result) B = B.as_basic().subs(result) rat_part = cancel(A/u.as_basic(), x) log_part = cancel(B/v.as_basic(), x) return rat_part, log_part
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 = Poly(f, x) g = Poly(g, x) u, v, _ = g.cofactors(g.diff()) n = u.degree() m = v.degree() d = g.degree() A_coeffs = [Dummy('a' + str(n - i)) for i in xrange(0, n)] B_coeffs = [Dummy('b' + str(m - i)) for i in xrange(0, m)] C_coeffs = A_coeffs + B_coeffs A = Poly(A_coeffs, x, domain=ZZ[C_coeffs]) B = Poly(B_coeffs, x, domain=ZZ[C_coeffs]) H = f - A.diff() * v + A * (u.diff() * v).exquo(u) - B * u result = solve(H.coeffs(), C_coeffs) A = A.as_basic().subs(result) B = B.as_basic().subs(result) rat_part = cancel(A / u.as_basic(), x) log_part = cancel(B / v.as_basic(), x) return rat_part, log_part
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} """ multiple = flags.get('multiple', False) 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') f, x = f.to_field(), 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 = f.decompose() result, g = {}, factors[0] for h, i in g.sqf_list()[1]: for r in _try_heuristics(h): _update_dict(result, r, i) for factor in factors[1:]: last, result = result.copy(), {} for last_r, i in last.iteritems(): g = factor - Poly(last_r, x) for h, j in g.sqf_list()[1]: for r in _try_heuristics(h): _update_dict(result, r, i*j) return result 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 [S(-1), S(1)]: if f.eval(i).expand().is_zero: f = f.exquo(Poly(x-1, 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 flags.get('cubics', True): result += roots_cubic(f) elif n == 4 and flags.get('quartics', True): 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.length() == 2: if f.degree() == 1: result[cancel(roots_linear(f)[0])] = 1 else: for r in roots_binomial(f): _update_dict(result, r, 1) elif f.degree() == 2: for r in roots_quadratic(f): _update_dict(result, cancel(r), 1) else: _, factors = Poly(f.as_basic()).factor_list() if len(factors) == 1 and factors[0][1] == 1: result = _try_decompose(f) else: for factor, k in factors: for r in _try_heuristics(Poly(factor, x, field=True)): _update_dict(result, r, k) result.update(zeros) filter = flags.get('filter', None) 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] predicate = flags.get('predicate', None) 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