src/HOL/Tools/Transfer/transfer_bnf.ML
author kuncar
Thu, 10 Apr 2014 17:48:18 +0200
changeset 57866 f4ba736040fa
child 57880 7c3b6b799b94
permissions -rw-r--r--
setup for Transfer and Lifting from BNF; tuned thm names
     1 (*  Title:      HOL/Tools/Transfer/transfer_bnf.ML
     2     Author:     Ondrej Kuncar, TU Muenchen
     3 
     4 Setup for Transfer for types that are BNF.
     5 *)
     6 
     7 signature TRANSFER_BNF =
     8 sig
     9   val base_name_of_bnf: BNF_Def.bnf -> binding
    10   val type_name_of_bnf: BNF_Def.bnf -> string
    11   val lookup_defined_pred_data: Proof.context -> string -> Transfer.pred_data
    12   val map_local_theory: (local_theory -> local_theory) -> theory -> theory
    13   val bnf_only_type_ctr: (BNF_Def.bnf -> 'a -> 'a) -> BNF_Def.bnf -> 'a -> 'a
    14 end
    15 
    16 structure Transfer_BNF : TRANSFER_BNF =
    17 struct
    18 
    19 open BNF_Util
    20 open BNF_Def
    21 open BNF_FP_Def_Sugar
    22 
    23 (* util functions *)
    24 
    25 fun base_name_of_bnf bnf = Binding.name (Binding.name_of (name_of_bnf bnf))
    26 fun mk_Frees_free x Ts ctxt = Variable.variant_frees ctxt [] (mk_names (length Ts) x ~~ Ts) |> map Free
    27 
    28 fun mk_Domainp P =
    29   let
    30     val PT = fastype_of P
    31     val argT = hd (binder_types PT)
    32   in
    33     Const (@{const_name Domainp}, PT --> argT --> HOLogic.boolT) $ P
    34   end
    35 
    36 fun mk_pred pred_def args T =
    37   let
    38     val pred_name = pred_def |> prop_of |> HOLogic.dest_Trueprop |> fst o HOLogic.dest_eq 
    39       |> head_of |> fst o dest_Const
    40     val argsT = map fastype_of args
    41   in
    42     list_comb (Const (pred_name, argsT ---> (T --> HOLogic.boolT)), args)
    43   end
    44 
    45 fun mk_eq_onp arg = 
    46   let
    47     val argT = domain_type (fastype_of arg)
    48   in
    49     Const (@{const_name eq_onp}, (argT --> HOLogic.boolT) --> argT --> argT --> HOLogic.boolT)
    50       $ arg
    51   end
    52 
    53 fun subst_conv thm =
    54   Conv.top_sweep_conv (K (Conv.rewr_conv (safe_mk_meta_eq thm))) @{context}
    55 
    56 fun type_name_of_bnf bnf = T_of_bnf bnf |> dest_Type |> fst
    57 
    58 fun is_Type (Type _) = true
    59   | is_Type _ = false
    60 
    61 fun map_local_theory f = Named_Target.theory_init #> f #> Local_Theory.exit_global
    62 
    63 fun bnf_only_type_ctr f bnf = if is_Type (T_of_bnf bnf) then f bnf else I
    64 
    65 fun bnf_of_fp_sugar (fp_sugar:fp_sugar) = nth (#bnfs (#fp_res fp_sugar)) (#fp_res_index fp_sugar)
    66 
    67 fun fp_sugar_only_type_ctr f fp_sugar = 
    68   if is_Type (T_of_bnf (bnf_of_fp_sugar fp_sugar)) then f fp_sugar else I
    69 
    70 (* relation constraints - bi_total & co. *)
    71 
    72 fun mk_relation_constraint name arg =
    73   (Const (name, fastype_of arg --> HOLogic.boolT)) $ arg
    74 
    75 fun side_constraint_tac bnf constr_defs ctxt i = 
    76   let
    77     val thms = constr_defs @ map mk_sym [rel_eq_of_bnf bnf, rel_conversep_of_bnf bnf,
    78       rel_OO_of_bnf bnf]
    79   in                
    80     (SELECT_GOAL (Local_Defs.unfold_tac ctxt thms) THEN' rtac (rel_mono_of_bnf bnf)
    81       THEN_ALL_NEW atac) i
    82   end
    83 
    84 fun bi_constraint_tac constr_iff sided_constr_intros ctxt i = 
    85   (SELECT_GOAL (Local_Defs.unfold_tac ctxt [constr_iff]) THEN' 
    86     CONJ_WRAP' (fn thm => rtac thm THEN_ALL_NEW (REPEAT_DETERM o etac conjE THEN' atac)) sided_constr_intros) i
    87 
    88 fun generate_relation_constraint_goal ctxt bnf constraint_def =
    89   let
    90     val constr_name = constraint_def |> prop_of |> HOLogic.dest_Trueprop |> fst o HOLogic.dest_eq
    91       |> head_of |> fst o dest_Const
    92     val live = live_of_bnf bnf
    93     val (((As, Bs), Ds), ctxt) = ctxt
    94       |> mk_TFrees live
    95       ||>> mk_TFrees live
    96       ||>> mk_TFrees (dead_of_bnf bnf)
    97       
    98     val relator = mk_rel_of_bnf Ds As Bs bnf
    99     val relsT = map2 mk_pred2T As Bs
   100     val (args, ctxt) = Ctr_Sugar_Util.mk_Frees "R" relsT ctxt
   101     val concl = HOLogic.mk_Trueprop (mk_relation_constraint constr_name (list_comb (relator, args)))
   102     val assms = map (HOLogic.mk_Trueprop o (mk_relation_constraint constr_name)) args
   103     val goal = Logic.list_implies (assms, concl)
   104   in
   105     (goal, ctxt)
   106   end
   107 
   108 fun prove_relation_side_constraint ctxt bnf constraint_def =
   109   let
   110     val old_ctxt = ctxt
   111     val (goal, ctxt) = generate_relation_constraint_goal ctxt bnf constraint_def
   112     val thm = Goal.prove ctxt [] [] goal 
   113       (fn {context = ctxt, prems = _} => side_constraint_tac bnf [constraint_def] ctxt 1)
   114   in
   115     Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm)
   116   end
   117 
   118 fun prove_relation_bi_constraint ctxt bnf constraint_def side_constraints =
   119   let
   120     val old_ctxt = ctxt
   121     val (goal, ctxt) = generate_relation_constraint_goal ctxt bnf constraint_def
   122     val thm = Goal.prove ctxt [] [] goal 
   123       (fn {context = ctxt, prems = _} => bi_constraint_tac constraint_def side_constraints ctxt 1)
   124   in
   125     Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm)
   126   end
   127 
   128 val defs = [("left_total_rel", @{thm left_total_alt_def}), ("right_total_rel", @{thm right_total_alt_def}),
   129   ("left_unique_rel", @{thm left_unique_alt_def}), ("right_unique_rel", @{thm right_unique_alt_def})]
   130 
   131 fun prove_relation_constraints bnf lthy =
   132   let
   133     val transfer_attr = @{attributes [transfer_rule]}
   134     val Tname = base_name_of_bnf bnf
   135     fun qualify suffix = Binding.qualified true suffix Tname
   136     
   137     val defs = map (apsnd (prove_relation_side_constraint lthy bnf)) defs
   138     val bi_total = prove_relation_bi_constraint lthy bnf @{thm bi_total_alt_def} 
   139       [snd (nth defs 0), snd (nth defs 1)]
   140     val bi_unique = prove_relation_bi_constraint lthy bnf @{thm bi_unique_alt_def} 
   141       [snd (nth defs 2), snd (nth defs 3)]
   142     val defs = ("bi_total_rel", bi_total) :: ("bi_unique_rel", bi_unique) :: defs
   143     val notes = maps (fn (name, thm) => [((qualify name, []), [([thm], transfer_attr)])]) defs
   144   in
   145     notes
   146   end
   147 
   148 (* relator_eq *)
   149 
   150 fun relator_eq bnf =
   151   [((Binding.empty, []), [([rel_eq_of_bnf bnf], @{attributes [relator_eq]})])]
   152 
   153 (* predicator definition and Domainp and eq_onp theorem *)
   154 
   155 fun define_pred bnf lthy =
   156   let
   157     fun mk_pred_name c = Binding.prefix_name "pred_" c
   158     val live = live_of_bnf bnf
   159     val Tname = base_name_of_bnf bnf
   160     val ((As, Ds), lthy) = lthy
   161       |> mk_TFrees live
   162       ||>> mk_TFrees (dead_of_bnf bnf)
   163     val T = mk_T_of_bnf Ds As bnf
   164     val sets = mk_sets_of_bnf (replicate live Ds) (replicate live As) bnf
   165     val argTs = map mk_pred1T As
   166     val args = mk_Frees_free "P" argTs lthy
   167     val conjs = map (fn (set, arg) => mk_Ball (set $ Bound 0) arg) (sets ~~ args)
   168     val rhs = Abs ("x", T, foldr1 HOLogic.mk_conj conjs)
   169     val pred_name = mk_pred_name Tname
   170     val headT = argTs ---> (T --> HOLogic.boolT)
   171     val head = Free (Binding.name_of pred_name, headT)
   172     val lhs = list_comb (head, args)
   173     val def = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs))
   174     val ((_, (_, pred_def)), lthy) = Specification.definition ((SOME (pred_name, SOME headT, NoSyn)), 
   175       ((Binding.empty, []), def)) lthy
   176   in
   177     (pred_def, lthy)
   178   end
   179 
   180 fun Domainp_tac bnf pred_def ctxt i =
   181   let
   182     val n = live_of_bnf bnf
   183     val set_map's = set_map_of_bnf bnf
   184   in
   185     EVERY' [rtac ext, SELECT_GOAL (Local_Defs.unfold_tac ctxt [@{thm Domainp.simps}, 
   186         in_rel_of_bnf bnf, pred_def]), rtac iffI,
   187         REPEAT_DETERM o eresolve_tac [exE, conjE, CollectE], hyp_subst_tac ctxt,
   188         CONJ_WRAP' (fn set_map => EVERY' [rtac ballI, dtac (set_map RS equalityD1 RS set_mp),
   189           etac imageE, dtac set_rev_mp, atac, REPEAT_DETERM o eresolve_tac [CollectE, @{thm case_prodE}],
   190           hyp_subst_tac ctxt, rtac @{thm iffD2[OF arg_cong2[of _ _ _ _ Domainp, OF refl fst_conv]]},
   191           etac @{thm DomainPI}]) set_map's, 
   192         REPEAT_DETERM o etac conjE, REPEAT_DETERM o resolve_tac [exI, (refl RS conjI), rotate_prems 1 conjI], 
   193         rtac refl, rtac (box_equals OF [map_cong0_of_bnf bnf, map_comp_of_bnf bnf RS sym,
   194           map_id_of_bnf bnf]),
   195         REPEAT_DETERM_N n o (EVERY' [rtac @{thm box_equals[OF _ sym[OF o_apply] sym[OF id_apply]]},
   196           rtac @{thm fst_conv}]), rtac CollectI,
   197         CONJ_WRAP' (fn set_map => EVERY' [rtac (set_map RS @{thm ord_eq_le_trans}), 
   198           REPEAT_DETERM o resolve_tac [@{thm image_subsetI}, CollectI, @{thm case_prodI}],
   199           dtac (rotate_prems 1 bspec), atac, etac @{thm DomainpE}, etac @{thm someI}]) set_map's
   200       ] i
   201   end
   202 
   203 fun prove_Domainp_rel ctxt bnf pred_def =
   204   let
   205     val live = live_of_bnf bnf
   206     val old_ctxt = ctxt
   207     val (((As, Bs), Ds), ctxt) = ctxt
   208       |> mk_TFrees live
   209       ||>> mk_TFrees live
   210       ||>> mk_TFrees (dead_of_bnf bnf)
   211 
   212     val relator = mk_rel_of_bnf Ds As Bs bnf
   213     val relsT = map2 mk_pred2T As Bs
   214     val T = mk_T_of_bnf Ds As bnf
   215     val (args, ctxt) = Ctr_Sugar_Util.mk_Frees "R" relsT ctxt
   216     val lhs = mk_Domainp (list_comb (relator, args))
   217     val rhs = mk_pred pred_def (map mk_Domainp args) T
   218     val goal = HOLogic.mk_eq (lhs, rhs) |> HOLogic.mk_Trueprop
   219     val thm = Goal.prove ctxt [] [] goal 
   220       (fn {context = ctxt, prems = _} => Domainp_tac bnf pred_def ctxt 1)
   221   in
   222     Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm)
   223   end
   224 
   225 fun pred_eq_onp_tac bnf pred_def ctxt i =
   226   (SELECT_GOAL (Local_Defs.unfold_tac ctxt [@{thm eq_onp_Grp}, 
   227     @{thm Ball_Collect}, pred_def]) THEN' CONVERSION (subst_conv (map_id0_of_bnf bnf RS sym))
   228   THEN' rtac (rel_Grp_of_bnf bnf)) i
   229 
   230 fun prove_rel_eq_onp ctxt bnf pred_def =
   231   let
   232     val live = live_of_bnf bnf
   233     val old_ctxt = ctxt
   234     val ((As, Ds), ctxt) = ctxt
   235       |> mk_TFrees live
   236       ||>> mk_TFrees (dead_of_bnf bnf)
   237     val T = mk_T_of_bnf Ds As bnf
   238     val argTs = map mk_pred1T As
   239     val (args, ctxt) = mk_Frees "P" argTs ctxt
   240     val relator = mk_rel_of_bnf Ds As As bnf
   241     val lhs = list_comb (relator, map mk_eq_onp args)
   242     val rhs = mk_eq_onp (mk_pred pred_def args T)
   243     val goal = HOLogic.mk_eq (lhs, rhs) |> HOLogic.mk_Trueprop
   244     val thm = Goal.prove ctxt [] [] goal 
   245       (fn {context = ctxt, prems = _} => pred_eq_onp_tac bnf pred_def ctxt 1)
   246   in
   247     Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm)
   248   end
   249 
   250 fun predicator bnf lthy =
   251   let
   252     val (pred_def, lthy) = define_pred bnf lthy
   253     val pred_def = Morphism.thm (Local_Theory.target_morphism lthy) pred_def
   254     val Domainp_rel = prove_Domainp_rel lthy bnf pred_def
   255     val rel_eq_onp = prove_rel_eq_onp lthy bnf pred_def
   256     fun qualify defname suffix = Binding.qualified true suffix defname
   257     val Domainp_rel_thm_name = qualify (base_name_of_bnf bnf) "Domainp_rel"
   258     val rel_eq_onp_thm_name = qualify (base_name_of_bnf bnf) "rel_eq_onp"
   259     val pred_data = {rel_eq_onp = rel_eq_onp}
   260     val type_name = type_name_of_bnf bnf
   261     val relator_domain_attr = @{attributes [relator_domain]}
   262     val notes = [((Domainp_rel_thm_name, []), [([Domainp_rel], relator_domain_attr)]),
   263       ((rel_eq_onp_thm_name, []), [([rel_eq_onp], [])])]
   264     val lthy = Local_Theory.declaration {syntax = false, pervasive = true}
   265       (fn phi => Transfer.update_pred_data type_name (Transfer.morph_pred_data phi pred_data)) lthy
   266   in
   267     (notes, lthy)
   268   end
   269 
   270 (* BNF interpretation *)
   271 
   272 fun transfer_bnf_interpretation bnf lthy =
   273   let
   274     val constr_notes = if dead_of_bnf bnf > 0 then []
   275       else prove_relation_constraints bnf lthy
   276     val relator_eq_notes = if dead_of_bnf bnf > 0 then [] 
   277       else relator_eq bnf
   278     val (pred_notes, lthy) = predicator bnf lthy
   279   in
   280     snd (Local_Theory.notes (constr_notes @ relator_eq_notes @ pred_notes) lthy)
   281   end
   282 
   283 val _ = Context.>> (Context.map_theory (bnf_interpretation
   284   (bnf_only_type_ctr (fn bnf => map_local_theory (transfer_bnf_interpretation bnf)))))
   285 
   286 (* simplification rules for the predicator *)
   287 
   288 fun lookup_defined_pred_data lthy name =
   289   case (Transfer.lookup_pred_data lthy name) of
   290     SOME data => data
   291     | NONE => (error "lookup_pred_data: something went utterly wrong")
   292 
   293 fun prove_pred_inject lthy (fp_sugar:fp_sugar) =
   294   let
   295     val involved_types = distinct op= (
   296         map type_name_of_bnf (#nested_bnfs fp_sugar) 
   297       @ map type_name_of_bnf (#nesting_bnfs fp_sugar)
   298       @ map type_name_of_bnf (#bnfs (#fp_res fp_sugar)))
   299     val eq_onps = map (Transfer.rel_eq_onp o lookup_defined_pred_data lthy) involved_types
   300     val live = live_of_bnf (bnf_of_fp_sugar fp_sugar)
   301     val old_lthy = lthy
   302     val (As, lthy) = mk_TFrees live lthy
   303     val predTs = map mk_pred1T As
   304     val (preds, lthy) = mk_Frees "P" predTs lthy
   305     val args = map mk_eq_onp preds
   306     val cTs = map (SOME o certifyT lthy) (maps (replicate 2) As)
   307     val cts = map (SOME o certify lthy) args
   308     fun get_rhs thm = thm |> concl_of |> HOLogic.dest_Trueprop |> HOLogic.dest_eq |> snd
   309     fun is_eqn thm = can get_rhs thm
   310     fun rel2pred_massage thm =
   311       let
   312         fun pred_eq_onp_conj 0 = error "not defined"
   313           | pred_eq_onp_conj 1 = @{thm eq_onp_same_args}
   314           | pred_eq_onp_conj n = 
   315             let
   316               val conj_cong = @{thm arg_cong2[of _ _ _ _ "op \<and>"]}
   317               val start = @{thm eq_onp_same_args} RS conj_cong
   318             in
   319               @{thm eq_onp_same_args} RS (funpow (n - 2) (fn thm => start RS thm) start)
   320             end
   321         val n = if is_eqn thm then thm |> get_rhs |> HOLogic.dest_conj |> length else 0
   322       in
   323         thm
   324         |> Drule.instantiate' cTs cts
   325         |> Local_Defs.unfold lthy eq_onps
   326         |> (fn thm => if n > 0 then @{thm box_equals} 
   327               OF [thm, @{thm eq_onp_same_args}, pred_eq_onp_conj n]
   328             else thm RS (@{thm eq_onp_same_args} RS iffD1))
   329       end
   330     val rel_injects = #rel_injects fp_sugar
   331   in
   332     rel_injects
   333     |> map rel2pred_massage
   334     |> Variable.export lthy old_lthy
   335     |> map Drule.zero_var_indexes
   336   end
   337 
   338 (* fp_sugar interpretation *)
   339 
   340 fun transfer_fp_sugar_interpretation fp_sugar lthy =
   341   let
   342     val pred_injects = prove_pred_inject lthy fp_sugar
   343     fun qualify defname suffix = Binding.qualified true suffix defname
   344     val pred_inject_thm_name = qualify (base_name_of_bnf (bnf_of_fp_sugar fp_sugar)) "pred_inject"
   345     val simp_attrs = @{attributes [simp]}
   346   in
   347     snd (Local_Theory.note ((pred_inject_thm_name, simp_attrs), pred_injects) lthy)
   348   end
   349 
   350 val _ = Context.>> (Context.map_theory (fp_sugar_interpretation
   351   (fp_sugar_only_type_ctr (fn fp_sugar => map_local_theory (transfer_fp_sugar_interpretation fp_sugar)))))
   352 
   353 end