def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=False, **kwds): """ Learn new polynomials by running SAT-solver ``solver`` on SAT-instance produced by ``converter`` from ``F``. INPUT: - ``F`` - a sequence of Boolean polynomials - ``converter`` - an ANF to CNF converter class or object. If ``converter`` is ``None`` then :class:`sage.sat.converters.polybori.CNFEncoder` is used to construct a new converter. (default: ``None``) - ``solver`` - a SAT-solver class or object. If ``solver`` is ``None`` then :class:`sage.sat.solvers.cryptominisat.CryptoMiniSat` is used to construct a new converter. (default: ``None``) - ``max_learnt_length`` - only clauses of length <= ``max_length_learnt`` are considered and converted to polynomials. (default: ``3``) - ``interreduction`` - inter-reduce the resulting polynomials (default: ``False``) .. NOTE:: More parameters can be passed to the converter and the solver by prefixing them with ``c_`` and ``s_`` respectively. For example, to increase CryptoMiniSat's verbosity level, pass ``s_verbosity=1``. OUTPUT: A sequence of Boolean polynomials. EXAMPLES:: sage: from sage.sat.boolean_polynomials import learn as learn_sat # optional - cryptominisat We construct a simple system and solve it:: sage: set_random_seed(2300) # optional - cryptominisat sage: sr = mq.SR(1,2,2,4,gf2=True,polybori=True) # optional - cryptominisat sage: F,s = sr.polynomial_system() # optional - cryptominisat sage: H = learn_sat(F) # optional - cryptominisat sage: H[-1] # optional - cryptominisat k033 + 1 """ try: len(F) except AttributeError: F = F.gens() len(F) P = next(iter(F)).parent() K = P.base_ring() # instantiate the SAT solver if solver is None: from sage.sat.solvers.cryptominisat import CryptoMiniSat as solver solver_kwds = {} for k, v in six.iteritems(kwds): if k.startswith("s_"): solver_kwds[k[2:]] = v solver = solver(**solver_kwds) # instantiate the ANF to CNF converter if converter is None: from sage.sat.converters.polybori import CNFEncoder as converter converter_kwds = {} for k, v in six.iteritems(kwds): if k.startswith("c_"): converter_kwds[k[2:]] = v converter = converter(solver, P, **converter_kwds) phi = converter(F) rho = dict((phi[i], i) for i in range(len(phi))) s = solver() if s: learnt = [x + K(s[rho[x]]) for x in P.gens()] else: learnt = [] try: lc = solver.learnt_clauses() except (AttributeError, NotImplementedError): # solver does not support recovering learnt clauses lc = [] for c in lc: if len(c) <= max_learnt_length: try: learnt.append(converter.to_polynomial(c)) except (ValueError, NotImplementedError, AttributeError): # the solver might have learnt clauses that contain CNF # variables which have no correspondence to variables in our # polynomial ring (XOR chaining variables for example) pass learnt = PolynomialSequence(P, learnt) if interreduction: learnt = learnt.ideal().interreduced_basis() return learnt
def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=False, **kwds): """ Learn new polynomials by running SAT-solver ``solver`` on SAT-instance produced by ``converter`` from ``F``. INPUT: - ``F`` - a sequence of Boolean polynomials - ``converter`` - an ANF to CNF converter class or object. If ``converter`` is ``None`` then :class:`sage.sat.converters.polybori.CNFEncoder` is used to construct a new converter. (default: ``None``) - ``solver`` - a SAT-solver class or object. If ``solver`` is ``None`` then :class:`sage.sat.solvers.cryptominisat.CryptoMiniSat` is used to construct a new converter. (default: ``None``) - ``max_learnt_length`` - only clauses of length <= ``max_length_learnt`` are considered and converted to polynomials. (default: ``3``) - ``interreduction`` - inter-reduce the resulting polynomials (default: ``False``) .. NOTE:: More parameters can be passed to the converter and the solver by prefixing them with ``c_`` and ``s_`` respectively. For example, to increase CryptoMiniSat's verbosity level, pass ``s_verbosity=1``. OUTPUT: A sequence of Boolean polynomials. EXAMPLE:: sage: from sage.sat.boolean_polynomials import learn as learn_sat # optional - cryptominisat We construct a simple system and solve it:: sage: set_random_seed(2300) # optional - cryptominisat sage: sr = mq.SR(1,2,2,4,gf2=True,polybori=True) # optional - cryptominisat sage: F,s = sr.polynomial_system() # optional - cryptominisat sage: H = learn_sat(F) # optional - cryptominisat sage: H[-1] # optional - cryptominisat k033 + 1 We construct a slightly larger equation system and recover some equations after 20 restarts:: sage: set_random_seed(2303) # optional - cryptominisat sage: sr = mq.SR(1,4,4,4,gf2=True,polybori=True) # optional - cryptominisat sage: F,s = sr.polynomial_system() # optional - cryptominisat sage: from sage.sat.boolean_polynomials import learn as learn_sat # optional - cryptominisat sage: H = learn_sat(F, s_maxrestarts=20, interreduction=True) # optional - cryptominisat sage: H[-1] # optional - cryptominisat, output random k001200*s031*x011201 + k001200*x011201 .. NOTE:: This function is meant to be called with some parameter such that the SAT-solver is interrupted. For CryptoMiniSat this is max_restarts, so pass 'c_max_restarts' to limit the number of restarts CryptoMiniSat will attempt. If no such parameter is passed, then this function behaves essentially like :func:`solve` except that this function does not support ``n>1``. TESTS: We test that :trac:`17351` is fixed, by checking that the following doctest does not raise an error:: sage: P.<a,b,c> = BooleanPolynomialRing() sage: F = [a*c + a + b*c + c + 1, a*b + a*c + a + c + 1, a*b + a*c + a + b*c + 1] sage: from sage.sat.boolean_polynomials import learn as learn_sat # optional - cryptominisat sage: learn_sat(F, s_maxrestarts=0, interreduction=True) # optional - cryptominisat [] """ try: len(F) except AttributeError: F = F.gens() len(F) P = next(iter(F)).parent() K = P.base_ring() # instantiate the SAT solver if solver is None: from sage.sat.solvers.cryptominisat import CryptoMiniSat as solver solver_kwds = {} for k, v in kwds.iteritems(): if k.startswith("s_"): solver_kwds[k[2:]] = v solver = solver(**solver_kwds) # instantiate the ANF to CNF converter if converter is None: from sage.sat.converters.polybori import CNFEncoder as converter converter_kwds = {} for k, v in kwds.iteritems(): if k.startswith("c_"): converter_kwds[k[2:]] = v converter = converter(solver, P, **converter_kwds) phi = converter(F) rho = dict((phi[i], i) for i in range(len(phi))) s = solver() if s: learnt = [x + K(s[rho[x]]) for x in P.gens()] else: learnt = [] for c in solver.learnt_clauses(): if len(c) <= max_learnt_length: try: learnt.append(converter.to_polynomial(c)) except (ValueError, NotImplementedError, AttributeError): # the solver might have learnt clauses that contain CNF # variables which have no correspondence to variables in our # polynomial ring (XOR chaining variables for example) pass learnt = PolynomialSequence(P, learnt) if interreduction: learnt = learnt.ideal().interreduced_basis() return learnt
def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=False, **kwds): """ Learn new polynomials by running SAT-solver ``solver`` on SAT-instance produced by ``converter`` from ``F``. INPUT: - ``F`` - a sequence of Boolean polynomials - ``converter`` - an ANF to CNF converter class or object. If ``converter`` is ``None`` then :class:`sage.sat.converters.polybori.CNFEncoder` is used to construct a new converter. (default: ``None``) - ``solver`` - a SAT-solver class or object. If ``solver`` is ``None`` then :class:`sage.sat.solvers.cryptominisat.CryptoMiniSat` is used to construct a new converter. (default: ``None``) - ``max_learnt_length`` - only clauses of length <= ``max_length_learnt`` are considered and converted to polynomials. (default: ``3``) - ``interreduction`` - inter-reduce the resulting polynomials (default: ``False``) .. NOTE:: More parameters can be passed to the converter and the solver by prefixing them with ``c_`` and ``s_`` respectively. For example, to increase CryptoMiniSat's verbosity level, pass ``s_verbosity=1``. OUTPUT: A sequence of Boolean polynomials. EXAMPLES:: sage: from sage.sat.boolean_polynomials import learn as learn_sat # optional - cryptominisat We construct a simple system and solve it:: sage: set_random_seed(2300) # optional - cryptominisat sage: sr = mq.SR(1,2,2,4,gf2=True,polybori=True) # optional - cryptominisat sage: F,s = sr.polynomial_system() # optional - cryptominisat sage: H = learn_sat(F) # optional - cryptominisat sage: H[-1] # optional - cryptominisat k033 + 1 """ try: len(F) except AttributeError: F = F.gens() len(F) P = next(iter(F)).parent() K = P.base_ring() # instantiate the SAT solver if solver is None: from sage.sat.solvers.cryptominisat import CryptoMiniSat as solver solver_kwds = {} for k, v in kwds.items(): if k.startswith("s_"): solver_kwds[k[2:]] = v solver = solver(**solver_kwds) # instantiate the ANF to CNF converter if converter is None: from sage.sat.converters.polybori import CNFEncoder as converter converter_kwds = {} for k, v in kwds.items(): if k.startswith("c_"): converter_kwds[k[2:]] = v converter = converter(solver, P, **converter_kwds) phi = converter(F) rho = dict((phi[i], i) for i in range(len(phi))) s = solver() if s: learnt = [x + K(s[rho[x]]) for x in P.gens()] else: learnt = [] try: lc = solver.learnt_clauses() except (AttributeError, NotImplementedError): # solver does not support recovering learnt clauses lc = [] for c in lc: if len(c) <= max_learnt_length: try: learnt.append(converter.to_polynomial(c)) except (ValueError, NotImplementedError, AttributeError): # the solver might have learnt clauses that contain CNF # variables which have no correspondence to variables in our # polynomial ring (XOR chaining variables for example) pass learnt = PolynomialSequence(P, learnt) if interreduction: learnt = learnt.ideal().interreduced_basis() return learnt