Theory Refine_Monadic.Refine_Transfer
section ‹Transfer Setup›
theory Refine_Transfer
imports
  Refine_Basic
  Refine_While
  Refine_Det 
  "Generic/RefineG_Transfer"
begin
subsection ‹Transfer to Deterministic Result Lattice›
text ‹
  TODO: Once lattice and ccpo are connected, also transfer to option monad, that
  is a ccpo, but no complete lattice!
›
subsubsection ‹Connecting Deterministic and Non-Deterministic Result Lattices›
definition "nres_of r ≡ case r of
  dSUCCEEDi ⇒ SUCCEED
| dFAILi ⇒ FAIL
| dRETURN x ⇒ RETURN x"
lemma nres_of_simps[simp]:
  "nres_of dSUCCEED = SUCCEED"
  "nres_of dFAIL = FAIL"
  "nres_of (dRETURN x) = RETURN x"
  apply -
  unfolding nres_of_def bot_dres_def top_dres_def
  by (auto simp del: dres_internal_simps)
lemma nres_of_mono: "mono nres_of"
  apply (rule)
  apply (case_tac x, simp_all, case_tac y, simp_all)
  done
lemma nres_transfer:
  "nres_of dSUCCEED = SUCCEED"
  "nres_of dFAIL = FAIL"
  "nres_of a ≤ nres_of b ⟷ a≤b"
  "nres_of a < nres_of b ⟷ a<b"
  "is_chain A ⟹ nres_of (Sup A) = Sup (nres_of`A)"
  "is_chain A ⟹ nres_of (Inf A) = Inf (nres_of`A)"
  apply simp_all
  apply (case_tac a, simp_all, case_tac [!] b, simp_all) [1]
  apply (simp add: less_le)
  apply (case_tac a, simp_all, case_tac [!] b, simp_all) [1]
  apply (erule dres_Sup_chain_cases)
    apply (cases "A={}")
    apply auto []
    apply (subgoal_tac "A={dSUCCEED}", auto) []
    apply (case_tac "A={dRETURN r}")
    apply auto []
    apply (subgoal_tac "A={dSUCCEED,dRETURN r}", auto) []
    apply (drule imageI[where f=nres_of])
    apply auto []
  apply (erule dres_Inf_chain_cases)
    apply (cases "A={}")
    apply auto []
    apply (subgoal_tac "A={dFAIL}", auto) []
    apply (case_tac "A={dRETURN r}")
    apply auto []
    apply (subgoal_tac "A={dFAIL,dRETURN r}", auto) []
    apply (drule imageI[where f=nres_of])
    apply (auto intro: bot_Inf [symmetric]) []
  done
lemma nres_correctD:
  assumes "nres_of S ≤ SPEC Φ"
  shows 
  "S=dRETURN x ⟹ Φ x"
  "S≠dFAIL"
  using assms apply -
  apply (cases S, simp_all)+
  done
subsubsection ‹Transfer Theorems Setup›
interpretation dres: dist_transfer nres_of 
  apply unfold_locales
  apply (simp add: nres_transfer)
  done
lemma nres_of_transfer[refine_transfer]: "nres_of x ≤ nres_of x" by simp
lemma det_FAIL[refine_transfer]: "nres_of (dFAIL) ≤ FAIL" by auto
lemma det_SUCCEED[refine_transfer]: "nres_of (dSUCCEED) ≤ SUCCEED" by auto
lemma det_SPEC: "Φ x ⟹ nres_of (dRETURN x) ≤ SPEC Φ" by simp
lemma det_RETURN[refine_transfer]: 
  "nres_of (dRETURN x) ≤ RETURN x" by simp
lemma det_bind[refine_transfer]:
  assumes "nres_of m ≤ M"
  assumes "⋀x. nres_of (f x) ≤ F x"
  shows "nres_of (dbind m f) ≤ bind M F"
  using assms 
  apply (cases m) 
  apply (auto simp: pw_le_iff refine_pw_simps)
  done
interpretation det_assert: transfer_generic_Assert_remove 
  bind RETURN ASSERT ASSUME
  nres_of
  by unfold_locales
interpretation det_while: transfer_WHILE
  dbind dRETURN dWHILEIT dWHILEI dWHILET dWHILE 
  bind RETURN WHILEIT WHILEI WHILET WHILE nres_of
  apply unfold_locales
  apply (auto intro: det_bind)
  done
subsection ‹Transfer to Plain Function›
interpretation plain: transfer RETURN .
lemma plain_RETURN[refine_transfer]: "RETURN a ≤ RETURN a" by simp
lemma plain_bind[refine_transfer]: 
  "⟦RETURN x ≤ M; ⋀x. RETURN (f x) ≤ F x⟧ ⟹ RETURN (Let x f) ≤ bind M F"
  apply (erule order_trans[rotated,OF bind_mono(1)])
  apply assumption
  apply simp
  done
interpretation plain_assert: transfer_generic_Assert_remove 
  bind RETURN ASSERT ASSUME
  RETURN
  by unfold_locales
subsection ‹Total correctness in deterministic monad›
text ‹
  Sometimes one cannot extract total correct programs to executable plain 
  Isabelle functions, for example, if the total correctness only holds for
  certain preconditions. In those cases, one can still show
  ‹RETURN (the_res S) ≤ S'›. Here, ‹the_res› extracts
  the result from a deterministic monad. As ‹the_res› is executable,
  the above shows that ‹(the_res S)› is always a correct result.
›
fun the_res where "the_res (dRETURN x) = x"
text ‹The following lemma converts a proof-obligation
  with result extraction to a transfer proof obligation,
  and a proof obligation that the program yields not bottom.
  Note that this rule has to be applied manually, as, otherwise,
  it would interfere with the default setup, that tries to generate a
  plain function.
›
lemma the_resI:
  assumes "nres_of S ≤ S'"
  assumes "S ≠ dSUCCEED"
  shows "RETURN (the_res S) ≤ S'"
  using assms
  by (cases S, simp_all)
text ‹The following rule sets up a refinement goal, a transfer goal, and a 
  final optimization goal.›
definition "detTAG x ≡ x"
lemma detTAGI: "x = detTAG x" unfolding detTAG_def by simp
lemma autoref_detI:
  assumes "(b,a)∈⟨R⟩nres_rel"
  assumes "RETURN c ≤ b"
  assumes "c = detTAG d"
  shows "(RETURN d, a)∈⟨R⟩nres_rel"
  using assms
  unfolding nres_rel_def detTAG_def
  by simp
subsection ‹Relator-Based Transfer›
definition dres_nres_rel_internal_def: 
  "dres_nres_rel R ≡ {(c,a). nres_of c ≤ ⇓ R a}"
lemma dres_nres_rel_def: "⟨R⟩dres_nres_rel ≡ {(c,a). nres_of c ≤ ⇓ R a}"
  by (simp add: dres_nres_rel_internal_def relAPP_def)
lemma dres_nres_relI[intro?]: "nres_of c ≤ ⇓ R a ⟹ (c,a)∈⟨R⟩dres_nres_rel"
  by (simp add: dres_nres_rel_def)
lemma dres_nres_relD: "(c,a)∈⟨R⟩dres_nres_rel ⟹ nres_of c ≤ ⇓ R a"
  by (simp add: dres_nres_rel_def)
lemma dres_nres_rel_as_br_conv: 
  "⟨R⟩dres_nres_rel = br nres_of (λ_. True) O ⟨R⟩nres_rel"
  unfolding dres_nres_rel_def br_def nres_rel_def by auto
definition plain_nres_rel_internal_def: 
  "plain_nres_rel R ≡ {(c,a). RETURN c ≤ ⇓ R a}"
lemma plain_nres_rel_def: "⟨R⟩plain_nres_rel ≡ {(c,a). RETURN c ≤ ⇓ R a}"
  by (simp add: plain_nres_rel_internal_def relAPP_def)
lemma plain_nres_relI[intro?]: "RETURN c ≤ ⇓ R a ⟹ (c,a)∈⟨R⟩plain_nres_rel"
  by (simp add: plain_nres_rel_def)
lemma plain_nres_relD: "(c,a)∈⟨R⟩plain_nres_rel ⟹ RETURN c ≤ ⇓ R a"
  by (simp add: plain_nres_rel_def)
lemma plain_nres_rel_as_br_conv: 
  "⟨R⟩plain_nres_rel = br RETURN (λ_. True) O ⟨R⟩nres_rel"
  unfolding plain_nres_rel_def br_def nres_rel_def by auto
subsection ‹Post-Simplification Setup›
lemma dres_unit_simps[refine_transfer_post_simp]:
  "dbind (dRETURN (u::unit)) f = f ()"
  by auto
lemma Let_dRETURN_simp[refine_transfer_post_simp]:
  "Let m dRETURN = dRETURN m" by auto
lemmas [refine_transfer_post_simp] = dres_monad_laws
end