Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
00b5eca
Add axiomatization of the SMT-LIB FPA theory
hra687261 Jun 22, 2026
fcd9014
Map Dolmen terms to the symbols of the SMT-LIB FPA theory axiomatization
hra687261 Jun 23, 2026
fd96706
Propagate axiomatized predicates for FPA literals
hra687261 Jun 24, 2026
b23f211
Propagate deduced equalities from asserted predicates in FPA relation
hra687261 Jun 30, 2026
56b38f9
Add FPA shostak theory to solve equalities with literals
hra687261 Jun 30, 2026
746852e
Ensure that the FPA shostak theory solver and relation are only used …
hra687261 Jun 30, 2026
a9f8625
Test symbolic reasoning on smt-lib fpa theory
hra687261 Jun 24, 2026
76b1ca7
upd CHANGES.md
hra687261 Jun 24, 2026
3981814
Use a domain to store and represent FPA predicates, and make deductio…
hra687261 Jul 7, 2026
ddfb824
Add debug messages to FPA relation and shostak theory
hra687261 Jul 7, 2026
f8da815
Cleanup axiomatization by using builtin int.pow2
hra687261 Jul 7, 2026
65b553e
Use builtin ae.float symbol, and add domain to support its applicatio…
hra687261 Jul 7, 2026
a96023a
Add patterns to all axioms
hra687261 Jul 7, 2026
d1b5a07
Only track ae.float's mode argument, not eb and sb since they will al…
hra687261 Jul 8, 2026
96d825f
Add FPA timer
hra687261 Jul 8, 2026
6a9f68e
Cleanup and avoid duplicate calls to `E.Ints.of_int` in `fpa_rel`
hra687261 Jul 8, 2026
f5f8854
Track new_terms in fpa_rel
hra687261 Jul 8, 2026
6c5cf9e
Simplify `deduce_fpval_eq`
hra687261 Jul 8, 2026
625d054
Pass `ex` as an argument to `apply`
hra687261 Jul 8, 2026
ed93826
Add comment explaining how SMT-LIB FPA axiomatization was produced.
hra687261 Jul 8, 2026
d842bbc
Take explanations into account in AEFloat_arg_watch
hra687261 Jul 8, 2026
b1b7597
use sqrt_real
hra687261 Jul 8, 2026
f197078
Upd doc comments, improve debug printing of finite FPA literals, and …
hra687261 Jul 10, 2026
dbfd377
Better matching order in translate.ml
hra687261 Jul 10, 2026
88fefa3
Replace Fpa_rounding.rounding_mode with Dolmen's rounding mode constr…
hra687261 Jul 10, 2026
2fc901b
Add symbolic reasoning tests
hra687261 Jul 10, 2026
9ae85fa
Add Fp_value.equal
hra687261 Jul 10, 2026
5d3b9de
Better error msg in fpa.ml
hra687261 Jul 10, 2026
2ecc45a
Put type parameters in literals in the shostak FPA theory
hra687261 Jul 10, 2026
e1474a5
Inline const_view
hra687261 Jul 10, 2026
fba01a1
Treat unsupported FPA functions as uninterpreted symbols
hra687261 Jul 10, 2026
98de1b6
Use `eb` and `sb` instead of `e` and `s` in `Expr.FP`
hra687261 Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## unreleased

- Support parsing and reasoning over most SMT-LIB FPA Theory symbols (except
fp.rem, fp.to_fp, and bv/fp conversion operations), usable with
`--enable-theory smt.float`. Add a prelude axiomatizing the semantics of the
FPA Theory symbols, adapted from Why3's generated axiomatization. (#1364)
- Support the `int.pow2` function, which takes an integer `n` and computes
`ae.pow_int 2 n` (#1365)
- Support parsing of SMT-LIB FPA Theory literals and add the theory `smt.float`
Expand Down
2 changes: 1 addition & 1 deletion src/lib/dune
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
; reasoners
Ac Arith Arrays_rel Bitv Ccx Shostak Relation
Fun_sat Fun_sat_frontend Inequalities Bitv_rel Th_util Adt Adt_rel
Instances IntervalCalculus Intervals_intf Intervals_core Intervals
Fpa Fpa_rel Instances IntervalCalculus Intervals_intf Intervals_core Intervals
Ite_rel Matching Matching_types Polynome
Satml_frontend Satml Sat_solver Sat_solver_sig
Sig Sig_rel Theory Uf Use Domains Domains_intf Rel_utils Bitlist
Expand Down
194 changes: 149 additions & 45 deletions src/lib/frontend/translate.ml
Original file line number Diff line number Diff line change
Expand Up @@ -155,33 +155,39 @@ let builtin_term t = Dl.Typer.T.builtin_term t

let builtin_ty t = Dl.Typer.T.builtin_ty t

let ty (ty_cst : DE.ty_cst) ty =
let name = get_basename ty_cst.path in
DStd.Id.Map.add { name = DStd.Name.simple name; ns = Sort } @@ fun env s ->
builtin_ty @@ Dolmen_type.Base.app0 (module Dl.Typer.T) env s ty

let fpa_rounding_mode, rounding_modes, add_rounding_modes =
match DT.view Fpa_rounding.fpa_rounding_mode_dty with
| `App (`Generic ty_cst, []) ->
let constrs = Fpa_rounding.d_constrs in
let add_constrs map =
List.fold_left
(fun map (c : DE.term_cst) ->
let name = get_basename c.path in
DStd.Id.Map.add
{ name = DStd.Name.simple name; ns = Term }
(fun env _ ->
builtin_term
@@ Dolmen_type.Base.term_app_cst (module Dl.Typer.T) env c)
map)
map constrs
in
Cache.store_ty ty_cst Fpa_rounding.fpa_rounding_mode;
( Fpa_rounding.fpa_rounding_mode_dty,
constrs,
fun map ->
map |> ty ty_cst Fpa_rounding.fpa_rounding_mode_dty |> add_constrs )
| _ -> assert false
let smt_constrs =
DE.Term.Const.Float.
[ "RNE", roundNearestTiesToEven;
"RNA", roundNearestTiesToAway;
"RTP", roundTowardPositive;
"RTN", roundTowardNegative;
"RTZ", roundTowardZero ]
in
let constrs = List.map snd smt_constrs in
let add_constrs map =
List.fold_left
(fun map (name, c) ->
DStd.Id.Map.add
{ name = DStd.Name.simple name; ns = Term }
(fun env _ ->
builtin_term
@@ Dolmen_type.Base.term_app_cst (module Dl.Typer.T) env c)
map)
map smt_constrs
in
( DE.Ty.roundingMode,
constrs,
fun map ->
map
|> DStd.Id.Map.add
{ name = DStd.Name.simple "RoundingMode"; ns = Sort }
(fun env s ->
builtin_ty
@@ Dolmen_type.Base.app0
(module Dl.Typer.T)
env s DE.Ty.roundingMode)
|> add_constrs )

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).


module Const = struct
open DE
Expand Down Expand Up @@ -343,6 +349,11 @@ let smt_fpa_builtins =
let ty = DT.arrow [DT.int] DT.int in
DE.Id.mk ~name:"int.pow2" ~builtin:Int_pow2 (DStd.Path.global "int.pow2") ty
in
let ae_float_cst =
let name = E.FP.Names.ae_float in
let ty = DT.(arrow [int; int; fpa_rounding_mode; real] real) in
DE.Id.mk ~name ~builtin:Float (DStd.Path.global name) ty
in
let other_builtins = DStd.Id.Map.empty |> add_rounding_modes in
fun env s ->
match s with
Expand All @@ -369,6 +380,9 @@ let smt_fpa_builtins =
| Id { ns = Term; name = Simple "int.pow2" } ->
Dl.Typer.T.builtin_term
@@ Dolmen_type.Base.term_app_cst (module Dl.Typer.T) env int_pow2_cst
| 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
Comment on lines +388 to +390

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it is unfortunate that we need to expose both ae.round (with _ constant args) and ae.float :(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

| Dl.Typer.T.Id id -> begin
match DStd.Id.Map.find_exn id other_builtins env s with
| e -> e
Expand Down Expand Up @@ -447,6 +461,8 @@ let rec dty_to_ty ?(update = false) ?(is_var = false) dty =
| `Pi (tyvl, ty) ->
if update then Cache.store_tyvl ~is_var tyvl;
aux ty
| `App (`Builtin (B.Float B.Float.RoundingMode), []) ->
Fpa_rounding.fpa_rounding_mode

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should go above, along with the other App cases (likely just after B.Unit).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

| _ -> unsupported "Type %a" DE.Ty.print dty

and handle_ty_app ?(update = false) ty_c l =
Expand All @@ -456,6 +472,11 @@ and handle_ty_app ?(update = false) ty_c l =
match Cache.find_ty ty_c with
| Tadt (hs, _) -> Tadt (hs, tyl)
| Text (_, s) -> Text (tyl, s)
| Tvar { path = Absolute { name; _ } | Local { name; _ }; _ } as tv
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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

| _ -> assert false

(** Handles a simple type declaration. *)
Expand All @@ -482,13 +503,17 @@ let mk_ty_decl (ty_c : DE.ty_cst) =
in
let ty = Ty.t_adt ~body:(Some cs) ty_c tyvl in
Cache.store_ty ty_c ty
| None | Some Abstract ->
let ty_params =
[]
(* List.init ty_c.id_ty.arity (fun _ -> Ty.fresh_tvar ()) *)
in
let ty = Ty.text ty_params ty_c in
Cache.store_ty ty_c ty
| None | Some Abstract -> (
match ty_c with
| { path = Absolute { name; _ }; _ }
when Options.get_smt_lib_fpa () && String.equal name E.FP.Names.t ->
(* Storing the generic abstract float type from the axiomatization as a
type variable `ae.fp.t`, so that axioms defined for it can apply for
specific instances of the Float(es,sb) type. *)
Cache.store_ty ty_c (Ty.named_tvar E.FP.Names.t)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this either. My understanding was that for now we would map all the Float(eb, sb) types to ae.fp.t (with an assertion saying that the value is a valid float for these eb and sb), but it seems you are keeping the type around?

I think if we want to make ae.fp.t a variable (that in practice ranges over the fpa types) we should do that explicitly using par instead of this hack.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is indeed to make ae.fp.t a variable, so that axioms we write over it would match over any type Float (eb, sb) (we want to keep the types Float (eb,sb) as is because its more convenient/practical, tho I suppose we could cheat by having the type parameters embedded into ae.fp.t but still somehow have a generic one that matches over all of them (?) not sure how that would work).
But yes, the proper solution would be to use par in the axiomatization.

| _ ->
let ty = Ty.text [] ty_c in
Cache.store_ty ty_c ty)

(** Handles term declaration by storing the eventual present type variables in
the cache as well as the symbol associated to the term. *)
Expand Down Expand Up @@ -779,6 +804,11 @@ let rec mk_expr ?(loc = Loc.dummy) ?(name_base = "") ?(toplevel = false)
| B.Adt (Constructor _) ->
let ty = dty_to_ty term_ty in
E.mk_constr tcst [] ty
| 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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep these within the global match on B.Float below (moving guards on when get_smt_lib_fpa to the constants).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

| B.Float cst when Options.get_smt_lib_fpa () -> begin
match cst with
| Plus_infinity { e; s } -> E.float Fp_value.Plus_infinity e s
Expand Down Expand Up @@ -1159,22 +1189,96 @@ let rec mk_expr ?(loc = Loc.dummy) ?(name_base = "") ?(toplevel = false)
(* Floating-point builtins *)
| B.Float builtin, args -> (
match builtin, args with
| RoundNearestTiesToEven, _ -> mk_rounding NearestTiesToEven
| RoundNearestTiesToAway, _ -> mk_rounding NearestTiesToAway
| RoundTowardPositive, _ -> mk_rounding Up
| RoundTowardNegative, _ -> mk_rounding Down
| RoundTowardZero, _ -> mk_rounding ToZero
| Fp { e; s }, [sign_t; exp_t; sig_t] when Options.get_smt_lib_fpa ()
->
E.FP.fp (mk sign_t) (mk exp_t) (mk sig_t) e s
| Ieee_format_to_fp { e; s }, [bv_t] when Options.get_smt_lib_fpa ()
->
E.FP.ieee_format_to_fp (mk bv_t) e s
(* SMT-LIB FPA theory operations *)
| _ when Options.get_smt_lib_fpa () -> begin
match builtin, args with
| Fp { e; s }, [sign_t; exp_t; sig_t] ->
E.FP.fp (mk sign_t) (mk exp_t) (mk sig_t) e s
| Ieee_format_to_fp { e; s }, [bv_t] ->
E.FP.ieee_format_to_fp (mk bv_t) e s
(* arithmetic with rounding mode *)
| Add { e; s }, [mode; x; y] ->
E.FP.add ~e ~s ~mode:(mk mode) (mk x) (mk y)
| Sub { e; s }, [mode; x; y] ->
E.FP.sub ~e ~s ~mode:(mk mode) (mk x) (mk y)
| Mul { e; s }, [mode; x; y] ->
E.FP.mul ~e ~s ~mode:(mk mode) (mk x) (mk y)
| Div { e; s }, [mode; x; y] ->
E.FP.div ~e ~s ~mode:(mk mode) (mk x) (mk y)
| Fma { e; s }, [mode; x; y; z] ->
E.FP.fma ~e ~s ~mode:(mk mode) (mk x) (mk y) (mk z)
| Sqrt { e; s }, [mode; x] -> E.FP.sqrt ~e ~s ~mode:(mk mode) (mk x)
| RoundToIntegral { e; s }, [mode; x] ->
E.FP.round_to_integral ~e ~s ~mode:(mk mode) (mk x)
| Of_real { e; s }, [mode; x] ->
E.FP.of_real ~e ~s ~mode:(mk mode) (mk x)
(* arithmetic without rounding mode *)
| Abs { e; s }, [x] -> E.FP.abs ~e ~s (mk x)
| Neg { e; s }, [x] -> E.FP.neg ~e ~s (mk x)
| Rem { e = _; s = _ }, [_x; _y] ->
(* TODO: rem is not currently in the axiomatization, its semantics
need to be either axiomatized or implemented in Alt-Ergo. *)
unsupported_app_term ()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should become an uninterpreted function in that case, not raise an error!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
But IMO, if we don't support any reasoning over something, it would be better to have a failure than have surprising behavior.
From a user's pov, it would be confusing if the solver is unable to solve simple queries, or its able to solve a query but not a similar with maybe a couple of additional symbols, if the user's mind does not go to AE's support for those specific symbols, they might end up wasting a lot of time looking for the solution elsewhere. But, support for them is meant to be added before the next is release anyway, so it should not be an issue.

| Min { e; s }, [x; y] -> E.FP.min ~e ~s (mk x) (mk y)
| Max { e; s }, [x; y] -> E.FP.max ~e ~s (mk x) (mk y)
(* comparisons *)
| Leq { e; s }, [x; y] -> E.FP.le ~e ~s (mk x) (mk y)
| Lt { e; s }, [x; y] -> E.FP.lt ~e ~s (mk x) (mk y)
| Geq { e; s }, [x; y] -> E.FP.ge ~e ~s (mk x) (mk y)
| Gt { e; s }, [x; y] -> E.FP.gt ~e ~s (mk x) (mk y)
| Eq { e; s }, [x; y] -> E.FP.eq ~e ~s (mk x) (mk y)
(* predicates *)
| IsNormal { e; s }, [x] -> E.FP.is_normal ~e ~s (mk x)
| IsSubnormal { e; s }, [x] -> E.FP.is_subnormal ~e ~s (mk x)
| IsZero { e; s }, [x] -> E.FP.is_zero ~e ~s (mk x)
| IsInfinite { e; s }, [x] -> E.FP.is_infinite ~e ~s (mk x)
| IsNaN { e; s }, [x] -> E.FP.is_nan ~e ~s (mk x)
| IsNegative { e; s }, [x] -> E.FP.is_negative ~e ~s (mk x)
| IsPositive { e; s }, [x] -> E.FP.is_positive ~e ~s (mk x)
(* real conversion *)
| To_real { e; s }, [x] -> E.FP.to_real ~e ~s (mk x)
(* TODO: FP <-> FP and BV <-> FP conversion *)
| To_fp { e1 = _; s1 = _; e2 = _; s2 = _ }, [_; _]
| ( ( Of_sbv { m = _; e = _; s = _ }
| Of_ubv { m = _; e = _; s = _ }
| To_ubv { m = _; e = _; s = _ }
| To_sbv { m = _; e = _; s = _ } ),
[_] ) ->
unsupported_app_term ()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should become uninterpreted as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

(* can't be applied *)
| (RoundingMode | T _ | Fp _), _
| ( ( Plus_infinity _ | Minus_infinity _ | Plus_zero _
| Minus_zero _ | NaN _ ),
_ )
| RoundNearestTiesToEven, _
| RoundNearestTiesToAway, _
| RoundTowardPositive, _
| RoundTowardNegative, _
| RoundTowardZero, _
(* wrong arity *)
| ( ( Ieee_format_to_fp _ | To_fp _ | Of_sbv _ | Of_ubv _ | To_ubv _
| To_sbv _ | Add _ | Sub _ | Mul _ | Div _ | Fma _ | Sqrt _
| RoundToIntegral _ | Of_real _ | Abs _ | Neg _ | Rem _ | Min _
| Max _ | Leq _ | Lt _ | Geq _ | Gt _ | Eq _ | IsNormal _
| IsSubnormal _ | IsZero _ | IsInfinite _ | IsNaN _
| IsNegative _ | IsPositive _ | To_real _ ),
_ ) ->
invalid_app_term ()
end
(* can't be applied *)
| (RoundingMode | T _ | Fp _), _
| ( ( Plus_infinity _ | Minus_infinity _ | Plus_zero _ | Minus_zero _
| NaN _ ),
_ ) ->
_ )
(* roudning modes are now matched as literals since we use the SMT-LIB
Comment thread
hra687261 marked this conversation as resolved.
Outdated
FP theory ones provided by dolmen *)
| RoundNearestTiesToEven, _
| RoundNearestTiesToAway, _
| RoundTowardPositive, _
| RoundTowardNegative, _
| RoundTowardZero, _ ->
invalid_app_term ()
(* not supported without [Options.get_smt_lib_fpa ()] *)
| ( ( Abs _ | Neg _ | Add _ | Sub _ | Mul _ | Div _ | Fma _ | Sqrt _
| Rem _ | RoundToIntegral _ | Min _ | Max _ | Leq _ | Lt _ | Geq _
| Gt _ | Eq _ | IsNormal _ | IsSubnormal _ | IsZero _
Expand Down
35 changes: 26 additions & 9 deletions src/lib/reasoners/arith.ml
Original file line number Diff line number Diff line change
Expand Up @@ -289,18 +289,35 @@ struct
in
P.add p (P.mult_const coef p3), ctx
(*** <begin>: partial handling of some arith/FPA operators **)
| Sy.Op Float, [prec; exp; mode; x] ->
| Sy.Op Float, [prec; exp; mode; x] -> (
let prec = E.int_view prec and exp = E.int_view exp in
let mode = E.rounding_mode_view mode in
let aux_func e =
let res, _, _ = Fpa_rounding.float_of_rational prec exp mode e in
res
in
mk_partial_interpretation_1 aux_func coef p ty t x, ctx
match E.rounding_mode_view mode with
| Some mode ->
let aux_func e =
let res, _, _ = Fpa_rounding.float_of_rational prec exp mode e in
res
in
mk_partial_interpretation_1 aux_func coef p ty t x, ctx
| None when Options.get_smt_lib_fpa () ->
(* If the rounding mode is not a literal and [Options.get_smt_lib_fpa
()] is true, treat it as an uninterpreted function and wait for
fpa_rel to update it when the rounding mode is substituted with a
literal. *)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can do this unconditionally

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

P.add (P.create [coef, X.term_embed t] Q.zero ty) p, ctx
| None ->
Fmt.failwith
"ae.float: The given term %a is not a constant rounding mode" E.print
mode)
| Sy.Op Sy.Integer_round, [mode; x] ->
let aux_func =
Fpa_rounding.round_to_integer (E.rounding_mode_view mode)
let mode =
match E.rounding_mode_view mode with
| Some mode -> mode
| None ->
Fmt.failwith
"integer_round: The given term %a is not a constant rounding mode"
E.print mode
in
let aux_func = Fpa_rounding.round_to_integer mode in
mk_partial_interpretation_1 aux_func coef p ty t x, ctx
| Sy.Op (Sy.Abs_int | Sy.Abs_real), [x] ->
mk_partial_interpretation_1 Q.abs coef p ty t x, ctx
Expand Down
Loading
Loading