def _eval_product(self, term=None): k = self.index a = self.lower n = self.upper if term is None: term = self.term if not term.has(k): return term ** (n - a + 1) elif term.is_polynomial(k): poly = term.as_polynomial(k) A = B = Q = S.One C = poly.leading_coeff() all_roots = roots(poly) for r in all_roots: A *= Basic.RisingFactorial(a - r, n - a + 1) Q *= n - r if len(all_roots) < poly.degree(): B = Product(quo(poly, Q, k), (k, a, n)) return C ** (n - a + 1) * A * B elif isinstance(term, Basic.Add): p, q = term.as_numer_denom() p = self._eval_product(p) q = self._eval_product(q) return p / q elif isinstance(term, Basic.Mul): exclude, include = [], [] for t in term: p = self._eval_product(t) if p is not None: exclude.append(p) else: include.append(p) if not exclude: return None else: A, B = Mul(*exclude), Mul(*include) return A * Product(B, (k, a, n)) elif isinstance(term, Basic.Pow): if not term.base.has(k): s = sum(term.exp, (k, a, n)) if not isinstance(s, Sum): return term.base ** s elif not term.exp.has(k): p = self._eval_product(term.base) if p is not None: return p ** term.exp
def factorization(poly, linear=False): """Returns a list with polynomial factors over rationals or, if 'linear' flag is set over Q(i). This simple handler should be merged with original factor() method. >>> from sympy import * >>> x, y = symbols('xy') >>> factorization(x**2 - y**2) set([1, x - y, x + y]) >>> factorization(x**2 + 1) set([1, 1 + x**2]) >>> factorization(x**2 + 1, linear=True) set([1, x - I, I + x]) """ factored = set([ q.as_basic() for q in factor_.factor(poly) ]) if not linear: return factored else: factors = [] for factor in factored: symbols = factor.atoms(Symbol) if len(symbols) == 1: x = symbols.pop() else: factors += [ factor ] continue linearities = [ x - r for r in roots(factor, x) ] if not linearities: factors += [ factor ] else: unfactorable = quo(factor, Basic.Mul(*linearities)) if not isinstance(unfactorable, Basic.Number): factors += [ unfactorable ] factors += linearities return set(factors)
def filter_roots(poly, n, predicate): return [ r for r in set(roots(poly, n)) if predicate(r) ]
def rsolve_hyper(coeffs, f, n, **hints): """Given linear recurrence operator L of order 'k' with polynomial coefficients and inhomogeneous equation Ly = f we seek for all hypergeometric solutions over field K of characteristic zero. The inhomogeneous part can be either hypergeometric or a sum of a fixed number of pairwise dissimilar hypergeometric terms. The algorithm performs three basic steps: (1) Group together similar hypergeometric terms in the inhomogeneous part of Ly = f, and find particular solution using Abramov's algorithm. (2) Compute generating set of L and find basis in it, so that all solutions are lineary independent. (3) Form final solution with the number of arbitrary constants equal to dimension of basis of L. Term a(n) is hypergeometric if it is anihilated by first order linear difference equations with polynomial coefficients or, in simpler words, if consecutive term ratio is a rational function. The output of this procedure is a linear combination of fixed number of hypergeometric terms. However the underlying method can generate larger class of solutions - D'Alembertian terms. Note also that this method not only computes the kernel of the inhomogeneous equation, but also reduces in to a basis so that solutions generated by this procedure are lineary independent For more information on the implemented algorithm refer to: [1] M. Petkovsek, Hypergeometric solutions of linear recurrences with polynomial coefficients, J. Symbolic Computation, 14 (1992), 243-264. [2] M. Petkovsek, H. S. Wilf, D. Zeilberger, A = B, 1996. """ coeffs = map(Basic.sympify, coeffs) f = Basic.sympify(f) r, kernel = len(coeffs)-1, [] if not isinstance(f, Basic.Zero): if isinstance(f, Basic.Add): similar = {} for g in f.expand(): if not g.is_hypergeometric(n): return None for h in similar.iterkeys(): if hypersimilar(g, h, n): similar[h] += g break else: similar[g] = S.Zero inhomogeneous = [] for g, h in similar.iteritems(): inhomogeneous.append(g+h) elif f.is_hypergeometric(n): inhomogeneous = [f] else: return None for i, g in enumerate(inhomogeneous): coeff, polys = S.One, coeffs[:] denoms = [ S.One ] * (r+1) s = hypersimp(g, n) for j in xrange(1, r+1): coeff *= s.subs(n, n+j-1) p, q = coeff.as_numer_denom() polys[j] *= p denoms[j] = q for j in xrange(0, r+1): polys[j] *= Mul(*(denoms[:j] + denoms[j+1:])) R = rsolve_poly(polys, Mul(*denoms), n) if not (R is None or isinstance(R, Basic.Zero)): inhomogeneous[i] *= R else: return None result = Add(*inhomogeneous) else: result = S.Zero Z = Symbol('Z', dummy=True) p, q = coeffs[0], coeffs[r].subs(n, n-r+1) p_factors = [ z for z in set(roots(p, n)) ] q_factors = [ z for z in set(roots(q, n)) ] factors = [ (S.One, S.One) ] for p in p_factors: for q in q_factors: if p.is_integer and q.is_integer and p <= q: continue else: factors += [(n-p, n-q)] p = [ (n-p, S.One) for p in p_factors ] q = [ (S.One, n-q) for q in q_factors ] factors = p + factors + q for A, B in factors: polys, degrees = [], [] D = A*B.subs(n, n+r-1) for i in xrange(0, r+1): a = Mul(*[ A.subs(n, n+j) for j in xrange(0, i) ]) b = Mul(*[ B.subs(n, n+j) for j in xrange(i, r) ]) poly = (quo(coeffs[i]*a*b, D, n)) polys.append(poly.as_polynomial(n)) if not isinstance(poly, Basic.Zero): degrees.append(polys[i].degree()) d, poly = max(degrees), S.Zero for i in xrange(0, r+1): coeff = polys[i].nth_coeff(d) if not isinstance(coeff, Basic.Zero): poly += coeff * Z**i for z in set(roots(poly, Z)): if not z.is_real or z.is_zero: continue C = rsolve_poly([ polys[i]*z**i for i in xrange(r+1) ], 0, n) if C is not None and not isinstance(C, Basic.Zero): ratio = z * A * C.subs(n, n + 1) / B / C K = product(simplify(ratio), (n, 0, n-1)) if casoratian(kernel+[K], n) != 0: kernel.append(K) symbols = [ Symbol('C'+str(i)) for i in xrange(len(kernel)) ] for C, ker in zip(symbols, kernel): result += C * ker if hints.get('symbols', False): return (result, symbols) else: return result
def solve(eq, syms, simplified=True): """Solves univariate polynomial equations and linear systems with arbitrary symbolic coefficients. This function is just a wrapper which makes analysis of its arguments and executes more specific functions like 'roots' or 'solve_linear_system' etc. On input you have to specify equation or a set of equations (in this case via a list) using '==' pretty syntax or via ordinary expressions, and a list of variables. On output you will get a list of solutions in univariate case or a dictionary with variables as keys and solutions as values in the other case. If there were variables with can be assigned with arbitrary value, then they will be avoided in the output. Optionaly it is possible to have the solutions preprocessed using simplification routines if 'simplified' flag is set. To solve recurrence relations or differential equations use 'rsolve' or 'dsolve' functions respectively, which are also wrappers combining set of problem specific methods. >>> from sympy import * >>> x, y, a = symbols('xya') >>> r = solve(x**2 - 3*x + 2, x) >>> r.sort() >>> print r [1, 2] >>> solve(x**2 == a, x) [-a**(1/2), a**(1/2)] >>> solve(x**4 == 1, x) [I, 1, -1, -I] >>> solve([x + 5*y == 2, -3*x + 6*y == 15], [x, y]) {y: 1, x: -3} """ if isinstance(syms, Basic): syms = [syms] if not isinstance(eq, list): if isinstance(eq, Equality): # got equation, so move all the # terms to the left hand side equ = eq.lhs - eq.rhs else: equ = Basic.sympify(eq) try: # 'roots' method will return all possible complex # solutions, however we have to remove duplicates solutions = list(set(roots(equ, syms[0]))) except PolynomialException: raise "Not a polynomial equation. Can't solve it, yet." if simplified == True: return [ simplify(s) for s in solutions ] else: return solutions else: if eq == []: return {} else: # augmented matrix n, m = len(eq), len(syms) matrix = zeronm(n, m+1) index = {} for i in range(0, m): index[syms[i]] = i for i in range(0, n): if isinstance(eq[i], Equality): # got equation, so move all the # terms to the left hand side equ = eq[i].lhs - eq[i].rhs else: equ = Basic.sympify(eq[i]) content = collect(equ.expand(), syms, evaluate=False) for var, expr in content.iteritems(): if isinstance(var, Symbol) and not expr.has(*syms): matrix[i, index[var]] = expr elif isinstance(var, Basic.One) and not expr.has(*syms): matrix[i, m] = -expr else: raise "Not a linear system. Can't solve it, yet." else: return solve_linear_system(matrix, syms, simplified)