src/HOL/HOLCF/Tools/Domain/domain_induction.ML
author wenzelm
Sat Dec 14 17:28:05 2013 +0100 (2013-12-14)
changeset 54742 7a86358a3c0b
parent 51717 9e7d1c139569
child 54895 515630483010
permissions -rw-r--r--
proper context for basic Simplifier operations: rewrite_rule, rewrite_goals_rule, rewrite_goals_tac etc.;
clarified tool context in some boundary cases;
wenzelm@42151
     1
(*  Title:      HOL/HOLCF/Tools/Domain/domain_induction.ML
wenzelm@23152
     2
    Author:     David von Oheimb
wenzelm@32740
     3
    Author:     Brian Huffman
wenzelm@23152
     4
huffman@40040
     5
Proofs of high-level (co)induction rules for domain command.
wenzelm@23152
     6
*)
wenzelm@23152
     7
huffman@40040
     8
signature DOMAIN_INDUCTION =
huffman@31005
     9
sig
huffman@35657
    10
  val comp_theorems :
huffman@40097
    11
      binding list ->
huffman@35657
    12
      Domain_Take_Proofs.take_induct_info ->
huffman@40016
    13
      Domain_Constructors.constr_info list ->
huffman@35657
    14
      theory -> thm list * theory
huffman@35657
    15
huffman@40832
    16
  val quiet_mode: bool Unsynchronized.ref
huffman@40832
    17
  val trace_domain: bool Unsynchronized.ref
huffman@40832
    18
end
huffman@31005
    19
huffman@41296
    20
structure Domain_Induction : DOMAIN_INDUCTION =
huffman@31005
    21
struct
wenzelm@23152
    22
huffman@40832
    23
val quiet_mode = Unsynchronized.ref false
huffman@40832
    24
val trace_domain = Unsynchronized.ref false
huffman@29402
    25
huffman@40832
    26
fun message s = if !quiet_mode then () else writeln s
huffman@40832
    27
fun trace s = if !trace_domain then tracing s else ()
huffman@29402
    28
huffman@40832
    29
open HOLCF_Library
wenzelm@23152
    30
huffman@40013
    31
(******************************************************************************)
huffman@40013
    32
(***************************** proofs about take ******************************)
huffman@40013
    33
(******************************************************************************)
wenzelm@23152
    34
huffman@40013
    35
fun take_theorems
huffman@40019
    36
    (dbinds : binding list)
huffman@35775
    37
    (take_info : Domain_Take_Proofs.take_induct_info)
huffman@40016
    38
    (constr_infos : Domain_Constructors.constr_info list)
huffman@40016
    39
    (thy : theory) : thm list list * theory =
wenzelm@23152
    40
let
huffman@40832
    41
  val {take_consts, take_Suc_thms, deflation_take_thms, ...} = take_info
huffman@40832
    42
  val deflation_thms = Domain_Take_Proofs.get_deflation_thms thy
wenzelm@23152
    43
huffman@40832
    44
  val n = Free ("n", @{typ nat})
huffman@40832
    45
  val n' = @{const Suc} $ n
huffman@35559
    46
huffman@40016
    47
  local
huffman@40832
    48
    val newTs = map (#absT o #iso_info) constr_infos
huffman@40832
    49
    val subs = newTs ~~ map (fn t => t $ n) take_consts
huffman@40016
    50
    fun is_ID (Const (c, _)) = (c = @{const_name ID})
huffman@40832
    51
      | is_ID _              = false
huffman@40016
    52
  in
huffman@40488
    53
    fun map_of_arg thy v T =
huffman@40832
    54
      let val m = Domain_Take_Proofs.map_of_typ thy subs T
huffman@40832
    55
      in if is_ID m then v else mk_capply (m, v) end
huffman@40016
    56
  end
huffman@40016
    57
huffman@40016
    58
  fun prove_take_apps
huffman@40019
    59
      ((dbind, take_const), constr_info) thy =
wenzelm@23152
    60
    let
paulson@41214
    61
      val {iso_info, con_specs, con_betas, ...} : Domain_Constructors.constr_info = constr_info
huffman@40832
    62
      val {abs_inverse, ...} = iso_info
huffman@40019
    63
      fun prove_take_app (con_const, args) =
huffman@40016
    64
        let
huffman@40832
    65
          val Ts = map snd args
huffman@40832
    66
          val ns = Name.variant_list ["n"] (Datatype_Prop.make_tnames Ts)
huffman@40832
    67
          val vs = map Free (ns ~~ Ts)
huffman@40832
    68
          val lhs = mk_capply (take_const $ n', list_ccomb (con_const, vs))
huffman@40832
    69
          val rhs = list_ccomb (con_const, map2 (map_of_arg thy) vs Ts)
huffman@40832
    70
          val goal = mk_trp (mk_eq (lhs, rhs))
huffman@40016
    71
          val rules =
huffman@40016
    72
              [abs_inverse] @ con_betas @ @{thms take_con_rules}
huffman@40832
    73
              @ take_Suc_thms @ deflation_thms @ deflation_take_thms
wenzelm@51717
    74
          val tac = simp_tac (Simplifier.global_context thy HOL_basic_ss addsimps rules) 1
huffman@40016
    75
        in
huffman@40016
    76
          Goal.prove_global thy [] [] goal (K tac)
huffman@40832
    77
        end
huffman@40832
    78
      val take_apps = map prove_take_app con_specs
huffman@40016
    79
    in
huffman@40016
    80
      yield_singleton Global_Theory.add_thmss
huffman@40016
    81
        ((Binding.qualified true "take_rews" dbind, take_apps),
huffman@40016
    82
        [Simplifier.simp_add]) thy
huffman@40832
    83
    end
wenzelm@23152
    84
in
huffman@40016
    85
  fold_map prove_take_apps
huffman@40019
    86
    (dbinds ~~ take_consts ~~ constr_infos) thy
huffman@40832
    87
end
wenzelm@23152
    88
huffman@40029
    89
(******************************************************************************)
huffman@40029
    90
(****************************** induction rules *******************************)
huffman@40029
    91
(******************************************************************************)
huffman@40013
    92
huffman@40020
    93
val case_UU_allI =
huffman@40832
    94
    @{lemma "(!!x. x ~= UU ==> P x) ==> P UU ==> ALL x. P x" by metis}
huffman@40020
    95
huffman@35585
    96
fun prove_induction
huffman@40023
    97
    (comp_dbind : binding)
huffman@40018
    98
    (constr_infos : Domain_Constructors.constr_info list)
huffman@40018
    99
    (take_info : Domain_Take_Proofs.take_induct_info)
huffman@35585
   100
    (take_rews : thm list)
huffman@35585
   101
    (thy : theory) =
huffman@35585
   102
let
huffman@40832
   103
  val comp_dname = Binding.name_of comp_dbind
huffman@35585
   104
huffman@40832
   105
  val iso_infos = map #iso_info constr_infos
huffman@40832
   106
  val exhausts = map #exhaust constr_infos
huffman@40832
   107
  val con_rews = maps #con_rews constr_infos
huffman@40832
   108
  val {take_consts, take_induct_thms, ...} = take_info
huffman@35658
   109
huffman@40832
   110
  val newTs = map #absT iso_infos
huffman@40832
   111
  val P_names = Datatype_Prop.indexify_names (map (K "P") newTs)
huffman@40832
   112
  val x_names = Datatype_Prop.indexify_names (map (K "x") newTs)
huffman@40832
   113
  val P_types = map (fn T => T --> HOLogic.boolT) newTs
huffman@40832
   114
  val Ps = map Free (P_names ~~ P_types)
huffman@40832
   115
  val xs = map Free (x_names ~~ newTs)
huffman@40832
   116
  val n = Free ("n", HOLogic.natT)
huffman@40020
   117
huffman@40020
   118
  fun con_assm defined p (con, args) =
huffman@35585
   119
    let
huffman@40832
   120
      val Ts = map snd args
huffman@40832
   121
      val ns = Name.variant_list P_names (Datatype_Prop.make_tnames Ts)
huffman@40832
   122
      val vs = map Free (ns ~~ Ts)
huffman@40832
   123
      val nonlazy = map snd (filter_out (fst o fst) (args ~~ vs))
huffman@40020
   124
      fun ind_hyp (v, T) t =
huffman@40020
   125
          case AList.lookup (op =) (newTs ~~ Ps) T of NONE => t
huffman@40832
   126
          | SOME p' => Logic.mk_implies (mk_trp (p' $ v), t)
huffman@40832
   127
      val t1 = mk_trp (p $ list_ccomb (con, vs))
huffman@40832
   128
      val t2 = fold_rev ind_hyp (vs ~~ Ts) t1
huffman@40832
   129
      val t3 = Logic.list_implies (map (mk_trp o mk_defined) nonlazy, t2)
huffman@40832
   130
    in fold_rev Logic.all vs (if defined then t3 else t2) end
huffman@40020
   131
  fun eq_assms ((p, T), cons) =
huffman@40832
   132
      mk_trp (p $ HOLCF_Library.mk_bottom T) :: map (con_assm true p) cons
huffman@40832
   133
  val assms = maps eq_assms (Ps ~~ newTs ~~ map #con_specs constr_infos)
huffman@35585
   134
wenzelm@51717
   135
  val take_ss =
wenzelm@51717
   136
    simpset_of (put_simpset HOL_ss @{context} addsimps (@{thm Rep_cfun_strict1} :: take_rews))
huffman@35585
   137
  fun quant_tac ctxt i = EVERY
huffman@40832
   138
    (map (fn name => res_inst_tac ctxt [(("x", 0), name)] spec i) x_names)
huffman@35585
   139
huffman@40023
   140
  (* FIXME: move this message to domain_take_proofs.ML *)
huffman@40832
   141
  val is_finite = #is_finite take_info
huffman@40023
   142
  val _ = if is_finite
huffman@40023
   143
          then message ("Proving finiteness rule for domain "^comp_dname^" ...")
huffman@40832
   144
          else ()
huffman@35585
   145
huffman@40832
   146
  val _ = trace " Proving finite_ind..."
huffman@35585
   147
  val finite_ind =
huffman@35585
   148
    let
huffman@40020
   149
      val concls =
huffman@40023
   150
          map (fn ((P, t), x) => P $ mk_capply (t $ n, x))
huffman@40832
   151
              (Ps ~~ take_consts ~~ xs)
huffman@40832
   152
      val goal = mk_trp (foldr1 mk_conj concls)
huffman@35585
   153
wenzelm@42793
   154
      fun tacf {prems, context = ctxt} =
huffman@35585
   155
        let
huffman@40020
   156
          (* Prove stronger prems, without definedness side conditions *)
huffman@40020
   157
          fun con_thm p (con, args) =
huffman@40020
   158
            let
huffman@40832
   159
              val subgoal = con_assm false p (con, args)
wenzelm@45654
   160
              val rules = prems @ con_rews @ @{thms simp_thms}
wenzelm@51717
   161
              val simplify = asm_simp_tac (put_simpset HOL_basic_ss ctxt addsimps rules)
huffman@40020
   162
              fun arg_tac (lazy, _) =
huffman@40832
   163
                  rtac (if lazy then allI else case_UU_allI) 1
wenzelm@54742
   164
              fun tacs ctxt =
wenzelm@54742
   165
                  rewrite_goals_tac ctxt @{thms atomize_all atomize_imp} ::
huffman@40020
   166
                  map arg_tac args @
huffman@40832
   167
                  [REPEAT (rtac impI 1), ALLGOALS simplify]
huffman@40020
   168
            in
wenzelm@54742
   169
              Goal.prove ctxt [] [] subgoal (EVERY o tacs o #context)
huffman@40832
   170
            end
huffman@40832
   171
          fun eq_thms (p, cons) = map (con_thm p) cons
huffman@40832
   172
          val conss = map #con_specs constr_infos
huffman@40832
   173
          val prems' = maps eq_thms (Ps ~~ conss)
huffman@40020
   174
huffman@35585
   175
          val tacs1 = [
wenzelm@42793
   176
            quant_tac ctxt 1,
wenzelm@51717
   177
            simp_tac (put_simpset HOL_ss ctxt) 1,
wenzelm@45133
   178
            Induct_Tacs.induct_tac ctxt [[SOME "n"]] 1,
wenzelm@51717
   179
            simp_tac (put_simpset take_ss ctxt addsimps prems) 1,
wenzelm@42793
   180
            TRY (safe_tac (put_claset HOL_cs ctxt))]
huffman@40020
   181
          fun con_tac _ = 
wenzelm@51717
   182
            asm_simp_tac (put_simpset take_ss ctxt) 1 THEN
huffman@40832
   183
            (resolve_tac prems' THEN_ALL_NEW etac spec) 1
huffman@35781
   184
          fun cases_tacs (cons, exhaust) =
wenzelm@42793
   185
            res_inst_tac ctxt [(("y", 0), "x")] exhaust 1 ::
wenzelm@51717
   186
            asm_simp_tac (put_simpset take_ss ctxt addsimps prems) 1 ::
huffman@40832
   187
            map con_tac cons
huffman@40020
   188
          val tacs = tacs1 @ maps cases_tacs (conss ~~ exhausts)
huffman@35585
   189
        in
huffman@40020
   190
          EVERY (map DETERM tacs)
huffman@40832
   191
        end
huffman@40832
   192
    in Goal.prove_global thy [] assms goal tacf end
huffman@35585
   193
huffman@40832
   194
  val _ = trace " Proving ind..."
huffman@35661
   195
  val ind =
huffman@40022
   196
    let
huffman@40832
   197
      val concls = map (op $) (Ps ~~ xs)
huffman@40832
   198
      val goal = mk_trp (foldr1 mk_conj concls)
huffman@40832
   199
      val adms = if is_finite then [] else map (mk_trp o mk_adm) Ps
wenzelm@42793
   200
      fun tacf {prems, context = ctxt} =
huffman@40022
   201
        let
huffman@40022
   202
          fun finite_tac (take_induct, fin_ind) =
huffman@40022
   203
              rtac take_induct 1 THEN
huffman@40022
   204
              (if is_finite then all_tac else resolve_tac prems 1) THEN
huffman@40832
   205
              (rtac fin_ind THEN_ALL_NEW solve_tac prems) 1
wenzelm@42793
   206
          val fin_inds = Project_Rule.projections ctxt finite_ind
huffman@40022
   207
        in
wenzelm@42793
   208
          TRY (safe_tac (put_claset HOL_cs ctxt)) THEN
huffman@40022
   209
          EVERY (map finite_tac (take_induct_thms ~~ fin_inds))
huffman@40832
   210
        end
huffman@40022
   211
    in Goal.prove_global thy [] (adms @ assms) goal tacf end
huffman@35585
   212
huffman@40023
   213
  (* case names for induction rules *)
huffman@40832
   214
  val dnames = map (fst o dest_Type) newTs
huffman@40023
   215
  val case_ns =
huffman@40023
   216
    let
huffman@40023
   217
      val adms =
huffman@40023
   218
          if is_finite then [] else
huffman@40023
   219
          if length dnames = 1 then ["adm"] else
huffman@40832
   220
          map (fn s => "adm_" ^ Long_Name.base_name s) dnames
huffman@40023
   221
      val bottoms =
huffman@40023
   222
          if length dnames = 1 then ["bottom"] else
huffman@40832
   223
          map (fn s => "bottom_" ^ Long_Name.base_name s) dnames
paulson@41214
   224
      fun one_eq bot (constr_info : Domain_Constructors.constr_info) =
huffman@44080
   225
        let fun name_of (c, _) = Long_Name.base_name (fst (dest_Const c))
huffman@40832
   226
        in bot :: map name_of (#con_specs constr_info) end
huffman@40832
   227
    in adms @ flat (map2 one_eq bottoms constr_infos) end
huffman@35630
   228
wenzelm@42361
   229
  val inducts = Project_Rule.projections (Proof_Context.init_global thy) ind
huffman@40023
   230
  fun ind_rule (dname, rule) =
huffman@40026
   231
      ((Binding.empty, rule),
huffman@40832
   232
       [Rule_Cases.case_names case_ns, Induct.induct_type dname])
huffman@35630
   233
huffman@35774
   234
in
huffman@35774
   235
  thy
huffman@40026
   236
  |> snd o Global_Theory.add_thms [
huffman@40026
   237
     ((Binding.qualified true "finite_induct" comp_dbind, finite_ind), []),
huffman@40026
   238
     ((Binding.qualified true "induct"        comp_dbind, ind       ), [])]
huffman@40026
   239
  |> (snd o Global_Theory.add_thms (map ind_rule (dnames ~~ inducts)))
huffman@40832
   240
end (* prove_induction *)
huffman@35585
   241
huffman@35585
   242
(******************************************************************************)
huffman@35585
   243
(************************ bisimulation and coinduction ************************)
huffman@35585
   244
(******************************************************************************)
huffman@35585
   245
huffman@35574
   246
fun prove_coinduction
huffman@40025
   247
    (comp_dbind : binding, dbinds : binding list)
huffman@40025
   248
    (constr_infos : Domain_Constructors.constr_info list)
huffman@40025
   249
    (take_info : Domain_Take_Proofs.take_induct_info)
huffman@40025
   250
    (take_rews : thm list list)
huffman@35599
   251
    (thy : theory) : theory =
wenzelm@23152
   252
let
huffman@40832
   253
  val iso_infos = map #iso_info constr_infos
huffman@40832
   254
  val newTs = map #absT iso_infos
huffman@40025
   255
huffman@40832
   256
  val {take_consts, take_0_thms, take_lemma_thms, ...} = take_info
wenzelm@23152
   257
huffman@40832
   258
  val R_names = Datatype_Prop.indexify_names (map (K "R") newTs)
huffman@40832
   259
  val R_types = map (fn T => T --> T --> boolT) newTs
huffman@40832
   260
  val Rs = map Free (R_names ~~ R_types)
huffman@40832
   261
  val n = Free ("n", natT)
huffman@40832
   262
  val reserved = "x" :: "y" :: R_names
huffman@35497
   263
huffman@40025
   264
  (* declare bisimulation predicate *)
huffman@40832
   265
  val bisim_bind = Binding.suffix_name "_bisim" comp_dbind
huffman@40832
   266
  val bisim_type = R_types ---> boolT
huffman@35497
   267
  val (bisim_const, thy) =
wenzelm@42375
   268
      Sign.declare_const_global ((bisim_bind, bisim_type), NoSyn) thy
huffman@35497
   269
huffman@40025
   270
  (* define bisimulation predicate *)
huffman@40025
   271
  local
huffman@40025
   272
    fun one_con T (con, args) =
huffman@40025
   273
      let
huffman@40832
   274
        val Ts = map snd args
huffman@40832
   275
        val ns1 = Name.variant_list reserved (Datatype_Prop.make_tnames Ts)
huffman@40832
   276
        val ns2 = map (fn n => n^"'") ns1
huffman@40832
   277
        val vs1 = map Free (ns1 ~~ Ts)
huffman@40832
   278
        val vs2 = map Free (ns2 ~~ Ts)
huffman@40832
   279
        val eq1 = mk_eq (Free ("x", T), list_ccomb (con, vs1))
huffman@40832
   280
        val eq2 = mk_eq (Free ("y", T), list_ccomb (con, vs2))
huffman@40025
   281
        fun rel ((v1, v2), T) =
huffman@40025
   282
            case AList.lookup (op =) (newTs ~~ Rs) T of
huffman@40832
   283
              NONE => mk_eq (v1, v2) | SOME r => r $ v1 $ v2
huffman@40832
   284
        val eqs = foldr1 mk_conj (map rel (vs1 ~~ vs2 ~~ Ts) @ [eq1, eq2])
huffman@40025
   285
      in
huffman@40025
   286
        Library.foldr mk_ex (vs1 @ vs2, eqs)
huffman@40832
   287
      end
huffman@40025
   288
    fun one_eq ((T, R), cons) =
huffman@40025
   289
      let
huffman@40832
   290
        val x = Free ("x", T)
huffman@40832
   291
        val y = Free ("y", T)
huffman@40832
   292
        val disj1 = mk_conj (mk_eq (x, mk_bottom T), mk_eq (y, mk_bottom T))
huffman@40832
   293
        val disjs = disj1 :: map (one_con T) cons
huffman@40025
   294
      in
huffman@40025
   295
        mk_all (x, mk_all (y, mk_imp (R $ x $ y, foldr1 mk_disj disjs)))
huffman@40832
   296
      end
huffman@40832
   297
    val conjs = map one_eq (newTs ~~ Rs ~~ map #con_specs constr_infos)
huffman@40832
   298
    val bisim_rhs = lambdas Rs (Library.foldr1 mk_conj conjs)
huffman@40832
   299
    val bisim_eqn = Logic.mk_equals (bisim_const, bisim_rhs)
huffman@40025
   300
  in
huffman@40025
   301
    val (bisim_def_thm, thy) = thy |>
huffman@40025
   302
        yield_singleton (Global_Theory.add_defs false)
huffman@40832
   303
         ((Binding.qualified true "bisim_def" comp_dbind, bisim_eqn), [])
huffman@40025
   304
  end (* local *)
huffman@35497
   305
huffman@40025
   306
  (* prove coinduction lemma *)
huffman@40025
   307
  val coind_lemma =
huffman@35497
   308
    let
huffman@40832
   309
      val assm = mk_trp (list_comb (bisim_const, Rs))
huffman@40025
   310
      fun one ((T, R), take_const) =
huffman@40025
   311
        let
huffman@40832
   312
          val x = Free ("x", T)
huffman@40832
   313
          val y = Free ("y", T)
huffman@40832
   314
          val lhs = mk_capply (take_const $ n, x)
huffman@40832
   315
          val rhs = mk_capply (take_const $ n, y)
huffman@40025
   316
        in
huffman@40025
   317
          mk_all (x, mk_all (y, mk_imp (R $ x $ y, mk_eq (lhs, rhs))))
huffman@40832
   318
        end
huffman@40025
   319
      val goal =
huffman@40832
   320
          mk_trp (foldr1 mk_conj (map one (newTs ~~ Rs ~~ take_consts)))
huffman@40832
   321
      val rules = @{thm Rep_cfun_strict1} :: take_0_thms
wenzelm@42793
   322
      fun tacf {prems, context = ctxt} =
huffman@40025
   323
        let
wenzelm@54742
   324
          val prem' = rewrite_rule ctxt [bisim_def_thm] (hd prems)
wenzelm@42793
   325
          val prems' = Project_Rule.projections ctxt prem'
huffman@40832
   326
          val dests = map (fn th => th RS spec RS spec RS mp) prems'
huffman@40025
   327
          fun one_tac (dest, rews) =
wenzelm@42793
   328
              dtac dest 1 THEN safe_tac (put_claset HOL_cs ctxt) THEN
wenzelm@51717
   329
              ALLGOALS (asm_simp_tac (put_simpset HOL_basic_ss ctxt addsimps rews))
huffman@40025
   330
        in
huffman@40025
   331
          rtac @{thm nat.induct} 1 THEN
wenzelm@51717
   332
          simp_tac (put_simpset HOL_ss ctxt addsimps rules) 1 THEN
wenzelm@42793
   333
          safe_tac (put_claset HOL_cs ctxt) THEN
huffman@40025
   334
          EVERY (map one_tac (dests ~~ take_rews))
huffman@40025
   335
        end
huffman@35497
   336
    in
huffman@40025
   337
      Goal.prove_global thy [] [assm] goal tacf
huffman@40832
   338
    end
huffman@40025
   339
huffman@40025
   340
  (* prove individual coinduction rules *)
huffman@40025
   341
  fun prove_coind ((T, R), take_lemma) =
huffman@40025
   342
    let
huffman@40832
   343
      val x = Free ("x", T)
huffman@40832
   344
      val y = Free ("y", T)
huffman@40832
   345
      val assm1 = mk_trp (list_comb (bisim_const, Rs))
huffman@40832
   346
      val assm2 = mk_trp (R $ x $ y)
huffman@40832
   347
      val goal = mk_trp (mk_eq (x, y))
wenzelm@51717
   348
      fun tacf {prems, context = ctxt} =
huffman@40025
   349
        let
huffman@40832
   350
          val rule = hd prems RS coind_lemma
huffman@40025
   351
        in
huffman@40025
   352
          rtac take_lemma 1 THEN
wenzelm@51717
   353
          asm_simp_tac (put_simpset HOL_basic_ss ctxt addsimps (rule :: prems)) 1
huffman@40832
   354
        end
huffman@40025
   355
    in
huffman@40025
   356
      Goal.prove_global thy [] [assm1, assm2] goal tacf
huffman@40832
   357
    end
huffman@40832
   358
  val coinds = map prove_coind (newTs ~~ Rs ~~ take_lemma_thms)
huffman@40832
   359
  val coind_binds = map (Binding.qualified true "coinduct") dbinds
huffman@35497
   360
huffman@35497
   361
in
huffman@40025
   362
  thy |> snd o Global_Theory.add_thms
huffman@40025
   363
    (map Thm.no_attributes (coind_binds ~~ coinds))
huffman@40832
   364
end (* let *)
huffman@35574
   365
huffman@40018
   366
(******************************************************************************)
huffman@40018
   367
(******************************* main function ********************************)
huffman@40018
   368
(******************************************************************************)
huffman@40018
   369
huffman@35657
   370
fun comp_theorems
huffman@40019
   371
    (dbinds : binding list)
huffman@35659
   372
    (take_info : Domain_Take_Proofs.take_induct_info)
huffman@40016
   373
    (constr_infos : Domain_Constructors.constr_info list)
huffman@35657
   374
    (thy : theory) =
huffman@35574
   375
let
huffman@40097
   376
huffman@40832
   377
val comp_dname = space_implode "_" (map Binding.name_of dbinds)
huffman@40832
   378
val comp_dbind = Binding.name comp_dname
huffman@35574
   379
huffman@40023
   380
(* Test for emptiness *)
huffman@40026
   381
(* FIXME: reimplement emptiness test
huffman@40023
   382
local
huffman@40832
   383
  open Domain_Library
huffman@40832
   384
  val dnames = map (fst o fst) eqs
huffman@40832
   385
  val conss = map snd eqs
huffman@40023
   386
  fun rec_to ns lazy_rec (n,cons) = forall (exists (fn arg => 
huffman@40023
   387
        is_rec arg andalso not (member (op =) ns (rec_of arg)) andalso
huffman@40023
   388
        ((rec_of arg =  n andalso not (lazy_rec orelse is_lazy arg)) orelse 
huffman@40023
   389
          rec_of arg <> n andalso rec_to (rec_of arg::ns) 
wenzelm@42364
   390
            (lazy_rec orelse is_lazy arg) (n, nth conss (rec_of arg)))
huffman@40832
   391
        ) o snd) cons
huffman@40023
   392
  fun warn (n,cons) =
huffman@40023
   393
    if rec_to [] false (n,cons)
wenzelm@42364
   394
    then (warning ("domain " ^ nth dnames n ^ " is empty!") true)
huffman@40832
   395
    else false
huffman@40023
   396
in
huffman@40832
   397
  val n__eqs = mapn (fn n => fn (_,cons) => (n,cons)) 0 eqs
huffman@40832
   398
  val is_emptys = map warn n__eqs
huffman@40832
   399
end
huffman@40026
   400
*)
wenzelm@23152
   401
huffman@35585
   402
(* Test for indirect recursion *)
huffman@35585
   403
local
huffman@40832
   404
  val newTs = map (#absT o #iso_info) constr_infos
huffman@40026
   405
  fun indirect_typ (Type (_, Ts)) =
huffman@40026
   406
      exists (fn T => member (op =) newTs T orelse indirect_typ T) Ts
huffman@40832
   407
    | indirect_typ _ = false
huffman@40832
   408
  fun indirect_arg (_, T) = indirect_typ T
huffman@40832
   409
  fun indirect_con (_, args) = exists indirect_arg args
huffman@40832
   410
  fun indirect_eq cons = exists indirect_con cons
huffman@35585
   411
in
huffman@40832
   412
  val is_indirect = exists indirect_eq (map #con_specs constr_infos)
huffman@35599
   413
  val _ =
huffman@35599
   414
      if is_indirect
huffman@35599
   415
      then message "Indirect recursion detected, skipping proofs of (co)induction rules"
huffman@40832
   416
      else message ("Proving induction properties of domain "^comp_dname^" ...")
huffman@40832
   417
end
huffman@35585
   418
huffman@35585
   419
(* theorems about take *)
wenzelm@23152
   420
huffman@40016
   421
val (take_rewss, thy) =
huffman@40832
   422
    take_theorems dbinds take_info constr_infos thy
wenzelm@23152
   423
huffman@44080
   424
val {take_0_thms, take_strict_thms, ...} = take_info
huffman@40016
   425
huffman@40832
   426
val take_rews = take_0_thms @ take_strict_thms @ flat take_rewss
wenzelm@23152
   427
huffman@35585
   428
(* prove induction rules, unless definition is indirect recursive *)
huffman@35585
   429
val thy =
huffman@35585
   430
    if is_indirect then thy else
huffman@40832
   431
    prove_induction comp_dbind constr_infos take_info take_rews thy
wenzelm@23152
   432
huffman@35599
   433
val thy =
huffman@35599
   434
    if is_indirect then thy else
huffman@40832
   435
    prove_coinduction (comp_dbind, dbinds) constr_infos take_info take_rewss thy
wenzelm@23152
   436
huffman@35642
   437
in
huffman@35642
   438
  (take_rews, thy)
huffman@40832
   439
end (* let *)
huffman@40832
   440
end (* struct *)