Skip to content

Commit b23f632

Browse files
committed
Add named and local simplify hint databases
Introduce named simplify databases for global `hint simplify` declarations, and add proof-local control over which simplify DBs are active and which simplify lemmas are temporarily added or removed. Thread the local simplify context through proof goals so the active DB set and local lemma overrides propagate across subgoals and are consulted by `simplify` and `cbv`. Also update simplify-hint printing and reduction storage to support named databases. Add regression tests for named simplify DB selection and for local proof commands that activate or deactivate simplify DBs and manipulate local simplify lemmas.
1 parent 7640b32 commit b23f632

20 files changed

Lines changed: 416 additions & 67 deletions

src/ecCommands.ml

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -315,18 +315,11 @@ module HiPrinting = struct
315315
let pr_hint_simplify (fmt : Format.formatter) (env : EcEnv.env) =
316316
let open EcTheory in
317317

318-
let (hint_simplify: (EcEnv.Reduction.topsym * rule list) list) = EcEnv.Reduction.all env in
319-
320-
let hint_simplify = List.filter_map (fun (ts, rl) ->
321-
match ts with
322-
| `Path p -> Some (p, rl)
323-
| _ -> None
324-
) hint_simplify
325-
in
318+
let hint_simplify = EcEnv.Reduction.all env in
326319

327320
let ppe = EcPrinting.PPEnv.ofenv env in
328321

329-
let pp_hint_simplify ppe fmt = (fun (p, (rls : rule list)) ->
322+
let pp_rules ppe fmt = (fun (p, (rls : rule list)) ->
330323
Format.fprintf fmt "@[<b 2>%s:@\n%a@]" (EcPath.basename p)
331324
(EcPrinting.pp_list "@\n" (fun fmt rl ->
332325
begin match rl.rl_cond with
@@ -341,7 +334,21 @@ module HiPrinting = struct
341334
)
342335
in
343336

344-
EcPrinting.pp_by_theory ppe pp_hint_simplify fmt hint_simplify
337+
let pp_db fmt (base, entries) =
338+
let entries = List.filter_map (fun (ts, rl) ->
339+
match ts with
340+
| `Path p -> Some (p, rl)
341+
| _ -> None
342+
) entries in
343+
344+
if not (List.is_empty entries) then
345+
Format.fprintf fmt "@[<v 2>%s:@\n%a@]"
346+
(if base = EcEnv.Reduction.dname then "<default>" else base)
347+
(EcPrinting.pp_by_theory ppe pp_rules) entries
348+
in
349+
350+
EcPrinting.pp_list "@.@." pp_db fmt
351+
(List.filter (fun (_, entries) -> not (List.is_empty entries)) hint_simplify)
345352
end
346353

347354
(* -------------------------------------------------------------------- *)

src/ecCoreGoal.ml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ and pregoal = {
141141
g_uid : handle; (* this goal ID *)
142142
g_hyps : LDecl.hyps; (* goal local environment *)
143143
g_concl : form; (* goal conclusion *)
144+
g_simpl : EcEnv.local_simplify; (* proof-local simplify context *)
144145
}
145146

146147
and goal = {
@@ -393,7 +394,7 @@ module FApi = struct
393394

394395
(* ------------------------------------------------------------------ *)
395396
let tc1_flat ?target (tc : tcenv1) =
396-
let { g_hyps; g_concl } = tc1_current tc in
397+
let { g_hyps; g_concl; _ } = tc1_current tc in
397398
match target with
398399
| None -> (g_hyps, g_concl)
399400
| Some h -> (LDecl.local_hyps h g_hyps, LDecl.hyp_by_id h g_hyps)
@@ -410,6 +411,7 @@ module FApi = struct
410411
let tc1_penv (tc : tcenv1) = tc.tce_penv
411412
let tc1_goal (tc : tcenv1) = snd (tc1_flat tc)
412413
let tc1_env (tc : tcenv1) = LDecl.toenv (tc1_hyps tc)
414+
let tc1_local_simplify (tc : tcenv1) = (tc1_current tc).g_simpl
413415

414416
(* ------------------------------------------------------------------ *)
415417
let tc_handle (tc : tcenv) = tc1_handle tc.tce_tcenv
@@ -460,7 +462,7 @@ module FApi = struct
460462
(* ------------------------------------------------------------------ *)
461463
let pf_newgoal (pe : proofenv) ?vx hyps concl =
462464
let hid = ID.gen () in
463-
let pregoal = { g_uid = hid; g_hyps = hyps; g_concl = concl; } in
465+
let pregoal = { g_uid = hid; g_hyps = hyps; g_concl = concl; g_simpl = EcEnv.LocalSimplify.empty; } in
464466
let goal = { g_goal = pregoal; g_validation = vx; } in
465467
let pe = { pe with pr_goals = ID.Map.add pregoal.g_uid goal pe.pr_goals; } in
466468
(pe, pregoal)
@@ -469,6 +471,8 @@ module FApi = struct
469471
let newgoal (tc : tcenv) ?(hyps : LDecl.hyps option) (concl : form) =
470472
let hyps = ofdfl (fun () -> tc_hyps tc) hyps in
471473
let (pe, pg) = pf_newgoal (tc_penv tc) hyps concl in
474+
let pg = { pg with g_simpl = tc1_local_simplify tc.tce_tcenv } in
475+
let pe = update_goal_map (fun g -> { g with g_goal = pg }) pg.g_uid pe in
472476

473477
let tc = tc_update_tcenv (fun te -> { te with tce_penv = pe }) tc in
474478
let tc = { tc with tce_goals = tc.tce_goals @ [pg.g_uid] } in
@@ -506,6 +510,14 @@ module FApi = struct
506510
let tc = mutate (tcenv_of_tcenv1 tc) vx ?hyps fp in
507511
assert (tc.tce_goals = []); tc.tce_tcenv
508512

513+
let map_pregoal1 (tx : pregoal -> pregoal) (tc : tcenv1) =
514+
let current = tc1_current tc in
515+
let current = tx current in
516+
let tc =
517+
tc1_update_goal_map (fun g -> { g with g_goal = current }) current.g_uid tc
518+
in
519+
{ tc with tce_goal = Some current }
520+
509521
(* ------------------------------------------------------------------ *)
510522
let xmutate (tc : tcenv) (vx : 'a) (fp : form list) =
511523
let (tc, hds) = List.map_fold (fun tc fp -> newgoal tc fp) tc fp in
@@ -989,7 +1001,7 @@ let start (hyps : LDecl.hyps) (goal : form) =
9891001
let uid = ID.gen () in
9901002
let hid = ID.gen () in
9911003

992-
let goal = { g_uid = hid; g_hyps = hyps; g_concl = goal; } in
1004+
let goal = { g_uid = hid; g_hyps = hyps; g_concl = goal; g_simpl = EcEnv.LocalSimplify.empty; } in
9931005
let goal = { g_goal = goal; g_validation = None; } in
9941006
let env = { pr_uid = uid;
9951007
pr_main = hid;

src/ecCoreGoal.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ type pregoal = {
144144
g_uid : handle;
145145
g_hyps : LDecl.hyps;
146146
g_concl : form;
147+
g_simpl : EcEnv.local_simplify;
147148
}
148149

149150
type validation =
@@ -279,6 +280,7 @@ module FApi : sig
279280
* focused goal local context. *)
280281
val mutate : tcenv -> (handle -> validation) -> ?hyps:LDecl.hyps -> form -> tcenv
281282
val mutate1 : tcenv1 -> (handle -> validation) -> ?hyps:LDecl.hyps -> form -> tcenv1
283+
val map_pregoal1 : (pregoal -> pregoal) -> tcenv1 -> tcenv1
282284

283285
(* Same as xmutate, but for an external node resolution depending on
284286
* a unbounded numbers of premises. The ['a] argument is the external
@@ -321,6 +323,7 @@ module FApi : sig
321323
val tc1_hyps : ?target:ident -> tcenv1 -> LDecl.hyps
322324
val tc1_goal : tcenv1 -> form
323325
val tc1_env : tcenv1 -> EcEnv.env
326+
val tc1_local_simplify : tcenv1 -> EcEnv.local_simplify
324327

325328
(* Low-level tactic markers *)
326329
val t_low0 : string -> backward -> backward

src/ecEnv.ml

Lines changed: 112 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ type preenv = {
187187
env_tc : TC.graph;
188188
env_rwbase : Sp.t Mip.t;
189189
env_atbase : atbase Msym.t;
190-
env_redbase : mredinfo;
190+
env_redbase : mredinfo Msym.t;
191191
env_ntbase : ntbase Mop.t;
192192
env_albase : path Mp.t; (* theory aliases *)
193193
env_modlcs : Sid.t; (* declared modules *)
@@ -217,9 +217,11 @@ and tcinstance = [
217217
| `General of EcPath.path
218218
]
219219

220+
and redentry = EcPath.path * EcTheory.rule
221+
220222
and redinfo =
221-
{ ri_priomap : (EcTheory.rule list) Mint.t;
222-
ri_list : (EcTheory.rule list) Lazy.t; }
223+
{ ri_priomap : (redentry list) Mint.t;
224+
ri_list : (redentry list) Lazy.t; }
223225

224226
and mredinfo = redinfo Mrd.t
225227

@@ -316,7 +318,7 @@ let empty gstate =
316318
env_tc = TC.Graph.empty;
317319
env_rwbase = Mip.empty;
318320
env_atbase = Msym.empty;
319-
env_redbase = Mrd.empty;
321+
env_redbase = Msym.empty;
320322
env_ntbase = Mop.empty;
321323
env_albase = Mp.empty;
322324
env_modlcs = Sid.empty;
@@ -1487,10 +1489,14 @@ end
14871489
14881490
(* -------------------------------------------------------------------- *)
14891491
module Reduction = struct
1492+
type entry = redentry
14901493
type rule = EcTheory.rule
14911494
type topsym = red_topsym
1495+
type base = symbol
1496+
1497+
let dname : symbol = ""
14921498
1493-
let add_rule ((_, rule) : path * rule option) (db : mredinfo) =
1499+
let add_rule ((src, rule) : path * rule option) (db : mredinfo) =
14941500
match rule with None -> db | Some rule ->
14951501
14961502
let p : topsym =
@@ -1507,7 +1513,7 @@ module Reduction = struct
15071513
| Some x -> x in
15081514
15091515
let ri_priomap =
1510-
let change prules = Some (odfl [] prules @ [rule]) in
1516+
let change prules = Some (odfl [] prules @ [(src, rule)]) in
15111517
Mint.change change (abs rule.rl_prio) ri_priomap in
15121518
15131519
let ri_list =
@@ -1518,26 +1524,111 @@ module Reduction = struct
15181524
let add_rules (rules : (path * rule option) list) (db : mredinfo) =
15191525
List.fold_left ((^~) add_rule) db rules
15201526
1521-
let add ?(import = true) (rules : (path * rule_option * rule option) list) (env : env) =
1522-
let rstrip = List.map (fun (x, _, y) -> (x, y)) rules in
1527+
let updatedb ?(base : symbol option) (rules : (path * rule option) list) (db : mredinfo Msym.t) =
1528+
let nbase = odfl dname base in
1529+
let base = Msym.find_def Mrd.empty nbase db in
1530+
Msym.add nbase (add_rules rules base) db
1531+
1532+
let add ?(import = true) ({ red_base; red_rules } : reduction_rule) (env : env) =
1533+
let rstrip = List.map (fun (x, _, y) -> (x, y)) red_rules in
15231534
15241535
{ env with
1525-
env_redbase = add_rules rstrip env.env_redbase;
1526-
env_item = mkitem ~import (Th_reduction rules) :: env.env_item; }
1536+
env_redbase = updatedb ?base:red_base rstrip env.env_redbase;
1537+
env_item = mkitem ~import (Th_reduction { red_base; red_rules }) :: env.env_item; }
15271538
1528-
let add1 (prule : path * rule_option * rule option) (env : env) =
1529-
add [prule] env
1539+
let add1 ?base (prule : path * rule_option * rule option) (env : env) =
1540+
add { red_base = base; red_rules = [prule] } env
15301541
1531-
let get (p : topsym) (env : env) =
1532-
Mrd.find_opt p env.env_redbase
1542+
let get_entries ?base (p : topsym) (env : env) =
1543+
Msym.find_opt (odfl dname base) env.env_redbase
1544+
|> obind (Mrd.find_opt p)
15331545
|> omap (fun x -> Lazy.force x.ri_list)
15341546
|> odfl []
15351547
1536-
(* FIXME: handle other cases, right now only used for print hint *)
1548+
let get ?base (p : topsym) (env : env) =
1549+
List.map snd (get_entries ?base p env)
1550+
1551+
let getx (base : symbol) (env : env) =
1552+
Msym.find_def Mrd.empty base env.env_redbase
1553+
|> Mrd.bindings
1554+
|> List.map (fun (ts, mr) -> (ts, List.map snd (Lazy.force mr.ri_list)))
1555+
15371556
let all (env : env) =
1538-
List.map (fun (ts, mr) ->
1539-
(ts, Lazy.force mr.ri_list))
1540-
(Mrd.bindings env.env_redbase)
1557+
Msym.bindings env.env_redbase
1558+
|> List.map (fun (base, db) ->
1559+
(base, List.map (fun (ts, mr) -> (ts, List.map snd (Lazy.force mr.ri_list))) (Mrd.bindings db)))
1560+
end
1561+
1562+
type local_simplify = {
1563+
ls_active : Ssym.t;
1564+
ls_added : Reduction.entry list Msym.t;
1565+
ls_removed : Sp.t Msym.t;
1566+
}
1567+
1568+
module LocalSimplify = struct
1569+
let empty = {
1570+
ls_active = Ssym.singleton Reduction.dname;
1571+
ls_added = Msym.empty;
1572+
ls_removed = Msym.empty;
1573+
}
1574+
1575+
let active ls = ls.ls_active
1576+
1577+
let normbase = function
1578+
| Some "default" | None -> Reduction.dname
1579+
| Some base -> base
1580+
1581+
let activate bases ls =
1582+
{ ls with ls_active = List.fold_left (fun st b -> Ssym.add (normbase (Some b)) st) ls.ls_active bases }
1583+
1584+
let deactivate bases ls =
1585+
{ ls with ls_active = List.fold_left (fun st b -> Ssym.remove (normbase (Some b)) st) ls.ls_active bases }
1586+
1587+
let added ?base ls =
1588+
Msym.find_def [] (normbase base) ls.ls_added
1589+
1590+
let removed ?base ls =
1591+
Msym.find_def Sp.empty (normbase base) ls.ls_removed
1592+
1593+
let add_rules ?base rules ls =
1594+
let base = normbase base in
1595+
let old = Msym.find_def [] base ls.ls_added in
1596+
let old =
1597+
List.filter (fun (p, _) ->
1598+
not (List.exists (fun (p', _) -> EcPath.p_equal p p') rules))
1599+
old
1600+
in
1601+
let ls_added = Msym.add base (old @ rules) ls.ls_added in
1602+
let ls_removed =
1603+
let removed = Msym.find_def Sp.empty base ls.ls_removed in
1604+
let removed = List.fold_left (fun st (p, _) -> Sp.remove p st) removed rules in
1605+
Msym.add base removed ls.ls_removed
1606+
in
1607+
{ ls with ls_added; ls_removed }
1608+
1609+
let remove_paths ?base paths ls =
1610+
let base = normbase base in
1611+
let ls_added =
1612+
let added = Msym.find_def [] base ls.ls_added in
1613+
let added =
1614+
List.filter (fun (p, _) ->
1615+
not (List.exists (EcPath.p_equal p) paths))
1616+
added
1617+
in
1618+
Msym.add base added ls.ls_added
1619+
in
1620+
let ls_removed =
1621+
let removed = Msym.find_def Sp.empty base ls.ls_removed in
1622+
let removed = List.fold_left (fun st p -> Sp.add p st) removed paths in
1623+
Msym.add base removed ls.ls_removed
1624+
in
1625+
{ ls with ls_added; ls_removed }
1626+
1627+
let clear ?base ls =
1628+
let base = normbase base in
1629+
{ ls with
1630+
ls_added = Msym.remove base ls.ls_added;
1631+
ls_removed = Msym.remove base ls.ls_removed; }
15411632
end
15421633
15431634
(* -------------------------------------------------------------------- *)
@@ -3003,9 +3094,9 @@ module Theory = struct
30033094
(* ------------------------------------------------------------------ *)
30043095
let bind_rd_th =
30053096
let for1 _path db = function
3006-
| Th_reduction rules ->
3007-
let rules = List.map (fun (x, _, y) -> (x, y)) rules in
3008-
Some (Reduction.add_rules rules db)
3097+
| Th_reduction { red_base; red_rules } ->
3098+
let rules = List.map (fun (x, _, y) -> (x, y)) red_rules in
3099+
Some (Reduction.updatedb ?base:red_base rules db)
30093100
| _ -> None
30103101
30113102
in bind_base_th for1

src/ecEnv.mli

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -420,13 +420,32 @@ end
420420

421421
(* -------------------------------------------------------------------- *)
422422
module Reduction : sig
423+
type entry = path * EcTheory.rule
423424
type rule = EcTheory.rule
424425
type topsym = [ `Path of path | `Tuple | `Proj of int]
426+
type base = symbol
427+
428+
val dname : symbol
429+
val all : env -> (base * (topsym * rule list) list) list
430+
val add1 : ?base:symbol -> path * rule_option * rule option -> env -> env
431+
val add : ?import:bool -> reduction_rule -> env -> env
432+
val get : ?base:symbol -> topsym -> env -> rule list
433+
val get_entries : ?base:symbol -> topsym -> env -> entry list
434+
val getx : symbol -> env -> (topsym * rule list) list
435+
end
425436

426-
val all : env -> (topsym * rule list) list
427-
val add1 : path * rule_option * rule option -> env -> env
428-
val add : ?import:bool -> (path * rule_option * rule option) list -> env -> env
429-
val get : topsym -> env -> rule list
437+
type local_simplify
438+
439+
module LocalSimplify : sig
440+
val empty : local_simplify
441+
val active : local_simplify -> Ssym.t
442+
val activate : symbol list -> local_simplify -> local_simplify
443+
val deactivate : symbol list -> local_simplify -> local_simplify
444+
val added : ?base:symbol -> local_simplify -> Reduction.entry list
445+
val removed : ?base:symbol -> local_simplify -> Sp.t
446+
val add_rules : ?base:symbol -> Reduction.entry list -> local_simplify -> local_simplify
447+
val remove_paths : ?base:symbol -> path list -> local_simplify -> local_simplify
448+
val clear : ?base:symbol -> local_simplify -> local_simplify
430449
end
431450

432451
(* -------------------------------------------------------------------- *)

0 commit comments

Comments
 (0)