src/HOL/Nominal/nominal_inductive.ML
changeset 59582 0fbed69ff081
parent 59498 50b60f501b05
child 59586 ddf6deaadfe8
equal deleted inserted replaced
59580:cbc38731d42f 59582:0fbed69ff081
    32 val fresh_prod = @{thm fresh_prod};
    32 val fresh_prod = @{thm fresh_prod};
    33 
    33 
    34 val perm_bool = mk_meta_eq @{thm perm_bool_def};
    34 val perm_bool = mk_meta_eq @{thm perm_bool_def};
    35 val perm_boolI = @{thm perm_boolI};
    35 val perm_boolI = @{thm perm_boolI};
    36 val (_, [perm_boolI_pi, _]) = Drule.strip_comb (snd (Thm.dest_comb
    36 val (_, [perm_boolI_pi, _]) = Drule.strip_comb (snd (Thm.dest_comb
    37   (Drule.strip_imp_concl (cprop_of perm_boolI))));
    37   (Drule.strip_imp_concl (Thm.cprop_of perm_boolI))));
    38 
    38 
    39 fun mk_perm_bool pi th = th RS Drule.cterm_instantiate
    39 fun mk_perm_bool pi th = th RS Drule.cterm_instantiate
    40   [(perm_boolI_pi, pi)] perm_boolI;
    40   [(perm_boolI_pi, pi)] perm_boolI;
    41 
    41 
    42 fun mk_perm_bool_simproc names = Simplifier.simproc_global_i
    42 fun mk_perm_bool_simproc names = Simplifier.simproc_global_i
    43   (theory_of_thm perm_bool) "perm_bool" [@{term "perm pi x"}] (fn ctxt =>
    43   (Thm.theory_of_thm perm_bool) "perm_bool" [@{term "perm pi x"}] (fn ctxt =>
    44     fn Const (@{const_name Nominal.perm}, _) $ _ $ t =>
    44     fn Const (@{const_name Nominal.perm}, _) $ _ $ t =>
    45          if member (op =) names (the_default "" (try (head_of #> dest_Const #> fst) t))
    45          if member (op =) names (the_default "" (try (head_of #> dest_Const #> fst) t))
    46          then SOME perm_bool else NONE
    46          then SOME perm_bool else NONE
    47      | _ => NONE);
    47      | _ => NONE);
    48 
    48 
   124 (*         Prove  F[f t]  from  F[t],  where F is monotone           *)
   124 (*         Prove  F[f t]  from  F[t],  where F is monotone           *)
   125 (*********************************************************************)
   125 (*********************************************************************)
   126 
   126 
   127 fun map_thm ctxt f tac monos opt th =
   127 fun map_thm ctxt f tac monos opt th =
   128   let
   128   let
   129     val prop = prop_of th;
   129     val prop = Thm.prop_of th;
   130     fun prove t =
   130     fun prove t =
   131       Goal.prove ctxt [] [] t (fn _ =>
   131       Goal.prove ctxt [] [] t (fn _ =>
   132         EVERY [cut_facts_tac [th] 1, etac rev_mp 1,
   132         EVERY [cut_facts_tac [th] 1, etac rev_mp 1,
   133           REPEAT_DETERM (FIRSTGOAL (resolve_tac ctxt monos)),
   133           REPEAT_DETERM (FIRSTGOAL (resolve_tac ctxt monos)),
   134           REPEAT_DETERM (rtac impI 1 THEN (atac 1 ORELSE tac))])
   134           REPEAT_DETERM (rtac impI 1 THEN (atac 1 ORELSE tac))])
   139 fun first_order_matchs pats objs = Thm.first_order_match
   139 fun first_order_matchs pats objs = Thm.first_order_match
   140   (eta_contract_cterm (Conjunction.mk_conjunction_balanced pats),
   140   (eta_contract_cterm (Conjunction.mk_conjunction_balanced pats),
   141    eta_contract_cterm (Conjunction.mk_conjunction_balanced objs));
   141    eta_contract_cterm (Conjunction.mk_conjunction_balanced objs));
   142 
   142 
   143 fun first_order_mrs ths th = ths MRS
   143 fun first_order_mrs ths th = ths MRS
   144   Thm.instantiate (first_order_matchs (cprems_of th) (map cprop_of ths)) th;
   144   Thm.instantiate (first_order_matchs (cprems_of th) (map Thm.cprop_of ths)) th;
   145 
   145 
   146 fun prove_strong_ind s avoids ctxt =
   146 fun prove_strong_ind s avoids ctxt =
   147   let
   147   let
   148     val thy = Proof_Context.theory_of ctxt;
   148     val thy = Proof_Context.theory_of ctxt;
   149     val ({names, ...}, {raw_induct, intrs, elims, ...}) =
   149     val ({names, ...}, {raw_induct, intrs, elims, ...}) =
   157         [] => ()
   157         [] => ()
   158       | xs => error ("Missing equivariance theorem for predicate(s): " ^
   158       | xs => error ("Missing equivariance theorem for predicate(s): " ^
   159           commas_quote xs));
   159           commas_quote xs));
   160     val induct_cases = map (fst o fst) (fst (Rule_Cases.get (the
   160     val induct_cases = map (fst o fst) (fst (Rule_Cases.get (the
   161       (Induct.lookup_inductP ctxt (hd names)))));
   161       (Induct.lookup_inductP ctxt (hd names)))));
   162     val ([raw_induct'], ctxt') = Variable.import_terms false [prop_of raw_induct] ctxt;
   162     val ([raw_induct'], ctxt') = Variable.import_terms false [Thm.prop_of raw_induct] ctxt;
   163     val concls = raw_induct' |> Logic.strip_imp_concl |> HOLogic.dest_Trueprop |>
   163     val concls = raw_induct' |> Logic.strip_imp_concl |> HOLogic.dest_Trueprop |>
   164       HOLogic.dest_conj |> map (HOLogic.dest_imp ##> strip_comb);
   164       HOLogic.dest_conj |> map (HOLogic.dest_imp ##> strip_comb);
   165     val ps = map (fst o snd) concls;
   165     val ps = map (fst o snd) concls;
   166 
   166 
   167     val _ = (case duplicates (op = o apply2 fst) avoids of
   167     val _ = (case duplicates (op = o apply2 fst) avoids of
   202     val (fs_ctxt_tyname, _) = Name.variant "'n" (Variable.names_of ctxt');
   202     val (fs_ctxt_tyname, _) = Name.variant "'n" (Variable.names_of ctxt');
   203     val ([fs_ctxt_name], ctxt'') = Variable.variant_fixes ["z"] ctxt';
   203     val ([fs_ctxt_name], ctxt'') = Variable.variant_fixes ["z"] ctxt';
   204     val fsT = TFree (fs_ctxt_tyname, ind_sort);
   204     val fsT = TFree (fs_ctxt_tyname, ind_sort);
   205 
   205 
   206     val inductive_forall_def' = Drule.instantiate'
   206     val inductive_forall_def' = Drule.instantiate'
   207       [SOME (ctyp_of thy fsT)] [] inductive_forall_def;
   207       [SOME (Thm.ctyp_of thy fsT)] [] inductive_forall_def;
   208 
   208 
   209     fun lift_pred' t (Free (s, T)) ts =
   209     fun lift_pred' t (Free (s, T)) ts =
   210       list_comb (Free (s, fsT --> T), t :: ts);
   210       list_comb (Free (s, fsT --> T), t :: ts);
   211     val lift_pred = lift_pred' (Bound 0);
   211     val lift_pred = lift_pred' (Bound 0);
   212 
   212 
   303             [etac exE 1,
   303             [etac exE 1,
   304              full_simp_tac (put_simpset HOL_ss ctxt' addsimps (fresh_prod :: fresh_atm)) 1,
   304              full_simp_tac (put_simpset HOL_ss ctxt' addsimps (fresh_prod :: fresh_atm)) 1,
   305              full_simp_tac (put_simpset HOL_basic_ss ctxt' addsimps [@{thm id_apply}]) 1,
   305              full_simp_tac (put_simpset HOL_basic_ss ctxt' addsimps [@{thm id_apply}]) 1,
   306              REPEAT (etac conjE 1)])
   306              REPEAT (etac conjE 1)])
   307           [ex] ctxt
   307           [ex] ctxt
   308       in (freshs1 @ [term_of cx], freshs2 @ ths, ctxt') end;
   308       in (freshs1 @ [Thm.term_of cx], freshs2 @ ths, ctxt') end;
   309 
   309 
   310     fun mk_ind_proof ctxt' thss =
   310     fun mk_ind_proof ctxt' thss =
   311       Goal.prove ctxt' [] prems' concl' (fn {prems = ihyps, context = ctxt} =>
   311       Goal.prove ctxt' [] prems' concl' (fn {prems = ihyps, context = ctxt} =>
   312         let val th = Goal.prove ctxt [] [] concl (fn {context, ...} =>
   312         let val th = Goal.prove ctxt [] [] concl (fn {context, ...} =>
   313           rtac raw_induct 1 THEN
   313           rtac raw_induct 1 THEN
   314           EVERY (maps (fn ((((_, bvars, oprems, _), vc_compat_ths), ihyp), (vs, ihypt)) =>
   314           EVERY (maps (fn ((((_, bvars, oprems, _), vc_compat_ths), ihyp), (vs, ihypt)) =>
   315             [REPEAT (rtac allI 1), simp_tac (put_simpset eqvt_ss context) 1,
   315             [REPEAT (rtac allI 1), simp_tac (put_simpset eqvt_ss context) 1,
   316              SUBPROOF (fn {prems = gprems, params, concl, context = ctxt', ...} =>
   316              SUBPROOF (fn {prems = gprems, params, concl, context = ctxt', ...} =>
   317                let
   317                let
   318                  val (params', (pis, z)) =
   318                  val (params', (pis, z)) =
   319                    chop (length params - length atomTs - 1) (map (term_of o #2) params) ||>
   319                    chop (length params - length atomTs - 1) (map (Thm.term_of o #2) params) ||>
   320                    split_last;
   320                    split_last;
   321                  val bvars' = map
   321                  val bvars' = map
   322                    (fn (Bound i, T) => (nth params' (length params' - i), T)
   322                    (fn (Bound i, T) => (nth params' (length params' - i), T)
   323                      | (t, T) => (t, T)) bvars;
   323                      | (t, T) => (t, T)) bvars;
   324                  val pi_bvars = map (fn (t, _) =>
   324                  val pi_bvars = map (fn (t, _) =>
   325                    fold_rev (NominalDatatype.mk_perm []) pis t) bvars';
   325                    fold_rev (NominalDatatype.mk_perm []) pis t) bvars';
   326                  val (P, ts) = strip_comb (HOLogic.dest_Trueprop (term_of concl));
   326                  val (P, ts) = strip_comb (HOLogic.dest_Trueprop (Thm.term_of concl));
   327                  val (freshs1, freshs2, ctxt'') = fold
   327                  val (freshs1, freshs2, ctxt'') = fold
   328                    (obtain_fresh_name (ts @ pi_bvars))
   328                    (obtain_fresh_name (ts @ pi_bvars))
   329                    (map snd bvars') ([], [], ctxt');
   329                    (map snd bvars') ([], [], ctxt');
   330                  val freshs2' = NominalDatatype.mk_not_sym freshs2;
   330                  val freshs2' = NominalDatatype.mk_not_sym freshs2;
   331                  val pis' = map NominalDatatype.perm_of_pair (pi_bvars ~~ freshs1);
   331                  val pis' = map NominalDatatype.perm_of_pair (pi_bvars ~~ freshs1);
   334                    in if T = fastype_of pi2 then
   334                    in if T = fastype_of pi2 then
   335                        Const (@{const_name append}, T --> T --> T) $ pi1 $ pi2
   335                        Const (@{const_name append}, T --> T --> T) $ pi1 $ pi2
   336                      else pi2
   336                      else pi2
   337                    end;
   337                    end;
   338                  val pis'' = fold (concat_perm #> map) pis' pis;
   338                  val pis'' = fold (concat_perm #> map) pis' pis;
   339                  val env = Pattern.first_order_match thy (ihypt, prop_of ihyp)
   339                  val env = Pattern.first_order_match thy (ihypt, Thm.prop_of ihyp)
   340                    (Vartab.empty, Vartab.empty);
   340                    (Vartab.empty, Vartab.empty);
   341                  val ihyp' = Thm.instantiate ([], map (apply2 (cterm_of thy))
   341                  val ihyp' = Thm.instantiate ([], map (apply2 (Thm.cterm_of thy))
   342                    (map (Envir.subst_term env) vs ~~
   342                    (map (Envir.subst_term env) vs ~~
   343                     map (fold_rev (NominalDatatype.mk_perm [])
   343                     map (fold_rev (NominalDatatype.mk_perm [])
   344                       (rev pis' @ pis)) params' @ [z])) ihyp;
   344                       (rev pis' @ pis)) params' @ [z])) ihyp;
   345                  fun mk_pi th =
   345                  fun mk_pi th =
   346                    Simplifier.simplify (put_simpset HOL_basic_ss ctxt' addsimps [@{thm id_apply}]
   346                    Simplifier.simplify (put_simpset HOL_basic_ss ctxt' addsimps [@{thm id_apply}]
   347                        addsimprocs [NominalDatatype.perm_simproc])
   347                        addsimprocs [NominalDatatype.perm_simproc])
   348                      (Simplifier.simplify (put_simpset eqvt_ss ctxt')
   348                      (Simplifier.simplify (put_simpset eqvt_ss ctxt')
   349                        (fold_rev (mk_perm_bool o cterm_of thy)
   349                        (fold_rev (mk_perm_bool o Thm.cterm_of thy)
   350                          (rev pis' @ pis) th));
   350                          (rev pis' @ pis) th));
   351                  val (gprems1, gprems2) = split_list
   351                  val (gprems1, gprems2) = split_list
   352                    (map (fn (th, t) =>
   352                    (map (fn (th, t) =>
   353                       if null (preds_of ps t) then (SOME th, mk_pi th)
   353                       if null (preds_of ps t) then (SOME th, mk_pi th)
   354                       else
   354                       else
   358                            (inst_conj_all_tac ctxt' (length pis'')) monos (SOME t) th))))
   358                            (inst_conj_all_tac ctxt' (length pis'')) monos (SOME t) th))))
   359                       (gprems ~~ oprems)) |>> map_filter I;
   359                       (gprems ~~ oprems)) |>> map_filter I;
   360                  val vc_compat_ths' = map (fn th =>
   360                  val vc_compat_ths' = map (fn th =>
   361                    let
   361                    let
   362                      val th' = first_order_mrs gprems1 th;
   362                      val th' = first_order_mrs gprems1 th;
   363                      val (bop, lhs, rhs) = (case concl_of th' of
   363                      val (bop, lhs, rhs) = (case Thm.concl_of th' of
   364                          _ $ (fresh $ lhs $ rhs) =>
   364                          _ $ (fresh $ lhs $ rhs) =>
   365                            (fn t => fn u => fresh $ t $ u, lhs, rhs)
   365                            (fn t => fn u => fresh $ t $ u, lhs, rhs)
   366                        | _ $ (_ $ (_ $ lhs $ rhs)) =>
   366                        | _ $ (_ $ (_ $ lhs $ rhs)) =>
   367                            (curry (HOLogic.mk_not o HOLogic.mk_eq), lhs, rhs));
   367                            (curry (HOLogic.mk_not o HOLogic.mk_eq), lhs, rhs));
   368                      val th'' = Goal.prove ctxt'' [] [] (HOLogic.mk_Trueprop
   368                      val th'' = Goal.prove ctxt'' [] [] (HOLogic.mk_Trueprop
   380                       (vc_compat_ths'' @ freshs2');
   380                       (vc_compat_ths'' @ freshs2');
   381                  val th = Goal.prove ctxt'' [] []
   381                  val th = Goal.prove ctxt'' [] []
   382                    (HOLogic.mk_Trueprop (list_comb (P $ hd ts,
   382                    (HOLogic.mk_Trueprop (list_comb (P $ hd ts,
   383                      map (fold (NominalDatatype.mk_perm []) pis') (tl ts))))
   383                      map (fold (NominalDatatype.mk_perm []) pis') (tl ts))))
   384                    (fn _ => EVERY ([simp_tac (put_simpset eqvt_ss ctxt'') 1, rtac ihyp' 1,
   384                    (fn _ => EVERY ([simp_tac (put_simpset eqvt_ss ctxt'') 1, rtac ihyp' 1,
   385                      REPEAT_DETERM_N (nprems_of ihyp - length gprems)
   385                      REPEAT_DETERM_N (Thm.nprems_of ihyp - length gprems)
   386                        (simp_tac swap_simps_simpset 1),
   386                        (simp_tac swap_simps_simpset 1),
   387                      REPEAT_DETERM_N (length gprems)
   387                      REPEAT_DETERM_N (length gprems)
   388                        (simp_tac (put_simpset HOL_basic_ss ctxt''
   388                        (simp_tac (put_simpset HOL_basic_ss ctxt''
   389                           addsimps [inductive_forall_def']
   389                           addsimps [inductive_forall_def']
   390                           addsimprocs [NominalDatatype.perm_simproc]) 1 THEN
   390                           addsimprocs [NominalDatatype.perm_simproc]) 1 THEN
   391                         resolve_tac ctxt'' gprems2 1)]));
   391                         resolve_tac ctxt'' gprems2 1)]));
   392                  val final = Goal.prove ctxt'' [] [] (term_of concl)
   392                  val final = Goal.prove ctxt'' [] [] (Thm.term_of concl)
   393                    (fn _ => cut_facts_tac [th] 1 THEN full_simp_tac (put_simpset HOL_ss ctxt''
   393                    (fn _ => cut_facts_tac [th] 1 THEN full_simp_tac (put_simpset HOL_ss ctxt''
   394                      addsimps vc_compat_ths'' @ freshs2' @
   394                      addsimps vc_compat_ths'' @ freshs2' @
   395                        perm_fresh_fresh @ fresh_atm) 1);
   395                        perm_fresh_fresh @ fresh_atm) 1);
   396                  val final' = Proof_Context.export ctxt'' ctxt' [final];
   396                  val final' = Proof_Context.export ctxt'' ctxt' [final];
   397                in resolve_tac ctxt' final' 1 end) context 1])
   397                in resolve_tac ctxt' final' 1 end) context 1])
   405 
   405 
   406     (** strong case analysis rule **)
   406     (** strong case analysis rule **)
   407 
   407 
   408     val cases_prems = map (fn ((name, avoids), rule) =>
   408     val cases_prems = map (fn ((name, avoids), rule) =>
   409       let
   409       let
   410         val ([rule'], ctxt') = Variable.import_terms false [prop_of rule] ctxt;
   410         val ([rule'], ctxt') = Variable.import_terms false [Thm.prop_of rule] ctxt;
   411         val prem :: prems = Logic.strip_imp_prems rule';
   411         val prem :: prems = Logic.strip_imp_prems rule';
   412         val concl = Logic.strip_imp_concl rule'
   412         val concl = Logic.strip_imp_concl rule'
   413       in
   413       in
   414         (prem,
   414         (prem,
   415          List.drop (snd (strip_comb (HOLogic.dest_Trueprop prem)), length ind_params),
   415          List.drop (snd (strip_comb (HOLogic.dest_Trueprop prem)), length ind_params),
   470             SUBPROOF (fn {prems = case_hyps, params, context = ctxt2, concl, ...} =>
   470             SUBPROOF (fn {prems = case_hyps, params, context = ctxt2, concl, ...} =>
   471               if null qs then
   471               if null qs then
   472                 rtac (first_order_mrs case_hyps case_hyp) 1
   472                 rtac (first_order_mrs case_hyps case_hyp) 1
   473               else
   473               else
   474                 let
   474                 let
   475                   val params' = map (term_of o #2 o nth (rev params)) is;
   475                   val params' = map (Thm.term_of o #2 o nth (rev params)) is;
   476                   val tab = params' ~~ map fst qs;
   476                   val tab = params' ~~ map fst qs;
   477                   val (hyps1, hyps2) = chop (length args) case_hyps;
   477                   val (hyps1, hyps2) = chop (length args) case_hyps;
   478                   (* turns a = t and [x1 # t, ..., xn # t] *)
   478                   (* turns a = t and [x1 # t, ..., xn # t] *)
   479                   (* into [x1 # a, ..., xn # a]            *)
   479                   (* into [x1 # a, ..., xn # a]            *)
   480                   fun inst_fresh th' ths =
   480                   fun inst_fresh th' ths =
   481                     let val (ths1, ths2) = chop (length qs) ths
   481                     let val (ths1, ths2) = chop (length qs) ths
   482                     in
   482                     in
   483                       (map (fn th =>
   483                       (map (fn th =>
   484                          let
   484                          let
   485                            val (cf, ct) =
   485                            val (cf, ct) =
   486                              Thm.dest_comb (Thm.dest_arg (cprop_of th));
   486                              Thm.dest_comb (Thm.dest_arg (Thm.cprop_of th));
   487                            val arg_cong' = Drule.instantiate'
   487                            val arg_cong' = Drule.instantiate'
   488                              [SOME (ctyp_of_term ct)]
   488                              [SOME (Thm.ctyp_of_term ct)]
   489                              [NONE, SOME ct, SOME cf] (arg_cong RS iffD2);
   489                              [NONE, SOME ct, SOME cf] (arg_cong RS iffD2);
   490                            val inst = Thm.first_order_match (ct,
   490                            val inst = Thm.first_order_match (ct,
   491                              Thm.dest_arg (Thm.dest_arg (cprop_of th')))
   491                              Thm.dest_arg (Thm.dest_arg (Thm.cprop_of th')))
   492                          in [th', th] MRS Thm.instantiate inst arg_cong'
   492                          in [th', th] MRS Thm.instantiate inst arg_cong'
   493                          end) ths1,
   493                          end) ths1,
   494                        ths2)
   494                        ths2)
   495                     end;
   495                     end;
   496                   val (vc_compat_ths1, vc_compat_ths2) =
   496                   val (vc_compat_ths1, vc_compat_ths2) =
   503                     (obtain_fresh_name (args @ map fst qs @ params'))
   503                     (obtain_fresh_name (args @ map fst qs @ params'))
   504                     (map snd qs) ([], [], ctxt2);
   504                     (map snd qs) ([], [], ctxt2);
   505                   val freshs2' = NominalDatatype.mk_not_sym freshs2;
   505                   val freshs2' = NominalDatatype.mk_not_sym freshs2;
   506                   val pis = map (NominalDatatype.perm_of_pair)
   506                   val pis = map (NominalDatatype.perm_of_pair)
   507                     ((freshs1 ~~ map fst qs) @ (params' ~~ freshs1));
   507                     ((freshs1 ~~ map fst qs) @ (params' ~~ freshs1));
   508                   val mk_pis = fold_rev mk_perm_bool (map (cterm_of thy) pis);
   508                   val mk_pis = fold_rev mk_perm_bool (map (Thm.cterm_of thy) pis);
   509                   val obj = cterm_of thy (foldr1 HOLogic.mk_conj (map (map_aterms
   509                   val obj = Thm.cterm_of thy (foldr1 HOLogic.mk_conj (map (map_aterms
   510                      (fn x as Free _ =>
   510                      (fn x as Free _ =>
   511                            if member (op =) args x then x
   511                            if member (op =) args x then x
   512                            else (case AList.lookup op = tab x of
   512                            else (case AList.lookup op = tab x of
   513                              SOME y => y
   513                              SOME y => y
   514                            | NONE => fold_rev (NominalDatatype.mk_perm []) pis x)
   514                            | NONE => fold_rev (NominalDatatype.mk_perm []) pis x)
   515                        | x => x) o HOLogic.dest_Trueprop o prop_of) case_hyps));
   515                        | x => x) o HOLogic.dest_Trueprop o Thm.prop_of) case_hyps));
   516                   val inst = Thm.first_order_match (Thm.dest_arg
   516                   val inst = Thm.first_order_match (Thm.dest_arg
   517                     (Drule.strip_imp_concl (hd (cprems_of case_hyp))), obj);
   517                     (Drule.strip_imp_concl (hd (cprems_of case_hyp))), obj);
   518                   val th = Goal.prove ctxt3 [] [] (term_of concl)
   518                   val th = Goal.prove ctxt3 [] [] (Thm.term_of concl)
   519                     (fn {context = ctxt4, ...} =>
   519                     (fn {context = ctxt4, ...} =>
   520                        rtac (Thm.instantiate inst case_hyp) 1 THEN
   520                        rtac (Thm.instantiate inst case_hyp) 1 THEN
   521                        SUBPROOF (fn {prems = fresh_hyps, ...} =>
   521                        SUBPROOF (fn {prems = fresh_hyps, ...} =>
   522                          let
   522                          let
   523                            val fresh_hyps' = NominalDatatype.mk_not_sym fresh_hyps;
   523                            val fresh_hyps' = NominalDatatype.mk_not_sym fresh_hyps;
   608            | xs => error ("No such atoms: " ^ commas xs);
   608            | xs => error ("No such atoms: " ^ commas xs);
   609          atoms)
   609          atoms)
   610       end;
   610       end;
   611     val perm_pi_simp = Global_Theory.get_thms thy "perm_pi_simp";
   611     val perm_pi_simp = Global_Theory.get_thms thy "perm_pi_simp";
   612     val (([t], [pi]), ctxt') = ctxt |>
   612     val (([t], [pi]), ctxt') = ctxt |>
   613       Variable.import_terms false [concl_of raw_induct] ||>>
   613       Variable.import_terms false [Thm.concl_of raw_induct] ||>>
   614       Variable.variant_fixes ["pi"];
   614       Variable.variant_fixes ["pi"];
   615     val eqvt_simpset = put_simpset HOL_basic_ss ctxt' addsimps
   615     val eqvt_simpset = put_simpset HOL_basic_ss ctxt' addsimps
   616       (NominalThmDecls.get_eqvt_thms ctxt' @ perm_pi_simp) addsimprocs
   616       (NominalThmDecls.get_eqvt_thms ctxt' @ perm_pi_simp) addsimprocs
   617       [mk_perm_bool_simproc names,
   617       [mk_perm_bool_simproc names,
   618        NominalPermeq.perm_simproc_app, NominalPermeq.perm_simproc_fun];
   618        NominalPermeq.perm_simproc_app, NominalPermeq.perm_simproc_fun];
   619     val ps = map (fst o HOLogic.dest_imp)
   619     val ps = map (fst o HOLogic.dest_imp)
   620       (HOLogic.dest_conj (HOLogic.dest_Trueprop t));
   620       (HOLogic.dest_conj (HOLogic.dest_Trueprop t));
   621     fun eqvt_tac pi (intr, vs) st =
   621     fun eqvt_tac pi (intr, vs) st =
   622       let
   622       let
   623         fun eqvt_err s =
   623         fun eqvt_err s =
   624           let val ([t], ctxt'') = Variable.import_terms true [prop_of intr] ctxt'
   624           let val ([t], ctxt'') = Variable.import_terms true [Thm.prop_of intr] ctxt'
   625           in error ("Could not prove equivariance for introduction rule\n" ^
   625           in error ("Could not prove equivariance for introduction rule\n" ^
   626             Syntax.string_of_term ctxt'' t ^ "\n" ^ s)
   626             Syntax.string_of_term ctxt'' t ^ "\n" ^ s)
   627           end;
   627           end;
   628         val res = SUBPROOF (fn {context = ctxt'', prems, params, ...} =>
   628         val res = SUBPROOF (fn {context = ctxt'', prems, params, ...} =>
   629           let
   629           let
   630             val prems' = map (fn th => the_default th (map_thm ctxt''
   630             val prems' = map (fn th => the_default th (map_thm ctxt''
   631               (split_conj (K I) names) (etac conjunct2 1) monos NONE th)) prems;
   631               (split_conj (K I) names) (etac conjunct2 1) monos NONE th)) prems;
   632             val prems'' = map (fn th => Simplifier.simplify eqvt_simpset
   632             val prems'' = map (fn th => Simplifier.simplify eqvt_simpset
   633               (mk_perm_bool (cterm_of thy pi) th)) prems';
   633               (mk_perm_bool (Thm.cterm_of thy pi) th)) prems';
   634             val intr' = Drule.cterm_instantiate (map (cterm_of thy) vs ~~
   634             val intr' = Drule.cterm_instantiate (map (Thm.cterm_of thy) vs ~~
   635                map (cterm_of thy o NominalDatatype.mk_perm [] pi o term_of o #2) params)
   635                map (Thm.cterm_of thy o NominalDatatype.mk_perm [] pi o Thm.term_of o #2) params)
   636                intr
   636                intr
   637           in (rtac intr' THEN_ALL_NEW (TRY o resolve_tac ctxt'' prems'')) 1
   637           in (rtac intr' THEN_ALL_NEW (TRY o resolve_tac ctxt'' prems'')) 1
   638           end) ctxt' 1 st
   638           end) ctxt' 1 st
   639       in
   639       in
   640         case (Seq.pull res handle THM (s, _, _) => eqvt_err s) of
   640         case (Seq.pull res handle THM (s, _, _) => eqvt_err s) of
   641           NONE => eqvt_err ("Rule does not match goal\n" ^
   641           NONE => eqvt_err ("Rule does not match goal\n" ^
   642             Syntax.string_of_term ctxt' (hd (prems_of st)))
   642             Syntax.string_of_term ctxt' (hd (Thm.prems_of st)))
   643         | SOME (th, _) => Seq.single th
   643         | SOME (th, _) => Seq.single th
   644       end;
   644       end;
   645     val thss = map (fn atom =>
   645     val thss = map (fn atom =>
   646       let val pi' = Free (pi, NominalAtoms.mk_permT (Type (atom, [])))
   646       let val pi' = Free (pi, NominalAtoms.mk_permT (Type (atom, [])))
   647       in map (fn th => zero_var_indexes (th RS mp))
   647       in map (fn th => zero_var_indexes (th RS mp))