def query(self, *query, **kwargs): if 'max_solutions' in kwargs: max_solutions = kwargs['max_solutions'] else: max_solutions = -1 body_atms = [x.as_muz() for x in query] self._solver.query(*body_atms) ans = self._solver.get_answer() query_vars = [x.get_variables() for x in query] query_vars = reduce(lambda x, y: x + [v for v in y if v not in x], query_vars, []) if is_false(ans): # no solution return [] elif not (is_and(ans) or is_or(ans)): # single solution, value of a single variable val = int(ans.children()[1].as_long()) #varb = query.get_variables()[0] varb = query_vars[0] return [{varb: c_id_to_const(val, varb.get_type())}] elif is_or(ans) and not (is_and(ans.children()[0]) or is_or(ans.children()[0])): # multiple solutions of single variable vals = [int(x.children()[1].as_long()) for x in ans.children()] #varbs = query.get_variables()[0] varbs = query_vars[0] varbs = [varbs] * len(vals) return [{ k: c_id_to_const(v, varbs[0].get_type()) } for k, v in zip(varbs, vals)] elif is_and(ans): # single solution of more than 1 variable ans = [int(x.children()[1].as_long()) for x in ans.children()] ans = [ans] elif is_or(ans): # multiple solutions of more than 1 variable ans = ans.children() ans = [[int(y.children()[1].as_long()) for y in x.children()] for x in ans] else: raise Exception(f"don't know how to parse {ans}") tmp_args = [v for x in query for v in x.get_variables()] args = reduce(lambda x, y: x + [y] if y not in x else x, tmp_args, []) answer = [ dict([(v, c_id_to_const(c, v.get_type().name)) for v, c in zip(args, x)]) for x in ans ] if max_solutions > 0: return answer[:max_solutions] else: return answer
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 transformNonBooleanLazyEvaluations(var): if z3.is_or(var): # in this case it needs to be the first child since we are using it as a first child when coercing any expression to bool left = var.children()[0].children()[0] if len(var.children()[1].children()) == 0: if str(var.children()[1]) == 'False': return left else: raise Exception('Why would the lazy side of the or be a truthy value?') else: right = var.children()[1].children()[0] sub = z3.String('__ignore({}||{})'.format(str(left), str(right))) GLOBAL_CONSTRAINTS.append(z3.Or(left == sub, right == sub)) return sub if z3.is_and(var): # FIXME what about the first child # in this case it needs to be the first child since we are using it as a first child when coercing any expression to bool right = var.children()[1].children()[0] # this is by construction the not null of the first GLOBAL_CONSTRAINTS.append(var.children()[0]) return right return var
def coerceTypesIfPossible(var, other_var): if z3.is_or(other_var) and not z3.is_bool(var): other_var = transformNonBooleanLazyEvaluations(other_var) if z3.is_or(var) and not z3.is_bool(other_var): var = transformNonBooleanLazyEvaluations(var) if z3.is_and(other_var) and not z3.is_bool(var): other_var = transformNonBooleanLazyEvaluations(other_var) if z3.is_and(var) and not z3.is_bool(other_var): var = transformNonBooleanLazyEvaluations(var) if var.decl().kind() == z3.Z3_OP_UNINTERPRETED: if z3.is_bool(other_var) and not z3.is_bool(var): infered_types[str(var)] = 'boolean' return z3.Bool(str(var)), other_var if z3.is_string(other_var) and not z3.is_string(var): if other_var.as_string() == '': # we probably dont want to coerce in this specific case as this is merely a non empty check if z3.is_bool(var): return var, z3.BoolVal(False) if z3.is_int(var): return var, z3.IntVal(0) else: infered_types[str(var)] = 'string' return z3.String(str(var)), other_var if z3.is_int(other_var) and not z3.is_int(var): infered_types[str(var)] = 'number' return z3.Int(str(var)), other_var elif var.decl().kind() == z3.Z3_OP_UNINTERPRETED: if z3.is_bool(var): infered_types[str(var)] = 'boolean' if z3.is_string(var): infered_types[str(var)] = 'string' if z3.is_int(var): infered_types[str(var)] = 'number' else: # this means that it is non-interpreted and we need to coerce other var to the type of var if z3.is_string(var) and z3.is_int_value(other_var): other_var = z3.StringVal(str(other_var)) if z3.is_arith(var) and z3.is_string(other_var): other_var = z3.IntVal(int(other_var.as_string())) return var, other_var
def formula2dimacs(z3_formula, output_filename, append_to_file=False, verbose=False): seen_literals = {} number_of_clauses = 0 clauses = [] if append_to_file: if not os.path.isfile(output_filename): print('{} does not exist! Exiting...') exit(1) cnf_clauses = [] # Z3 expressions can be applications, quantifiers and bounded/free variables # FIXME for expr in z3_formula: if z3.is_quantifier(expr): print('Expecting {} to be OR, got quantifier in CNF!'.format(expr)) return #print(expr) if z3.is_or(expr): or_clause = ''.join( [translate2(lit, seen_literals) for lit in expr.children()]) cnf_clauses.append(or_clause) else: lit = translate2(expr, seen_literals) cnf_clauses.append(lit) if not append_to_file: with open(output_filename, 'w') as f: f.write('p cnf {} {}\n'.format(len(seen_literals), len(cnf_clauses))) for clause in cnf_clauses: f.write('{}0\n'.format(clause)) else: (num_vars, num_clauses) = parse_dimacs_header(output_filename) with open(output_filename, 'r') as from_file: tmp_path = output_filename + ".tmp" with open(tmp_path, 'w') as tmp_file: tmp_file.write('p cnf {} {}\n'.format( num_vars + len(seen_literals), num_clauses + len(cnf_clauses))) line = from_file.readline() for line in from_file.readlines(): tmp_file.write(line) for clause in cnf_clauses: tmp_file.write('{}0\n'.format(clause)) os.rename(tmp_path, output_filename)
def toCnf(self): #t = Then('simplify','nnf') #subgoal = t(simplify(self._kb)) #self._logger.writeToLog("subgoal",subgoal) cnf = z3.simplify(self._toCnf(self._kb)) cnflist = [] if z3.is_and(cnf): for i in cnf.children(): tmp = [] if z3.is_or(i): for ii in i.children(): if z3.is_const(ii) or z3.is_not(ii) and z3.is_const( ii.children()[0]): tmp.append(ii) else: self._logger.writeToLog("Wrongly formulated CNF") raise Exception elif z3.is_not(i) and z3.is_const(i.children()[0]): tmp.append(i) elif z3.is_const(i): tmp.append(i) else: self._logger.writeToLog("Wonrgly formulated CNF") cnflist.append(tmp) elif z3.is_or(cnf): tmp = [] for i in cnf.children(): if z3.is_const(i) or z3.is_not(i) and z3.is_const( i.children()[0]): tmp.append(i) else: self._logger.writeToLog("Wonrgly formulated CNF") cnflist.append(tmp) self._logger.writeToLog( "Full Propositional KB in CNF: {}".format(cnflist)) return cnflist
def _parseSmt2String(self, formula): try: if z3.is_or(formula): return z3.Or(self._parseSmt2String(formula.children())) elif z3.is_and(formula): return z3.And(self._parseSmt2String(formula.children())) elif isinstance(formula, list): # and len(formula) > 1: tmp = [] for elem in formula: tmp.append(self._parseSmt2String(elem)) return tmp elif z3.is_not(formula): return z3.Not(self._parseSmt2String(formula.children()[0])) else: return self._abstraction(formula) except: self._logger.writeToLog( "Some Error Occured parsing formula: {}".format(formula)) raise Exception
def mk_app(self, f, args): if z3.is_eq(f): return args[0] == args[1] elif z3.is_and(f): return And(*args) elif z3.is_or(f): return Or(*args) elif z3.is_not(f): return Not(*args) elif z3.is_add(f): return reduce(operator.add, args[1:], args[0]) elif z3.is_mul(f): return reduce(operator.mul, args[1:], args[0]) elif z3.is_sub(f): return args[0] - args[1] elif z3.is_div(f): return args[0] / args[1] elif z3.is_lt(f): return args[0] < args[1] elif z3.is_le(f): return args[0] <= args[1] elif z3.is_gt(f): return args[0] > args[1] elif z3.is_ge(f): return args[0] >= args[1] elif z3.is_to_real(f): # TODO: ignore coercions? return args[0] elif z3.is_to_int(f): return args[0] elif f.name() == '=>': return implies(args[0], args[1]) else: dom_types = [self.mk_sort(f.domain(i))\ for i in range(0, f.arity())] cod_type = self.mk_sort(f.range()) dom_types.reverse() fun_type = reduce((lambda X, Y: type_arrow(Y, X)), \ dom_types, cod_type) func = self.mk_fun(f) return func(*args)
def _toCnf(self, formula): if z3.is_or(formula): tmp = [] ground = [] for i in formula.children(): tmp.append(self._toCnf(i)) for i in tmp: if z3.is_and(i): ground.append(i.children()) elif z3.is_const(i): ground.append([i]) elif z3.is_not(i) and z3.is_const(i.children()[0]): ground.append([i]) elif z3.is_or(i) and all( z3.is_const(elem) or z3.is_not(elem) and z3.is_const(elem.children()[0]) for elem in i.children()): for j in i.children(): ground.append([j]) else: self._logger.writeToLog("is_or, {},{}".format(formula, i)) raise Exception result = [] self._logger.writeToLog("CROSS: {}".format(ground)) for i in itertools.product(*ground): self._logger.writeToLog('Writing to rsults: {},{}'.format( i, list(i))) result.append(z3.Or(i)) self._logger.writeToLog('Resutl: {}'.format(result)) result = z3.And(result) self._logger.writeToLog('ResutAnd: {}'.format(result)) resultS = z3.simplify(result) self._logger.writeToLog("Result simplified: {}".format(resultS)) return resultS elif z3.is_and(formula): tmp = [] ground = [] for i in formula.children(): tmp.append(self._toCnf(i)) for i in tmp: if z3.is_and(i): ground.extend(i.children()) elif z3.is_const(i): ground.append(i) elif z3.is_not(i) and z3.is_const(i.children()[0]): ground.append(i) elif z3.is_or(i) and all( z3.is_const(elem) or z3.is_not(elem) and z3.is_const(elem.children()[0]) for elem in i.children()): ground.append(i) # SHoueld be ----> (1 v 2) and 3 --> (1 and 3 or 2 and 3) not just adding them to the and statement.... right ? else: self._logger.error("is_and, {}, {}".format(formula, i)) raise Exception return z3.simplify(z3.And(ground)) elif z3.is_not(formula): if z3.is_const(formula.children()[0]): return formula elif z3.is_not(formula.children()[0]): return self._toCnf(formula.children()[0]) elif z3.is_and(formula.children()[0]): return self._toCnf( z3.Or([ z3.Not(elem) for elem in formula.children()[0].children() ])) elif z3.is_or(formula.children()[0]): return self._toCnf( z3.And([ z3.Not(elem) for elem in formula.children()[0].children() ])) else: self._logger.writeToLog("is_not({}) problem".formula(formula)) raise Exception elif z3.is_const(formula): return formula else: self._logger.writeToLog("is_nothing problem", formula)
def get_disjuncts (exp) : assert z3.is_bool (exp) if z3.is_or (exp) : return exp.children () else : return [exp]
def writeQDIMACS(filename, constraint, quantifiers, bitmap=None): # filename: String # constraints: list of BV constraints # quantifiers: list of tuples (['a','e','max','count'], list of vars) assert_consistent_quantifiers(quantifiers) log('Bit blasting') bitmap = {} for q in quantifiers: bitvecs = filter(is_bv, q[1]) localBitmap, localBitmapConstraints = create_bitmap(bitvecs) bitmap.update(localBitmap) constraint = And(localBitmapConstraints, constraint) newQuantifiedVars = filter(lambda v: not is_bv(v), q[1]) for (_, boolvar) in localBitmap.iteritems(): newQuantifiedVars.append(boolvar) q[1] = newQuantifiedVars g = Goal() g.add(constraint) matrix = [] t = Then('simplify', 'bit-blast', 'tseitin-cnf') subgoal = t(g) # print(subgoal[0][0].children()[1].children()[0] == bitmap()) assert len(subgoal) == 1 # print('Printing quantifier') # print(quantifiers) # print('Printing goal') # print(g) # exit() max_var = 0 var_mapping = {} # maps to qdimacs variables textFile = open(filename, "w") log('Creating and writing symbol table') textFile.write('c Symbol table for bitvectors\n') symbol_table = [] for ((bv, i), boolvar) in bitmap.iteritems(): max_var += 1 var_mapping[boolvar.get_id()] = max_var # symbol_table.append('c ' + str(boolvar) + ' --> ' + str(max_var)) textFile.write('c ' + str(boolvar) + ' --> ' + str(max_var) + '\n') log('Reserving variable names for quantified variables') for i, q in enumerate(quantifiers): for var in q[1]: if var.get_id() not in var_mapping: max_var += 1 var_mapping[var.get_id()] = max_var # minTseitin = max_var + 1 Tseitin_vars = [] log('Generating clauses ... (this may take a while)') clause_num = 0 for c in subgoal[0]: clause_num += 1 if clause_num % 10000 == 0: log(' {} clauses'.format(clause_num)) if is_or(c): clause = '' for l in c.children(): # literals max_var, lit_str = encode_literal(var_mapping, Tseitin_vars, max_var, l) clause += lit_str matrix.append(clause) elif is_const(c) or is_not(c): max_var, lit_str = encode_literal(var_mapping, Tseitin_vars, max_var, c) matrix.append(lit_str) else: log('Error: Unknown element ' + str(c)) assert false matrix.append('') log(' Generated ' + str(clause_num) + ' clauses') log('Writing header') textFile.write('p cnf {} {}\n'.format(max_var, clause_num)) # Extending quantifiers by innermost existential if necessary if quantifiers[-1][0] == 'a' and len( Tseitin_vars) > 0: # max_var + 1 - minTseitin > 0 quantifiers.append(['e', []]) # empty existential log('Writing quantifiers') for i, q in enumerate(quantifiers): textFile.write(q[0]) for v in q[1]: # try: v_id = v.get_id() textFile.write(' ' + str(var_mapping[v_id])) # except Exception as ex: # log(' Error when writing var {} to file ({})'.format(str(v), str(ex))) # # template = "An exception of type {0} occurred. Arguments:\n{1!r}" # message = template.format(type(ex).__name__, ex.args) # print message # # exit() if i == len(quantifiers) - 1: log('Adding {} Tseitin variables'.format(len(Tseitin_vars))) for varID in Tseitin_vars: textFile.write(' ' + str(varID)) # for varID in range(minTseitin,max_var+1): # # log('Adding var {}'.format(varID)) # textFile.write(' '+str(varID)) # # quantifiers[-1][1].append(varID) # log(' OK (added {} Tseitin vars)'.format(len(range(minTseitin,max_var+1)))) textFile.write(' 0\n') log('Writing clauses') textFile.write('0\n'.join(matrix)) textFile.close() return var_mapping
def _back_single_term(self, expr, args): assert z3.is_expr(expr) if z3.is_quantifier(expr): raise NotImplementedError( "Quantified back conversion is currently not supported") res = None if z3.is_and(expr): res = self.mgr.And(args) elif z3.is_or(expr): res = self.mgr.Or(args) elif z3.is_add(expr): res = self.mgr.Plus(args) elif z3.is_div(expr): res = self.mgr.Div(args[0], args[1]) elif z3.is_eq(expr): if self._get_type(args[0]).is_bool_type(): res = self.mgr.Iff(args[0], args[1]) else: res = self.mgr.Equals(args[0], args[1]) elif z3.is_iff(expr): res = self.mgr.Iff(args[0], args[1]) elif z3.is_xor(expr): res = self.mgr.Xor(args[0], args[1]) elif z3.is_false(expr): res = self.mgr.FALSE() elif z3.is_true(expr): res = self.mgr.TRUE() elif z3.is_gt(expr): res = self.mgr.GT(args[0], args[1]) elif z3.is_ge(expr): res = self.mgr.GE(args[0], args[1]) elif z3.is_lt(expr): res = self.mgr.LT(args[0], args[1]) elif z3.is_le(expr): res = self.mgr.LE(args[0], args[1]) elif z3.is_mul(expr): res = self.mgr.Times(args[0], args[1]) elif z3.is_uminus(expr): tp = self._get_type(args[0]) if tp.is_real_type(): minus_one = self.mgr.Real(-1) else: assert tp.is_int_type() minus_one = self.mgr.Int(-1) res = self.mgr.Times(args[0], minus_one) elif z3.is_sub(expr): res = self.mgr.Minus(args[0], args[1]) elif z3.is_not(expr): res = self.mgr.Not(args[0]) elif z3.is_implies(expr): res = self.mgr.Implies(args[0], args[1]) elif z3.is_quantifier(expr): raise NotImplementedError elif z3.is_const(expr): if z3.is_rational_value(expr): n = expr.numerator_as_long() d = expr.denominator_as_long() f = Fraction(n, d) res = self.mgr.Real(f) elif z3.is_int_value(expr): n = expr.as_long() res = self.mgr.Int(n) elif z3.is_bv_value(expr): n = expr.as_long() w = expr.size() res = self.mgr.BV(n, w) else: # it must be a symbol res = self.mgr.get_symbol(str(expr)) elif z3.is_ite(expr): res = self.mgr.Ite(args[0], args[1], args[2]) elif z3.is_function(expr): res = self.mgr.Function(self.mgr.get_symbol(expr.decl().name()), args) elif z3.is_to_real(expr): res = self.mgr.ToReal(args[0]) elif z3.is_bv_and(expr): res = self.mgr.BVAnd(args[0], args[1]) elif z3.is_bv_or(expr): res = self.mgr.BVOr(args[0], args[1]) elif z3.is_bv_xor(expr): res = self.mgr.BVXor(args[0], args[1]) elif z3.is_bv_not(expr): res = self.mgr.BVNot(args[0]) elif z3.is_bv_neg(expr): res = self.mgr.BVNeg(args[0]) elif z3.is_bv_concat(expr): res = self.mgr.BVConcat(args[0], args[1]) elif z3.is_bv_ult(expr): res = self.mgr.BVULT(args[0], args[1]) elif z3.is_bv_uleq(expr): res = self.mgr.BVULE(args[0], args[1]) elif z3.is_bv_slt(expr): res = self.mgr.BVSLT(args[0], args[1]) elif z3.is_bv_sleq(expr): res = self.mgr.BVSLE(args[0], args[1]) elif z3.is_bv_ugt(expr): res = self.mgr.BVUGT(args[0], args[1]) elif z3.is_bv_ugeq(expr): res = self.mgr.BVUGE(args[0], args[1]) elif z3.is_bv_sgt(expr): res = self.mgr.BVSGT(args[0], args[1]) elif z3.is_bv_sgeq(expr): res = self.mgr.BVSGE(args[0], args[1]) elif z3.is_bv_extract(expr): end = z3.get_payload(expr, 0) start = z3.get_payload(expr, 1) res = self.mgr.BVExtract(args[0], start, end) elif z3.is_bv_add(expr): res = self.mgr.BVAdd(args[0], args[1]) elif z3.is_bv_mul(expr): res = self.mgr.BVMul(args[0], args[1]) elif z3.is_bv_udiv(expr): res = self.mgr.BVUDiv(args[0], args[1]) elif z3.is_bv_sdiv(expr): res = self.mgr.BVSDiv(args[0], args[1]) elif z3.is_bv_urem(expr): res = self.mgr.BVURem(args[0], args[1]) elif z3.is_bv_srem(expr): res = self.mgr.BVSRem(args[0], args[1]) elif z3.is_bv_lshl(expr): res = self.mgr.BVLShl(args[0], args[1]) elif z3.is_bv_lshr(expr): res = self.mgr.BVLShr(args[0], args[1]) elif z3.is_bv_ashr(expr): res = self.mgr.BVAShr(args[0], args[1]) elif z3.is_bv_sub(expr): res = self.mgr.BVSub(args[0], args[1]) elif z3.is_bv_rol(expr): amount = z3.get_payload(expr, 0) res = self.mgr.BVRol(args[0], amount) elif z3.is_bv_ror(expr): amount = z3.get_payload(expr, 0) res = self.mgr.BVRor(args[0], amount) elif z3.is_bv_ext_rol(expr): amount = args[1].bv_unsigned_value() res = self.mgr.BVRol(args[0], amount) elif z3.is_bv_ext_ror(expr): amount = args[1].bv_unsigned_value() res = self.mgr.BVRor(args[0], amount) elif z3.is_bv_sext(expr): amount = z3.get_payload(expr, 0) res = self.mgr.BVSExt(args[0], amount) elif z3.is_bv_zext(expr): amount = z3.get_payload(expr, 0) res = self.mgr.BVZExt(args[0], amount) if res is None: raise ConvertExpressionError(message=("Unsupported expression: %s" % str(expr)), expression=expr) return res
def back(self, expr): assert z3.is_expr(expr) if askey(expr) in self.backconversion: return self.backconversion[askey(expr)] if z3.is_quantifier(expr): raise NotImplementedError( "Quantified back conversion is currently not supported") args = [self.back(x) for x in expr.children()] res = None if z3.is_and(expr): res = self.mgr.And(args) elif z3.is_or(expr): res = self.mgr.Or(args) elif z3.is_add(expr): res = self.mgr.Plus(args) elif z3.is_div(expr): res = self.mgr.Div(args[0], args[1]) elif z3.is_eq(expr): if self._get_type(args[0]) == types.BOOL: res = self.mgr.Iff(args[0], args[1]) else: res = self.mgr.Equals(args[0], args[1]) elif z3.is_false(expr): res = self.mgr.FALSE() elif z3.is_true(expr): res = self.mgr.TRUE() elif z3.is_gt(expr): res = self.mgr.GT(args[0], args[1]) elif z3.is_ge(expr): res = self.mgr.GE(args[0], args[1]) elif z3.is_lt(expr): res = self.mgr.LT(args[0], args[1]) elif z3.is_le(expr): res = self.mgr.LE(args[0], args[1]) elif z3.is_mul(expr): res = self.mgr.Times(args[0], args[1]) elif z3.is_sub(expr): res = self.mgr.Minus(args[0], args[1]) elif z3.is_not(expr): res = self.mgr.Not(args[0]) elif z3.is_quantifier(expr): if expr.is_forall(): pass else: pass raise NotImplementedError elif z3.is_const(expr): if z3.is_rational_value(expr): n = expr.numerator_as_long() d = expr.denominator_as_long() f = Fraction(n, d) res = self.mgr.Real(f) elif z3.is_int_value(expr): n = expr.as_long() res = self.mgr.Int(n) else: # it must be a symbol res = self.mgr.get_symbol(str(expr)) elif z3.is_ite(expr): res = self.mgr.Ite(args[0], args[1], args[2]) else: raise TypeError("Unsupported expression:", expr) if res is None: raise TypeError("Unsupported expression:", expr) self.backconversion[askey(expr)] = res return res
def _back_single_term(self, expr, args, model=None): assert z3.is_expr(expr) if z3.is_quantifier(expr): raise NotImplementedError( "Quantified back conversion is currently not supported") res = None if z3.is_and(expr): res = self.mgr.And(args) elif z3.is_or(expr): res = self.mgr.Or(args) elif z3.is_add(expr): res = self.mgr.Plus(args) elif z3.is_div(expr): res = self.mgr.Div(args[0], args[1]) elif z3.is_eq(expr): if self._get_type(args[0]).is_bool_type(): res = self.mgr.Iff(args[0], args[1]) else: res = self.mgr.Equals(args[0], args[1]) elif z3.is_iff(expr): res = self.mgr.Iff(args[0], args[1]) elif z3.is_xor(expr): res = self.mgr.Xor(args[0], args[1]) elif z3.is_false(expr): res = self.mgr.FALSE() elif z3.is_true(expr): res = self.mgr.TRUE() elif z3.is_gt(expr): res = self.mgr.GT(args[0], args[1]) elif z3.is_ge(expr): res = self.mgr.GE(args[0], args[1]) elif z3.is_lt(expr): res = self.mgr.LT(args[0], args[1]) elif z3.is_le(expr): res = self.mgr.LE(args[0], args[1]) elif z3.is_mul(expr): res = self.mgr.Times(args[0], args[1]) elif z3.is_uminus(expr): tp = self._get_type(args[0]) if tp.is_real_type(): minus_one = self.mgr.Real(-1) else: assert tp.is_int_type() minus_one = self.mgr.Int(-1) res = self.mgr.Times(args[0], minus_one) elif z3.is_sub(expr): res = self.mgr.Minus(args[0], args[1]) elif z3.is_not(expr): res = self.mgr.Not(args[0]) elif z3.is_implies(expr): res = self.mgr.Implies(args[0], args[1]) elif z3.is_quantifier(expr): raise NotImplementedError elif z3.is_const(expr): if z3.is_rational_value(expr): n = expr.numerator_as_long() d = expr.denominator_as_long() f = Fraction(n, d) res = self.mgr.Real(f) elif z3.is_int_value(expr): n = expr.as_long() res = self.mgr.Int(n) elif z3.is_bv_value(expr): n = expr.as_long() w = expr.size() res = self.mgr.BV(n, w) elif z3.is_as_array(expr): if model is None: raise NotImplementedError("As-array expressions cannot be" \ " handled as they are not " \ "self-contained") else: interp_decl = z3.get_as_array_func(expr) interp = model[interp_decl] default = self.back(interp.else_value(), model=model) assign = {} for i in xrange(interp.num_entries()): e = interp.entry(i) assert e.num_args() == 1 idx = self.back(e.arg_value(0), model=model) val = self.back(e.value(), model=model) assign[idx] = val arr_type = self._z3_to_type(expr.sort()) res = self.mgr.Array(arr_type.index_type, default, assign) elif z3.is_algebraic_value(expr): # Algebraic value return self.mgr._Algebraic(Numeral(expr)) else: # it must be a symbol res = self.mgr.get_symbol(str(expr)) elif z3.is_ite(expr): res = self.mgr.Ite(args[0], args[1], args[2]) elif z3.is_function(expr): res = self.mgr.Function(self.mgr.get_symbol(expr.decl().name()), args) elif z3.is_to_real(expr): res = self.mgr.ToReal(args[0]) elif z3.is_bv_and(expr): res = self.mgr.BVAnd(args[0], args[1]) elif z3.is_bv_or(expr): res = self.mgr.BVOr(args[0], args[1]) elif z3.is_bv_xor(expr): res = self.mgr.BVXor(args[0], args[1]) elif z3.is_bv_not(expr): res = self.mgr.BVNot(args[0]) elif z3.is_bv_neg(expr): res = self.mgr.BVNeg(args[0]) elif z3.is_bv_concat(expr): res = self.mgr.BVConcat(args[0], args[1]) elif z3.is_bv_ult(expr): res = self.mgr.BVULT(args[0], args[1]) elif z3.is_bv_uleq(expr): res = self.mgr.BVULE(args[0], args[1]) elif z3.is_bv_slt(expr): res = self.mgr.BVSLT(args[0], args[1]) elif z3.is_bv_sleq(expr): res = self.mgr.BVSLE(args[0], args[1]) elif z3.is_bv_ugt(expr): res = self.mgr.BVUGT(args[0], args[1]) elif z3.is_bv_ugeq(expr): res = self.mgr.BVUGE(args[0], args[1]) elif z3.is_bv_sgt(expr): res = self.mgr.BVSGT(args[0], args[1]) elif z3.is_bv_sgeq(expr): res = self.mgr.BVSGE(args[0], args[1]) elif z3.is_bv_extract(expr): end = z3.get_payload(expr, 0) start = z3.get_payload(expr, 1) res = self.mgr.BVExtract(args[0], start, end) elif z3.is_bv_add(expr): res = self.mgr.BVAdd(args[0], args[1]) elif z3.is_bv_mul(expr): res = self.mgr.BVMul(args[0], args[1]) elif z3.is_bv_udiv(expr): res = self.mgr.BVUDiv(args[0], args[1]) elif z3.is_bv_sdiv(expr): res = self.mgr.BVSDiv(args[0], args[1]) elif z3.is_bv_urem(expr): res = self.mgr.BVURem(args[0], args[1]) elif z3.is_bv_srem(expr): res = self.mgr.BVSRem(args[0], args[1]) elif z3.is_bv_lshl(expr): res = self.mgr.BVLShl(args[0], args[1]) elif z3.is_bv_lshr(expr): res = self.mgr.BVLShr(args[0], args[1]) elif z3.is_bv_ashr(expr): res = self.mgr.BVAShr(args[0], args[1]) elif z3.is_bv_sub(expr): res = self.mgr.BVSub(args[0], args[1]) elif z3.is_bv_rol(expr): amount = z3.get_payload(expr, 0) res = self.mgr.BVRol(args[0], amount) elif z3.is_bv_ror(expr): amount = z3.get_payload(expr, 0) res = self.mgr.BVRor(args[0], amount) elif z3.is_bv_ext_rol(expr): amount = args[1].bv_unsigned_value() res = self.mgr.BVRol(args[0], amount) elif z3.is_bv_ext_ror(expr): amount = args[1].bv_unsigned_value() res = self.mgr.BVRor(args[0], amount) elif z3.is_bv_sext(expr): amount = z3.get_payload(expr, 0) res = self.mgr.BVSExt(args[0], amount) elif z3.is_bv_zext(expr): amount = z3.get_payload(expr, 0) res = self.mgr.BVZExt(args[0], amount) elif z3.is_array_select(expr): res = self.mgr.Select(args[0], args[1]) elif z3.is_array_store(expr): res = self.mgr.Store(args[0], args[1], args[2]) elif z3.is_const_array(expr): arr_ty = self._z3_to_type(expr.sort()) k = args[0] res = self.mgr.Array(arr_ty.index_type, k) elif z3.is_power(expr): res = self.mgr.Pow(args[0], args[1]) if res is None: raise ConvertExpressionError(message=("Unsupported expression: %s" % str(expr)), expression=expr) return res
def _back_single_term(self, expr, args, model=None): assert z3.is_expr(expr) if z3.is_quantifier(expr): raise NotImplementedError( "Quantified back conversion is currently not supported") assert not len(args) > 2 or \ (z3.is_and(expr) or z3.is_or(expr) or z3.is_add(expr) or z3.is_mul(expr) or (len(args) == 3 and (z3.is_ite(expr) or z3.is_array_store(expr)))),\ "Unexpected n-ary term: %s" % expr res = None try: decl = z3.Z3_get_app_decl(expr.ctx_ref(), expr.as_ast()) kind = z3.Z3_get_decl_kind(expr.ctx.ref(), decl) # Try to get the back-conversion function for the given Kind fun = self._back_fun[kind] return fun(args, expr) except KeyError as ex: pass if z3.is_const(expr): # Const or Symbol if z3.is_rational_value(expr): n = expr.numerator_as_long() d = expr.denominator_as_long() f = Fraction(n, d) return self.mgr.Real(f) elif z3.is_int_value(expr): n = expr.as_long() return self.mgr.Int(n) elif z3.is_bv_value(expr): n = expr.as_long() w = expr.size() return self.mgr.BV(n, w) elif z3.is_as_array(expr): if model is None: raise NotImplementedError("As-array expressions cannot be" \ " handled as they are not " \ "self-contained") else: interp_decl = z3.get_as_array_func(expr) interp = model[interp_decl] default = self.back(interp.else_value(), model=model) assign = {} for i in xrange(interp.num_entries()): e = interp.entry(i) assert e.num_args() == 1 idx = self.back(e.arg_value(0), model=model) val = self.back(e.value(), model=model) assign[idx] = val arr_type = self._z3_to_type(expr.sort()) return self.mgr.Array(arr_type.index_type, default, assign) elif z3.is_algebraic_value(expr): # Algebraic value return self.mgr._Algebraic(Numeral(expr)) else: # it must be a symbol try: return self.mgr.get_symbol(str(expr)) except UndefinedSymbolError: import warnings symb_type = self._z3_to_type(expr.sort()) warnings.warn("Defining new symbol: %s" % str(expr)) return self.mgr.FreshSymbol(symb_type, template="__z3_%d") elif z3.is_function(expr): # This needs to be after we try to convert regular Symbols fsymbol = self.mgr.get_symbol(expr.decl().name()) return self.mgr.Function(fsymbol, args) # If we reach this point, we did not manage to translate the expression raise ConvertExpressionError(message=("Unsupported expression: %s" % (str(expr))), expression=expr)
def translate2dimacs(z3_formula, start_var, output_filename, append_to_file=False, overlap_vars=0, indep_set=0, verbose=False): """Write a z3 formula to a DIMACS output format. Parameters: - start_var: Offset the auxiliary variables by start_var """ seen_literals = {} cnf_clauses = [] start = time.time() # Z3 expressions can be applications, quantifiers and bounded/free variables for expr in z3_formula: if z3.is_quantifier(expr): print('Expecting {} to be OR, got quantifier in CNF!'.format(expr)) return if z3.is_or(expr): # for lit in expr.children(): # or_clause += translate(start_var, lit, seen_literals) or_clause = ''.join([ translate(start_var, lit, seen_literals) for lit in expr.children() ]) cnf_clauses.append(or_clause) else: lit = translate(start_var, expr, seen_literals) if verbose: print('{} not OR. translated to {}'.format(expr, lit)) cnf_clauses.append(lit) number_of_clauses = len(cnf_clauses) end = time.time() if verbose: print('SEEN LITERALS {}'.format(seen_literals)) print('Iterating took {} sec'.format(end - start)) if not append_to_file: with open(output_filename, 'w') as f: f.write('p cnf {} {}\n'.format( len(seen_literals) + start_var, number_of_clauses)) if indep_set > 0: f.write('{}\n'.format(count_header(indep_set))) curr = 0 prev = 0 for curr, clause in enumerate(cnf_clauses): curr += 1 # flush every 32K elements -- this 32k is an approx. if curr % 99991 == 0: f.write('0\n'.join(cnf_clauses[prev:curr])) f.write('0\n') prev = curr #f.write('0\n'.join(cnf_clauses)) f.write('0\n'.join(cnf_clauses[prev:curr])) f.write('0\n') else: (num_vars, num_clauses) = parse_dimacs_header(output_filename) with open(output_filename, 'r') as from_file: tmp_path = output_filename + '.tmp' with open(tmp_path, 'w') as tmp_file: number_of_clauses += num_clauses tmp_file.write('p cnf {} {}\n'.format( num_vars + start_var + len(seen_literals) - overlap_vars, number_of_clauses)) if indep_set > 0: tmp_file.write('{}\n'.format(count_header(indep_set))) line = from_file.readline() start = time.time() shutil.copyfileobj(from_file, tmp_file) end = time.time() logger.debug('shutil.copyfileobj took {} sec'.format(end - start)) curr = 0 prev = 0 if len(cnf_clauses) < 99991: tmp_file.write('0\n'.join(cnf_clauses)) tmp_file.write('0\n') else: for curr, clause in enumerate(cnf_clauses): curr += 1 # flush every 100K elements -- this 32k is an approx. if curr % 99991 == 0: tmp_file.write('0\n'.join(cnf_clauses[prev:curr])) tmp_file.write('0\n') prev = curr tmp_file.write('0\n'.join(cnf_clauses[prev:curr])) tmp_file.write('0\n') #tmp_file.write('0\n'.join(cnf_clauses)) os.rename(tmp_path, output_filename) return len(seen_literals), number_of_clauses