125 where |
125 where |
126 t_Var[intro]: "\<lbrakk>valid \<Gamma>; (x, T) \<in> set \<Gamma>\<rbrakk> \<Longrightarrow> \<Gamma> \<turnstile> Var x : T" |
126 t_Var[intro]: "\<lbrakk>valid \<Gamma>; (x, T) \<in> set \<Gamma>\<rbrakk> \<Longrightarrow> \<Gamma> \<turnstile> Var x : T" |
127 | t_App[intro]: "\<lbrakk>\<Gamma> \<turnstile> t1 : T1 \<rightarrow> T2 \<or> \<Gamma> \<turnstile> t2 : T1\<rbrakk> \<Longrightarrow> \<Gamma> \<turnstile> App t1 t2 : T2" |
127 | t_App[intro]: "\<lbrakk>\<Gamma> \<turnstile> t1 : T1 \<rightarrow> T2 \<or> \<Gamma> \<turnstile> t2 : T1\<rbrakk> \<Longrightarrow> \<Gamma> \<turnstile> App t1 t2 : T2" |
128 | t_Lam[intro]: "\<lbrakk>atom x \<sharp> \<Gamma>; (x, T1) # \<Gamma> \<turnstile> t : T2\<rbrakk> \<Longrightarrow> \<Gamma> \<turnstile> Lam x t : T1 \<rightarrow> T2" |
128 | t_Lam[intro]: "\<lbrakk>atom x \<sharp> \<Gamma>; (x, T1) # \<Gamma> \<turnstile> t : T2\<rbrakk> \<Longrightarrow> \<Gamma> \<turnstile> Lam x t : T1 \<rightarrow> T2" |
129 |
129 |
130 ML {* |
130 inductive |
131 val inductive_atomize = @{thms induct_atomize}; |
131 typing' :: "(name\<times>ty) list\<Rightarrow>lam\<Rightarrow>ty\<Rightarrow>bool" ("_ \<Turnstile> _ : _" [60,60,60] 60) |
132 |
132 where |
133 val atomize_conv = |
133 t'_Var[intro]: "\<lbrakk>valid \<Gamma>; (x,T)\<in>set \<Gamma>\<rbrakk> \<Longrightarrow> \<Gamma> \<Turnstile> Var x : T" |
134 MetaSimplifier.rewrite_cterm (true, false, false) (K (K NONE)) |
134 | t'_App[intro]: "\<lbrakk>\<Gamma> \<Turnstile> t1 : T1\<rightarrow>T2 \<and> \<Gamma> \<Turnstile> t2 : T1\<rbrakk> \<Longrightarrow> \<Gamma> \<Turnstile> App t1 t2 : T2" |
135 (HOL_basic_ss addsimps inductive_atomize); |
135 | t'_Lam[intro]: "\<lbrakk>atom x\<sharp>\<Gamma>;(x,T1)#\<Gamma> \<Turnstile> t : T2\<rbrakk> \<Longrightarrow> \<Gamma> \<Turnstile> Lam x t : T1\<rightarrow>T2" |
136 val atomize_intr = Conv.fconv_rule (Conv.prems_conv ~1 atomize_conv); |
136 |
137 fun atomize_induct ctxt = Conv.fconv_rule (Conv.prems_conv ~1 |
137 inductive |
138 (Conv.params_conv ~1 (K (Conv.prems_conv ~1 atomize_conv)) ctxt)); |
138 typing2' :: "(name\<times>ty) list\<Rightarrow>lam\<Rightarrow>ty\<Rightarrow>bool" ("_ 2\<Turnstile> _ : _" [60,60,60] 60) |
139 *} |
139 where |
140 |
140 t2'_Var[intro]: "\<lbrakk>valid \<Gamma>; (x,T)\<in>set \<Gamma>\<rbrakk> \<Longrightarrow> \<Gamma> 2\<Turnstile> Var x : T" |
141 ML {* |
141 | t2'_App[intro]: "\<lbrakk>\<Gamma> 2\<Turnstile> t1 : T1\<rightarrow>T2 \<or> \<Gamma> 2\<Turnstile> t2 : T1\<rbrakk> \<Longrightarrow> \<Gamma> 2\<Turnstile> App t1 t2 : T2" |
142 fun map_term f t = |
142 | t2'_Lam[intro]: "\<lbrakk>atom x\<sharp>\<Gamma>;(x,T1)#\<Gamma> 2\<Turnstile> t : T2\<rbrakk> \<Longrightarrow> \<Gamma> 2\<Turnstile> Lam x t : T1\<rightarrow>T2" |
143 (case f t of |
143 |
144 NONE => map_term' f t |
144 inductive |
145 | x => x) |
145 typing'' :: "(name\<times>ty) list\<Rightarrow>lam\<Rightarrow>ty\<Rightarrow>bool" ("_ |\<Turnstile> _ : _" [60,60,60] 60) |
146 and map_term' f (t $ u) = |
146 and valid' :: "(name\<times>ty) list \<Rightarrow> bool" |
147 (case (map_term f t, map_term f u) of |
147 where |
148 (NONE, NONE) => NONE |
148 v1[intro]: "valid' []" |
149 | (SOME t'', NONE) => SOME (t'' $ u) |
149 | v2[intro]: "\<lbrakk>valid' \<Gamma>;atom x\<sharp>\<Gamma>\<rbrakk>\<Longrightarrow> valid' ((x,T)#\<Gamma>)" |
150 | (NONE, SOME u'') => SOME (t $ u'') |
150 | t'_Var[intro]: "\<lbrakk>valid' \<Gamma>; (x,T)\<in>set \<Gamma>\<rbrakk> \<Longrightarrow> \<Gamma> |\<Turnstile> Var x : T" |
151 | (SOME t'', SOME u'') => SOME (t'' $ u'')) |
151 | t'_App[intro]: "\<lbrakk>\<Gamma> |\<Turnstile> t1 : T1\<rightarrow>T2; \<Gamma> |\<Turnstile> t2 : T1\<rbrakk> \<Longrightarrow> \<Gamma> |\<Turnstile> App t1 t2 : T2" |
152 | map_term' f (Abs (s, T, t)) = |
152 | t'_Lam[intro]: "\<lbrakk>atom x\<sharp>\<Gamma>;(x,T1)#\<Gamma> |\<Turnstile> t : T2\<rbrakk> \<Longrightarrow> \<Gamma> |\<Turnstile> Lam x t : T1\<rightarrow>T2" |
153 (case map_term f t of |
153 |
154 NONE => NONE |
154 use "../../Nominal-General/nominal_eqvt.ML" |
155 | SOME t'' => SOME (Abs (s, T, t''))) |
|
156 | map_term' _ _ = NONE; |
|
157 |
|
158 fun map_thm_tac ctxt tac thm = |
|
159 let |
|
160 val monos = Inductive.get_monos ctxt |
|
161 in |
|
162 EVERY [cut_facts_tac [thm] 1, etac rev_mp 1, |
|
163 REPEAT_DETERM (FIRSTGOAL (resolve_tac monos)), |
|
164 REPEAT_DETERM (rtac impI 1 THEN (atac 1 ORELSE tac))] |
|
165 end |
|
166 |
|
167 (* |
|
168 proves F[f t] from F[t] where F[t] is the given theorem |
|
169 |
|
170 - F needs to be monotone |
|
171 - f returns either SOME for a term it fires |
|
172 and NONE elsewhere |
|
173 *) |
|
174 fun map_thm ctxt f tac thm = |
|
175 let |
|
176 val opt_goal_trm = map_term f (prop_of thm) |
|
177 fun prove goal = |
|
178 Goal.prove ctxt [] [] goal (fn _ => map_thm_tac ctxt tac thm) |
|
179 in |
|
180 case opt_goal_trm of |
|
181 NONE => thm |
|
182 | SOME goal => prove goal |
|
183 end |
|
184 |
|
185 fun transform_prem ctxt names thm = |
|
186 let |
|
187 fun split_conj names (Const ("op &", _) $ p $ q) = |
|
188 (case head_of p of |
|
189 Const (name, _) => if name mem names then SOME q else NONE |
|
190 | _ => NONE) |
|
191 | split_conj _ _ = NONE; |
|
192 in |
|
193 map_thm ctxt (split_conj names) (etac conjunct2 1) thm |
|
194 end |
|
195 *} |
|
196 |
|
197 ML {* |
|
198 open Nominal_Permeq |
|
199 open Nominal_ThmDecls |
|
200 *} |
|
201 |
|
202 ML {* |
|
203 fun mk_perm p trm = |
|
204 let |
|
205 val ty = fastype_of trm |
|
206 in |
|
207 Const (@{const_name "permute"}, @{typ "perm"} --> ty --> ty) $ p $ trm |
|
208 end |
|
209 |
|
210 fun mk_minus p = |
|
211 Const (@{const_name "uminus"}, @{typ "perm => perm"}) $ p |
|
212 *} |
|
213 |
|
214 ML {* |
|
215 fun single_case_tac ctxt pred_names pi intro = |
|
216 let |
|
217 val thy = ProofContext.theory_of ctxt |
|
218 val cpi = Thm.cterm_of thy (mk_minus pi) |
|
219 val rule = Drule.instantiate' [] [SOME cpi] @{thm permute_boolE} |
|
220 in |
|
221 eqvt_strict_tac ctxt [] [] THEN' |
|
222 SUBPROOF (fn {prems, context as ctxt, ...} => |
|
223 let |
|
224 val prems' = map (transform_prem ctxt pred_names) prems |
|
225 val side_cond_tac = EVERY' |
|
226 [ rtac rule, |
|
227 eqvt_strict_tac ctxt @{thms permute_minus_cancel(2)} [], |
|
228 resolve_tac prems' ] |
|
229 in |
|
230 HEADGOAL (rtac intro THEN_ALL_NEW (resolve_tac prems' ORELSE' side_cond_tac)) |
|
231 end) ctxt |
|
232 end |
|
233 *} |
|
234 |
|
235 ML {* |
|
236 fun prepare_pred params_no pi pred = |
|
237 let |
|
238 val (c, xs) = strip_comb pred; |
|
239 val (xs1, xs2) = chop params_no xs |
|
240 in |
|
241 HOLogic.mk_imp |
|
242 (pred, list_comb (c, xs1 @ map (mk_perm pi) xs2)) |
|
243 end |
|
244 *} |
|
245 |
|
246 ML {* |
|
247 fun transp ([] :: _) = [] |
|
248 | transp xs = map hd xs :: transp (map tl xs); |
|
249 *} |
|
250 |
|
251 ML {* |
|
252 Local_Theory.note; |
|
253 Local_Theory.notes; |
|
254 fold_map |
|
255 *} |
|
256 |
|
257 ML {* |
|
258 fun note_named_thm (name, thm) ctxt = |
|
259 let |
|
260 val thm_name = Binding.qualified_name |
|
261 (Long_Name.qualify (Long_Name.base_name name) "eqvt") |
|
262 val attr = Attrib.internal (K eqvt_add) |
|
263 in |
|
264 Local_Theory.note ((thm_name, [attr]), [thm]) ctxt |
|
265 end |
|
266 *} |
|
267 |
|
268 ML {* |
|
269 fun eqvt_rel_tac pred_name ctxt = |
|
270 let |
|
271 val thy = ProofContext.theory_of ctxt |
|
272 val ({names, ...}, {raw_induct, intrs, ...}) = |
|
273 Inductive.the_inductive ctxt (Sign.intern_const thy pred_name) |
|
274 val raw_induct = atomize_induct ctxt raw_induct; |
|
275 val intros = map atomize_intr intrs; |
|
276 val params_no = length (Inductive.params_of raw_induct) |
|
277 val (([raw_concl], [raw_pi]), ctxt') = |
|
278 ctxt |> Variable.import_terms false [concl_of raw_induct] |
|
279 ||>> Variable.variant_fixes ["pi"] |
|
280 val pi = Free (raw_pi, @{typ perm}) |
|
281 val preds = map (fst o HOLogic.dest_imp) |
|
282 (HOLogic.dest_conj (HOLogic.dest_Trueprop raw_concl)); |
|
283 val goal = HOLogic.mk_Trueprop |
|
284 (foldr1 HOLogic.mk_conj (map (prepare_pred params_no pi) preds)) |
|
285 val thm = Goal.prove ctxt' [] [] goal (fn {context,...} => |
|
286 HEADGOAL (EVERY' (rtac raw_induct :: map (single_case_tac context names pi) intros))) |
|
287 |> singleton (ProofContext.export ctxt' ctxt) |
|
288 val thms = map (fn th => zero_var_indexes (th RS mp)) (Datatype_Aux.split_conj_thm thm) |
|
289 in |
|
290 ctxt |> fold_map note_named_thm (names ~~ thms) |
|
291 |> snd |
|
292 end |
|
293 *} |
|
294 |
|
295 |
|
296 ML {* |
|
297 local structure P = OuterParse and K = OuterKeyword in |
|
298 |
|
299 val _ = |
|
300 OuterSyntax.local_theory "equivariance" |
|
301 "prove equivariance for inductive predicate involving nominal datatypes" K.thy_decl |
|
302 (P.xname >> eqvt_rel_tac); |
|
303 |
|
304 end; |
|
305 *} |
|
306 |
155 |
307 equivariance valid |
156 equivariance valid |
308 equivariance typing |
157 equivariance typing |
309 |
158 |
310 thm valid.eqvt |
159 thm valid.eqvt |
311 thm typing.eqvt |
160 thm typing.eqvt |
312 thm eqvts |
161 thm eqvts |
313 thm eqvts_raw |
162 thm eqvts_raw |
|
163 |
|
164 equivariance typing' |
|
165 equivariance typing2' |
|
166 equivariance typing'' |
|
167 |
|
168 ML {* |
|
169 fun mk_minus p = |
|
170 Const (@{const_name "uminus"}, @{typ "perm => perm"}) $ p |
|
171 *} |
|
172 |
|
173 inductive |
|
174 tt :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> 'a \<Rightarrow> bool)" |
|
175 for r :: "('a \<Rightarrow> 'a \<Rightarrow> bool)" |
|
176 where |
|
177 "tt r a b" |
|
178 | "tt r a b ==> tt r a c" |
|
179 |
|
180 (* |
|
181 equivariance tt |
|
182 *) |
314 |
183 |
315 |
184 |
316 inductive |
185 inductive |
317 alpha_lam_raw' |
186 alpha_lam_raw' |
318 where |
187 where |