def simplify(self, expr): if expr._simplified: return expr if self._enable_simplification_cache: try: k = self._simplification_cache_key[expr._cache_key] #print "HIT WEAK KEY CACHE" return k except KeyError: pass try: k = self._simplification_cache_val[expr._cache_key] #print "HIT WEAK VALUE CACHE" return k except KeyError: pass #print "MISS CACHE" l.debug("SIMPLIFYING EXPRESSION") #print "SIMPLIFYING" expr_raw = self.convert(expr) #l.debug("... before: %s (%s)", expr_raw, expr_raw.__class__.__name__) if isinstance(expr_raw, z3.BoolRef): tactics = z3.Then(z3.Tactic("simplify"), z3.Tactic("propagate-ineqs"), z3.Tactic("propagate-values"), z3.Tactic("unit-subsume-simplify")) s = tactics(expr_raw).as_expr() n = s.decl().name() if n == 'true': s = True elif n == 'false': s = False elif isinstance(expr_raw, z3.BitVecRef): s = z3.simplify(expr_raw) else: s = expr_raw for b in _eager_backends: try: o = self.wrap(b.convert(s)) break except BackendError: continue else: o = self._abstract(s) #print "SIMPLIFIED" #l.debug("... after: %s (%s)", s, s.__class__.__name__) o._simplified = Base.FULL_SIMPLIFY if self._enable_simplification_cache: self._simplification_cache_val[expr._cache_key] = o self._simplification_cache_key[expr._cache_key] = o return o
def eliminate_quantifiers(self, formula): logic = get_logic(formula, self.environment) if not logic <= LRA and not logic <= LIA: raise PysmtValueError("Z3 quantifier elimination only "\ "supports LRA or LIA without combination."\ "(detected logic is: %s)" % str(logic)) simplifier = z3.Tactic('simplify') eliminator = z3.Tactic('qe') f = self.converter.convert(formula) s = simplifier(f, elim_and=True, pull_cheap_ite=True, ite_extra_rules=True).as_expr() res = eliminator(f).as_expr() pysmt_res = None try: pysmt_res = self.converter.back(res) except ConvertExpressionError: if logic <= LRA: raise raise ConvertExpressionError(message=("Unable to represent" \ "expression %s in pySMT: the quantifier elimination for " \ "LIA is incomplete as it requires the modulus. You can " \ "find the Z3 expression representing the quantifier " \ "elimination as the attribute 'expression' of this " \ "exception object" % str(res)), expression=res) return pysmt_res
def check_equivalence(prog_before, prog_after, allow_undef): # The equivalence check of the solver # For all input packets and possible table matches the programs should # be the same z3_prog_before, input_names_before, _ = prog_before z3_prog_after, input_names_after, _ = prog_after undef_violation = False try: z3_prog_before = z3.simplify(z3_prog_before) z3_prog_after = z3.simplify(z3_prog_after) # the equivalence equation log.debug("Simplifying equation...") tv_equiv = z3.simplify(z3_prog_before != z3_prog_after) except z3.Z3Exception as e: # Encountered an exception when trying to compare the formulas # There might be many reasons for this error_string = "Failed to compare Z3 formulas!\nReason: %s" % e error_string += "\nPROGRAM BEFORE\n" error_string += get_hdr_table(z3_prog_before, input_names_before) error_string += "\n\nPROGRAM AFTER\n" error_string += get_hdr_table(z3_prog_after, input_names_after) log.error(error_string) return util.EXIT_VIOLATION log.debug("Checking...") log.debug(z3.tactics()) t = z3.Then( z3.Tactic("simplify"), # z3.Tactic("distribute-forall"), # z3.Tactic("ackermannize_bv"), # z3.Tactic("bvarray2uf"), # z3.Tactic("card2bv"), # z3.Tactic("propagate-bv-bounds-new"), # z3.Tactic("reduce-bv-size"), # z3.Tactic("qe_rec"), z3.Tactic("smt"), ) solver = t.solver() log.debug(solver.sexpr()) ret = solver.check(tv_equiv) log.debug(tv_equiv) log.debug(ret) if allow_undef and ret == z3.sat: undef_violation = True # if we allow undefined changes we need to explicitly recheck log.info("Detected difference in undefined behavior. " "Rechecking while substituting undefined variables.") ret = undef_check(solver, z3_prog_before, z3_prog_after) if ret == z3.sat: print_validation_error(prog_before, prog_after, solver.model()) return util.EXIT_VIOLATION elif ret == z3.unknown: log.error("Solution unknown! There might be a problem...") return util.EXIT_VIOLATION else: if undef_violation: return util.EXIT_UNDEF return util.EXIT_SUCCESS
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 _search_simplify_tactics(self): try: return self._tls.search_simplify_tactics except AttributeError: tactics = z3.Then(z3.Tactic("simplify", ctx=self._context), z3.Tactic("aig", ctx=self._context), ctx=self._context) self._tls.search_simplify_tactics = tactics return self._tls.search_simplify_tactics
def build_test(config, main_formula, cond_tuple, pkt_range): permut_conds, avoid_conds, undefined_conds = cond_tuple # now we actually verify that we can find an input s = z3.Solver() # bind the output constant to the output of the main program output_const = z3.Const("output", main_formula.sort()) s.add(main_formula == output_const) undefined_matches = z3.And(*undefined_conds) s.add(undefined_matches) avoid_matches = z3.Not(z3.Or(*avoid_conds)) s.add(avoid_matches) # we need this tactic to find out which values will be undefined at the end # or which headers we expect to be invalid # the tactic effectively simplifies the formula to a single expression # under the constraints we have defined t = z3.Then(z3.Tactic("propagate-values"), z3.Tactic("ctx-solver-simplify"), z3.Tactic("elim-and")) # this is the test string we assemble stf_str = "" for permut in permut_conds: s.push() s.add(permut) log.info("Checking for solution...") ret = s.check() if ret == z3.sat: log.info("Found a solution!") # get the model m = s.model() # this does not work well yet... desperate hack # FIXME: Figure out a way to solve this, might not be solvable g = z3.Goal() g.add(main_formula == output_const, avoid_matches, undefined_matches, z3.And(*permut)) log.debug(z3.tactics()) log.info("Inferring simplified input and output") constrained_output = t.apply(g) log.info("Inferring dont-care map...") # FIXME: horrible output_var = constrained_output[0][0].children()[0] dont_care_map = get_dont_care_map(config, output_var, pkt_range) input_hdr = m[z3.Const(config["ingress_var"], output_const.sort())] output_hdr = m[output_const] log.debug("Output header: %s", output_hdr) log.debug("Input header: %s", input_hdr) flat_input = input_hdr.children()[pkt_range] flat_output = output_hdr.children()[pkt_range] stf_str += get_stf_str(flat_input, flat_output, dont_care_map) stf_str += "\n" else: # FIXME: This should be an error log.warning("No valid input could be found!") s.pop() # the final stf string lists all the interesting packets to test return stf_str
def simplify(self, expr): if expr._simplified: return expr if self._enable_simplification_cache: try: k = self._simplification_cache_key[expr._cache_key] #print "HIT WEAK KEY CACHE" return k except KeyError: pass try: k = self._simplification_cache_val[expr._cache_key] #print "HIT WEAK VALUE CACHE" return k except KeyError: pass #print "MISS CACHE" l.debug("SIMPLIFYING EXPRESSION") #print "SIMPLIFYING" expr_raw = self.convert(expr) #l.debug("... before: %s (%s)", expr_raw, expr_raw.__class__.__name__) #s = expr_raw if isinstance(expr_raw, z3.BoolRef): tactics = z3.Then( z3.Tactic("simplify", ctx=self._context), z3.Tactic("propagate-ineqs", ctx=self._context), z3.Tactic("propagate-values", ctx=self._context), z3.Tactic("unit-subsume-simplify", ctx=self._context), z3.Tactic("aig", ctx=self._context), ctx=self._context ) s = tactics(expr_raw).as_expr() #n = s.decl().name() #if n == 'true': # s = True #elif n == 'false': # s = False elif isinstance(expr_raw, z3.BitVecRef): s = z3.simplify(expr_raw) else: s = expr_raw o = self._abstract(s) o._simplified = Base.FULL_SIMPLIFY if self._enable_simplification_cache: self._simplification_cache_val[expr._cache_key] = o self._simplification_cache_key[expr._cache_key] = o return o
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 eliminate_quantifiers(self, formula): simplifier = z3.Tactic('simplify') eliminator = z3.Tactic('qe') f = self.converter.convert(formula) s = simplifier(f, elim_and=True, pull_cheap_ite=True, ite_extra_rules=True).as_expr() res = eliminator(s, eliminate_variables_as_block=True).as_expr() return self.converter.back(res)
def _boolref_tactics(self): try: return self._tls.boolref_tactics except AttributeError: tactics = z3.Then(z3.Tactic("simplify", ctx=self._context), z3.Tactic("propagate-ineqs", ctx=self._context), z3.Tactic("propagate-values", ctx=self._context), z3.Tactic("unit-subsume-simplify", ctx=self._context), z3.Tactic("aig", ctx=self._context), ctx=self._context) self._tls.boolref_tactics = tactics return self._tls.boolref_tactics
def __init__(self, model_check_timeout: float): smt_tactic = z3.TryFor(z3.Tactic('smt'), 1 + int(model_check_timeout * 1000 * 0.75)) nlsat_tactic = z3.TryFor(z3.Tactic('qfnra-nlsat'), 1 + int(model_check_timeout * 1000 * 0.25)) self.solver = z3.OrElse(smt_tactic, nlsat_tactic).solver() self.solver.set(mbqi=True) # turn off every randomization thing we can think of: self.solver.set('random-seed', 42) self.solver.set('smt.random-seed', 42) self.solver.set('randomize', False) self.choices_made: List[SearchTreeNode] = [] self.running_framework_code = False self.heaps: List[List[Tuple[z3.ExprRef, Type, object]]] = [[]] self.next_uniq = 1
def convert(self, c): """ Main conversion function Parameter: c (BoolExp): the boolean expression to translate returns a pair of: var_id (dict): maps all variables in c into a index into the CNF constraint cnf (list of list of int): the CNF constraint, where variables are encoded as positive int, and negation of a variable is encoded as -variable_id """ z3_translator = gzl.toZ3Visitor() z3_constraint = z3_translator.visit(c) goal = z3.Goal() goal.add(z3_constraint) tactic = z3.Tactic('tseitin-cnf') z3_cnf = tactic(goal) self._cnf = [] self._var_dict = {} self._curr_id = 1 for z3_c in z3_cnf[0]: self.visit_or(z3_c) self._var_translation = { k.decl().name(): v_id for k, v_id in self._var_dict.items() } return self
def bitblast(e): ctx = e.ctx goal = z3.Goal(ctx=ctx) goal.add(z3.simplify(e)) tactic = z3.Tactic('bit-blast', ctx=ctx) res = tactic.apply(goal, blast_full=True) assert (len(res) == 1) return res[0].as_expr()
def quantifier_free(self, formula): term = self.convert(formula) if not z3.is_bool(term): return term if term in self.cache_qf: return self.cache_qf[term] simplifier = z3.Tactic('simplify') eliminator = z3.Tactic('qe') res = term res = simplifier(res, elim_and=True, pull_cheap_ite=True, ite_extra_rules=True ).as_expr() res = eliminator(res).as_expr() # print(term, " -> ", res) self.cache_qf[term] = res return res
def __init__(self, name): self.name = name self.params = {} pds = z3.Tactic(name).param_descrs() for i in range(pds.size()): pname = pds.get_name(i) self.params[pname] = Param(pname, None, pds.get_kind(pname))
def __init__(self, s): """ Initializes object of type Tactic. :param s: name of the tactic """ assert isinstance(s, str) self.s = s self.tactic = z3.Tactic(s)
def simplify(cls, f): assert z3.is_expr(f), f simpl = z3.Tactic('ctx-solver-simplify') simpl = z3.TryFor(simpl, settings.SOLVER_TIMEOUT) try: f = simpl(f).as_expr() except z3.Z3Exception: pass return f
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 cofactor_term_ite(exp): if z3.is_quantifier(exp): (qvars, matrix) = strip_qblock(exp) matrix = cofactor_term_ite(matrix) if exp.is_forall(): return z3.ForAll(qvars, matrix) else: return z3.Exists(qvars, matrix) t = z3.Tactic('cofactor-term-ite', ctx=exp.ctx) return t(exp).as_expr()
def programVisit(self, program): res = [retvisit(self, i) for i in self.solver.instantiate_graph_constraints] for i in program.ast: val = retvisit(self, i) if val: res.append(val) expr = z3.And(res) goal = z3.Goal() goal.add(expr) tactic = z3.Tactic("tseitin-cnf") prog = tactic(goal)[0] return self.parse_Z3_tseitin(prog)
def mk(cls, using_nla=False, myseed=None): if using_nla: int_theory = 'qfnia' # qfnra real_theory = 'qfnra' else: int_theory = 'qflia' # qflia real_theory = 'qflra' ti = z3.Tactic(int_theory) tr = z3.Tactic(real_theory) if myseed: z3.set_param('smt.arith.random_initial_value', True) p = z3.ParamsRef() p.set("random-seed", myseed) ti = z3.WithParams(ti, p) tr = z3.WithParams(tr, p) t = z3.ParOr(ti, tr) t = z3.TryFor(t, settings.SOLVER_TIMEOUT) return t.solver()
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 get_boolref_tactics(self): tactics = z3.Then( z3.Tactic("simplify"), z3.Tactic("sat-preprocess"), z3.Tactic("cofactor-term-ite"), z3.Tactic("propagate-ineqs"), z3.Tactic("propagate-values"), z3.Tactic("unit-subsume-simplify"), z3.Tactic("aig"), ) return tactics
def __init__(self, model_check_timeout: float): smt_tactic = z3.TryFor(z3.Tactic('smt'), 1 + int(model_check_timeout * 1000)) self.solver = smt_tactic.solver() self.solver.set(mbqi=True) # turn off every randomization thing we can think of: self.solver.set('random-seed', 42) self.solver.set('smt.random-seed', 42) #self.solver.set('randomize', False) self.choices_made: List[SearchTreeNode] = [] self.running_framework_code = False self.heaps: List[List[Tuple[z3.ExprRef, Type, object]]] = [[]] self.next_uniq = 1 self.type_repo = SmtTypeRepository(self.solver)
def qe_array(exp): if not z3.is_quantifier(exp): return exp is_forall = False if exp.is_forall(): is_forall = True (qvars, matrix) = strip_qblock(exp) exp = z3.Exists(qvars, z3.Not(matrix)) qf_exp = z3.Tactic('qe-array', ctx=exp.ctx)(exp).as_expr() if is_forall: (qvars, matrix) = strip_qblock(qf_exp) if len(qvars) > 0: res = z3.ForAll(qvars, z3.Not(matrix)) else: res = z3.Not(matrix) else: res = qf_exp return res
def qe_lite(exp): if not z3.is_quantifier(exp): return exp e = exp t = z3.Tactic('qe-light', ctx=exp.ctx) # invoke qe_lite once per quantified variable, for better result for i in range(exp.num_vars()): e = t(e).as_expr() if not z3.is_quantifier(e): return e if z3.is_quantifier(e): # invoke qe_lite for each variable, separately (qvars, matrix) = strip_qblock(e) for v in qvars: if exp.is_forall(): matrix = t(z3.ForAll([v], matrix)).as_expr() else: matrix = t(z3.Exists([v], matrix)).as_expr() e = matrix return e
def __init__(self, types, cons): super().__init__() assert isinstance(types, dict), 'Types for SMT must be a dictionary' assert isinstance(cons, list), 'Constraints for SMT must be a list' self.types = types self.cons = cons self.asmpts = [] # Some may call this the dark side but # put SMT variables in object locals, so that we can refer to them # at other places. single = 'z3.Float32()' double = 'z3.Float64()' BV32 = 'z3.BitVecSort(32)' BV64 = 'z3.BitVecSort(64)' RNE = 'z3.RNE()' for v in list(self.types.keys()): assert v not in vars(self) if self.types[v] == 'float': dym_str = 'vars(self)["{}"] = z3.Const("{}", {})'.format( v, v, double) else: assert self.types[v] == 'int' dym_str = 'vars(self)["{}"] = z3.fpSignedToFP({}, z3.Const("{}", {}), {})'.format( v, RNE, v, BV64, double) exec(dym_str) # TODO Cannot find reference to Tactic, check for problems t1 = z3.Tactic('simplify') t2 = z3.Tactic('solve-eqs') t3 = z3.Tactic('split-clause') t4 = z3.Tactic('qffpbv') t5 = z3.Tactic('qfnra-nlsat') t6 = z3.Tactic('normalize-bounds') t7 = z3.Tactic('smt') goal = z3.Then(z3.AndThen(t1, t2, t6), t4) # goal = z3.AndThen(t1, t2, t6) self.solver = goal.solver() for con in self.cons: trans_con = self.__transform(con) self.solver.add(trans_con)
def __init__( self, execution_deadline: float, model_check_timeout: float, search_root: SinglePathNode, ): smt_tactic = z3.TryFor(z3.Tactic("smt"), 1 + int(model_check_timeout * 1000)) self.solver = smt_tactic.solver() self.solver.set(mbqi=True) # turn off every randomization thing we can think of: self.solver.set("random-seed", 42) self.solver.set("smt.random-seed", 42) # self.solver.set('randomize', False) self.choices_made: List[SearchTreeNode] = [] self.running_framework_code = False self.heaps: List[List[Tuple[z3.ExprRef, Type, object]]] = [[]] self.next_uniq = 1 self.type_repo = SymbolicTypeRepository(self.solver) self.execution_deadline = execution_deadline self._random = search_root._random _, self.search_position = search_root.choose() self._deferred_assumptions = []
def elim_term_ite(exp): if z3.is_quantifier(exp): (qvars, matrix) = strip_qblock(exp) matrix = elim_term_ite(matrix) if exp.is_forall(): e = z3.ForAll(qvars, matrix) else: e = z3.Exists(qvars, matrix) return e pre_consts = extract_consts(exp) pre_const_keys = map(exp_key, pre_consts) t = z3.Tactic('elim-term-ite', ctx=exp.ctx) e = t(exp).as_expr() # tactic introduces new constants which need to be existentially quantified post_consts = extract_consts(e) post_const_keys = map(exp_key, post_consts) exist_consts = [] for i in range(len(post_consts)): post_key = post_const_keys[i] if post_key not in pre_const_keys: exist_consts.append(post_consts[i]) if len(exist_consts) > 0: e = z3.Exists(exist_consts, e) return qe_lite(e)
def qe_tactic(ctx=None): ctx = z3._get_ctx(ctx) return z3.Tactic(z3core.Z3_mk_tactic(ctx.ref(), 'qe'), ctx)