def back(self, expr): res = None if expr.isConst(): if expr.getType().isBoolean(): v = expr.getConstBoolean() res = self.mgr.Bool(v) elif expr.getType().isInteger(): v = expr.getConstRational().toString() res = self.mgr.Int(int(v)) elif expr.getType().isReal(): v = expr.getConstRational().toString() res = self.mgr.Real(Fraction(v)) elif expr.getType().isBitVector(): bv = expr.getConstBitVector() v = bv.getValue().toString() width = bv.getSize() res = self.mgr.BV(int(v), width) elif expr.getType().isString(): v = expr.getConstString() res = self.mgr.String(v.toString()) elif expr.getType().isArray(): const_ = expr.getConstArrayStoreAll() array_type = self._cvc4_type_to_type(const_.getType()) base_value = self.back(const_.getExpr()) res = self.mgr.Array(array_type.index_type, base_value) else: raise PyomtTypeError("Unsupported constant type:", expr.getType().toString()) else: raise PyomtTypeError("Unsupported expression:", expr.toString()) return res
def Real(self, value): """ Returns a Real-type constant of the given value. value can be: - A Fraction(n,d) - A tuple (n,d) - A long or int n - A float - (Optionally) a mpq or mpz object """ if value in self.real_constants: return self.real_constants[value] if is_pyomt_fraction(value): val = value elif type(value) == tuple: val = Fraction(value[0], value[1]) elif is_python_rational(value): val = pyomt_fraction_from_rational(value) else: raise PyomtTypeError("Invalid type in constant. The type was:" + \ str(type(value))) n = self.create_node(node_type=op.REAL_CONSTANT, args=tuple(), payload=val) self.real_constants[value] = n return n
def get_value(self, item): self._assert_no_function_type(item) term = self.converter.convert(item) cvc4_res = self.cvc4.getValue(term) res = self.converter.back(cvc4_res) if self.environment.stc.get_type(item).is_real_type() and \ self.environment.stc.get_type(res).is_int_type(): res = self.environment.formula_manager.Real( Fraction(res.constant_value(), 1)) return res
def algebraic_approx_value(self, precision=10): value = self.constant_value() approx = value.approx(precision) # MG: This is a workaround python 3 since Z3 mixes int and long. # The bug was fixed in master of Z3, but no official relase # has been done containing it. # In the most recent version of z3, this can be done with: # return approx.as_fraction() n = int(str(approx.numerator())) d = int(str(approx.denominator())) return Fraction(n, d)
def Div(self, left, right): """ Creates an expression of the form: left / right """ if right.is_constant(types.REAL): # If right is a constant we rewrite as left * 1/right inverse = Fraction(1) / right.constant_value() return self.Times(left, self.Real(inverse)) elif right.is_constant(types.INT): raise NotImplementedError # This is a non-linear expression return self.create_node(node_type=op.DIV, args=(left, right))
def get_value(self, item): self._assert_no_function_type(item) titem = self.converter.convert(item) ty = self.environment.stc.get_type(item) if ty.is_bool_type(): status, res = yicespy.yices_get_bool_value(self.model, titem) self._check_error(status) return self.mgr.Bool(bool(res)) elif ty.is_int_type(): res = yicespy.yices_get_integer_value(self.model, titem) return self.mgr.Int(res) elif ty.is_real_type(): status, val = yicespy.yices_get_rational_value(self.model, titem) self._check_error(status) return self.mgr.Real(Fraction(val)) elif ty.is_bv_type(): status, res = yicespy.yices_get_bv_value(self.model, titem, ty.width) self._check_error(status) str_val = "".join(str(x) for x in reversed(res)) return self.mgr.BV("#b" + str_val) else: raise NotImplementedError()
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 real_constant(self, read): return Constant(self.mgr.Real(Fraction(read)))