def snakes_find_the_head(g): # We'll want a type that represents a cell in the grid. We use a datatype because we can make it a sum type - # that is, its 0-arity constructors represent a closed enumeration of distinct objects. Cell = Datatype("Cell") for x, y in g.coords(): if g.snake(x, y) is not None: Cell.declare("cell_{}_{}".format(x, y)) Cell = Cell.create() # We'll have two functions that we explicitly declare. One is the short-distance "connected" relationship. # The other is a convenience function for turning the coordinates of a cell into the datatype member that # represents that position. Connected = Function("Connected", Cell, Cell, BoolSort()) XYToCell = Function("XYToCell", IntSort(), IntSort(), Cell) cell = {} for x, y in g.coords(): if g.snake(x, y) is not None: cell[x, y] = getattr(Cell, "cell_{}_{}".format(x, y)) g.add(XYToCell(x, y) == cell[x, y]) # Two cells are connected *if and only* if they are adjacent and both hold snakes # We need to be really clear about the "and only if" part; a naive implementation here will let the # solver fill in other arbitrary values for `Connected` in order to make the desired outcome true. # We do this by ensuring there's a value declared for our Connected relationship between every pair # of potential arguments. for x1, y1 in g.coords(): c1 = g.snake(x1, y1) if c1 is None: continue # If there's a snake here, the cell is connected to itself g.add(Connected(cell[x1, y1], cell[x1, y1]) == c1) for x2, y2 in g.coords(): c2 = g.snake(x2, y2) if c2 is None or (x1, y1) == (x2, y2): continue if manh(x1, y1, x2, y2) == 1: g.add(Connected(cell[x1, y1], cell[x2, y2]) == And(c1, c2)) else: # Without this, our function declaration is only partial. The solver can fill in missing values # in order to scupper our good intentions. g.add(Not(Connected(cell[x1, y1], cell[x2, y2]))) # The transitive closure of Connectedness is Reaches Reaches = TransitiveClosure(Connected) # For every cell in the grid, if it's a snake then we can connect it to the head position hx, hy = g.head() for x, y in g.coords(): c = g.snake(x, y) if c is None: continue g.add(Implies(c, Reaches(cell[x, y], XYToCell(hx, hy))))
def __init__(self, max_segs=None): self.corners_x = Function(f'seg_belt{self._IDX}_x', IntSort(), IntSort()) self.corners_y = Function(f'seg_belt{self._IDX}_y', IntSort(), IntSort()) self.num_segs = Const(f'seg_belt{self._IDX}_num_segs', IntSort()) SOL.add(self.num_segs > 0) if max_segs: SOL.add(self.num_segs <= max_segs) i,j = Consts("i j", IntSort()) SOL.add(ForAll([i], Implies(And(0 <= i, i < self.num_segs), Or(self.segment(i).horizontal(), self.segment(i).vertical())))) self.__class__._IDX += 1
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 function(self, name, return_sort: z3.SortRef) -> z3.ExprRef: """Return a new function that receives all environment variables as arguments.""" params = self._z3_sorts if self.forall_mode != ForallMode.FORALL_GLOBALS else [] func = Function(name, params + [return_sort]) # Registering types for faster apply. if str(return_sort) == "Real": Ref = RatNumRef elif str(return_sort) == "Int": Ref = IntNumRef else: assert str(return_sort) == "Bool" Ref = BoolRef self._function_types[func.get_id()] = Ref return func
def declare_predicate(self, elem_predicate: Predicate): arg_types = [ x.get_engine_obj(self._name) for x in elem_predicate.get_arg_types() ] arg_types += [BoolSort()] rel = Function(elem_predicate.get_name(), *arg_types) self._solver.register_relation(rel) elem_predicate.add_engine_object(rel)
def add_observation_constraints(self, s, planner, ground_actions, length, observations): obsSort = DeclareSort('Obs') orderObs = Function('orderObs', obsSort, IntSort()) orderExec = Function('orderExec', obsSort, IntSort()) obsConsts = [] for i in range(0, len(observations)): o = Const(str(observations[i]), obsSort) obsConsts.append(o) s.add(orderObs(o) == i) for t in range(0, length): # forced_obs = [] for action in ground_actions: index = observations.index_of(action.signature()) if index > -1: obsC = obsConsts[index] # forced_obs.append(planner.action_prop_at(action, t)) s.add( Implies(planner.action_prop_at(action, t), orderExec(obsC) == t)) # s.add(Or(*forced_obs)) x = Const('x', obsSort) y = Const('y', obsSort) # orderSync = Function('order-sync', BoolSort()) s.add( ForAll([x, y], Implies( orderObs(x) < orderObs(y), orderExec(x) < orderExec(y)))) s.add( ForAll([x, y], Implies( orderObs(x) == orderObs(y), orderExec(x) == orderExec(y)))) s.add( ForAll([x, y], Implies( orderObs(x) > orderObs(y), orderExec(x) > orderExec(y))))
## Qui a tué le chat? from z3 import Function, EnumSort, BoolSort, ForAll, Solver, Implies, Const, Consts, Exists, Not, And, Or # type et ses constantes Entity, (jack, luna, curiosity) = EnumSort('Entity', ('jack', 'luna', 'curiosity')) Animal = Function('Animal', Entity, BoolSort()) Aimer = Function('Aimer', Entity, Entity, BoolSort()) Tuer = Function('Tuer', Entity, Entity, BoolSort()) s = Solver() x, y, z = Consts('x y z', Entity) # Tous ceux qui aiment tous les animaux sont aimés par qqun s.add( ForAll( x, Implies(ForAll(y, Implies(Animal(y), Aimer(x, y))), Exists(z, Aimer(z, x))))) # Quiconque tue un animal n’est aimé par personne s.add( ForAll( x, Implies(Exists(y, And(Animal(y), Tuer(x, y))), ForAll(z, Not(Exists(z, Aimer(z, x))))))) # Jack aime tous les animaux s.add(ForAll(x, Implies(Animal(x), Aimer(jack, x)))) # C’est soit Jack soit Curiosité qui a tué le chat appelé Luna s.add(Or(Tuer(jack, luna), Tuer(curiosity, luna)))
# functions - on these domains. # So, first we declare two enum 'sorts'. In Z3 a 'sort' is like a type. # EnumSort thus is a sort of enumerable many values. In this case, Knight, # Knave, and Spy. # The first is the name (Role) followed by a tuple of all values. Role, (Knight, Knave, Spy) = EnumSort('Role', ('Knight', 'Knave', 'Spy')) # Same for Person. Values A, B, C. Person, (A,B,C) = EnumSort('Person', ('A', 'B', 'C')) # Now, what we want to do is reconstruct who is who based on puzzle # statements as predicates. # Let's declare a function R which gives the role of a person. # This is a function which maps from Person to Role: R = Function('R', Person, Role) # As you can see we have just declared a function - there's no # 'implementation' or code. This because if we know how to encode # this function, the problem would be solved! (We would know who was # who.) In fact, the function R is the unknown quantity, this is what # our solver will reconstruct. So it is an unknown! # But, as it is a z3 function, we can go ahead and write predicates # using it. For example, R(A) != R(B) would encode that the role of A cannot be # the same as the role of B. # In fact, the first general constraint of the game - that there is always one # person of each sort - could be encoded in this manner: # Saying "The role of A is not the same as the role of B, is not the same as role of C." # Or in code as `And([R(A) != R(B), R(B) != R(C), R(C) != R(A)])`
def new_interpretation(): return Function('interpretation', Variable, Node)
import sys from z3 import Const, DeclareSort, Function, Solver print(""" S = DeclareSort('S') # Declare an uninterpreted sort S f = Function('f', S, S) # Declare function f : S -> S x = Const('x', S) # Declare constant x : S """) sys.stdin.readline() S = DeclareSort('S') f = Function('f', S, S) x = Const('x', S) print(""" s = Solver() # Create a solver context s.add(x == f(f(x))) # Assert fact 1 s.add(x == f(f(f(x)))) # Assert fact 2 """) sys.stdin.readline() s = Solver() s.add(x == f(f(x))) s.add(x == f(f(f(x)))) print(""" print s # Print solver's state """) sys.stdin.readline() print(">>", s)
## Les dragons chinois from z3 import Function, EnumSort, BoolSort, ForAll, Solver, Implies, Const, Consts, Exists, Not, And, Or animal, (dragon) = EnumSort('animal', ('dragon')) humain, (touriste) = EnumSort('humain', ('touriste')) est_fort = Function('est_fort', animal, BoolSort()) souffler_feu = Function('souffler_feu', animal, BoolSort()) # Formaliser les phrases suivantes : # Aucun dragon fort ne peut ne pas souffler le feu. # Un dragon rusé a toujours des cornes. # Aucun dragon faible n’a des cornes. # Les touristes ne chassent que les dragons ne soufflant pas le feu. # On veut répondre à la question suivante : # Un dragon rusé doit-il craindre les touristes ? (autrement dit : est-il chassé ?) """ # Corrigé from z3 import * Dragon, (drago,) = EnumSort('Dragon', ('drago',)) fort = Function('fort',Dragon,BoolSort()) feu = Function('feu',Dragon,BoolSort()) ruse = Function('ruse',Dragon,BoolSort()) cornes = Function('cornes',Dragon,BoolSort()) chasse = Function('chasse',Dragon,BoolSort())
from z3 import Not, And, ForAll, Implies, IntSort, BoolSort, Solver, Function, Int __counter = 100 __agents = {} def new_noun(name): global __counter global __agents if name not in __agents: __agents[name] = __counter __counter += 1 return Int(__agents[name]) IsKinase = Function("is_kinase", IntSort(), BoolSort()) IsActiveWhenPhosphorylated = Function("is_active_when_phosphorylated", IntSort(), BoolSort()) Phosphorylates = Function("phosphorylates", IntSort(), IntSort(), BoolSort()) Activates = Function("activates", IntSort(), IntSort(), BoolSort()) ActivityIncreasesActivity = Function("activity_increases_activity", IntSort(), IntSort(), BoolSort()) solver = Solver() MEK1 = new_noun("MEK1") ERK1 = new_noun("ERK1") RAF = new_noun("RAF") HRAS = new_noun("HRAS")
def function(name, *sort): return Function(id_name(name), sort)
def __init__(self, name: str, max_num_vars: int): self.name = name self.input_range = randint(1, min(max_num_vars, 5)) z3_input = [RealSort()] * self.input_range self.z3 = Function(name, *z3_input, RealSort())
#!/usr/bin/env python # from TU Graz presentation by Vedad Hadzic from z3 import Solver, Int, IntSort, BoolSort, Function from z3 import ForAll, And, Or, Not, Implies, sat as SAT # create an integer and a function x = Int("x") f = Function("f", IntSort(), IntSort(), BoolSort()) solver = Solver() solver.add(ForAll([x], Implies(And(x > 0, x < 4), f(x, x)))) solver.add(ForAll([x], Implies(Or(x <= 0, x >= 4), Not(f(x, x))))) if solver.check() != SAT: exit(1) m = solver.model() print(f'f(0,0)={m.eval(f(0,0))}') print(f'f(1,2)={m.eval(f(1,2))}') print(f'f(2,3)={m.eval(f(2,3))}') print(f'f(3,3)={m.eval(f(3,3))}') for i in range(0, 5): # assert ∀ x in (0,4). f(x,x) = 1 # check if satisfiable # get the solution # print the relation table vs = [int(bool(m.eval(f(i, j)))) for j in range(0, 5)]
# This represents a set of possible <graph, action> pairs -- a single Kappa # chemical system or model. Model = Datatype('Model') Model.declare('model', ('pregraph', Graph), ('action', Action), ('postgraph', Graph)) Model = Model.create() import collections Submodel = collections.namedtuple('Submodel', ['pregraph', 'action', 'postgraph']) # This represents a set of sets of <graph, action> pairs -- many possible # chemical systems that an L statement could represent. ModelSet = Function('possible_system', Model, BoolSort()) Variable = Datatype('Variable') Variable.declare('variable', ('get_name', IntSort())) Variable = Variable.create() def new_thing_function(datatype, default_name): def new_thing(nickname=default_name): return Const(_collision_free_string(nickname), datatype) return new_thing new_variable = new_thing_function(Variable, 'var') new_graph = new_thing_function(Graph, 'graph')
from z3 import EnumSort, Solver, Function, Const, sat import itertools R, values = EnumSort('R', ('alpha', 'beta', 'gamma')) plus = Function('plus', R, R, R) multiply = Function('multiply', R, R, R) neutral_plus = Const('neutral_plus', R) neutral_multiply = Const('neutral_multiply', R) solver = Solver() for a, b, c in itertools.product(values, repeat=3): # (R, +) is a commutative monoid with identity element 0: # (a + b) + c = a + (b + c) # 0 + a = a + 0 = a # a + b = b + a solver.add(plus(plus(a, b), c) == plus(a, plus(b, c))) solver.add(plus(neutral_plus, a) == a) solver.add(plus(a, neutral_plus) == a) solver.add(plus(a, b) == plus(b, a)) # (R, ⋅) is a monoid with identity element 1: # (a⋅b)⋅c = a⋅(b⋅c) # 1⋅a = a⋅1 = a solver.add(multiply(multiply(a, b), c) == multiply(a, multiply(b, c))) solver.add(multiply(neutral_multiply, a) == a) solver.add(multiply(a, neutral_multiply) == a) # Multiplication left and right distributes over addition:
def new_modelset(nickname='modelset'): return Function(_collision_free_string(nickname), Model, BoolSort())
} dna_to_z3_enum_codon = { str_codon: z3_codon for str_codon, z3_codon in zip(triplet_dna_codons, z3_enum_codons) } dna_to_z3_enum_nuc = { str_nuc: z3nuc for str_nuc, z3nuc in zip(dNTPs, z3_enum_nucleotides) } rna_to_z3_enum_codon = { str_codon: z3_codon for str_codon, z3_codon in zip(triplet_rna_codons, z3_enum_codons) } amino_to_z3_enum_amino = { str_amino: z3_amino for str_amino, z3_amino in zip(aminoacids, z3_enum_aminos) } amino_to_z3_bv_amino = { str_amino: z3_bitvec_amino for str_amino, z3_bitvec_amino in zip(aminoacids, z3_bitvec_aminos) } # z3 Functions f_nuc_to_codon = Function("nucleotides -> codons", NucleotideBitVecSort, NucleotideBitVecSort, NucleotideBitVecSort, CodonEnumSort) f_codon_to_amino = Function("codons -> aminos", CodonEnumSort, AminoBitVecSort) f_nuc_to_amino = Function("nucleotides -> aminos", NucleotideBitVecSort, NucleotideBitVecSort, NucleotideBitVecSort, AminoBitVecSort)
print(problem) # declare finite data type mansion MansionDT = Datatype("Mansion") MansionDT.declare("Agatha") MansionDT.declare("Butler") MansionDT.declare("Charles") # create finite sort Mansion Mansion = MansionDT.create() # constants for ease of reference a, b, c = Mansion.Agatha, Mansion.Butler, Mansion.Charles # declare predicates killed = Function("killed", Mansion, Mansion, BoolSort()) hates = Function("hates", Mansion, Mansion, BoolSort()) richer = Function("richer", Mansion, Mansion, BoolSort()) # quantified variables x = Const("x", Mansion) y = Const("y", Mansion) e1 = Exists([x], killed(x, a)) e2a = ForAll([x, y], Implies(killed(x, y), hates(x, y))) e2b = ForAll([x, y], Implies(killed(x, y), Not(richer(x, y)))) e3 = ForAll([x], Implies(hates(a, x), Not(hates(c, x)))) e4a = hates(a, a) e4b = hates(a, c) e5 = ForAll([x], Implies(Not(richer(x, a)), hates(b, x))) e6 = ForAll([x], Implies(hates(a, x), hates(b, x)))