Theory DenotSoundFSet
section "Soundness of the declarative semantics wrt. operational"
theory DenotSoundFSet
  imports SmallStepLam BigStepLam ChangeEnv
begin
subsection "Substitution preserves denotation"
  
lemma subst_app: "subst x v (EApp e1 e2) = EApp (subst x v e1) (subst x v e2)"
  by auto 
    
lemma subst_prim: "subst x v (EPrim f e1 e2) = EPrim f (subst x v e1) (subst x v e2)"
  by auto 
lemma subst_lam_eq: "subst x v (ELam x e) = ELam x e" by auto 
lemma subst_lam_neq: "y ≠ x ⟹ subst x v (ELam y e) = ELam y (subst x v e)" by simp 
lemma subst_if: "subst x v (EIf e1 e2 e3) = EIf (subst x v e1) (subst x v e2) (subst x v e3)"
  by auto 
lemma substitution:
  fixes Γ::env and A::val 
  assumes wte: "B ∈ E e Γ'" and wtv: "A ∈ E v []"
    and gp: "Γ' ≈ (x,A)#Γ" and v: "is_val v"
  shows "B ∈ E (subst x v e) Γ"
  using wte wtv gp v
proof (induction arbitrary: v A B Γ x rule: E.induct)
  case (1 n ρ)
  then show ?case by auto
next
  case (2 x ρ v A B Γ x')
  then show ?case 
    apply (simp only: env_eq_def)
    apply (cases "x = x'")
     apply simp apply clarify
     apply (rule env_strengthen)
      apply (rule e_sub)
       apply auto
    done
next
  case (3 x e ρ v A B Γ x')
  then show ?case 
    apply (case_tac "x' = x") apply (simp only: subst_lam_eq)
     apply (rule env_strengthen) apply assumption apply (simp add: env_eq_def) 
    apply (simp only: subst_lam_neq) apply (erule e_lam_elim)
    apply (rule e_lam_intro)
     apply assumption apply clarify apply (erule_tac x=v1 in allE) apply (erule_tac x=v2 in allE)
    apply clarify 
    apply (subgoal_tac "(x,v1)#ρ ≈ (x',A)#(x,v1)#Γ")
     prefer 2 apply (simp add: env_eq_def)
    apply blast 
    done
next
  case (4 e1 e2 ρ)
  then show ?case
    apply (simp only: subst_app)
    apply (erule e_app_elim) 
    apply (rule e_app_intro) 
        apply auto 
    done
next
  case (5 f e1 e2 ρ)
  then show ?case 
    apply (simp only: subst_prim) apply (erule e_prim_elim) apply simp 
    apply (rule_tac x=n1 in exI) apply (rule conjI)
     apply force
    apply (rule_tac x=n2 in exI) 
    apply auto
    done
next
  case (6 e1 e2 e3 ρ)
  then show ?case 
    apply (simp only: subst_if) apply (erule e_if_elim) apply (rename_tac n)
    apply simp
    apply (case_tac "n = 0") apply (rule_tac x=0 in exI)
     apply force
    apply (rule_tac x=n in exI) apply simp done
qed
 
subsection "Reduction preserves denotation"
  
lemma subject_reduction: fixes e::exp assumes v: "v ∈ E e ρ" and r: "e ⟶ e'" shows "v ∈ E e' ρ"
  using r v 
proof (induction arbitrary: v ρ rule: reduce.induct)
   case (beta v x e v' ρ)
   then show ?case apply (simp only: is_val_def)
     apply (erule e_app_elim) apply (erule e_lam_elim) apply clarify 
     apply (rename_tac f v2 v2' v3' f')
     apply (erule_tac x=v2' in allE) apply (erule_tac x=v3' in allE) apply clarify
     apply (subgoal_tac "v3' ∈ E (subst x v e) ρ") prefer 2 apply (rule substitution)
         apply (subgoal_tac "v3' ∈ E e ((x,v2)#ρ)") prefer 2 apply (rule raise_env)
           apply assumption apply (simp add: env_le_def) prefer 2 apply (rule env_strengthen)
          apply assumption apply force prefer 2 apply (subgoal_tac "(x,v2)#ρ ≈ (x,v2)#ρ") prefer 2
         apply (simp add: env_eq_def) apply assumption apply assumption
      apply simp
     apply simp
     apply (rule e_sub)
      apply assumption
     apply (rule val_le_trans)
      apply blast
     apply force  
     done
qed force+
theorem preservation: assumes v: "v ∈ E e ρ" and rr: "e ⟶* e'" shows "v ∈ E e' ρ"
  using rr v subject_reduction by (induction arbitrary: ρ v) auto 
lemma canonical_nat: assumes v: "VNat n ∈ E v ρ" and vv: "isval v" shows "v = ENat n"
  using v vv by (cases v) auto
lemma canonical_fun: assumes v: "VFun f ∈ E v ρ" and vv: "isval v" shows "∃ x e. v = ELam x e"
  using v vv by (cases v) auto
subsection "Progress"
theorem progress: assumes v: "v ∈ E e ρ" and r: "ρ = []" and fve: "FV e = {}"
  shows "is_val e ∨ (∃ e'. e ⟶ e')"
  using v r fve
proof (induction arbitrary: v rule: E.induct)
  case (4 e1 e2 ρ)
  show ?case 
    apply (rule e_app_elim) using 4(3) apply assumption
    apply (cases "is_val e1")
     apply (cases "is_val e2")
      apply (frule canonical_fun) apply force apply (erule exE)+ apply simp apply (rule disjI2) 
      apply (rename_tac x e)
      apply (rule_tac x="subst x e2 e" in exI)
      apply (rule beta) apply simp
    using 4 apply simp 
     apply blast
    using 4 apply simp 
    apply blast done
next
  case (5 f e1 e2 ρ)
   show ?case 
     apply (rule e_prim_elim) using 5(3) apply assumption
     using 5 apply (case_tac "isval e1")
      apply (case_tac "isval e2")
       apply (subgoal_tac "e1 = ENat n1") prefer 2 using canonical_nat apply blast 
       apply (subgoal_tac "e2 = ENat n2") prefer 2 using canonical_nat apply blast 
       apply force
      apply force
     apply force done
next
  case (6 e1 e2 e3 ρ)
  show ?case
    apply (rule e_if_elim) 
    using 6(4) apply assumption
    apply (cases "isval e1")
     apply (rename_tac n)
     apply (subgoal_tac "e1 = ENat n") prefer 2 apply (rule canonical_nat) apply blast apply blast
     apply (rule disjI2) apply (case_tac "n = 0") apply force apply force 
    apply (rule disjI2)
    using 6 apply (subgoal_tac "∃ e1'. e1 ⟶ e1'") prefer 2 apply force 
    apply clarify apply (rename_tac e1')
    apply (rule_tac x="EIf e1' e2 e3" in exI)
    apply (rule if_cond) apply assumption
    done
qed auto
    
subsection "Logical relation between values and big-step values"
fun good_entry :: "name ⇒ exp ⇒ benv ⇒ (val × bval set) × (val × bval set) ⇒ bool ⇒ bool" where
  "good_entry x e ρ ((v1,g1),(v2,g2)) r = ((∀ v ∈ g1. ∃ v'. (x,v)#ρ ⊢ e ⇓ v' ∧ v' ∈ g2) ∧ r)"
 
primrec good :: "val ⇒ bval set" where
  Gnat: "good (VNat n) = { BNat n }" |
  Gfun: "good (VFun f) = { vc. ∃ x e ρ. vc = BClos x e ρ 
          ∧ (ffold (good_entry x e ρ) True (fimage (map_prod (λv. (v,good v)) (λv. (v,good v))) f)) }"
inductive good_env :: "benv ⇒ env ⇒ bool" where
  genv_nil[intro!]: "good_env [] []" |
  genv_cons[intro!]: "⟦ v ∈ good v'; good_env ρ ρ' ⟧ ⟹ good_env ((x,v)#ρ) ((x,v')#ρ')" 
  
inductive_cases 
  genv_any_nil_inv: "good_env ρ []" and
  genv_any_cons_inv: "good_env ρ (b#ρ')" 
lemma lookup_good:
  assumes l: "lookup ρ' x = Some A" and EE: "good_env ρ ρ'"
  shows "∃ v. lookup ρ x = Some v ∧ v ∈ good A"
  using l EE
proof (induction ρ' arbitrary: x A ρ)
  case Nil
  show ?case apply (rule genv_any_nil_inv) using Nil by auto
next
  case (Cons a ρ')
  show ?case
    apply (rule genv_any_cons_inv) 
     using Cons apply force
    apply (rename_tac x') apply clarify
    using Cons apply (case_tac "x = x'") 
     apply force
    apply force 
    done
qed
abbreviation good_prod :: "val × val ⇒ (val × bval set) × (val × bval set)" where
  "good_prod ≡ map_prod (λv. (v,good v)) (λv. (v,good v))"
    
lemma good_prod_inj: "inj_on good_prod (fset A)"
  unfolding inj_on_def apply auto done
  
definition good_fun :: "func ⇒ name ⇒ exp ⇒ benv ⇒ bool" where
  "good_fun f x e ρ ≡ (ffold (good_entry x e ρ) True (fimage good_prod f))"
lemma good_fun_def2:
  "good_fun f x e ρ = ffold (good_entry x e ρ ∘ good_prod) True f"
proof -
  interpret ge: comp_fun_commute "(good_entry x e ρ) ∘ good_prod"
    unfolding comp_fun_commute_def by auto  
  show "good_fun f x e ρ
         = ffold ((good_entry x e ρ) ∘ good_prod) True f"
     using good_prod_inj[of "f"] good_fun_def
        ffold_fimage[of good_prod "f" "good_entry x e ρ" True] by auto
qed
lemma gfun_elim: "w ∈ good (VFun f) ⟹ ∃ x e ρ. w = BClos x e ρ ∧ good_fun f x e ρ"
  using good_fun_def by auto
  
lemma gfun_mem_iff: "good_fun f x e ρ = (∀ v1 v2. (v1,v2) ∈ fset f ⟶ 
    (∀ v ∈ good v1. ∃ v'. (x,v)#ρ ⊢ e ⇓ v' ∧ v' ∈ good v2))"
proof (induction f arbitrary: x e ρ)
  case empty
  interpret ge: comp_fun_commute "(good_entry x e ρ)"
    unfolding comp_fun_commute_def by auto
  from empty show ?case using good_fun_def2
    by (simp add: comp_fun_commute.ffold_empty ge.comp_comp_fun_commute)
next
  case (insert p f)
  interpret ge: comp_fun_commute "(good_entry x e ρ) ∘ good_prod"
    unfolding comp_fun_commute_def by auto
  have "good_fun (finsert p f) x e ρ
         = ffold ((good_entry x e ρ) ∘ good_prod) True (finsert p f)" by (simp add: good_fun_def2)
  also from insert(1) have "... = ((good_entry x e ρ) ∘ good_prod) p 
                  (ffold ((good_entry x e ρ) ∘ good_prod) True f)" by simp
  finally have 1: "good_fun (finsert p f) x e ρ
      = ((good_entry x e ρ) ∘ good_prod) p (ffold ((good_entry x e ρ) ∘ good_prod) True f)" .  
  show ?case
  proof
    assume 2: "good_fun (finsert p f) x e ρ"
    show "∀v1 v2. (v1, v2) ∈ fset (finsert p f) ⟶
       (∀v∈good v1. ∃v'. (x, v) # ρ ⊢ e ⇓ v' ∧ v' ∈ good v2)"
    proof clarify
      fix v1 v2 v assume 3: "(v1, v2) ∈ fset (finsert p f)" and 4: "v ∈ good v1"
      from 3 have "(v1,v2) = p ∨ (v1,v2) ∈ fset f" by auto
      from this show "∃v'. (x, v) # ρ ⊢ e ⇓ v' ∧ v' ∈ good v2"
      proof 
        assume v12_p: "(v1,v2) = p"
        from 1 v12_p[THEN sym] 2 4 show ?thesis by simp
      next
        assume v12_f: "(v1,v2) ∈ fset f"
        from 1 2 have 5: "good_fun f x e ρ" apply simp 
          apply (cases "(good_prod p)") by (auto simp: good_fun_def2)
        from v12_f 5 4 insert(2)[of x e ρ] show ?thesis by auto
      qed
    qed
  next
    assume 2: "∀v1 v2. (v1, v2) ∈ fset (finsert p f) ⟶
       (∀v∈good v1. ∃v'. (x, v) # ρ ⊢ e ⇓ v' ∧ v' ∈ good v2)"
    have 3: "good_entry x e ρ (good_prod p) True" 
      apply (cases p) apply simp apply clarify
    proof -
      fix v1 v2 v
      assume p: "p = (v1,v2)" and v_v1: "v ∈ good v1"
      from p have "(v1,v2) ∈ fset (finsert p f)" by simp
      from this 2 v_v1 show "∃v'. (x, v) # ρ ⊢ e ⇓ v' ∧ v' ∈ good v2" by blast
    qed        
    from insert(2) 2 have 4: "good_fun f x e ρ" by auto
    have "(good_entry x e ρ ∘ good_prod) p
     (ffold (good_entry x e ρ ∘ good_prod) True f)" 
      apply simp apply (cases "good_prod p")
      apply (rename_tac a b c)
      apply (case_tac a) apply simp
      apply (rule conjI) prefer 2 using 4 good_fun_def2 apply force
      using 3 apply force done
    from this 1 show "good_fun (finsert p f) x e ρ"
       unfolding good_fun_def by simp
  qed
qed
  
lemma gfun_mem: "⟦ (v1,v2) ∈ fset f; good_fun f x e ρ ⟧ 
      ⟹ ∀ v ∈ good v1. ∃ v'. (x,v)#ρ ⊢ e ⇓ v' ∧ v' ∈ good v2"
  using gfun_mem_iff by blast 
  
lemma gfun_intro: "(∀ v1 v2.(v1,v2)∈fset f⟶(∀v∈good v1.∃ v'.(x,v)#ρ ⊢ e ⇓ v'∧v'∈good v2))
  ⟹ good_fun f x e ρ" using gfun_mem_iff[of f x e ρ] by simp
    
lemma sub_good: fixes v::val assumes wv: "w ∈ good v" and vp_v: "v' ⊑ v" shows "w ∈ good v'"
proof (cases v)
  case (VNat n)
  from this wv vp_v show ?thesis by auto
next
  case (VFun t1)
  from vp_v VFun obtain t2 where b: "v' = VFun t2" and t2_t1: "fset t2 ⊆ fset t1" by auto
  from wv VFun obtain x e ρ where w: "w = BClos x e ρ" by auto
  from w wv VFun have gt1: "good_fun t1 x e ρ" by (simp add: good_fun_def)          
  have gt2: "good_fun t2 x e ρ" apply (rule gfun_intro) apply clarify
  proof -
    fix v1 v2 w1
    assume v12: "(v1,v2) ∈ fset t2" and w1_v1: "w1 ∈ good v1"
    from v12 t2_t1 have v12_t1: "(v1,v2) ∈ fset t1" by blast
    from gt1 v12_t1 w1_v1 show "∃v'. (x, w1) # ρ ⊢ e ⇓ v' ∧ v' ∈ good v2" 
      by (simp add: gfun_mem)
  qed
  from gt2 b w show ?thesis by (simp add: good_fun_def)
qed
subsection "Denotational semantics sound wrt. big-step"
    
lemma denot_terminates: assumes vp_e: "v' ∈ E e ρ'" and ge: "good_env ρ ρ'" 
  shows "∃ v. ρ ⊢ e ⇓ v ∧ v ∈ good v'"
  using vp_e ge 
proof (induction arbitrary: v' ρ rule: E.induct)
  case (1 n ρ) 
  then show ?case by auto
next 
  case (2 x ρ v' ρ')
  from 2 obtain v1 where lx_vpp: "lookup ρ x = Some v1" and vp_v1: "v' ⊑ v1" by auto
  from lx_vpp 2(2) obtain v2 where lx: "lookup ρ' x = Some v2" and v2_v1: "v2 ∈ good v1"
    using lookup_good[of ρ x v1 ρ'] by blast
  from lx have x_v2: "ρ' ⊢ EVar x ⇓ v2" by auto
  from v2_v1 vp_v1 have v2_vp: "v2 ∈ good v'" using sub_good by blast
  from x_v2 v2_vp show ?case by blast
next 
  case (3 x e ρ v' ρ')
  have 1: "ρ' ⊢ ELam x e ⇓ BClos x e ρ'" by auto
  have 2: "BClos x e ρ' ∈ good v'"
  proof -
    from 3(2) obtain t where vp: "v' = VFun t" and 
      body: "∀v1 v2. (v1, v2) ∈ fset t ⟶ v2 ∈ E e ((x, v1) # ρ)" by blast
    have gt: "good_fun t x e ρ'" apply (rule gfun_intro) apply clarify 
    proof -
      fix v1 v2 w1 assume v12_t: "(v1,v2) ∈ fset t" and w1_v1: "w1 ∈ good v1" 
      from v12_t body have v2_Ee: "v2 ∈ E e ((x, v1) # ρ)" by blast
      from 3(3) w1_v1 have ge: "good_env ((x,w1)#ρ') ((x,v1)#ρ)" by auto
      from v12_t v2_Ee ge 3(1)[of v1 v2 t v2]
      show "∃v'. (x, w1) # ρ' ⊢ e ⇓ v' ∧ v' ∈ good v2" by blast
    qed
    from vp gt show ?thesis unfolding good_fun_def by simp         
  qed
  from 1 2 show ?case by blast
next 
  case (4 e1 e2 ρ v' ρ')
  from 4(3) show ?case
  proof
    fix t v2 and v2'::val and v3' assume t_Ee1: "VFun t ∈ E e1 ρ" and v2_Ee2: "v2 ∈ E e2 ρ" and
      v23_t: "(v2',v3') ∈ fset t" and v2p_v2: "v2' ⊑ v2" and vp_v3p: "v' ⊑ v3'"
    from 4(1) t_Ee1 4(4) obtain w1 where e1_w1: "ρ' ⊢ e1 ⇓ w1" and
      w1_t: "w1 ∈ good (VFun t)" by blast
    from 4(2) v2_Ee2 4(4) obtain w2 where e2_w2: "ρ' ⊢ e2 ⇓ w2" and w2_v2: "w2 ∈ good v2" by blast
    from w1_t obtain x e ρ1 where w1: "w1 = BClos x e ρ1" and gt: "good_fun t x e ρ1"
      by (auto simp: good_fun_def)
    from w2_v2 v2p_v2 have w2_v2p: "w2 ∈ good v2'" by (rule sub_good)
    from v23_t gt w2_v2p obtain w3 where e_w3: "(x,w2)#ρ1 ⊢ e ⇓ w3" and w3_v3p: "w3 ∈ good v3'"
      using gfun_mem[of v2' v3' t x e ρ1] by blast
    from w3_v3p vp_v3p have w3_vp: "w3 ∈ good v'" by (rule sub_good)
    from e1_w1 e2_w2 w1 e_w3 w3_vp show "∃v. ρ' ⊢ EApp e1 e2 ⇓ v ∧ v ∈ good v'" by blast
  qed
next 
  case (5 f e1 e2 ρ v' ρ')
  from 5(3) show ?case
  proof
    fix n1 n2 assume n1_e1: "VNat n1 ∈ E e1 ρ" and n2_e2: "VNat n2 ∈ E e2 ρ" and
      vp: "v' = VNat (f n1 n2)"
    from 5(1)[of "VNat n1" ρ'] n1_e1 5(4) have e1_w1: "ρ' ⊢ e1 ⇓ BNat n1" by auto
    from 5(2)[of "VNat n2" ρ'] n2_e2 5(4) have e2_w2: "ρ' ⊢ e2 ⇓ BNat n2" by auto
    from e1_w1 e2_w2 have 1: "ρ' ⊢ EPrim f e1 e2 ⇓ BNat (f n1 n2)" by blast
    from vp have 2: "BNat (f n1 n2) ∈ good v'" by auto
    from 1 2 show "∃v. ρ' ⊢ EPrim f e1 e2 ⇓ v ∧ v ∈ good v'" by auto
  qed
next 
  case (6 e1 e2 e3 ρ v' ρ')
  from 6(4) show ?case
  proof
    fix n assume n_e1: "VNat n ∈ E e1 ρ" and els: "n = 0 ⟶ v' ∈ E e3 ρ" and
      thn: "n ≠ 0 ⟶ v' ∈ E e2 ρ"
    from 6(1)[of "VNat n" ρ'] n_e1 6(5) have e1_w1: "ρ' ⊢ e1 ⇓ BNat n" by auto
    show "∃v. ρ' ⊢ EIf e1 e2 e3 ⇓ v ∧ v ∈ good v'"
    proof (cases "n = 0")
      case True
      from 6(2)[of n v' ρ'] True els 6(5) obtain w3 where 
        e3_w3: "ρ' ⊢ e3 ⇓ w3" and w3_vp: "w3 ∈ good v'" by blast 
      from e1_w1 True e3_w3 w3_vp show ?thesis by blast
    next
      case False
      from 6(3)[of n v' ρ'] False thn 6(5) obtain w2 where 
        e2_w2: "ρ' ⊢ e2 ⇓ w2" and w2_vp: "w2 ∈ good v'" by blast 
      from e1_w1 False e2_w2 have "ρ' ⊢ EIf e1 e2 e3 ⇓ w2" 
        using eval_if1[of ρ' e1 n e2 w2 e3] by simp
      from this w2_vp show ?thesis by (rule_tac x=w2 in exI) simp
    qed
  qed
qed
theorem sound_wrt_op_sem:
  assumes E_e_n: "E e [] = E (ENat n) []" and fv_e: "FV e = {}" shows "e ⇓ ONat n"
proof -
  have "VNat n ∈ E (ENat n) []" by simp  
  with E_e_n have 1: "VNat n ∈ E e []" by simp
  have 2: "good_env [] []" by auto
  from 1 2 obtain v where e_v: "[] ⊢ e ⇓ v" and v_n: "v ∈ good (VNat n)" using denot_terminates by blast
  from v_n have v: "v = BNat n" by auto
  from e_v fv_e obtain v' ob where e_vp: "e ⟶* v'" and 
    vp_ob: "observe v' ob" and v_ob: "bs_observe v ob" using sound_wrt_small_step by blast
  from e_vp vp_ob v_ob v show ?thesis unfolding run_def by (case_tac ob) auto
qed
end