def _fcmp(term, smt): x = smt.eval(term.x) y = smt.eval(term.y) if term.pred == '': var = z3.BitVec('fcmp_' + term.name, 4) ops = smt._fcmp_ops.itervalues() # since _fcmp_ops should never change, this should be stable cmp = ops.next()(x, y) i = 1 for op in ops: cmp = z3.If(var == i, op(x, y), cmp) i += 1 else: cmp = smt._fcmp_ops[term.pred](x, y) conds = [] if 'nnan' in term.flags: conds += [z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y))] if 'ninf' in term.flags: conds += [z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y))] return smt._conditional_value(conds, bool_to_BitVec(cmp), term.name)
def _fcmp(term, smt): x = smt.eval(term.x) y = smt.eval(term.y) if term.pred == '': var = z3.BitVec('fcmp_' + term.name, 4) ops = smt._fcmp_ops.itervalues() # since _fcmp_ops should never change, this should be stable cmp = ops.next()(x,y) i = 1 for op in ops: cmp = z3.If(var == i, op(x,y), cmp) i += 1 else: cmp = smt._fcmp_ops[term.pred](x,y) conds = [] if 'nnan' in term.flags: conds += [z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y))] if 'ninf' in term.flags: conds += [z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y))] return smt._conditional_value( conds, bool_to_BitVec(cmp), term.name)
def _float_binary_operator(self, term, op): x = self.eval(term.x) y = self.eval(term.y) if 'nnan' in term.flags: self.add_defs(z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(op(x,y)))) if 'ninf' in term.flags: self.add_defs(z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(op(x,y)))) if 'nsz' in term.flags: # NOTE: this will return a different qvar for each (in)direct reference # to this term. Is this desirable? nz = z3.fpMinusZero(_ty_sort(self.type(term))) self.add_defs(z3.Not(x == nz), z3.Not(y == nz)) return op(x,y) # turns -0 to +0 return op(x,y)
def _float_binary_operator(self, term, op): x = self.eval(term.x) y = self.eval(term.y) if 'nnan' in term.flags: self.add_defs(z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(op(x, y)))) if 'ninf' in term.flags: self.add_defs(z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(op(x, y)))) if 'nsz' in term.flags: # NOTE: this will return a different qvar for each (in)direct reference # to this term. Is this desirable? nz = z3.fpMinusZero(_ty_sort(self.type(term))) self.add_defs(z3.Not(x == nz), z3.Not(y == nz)) return op(x, y) # turns -0 to +0 return op(x, y)
def _float_binary_operator(self, term, op): x = self.eval(term.x) y = self.eval(term.y) if 'nnan' in term.flags: self.add_defs(z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(op(x,y)))) if 'ninf' in term.flags: self.add_defs(z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(op(x,y)))) if 'nsz' in term.flags: # NOTE: this will return a different qvar for each (in)direct reference # to this term. Is this desirable? q = self.fresh_var(self.type(term)) self.add_qvar(q) # FIXME self.add_defs(z3.fpEQ(q,0)) z = op(x,y) return z3.If(z3.fpEQ(z,0), q, z) return op(x,y)
def _float_binary_operator(self, term, op): x = self.eval(term.x) y = self.eval(term.y) if 'nnan' in term.flags: self.add_defs(z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(op(x, y)))) if 'ninf' in term.flags: self.add_defs(z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(op(x, y)))) if 'nsz' in term.flags: # NOTE: this will return a different qvar for each (in)direct reference # to this term. Is this desirable? q = self.fresh_var(self.type(term)) self.add_qvar(q) # FIXME self.add_defs(z3.fpEQ(q, 0)) z = op(x, y) return z3.If(z3.fpEQ(z, 0), q, z) return op(x, y)
def _float_binary_operator(self, term, op): logger.debug('_fbo: %s\n%s', term, self.attrs[term]) x = self.eval(term.x) y = self.eval(term.y) z = op(x, y) conds = [] if 'nnan' in self.attrs[term]: df = z3.And(z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(z))) conds.append(z3.Implies(self.attrs[term]['nnan'], df)) elif 'nnan' in term.flags: conds += [ z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(z)) ] if 'ninf' in self.attrs[term]: df = z3.And(z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(z))) conds.append(z3.Implies(self.attrs[term]['ninf'], df)) elif 'ninf' in term.flags: conds += [ z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(z)) ] if 'nsz' in self.attrs[term] or 'nsz' in term.flags: # NOTE: this will return a different qvar for each (in)direct reference # to this term. Is this desirable? b = self.fresh_bool() self.add_qvar(b) z = op(x, y) c = z3.fpIsZero(z) if 'nsz' in self.attrs[term]: c = z3.And(self.attrs[term]['nsz'], c) s = _ty_sort(self.type(term)) z = z3.If(c, z3.If(b, 0, z3.fpMinusZero(s)), z) if isinstance(term, FDivInst): c = [z3.Not(z3.fpIsZero(x)), z3.fpIsZero(y)] if 'nsz' in self.attrs[term]: c.append(self.attrs[term]['nsz']) z = z3.If( z3.And(c), z3.If(b, z3.fpPlusInfinity(s), z3.fpMinusInfinity(s)), z) return self._conditional_value(conds, z, term.name)
def _float_binary_operator(self, term, op): logger.debug('_fbo: %s\n%s', term, self.attrs[term]) x = self.eval(term.x) y = self.eval(term.y) z = op(x,y) conds = [] if 'nnan' in self.attrs[term]: df = z3.And(z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(z))) conds.append(z3.Implies(self.attrs[term]['nnan'], df)) elif 'nnan' in term.flags: conds += [z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(z))] if 'ninf' in self.attrs[term]: df = z3.And(z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(z))) conds.append(z3.Implies(self.attrs[term]['ninf'], df)) elif 'ninf' in term.flags: conds += [z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(z))] if 'nsz' in self.attrs[term] or 'nsz' in term.flags: # NOTE: this will return a different qvar for each (in)direct reference # to this term. Is this desirable? b = self.fresh_bool() self.add_qvar(b) z = op(x,y) c = z3.fpIsZero(z) if 'nsz' in self.attrs[term]: c = z3.And(self.attrs[term]['nsz'], c) s = _ty_sort(self.type(term)) z = z3.If(c, z3.If(b, 0, z3.fpMinusZero(s)), z) if isinstance(term, FDivInst): c = [z3.Not(z3.fpIsZero(x)), z3.fpIsZero(y)] if 'nsz' in self.attrs[term]: c.append(self.attrs[term]['nsz']) z = z3.If(z3.And(c), z3.If(b, z3.fpPlusInfinity(s), z3.fpMinusInfinity(s)), z) return self._conditional_value(conds, z, term.name)
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), ]: s.add(z3.Not(z3.fpIsSubnormal(x))) s.add(z3.Not(z3.fpIsZero(x))) s.add(z3.Not(z3.fpIsInf(x))) if s.check() == z3.sat: m = s.model() print("Counterexample found!") print(m) print("a*c: ", z3.simplify(m[a] * m[c])) print("b*c: ", z3.simplify(m[b] * m[c])) print("a+b: ", z3.simplify(m[a] + m[b])) print("a*c + b*c: ", z3.simplify(m[a] * m[c] + m[b] * m[c])) print("(a+b) * c: ", z3.simplify((m[a] + m[b]) * m[c])) else: print("Proved!")