From 6c971b130132c8774d5e92b2a331a5a702485382 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 11 Jan 2015 18:29:40 +0000 Subject: [PATCH] Beginnings of a Python API for FPA Signed-off-by: Christoph M. Wintersteiger --- src/api/python/z3.py | 912 ++++++++++++++++++++++++++++++++++++ src/api/python/z3printer.py | 207 +++++++- 2 files changed, 1114 insertions(+), 5 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index bb0212820..a2f0191cf 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -555,6 +555,10 @@ def _to_sort_ref(s, ctx): return ArraySortRef(s, ctx) elif k == Z3_DATATYPE_SORT: return DatatypeSortRef(s, ctx) + elif k == Z3_FLOATING_POINT_SORT: + return FPSortRef(s, ctx) + elif k == Z3_ROUNDING_MODE_SORT: + return FPRMSortRef(s, ctx) return SortRef(s, ctx) def _sort(ctx, a): @@ -899,6 +903,17 @@ def _to_expr_ref(a, ctx): return ArrayRef(a, ctx) if sk == Z3_DATATYPE_SORT: return DatatypeRef(a, ctx) + if sk == Z3_FLOATING_POINT_SORT: + if k == Z3_APP_AST: + e = ExprRef(a, ctx) + if e.decl().kind() == Z3_OP_FPA_NUM: + return FPNumRef(a, ctx) + else: + return FPRef(a, ctx) + else: + return FPRef(a, ctx) + if sk == Z3_ROUNDING_MODE_SORT: + return FPRMRef(a, ctx) return ExprRef(a, ctx) def _coerce_expr_merge(s, a): @@ -7429,3 +7444,900 @@ def sequence_interpolant(v,p=None,ctx=None): f = And(Interpolant(f),v[i]) return tree_interpolant(f,p,ctx) +######################################### +# +# Floating-Point Arithmetic +# +######################################### + + +# Global default rounding mode +_dflt_rounding_mode = Z3_OP_FPA_RM_TOWARD_ZERO +_dflt_fpsort_ebits = 11 +_dflt_fpsort_sbits = 53 + +def get_default_rounding_mode(ctx=None): + """Retrieves the global default rounding mode.""" + global _dflt_rounding_mode + if _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_ZERO: + return RTZ(ctx) + elif _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_NEGATIVE: + return RTN(ctx) + elif _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_POSITIVE: + return RTP(ctx) + elif _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN: + return RNE(ctx) + elif _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY: + return RNA(ctx) + +def set_default_rounding_mode(rm, ctx=None): + global _dflt_rounding_mode + if is_fprm_value(rm): + _dflt_rounding_mode = rm.decl().kind() + else: + _z3_assert(_dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_ZERO or + _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_NEGATIVE or + _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_POSITIVE or + _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN or + _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY, + "illegal rounding mode") + _dflt_rounding_mode = rm + +def get_default_fp_sort(ctx=None): + return FPSort(_dflt_fpsort_ebits, _dflt_fpsort_sbits, ctx) + +def set_default_fp_sort(ebits, sbits, ctx=None): + global _dflt_fpsort_ebits + global _dflt_fpsort_sbits + _dflt_fpsort_ebits = ebits + _dflt_fpsort_sbits = sbits + +def _dflt_rm(ctx=None): + return get_default_rounding_mode(ctx) + +def _dflt_fps(ctx=None): + return get_default_fp_sort(ctx) + +### FP Sorts + +class FPSortRef(SortRef): + """Floating-point sort.""" + + def ebits(self): + """Retrieves the number of bits reserved for the exponent in the FloatingPoint sort `self`. + >>> b = FPSort(8, 24) + >>> b.ebits() + 8 + """ + return int(Z3_fpa_get_ebits(self.ctx_ref(), self.ast)) + + def sbits(self): + """Retrieves the number of bits reserved for the exponent in the FloatingPoint sort `self`. + >>> b = FloatingPointSort(8, 24) + >>> b.sbits() + 24 + """ + return int(Z3_fpa_get_sbits(self.ctx_ref(), self.ast)) + + def cast(self, val): + """Try to cast `val` as a Floating-point expression + + >>> b = FPSort(8, 24) + >>> b.cast(1.0) + 1.0 + >>> b.cast(1.0).sexpr() + '1.0' + """ + if is_expr(val): + if __debug__: + _z3_assert(self.ctx == val.ctx, "Context mismatch") + return val + else: + return FPVal(val, None, self, self.ctx) + + +def Float16(ctx=None): + """Floating-point 16-bit (half) sort.""" + ctx = _get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort_16(ctx.ref()), ctx) + +def FloatHalf(ctx=None): + """Floating-point 16-bit (half) sort.""" + ctx = _get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort_half(ctx.ref()), ctx) + +def Float32(ctx=None): + """Floating-point 32-bit (single) sort.""" + ctx = _get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort_32(ctx.ref()), ctx) + +def FloatSingle(ctx=None): + """Floating-point 32-bit (single) sort.""" + ctx = _get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort_single(ctx.ref()), ctx) + +def Float64(ctx=None): + """Floating-point 64-bit (double) sort.""" + ctx = _get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort_64(ctx.ref()), ctx) + +def FloatSingle(ctx=None): + """Floating-point 64-bit (double) sort.""" + ctx = _get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort_double(ctx.ref()), ctx) + +def Float128(ctx=None): + """Floating-point 128-bit (quadruple) sort.""" + ctx = _get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort_128(ctx.ref()), ctx) + +def FloatSingle(ctx=None): + """Floating-point 128-bit (quadruple) sort.""" + ctx = _get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort_quadruple(ctx.ref()), ctx) + +class FPRMSortRef(SortRef): + """"Floating-point rounding mode sort.""" + + +def is_fp_sort(s): + """Return True if `s` is a Z3 floating-point sort. + + >>> is_fp_sort(FloatingPointSort(8, 24)) + True + >>> is_fp_sort(IntSort()) + False + """ + return isinstance(s, FPSortRef) + +def is_fprm_sort(s): + """Return True if `s` is a Z3 floating-point rounding mode sort. + + >>> is_fprm_sort(FPSort(8, 24)) + False + >>> is_fprm_sort() + False + """ + return isinstance(s, FPSortRef) + +### FP Expressions + +class FPRef(ExprRef): + """Floating-point expressions.""" + + def sort(self): + """Return the sort of the floating-point expression `self`. + + >>> x = FP('1.0', FPSort(8, 24)) + >>> x.sort() + (_ FloatingPoint 8 24) + >>> x.sort() == FloatingPointSort(8, 24) + True + """ + return FPSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) + + def ebits(self): + """Retrieves the number of bits reserved for the exponent in the FloatingPoint expression `self`. + >>> b = FloatingPointSort(8, 24) + >>> b.ebits() + 8 + """ + return self.sort().ebits(); + + def sbits(self): + """Retrieves the number of bits reserved for the exponent in the FloatingPoint expression `self`. + >>> b = FloatingPointSort(8, 24) + >>> b.sbits() + 24 + """ + return self.sort().sbits(); + + def as_string(self): + """Return a Z3 floating point expression as a Python string.""" + return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) + + def __le__(self, other): + return fpLEQ(self, other) + + def __lt__(self, other): + return fpLEQ(self, other) + + def __ge__(self, other): + return fpGEQ(self, other) + + def __gt__(self, other): + return fpGT(self, other) + + def __ne__(self, other): + return fpNEQ(self, other) + + + def __add__(self, other): + """Create the Z3 expression `self + other`. + + >>> x = FP('x', 8, 24) + >>> y = FP('y', 8, 24) + >>> x + y + x + y + >>> (x + y).sort() + FloatingPoint(8 24) + """ + a, b = z3._coerce_exprs(self, other) + return fpAdd(_dflt_rm(), self, other) + + def __radd__(self, other): + """Create the Z3 expression `other + self`. + + >>> x = FP('x', FPSort(8, 24)) + >>> 10 + x + 10 + x + """ + a, b = _coerce_exprs(self, other) + return fpAdd(_dflt_rm(), other, self) + + def __sub__(self, other): + """Create the Z3 expression `self - other`. + + >>> x = FP('x', 8, 24) + >>> y = FP('y', 8, 24) + >>> x - y + x - y + >>> (x - y).sort() + FloatingPoint(8 24) + """ + a, b = z3._coerce_exprs(self, other) + return fpSub(_dflt_rm(), self, other) + + def __rsub__(self, other): + """Create the Z3 expression `other - self`. + + >>> x = FP('x', FPSort(8, 24)) + >>> 10 - x + 10 - x + """ + a, b = _coerce_exprs(self, other) + return fpSub(_dflt_rm(), other, self) + + def __mul__(self, other): + """Create the Z3 expression `self * other`. + + >>> x = FP('x', 8, 24) + >>> y = FP('y', 8, 24) + >>> x * y + x * y + >>> (x * y).sort() + FloatingPoint(8 24) + """ + a, b = z3._coerce_exprs(self, other) + return fpMul(_dflt_rm(), self, other) + + def __rmul_(self, other): + """Create the Z3 expression `other * self`. + + >>> x = FP('x', FPSort(8, 24)) + >>> 10 * x + 10 * x + """ + a, b = _coerce_exprs(self, other) + return fpMul(_dflt_rm(), other, self) + + def __pos__(self): + """Create the Z3 expression `+self`.""" + return self + + def __neg__(self): + """Create the Z3 expression `-self`.""" + return FPRef(fpNeg(self)) + + def __truediv__(self, other): + """Create the Z3 expression division `self / other`.""" + return self.__div__(other) + + def __rtruediv__(self, other): + """Create the Z3 expression division `other / self`.""" + return self.__rdiv__(other) + + def __mod__(self, other): + """Create the Z3 expression mod `self % other`.""" + return fpRem(self, other) + + def __rmod__(self, other): + """Create the Z3 expression mod `other % self`.""" + return fpRem(other, self) + +class FPRMRef(ExprRef): + """Floating-point rounding mode expressions""" + + def as_string(self): + """Return a Z3 floating point expression as a Python string.""" + return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) + + +def RoundNearestTiesToEven (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx) + +def RNE (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx) + +def RoundNearestTiesToAway (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_away(ctx.ref()), ctx) + +def RNA (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_away(ctx.ref()), ctx) + +def RoundTowardPositive (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_toward_positive(ctx.ref()), ctx) + +def RTP (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_toward_positive(ctx.ref()), ctx) + +def RoundTowardNegative (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_toward_negative(ctx.ref()), ctx) + +def RTN (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_toward_negative(ctx.ref()), ctx) + +def RoundTowardZero (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_toward_zero(ctx.ref()), ctx) + +def RTZ (ctx=None): + ctx = _get_ctx(ctx) + return FPRMRef(Z3_mk_fpa_round_toward_zero(ctx.ref()), ctx) + +def is_fprm(a): + """Return `True` if `a` is a Z3 floating-point rounding mode expression. + + >>> rm = ? + """ + return isinstance(a, FPRMRef) + +def is_fprm_value(a): + """Return `True` if `a` is a Z3 floating-point rounding mode numeral value.""" + return is_fprm(a) and _is_numeral(a.ctx, a.ast) + +### FP Numerals + +class FPNumRef(FPRef): + def isNaN(self): + return self.decl().kind() == Z3_OP_FPA_NAN + + def isInf(self): + return self.decl().kind() == Z3_OP_FPA_PLUS_INF or self.decl().kind() == Z3_OP_FPA_MINUS_INF + + def isZero(self): + return self.decl().kind() == Z3_OP_FPA_PLUS_ZERO or self.decl().kind() == Z3_OP_FPA_MINUS_ZERO + + def isNegative(self): + return (self.num_args() == 0 and (Z3_OP_FPA_MINUS_INF or Z3_OP_FPA_MINUS_ZERO)) or (self.num_args() == 3 and self.arg(0) == BitVecVal(1)) + +def _to_fpnum(num, ctx=None): + if isinstance(num, FPNum): + return num + else: + return FPNum(num, ctx) + +def is_fp(a): + """Return `True` if `a` is a Z3 floating-point expression. + + >>> b = FP('b', FPSort(8, 24)) + >>> is_fp(b) + True + >>> is_fp(b + 1.0) + True + >>> is_fp(Int('x')) + False + """ + return isinstance(a, FPRef) + +def is_fp_value(a): + """Return `True` if `a` is a Z3 floating-point numeral value. + + >>> b = FP('b', FPSort(8, 24)) + >>> is_fp_value(b) + False + >>> b = FPVal(1.0, FPSort(8, 24)) + >>> b + 1.0p0 + >>> is_fp_value(b) + True + """ + return is_fp(a) and _is_numeral(a.ctx, a.ast) + +def FPSort(ebits, sbits, ctx=None): + """Return a Z3 floating-point sort of the given sizes. If `ctx=None`, then the global context is used. + + >>> Single = FPSort(8, 24) + >>> Double = FPSort(11, 53) + >>> Single + (_ FloatingPoint 8 24) + >>> x = Const('x', Single) + >>> eq(x, FP('x', 8, 24)) + True + """ + ctx = z3._get_ctx(ctx) + return FPSortRef(Z3_mk_fpa_sort(ctx.ref(), ebits, sbits), ctx) + +def _to_float_str(val): + if isinstance(val, float): + return str(val) + elif isinstance(val, bool): + if val: + return "1.0" + else: + return "0.0" + elif _is_int(val): + return str(val) + elif isinstance(val, str): + return val + if __debug__: + _z3_assert(False, "Python value cannot be used as a double") + +def fpNaN(s): + _z3_assert(isinstance(s, FPSortRef), "sort mismatch") + return FPNumRef(Z3_mk_fpa_nan(s.ctx_ref(), s.ast), s.ctx) + +def fpPlusInfinity(s): + _z3_assert(isinstance(s, FPSortRef), "sort mismatch") + return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, False), s.ctx) + +def fpMinusInfinity(s): + _z3_assert(isinstance(s, FPSortRef), "sort mismatch") + return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, True), s.ctx) + +def fpInfinity(s, negative): + _z3_assert(isinstance(s, FPSortRef), "sort mismatch") + _z3_assert(isinstance(negative, bool), "expected Boolean flag") + return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, negative), s.ctx) + +def fpPlusZero(s): + _z3_assert(isinstance(s, FPSortRef), "sort mismatch") + return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, False), s.ctx) + +def fpMinusZero(s): + _z3_assert(isinstance(s, FPSortRef), "sort mismatch") + return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, True), s.ctx) + +def fpZero(s, negative): + _z3_assert(isinstance(s, FPSortRef), "sort mismatch") + _z3_assert(isinstance(negative, bool), "expected Boolean flag") + return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, negative), s.ctx) + +def FPVal(sig, exp=None, fps=None, ctx=None): + """Return a floating-point value of value `val` and sort `fps`. If `ctx=None`, then the global context is used. + + >>> v = FPVal(1.0, FPSort(8, 24))) + >>> v + 1.0 + >>> print("0x%.8x" % v.as_long()) + 0x0000000a + """ + ctx = _get_ctx(ctx) + if is_fp_sort(exp): + fps = exp + exp = None + elif fps == None: + fps = _dflt_fps(ctx) + _z3_assert(is_fp_sort(fps), "sort mismatch") + if exp == None: + exp = 0 + val = _to_float_str(sig) + val = val + 'p' + val = val + _to_int_str(exp) + return FPNumRef(Z3_mk_numeral(ctx.ref(), val, fps.ast), ctx) + +def FP(name, fpsort, ctx=None): + """Return a floating-point constant named `name`. + `fpsort` is the floating-point sort. + If `ctx=None`, then the global context is used. + + >>> x = FP('x', FPSort(8, 24)) + >>> is_fp(x) + True + >>> x.ebits() + 8 + >>> x.sort() + (_ FloatingPoint 8 24) + >>> word = FPSort(8, 24) + >>> x2 = FP('x', word) + >>> eq(x, x2) + True + """ + ctx = fpsort.ctx + return FPRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), fpsort.ast), ctx) + +def FPs(names, fpsort, ctx=None): + """Return an array of floating-point constants. + + >>> x, y, z = BitVecs('x y z', 16) + >>> x.size() + 16 + >>> x.sort() + BitVec(16) + >>> Sum(x, y, z) + 0 + x + y + z + >>> Product(x, y, z) + 1*x*y*z + >>> simplify(Product(x, y, z)) + x*y*z + """ + ctx = z3._get_ctx(ctx) + if isinstance(names, str): + names = names.split(" ") + return [FP(name, fpsort, ctx) for name in names] + +def fpAbs(a): + """Create a Z3 floating-point absolute value expression. + + >>> s = FPSort(8, 24) + >>> rm = FPRM.RNE + >>> x = FPVal(1.0, s) + >>> fpAbs(x) + 1.0 + >>> x = FPVal(-1.0, s) + >>> fpAbs(x) + 1.0 + >>> fpAbs(x).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fp(a), "First argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_abs(a.ctx_ref(), a.as_ast()), a.ctx) + +def fpNeg(a): + """Create a Z3 floating-point addition expression. + + >>> s = FPSort(8, 24) + >>> rm = FPRM.RNE + >>> x = FP('x', s) + >>> y = FP('y', s) + fp.add(rm, x, y) + >>> fp.add(rm, x, y).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fp(a), "First argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_neg(a.ctx_ref(), a.as_ast()), a.ctx) + +def fpAdd(rm, a, b): + """Create a Z3 floating-point addition expression. + + >>> s = FPSort(8, 24) + >>> rm = FPRM.RNE + >>> x = FP('x', s) + >>> y = FP('y', s) + fp.add(rm, x, y) + >>> fp.add(rm, x, y).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a) and is_fp(b), "Second and third argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_add(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx) + +def fpSub(rm, a, b): + """Create a Z3 floating-point subtraction expression. + + >>> s = FPSort(8, 24) + >>> rm = FPRM.RNE + >>> x = FP('x', s) + >>> y = FP('y', s) + fp.add(rm, x, y) + >>> fp.add(rm, x, y).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a) and is_fp(b), "Second and third argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_sub(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx) + +def fpMul(rm, a, b): + """Create a Z3 floating-point multiplication expression. + + >>> s = FPSort(8, 24) + >>> rm = FPRM.RNE + >>> x = FP('x', s) + >>> y = FP('y', s) + fp.add(rm, x, y) + >>> fp.add(rm, x, y).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a) and is_fp(b), "Second and third argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_mul(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx) + +def fpDiv(rm, a, b): + """Create a Z3 floating-point divison expression. + + >>> s = FPSort(8, 24) + >>> rm = FPRM.RNE + >>> x = FP('x', s) + >>> y = FP('y', s) + fpAdd(rm, x, y) + >>> fp.add(rm, x, y).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a) and is_fp(b), "Second and third argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_mul(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx) + +def fpRem(a, b): + """Create a Z3 floating-point remainder expression. + + >>> s = FPSort(8, 24) + >>> rm = RNE() + >>> x = FP('x', s) + >>> y = FP('y', s) + fpRem(x, y) + >>> fpRem(rm, x, y).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fp(a) and is_fp(b), "Both arguments must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_rem(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def fpMin(a, b): + """Create a Z3 floating-point minimium expression. + + >>> s = FPSort(8, 24) + >>> rm = RNE() + >>> x = FP('x', s) + >>> y = FP('y', s) + fpMin(x, y) + >>> fpMin(rm, x, y).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fp(a) and is_fp(b), "Both arguments must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_min(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def fpMax(a, b): + """Create a Z3 floating-point maximum expression. + + >>> s = FPSort(8, 24) + >>> rm = RNE() + >>> x = FP('x', s) + >>> y = FP('y', s) + fpMin(x, y) + >>> fpMin(rm, x, y).sort() + FloatingPoint(8, 24) + """ + if __debug__: + _z3_assert(is_fp(a) and is_fp(b), "Both arguments must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_max(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def fpFMA(rm, a, b, c): + """Create a Z3 floating-point fused multiply-add expression. + """ + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a) and is_fp(b) and is_fp(c), "Second, third, and fourth argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_fma(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast(), c.as_ast()), rm.ctx) + +def fpSqrt(rm, a): + """Create a Z3 floating-point square root expression. + """ + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a), "Second argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_sqrt(rm.ctx_ref(), rm.as_ast(), a.as_ast()), rm.ctx) + +def fpRoundToIntegral(rm, a): + """Create a Z3 floating-point roundToIntegral expression. + """ + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a), "Second argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_round_to_integral(rm.ctx_ref(), rm.as_ast(), a.as_ast()), rm.ctx) + +def fpIsNaN(a): + """Create a Z3 floating-point isNaN expression. + """ + if __debug__: + _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_is_nan(a.ctx_ref(), a.as_ast()), a.ctx) + +def fpIsInfinite(a): + """Create a Z3 floating-point isNaN expression. + """ + if __debug__: + _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_is_infinite(a.ctx_ref(), a.as_ast()), a.ctx) + +def fpIsZero(a): + """Create a Z3 floating-point isNaN expression. + """ + if __debug__: + _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_is_zero(a.ctx_ref(), a.as_ast()), a.ctx) + +def fpIsNormal(a): + """Create a Z3 floating-point isNaN expression. + """ + if __debug__: + _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_is_normal(a.ctx_ref(), a.as_ast()), a.ctx) + +def fpIsSubnormal(a): + """Create a Z3 floating-point isNaN expression. + """ + if __debug__: + _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_is_subnormal(a.ctx_ref(), a.as_ast()), a.ctx) + +def fpIsNegative(a): + """Create a Z3 floating-point isNaN expression. + """ + if __debug__: + _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_is_negative(a.ctx_ref(), a.as_ast()), a.ctx) + +def fpIsPositive(a): + """Create a Z3 floating-point isNaN expression. + """ + if __debug__: + _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") + return FPRef(Z3_mk_fpa_is_positive(a.ctx_ref(), a.as_ast()), a.ctx) + +def _check_fp_args(a, b): + if __debug__: + _z3_assert(is_fp(a) or is_fp(b), "At least one of the arguments must be a Z3 floating-point expression") + +def fpLT(a, b): + """Create the Z3 floating-point expression `other <= self`. + + >>> x, y = FPs('x y', FPSort(8, 24)) + >>> fpLT(x, y) + x <= y + >>> (x <= y).sexpr() + '?' + >>> fpLT(x, y).sexpr() + '?' + """ + _check_fp_args(a, b) + a, b = _coerce_exprs(a, b) + return BoolRef(Z3_mk_fpa_lt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def fpLEQ(a, b): + """Create the Z3 floating-point expression `other <= self`. + + >>> x, y = FPs('x y', FPSort(8, 24)) + >>> fpLEQ(x, y) + x <= y + >>> (x <= y).sexpr() + '?' + >>> fpLEQ(x, y).sexpr() + '?' + """ + _check_fp_args(a, b) + a, b = _coerce_exprs(a, b) + return BoolRef(Z3_mk_fpa_leq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def fpGT(a, b): + """Create the Z3 floating-point expression `other <= self`. + + >>> x, y = FPs('x y', FPSort(8, 24)) + >>> fpGT(x, y) + x <= y + >>> (x <= y).sexpr() + '?' + >>> fpGT(x, y).sexpr() + '?' + """ + _check_fp_args(a, b) + a, b = _coerce_exprs(a, b) + return BoolRef(Z3_mk_fpa_gt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + + +def fpGEQ(a, b): + """Create the Z3 floating-point expression `other <= self`. + + >>> x, y = FPs('x y', FPSort(8, 24)) + >>> fp_geq(x, y) + x <= y + >>> (x <= y).sexpr() + '?' + >>> fp_geq(x, y).sexpr() + '?' + """ + _check_fp_args(a, b) + a, b = _coerce_exprs(a, b) + return BoolRef(Z3_mk_fpa_geq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def fpEQ(a, b): + """Create the Z3 floating-point expression `other <= self`. + + >>> x, y = FPs('x y', FPSort(8, 24)) + >>> fpEQ(x, y) + x <= y + >>> (x <= y).sexpr() + '?' + >>> fpEQ(x, y).sexpr() + '?' + """ + _check_fp_args(a, b) + a, b = _coerce_exprs(a, b) + return BoolRef(Z3_mk_fpa_eq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def fpNEQ(a, b): + """Create the Z3 floating-point expression `other <= self`. + + >>> x, y = FPs('x y', FPSort(8, 24)) + >>> fpNEQ(x, y) + x <= y + >>> (x <= y).sexpr() + '?' + >>> fpNEQ(x, y).sexpr() + '?' + """ + _check_fp_args(a, b) + a, b = _coerce_exprs(a, b) + return Not(BoolRef(Z3_mk_fpa_eq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx), a.ctx) + + + +def fpFP(sgn, exp, sig): + """Create the Z3 floating-point value `fpFP(sgn, sig, exp)` from the three bit-vectorssgn, sig, and exp.""" + _z3_assert(is_bv(sgn) and is_bv(exp) and is_bv(sig), "sort mismatch") + _z3_assert(sgn.sort().size() == 1, "sort mismatch") + return FPRef(Z3_mk_fpa_fp(sgn.ctx_ref(), sgn.ast, exp.ast, sig.ast), sgn.ctx) + + +def fpToFP(a1, a2=None, a3=None): + """Create a Z3 floating-point conversion expression from other terms.""" + if is_bv(a1) and is_fp_sort(a2): + return FPRef(Z3_mk_fpa_to_fp_bv(a1.ctx_ref(), a1.ast, a2.ast), a1.ctx) + elif is_fprm(a1) and is_fp(a2) and is_fp_sort(a3): + return FPRef(Z3_mk_fpa_to_fp_float(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx) + elif is_fprm(a1) and is_real(a2) and is_fp_sort(a3): + return FPRef(Z3_mk_fpa_to_fp_real(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx) + elif is_fprm(a1) and is_bv(a2) and is_fp_sort(a3): + return FPRef(Z3_mk_fpa_to_fp_signed(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx) + else: + raise Z3Exception("Unsupported combination of arguments for conversion to floating-point term.") + +def fpToFPUnsigned(rm, x, s): + """Create a Z3 floating-point conversion expression, from unsigned bit-vector to floating-point expression.""" + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_bv(x), "Second argument must be a Z3 bit-vector expression") + _z3_assert(is_fp_sort(s), "Third argument must be Z3 floating-point sort") + return FPRef(Z3_mk_fpa_to_fp_unsigned(rm.ctx_ref(), rm.ast, x.ast, s.ast), rm.ctx) + +def fpToSBV(rm, x, s): + """Create a Z3 floating-point conversion expression, from floating-point expression to signed bit-vector.""" + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(x), "Second argument must be a Z3 floating-point expression") + _z3_assert(is_bv_sort(s), "Third argument must be Z3 bit-vector sort") + return FPRef(Z3_mk_fpa_to_sbv(rm.ctx_ref(), rm.ast, x.ast, s.size()), rm.ctx) + +def fpToUBV(rm, x, s): + """Create a Z3 floating-point conversion expression, from floating-point expression to unsigned bit-vector.""" + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(x), "Second argument must be a Z3 floating-point expression") + _z3_assert(is_bv_sort(s), "Third argument must be Z3 bit-vector sort") + return FPRef(Z3_mk_fpa_to_ubv(rm.ctx_ref(), rm.ast, x.ast, s.size()), rm.ctx) + +def fpToReal(x): + """Create a Z3 floating-point conversion expression, from floating-point expression to real.""" + if __debug__: + _z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression") + return FPRef(Z3_mk_fpa_to_real(x.ctx_ref(), x.ast), x.ctx) + +def fpToIEEEBV(x): + """Create a Z3 floating-point conversion expression, from floating-point expression to IEEE bit-vector.""" + if __debug__: + _z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression") + return FPRef(Z3_mk_fpa_to_ieee_bv(x.ctx_ref(), x.ast), x.ctx) \ No newline at end of file diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index d1d85d30e..a74a67fa8 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -8,6 +8,7 @@ import sys, io, z3 from z3consts import * from z3core import * +from ctypes import * ############################## # @@ -30,7 +31,7 @@ _z3_op_to_str = { Z3_OP_BASHR : '>>', Z3_OP_BSHL : '<<', Z3_OP_BLSHR : 'LShR', Z3_OP_CONCAT : 'Concat', Z3_OP_EXTRACT : 'Extract', Z3_OP_BV2INT : 'BV2Int', Z3_OP_ARRAY_MAP : 'Map', Z3_OP_SELECT : 'Select', Z3_OP_STORE : 'Store', - Z3_OP_CONST_ARRAY : 'K' + Z3_OP_CONST_ARRAY : 'K' } # List of infix operators @@ -45,17 +46,65 @@ _z3_unary = [ Z3_OP_UMINUS, Z3_OP_BNOT, Z3_OP_BNEG ] # Precedence _z3_precedence = { Z3_OP_POWER : 0, - Z3_OP_UMINUS : 1, Z3_OP_BNEG : 1, Z3_OP_BNOT : 1, + Z3_OP_UMINUS : 1, Z3_OP_BNEG : 1, Z3_OP_BNOT : 1, Z3_OP_MUL : 2, Z3_OP_DIV : 2, Z3_OP_IDIV : 2, Z3_OP_MOD : 2, Z3_OP_BMUL : 2, Z3_OP_BSDIV : 2, Z3_OP_BSMOD : 2, - Z3_OP_ADD : 3, Z3_OP_SUB : 3, Z3_OP_BADD : 3, Z3_OP_BSUB : 3, + Z3_OP_ADD : 3, Z3_OP_SUB : 3, Z3_OP_BADD : 3, Z3_OP_BSUB : 3, Z3_OP_BASHR : 4, Z3_OP_BSHL : 4, Z3_OP_BAND : 5, Z3_OP_BXOR : 6, Z3_OP_BOR : 7, Z3_OP_LE : 8, Z3_OP_LT : 8, Z3_OP_GE : 8, Z3_OP_GT : 8, Z3_OP_EQ : 8, Z3_OP_SLEQ : 8, Z3_OP_SLT : 8, Z3_OP_SGEQ : 8, Z3_OP_SGT : 8, - Z3_OP_IFF : 8 + Z3_OP_IFF : 8, + + Z3_OP_FPA_NEG : 1, + Z3_OP_FPA_MUL : 2, Z3_OP_FPA_DIV : 2, Z3_OP_FPA_REM : 2, Z3_OP_FPA_FMA : 2, + Z3_OP_FPA_ADD: 3, Z3_OP_FPA_SUB : 3, + Z3_OP_FPA_LE : 8, Z3_OP_FPA_LT : 8, Z3_OP_FPA_GE : 8, Z3_OP_FPA_GT : 8, Z3_OP_FPA_EQ : 8 } +# FPA operators +_z3_op_to_fpa_normal_str = { + Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN : 'RNE()', Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY : 'RNA()', + Z3_OP_FPA_RM_TOWARD_POSITIVE : 'RTP()', Z3_OP_FPA_RM_TOWARD_NEGATIVE : 'RTN()', + Z3_OP_FPA_RM_TOWARD_ZERO : 'RTZ()', + Z3_OP_FPA_PLUS_INF : '+oo', Z3_OP_FPA_MINUS_INF : '-oo', + Z3_OP_FPA_NAN : 'NaN', Z3_OP_FPA_PLUS_ZERO : 'PZero', Z3_OP_FPA_MINUS_ZERO : 'NZero', + Z3_OP_FPA_ADD : 'fpAdd', Z3_OP_FPA_SUB : 'fpSub', Z3_OP_FPA_NEG : 'fpNeg', Z3_OP_FPA_MUL : 'fpMul', + Z3_OP_FPA_DIV : 'fpDiv', Z3_OP_FPA_REM : 'fpRem', Z3_OP_FPA_ABS : 'fpAbs', + Z3_OP_FPA_NEG : 'fpNeg', Z3_OP_FPA_MIN : 'fpMin', Z3_OP_FPA_MAX : 'fpMax', + Z3_OP_FPA_FMA : 'fpFMA', Z3_OP_FPA_SQRT : 'fpSqrt', Z3_OP_FPA_ROUND_TO_INTEGRAL : 'fpRoundToIntegral', + + Z3_OP_FPA_EQ : 'fpEQ', Z3_OP_FPA_LT : 'fpLT', Z3_OP_FPA_GT : 'fpGT', Z3_OP_FPA_LE : 'fpLEQ', + Z3_OP_FPA_GE : 'fpGEQ', + + Z3_OP_FPA_IS_NAN : 'fpIsNaN', Z3_OP_FPA_IS_INF : 'fpIsInf', Z3_OP_FPA_IS_ZERO : 'fpIsZero', + Z3_OP_FPA_IS_NORMAL : 'fpIsNormal', Z3_OP_FPA_IS_SUBNORMAL : 'fpIsSubnormal', + Z3_OP_FPA_IS_NEGATIVE : 'fpIsNegative', Z3_OP_FPA_IS_POSITIVE : 'fpIsPositive', + + Z3_OP_FPA_FP : 'fpFP', Z3_OP_FPA_TO_FP : 'fpToFP', Z3_OP_FPA_TO_FP_UNSIGNED: 'fpToFPUnsigned', + Z3_OP_FPA_TO_UBV : 'fpToUBV', Z3_OP_FPA_TO_SBV : 'fpToSBV', Z3_OP_FPA_TO_REAL: 'fpToReal', + Z3_OP_FPA_TO_IEEE_BV : 'fpToIEEEBV' + } + +_z3_op_to_fpa_pretty_str = { + Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN : 'RNE()', Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY : 'RNA()', + Z3_OP_FPA_RM_TOWARD_POSITIVE : 'RTP()', Z3_OP_FPA_RM_TOWARD_NEGATIVE : 'RTN()', + Z3_OP_FPA_RM_TOWARD_ZERO : 'RTZ()', + Z3_OP_FPA_PLUS_INF : '+oo', Z3_OP_FPA_MINUS_INF : '-oo', + Z3_OP_FPA_NAN : 'NaN', Z3_OP_FPA_PLUS_ZERO : '+0.0', Z3_OP_FPA_MINUS_ZERO : '-0.0', + + Z3_OP_FPA_ADD : '+', Z3_OP_FPA_SUB : '-', Z3_OP_FPA_NEG : '-', Z3_OP_FPA_MUL : '*', + Z3_OP_FPA_DIV : '/', Z3_OP_FPA_REM : '%', + Z3_OP_FPA_NEG: '-', + + Z3_OP_FPA_EQ : 'fpEQ', Z3_OP_FPA_LT : '<', Z3_OP_FPA_GT : '>', Z3_OP_FPA_LE : '<=', Z3_OP_FPA_GE : '>=' +} + +_z3_fpa_infix = [ + Z3_OP_FPA_ADD, Z3_OP_FPA_SUB, Z3_OP_FPA_MUL, Z3_OP_FPA_DIV, Z3_OP_FPA_REM, + Z3_OP_FPA_LT, Z3_OP_FPA_GT, Z3_OP_FPA_LE, Z3_OP_FPA_GE +] + def _is_assoc(k): return k == Z3_OP_BOR or k == Z3_OP_BXOR or k == Z3_OP_BAND or k == Z3_OP_ADD or k == Z3_OP_BADD or k == Z3_OP_MUL or k == Z3_OP_BMUL @@ -134,10 +183,14 @@ _infix_map = {} _unary_map = {} _infix_compact_map = {} +for (_k,_v) in _z3_op_to_fpa_normal_str.items(): + _z3_op_to_str[_k] = _v + for _k in _z3_infix: _infix_map[_k] = True for _k in _z3_unary: _unary_map[_k] = True + for _k in _z3_infix_compact: _infix_compact_map[_k] = True @@ -463,6 +516,7 @@ class Formatter: self.precision = 10 self.ellipses = to_format(_ellipses) self.max_visited = 10000 + self.fpa_pretty = False def pp_ellipses(self): return self.ellipses @@ -499,6 +553,8 @@ class Formatter: return seq1('Array', (self.pp_sort(s.domain()), self.pp_sort(s.range()))) elif isinstance(s, z3.BitVecSortRef): return seq1('BitVec', (to_format(s.size()), )) + elif isinstance(s, z3.FPSortRef): + return seq1('FPSort', (to_format(s.ebits()), to_format(s.sbits()))) else: return to_format(s.name()) @@ -520,6 +576,118 @@ class Formatter: def pp_bv(self, a): return to_format(a.as_string()) + def pp_fprm_value(self, a): + z3._z3_assert(z3.is_fprm_value(a), 'expected FPRMNumRef') + if self.fpa_pretty and _z3_op_to_fpa_pretty_str.has_key(a.decl().kind()): + return to_format(_z3_op_to_fpa_pretty_str.get(a.decl().kind())) + else: + return to_format(a.as_string()) + + def pp_fp_value(self, a): + z3._z3_assert(isinstance(a, z3.FPNumRef), 'type mismatch') + if not self.fpa_pretty: + if (a.isNaN()): + return to_format('NaN') + elif (a.isInf()): + if (a.isNegative()): + return to_format('-oo') + else: + return to_format('+oo') + elif (a.isZero()): + if (a.isNegative()): + return to_format('-zero') + else: + return to_format('+zero') + else: + z3._z3_assert(z3.is_fp_value(a), 'expecting FP num ast') + r = [] + sgn = c_long(0) + sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn)) + sig = Z3_fpa_get_numeral_significand_string(a.ctx_ref(), a.ast) + exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast) + r.append(to_format('FPVal(')) + if not sgnb and sgn: + r.append(to_format('-')) + r.append(to_format(sig)) + r.append(to_format('*(2**')) + r.append(to_format(exp)) + r.append(to_format(', ')) + r.append(to_format(a.sort())) + r.append(to_format('))')) + return compose(r) + else: + if (a.isNaN()): + return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_NAN]) + elif (a.isInf()): + if (a.isNegative()): + return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_MINUS_INF]) + else: + return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_PLUS_INF]) + elif (a.isZero()): + if (a.isNegative()): + return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_MINUS_ZERO]) + else: + return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_PLUS_ZERO]) + else: + z3._z3_assert(z3.is_fp_value(a), 'expecting FP num ast') + r = [] + sgn = c_long(0) + sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn)) + sig = Z3_fpa_get_numeral_significand_string(a.ctx_ref(), a.ast) + exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast) + if not sgnb and sgn != 0: + r.append(to_format('-')) + r.append(to_format(sig)) + if (exp != '0'): + r.append(to_format('*(2**')) + r.append(to_format(exp)) + r.append(to_format(')')) + return compose(r) + + + def pp_fp(self, a, d, xs): + z3._z3_assert(isinstance(a, z3.FPRef), "type mismatch") + k = a.decl().kind() + op = '?' + if self.fpa_pretty: + op = _z3_op_to_fpa_pretty_str.get(k, None) + if (op == None): + op = _z3_op_to_str.get(k, None) + + n = a.num_args() + + if self.fpa_pretty and self.is_infix(k) and n >= 3: + rm = a.arg(0) + if z3.is_fprm_value(rm) and z3._dflt_rm(a.ctx).eq(rm): + arg1 = to_format(self.pp_expr(a.arg(1), d+1, xs)) + arg2 = to_format(self.pp_expr(a.arg(2), d+1, xs)) + r = [] + r.append(arg1) + r.append(to_format(' ')) + r.append(to_format(op)) + r.append(to_format(' ')) + r.append(arg2) + return compose(r) + + if _z3_op_to_fpa_normal_str.has_key(k): + op = _z3_op_to_fpa_normal_str.get(k, None) + + r = [] + r.append(to_format(op)) + if not z3.is_const(a): + r.append(to_format('(')) + first = True + for c in a.children(): + if first: + first = False + else: + r.append(to_format(', ')) + r.append(self.pp_expr(c, d+1, xs)) + r.append(to_format(')')) + return compose(r) + else: + return to_format(a.as_string()) + def pp_prefix(self, a, d, xs): r = [] sz = 0 @@ -678,9 +846,15 @@ class Formatter: elif z3.is_rational_value(a): return self.pp_rational(a) elif z3.is_algebraic_value(a): - return self.pp_algebraic(a) + return self.pp_algebraic(a) elif z3.is_bv_value(a): return self.pp_bv(a) + elif z3.is_fprm_value(a): + return self.pp_fprm_value(a) + elif z3.is_fp_value(a): + return self.pp_fp_value(a) + elif z3.is_fp(a): + return self.pp_fp(a, d, xs) elif z3.is_const(a): return self.pp_const(a) else: @@ -939,6 +1113,12 @@ def set_pp_option(k, v): else: set_html_mode(False) return True + if k == 'fpa_pretty': + if v: + set_fpa_pretty(True) + else: + set_fpa_pretty(False) + return True val = getattr(_PP, k, None) if val != None: z3._z3_assert(type(v) == type(val), "Invalid pretty print option value") @@ -965,6 +1145,23 @@ def set_html_mode(flag=True): else: _Formatter = Formatter() +def set_fpa_pretty(flag=True): + global _Formatter + global _z3_op_to_str + _Formatter.fpa_pretty = flag + if flag: + for (_k,_v) in _z3_op_to_fpa_pretty_str.items(): + _z3_op_to_str[_k] = _v + for _k in _z3_fpa_infix: + _infix_map[_k] = True + else: + for (_k,_v) in _z3_op_to_fpa_normal_str.items(): + _z3_op_to_str[_k] = _v + for _k in _z3_fpa_infix: + _infix_map[_k] = False + + + def in_html_mode(): return isinstance(_Formatter, HTMLFormatter)