def __eq__(self, other): if isinstance(other, z3.ExprRef): # if we compare to a z3 expression we are free to chose the value # it does not matter if we are out of range, this just means false # with this we can generate an interpretable type # TODO: Should the type differ per invocation? z3_type = other.sort() return z3.Const(self.name, z3_type) == other else: log.warning("Enum: Comparison to %s of type %s not supported", other, type(other)) return z3.BoolVal(False)
def _addConstraints(self, solver): solver.add(self.constraints) p = z3.Const('__ips_acl_Packet_%s' % (self.ips), self.ctx.packet) addr_a = z3.Const('__ips_acl_cache_a_%s' % (self.ips), self.ctx.address) port_a = z3.Const('__ips_acl_port_a_%s' % (self.ips), z3.IntSort()) addr_b = z3.Const('__ips_acl_cache_b_%s' % (self.ips), self.ctx.address) port_b = z3.Const('__ips_acl_port_b_%s' % (self.ips), z3.IntSort()) aclConstraints = map(lambda (a, b): z3.And(self.ctx.packet.src(p) == a, \ self.ctx.packet.dest(p) == b), self.acls) eh = z3.Const('__ips_acl_node_%s' % (self.ips), self.ctx.node) # Constraints for what holes are punched # \forall a, b cached(a, b) \iff \exists e, p send(f, e, p) \land # p.src == a \land p.dest == b \land ctime(a, b) = etime(ips, p, R) \land # neg(ACL(p)) if len(aclConstraints) > 0: solver.add(z3.ForAll([addr_a, port_a, addr_b, port_b], self.cached(addr_a, port_a, addr_b, port_b) ==\ z3.Exists([eh, p], \ z3.And(self.ctx.recv(eh, self.ips, p), \ z3.And(self.ctx.packet.src (p) == addr_a, self.ctx.packet.dest(p) == addr_b, \ self.ctx.src_port (p) == port_a, self.ctx.dest_port (p) == port_b, \ self.ctime (addr_a, port_a, addr_b, port_b) == self.ctx.etime(self.ips, p, self.ctx.recv_event), \ z3.Not(z3.Or(aclConstraints))))))) else: solver.add(z3.ForAll([addr_a, port_a, addr_b, port_b], self.cached(addr_a, port_a, addr_b, port_b) ==\ z3.Exists([eh, p], \ z3.And(self.ctx.recv(eh, self.ips, p), \ z3.And(self.ctx.packet.src (p) == addr_a, self.ctx.packet.dest(p) == addr_b, \ self.ctx.src_port (p) == port_a, self.ctx.dest_port (p) == port_b, \ self.ctime (addr_a, port_a, addr_b, port_b) == self.ctx.etime(self.ips, p, self.ctx.recv_event))))))
def reconciliate(self, context): """Generate specialization predicates Translation has generated semi specialized predicates. It is time now to define those semi specialized predicates using the fully specialized ones. :param context: A Z3 context to create the new rules. """ for table, fixed_pos in six.iteritems(self.grounded): base_pred = self.relations[table] arity = base_pred.arity() # For each argument of the base pred we build a variable vars = [ z3.Const("V_{}_{}".format(table, i), base_pred.domain(i)) for i in range(arity) ] # All the tuples of ground values associated to our pred. row = self.items.get(table, {}) # from argument position to index in the tuple of ground value. idx = {i: p for p, i in enumerate(fixed_pos)} # enumerate all the values and associated pred. for val1, pred1 in six.iteritems(row.get(fixed_pos, {})): # get partial predicates for partial_pos, valpred in six.iteritems(row): if partial_pos == fixed_pos: # not this one: it is not partial continue # project our full tuple to what is fixed for this # combination val2 = tuple([val1[idx[pos]] for pos in partial_pos]) pred2 = valpred.get(val2, None) if pred2 is None: continue # We found a predicate. We build the rule. # forall args1. pred2(args2) :- pred1(args1) # args2 is args1 augmented with fixed args from the record # not captured by pred2. args1 = [ vars[i] for i in range(arity) if i not in fixed_pos ] args2 = [ (val1[idx[i]] if i in fixed_pos else vars[i]) for i in range(arity) if i not in partial_pos ] rule = z3.Implies(pred1(*args1), pred2(*args2)) if len(args1) > 0: rule = z3.ForAll(args1, rule) context.rule(rule)
def make_z3_const(self, etype, name): if etype.equals(Bool) or etype.is_const(): z3_sort = self.get_z3_sort(etype) z3_const = z3.Const(name, z3_sort) self.symbol_dict[name] = z3_const return z3_const elif etype.is_bound() and etype.binder.is_pi(): arg_sorts, return_sort = self.get_z3_fun_type(etype) z3_func = z3.Function(name, *(arg_sorts + [return_sort])) self.symbol_dict[name] = z3_func return z3_func else: raise Z3_Unexpected_Type('Cannot handle polymorphism')
def numeral_to_z3(num): # TODO: allow other numeric types z3sort = lookup_native(num.sort, sorts, "sort") if z3sort == None: return z3.Const(num.name, num.sort.to_z3()) # uninterpreted sort try: name = num.name[1:-1] if num.name.startswith('"') else num.name if isinstance(z3sort, z3.SeqSortRef) and z3sort.is_string(): return z3.StringVal(name) return z3sort.cast(str(int(name, 0))) # allow 0x,0b, etc except: raise iu.IvyError( None, 'Cannot cast "{}" to native sort {}'.format(num, z3sort))
def _firewallSendRules(self): p_0 = z3.Const('%s_firewall_send_p_0' % (self.fw), self.ctx.packet) p_1 = z3.Const('%s_firewall_send_p_1' % (self.fw), self.ctx.packet) n_0 = z3.Const('%s_firewall_send_n_0' % (self.fw), self.ctx.node) n_1 = z3.Const('%s_firewall_send_n_1' % (self.fw), self.ctx.node) t_0 = z3.Int('%s_firewall_send_t_0' % (self.fw)) t_1 = z3.Int('%s_firewall_send_t_1' % (self.fw)) self.acl_func = z3.Function('%s_acl_func' % (self.fw), self.ctx.packet, z3.BoolSort()) self.constraints.append(z3.ForAll([n_0, p_0, t_0], z3.Implies(self.ctx.send(self.fw, n_0, p_0, t_0), \ z3.Exists([n_1, t_1], \ z3.And(self.ctx.recv(n_1, self.fw, p_0, t_1), \ z3.Not(self.failed(t_0)), \ z3.Not(self.failed(t_1)), \ t_1 < t_0))))) # Let us first try a non-learning firewall self.constraints.append(z3.ForAll([n_0, p_0, t_0], z3.Implies(\ self.ctx.send(self.fw, n_0, p_0, t_0), \ z3.And(self.acl_func(p_0), z3.Not(self.failed(t_0))))))
def _wanOptSendRule(self): p1 = z3.Const('__wanopt_unmoded_packet_%s' % (self.opt), self.ctx.packet) p2 = z3.Const('__wanopt_moded_packet_%s' % (self.opt), self.ctx.packet) e1 = z3.Const('__wanopt_ingress_node_%s' % (self.opt), self.ctx.node) e2 = z3.Const('__wanopt_egress_node_%s' % (self.opt), self.ctx.node) e3 = z3.Const('__wanopt_not_egress_node_%s' % (self.opt), self.ctx.node) self.constraints.append( \ z3.ForAll([e1, p1], \ z3.Implies(self.ctx.send(self.opt, e1, p1), \ z3.Exists([e2, p2], \ z3.And(self.ctx.recv(e2, self.opt, p2), \ self.ctx.PacketsHeadersEqual(p1, p2), \ self.ctx.packet.body(p1) == self.transformation(self.ctx.packet.body(p2)), \ self.ctx.packet.orig_body(p1) == self.ctx.packet.orig_body(p2), \ z3.Not(z3.Exists([e3], \ z3.And(e3 != e1, \ self.ctx.send(self.opt, e3, p2)))), \ self.ctx.etime(self.opt, p1, self.ctx.send_event) > \ self.ctx.etime(self.opt, p2, self.ctx.recv_event))))))
def CheckDataIsolationProperty(self, src, dest): class DataIsolationResult(object): def __init__(self, result, violating_packet, last_hop, last_time, ctx, assertions, model=None): self.ctx = ctx self.result = result self.violating_packet = violating_packet self.last_hop = last_hop self.model = model self.last_time = last_time self.assertions = assertions assert (src in self.net.elements) assert (dest in self.net.elements) self.solver.push() self.AddConstraints() p = z3.Const('check_isolation_p_%s_%s' % (src.z3Node, dest.z3Node), self.ctx.packet) n_0 = z3.Const('check_isolation_n_0_%s_%s' % (src.z3Node, dest.z3Node), self.ctx.node) n_1 = z3.Const('check_isolation_n_1_%s_%s' % (src.z3Node, dest.z3Node), self.ctx.node) t = z3.Int('check_isolation_t_%s_%s' % (src.z3Node, dest.z3Node)) self.solver.add(self.ctx.recv(n_0, dest.z3Node, p, t)) self.solver.add(self.ctx.packet.origin(p) == src.z3Node) result = self.solver.check() model = None assertions = self.solver.assertions() if result == z3.sat: model = self.solver.model() self.solver.pop() return DataIsolationResult(result, p, n_0, t, self.ctx, assertions, model)
def _relational_cardinality_constraint(self, relation: z3.FuncDeclRef, n: int) -> z3.ExprRef: if relation.arity() == 0: return z3.BoolVal(True) consts = [[ z3.Const(f'card$_{relation}_{i}_{j}', relation.domain(j)) for j in range(relation.arity()) ] for i in range(n)] vs = [ z3.Const(f'x$_{relation}_{j}', relation.domain(j)) for j in range(relation.arity()) ] result = z3.ForAll( vs, z3.Implies( relation(*vs), z3.Or(*(z3.And(*(c == v for c, v in zip(cs, vs))) for cs in consts)))) return result
def does_contain(*tup): assert len(tup) == len(kept_columns) col_map = dict(zip(kept_columns, tup)) variables = [] existentials = [] for c in self.columns: if c in col_map: variables.append(col_map[c]) else: var = z3.Const(c, self.sort) existentials.append(var) variables.append(var) return z3.Exists(existentials, self.does_contain(*variables))
def lemma_to_string(lemma, pred): """ convert a lemma returned by get_cover_delta into a string that parse_smt2_string can parse """ const_list = [z3.Const(pred.name()+"_"+str(j), pred.domain(j)) for j in range(pred.arity())] lhs = pred(*const_list) rhs = z3.substitute_vars(lemma, *(const_list)) imp = z3.Implies(lhs, rhs) forall = z3.ForAll(list(reversed(const_list)), imp) lemma_str = "(assert %s)"%forall.sexpr() print("\toriginal lemma:", lemma) print("\tforall lemma:", forall.body().arg(1)) assert lemma == forall.body().arg(1) return lemma_str
def smt_var(typ: Type, name: str): z3type = type_to_smt_sort(typ) if z3type is None: if getattr(typ, '__origin__', None) is Tuple: if len(typ.__args__) == 2 and typ.__args__[1] == ...: z3type = z3.SeqSort(type_to_smt_sort(typ.__args__[0])) else: return tuple( smt_var(t, name + str(idx)) for (idx, t) in enumerate(typ.__args__)) var = z3.Const(name, z3type) if isinstance(z3type, z3.SeqSortRef): var = SymbolicSeq(var) return var
def bind_to_name(self, name): for member_name, member_constructor in self.members.items(): var_name = f"{name}.{member_name}" # retrieve the member we are accessing member = self.resolve_reference(member_name) member_type = member_constructor.range() if isinstance(member, P4ComplexInstance): # it is a complex type # propagate the parent constant to all children member.bind_to_name(var_name) else: # a simple z3 type, just update the constructor self.set_or_add_var( member_name, z3.Const(var_name, member_type))
def _(term, smt): with smt.local_nonpoison() as n: x = smt.eval(term.x) # if term is never poison, return it's interp directly if not n: return x ty = smt.type(term) u = z3.Const('frozen_' + term.name, _ty_sort(ty)) # TODO: don't assume unique names smt.add_qvar(u) return z3.If(mk_and(n), x, u)
def _webProxyFunctions(self): self.cached = z3.Function('__webproxy_cached_%s' % (self.proxy), self.ctx.address, z3.IntSort(), z3.BoolSort()) self.ctime = z3.Function('__webproxy_ctime_%s' % (self.proxy), self.ctx.address, z3.IntSort(), z3.IntSort()) self.cresp = z3.Function('__webproxy_cresp_%s' % (self.proxy), self.ctx.address, z3.IntSort(), z3.IntSort()) self.corigbody = z3.Function('__webproxy_corigbody_%s' % (self.proxy), self.ctx.address, z3.IntSort(), z3.IntSort()) self.corigin = z3.Function('__webproxy_corigin_%s' % (self.proxy), self.ctx.address, z3.IntSort(), self.ctx.node) self.crespacket = z3.Function( '__webproxy_crespacket_%s' % (self.proxy), self.ctx.address, z3.IntSort(), self.ctx.packet) self.creqpacket = z3.Function( '__webproxy_creqpacket_%s' % (self.proxy), self.ctx.address, z3.IntSort(), self.ctx.packet) self.creqopacket = z3.Function( '__webproxy_creqopacket_%s' % (self.proxy), self.ctx.address, z3.IntSort(), self.ctx.packet) a = z3.Const('__webproxyfunc_cache_addr_%s' % (self.proxy), self.ctx.address) i = z3.Const('__webproxyfunc_cache_body_%s' % (self.proxy), z3.IntSort()) # Model cache as a function # If not cached, cache time is 0 self.constraints.append( z3.ForAll([a, i], z3.Not(self.cached(a, i)) == (self.ctime(a, i) == 0))) self.constraints.append( z3.ForAll([a, i], z3.Not(self.cached(a, i)) == (self.cresp(a, i) == 0)))
def find_val_in_heap(self, value: object) -> z3.ExprRef: lastheap = self.heaps[-1] with self.framework(): for (curref, curtyp, curval) in lastheap: if curval is value: debug('HEAP value lookup for ', type(value), ' value type; found', curref) return curref ref = z3.Const('heapkey' + str(value) + self.uniq(), HeapRef) for (curref, _, _) in lastheap: self.add(ref != curref) self.add_value_to_heaps(ref, type(value), value) debug('HEAP value lookup for ', type(value), ' value type; created new ', ref) return ref
def relation_to_z3( r: syntax.RelationDecl, key: Optional[str]) -> Union[z3.FuncDeclRef, z3.ExprRef]: if r.mutable: assert key is not None if key not in r.mut_z3: if r.arity: a = [Z3Translator.sort_to_z3(s) for s in r.arity] + [z3.BoolSort()] r.mut_z3[key] = z3.Function(key + '_' + r.name, *a) else: r.mut_z3[key] = z3.Const(key + '_' + r.name, z3.BoolSort()) return r.mut_z3[key] else: if r.immut_z3 is None: if r.arity: a = [Z3Translator.sort_to_z3(s) for s in r.arity] + [z3.BoolSort()] r.immut_z3 = z3.Function(r.name, *a) else: r.immut_z3 = z3.Const(r.name, z3.BoolSort()) return r.immut_z3
def numeral_to_z3(num): # TODO: allow other numeric types tn = ivy_logic.sig.default_numeric_sort if num.sort != tn: return z3.Const(num.name, num.sort.to_z3()) num = num.name z3sort = lookup_native(tn, sorts, "sort") if z3sort == None: raise iu.IvyError( None, 'default numeric type {} is uninterpreted'.format(tn)) try: return z3sort.cast(num) except: raise IvyError(None, 'Cannot cast "{}" to native sort {}'.format(num, tn))
def LearningFwModel(mc, acl): p = z3.Const('p', mc.ctx.packet) #acl = ConfigMap('acl', mc, [mc.ctx.address, mc.ctx.address], z3.BoolSort()) flows = ModelMap( 'flows', mc, [mc.ctx.address, mc.ctx.address, z3.IntSort(), z3.IntSort()], z3.BoolSort()) src = z3.Const('src', mc.ctx.address) dest = z3.Const('dest', mc.ctx.address) sp = z3.Int('sp') dp = z3.Int('dp') Body(mc, \ [lambda: ModelRecv(mc, p), lambda: If(mc, acl[(mc.ctx.packet.src(p), mc.ctx.packet.dest(p))], \ [lambda: ModelSend(mc, p), \ lambda: src == mc.ctx.packet.src(p), \ lambda: dest == mc.ctx.packet.dest(p), \ lambda: sp == mc.ctx.src_port(p), \ lambda: dp == mc.ctx.dest_port(p), \ lambda: flows.set((src, dest, sp, dp), True, [src, dest, sp, dp])], \ [lambda: If(mc, flows[(mc.ctx.packet.dest(p), mc.ctx.packet.src(p), mc.ctx.dest_port(p), \ mc.ctx.src_port(p))], \ [lambda: ModelSend(mc, p)])])])
def CacheModel(mc): cache = ModelMap('cached', mc, [z3.IntSort()], z3.BoolSort()) cbody = ModelMap('cbody', mc, [z3.IntSort()], z3.IntSort()) is_request = ModelMap( 'is_request', mc, [mc.ctx.address, z3.IntSort(), z3.IntSort()], z3.BoolSort()) p_req = z3.Const('p_req', mc.ctx.packet) p_resp = z3.Const('p_resp', mc.ctx.packet) Body(mc, \ [lambda: ModelRecv(mc, p_req), \ lambda: If(mc, cache[mc.ctx.packet.body(p_req)], \ [lambda: mc.ctx.packet.body(p_resp) == cbody[mc.ctx.packet.body(p_req)], \ lambda: mc.ctx.packet.src(p_resp) == mc.ctx.packet.dest(p_req), \ lambda: mc.ctx.src_port(p_resp) == mc.ctx.dest_port(p_req), \ lambda: mc.ctx.dest_port(p_resp) == mc.ctx.src_port(p_req), \ lambda: ModelSend(mc, p_resp)], [lambda: mc.ctx.packet.body(p_resp) == mc.ctx.packet.body(p_req), lambda: mc.ctx.packet.dest(p_resp) == mc.ctx.packet.dest(p_req), lambda: mc.ctx.packet.dest_port(p_resp) == mc.ctx.packet.dest_port(p_req), lambda: mc.ctx.packet.origin(p_resp) == mc.ctx.packet.origin(p_req), lambda: mc.ctx.packet.orig_body(p_resp) == mc.ctx.packet.orig_body(p_req), lambda: mc.ctx.nodeHasAddr(mc.ctx.packet.src(p_resp), mc.node), lambda: ModelSend(mc, p_resp)])])
def register(self, definition): # print('register?', definition) refs = self.env.refs if type(definition) == ast.Name: raise ResolutionError(definition) return z3.Const(definition.id, Unk) if type(definition) == ast.arg: name = definition.arg elif type(definition) == ast.FunctionDef: name = definition.name else: # z3 function (z3 functions must be called immediately - they are not values) # print('register abort : ', repr(definition)) return definition # if hasattr(definition, 'name'): # name = definition.name() # else: # name = definition.__name__ if definition not in refs: #print('register new ref: ', name, id(definition), " at ", # getattr(definition, 'lineno', ''), ":", # getattr(definition, 'col_offset', '') #) refs[definition] = z3.Const(name, Unk) return refs[definition]
def get_type(self, typ: Type) -> z3.ExprRef: pytype_to_smt = self.pytype_to_smt if typ not in pytype_to_smt: stmts = [] expr = z3.Const('typrepo_'+typ.__qualname__, PYTYPE_SORT) for other_pytype, other_expr in pytype_to_smt.items(): stmts.append(other_expr != expr) stmts.append(SMT_SUBTYPE_FN(expr, other_expr) == issubclass(typ, other_pytype)) stmts.append(SMT_SUBTYPE_FN(other_expr, expr) == issubclass(other_pytype, typ)) stmts.append(SMT_SUBTYPE_FN(expr, expr) == True) self.solver.add(stmts) pytype_to_smt[typ] = expr return pytype_to_smt[typ]
def _update(self): self._sig = [] for i in range(self._fdecl.arity()): name = self._mk_arg_name(i) sort = self._fdecl.domain(i) self._sig.append(z3.Const(name, sort)) # compute pysmt version of the signature env = pysmt.environment.reset_env() mgr = env.formula_manager ctx = z3.get_ctx(None) converter = pyz3.Z3Converter(env, ctx) self._pysmt_sig = [ mgr.Symbol(v.decl().name(), converter._z3_to_type(v.sort())) for v in self._sig ]
def __init__(self, name, type_params=[], methods=[]): # Externs are this weird bastard child of callables and a complex type # FIXME: Unify types z3_type = z3.Datatype(name) z3_type.declare(f"mk_{name}") self.members = OrderedDict() self.z3_type = z3_type.create() self.const = z3.Const(name, self.z3_type) self.p4_attrs = {} # simple fix for now until I know how to initialize params for externs self.params = {} self.name = name self.type_params = type_params # these are method declarations, not methods for method in methods: self.p4_attrs[method.lval] = method.rval
def _update(self): self._sig = [] for i in range(self._fdecl.arity()): name = self._mk_arg_name(i) sort = self._fdecl.domain(i) self._sig.append(z3.Const(name, sort)) # compute pysmt version of the signature mgr = self._env.formula_manager converter = pyz3.Z3Converter(self._env, self.get_ctx()) # noinspection PyProtectedMember self._pysmt_sig = [ mgr.Symbol(v.decl().name(), converter._z3_to_type(v.sort())) for v in self._sig ]
def generate_kconnected_smt(self, paths): src, dst = paths[0][0], paths[0][-1] path_costs = [self._get_path_cost(path) for path in paths] path_names = [get_path_name(path) for path in paths] cuttoff = self.gen_paths count = 0 path_key_req = tuple(paths[0]) if path_key_req not in self.saved_path_gen: self.saved_path_gen[path_key_req] = self.generate_random_paths( src, dst, 0.6, self.random_gen) elif path_key_req not in self.counter_examples: return path_costs_var = [] for index, cost in enumerate(path_costs): if is_symbolic(cost): path_costs_var.append(cost) continue var = z3.Const("%s_cost" % path_names[index], z3.IntSort()) self.solver.add(var == cost) path_costs_var.append(var) for rand_path in self.saved_path_gen[path_key_req]: # Skip if we generated the same path as the requirement if rand_path in paths: continue if rand_path: for index, path in enumerate(paths): path_name = path_names[index] path_cost = path_costs[index] rand_path_name = get_path_name(rand_path) rand_path_cost = self._get_path_cost(rand_path) track_name = '%s_ISLESS_%s' % (path_name, rand_path_name) if track_name in self._names_cache: continue else: self._names_cache.append(track_name) if is_symbolic(path_cost) or is_symbolic(rand_path_cost): self.solver.assert_and_track( path_cost < rand_path_cost, track_name) else: if not (path_cost < rand_path_cost): path_cost_var = path_costs_var[index] self.solver.assert_and_track( path_cost_var < rand_path_cost, track_name) count += 1 if count > cuttoff: break
def extract_implies(clause): clause = fix_quantifier(clause) qvars = [ z3.Const(clause.var_name(n), clause.var_sort(n)) for n in range(0, clause.num_vars()) ] implies = fix_implies(clause.body()) kids = implies.children() body = get_conjuncts(qvars, kids[0]) head = z3.substitute_vars(kids[1], *qvars) return { 'qvars': qvars, 'body': body, 'head': head, }
def __init__(self, name, p4z3_type, member_id): super(StructInstance, self).__init__(name, p4z3_type, member_id) self.const = z3.Const(name, self.z3_type) # we use the overall index of the struct for a uniform naming scheme flat_idx = self.member_id for member_name, member_type in self.fields: if isinstance(member_type, P4ComplexType): # the z3 variable of the instance is only an id instance = member_type.instantiate(str(flat_idx), flat_idx) # but what we add is its fully qualified name, e.g. x.y.z self.locals[member_name] = instance flat_idx += len(member_type.flat_names) else: # this is just a filler value, it must be overridden by bind() self.locals[member_name] = None flat_idx += 1
def Const(name, uct_sort, annctx=default_annctx): """ Declare a constant with the given name and uct sort. :param name: string :param uct_sort: naturalproofs.uct.UCTSort :param annctx: naturalproofs.AnnotatedContext.AnnotatedContext :return: z3.ExprRef """ if not isinstance(uct_sort, UCTSort): raise TypeError('UCTSort expected.') z3const = z3.Const(name, uct_sort.z3sort) if not isinstance(annctx, AnnotatedContext): raise TypeError('AnnotatedContext expected.') # The constant must be tracked as a 0-arity function declaration = z3const.decl() annctx.add_alias_annotation(declaration, tuple([uct_sort])) annctx.add_vocabulary_annotation(declaration) return z3const
def write_clauses_datalog(declarations, clauses, writer): reserved_exit_point = 'reserved_exit_point' writer.write('(declare-rel {} ())\n\n'.format(reserved_exit_point)) for decl in declarations: symbol = quote_symbol_if_needed(decl.name()) writer.write('(declare-rel {} ('.format(symbol)) for n in range(0, decl.arity()): writer.write((" {}".format(decl.domain(n)))) writer.write(' ))\n') known_vars = set([]) implications = [] writer.write('\n') for clause in clauses: if not (z3.is_quantifier(clause) and clause.is_forall()): raise Exception("Illegal clause for write_clause_smt2: {}".format( clause.decl())) for idx in range(0, clause.num_vars()): if (clause.var_name(idx), clause.var_sort(idx)) not in known_vars: known_vars.add((clause.var_name(idx), clause.var_sort(idx))) writer.write("(declare-var {} {})\n".format( clause.var_name(idx), clause.var_sort(idx).sexpr())) implication = clause.body() subst = list( reversed([ z3.Const(clause.var_name(n), clause.var_sort(n)) for n in range(0, clause.num_vars()) ])) implications.append(z3.substitute_vars(implication, *subst)) writer.write('\n') for implication in implications: writer.write('(rule\n') write_implication_smt2(implication, ' ', reserved_exit_point, writer) writer.write('\n)\n') writer.write('\n\n(query {})\n\n'.format(reserved_exit_point))