src/HOL/Nominal/nominal_thmdecls.ML
author wenzelm
Thu Jun 26 15:06:25 2008 +0200 (2008-06-26)
changeset 27370 8e8f96dfaf63
parent 26928 ca87aff1ad2d
child 29585 c23295521af5
permissions -rw-r--r--
Args.context;
     1 (* ID: "$Id$"
     2    Authors: Julien Narboux and Christian Urban
     3 
     4    This file introduces the infrastructure for the lemma
     5    declaration "eqvts" "bijs" and "freshs".
     6 
     7    By attaching [eqvt] [bij] or [fresh] to a lemma, the lemma gets stored
     8    in a data-slot in the context. Possible modifiers
     9    are [attribute add] and [attribute del] for adding and deleting,
    10    respectively the lemma from the data-slot.
    11 *)
    12 
    13 signature NOMINAL_THMDECLS =
    14 sig
    15   val eqvt_add: attribute
    16   val eqvt_del: attribute
    17   val eqvt_force_add: attribute
    18   val eqvt_force_del: attribute
    19   val setup: theory -> theory
    20   val get_eqvt_thms: Proof.context -> thm list
    21   val get_fresh_thms: Proof.context -> thm list
    22   val get_bij_thms: Proof.context -> thm list
    23 
    24 
    25   val NOMINAL_EQVT_DEBUG : bool ref
    26 end;
    27 
    28 structure NominalThmDecls: NOMINAL_THMDECLS =
    29 struct
    30 
    31 structure Data = GenericDataFun
    32 (
    33   type T = {eqvts:thm list, freshs:thm list, bijs:thm list};
    34   val empty = ({eqvts=[], freshs=[], bijs=[]}:T);
    35   val extend = I;
    36   fun merge _ (r1:T,r2:T) = {eqvts  = Thm.merge_thms (#eqvts r1, #eqvts r2),
    37                              freshs = Thm.merge_thms (#freshs r1, #freshs r2),
    38                              bijs   = Thm.merge_thms (#bijs r1, #bijs r2)}
    39 );
    40 
    41 (* Exception for when a theorem does not conform with form of an equivariance lemma. *)
    42 (* There are two forms: one is an implication (for relations) and the other is an    *)
    43 (* equality (for functions). In the implication-case, say P ==> Q, Q must be equal   *)
    44 (* to P except that every free variable of Q, say x, is replaced by pi o x. In the   *)
    45 (* equality case, say lhs = rhs, the lhs must be of the form pi o t and the rhs must *)
    46 (* be equal to t except that every free variable, say x, is replaced by pi o x. In   *)
    47 (* the implicational case it is also checked that the variables and permutation fit  *)
    48 (* together, i.e. are of the right "pt_class", so that a stronger version of the     *)
    49 (* equality-lemma can be derived. *)
    50 exception EQVT_FORM of string;
    51 
    52 val get_eqvt_thms = Context.Proof #> Data.get #> #eqvts;
    53 val get_fresh_thms = Context.Proof #> Data.get #> #freshs;
    54 val get_bij_thms = Context.Proof #> Data.get #> #bijs;
    55 
    56 (* FIXME: should be a function in a library *)
    57 fun mk_permT T = HOLogic.listT (HOLogic.mk_prodT (T, T));
    58 
    59 val NOMINAL_EQVT_DEBUG = ref false;
    60 
    61 fun tactic (msg,tac) =
    62     if !NOMINAL_EQVT_DEBUG
    63     then tac THEN print_tac ("after "^msg)
    64     else tac
    65 
    66 fun tactic_eqvt ctx orig_thm pi typi =
    67     let
    68         val mypi = Thm.cterm_of ctx (Var (pi,typi))
    69         val mypifree = Thm.cterm_of ctx (Const ("List.rev",typi --> typi) $ Free (fst pi,typi))
    70         val perm_pi_simp = PureThy.get_thms ctx "perm_pi_simp"
    71     in
    72         EVERY [tactic ("iffI applied",rtac iffI 1),
    73 	       tactic ("remove pi with perm_boolE", (dtac @{thm perm_boolE} 1)),
    74                tactic ("solve with orig_thm", (etac orig_thm 1)),
    75                tactic ("applies orig_thm instantiated with rev pi",
    76                           dtac (Drule.cterm_instantiate [(mypi,mypifree)] orig_thm) 1),
    77 	       tactic ("getting rid of the pi on the right",
    78                           (rtac @{thm perm_boolI} 1)),
    79                tactic ("getting rid of all remaining perms",
    80                           full_simp_tac (HOL_basic_ss addsimps perm_pi_simp) 1)]
    81     end;
    82 
    83 fun get_derived_thm thy hyp concl orig_thm pi typi =
    84    let
    85        val lhs = (Const("Nominal.perm", typi --> HOLogic.boolT --> HOLogic.boolT) $ Var(pi,typi) $ hyp)
    86        val goal_term = Logic.unvarify (HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs,concl)))
    87        val _ = Display.print_cterm (cterm_of thy goal_term)
    88    in
    89      Goal.prove_global thy [] [] goal_term (fn _ => (tactic_eqvt thy orig_thm pi typi))
    90    end
    91 
    92 (* replaces every variable x in t with pi o x *)
    93 fun apply_pi trm (pi,typi) =
    94   let
    95     fun only_vars t =
    96        (case t of
    97           Var (n,ty) => (Const ("Nominal.perm",typi --> ty --> ty) $ (Var (pi,typi)) $ (Var (n,ty)))
    98         | _ => t)
    99   in
   100      map_aterms only_vars trm
   101   end;
   102 
   103 (* returns *the* pi which is in front of all variables, provided there *)
   104 (* exists such a pi; otherwise raises EQVT_FORM                        *)
   105 fun get_pi t thy =
   106   let fun get_pi_aux s =
   107         (case s of
   108           (Const ("Nominal.perm",typrm) $
   109              (Var (pi,typi as Type("List.list",[Type ("*",[Type (tyatm,[]),_])]))) $
   110                (Var (n,ty))) =>
   111              let
   112                 (* FIXME: this should be an operation the library *)
   113                 val class_name = (NameSpace.map_base (fn s => "pt_"^s) tyatm)
   114              in
   115                 if (Sign.of_sort thy (ty,[class_name]))
   116                 then [(pi,typi)]
   117                 else raise
   118                 EQVT_FORM ("Could not find any permutation or an argument is not an instance of "^class_name)
   119              end
   120         | Abs (_,_,t1) => get_pi_aux t1
   121         | (t1 $ t2) => get_pi_aux t1 @ get_pi_aux t2
   122         | _ => [])
   123   in
   124     (* collect first all pi's in front of variables in t and then use distinct *)
   125     (* to ensure that all pi's must have been the same, i.e. distinct returns  *)
   126     (* a singleton-list  *)
   127     (case (distinct (op =) (get_pi_aux t)) of
   128       [(pi,typi)] => (pi,typi)
   129     | _ => raise EQVT_FORM "All permutation should be the same")
   130   end;
   131 
   132 (* Either adds a theorem (orig_thm) to or deletes one from the equivariance *)
   133 (* lemma list depending on flag. To be added the lemma has to satisfy a     *)
   134 (* certain form. *)
   135 
   136 fun eqvt_add_del_aux flag orig_thm context = 
   137   let
   138     val thy = Context.theory_of context
   139     val thms_to_be_added = (case (prop_of orig_thm) of
   140         (* case: eqvt-lemma is of the implicational form *)
   141         (Const("==>", _) $ (Const ("Trueprop",_) $ hyp) $ (Const ("Trueprop",_) $ concl)) =>
   142           let
   143             val (pi,typi) = get_pi concl thy
   144           in
   145              if (apply_pi hyp (pi,typi) = concl)
   146              then
   147                (warning ("equivariance lemma of the relational form");
   148                 [orig_thm, get_derived_thm thy hyp concl orig_thm pi typi])
   149              else raise EQVT_FORM "Type Implication"
   150           end
   151        (* case: eqvt-lemma is of the equational form *)
   152       | (Const ("Trueprop", _) $ (Const ("op =", _) $
   153             (Const ("Nominal.perm",typrm) $ Var (pi,typi) $ lhs) $ rhs)) =>
   154            (if (apply_pi lhs (pi,typi)) = rhs
   155                then [orig_thm]
   156                else raise EQVT_FORM "Type Equality")
   157       | _ => raise EQVT_FORM "Type unknown")
   158   in
   159       fold (fn thm => Data.map (flag thm)) thms_to_be_added context
   160   end
   161   handle EQVT_FORM s =>
   162       error (Display.string_of_thm orig_thm ^ " does not comply with the form of an equivariance lemma ("^s^").")
   163 
   164 (* in cases of bij- and freshness, we just add the lemmas to the *)
   165 (* data-slot *)
   166 
   167 fun eqvt_map f (r:Data.T)  = {eqvts = f (#eqvts r), freshs = #freshs r, bijs = #bijs r};
   168 fun fresh_map f (r:Data.T) = {eqvts = #eqvts r, freshs = f (#freshs r), bijs = #bijs r};
   169 fun bij_map f (r:Data.T)   = {eqvts = #eqvts r, freshs = #freshs r, bijs = f (#bijs r)};
   170 
   171 val eqvt_add = Thm.declaration_attribute (eqvt_add_del_aux (eqvt_map o Thm.add_thm));
   172 val eqvt_del = Thm.declaration_attribute (eqvt_add_del_aux (eqvt_map o Thm.del_thm));
   173 
   174 val eqvt_force_add  = Thm.declaration_attribute (Data.map o eqvt_map o Thm.add_thm);
   175 val eqvt_force_del  = Thm.declaration_attribute (Data.map o eqvt_map o Thm.del_thm);
   176 val bij_add   = Thm.declaration_attribute (Data.map o bij_map o Thm.add_thm);
   177 val bij_del   = Thm.declaration_attribute (Data.map o bij_map o Thm.del_thm);
   178 val fresh_add = Thm.declaration_attribute (Data.map o fresh_map o Thm.add_thm);
   179 val fresh_del = Thm.declaration_attribute (Data.map o fresh_map o Thm.del_thm);
   180 
   181 
   182 
   183 val setup =
   184   Attrib.add_attributes
   185      [("eqvt",  Attrib.add_del_args eqvt_add eqvt_del,   "equivariance theorem declaration"),
   186       ("eqvt_force", Attrib.add_del_args eqvt_force_add eqvt_force_del,
   187         "equivariance theorem declaration (without checking the form of the lemma)"),
   188       ("fresh", Attrib.add_del_args fresh_add fresh_del, "freshness theorem declaration"),
   189       ("bij",   Attrib.add_del_args bij_add bij_del,     "bijection theorem declaration")] #>
   190   PureThy.add_thms_dynamic ("eqvts", #eqvts o Data.get) #>
   191   PureThy.add_thms_dynamic ("freshs", #freshs o Data.get) #>
   192   PureThy.add_thms_dynamic ("bijs", #bijs o Data.get);
   193 
   194 end;