Theory C-restr

theory "C-restr"
imports C "C-Meet" "HOLCF-Utils"
begin

subsubsection ‹The demand of a $C$-function›

text ‹
The demand is the least amount of resources required to produce a non-bottom element,
if at all.
›

definition demand :: "(C → 'a::pcpo) ⇒ C" where
  "demand f = (if f⋅C∞ ≠ ⊥ then C⇗(LEAST n. f⋅C⇗n⇖ ≠ ⊥)⇖ else C∞)"

text ‹
Because of continuity, a non-bottom value can always be obtained with finite resources.
›

lemma finite_resources_suffice:
  assumes "f⋅C∞ ≠ ⊥"
  obtains n where "f⋅C⇗n⇖ ≠ ⊥"
proof-
  {
  assume "∀n. f⋅(C⇗n⇖) = ⊥"
  hence "f⋅C∞ ⊑ ⊥"
    by (auto intro: lub_below[OF ch2ch_Rep_cfunR[OF chain_iterate]]
             simp add: Cinf_def fix_def2 contlub_cfun_arg[OF chain_iterate])
  with assms have False by simp
  }
  thus ?thesis using that by blast
qed

text ‹
Because of monotonicity, a non-bottom value can always be obtained with more resources.
›


lemma more_resources_suffice:
  assumes "f⋅r ≠ ⊥" and "r ⊑ r'"
  shows "f⋅r' ≠ ⊥"
  using assms(1) monofun_cfun_arg[OF assms(2), where  f = f]
  by auto

lemma infinite_resources_suffice:
  shows "f⋅r ≠ ⊥ ⟹ f⋅C∞ ≠ ⊥"
  by (erule more_resources_suffice[OF _ below_Cinf])

lemma demand_suffices:
  assumes "f⋅C∞ ≠ ⊥"
  shows "f⋅(demand f) ≠ ⊥"
  apply (simp add: assms demand_def)
  apply (rule finite_resources_suffice[OF assms])
  apply (rule LeastI)
  apply assumption
  done

lemma not_bot_demand:
  "f⋅r ≠ ⊥ ⟷ demand f ≠ C∞ ∧ demand f ⊑ r"
proof(intro iffI)
  assume "f⋅r ≠ ⊥"
  thus "demand f ≠ C∞ ∧ demand f ⊑ r"
    apply (cases r rule:C_cases)
    apply (auto intro: Least_le simp add: demand_def dest: infinite_resources_suffice)
    done
next
  assume *: "demand f ≠ C∞  ∧ demand f ⊑ r"
  then have "f⋅C∞ ≠ ⊥" by (auto intro: Least_le simp add: demand_def dest: infinite_resources_suffice)
  hence "f⋅(demand f) ≠ ⊥" by (rule demand_suffices)
  moreover from * have "demand f ⊑ r"..
  ultimately
  show "f⋅r ≠ ⊥" by (rule more_resources_suffice)
qed

lemma infinity_bot_demand:
  "f⋅C∞ = ⊥ ⟷ demand f = C∞"
  by (metis below_Cinf not_bot_demand)

lemma demand_suffices':
  assumes "demand f = C⇗n⇖"
  shows "f⋅(demand f) ≠ ⊥"
  by (metis C_eq_Cinf assms demand_suffices infinity_bot_demand)

lemma demand_Suc_Least:
  assumes [simp]: "f⋅⊥ = ⊥"
  assumes "demand f ≠ C∞"
  shows "demand f = C⇗(Suc (LEAST n. f⋅C⇗Suc n⇖ ≠ ⊥))⇖"
proof-
  from assms
  have "demand f = C⇗(LEAST n. f⋅C⇗n⇖ ≠ ⊥)⇖" by (auto simp add: demand_def)
  also
  then obtain n where "f⋅C⇗n⇖ ≠ ⊥" by (metis  demand_suffices')
  hence "(LEAST n. f⋅C⇗n⇖ ≠ ⊥) = Suc (LEAST n. f⋅C⇗Suc n⇖ ≠ ⊥)"
    apply (rule Least_Suc) by simp
  finally show ?thesis.
qed

lemma demand_C_case[simp]: "demand (C_case⋅f) = C ⋅ (demand f)"
proof(cases "demand (C_case⋅f) = C∞")
  case True
  then have "C_case⋅f⋅C∞ = ⊥"
    by (metis infinity_bot_demand)
  with True
  show ?thesis apply auto by (metis infinity_bot_demand)
next
  case False
  hence "demand (C_case⋅f) = C⇗Suc (LEAST n. (C_case⋅f)⋅C⇗Suc n⇖ ≠ ⊥)⇖"
    by (rule demand_Suc_Least[OF C.case_rews(1)])
  also have "… = C⋅C⇗LEAST n. f⋅C⇗n⇖ ≠ ⊥⇖" by simp
  also have "… = C⋅(demand  f)"
    using False unfolding demand_def by auto
  finally show ?thesis.
qed

lemma demand_contravariant:
  assumes "f ⊑ g"
  shows "demand g ⊑ demand f"
proof(cases "demand f" rule:C_cases)
  fix n
  assume "demand f = C⇗n⇖"
  hence "f⋅(demand f) ≠ ⊥" by (metis demand_suffices')
  also note monofun_cfun_fun[OF assms]
  finally have "g⋅(demand f) ≠ ⊥" by this (intro cont2cont)
  thus "demand g ⊑ demand f" unfolding not_bot_demand by auto
qed auto

subsubsection ‹Restricting functions with domain C›

fixrec C_restr :: "C → (C → 'a::pcpo) → (C → 'a)"
  where "C_restr⋅r⋅f⋅r' = (f⋅(r ⊓ r'))" 

abbreviation C_restr_syn :: "(C → 'a::pcpo) ⇒ C ⇒ (C → 'a)" ( ‹_|⇘_⇙› [111,110] 110)
  where "f|⇘r⇙ ≡ C_restr⋅r⋅f"

lemma [simp]: "⊥|⇘r⇙ = ⊥" by fixrec_simp
lemma [simp]: "f⋅⊥ = ⊥ ⟹ f|⇘⊥⇙ = ⊥"  by fixrec_simp

lemma C_restr_C_restr[simp]: "(v|⇘r'⇙)|⇘r⇙ = v|⇘(r' ⊓ r)⇙"
  by (rule cfun_eqI) simp

lemma C_restr_eqD:
  assumes "f|⇘r⇙ = g|⇘r⇙"
  assumes "r' ⊑ r"
  shows "f⋅r' = g⋅r'"
by (metis C_restr.simps assms below_refl is_meetI)

lemma C_restr_eq_lower:
  assumes "f|⇘r⇙ = g|⇘r⇙"
  assumes "r' ⊑ r"
  shows "f|⇘r'⇙ = g|⇘r'⇙"
by (metis C_restr_C_restr assms below_refl is_meetI)

lemma C_restr_below[intro, simp]:
  "x|⇘r⇙ ⊑ x"
  apply (rule cfun_belowI)
  apply simp
  by (metis below_refl meet_below2 monofun_cfun_arg)
  

lemma C_restr_below_cong:
  "(⋀ r'. r' ⊑ r ⟹ f ⋅ r' ⊑ g ⋅ r') ⟹ f|⇘r⇙ ⊑ g|⇘r⇙"
  apply (rule cfun_belowI)
  apply simp
  by (metis below_refl meet_below1)

lemma C_restr_cong:
  "(⋀ r'. r' ⊑ r ⟹ f ⋅ r' = g ⋅ r') ⟹ f|⇘r⇙ = g|⇘r⇙"
  apply (intro below_antisym C_restr_below_cong )
  by (metis below_refl)+

lemma C_restr_C_cong:
  "(⋀ r'. r' ⊑ r ⟹ f ⋅ (C⋅r') = g ⋅ (C⋅r')) ⟹ f⋅⊥=g⋅⊥ ⟹ f|⇘C⋅r⇙ = g|⇘C⋅r⇙"
  apply (rule C_restr_cong)
  by (case_tac r', auto)

lemma C_restr_C_case[simp]:
  "(C_case⋅f)|⇘C⋅r⇙ = C_case⋅(f|⇘r⇙)"
  apply (rule cfun_eqI)
  apply simp
  apply (case_tac x)
  apply simp
  apply simp
  done

lemma C_restr_bot_demand:
  assumes "C⋅r ⊑ demand f"
  shows "f|⇘r⇙ = ⊥"
proof(rule cfun_eqI)
  fix r'
  have "f⋅(r ⊓ r') = ⊥"
  proof(rule classical)
    have "r ⊑ C ⋅ r" by (rule below_C)
    also
    note assms
    also
    assume *: "f⋅(r ⊓ r') ≠ ⊥"
    hence "demand f ⊑ (r ⊓ r')" unfolding not_bot_demand by auto
    hence "demand f ⊑ r"  by (metis below_refl meet_below1 below_trans)
    finally (below_antisym) have "r = demand f" by this (intro cont2cont)
    with assms
    have "demand f = C∞" by (cases "demand f" rule:C_cases) (auto simp add: iterate_Suc[symmetric] simp del: iterate_Suc)
    thus "f⋅(r ⊓ r') = ⊥" by (metis not_bot_demand)
  qed
  thus "(f|⇘r⇙)⋅r' = ⊥⋅r'" by simp
qed

subsubsection ‹Restricting maps of C-ranged functions›

definition env_C_restr :: "C → ('var::type ⇒ (C → 'a::pcpo)) → ('var ⇒ (C → 'a))" where
  "env_C_restr = (Λ r f.  cfun_comp⋅(C_restr⋅r)⋅f)"

abbreviation env_C_restr_syn :: "('var::type ⇒ (C → 'a::pcpo)) ⇒ C ⇒  ('var ⇒ (C → 'a))" ( ‹_|∘⇘_⇙› [111,110] 110)
  where "f|∘⇘r⇙ ≡ env_C_restr⋅r⋅f"


lemma env_C_restr_upd[simp]: "(ρ(x := v))|∘⇘r⇙ = (ρ|∘⇘r⇙)(x := v|⇘r⇙)"
  unfolding env_C_restr_def by simp

lemma env_C_restr_lookup[simp]: "(ρ|∘⇘r⇙) v = ρ v|⇘r⇙"
  unfolding env_C_restr_def by simp

lemma env_C_restr_bot[simp]: " ⊥|∘⇘r⇙ = ⊥"
  unfolding env_C_restr_def by auto

lemma env_C_restr_restr_below[intro]: "ρ|∘⇘r⇙ ⊑ ρ"
  by (auto intro: fun_belowI)

lemma env_C_restr_env_C_restr[simp]: "(v|∘⇘r'⇙)|∘⇘r⇙ = v|∘⇘(r' ⊓ r)⇙"
  unfolding env_C_restr_def by auto

lemma env_C_restr_cong:
  "(⋀ x r'. r' ⊑ r ⟹ f x ⋅ r' = g x ⋅ r') ⟹ f|∘⇘r⇙ = g|∘⇘r⇙"
  unfolding env_C_restr_def
  by (rule ext) (auto intro: C_restr_cong)

end