def _convert(self, obj): if isinstance(obj, FSort): return z3.FPSort(obj.exp, obj.mantissa, ctx=self._context) elif isinstance(obj, RM): if obj == RM_RNE: return z3.RNE(ctx=self._context) elif obj == RM_RNA: return z3.RNA(ctx=self._context) elif obj == RM_RTP: return z3.RTP(ctx=self._context) elif obj == RM_RTN: return z3.RTN(ctx=self._context) elif obj == RM_RTZ: return z3.RTZ(ctx=self._context) else: raise BackendError("unrecognized rounding mode") elif obj is True: return z3.BoolVal(True, ctx=self._context) elif obj is False: return z3.BoolVal(False, ctx=self._context) elif isinstance(obj, (numbers.Number, str)): return obj elif hasattr(obj, '__module__') and obj.__module__ in ('z3', 'z3.z3'): return obj else: l.debug("BackendZ3 encountered unexpected type %s", type(obj)) raise BackendError("unexpected type %s encountered in BackendZ3" % type(obj))
def _convert(self, obj, result=None): if type(obj) is NativeBVV: return z3.BitVecVal(obj.value, obj.bits) elif isinstance(obj, FSort): return z3.FPSort(obj.exp, obj.mantissa) elif isinstance(obj, RM): if obj == RM_RNE: return z3.RNE() elif obj == RM_RNA: return z3.RNA() elif obj == RM_RTP: return z3.RTP() elif obj == RM_RTN: return z3.RTN() elif obj == RM_RTZ: return z3.RTZ() else: raise BackendError("unrecognized rounding mode") elif isinstance(obj, NativeFPV): val = str(obj.value) sort = self._convert(obj.sort) if val == 'inf': return z3.fpPlusInfinity(sort) elif val == '-inf': return z3.fpMinusInfinity(sort) elif val == '0.0': return z3.fpPlusZero(sort) elif val == '-0.0': return z3.fpMinusZero(sort) elif val == 'nan': return z3.fpNaN(sort) else: better_val = str(Decimal(obj.value)) return z3.FPVal(better_val, sort) elif obj is True: return z3.BoolVal(True) elif obj is False: return z3.BoolVal(False) elif type(obj) in (int, long, float, str): return obj elif hasattr(obj, '__module__') and obj.__module__ == 'z3': return obj else: l.debug("BackendZ3 encountered unexpected type %s", type(obj)) raise BackendError("unexpected type %s encountered in BackendZ3" % type(obj))
# We do float16 because it lets the solver run much faster. These results # should generalize to fp32 and fp64, and you can verify this by changing the # value of FLOAT_TY (and then waiting a while). FLOAT_TY = z3.Float16 a = z3.FP("a", FLOAT_TY()) b = z3.FP("b", FLOAT_TY()) c = z3.FP("c", FLOAT_TY()) s = z3.Solver() # C must be a power of 2, i.e. significand bits must all be 0. s.add(z3.Extract(FLOAT_TY().sbits() - 1, 0, z3.fpToIEEEBV(c)) == 0) for rm in [z3.RTZ(), z3.RNE()]: z3.set_default_rounding_mode(rm) before = a * c + b * c after = (a + b) * c # Check that before == after, allowing that 0 == -0. s.add( z3.Not( z3.Or( before == after, # z3.And(z3.fpIsZero(before), z3.fpIsZero(after))))) for x in [ (a * c), (b * c), (a + b),
def cast(self, value, is_type, to_type): if is_type is Types.STRING and isinstance(to_type, z3.z3.DatatypeSortRef): # the value is a string and it should be cast to a datatyperef # (i.e. an enum-type), just return the value because we can deal with it return value value_is_int = isinstance(value, int) value_is_float = isinstance(value, float) if is_type is to_type: # already correct type, just return the value return value """ INT <---> INTEGER """ elif is_type is Types.INT and to_type is Types.INTEGER: if value_is_int or value_is_float: return value # this happens if it is an int numeral (e.g. 2) else: return z3.BV2Int(value) elif is_type is Types.INTEGER and to_type is Types.INT: if value_is_int or value_is_float: return value else: return z3.Int2BV(value, 32) """ INT <---> FLOAT """ elif is_type is Types.FLOAT and to_type is Types.INT: if value_is_float: return value # this happens if it is a float numeral (e.g. 3.14) else: return z3.fpToSBV(z3.RNE(), value, z3.BitVecSort(32)) elif is_type is Types.INT and to_type is Types.FLOAT: if value_is_int: return value else: return z3.fpSignedToFP(z3.RNE(), value, z3.Float32()) """ INTEGER <---> FLOAT """ elif is_type is Types.FLOAT and to_type is Types.INTEGER: if value_is_float: return value # this happens if it is a float numeral (e.g. 3.14) else: return self.cast(self.cast(value, Types.FLOAT, Types.INT), Types.INT, Types.INTEGER) elif is_type is Types.INTEGER and to_type is Types.FLOAT: if value_is_int: return value else: return self.cast(self.cast(value, Types.INTEGER, Types.INT), Types.INT, Types.FLOAT) """ from REAL """ elif is_type is Types.REAL and to_type is Types.INTEGER: if value_is_float: return value else: return z3.ToInt(value) elif is_type is Types.REAL and to_type is Types.INT: return self.cast(self.cast(value, Types.REAL, Types.INTEGER), Types.INTEGER, Types.INT) elif is_type is Types.REAL and to_type is Types.FLOAT: """ Rounding modes: probably should make these parameterizable! roundNearestTiesToEven ... RNE() = default roundNearestTiesToAway ... RNA() roundTowardPositive ...... RTP() roundTowardNegative ...... RTN() roundTowardZero .......... RTZ() """ if value_is_int or value_is_float: # int numeral return value else: return z3.fpRealToFP(z3.RNE(), value, z3.Float32()) """ to REAL """ elif is_type is Types.INT and to_type is Types.REAL: if value_is_int or value_is_float: # int numeral return value else: return z3.ToReal(self.cast(value, Types.INT, Types.INTEGER)) elif is_type is Types.INTEGER and to_type is Types.REAL: if value_is_int or value_is_float: # int numeral return value else: return z3.ToReal(value) elif is_type is Types.FLOAT and to_type is Types.REAL: if value_is_int or value_is_float: return value # this happens if it is a float numeral (e.g. 3.14) else: return z3.fpToReal(value) """ FROM BOOL conversions """ elif is_type is Types.BOOL and to_type is Types.INT: return z3.If(value, z3.BitVecVal(1, 32), z3.BitVecVal(0, 32)) elif is_type is Types.BOOL and to_type is Types.INTEGER: return z3.If(value, 1, 0) elif is_type is Types.BOOL and to_type is Types.REAL: return z3.If(value, 1.0, 0.0) elif is_type is Types.BOOL and to_type is Types.FLOAT: return z3.If(value, z3.FPVal(1.0, z3.Float32()), z3.FPVal(0.0, z3.Float32())) """ TO BOOL conversions """ elif is_type is Types.INT and to_type is Types.BOOL: return value == 1 elif is_type is Types.INTEGER and to_type is Types.BOOL: return value == 1 elif is_type is Types.REAL and to_type is Types.BOOL: return value == 1 elif is_type is Types.FLOAT and to_type is Types.BOOL: return value == 1 raise TypeError(f"Don't know how to cast from {is_type} to {to_type}!")
def _(term, smt): v = smt.eval(term._args[0]) return z3.fpToFP(z3.RNE(), v, _ty_sort(smt.type(term)))