Theory HOLCF-Utils

theory "HOLCF-Utils"
  imports  HOLCF Pointwise
begin

default_sort type

lemmas cont_fun[simp]
lemmas cont2cont_fun[simp]

lemma cont_compose2:
  assumes " y. cont (λ x. c x y)"
  assumes " x. cont (λ y. c x y)"
  assumes "cont f"
  assumes "cont g"
  shows "cont (λx. c (f x) (g x))"
  by (intro cont_apply[OF assms(4) assms(2)]
            cont2cont_fun[OF cont_compose[OF _ assms(3)]]
            cont2cont_lambda[OF assms(1)])

lemma pointwise_adm:
  fixes P :: "'a::pcpo  'b::pcpo  bool"
  assumes "adm (λ x. P (fst x) (snd x))"
  shows "adm (λ m. pointwise P (fst m) (snd m))"
proof (rule admI, goal_cases)
  case prems: (1 Y)
  show ?case
    apply (rule pointwiseI)
    apply (rule admD[OF adm_subst[where t = "λp . (fst p x, snd p x)" for x, OF _ assms, simplified] chain Y])
    using prems(2) unfolding pointwise_def apply auto
    done
qed

lemma cfun_beta_Pair:
  assumes "cont (λ p. f (fst p) (snd p))"
  shows "csplit(Λ a b . f a b)(x, y) = f x y"
  apply simp
  apply (subst beta_cfun)
  apply (rule cont2cont_LAM')
  apply (rule assms)
  apply (rule beta_cfun)
  apply (rule cont2cont_fun)
  using assms
  unfolding prod_cont_iff
  apply auto
  done


lemma fun_upd_mono:
  "ρ1  ρ2  v1  v2  ρ1(x := v1)  ρ2(x := v2)"
  apply (rule fun_belowI)
  apply (case_tac "xa = x")
  apply simp
  apply (auto elim:fun_belowD)
  done

lemma fun_upd_cont[simp,cont2cont]:
  assumes "cont f" and "cont h"
  shows "cont (λ x. (f x)(v := h x) :: 'a  'b::pcpo)"
  by (rule cont2cont_lambda)(auto simp add: assms)

lemma fun_upd_belowI:
  assumes " z . z  x  ρ z  ρ' z" 
  assumes "y  ρ' x"
  shows  "ρ(x := y)  ρ'"
  apply (rule fun_belowI)
  using assms
  apply (case_tac "xa = x")
  apply auto
  done


lemma cont_if_else_above: 
  assumes "cont f"
  assumes "cont g"
  assumes " x. f x  g x"
  assumes " x y. x  y  P y  P x"
  assumes "adm P"
  shows "cont (λx. if P x then f x else g x)" (is "cont ?I")
proof(intro contI2 monofunI)
  fix x y :: 'a
  assume "x  y"
  with assms(4)[OF this]
  show "?I x  ?I y"
    apply (auto)
    apply (rule cont2monofunE[OF assms(1)], assumption)
    apply (rule below_trans[OF cont2monofunE[OF assms(1)] assms(3)], assumption)
    apply (rule cont2monofunE[OF assms(2)], assumption)
    done
next
  fix Y :: "nat  'a"
  assume "chain Y"
  assume "chain (λi . ?I (Y i))"

  have ch_f: "f ( i. Y i)  ( i. f (Y i))" by (metis chain Y assms(1) below_refl cont2contlubE)

  show "?I ( i. Y i)  ( i. ?I (Y i))" 
  proof(cases " i. P (Y i)")
    case True hence "P ( i. Y i)" by (metis chain Y adm_def assms(5))
    with True ch_f show ?thesis by auto
  next
    case False
    then obtain j where "¬ P (Y j)" by auto
    hence *:  " i  j. ¬ P (Y i)" "¬ P ( i. Y i)"
      apply (auto)
      apply (metis assms(4) chain_mono[OF chain Y])
      apply (metis assms(4) is_ub_thelub[OF chain Y])
      done

    have "?I ( i. Y i) = g ( i. Y i)" using * by simp
    also have " = g ( i. Y (i + j))" by (metis lub_range_shift[OF chain Y])
    also have " = ( i. (g (Y (i + j))))" by (rule cont2contlubE[OF assms(2) chain_shift[OF chain Y]] )
    also have " = ( i. (?I (Y (i + j))))" using * by auto
    also have " = ( i. (?I (Y i)))" by (metis lub_range_shift[OF chain (λi . ?I (Y i))])
    finally show ?thesis by simp
  qed
qed

fun up2option :: "'a::cpo  'a option"
  where "up2option Ibottom = None"
  |     "up2option (Iup a) = Some a"

lemma up2option_simps[simp]:
  "up2option  = None"
  "up2option (upx) = Some x"
  unfolding up_def by (simp_all add: cont_Iup inst_up_pcpo)

fun option2up :: "'a option  'a::cpo"
  where "option2up None = "
  |     "option2up (Some a) = upa"

lemma option2up_up2option[simp]:
  "option2up (up2option x) = x"
  by (cases x) auto
lemma up2option_option2up[simp]:
  "up2option (option2up x) = x"
  by (cases x) auto

lemma adm_subst2: "cont f  cont g  adm (λx. f (fst x) = g (snd x))"
  apply (rule admI)
  apply (simp add:
      cont2contlubE[where f = f]  cont2contlubE[where f = g]
      cont2contlubE[where f = snd]  cont2contlubE[where f = fst]
      )
  done


subsubsection ‹Composition of fun and cfun›

lemma cont2cont_comp [simp, cont2cont]:
  assumes "cont f"
  assumes " x. cont (f x)"
  assumes "cont g"
  shows "cont (λ x. (f x)  (g x))"
  unfolding comp_def
  by (rule cont2cont_lambda)
     (intro cont2cont  cont g cont f cont_compose2[OF cont2cont_fun[OF assms(1)] assms(2)] cont2cont_fun)

definition cfun_comp :: "('a::pcpo  'b::pcpo)  ('c::type  'a)  ('c::type  'b)"
  where  "cfun_comp = (Λ f ρ. (λ x. fx)  ρ)"

lemma [simp]: "cfun_compf(ρ(x := v)) = (cfun_compfρ)(x := fv)"
  unfolding cfun_comp_def by auto

lemma cfun_comp_app[simp]: "(cfun_compfρ) x = f(ρ x)"
  unfolding cfun_comp_def by auto

lemma fix_eq_fix:
  "f(fixg)  fixg  g(fixf)  fixf  fixf = fixg"
  by (metis fix_least_below below_antisym)

subsubsection ‹Additional transitivity rules›

text ‹
These collect side-conditions of the form @{term "cont f"}, so the usual way to discharge them
is to write @{text[source] "by this (intro cont2cont)+"} at the end.
›

lemma below_trans_cong[trans]:
  "a  f x  x  y  cont f  a  f y "
by (metis below_trans cont2monofunE)

lemma not_bot_below_trans[trans]:
  "a    a  b  b  "
  by (metis below_bottom_iff)

lemma not_bot_below_trans_cong[trans]:
  "f a    a  b  cont f  f b  "
  by (metis below_bottom_iff cont2monofunE)

end