def f5_reduce(f, B, u, O, K): """ 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 (sdp_rem) need not be F5-reducible, e.g.: >>> from sympy.polys.groebnertools import lbp, sig, f5_reduce, Polyn >>> from sympy.polys.distributedpolys import sdp_rem >>> from sympy.polys.monomialtools import lex >>> from sympy import QQ >>> f = lbp(sig((1, 1, 1), 4), [((1, 0, 0), QQ(1))], 3) >>> g = lbp(sig((0, 0, 0), 2), [((1, 0, 0), QQ(1))], 2) >>> sdp_rem(Polyn(f), [Polyn(g)], 2, lex, QQ) [] >>> f5_reduce(f, [g], 2, lex, QQ) (((1, 1, 1), 4), [((1, 0, 0), 1/1)], 3) """ if Polyn(f) == []: return f if K.has_Field: term_div = _term_ff_div else: term_div = _term_rr_div while True: g = f for h in B: if Polyn(h) != []: if monomial_divides(sdp_LM(Polyn(f), u), sdp_LM(Polyn(h), u)): t = term_div( sdp_LT(Polyn(f), u, K), sdp_LT(Polyn(h), u, K), K) if sig_cmp(sig_mult(Sign(h), t[0]), Sign(f), O) < 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, u, K): hp = lbp_mul_term(h, t, u, O, K) f = lbp_sub(f, hp, u, O, K) break if g == f or Polyn(f) == []: return f
def f5_reduce(f, B, u, O, K): """ 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 (sdp_rem) need not be F5-reducible, e.g.: >>> from sympy.polys.groebnertools import lbp, sig, f5_reduce, Polyn >>> from sympy.polys.distributedpolys import sdp_rem >>> from sympy.polys.monomialtools import lex >>> from sympy import QQ >>> f = lbp(sig((1, 1, 1), 4), [((1, 0, 0), QQ(1))], 3) >>> g = lbp(sig((0, 0, 0), 2), [((1, 0, 0), QQ(1))], 2) >>> sdp_rem(Polyn(f), [Polyn(g)], 2, lex, QQ) [] >>> f5_reduce(f, [g], 2, lex, QQ) (((1, 1, 1), 4), [((1, 0, 0), 1/1)], 3) """ if Polyn(f) == []: return f if K.has_Field: term_div = _term_ff_div else: term_div = _term_rr_div while True: g = f for h in B: if Polyn(h) != []: if monomial_divides(sdp_LM(Polyn(f), u), sdp_LM(Polyn(h), u)): t = term_div(sdp_LT(Polyn(f), u, K), sdp_LT(Polyn(h), u, K), K) if sig_cmp(sig_mult(Sign(h), t[0]), Sign(f), O) < 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, u, K): hp = lbp_mul_term(h, t, u, O, K) f = lbp_sub(f, hp, u, O, K) break if g == f or Polyn(f) == []: return f
def critical_pair(f, g, u, O, K): """ 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. """ ltf = sdp_LT(Polyn(f), u, K) ltg = sdp_LT(Polyn(g), u, K) lt = (monomial_lcm(ltf[0], ltg[0]), K.one) if K.has_Field: term_div = _term_ff_div else: term_div = _term_rr_div um = term_div(lt, ltf, K) vm = term_div(lt, ltg, K) # The full information is not needed (now), so only the product # with the leading term is considered: fr = lbp_mul_term(lbp(Sign(f), [sdp_LT(Polyn(f), u, K)], Num(f)), um, u, O, K) gr = lbp_mul_term(lbp(Sign(g), [sdp_LT(Polyn(g), u, K)], Num(g)), vm, u, O, K) # return in proper order, such that the S-polynomial is just # u_first * f_first - u_second * f_second: if lbp_cmp(fr, gr, O) == -1: return (Sign(gr), vm, g, Sign(fr), um, f) else: return (Sign(fr), um, f, Sign(gr), vm, g)
def critical_pair(f, g, u, O, K): """ 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. """ ltf = sdp_LT(Polyn(f), u, K) ltg = sdp_LT(Polyn(g), u, K) lt = (monomial_lcm(ltf[0], ltg[0]), K.one) if K.has_Field: term_div = _term_ff_div else: term_div = _term_rr_div um = term_div(lt, ltf, K) vm = term_div(lt, ltg, K) # The full information is not needed (now), so only the product # with the leading term is considered: fr = lbp_mul_term( lbp(Sign(f), [sdp_LT(Polyn(f), u, K)], Num(f)), um, u, O, K) gr = lbp_mul_term( lbp(Sign(g), [sdp_LT(Polyn(g), u, K)], Num(g)), vm, u, O, K) # return in proper order, such that the S-polynomial is just # u_first * f_first - u_second * f_second: if lbp_cmp(fr, gr, O) == -1: return (Sign(gr), vm, g, Sign(fr), um, f) else: return (Sign(fr), um, f, Sign(gr), vm, g)
def test_sdp_LT(): assert sdp_LT([], 1, QQ) == ((0, 0), QQ(0)) assert sdp_LT([((1, 0), QQ(1, 2))], 1, QQ) == ((1, 0), QQ(1, 2)) assert sdp_LT( [((1, 1), QQ(1, 4)), ((1, 0), QQ(1, 2))], 1, QQ) == ((1, 1), QQ(1, 4))