File ‹~~/src/Tools/atomize_elim.ML›
signature ATOMIZE_ELIM =
sig
  val atomize_elim_conv : Proof.context -> conv
  val full_atomize_elim_conv : Proof.context -> conv
  val atomize_elim_tac : Proof.context -> int -> tactic
end
structure Atomize_Elim : ATOMIZE_ELIM =
struct
val named_theorems =
  Context.>>> (Context.map_theory_result
   (Named_Target.theory_init #>
    Named_Theorems.declare \<^binding>‹atomize_elim› "atomize_elim rewrite rule" ##>
    Local_Theory.exit_global));
local open Conv in
fun invert_perm pi =
      (pi @ subtract (op =) pi (0 upto (fold Integer.max pi 0)))
           |> map_index I
           |> sort (int_ord o apply2 snd)
           |> map fst
fun rearrange_prems_conv pi ct =
    let
      val pi' = 0 :: map (Integer.add 1) pi
      val fwd  = Thm.trivial ct
                  |> Drule.rearrange_prems pi'
      val back = Thm.trivial (snd (Thm.dest_implies (Thm.cprop_of fwd)))
                  |> Drule.rearrange_prems (invert_perm pi')
    in Thm.equal_intr fwd back end
fun atomize_elim_conv ctxt ct =
    (forall_conv (prems_conv ~1 o Object_Logic.atomize_prems o snd) ctxt
    then_conv Raw_Simplifier.rewrite ctxt true (Named_Theorems.get ctxt named_theorems)
    then_conv (fn ct' => if can (Object_Logic.dest_judgment ctxt) ct'
                         then all_conv ct'
                         else raise CTERM ("atomize_elim", [ct', ct])))
    ct
fun thesis_miniscope_conv inner_cv ctxt =
    let
      
      fun is_forall_thesis t =
          case Logic.strip_assums_concl t of
            (_ $ Bound i) => i = length (Logic.strip_params t) - 1
          | _ => false
      
      fun movea_conv ctxt ct =
          let
            val _ $ Abs (_, _, b) = Thm.term_of ct
            val idxs = fold_index (fn (i, t) => not (Term.is_dependent t) ? cons i)
                       (Logic.strip_imp_prems b) []
                       |> rev
            fun skip_over_assm cv = rewr_conv (Thm.symmetric Drule.norm_hhf_eq)
                                    then_conv (implies_concl_conv cv)
          in
            (forall_conv (K (rearrange_prems_conv idxs)) ctxt
             then_conv (funpow (length idxs) skip_over_assm (inner_cv ctxt)))
            ct
          end
      
      fun moveq_conv ctxt =
          (rewr_conv @{thm swap_params} then_conv (forall_conv (moveq_conv o snd) ctxt))
          else_conv (movea_conv ctxt)
      fun ms_conv ctxt ct =
          if is_forall_thesis (Thm.term_of ct)
          then moveq_conv ctxt ct
          else (implies_concl_conv (ms_conv ctxt)
            else_conv
            (forall_conv (ms_conv o snd) ctxt))
            ct
    in
      ms_conv ctxt
    end
val full_atomize_elim_conv = thesis_miniscope_conv atomize_elim_conv
end
fun atomize_elim_tac ctxt = SUBGOAL (fn (subg, i) =>
    let
      val thy = Proof_Context.theory_of ctxt
      val _ $ thesis = Logic.strip_assums_concl subg
      
      val quantify_thesis =
          if is_Bound thesis then all_tac
          else let
              val cthesis = Thm.global_cterm_of thy thesis
              val rule = Thm.instantiate' [SOME (Thm.ctyp_of_cterm cthesis)] [NONE, SOME cthesis]
                         @{thm meta_spec}
            in
              compose_tac ctxt (false, rule, 1) i
            end
    in
      quantify_thesis
      THEN (CONVERSION (full_atomize_elim_conv ctxt) i)
    end)
val _ =
  Theory.setup
    (Method.setup \<^binding>‹atomize_elim› (Scan.succeed (SIMPLE_METHOD' o atomize_elim_tac))
      "convert obtains statement to atomic object logic goal")
end