Theory RefineG_Transfer

theory RefineG_Transfer
imports Refine_Misc
header {* \isaheader{Transfer between Domains} *}
theory RefineG_Transfer
imports "../Refine_Misc"
begin
  text {* Currently, this theory is specialized to 
    transfers that include no data refinement.
    *}


definition "REFINEG_TRANSFER_POST_SIMP x y ≡ x=y"
definition [simp]: "REFINEG_TRANSFER_ALIGN x y == True"
lemma REFINEG_TRANSFER_ALIGNI: "REFINEG_TRANSFER_ALIGN x y" by simp

lemma START_REFINEG_TRANSFER: 
  assumes "REFINEG_TRANSFER_ALIGN d c"
  assumes "c≤a"
  assumes "REFINEG_TRANSFER_POST_SIMP c d"
  shows "d≤a"
  using assms
  by (simp add: REFINEG_TRANSFER_POST_SIMP_def)

lemma STOP_REFINEG_TRANSFER: "REFINEG_TRANSFER_POST_SIMP c c" 
  unfolding REFINEG_TRANSFER_POST_SIMP_def ..

ML {*
structure RefineG_Transfer = struct

  structure Post_Processors = Theory_Data (
    type T = (Proof.context -> tactic') Symtab.table
    val empty = Symtab.empty
    val extend = I
    val merge = Symtab.join (K snd)
  )

  fun add_post_processor name tac =
    Post_Processors.map (Symtab.update_new (name,tac))
  fun delete_post_processor name =
    Post_Processors.map (Symtab.delete name)
  val get_post_processors = Post_Processors.get #> Symtab.dest

  fun post_process_tac ctxt = let
    val tacs = get_post_processors (Proof_Context.theory_of ctxt)
      |> map (fn (_,tac) => tac ctxt)

    val tac = REPEAT_DETERM' (CHANGED o EVERY' (map (fn t => TRY o t) tacs))
  in
    tac
  end

  structure Post_Simp = Generic_Data (
      type T = simpset
      val empty = HOL_basic_ss
      val extend = I
      val merge = Raw_Simplifier.merge_ss
  )

  fun post_simps_op f a context = let
    val ctxt = Context.proof_of context
    fun do_it ss = simpset_of (f (put_simpset ss ctxt, a))
  in
    Post_Simp.map do_it context
  end
    
  val add_post_simps = post_simps_op (op addsimps)
  val del_post_simps = post_simps_op (op delsimps)

  fun get_post_ss ctxt = let
    val ss = Post_Simp.get (Context.Proof ctxt)
    val ctxt = put_simpset ss ctxt
  in
    ctxt
  end

  structure post_subst = Named_Thms
    ( val name = @{binding refine_transfer_post_subst}
      val description = "Refinement Framework: " ^ 
        "Transfer postprocessing substitutions" );

  fun post_subst_tac ctxt = let
    val s_thms = post_subst.get ctxt
    val dis_tac = (ALLGOALS (Tagged_Solver.solve_tac ctxt))
    val cnv = Cond_Rewr_Conv.cond_rewrs_conv dis_tac s_thms
    val ts_conv = Conv.top_sweep_conv cnv ctxt
    val ss = get_post_ss ctxt
  in
    REPEAT o CHANGED o 
    (Simplifier.simp_tac ss THEN' CONVERSION ts_conv)
  end


  structure transfer = Named_Thms
    ( val name = @{binding refine_transfer}
      val description = "Refinement Framework: " ^ 
        "Transfer rules" );

  fun transfer_tac thms ctxt i st = let 
    val thms = thms @ transfer.get ctxt;
    val ss = put_simpset HOL_basic_ss ctxt addsimps @{thms nested_prod_case_simp}
  in
    REPEAT_DETERM1 (
      COND (has_fewer_prems (nprems_of st)) no_tac (
        FIRST [
          Method.assm_tac ctxt i,
          resolve_tac thms i,
          Tagged_Solver.solve_tac ctxt i,
          CHANGED_PROP (simp_tac ss i)]
      )) st
  end

  (* Adjust right term to have same structure as left one *)
  val align_tac = IF_EXGOAL (fn i => fn st =>
    case Logic.concl_of_goal (prop_of st) i of
      @{mpat "Trueprop (REFINEG_TRANSFER_ALIGN ?c _)"} => let
        val thy = theory_of_thm st
        val c = cterm_of thy c
        val cT = ctyp_of_term c
        
        val rl = @{thm REFINEG_TRANSFER_ALIGNI}
          |> Thm.incr_indexes (Thm.maxidx_of st + 1)
          |> instantiate' [NONE,SOME cT] [NONE,SOME c]
        (*val _ = tracing (@{make_string} rl)*)
      in
        rtac rl i st
      end
    | _ => Seq.empty
  )

  fun post_transfer_tac thms ctxt = let open Autoref_Tacticals in
    rtac @{thm START_REFINEG_TRANSFER} 
    THEN' align_tac 
    THEN' IF_SOLVED (transfer_tac thms ctxt)
      (post_process_tac ctxt THEN' rtac @{thm STOP_REFINEG_TRANSFER})
      (K all_tac)

  end

  fun get_post_simp_rules context = Context.proof_of context
      |> get_post_ss
      |> simpset_of 
      |> Raw_Simplifier.dest_ss
      |> #simps |> map snd


  local
    val add_ps = Thm.declaration_attribute (add_post_simps o single)
    val del_ps = Thm.declaration_attribute (del_post_simps o single)
  in
    val setup = I
      #> add_post_processor "RefineG_Transfer.post_subst" post_subst_tac
      #> post_subst.setup
      #> transfer.setup
      #> Attrib.setup @{binding refine_transfer_post_simp} 
          (Attrib.add_del add_ps del_ps) 
          ("declaration of transfer post simplification rules")
      #> Global_Theory.add_thms_dynamic (
           @{binding refine_transfer_post_simps}, get_post_simp_rules)

  end
end
*}

setup {* RefineG_Transfer.setup *}
method_setup refine_transfer = 
  {* Scan.lift (Args.mode "post") -- Attrib.thms 
  >> (fn (post,thms) => fn ctxt => SIMPLE_METHOD'
    ( if post then RefineG_Transfer.post_transfer_tac thms ctxt
      else RefineG_Transfer.transfer_tac thms ctxt))
  *} "Invoke transfer rules"


locale transfer = fixes α :: "'c => 'a::complete_lattice"
begin

text {*
  In the following, we define some transfer lemmas for general
  HOL - constructs.
*}

lemma transfer_if[refine_transfer]:
  assumes "b ==> α s1 ≤ S1"
  assumes "¬b ==> α s2 ≤ S2"
  shows "α (if b then s1 else s2) ≤ (if b then S1 else S2)"
  using assms by auto

lemma transfer_prod[refine_transfer]:
  assumes "!!a b. α (f a b) ≤ F a b"
  shows "α (case_prod f x) ≤ (case_prod F x)"
  using assms by (auto split: prod.split)

lemma transfer_Let[refine_transfer]:
  assumes "!!x. α (f x) ≤ F x"
  shows "α (Let x f) ≤ Let x F"
  using assms by auto

lemma transfer_option[refine_transfer]:
  assumes "α fa ≤ Fa"
  assumes "!!x. α (fb x) ≤ Fb x"
  shows "α (case_option fa fb x) ≤ case_option Fa Fb x"
  using assms by (auto split: option.split)

lemma transfer_list[refine_transfer]:
  assumes "α fn ≤ Fn"
  assumes "!!x xs. α (fc x xs) ≤ Fc x xs"
  shows "α (case_list fn fc l) ≤ case_list Fn Fc l"
  using assms by (auto split: list.split)


lemma transfer_rec_list[refine_transfer]:
  assumes FN: "!!s. α (fn s) ≤ fn' s"
  assumes FC: "!!x l rec rec' s. [| !!s. α (rec s) ≤ (rec' s) |] 
    ==> α (fc x l rec s) ≤ fc' x l rec' s"
  shows "α (rec_list fn fc l s) ≤ rec_list fn' fc' l s"
  apply (induct l arbitrary: s)
  apply (simp add: FN)
  apply (simp add: FC)
  done

lemma transfer_rec_nat[refine_transfer]:
  assumes FN: "!!s. α (fn s) ≤ fn' s"
  assumes FC: "!!n rec rec' s. [| !!s. α (rec s) ≤ rec' s |] 
    ==> α (fs n rec s) ≤ fs' n rec' s"
  shows "α (rec_nat fn fs n s) ≤ rec_nat fn' fs' n s"
  apply (induct n arbitrary: s)
  apply (simp add: FN)
  apply (simp add: FC)
  done

end

text {* Transfer into complete lattice structure *}
locale ordered_transfer = transfer + 
  constrains α :: "'c::complete_lattice => 'a::complete_lattice"

text {* Transfer into complete lattice structure with distributive
  transfer function. *}
locale dist_transfer = ordered_transfer + 
  constrains α :: "'c::complete_lattice => 'a::complete_lattice"
  assumes α_dist: "!!A. is_chain A ==> α (Sup A) = Sup (α`A)"
begin
  lemma α_mono[simp, intro!]: "mono α"
    apply rule
    apply (subgoal_tac "is_chain {x,y}")
    apply (drule α_dist)
    apply (auto simp: le_iff_sup) []
    apply (rule chainI)
    apply auto
    done

  lemma α_strict[simp]: "α bot = bot"
    using α_dist[of "{}"] by simp
end


text {* Transfer into ccpo *}
locale ccpo_transfer = transfer α for
  α :: "'c::ccpo => 'a::complete_lattice" 

text {* Transfer into ccpo with distributive
  transfer function. *}
locale dist_ccpo_transfer = ccpo_transfer α
  for α :: "'c::ccpo => 'a::complete_lattice" + 
  assumes α_dist: "!!A. is_chain A ==> α (Sup A) = Sup (α`A)"
begin

  lemma α_mono[simp, intro!]: "mono α"
  proof
    fix x y :: 'c
    assume LE: "x≤y"
    hence C[simp, intro!]: "is_chain {x,y}" by (auto intro: chainI)
    from LE have "α x ≤ sup (α x) (α y)" by simp
    also have "… = Sup (α`{x,y})" by simp
    also have "… = α (Sup {x,y})"
      by (rule α_dist[symmetric]) simp
    also have "Sup {x,y} = y"
      apply (rule antisym)
      apply (rule ccpo_Sup_least[OF C]) using LE apply auto []
      apply (rule ccpo_Sup_upper[OF C]) by auto
    finally show "α x ≤ α y" .
  qed

  lemma α_strict[simp]: "α (Sup {}) = bot"
    using α_dist[of "{}"] by simp
end

end