Open epatrizio opened 7 months ago
Small reproduction case:
(module
(import "symbolic" "f32_symbol" (func $f32_symbol (result f32)))
(func $start
(f32.eq (f32.sqrt (call $f32_symbol)) (f32.const 0))
(if (then unreachable))
)
(start $start)
)
Actually, this is hanging because encoding is raising Encoding.Solver.Unknown
and we do not properly handle this in Symbolic_choice
.
So two questions:
sqrt
? After a quick search online, I believe we would have to use the non-linear solver or something like this ?Symbolic_choice
? This is hopefully similar to ed033dfb7d665b941b19be3345834543a8c01231.Also, on a related note, @filipeom, do you think we should change the type of Encoding.Solver.check
(to a bool option
for instance) to avoid using exceptions ?
* @filipeom, is it expected that Z3 can not handle `sqrt` ? After a quick search online, I believe we would have to use the non-linear solver or something like this ?
Z3 should be able to handle the sqrt
(but really slooowly, see https://github.com/formalsec/encoding/commit/92ae62526cfb1fc9bb7b872622271fad61493971)
Also, on a related note, @filipeom, do you think we should change the type of
Encoding.Solver.check
(to abool option
for instance) to avoid using exceptions ?
Yes, I agree this should be done :smiley: Either an option or a ADT like type satisfiabilty to be more expressive
Edit: I ran the example to reproduce and it gave-me this:
$ time owi sym test.wast
Trap: unreachable
Model:
(model
(symbol_0 (f32 -0.)))
Reached problem!
owi sym test.wast 17.68s user 0.10s system 99% cpu 17.809 total
Also, using assert
:
(call $assert
(f32.ne
(f32.sqrt (local.get $f))
(f32.const 0.0)))
Instead of:
(f32.eq (f32.sqrt (call $f32_symbol)) (f32.const 0))
(if (then unreachable))
Dropped execution time to ~10s. While, adding an assume, made it instantaneous. But not very interesting:
(module
(import "symbolic" "f32_symbol" (func $f32_symbol (result f32)))
(import "symbolic" "assume" (func $assume (param i32)))
(import "symbolic" "assert" (func $assert (param i32)))
(func $start
(local $f f32)
(local.set $f (call $f32_symbol))
(call $assume
(f32.eq
(local.get $f)
(f32.const 4.0)))
(call $assert
(f32.ne
(f32.sqrt (local.get $f))
(f32.const 2.0)))
)
(start $start)
)
I cannot reproduce this either, neither on main nor on #170
I can reproduce on main...
Not that it is looping indefinitely, but that it is very slow and we should try to fix it.
I asked @silene (thanks again! :)) and this is because float arithmetic is implemented through bit-blasting. It is very slow because it requires generating a huge amount of variables. You can confirm this by:
For some reason, it seems that using other numbers (e.g. 12 instead of 0, is a little bit faster).
If we still want to check this in our tests (and I'd like to), we should find numbers for which it is fast (and maybe combine this with the assert
+ f32.ne
that @filipeom mentionned, if it makes things faster for some reason).
For information, in the PR #194 mentioned above, float operations div
and mul
have been deactivated (they are very time-consuming - ~ 25 sec !)
It's the same for float copysign
, but it's less important.
f32.sqrt
andf64.sqrt
instructions do not end. So, in symbolic tests, these instructions have been commented out.https://github.com/OCamlPro/owi/blob/2ef083c191e8fa1da71ceb6b46f5d2dc19334841/test/sym/unop_f32.wat#L37
https://github.com/OCamlPro/owi/blob/2ef083c191e8fa1da71ceb6b46f5d2dc19334841/test/sym/unop_f64.wat#L37