|
1 (* Title: nominal_eqvt.ML |
|
2 Author: Stefan Berghofer |
|
3 Author: Christian Urban |
|
4 |
|
5 Automatic proofs for equivariance of inductive predicates. |
|
6 *) |
|
7 |
|
8 signature NOMINAL_EQVT = |
|
9 sig |
|
10 val eqvt_rel_tac : xstring -> Proof.context -> local_theory |
|
11 end |
|
12 |
|
13 structure Nominal_Eqvt : NOMINAL_EQVT = |
|
14 struct |
|
15 |
|
16 open Nominal_Permeq; |
|
17 open Nominal_ThmDecls; |
|
18 |
|
19 val atomize_conv = |
|
20 MetaSimplifier.rewrite_cterm (true, false, false) (K (K NONE)) |
|
21 (HOL_basic_ss addsimps @{thms induct_atomize}); |
|
22 val atomize_intr = Conv.fconv_rule (Conv.prems_conv ~1 atomize_conv); |
|
23 fun atomize_induct ctxt = Conv.fconv_rule (Conv.prems_conv ~1 |
|
24 (Conv.params_conv ~1 (K (Conv.prems_conv ~1 atomize_conv)) ctxt)); |
|
25 |
|
26 fun map_term f t = |
|
27 (case f t of |
|
28 NONE => map_term' f t |
|
29 | x => x) |
|
30 and map_term' f (t $ u) = |
|
31 (case (map_term f t, map_term f u) of |
|
32 (NONE, NONE) => NONE |
|
33 | (SOME t'', NONE) => SOME (t'' $ u) |
|
34 | (NONE, SOME u'') => SOME (t $ u'') |
|
35 | (SOME t'', SOME u'') => SOME (t'' $ u'')) |
|
36 | map_term' f (Abs (s, T, t)) = |
|
37 (case map_term f t of |
|
38 NONE => NONE |
|
39 | SOME t'' => SOME (Abs (s, T, t''))) |
|
40 | map_term' _ _ = NONE; |
|
41 |
|
42 fun map_thm_tac ctxt tac thm = |
|
43 let |
|
44 val monos = Inductive.get_monos ctxt |
|
45 in |
|
46 EVERY [cut_facts_tac [thm] 1, etac rev_mp 1, |
|
47 REPEAT_DETERM (FIRSTGOAL (resolve_tac monos)), |
|
48 REPEAT_DETERM (rtac impI 1 THEN (atac 1 ORELSE tac))] |
|
49 end |
|
50 |
|
51 (* |
|
52 proves F[f t] from F[t] where F[t] is the given theorem |
|
53 |
|
54 - F needs to be monotone |
|
55 - f returns either SOME for a term it fires |
|
56 and NONE elsewhere |
|
57 *) |
|
58 fun map_thm ctxt f tac thm = |
|
59 let |
|
60 val opt_goal_trm = map_term f (prop_of thm) |
|
61 fun prove goal = |
|
62 Goal.prove ctxt [] [] goal (fn _ => map_thm_tac ctxt tac thm) |
|
63 in |
|
64 case opt_goal_trm of |
|
65 NONE => thm |
|
66 | SOME goal => prove goal |
|
67 end |
|
68 |
|
69 fun transform_prem ctxt names thm = |
|
70 let |
|
71 fun split_conj names (Const ("op &", _) $ p $ q) = |
|
72 (case head_of p of |
|
73 Const (name, _) => if name mem names then SOME q else NONE |
|
74 | _ => NONE) |
|
75 | split_conj _ _ = NONE; |
|
76 in |
|
77 map_thm ctxt (split_conj names) (etac conjunct2 1) thm |
|
78 end |
|
79 |
|
80 fun single_case_tac ctxt pred_names pi intro = |
|
81 let |
|
82 val thy = ProofContext.theory_of ctxt |
|
83 val cpi = Thm.cterm_of thy (mk_minus pi) |
|
84 val rule = Drule.instantiate' [] [SOME cpi] @{thm permute_boolE} |
|
85 in |
|
86 eqvt_strict_tac ctxt [] [] THEN' |
|
87 SUBPROOF (fn {prems, context as ctxt, ...} => |
|
88 let |
|
89 val prems' = map (transform_prem ctxt pred_names) prems |
|
90 val side_cond_tac = EVERY' |
|
91 [ rtac rule, |
|
92 eqvt_strict_tac ctxt @{thms permute_minus_cancel(2)} [], |
|
93 resolve_tac prems' ] |
|
94 in |
|
95 HEADGOAL (rtac intro THEN_ALL_NEW (resolve_tac prems' ORELSE' side_cond_tac)) |
|
96 end) ctxt |
|
97 end |
|
98 |
|
99 |
|
100 fun prepare_pred params_no pi pred = |
|
101 let |
|
102 val (c, xs) = strip_comb pred; |
|
103 val (xs1, xs2) = chop params_no xs |
|
104 in |
|
105 HOLogic.mk_imp |
|
106 (pred, list_comb (c, xs1 @ map (mk_perm pi) xs2)) |
|
107 end |
|
108 |
|
109 |
|
110 fun note_named_thm (name, thm) ctxt = |
|
111 let |
|
112 val thm_name = Binding.qualified_name |
|
113 (Long_Name.qualify (Long_Name.base_name name) "eqvt") |
|
114 val attr = Attrib.internal (K eqvt_add) |
|
115 in |
|
116 Local_Theory.note ((thm_name, [attr]), [thm]) ctxt |
|
117 end |
|
118 |
|
119 |
|
120 fun eqvt_rel_tac pred_name ctxt = |
|
121 let |
|
122 val thy = ProofContext.theory_of ctxt |
|
123 val ({names, ...}, {raw_induct, intrs, ...}) = |
|
124 Inductive.the_inductive ctxt (Sign.intern_const thy pred_name) |
|
125 val raw_induct = atomize_induct ctxt raw_induct; |
|
126 val intros = map atomize_intr intrs; |
|
127 val params_no = length (Inductive.params_of raw_induct) |
|
128 val (([raw_concl], [raw_pi]), ctxt') = |
|
129 ctxt |> Variable.import_terms false [concl_of raw_induct] |
|
130 ||>> Variable.variant_fixes ["pi"] |
|
131 val pi = Free (raw_pi, @{typ perm}) |
|
132 val preds = map (fst o HOLogic.dest_imp) |
|
133 (HOLogic.dest_conj (HOLogic.dest_Trueprop raw_concl)); |
|
134 val goal = HOLogic.mk_Trueprop |
|
135 (foldr1 HOLogic.mk_conj (map (prepare_pred params_no pi) preds)) |
|
136 val thm = Goal.prove ctxt' [] [] goal (fn {context,...} => |
|
137 HEADGOAL (EVERY' (rtac raw_induct :: map (single_case_tac context names pi) intros))) |
|
138 |> singleton (ProofContext.export ctxt' ctxt) |
|
139 val thms = map (fn th => zero_var_indexes (th RS mp)) (Datatype_Aux.split_conj_thm thm) |
|
140 in |
|
141 ctxt |> fold_map note_named_thm (names ~~ thms) |
|
142 |> snd |
|
143 end |
|
144 |
|
145 |
|
146 local structure P = OuterParse and K = OuterKeyword in |
|
147 |
|
148 val _ = |
|
149 OuterSyntax.local_theory "equivariance" |
|
150 "prove equivariance for inductive predicate involving nominal datatypes" K.thy_decl |
|
151 (P.xname >> eqvt_rel_tac); |
|
152 |
|
153 end; |
|
154 |
|
155 end (* structure *) |