def convert_to_dimacs(goal, project_onto): ''' Convert a Z3 goal into DIMACS so that ApproxMC can understand it. ''' # Based on https://stackoverflow.com/a/33860849 bits = set() for var in project_onto: nbits = var.sort().size() # Give a name to each bit of each bitvector for bit_index in range(nbits): name = '%s_%d' % (var, bit_index) bits.add(name) bit = z3.Bool(name) mask = z3.BitVecVal(1 << bit_index, nbits) goal.add(bit == ((var & mask) == mask)) # z3.With(..., args) provides arguments to the "..." tactic. tactic = z3.Then( 'simplify', z3.With( z3.Tactic('bit-blast'), blast_full=True, blast_quant=True, ), 'blast-term-ite', z3.With( z3.Tactic('propagate-values'), blast_eq_value=True, blast_distinct=True, ), z3.With( z3.Tactic('simplify'), blast_eq_value=True, ), 'blast-term-ite', 'tseitin-cnf', 'blast-term-ite', ) expr = tactic(goal) assert len(expr) == 1 expr = expr[0] dimacs = expr.dimacs() # ind is the Independent Set ind = set() # Parse the dimacs to determine how Z3 maps the boolean variables to the # dimacs variable number lines = dimacs.split('\n') for line in lines: if not line.startswith('c '): # It's not a comment. continue # Otherwise assume that this line maps variables to names parts = line.split() _, number, var = parts if var in bits: bits.remove(var) ind.add(number) # TODO: will this always be true? assert len(bits) == 0, repr(bits) return 'c ind %s 0\n%s\n' % (' '.join(ind), dimacs)
def parse_with_z3(file): t = z3.With(z3.Tactic("horn-simplify"), "xform.inline_eager", False) assertions = z3.parse_smt2_file(file) g = z3.Goal() g.add(assertions) r = t(g) s = z3.Solver() s.add(r[0]) print(s.sexpr())
def count(smt_file): formula = z3.parse_smt2_file(smt_file) tactic_simp = z3.With(z3.Tactic('simplify'), 'elim_and', True) tactic_total = z3.Then(tactic_simp, z3.Tactic('elim-term-ite')) tactic_total = z3.Then(tactic_total, z3.Tactic('tseitin-cnf')) goals = tactic_total(formula) if len(goals) == 1: goal = goals[0] return len(goal) else: return -1
def calculate(input_smt): formula = z3.parse_smt2_file(input_smt) tactic_simp = z3.With(z3.Tactic('simplify'), 'elim_and', True) tactic_total = z3.Then(tactic_simp, z3.Tactic('elim-term-ite')) tactic_total = z3.Then(tactic_total, z3.Tactic('tseitin-cnf')) goals = tactic_total.apply(formula) if len(goals) == 1: goal = goals[0] # the goal is the list of constraints, and conjunction of which is equivalent to the original problem manager = compute(goal) # compute sparseness num_visible = manager.get_visible_size() num_var = manager.get_var_size() num_total = manager.get_total_size() num_min = manager.get_maximum_clause_size() sparse = (num_visible - num_min) / (num_total - num_min) factor_min = math.ceil((1 + math.sqrt(1 + 8 * num_visible)) / 2) factor_max = 2 * num_total factor = (num_var - factor_min) / (factor_max - factor_min) return sparse, factor else: return '*', '*'
def walk_block(node, prev_g=None, cond=True): g = z3.Goal() g.add(cond) if prev_g is not None: for e in prev_g: if isinstance(e, z3.Goal): g.add(e.as_expr()) else: g.add(e) if isinstance(node, pycp.c_ast.Compound): if node.block_items is not None: for e in node.block_items: g_next = walk_block(e, g) g = g_next elif isinstance(node, pycp.c_ast.Decl): if "int" in node.type.type.names: vars[node.name] = z3.Int(node.name) if "float" in node.type.type.names: vars[node.name] = z3.Real(node.name) elif isinstance(node, pycp.c_ast.FuncCall): if node.name.name == "__ASSUME": for e_exp in node.args.exprs: g.add(gen_smt_expr(e_exp)) elif node.name.name == "__ASSERT": assertions = z3.Goal() for e_exp in node.args.exprs: assertions.add(gen_smt_expr(e_exp)) print("solving..") print("SP:", g.as_expr()) print("assert:", assertions) seen = set() 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) t = z3.Tactic('nla2bv') s = z3.Then(t, 'default').solver() fml = z3.And(g.as_expr(), z3.Not(assertions.as_expr())) print("solving using bitvector underapproximation..") s.add(fml) status = s.check() if status == z3.unknown: print("returned 'unknown'! trying again with bigger bit length..") print("getting highest bit length used in formula..") bv_l = bv_length(t(fml).as_expr()) print("highest bit length used:", bv_l) while True: bv_l += 1 print("trying with bit length:", bv_l) s = z3.Then(z3.With('nla2bv', nla2bv_bv_size=bv_l), 'default').solver() s.add(fml) status = s.check() if status != z3.unknown or bv_l >= 64: break if status == z3.sat: model = s.model() print("program is unsafe.\nlisting an unsafe assignments..") for e in vars: print(e, ':', model[vars[e]]) elif status == z3.unsat: print("program is safe.") elif status == z3.unknown: print("unknown") s.reset() else: print("found a func call") elif isinstance(node, pycp.c_ast.Assignment): rexp = gen_smt_expr(node.rvalue) if z3.is_int(vars[node.lvalue.name]): hand_ = z3.Int('__hand__') elif z3.is_real(vars[node.lvalue.name]): hand_ = z3.Real('__hand__') if node.op == "=": g.add(hand_ == rexp) elif node.op == "+=": g.add(hand_ == (vars[node.lvalue.name] + rexp)) elif node.op == "-=": g.add(hand_ == (vars[node.lvalue.name] - rexp)) elif node.op == "*=": g.add(hand_ == (vars[node.lvalue.name] * rexp)) elif node.op == "%=": g.add(hand_ == (vars[node.lvalue.name] % rexp)) g_ = z3.Goal() g_.add(z3.Exists(vars[node.lvalue.name], g.as_expr())) g_ = t_qe_(g_) g = z3.Goal() g.add(z3.substitute(g_.as_expr(), (hand_, vars[node.lvalue.name]))) # g = g.simplify() elif isinstance(node, pycp.c_ast.If): cond_exp = gen_smt_expr(node.cond) if node.iftrue is not None: true_expr = walk_block(node.iftrue, g, cond_exp).as_expr() else: true_expr = z3.And(cond_exp, g.as_expr()) if node.iffalse is not None: false_expr = walk_block( node.iffalse, g, z3.Not(cond_exp)).as_expr() else: false_expr = z3.And(z3.Not(cond_exp), g.as_expr()) g = z3.Goal() g.add(z3.Or(true_expr, false_expr)) g = t(g) # g.simplify() else: return prev_g # print(g.as_expr(), "\n") return g
def __init__(self, s, params): assert isinstance(s, str) self.s = s self.params = params self.tactic = z3.With(s, **params)
def parse_with_z3(file, out_dir, check_only): lst = file.split('/') tmp = lst.pop() lst = tmp.split('.') base_name = lst[0] assert len(lst) > 0 if len(lst) > 1: for stuff in lst[1:-1]: base_name = base_name + '.' + stuff t = z3.With( z3.Tactic("horn-simplify"), "xform.inline_eager", False, "xform.inline_linear", False, "xform.slice", False, "xform.coi", False, "xform.compress_unbound", False, ) assertions = z3.parse_smt2_file(file) goals = z3.Goal() goals.add(assertions) if check_only: check_chcs(goals) print "success" else: simplified = t(goals) clauses = [] queries = [] for clause, is_query in [ fix_clause(clause) for clause in simplified[0] ]: if is_query: queries.append(clause) else: clauses.append(clause) for cnt, query in enumerate(queries): these_clauses = [] for clause in clauses: these_clauses.append(clause) these_clauses.append(query) goals = z3.Solver() goals.add(these_clauses) if out_dir is None: print('(set-logic HORN)') print goals.sexpr() print '(check-sat)' print '(exit)' else: out_file = "{}/{}_{:0>3}.smt2".format(out_dir, base_name, cnt) print 'Writing to {}'.format(out_file) out_file = open(out_file, mode='w') out_file.write('(set-logic HORN)\n\n') out_file.write(goals.sexpr()) out_file.write('\n\n(check-sat)\n') out_file.write('(exit)\n') try: check_chcs(these_clauses) except Exception, blah: raise Exception( "Result of formatting is ill-formed:\n{}".format(blah))