Z3Prover / z3

The Z3 Theorem Prover
Other
10.36k stars 1.48k forks source link

possible bug in model for fp.fma #872

Closed florianschanda closed 7 years ago

florianschanda commented 7 years ago

Hey,

I am not sure if the attached testcase should be ultimately SAT or UNSAT. However, I am reasonably sure that the model is bogus.

(set-logic QF_FP)
(set-option :produce-models true)
(set-info :source |Florian Schanda|)
(set-info :smt-lib-version 2.5)
(set-info :category crafted)

(declare-const x Float32)
(declare-const y Float32)
(declare-const z Float32)

(define-const x2 Float64 ((_ to_fp 11 53) RNE x))
(define-const y2 Float64 ((_ to_fp 11 53) RNE y))
(define-const z2 Float64 ((_ to_fp 11 53) RNE z))

(define-const r Float32 (fp.fma RNE x y z))
(define-const r2 Float32
  ((_ to_fp 8 24) RNE (fp.add RNE (fp.mul RNE x2 y2) z2)))

(assert (not (= r r2)))
(check-sat)

(get-value (x y z))
(get-value (x2 y2 z2))
(get-value (r r2))
(get-value ((= r r2)))

(exit)

If I run this with the current master branch I get:

sat
((x (fp #b0 #x80 #b10111011101101010010011))
 (y (fp #b1 #xfe #b00000000010100101111000))
 (z (fp #b0 #xfe #b11111000100010011100101)))
((x2 (fp #b0 #b10000000000 #xbbb5260000000))
 (y2 (fp #b1 #b10001111110 #x0052f00000000))
 (z2 (fp #b0 #b10001111110 #xf889ca0000000)))
((r  (fp #b1 #xfe #b10000000000000000000001))
 (r2 (fp #b1 #xfe #b10000000000000000000001)))
(((= r r2) true))

In particular r and r2 seem quite equal in this model, but that is not what I asserted. (And yes, I did intend to use '=' and not 'fp.eq'.)

ikirill commented 7 years ago

I don't have any more counterexamples now. I find Z3 invaluable for rigorously checking the finer points of floating-point arithmetic, and especially for generating counterexamples. For example, in the chapter in The Art of Computer Programming about fp, about half the exercises are trivially solvable by running Z3 on them with no manual work required. So thanks!

wintersteiger commented 7 years ago

Thanks for catching the typo! I haven't found any new soundness issues either, but I noticed that it now takes a lot longer to solve some of the examples given here.

Thanks for the information on TAOCP, that's great to hear! Since you already have (some of) them encoded, would you mind submitting them to SMT-LIB? They would definitely make good test cases!

florianschanda commented 7 years ago

Hello again :)

I've re-run my benchmarks with Z3 (e677030b7469933a14c02376a7935a307a919482) and I think there are still some issues. Consider the below benchmark, I think fma(rne, +0, +0, -0) should indeed be +0, and not -0. I've checked this with my python float implementation, MPFR, and Intel hardware; so I am reasonably confident.

EDIT: I see there are more commits, I'll re-compile and try again :)

(set-info :smt-lib-version 2.6)
(set-logic QF_FP)
(set-option :produce-models true)
(set-info :source |Random FP created by PyMPF|)
(set-info :license |https://www.gnu.org/licenses/gpl-3.0.html|)
(set-info :category random)
(set-info :status sat)
(declare-const x Float32)
(assert (= x ((_ to_fp 8 24) #x00000000)))
;; x should be Float32(+zero)

(declare-const y Float32)
(assert (= y ((_ to_fp 8 24) #x00000000)))
;; y should be Float32(+zero)

(declare-const z Float32)
(assert (= z (_ -zero 8 24)))
;; z should be Float32(-zero)

(declare-const result Float32)
(assert (= result (fp.fma RNE x y z)))
(assert (= result (fp #b0 #b00000000 #b00000000000000000000000)))
(check-sat)
(exit)
wintersteiger commented 7 years ago

Yes, that's a bit of a corner case. I think I remember that not all Intel CPUs agree with AMD's on this one, so I'll probably end up passing that on to the SMT FP semantics people.

florianschanda commented 7 years ago

Yep, so that still happens.

I believe my interpretation in PyMPF (which happens to co-incide with intel and MPFR) matches the both IEEE semantics and the SMT FP semantics.

IEEE says: "When (a × b) + c is exactly zero, the sign of fusedMultiplyAdd(a, b, c) shall be determined by the rules above for a sum of operands.". The "rules above" then state: "When the sum of two operands with opposite signs is exactly zero, the sign of that sum shall be +0 in all rounding-direction attributes except roundTowardNegative."

The SMT FP semantics document /should/ say that, if it doesn't then its a bug :)

wintersteiger commented 7 years ago

Yeah, looks like I had decided on that too, just forgot to propagate that to the MPFs (or maybe it was simply a typo). Should behave as expected now.

florianschanda commented 7 years ago

It does indeed. I now do not have any more general FMA bugs I can report. I'll open separate tickets with RNA issues :)

Thank you Christoph!