def main(known): s = Solver() matrix = [[Int(f"m{x}{y}") for x in range(1, 10)] for y in range(1, 10)] for i in range(9): for j in range(9): v = matrix[i][j] if known[i][j]: s.add(v == known[i][j]) else: s.add(v >= 1) s.add(v <= 9) for i in range(9): s.add(Distinct(*[matrix[i][j] for j in range(9)])) s.add(Distinct(*[matrix[j][i] for j in range(9)])) for i in range(3): for j in range(3): s.add( Distinct(*[ matrix[3 * i + k][3 * j + l] for k in range(3) for l in range(3) ])) s.check() m = s.model() print("Solution:") for i in range(9): print(*[m[matrix[i][j]] for j in range(9)])
def __init__(self, component, assigns): self.component = component self.assigns = [] self.bus_assigns = [] self.constraints = [] for bus_assign in assigns: if isinstance(bus_assign, Z3Assign): bus_assign = Z3BusAssign(bus_assign) self.constraints += bus_assign.constraints self.bus_assigns.append(bus_assign) for assign in bus_assign: assign.component_constraint(component) self.constraints += assign.constraints self.assigns.append(assign) # Each assignment needs a different Fun self.constraints.append( Distinct([assign.z3_fun for assign in self.assigns])) # Each assignment needs a different Pin self.constraints.append( Distinct([assign.z3_pin for assign in self.assigns])) # Each BusFun needs a different bus self.constraints.append( Distinct([bus_assign.z3_bus for bus_assign in self.bus_assigns]))
def solve_z3(self): print("[+] {}".format("Sovling using Z3\n")) symbols = {e: Int(e) for e in self.elements} # first we build a solver with the general constraints for sudoku puzzles: s = Solver() # assure that every cell holds a value of [1,9] for symbol in symbols.values(): s.add(Or([symbol == int(i) for i in self.cols])) # assure that every row covers every value: for row in "ABCDEFGHI": s.add(Distinct([symbols[row + col] for col in "123456789"])) # assure that every column covers every value: for col in "123456789": s.add(Distinct([symbols[row + col] for row in "ABCDEFGHI"])) # assure that every block covers every value: for i in range(3): for j in range(3): s.add( Distinct([ symbols["ABCDEFGHI"[m + i * 3] + "123456789"[n + j * 3]] for m in range(3) for n in range(3) ])) # adding sum constraints if provided if self.constraints is not None: print("[+] {}\n{}".format("Applying constraints", self.constraints)) sum_constr = self.get_constraints() for c in sum_constr: expr = [] for i in c[0]: expr.append("symbols['" + i + "']") s.add(eval("+".join(expr) + "==" + str(c[1]))) # now we put the assumptions of the given puzzle into the solver: for elem, value in self.values.items(): if value in "123456789": s.add(symbols[elem] == value) if not s.check() == sat: raise Exception("Unsolvable") model = s.model() values = {e: model.evaluate(s).as_string() for e, s in symbols.items()} self.solution = values
def gen_latin_square_constraints(matrix, order): assert len(matrix) == order assert len(transpose(matrix)) == order numbers = itertools.chain(*matrix) range_c = [And(n >= 1, n <= order) for n in numbers] row_c = [Distinct(row) for row in matrix] col_c = [Distinct(row) for row in transpose(matrix)] return range_c + row_c + col_c
def main(): """Skyscraper solver example.""" lattice = grilops.get_square_lattice(SIZE) directions = {d.name: d for d in lattice.edge_sharing_directions()} sg = grilops.SymbolGrid(lattice, SYM) # Each row and each column contains each building height exactly once. for y in range(SIZE): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for x in range(SIZE)])) for x in range(SIZE): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for y in range(SIZE)])) # We'll use the sightlines accumulator to keep track of a tuple storing: # the tallest building we've seen so far # the number of visible buildings we've encountered Acc = Datatype("Acc") # pylint: disable=C0103 Acc.declare("acc", ("tallest", IntSort()), ("num_visible", IntSort())) Acc = Acc.create() # pylint: disable=C0103 def accumulate(a, height): return Acc.acc( If(height > Acc.tallest(a), height, Acc.tallest(a)), If(height > Acc.tallest(a), Acc.num_visible(a) + 1, Acc.num_visible(a))) for x, c in enumerate(GIVEN_TOP): sg.solver.add(c == Acc.num_visible( grilops.sightlines.reduce_cells(sg, Point(0, x), directions["S"], Acc.acc(0, 0), accumulate))) for y, c in enumerate(GIVEN_LEFT): sg.solver.add(c == Acc.num_visible( grilops.sightlines.reduce_cells(sg, Point(y, 0), directions["E"], Acc.acc(0, 0), accumulate))) for y, c in enumerate(GIVEN_RIGHT): sg.solver.add(c == Acc.num_visible( grilops.sightlines.reduce_cells(sg, Point( y, SIZE - 1), directions["W"], Acc.acc(0, 0), accumulate))) for x, c in enumerate(GIVEN_BOTTOM): sg.solver.add(c == Acc.num_visible( grilops.sightlines.reduce_cells(sg, Point( SIZE - 1, x), directions["N"], Acc.acc(0, 0), accumulate))) if sg.solve(): sg.print() print() if sg.is_unique(): print("Unique solution") else: print("Alternate solution") sg.print() else: print("No solution")
def require_unique_row_and_column_cells(self, board): constraints = [] rows = set([x for (x, _, _, _) in board]) columns = set([y for (_, y, _, _) in board]) for row in rows: cells = [c for (x, _, _, c) in board if x == row] constraints.append(Distinct(*cells)) for column in columns: cells = [c for (_, y, _, c) in board if y == column] constraints.append(Distinct(*cells)) return constraints
def add_sudoku_constraints(sg): """Add constraints for the normal Sudoku rules.""" for y in range(9): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for x in range(9)])) for x in range(9): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for y in range(9)])) for z in range(9): top = (z // 3) * 3 left = (z % 3) * 3 cells = [ sg.grid[Point(y, x)] for y in range(top, top + 3) for x in range(left, left + 3) ] sg.solver.add(Distinct(*cells))
def killer_sudoku(cages: List[str], cage_sum_grid: List[List[int]]) -> str: """Solver for Killer Sudoku minipuzzles.""" sym = grilops.make_number_range_symbol_set(1, SIZE) sg = grilops.SymbolGrid(LATTICE, sym) shifter = Shifter(sg.solver) # Add normal sudoku constraints. for y in range(SIZE): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for x in range(SIZE)])) for x in range(SIZE): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for y in range(SIZE)])) for z in range(9): top = (z // 3) * 3 left = (z % 3) * 3 cells = [ sg.grid[Point(y, x)] for y in range(top, top + 3) for x in range(left, left + 3) ] sg.solver.add(Distinct(*cells)) # Build a map from each cage label to the cells within that cage. cage_cells = defaultdict(list) for p in LATTICE.points: cage_cells[cages[p.y][p.x]].append(sg.grid[p]) # The digits used in each cage must be unique. for cells_in_cage in cage_cells.values(): sg.solver.add(Distinct(*cells_in_cage)) cage_sums = {} for p in LATTICE.points: cage_sum = cage_sum_grid[p.y][p.x] if cage_sum > 0: shifted_cage_sum = shifter.given(p, cage_sum) cage_label = cages[p.y][p.x] assert cage_label not in cage_sums cage_sums[cage_label] = shifted_cage_sum # Add constraints for cages with given sums. for cage_label, shifted_cage_sum in cage_sums.items(): sg.solver.add(Sum(*cage_cells[cage_label]) == shifted_cage_sum) assert sg.solve() sg.print() print() shifter.print_shifts() print() return shifter.eval_binary()
def boxes_distinct(g): dx = dy = 3 for j in range(g.height // dy): for i in range(g.width // dx): g.add( Distinct(*(g.digit(x + i * dx, y + j * dy) for y in range(dy) for x in range(dx))))
def __add_single_loop_constraints(self): solver = self.__symbol_grid.solver sym: LoopSymbolSet = self.__symbol_grid.symbol_set cell_count = len(self.__symbol_grid.grid) for p in self.__symbol_grid.grid: v = Int(f"log-{LoopConstrainer._instance_index}-{p.y}-{p.x}") solver.add(v >= -cell_count) solver.add(v < cell_count) self.__loop_order_grid[p] = v solver.add(Distinct(*self.__loop_order_grid.values())) for p, cell in self.__symbol_grid.grid.items(): li = self.__loop_order_grid[p] solver.add(If(sym.is_loop(cell), li >= 0, li < 0)) for idx, d1, d2 in self.__all_direction_pairs(): pi = p.translate(d1) pj = p.translate(d2) if pi in self.__loop_order_grid and pj in self.__loop_order_grid: solver.add( Implies( And(cell == idx, li > 0), Or(self.__loop_order_grid[pi] == li - 1, self.__loop_order_grid[pj] == li - 1)))
def _add_block_conditions(self): for i, j in product(range(3), repeat=2): blocks = [ self.symbols[self.rows[m + 3 * i] + self.cols[n + 3 * j]] for m, n in product(range(3), repeat=2) ] self.solver.add(Distinct(blocks))
def skyscraper(givens: Dict[Direction, List[int]]) -> str: """Solver for Skyscraper minipuzzles.""" sym = grilops.make_number_range_symbol_set(1, SIZE) sg = grilops.SymbolGrid(LATTICE, sym) shifter = Shifter(sg.solver) # Each row and each column contains each building height exactly once. for y in range(SIZE): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for x in range(SIZE)])) for x in range(SIZE): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for y in range(SIZE)])) # We'll use the sightlines accumulator to keep track of a tuple storing: # the tallest building we've seen so far # the number of visible buildings we've encountered Acc = Datatype("Acc") # pylint: disable=C0103 Acc.declare("acc", ("tallest", IntSort()), ("num_visible", IntSort())) Acc = Acc.create() # pylint: disable=C0103 def accumulate(a, height): return Acc.acc( If(height > Acc.tallest(a), height, Acc.tallest(a)), If(height > Acc.tallest(a), Acc.num_visible(a) + 1, Acc.num_visible(a))) for d, gs in givens.items(): for i, g in enumerate(gs): if d.vector.dy != 0: g = g - shifter.col_shifts.get(i, 0) p = Point(0 if d.vector.dy < 0 else SIZE - 1, i) elif d.vector.dx != 0: g = g - shifter.row_shifts.get(i, 0) p = Point(i, 0 if d.vector.dx < 0 else SIZE - 1) sg.solver.add(g == Acc.num_visible( # type: ignore[attr-defined] grilops.sightlines.reduce_cells( sg, p, LATTICE.opposite_direction(d), Acc.acc(0, 0), # type: ignore[attr-defined] accumulate))) assert sg.solve() sg.print() print() shifter.print_shifts() print() return shifter.eval_binary()
def init_solver(cols): s = Solver() for col in cols: cond = And(col >= 0, col < len(COLORS)) #possible values for each column s.add(cond) cond_unicity = Distinct(cols) #each column is different s.add(cond_unicity) return s
def abc_different(): """ R(A),R(B),R(C) must all have distinct values. Returns ------- Formula """ return Distinct([R(A), R(B), R(C)])
def main(): """Sudoku solver example.""" givens = [ [5, 3, 0, 0, 7, 0, 0, 0, 0], [6, 0, 0, 1, 9, 5, 0, 0, 0], [0, 9, 8, 0, 0, 0, 0, 6, 0], [8, 0, 0, 0, 6, 0, 0, 0, 3], [4, 0, 0, 8, 0, 3, 0, 0, 1], [7, 0, 0, 0, 2, 0, 0, 0, 6], [0, 6, 0, 0, 0, 0, 2, 8, 0], [0, 0, 0, 4, 1, 9, 0, 0, 5], [0, 0, 0, 0, 8, 0, 0, 7, 9], ] sym = grilops.make_number_range_symbol_set(1, 9) sg = grilops.SymbolGrid(grilops.get_square_lattice(9), sym) for y, given_row in enumerate(givens): for x, given in enumerate(given_row): if given != 0: sg.solver.add(sg.cell_is(Point(y, x), sym[given])) for y in range(9): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for x in range(9)])) for x in range(9): sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for y in range(9)])) for z in range(9): top = (z // 3) * 3 left = (z % 3) * 3 cells = [sg.grid[Point(y, x)] for y in range(top, top + 3) for x in range(left, left + 3)] sg.solver.add(Distinct(*cells)) if sg.solve(): sg.print() print() if sg.is_unique(): print("Unique solution") else: print("Alternate solution") sg.print() else: print("No solution")
def freedom_search(language: Language, space, generate_rules_only=False, distinct=False, can_be_same=True): rules = set() names = language.all_card_names() all_vars = list(map(z3.Int, names)) print(names) print(all_vars) for cut1 in tqdm(space(1)): for cut2 in space(2, cut1): for cut3 in space(3, cut1, cut2): for sequence in permutations(range(4)): cuts = (cut1, cut2, cut3) rule = freedom_of_spelling(all_vars, cuts, sequence, language, can_be_same) rules.add(rule) if distinct: rules.add(Distinct(all_vars)) else: for position in range(0, 52): at_starting_point = [card == position for card in all_vars] rule = AtMost(*at_starting_point, 1) rules.add(rule) rules.add(rules_all_cards_on_deck(all_vars)) if generate_rules_only: return print(len(rules)) s = Solver() s.set('smt.arith.random_initial_value', True) # random_seed (unsigned int) random seed (default: 0) s.set('random_seed', random.randint(0, 2 ** 8)) # seed (unsigned int) random seed. (default: 0) s.set('seed', random.randint(0, 2 ** 8)) s.add(rules) r = s.check() if r == unsat: print("no solution") elif r == unknown: print("failed to solve") try: print(s.reason_unknown()) print(s.model()) except Z3Exception: return else: print(s.model())
def solve(grid): values = parseGrid(grid) elements = squares symbols = {e: Int(e) for e in elements} s = Solver() #Each square should have a value in the interval [1,9] for element in symbols.values(): s.add(Or([element == i for i in range(1, 10)])) #Then every row should cover every value for row in "ABCDEFGHI": s.add(Distinct([symbols[row + col] for col in "123456789"])) #Then every column should cover every value for column in "123456789": s.add(Distinct([symbols[row + column] for row in "ABCDEFGHI"])) # Finally every block neighborhood should cover every value for i in range(3): for j in range(3): s.add( Distinct([ symbols["ABCDEFGHI"[m + i * 3] + "123456789"[n + j * 3]] for m in range(3) for n in range(3) ])) #Now we fill in the given intial puzzle for element, value in values.items(): if value in "123456789": s.add(symbols[element] == value) if not s.check() == sat: raise Exception("unsolvable") model = s.model() values = {e: model.evaluate(s).as_string() for e, s in symbols.items()} #for key in values: # print(key,'--->', values[key]) return values
def _get_variables_and_constraints(grid): n = grid.n # a variable for each cell X = [[Int("x_%s_%s" % (i + 1, j + 1)) for j in range(n)] for i in range(n)] # each cell contains a value in {1, ..., n} cells_c = [ And(1 <= X[i][j], X[i][j] <= n) for i in range(n) for j in range(n) ] # each row contains distinct values rows_c = [Distinct(X[i]) for i in range(n)] # each column contains distinct values cols_c = [Distinct([X[i][j] for i in range(n)]) for j in range(n)] # add constraints for inequalities ineq_c = [] for i, row in enumerate(grid.values): for j, _ in enumerate(row): if j < n - 1: ineq = grid.across[i, j] if ineq == -1: ineq_c.append(X[i][j] < X[i][j + 1]) elif ineq == 1: ineq_c.append(X[i][j] > X[i][j + 1]) if i < n - 1: for j, _ in enumerate(row): ineq = grid.down[i, j] if ineq == -1: ineq_c.append(X[i][j] < X[i + 1][j]) elif ineq == 1: ineq_c.append(X[i][j] > X[i + 1][j]) # add constraints for any values provided instance_c = [ X[i][j] == int(grid.values[i, j]) for i in range(n) for j in range(n) if grid.values[i, j] != 0 ] return X, cells_c + rows_c + cols_c + ineq_c + instance_c
def main(): """Hex kakuro solver example.""" points = [] points.extend([Point(1, i) for i in range(-3, 4, 2)]) points.extend([Point(2, i) for i in range(-4, 5, 2)]) points.extend([Point(3, -5), Point(3, -3), Point(3, 3), Point(3, 5)]) points.extend([ Point(4, -6), Point(4, -4), Point(4, -2), Point(4, 2), Point(4, 4), Point(4, 6) ]) points.extend([Point(5, -5), Point(5, -3), Point(5, 3), Point(5, 5)]) points.extend([Point(6, i) for i in range(-4, 5, 2)]) points.extend([Point(7, i) for i in range(-3, 4, 2)]) lattice = PointyToppedHexagonalLattice(points) sym = grilops.make_number_range_symbol_set(1, 9) sg = grilops.SymbolGrid(lattice, sym) dirs_by_name = dict(sg.lattice.edge_sharing_directions()) for entry in SUMS: (y, x), dirname, given = entry d = dirs_by_name[dirname] s = grilops.sightlines.count_cells(sg, Point(y, x), d, count=lambda c: c) sg.solver.add(given == s) for p in lattice.points: for d in [Vector(0, 2), Vector(1, 1), Vector(1, -1)]: if p.translate(d.negate()) not in sg.grid: q = p ps = [] while q in sg.grid: ps.append(sg.grid[q]) q = q.translate(d) sg.solver.add(Distinct(*ps)) if sg.solve(): sg.print() print() if sg.is_unique(): print("Unique solution") else: print("Alternate solution") sg.print() else: print("No solution")
def Z3Solving(sudoku): from z3 import Solver, Int, Or, Distinct, sat elements = cross("ABCDEFGHI", "123456789") symbols = {e: Int(e) for e in elements} # first we build a solver with the general constraints for sudoku puzzles: s = Solver() # assure that every cell holds a value of [1,9] for symbol in symbols.values(): s.add(Or([symbol == i for i in range(1, 10)])) # assure that every row covers every value: for row in "ABCDEFGHI": s.add(Distinct([symbols[row + col] for col in "123456789"])) # assure that every column covers every value: for col in "123456789": s.add(Distinct([symbols[row + col] for row in "ABCDEFGHI"])) # assure that every block covers every value: for i in range(3): for j in range(3): s.add(Distinct([symbols["ABCDEFGHI"[m + i * 3] + "123456789"[n + j * 3]] for m in range(3) for n in range(3)])) # now we put the assumptions of the given puzzle into the solver: for elem, value in sudoku.values.items(): if value in "123456789": s.add(symbols[elem] == value) if not s.check() == sat: raise Exception("unsolvable") model = s.model() values = {e: model.evaluate(s).as_string() for e, s in symbols.items()} return Sudoku(values)
def __add_single_loop_constraints(self): """Internal: There must be exactly one loop in the grid. This method uses the concept of a 'loop order'. """ solver = self.__symbol_grid.solver sym: LoopSymbolSet = self.__symbol_grid.symbol_set cell_count = len(self.__symbol_grid.grid) # Loop orders are constrained in [-cell_count, cell_count) for p in self.__symbol_grid.grid: v = Int(f"log-{LoopConstrainer._instance_index}-{p.y}-{p.x}") solver.add(v >= -cell_count) solver.add(v < cell_count) self.__loop_order_grid[p] = v # All loop orders must be distinct solver.add(Distinct(*self.__loop_order_grid.values())) for p, cell in self.__symbol_grid.grid.items(): li = self.__loop_order_grid[p] # Cells on the loop have positive loop order, cells not on the loop # have negative loop order. solver.add(If(sym.is_loop(cell), li >= 0, li < 0)) # Look at all possible cells that can come before / after on the path. for idx, d1, d2 in self.__all_direction_pairs(): pi = p.translate(d1) pj = p.translate(d2) if pi in self.__loop_order_grid and pj in self.__loop_order_grid: # If the cell is using this direction pair (cell == idx) # AND the cell is on the loop (and not 0), one of the cells before / # after must be offset by 1 from this cell. Imagine indicating the # 'start' of the loop with loop order 0. This forces a # 'directionality' on the loop. Start at any arbitrary point on the # loop, this condition means that you must be able to descend towards # 0, while remaining on the loop. By descent, every cell must reach # 0 while remaining on the loop, so every cell must be part of the # same loop. solver.add(Implies( And(cell == idx, li > 0), Or( self.__loop_order_grid[pi] == li - 1, self.__loop_order_grid[pj] == li - 1 ) ))
def find_queens(): from z3 import Int, And, Distinct, Solver queens = [Int(f"Q{i+1}") for i in range(8)] columns = [And(1 <= q, q <= 8) for q in queens] distinct = [Distinct(queens)] diags = [ And(queens[i] - queens[j] != i - j, queens[i] - queens[j] != j - i) for i in range(8) for j in range(i) ] solver = Solver() solver.add(columns + distinct + diags) solver.check() m = solver.model() return m
def main(): s = Solver() X = Int('X') Y = Int('Y') Z = Int('Z') # X, Y, Z: 1-9 s.add(*[And(cur >= 1, cur <= 9) for cur in (X, Y, Z)]) s.add(Distinct(X, Y, Z)) given_number = as_number(X, Y, Z) reversed_number = as_number(Z, Y, X) high_min_low = symbolic_max(given_number, reversed_number) - symbolic_min( given_number, reversed_number) high_min_low_rev = as_number(digit_at_pos(high_min_low, 0), digit_at_pos(high_min_low, 1), digit_at_pos(high_min_low, 2)) s.push() # Check that it always holds/there is no counterexample: total = high_min_low + high_min_low_rev s.add(total != 1089) res = s.check() if res.r == -1: print("unsat -> it holds. Example:") s.pop() s.add(total == 1089) s.check() mod = s.model() print(f"given number: {mod.eval(given_number)}") print(f"reversed: {mod.eval(reversed_number)}") print( f"highest - lowest: {mod.eval(high_min_low)}, reversed: {mod.eval(high_min_low_rev)}" ) print(f"sums to: {mod.eval(total)}") else: print("sat.") print(s.model())
def find_queens(): from z3 import Int, And, Distinct, Solver, sat, Or queens = [Int(f"Q{i+1}") for i in range(8)] columns = [And(1 <= q, q <= 8) for q in queens] distinct = [Distinct(queens)] diags = [ And(queens[i] - queens[j] != i - j, queens[i] - queens[j] != j - i) for i in range(8) for j in range(i) ] solver = Solver() solver.add(columns + distinct + diags) while solver.check() == sat: m = solver.model() yield m block = [] for var in m: v = var() block.append(v != m[v]) solver.add(Or(block))
inums = [] for i in inames: if i not in ingredients: n_i += 1 ingredients[i] = n_i inums.append(ingredients[i]) all_inums += inums # Make SAT clauses for allergens: # "a b c (contains x, y)" => (x=a or x=b or x=c) and (y=a or y=b or y=c) for a in anames: if a not in allergens: allergens[a] = Int(a) solver.add(Or([allergens[a] == i for i in inums])) # All variables are distinct ("Each ingredient contains zero or one allergen", # i.e. no ingredient occurs twice or more among the solution.) solver.add(Distinct(list(allergens.values()))) # Merry Christmas!!!!!!!!!!!! solver.check() m = solver.model() # * bad_ingredients = {m[a].as_long() for a in m} print('* ', sum(i not in bad_ingredients for i in all_inums)) # ** Oh no, we need the ingredient names again, dfgjh ok lookup = {v: k for k, v in ingredients.items()} answer = [(a.name(), lookup[m[a].as_long()]) for a in m] print('** ', ','.join(i for (a, i) in sorted(answer)))
def solve(data): men_str = data['men_str'] women_str = data['women_str'] men_prefer = data['men'] women_prefer = data['women'] s = Solver() size = len(men_prefer) size_range = range(size) men_choice = [Int(f'men_choice_{i}') for i in size_range] women_choice = [Int(f'women_choice_{i}') for i in size_range] for i in size_range: s.add(And(men_choice[i] >= 0, men_choice[i] <= size - 1)) s.add(And(women_choice[i] >= 0, women_choice[i] <= size - 1)) s.add(Distinct(men_choice)) for i in size_range: s.add(women_choice[i] == _if_x(men_choice, i, 0)) men_own_choice = [Int(f'men_own_choice_{i}') for i in size_range] women_own_choice = [Int(f'women_own_choice_{i}') for i in size_range] for m in size_range: s.add(men_own_choice[m] == _if_xy(men_choice[m], men_prefer[m], 0)) for w in size_range: s.add( women_own_choice[w] == _if_xy(women_choice[w], women_prefer[w], 0)) men_want = [[Bool(f'men_want_{m}_{w}') for w in size_range] for m in size_range] women_want = [[Bool(f'women_want_{w}_{m}') for m in size_range] for w in size_range] for m in size_range: for w in men_prefer[m]: s.add( men_want[m][w] == (men_prefer[m].index(w) < men_own_choice[m])) for w in size_range: for m in women_prefer[w]: s.add(women_want[w][m] == ( women_prefer[w].index(m) < women_own_choice[w])) for m in size_range: for w in size_range: s.add(Not(And(men_want[m][w], women_want[w][m]))) if s.check() != sat: raise Exception('not a valid input') with open('z3_input.txt', 'w') as f: f.write(s.sexpr()) mdl = s.model() with open('z3_model.txt', 'w') as f: f.write(str(mdl)) return { women_str[mdl[men_choice[m]].as_long()]: men_str[m] for m in size_range }
def main(): """Greater Than Killer Sudoku solver example.""" cages = [ "AABCCDDEE", "FFBGGHIJK", "FLMNHHIJK", "LLMNNOIPP", "QQRNSOTTU", "VWRSSXTUU", "VWYYSXZaa", "bccddXZee", "bbbdffZgg", ] cage_sums = { "B": 6, "D": 16, "F": 14, "H": 17, "I": 9, "J": 12, "K": 9, "L": 20, "M": 13, "N": 29, "O": 4, "R": 8, "S": 12, "V": 8, "W": 14, "Y": 17, "b": 11, "d": 11, "e": 8, } sym = grilops.make_number_range_symbol_set(1, 9) lattice = grilops.get_square_lattice(9) sg = grilops.SymbolGrid(lattice, sym) add_sudoku_constraints(sg) # Build a map from each cage label to the cells within that cage. cage_cells = defaultdict(list) for p in lattice.points: cage_cells[cages[p.y][p.x]].append(sg.grid[p]) # The digits used in each cage must be unique. for cells_in_cage in cage_cells.values(): sg.solver.add(Distinct(*cells_in_cage)) # Add constraints for cages with given sums. for cage_label, cage_sum in cage_sums.items(): sg.solver.add(Sum(*cage_cells[cage_label]) == cage_sum) # Add constraints between cage sums. def cage_sum_greater(a, b): sg.solver.add(Sum(*cage_cells[a]) > Sum(*cage_cells[b])) def cage_sum_equal(a, b): sg.solver.add(Sum(*cage_cells[a]) == Sum(*cage_cells[b])) cage_sum_equal("C", "G") cage_sum_greater("J", "E") cage_sum_greater("E", "K") cage_sum_greater("W", "c") cage_sum_greater("c", "b") cage_sum_greater("f", "d") cage_sum_greater("X", "f") if sg.solve(): sg.print() print() if sg.is_unique(): print("Unique solution") else: print("Alternate solution") sg.print() else: print("No solution")
from z3 import Solver, EnumSort, Const, Distinct s = Solver() Color, (red, green, blue) = EnumSort('Color', ['red', 'green', 'blue']) a = Const('a', Color) b = Const('b', Color) s.add(Distinct(a, b)) s.check() print(s.model()) # [b = green, a = red]
def constraint_distinct(self, iterable): """ All elements are different. """ self.solver.add(Distinct([self.symbols[elem] for elem in iterable]))
except IndexError: help() n = check_count_device(superstring) d = {} l = [] s = Optimize() for i in range(n): d[abc[i]] = Int(abc[i]) globals()[abc[i]] = Int(abc[i]) l.append(abc[i]) s.add(And(d[abc[i]] >= 0, d[abc[i]] <= n - 1)) s.add(Distinct([d[x] for x in l])) for i in superstring.split(' '): s.add( Int('diff_{0}_{1}'.format(i[0], i[1])) == diff(d.get(i[0]), d.get( i[1]))) try: final_sum += Int('diff_{0}_{1}'.format(i[0], i[1])) * int(i[2]) except NameError: final_sum = Int('diff_{0}_{1}'.format(i[0], i[1])) * int(i[2]) final_sum2 = Int("final_sum2") s.add(final_sum == final_sum2) s.minimize(final_sum) s.check() m = s.model()