def main(argv=None): (opts,args)= parser.parse_args() mydata=load_file(args[0]) claims=mydata.claims if opts.method==NF3: strat=gen_strat(mydata.ideal) for c in claims: proof(to_if_then(c),strat) del strat try: del c except NameError: pass else: if opts.method==LINEAR_LEAD_NOREDSB: reductors=ll_encode(mydata.ideal) for c in claims: proofll(to_if_then(c),reductors,redsb=False) del reductors try: del c except NameError: pass else: reductors=ll_encode(mydata.ideal, reduce=True) for c in claims: proofll(to_if_then(c),reductors) del reductors try: del c except NameError: pass return 0
def main(argv=None): (opts, args) = parser.parse_args() mydata = load_file(args[0]) claims = mydata.claims if opts.method == NF3: strat = gen_strat(mydata.ideal) for c in claims: proof(to_if_then(c), strat) del strat try: del c except NameError: pass else: if opts.method == LINEAR_LEAD_NOREDSB: reductors = ll_encode(mydata.ideal) for c in claims: proofll(to_if_then(c), reductors, redsb=False) del reductors try: del c except NameError: pass else: reductors = ll_encode(mydata.ideal, reduce=True) for c in claims: proofll(to_if_then(c), reductors) del reductors try: del c except NameError: pass return 0
def add_bit_expressions(bit_expressions): """Adds n bits, which can be arbitrary expressions, the first n variables of the ring are reversed for usage in this function. >>> from polybori import * >>> r=Ring(20) >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)]) [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)] >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)]) [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)] >>> add_bit_expressions([r.variable(11), r.variable(11)]) [0, x(11)] >>> add_bit_expressions([r.variable(11),r.variable(12),r.variable(13)]) [x(11) + x(12) + x(13), x(11)*x(12) + x(11)*x(13) + x(12)*x(13)] """ bit_variables = [] if bit_expressions: ring = bit_expressions[0].ring() bit_variables = [ ring.variable(i) for i in xrange(len(bit_expressions)) ] for expr in bit_expressions: assert BooleSet(expr).navigation().value() >= len(bit_variables) mapping = ll_encode( [b + expr for (b, expr) in zip(bit_variables, bit_expressions)]) return [ll_red_nf_redsb(p, mapping) for p in add_bits(bit_variables)]
def eliminate_identical_variables_pre(I, prot): changed = True ll_system = [] treated_linears = set() while changed: changed = False rules = dict() for p in I: t = p + p.lead() if p.lead_deg() == 1: l = p.lead() if l in treated_linears: continue else: treated_linears.add(l) if t.deg() > 0: rules.setdefault(t, []) leads = rules[t] leads.append(l) def my_sort_key(l): return l.navigation().value() for (t, leads) in rules.iteritems(): if len(leads) > 1: changed = True leads = sorted(leads, key=my_sort_key, reverse=True) chosen = leads[0] for v in leads[1:]: ll_system.append(chosen + v) if len(ll_system) > 0: ll_encoded = ll_encode(ll_system, reduce=True) I = set([ll_red_nf_redsb(p, ll_encoded) for p in I]) return (I, ll_system)
def ll_constants_pre(I): ll_res = [] while len([p for p in I if p.lex_lead_deg() == 1 and (p + p.lex_lead()).constant()]) > 0: I_new = [] ll = [] leads = set() for p in I: if p.lex_lead_deg() == 1: l = p.lead() if not (l in leads) and p.is_singleton_or_pair(): tail = p + l if tail.deg() <= 0: ll.append(p) leads.add(l) continue I_new.append(p) encoded = ll_encode(ll) reduced = [] for p in I_new: p = ll_red_nf_redsb(p, encoded) if not p.is_zero(): reduced.append(p) I = reduced ll_res.extend(ll) return (I, ll_res)
def ll_constants_pre(I): ll_res = [] while len([ p for p in I if p.lex_lead_deg() == 1 and (p + p.lex_lead()).constant() ]) > 0: I_new = [] ll = [] leads = set() for p in I: if p.lex_lead_deg() == 1: l = p.lead() if not (l in leads) and p.is_singleton_or_pair(): tail = p + l if tail.deg() <= 0: ll.append(p) leads.add(l) continue I_new.append(p) encoded = ll_encode(ll) reduced = [] for p in I_new: p = ll_red_nf_redsb(p, encoded) if not p.is_zero(): reduced.append(p) I = reduced ll_res.extend(ll) return (I, ll_res)
def add_bit_expressions(bit_expressions): """Adds n bits, which can be arbitrary expressions, the first n variables of the ring are reversed for usage in this function. >>> from polybori import * >>> r=Ring(20) >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)]) [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)] >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)]) [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)] >>> add_bit_expressions([r.variable(11), r.variable(11)]) [0, x(11)] >>> add_bit_expressions([r.variable(11),r.variable(12),r.variable(13)]) [x(11) + x(12) + x(13), x(11)*x(12) + x(11)*x(13) + x(12)*x(13)] """ bit_variables = [] if bit_expressions: ring = bit_expressions[0].ring() bit_variables = [ring.variable(i) for i in xrange(len(bit_expressions) )] for expr in bit_expressions: assert BooleSet(expr).navigation().value() >= len(bit_variables) mapping = ll_encode([b + expr for (b, expr) in zip(bit_variables, bit_expressions)]) return [ll_red_nf_redsb(p, mapping) for p in add_bits(bit_variables)]
def sparse_random_system(ring, number_of_polynomials, variables_per_polynomial, degree, random_seed=None): """ generates a system, which is sparse in the sense, that each polynomial contains only a small subset of variables. In each variable that occurrs in a polynomial it is dense in the terms up to the given degree (every term occurs with probability 1/2). The system will be satisfiable by at least one solution. >>> from polybori import * >>> r=Ring(10) >>> s=sparse_random_system(r, number_of_polynomials = 20, variables_per_polynomial = 3, degree=2, random_seed=123) >>> [p.deg() for p in s] [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] >>> sorted(groebner_basis(s), reverse=True) [x(0), x(1), x(2), x(3), x(4) + 1, x(5), x(6) + 1, x(7), x(8) + 1, x(9)] """ if random_seed is not None: set_random_seed(random_seed) random_generator = Random(random_seed) solutions=[] variables = [ring.variable(i) for i in xrange(ring.n_variables())] for v in variables: solutions.append(v+random_generator.randint(0,1)) solutions=ll_encode(solutions) res = [] while len(res)<number_of_polynomials: variables_as_monomial=Monomial( random_generator.sample( variables, variables_per_polynomial) ) p=Polynomial(random_set(variables_as_monomial, 2**(variables_per_polynomial-1))) p=sum([p.graded_part(i) for i in xrange(degree+1)]) if p.deg()==degree: res.append(p) res=[p+ll_red_nf_redsb(p, solutions) for p in res]# evaluate it to guarantee a solution return res
def preprocess(I, prot=True): def min_gb(I): strat = symmGB_F2_C(I, opt_lazy=False, opt_exchange=False, prot=prot, selection_size=10000, opt_red_tail=True) return list(strat.minimalize_and_tail_reduce()) I = [Polynomial(p) for p in I] lin = [p for p in I if p.deg() == 1] # lin_strat=symmGB_F2_C(lin, opt_lazy=False,opt_exchange=False,prot=prot,sele # ction_size=10000,opt_red_tail=True) lin = min_gb(lin) # list(lin_strat.minimalize_and_tail_reduce()) for m in sorted([p.lead() for p in lin]): print m lin_ll = ll_encode(lin) square = [p.lead() for p in I if p.deg() == 2 and len(p) == 1] assert(len(lin) + len(square) == len(I)) res = list(lin) counter = OccCounter() def unique_index(s): for idx in s: if counter[idx] == 1: return idx never_come_here = False assert never_come_here for m in square: for idx in m: counter.increase(idx) systems = dict(((idx, []) for idx in counter.uniques())) for m in square: u_index = unique_index(m) systems[u_index].append(ll_red_nf(m / Variable(u_index), lin_ll)) rewritings = dict() u_var = Variable(u) u_im = ll_red_nf(u_var, lin_ll) if not u_im.isConstant(): if u_im != u_var: r = u_im.navigation().value() else: pass for u in counter.uniques(): #print u u_var = Variable(u) u_im = ll_red_nf(u_var, lin_ll) if not u_im.isConstant(): if u_im != u_var: r = u_im.navigation().value() else: pass for u in systems.keys(): u_var = Variable(u) u_im = ll_red_nf(u_var, lin_ll) res.extend([u_im * p for p in min_gb(systems[u])]) #print [u_im*p for p in min_gb(systems[u])] print "lin:", len(lin), "res:", len(res), "square:", len(square) res = [p for p in (Polynomial(p) for p in res) if not p.is_zero()] return res
def apply_map(self, eq): encoded = ll_encode((k + v for (k, v) in self.__map.items())) return [ll_red_nf_noredsb(p, encoded) for p in eq]
def eliminate_linear_variables(self, maxlength=3, skip=lambda lm, tail: False, return_reductors=False): """ Return a new system where linear leading variables are eliminated if the tail of the polynomial has length at most ``maxlength``. INPUT: - ``maxlength`` - an optional upper bound on the number of monomials by which a variable is replaced. - ``skip`` - an optional callable to skip eliminations. It must accept two parameters and return either ``True`` or ``False``. The two parameters are the leading term and the tail of a polynomial (default: ``lambda lm,tail: False``). - ``return_reductors`` - if ``True`` the list of polynomials with linear leading terms which were used for reduction is also returned (default: ``False``). EXAMPLE:: sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c]) sage: F.eliminate_linear_variables() # everything vanishes [] sage: F.eliminate_linear_variables(maxlength=2) [b + c + d + 1, b*c + b*d + c, b*c*d + c] sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a') [a + c + d, a*c + a*d + a + c, c*d + c] The list of reductors can be requested by setting 'return_reductors' to ``True``:: sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([a + b + d, a + b + c]) sage: F,R = F.eliminate_linear_variables(return_reductors=True) sage: F [c + d] sage: R [a + b + d] .. note:: This is called "massaging" in [CBJ07]_. """ from polybori.ll import ll_encode from polybori.ll import ll_red_nf_redsb from sage.rings.polynomial.pbori import BooleanPolynomialRing from sage.misc.misc import get_verbose R = self.ring() if not isinstance(R, BooleanPolynomialRing): raise NotImplementedError( "Only BooleanPolynomialRing's are supported.") F = self elim = [] while True: linear = [] higher = [] for f in F: if f.degree() == 1 and len(f) <= maxlength + 1: flm = f.lex_lead() if skip(flm, f - flm): higher.append(f) continue lex_lead = map(lambda x: x.lex_lead(), linear) if not flm in lex_lead: linear.append(f) else: higher.append(f) else: higher.append(f) if not linear: break if not higher: higher = linear break assert len(set(linear)) == len(linear) rb = ll_encode(linear) elim.extend(linear) F = [] for f in linear: f = ll_red_nf_redsb(f, rb) if f: F.append(f) for f in higher: f = ll_red_nf_redsb(f, rb) if f: F.append(f) if get_verbose() > 0: print ".", if get_verbose() > 0: print ret = PolynomialSequence(R, higher) if return_reductors: return ret, PolynomialSequence(R, elim) else: return ret
def preprocess(I, prot=True): def min_gb(I): strat = symmGB_F2_C(I, opt_lazy=False, opt_exchange=False, prot=prot, selection_size=10000, opt_red_tail=True) return list(strat.minimalize_and_tail_reduce()) I = [Polynomial(p) for p in I] lin = [p for p in I if p.deg() == 1] # lin_strat=symmGB_F2_C(lin, opt_lazy=False,opt_exchange=False,prot=prot,sele # ction_size=10000,opt_red_tail=True) lin = min_gb(lin) # list(lin_strat.minimalize_and_tail_reduce()) for m in sorted([p.lead() for p in lin]): print m lin_ll = ll_encode(lin) square = [p.lead() for p in I if p.deg() == 2 and len(p) == 1] assert (len(lin) + len(square) == len(I)) res = list(lin) counter = OccCounter() def unique_index(s): for idx in s: if counter[idx] == 1: return idx never_come_here = False assert never_come_here for m in square: for idx in m: counter.increase(idx) systems = dict(((idx, []) for idx in counter.uniques())) for m in square: u_index = unique_index(m) systems[u_index].append(ll_red_nf(m / Variable(u_index), lin_ll)) rewritings = dict() u_var = Variable(u) u_im = ll_red_nf(u_var, lin_ll) if not u_im.isConstant(): if u_im != u_var: r = u_im.navigation().value() else: pass for u in counter.uniques(): #print u u_var = Variable(u) u_im = ll_red_nf(u_var, lin_ll) if not u_im.isConstant(): if u_im != u_var: r = u_im.navigation().value() else: pass for u in systems.keys(): u_var = Variable(u) u_im = ll_red_nf(u_var, lin_ll) res.extend([u_im * p for p in min_gb(systems[u])]) #print [u_im*p for p in min_gb(systems[u])] print "lin:", len(lin), "res:", len(res), "square:", len(square) res = [p for p in (Polynomial(p) for p in res) if not p.is_zero()] return res
def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reductors=False): """ Return a new system where linear leading variables are eliminated if the tail of the polynomial has length at most ``maxlength``. INPUT: - ``maxlength`` - an optional upper bound on the number of monomials by which a variable is replaced. If ``maxlength==+Infinity`` then no condition is checked. (default: +Infinity). - ``skip`` - an optional callable to skip eliminations. It must accept two parameters and return either ``True`` or ``False``. The two parameters are the leading term and the tail of a polynomial (default: ``None``). - ``return_reductors`` - if ``True`` the list of polynomials with linear leading terms which were used for reduction is also returned (default: ``False``). OUTPUT: When ``return_reductors==True``, then a pair of sequences of boolean polynomials are returned, along with the promises that: 1. The union of the two sequences spans the same boolean ideal as the argument of the method 2. The second sequence only contains linear polynomials, and it forms a reduced groebner basis (they all have pairwise distinct leading variables, and the leading variable of a polynomial does not occur anywhere in other polynomials). 3. The leading variables of the second sequence do not occur anywhere in the first sequence (these variables have been eliminated). When ``return_reductors==False``, only the first sequence is returned. EXAMPLE:: sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c]) sage: F.eliminate_linear_variables() # everything vanishes [] sage: F.eliminate_linear_variables(maxlength=2) [b + c + d + 1, b*c + b*d + c, b*c*d + c] sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a') [a + c + d, a*c + a*d + a + c, c*d + c] The list of reductors can be requested by setting 'return_reductors' to ``True``:: sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([a + b + d, a + b + c]) sage: F,R = F.eliminate_linear_variables(return_reductors=True) sage: F [] sage: R [a + b + d, c + d] TESTS: The function should really dispose of linear equations (:trac:`13968`):: sage: R.<x,y,z> = BooleanPolynomialRing() sage: S = Sequence([x+y+z+1, y+z]) sage: S.eliminate_linear_variables(return_reductors=True) ([], [x + 1, y + z]) The function should take care of linear variables created by previous substitution of linear variables :: sage: R.<x,y,z> = BooleanPolynomialRing() sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y]) sage: S.eliminate_linear_variables(return_reductors=True) ([], [x + y, z + 1]) .. NOTE:: This is called "massaging" in [CBJ07]_. REFERENCES: .. [CBJ07] Gregory V. Bard, and Nicolas T. Courtois, and Chris Jefferson. *Efficient Methods for Conversion and Solution of Sparse Systems of Low-Degree Multivariate Polynomials over GF(2) via SAT-Solvers*. Cryptology ePrint Archive: Report 2007/024. available at http://eprint.iacr.org/2007/024 """ from polybori import gauss_on_polys from polybori.ll import eliminate,ll_encode,ll_red_nf_redsb from sage.rings.polynomial.pbori import BooleanPolynomialRing R = self.ring() if not isinstance(R, BooleanPolynomialRing): raise NotImplementedError("Only BooleanPolynomialRing's are supported.") F = self reductors = [] if skip is None and maxlength==Infinity: # faster solution based on polybori.ll.eliminate while True: (this_step_reductors, _, higher) = eliminate(F) if this_step_reductors == []: break reductors.extend( this_step_reductors ) F = higher else: # slower, more flexible solution if skip is None: skip = lambda lm,tail: False while True: linear = [] higher = [] for f in F: if f.degree() == 1 and len(f) <= maxlength + 1: flm = f.lex_lead() if skip(flm, f-flm): higher.append(f) continue linear.append(f) else: higher.append(f) if not linear: break linear = gauss_on_polys(linear) rb = ll_encode(linear) reductors.extend(linear) F = [] for f in higher: f = ll_red_nf_redsb(f, rb) if f != 0: F.append(f) ret = PolynomialSequence(R, higher) if return_reductors: reduced_reductors = gauss_on_polys(reductors) return ret, PolynomialSequence(R, reduced_reductors) else: return ret
def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reductors=False): """ Return a new system where linear leading variables are eliminated if the tail of the polynomial has length at most ``maxlength``. INPUT: - ``maxlength`` - an optional upper bound on the number of monomials by which a variable is replaced. If ``maxlength==+Infinity`` then no condition is checked. (default: +Infinity). - ``skip`` - an optional callable to skip eliminations. It must accept two parameters and return either ``True`` or ``False``. The two parameters are the leading term and the tail of a polynomial (default: ``None``). - ``return_reductors`` - if ``True`` the list of polynomials with linear leading terms which were used for reduction is also returned (default: ``False``). OUTPUT: When ``return_reductors==True``, then a pair of sequences of boolean polynomials are returned, along with the promises that: 1. The union of the two sequences spans the same boolean ideal as the argument of the method 2. The second sequence only contains linear polynomials, and it forms a reduced groebner basis (they all have pairwise distinct leading variables, and the leading variable of a polynomial does not occur anywhere in other polynomials). 3. The leading variables of the second sequence do not occur anywhere in the first sequence (these variables have been eliminated). When ``return_reductors==False``, only the first sequence is returned. EXAMPLE:: sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c]) sage: F.eliminate_linear_variables() # everything vanishes [] sage: F.eliminate_linear_variables(maxlength=2) [b + c + d + 1, b*c + b*d + c, b*c*d + c] sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a') [a + c + d, a*c + a*d + a + c, c*d + c] The list of reductors can be requested by setting 'return_reductors' to ``True``:: sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([a + b + d, a + b + c]) sage: F,R = F.eliminate_linear_variables(return_reductors=True) sage: F [] sage: R [a + b + d, c + d] TESTS: The function should really dispose of linear equations (:trac:`13968`):: sage: R.<x,y,z> = BooleanPolynomialRing() sage: S = Sequence([x+y+z+1, y+z]) sage: S.eliminate_linear_variables(return_reductors=True) ([], [x + 1, y + z]) The function should take care of linear variables created by previous substitution of linear variables :: sage: R.<x,y,z> = BooleanPolynomialRing() sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y]) sage: S.eliminate_linear_variables(return_reductors=True) ([], [x + y, z + 1]) .. NOTE:: This is called "massaging" in [CBJ07]_. REFERENCES: .. [CBJ07] Gregory V. Bard, and Nicolas T. Courtois, and Chris Jefferson. *Efficient Methods for Conversion and Solution of Sparse Systems of Low-Degree Multivariate Polynomials over GF(2) via SAT-Solvers*. Cryptology ePrint Archive: Report 2007/024. available at http://eprint.iacr.org/2007/024 """ from sage.rings.polynomial.pbori import BooleanPolynomialRing from polybori import gauss_on_polys from polybori.ll import eliminate,ll_encode,ll_red_nf_redsb R = self.ring() if not isinstance(R, BooleanPolynomialRing): raise NotImplementedError("Only BooleanPolynomialRing's are supported.") F = self reductors = [] if skip is None and maxlength==Infinity: # faster solution based on polybori.ll.eliminate while True: (this_step_reductors, _, higher) = eliminate(F) if this_step_reductors == []: break reductors.extend( this_step_reductors ) F = higher else: # slower, more flexible solution if skip is None: skip = lambda lm,tail: False while True: linear = [] higher = [] for f in F: if f.degree() == 1 and len(f) <= maxlength + 1: flm = f.lex_lead() if skip(flm, f-flm): higher.append(f) continue linear.append(f) else: higher.append(f) if not linear: break linear = gauss_on_polys(linear) rb = ll_encode(linear) reductors.extend(linear) F = [] for f in higher: f = ll_red_nf_redsb(f, rb) if f != 0: F.append(f) ret = PolynomialSequence(R, higher) if return_reductors: reduced_reductors = gauss_on_polys(reductors) return ret, PolynomialSequence(R, reduced_reductors) else: return ret
def eliminate_linear_variables(self, maxlength=3, skip=lambda lm,tail: False, return_reductors=False): """ Return a new system where linear leading variables are eliminated if the tail of the polynomial has length at most ``maxlength``. INPUT: - ``maxlength`` - an optional upper bound on the number of monomials by which a variable is replaced. - ``skip`` - an optional callable to skip eliminations. It must accept two parameters and return either ``True`` or ``False``. The two parameters are the leading term and the tail of a polynomial (default: ``lambda lm,tail: False``). - ``return_reductors`` - if ``True`` the list of polynomials with linear leading terms which were used for reduction is also returned (default: ``False``). EXAMPLE:: sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c]) sage: F.eliminate_linear_variables() # everything vanishes [] sage: F.eliminate_linear_variables(maxlength=2) [b + c + d + 1, b*c + b*d + c, b*c*d + c] sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a') [a + c + d, a*c + a*d + a + c, c*d + c] The list of reductors can be requested by setting 'return_reductors' to ``True``:: sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([a + b + d, a + b + c]) sage: F,R = F.eliminate_linear_variables(return_reductors=True) sage: F [c + d] sage: R [a + b + d] .. note:: This is called "massaging" in [CBJ07]_. """ from polybori.ll import ll_encode from polybori.ll import ll_red_nf_redsb from sage.rings.polynomial.pbori import BooleanPolynomialRing from sage.misc.misc import get_verbose R = self.ring() if not isinstance(R, BooleanPolynomialRing): raise NotImplementedError("Only BooleanPolynomialRing's are supported.") F = self elim = [] while True: linear = [] higher = [] for f in F: if f.degree() == 1 and len(f) <= maxlength + 1: flm = f.lex_lead() if skip(flm, f-flm): higher.append(f) continue lex_lead = map(lambda x: x.lex_lead(), linear) if not flm in lex_lead: linear.append(f) else: higher.append(f) else: higher.append(f) if not linear: break if not higher: higher = linear break assert len(set(linear)) == len(linear) rb = ll_encode(linear) elim.extend(linear) F = [] for f in linear: f = ll_red_nf_redsb(f, rb) if f: F.append(f) for f in higher: f = ll_red_nf_redsb(f, rb) if f: F.append(f) if get_verbose() > 0: print ".", if get_verbose() > 0: print ret = PolynomialSequence(R, higher) if return_reductors: return ret, PolynomialSequence(R, elim) else: return ret