def solve(problem: List[str]) -> int: X = [[z3.Int(f"x{i}{j}") for j in range(9)] for i in range(9)] solver = z3.Solver() for i in range(9): for j in range(9): solver.add(1 <= X[i][j], X[i][j] <= 9) for i in range(9): solver.add(z3.Distinct(X[i])) for j in range(9): solver.add(z3.Distinct([X[i][j] for i in range(9)])) for i in range(0, 9, 3): for j in range(0, 9, 3): solver.add(z3.Distinct( [X[i + d // 3][j + d % 3] for d in range(9)])) for i in range(9): for j in range(9): if problem[i+1][j] != '0': solver.add(X[i][j] == ord(problem[i+1][j]) - ord('0')) if solver.check() != z3.sat: print(f"{problem[0]} unsat") return 0 return solver.model().evaluate(X[0][0] * 100 + X[0][1] * 10 + X[0][2]).as_long()
def classic_constraints(s, cells): """Adds the classic sudoku constraints to a z3 solver. Args: s: z3.Solver instance. cells: a 9x9 list of lists, where each element is a z3.Int instance. """ # All values must be 1 <= x <= 9. for r in rows(): for c in cols(): v = cells[r][c] s.add(v >= 1) s.add(v <= 9) # All cells on the same row must be distinct. for r in rows(): s.add(z3.Distinct(cells[r])) # All cells on the same column must be distinct. for c in cols(): col = [cells[r][c] for r in rows()] s.add(z3.Distinct(col)) # All cells in a 3x3 matrix must be distinct. offsets = list(itertools.product(range(0, 3), range(0, 3))) for r in range(0, 9, 3): for c in range(0, 9, 3): group_cells = [] for dy, dx in offsets: group_cells.append(cells[r + dy][c + dx]) s.add(z3.Distinct(group_cells))
def visitCompare(self, node): children = node.getChildren() if len(children) == 3: left = node.getChildren()[0] op = str(node.getChildren()[1]) if op == "==" or op == "!=": right = node.getChildren()[2] left_z3 = self.visit(left) right_z3 = self.visit(right) if z3.is_string(left_z3) and z3.is_string( right_z3) or z3.is_bool(left_z3) and z3.is_bool( right_z3): if op == "==": result = z3.simplify( z3.Not(z3.Distinct(left_z3, right_z3))) return result elif op == "!=": # sys.stderr.write("%s != %s\n" % (left_z3, right_z3)) result = z3.simplify(z3.Distinct(left_z3, right_z3)) return result # elif z3.is_string(left_z3) and z3.is_bool(right_z3): # if op == "==": # pass # elif op == "!=": # pass # elif z3.is_bool(left_z3) and z3.is_string(right_z3): # if op == "==": # pass # elif op == "!=": # pass # this expression is not supported, so make a predicate variable for it predicate = str(node) return z3.Bool("PREDICATE_%s" % (predicate))
def get_diag_constraint(n, queens_x, queens_y): queens = list(zip(queens_x, queens_y)) main_diag_distances = [q[0] - q[1] for q in queens] main_diag_constraint = z3.Distinct(main_diag_distances) second_diag_distances = [(n - q[0]) - q[1] for q in queens] second_diag_constraint = z3.Distinct(second_diag_distances) constraint = z3.And(main_diag_constraint, second_diag_constraint) return constraint
def unique_rowcols(m): '''Returns uniqueness constraints on each row and column of m. m can be a Z3Matrix or a numpy array of variables. ''' if isinstance(m, Z3Matrix): m = m.M h, w = m.shape for r in range(h): yield z3.Distinct(*m[r, :]) for c in range(w): yield z3.Distinct(*m[:, c])
def puzzle_2(all_ingredients, all_allergens, inert_ingredients): possible_ingredients = list( set(all_ingredients.keys()) - inert_ingredients) possible_allergens = list(set(all_allergens.keys())) solver = z3.Solver() assignments = z3.IntVector('allergen', len(possible_allergens)) for assignment in assignments: solver.add(0 <= assignment) solver.add(assignment < len(possible_allergens)) solver.add(z3.Distinct(assignments)) for ai, allergen in enumerate(possible_allergens): conditions = [] for ii, ingredient in enumerate(possible_ingredients): if all_ingredients[ingredient] >= all_allergens[allergen]: conditions.append(assignments[ii] == ai) solver.add(z3.Or(conditions)) solver.check() model = solver.model() matches = [] for ii, _ in enumerate(assignments): matches.append( (possible_allergens[model.evaluate(assignments[ii]).as_long()], possible_ingredients[ii])) matches.sort() return (','.join(match[1] for match in matches))
def test_eight_queens(self): # See https://ericpony.github.io/z3py-tutorial/guide-examples.htm def test_fn(queens): diagonals = [] for i in range(8): for j in range(i): result = None if i == j: result = True else: result = queens[i] - queens[j] != i - j and queens[ i] - queens[j] != j - 1 diagonals.append(result) return diagonals queens = [z3.Int('queens_%i' % (i + 1)) for i in range(8)] ranks = [z3.And(1 <= queens[i], queens[i] <= 8) for i in range(8)] files = [z3.Distinct(queens)] converted_fn = conversion.convert( test_fn, z3py, [logical_ops, variables, control_flow]) diagonals = converted_fn(queens) self.assertTrue(can_solve(ranks + files + diagonals))
def _synthesize(self, m): cm = self.cond.synthesize(m) tm = self.exptrue.synthesize(m) fm = self.expfalse.synthesize(m) cm.clearCache() cz3 = cm.toZ3() S = z3.Solver() S.add(cz3) if S.check() == z3.unsat: fm.clearCache() return fm S = z3.Solver() S.add(z3.Not(cz3)) if S.check() == z3.unsat: tm.clearCache() return tm S = z3.Solver() tm.clearCache() fm.clearCache() tz3 = tm.toZ3() fz3 = fm.toZ3() S.add(z3.Distinct(tz3, fz3)) if S.check() == z3.unsat: tm.clearCache() return tm obj_ = If(cm, tm, fm) return obj_
def _convert_expr(e, variables_dict): if isinstance(e, (bool, int)): return e if not isinstance(e, Expr): raise TypeError() if isinstance(e, (BoolVar, IntVar)): return variables_dict[e.id] else: operands = list( map(lambda x: _convert_expr(x, variables_dict), e.operands)) if e.op == Op.NEG: return -operands[0] elif e.op == Op.ADD: ret = operands[0] for i in range(1, len(operands)): ret = ret + operands[i] return ret elif e.op == Op.SUB: ret = operands[0] for i in range(1, len(operands)): ret = ret - operands[i] return ret elif e.op == Op.MUL: ret = operands[0] for i in range(1, len(operands)): ret = ret * operands[i] return ret elif e.op == Op.MOD: ret = operands[0] for i in range(1, len(operands)): ret = ret % operands[i] return ret elif e.op == Op.EQ: return operands[0] == operands[1] elif e.op == Op.NE: return operands[0] != operands[1] elif e.op == Op.LE: return operands[0] <= operands[1] elif e.op == Op.LT: return operands[0] < operands[1] elif e.op == Op.GE: return operands[0] >= operands[1] elif e.op == Op.GT: return operands[0] > operands[1] elif e.op == Op.NOT: return z3.Not(operands[0]) elif e.op == Op.AND: return z3.And(operands) elif e.op == Op.OR: return z3.Or(operands) elif e.op == Op.XOR: return z3.Xor(operands[0], operands[1]) elif e.op == Op.IFF: return operands[0] == operands[1] elif e.op == Op.IMP: return z3.Or(z3.Not(operands[0]), operands[1]) elif e.op == Op.IF: return z3.If(operands[0], operands[1], operands[2]) elif e.op == Op.ALLDIFF: return z3.Distinct(operands)
def to_z3(self): z3_constraints = [] for predicate_name in self.program.get_idb_predicate_names(): self.reset_fresh_vars() predicate = self.get_predicate(predicate_name, self.unroll_limit) z3_head_vars = [] for var_id in range(predicate.arity()): z3_fresh_var = self.get_fresh_var(predicate.domain(var_id)) z3_head_vars.append(z3_fresh_var) (z3_body_free_vars, z3_body_constraint) = self.pred_to_z3(predicate_name, self.unroll_limit, z3_head_vars) if DISTINCT_CONSTRAINT: vertex_variables = [ var for var in z3_head_vars + z3_body_free_vars if var.sort() == VERTEX ] if vertex_variables: z3_body_constraint = z3.And(z3.Distinct(vertex_variables), z3_body_constraint) z3_constraint = z3.ForAll( z3_head_vars, predicate(z3_head_vars) == ( z3_body_constraint if len(z3_body_free_vars) == 0 else z3.Exists(z3_body_free_vars, z3_body_constraint))) z3_constraints.append(z3_constraint) return z3_constraints
def solve(mask, compromise): shiftlen = 64 - popcount(mask) - compromise bb = z3.BitVec("bb", 64) masked_bb = [z3.BitVec(f"masked_bb_{i}", 64) for i in range(2 ** popcount(mask))] magic_number = z3.BitVec("magic_number", 64) imul_tmp = [z3.BitVec(f"imul_tmp_{i}", 64) for i in range(2 ** popcount(mask))] result_index_short = [z3.BitVec(f"result_index_{i}", popcount(mask) + compromise) for i in range(2 ** popcount(mask))] s = z3.Solver() for i in range(2 ** popcount(mask)): s.add(masked_bb[i] == pdep(i, mask)) s.add(imul_tmp[i] == masked_bb[i] * magic_number) s.add(result_index_short[i] == z3.Extract(63, 63 - popcount(mask) - compromise + 1, imul_tmp[i])) s.add(z3.Distinct(result_index_short)) # for i in range(2 ** popcount(mask)): # for j in range(i + 1, 2 ** popcount(mask)): # s.add(result_index_short[i] != result_index_short[j]) s.add(magic_number >= 1) time_start = time.time() result = s.check() time_end = time.time() print(f"mask = {hex64(mask)}") print(f"compromise = {compromise}") print(f"result = {result}") print(f"elapsed time = {int(time_end - time_start)} second") if result == z3.unsat: return False print(f"magic_number = {hex64(s.model()[magic_number].as_long())}") return True
def solve(s1, s2, s3): global vars vars = dict() s = set() X1 = sep(s, s1) X2 = sep(s, s2) X3 = sep(s, s3) X = [z3.Int('%s' % i) for i in s] solver = z3.Solver() for i in X: solver.add(i >= 0, i <= 9) t1 = z3.Int('t1') t1 = 0 t2 = z3.Int('t2') t2 = 0 t3 = z3.Int('t3') t3 = 0 t1 = Ath(t1, X1) t2 = Ath(t2, X2) t3 = Ath(t3, X3) solver.add(t1 + t2 == t3) solver.add(z3.Distinct(X)) res = solver.check() if res == z3.sat: m = solver.model() return (Num(m, X1), Num(m, X2), Num(m, X3)) elif res == z3.unsat: print 'unsat' else: print 'unknown'
def solve_z3py(sudoku_problem: str, known_answer=None): # http://ericpony.github.io/z3py-tutorial/guide-examples.htm s = z3.Solver() # ソルバーに与える変数を用意する。9*9個の整数であり、特定の座標に入る数字を意味する。 vals = [[z3.Int(f"val({y},{x})") for y in range(9)] for x in range(9)] # 入る数字は1以上9以下であるという制約。 s.add([z3.And(1 <= vals[y][x], vals[y][x] <= 9) for y in range(9) for x in range(9)]) # 各々の行には各々の数字がちょうど一つだけ入るという制約。 s.add([z3.Distinct(vals[y]) for y in range(9)]) # 各々の列には各々の数字がちょうど一つだけ入るという制約。 s.add([z3.Distinct([vals[y][x] for y in range(9)]) for x in range(9)]) # 各々の枠(3*3に区切られた領域)には各々の数字がちょうど一つだけ入るという制約。 s.add([z3.Distinct([vals[y+i][x+j] for i in range(3) for j in range(3)]) for y in range(0,9,3) for x in range(0,9,3)]) # 問題文で与えられたヒント(最初から埋まっている数字)も制約として与える。 for y in range(9): for x in range(9): if sudoku_problem[y*9+x] != ".": n = int(sudoku_problem[y*9+x]) s.add(vals[y][x] == n) # 第2引数で既知の解が与えられている場合、それ以外の解を探索したい。 # そのため、「既知の解と完全一致してはいけない」という制約を与える。 if known_answer is not None: if re.fullmatch(r"[1-9]{81}", known_answer) is None: raise ValueError("error: known_answer is invalid format.") s.add(z3.Not(z3.And([vals[y][x] == int(known_answer[y*9+x]) for y in range(9) for x in range(9)]))) # 充足可能か調べる。充足可能ならば、答えを得てstrにまとめて返す。 if s.check() == z3.sat: m = s.model() sudoku_answer_list = list(sudoku_problem) for y in range(9): for x in range(9): sudoku_answer_list[y*9+x] = m.evaluate(vals[y][x]).as_string() if sudoku_problem[y*9+x] != ".": assert sudoku_answer_list[y*9+x] == sudoku_problem[y*9+x] return "".join(sudoku_answer_list) #充足不可能だったので問題文をそのまま返す。 return sudoku_problem
def add_killer_cage(s, cage_coords, cage_sum): '''Add a single killer sudoku cage. Takes a list of (row, col) coordinates and the sum ''' cagecells = [X[i][j] for i, j in cage_coords] # Digits dont repeat within cages s.add(z3.Distinct(cagecells)) s.add(z3.Sum(cagecells) == cage_sum)
def add_cage_constraints(self, cage): cage_sum = int(cage[:2]) cage_vars = [] for r, c in zip(cage[2::2], cage[3::2]): cage_vars.append(self._grid[int(r) - 1][int(c) - 1]) self._solver.add(z3.Distinct(cage_vars)) self._solver.add(z3.Sum(cage_vars) == cage_sum)
def constraints(self): yield from super().constraints() for _, subgrid in iter_blocks(self.M, self.shape.sqrt()): yield z3.Distinct(*subgrid.flat) if self.clues is not None: for p, v in index(self.clues): if v is not None: yield self.M[p] == v
def make_sbox(s, vecs): upper_half, lower_half = vecs #rows and columns for i in range(MAXVAL): #upper s.add(z3.Distinct(*(upper_half(i, j) for j in range(MAXVAL)))) s.add(z3.Distinct(*(upper_half(j, i) for j in range(MAXVAL)))) #lower s.add(z3.Distinct(*(lower_half(i, j) for j in range(MAXVAL)))) s.add(z3.Distinct(*(lower_half(j, i) for j in range(MAXVAL)))) #distinct link s.add(z3.Distinct(*(lower_half(j,upper_half(i,j)) \ for j in range(MAXVAL)))) #get model if s.check() == z3.unsat: print z3.unsat exit() m = s.model() #fix upper_half resolved_upper = [[m.eval(upper_half(i,j)).as_long() \ for j in range(MAXVAL)] for i in range(MAXVAL)] fixed_upper = [[0 for _ in range(MAXVAL)] for _ in range(MAXVAL)] for i in range(MAXVAL): for j in range(MAXVAL): fixed_upper[j][resolved_upper[i][j]] = i #reassemble flat = (z3.Concat(z3.BitVecVal(fixed_upper[i][j],MAXBITS), lower_half(i,j)) \ for j in range(MAXVAL) for i in range(MAXVAL)) sbox = [m.eval(x, model_completion=True).as_long() for x in flat] #print sbox def lb642sb64(x): x = int(''.join(map(lambda x: bin(x)[2:].zfill(MAXBITS * 2), x)), 2) x = hex(x)[2:].replace('L', '') return x.zfill( (len(x) + 1) // 2 * 2).decode('hex').encode('base64').strip() b64_sbox = lb642sb64(sbox) print b64_sbox fmt_sbox = map(fmt, sbox) for row in grouper(fmt_sbox, MAXVAL): print row with open('/tmp/save.txt', 'w') as f: f.write(''.join(b64_sbox)) return sbox
def place_constraints_2d(comps, fab_dims, wire_lengths, pack=True): ''' place_constraints :: {Component} -> (int, int) -> [int] -> Bool? -> z3.z3.BoolRef ''' nnode = len(comps) frows, fcols = fab_dims constraints = [] if pack: def _get_x(bv): return z3.Extract(frows + fcols - 1, frows, bv) def _get_y(bv): return z3.Extract(frows - 1, 0, bv) for comp in comps: comp.pos = z3.BitVec(comp.name, frows + fcols) constraints.append( z3.simplify(z3.Distinct(*(c.pos for c in comps)), ':blast-distinct', True)) else: def _get_x(bv): return bv[0] def _get_y(bv): return bv[1] for comp in comps: comp.pos = (z3.BitVec(comp.name + '_x', frows), z3.BitVec(comp.name + '_y', fcols)) constraints.append( z3.simplify( z3.Distinct(*(z3.Concat(c.pos[0], c.pos[1]) for c in comps)), ':blast-distinct', True)) for comp in comps: constraints.append(zu.hamming(_get_x(comp.pos)) == __COMP_X) constraints.append(zu.hamming(_get_y(comp.pos)) == __COMP_Y) return z3.And(constraints)
def solve(self): self.cells = [ [self.cell_var(self.data[j][i], i, j) for i in range(6)] for j in range(6)] for i in range(6): self.solver.add(z3.Distinct(self.cells[i])) for j in range(6): self.solver.add(z3.Distinct([row[j] for row in self.cells])) for i in [0,2,4]: for j in [0,3]: self.solver.add(z3.Distinct([c for row in self.cells[i:i+2] for c in row[j:j+3]])) if self.solver.check() == z3.sat: self.model = self.solver.model() self.print_answer() else: print("failed to solve")
def add_classic_constraints(self): # Digits from 1-9 for r in range(9): for c in range(9): v = self._grid[r][c] self._solver.add(v >= 1) self._solver.add(v <= 9) # Distinct digits in row/column for i in range(9): self._solver.add(z3.Distinct(self._grid[i])) # Row self._solver.add(z3.Distinct([self._grid[r][i] for r in range(9)])) # Column # Distinct digits in boxes offset = list(itertools.product(range(0, 3), range(0, 3))) for r in range(0, 9, 3): for c in range(0, 9, 3): box = [self._grid[r + dy][c + dx] for dy, dx in offset] self._solver.add(z3.Distinct(box))
def setup_line(self, x0, y0, dx, dy, sum): if sum == 0: return vs = [] x, y = x0 + dx, y0 + dy while (x, y) in self.cells: vs.append(self.cells[x, y]) x += dx y += dy self.solver.add(z3.Distinct(vs)) self.solver.add(z3.Sum(vs) == sum)
def solve_board(B, max_sols): """Finds all solutions for a given sudoku board.""" sz = int(len(B)**.5) box = int(sz**.5) # initialize z3 objects X = [z3.Int('x%s%s' % (1 + (i % sz), 1 + (i // sz))) for i in range(sz**2)] s = z3.Solver() # load in the unsolved board to z3 for i in range(len(B)): if B[i] == 0: s.add(z3.And(0 < X[i], X[i] <= sz)) else: s.add(X[i] == B[i]) # horizontal and vertical constraints s.add([z3.Distinct([X[j + sz * i] for i in range(sz)]) for j in range(sz)]) s.add([z3.Distinct([X[i + sz * j] for i in range(sz)]) for j in range(sz)]) # box constraints for b in range(sz): box_ind = [] for i in range(box): ind = box * (1 + (b % box)) + box * sz * (b // box) box_ind += [x + i * sz for x in range(ind - box, ind)] s.add(z3.Distinct([X[i] for i in box_ind])) num_sols = 0 Sols = [] # build that board while s.check() == z3.sat: num_sols += 1 m = s.model() s.add(z3.Or([i != m[i] for i in X])) Sols.append([m[x].as_long() for x in X]) if max_sols and num_sols >= max_sols: break return Sols, num_sols
def _set_restriction(self): N = Z3Solver.GRID_SIZE B = Z3Solver.GRID_SIZE // Z3Solver.SUB_GRID_SIZE SUB_GRID_SIZE = Z3Solver.SUB_GRID_SIZE self.add(*[1 <= grid(i, j) for i, j in product(range(N), repeat=2)]) self.add(*[grid(i, j) <= 9 for i, j in product(range(N), repeat=2)]) for row in range(N): self.add(z3.Distinct([grid(row, col) for col in range(N)])) for col in range(N): self.add(z3.Distinct([grid(row, col) for row in range(N)])) for row in range(B): for col in range(B): block = [ grid(B * row + i, B * col + j) for i, j in product(range(SUB_GRID_SIZE), repeat=2) ] self.add(z3.Distinct(block))
def test_fn(): queens = [z3.Int('queens_%i' % (i + 1)) for i in range(8)] ranks = [1 <= queens[i] and queens[i] <= 8 for i in range(8)] files = [z3.Distinct(queens)] diagonals = [] for i in range(8): for j in range(i): if i != j: diagonals.append( abs(queens[i] - queens[j]) != abs(i - j)) return ranks, files, diagonals
def part_2_z3(): foods = get_foods() hypoallergenic = get_hypoallergenic_ingredients(foods) allergens = set() ingredients = set() foods_by_allergen = collections.defaultdict(set) foods_by_ingredient = collections.defaultdict(set) for food in foods: for allergen in food.allergens: foods_by_allergen[allergen].add(food) allergens.add(allergen) for ingredient in food.ingredients: foods_by_ingredient[ingredient].add(food) ingredients.add(ingredient) allergens = list(allergens) ingredients = list(ingredients - hypoallergenic) # List of variables representing possible assignment of ingredient to allergen assignments = z3.IntVector('assignment', len(ingredients)) solver = z3.Solver() for assignment in assignments: solver.add(0 <= assignment) solver.add(assignment < len(allergens)) solver.add(z3.Distinct(assignments)) for i, allergen in enumerate(allergens): candidates = [] for j, ingredient in enumerate(ingredients): # If set of foods that we know contain allergen_i is a subset of foods containing ingredient_j, # then ingredient_j = allergen_i is a possible assignment if foods_by_allergen[allergen] <= foods_by_ingredient[ingredient]: candidates.append(assignments[j] == i) solver.add(z3.Or(candidates)) assert solver.check() == z3.sat model = solver.model() matches = [] for i, assignment in enumerate(assignments): assignment = model.evaluate(assignment).as_long() matches.append((allergens[assignment], ingredients[i])) print(','.join(ingredient for _, ingredient in sorted(matches)))
def naive_sudoku(): # 9x9 matrix of integer variables x = [[z3.Int('x_%s_%s' % (i + 1, j + 1)) for j in range(9)] for i in range(9)] # each cell contains a value in {1, ..., 9} cells_c = [ 1 <= x[i][j] and x[i][j] <= 9 for i in range(9) for j in range(9) ] # each row contains a digit at most once rows_c = [z3.Distinct(x[i]) for i in range(9)] # each column contains a digit at most once cols_c = [ z3.Distinct([x[i][j] for i in range(9)]) for j in range(9) ] # each 3x3 square contains a digit at most once sq_c = [ z3.Distinct([ x[3 * i0 + i][3 * j0 + j] for i in range(3) for j in range(3) ]) for i0 in range(3) for j0 in range(3) ] sudoku_c = cells_c + rows_c + cols_c + sq_c instance = get_instance() instance_c = [] for i in range(9): for j in range(9): if instance[i][j] == 0: instance_c.append(True) else: instance_c.append(x[i][j] == instance[i][j]) return sudoku_c + instance_c
def solve(self): start_time = time.time() # First, create all the symbols the pyramid self.walk_pyramid(self.add_constraints) # All symbols are distinct self.solver.add([z3.Distinct([sym for sym in self.syms.values()])]) # All symbols range from 1 to sigma(rows) self.solver.add( [z3.And(s >= 1, s <= len(self.data)) for s in self.syms.values()]) nb_sols = 0 total_time = 0 while self.solver.check() == z3.sat: # Get the solution for this model model = self.solver.model() for n in self.syms.keys(): sym = model[self.get_sym(n)] val = sym.as_long() self.data[n - 1] = val # Finished timing this solution end_time = time.time() nb_sols += 1 self.print_pyramid() print("\nSolution #%d took %2.3f second(s)" % (nb_sols, end_time - start_time)) # Reset the timing total_time += end_time - start_time start_time = time.time() # Add the previous solution as the new constraints for n in self.syms.keys(): sym = model[self.get_sym(n)] self.solver.add(sym != sym.as_long()) # Find the next solution... if nb_sols == 0: end_time = time.time() print("\nNo solutions found! Spent, %2.3f second(s)" % (end_time - start_time)) else: print("Found %d total solution(s) and spent %2.3f second(s)" % (nb_sols, total_time)) return False return True
def z3_sudoku(): # See https://ericpony.github.io/z3py-tutorial/guide-examples.htm # 9x9 matrix of integer variables x = [[z3.Int('x_%s_%s' % (i + 1, j + 1)) for j in range(9)] for i in range(9)] # each cell contains a value in {1, ..., 9} cells_c = [ z3.And(1 <= x[i][j], x[i][j] <= 9) for i in range(9) for j in range(9) ] # each row contains a digit at most once rows_c = [z3.Distinct(x[i]) for i in range(9)] # each column contains a digit at most once cols_c = [ z3.Distinct([x[i][j] for i in range(9)]) for j in range(9) ] # each 3x3 square contains a digit at most once sq_c = [ z3.Distinct([ x[3 * i0 + i][3 * j0 + j] for i in range(3) for j in range(3) ]) for i0 in range(3) for j0 in range(3) ] sudoku_c = cells_c + rows_c + cols_c + sq_c instance = get_instance() instance_c = [ z3.If(instance[i][j] == 0, True, x[i][j] == instance[i][j]) for i in range(9) for j in range(9) ] return sudoku_c + instance_c
def solveSAT(self, problem): """ args: problem : 9×9のintのarray、数独の問題 return: ans : 9×9のintのarray、数独の解答 """ solver = z3.Solver() x = [[0] * 9 for i in range(9)] for i in range(9): for j in range(9): x[i][j] = z3.Int(str(9 * i + j)) if problem[i][j] > 0: solver.add(x[i][j] == problem[i][j]) else: solver.add(x[i][j] > 0) solver.add(x[i][j] < 10) for i in range(9): solver.add(z3.Distinct(x[i])) solver.add(z3.Distinct([row[i] for row in x])) solver.add(z3.Distinct(x[1][0], x[2][0])) solver.add( z3.Distinct([ x[i // 3 * 3 + j // 3][i % 3 * 3 + j % 3] for j in range(9) ])) ans = [[0] * 9 for i in range(9)] state = solver.check() if state == z3.sat: res = solver.model() for i in range(9): for j in range(9): ans[i][j] = res[x[i][j]].as_long() else: print(state) ans = None return ans
def solve(s1, s2, s3): global vars vars = dict() list1 = list(s1) #list=[s,e,n,d] list2 = list(s2) list3 = list(s3) #initial list in z3 for i in list1: mk_var(i) for i in list2: mk_var(i) for i in list3: mk_var(i) #equation lhs1 = reduce(lambda a, b: 10 * a + vars[b], list1, 0) lhs2 = reduce(lambda a, b: 10 * a + vars[b], list2, 0) rhs1 = reduce(lambda a, b: 10 * a + vars[b], list3, 0) solver = z3.Solver() #distinct solver.add(z3.Distinct(get_vars())) #equation solver.add(lhs1 + lhs2 == rhs1) solver.add(vars[list1[0]] != 0) solver.add(vars[list2[0]] != 0) solver.add(vars[list3[0]] != 0) #digital range for x in vars: solver.add(vars[x] >= z3.IntVal(0)) solver.add(vars[x] <= z3.IntVal(9)) res = solver.check() if res == z3.sat: model = solver.model() result = [] result.append( int(reduce(lambda a, b: "%s%s" % (a, model[vars[b]]), list1, ''))) result.append( int(reduce(lambda a, b: "%s%s" % (a, model[vars[b]]), list2, ''))) result.append( int(reduce(lambda a, b: "%s%s" % (a, model[vars[b]]), list3, ''))) return result else: return None