Ejemplo 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
Ejemplo 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
Ejemplo n.º 3
0
def test_squarefree():
    assert Poly(x-1, x).is_squarefree == True
    assert Poly((x-1)**2, x).is_squarefree == False

    assert Poly(3*x**2, x).as_squarefree() == Poly(3*x, x)
    assert Poly(x**2+2*x+1, x).as_squarefree() == Poly(x+1, x)
    assert Poly(x**5-x**4-x+1, x).as_squarefree() == Poly(x**4-1, x)

    assert poly_sqf(1, x) == [Poly(1, x)]
    assert poly_sqf(x, x) == [Poly(x, x)]

    assert poly_sqf(3*x**2, x) == [Poly(3, x), Poly(x, x)]
    assert poly_sqf(x**2+2*x+1, x) == [Poly(1, x), Poly(x+1, x)]

    assert poly_sqf(x**5-x**4-x+1, x) == \
        [Poly(x**3 + x**2 + x + 1, x), Poly(x-1, x)]
    assert poly_sqf(x**8+6*x**6+12*x**4+8*x**2, x) == \
        [Poly(1, x), Poly(x, x), Poly(x**2+2, x)]

    # Bronstein, Symbolic Integration, pp. 52

    A = Poly(x**4 - 3*x**2 + 6, x)
    D = Poly(x**6 - 5*x**4 + 5*x**2 + 4, x)

    f, g = D, A - D.diff(x).mul_term(t)

    res, R = poly_subresultants(f, g)
    S = poly_sqf(Poly(res, t))

    assert S == [Poly(45796, t), Poly(1, t), Poly(4*t**2 + 1, t)]
Ejemplo n.º 4
0
def test_squarefree():
    assert Poly(x-1, x).is_squarefree == True
    assert Poly((x-1)**2, x).is_squarefree == False

    assert Poly(3*x**2, x).as_squarefree() == Poly(3*x, x)
    assert Poly(x**2+2*x+1, x).as_squarefree() == Poly(x+1, x)
    assert Poly(x**5-x**4-x+1, x).as_squarefree() == Poly(x**4-1, x)

    assert poly_sqf(1, x) == [Poly(1, x)]
    assert poly_sqf(x, x) == [Poly(x, x)]

    assert poly_sqf(3*x**2, x) == [Poly(3, x), Poly(x, x)]
    assert poly_sqf(x**2+2*x+1, x) == [Poly(1, x), Poly(x+1, x)]

    assert poly_sqf(x**5-x**4-x+1, x) == \
        [Poly(x**3 + x**2 + x + 1, x), Poly(x-1, x)]
    assert poly_sqf(x**8+6*x**6+12*x**4+8*x**2, x) == \
        [Poly(1, x), Poly(x, x), Poly(x**2+2, x)]

    # Bronstein, Symbolic Integration, pp. 52

    A = Poly(x**4 - 3*x**2 + 6, x)
    D = Poly(x**6 - 5*x**4 + 5*x**2 + 4, x)

    f, g = D, A - D.diff(x).mul_term(t)

    res, R = poly_subresultants(f, g)
    S = poly_sqf(Poly(res, t))

    assert S == [Poly(45796, t), Poly(1, t), Poly(4*t**2 + 1, t)]
Ejemplo n.º 5
0
    def _try_decompose(f):
        """Find roots using functional decomposition. """
        factors = poly_decompose(f)
        result, g = {}, factors[0]

        for i, h in enumerate(poly_sqf(g)):
            for r in _try_heuristics(h):
                _update_dict(result, r, i + 1)

        for factor in factors[1:]:
            last, result = result.copy(), {}

            for last_r, i in last.iteritems():
                g = factor.sub_term(last_r, (0,))

                for j, h in enumerate(poly_sqf(g)):
                    for r in _try_heuristics(h):
                        _update_dict(result, r, i * (j + 1))

        return result
Ejemplo n.º 6
0
    def _try_decompose(f):
        """Find roots using functional decomposition. """
        factors = poly_decompose(f)
        result, g = {}, factors[0]

        for i, h in enumerate(poly_sqf(g)):
            for r in _try_heuristics(h):
                _update_dict(result, r, i + 1)

        for factor in factors[1:]:
            last, result = result.copy(), {}

            for last_r, i in last.iteritems():
                g = factor.sub_term(last_r, (0, ))

                for j, h in enumerate(poly_sqf(g)):
                    for r in _try_heuristics(h):
                        _update_dict(result, r, i * (j + 1))

        return result
Ejemplo n.º 7
0
def test_squarefree():
    assert Poly(x-1, x).is_squarefree == True
    assert Poly((x-1)**2, x).is_squarefree == False

    assert Poly(3*x**2, x).as_squarefree() == Poly(3*x, x)
    assert Poly(x**2+2*x+1, x).as_squarefree() == Poly(x+1, x)
    assert Poly(x**5-x**4-x+1, x).as_squarefree() == Poly(x**4-1, x)

    assert poly_sqf(1, x) == [Poly(1, x)]
    assert poly_sqf(x, x) == [Poly(x, x)]

    assert poly_sqf(3*x**2, x) == [Poly(3, x), Poly(x, x)]
    assert poly_sqf(x**2+2*x+1, x) == [Poly(1, x), Poly(x+1, x)]

    assert poly_sqf(x**5-x**4-x+1, x) == \
        [Poly(x**3 + x**2 + x + 1, x), Poly(x-1, x)]
    assert poly_sqf(x**8+6*x**6+12*x**4+8*x**2, x) == \
        [Poly(1, x), Poly(x, x), Poly(x**2+2, x)]
Ejemplo n.º 8
0
def test_squarefree():
    assert Poly(x - 1, x).is_squarefree == True
    assert Poly((x - 1)**2, x).is_squarefree == False

    assert Poly(3 * x**2, x).as_squarefree() == Poly(3 * x, x)
    assert Poly(x**2 + 2 * x + 1, x).as_squarefree() == Poly(x + 1, x)
    assert Poly(x**5 - x**4 - x + 1, x).as_squarefree() == Poly(x**4 - 1, x)

    assert poly_sqf(1, x) == [Poly(1, x)]
    assert poly_sqf(x, x) == [Poly(x, x)]

    assert poly_sqf(3 * x**2, x) == [Poly(3, x), Poly(x, x)]
    assert poly_sqf(x**2 + 2 * x + 1, x) == [Poly(1, x), Poly(x + 1, x)]

    assert poly_sqf(x**5-x**4-x+1, x) == \
        [Poly(x**3 + x**2 + x + 1, x), Poly(x-1, x)]
    assert poly_sqf(x**8+6*x**6+12*x**4+8*x**2, x) == \
        [Poly(1, x), Poly(x, x), Poly(x**2+2, x)]
Ejemplo n.º 9
0
def roots(f, *symbols, **flags):
    """Computes symbolic roots of an univariate polynomial.

       Given an univariate  polynomial f with symbolic 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 aren't used in
       the algorithm because of unreadable output. To enable them
       set cubics=True or quartics=True respectively.

       To get roots from a specific domain set the 'domain' flag with
       one of the following specifiers: Z, Q, R, I, C. By default all
       roots are returned (this is equivalent to setting domain='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.

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

       >>> roots(x**2 - 1, x)
       {1: 1, -1: 1}

       >>> roots(x**2 - y, x)
       {y**(1/2): 1, -y**(1/2): 1}

    """
    if not isinstance(f, Poly):
        f = Poly(f, *symbols)
    elif symbols:
        raise SymbolsError("Redundant symbols were given")

    if f.is_multivariate:
        raise MultivariatePolyError(f)

    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

    multiple = flags.get("multiple", False)

    if f.length == 1:
        if f.is_constant:
            if multiple:
                return []
            else:
                return {}
        else:
            result = {S.Zero: f.degree}
    else:
        (k,), f = f.as_reduced()

        if k == 0:
            result = {}
        else:
            result = {S.Zero: k}

        if f.degree == 1:
            result[roots_linear(f)[0]] = 1
        else:
            factors = poly_decompose(f)

            zeros, g = {}, factors[0]

            for i, h in enumerate(poly_sqf(g)):
                for zero in roots_trivial(h):
                    if zeros.has_key(zero):
                        zeros[zero] += i + 1
                    else:
                        zeros[zero] = i + 1

            for factor in factors[1:]:
                previous, zeros = zeros.copy(), {}

                for zero, i in previous.iteritems():
                    g = factor.sub_term(zero, (0,))

                    for j, h in enumerate(poly_sqf(g)):
                        for zero in roots_trivial(h):
                            if zeros.has_key(zero):
                                zeros[zero] += i * (j + 1)
                            else:
                                zeros[zero] = i * (j + 1)

            result.update(zeros)

    domain = flags.get("domain", None)

    if domain 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[domain]
        except KeyError:
            raise ValueError("Invalid domain: %s" % domain)

        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
Ejemplo n.º 10
0
def roots(f, *symbols, **flags):
    """Computes symbolic roots of an univariate polynomial.

       Given an univariate  polynomial f with symbolic 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 aren't used in
       the algorithm because of unreadable output. To enable them
       set cubics=True or quartics=True respectively.

       To get roots from a specific domain set the 'domain' flag with
       one of the following specifiers: Z, Q, R, I, C. By default all
       roots are returned (this is equivalent to setting domain='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.

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

       >>> roots(x**2 - 1, x)
       {1: 1, -1: 1}

       >>> roots(x**2 - y, x)
       {y**(1/2): 1, -y**(1/2): 1}

    """
    if not isinstance(f, Poly):
        f = Poly(f, *symbols)
    elif symbols:
        raise SymbolsError("Redundant symbols were given")

    if f.is_multivariate:
        raise MultivariatePolyError(f)

    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

    multiple = flags.get('multiple', False)

    if f.length == 1:
        if f.is_constant:
            if multiple:
                return []
            else:
                return {}
        else:
            result = {S.Zero: f.degree}
    else:
        (k, ), f = f.as_reduced()

        if k == 0:
            result = {}
        else:
            result = {S.Zero: k}

        if f.degree == 1:
            result[roots_linear(f)[0]] = 1
        else:
            factors = poly_decompose(f)

            zeros, g = {}, factors[0]

            for i, h in enumerate(poly_sqf(g)):
                for zero in roots_trivial(h):
                    if zeros.has_key(zero):
                        zeros[zero] += i + 1
                    else:
                        zeros[zero] = i + 1

            for factor in factors[1:]:
                previous, zeros = zeros.copy(), {}

                for zero, i in previous.iteritems():
                    g = factor.sub_term(zero, (0, ))

                    for j, h in enumerate(poly_sqf(g)):
                        for zero in roots_trivial(h):
                            if zeros.has_key(zero):
                                zeros[zero] += i * (j + 1)
                            else:
                                zeros[zero] = i * (j + 1)

            result.update(zeros)

    domain = flags.get('domain', None)

    if domain 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[domain]
        except KeyError:
            raise ValueError("Invalid domain: %s" % domain)

        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
Ejemplo n.º 11
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
Ejemplo n.º 12
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