def buchberger_improved(F): """ An improved version of Buchberger's algorithm as presented in [BW93]_, page 232. This variant uses the Gebauer-Moeller Installation to apply Buchberger's first and second criterion to avoid useless pairs. INPUT: - ``F`` - an ideal in a multivariate polynomial ring OUTPUT: a Groebner basis for F .. note:: The verbosity of this function may be controlled with a ``set_verbose()`` call. Any value ``>=1`` will result in this function printing intermediate Groebner bases. EXAMPLES:: sage: from sage.rings.polynomial.toy_buchberger import buchberger_improved sage: R.<x,y,z> = PolynomialRing(QQ,3) sage: set_verbose(0) sage: buchberger_improved(R.ideal([x^4-y-z,x*y*z-1])) [x*y*z - 1, x^3 - y^2*z - y*z^2, y^3*z^2 + y^2*z^3 - x^2] """ F = inter_reduction(F.gens()) G = set() B = set() if get_verbose() >=1: reductions_to_zero = 0 while F != set(): f = min(F) F.remove(f) G,B = update(G,B,f) while B != set(): g1,g2 = select(B) B.remove((g1,g2)) h = spol(g1,g2).reduce(G) if h!=0: G,B = update(G,B,h) if get_verbose() >= 1: print "(%s, %s) => %s"%(g1,g2,h) print "G: %s\n"%(G) if h==0: reductions_to_zero +=1 if get_verbose() >= 1: print "%d reductions to zero."%(reductions_to_zero) return Sequence(inter_reduction(G))
def buchberger_improved(F): """ An improved version of Buchberger's algorithm as presented in [BW93]_, page 232. This variant uses the Gebauer-Moeller Installation to apply Buchberger's first and second criterion to avoid useless pairs. INPUT: - ``F`` - an ideal in a multivariate polynomial ring OUTPUT: a Groebner basis for F .. note:: The verbosity of this function may be controlled with a ``set_verbose()`` call. Any value ``>=1`` will result in this function printing intermediate Groebner bases. EXAMPLES:: sage: from sage.rings.polynomial.toy_buchberger import buchberger_improved sage: R.<x,y,z> = PolynomialRing(QQ,3) sage: set_verbose(0) sage: buchberger_improved(R.ideal([x^4-y-z,x*y*z-1])) [x*y*z - 1, x^3 - y^2*z - y*z^2, y^3*z^2 + y^2*z^3 - x^2] """ F = inter_reduction(F.gens()) G = set() B = set() if get_verbose() >= 1: reductions_to_zero = 0 while F != set(): f = min(F) F.remove(f) G, B = update(G, B, f) while B != set(): g1, g2 = select(B) B.remove((g1, g2)) h = spol(g1, g2).reduce(G) if h != 0: G, B = update(G, B, h) if get_verbose() >= 1: print "(%s, %s) => %s" % (g1, g2, h) print "G: %s\n" % (G) if h == 0: reductions_to_zero += 1 if get_verbose() >= 1: print "%d reductions to zero." % (reductions_to_zero) return Sequence(inter_reduction(G))
def buchberger(F): """ The original version of Buchberger's algorithm as presented in [BW93]_, page 214. INPUT: - ``F`` - an ideal in a multivariate polynomial ring OUTPUT: a Groebner basis for F .. note:: The verbosity of this function may be controlled with a ``set_verbose()`` call. Any value >=1 will result in this function printing intermediate bases. EXAMPLES:: sage: from sage.rings.polynomial.toy_buchberger import buchberger sage: R.<x,y,z> = PolynomialRing(QQ,3) sage: set_verbose(0) sage: buchberger(R.ideal([x^2 - z - 1, z^2 - y - 1, x*y^2 - x - 1])) [-y^3 + x*z - x + y, y^2*z + y^2 - x - z - 1, x*y^2 - x - 1, x^2 - z - 1, z^2 - y - 1] """ G = set(F.gens()) B = set(filter(lambda x_y: x_y[0] != x_y[1], [(g1, g2) for g1 in G for g2 in G])) if get_verbose() >= 1: reductions_to_zero = 0 while B!=set(): g1,g2 = select(B) B.remove( (g1,g2) ) h = spol(g1,g2).reduce(G) if h != 0: B = B.union( [(g,h) for g in G] ) G.add( h ) if get_verbose() >= 1: print "(%s, %s) => %s"%(g1, g2, h) print "G: %s\n"%(G) if h==0: reductions_to_zero +=1 if get_verbose() >= 1: print "%d reductions to zero."%(reductions_to_zero) return Sequence(G)
def buchberger(F): """ Compute a Groebner basis using the original version of Buchberger's algorithm as presented in [BW1993]_, page 214. INPUT: - ``F`` -- an ideal in a multivariate polynomial ring OUTPUT: a Groebner basis for F .. NOTE:: The verbosity of this function may be controlled with a ``set_verbose()`` call. Any value >=1 will result in this function printing intermediate bases. EXAMPLES:: sage: from sage.rings.polynomial.toy_buchberger import buchberger sage: R.<x,y,z> = PolynomialRing(QQ) sage: I = R.ideal([x^2 - z - 1, z^2 - y - 1, x*y^2 - x - 1]) sage: set_verbose(0) sage: gb = buchberger(I) sage: gb.is_groebner() True sage: gb.ideal() == I True """ G = set(F.gens()) B = set((g1, g2) for g1 in G for g2 in G if g1 != g2) if get_verbose() >= 1: reductions_to_zero = 0 while B: g1, g2 = select(B) B.remove((g1, g2)) h = spol(g1, g2).reduce(G) if h != 0: B = B.union((g, h) for g in G) G.add(h) if get_verbose() >= 1: print("(%s, %s) => %s" % (g1, g2, h)) print("G: %s\n" % G) if h == 0: reductions_to_zero += 1 if get_verbose() >= 1: print("%d reductions to zero." % reductions_to_zero) return Sequence(G)
def __call__(self, assumptions=None): """ Run 'command' and collect output. INPUT: - ``assumptions`` - ignored, accepted for compatibility with other solvers (default: ``None``) TESTS: This class is not meant to be called directly:: sage: from sage.sat.solvers.dimacs import DIMACS sage: fn = tmp_filename() sage: solver = DIMACS(filename=fn) sage: solver.add_clause( (1, -2 , 3) ) sage: solver() Traceback (most recent call last): ... ValueError: No SAT solver command selected. """ if assumptions is not None: raise NotImplementedError("Assumptions are not supported for DIMACS based solvers.") self.write() output_filename = None self._output = [] command = self._command.strip() if not command: raise ValueError("No SAT solver command selected.") if "{output}" in command: output_filename = tmp_filename() command = command.format(input=self._headname, output=output_filename) args = shlex.split(command) try: process = subprocess.Popen(args, stdout=subprocess.PIPE) except OSError: raise OSError("Could run '%s', perhaps you need to add your SAT solver to $PATH?"%(" ".join(args))) try: while process.poll() is None: for line in iter(process.stdout.readline,''): if get_verbose() or self._verbosity: print line, sys.stdout.flush() self._output.append(line) sleep(0.1) if output_filename: self._output.extend(open(output_filename).readlines()) except KeyboardInterrupt: process.kill() raise KeyboardInterrupt
def gghlite_brief(l, kappa, **kwds): """ Return parameter choics for a GGHLite-like graded encoding scheme instance with security level at least ‘λ‘ and multilinearity level ‘κ‘ :param l:security parameter ‘λ‘ :param kappa: multilinearity level ‘k‘ :returns:parameter choices for a GGHLite-like graded-encoding scheme .. note:: ‘‘lambda‘‘ is a reserved key word in Python. """ n = _sage_const_1024 while True: params = gghlite_params(n, kappa, target_lambda=l, **kwds) best = gghlite_attacks(params, rerand=kwds.get('rerand', False)) current = OrderedDict() current[u"λ"] = l current[u"κ"] = kappa current["n"] = n current["q"] = params["q"] current["|enc|"] = params["|enc|"] current["|par|"] = params["|par|"] current[u"δ_0"]= best[u"δ_0"] current[u"bkz2"]= best[u"bkz2"] current[u"sieve"] = best[u"sieve"] current[u"k"] = best[u"k"] # if get_verbose() >= 1: # print(params_str(current)) if best["bkz2"] >= ZZ(_sage_const_2 )**l and best["sieve"] >= ZZ(_sage_const_2 )**l: break n = _sage_const_2 *n if get_verbose() >= _sage_const_1 : print(params_str(current)) return current
def gghlite_brief(l, kappa, **kwds): """ Return parameter choics for a GGHLite-like graded encoding scheme instance with security level at least ‘λ‘ and multilinearity level ‘κ‘ :param l:security parameter ‘λ‘ :param kappa: multilinearity level ‘k‘ :returns:parameter choices for a GGHLite-like graded-encoding scheme .. note:: ‘‘lambda‘‘ is a reserved key word in Python. """ n = _sage_const_1024 while True: params = gghlite_params(n, kappa, target_lambda=l, **kwds) best = gghlite_attacks(params, rerand=kwds.get('rerand', False)) current = OrderedDict() current[u"λ"] = l current[u"κ"] = kappa current["n"] = n current["q"] = params["q"] current["|enc|"] = params["|enc|"] current["|par|"] = params["|par|"] current[u"δ_0"] = best[u"δ_0"] current[u"bkz2"] = best[u"bkz2"] current[u"sieve"] = best[u"sieve"] current[u"k"] = best[u"k"] # if get_verbose() >= 1: # print(params_str(current)) if best["bkz2"] >= ZZ(_sage_const_2)**l and best["sieve"] >= ZZ( _sage_const_2)**l: break n = _sage_const_2 * n if get_verbose() >= _sage_const_1: print(params_str(current)) return current
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 __call__(self, assumptions=None): """ Run 'command' and collect output. INPUT: - ``assumptions`` - ignored, accepted for compatibility with other solvers (default: ``None``) TESTS: This class is not meant to be called directly:: sage: from sage.sat.solvers.dimacs import DIMACS sage: fn = tmp_filename() sage: solver = DIMACS(filename=fn) sage: solver.add_clause( (1, -2 , 3) ) sage: solver() Traceback (most recent call last): ... ValueError: No SAT solver command selected. """ if assumptions is not None: raise NotImplementedError( "Assumptions are not supported for DIMACS based solvers.") self.write() output_filename = None self._output = [] command = self._command.strip() if not command: raise ValueError("No SAT solver command selected.") if "{output}" in command: output_filename = tmp_filename() command = command.format(input=self._headname, output=output_filename) args = shlex.split(command) try: process = subprocess.Popen(args, stdout=subprocess.PIPE) except OSError: raise OSError( "Could run '%s', perhaps you need to add your SAT solver to $PATH?" % (" ".join(args))) try: while process.poll() is None: for line in iter(process.stdout.readline, ''): if get_verbose() or self._verbosity: print line, sys.stdout.flush() self._output.append(line) sleep(0.1) if output_filename: self._output.extend(open(output_filename).readlines()) except KeyboardInterrupt: process.kill() raise KeyboardInterrupt
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