def _add_postconditions(self, gate, ctrl_ones, trgtqb, trgtvar): """create boolean variables for each qubit the gate is applied to and apply the relevant post conditions. a gate rotating out of the z-basis will not have any valid post-conditions, in which case the qubit state is unknown Args: gate (Gate): gate to inspect ctrl_ones (BoolRef): z3 condition asserting all control qubits to 1 trgtqb (list((QuantumRegister, int))): list of target qubits trgtvar (list(BoolRef)): z3 variables corresponding to latest state of target qubits """ new_vars = [] for qbt in trgtqb: new_vars.append(self._gen_variable(qbt)) try: self.solver.add( Implies(ctrl_ones, gate._postconditions(*(trgtvar + new_vars)))) except AttributeError: pass for i, tvar in enumerate(trgtvar): self.solver.add(Implies(Not(ctrl_ones), new_vars[i] == tvar))
def constrain_islands(sym, sg, rc): """Add constraints to the island cells.""" # Each numbered cell is an island cell. The number in it is the number of # cells in that island. Each island must contain exactly one numbered cell. for y in range(HEIGHT): for x in range(WIDTH): p = Point(y, x) if (y, x) in GIVENS: sg.solver.add(sg.cell_is(p, sym.W)) # Might as well force the given cell to be the root of the region's tree, # to reduce the number of possibilities. sg.solver.add(rc.parent_grid[p] == grilops.regions.R) sg.solver.add(rc.region_size_grid[p] == GIVENS[(y, x)]) else: # Ensure that cells that are part of island regions are colored white. for gp in GIVENS: island_id = sg.lattice.point_to_index(gp) sg.solver.add( Implies(rc.region_id_grid[p] == island_id, sg.cell_is(p, sym.W))) # Force a non-given white cell to not be the root of the region's tree, # to reduce the number of possibilities. sg.solver.add( Implies(sg.cell_is(p, sym.W), rc.parent_grid[p] != grilops.regions.R))
def main(): # 1. Create a list of z3 Int variables called prestate which is [x[0], x[1], x[2],....,x[15]] # use the range() function in Python and the parameter N # do not hardcode the list explicitly prestate = [Int("x["+str(i)+"]") for i in range(N)] # 2. create a list of z3 Int variables called poststate which is [x'[0], x'[1], x'[2],....,x'[N-1]] poststate = [Int("x'["+str(i)+"]") for i in range(N)] # Do not change # Defines init as prestate that is legal init = legal_config(prestate) # 3. Write the base_case predicate using the Implies() function of z3 # base_case = Implies(And(bounds(prestate), init), invariant(prestate)) base_case = Implies(init, invariant(prestate)) # 4. Write the induction step predicate using the Implies() function of z3 # prestate and poststate and transition_relation # ind_case = Implies(And(bounds(prestate), invariant(prestate), transition_relation(prestate, poststate)), And(bounds(poststate), invariant(poststate))) ind_case = Implies(And(invariant(prestate), transition_relation(prestate, poststate)), invariant(poststate)) # Do not change print("## Proving base case:") prove(base_case) print("## Proving induction case") prove(ind_case)
def constrain_sea(sym, sg, rc): """Add constraints to the sea cells.""" # There must be only one sea, containing all black cells. sea_id = Int("sea-id") sg.solver.add(sea_id >= 0) sg.solver.add(sea_id < HEIGHT * WIDTH) for p in GIVENS: sg.solver.add(sea_id != sg.lattice.point_to_index(p)) for y in range(HEIGHT): for x in range(WIDTH): p = Point(y, x) sg.solver.add( Implies(sg.cell_is(p, sym.B), rc.region_id_grid[p] == sea_id)) sg.solver.add( Implies(sg.cell_is(p, sym.W), rc.region_id_grid[p] != sea_id)) # The sea is not allowed to contain 2x2 areas of black cells. for sy in range(HEIGHT - 1): for sx in range(WIDTH - 1): pool_cells = [ sg.grid[Point(y, x)] for y in range(sy, sy + 2) for x in range(sx, sx + 2) ] sg.solver.add(Not(And(*[cell == sym.B for cell in pool_cells])))
def prog_constraint(p): # return And(p.pre() <= p.set(), p.post() <= p.set() ^ p.set()) from z3 import ForAll, And, Implies x, y = consts('x y', U) return ForAll([x, y], And( Implies(p.pre(x), p.set(x)), Implies(p.post(x, y), And(p.set(x), p.set(y))), ))
def constrain_side(p, sp, sd): self.__solver.add(Implies( self.__parent_grid[p] == X, self.__parent_grid[sp] != sd )) self.__solver.add(Implies( self.__parent_grid[sp] == sd, And( self.__region_id_grid[p] == self.__region_id_grid[sp], self.__region_size_grid[p] == self.__region_size_grid[sp], ) ))
def __create_grids(self): """Create the grids used to model region constraints.""" self.__parent_grid: Dict[Point, ArithRef] = {} for p in self.__lattice.points: v = Int(f"rcp-{RegionConstrainer._instance_index}-{p.y}-{p.x}") if self.__complete: self.__solver.add(v >= R) else: self.__solver.add(v >= X) self.__solver.add(v < len(self.__parent_types)) self.__parent_grid[p] = v self.__subtree_size_grid: Dict[Point, ArithRef] = {} for p in self.__lattice.points: v = Int(f"rcss-{RegionConstrainer._instance_index}-{p.y}-{p.x}") if self.__complete: self.__solver.add(v >= 1) else: self.__solver.add(v >= 0) self.__solver.add(v <= self.__max_region_size) self.__subtree_size_grid[p] = v self.__region_id_grid: Dict[Point, ArithRef] = {} for p in self.__lattice.points: v = Int(f"rcid-{RegionConstrainer._instance_index}-{p.y}-{p.x}") if self.__complete: self.__solver.add(v >= 0) else: self.__solver.add(v >= -1) self.__solver.add(v < len(self.__lattice.points)) parent = self.__parent_grid[p] self.__solver.add(Implies(parent == X, v == -1)) self.__solver.add(Implies( parent == R, v == self.__lattice.point_to_index(p) )) self.__region_id_grid[p] = v self.__region_size_grid: Dict[Point, ArithRef] = {} for p in self.__lattice.points: v = Int(f"rcrs-{RegionConstrainer._instance_index}-{p.y}-{p.x}") if self.__complete: self.__solver.add(v >= self.__min_region_size) else: self.__solver.add(Or(v >= self.__min_region_size, v == -1)) self.__solver.add(v <= self.__max_region_size) parent = self.__parent_grid[p] subtree_size = self.__subtree_size_grid[p] self.__solver.add(Implies(parent == X, v == -1)) self.__solver.add(Implies(parent == R, v == subtree_size)) self.__region_size_grid[p] = v
def dataflow_constraint(env: Env) -> Constraint: I, C, F, P, R, o = env # On one case the call to the solver was much faster without this. # R_ = lambda p: tuple(f.ret_val for f in F if p not in f.params) for p in P: for x in I + C + R: #R_(p): if p.kind == x.kind: yield Implies(p.line == x.line, p == x) for r in R: if r.kind == o.kind: yield Implies(r.line == o.line, r == o)
def __init__(self): self.belt_x = Function(f'belt{self._IDX}_x', IntSort(), IntSort()) self.belt_y = Function(f'belt{self._IDX}_y', IntSort(), IntSort()) self.belt_len = Const(f'belt{self._IDX}_len', IntSort()) SOL.add(self.belt_len > 0) i,j = Consts("i j", IntSort()) # neighbor condition SOL.add(ForAll([i], Implies(And(i < self.belt_len - 1, i >= 0), neighs(self[i], self[i+1])))) # no intersections SOL.add(ForAll([i, j], Implies(And(i >= 0, i < j, j < self.belt_len), Not(self[i] == self[j])))) self.__class__._IDX += 1
def _add_soft_constraints(self): self.s.push() for tid in range(self.agents): a = self.info.spawn[tid] for i, attr in enumerate(self.attrs[tid]): v = get_var(a.iface, i) fresh_bool = Bool(f"{v.store}_{tid}_{v.index}_%%soft%%") self.softs.add(fresh_bool) self.s.add(Implies(fresh_bool, attr == v.rnd_value(tid))) for i, env_var in enumerate(self.envs): v = get_var(self.info.e, i) fresh_bool = Bool(f"{v.store}_{v.index}_%%soft%%") self.softs.add(fresh_bool) self.s.add(Implies(fresh_bool, attr == v.rnd_value(tid)))
def GenerateConnectionConstraints(self): constraints = [Bool(True)] numInputPorts = len(self.inputPorts) numComponents = len(self.components) for i in range(numInputPorts): for comp in self.components: for inputPort in comp.inputPorts: if inputPort.breed == self.inputPorts[i].breed: antecedent = (Int(self.PN2LNMap[inputPort.name]) == i) consequent = (inputPort.var == self.inputPorts[i].var) constraints.append(Implies(antecedent, consequent)) else: constraints.append( Int(self.PN2LNMap[inputPort.name]) != i) numLabels = len(self.labels) for i in range(numLabels): for j in range(i + 1, numLabels): labelX = self.labels[i] labelY = self.labels[j] portX = self.LN2PMap[labelX] portY = self.LN2PMap[labelY] if portX.breed == portY.breed: antecedent = Int(labelX) == Int(labelY) consequent = (portX.var == portY.var) constraints.append(Implies(antecedent, consequent)) else: constraints.append(Int(labelX) != Int(labelY)) for comp in self.components: if comp.outputPort.breed == self.outputPort.breed: antecedent = (Int( self.PN2LNMap[comp.outputPort.name]) == numInputPorts + numComponents - 1) consequent = (self.outputPort.var == comp.outputPort.var) constraints.append(Implies(antecedent, consequent)) else: constraints.append( Int(self.PN2LNMap[comp.outputPort.name]) != numInputPorts + numComponents - 1) constraints.extend([comp.spec for comp in self.components]) return And(constraints)
def command_specific_forall(self, z3_formula: z3.ExprRef) -> z3.ExprRef: """ See `ForallMode` documentation. """ if self.forall_mode == ForallMode.FORALL_QUANTIFIER: return ForAll(self._z3_local_var_list, substitute(z3_formula, *self._z3_local_subst)) elif self.forall_mode in [ForallMode.FORALL_MACRO, ForallMode.FORALL_GLOBALS]: result = [] for command in self.input_module.commands: # For every command, we add a conjunct # "No goal" AND "guard of command" >= (conjunction of substituted formulae for corresponding frame variables) result.append(Implies(And(Not(self.smt_program.goal_expr), command.guard), And([ substitute(z3_formula, substitution) for substitution in self.command_to_substs[command] ]) )) return And(result) else: raise ValueError("invalid forall_mode: %s" % self.forall_mode)
def encodeTarget(target): if target in BOOL_VARS.keys(): return BOOL_VARS[target] elif target[0] in ENUM_VARS.keys(): attrName = target[0] var = ENUM_VARS[attrName] values = target[2] disjunctions = [] for val in values: disjunctions.append( ENUM_VARS[attrName] == ENUM_VALUES[attrName][val]) return Or(disjunctions) elif target[0] in NUMERIC_VARS.keys(): var = NUMERIC_VARS[target[0]] _min = int(target[2][0]) _max = int(target[2][1]) return And(var >= _min, var <= _max) elif target[0] == 'not': return Not(encodeTarget(target[1])) elif target[0] == 'and': return And([encodeTarget(x) for x in target[1:]]) elif target[0] == 'or': return Or([encodeTarget(x) for x in target[1:]]) elif target[0] == '=>': return Implies(encodeTarget(target[1]), encodeTarget(target[2])) elif target == 'true': return True elif target == 'false': return False else: raise NameError( 'could not convert propositional formula to the Z3 format')
def __gen_b_snk(self): id1 = SentenceTranslator.id_table[self.sentence[-2]] id2 = SentenceTranslator.id_table[self.sentence[-1]] size = len(SentenceTranslator.alphabet) slen = len(self.sentence) result = [] for j in range(1, SentenceTranslator.k + 1): if slen == 2: pre_idx = SentenceTranslator._quadruple_to_idx(id1, 1, id2, j) pre = SentenceTranslator.var_list[pre_idx] else: pre_id_list = [ SentenceTranslator._quadruple_to_idx(id1, j1, id2, j) for j1 in range(1, SentenceTranslator.k + 1) ] pre = SentenceTranslator._get_or_formula(pre_id_list) post_idx = SentenceTranslator._quadruple_to_idx( id2, j, size + 1, 0) post = SentenceTranslator.var_list[post_idx] result.append(Implies(pre, post)) return And(result)
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 get_mus(constraints): ''' Returns a single MUS ''' seed = set(range(len(constraints))) idx2indicator = {i:Bool(str(i)) for i in seed} indicator2idx = {b.get_id():i for (i,b) in idx2indicator.items()} s = Solver() for i, b in idx2indicator.items(): s.add(Implies(b, constraints[i])) def check_subset(current_seed): assumptions = [idx2indicator[i] for i in current_seed] return (s.check(assumptions) == sat) current = set(seed) for i in seed: if i not in current: continue current.remove(i) if not check_subset(current): core = s.unsat_core() # FIXME: do constraints never show up in the core? Seems like we could get a key error current = set(indicator2idx[ind.get_id()] for ind in core) else: current.add(i) assert not check_subset(current), "Expecting unsat at end of get_mus" return [constraints[i] for i in current]
def non_intersecting_seg_belts(belt1: SegmentedBelt , belt2: SegmentedBelt): assert isinstance(belt1, SegmentedBelt) assert isinstance(belt2, SegmentedBelt) i,j = Consts("i j", IntSort()) return ForAll([i,j], Implies(And(0 <= i, i < belt1.num_segs, 0 <=j, j < belt2.num_segs), non_intersecting_segs(belt1.segment(i), belt2.segment(j))))
def __add_rectangular_constraints(self): for p in self.__lattice.points: neighbors = self.__lattice.edge_sharing_neighbors( self.__region_id_grid, p) for n1, n2 in itertools.combinations(neighbors, 2): n1_neighbors = self.__lattice.edge_sharing_neighbors( self.__region_id_grid, n1.location) n2_neighbors = self.__lattice.edge_sharing_neighbors( self.__region_id_grid, n2.location) common_points = ( set(n.location for n in n1_neighbors) & set(n.location for n in n2_neighbors) - {p} ) if common_points: self.__solver.add( Implies( And( n1.symbol == self.__region_id_grid[p], n2.symbol == self.__region_id_grid[p] ), And(*[ self.__region_id_grid[cp] == self.__region_id_grid[p] for cp in common_points ]) ) )
def no_intersections(belt1: Belt, belt2: Belt): assert isinstance(belt1, Belt) assert isinstance(belt2, Belt) i,j = Consts("i j", IntSort()) return ForAll([i,j], Implies(And(0 <= i, i < belt1.belt_len, 0 <=j, j < belt2.belt_len), Not(belt1[i] == belt2[j])))
def constrain_no_inside_diagonal(y, x): """Add constraints for diagonally touching cells. "Inside" cells may not diagonally touch each other unless they also share an adjacent cell. """ nw = sg.grid[Point(y, x)] ne = sg.grid[Point(y, x + 1)] sw = sg.grid[Point(y + 1, x)] se = sg.grid[Point(y + 1, x + 1)] sg.solver.add( Implies(And(nw == sym.I, se == sym.I), Or(ne == sym.I, sw == sym.I))) sg.solver.add( Implies(And(ne == sym.I, sw == sym.I), Or(nw == sym.I, se == sym.I)))
def main(): """Status Park (Loop) solver example.""" for row in GIVENS: for cell in row: sys.stdout.write(cell) print() points = [] for y, row in enumerate(GIVENS): for x, c in enumerate(row): if c != X: points.append(Point(y, x)) lattice = RectangularLattice(points) sym = grilops.loops.LoopSymbolSet(lattice) sym.append("EMPTY", " ") sg = grilops.SymbolGrid(lattice, sym) grilops.loops.LoopConstrainer(sg, single_loop=True) sc = ShapeConstrainer( lattice, [Shape([Vector(y, x) for y, x in shape]) for shape in SHAPES], solver=sg.solver, allow_rotations=True, allow_reflections=True, allow_copies=False) for p in points: if GIVENS[p.y][p.x] == W: # White circles must be part of the loop. sg.solver.add(sym.is_loop(sg.grid[p])) elif GIVENS[p.y][p.x] == B: # Black circles must be part of a shape. sg.solver.add(sc.shape_type_grid[p] != -1) # A cell is part of the loop if and only if it is not part of # any shape. sg.solver.add(sym.is_loop(sg.grid[p]) == (sc.shape_type_grid[p] == -1)) # Orthogonally-adjacent cells must be part of the same shape. for n in sg.edge_sharing_neighbors(p): np = n.location sg.solver.add( Implies( And(sc.shape_type_grid[p] != -1, sc.shape_type_grid[np] != -1), sc.shape_type_grid[p] == sc.shape_type_grid[np])) if sg.solve(): sg.print() print() sc.print_shape_types() print() if sg.is_unique(): print("Unique solution") else: print("Alternate solution") sg.print() else: print("No solution")
def set_z3_assertions(self, list_of_z3_assertions: List[BoolRef]) -> None: """Each constraint comes with a set of z3 assertions to satisfy.""" if self.optional: self.append_z3_assertion( Implies(self.applied, list_of_z3_assertions)) else: self.append_z3_assertion(list_of_z3_assertions)
def _get_if_at_least_one_guard_holds_choose_exactly_one_command_formula(self): at_least_one_guard_holds_formula = Or([command.guard for command in self.input_program.module.commands]) choose_exactly_one_guard_formula = Or([And(command.guard, self.chosen_command ==i) for i, command in enumerate(self.input_program.module.commands)]) return Implies(at_least_one_guard_holds_formula, choose_exactly_one_guard_formula)
def myBinOp(op, *L): """ Shortcut to apply operation op to a list L. Returns None if the list is empty. E.g. applying 'And' over a list of formulas f1,f2..,fn yields And(f1,f2,...,fn). >>> from z3 import * >>> myAnd(*[Bool('x'),Bool('y')]) And(x, y) >>> myAnd(*[Bool('x'),None]) x >>> myAnd(*[Bool('x')]) x >>> myAnd(*[]) >>> myAnd(Bool('x'),Bool('y')) And(x, y) >>> myAnd(*[Bool('x'),Bool('y')]) And(x, y) >>> myAnd([Bool('x'),Bool('y')]) And(x, y) >>> myAnd((Bool('x'),Bool('y'))) And(x, y) >>> myAnd(*[Bool('x'),Bool('y'),True]) Traceback (most recent call last): ... AssertionError """ assert op == Z3_OP_OR or op == Z3_OP_AND or op == Z3_OP_IMPLIES if len(L) == 1 and (isinstance(L[0], list) or isinstance(L[0], tuple)): L = L[0] assert all(not isinstance(l, bool) for l in L) L = [l for l in L if is_expr(l)] if L: if len(L) == 1: return L[0] else: if op == Z3_OP_OR: return Or(L) elif op == Z3_OP_AND: return And(L) else: #IMPLIES return Implies(L[0], L[1]) else: return None
def main(): """Kuromasu solver example.""" sym = grilops.SymbolSet([("B", chr(0x2588) * 2), ("W", " ")]) lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH) sg = grilops.SymbolGrid(lattice, sym) rc = grilops.regions.RegionConstrainer(lattice, solver=sg.solver, complete=False) for p, c in GIVENS.items(): # Numbered cells may not be black. sg.solver.add(sg.cell_is(p, sym.W)) # Each number on the board represents the number of white cells that can be # seen from that cell, including itself. A cell can be seen from another # cell if they are in the same row or column, and there are no black cells # between them in that row or column. visible_cell_count = 1 + sum( grilops.sightlines.count_cells( sg, n.location, n.direction, stop=lambda c: c == sym.B) for n in sg.edge_sharing_neighbors(p)) sg.solver.add(visible_cell_count == c) # All the white cells must be connected horizontally or vertically. Enforce # this by requiring all white cells to have the same region ID. Force the # root of this region to be the first given, to reduce the space of # possibilities. white_root = min(GIVENS.keys()) white_region_id = lattice.point_to_index(white_root) for p in lattice.points: # No two black cells may be horizontally or vertically adjacent. sg.solver.add( Implies( sg.cell_is(p, sym.B), And(*[n.symbol == sym.W for n in sg.edge_sharing_neighbors(p)]))) # All white cells must have the same region ID. All black cells must not # be part of a region. sg.solver.add( If(sg.cell_is(p, sym.W), rc.region_id_grid[p] == white_region_id, rc.region_id_grid[p] == -1)) def print_grid(): sg.print(lambda p, _: f"{GIVENS[(p.y, p.x)]:02}" if (p.y, p.x) in GIVENS else None) if sg.solve(): print_grid() print() if sg.is_unique(): print("Unique solution") else: print("Alternate solution") print_grid() else: print("No solution")
def _generate_global_constraint_b(cls): parts = [] # alphabet1 -> alphabet2 -> alphabet3 part_1 = [] for key, value in cls.alphabet1_to_alphabet_imply_table.items(): if value > 0: id1 = key[0] id2 = key[1] id3 = key[2] pre_post_list = cls._get_alphabet_to_alphabet_imply_list( id1, id2, id3, True) for pre_post in pre_post_list: part_1.append( Implies(cls._get_or_formula(pre_post[0]), cls._get_or_formula(pre_post[1]))) parts.extend(part_1) # id1 -> id2 -> id3 part_2 = [] for key, value in cls.alphabet_to_alphabet_imply_table.items(): if value > 0: id1 = key[0] id2 = key[1] id3 = key[2] pre_post_list = cls._get_alphabet_to_alphabet_imply_list( id1, id2, id3) for pre_post in pre_post_list: part_2.append( Implies(cls._get_or_formula(pre_post[0]), cls._get_or_formula(pre_post[1]))) parts.extend(part_2) # id1 -> id2 -> snk part_3 = [] for key, value in cls.alphabet_to_snk_imply_table.items(): if value > 0: id1 = key[0] id2 = key[1] pre_post_list = cls._get_alphabet_to_alphabet_imply_list( id1, id2, cls.get_size() + 1) for pre_post in pre_post_list: part_3.append( Implies(cls._get_or_formula(pre_post[0]), cls._get_or_formula(pre_post[1]))) parts.extend(part_3) return parts
def _get_sink_phi_zero_formula(self): vars_in_range = self.get_bounds_formula() not_goal = Not(self.goal_expr) no_guard_active = And([ Not(command.guard) for command in self.input_program.module.commands ]) return Implies(And(vars_in_range, not_goal, no_guard_active), 0 == self.env.apply_to_state_valuation(self.phi))
def deterministic(p): x,y,z = consts('x y z', U) return And( ForAll(x, Exists(y, p.post(x, y))), ForAll([x,y,z], Implies( And(p.post(x, y), p.post(x, z)), y == z )) )
def _get_frame_zero_formula(self): not_goal = Not(self.goal_expr) no_guard_active = And([ Not(command.guard) for command in self.input_program.module.commands ]) return self.env.forall( Implies(And(not_goal, no_guard_active), 0 == self.env.apply_to_state_valuation(self.frame)))
def _get_commands_formula_deterministic(self): phi_applied = self.env.apply_to_state_valuation(self.phi) frames_iter = iter(self.frames) return And([ Implies(And(Not(self.goal_expr), command.guard, self.chosen_command == i), phi_applied == self._get_updates_formula(command.updates, frames_iter) ) for i, command in enumerate(self.input_program.module.commands) ])