def critical_pair(f, g, ring): """ Compute the critical pair corresponding to two labeled polynomials. A critical pair is a tuple (um, f, vm, g), where um and vm are terms such that um * f - vm * g is the S-polynomial of f and g (so, wlog assume um * f > vm * g). For performance sake, a critical pair is represented as a tuple (Sign(um * f), um, f, Sign(vm * g), vm, g), since um * f creates a new, relatively expensive object in memory, whereas Sign(um * f) and um are lightweight and f (in the tuple) is a reference to an already existing object in memory. """ domain = ring.domain ltf = Polyn(f).LT ltg = Polyn(g).LT lt = (monomial_lcm(ltf[0], ltg[0]), domain.one) um = term_div(lt, ltf, domain) vm = term_div(lt, ltg, domain) # The full information is not needed (now), so only the product # with the leading term is considered: fr = lbp_mul_term(lbp(Sign(f), Polyn(f).leading_term(), Num(f)), um) gr = lbp_mul_term(lbp(Sign(g), Polyn(g).leading_term(), Num(g)), vm) # return in proper order, such that the S-polynomial is just # u_first * f_first - u_second * f_second: if lbp_cmp(fr, gr) == -1: return (Sign(gr), vm, g, Sign(fr), um, f) else: return (Sign(fr), um, f, Sign(gr), vm, g)
def f5_reduce(f, B): """ F5-reduce a labeled polynomial f by B. Continuously 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 import ring, QQ, lex >>> R, x,y,z = ring("x,y,z", QQ, lex) >>> 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 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 import ring, QQ, lex >>> R, x,y,z = ring("x,y,z", QQ, lex) >>> 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