Exemplo n.º 1
0
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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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
Exemplo n.º 6
0
def test_poly_gcd():
    assert poly_gcd(0, 0, x) == Poly(0, x)
    assert poly_gcd(0, 1, x) == Poly(1, x)
    assert poly_gcd(1, 0, x) == Poly(1, x)
    assert poly_gcd(1, 1, x) == Poly(1, x)

    assert poly_gcd(x-1, 0, x) == Poly(x-1, x)
    assert poly_gcd(0, x-1, x) == Poly(x-1, x)

    assert poly_gcd(-x-1, 0, x) == Poly(x+1, x)
    assert poly_gcd(0, -x-1, x) == Poly(x+1, x)

    assert poly_gcd(2, 6, x) == Poly(2, x)
    assert poly_gcd(2, 6, x, y) == Poly(2, x, y)

    assert poly_gcd(x, y, x, y) == Poly(1, x, y)

    assert poly_gcd(2*x**3, 6*x, x) == Poly(2*x, x)
    assert poly_gcd(2*x**3, 3*x, x) == Poly(x, x)

    assert poly_gcd(2*x**3*y, 6*x*y**2, x, y) == Poly(2*x*y, x, y)
    assert poly_gcd(2*x**3*y, 3*x*y**2, x, y) == Poly(x*y, x, y)

    assert poly_gcd(x**2+2*x+1, x+1, x) == Poly(x+1, x)
    assert poly_gcd(x**2+2*x+2, x+1, x) == Poly(1, x)

    assert poly_gcd(x**2+2*x+1, 2+2*x, x) == Poly(x+1, x)
    assert poly_gcd(x**2+2*x+2, 2+2*x, x) == Poly(1, x)

    assert poly_gcd(sin(z)*(x+y), x**2+2*x*y+y**2,
        x, y) == Poly(x+y, x, y)

    f = x**8+x**6-3*x**4-3*x**3+8*x**2+2*x-5
    g = 3*x**6+5*x**4-4*x**2-9*x+21

    assert poly_gcd(f, g, x) == Poly(1, x)
Exemplo n.º 7
0
def test_poly_gcd():
    assert poly_gcd(0, 0, x) == Poly(0, x)
    assert poly_gcd(0, 1, x) == Poly(1, x)
    assert poly_gcd(1, 0, x) == Poly(1, x)
    assert poly_gcd(1, 1, x) == Poly(1, x)

    assert poly_gcd(x-1, 0, x) == Poly(x-1, x)
    assert poly_gcd(0, x-1, x) == Poly(x-1, x)

    assert poly_gcd(-x-1, 0, x) == Poly(x+1, x)
    assert poly_gcd(0, -x-1, x) == Poly(x+1, x)

    assert poly_gcd(2, 6, x) == Poly(2, x)
    assert poly_gcd(2, 6, x, y) == Poly(2, x, y)

    assert poly_gcd(x, y, x, y) == Poly(1, x, y)

    assert poly_gcd(2*x**3, 6*x, x) == Poly(2*x, x)
    assert poly_gcd(2*x**3, 3*x, x) == Poly(x, x)

    assert poly_gcd(2*x**3*y, 6*x*y**2, x, y) == Poly(2*x*y, x, y)
    assert poly_gcd(2*x**3*y, 3*x*y**2, x, y) == Poly(x*y, x, y)

    assert poly_gcd(x**2+2*x+1, x+1, x) == Poly(x+1, x)
    assert poly_gcd(x**2+2*x+2, x+1, x) == Poly(1, x)

    assert poly_gcd(x**2+2*x+1, 2+2*x, x) == Poly(x+1, x)
    assert poly_gcd(x**2+2*x+2, 2+2*x, x) == Poly(1, x)

    assert poly_gcd(sin(z)*(x+y), x**2+2*x*y+y**2,
        x, y) == Poly(x+y, x, y)

    f = x**8+x**6-3*x**4-3*x**3+8*x**2+2*x-5
    g = 3*x**6+5*x**4-4*x**2-9*x+21

    assert poly_gcd(f, g, x) == Poly(1, x)
Exemplo n.º 8
0
def apart(f, z, **flags):
    """Compute partial fraction decomposition of a rational function.

       Given a rational function 'f', performing only gcd operations
       over the algebraic closue of the initial field of definition,
       compute full partial fraction decomposition with fractions
       having linear denominators.

       For all other kinds of expressions the input is returned in an
       unchanged form. Note however, that 'apart' function can thread
       over sums and relational operators.

       Note that no factorization of the initial denominator of 'f' is
       needed.  The final decomposition is formed in terms of a sum of
       RootSum instances.  By default RootSum tries to compute all its
       roots to simplify itself. This behaviour can be however avoided
       by seting the keyword flag evaluate=False, which will make this
       function return a formal decomposition.

       >>> from sympy import *
       >>> x,y = symbols('xy')

       >>> apart(y/(x+2)/(x+1), x)
       y/(1 + x) - y/(2 + x)

       >>> apart(1/(1+x**5), x, evaluate=False)
       RootSum(Lambda(_a, -1/5/(x - _a)*_a), x**5 + 1, x)

       For more information on the implemented algorithm refer to:

       [1] M. Bronstein, B. Salvy, Full partial fraction decomposition
           of rational functions,  in: M. Bronstein,  ed., Proceedings
           ISSAC '93, ACM Press, Kiev, Ukraine, 1993, pp. 157-160.

    """
    if not f.has(z):
        return f

    f = Poly.cancel(f, z)

    P, Q = f.as_numer_denom()

    if not Q.has(z):
        return f

    partial, r = div(P, Q, z)
    f, q, U = r / Q, Q, []

    u = Function('u')(z)
    a = Symbol('a', dummy=True)

    for k, d in enumerate(poly_sqf(q, z)):
        n, b = k + 1, d.as_basic()
        U += [u.diff(z, k)]

        h = together(Poly.cancel(f * b**n, z) / u**n)

        H, subs = [h], []

        for j in range(1, n):
            H += [H[-1].diff(z) / j]

        for j in range(1, n + 1):
            subs += [(U[j - 1], b.diff(z, j) / j)]

        for j in range(0, n):
            P, Q = together(H[j]).as_numer_denom()

            for i in range(0, j + 1):
                P = P.subs(*subs[j - i])

            Q = Q.subs(*subs[0])

            P, Q = Poly(P, z), Poly(Q, z)

            G = poly_gcd(P, d)
            D = poly_quo(d, G)

            B, g = poly_half_gcdex(Q, D)
            b = poly_rem(P * poly_quo(B, g), D)

            numer = b.as_basic()
            denom = (z - a)**(n - j)

            expr = numer.subs(z, a) / denom

            partial += RootSum(Lambda(a, expr), D, **flags)

    return partial
Exemplo n.º 9
0
def apart(f, z, **flags):
    """Compute partial fraction decomposition of a rational function.

       Given a rational function 'f', performing only gcd operations
       over the algebraic closue of the initial field of definition,
       compute full partial fraction decomposition with fractions
       having linear denominators.

       For all other kinds of expressions the input is returned in an
       unchanged form. Note however, that 'apart' function can thread
       over sums and relational operators.

       Note that no factorization of the initial denominator of 'f' is
       needed.  The final decomposition is formed in terms of a sum of
       RootSum instances.  By default RootSum tries to compute all its
       roots to simplify itself. This behaviour can be however avoided
       by seting the keyword flag evaluate=False, which will make this
       function return a formal decomposition.

       >>> from sympy import *
       >>> x,y = symbols('xy')

       >>> apart(y/(x+2)/(x+1), x)
       y/(1 + x) - y/(2 + x)

       >>> apart(1/(1+x**5), x, evaluate=False)
       RootSum(Lambda(_a, -1/5/(x - _a)*_a), x**5 + 1, x)

       For more information on the implemented algorithm refer to:

       [1] M. Bronstein, B. Salvy, Full partial fraction decomposition
           of rational functions,  in: M. Bronstein,  ed., Proceedings
           ISSAC '93, ACM Press, Kiev, Ukraine, 1993, pp. 157-160.

    """
    if not f.has(z):
        return f

    f = Poly.cancel(f, z)

    P, Q = f.as_numer_denom()

    if not Q.has(z):
        return f

    partial, r = div(P, Q, z)
    f, q, U = r / Q, Q, []

    u = Function('u')(z)
    a = Symbol('a', dummy=True)

    for k, d in enumerate(poly_sqf(q, z)):
        n, b = k + 1, d.as_basic()
        U += [ u.diff(z, k) ]

        h = together(Poly.cancel(f*b**n, z) / u**n)

        H, subs = [h], []

        for j in range(1, n):
            H += [ H[-1].diff(z) / j ]

        for j in range(1, n+1):
            subs += [ (U[j-1], b.diff(z, j) / j) ]

        for j in range(0, n):
            P, Q = together(H[j]).as_numer_denom()

            for i in range(0, j+1):
                P = P.subs(*subs[j-i])

            Q = Q.subs(*subs[0])

            P, Q = Poly(P, z), Poly(Q, z)

            G = poly_gcd(P, d)
            D = poly_quo(d, G)

            B, g = poly_half_gcdex(Q, D)
            b = poly_rem(P * poly_quo(B, g), D)

            numer = b.as_basic()
            denom = (z-a)**(n-j)

            expr = numer.subs(z, a) / denom

            partial += RootSum(Lambda(a, expr), D, **flags)

    return partial
Exemplo n.º 10
0
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