Skip to content

Commit 456191f

Browse files
authored
Merge pull request #56 from jvanbruegge/popl2025_updated
Popl2025 updated
2 parents 08bac7e + 0b8c10c commit 456191f

File tree

83 files changed

+2339
-1846
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+2339
-1846
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
*~
2+
Scratch.thy

README.md

Lines changed: 26 additions & 26 deletions
Large diffs are not rendered by default.

Tools/binder_inductive.ML

Lines changed: 161 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
signature BINDER_INDUCTIVE =
22
sig
3-
val binder_inductive_cmd: (string * (string * string list) list option) * (string list option * string list option)
3+
datatype options = No_Equiv | No_Refresh | Verbose
4+
5+
val binder_inductive_cmd: ((options list * string) * (string * string list) list option) * (string list option * string list option)
46
-> local_theory -> Proof.state;
7+
8+
val config_parser: options list parser;
59
end
610

711
structure Binder_Inductive : BINDER_INDUCTIVE =
@@ -22,7 +26,9 @@ fun collapse (Inl x) = x
2226
fun mk_insert x S =
2327
Const (@{const_name Set.insert}, fastype_of x --> fastype_of S --> fastype_of S) $ x $ S;
2428

25-
fun binder_inductive_cmd ((pred_name, binds_opt), perms_supps) no_defs_lthy =
29+
datatype options = No_Equiv | No_Refresh | Verbose
30+
31+
fun binder_inductive_cmd (((options, pred_name), binds_opt), perms_supps) no_defs_lthy =
2632
let
2733
val binds = the_default [] binds_opt;
2834

@@ -74,6 +80,10 @@ fun binder_inductive_cmd ((pred_name, binds_opt), perms_supps) no_defs_lthy =
7480

7581
val param_Ts = map (Term.typ_subst_TVars subst) param_Ts;
7682

83+
val param_sugars = map (fn T => Option.mapPartial (fn s =>
84+
MRBNF_Sugar.binder_sugar_of no_defs_lthy s
85+
) (try (fn () => fst (dest_Type T)) ())) param_Ts;
86+
7787
fun collect_binders (Free _) = []
7888
| collect_binders (Var _) = []
7989
| collect_binders (Bound _) = []
@@ -373,17 +383,21 @@ fun binder_inductive_cmd ((pred_name, binds_opt), perms_supps) no_defs_lthy =
373383
val perms_specified = map (fn Inl _ => false | _ => true) raw_perms;
374384
val supps_specified = map (fn Inl _ => false | _ => true) raw_supps;
375385
val one_specified = map2 (fn a => fn b => a orelse b) perms_specified supps_specified;
386+
376387
fun keep_perm xs = cond_keep xs perms_specified;
377388
fun keep_supp xs = cond_keep xs supps_specified;
378389
fun keep_both xs = cond_keep xs one_specified;
379390
fun keep_binders xs = cond_keep xs binders_specified;
380391

392+
fun option x t f = if member (op=) options x then t else f;
393+
381394
val defs = map snd (perms @ supps);
395+
val verbose = member (op=) options Verbose;
382396

383397
val goals = map (single o rpair []) (
384398
keep_perm perm_id0_goals @ keep_perm perm_comp_goals @ keep_both supp_seminat_goals
385399
@ keep_both perm_support_goals @ keep_supp supp_small_goals @ flat (keep_binders B_small_goals)
386-
@ [G_equiv_goal, G_refresh_goal]
400+
@ option No_Equiv [G_equiv_goal] [] @ option No_Refresh [G_refresh_goal] []
387401
);
388402
fun after_qed thmss lthy =
389403
let
@@ -445,15 +459,14 @@ fun binder_inductive_cmd ((pred_name, binds_opt), perms_supps) no_defs_lthy =
445459
val m2 = length (filter not one_specified);
446460
val m3 = length (filter not supps_specified);
447461
val m4 = length (filter not binders_specified);
448-
val (((((((perm_id0s, perm_comps), supp_seminats), perm_supports), supp_smalls), B_smalls), G_equiv), G_refresh) = map hd thmss
462+
val (((((((perm_id0s, perm_comps), supp_seminats), perm_supports), supp_smalls), B_smalls), G_equivs), G_refreshs) = map hd thmss
449463
|> chop (n - m)
450464
||>> chop (n - m)
451465
||>> chop (n - m2)
452466
||>> chop (n - m2)
453467
||>> chop (num_vars * (n - m3))
454468
||>> chop (length bind_ts - m4)
455-
||>> apfst hd o chop 1
456-
||> hd;
469+
||>> chop (option No_Equiv 1 0);
457470

458471
fun map_id0_of_mr_bnf (Inl mrbnf) = [MRBNF_Def.map_id0_of_mrbnf mrbnf]
459472
| map_id0_of_mr_bnf (Inr (Inl bnf)) = [BNF_Def.map_id0_of_bnf bnf]
@@ -601,6 +614,138 @@ fun binder_inductive_cmd ((pred_name, binds_opt), perms_supps) no_defs_lthy =
601614

602615
val perm_ids = map (fn thm => thm RS fun_cong RS @{thm trans[OF _ id_apply]}) perm_id0s;
603616

617+
val G_equiv = if member (op=) options No_Equiv then hd G_equivs else
618+
Goal.prove_sorry lthy [] [] G_equiv_goal (fn {context=ctxt, ...} => EVERY1 [
619+
K (Local_Defs.unfold0_tac ctxt [snd G]),
620+
REPEAT_DETERM o EVERY' [
621+
TRY o etac ctxt @{thm disj_forward},
622+
REPEAT_DETERM o eresolve_tac ctxt [exE, conjE],
623+
REPEAT_DETERM_N (length param_Ts + 1) o etac ctxt @{thm subst[OF sym]},
624+
Subgoal.FOCUS_PARAMS (fn {context=ctxt, params, ...} =>
625+
let
626+
val (fs, args) = map (Thm.term_of o snd) params
627+
|> drop 2
628+
|> chop 1
629+
||> drop (length param_Ts);
630+
val (mr_bnfs, ts) = apfst (map snd o flat) (split_list (map (fn x => case find_index (curry (op=) (fastype_of x)) param_Ts of
631+
~1 => (case find_index (curry (op=) (fastype_of x)) var_Ts of
632+
~1 => apsnd (fn t => t $ x) (build_permute_for fs var_Ts (fastype_of x))
633+
| n => ([], nth fs n $ x))
634+
| n => ([], Term.list_comb (fst (nth perms n), fs) $ x)
635+
) args));
636+
val equiv_commute = Named_Theorems.get ctxt "MRBNF_Recursor.equiv_commute";
637+
val equiv = Named_Theorems.get ctxt "MRBNF_Recursor.equiv" @ equiv_commute;
638+
val equiv_simps = Named_Theorems.get ctxt "MRBNF_Recursor.equiv_simps"
639+
val monos = Inductive.get_monos ctxt
640+
val set_maps = maps set_map_of_mr_bnf mr_bnfs;
641+
in EVERY1 [
642+
EVERY' (map (fn t => rtac ctxt (
643+
infer_instantiate' ctxt [NONE, SOME (Thm.cterm_of ctxt t)] exI
644+
)) ts),
645+
SELECT_GOAL (Local_Defs.unfold0_tac ctxt (map snd perms)),
646+
rtac ctxt conjI,
647+
SELECT_GOAL (Local_Defs.unfold0_tac ctxt (@{thms image_Un} @ equiv_simps)),
648+
REPEAT_DETERM o rtac ctxt @{thm arg_cong2[of _ _ _ _ "(\<union>)"]},
649+
REPEAT_DETERM1 o EVERY' [
650+
resolve_tac ctxt @{thms image_single[symmetric] image_empty refl} ORELSE' EVERY' [
651+
resolve_tac ctxt (map (fn thm => thm RS sym) (set_maps @ equiv_simps) @ equiv_simps),
652+
REPEAT_DETERM o assume_tac ctxt
653+
]
654+
],
655+
K (Local_Defs.unfold0_tac ctxt @{thms id_apply}),
656+
K (Local_Defs.unfold0_tac ctxt @{thms id_def[symmetric]}),
657+
REPEAT_DETERM o EVERY' [
658+
TRY o rtac ctxt conjI,
659+
SELECT_GOAL (EVERY1 [
660+
REPEAT_DETERM1 o FIRST' [
661+
assume_tac ctxt,
662+
eresolve_tac ctxt [conjE],
663+
resolve_tac ctxt @{thms conjI refl TrueI bij_imp_bij_inv supp_inv_bound},
664+
rtac ctxt impI THEN' eresolve_tac ctxt @{thms injD[OF bij_is_inj, rotated -1]},
665+
EVERY' [
666+
SELECT_GOAL (Local_Defs.unfold0_tac ctxt (map_filter (try (fn thm => thm RS sym)) equiv_commute)),
667+
REPEAT_DETERM1 o EVERY' [
668+
EqSubst.eqsubst_tac ctxt [0] (map (Local_Defs.unfold0 ctxt (map snd perms)) perm_comps),
669+
REPEAT_DETERM1 o (assume_tac ctxt ORELSE' resolve_tac ctxt @{thms supp_inv_bound bij_imp_bij_inv})
670+
],
671+
K (Local_Defs.unfold0_tac ctxt @{thms inv_o_simp1 inv_o_simp2 inv_simp1 inv_simp2}),
672+
K (Local_Defs.unfold0_tac ctxt (map (Local_Defs.unfold0 ctxt (map snd perms)) perm_ids)),
673+
assume_tac ctxt
674+
],
675+
eresolve_tac ctxt (map_filter (try (fn thm => Drule.rotate_prems ~1 thm)) equiv),
676+
CHANGED o SELECT_GOAL (Local_Defs.unfold0_tac ctxt (equiv @ equiv_simps @ flat (map_filter (Option.map #permute_simps) param_sugars))),
677+
eresolve_tac ctxt (map (fn thm => Drule.rotate_prems ~1 (thm RS mp)) monos),
678+
resolve_tac ctxt monos,
679+
CHANGED o SELECT_GOAL (Local_Defs.unfold0_tac ctxt (flat (map_filter (Option.map (map (fn thm => thm RS sym) o #permute_simps)) param_sugars)))
680+
]
681+
])
682+
]
683+
] end
684+
) ctxt
685+
]
686+
]);
687+
val _ = (verbose ? @{print}) G_equiv
688+
689+
val G_refresh = if member (op=) options No_Refresh then hd (G_refreshs) else
690+
let
691+
val var_rules = map (fn thm =>
692+
let val t = Logic.unvarify_global (Thm.prop_of thm)
693+
in (map Free (rev (Term.add_frees t [])), t) end
694+
) intrs;
695+
696+
fun collect_permutes _ (Free _) = []
697+
| collect_permutes _ (Var _) = []
698+
| collect_permutes _ (Bound _) = []
699+
| collect_permutes _ (Const _) = []
700+
| collect_permutes vars (Abs (_, _, t)) = collect_permutes vars t
701+
| collect_permutes vars (t as (t1 $ t2)) = case try (dest_Type o Term.body_type o fastype_of) t of
702+
NONE => collect_permutes vars t1 @ collect_permutes vars t2
703+
| SOME (s, _) => (case MRBNF_Sugar.binder_sugar_of no_defs_lthy s of
704+
NONE => collect_permutes vars t1 @ collect_permutes vars t2
705+
| SOME sugar =>
706+
let val (ctor, args) = Term.strip_comb t
707+
in case (map_filter I (map_index (fn (i, (t, _)) =>
708+
if (op=) (apply2 (fst o dest_Const) (t, ctor)) then
709+
SOME i else NONE
710+
) (#ctors sugar))) of
711+
[] => collect_permutes vars t1 @ collect_permutes vars t2
712+
| ctor_idx::_ => (case nth (hd (#bsetss sugar)) ctor_idx of
713+
NONE => maps (collect_permutes vars) args
714+
| SOME _ =>
715+
let
716+
val arg_Ts = Term.binder_types (fastype_of ctor);
717+
val permute_bounds = nth (#permute_bounds sugar) ctor_idx;
718+
val var_args = map (fn t => if member (op=) vars t then SOME t else NONE) args;
719+
val result = map_filter I (map2 (fn NONE => K NONE
720+
| SOME perm => Option.map (fn x => (x, perm))
721+
) permute_bounds var_args);
722+
723+
val tyenv = @{fold 2} (fn NONE => K I | SOME perm => fn T =>
724+
Sign.typ_match (Proof_Context.theory_of no_defs_lthy) (body_type (fastype_of perm), T)
725+
) permute_bounds arg_Ts Vartab.empty;
726+
727+
in map (apsnd (Envir.subst_term (tyenv, Vartab.empty))) result
728+
@ maps (collect_permutes vars) args
729+
end
730+
)
731+
end
732+
);
733+
fun isNONE NONE = true
734+
| isNONE _ = false
735+
val permute_bounds = map (distinct (op=) o uncurry collect_permutes) var_rules;
736+
val matrix = map2 (fn (vars, _) => fn perms =>
737+
let val inner = map (AList.lookup (op=) perms) vars;
738+
in if forall isNONE inner then NONE else SOME inner end
739+
) var_rules permute_bounds;
740+
val _ = (verbose ? @{print}) (map (Option.map (map (Option.map (Thm.cterm_of lthy)))) matrix)
741+
in Goal.prove_sorry lthy [] [] G_refresh_goal (fn {context=ctxt, ...} => EVERY1 [
742+
K (Local_Defs.unfold0_tac ctxt (snd G :: map snd perms)),
743+
Subgoal.FOCUS (fn {context=ctxt, prems, ...} =>
744+
refreshability_tac_internal verbose (map fst supps) matrix (nth prems 2) (nth prems 1) supp_smalls (map snd supps) ctxt
745+
) ctxt
746+
]) end;
747+
val _ = (verbose ? @{print}) G_refresh
748+
604749
fun mk_induct mono = Drule.rotate_prems ~1 (
605750
apply_n @{thm le_funD} n (@{thm lfp_induct} OF [mono])
606751
RS @{thm le_boolD}
@@ -1009,12 +1154,20 @@ val parse_perm_supps =
10091154
>> (fn ps => fold extract_perm_supp ps (NONE, NONE))
10101155
|| Scan.succeed (NONE, NONE);
10111156

1012-
val binder_inductive_parser = Parse.name -- Scan.option (
1157+
val options_parser = Parse.group (fn () => "option")
1158+
((Parse.reserved "no_auto_equiv" >> K No_Equiv)
1159+
|| (Parse.reserved "no_auto_refresh" >> K No_Refresh)
1160+
|| (Parse.reserved "verbose" >> K Verbose))
1161+
1162+
val config_parser = Scan.optional (@{keyword "("} |--
1163+
Parse.!!! (Parse.list1 options_parser) --| @{keyword ")"}) []
1164+
1165+
val binder_inductive_parser = config_parser -- Parse.name -- Scan.option (
10131166
@{keyword where} |-- Parse.enum1 "|" (Parse.name --| @{keyword binds} -- Parse.and_list Parse.term)
10141167
) -- parse_perm_supps
10151168

10161169
val _ =
10171170
Outer_Syntax.local_theory_to_proof \<^command_keyword>\<open>make_binder_inductive\<close> "derive strengthened induction theorems for inductive predicates"
10181171
(binder_inductive_parser >> binder_inductive_cmd);
10191172

1020-
end
1173+
end

Tools/binder_inductive_combined.ML

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ struct
33

44
fun ind_decl co args =
55
let
6-
val names = map (fn (x, _, _) => x) (fst (Parse.vars args));
7-
val (inductive, rest) = Inductive.gen_ind_decl Inductive.add_ind_def co args;
6+
val (options, rest) = Binder_Inductive.config_parser args;
7+
val names = map (fn (x, _, _) => x) (fst (Parse.vars rest));
8+
val (inductive, rest) = Inductive.gen_ind_decl Inductive.add_ind_def co rest;
89
in (fn lthy =>
910
let
1011
val lthy = snd (Local_Theory.begin_nested lthy);
1112
val lthy = inductive lthy;
1213
val (lthy, old_lthy) = `Local_Theory.end_nested lthy;
13-
val state = Binder_Inductive.binder_inductive_cmd ((Binding.name_of (hd names), NONE), (NONE, NONE)) lthy
14+
val state = Binder_Inductive.binder_inductive_cmd (((options, Binding.name_of (hd names)), NONE), (NONE, NONE)) lthy
1415
in state end, rest) end;
1516

1617
val _ =
1718
Outer_Syntax.local_theory_to_proof \<^command_keyword>\<open>binder_inductive\<close> "derive strengthened induction theorems for inductive predicates"
1819
(ind_decl false);
1920

20-
end
21+
end

Tools/mrbnf_fp.ML

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,6 +2363,35 @@ fun construct_binder_fp fp mrbnf_ks binding_relation lthy =
23632363
val cctor_eq_intro_rrenames = map (fn thm => (thm RS iffD2)
23642364
|> funpow fbound (fn thm => thm OF [exI]) OF [mk_conjIN (3*fbound + 1)]) TT_injects0;
23652365

2366+
fun mk_noclash_rename renames FVars_renames = @{map 4} (fn mrbnf => fn map_t => fn noclash => fn x =>
2367+
let
2368+
val goal = mk_Trueprop_eq (
2369+
fst noclash $ (comb_mrbnf_term ffs_ids (map (fn t => Term.list_comb (t, ffs)) renames) map_t $ x),
2370+
fst noclash $ x
2371+
);
2372+
in Goal.prove_sorry lthy (map (fst o dest_Free) (ffs @ [x])) prem_terms_ffs goal (fn {context=ctxt, prems} => EVERY1 [
2373+
K (Local_Defs.unfold0_tac ctxt [snd noclash]),
2374+
REPEAT_DETERM o EVERY' [
2375+
EqSubst.eqsubst_tac ctxt [0] (MRBNF_Def.set_map_of_mrbnf mrbnf),
2376+
REPEAT_DETERM o resolve_tac ctxt (@{thms supp_id_bound bij_id} @ prems)
2377+
],
2378+
K (Local_Defs.unfold0_tac ctxt @{thms image_comp[unfolded comp_def]}),
2379+
REPEAT_DETERM o EVERY' [
2380+
EqSubst.eqsubst_tac ctxt [0] FVars_renames,
2381+
REPEAT_DETERM o resolve_tac ctxt prems
2382+
],
2383+
K (Local_Defs.unfold0_tac ctxt @{thms image_Un[symmetric] image_UN[symmetric]}),
2384+
REPEAT_DETERM o EVERY' [
2385+
EqSubst.eqsubst_tac ctxt [0] @{thms image_Int[OF bij_is_inj, symmetric]},
2386+
resolve_tac ctxt prems
2387+
],
2388+
K (Local_Defs.unfold0_tac ctxt @{thms image_is_empty}),
2389+
rtac ctxt refl
2390+
]) end
2391+
) mrbnfs;
2392+
val noclash_renames = mk_noclash_rename renamesAs (flat FVars_renamess) mrbnf_maps_AsAs noclashs xs;
2393+
val nnoclash_rrenames = mk_noclash_rename rrenamesAs (flat FFVars_rrenamess) mrbnf_maps_BsBs nnoclashs vs;
2394+
23662395
(* TODO: use giant map instead of x times (nth ... i) *)
23672396
val (raw_ress, quot_ress) = split_list (map (fn i =>
23682397
let
@@ -2375,6 +2404,7 @@ fun construct_binder_fp fp mrbnf_ks binding_relation lthy =
23752404
noclash = nth noclashs i,
23762405

23772406
inject = nth raw_injects i,
2407+
noclash_rename = nth noclash_renames i,
23782408
rename_id0 = nth rename_id0s i,
23792409
rename_id = nth rename_ids i,
23802410
rename_comp0 = nth rename_comp0s i,
@@ -2417,6 +2447,7 @@ fun construct_binder_fp fp mrbnf_ks binding_relation lthy =
24172447
noclash = nth nnoclashs i,
24182448

24192449
inject = nth TT_injects0 i,
2450+
noclash_rename = nth nnoclash_rrenames i,
24202451
rename_id0 = nth rrename_id0s i,
24212452
rename_id = nth rrename_ids i,
24222453
rename_comp0 = nth rrename_comp0s i,
@@ -2491,6 +2522,8 @@ fun construct_binder_fp fp mrbnf_ks binding_relation lthy =
24912522
("alpha_avoids", alpha_avoids),
24922523
("equivp_alphas", equivp_alphas),
24932524
("nnoclash_noclashs", nnoclash_noclashs),
2525+
("nnoclash_rrenames", nnoclash_rrenames),
2526+
("noclash_renames", noclash_renames),
24942527
("TT_Quotients", TT_Quotients),
24952528
("TT_alpha_quotient_syms", alpha_quotient_syms),
24962529
("TT_Quotient_total_abs_eq_iffs", Quotient_total_abs_eq_iffs),

Tools/mrbnf_fp_def_sugar.ML

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ sig
99
inner: 'a,
1010

1111
inject: thm,
12+
noclash_rename: thm,
1213
rename_id0: thm,
1314
rename_id: thm,
1415
rename_comp0: thm,
@@ -100,6 +101,7 @@ type 'a fp_result_T = {
100101
inner: 'a,
101102

102103
inject: thm,
104+
noclash_rename: thm,
103105
rename_id0: thm,
104106
rename_id: thm,
105107
rename_comp0: thm,
@@ -115,14 +117,15 @@ type 'a fp_result_T = {
115117

116118
fun morph_fp_result_T morph phi { T, ctor, rename, FVars, inner, inject, rename_id0, rename_id,
117119
rename_comp0, rename_comp, rename_bij, rename_inv_simp, FVars_ctors, FVars_renames, card_of_FVars_bounds,
118-
card_of_FVars_bound_UNIVs, FVars_intross, noclash } = {
120+
card_of_FVars_bound_UNIVs, FVars_intross, noclash, noclash_rename } = {
119121
T = Morphism.typ phi T,
120122
ctor = Morphism.term phi ctor,
121123
rename = Morphism.term phi rename,
122124
FVars = map (Morphism.term phi) FVars,
123125
noclash = BNF_Util.map_prod (Morphism.term phi) (Morphism.thm phi) noclash,
124126
inner = morph phi inner,
125127
inject = Morphism.thm phi inject,
128+
noclash_rename = Morphism.thm phi noclash_rename,
126129
rename_id0 = Morphism.thm phi rename_id0,
127130
rename_id = Morphism.thm phi rename_id,
128131
rename_comp0 = Morphism.thm phi rename_comp0,

0 commit comments

Comments
 (0)