Пример #1
0
def poly_subresultants(f, g, *symbols, **flags):
    """Computes subresultant PRS of two univariate polynomials.

       Polynomial remainder sequence (PRS) is a fundamental tool in
       computer algebra as it gives as a sub-product the polynomial
       greatest common divisor (GCD), provided that the coefficient
       domain is an unique factorization domain.

       There are several methods for computing PRS, eg.: Euclidean
       PRS, where the most famous algorithm is used, primitive PRS
       and, finally, subresultants which are implemented here.

       The Euclidean approach is reasonably efficient but suffers
       severely from coefficient growth.  The primitive algorithm
       avoids this but requires a lot of coefficient computations.

       Subresultants solve both problems and so it is efficient and
       have moderate coefficient growth. The current implementation
       uses pseudo-divisions  which is well suited for coefficients
       in integral domains or number fields.

       Formally,  given univariate polynomials f and g over an UFD,
       then a sequence (R_0, R_1, ..., R_k, 0, ...) is a polynomial
       remainder sequence where R_0 = f, R_1 = g, R_k != 0 and R_k
       is similar to gcd(f, g).

       The result is returned as tuple (res, R) where R is the PRS
       sequence and res is the resultant of the input polynomials.

       If only polynomial remainder sequence is important,  then by
       setting res=False in keyword arguments expensive computation
       of the resultant can be avoided (only PRS is returned).

       For more information on the implemented algorithm refer to:

       [1] M. Bronstein, Symbolic Integration I: Transcendental
           Functions, Second Edition, Springer-Verlang, 2005

       [2] M. Keber, Division-Free computation of subresultants
           using Bezout matrices, Tech. Report MPI-I-2006-1-006,
           Saarbrucken, 2006

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

    f, g = f.unify_with(g)

    if f.is_multivariate:
        raise MultivariatePolyError(f)
    else:
        symbols = f.symbols

    n, m = f.degree, g.degree

    if n < m:
        f, g = g, f
        n, m = m, n

    R = [f, g]

    d = n - m

    b = S(-1)**(d + 1)
    c = S(-1)

    B, D = [b], [d]

    h = poly_prem(f, g)
    h = h.mul_term(b)

    while not h.is_zero:
        k = h.degree
        R.append(h)

        lc = g.LC

        C = (-lc)**d / c**(d - 1)
        c = Poly.cancel(C)

        b = -lc * c**(m - k)

        f, g, m, d = g, h, k, m - k

        B.append(b)
        D.append(d)

        h = poly_prem(f, g)
        h = h.div_term(b)

    if not flags.get('res', True):
        return R

    if R[-1].degree > 0:
        return (Poly((), *symbols), R)
    if R[-2].is_one:
        return (R[-1], R)

    s, c, i = 1, S(1), 1

    for b, d in zip(B, D)[:-1]:
        u = R[i - 1].degree
        v = R[i].degree
        w = R[i + 1].degree

        if u % 2 and v % 2:
            s = -s

        lc = R[i].LC

        C = c * (b / lc**(1 + d))**v * lc**(u - w)
        c = Poly.cancel(C)

        i += 1

    j = R[-2].degree

    return (R[-1]**j * s * c, R)
Пример #2
0
def poly_resultant(f, g, *symbols):
    """Computes resultant of two univariate polynomials.

       Resultants are a classical algebraic tool for determining if
       a  system of n polynomials in n-1 variables have common root
       without explicitly solving for the roots.

       They are efficiently represented as  determinants of Bezout
       matrices whose entries are computed using O(n**2) additions
       and multiplications where n = max(deg(f), deg(g)).

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

       Polynomials x**2-1 and (x-1)**2 have common root:

       >>> poly_resultant(x**2-1, (x-1)**2, x)
       0

       For more information on the implemented algorithm refer to:

       [1] Eng-Wee Chionh, Fast Computation of the Bezout and Dixon
           Resultant Matrices, Journal of Symbolic Computation, ACM,
           Volume 33, Issue 1, January 2002, Pages 13-29

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

    f, g = f.unify_with(g)

    if f.is_multivariate:
        raise MultivariatePolyError(f)

    n, m = f.degree, g.degree

    N = max(n, m)

    if n < m:
        p = f.as_uv_dict()
        q = g.as_uv_dict()
    else:
        q = f.as_uv_dict()
        p = g.as_uv_dict()

    import sympy.matrices

    B = sympy.matrices.zeros(N)

    for i in xrange(N):
        for j in xrange(i, N):
            if i in p and j + 1 in q:
                B[i, j] += p[i] * q[j + 1]

            if j + 1 in p and i in q:
                B[i, j] -= p[j + 1] * q[i]

    for i in xrange(1, N - 1):
        for j in xrange(i, N - 1):
            B[i, j] += B[i - 1, j + 1]

    for i in xrange(N):
        for j in xrange(i + 1, N):
            B[j, i] = B[i, j]

    det = B.det()

    if not det:
        return det
    else:
        if n >= m:
            det /= f.LC**(n - m)
        else:
            det /= g.LC**(m - n)

        sign = (-1)**(n * (n - 1) // 2)

        if det.is_Atom:
            return sign * det
        else:
            return sign * Poly.cancel(det)
Пример #3
0
def poly_div(f, g, *symbols):
    """Generalized polynomial division with remainder.

       Given polynomial f and a set of polynomials g = (g_1, ..., g_n)
       compute a set of quotients q = (q_1, ..., q_n) and remainder r
       such that f = q_1*f_1 + ... + q_n*f_n + r, where r = 0 or r is
       a completely reduced polynomial with respect to g.

       In particular g can be a tuple, list or a singleton. All g_i
       and f can be given as Poly class instances or as expressions.

       For more information on the implemented algorithm refer to:

       [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and
           Algorithms, Springer, Second Edition, 1997, pp. 62

       [2] I.A. Ajwa, Z. Liu, P.S. Wang, Groebner Bases Algorithm,
           http://citeseer.ist.psu.edu/ajwa95grbner.html, 1995

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

    f, g = f.unify_with(g)

    symbols, flags = f.symbols, f.flags

    r = Poly((), *symbols, **flags)

    if isinstance(g, Basic):
        if g.is_constant:
            if g.is_zero:
                raise ZeroDivisionError
            elif g.is_one:
                return f, r
            else:
                return f.div_term(g.LC), r

        if g.is_monomial:
            LC, LM = g.lead_term

            q_coeffs, q_monoms = [], []
            r_coeffs, r_monoms = [], []

            for coeff, monom in f.iter_terms():
                quotient = monomial_div(monom, LM)

                if quotient is not None:
                    coeff /= LC

                    q_coeffs.append(Poly.cancel(coeff))
                    q_monoms.append(quotient)
                else:
                    r_coeffs.append(coeff)
                    r_monoms.append(monom)

            return (Poly((q_coeffs, q_monoms), *symbols,
                         **flags), Poly((r_coeffs, r_monoms), *symbols,
                                        **flags))

        g, q = [g], [r]
    else:
        q = [r] * len(g)

    while not f.is_zero:
        for i, h in enumerate(g):
            monom = monomial_div(f.LM, h.LM)

            if monom is not None:
                coeff = Poly.cancel(f.LC / h.LC)

                q[i] = q[i].add_term(coeff, monom)
                f -= h.mul_term(coeff, monom)

                break
        else:
            r = r.add_term(*f.LT)
            f = f.kill_lead_term()

    if len(q) != 1:
        return q, r
    else:
        return q[0], r
Пример #4
0
def poly_resultant(f, g, *symbols):
    """Computes resultant of two univariate polynomials.

       Resultants are a classical algebraic tool for determining if
       a  system of n polynomials in n-1 variables have common root
       without explicitly solving for the roots.

       They are efficiently represented as  determinants of Bezout
       matrices whose entries are computed using O(n**2) additions
       and multiplications where n = max(deg(f), deg(g)).

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

       Polynomials x**2-1 and (x-1)**2 have common root:

       >>> poly_resultant(x**2-1, (x-1)**2, x)
       0

       For more information on the implemented algorithm refer to:

       [1] Eng-Wee Chionh, Fast Computation of the Bezout and Dixon
           Resultant Matrices, Journal of Symbolic Computation, ACM,
           Volume 33, Issue 1, January 2002, Pages 13-29

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

    f, g = f.unify_with(g)

    if f.is_multivariate:
        raise MultivariatePolyError(f)

    n, m = f.degree, g.degree

    N = max(n, m)

    if n < m:
        p = f.as_uv_dict()
        q = g.as_uv_dict()
    else:
        q = f.as_uv_dict()
        p = g.as_uv_dict()

    import sympy.matrices

    B = sympy.matrices.zeros(N)

    for i in xrange(N):
        for j in xrange(i, N):
            if p.has_key(i) and q.has_key(j+1):
                B[i, j] += p[i] * q[j+1]

            if p.has_key(j+1) and q.has_key(i):
                B[i, j] -= p[j+1] * q[i]

    for i in xrange(1, N-1):
        for j in xrange(i, N-1):
            B[i, j] += B[i-1, j+1]

    for i in xrange(N):
        for j in xrange(i+1, N):
            B[j, i] = B[i, j]

    det = B.det()

    if not det:
        return det
    else:
        if n >= m:
            det /= f.LC**(n-m)
        else:
            det /= g.LC**(m-n)

        sign = (-1)**(n*(n-1)//2)

        if det.is_Atom:
            return sign * det
        else:
            return sign * Poly.cancel(det)
Пример #5
0
def poly_div(f, g, *symbols):
    """Generalized polynomial division with remainder.

       Given polynomial f and a set of polynomials g = (g_1, ..., g_n)
       compute a set of quotients q = (q_1, ..., q_n) and remainder r
       such that f = q_1*f_1 + ... + q_n*f_n + r, where r = 0 or r is
       a completely reduced polynomial with respect to g.

       In particular g can be a tuple, list or a singleton. All g_i
       and f can be given as Poly class instances or as expressions.

       For more information on the implemented algorithm refer to:

       [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and
           Algorithms, Springer, Second Edition, 1997, pp. 62

       [2] I.A. Ajwa, Z. Liu, P.S. Wang, Groebner Bases Algorithm,
           http://citeseer.ist.psu.edu/ajwa95grbner.html, 1995

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

    f, g = f.unify_with(g)

    symbols, flags = f.symbols, f.flags

    r = Poly((), *symbols, **flags)

    if isinstance(g, Basic):
        if g.is_constant:
            if g.is_zero:
                raise ZeroDivisionError
            elif g.is_one:
                return f, r
            else:
                return f.div_term(g.LC), r

        if g.is_monomial:
            LC, LM = g.lead_term

            q_coeffs, q_monoms = [], []
            r_coeffs, r_monoms = [], []

            for coeff, monom in f.iter_terms():
                quotient = monomial_div(monom, LM)

                if quotient is not None:
                    coeff /= LC

                    q_coeffs.append(Poly.cancel(coeff))
                    q_monoms.append(quotient)
                else:
                    r_coeffs.append(coeff)
                    r_monoms.append(monom)

            return (Poly((q_coeffs, q_monoms), *symbols, **flags),
                    Poly((r_coeffs, r_monoms), *symbols, **flags))

        g, q = [g], [r]
    else:
        q = [r] * len(g)

    while not f.is_zero:
        for i, h in enumerate(g):
            monom = monomial_div(f.LM, h.LM)

            if monom is not None:
                coeff = Poly.cancel(f.LC / h.LC)

                q[i] = q[i].add_term(coeff, monom)
                f -= h.mul_term(coeff, monom)

                break
        else:
            r = r.add_term(*f.LT)
            f = f.kill_lead_term()

    if len(q) != 1:
        return q, r
    else:
        return q[0], r
Пример #6
0
def poly_subresultants(f, g, *symbols, **flags):
    """Computes subresultant PRS of two univariate polynomials.

       Polynomial remainder sequence (PRS) is a fundamental tool in
       computer algebra as it gives as a sub-product the polynomial
       greatest common divisor (GCD), provided that the coefficient
       domain is an unique factorization domain.

       There are several methods for computing PRS, eg.: Euclidean
       PRS, where the most famous algorithm is used, primitive PRS
       and, finally, subresultants which are implemented here.

       The Euclidean approach is reasonably efficient but suffers
       severely from coefficient growth.  The primitive algorithm
       avoids this but requires a lot of coefficient computations.

       Subresultants solve both problems and so it is efficient and
       have moderate coefficient growth. The current implementation
       uses pseudo-divisions  which is well suited for coefficients
       in integral domains or number fields.

       Formally,  given univariate polynomials f and g over an UFD,
       then a sequence (R_0, R_1, ..., R_k, 0, ...) is a polynomial
       remainder sequence where R_0 = f, R_1 = g, R_k != 0 and R_k
       is similar to gcd(f, g).

       The result is returned as tuple (res, R) where R is the PRS
       sequence and res is the resultant of the input polynomials.

       If only polynomial remainder sequence is important,  then by
       setting res=False in keyword arguments expensive computation
       of the resultant can be avoided (only PRS is returned).

       For more information on the implemented algorithm refer to:

       [1] M. Bronstein, Symbolic Integration I: Transcendental
           Functions, Second Edition, Springer-Verlang, 2005

       [2] M. Keber, Division-Free computation of subresultants
           using Bezout matrices, Tech. Report MPI-I-2006-1-006,
           Saarbrucken, 2006

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

    f, g = f.unify_with(g)

    if f.is_multivariate:
        raise MultivariatePolyError(f)
    else:
        symbols = f.symbols

    n, m = f.degree, g.degree

    if n < m:
        f, g = g, f
        n, m = m, n

    R = [f, g]

    d = n - m

    b = S(-1)**(d + 1)
    c = S(-1)

    B, D = [b], [d]

    h = poly_prem(f, g)
    h = h.mul_term(b)

    while not h.is_zero:
        k = h.degree
        R.append(h)

        lc = g.LC

        C = (-lc)**d / c**(d-1)
        c = Poly.cancel(C)

        b = -lc * c**(m-k)

        f, g, m, d = g, h, k, m-k

        B.append(b)
        D.append(d)

        h = poly_prem(f, g)
        h = h.div_term(b)

    if not flags.get('res', True):
        return R

    if R[-1].degree > 0:
        return (Poly((), *symbols), R)
    if R[-2].is_one:
        return (R[-1], R)

    s, c, i = 1, S(1), 1

    for b, d in zip(B, D)[:-1]:
        u = R[i-1].degree
        v = R[i  ].degree
        w = R[i+1].degree

        if u % 2 and v % 2:
            s = -s

        lc = R[i].LC

        C = c*(b/lc**(1 + d))**v * lc**(u - w)
        c = Poly.cancel(C)

        i += 1

    j = R[-2].degree

    return (R[-1]**j*s*c, R)