Skip to content

Commit 1117779

Browse files
committed
smt: add [smt_inline] operator tag to δ/β-reduce at use sites
Higher-order combinators whose body builds a lambda from their own parameters (e.g. `right_loop inv o = forall y, cancel (fun x => o x y) ...`) are translated once, polymorphically, into a why3 predicate. The inner lambdas become polymorphic `unamed_lambda` symbols, forcing why3's polymorphism encoding (the `uni`/`sort`/`t2tb` bridges). Discharging a fully-ground goal like `right_loop idfun (^)` then requires the prover to chain several trigger-less higher-order `@`-apply axioms across that encoding before it can even case-split — which older SMT solvers fail to do within the time limit, even though the goal is trivial. Add a per-operator `[smt_inline]` tag (mirroring `[smt_opaque]`): a fully-applied tagged operator/predicate is δ/β-reduced into the goal before translation, so its lambdas are created at the call's concrete instantiation and stay monomorphic — no `uni`/`t2tb` detour. Unmarked definitions are translated exactly as before. The tag is threaded through the parser, parsetree (`pp_tags`), scope, and `op_opaque.inline`, and consulted by `EcSmt.try_inline`. Tag the eight `*_loop*` combinators in Logic.ec.
1 parent 76bf9e9 commit 1117779

8 files changed

Lines changed: 57 additions & 17 deletions

File tree

src/ecDecl.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ type operator = {
144144
op_unfold : int option;
145145
}
146146

147-
and opopaque = { smt: bool; reduction: bool; }
147+
and opopaque = { smt: bool; reduction: bool; inline: bool; }
148148

149149
(* -------------------------------------------------------------------- *)
150150
type axiom_kind = [`Axiom of (Ssym.t * bool) | `Lemma]
@@ -229,7 +229,7 @@ let mk_pred ?clinline ?unfold ~opaque tparams dom body lc =
229229
gen_op ?clinline ?unfold ~opaque tparams ty kind lc
230230

231231
let optransparent : opopaque =
232-
{ smt = false; reduction = false; }
232+
{ smt = false; reduction = false; inline = false; }
233233

234234
let mk_op ?clinline ?unfold ~opaque tparams ty body lc =
235235
let kind = OB_oper body in

src/ecDecl.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ type operator = {
128128
op_unfold : int option;
129129
}
130130

131-
and opopaque = { smt: bool; reduction: bool; }
131+
and opopaque = { smt: bool; reduction: bool; inline: bool; }
132132

133133
val op_ty : operator -> ty
134134
val is_pred : operator -> bool

src/ecHiPredicates.ml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,14 @@ let trans_preddecl_r (env : EcEnv.env) (pr : ppredicate located) =
8383

8484
let dom = Tuni.subst_dom uidmap dom in
8585

86-
EcDecl.mk_pred ~opaque:optransparent tparams dom body pr.pp_locality
86+
let tags = Ssym.of_list (List.map unloc pr.pp_tags) in
87+
let opaque = {
88+
EcDecl.smt = Ssym.mem "smt_opaque" tags;
89+
EcDecl.reduction = Ssym.mem "opaque" tags;
90+
EcDecl.inline = Ssym.mem "smt_inline" tags;
91+
} in
92+
93+
EcDecl.mk_pred ~opaque tparams dom body pr.pp_locality
8794

8895
(* -------------------------------------------------------------------- *)
8996
let trans_preddecl (env : EcEnv.env) (pr : ppredicate located) =

src/ecParser.mly

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,22 +1867,25 @@ exception_:
18671867
(* -------------------------------------------------------------------- *)
18681868
(* Predicate definitions *)
18691869
predicate:
1870-
| locality=locality PRED x=oident
1870+
| locality=locality PRED tags=bracket(ident*)? x=oident
18711871
{ { pp_name = x;
18721872
pp_tyvars = None;
18731873
pp_def = PPabstr [];
1874+
pp_tags = odfl [] tags;
18741875
pp_locality = locality; } }
18751876

1876-
| locality=locality PRED x=oident tyvars=tyvars_decl? COLON sty=pred_tydom
1877+
| locality=locality PRED tags=bracket(ident*)? x=oident tyvars=tyvars_decl? COLON sty=pred_tydom
18771878
{ { pp_name = x;
18781879
pp_tyvars = tyvars;
18791880
pp_def = PPabstr sty;
1881+
pp_tags = odfl [] tags;
18801882
pp_locality = locality; } }
18811883

1882-
| locality=locality PRED x=oident tyvars=tyvars_decl? p=ptybindings? EQ f=form
1884+
| locality=locality PRED tags=bracket(ident*)? x=oident tyvars=tyvars_decl? p=ptybindings? EQ f=form
18831885
{ { pp_name = x;
18841886
pp_tyvars = tyvars;
18851887
pp_def = PPconcr (odfl [] p, f);
1888+
pp_tags = odfl [] tags;
18861889
pp_locality = locality; } }
18871890

18881891
| locality=locality INDUCTIVE x=oident tyvars=tyvars_decl? p=ptybindings?
@@ -1891,6 +1894,7 @@ predicate:
18911894
{ { pp_name = x;
18921895
pp_tyvars = tyvars;
18931896
pp_def = PPind (odfl [] p, b);
1897+
pp_tags = [];
18941898
pp_locality = locality; } }
18951899

18961900
indpred_def:

src/ecParsetree.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ type ppredicate = {
508508
pp_name : psymbol;
509509
pp_tyvars : psymbol list option;
510510
pp_def : ppred_def;
511+
pp_tags : psymbol list;
511512
pp_locality : locality;
512513
}
513514

src/ecScope.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,7 +1349,8 @@ module Op = struct
13491349
let tags = Sstr.of_list (List.map unloc op.po_tags) in
13501350
let opaque = {
13511351
smt = Sstr.mem "smt_opaque" tags;
1352-
reduction = Sstr.mem "opaque" tags
1352+
reduction = Sstr.mem "opaque" tags;
1353+
inline = Sstr.mem "smt_inline" tags;
13531354
} in
13541355
let unfold =
13551356
match op.po_args with
@@ -1383,7 +1384,7 @@ module Op = struct
13831384
let axop =
13841385
let nargs = List.sum (List.map (List.length -| fst) args) in
13851386
EcDecl.axiomatized_op ~nargs path (tyop.op_tparams, bd) lc in
1386-
let tyop = { tyop with op_opaque = { reduction = true; smt = false; }} in
1387+
let tyop = { tyop with op_opaque = { reduction = true; smt = false; inline = false; }} in
13871388
let scope = bind scope (unloc op.po_name, tyop) in
13881389
Ax.bind scope (unloc ax, axop)
13891390

src/ecSmt.ml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,9 +654,36 @@ and trans_kpatterns env (ks : (kpattern * w3_known_op) list) (f : form) =
654654
ks)
655655

656656
(* -------------------------------------------------------------------- *)
657+
(* Operators tagged `[smt_inline]` are δ/β-reduced at their use sites instead
658+
of being emitted as a symbol plus a defining axiom. This keeps lambdas
659+
occurring in their bodies monomorphic at the call's instantiation, which
660+
avoids the polymorphic higher-order encoding (uni/t2tb bridges) that
661+
weaker SMT solvers fail to navigate. *)
662+
and try_inline ((genv, _) : tenv * lenv) (fp : form) =
663+
let hd, args =
664+
match fp.f_node with
665+
| Fapp (hd, args) -> (hd, args)
666+
| _ -> (fp, []) in
667+
match hd.f_node with
668+
| Fop (p, tys) -> begin
669+
match Op.by_path_opt p genv.te_env with
670+
| Some op when op.op_opaque.inline -> begin
671+
match op.op_kind with
672+
| OB_oper (Some (OP_Plain _)) | OB_pred (Some (PR_Plain _)) ->
673+
Some (f_app_simpl (Op.reduce ~mode:`Force genv.te_env p tys) args fp.f_ty)
674+
| _ -> None
675+
end
676+
| _ -> None
677+
end
678+
| _ -> None
679+
657680
and trans_form ((genv, lenv) as env : tenv * lenv) (fp : form) =
658681
try trans_kpatterns env genv.tk_known_w3 fp with CanNotTranslate ->
659682

683+
match try_inline env fp with
684+
| Some fp -> trans_form env fp
685+
| None ->
686+
660687
match fp.f_node with
661688
| Fquant (qt, bds, body) ->
662689
begin

theories/prelude/Logic.ec

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,28 +181,28 @@ pred right_commutative (o:'a -> 'b -> 'a) =
181181
pred left_distributive (o1:'a -> 'b -> 'a) (o2:'a -> 'a -> 'a) =
182182
forall x y z, o1 (o2 x y) z = o2 (o1 x z) (o1 y z).
183183
184-
pred right_loop (inv : 'b -> 'b) (o:'a -> 'b -> 'a) =
184+
pred [smt_inline] right_loop (inv : 'b -> 'b) (o:'a -> 'b -> 'a) =
185185
forall y, cancel (fun x, o x y) (fun x, o x (inv y)).
186186

187-
pred rev_right_loop inv (o:'a -> 'b -> 'a) =
187+
pred [smt_inline] rev_right_loop inv (o:'a -> 'b -> 'a) =
188188
forall y, cancel (fun x, o x (inv y)) (fun x, o x y).
189189
190-
pred left_loop inv (o:'a -> 'b -> 'b) =
190+
pred [smt_inline] left_loop inv (o:'a -> 'b -> 'b) =
191191
forall x, cancel (o x) (o (inv x)).
192192

193-
pred rev_left_loop inv (o:'a -> 'b -> 'b) =
193+
pred [smt_inline] rev_left_loop inv (o:'a -> 'b -> 'b) =
194194
forall x, cancel (o (inv x)) (o x).
195195
196-
pred right_loop_in p (inv : 'b -> 'b) (o:'a -> 'b -> 'a) =
196+
pred [smt_inline] right_loop_in p (inv : 'b -> 'b) (o:'a -> 'b -> 'a) =
197197
forall y, p y => cancel (fun x, o x y) (fun x, o x (inv y)).
198198

199-
pred rev_right_loop_in p inv (o:'a -> 'b -> 'a) =
199+
pred [smt_inline] rev_right_loop_in p inv (o:'a -> 'b -> 'a) =
200200
forall y, p y => cancel (fun x, o x (inv y)) (fun x, o x y).
201201
202-
pred left_loop_in p inv (o:'a -> 'b -> 'b) =
202+
pred [smt_inline] left_loop_in p inv (o:'a -> 'b -> 'b) =
203203
forall x, p x => cancel (o x) (o (inv x)).
204204

205-
pred rev_left_loop_in p inv (o:'a -> 'b -> 'b) =
205+
pred [smt_inline] rev_left_loop_in p inv (o:'a -> 'b -> 'b) =
206206
forall x, p x => cancel (o (inv x)) (o x).
207207
208208
pred left_id e (o:'a -> 'b -> 'b) =

0 commit comments

Comments
 (0)