Esempio n. 1
0
    def generate(R, P, G, B):
        while R:
            h = normal(f[R.pop()], G | P)

            if h is not None:
                k, LM = h

                G0 = set(g for g in G if monomial_div(f[g].LM, LM))
                P0 = set(p for p in P if monomial_div(f[p].LM, LM))

                G, P, R = G - G0, P - P0 | set([k]), R | G0 | P0

                for i, j in set(B):
                    if i in G0 or j in G0:
                        del B[(i, j)]

        G |= P

        for i in G:
            for j in P:
                if i == j:
                    continue

                if i < j:
                    k = (i, j)
                else:
                    k = (j, i)

                if k not in B:
                    B[k] = monomial_lcm(f[i].LM, f[j].LM)

        G = set([normal(f[g], G - set([g]))[0] for g in G])

        return R, P, G, B
Esempio n. 2
0
    def generate(R, P, G, B):
        while R:
            h = normal(f[R.pop()], G | P)

            if h is not None:
                k, LM = h

                G0 = set(g for g in G if monomial_div(f[g].LM, LM))
                P0 = set(p for p in P if monomial_div(f[p].LM, LM))

                G, P, R = G - G0, P - P0 | set([k]), R | G0 | P0

                for i, j in set(B):
                    if i in G0 or j in G0:
                        del B[(i, j)]

        G |= P

        for i in G:
            for j in P:
                if i == j:
                    continue

                if i < j:
                   k = (i, j)
                else:
                   k = (j, i)

                if not B.has_key(k):
                    B[k] = monomial_lcm(f[i].LM, f[j].LM)

        G = set([ normal(f[g], G - set([g]))[0] for g in G ])

        return R, P, G, B
Esempio n. 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
Esempio n. 4
0
def poly_groebner(f, *symbols, **flags):
    """Computes reduced Groebner basis for a set of polynomials.

       Given a set of multivariate polynomials F, find another set G,
       such that Ideal F = Ideal G and G is a reduced Groebner basis.

       The resulting basis is unique and has monic generators.

       Groebner bases can be used to choose specific generators for a
       polynomial ideal. Because these bases are unique you can check
       for ideal equality by comparing the Groebner bases.  To see if
       one polynomial lies in an ideal, divide by the elements in the
       base and see if the remainder vanishes.

       They can also be used to  solve systems of polynomial equations
       as,  by choosing lexicographic ordering,  you can eliminate one
       variable at a time, provided that the ideal is zero-dimensional
       (finite number of solutions).

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

       >>> G = poly_groebner([x**2 + y**3, y**2-x], x, y, order='lex')

       >>> [ g.as_basic() for g in G ]
       [x - y**2, y**3 + y**4]

       For more information on the implemented algorithm refer to:

       [1] N.K. Bose, B. Buchberger, J.P. Guiver, Multidimensional
           Systems Theory and Applications, Springer, 2003, pp. 98+

       [2] A. Giovini, T. Mora, "One sugar cube, please" or Selection
           strategies in Buchberger algorithm, Proc. ISSAC '91, ACM

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

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

    """
    if isinstance(f, (tuple, list, set)):
        f, g = f[0], list(f[1:])

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

        f, g = f.unify_with(g)

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

        return [f.as_monic()]

    compare = monomial_cmp(flags.get('order'))

    f = [h for h in [f] + g if h]

    if not f:
        return [Poly((), *symbols, **flags)]

    R, P, G, B, F = set(), set(), set(), {}, {}

    for i, h in enumerate(f):
        F[h] = i
        R.add(i)

    def normal(g, H):
        h = poly_div(g, [f[i] for i in H])[1]

        if h.is_zero:
            return None
        else:
            if not h in F:
                F[h] = len(f)
                f.append(h)

            return F[h], h.LM

    def generate(R, P, G, B):
        while R:
            h = normal(f[R.pop()], G | P)

            if h is not None:
                k, LM = h

                G0 = set(g for g in G if monomial_div(f[g].LM, LM))
                P0 = set(p for p in P if monomial_div(f[p].LM, LM))

                G, P, R = G - G0, P - P0 | set([k]), R | G0 | P0

                for i, j in set(B):
                    if i in G0 or j in G0:
                        del B[(i, j)]

        G |= P

        for i in G:
            for j in P:
                if i == j:
                    continue

                if i < j:
                    k = (i, j)
                else:
                    k = (j, i)

                if k not in B:
                    B[k] = monomial_lcm(f[i].LM, f[j].LM)

        G = set([normal(f[g], G - set([g]))[0] for g in G])

        return R, P, G, B

    R, P, G, B = generate(R, P, G, B)

    while B:
        k, M = B.items()[0]

        for l, N in B.iteritems():
            if compare(M, N) == 1:
                k, M = l, N

        del B[k]

        i, j = k[0], k[1]
        p, q = f[i], f[j]

        p_LM, q_LM = p.LM, q.LM

        if M == monomial_mul(p_LM, q_LM):
            continue

        criterion = False

        for g in G:
            if g == i or g == j:
                continue

            if (min(i, g), max(i, g)) not in B:
                continue

            if (min(j, g), max(j, g)) not in B:
                continue

            if not monomial_div(M, f[g].LM):
                continue

            criterion = True
            break

        if criterion:
            continue

        p = p.mul_term(1 / p.LC, monomial_div(M, p_LM))
        q = q.mul_term(1 / q.LC, monomial_div(M, q_LM))

        h = normal(p - q, G)

        if h is not None:
            k, LM = h

            G0 = set(g for g in G if monomial_div(f[g].LM, LM))

            R, P, G = G0, set([k]), G - G0

            for i, j in set(B):
                if i in G0 or j in G0:
                    del B[(i, j)]

            R, P, G, B = generate(R, P, G, B)

    G = [f[g].as_monic() for g in G]

    G = sorted(G, compare, lambda p: p.LM)

    return list(reversed(G))
Esempio n. 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
Esempio n. 6
0
def poly_groebner(f, *symbols, **flags):
    """Computes reduced Groebner basis for a set of polynomials.

       Given a set of multivariate polynomials F, find another set G,
       such that Ideal F = Ideal G and G is a reduced Groebner basis.

       The resulting basis is unique and has monic generators.

       Groebner bases can be used to choose specific generators for a
       polynomial ideal. Because these bases are unique you can check
       for ideal equality by comparing the Groebner bases.  To see if
       one polynomial lies in an ideal, divide by the elements in the
       base and see if the remainder vanishes.

       They can also be used to  solve systems of polynomial equations
       as,  by choosing lexicographic ordering,  you can eliminate one
       variable at a time, provided that the ideal is zero-dimensional
       (finite number of solutions).

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

       >>> G = poly_groebner([x**2 + y**3, y**2-x], x, y, order='lex')

       >>> [ g.as_basic() for g in G ]
       [x - y**2, y**3 + y**4]

       For more information on the implemented algorithm refer to:

       [1] N.K. Bose, B. Buchberger, J.P. Guiver, Multidimensional
           Systems Theory and Applications, Springer, 2003, pp. 98+

       [2] A. Giovini, T. Mora, "One sugar cube, please" or Selection
           strategies in Buchberger algorithm, Proc. ISSAC '91, ACM

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

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

    """
    if isinstance(f, (tuple, list, set)):
        f, g = f[0], list(f[1:])

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

        f, g = f.unify_with(g)

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

        return [f.as_monic()]

    compare = monomial_cmp(flags.get('order'))

    f = [ h for h in [f] + g if h ]

    if not f:
        return [Poly((), *symbols, **flags)]

    R, P, G, B, F = set(), set(), set(), {}, {}

    for i, h in enumerate(f):
        F[h] = i; R.add(i)

    def normal(g, H):
        h = poly_div(g, [ f[i] for i in H ])[1]

        if h.is_zero:
            return None
        else:
            if not F.has_key(h):
                F[h] = len(f)
                f.append(h)

            return F[h], h.LM

    def generate(R, P, G, B):
        while R:
            h = normal(f[R.pop()], G | P)

            if h is not None:
                k, LM = h

                G0 = set(g for g in G if monomial_div(f[g].LM, LM))
                P0 = set(p for p in P if monomial_div(f[p].LM, LM))

                G, P, R = G - G0, P - P0 | set([k]), R | G0 | P0

                for i, j in set(B):
                    if i in G0 or j in G0:
                        del B[(i, j)]

        G |= P

        for i in G:
            for j in P:
                if i == j:
                    continue

                if i < j:
                   k = (i, j)
                else:
                   k = (j, i)

                if not B.has_key(k):
                    B[k] = monomial_lcm(f[i].LM, f[j].LM)

        G = set([ normal(f[g], G - set([g]))[0] for g in G ])

        return R, P, G, B

    R, P, G, B = generate(R, P, G, B)

    while B:
        k, M = B.items()[0]

        for l, N in B.iteritems():
            if compare(M, N) == 1:
                k, M = l, N

        del B[k]

        i, j = k[0], k[1]
        p, q = f[i], f[j]

        p_LM, q_LM = p.LM, q.LM

        if M == monomial_mul(p_LM, q_LM):
            continue

        criterion = False

        for g in G:
            if g == i or g == j:
                continue

            if not B.has_key((min(i, g), max(i, g))):
                continue

            if not B.has_key((min(j, g), max(j, g))):
                continue

            if not monomial_div(M, f[g].LM):
                continue

            criterion = True
            break

        if criterion:
            continue

        p = p.mul_term(1/p.LC, monomial_div(M, p_LM))
        q = q.mul_term(1/q.LC, monomial_div(M, q_LM))

        h = normal(p - q, G)

        if h is not None:
            k, LM = h

            G0 = set(g for g in G if monomial_div(f[g].LM, LM))

            R, P, G = G0, set([k]), G - G0

            for i, j in set(B):
                if i in G0 or j in G0:
                    del B[(i, j)]

            R, P, G, B = generate(R, P, G, B)

    G = [ f[g].as_monic() for g in G ]

    G = sorted(G, compare, lambda p: p.LM)

    return list(reversed(G))