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