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
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
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
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))
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))