Nominal-General/nominal_eqvt.ML
changeset 1833 2050b5723c04
child 1835 636de31888a6
equal deleted inserted replaced
1832:4650d428b1b5 1833:2050b5723c04
       
     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 *)