def poly_half_gcdex(f, g, *symbols): """Half extended Euclidean algorithm. Efficiently computes gcd(f, g) and one of the coefficients in extended Euclidean algorithm. Formally, given univariate polynomials f and g over an Euclidean domain, computes s and h, such that h = gcd(f, g) and s*f = h (mod g). For more information on the implemented algorithm refer to: [1] M. Bronstein, Symbolic Integration I: Transcendental Functions, Second Edition, Springer-Verlang, 2005 """ 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) symbols, flags = f.symbols, f.flags a = Poly(S.One, *symbols, **flags) b = Poly((), *symbols, **flags) while not g.is_zero: q, r = poly_div(f, g) f, g = g, r c = a - q * b a, b = b, c return a.div_term(f.LC), f.as_monic()
def poly_half_gcdex(f, g, *symbols): """Half extended Euclidean algorithm. Efficiently computes gcd(f, g) and one of the coefficients in extended Euclidean algorithm. Formally, given univariate polynomials f and g over an Euclidean domain, computes s and h, such that h = gcd(f, g) and s*f = h (mod g). For more information on the implemented algorithm refer to: [1] M. Bronstein, Symbolic Integration I: Transcendental Functions, Second Edition, Springer-Verlang, 2005 """ 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) symbols, flags = f.symbols, f.flags a = Poly(S.One, *symbols, **flags) b = Poly((), *symbols, **flags) while not g.is_zero: q, r = poly_div(f, g) f, g = g, r c = a - q*b a, b = b, c return a.div_term(f.LC), f.as_monic()
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))