Example #1
0
    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
Example #2
0
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)
Example #3
0
def filter_roots(poly, n, predicate):
    return [ r for r in set(roots(poly, n)) if predicate(r) ]
Example #4
0
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
Example #5
0
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)