def is_rewritable_or_comparable(sign, num, B): """ Check if a labeled polynomial is redundant by checking if its signature and number imply rewritability or comparability. (sign, num) is comparable if there exists a labeled polynomial h in B, such that sign[1] (the index) is less than Sign(h)[1] and sign[0] is divisible by the leading monomial of h. (sign, num) is rewritable if there exists a labeled polynomial h in B, such thatsign[1] is equal to Sign(h)[1], num < Num(h) and sign[0] is divisible by Sign(h)[0]. """ for h in B: # comparable if sign[1] < Sign(h)[1]: if monomial_divides(Polyn(h).LM, sign[0]): return True # rewritable if sign[1] == Sign(h)[1]: if num < Num(h): if monomial_divides(Sign(h)[0], sign[0]): return True return False
def red_groebner(G, ring): """ Compute reduced Groebner basis, from BeckerWeispfenning93, p. 216 Selects a subset of generators, that already generate the ideal and computes a reduced Groebner basis for them. """ def reduction(P): """ The actual reduction algorithm. """ Q = [] for i, p in enumerate(P): h = p.rem(P[:i] + P[i + 1:]) if h: Q.append(h) return [p.monic() for p in Q] F = G H = [] while F: f0 = F.pop() if not any(monomial_divides(f.LM, f0.LM) for f in F + H): H.append(f0) # Becker, Weispfenning, p. 217: H is Groebner basis of the ideal generated by G. return reduction(H)
def f5_reduce(f, B): """ F5-reduce a labeled polynomial f by B. Continously searches for non-zero labeled polynomial h in B, such that the leading term lt_h of h divides the leading term lt_f of f and Sign(lt_h * h) < Sign(f). If such a labeled polynomial h is found, f gets replaced by f - lt_f / lt_h * h. If no such h can be found or f is 0, f is no further F5-reducible and f gets returned. A polynomial that is reducible in the usual sense need not be F5-reducible, e.g.: >>> from sympy.polys.groebnertools import lbp, sig, f5_reduce, Polyn >>> from sympy.polys.monomialtools import lex >>> from sympy.polys import ring, QQ >>> R, x,y,z = ring("x,y,z", QQ) >>> f = lbp(sig((1, 1, 1), 4), x, 3) >>> g = lbp(sig((0, 0, 0), 2), x, 2) >>> Polyn(f).rem([Polyn(g)]) 0 >>> f5_reduce(f, [g]) (((1, 1, 1), 4), x, 3) """ order = Polyn(f).ring.order domain = Polyn(f).ring.domain if not Polyn(f): return f while True: g = f for h in B: if Polyn(h): if monomial_divides(Polyn(h).LM, Polyn(f).LM): t = term_div(Polyn(f).LT, Polyn(h).LT, domain) if sig_cmp(sig_mult(Sign(h), t[0]), Sign(f), order) < 0: # The following check need not be done and is in general slower than without. #if not is_rewritable_or_comparable(Sign(gp), Num(gp), B): hp = lbp_mul_term(h, t) f = lbp_sub(f, hp) break if g == f or not Polyn(f): return f
def prune(P, S, h): """ Prune the pair-set by applying the chain criterion [SCA, remark 2.5.11]. """ remove = set() for (a, b, c) in permutations(S, 3): A = sdm_LM(a) B = sdm_LM(b) C = sdm_LM(c) if len(set([A[0], B[0], C[0]])) != 1 or not h in [a, b, c]: continue if monomial_divides(B[1:], monomial_lcm(A[1:], C[1:])): remove.add((tuple(a), tuple(c))) return [(f, g) for (f, g) in P if (h not in [f, g]) or \ ((tuple(f), tuple(g)) not in remove and \ (tuple(g), tuple(f)) not in remove)]
def is_minimal(G, ring): """ Checks if G is a minimal Groebner basis. """ order = ring.order domain = ring.domain G.sort(key=lambda g: order(g.LM)) for i, g in enumerate(G): if g.LC != domain.one: return False for h in G[:i] + G[i + 1:]: if monomial_divides(h.LM, g.LM): return False return True
def prune(P, S, h): """ Prune the pair-set by applying the chain criterion [SCA, remark 2.5.11]. """ remove = set() retain = set() for (a, b, c) in permutations(S, 3): A = sdm_LM(a) B = sdm_LM(b) C = sdm_LM(c) if len(set([A[0], B[0], C[0]])) != 1 or not h in [a, b, c] or \ any(tuple(x) in retain for x in [a, b, c]): continue if monomial_divides(B[1:], monomial_lcm(A[1:], C[1:])): remove.add((tuple(a), tuple(c))) retain.update([tuple(b), tuple(c), tuple(a)]) return [(f, g) for (f, g) in P if (h not in [f, g]) or \ ((tuple(f), tuple(g)) not in remove and \ (tuple(g), tuple(f)) not in remove)]
def test_monomial_divides(): assert monomial_divides((1, 2, 3), (4, 5, 6)) is True assert monomial_divides((1, 2, 3), (0, 5, 6)) is False