def __init__(self, verbosity=0, confl_limit=None, threads=None): r""" Constuct a new CryptoMiniSat instance. See the documentation class for the description of inputs. EXAMPLES:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat(threads=1) # optional - cryptominisat """ if threads is None: from sage.parallel.ncpus import ncpus threads = ncpus() if confl_limit is None: from sys import maxint confl_limit = maxint try: from pycryptosat import Solver except ImportError: from sage.misc.package import PackageNotFoundError raise PackageNotFoundError("cryptominisat") self._solver = Solver(verbose=int(verbosity), confl_limit=int(confl_limit), threads=int(threads)) self._nvars = 0 self._clauses = []
def test_cnf3(self): solver = Solver() for cl in clauses3: solver.add_clause(cl) res, solution = solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses3, solution))
def oldfindFsmConsecutive(self, filename="SatFile", outputFile="satOutput"): self.numOfNodes = 1 FOUND = False startTime = time.time() totalSolveTime = 0 totalFileTime = 0 while not FOUND: print("Trying with", self.numOfNodes, "nodes...") if self.usePyCrypto: self.s = Solver() #Reinitialize sTime = time.time() self.constructClauses() self.clauses.addToSolver(self.s) endTime = time.time()-sTime totalFileTime += endTime print("Sat preperations took", endTime, "seconds") sTime = time.time() isSatisfiable, output = self.s.solve() solveEnd = time.time()-sTime totalSolveTime += solveEnd print("Solving took", solveEnd, "seconds") else: sFileTime = time.time() self.constructClauses() fileEnd = time.time()-sFileTime totalFileTime += fileEnd print("Sat file construction took", fileEnd, "seconds") solveTime = time.time() subprocess.run("cryptominisat5 --verb 0 {} > {}".format(filename, outputFile), shell=True) solveEnd = time.time()-solveTime totalSolveTime += solveEnd print("Solving took", solveEnd, "seconds") isSatisfiable, output = self.checkOutput() if isSatisfiable: print("Satisfiable with", self.numOfNodes, "nodes!") print("Total construction time:", totalFileTime, "seconds") print("Total solving time:", totalSolveTime, "seconds") print("\nConsecutive approach took", time.time()-startTime, "seconds.") print() FOUND = True self.numOfNodes += 1 return output
def obtain_labels(num_test_cases): row_solution = [] num_sat = 0 # Loop through the test cases for i in range(1, num_test_cases + 1): # Initialize the solver s = Solver() file = os.path.join(base_dir, f"test_case_{i}.cnf") # Obtain the CNF formula of the test case _, _, cnf = read_data(file) # Pass the CNF into the solver for row in cnf: s.add_clause(row) start = time.perf_counter() # Solve the CNF sat, _ = s.solve() # Obtain the number of satisfiable formulas if sat: num_sat += 1 # Record time taken for single test case time_taken = time.perf_counter() - start # Store the results row_solution.append([i, sat, time_taken]) # Save the results with open(os.path.join(base_dir, 'labels.csv'), 'w', newline='') as csvfile: spamwriter = csv.writer(csvfile, delimiter=' ', quotechar='|', quoting=csv.QUOTE_MINIMAL) for row in row_solution: spamwriter.writerow(row) return num_sat
def __init__(self, filename): self.s = Solver(threads=3) self.tt = 0 h2v = {} # hole 2 variable self.maximum_variable = -1 with open(filename, 'r') as f: for l in f: if len(l) > len('c hole ') and l[:len('c hole ')] == 'c hole ': ms = re.findall(r'(\d+) \- (\d+)', l)[0] assert int(ms[0]) == int(ms[1]) ms = int(ms[0]) n = int(re.findall(r'H__\S+_(\S+)\s', l)[0]) h2v[n] = ms elif len(l) > 0 and not 'c' in l and not 'p' in l: vs = re.findall(r'(\-?\d+)', l) assert vs[-1] == '0' clause = [int(v) for v in vs[:-1]] self.maximum_variable = max([self.maximum_variable] + [abs(v) for v in clause]) self.s.add_clause(clause) print "Loaded", filename, " with", len(h2v), "holes" # convert the tape index into a sat variable self.tape2variable = [v for h, v in sorted(h2v.items())] # converts a sat variable to a tape index self.variable2tape = dict([(v, h) for h, v in h2v.items()])
def test_cnf1_confl_limit(self): for lim in range(1, 20): solver = Solver(confl_limit=lim) for cl in clauses1: solver.add_clause(cl) res, solution = solver.solve() self.assertTrue(res == None or check_solution(clauses1, solution))
def cryptominisat_solve(self): s = Solver() for clause in self.clauses: s.add_clause(clause) sat, solution = s.solve() if sat: return solution else: return 'UNSAT'
class TestableSolver: def __init__(self): self.solver = Solver() def solve(self, assumptions=[]): return self.solver.solve(assumptions) @staticmethod def to_var(row, column, value): return row * 9 * 9 + column * 9 + value + 1 # return a tuple (row, column, value) @staticmethod def from_var(var): v = var - 1 row = v // (9 * 9) column = (v - row * 9 * 9) // 9 value = v - row * 9 * 9 - column * 9 return row, column, value # helper function: one and only one literal can be true def exactly_one(self, literals): # at least once self.solver.add_clause(literals) for i in literals: for j in range(i + 1, len(literals)): self.solver.add_clause([-literals[i], -literals[j]]) # adds the rule, that for each position, only one value can be true def add_uniqueness(self, rows, columns): for r in range(rows): for c in range(columns): lit = [self.to_var(r, c, v) for v in range(9)] self.exactly_one(lit) # adds the rule, that for each rule, the values 1..9 exist def add_row_rule(self, row): for v in range(9): lit = [self.to_var(row, c, v) for c in range(9)] self.exactly_one(lit) # adds the rule, that for each column, the values 0..8 exist def add_column_rule(self, column): for v in range(9): lit = [self.to_var(r, column, v) for r in range(9)] self.exactly_one(lit) # adds the rule, that for each box, the values 0..8 exist def add_box_rule(self, column, row): for v in range(9): lit = [ self.to_var(row + (i // 3), column + (i % 3), v) for i in range(9) ] self.exactly_one(lit)
def pyCrypto(self): if PyCryptoSat_Import_Successful: s = Solver() numOfClauses = len(self.clauseList) for i in range(numOfClauses): s.add_clause(self.clauseList.popleft) sat, solution = s.solve() if sat: return (sat, solution) return (sat, None)
def test_time(self): SAT_TIME_LIMIT = 1 clauses = self.get_clauses() #returns a few hundred short clauses t0 = time.time() solver = Solver(threads=4, time_limit=SAT_TIME_LIMIT) solver.add_clauses(clauses) sat, sol = solver.solve() took_time = time.time() - t0 # NOTE: the above CNF solves in about 1 hour. # So anything below 10min is good. Setting 2s would work... no most # systems, but not on overloaded CI servers self.assertLess(took_time, 4)
class TestDump(unittest.TestCase): def setUp(self): self.solver = Solver() def test_max_glue_missing(self): self.assertRaises(TypeError, self.solver.start_getting_small_clauses, 4) def test_one_dump(self): with open("tests/test.cnf", "r") as x: for line in x: line = line.strip() if "p" in line or "c" in line: continue out = [int(x) for x in line.split()[:-1]] self.solver.add_clause(out) res, _ = self.solver.solve() self.assertEqual(res, True) self.solver.start_getting_small_clauses(4, max_glue=10) x = self.solver.get_next_small_clause() self.assertNotEquals(x, None) self.solver.end_getting_small_clauses()
def __init__(self,filename): self.s = Solver(threads = 3) self.tt = 0 h2v = {} # hole 2 variable self.maximum_variable = -1 with open(filename,'r') as f: for l in f: if len(l) > len('c hole ') and l[:len('c hole ')] == 'c hole ': ms = re.findall(r'(\d+) \- (\d+)', l)[0] assert int(ms[0]) == int(ms[1]) ms = int(ms[0]) n = int(re.findall(r'H__\S+_(\S+)\s',l)[0]) h2v[n] = ms elif len(l) > 0 and not 'c' in l and not 'p' in l: vs = re.findall(r'(\-?\d+)',l) assert vs[-1] == '0' clause = [int(v) for v in vs[:-1] ] self.maximum_variable = max([self.maximum_variable] + [abs(v) for v in clause ]) self.s.add_clause(clause) print "Loaded",filename," with",len(h2v),"holes" # convert the tape index into a sat variable self.tape2variable = [ v for h,v in sorted(h2v.items()) ] # converts a sat variable to a tape index self.variable2tape = dict([ (v,h) for h,v in h2v.items() ])
def test_long(self) : for l in range(10,30) : solver = Solver() toadd = [] toassume = [] solution_expected = [None] for i in range(1,l) : toadd.append(i) solution_expected.append(False) if i != l-1 : toassume.append(i*-1) solver.add_xor_clause(toadd, False) res, solution = solver.solve(toassume) self.assertEqual(res, True) self.assertEqual(solution, tuple(solution_expected))
class CryptoMiniSatSolver: _model = None def __init__(self): from pycryptosat import Solver self.solver = Solver() self.add_clause = self.solver.add_clause def delete(self): pass def solve(self): sat, sol = self.solver.solve() if sat: model = [] for idx, val in enumerate(sol): if val is True: model.append(idx) elif val is False: model.append(-idx) self._model = model return sat def get_model(self): assert self._model is not None return self._model
def build_solver(game): s = Solver() constant_rules(game, s) row_rules(s) col_rules(s) box_rules(s) int_rules(s) return s
def solve_trace(data, dropout=[False for i in range(176)], cfl=300000, wr_dropout=1.0): keyschedule = aes_key_schedule(10) weight_restrictions = restrict_hw_in_aes_ks_fuzzy(data, dropout=dropout, wr_dropout=wr_dropout) solver = Solver(confl_limit=cfl) for clause in keyschedule: solver.add_clause(clause) for clause in weight_restrictions: solver.add_clause(clause) print("Number of clauses: ", len(keyschedule) + len(weight_restrictions)) sat, sol = 0, 1 try: sat, sol = solver.solve() except: sat = None if (not sat): print("No success satisfying system.") return (False, None) #convert solution to keyschedule byte values byte_arr = np.array( [convert_to_byte(sol[i:i + 8]) for i in range(1, 176 * 8, 8)], dtype=np.uint8) return (True, byte_arr)
def __init__(self, tracesList, numOfInputs, usePyCrypto=False): self.numOfInputs = numOfInputs self.tracesList = tracesList self.usePyCrypto = usePyCrypto self.s = None if self.usePyCrypto and PyCryptoSat_Import_Successful: self.s = Solver() print("Initialized solver") self.clauses = ClauseHandler() ## Creates the acyclic Fsm of trace nodes. self.constructTraceTree() # self.traceTree is created and filled self.numOfTraceNodes = len(self.traceTree.nodes) ### #This variable is used as global, handle with care self.numOfNodes = 0
def build_solver(keyset, gencon, n_pins, n_levels): s = Solver() n_keys = len(keyset[0]) n_locks = len(keyset) keys_have_exactly_one_cut(n_keys, n_pins, n_levels, s) locks_have_at_least_one_shear(n_keys, n_locks, n_pins, n_levels, s) keys_must_open_charted_locks(keyset, n_levels, n_pins, s) keys_must_not_open_uncharted_locks(keyset, n_levels, n_pins, s) keys_must_not_match_gencon(gencon, s) return s
def create_conditions(self): ''' Create conditions for solver from cipher description ''' if self.cipher == None: print('You need to load a cipher.') sys.exit(1) if self.rounds == None: print('You need to specify the number of rounds.') sys.exit(1) if self.fresh_conditions: return self.solver = Solver() self.next_variable = 1 self.state_bit = [i + 1 for i in range(self.state_size)] state = [self.state_bit[i] for i in range(self.state_size)] self.round_states.append(state) self.next_variable += self.state_size self.temporary = {i: None for i in self.cipher.temporaries} self.sbox_tmps = {} for rnd in range(self.rounds): for step in self.cipher.transition: if step[-1] == 'XOR': self.apply_xor(step[0], step[1], step[2]) elif step[-1] == 'AND': self.apply_and(step[0], step[1], step[2]) elif step[-1] == 'PERM': self.apply_permutation(step[0]) elif step[-1] == 'SBOX': self.apply_sbox(step[0], step[1], step[2]) elif step[-1] == 'MOV': self.apply_mov(step[0], step[1]) self.set_temporaries_to_zero() state = [self.state_bit[i] for i in range(self.state_size)] self.round_states.append(state) self.fresh_conditions = True return
def is_system_uniquely_satisfiable(self, system, n): """ Tests unique satisfiable by banning all zero solution :param system: :param n: :return: """ if not system: return False # Prep solver solver = Solver() for clause in system: solver.add_xor_clause(clause, False) # Ban all zero solver.add_clause(range(1, n + 1)) sat, sol = solver.solve() # print "Found system is {0}".format(sat) return not sat
def solve_or(model): s = Solver() for clause in model.clauses: s.add_clause(clause) return s.solve()
def solve_sat(self): solver = Solver() for clause in self.formula: solver.add_clause(clause) sat, assignments = solver.solve() return sat
def setUp(self): self.solver = Solver(threads=2)
class TestXor(unittest.TestCase) : def setUp(self) : self.solver = Solver(threads = 2); def test_wrong_args(self) : self.assertRaises(TypeError, self.solver.add_xor_clause, [1, 2]) self.assertRaises(ValueError, self.solver.add_xor_clause, [1, 0], True) self.assertRaises(ValueError, self.solver.add_xor_clause, [-1, 2], True) def test_binary(self) : self.solver.add_xor_clause([1,2], False) res, solution = self.solver.solve([1]) self.assertEqual(res, True) self.assertEqual(solution, (None, True, True)) def test_unit(self) : self.solver.add_xor_clause([1], False) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertEqual(solution, (None, False)) def test_unit2(self) : self.solver.add_xor_clause([1], True) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertEqual(solution, (None, True)) def test_3_long(self) : self.solver.add_xor_clause([1, 2, 3], False) res, solution = self.solver.solve([1, 2]) self.assertEqual(res, True) #self.assertEqual(solution, (None, True, True, False)) def test_3_long2(self) : self.solver.add_xor_clause([1, 2, 3], True) res, solution = self.solver.solve([1, -2]) self.assertEqual(res, True) self.assertEqual(solution, (None, True, False, False)) def test_long(self) : for l in range(10,30) : self.setUp() toadd = [] toassume = [] solution_expected = [None] for i in range(1,l) : toadd.append(i) solution_expected.append(False) if i != l-1 : toassume.append(i*-1) self.solver.add_xor_clause(toadd, False) res, solution = self.solver.solve(toassume) self.assertEqual(res, True) self.assertEqual(solution, tuple(solution_expected))
def setup(self, clauses, m, threads=1): from pycryptosat import Solver solver = Solver(threads=threads) solver.add_clauses(clauses.as_list()) return solver
class TestSolve(unittest.TestCase): def setUp(self): self.solver = Solver(threads=2) def test_wrong_args(self): self.assertRaises(TypeError, self.solver.add_clause, 'A') self.assertRaises(TypeError, self.solver.add_clause, 1) self.assertRaises(TypeError, self.solver.add_clause, 1.0) self.assertRaises(TypeError, self.solver.add_clause, object()) self.assertRaises(TypeError, self.solver.add_clause, ['a']) self.assertRaises(TypeError, self.solver.add_clause, [[1, 2], [3, None]]) self.assertRaises(ValueError, self.solver.add_clause, [1, 0]) def test_no_clauses(self): for _ in range(7): self.assertEqual(self.solver.solve([]), (True, (None, ))) def test_cnf1(self): for cl in clauses1: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses1, solution)) def test_bad_iter(self): class Liar: def __iter__(self): return None self.assertRaises(TypeError, self.solver.add_clause, Liar()) def test_cnf2(self): for cl in clauses2: self.solver.add_clause(cl) self.assertEqual(self.solver.solve(), (False, None)) def test_cnf3(self): for cl in clauses3: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses3, solution)) def test_cnf1_confl_limit(self): for _ in range(1, 20): self.setUp() for cl in clauses1: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertTrue(res is None or check_solution(clauses1, solution)) def test_by_re_curse(self): self.solver.add_clause([-1, -2, 3]) res, _ = self.solver.solve() self.assertEqual(res, True) self.solver.add_clause([-5, 1]) self.solver.add_clause([4, -3]) self.solver.add_clause([2, 3, 5]) res, _ = self.solver.solve() self.assertEqual(res, True)
def test_binary(self) : solver = Solver() solver.add_xor_clause([1,2], False) res, solution = solver.solve([1]) self.assertEqual(res, True) self.assertEqual(solution, (None, True, True))
def setUp(self): self.solver = Solver()
def __init__(self): from pycryptosat import Solver self.solver = Solver() self.add_clause = self.solver.add_clause
class CryptoMiniSat(SatSolver): r""" CryptoMiniSat Solver. INPUT: - ``verbosity`` -- an integer between 0 and 15 (default: 0). Verbosity. - ``confl_limit`` -- an integer (default: ``None``). Abort after this many conflicts. If set to ``None``, never aborts. - ``threads`` -- an integer (default: None). The number of thread to use. If set to ``None``, the number of threads used corresponds to the number of cpus. EXAMPLES:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat """ def __init__(self, verbosity=0, confl_limit=None, threads=None): r""" Constuct a new CryptoMiniSat instance. See the documentation class for the description of inputs. EXAMPLES:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat(threads=1) # optional - cryptominisat """ if threads is None: from sage.parallel.ncpus import ncpus threads = ncpus() if confl_limit is None: from sys import maxint confl_limit = maxint try: from pycryptosat import Solver except ImportError: from sage.misc.package import PackageNotFoundError raise PackageNotFoundError("cryptominisat") self._solver = Solver(verbose=int(verbosity), confl_limit=int(confl_limit), threads=int(threads)) self._nvars = 0 self._clauses = [] def var(self, decision=None): r""" Return a *new* variable. INPUT: - ``decision`` -- accepted for compatibility with other solvers, ignored. EXAMPLES:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat sage: solver.var() # optional - cryptominisat 1 sage: solver.add_clause((-1,2,-4)) # optional - cryptominisat sage: solver.var() # optional - cryptominisat 5 """ return self._nvars + 1 def nvars(self): r""" Return the number of variables. Note that for compatibility with DIMACS convention, the number of variables corresponds to the maximal index of the variables used. EXAMPLES:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat sage: solver.nvars() # optional - cryptominisat 0 If a variable with intermediate index is not used, it is still considered as a variable:: sage: solver.add_clause((1,-2,4)) # optional - cryptominisat sage: solver.nvars() # optional - cryptominisat 4 """ return self._nvars def add_clause(self, lits): r""" Add a new clause to set of clauses. INPUT: - ``lits`` -- a tuple of nonzero integers. .. note:: If any element ``e`` in ``lits`` has ``abs(e)`` greater than the number of variables generated so far, then new variables are created automatically. EXAMPLES:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat sage: solver.add_clause((1, -2 , 3)) # optional - cryptominisat """ if 0 in lits: raise ValueError("0 should not appear in the clause: {}".format(lits)) # cryptominisat does not handle Sage integers lits = tuple(int(i) for i in lits) self._nvars = max(self._nvars, max(abs(i) for i in lits)) self._solver.add_clause(lits) self._clauses.append((lits, False, None)) def add_xor_clause(self, lits, rhs=True): r""" Add a new XOR clause to set of clauses. INPUT: - ``lits`` -- a tuple of positive integers. - ``rhs`` -- boolean (default: ``True``). Whether this XOR clause should be evaluated to ``True`` or ``False``. EXAMPLES:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat sage: solver.add_xor_clause((1, 2 , 3), False) # optional - cryptominisat """ if 0 in lits: raise ValueError("0 should not appear in the clause: {}".format(lits)) # cryptominisat does not handle Sage integers lits = tuple(int(i) for i in lits) self._nvars = max(self._nvars, max(abs(i) for i in lits)) self._solver.add_xor_clause(lits, rhs) self._clauses.append((lits, True, rhs)) def __call__(self, assumptions=None): r""" Solve this instance. OUTPUT: - If this instance is SAT: A tuple of length ``nvars()+1`` where the ``i``-th entry holds an assignment for the ``i``-th variables (the ``0``-th entry is always ``None``). - If this instance is UNSAT: ``False``. EXAMPLES:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat sage: solver.add_clause((1,2)) # optional - cryptominisat sage: solver.add_clause((-1,2)) # optional - cryptominisat sage: solver.add_clause((-1,-2)) # optional - cryptominisat sage: solver() # optional - cryptominisat (None, False, True) sage: solver.add_clause((1,-2)) # optional - cryptominisat sage: solver() # optional - cryptominisat False """ satisfiable, assignments = self._solver.solve() if satisfiable: return assignments else: return False def __repr__(self): r""" TESTS:: sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat sage: solver # optional - cryptominisat CryptoMiniSat solver: 0 variables, 0 clauses. """ return "CryptoMiniSat solver: {} variables, {} clauses.".format(self.nvars(), len(self.clauses())) def clauses(self, filename=None): r""" Return original clauses. INPUT: - ``filename`` -- if not ``None`` clauses are written to ``filename`` in DIMACS format (default: ``None``) OUTPUT: If ``filename`` is ``None`` then a list of ``lits, is_xor, rhs`` tuples is returned, where ``lits`` is a tuple of literals, ``is_xor`` is always ``False`` and ``rhs`` is always ``None``. If ``filename`` points to a writable file, then the list of original clauses is written to that file in DIMACS format. EXAMPLES:: sage: from sage.sat.solvers import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat sage: solver.add_clause((1,2,3,4,5,6,7,8,-9)) # optional - cryptominisat sage: solver.add_xor_clause((1,2,3,4,5,6,7,8,9), rhs=True) # optional - cryptominisat sage: solver.clauses() # optional - cryptominisat [((1, 2, 3, 4, 5, 6, 7, 8, -9), False, None), ((1, 2, 3, 4, 5, 6, 7, 8, 9), True, True)] DIMACS format output:: sage: from sage.sat.solvers import CryptoMiniSat sage: solver = CryptoMiniSat() # optional - cryptominisat sage: solver.add_clause((1, 2, 4)) # optional - cryptominisat sage: solver.add_clause((1, 2, -4)) # optional - cryptominisat sage: fn = tmp_filename() # optional - cryptominisat sage: solver.clauses(fn) # optional - cryptominisat sage: print(open(fn).read()) # optional - cryptominisat p cnf 4 2 1 2 4 0 1 2 -4 0 <BLANKLINE> Note that in cryptominisat, the DIMACS standard format is augmented with the following extension: having an ``x`` in front of a line makes that line an XOR clause:: sage: solver.add_xor_clause((1,2,3), rhs=True) # optional - cryptominisat sage: solver.clauses(fn) # optional - cryptominisat sage: print(open(fn).read()) # optional - cryptominisat p cnf 4 3 1 2 4 0 1 2 -4 0 x1 2 3 0 <BLANKLINE> Note that inverting an xor-clause is equivalent to inverting one of the variables:: sage: solver.add_xor_clause((1,2,5),rhs=False) # optional - cryptominisat sage: solver.clauses(fn) # optional - cryptominisat sage: print(open(fn).read()) # optional - cryptominisat p cnf 5 4 1 2 4 0 1 2 -4 0 x1 2 3 0 x1 2 -5 0 <BLANKLINE> """ if filename is None: return self._clauses else: from sage.sat.solvers.dimacs import DIMACS DIMACS.render_dimacs(self._clauses, filename, self.nvars())
def solve_xor(model): s = Solver() for clause in model.clauses: s.add_xor_clause(_only_positive(clause), rhs=_get_clause_parity(clause)) return s.solve()
def __init__(self): self.solver = Solver()
def test_3_long2(self) : solver = Solver() solver.add_xor_clause([1, 2, 3], True) res, solution = solver.solve([1, -2]) self.assertEqual(res, True) self.assertEqual(solution, (None, True, False, False))
class ProgramSolver(): def __init__(self,filename): self.s = Solver(threads = 3) self.tt = 0 h2v = {} # hole 2 variable self.maximum_variable = -1 with open(filename,'r') as f: for l in f: if len(l) > len('c hole ') and l[:len('c hole ')] == 'c hole ': ms = re.findall(r'(\d+) \- (\d+)', l)[0] assert int(ms[0]) == int(ms[1]) ms = int(ms[0]) n = int(re.findall(r'H__\S+_(\S+)\s',l)[0]) h2v[n] = ms elif len(l) > 0 and not 'c' in l and not 'p' in l: vs = re.findall(r'(\-?\d+)',l) assert vs[-1] == '0' clause = [int(v) for v in vs[:-1] ] self.maximum_variable = max([self.maximum_variable] + [abs(v) for v in clause ]) self.s.add_clause(clause) print "Loaded",filename," with",len(h2v),"holes" # convert the tape index into a sat variable self.tape2variable = [ v for h,v in sorted(h2v.items()) ] # converts a sat variable to a tape index self.variable2tape = dict([ (v,h) for h,v in h2v.items() ]) def generate_variable(self): self.maximum_variable += 1 return self.maximum_variable def random_projection(self): self.s.add_xor_clause([v for v in self.variable2tape if random.random() > 0.5 ],random.random() > 0.5) def try_solving(self,assumptions = None): print "About to run solver == == == > " start_time = time.time() if assumptions != None: result = self.s.solve(assumptions) else: result = self.s.solve() dt = (time.time() - start_time) self.tt += dt print "Ran solver in time",dt if result[0]: bindings = {} for v in range(len(result[1])): if v in self.variable2tape: bindings[v] = result[1][v] print "Satisfiable." return bindings else: print "Unsatisfiable." return False def uniqueness_clause(self,tape): p,bit_mask = parse_tape(tape) clause = [] for j in range(len(tape)): if bit_mask[j] == 1: # jth tape position v = self.tape2variable[j] if tape[j] == 1: v = -v clause += [v] return clause def is_solution_unique(self,tape): d = self.generate_variable() clause = [d] + self.uniqueness_clause(tape) print "uniqueness clause",clause self.s.add_clause(clause) result = self.try_solving([-d]) self.s.add_clause([d]) # make the clause documents they satisfied if result: tp = self.holes2tape(result) print "alternative:",parse_tape(tp) print "alternative tape:",tp return False else: return True def holes2tape(self,result): return [ (1 if result[v] else 0) for v in self.tape2variable ] def try_sampling(self,subspace_dimension): for j in range(subspace_dimension): self.random_projection() result = self.try_solving() if result: print "Random projection satisfied" tp = self.holes2tape(result) print parse_tape(tp)[0] if self.is_solution_unique(tp): print "Unique. Accepted." else: print "Sample rejected" def adaptive_sample(self): subspace_dimension = 1 result = self.try_solving() if result: print "Formula satisfied" for j in range(subspace_dimension): self.random_projection() while True: print "\n\niterating:" result = self.try_solving() if result: print "Satisfied %d constraints" % subspace_dimension tp = self.holes2tape(result) print parse_tape(tp) print "tape = ",tp if self.is_solution_unique(tp): print "UNIQUE" print "<<< == == == >>>" self.random_projection() subspace_dimension += 1 else: print "Rejected %d projections" % subspace_dimension print "total time = ",self.tt break def enumerate_solutions(self): solutions = [] result = self.try_solving() d = self.generate_variable() logZ = float('-inf') while result: tp = self.holes2tape(result) program,mask = parse_tape(tp) solutions = solutions + [program] specified = sum(mask) logZ = lse(logZ, -specified * 0.693) print "Enumerated program", program, "with", specified, "specified bits." self.s.add_clause([d] + self.uniqueness_clause(tp)) result = self.try_solving([-d]) print "log(z) = ",logZ, "\t1/p = ", math.exp(-logZ) return solutions
def test_unit2(self) : solver = Solver() solver.add_xor_clause([1], True) res, solution = solver.solve() self.assertEqual(res, True) self.assertEqual(solution, (None, True))
def test_cnf2(self): solver = Solver() for cl in clauses2: solver.add_clause(cl) self.assertEqual(solver.solve(), (False, None))
class TestSolve(unittest.TestCase): def setUp(self): self.solver = Solver(threads=2) def test_wrong_args(self): self.assertRaises(TypeError, self.solver.add_clause, 'A') self.assertRaises(TypeError, self.solver.add_clause, 1) self.assertRaises(TypeError, self.solver.add_clause, 1.0) self.assertRaises(TypeError, self.solver.add_clause, object()) self.assertRaises(TypeError, self.solver.add_clause, ['a']) self.assertRaises(TypeError, self.solver.add_clause, [[1, 2], [3, None]]) self.assertRaises(ValueError, self.solver.add_clause, [1, 0]) def test_no_clauses(self): for _ in range(7): self.assertEqual(self.solver.solve([]), (True, (None, ))) def test_cnf1(self): for cl in clauses1: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses1, solution)) def test_add_clauses(self): self.solver.add_clauses([[1], [-1]]) res, solution = self.solver.solve() self.assertEqual(res, False) def test_add_clauses_wrong_zero(self): self.assertRaises(TypeError, self.solver.add_clause, [[1, 0], [-1]]) def test_add_clauses_array_SAT(self): cls = array('i', [1, 2, 0, 1, 2, 0]) self.solver.add_clauses(cls) res, solution = self.solver.solve() self.assertEqual(res, True) def test_add_clauses_array_UNSAT(self): cls = array('i', [-1, 0, 1, 0]) self.solver.add_clauses(cls) res, solution = self.solver.solve() self.assertEqual(res, False) def test_add_clauses_array_unterminated(self): cls = array('i', [1, 2, 0, 1, 2]) self.assertRaises(ValueError, self.solver.add_clause, cls) def test_bad_iter(self): class Liar: def __iter__(self): return None self.assertRaises(TypeError, self.solver.add_clause, Liar()) def test_get_conflict(self): self.solver.add_clauses([[-1], [2], [3], [-4]]) assume = [-2, 3, 4] res, model = self.solver.solve(assumptions=assume) self.assertEqual(res, False) confl = self.solver.get_conflict() self.assertEqual(isinstance(confl, list), True) self.assertNotIn(3, confl) if 2 in confl: self.assertIn(2, confl) elif -4 in confl: self.assertIn(-4, confl) else: self.assertEqual(False, True, msg="Either -2 or 4 should be conflicting!") assume = [2, 4] res, model = self.solver.solve(assumptions=assume) self.assertEqual(res, False) confl = self.solver.get_conflict() self.assertEqual(isinstance(confl, list), True) self.assertNotIn(2, confl) self.assertIn(-4, confl) def test_cnf2(self): for cl in clauses2: self.solver.add_clause(cl) self.assertEqual(self.solver.solve(), (False, None)) def test_cnf3(self): for cl in clauses3: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses3, solution)) def test_cnf1_confl_limit(self): for _ in range(1, 20): self.setUp() for cl in clauses1: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertTrue(res is None or check_solution(clauses1, solution)) def test_by_re_curse(self): self.solver.add_clause([-1, -2, 3]) res, _ = self.solver.solve() self.assertEqual(res, True) self.solver.add_clause([-5, 1]) self.solver.add_clause([4, -3]) self.solver.add_clause([2, 3, 5]) res, _ = self.solver.solve() self.assertEqual(res, True)
from pycryptosat import Solver s = Solver() s.add_clauses([(1,), (1, -1)]) assert s.is_satisfiable() s.add_clauses([(1,), (-1,)]) assert not s.is_satisfiable()
def setup(self, m, threads=1, **kwargs): from pycryptosat import Solver solver = Solver(threads=threads) solver.add_clauses(self._clauses.as_list()) return solver
class TestXor(unittest.TestCase): def setUp(self): self.solver = Solver(threads=2) def test_wrong_args(self): self.assertRaises(TypeError, self.solver.add_xor_clause, [1, 2]) self.assertRaises(ValueError, self.solver.add_xor_clause, [1, 0], True) self.assertRaises(ValueError, self.solver.add_xor_clause, [-1, 2], True) def test_binary(self): self.solver.add_xor_clause([1, 2], False) res, solution = self.solver.solve([1]) self.assertEqual(res, True) self.assertEqual(solution, (None, True, True)) def test_unit(self): self.solver.add_xor_clause([1], False) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertEqual(solution, (None, False)) def test_unit2(self): self.solver.add_xor_clause([1], True) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertEqual(solution, (None, True)) def test_3_long(self): self.solver.add_xor_clause([1, 2, 3], False) res, solution = self.solver.solve([1, 2]) self.assertEqual(res, True) # self.assertEqual(solution, (None, True, True, False)) def test_3_long2(self): self.solver.add_xor_clause([1, 2, 3], True) res, solution = self.solver.solve([1, -2]) self.assertEqual(res, True) self.assertEqual(solution, (None, True, False, False)) def test_long(self): for l in range(10, 30): self.setUp() toadd = [] toassume = [] solution_expected = [None] for i in range(1, l): toadd.append(i) solution_expected.append(False) if i != l - 1: toassume.append(i * -1) self.solver.add_xor_clause(toadd, False) res, solution = self.solver.solve(toassume) self.assertEqual(res, True) self.assertEqual(solution, tuple(solution_expected))
def experiment_many(k, n, r, times): sat_count = 0 for i in range(times): if experiment_once(Solver(), k, n, r): sat_count += 1 return sat_count
class TestSolve(unittest.TestCase): def setUp(self) : self.solver = Solver(threads = 2) def test_wrong_args(self): self.assertRaises(TypeError, self.solver.add_clause, 'A') self.assertRaises(TypeError, self.solver.add_clause, 1) self.assertRaises(TypeError, self.solver.add_clause, 1.0) self.assertRaises(TypeError, self.solver.add_clause, object()) self.assertRaises(TypeError, self.solver.add_clause, ['a']) self.assertRaises(TypeError, self.solver.add_clause, [[1, 2], [3, None]]) self.assertRaises(ValueError, self.solver.add_clause, [1, 0]) def test_no_clauses(self): for n in range(7): self.assertEqual(self.solver.solve([]), (True, (None,))) def test_cnf1(self): for cl in clauses1: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses1, solution)) def test_bad_iter(self): class Liar: def __iter__(self): return None self.assertRaises(TypeError, self.solver.add_clause, Liar()) def test_cnf2(self): for cl in clauses2: self.solver.add_clause(cl) self.assertEqual(self.solver.solve(), (False, None)) def test_cnf3(self): for cl in clauses3: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses3, solution)) def test_cnf1_confl_limit(self): for lim in range(1, 20): self.setUp() for cl in clauses1: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertTrue(res == None or check_solution(clauses1, solution))
class SatHandler: def __init__(self, tracesList, numOfInputs, usePyCrypto=False): self.numOfInputs = numOfInputs self.tracesList = tracesList self.usePyCrypto = usePyCrypto self.s = None if self.usePyCrypto and PyCryptoSat_Import_Successful: self.s = Solver() print("Initialized solver") self.clauses = ClauseHandler() ## Creates the acyclic Fsm of trace nodes. self.constructTraceTree() # self.traceTree is created and filled self.numOfTraceNodes = len(self.traceTree.nodes) ### #This variable is used as global, handle with care self.numOfNodes = 0 ### def varToNum(self, var): x, s = var.split("_") return int(x) * self.numOfNodes + int(s) + 1 def numToVar(self, num): num -= 1 return "{}_{}".format(int(num / self.numOfNodes), num % self.numOfNodes) def newVarToNum(self, newVar): ## newVar syntax is "y_a_i_j" y, a, i, j = newVar.split("_") a = int(a) # a+1 so that it doesn't clash with normal vars offset = (self.numOfTraceNodes * self.numOfNodes) * (a+1) return offset + self.varToNum(i+"_"+j) def numToNewVar(self, num): offset = self.numOfTraceNodes * self.numOfNodes offsetCount = int(num/offset) a = offsetCount - 1 num = num - offset * offsetCount x, s = self.numToVar(num).split("_") return "y_{}_{}_{}".format(a, x, s) def constructTraceTree(self, nameInBreathFirst = True): self.traceTree = FSM(0, self.numOfInputs, 0) # numOfNodes, numOfInputs, numOfOutputs rootNode = FSM.Node(self.numOfInputs, 0) # 0 is the index self.traceTree.nodes.append(rootNode) currentNode = rootNode temp = None for trace in self.tracesList: currentNode = rootNode #reset this temp = None for ioTuple in trace: # This transition exists if currentNode.transitions[ioTuple[0]][0] != None: currentNode = currentNode.transitions[ioTuple[0]][0] # Keep moving # This transition is new, create new branch else: temp = FSM.Node(self.numOfInputs, len(self.traceTree.nodes)) self.traceTree.nodes.append(temp) currentNode.transitions[ioTuple[0]] = (temp, ioTuple[1]) currentNode = temp ### Name the nodes in a BDF way if the argument is true if nameInBreathFirst: newNodeList = [] nodeQ = deque() nodeQ.append(rootNode) while len(nodeQ) != 0: currentNode = nodeQ.popleft() for transition in currentNode.transitions: if transition[0] != None: transition[0].parent = currentNode nodeQ.append(transition[0]) ## Set the index and append to the list currentNode.index = len(newNodeList) newNodeList.append(currentNode) self.traceTree.nodes = newNodeList def constructClauses(self, writeToFile=False, filename="SatFile", numOfNodes=-1): #This is for debugging if numOfNodes != -1: self.numOfNodes = numOfNodes countClauses = 0 # #Each trace node must correspond to at least one node #Does not the 0_0 condition # for i in range(self.numOfTraceNodes): tempList = [] for k in range(self.numOfNodes): tempList.append("x_{}_{}".format(i, k)) self.clauses.addClause(tempList) countClauses += 1 # #Each trace node must correspond to at most one node # for i in range(self.numOfTraceNodes): for k in range(self.numOfNodes - 1): for j in range(k + 1, self.numOfNodes): self.clauses.addClause(["-x_{}_{}".format(i,k), "-x_{}_{}".format(i,j)]) countClauses += 1 # #Check each transition between tracenodes and act accordingly # for i in range(self.numOfTraceNodes - 1): for j in range(i + 1, self.numOfTraceNodes): for k in range(len(self.traceTree.nodes[i].transitions)): # if outputs are not None if (self.traceTree.nodes[i].transitions[k][1] != None and self.traceTree.nodes[j].transitions[k][1] != None): #if outputs are different if (self.traceTree.nodes[i].transitions[k][1] != self.traceTree.nodes[j].transitions[k][1]): for h in range(self.numOfNodes): self.clauses.addClause(["-x_{}_{}".format(i,h), "-x_{}_{}".format(j,h)]) countClauses += 1 break for x in range(self.numOfTraceNodes): for a in range(len(self.traceTree.nodes[x].transitions)): for i in range(self.numOfNodes): for j in range(self.numOfNodes): if self.traceTree.nodes[x].transitions[a][0] != None: #file.write("y_a_i_j -x_i -x.transitions[a][0]_j") self.clauses.addClause(["y_{}_{}_{}".format(a,i,j), "-x_{}_{}".format(x,i), "-x_{}_{}".format(self.traceTree.nodes[x].transitions[a][0].index, j)]) countClauses += 1 for a in range(len(self.traceTree.nodes[0].transitions)): for i in range(self.numOfNodes): for h in range(self.numOfNodes - 1): for j in range(h + 1, self.numOfNodes): self.clauses.addClause(["-y_{}_{}_{}".format(a,i,h), "-y_{}_{}_{}".format(a,i,j)]) countClauses += 1 for a in range(len(self.traceTree.nodes[0].transitions)): for i in range(self.numOfNodes): tempList = [] for j in range(self.numOfNodes): tempList.append("y_{}_{}_{}".format(a,i,j)) self.clauses.addClause(tempList) countClauses += 1 for x in range(self.numOfTraceNodes): for a in range(len(self.traceTree.nodes[x].transitions)): for i in range(self.numOfNodes): for j in range(self.numOfNodes): if self.traceTree.nodes[x].transitions[a][0] != None: self.clauses.addClause(["-y_{}_{}_{}".format(a,i,j), "-x_{}_{}".format(x,i), "x_{}_{}".format(self.traceTree.nodes[x].transitions[a][0].index, j)]) countClauses += 1 if not self.usePyCrypto: varCount = self.numOfNodes * self.numOfTraceNodes * (len(self.traceTree.nodes[0].transitions) + 1) self.clauses.addFirstLine("p cnf {} {}".format(varCount, countClauses)) self.clauses.writeTheFile() def constructSatFile(self, writeFile=True, filename="SatFile", verbose=True, numOfNodes=-1): #This is for debugging if numOfNodes != -1: self.numOfNodes = numOfNodes file = FileHandler(filename) clauseHandler = ClauseHandler(filename) countClauses = 0 # #Each trace node must correspond to at least one node #Contains the 0_0 condition # if verbose: file.writeComment("##### Each must correspond to at least one node #####") for i in range(self.numOfTraceNodes): tempStr = "" commentStr = "" for k in range(self.numOfNodes): #min(i+1, self.numOfNodes tempStr += "{} ".format(self.varToNum("{}_{}".format(i, k))) commentStr += "{}_{} ".format(i, k) if verbose: file.writeComment(commentStr) file.write(tempStr) countClauses += 1 # #Each trace node must correspond to at most one node # if verbose: file.writeComment("##### Each must correspond to at most one node #####") for i in range(self.numOfTraceNodes): for k in range(self.numOfNodes - 1): for j in range(k + 1, self.numOfNodes): if verbose: file.writeComment("-{}_{} -{}_{}".format(i, k, i, j)) file.write("-{} -{}".format(self.varToNum("{}_{}".format(i, k)), self.varToNum("{}_{}".format(i, j)))) countClauses += 1 # #Check each trasition between tracenodes and act accordingly # for i in range(self.numOfTraceNodes - 1): for j in range(i + 1, self.numOfTraceNodes): for k in range(len(self.traceTree.nodes[i].transitions)): # if outputs are not None if (self.traceTree.nodes[i].transitions[k][1] != None and self.traceTree.nodes[j].transitions[k][1] != None): #if outputs are different if (self.traceTree.nodes[i].transitions[k][1] != self.traceTree.nodes[j].transitions[k][1]): for h in range(self.numOfNodes): if verbose: file.writeComment("-{}_{} -{}_{}".format(i, h, j, h)) file.write("-{} -{}".format(self.varToNum("{}_{}".format(i, h)), self.varToNum("{}_{}".format(j, h)))) countClauses += 1 break #if outputs are same """ # The Auxiliary variables will replace these else: iP = self.traceTree.nodes[i].transitions[k][0].index jP = self.traceTree.nodes[j].transitions[k][0].index for h in range(self.numOfNodes): for hP in range(self.numOfNodes): if verbose: file.writeComment("-{}_{} -{}_{} -{}_{} {}_{}".format(i, h, j, h, iP, hP, jP, hP)) file.write("-{} -{} -{} {}".format(self.varToNum("{}_{}".format(i, h)),\ self.varToNum("{}_{}".format(j, h)),\ self.varToNum("{}_{}".format(iP, hP)),\ self.varToNum("{}_{}".format(jP, hP)))) countClauses += 1 """ for x in range(self.numOfTraceNodes): for a in range(len(self.traceTree.nodes[x].transitions)): for i in range(self.numOfNodes): for j in range(self.numOfNodes): if self.traceTree.nodes[x].transitions[a][0] != None: #file.write("y_a_i_j -x_i -x.transitions[a][0]_j") file.writeComment("y_{}_{}_{} -{}_{} -{}_{}".format(a, i, j, \ x, i, \ self.traceTree.nodes[x].transitions[a][0].index, j)) file.write("{} -{} -{}".format(self.newVarToNum("y_{}_{}_{}".format(a, i, j)), \ self.varToNum("{}_{}".format(x, i)), \ self.varToNum("{}_{}".format(self.traceTree.nodes[x].transitions[a][0].index, j)))) countClauses += 1 for a in range(len(self.traceTree.nodes[0].transitions)): for i in range(self.numOfNodes): for h in range(self.numOfNodes - 1): for j in range(h + 1, self.numOfNodes): file.writeComment("-y_{}_{}_{} -y_{}_{}_{}".format(a,i,h,\ a,i,j)) file.write("-{} -{}".format(self.newVarToNum("-y_{}_{}_{}".format(a,i,h)), \ self.newVarToNum("-y_{}_{}_{}".format(a,i,j)))) countClauses += 1 for a in range(len(self.traceTree.nodes[0].transitions)): for i in range(self.numOfNodes): tempStr = "" commentStr = "" for j in range(self.numOfNodes): commentStr += "y_{}_{}_{} ".format(a, i, j) tempStr += "{} ".format(self.newVarToNum("y_{}_{}_{}".format(a, i, j))) file.writeComment(commentStr) file.write(tempStr) countClauses += 1 for x in range(self.numOfTraceNodes): for a in range(len(self.traceTree.nodes[x].transitions)): for i in range(self.numOfNodes): for j in range(self.numOfNodes): if self.traceTree.nodes[x].transitions[a][0] != None: #file.write("y_a_i_j -x_i -x.transitions[a][0]_j") file.writeComment("-y_{}_{}_{} -{}_{} {}_{}".format(a, i, j, \ x, i, \ self.traceTree.nodes[x].transitions[a][0].index, j)) file.write("-{} -{} {}".format(self.newVarToNum("y_{}_{}_{}".format(a, i, j)), \ self.varToNum("{}_{}".format(x, i)), \ self.varToNum("{}_{}".format(self.traceTree.nodes[x].transitions[a][0].index, j)))) countClauses += 1 varCount = self.numOfNodes * self.numOfTraceNodes * (len(self.traceTree.nodes[0].transitions) + 1) file.addFirstLine("p cnf {} {}".format(varCount, countClauses)) file.writeTheFile() def checkOutput(self, filename="satOutput", onlyCheck=False): with open(filename, "r") as f: #if the output has no solution, dont continue if f.readline().strip() != "s SATISFIABLE": return (False, None) #if the output has a solution BUT the onlyCheck parameter is true, dont read the output elif onlyCheck: return (True, None) output = [] for line in f.readlines(): for var in line.split()[1:]: if var[0] != "-" and var != "0": output.append(self.numToVar(int(var))) return (True, output) def addFormulasForSingleVariable(self, traceNo=0, numOfNodes=-1): if numOfNodes == -1: self.numOfNodes = numOfNodes if traceNo == 0: print("addFormulasForSingleVariable -> You should gice the traceNo to use this function!") return #This trace must be at least one of the nodes tempList = [] for k in range(self.numOfNodes): tempList.append("x_{}_{}".format(traceNo, k)) self.clauses.addClause(tempList) for k in range(self.numOfNodes - 1): for j in range(k + 1, self.numOfNodes): self.clauses.addClause(["-x_{}_{}".format(traceNo,k), "-x_{}_{}".format(traceNo,j)]) countClauses += 1 for j in range(traceNo): for k in range(len(self.traceTree.nodes[traceNo].transitions)): # if outputs are not None if (self.traceTree.nodes[traceNo].transitions[k][1] != None and self.traceTree.nodes[j].transitions[k][1] != None): #if outputs are different if (self.traceTree.nodes[traceNo].transitions[k][1] != self.traceTree.nodes[j].transitions[k][1]): for h in range(self.numOfNodes): self.clauses.addClause(["-x_{}_{}".format(traceNo,h), "-x_{}_{}".format(j,h)]) countClauses += 1 break for a in range(len(self.traceTree.nodes[traceNo].transitions)): for i in range(self.numOfNodes): for j in range(self.numOfNodes): if self.traceTree.nodes[traceNo].transitions[a][0] != None: #file.write("y_a_i_j -x_i -x.transitions[a][0]_j") self.clauses.addClause(["y_{}_{}_{}".format(a,i,j), "-x_{}_{}".format(traceNo,i), "-x_{}_{}".format(self.traceTree.nodes[traceNo].transitions[a][0].index, j)]) countClauses += 1 #Auxiliary for this for a in range(len(self.traceTree.nodes[traceNo].transitions)): for i in range(self.numOfNodes): for j in range(self.numOfNodes): if self.traceTree.nodes[traceNo].transitions[a][0] != None: self.clauses.addClause(["-y_{}_{}_{}".format(a,i,j), "-x_{}_{}".format(traceNo,i), "x_{}_{}".format(self.traceTree.nodes[traceNo].transitions[a][0].index, j)]) countClauses += 1 def oldfindFsmConsecutive(self, filename="SatFile", outputFile="satOutput"): self.numOfNodes = 1 FOUND = False startTime = time.time() totalSolveTime = 0 totalFileTime = 0 while not FOUND: print("Trying with", self.numOfNodes, "nodes...") if self.usePyCrypto: self.s = Solver() #Reinitialize sTime = time.time() self.constructClauses() self.clauses.addToSolver(self.s) endTime = time.time()-sTime totalFileTime += endTime print("Sat preperations took", endTime, "seconds") sTime = time.time() isSatisfiable, output = self.s.solve() solveEnd = time.time()-sTime totalSolveTime += solveEnd print("Solving took", solveEnd, "seconds") else: sFileTime = time.time() self.constructClauses() fileEnd = time.time()-sFileTime totalFileTime += fileEnd print("Sat file construction took", fileEnd, "seconds") solveTime = time.time() subprocess.run("cryptominisat5 --verb 0 {} > {}".format(filename, outputFile), shell=True) solveEnd = time.time()-solveTime totalSolveTime += solveEnd print("Solving took", solveEnd, "seconds") isSatisfiable, output = self.checkOutput() if isSatisfiable: print("Satisfiable with", self.numOfNodes, "nodes!") print("Total construction time:", totalFileTime, "seconds") print("Total solving time:", totalSolveTime, "seconds") print("\nConsecutive approach took", time.time()-startTime, "seconds.") print() FOUND = True self.numOfNodes += 1 return output def getFsmFromSolution(self, output): switchValueKey = {} for key, value in self.clauses.clausedict.items(): if key[0] == "x": switchValueKey[value] = key[2:] #init the fsm traceFsm = FSM(self.numOfNodes, self.numOfInputs, 0) traceToNode = {} for i in range(1, len(output)): if output[i]: # only check true ones ## continu here def findFsmConsecutive(self, filename="SatFile", outputFile="satOutput"): self.numOfNodes = 7 FOUND = False startTime = time.time() totalSolveTime = 0 totalFileTime = 0 while not FOUND: def findFsmBinary(self, filename="SatFile", outputFile="satOutput"): minNumOfNodes = 0 maxNumOfNodes = -1 self.numOfNodes = 1 lastOutput = None FOUND = False startTime = time.time() while not FOUND: if maxNumOfNodes == -1: self.numOfNodes *= 2 else: self.numOfNodes = int((minNumOfNodes + maxNumOfNodes)/2) print("Trying with", self.numOfNodes, "nodes...") self.constructSatFile() subprocess.run("cryptominisat5 --verb 0 {} > {}".format(filename, outputFile), shell=True) isSatisfiable, output = self.checkOutput() if isSatisfiable: print("Satisfiable with", self.numOfNodes, "nodes!") lastOutput = output maxNumOfNodes = self.numOfNodes else: print("Not satisfiable with", self.numOfNodes, "nodes.") minNumOfNodes = self.numOfNodes if minNumOfNodes == maxNumOfNodes - 1: print("Merged at", self.numOfNodes, "nodes!") print("\nBinary approach took", time.time()-startTime, "seconds.") FOUND = True return lastOutput def findFsm(self, tryBinarySearch=False, filename="SatFile", outputFile="satOutput"): if tryBinarySearch: return self.findFsmBinary(filename, outputFile) else: return self.findFsmConsecutive(filename, outputFile)
def setUp(self) : self.solver = Solver(threads = 2);
class TestSolve(unittest.TestCase): def setUp(self): self.solver = Solver(threads=2) def test_wrong_args(self): self.assertRaises(TypeError, self.solver.add_clause, 'A') self.assertRaises(TypeError, self.solver.add_clause, 1) self.assertRaises(TypeError, self.solver.add_clause, 1.0) self.assertRaises(TypeError, self.solver.add_clause, object()) self.assertRaises(TypeError, self.solver.add_clause, ['a']) self.assertRaises( TypeError, self.solver.add_clause, [[1, 2], [3, None]]) self.assertRaises(ValueError, self.solver.add_clause, [1, 0]) def test_no_clauses(self): for _ in range(7): self.assertEqual(self.solver.solve([]), (True, (None,))) def test_cnf1(self): for cl in clauses1: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses1, solution)) def test_add_clauses(self): self.solver.add_clauses([[1], [-1]]) res, solution = self.solver.solve() self.assertEqual(res, False) def test_add_clauses_wrong_zero(self): self.assertRaises(TypeError, self.solver.add_clause, [[1, 0], [-1]]) def test_add_clauses_array_SAT(self): cls = array('i', [1, 2, 0, 1, 2, 0]) self.solver.add_clauses(cls) res, solution = self.solver.solve() self.assertEqual(res, True) def test_add_clauses_array_UNSAT(self): cls = array('i', [-1, 0, 1, 0]) self.solver.add_clauses(cls) res, solution = self.solver.solve() self.assertEqual(res, False) def test_add_clauses_array_unterminated(self): cls = array('i', [1, 2, 0, 1, 2]) self.assertRaises(ValueError, self.solver.add_clause, cls) def test_bad_iter(self): class Liar: def __iter__(self): return None self.assertRaises(TypeError, self.solver.add_clause, Liar()) def test_get_conflict(self): self.solver.add_clauses([[-1], [2], [3], [-4]]) assume = [-2, 3, 4] res, model = self.solver.solve(assumptions=assume) self.assertEqual(res, False) confl = self.solver.get_conflict() self.assertEqual(isinstance(confl, list), True) self.assertNotIn(3, confl) if 2 in confl: self.assertIn(2, confl) elif -4 in confl: self.assertIn(-4, confl) else: self.assertEqual(False, True, msg="Either -2 or 4 should be conflicting!") assume = [2, 4] res, model = self.solver.solve(assumptions=assume) self.assertEqual(res, False) confl = self.solver.get_conflict() self.assertEqual(isinstance(confl, list), True) self.assertNotIn(2, confl) self.assertIn(-4, confl) def test_cnf2(self): for cl in clauses2: self.solver.add_clause(cl) self.assertEqual(self.solver.solve(), (False, None)) def test_cnf3(self): for cl in clauses3: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertEqual(res, True) self.assertTrue(check_solution(clauses3, solution)) def test_cnf1_confl_limit(self): for _ in range(1, 20): self.setUp() for cl in clauses1: self.solver.add_clause(cl) res, solution = self.solver.solve() self.assertTrue(res is None or check_solution(clauses1, solution)) def test_by_re_curse(self): self.solver.add_clause([-1, -2, 3]) res, _ = self.solver.solve() self.assertEqual(res, True) self.solver.add_clause([-5, 1]) self.solver.add_clause([4, -3]) self.solver.add_clause([2, 3, 5]) res, _ = self.solver.solve() self.assertEqual(res, True)
def test_no_clauses(self): solver = Solver() for n in range(7): self.assertEqual(solver.solve([]), (True, (None,)))
class ProgramSolver(): def __init__(self, filename): self.s = Solver(threads=3) self.tt = 0 h2v = {} # hole 2 variable self.maximum_variable = -1 with open(filename, 'r') as f: for l in f: if len(l) > len('c hole ') and l[:len('c hole ')] == 'c hole ': ms = re.findall(r'(\d+) \- (\d+)', l)[0] assert int(ms[0]) == int(ms[1]) ms = int(ms[0]) n = int(re.findall(r'H__\S+_(\S+)\s', l)[0]) h2v[n] = ms elif len(l) > 0 and not 'c' in l and not 'p' in l: vs = re.findall(r'(\-?\d+)', l) assert vs[-1] == '0' clause = [int(v) for v in vs[:-1]] self.maximum_variable = max([self.maximum_variable] + [abs(v) for v in clause]) self.s.add_clause(clause) print "Loaded", filename, " with", len(h2v), "holes" # convert the tape index into a sat variable self.tape2variable = [v for h, v in sorted(h2v.items())] # converts a sat variable to a tape index self.variable2tape = dict([(v, h) for h, v in h2v.items()]) def generate_variable(self): self.maximum_variable += 1 return self.maximum_variable def random_projection(self): self.s.add_xor_clause( [v for v in self.variable2tape if random.random() > 0.5], random.random() > 0.5) def try_solving(self, assumptions=None): print "About to run solver == == == > " start_time = time.time() if assumptions != None: result = self.s.solve(assumptions) else: result = self.s.solve() dt = (time.time() - start_time) self.tt += dt print "Ran solver in time", dt if result[0]: bindings = {} for v in range(len(result[1])): if v in self.variable2tape: bindings[v] = result[1][v] print "Satisfiable." return bindings else: print "Unsatisfiable." return False def uniqueness_clause(self, tape): p, bit_mask = parse_tape(tape) clause = [] for j in range(len(tape)): if bit_mask[j] == 1: # jth tape position v = self.tape2variable[j] if tape[j] == 1: v = -v clause += [v] return clause def is_solution_unique(self, tape): d = self.generate_variable() clause = [d] + self.uniqueness_clause(tape) print "uniqueness clause", clause self.s.add_clause(clause) result = self.try_solving([-d]) self.s.add_clause([d]) # make the clause documents they satisfied if result: tp = self.holes2tape(result) print "alternative:", parse_tape(tp) print "alternative tape:", tp return False else: return True def holes2tape(self, result): return [(1 if result[v] else 0) for v in self.tape2variable] def try_sampling(self, subspace_dimension): for j in range(subspace_dimension): self.random_projection() result = self.try_solving() if result: print "Random projection satisfied" tp = self.holes2tape(result) print parse_tape(tp)[0] if self.is_solution_unique(tp): print "Unique. Accepted." else: print "Sample rejected" def adaptive_sample(self): subspace_dimension = 1 result = self.try_solving() if result: print "Formula satisfied" for j in range(subspace_dimension): self.random_projection() while True: print "\n\niterating:" result = self.try_solving() if result: print "Satisfied %d constraints" % subspace_dimension tp = self.holes2tape(result) print parse_tape(tp) print "tape = ", tp if self.is_solution_unique(tp): print "UNIQUE" print "<<< == == == >>>" self.random_projection() subspace_dimension += 1 else: print "Rejected %d projections" % subspace_dimension print "total time = ", self.tt break def enumerate_solutions(self): solutions = [] result = self.try_solving() d = self.generate_variable() logZ = float('-inf') while result: tp = self.holes2tape(result) program, mask = parse_tape(tp) solutions = solutions + [program] specified = sum(mask) logZ = lse(logZ, -specified * 0.693) print "Enumerated program", program, "with", specified, "specified bits." self.s.add_clause([d] + self.uniqueness_clause(tp)) result = self.try_solving([-d]) print "log(z) = ", logZ, "\t1/p = ", math.exp(-logZ) return solutions