def predicates(expr): """Return a list of Z3 predicate names satisfied by expr. If expr is an application, the list will include the Z3_OP_* that expr is an application of. This is for debugging purposes. Real code should use the appropriate predicate functions directly. """ res = set() for pred_name in dir(z3): if not pred_name.startswith("is_"): continue if pred_name == "is_app_of": continue pred = getattr(z3, pred_name) if pred(expr): res.add(pred_name) if z3.is_app(expr): for op_name in dir(z3): if not op_name.startswith("Z3_OP_"): continue if z3.is_app_of(expr, getattr(z3, op_name)): res.add(op_name) return res
def f(_cache, e, seen): def f_cache(e): return _cache(f, e, seen) if z3.is_app_of(e, z3.Z3_OP_UMINUS): return f_cache((-1) * (e.arg(0))) elif z3.is_sub(e): return f_cache(e.arg(0) + (-1) * e.arg(1)) elif z3.is_app(e) and e.num_args() == 2: c1 = f_cache(e.arg(0)) c2 = f_cache(e.arg(1)) if z3.is_add(e): return c1 + c2 elif z3.is_mul(e): if z3.is_add(c1): c11 = c1.arg(0) c12 = c1.arg(1) return f_cache(c11 * c2 + c12 * c2) elif z3.is_add(c2): c21 = c2.arg(0) c22 = c2.arg(1) return f_cache(c1 * c21 + c1 * c22) else: return c1 * c2 else: return e else: return e
def is_atom(a): """ Check if the input formula is an atom. In FOL, atoms are defined as atom := t1 = t2 | R(t1,..,tn) where ti are terms. In addition, this function also allows Bool variable to be terms (in propositional logic, a bool variable is considered term) Example: >>> from z3 import * >>> is_atom(3) False >>> is_atom(Bool('b')) True >>> is_atom(Int('x')) False >>> is_atom(TRUE) False >>> is_atom(FALSE) False >>> is_atom(Int('x') + Int('y') > 3) True >>> is_atom(Bool('x') == TRUE) True >>> is_atom(Int('x') == 3) True >>> is_atom(IntVal(3)) False >>> is_atom(Not(TRUE)) False >>> is_atom(Or(TRUE,FALSE)) False >>> is_atom(Or(Bool('b'),Bool('y'))) False """ if not is_bool(a): return False if is_expr_val(a): return False if is_expr_var(a): return True return is_app(a) and a.decl().kind() not in CONNECTIVE_OPS and\ all(is_term(c) for c in a.children())
def partial_leaf_substitution(expr, substitution_dict): """Replaces consts/vars in `expr` according to `substitution_dict`. If a const/var is not in `substitution_dict.keys()`, it remains unchanged. >>> a, b, c = sl.list.locs("a b c") >>> subst = {b : c} >>> partial_leaf_substitution(sl.sepcon(sl.list("a"), sl.list("b")), subst) sl.sepcon(sl.list(a), sl.list(c)) >>> i, j = Ints("i j") >>> subst = {sl.alpha : i, sl.beta : j} >>> partial_leaf_substitution(sl.alpha < sl.beta, subst) i < j """ if z3.is_const(expr) or z3.is_var(expr): return substitution_dict.get(expr, expr) elif z3.is_app(expr): new_args = [ partial_leaf_substitution(child, substitution_dict) for child in expr.children() ] return replace_args(expr, new_args) else: assert (z3.is_quantifier(expr)) new_arg = partial_leaf_substitution(expr.body(), substitution_dict) return replace_args(expr, new_arg)
def infix_args_core(self, a, d, xs, r): sz = len(r) k = a.decl().kind() p = self.get_precedence(k) first = True for child in a.children(): child_pp = self.pp_expr(child, d + 1, xs) child_k = None if z3.is_app(child): child_k = child.decl().kind() if k == child_k and (self.is_assoc(k) or (first and self.is_left_assoc(k))): self.infix_args_core(child, d, xs, r) sz = len(r) if sz > self.max_args: return elif self.is_infix_unary(child_k): child_p = self.get_precedence(child_k) if p > child_p or (_is_add(k) and _is_sub(child_k)) or (_is_sub(k) and first and _is_add(child_k)): r.append(child_pp) else: r.append(self.add_paren(child_pp)) sz = sz + 1 elif z3.is_quantifier(child): r.append(self.add_paren(child_pp)) else: r.append(child_pp) sz = sz + 1 if sz > self.max_args: r.append(self.pp_ellipses()) return first = False
def infix_args_core(self, a, d, xs, r): sz = len(r) k = a.decl().kind() p = self.get_precedence(k) first = True for child in a.children(): child_pp = self.pp_expr(child, d+1, xs) child_k = None if z3.is_app(child): child_k = child.decl().kind() if k == child_k and (self.is_assoc(k) or (first and self.is_left_assoc(k))): self.infix_args_core(child, d, xs, r) sz = len(r) if sz > self.max_args: return elif self.is_infix_unary(child_k): child_p = self.get_precedence(child_k) if p > child_p or (_is_add(k) and _is_sub(child_k)) or (_is_sub(k) and first and _is_add(child_k)): r.append(child_pp) else: r.append(self.add_paren(child_pp)) sz = sz + 1 elif z3.is_quantifier(child): r.append(self.add_paren(child_pp)) else: r.append(child_pp) sz = sz + 1 if sz > self.max_args: r.append(self.pp_ellipses()) return first = False
def fixedpoint(M, bad): fp = z3.Fixedpoint() options = {'engine':'spacer'} fp.set(**options) xs = M.variables() xsp = M.variables('prime') sorts = M.sorts() + [z3.BoolSort()] inv = z3.Function('inv', *sorts) err = z3.Function('err', z3.BoolSort()) fp.register_relation(inv) fp.register_relation(err) for zi in xs + xsp: fp.declare_var(zi) inv_xs = inv(*xs) inv_xsp = inv(*xsp) fp.rule(inv_xs, M.init(xs)) fp.rule(inv_xsp, M.tr(xs, xsp) + [inv_xs]) fp.rule(err(), bad(xs) + [inv_xs]) if fp.query(err) == z3.unsat: inv = fp.get_answer() assert inv.is_forall() body = inv.body() assert z3.is_eq(body) fapp = body.arg(0) assert (z3.is_app(fapp)) args = [fapp.arg(i) for i in range(body.num_args())] assert len(args) == len(xs) expr = (body.arg(1)) return (z3.unsat, args, expr) else: return (z3.sat, None, None)
def translate(self, expr, bound_variables=[]): if z3.is_const(expr): return self.mk_const(expr) # raise Z3_Unexpected_Expression('Unrecognized constant') elif z3.is_var(expr): # a de Bruijn indexed bound variable bv_length = len(bound_variables) return bound_variables[bv_length - z3.get_var_index(expr) - 1] elif z3.is_app(expr): args = [self.translate(expr.arg(i), bound_variables) for i in range(expr.num_args())] return self.mk_fun(expr.decl())(*args) # else: # raise Z3_Unexpected_Expression(expr) elif z3.is_quantifier(expr): num_vars = expr.num_vars() # vars = [language.const_dict[expr.var_name(i)] # for i in range(num_vars)] vars = [const(expr.var_name(i), self.mk_sort(expr.var_sort(i))) \ for i in range(num_vars)] new_bound_variables = bound_variables + vars body = self.translate(expr.body(), new_bound_variables) if expr.is_forall(): return forall(vars, body) else: return exists(vars, body) elif z3.is_func_decl(expr): return self.mk_fun(expr) else: print expr.kind raise Z3_Unexpected_Expression(expr)
def visitor_app(e): if z3.is_app(e) and e.decl().kind() == z3.Z3_OP_UNINTERPRETED: if e.num_args() > 0: yield e for ch in e.children(): for e0 in visitor_app(ch): yield e0
def elim_bool_ite(exp): if z3.is_quantifier(exp): (qvars, matrix) = strip_qblock(exp) matrix = elim_bool_ite(matrix) if exp.is_forall(): e = z3.ForAll(qvars, matrix) else: e = z3.Exists(qvars, matrix) return e if not z3.is_bool(exp): return exp if z3.is_true(exp) or z3.is_false(exp): return exp assert z3.is_app(exp) decl = exp.decl() args = map(elim_bool_ite, exp.children()) # need to worry about And and Or because they can take >2 args and # decl(*args) doesn't seem to work with the py interface if z3.is_and(exp): return z3.And(*args) elif z3.is_or(exp): return z3.Or(*args) elif is_ite(exp): impl1 = z3.Implies(args[0], args[1]) impl2 = z3.Implies(z3.Not(args[0]), args[2]) return z3.And(impl1, impl2) else: return decl(*args)
def _update(self): if not self.has_formula(): return rels = list() find_all_uninterp_consts(self._formula, rels) self._rels = frozenset(rels) body = self._formula if z3.is_quantifier(body): body, self._bound_constants = ground_quantifier(body) if z3.is_implies(body): self._head = body.arg(1) body = body.arg(0) if z3.is_and(body): body = body.children() else: body = [body] else: self._head = body body = [] if len(body) > 0: self._body = body for i in range(len(body)): f = body[i] if z3.is_app(f) and f.decl() in self._rels: self._uninterp_sz += 1 else: break assert (self._head is not None)
def pp_power_arg(self, arg, d, xs): r = self.pp_expr(arg, d + 1, xs) k = None if z3.is_app(arg): k = arg.decl().kind() if self.is_infix_unary(k) or (z3.is_rational_value(arg) and arg.denominator_as_long() != 1): return self.add_paren(r) else: return r
def pp_power_arg(self, arg, d, xs): r = self.pp_expr(arg, d+1, xs) k = None if z3.is_app(arg): k = arg.decl().kind() if self.is_infix_unary(k) or (z3.is_rational_value(arg) and arg.denominator_as_long() != 1): return self.add_paren(r) else: return r
def convert(t, values): if z3.is_int_value(t): return t.as_long() if z3.is_app(t): func = globals()[t.decl().name()] return func( *[convert(t.arg(i), values) for i in range(t.num_args())]) elif z3.is_var(t): return values[z3.get_var_index(t)]
def unique_eq_terms_on_const(const, exp, eq_terms=None, done_exp=None): def insert(e): found = False for t in eq_terms: if z3.eq(t, e): found = True break if not found: eq_terms.append(e) return True return False def process_eq(e1, e2): if z3.eq(e1, const): ret_val = z3.simplify(e2) else: assert z3.is_app(e1) if not (z3.is_app_of(e1, z3.Z3_OP_ADD) or z3.is_app_of(e1, z3.Z3_OP_SUB)): return None is_add = z3.is_app_of(e1, z3.Z3_OP_ADD) arg0 = e1.arg(0) arg1 = e1.arg(1) if z3.eq(arg1, const): if is_add: ret_val = z3.simplify(e2 - arg0) else: ret_val = z3.simplify(arg0 - e2) else: if is_add: ret_val = process_eq(arg0, e2 - arg1) else: ret_val = process_eq(arg0, e2 + arg1) return ret_val if eq_terms is None: eq_terms = [] if done_exp is None: done_exp = [] for e in done_exp: if e.eq(exp): return # sub-dag is already processed if z3.is_eq(exp): arg0 = exp.arg(0) arg1 = exp.arg(1) if has_const(arg1, const): arg0, arg1 = arg1, arg0 # swap if has_const(arg0, const): t = process_eq(arg0, arg1) if t is not None: if insert(t): yield (t, exp) else: yield (None, exp) elif z3.is_app(exp): for i in range(exp.num_args()): for (t, eq) in unique_eq_terms_on_const(const, exp.arg(i), eq_terms, done_exp): yield (t, eq) done_exp.append(exp)
def pp_expr(self, a, d, xs): self.visited = self.visited + 1 if d > self.max_depth or self.visited > self.max_visited: return self.pp_ellipses() if z3.is_app(a): return self.pp_app(a, d, xs) elif z3.is_quantifier(a): return self.pp_quantifier(a, d, xs) elif z3.is_var(a): return self.pp_var(a, d, xs) else: return to_format(self.pp_unknown())
def f(_cache, e, seen): def f_cache(e): return _cache(f, e, seen) r = [] if z3.is_app(e): if e.decl().kind() in Z3_LOGICAL_OPS + Z3_REL_OPS: for c in e.children(): r = r + f_cache(c) elif z3.is_arith(e): e = cls._distribute_mul_over_add(e) r = r + cls._get_add_terms(e) return r
def visitor(e, seen): if e in seen: return seen[e] = True yield e if is_app(e): for ch in e.children(): for e in visitor(ch, seen): yield e return if is_quantifier(e): for e in visitor(e.body(), seen): yield e return
def existVars(self, v1, v2): """ create a list of variables to be bound """ v1_str = [str(v) for v in v1] v2_filtered = list() for v in v2: if z3.is_not(v): v2_filtered.append(v.children()[0]) elif z3.is_app(v) and not z3.is_not(v): v2_filtered.append(v) for v in v2_filtered: if str(v) not in v1_str: v1.append(v) return v1
def fp_add_cover(fp, pred, lemma, level=-1): # no trivial lemmas if z3.is_true(lemma): return assert (z3.is_app(pred)) sub = [] for i in range(0, pred.num_args()): arg = pred.arg(i) sub.append((arg, z3.Var(i, arg.decl().range()))) tlemma = z3.substitute(lemma, sub) if verbose: print "Lemma for ", pred.decl(), ": ", tlemma fp.add_cover(level, pred.decl(), tlemma)
def variables_in_expression(expression): expressions = [expression] variables = [] while len(expressions) > 0: expression = expressions.pop(0) if z3.is_const(expression): if not z3.is_bool_or_int_value(expression): variables.append(expression) elif z3.is_app(expression): if expression.decl().kind() == z3.Z3_OP_UNINTERPRETED: variables.append(expression.decl()) for i in range(expression.num_args()): expressions.append(expression.arg(i)) return variables
def existVars(self, v1, v2): """ create a list of variables to be bound """ v1_str = [str(v) for v in v1] v2_filtered = list() for v in v2: if z3.is_not(v): v2_filtered.append(v.children()[0]) elif z3.is_app(v) and not z3.is_not(v): v2_filtered.append(v) for v in v2_filtered: if str(v) not in v1_str : v1.append(v) return v1
def fp_add_cover (fp, pred, lemma, level=-1): # no trivial lemmas if z3.is_true (lemma): return assert (z3.is_app (pred)) sub = [] for i in range (0, pred.num_args ()): arg = pred.arg (i) sub.append ((arg, z3.Var (i, arg.decl ().range ()))) tlemma = z3.substitute (lemma, sub) if verbose: print "Lemma for ", pred.decl (), ": ", tlemma fp.add_cover (level, pred.decl (), tlemma)
def is_function_symbol(s: z3.ExprRef) -> bool: if not z3.is_app(s): return False if z3.is_const(s): return False func = s.decl() if func.range() == z3.BoolSort(): # predicate symbol return False if func.name().lower() == 'if': return False return True
def getLength1(M, bad): fp = z3.Fixedpoint() options = {'engine':'spacer'} fp.set(**options) Mp = TransitionSystem('prime') # addCounter(M) # addCounter(Mp) xs = M.variables xsp = Mp.variables trx = [xsp[i]==M.tr[i] for i in range(len(xs))] sorts = M.sorts + [z3.BoolSort()] inv = z3.Function('inv', *sorts) err = z3.Function('err', z3.BoolSort()) fp.register_relation(inv) fp.register_relation(err) for x in xs + xsp: fp.declare_var(x) inv_xs = inv(*xs) inv_xsp = inv(*xsp) fp.rule(inv_xs, M.init) fp.rule(inv_xsp, trx + [inv_xs]) fp.rule(err(), bad(xs) + [inv_xs]) r = fp.query(err) == z3.unsat if r: inv = fp.get_answer() print("INV:") print(inv) assert inv.is_forall() body = inv.body() # assert z3.is_eq(body) print("BODY:", body) fapp = body.arg(0) print("FAPP: ", fapp) assert (z3.is_app(fapp)) args = [fapp.arg(i) for i in range(body.num_args())] assert len(args) == len(xs) expr = (body.arg(1)) print(z3.unsat, args, expr) return (z3.unsat, args, expr) else: return (z3.sat, len(fp.get_answer().children()), None) # Are you sure this is the correct length?
def bv_length(e): li = [-1] if e in seen: return -1 if (z3.is_bv(e) and z3.is_const(e) and e.decl().kind() == z3.Z3_OP_UNINTERPRETED): li.append(e.size()) seen.add(e) if z3.is_app(e): for ch in e.children(): li.append(bv_length(ch)) elif z3.is_quantifier(e): for ch in e.body().children(): li.append(bv_length(ch)) return max(li)
def pp_unary(self, a, d, xs): k = a.decl().kind() p = self.get_precedence(k) child = a.children()[0] child_k = None if z3.is_app(child): child_k = child.decl().kind() child_pp = self.pp_expr(child, d + 1, xs) if k != child_k and self.is_infix_unary(child_k): child_p = self.get_precedence(child_k) if p <= child_p: child_pp = self.add_paren(child_pp) if z3.is_quantifier(child): child_pp = self.add_paren(child_pp) name = self.pp_name(a) return compose(to_format(name), indent(_len(name), child_pp))
def pp_unary(self, a, d, xs): k = a.decl().kind() p = self.get_precedence(k) child = a.children()[0] child_k = None if z3.is_app(child): child_k = child.decl().kind() child_pp = self.pp_expr(child, d+1, xs) if k != child_k and self.is_infix_unary(child_k): child_p = self.get_precedence(child_k) if p <= child_p: child_pp = self.add_paren(child_pp) if z3.is_quantifier(child): child_pp = self.add_paren(child_pp) name = self.pp_name(a) return compose(to_format(name), indent(_len(name), child_pp))
def unique_selects(exp, sel_keys=None): def insert_and_yield(e): k = exp_key(e) if k not in sel_keys: sel_keys.append(k) yield e if sel_keys is None: sel_keys = [] # post-order if z3.is_app(exp): for i in range(exp.num_args()): # args are the array and the idx for sel in unique_selects(exp.arg(i), sel_keys): yield sel if z3.is_select(exp): for sel in insert_and_yield(exp): yield sel
def tagged_conditional_rewrite(s, rewriting_dict, leaf_fn, default_fn): """ Apply given rewriter to subexpressions of s bottom up """ todo = [] todo.append(s) cache = {} while todo: n = todo[len(todo) - 1] #print("Rewriting {}".format(n)) #print("Current cache: {}".format(cache)) if z3.is_var(n): # No rewriting for variables todo.pop() # TODO: This is one difference => Could be added as leaf_fn to standard rewrite as well cache[n] = leaf_fn(n) elif z3.is_app(n): # Add non-rewritten children to rewriting stack processed_all_children = True for arg in n.children(): if arg not in cache: todo.append(arg) processed_all_children = False # All children haven been rewritten, so now rewrite n itself if processed_all_children: todo.pop() new_args = [cache[arg] for arg in n.children()] enabled_rewriter = rewriting_dict.get(n.decl()) if enabled_rewriter is not None: cache[n] = enabled_rewriter(n, new_args) else: #cache[n] = replace_args(n, new_args) cache[n] = default_fn(n, new_args) else: assert (z3.is_quantifier(n)) b = n.body() if b in cache: # The argument of the quantifier has already been rewritten # Substitute this rewritten term todo.pop() # TODO: Another difference (but actually not even relevant in our setting). This could also be encapsulated in a function argument which could default to replace_args in the non-tagged setting rewritten_arg, tag = cache[b] cache[n] = (replace_args(n, [rewritten_arg]), tags) else: todo.append(b) return cache[s]
def find_all_uninterp_consts(formula, res): if z3.is_quantifier(formula): formula = formula.body() worklist = [] if z3.is_implies(formula): worklist.append(formula.arg(1)) arg0 = formula.arg(0) if z3.is_and(arg0): worklist.extend(arg0.children()) else: worklist.append(arg0) else: worklist.append(formula) for t in worklist: if z3.is_app(t) and t.decl().kind() == z3.Z3_OP_UNINTERPRETED: res.append(t.decl())
def process_eq(e1, e2): if z3.eq(e1, const): ret_val = z3.simplify(e2) else: assert z3.is_app(e1) if not (z3.is_app_of(e1, z3.Z3_OP_ADD) or z3.is_app_of(e1, z3.Z3_OP_SUB)): return None is_add = z3.is_app_of(e1, z3.Z3_OP_ADD) arg0 = e1.arg(0) arg1 = e1.arg(1) if z3.eq(arg1, const): if is_add: ret_val = z3.simplify(e2 - arg0) else: ret_val = z3.simplify(arg0 - e2) else: if is_add: ret_val = process_eq(arg0, e2 - arg1) else: ret_val = process_eq(arg0, e2 + arg1) return ret_val
def __init__ (self, vs): if z3.is_app (vs): vs = [vs] self._saved_vs = vs self._num_vars = len (vs) num_vars = self._num_vars self._vs = (z3.Ast * num_vars) () for i in range (num_vars): self._vs [i] = vs[i].as_ast () self._pats = (z3.Pattern * 0) () self._num_pats = 0 self._num_no_pats = 0 self._no_pats = (z3.Ast * 0) ()
def visit(self, e): assert z3.is_ast(e) if not z3.is_app(e): raise Z3ExprDispatcherException('expr was not an application') # Call the appropriate function application handler app_kind = e.decl().kind() if app_kind == z3.Z3_OP_UNINTERPRETED and e.num_args() == 0: self.visit_variable(e) return try: handler = self._z3_app_dispatcher_map[app_kind] handler(e) except KeyError as e: msg = 'Handler for {} is missing from dispatch dictionary'.format( app_kind) raise NotImplementedError(msg)
def conditional_rewrite(s, rewriting_dict, default_fn=replace_args): """ Apply given rewriter to subexpressions of s bottom up """ todo = [] todo.append(s) cache = {} while todo: n = todo[len(todo) - 1] #print(n) if z3.is_var(n): # No rewriting for variables todo.pop() cache[n] = default_leaf_fn(n) elif z3.is_app(n): # Add non-rewritten children to rewriting stack processed_all_children = True for arg in n.children(): if arg not in cache: todo.append(arg) processed_all_children = False # All children haven been rewritten, so now rewrite n itself if processed_all_children: todo.pop() new_args = [cache[arg] for arg in n.children()] enabled_rewriter = rewriting_dict.get(n.decl()) if enabled_rewriter is not None: #print("Match for {}".format(n.decl())) cache[n] = enabled_rewriter(n, new_args) else: #cache[n] = replace_args(n, new_args) cache[n] = default_fn(n, new_args) else: assert (z3.is_quantifier(n)) b = n.body() if b in cache: # The argument of the quantifier has already been rewritten # Substitute this rewritten term todo.pop() cache[n] = replace_args(n, [cache[b]]) else: todo.append(b) return cache[s]
def checkLength1(M, bad, count): fp = z3.Fixedpoint() options = {'engine': 'spacer'} fp.set(**options) addCounter(M) xs = M.variables sorts = M.sorts + [z3.BoolSort()] inv = z3.Function('inv', *sorts) err = z3.Bool('err') fp.register_relation(inv) fp.register_relation(err.decl()) fp.declare_var(*xs) bad_state = [z3.And(bad(xs) + [xs[-1] == count])] fp.rule(inv(*xs), M.init) fp.rule(inv(*M.tr), inv(*xs)) fp.rule(err, bad_state + [inv(*xs)]) r = fp.query(err) if r == z3.unsat: inv = fp.get_answer() print("INV:") print(inv) assert inv.is_forall() body = inv.body() assert z3.is_eq(body) print("BODY:", body) fapp = body.arg(0) assert (z3.is_app(fapp)) args = [fapp.arg(i) for i in range(body.num_args())] assert len(args) == len(xs) expr = (body.arg(1)) print(z3.unsat, args, expr) return (z3.unsat, args, expr) else: return (z3.sat, len(inv.children()), None)
def find_atomic_terms (exp, terms = list (), seen = set ()): """ Finds all declarations in an expression """ if (z3.is_quantifier (exp)): return find_atomic_terms (exp.body (), terms, seen) if not (z3.is_app (exp)) : return terms if z3AstRefKey (exp) in seen: return terms seen.add (z3AstRefKey (exp)) decl = exp.decl () # atomic term if decl.kind () == z3.Z3_OP_UNINTERPRETED: if z3AstRefKey (decl) not in seen: seen.add (z3AstRefKey (decl)) terms.append (decl) # uninterpreted can also have kids for k in exp.children (): find_atomic_terms (k, terms, seen) return terms
def z3ExpChildGenerator (exp) : if z3.is_app (exp) : for i in range (exp.num_args ()) : yield exp.arg (i)
def getFirstConjunct (exp) : assert z3.is_app (exp) if z3.is_and (exp) : return exp.arg (0) else : return exp