Support reasoning over most the SMT-LIB FPA theory symbols - #1364
Support reasoning over most the SMT-LIB FPA theory symbols#1364hra687261 wants to merge 32 commits into
Conversation
f64ec20 to
0b6592b
Compare
…when the `smt_lib_fpa` option is set to true
…ns with symbolic precision and rounding mode arguments
…ways be literals in the theory, remove support for symbolic arguments for ae.round + float*
| | NaN -> Fmt.pf ppf "NaN" | ||
| | Finite { neg; biased_exp; significand } -> | ||
| Fmt.pf ppf "fp[%b;%d;%s]" neg biased_exp (Z.to_string significand) | ||
| | Finite q -> Fmt.pf ppf "fp[%s]" (Q.to_string q) |
There was a problem hiding this comment.
We display the size of the biased and significand in the smtlib printer but loss it in the debug printer.
There was a problem hiding this comment.
Yes, because the smt-lib printer is expected (I suppose) to produce something that is (at least close) to something parseable in the smt-lib format, while this one is for debugging only.
On the other hand, I am not sure if for debugging it is better to print a Q.t or the mantissa/significand bit-vectors, intuitively, since we represent finite Floats as Q.t, I'd say its this one but I am not sure, in practice I've seen that it quickly becomes unreadable anyway.
There was a problem hiding this comment.
Ideally for debug we would print as a float, i.e. a real with a dot (decimal would be nice but hexadecimal is easy to do I believe)!
There was a problem hiding this comment.
We could simply convert to float then print with "%.17g", but we would lose precision on float > 64, so maybe the hex format is best.
The current version should be good.
| watched_args = add_by_arg r_mode term t.watched_args | ||
| } | ||
|
|
||
| let subst ~ex:_ rr nrr t = |
There was a problem hiding this comment.
You don't need to track the explanation as these domains cannot generate conflicts?
There was a problem hiding this comment.
Indeed, this one simply tracks arguments and substitutes them when they becomes literals, then propagates equalities, but it might actually still be necessary to pass the explanation down to the deduced equalities, I will do that. (Not exactly sure, the explanation is probably attached to the semantic values already no?)
Now, that I think of it, since Sy.Op Float now supports symbolic arguments for the rounding mode, its not clear that this domain is still necessary.
| @@ -0,0 +1,1845 @@ | |||
| (set-logic ALL) | |||
There was a problem hiding this comment.
Should we be concerned about the license of this file? It is essentially a one-one translation of the Why3 theory.
There was a problem hiding this comment.
Not sure, though the transformation is pretty significant, I wouldn't call it a "one-one translation". It's also not clear how the license applies, since the original axiomatization was technically generated by Why3 and not part of its source code.
There was a problem hiding this comment.
Alt-Ergo is distributed under a unfree license but Why3 is a free software under the terms of LGPL 2.1 https://gitlab.inria.fr/why3/why3/-/blob/master/LICENSE?ref_type=heads
This file is a kind of derivative work of the original file in Why3.
There was a problem hiding this comment.
This file is a kind of derivative work of the original file in Why3.
That is unclear, since:
the original axiomatization was technically generated by Why3 and not part of its source code.
(Though it is generated from a whyml module which is part of the Why3 source code ...)
Anyway, what do you suggest?
bclement-ocp
left a comment
There was a problem hiding this comment.
Thanks :) Did a first pass with some comments, but did not look at the prelude and some calculations in detail yet.
| @@ Dolmen_type.Base.app0 | ||
| (module Dl.Typer.T) | ||
| env s DE.Ty.roundingMode) | ||
| |> add_constrs ) |
There was a problem hiding this comment.
We should remove the rounding mode type from fpa_rounding.ml if we don't use it anymore (and if we do, replace it with DE.Ty.roundingMode).
There was a problem hiding this comment.
Done. But unfortunately, rounding modes in Dolmen are put in the same ADT as other FP symbols, so it makes matching on rounding modes awkward (we always have to skip the cases of the non-rounding mode symbols).
I will open a PR on Dolmen to put rounding modes in their own enum type (with the hope that it will be accepted and be part of the next Dolmen release).
| | Id { ns = Term; name = Simple "ae.float" } -> | ||
| Dl.Typer.T.builtin_term | ||
| @@ Dolmen_type.Base.term_app_cst (module Dl.Typer.T) env ae_float_cst |
There was a problem hiding this comment.
Ah, it is unfortunate that we need to expose both ae.round (with _ constant args) and ae.float :(
There was a problem hiding this comment.
Indeed, IIRC indexed operators expect literals as indices not symbolic values, so we have to. But maybe in the future we can deprecate ae.round for ae.float, or rename ae.float to ae.round and make the precisions arguments normal arguments instead of indices (because its a better name, the operator in alt-ergo should probably renamed to something like FloatRound instead of just Float)
| | `App (`Builtin (B.Float B.Float.RoundingMode), []) -> | ||
| Fpa_rounding.fpa_rounding_mode |
There was a problem hiding this comment.
I think this should go above, along with the other App cases (likely just after B.Unit).
| when Compat.List.is_empty tyl && String.equal name E.FP.Names.t -> | ||
| (* To get the generic abstract float type from the axiomatization which is | ||
| stored as type varialbe `ae.fp.t`. *) | ||
| tv |
There was a problem hiding this comment.
I'm not sure I understand this. Why don't we define ae.fp.t directly here (like we do e.g. for rounding mode) and make it available to the axiomatization?
| | B.Float RoundNearestTiesToEven -> mk_rounding NearestTiesToEven | ||
| | B.Float RoundNearestTiesToAway -> mk_rounding NearestTiesToAway | ||
| | B.Float RoundTowardPositive -> mk_rounding Up | ||
| | B.Float RoundTowardNegative -> mk_rounding Down | ||
| | B.Float RoundTowardZero -> mk_rounding ToZero |
There was a problem hiding this comment.
Please keep these within the global match on B.Float below (moving guards on when get_smt_lib_fpa to the constants).
| val ieee_format_to_fp : t -> int -> int -> t | ||
|
|
||
| (* arithmetic with rounding mode *) | ||
| val add : e:int -> s:int -> mode:t -> t -> t -> t |
There was a problem hiding this comment.
The e and s labelled arguments should maybe be explained somewhere? Is there a reason they are called e and s rather than eb and sb following the SMT-LIB?
There was a problem hiding this comment.
This just follows what the Dolmen constructors used, e and s probably as short for eb and sb.
I changed them.
| | NaN -> Fmt.pf ppf "NaN" | ||
| | Finite { neg; biased_exp; significand } -> | ||
| Fmt.pf ppf "fp[%b;%d;%s]" neg biased_exp (Z.to_string significand) | ||
| | Finite q -> Fmt.pf ppf "fp[%s]" (Q.to_string q) |
There was a problem hiding this comment.
Ideally for debug we would print as a float, i.e. a real with a dot (decimal would be nice but hexadecimal is easy to do I believe)!
| (* hidden_bit = 2^(sb-1), m >= hidden_bit -> normal *) | ||
| let hidden_bit = Z.shift_left Z.one (sb - 1) in | ||
| let biased_exp, significand = | ||
| if Z.compare m hidden_bit >= 0 |
There was a problem hiding this comment.
I think we can simply check Z.testbit m (sb - 1)?
…fpa's hash function
This PR adds a prelude which axiomatizes the semantics of most of the SMT-LIB FPA theory symbols, and maps the symbols of the theory parsed by dolmen to these axiomatizations, providing support for symbolic reasoning over most of them (except fp.rem, fp.to_fp, fp.of_sbv, fp.of_ubv, fp.to_ubv and fp.to_sbv the support for which will be added in the future in a separate PR).
The PR also propagates for each of the FPA literals for which support was added in #1358 predicates and assertions which allow linking these literals to the axiomatization. It also adds propagation of equalities with literals from asserted predicates, as well as a shostak theory to solve equalities between fp literals among themselves or fp literals and fp variables.