Theory Foreach_Refine

section ‹\isaheader{Example for Foreach-Loops}›
theory Foreach_Refine
imports 
  Collections.Refine_Dflt_Only_ICF 
begin

text ‹
  This example presents the usage of the foreach loop.
  We define a simple foreach loop that looks for the largest element with
  a given property. Ordered loops are used to be sure to find the largest one.
›

subsection ‹Definition›

definition find_max_invar where
  "find_max_invar P S it σ = 
     (case σ of None  (x  S - it. ¬(P x))
             | Some y  (P y  y  S-it  (x  S - it - {y}. ¬(P x))))"

definition find_max :: "('a::{linorder}  bool)  'a set  ('a option) nres" where
  "find_max P S  
   FOREACHoci ((≥)) (find_max_invar P S) S
     (λσ. σ = None) (λx _. RETURN (if P x then Some x else None)) None"

subsection ‹Correctness›
text ‹As simple correctness property, we show:
  If the algorithm returns the maximal element satisfying P›.
›
lemma find_max_correct:
  fixes S:: "'a::{linorder} set"
  assumes "finite S"
  shows "find_max P S  SPEC (λσ. case σ of None  xS. ¬(P x)
                                          | Some y  (P y  y  S  (xS. P x  y  x)))"
  unfolding find_max_def
proof (rule FOREACHoci_rule)
  show "finite S" by fact
next
  show "find_max_invar P S S None" 
  unfolding find_max_invar_def by simp
next
  fix x it σ
  assume "σ = None"
         "x  it"
         "it  S"
         "find_max_invar P S it σ"
         "yit - {x}. y  x"
         "yS - it. x  y"

  from find_max_invar P S it σ σ = None 
  have not_P_others: "xS - it. ¬ P x"
    by (simp add: find_max_invar_def)

  from x  it it  S have "x  S" by blast

  show "RETURN (if P x then Some x else None)  SPEC (find_max_invar P S (it - {x}))"
    using not_P_others x  S
    by (auto simp add: find_max_invar_def)
next
  fix σ
  assume "find_max_invar P S {} σ"
  thus "case σ of None  xS. ¬ P x
        | Some y  P y  y  S  (xS. P x  x  y)"
    by (cases σ, auto simp add: find_max_invar_def)
next
  fix it σ
  assume "it  {}"
         "it  S"
         "find_max_invar P S it σ"
         "σ  None"
         "xit. yS - it. x  y"

  from σ  None obtain y where σ_eq[simp]: "σ = Some y" by auto
  from find_max_invar P S it σ 
    have y_props[simp]: "P y" "y  S" "y  it" and not_P: "xS - it - {y}. ¬ P x"
    by (simp_all add: find_max_invar_def)
 
  { fix x
    assume "x  S" "P x"
    with not_P have "x  it  x = y" by auto
    with xit. yS - it. x  y y_props have "x  y" by auto
  } note less_eq_y = this

  show "case σ of None  xS. ¬ P x
        | Some y  P y  y  S  (xS. P x  x  y)" 
   by (simp add: find_max_invar_def Ball_def less_eq_y)
qed

subsection ‹Data Refinement and Determinization›
text ‹
  Next, we use automatic data refinement and transfer to generate an
  executable algorithm using a red-black-tree. 
›
schematic_goal find_max_impl_refine_aux:
  assumes invar_S: "rs.invar S"
  shows "RETURN (?f)  (find_max P (rs.α S))"
  unfolding find_max_def
  by (refine_transfer 
    RBTSetImpl.rs.rev_iterateoi_correct[unfolded set_iterator_rev_linord_def,
    OF invar_S])

concrete_definition find_max_impl for P S uses find_max_impl_refine_aux

lemma find_max_impl_refine:
  assumes invar_S: "rs.invar S"
  shows "RETURN (find_max_impl P S)  (find_max P (rs.α S))"
  using assms by (rule find_max_impl.refine)

subsubsection ‹Executable Code›

lemma find_max_impl_correct :
assumes invar_S: "rs.invar S"
shows "case find_max_impl P S of None  xrs.α S. ¬(P x)
                               | Some y  (P y  y  (rs.α S) 
                                  (xrs.α S. P x  y  x))"
proof -
  note find_max_impl_refine [of S P, OF invar_S]
  also note find_max_correct [OF RBTSetImpl.rs.finite[of S, OF invar_S], of P]
  finally show ?thesis by simp
qed

text ‹Finally, we can generate code›
export_code find_max_impl checking SML
export_code find_max_impl checking OCaml?
export_code find_max_impl checking Haskell?
export_code find_max_impl checking Scala
  
end