Theory Overapproximation

(*  Title:       Information Flow Control via Stateful Intransitive Noninterference in Language IMP
    Author:      Pasquale Noce
                 Senior Staff Firmware Engineer at HID Global, Italy
                 pasquale dot noce dot lavoro at gmail dot com
                 pasquale dot noce at hidglobal dot com
*)

section "Overapproximation of program semantics by the type system"

theory Overapproximation
  imports Idempotence
begin

text ‹
\null

The purpose of this section is to prove that type system @{const [names_short] noninterf.ctyping2}
overapproximates program semantics, namely that if (a) @{prop "(c, s) ⇒ t"}, (b) the type system
outputs a @{typ "state set"} @{term B} and a @{typ "vname set"} @{term Y} when it is input program
@{term c}, @{typ "state set"} @{term A}, and @{typ "vname set"} @{term X}, and (c) state @{term s}
agrees with a state in @{term A} on the value of every state variable in @{term X}, then @{term t}
must agree with some state in @{term B} on the value of every state variable in @{term Y} (lemma
@{text ctyping2_approx}).

This proof makes use of the lemma @{text ctyping1_idem} proven in the previous section.
›


subsection "Global context proofs"

lemma avars_aval:
 "s = t (⊆ avars a) ⟹ aval a s = aval a t"
by (induction a, simp_all)


subsection "Local context proofs"

context noninterf
begin


lemma interf_set_mono:
 "⟦A' ⊆ A; X ⊆ X'; ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y;
    ∀(B, Y) ∈ insert (Univ? A X, Z) U. B: dom ` Y ↝ W⟧ ⟹
  ∀(B, Y) ∈ insert (Univ? A' X', Z) U'. B: dom ` Y ↝ W"
by (subgoal_tac "Univ? A' X' ⊆ Univ? A X", fastforce,
 auto simp: univ_states_if_def)


lemma btyping1_btyping2_aux_1 [elim]:
  assumes
    A: "avars a1 = {}" and
    B: "avars a2 = {}" and
    C: "aval a1 (λx. 0) < aval a2 (λx. 0)"
  shows "aval a1 s < aval a2 s"
proof -
  have "aval a1 s = aval a1 (λx. 0) ∧ aval a2 s = aval a2 (λx. 0)"
    using A and B by (blast intro: avars_aval)
  thus ?thesis
    using C by simp
qed

lemma btyping1_btyping2_aux_2 [elim]:
  assumes
    A: "avars a1 = {}" and
    B: "avars a2 = {}" and
    C: "¬ aval a1 (λx. 0) < aval a2 (λx. 0)" and
    D: "aval a1 s < aval a2 s"
  shows False
proof -
  have "aval a1 s = aval a1 (λx. 0) ∧ aval a2 s = aval a2 (λx. 0)"
    using A and B by (blast intro: avars_aval)
  thus ?thesis
    using C and D by simp
qed

lemma btyping1_btyping2_aux:
 "⊢ b = Some v ⟹ ⊫ b (⊆ A, X) = Some (if v then A else {})"
by (induction b arbitrary: v, auto split: if_split_asm option.split_asm)

lemma btyping1_btyping2:
 "⊢ b = Some v ⟹ ⊨ b (⊆ A, X) = (if v then (A, {}) else ({}, A))"
by (simp add: btyping2_def btyping1_btyping2_aux)

lemma btyping2_aux_subset:
 "⊫ b (⊆ A, X) = Some A' ⟹ A' = {s. s ∈ A ∧ bval b s}"
by (induction b arbitrary: A', auto split: if_split_asm option.split_asm)

lemma btyping2_aux_diff:
 "⟦⊫ b (⊆ A, X) = Some B; ⊫ b (⊆ A', X') = Some B'; A' ⊆ A; B' ⊆ B⟧ ⟹
    A' - B' ⊆ A - B"
by (blast dest: btyping2_aux_subset)

lemma btyping2_aux_mono:
 "⟦⊫ b (⊆ A, X) = Some B; A' ⊆ A; X ⊆ X'⟧ ⟹
    ∃B'. ⊫ b (⊆ A', X') = Some B' ∧ B' ⊆ B"
by (induction b arbitrary: B, auto dest: btyping2_aux_diff split:
 if_split_asm option.split_asm)

lemma btyping2_mono:
 "⟦⊨ b (⊆ A, X) = (B1, B2); ⊨ b (⊆ A', X') = (B1', B2'); A' ⊆ A; X ⊆ X'⟧ ⟹
    B1' ⊆ B1 ∧ B2' ⊆ B2"
by (simp add: btyping2_def split: option.split_asm,
 frule_tac [3-4] btyping2_aux_mono, auto dest: btyping2_aux_subset)

lemma btyping2_un_eq:
 "⊨ b (⊆ A, X) = (B1, B2) ⟹ B1 ∪ B2 = A"
by (auto simp: btyping2_def dest: btyping2_aux_subset split: option.split_asm)

lemma btyping2_fst_empty:
 "⊨ b (⊆ {}, X) = ({}, {})"
by (auto simp: btyping2_def dest: btyping2_aux_subset split: option.split)

lemma btyping2_aux_eq:
 "⟦⊫ b (⊆ A, X) = Some A'; s = t (⊆ state ∩ X)⟧ ⟹ bval b s = bval b t"
proof (induction b arbitrary: A')
  fix A' v
  show
   "⟦⊫ Bc v (⊆ A, X) = Some A'; s = t (⊆ state ∩ X)⟧ ⟹
      bval (Bc v) s = bval (Bc v) t"
    by simp
next
  fix A' b
  show
   "⟦⋀A'. ⊫ b (⊆ A, X) = Some A' ⟹ s = t (⊆ state ∩ X) ⟹
      bval b s = bval b t;
    ⊫ Not b (⊆ A, X) = Some A'; s = t (⊆ state ∩ X)⟧ ⟹
      bval (Not b) s = bval (Not b) t"
    by (simp split: option.split_asm)
next
  fix A' b1 b2
  show
   "⟦⋀A'. ⊫ b1 (⊆ A, X) = Some A' ⟹ s = t (⊆ state ∩ X) ⟹
      bval b1 s = bval b1 t;
    ⋀A'. ⊫ b2 (⊆ A, X) = Some A' ⟹ s = t (⊆ state ∩ X) ⟹
      bval b2 s = bval b2 t;
    ⊫ And b1 b2 (⊆ A, X) = Some A'; s = t (⊆ state ∩ X)⟧ ⟹
      bval (And b1 b2) s = bval (And b1 b2) t"
    by (simp split: option.split_asm)
next
  fix A' a1 a2
  show
   "⟦⊫ Less a1 a2 (⊆ A, X) = Some A'; s = t (⊆ state ∩ X)⟧ ⟹
      bval (Less a1 a2) s = bval (Less a1 a2) t"
    by (subgoal_tac "aval a1 s = aval a1 t",
     subgoal_tac "aval a2 s = aval a2 t",
     auto intro!: avars_aval split: if_split_asm)
qed


lemma ctyping1_merge_in:
 "xs ∈ A ∪ B ⟹ xs ∈ A ⊔ B"
by (force simp: ctyping1_merge_def)

lemma ctyping1_merge_append_in:
 "⟦xs ∈ A; ys ∈ B⟧ ⟹ xs @ ys ∈ A ⊔@ B"
by (force simp: ctyping1_merge_append_def ctyping1_append_def ctyping1_merge_in)

lemma ctyping1_aux_nonempty:
 "⊢ c ≠ {}"
by (induction c, simp_all add: Let_def ctyping1_append_def
 ctyping1_merge_def ctyping1_merge_append_def, fastforce+)

lemma ctyping1_mono:
 "⟦(B, Y) = ⊢ c (⊆ A, X); (B', Y') = ⊢ c (⊆ A', X'); A' ⊆ A; X ⊆ X'⟧ ⟹
    B' ⊆ B ∧ Y ⊆ Y'"
by (auto simp: ctyping1_def)

lemma ctyping2_fst_empty:
 "Some (B, Y) = (U, v) ⊨ c (⊆ {}, X) ⟹ (B, Y) = ({}, UNIV)"
proof (induction "(U, v)" c "{} :: state set" X arbitrary: B Y U v
 rule: ctyping2.induct)
  fix C X Y U v b c1 c2
  show
   "⟦⋀U' p B2 C Y.
      (U', p) = (insert (Univ? {} X, bvars b) U, ⊨ b (⊆ {}, X)) ⟹
      ({}, B2) = p ⟹ Some (C, Y) = (U', v) ⊨ c1 (⊆ {}, X) ⟹
      (C, Y) = ({}, UNIV);
    ⋀U' p B1 C Y.
      (U', p) = (insert (Univ? {} X, bvars b) U, ⊨ b (⊆ {}, X)) ⟹
      (B1, {}) = p ⟹ Some (C, Y) = (U', v) ⊨ c2 (⊆ {}, X) ⟹
      (C, Y) = ({}, UNIV);
    Some (C, Y) = (U, v) ⊨ IF b THEN c1 ELSE c2 (⊆ {}, X)⟧ ⟹
      (C, Y) = ({}, UNIV)"
    by (fastforce simp: btyping2_fst_empty split: option.split_asm)
next
  fix B X Z U v b c
  show
   "⟦⋀B2 C Y B1' B2' B Z.
      ({}, B2) = ⊨ b (⊆ {}, X) ⟹
      (C, Y) = ⊢ c (⊆ {}, X) ⟹
      (B1', B2') = ⊨ b (⊆ C, Y) ⟹
      ∀(B, W) ∈ insert (Univ? {} X ∪ Univ? C Y, bvars b) U.
        B: dom ` W ↝ UNIV ⟹
      Some (B, Z) = ({}, False) ⊨ c (⊆ {}, X) ⟹
      (B, Z) = ({}, UNIV);
    ⋀B1 B2 C Y B2' B Z.
      (B1, B2) = ⊨ b (⊆ {}, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹
      ({}, B2') = ⊨ b (⊆ C, Y) ⟹
      ∀(B, W) ∈ insert (Univ? {} X ∪ Univ? C Y, bvars b) U.
        B: dom ` W ↝ UNIV ⟹
      Some (B, Z) = ({}, False) ⊨ c (⊆ {}, Y) ⟹
      (B, Z) = ({}, UNIV);
    Some (B, Z) = (U, v) ⊨ WHILE b DO c (⊆ {}, X)⟧ ⟹
      (B, Z) = ({}, UNIV)"
    by (simp split: if_split_asm option.split_asm prod.split_asm,
     (fastforce simp: btyping2_fst_empty ctyping1_def)+)
qed (simp_all split: if_split_asm option.split_asm prod.split_asm)


lemma ctyping2_mono_assign [elim!]:
 "⟦(U, False) ⊨ x ::= a (⊆ A, X) = Some (C, Z); A' ⊆ A; X ⊆ X';
    ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y⟧ ⟹
  ∃C' Z'. (U', False) ⊨ x ::= a (⊆ A', X') = Some (C', Z') ∧
    C' ⊆ C ∧ Z ⊆ Z'"
by (frule interf_set_mono [where W = "{dom x}"], auto split: if_split_asm)

lemma ctyping2_mono_seq:
  assumes
    A: "⋀A' B X' Y U'.
      (U, False) ⊨ c1 (⊆ A, X) = Some (B, Y) ⟹ A' ⊆ A ⟹ X ⊆ X' ⟹
        ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y ⟹
          ∃B' Y'. (U', False) ⊨ c1 (⊆ A', X') = Some (B', Y') ∧
            B' ⊆ B ∧ Y ⊆ Y'" and
    B: "⋀p B Y B' C Y' Z U'.
      (U, False) ⊨ c1 (⊆ A, X) = Some p ⟹ (B, Y) = p ⟹
        (U, False) ⊨ c2 (⊆ B, Y) = Some (C, Z) ⟹ B' ⊆ B ⟹ Y ⊆ Y' ⟹
          ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y ⟹
            ∃C' Z'. (U', False) ⊨ c2 (⊆ B', Y') = Some (C', Z') ∧
              C' ⊆ C ∧ Z ⊆ Z'" and
    C: "(U, False) ⊨ c1;; c2 (⊆ A, X) = Some (C, Z)" and
    D: "A' ⊆ A" and
    E: "X ⊆ X'" and
    F: "∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y"
  shows "∃C' Z'. (U', False) ⊨ c1;; c2 (⊆ A', X') = Some (C', Z') ∧
    C' ⊆ C ∧ Z ⊆ Z'"
proof -
  obtain B Y where "(U, False) ⊨ c1 (⊆ A, X) = Some (B, Y) ∧
    (U, False) ⊨ c2 (⊆ B, Y) = Some (C, Z)"
    using C by (auto split: option.split_asm)
  moreover from this obtain B' Y' where
    G: "(U', False) ⊨ c1 (⊆ A', X') = Some (B', Y') ∧ B' ⊆ B ∧ Y ⊆ Y'"
    using A and D and E and F by fastforce
  ultimately obtain C' Z' where
   "(U', False) ⊨ c2 (⊆ B', Y') = Some (C', Z') ∧ C' ⊆ C ∧ Z ⊆ Z'"
    using B and F by fastforce
  thus ?thesis
    using G by simp
qed

lemma ctyping2_mono_if:
  assumes
    A: "⋀W p B1 B2 B1' C1 X' Y1 W'. (W, p) =
      (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹ (B1, B2) = p ⟹
        (W, False) ⊨ c1 (⊆ B1, X) = Some (C1, Y1) ⟹ B1' ⊆ B1 ⟹
          X ⊆ X' ⟹ ∀(B', Y') ∈ W'. ∃(B, Y) ∈ W. B' ⊆ B ∧ Y' ⊆ Y ⟹
            ∃C1' Y1'. (W', False) ⊨ c1 (⊆ B1', X') = Some (C1', Y1') ∧
              C1' ⊆ C1 ∧ Y1 ⊆ Y1'" and
    B: "⋀W p B1 B2 B2' C2 X' Y2 W'. (W, p) =
      (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹ (B1, B2) = p ⟹
        (W, False) ⊨ c2 (⊆ B2, X) = Some (C2, Y2) ⟹ B2' ⊆ B2 ⟹
          X ⊆ X' ⟹ ∀(B', Y') ∈ W'. ∃(B, Y) ∈ W. B' ⊆ B ∧ Y' ⊆ Y ⟹
            ∃C2' Y2'. (W', False) ⊨ c2 (⊆ B2', X') = Some (C2', Y2') ∧
              C2' ⊆ C2 ∧ Y2 ⊆ Y2'" and
    C: "(U, False) ⊨ IF b THEN c1 ELSE c2 (⊆ A, X) = Some (C, Y)" and
    D: "A' ⊆ A" and
    E: "X ⊆ X'" and
    F: "∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y"
  shows "∃C' Y'. (U', False) ⊨ IF b THEN c1 ELSE c2 (⊆ A', X') =
    Some (C', Y') ∧ C' ⊆ C ∧ Y ⊆ Y'"
proof -
  let ?W = "insert (Univ? A X, bvars b) U"
  let ?W' = "insert (Univ? A' X', bvars b) U'"
  obtain B1 B2 C1 C2 Y1 Y2 where
    G: "(C, Y) = (C1 ∪ C2, Y1 ∩ Y2) ∧ (B1, B2) = ⊨ b (⊆ A, X) ∧
      Some (C1, Y1) = (?W, False) ⊨ c1 (⊆ B1, X) ∧
      Some (C2, Y2) = (?W, False) ⊨ c2 (⊆ B2, X)"
    using C by (simp split: option.split_asm prod.split_asm)
  moreover obtain B1' B2' where H: "(B1', B2') = ⊨ b (⊆ A', X')"
    by (cases "⊨ b (⊆ A', X')", simp)
  ultimately have I: "B1' ⊆ B1 ∧ B2' ⊆ B2"
    by (metis btyping2_mono D E)
  moreover have J: "∀(B', Y') ∈ ?W'. ∃(B, Y) ∈ ?W. B' ⊆ B ∧ Y' ⊆ Y"
    using D and E and F by (auto simp: univ_states_if_def)
  ultimately have "∃C1' Y1'.
    (?W', False) ⊨ c1 (⊆ B1', X') = Some (C1', Y1') ∧ C1' ⊆ C1 ∧ Y1 ⊆ Y1'"
    using A and E and G by force
  moreover have "∃C2' Y2'.
    (?W', False) ⊨ c2 (⊆ B2', X') = Some (C2', Y2') ∧ C2' ⊆ C2 ∧ Y2 ⊆ Y2'"
    using B and E and G and I and J by force
  ultimately show ?thesis
    using G and H by (auto split: prod.split)
qed

lemma ctyping2_mono_while:
  assumes
    A: "⋀B1 B2 C Y B1' B2' D1 E X' V U'. (B1, B2) = ⊨ b (⊆ A, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹ (B1', B2') = ⊨ b (⊆ C, Y) ⟹
        ∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
          B: dom ` W ↝ UNIV ⟹
          ({}, False) ⊨ c (⊆ B1, X) = Some (E, V) ⟹ D1 ⊆ B1 ⟹
            X ⊆ X' ⟹ ∀(B', Y') ∈ U'. ∃(B, Y) ∈ {}. B' ⊆ B ∧ Y' ⊆ Y ⟹
              ∃E' V'. (U', False) ⊨ c (⊆ D1, X') = Some (E', V') ∧
                E' ⊆ E ∧ V ⊆ V'" and
    B: "⋀B1 B2 C Y B1' B2' D1' F Y' W U'. (B1, B2) = ⊨ b (⊆ A, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹ (B1', B2') = ⊨ b (⊆ C, Y) ⟹
        ∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
          B: dom ` W ↝ UNIV ⟹
          ({}, False) ⊨ c (⊆ B1', Y) = Some (F, W) ⟹ D1' ⊆ B1' ⟹
            Y ⊆ Y' ⟹ ∀(B', Y') ∈ U'. ∃(B, Y) ∈ {}. B' ⊆ B ∧ Y' ⊆ Y ⟹
              ∃F' W'. (U', False) ⊨ c (⊆ D1', Y') = Some (F', W') ∧
                F' ⊆ F ∧ W ⊆ W'" and
    C: "(U, False) ⊨ WHILE b DO c (⊆ A, X) = Some (B, Z)" and
    D: "A' ⊆ A" and
    E: "X ⊆ X'" and
    F: "∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y"
  shows "∃B' Z'. (U', False) ⊨ WHILE b DO c (⊆ A', X') = Some (B', Z') ∧
    B' ⊆ B ∧ Z ⊆ Z'"
proof -
  obtain B1 B1' B2 B2' C E F V W Y where G: "(B1, B2) = ⊨ b (⊆ A, X) ∧
    (C, Y) = ⊢ c (⊆ B1, X) ∧ (B1', B2') = ⊨ b (⊆ C, Y) ∧
    (∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
      B: dom ` W ↝ UNIV) ∧
    Some (E, V) = ({}, False) ⊨ c (⊆ B1, X) ∧
    Some (F, W) = ({}, False) ⊨ c (⊆ B1', Y) ∧
    (B, Z) = (B2 ∪ B2', Univ?? B2 X ∩ Y)"
    using C by (force split: if_split_asm option.split_asm prod.split_asm)
  moreover obtain D1 D2 where H: "⊨ b (⊆ A', X') = (D1, D2)"
    by (cases "⊨ b (⊆ A', X')", simp)
  ultimately have I: "D1 ⊆ B1 ∧ D2 ⊆ B2"
    by (smt (verit) btyping2_mono D E)
  moreover obtain C' Y' where J: "(C', Y') = ⊢ c (⊆ D1, X')"
    by (cases "⊢ c (⊆ D1, X')", simp)
  ultimately have K: "C' ⊆ C ∧ Y ⊆ Y'"
    by (meson ctyping1_mono E G)
  moreover obtain D1' D2' where L: "⊨ b (⊆ C', Y') = (D1', D2')"
    by (cases "⊨ b (⊆ C', Y')", simp)
  ultimately have M: "D1' ⊆ B1' ∧ D2' ⊆ B2'"
    by (smt (verit) btyping2_mono G)
  then obtain F' W' where
   "({}, False) ⊨ c (⊆ D1', Y') = Some (F', W') ∧ F' ⊆ F ∧ W ⊆ W'"
    using B and F and G and K by force
  moreover obtain E' V' where
   "({}, False) ⊨ c (⊆ D1, X') = Some (E', V') ∧ E' ⊆ E ∧ V ⊆ V'"
    using A and E and F and G and I by force
  moreover have "Univ? A' X' ⊆ Univ? A X"
    using D and E by (auto simp: univ_states_if_def)
  moreover have "Univ? C' Y' ⊆ Univ? C Y"
    using K by (auto simp: univ_states_if_def)
  ultimately have "(U', False) ⊨ WHILE b DO c (⊆ A', X') =
    Some (D2 ∪ D2', Univ?? D2 X' ∩ Y')"
    using F and G and H and J [symmetric] and L by force
  moreover have "D2 ∪ D2' ⊆ B"
    using G and I and M by auto
  moreover have "Z ⊆ Univ?? D2 X' ∩ Y'"
    using E and G and I and K by auto
  ultimately show ?thesis
    by simp
qed

lemma ctyping2_mono:
 "⟦(U, False) ⊨ c (⊆ A, X) = Some (C, Z); A' ⊆ A; X ⊆ X';
    ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y⟧ ⟹
  ∃C' Z'. (U', False) ⊨ c (⊆ A', X') = Some (C', Z') ∧ C' ⊆ C ∧ Z ⊆ Z'"
proof (induction "(U, False)" c A X arbitrary: A' C X' Z U U'
 rule: ctyping2.induct)
  fix A A' X X' U U' C Z c1 c2
  show
   "⟦⋀A' B X' Y U'.
      (U, False) ⊨ c1 (⊆ A, X) = Some (B, Y) ⟹
      A' ⊆ A ⟹ X ⊆ X' ⟹
      ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y ⟹
      ∃B' Y'. (U', False) ⊨ c1 (⊆ A', X') = Some (B', Y') ∧
        B' ⊆ B ∧ Y ⊆ Y';
    ⋀p B Y A' C X' Z U'. (U, False) ⊨ c1 (⊆ A, X) = Some p ⟹
      (B, Y) = p ⟹ (U, False) ⊨ c2 (⊆ B, Y) = Some (C, Z) ⟹
      A' ⊆ B ⟹ Y ⊆ X' ⟹
      ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y ⟹
      ∃C' Z'. (U', False) ⊨ c2 (⊆ A', X') = Some (C', Z') ∧
        C' ⊆ C ∧ Z ⊆ Z';
    (U, False) ⊨ c1;; c2 (⊆ A, X) = Some (C, Z);
    A' ⊆ A; X ⊆ X';
    ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y⟧ ⟹
      ∃C' Z'. (U', False) ⊨ c1;; c2 (⊆ A', X') = Some (C', Z') ∧
        C' ⊆ C ∧ Z ⊆ Z'"
    by (rule ctyping2_mono_seq)
next
  fix A A' X X' U U' C Z b c1 c2
  show
   "⟦⋀U'' p B1 B2 A' C X' Z U'.
      (U'', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
      (B1, B2) = p ⟹ (U'', False) ⊨ c1 (⊆ B1, X) = Some (C, Z) ⟹
      A' ⊆ B1 ⟹ X ⊆ X' ⟹
      ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U''. B' ⊆ B ∧ Y' ⊆ Y ⟹
      ∃C' Z'. (U', False) ⊨ c1 (⊆ A', X') = Some (C', Z') ∧
        C' ⊆ C ∧ Z ⊆ Z';
    ⋀U'' p B1 B2 A' C X' Z U'.
      (U'', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
      (B1, B2) = p ⟹ (U'', False) ⊨ c2 (⊆ B2, X) = Some (C, Z) ⟹
      A' ⊆ B2 ⟹ X ⊆ X' ⟹
      ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U''. B' ⊆ B ∧ Y' ⊆ Y ⟹
      ∃C' Z'. (U', False) ⊨ c2 (⊆ A', X') = Some (C', Z') ∧
        C' ⊆ C ∧ Z ⊆ Z';
    (U, False) ⊨ IF b THEN c1 ELSE c2 (⊆ A, X) = Some (C, Z);
    A' ⊆ A; X ⊆ X';
    ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y⟧ ⟹
      ∃C' Z'. (U', False) ⊨ IF b THEN c1 ELSE c2 (⊆ A', X') =
        Some (C', Z') ∧ C' ⊆ C ∧ Z ⊆ Z'"
    by (rule ctyping2_mono_if)
next
  fix A A' X X' U U' B Z b c
  show
   "⟦⋀B1 B2 C Y B1' B2' A' B X' Z U'.
      (B1, B2) = ⊨ b (⊆ A, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹
      (B1', B2') = ⊨ b (⊆ C, Y) ⟹
      ∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
        B: dom ` W ↝ UNIV ⟹
      ({}, False) ⊨ c (⊆ B1, X) = Some (B, Z) ⟹
      A' ⊆ B1 ⟹ X ⊆ X' ⟹
      ∀(B', Y') ∈ U'. ∃(B, Y) ∈ {}. B' ⊆ B ∧ Y' ⊆ Y ⟹
        ∃B' Z'. (U', False) ⊨ c (⊆ A', X') = Some (B', Z') ∧
          B' ⊆ B ∧ Z ⊆ Z';
    ⋀B1 B2 C Y B1' B2' A' B X' Z U'.
      (B1, B2) = ⊨ b (⊆ A, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹
      (B1', B2') = ⊨ b (⊆ C, Y) ⟹
      ∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
        B: dom ` W ↝ UNIV ⟹
      ({}, False) ⊨ c (⊆ B1', Y) = Some (B, Z) ⟹
      A' ⊆ B1' ⟹ Y ⊆ X' ⟹
      ∀(B', Y') ∈ U'. ∃(B, Y) ∈ {}. B' ⊆ B ∧ Y' ⊆ Y ⟹
        ∃B' Z'. (U', False) ⊨ c (⊆ A', X') = Some (B', Z') ∧
          B' ⊆ B ∧ Z ⊆ Z';
    (U, False) ⊨ WHILE b DO c (⊆ A, X) = Some (B, Z);
    A' ⊆ A; X ⊆ X';
    ∀(B', Y') ∈ U'. ∃(B, Y) ∈ U. B' ⊆ B ∧ Y' ⊆ Y⟧ ⟹
      ∃B' Z'. (U', False) ⊨ WHILE b DO c (⊆ A', X') =
        Some (B', Z') ∧ B' ⊆ B ∧ Z ⊆ Z'"
    by (rule ctyping2_mono_while)
qed fastforce+


lemma ctyping1_ctyping2_fst_assign [elim!]:
  assumes
    A: "(C, Z) = ⊢ x ::= a (⊆ A, X)" and
    B: "Some (C', Z') = (U, False) ⊨ x ::= a (⊆ A, X)"
  shows "C' ⊆ C"
proof -
  {
    fix s
    assume "s ∈ A"
    moreover assume "avars a = {}"
    hence "aval a s = aval a (λx. 0)"
      by (blast intro: avars_aval)
    ultimately have "∃s'. (∃t. s(x := aval a s) = (λx'. case case
      if x' = x then Some (Some (aval a (λx. 0))) else None of
        None ⇒ None | Some v ⇒ Some v of
          None ⇒ s' x' | Some None ⇒ t x' | Some (Some i) ⇒ i)) ∧ s' ∈ A"
      by fastforce
  }
  note C = this
  from A and B show ?thesis
    by (clarsimp simp: ctyping1_def ctyping1_seq_def split: if_split_asm,
     erule_tac C, simp, fastforce)
qed

lemma ctyping1_ctyping2_fst_seq:
  assumes
    A: "⋀B B' Y Y'. (B, Y) = ⊢ c1 (⊆ A, X) ⟹
      Some (B', Y') = (U, False) ⊨ c1 (⊆ A, X) ⟹ B' ⊆ B" and
    B: "⋀p B Y C C' Z Z'. (U, False) ⊨ c1 (⊆ A, X) = Some p ⟹
      (B, Y) = p ⟹ (C, Z) = ⊢ c2 (⊆ B, Y) ⟹
        Some (C', Z') = (U, False) ⊨ c2 (⊆ B, Y) ⟹ C' ⊆ C" and
    C: "(C, Z) = ⊢ c1;; c2 (⊆ A, X)" and
    D: "Some (C', Z') = (U, False) ⊨ c1;; c2 (⊆ A, X)"
  shows "C' ⊆ C"
proof -
  let ?f = "foldl (;;) (λx. None)"
  let ?P = "λr A S. ∃f s. (∃t. r = (λx. case f x of
    None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i)) ∧
    (∃ys. f = ?f ys ∧ ys ∈ S) ∧ s ∈ A"
  let ?F = "λA S. {r. ?P r A S}"
  {
    fix s3 B' Y'
    assume
      E: "⋀B'' B C C' Z'. B' = B'' ⟹ B = B'' ⟹ C = ?F B'' (⊢ c2) ⟹
        Some (C', Z') = (U, False) ⊨ c2 (⊆ B'', Y') ⟹
          C' ⊆ ?F B'' (⊢ c2)" and
      F: "⋀B B''. B = ?F A (⊢ c1) ⟹ B'' = B' ⟹ B' ⊆ ?F A (⊢ c1)" and
      G: "Some (C', Z') = (U, False) ⊨ c2 (⊆ B', Y')" and
      H: "s3 ∈ C'"
    have "?P s3 A (⊢ c1 ⊔@ ⊢ c2)"
    proof -
      obtain s2 and t2 and ys2 where
        I: "s3 = (λx. case ?f ys2 x of
          None ⇒ s2 x | Some None ⇒ t2 x | Some (Some i) ⇒ i) ∧
          s2 ∈ B' ∧ ys2 ∈ ⊢ c2"
        using E and G and H by fastforce
      from this obtain s1 and t1 and ys1 where
        J: "s2 = (λx. case ?f ys1 x of
          None ⇒ s1 x | Some None ⇒ t1 x | Some (Some i) ⇒ i) ∧
          s1 ∈ A ∧ ys1 ∈ ⊢ c1"
        using F by fastforce
      let ?t = "λx. case ?f ys2 x of
        None ⇒ case ?f ys1 x of Some None ⇒ t1 x | _ ⇒ 0 |
        Some None ⇒ t2 x | _ ⇒ 0"
      from I and J have "s3 = (λx. case ?f (ys1 @ ys2) x of
        None ⇒ s1 x | Some None ⇒ ?t x | Some (Some i) ⇒ i)"
        by (fastforce dest: last_in_set simp: Let_def ctyping1_seq_last
         split: option.split)
      moreover have "ys1 @ ys2 ∈ ⊢ c1 ⊔@ ⊢ c2"
        by (simp add: ctyping1_merge_append_in I J)
      ultimately show ?thesis
        using J by fastforce
    qed
  }
  note E = this
  from A and B and C and D show ?thesis
    by (auto simp: ctyping1_def split: option.split_asm, erule_tac E)
qed

lemma ctyping1_ctyping2_fst_if:
  assumes
    A: "⋀U' p B1 B2 C1 C1' Y1 Y1'.
      (U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
        (B1, B2) = p ⟹ (C1, Y1) = ⊢ c1 (⊆ B1, X) ⟹
          Some (C1', Y1') = (U', False) ⊨ c1 (⊆ B1, X) ⟹ C1' ⊆ C1" and
    B: "⋀U' p B1 B2 C2 C2' Y2 Y2'.
      (U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
        (B1, B2) = p ⟹ (C2, Y2) = ⊢ c2 (⊆ B2, X) ⟹
          Some (C2', Y2') = (U', False) ⊨ c2 (⊆ B2, X) ⟹ C2' ⊆ C2" and
    C: "(C, Y) = ⊢ IF b THEN c1 ELSE c2 (⊆ A, X)" and
    D: "Some (C', Y') = (U, False) ⊨ IF b THEN c1 ELSE c2 (⊆ A, X)"
  shows "C' ⊆ C"
proof -
  let ?f = "foldl (;;) (λx. None)"
  let ?P = "λr A S. ∃f s. (∃t. r = (λx. case f x of
    None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i)) ∧
    (∃ys. f = ?f ys ∧ ys ∈ S) ∧ s ∈ A"
  let ?F = "λA S. {r. ?P r A S}"
  let ?S1 = "λf. if f = Some True ∨ f = None then ⊢ c1 else {}"
  let ?S2 = "λf. if f = Some False ∨ f = None then ⊢ c2 else {}"
  {
    fix s' B1 B2 C1
    assume
      E: "⋀U' B1' C1' C1''. U' = insert (Univ? A X, bvars b) U ⟹
        B1' = B1 ⟹ C1' = ?F B1 (⊢ c1) ⟹ C1'' = C1 ⟹
          C1 ⊆ ?F B1 (⊢ c1)" and
      F: "⊨ b (⊆ A, X) = (B1, B2)" and
      G: "s' ∈ C1"
    have "?P s' A (let f = ⊢ b in ?S1 f ⊔ ?S2 f)"
    proof -
      obtain s and t and ys where
        H: "s' = (λx. case ?f ys x of
          None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i) ∧
          s ∈ B1 ∧ ys ∈ ⊢ c1"
        using E and G by fastforce
      moreover from F and this have "s ∈ A"
        by (blast dest: btyping2_un_eq)
      moreover from F and H have "⊢ b ≠ Some False"
        by (auto dest: btyping1_btyping2 [where A = A and X = X])
      hence "ys ∈ (let f = ⊢ b in ?S1 f ∪ ?S2 f)"
        using H by (auto simp: Let_def)
      hence "ys ∈ (let f = ⊢ b in ?S1 f ⊔ ?S2 f)"
        by (auto simp: Let_def intro: ctyping1_merge_in)
      ultimately show ?thesis
        by blast
    qed
  }
  note E = this
  {
    fix s' B1 B2 C2
    assume
      F: "⋀U' B2' C2' C2''. U' = insert (Univ? A X, bvars b) U ⟹
        B2' = B1 ⟹ C2' = ?F B2 (⊢ c2) ⟹ C2'' = C2 ⟹
          C2 ⊆ ?F B2 (⊢ c2)" and
      G: "⊨ b (⊆ A, X) = (B1, B2)" and
      H: "s' ∈ C2"
    have "?P s' A (let f = ⊢ b in ?S1 f ⊔ ?S2 f)"
    proof -
      obtain s and t and ys where
        I: "s' = (λx. case ?f ys x of
          None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i) ∧
          s ∈ B2 ∧ ys ∈ ⊢ c2"
        using F and H by fastforce
      moreover from G and this have "s ∈ A"
        by (blast dest: btyping2_un_eq)
      moreover from G and I have "⊢ b ≠ Some True"
        by (auto dest: btyping1_btyping2 [where A = A and X = X])
      hence "ys ∈ (let f = ⊢ b in ?S1 f ∪ ?S2 f)"
        using I by (auto simp: Let_def)
      hence "ys ∈ (let f = ⊢ b in ?S1 f ⊔ ?S2 f)"
        by (auto simp: Let_def intro: ctyping1_merge_in)
      ultimately show ?thesis
        by blast
    qed
  }
  note F = this
  from A and B and C and D show ?thesis
    by (auto simp: ctyping1_def split: option.split_asm prod.split_asm,
     erule_tac [2] F, erule_tac E)
qed

lemma ctyping1_ctyping2_fst_while:
  assumes
    A: "(C, Y) = ⊢ WHILE b DO c (⊆ A, X)" and
    B: "Some (C', Y') = (U, False) ⊨ WHILE b DO c (⊆ A, X)"
  shows "C' ⊆ C"
proof -
  let ?f = "foldl (;;) (λx. None)"
  let ?P = "λr A S. ∃f s. (∃t. r = (λx. case f x of
    None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i)) ∧
    (∃ys. f = ?f ys ∧ ys ∈ S) ∧ s ∈ A"
  let ?F = "λA S. {r. ?P r A S}"
  let ?S1 = "λf. if f = Some False ∨ f = None then {[]} else {}"
  let ?S2 = "λf. if f = Some True ∨ f = None then ⊢ c else {}"
  {
    fix s' B1 B2 B1' B2'
    assume
      C: "⊨ b (⊆ A, X) = (B1, B2)" and
      D: "⊨ b (⊆ ?F B1 (⊢ c), Univ?? B1 {x. ∀f ∈ {?f ys |ys. ys ∈ ⊢ c}.
        f x ≠ Some None ∧ (f x = None ⟶ x ∈ X)}) = (B1', B2')"
        (is "⊨ _ (⊆ ?C, ?Y) = _")
    assume "s' ∈ C'" and "Some (C', Y') = (if (∀s ∈ Univ? A X ∪
      Univ? ?C ?Y. ∀x ∈ bvars b. All (interf s (dom x))) ∧
      (∀p ∈ U. ∀B W. p = (B, W) ⟶ (∀s ∈ B. ∀x ∈ W. All (interf s (dom x))))
        then Some (B2 ∪ B2', Univ?? B2 X ∩ ?Y)
        else None)"
    hence "s' ∈ B2 ∪ B2'"
      by (simp split: if_split_asm)
    hence "?P s' A (let f = ⊢ b in ?S1 f ∪ ?S2 f)"
    proof
      assume E: "s' ∈ B2"
      hence "s' ∈ A"
        using C by (blast dest: btyping2_un_eq)
      moreover from C and E have "⊢ b ≠ Some True"
        by (auto dest: btyping1_btyping2 [where A = A and X = X])
      hence "[] ∈ (let f = ⊢ b in ?S1 f ∪ ?S2 f)"
        by (auto simp: Let_def)
      ultimately show ?thesis
        by force
    next
      assume "s' ∈ B2'"
      then obtain s and t and ys where
        E: "s' = (λx. case ?f ys x of
          None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i) ∧
          s ∈ B1 ∧ ys ∈ ⊢ c"
        using D by (blast dest: btyping2_un_eq)
      moreover from C and this have "s ∈ A"
        by (blast dest: btyping2_un_eq)
      moreover from C and E have "⊢ b ≠ Some False"
        by (auto dest: btyping1_btyping2 [where A = A and X = X])
      hence "ys ∈ (let f = ⊢ b in ?S1 f ∪ ?S2 f)"
        using E by (auto simp: Let_def)
      ultimately show ?thesis
        by blast
    qed
  }
  note C = this
  from A and B show ?thesis
    by (auto intro: C simp: ctyping1_def
     split: option.split_asm prod.split_asm)
qed

lemma ctyping1_ctyping2_fst:
 "⟦(C, Z) = ⊢ c (⊆ A, X); Some (C', Z') = (U, False) ⊨ c (⊆ A, X)⟧ ⟹
    C' ⊆ C"
proof (induction "(U, False)" c A X arbitrary: C C' Z Z' U
 rule: ctyping2.induct)
  fix A X C C' Z Z' U c1 c2
  show
   "⟦⋀C C' Z Z'.
      (C, Z) = ⊢ c1 (⊆ A, X) ⟹
      Some (C', Z') = (U, False) ⊨ c1 (⊆ A, X) ⟹
      C' ⊆ C;
    ⋀p B Y C C' Z Z'. (U, False) ⊨ c1 (⊆ A, X) = Some p ⟹
      (B, Y) = p ⟹ (C, Z) = ⊢ c2 (⊆ B, Y) ⟹
      Some (C', Z') = (U, False) ⊨ c2 (⊆ B, Y) ⟹
      C' ⊆ C;
    (C, Z) = ⊢ c1;; c2 (⊆ A, X);
    Some (C', Z') = (U, False) ⊨ c1;; c2 (⊆ A, X)⟧ ⟹
      C' ⊆ C"
    by (rule ctyping1_ctyping2_fst_seq)
next
  fix A X C C' Z Z' U b c1 c2
  show
   "⟦⋀U' p B1 B2 C C' Z Z'.
      (U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
      (B1, B2) = p ⟹ (C, Z) = ⊢ c1 (⊆ B1, X) ⟹
      Some (C', Z') = (U', False) ⊨ c1 (⊆ B1, X) ⟹
      C' ⊆ C;
    ⋀U' p B1 B2 C C' Z Z'.
      (U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
      (B1, B2) = p ⟹ (C, Z) = ⊢ c2 (⊆ B2, X) ⟹
      Some (C', Z') = (U', False) ⊨ c2 (⊆ B2, X) ⟹
      C' ⊆ C;
    (C, Z) = ⊢ IF b THEN c1 ELSE c2 (⊆ A, X);
    Some (C', Z') = (U, False) ⊨ IF b THEN c1 ELSE c2 (⊆ A, X)⟧ ⟹
      C' ⊆ C"
    by (rule ctyping1_ctyping2_fst_if)
next
  fix A X B B' Z Z' U b c
  show
   "⟦⋀B1 B2 C Y B1' B2' B B' Z Z'.
      (B1, B2) = ⊨ b (⊆ A, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹
      (B1', B2') = ⊨ b (⊆ C, Y) ⟹
      ∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
        B: dom ` W ↝ UNIV ⟹
      (B, Z) = ⊢ c (⊆ B1, X) ⟹
      Some (B', Z') = ({}, False) ⊨ c (⊆ B1, X) ⟹
      B' ⊆ B;
    ⋀B1 B2 C Y B1' B2' B B' Z Z'.
      (B1, B2) = ⊨ b (⊆ A, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹
      (B1', B2') = ⊨ b (⊆ C, Y) ⟹
      ∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
        B: dom ` W ↝ UNIV ⟹
      (B, Z) = ⊢ c (⊆ B1', Y) ⟹
      Some (B', Z') = ({}, False) ⊨ c (⊆ B1', Y) ⟹
      B' ⊆ B;
    (B, Z) = ⊢ WHILE b DO c (⊆ A, X);
    Some (B', Z') = (U, False) ⊨ WHILE b DO c (⊆ A, X)⟧ ⟹
      B' ⊆ B"
    by (rule ctyping1_ctyping2_fst_while)
qed (simp add: ctyping1_def, auto)


lemma ctyping1_ctyping2_snd_assign [elim!]:
 "⟦(C, Z) = ⊢ x ::= a (⊆ A, X);
    Some (C', Z') = (U, False) ⊨ x ::= a (⊆ A, X)⟧ ⟹ Z ⊆ Z'"
by (auto simp: ctyping1_def ctyping1_seq_def split: if_split_asm)

lemma ctyping1_ctyping2_snd_seq:
  assumes
    A: "⋀B B' Y Y'. (B, Y) = ⊢ c1 (⊆ A, X) ⟹
      Some (B', Y') = (U, False) ⊨ c1 (⊆ A, X) ⟹ Y ⊆ Y'" and
    B: "⋀p B Y C C' Z Z'. (U, False) ⊨ c1 (⊆ A, X) = Some p ⟹
      (B, Y) = p ⟹ (C, Z) = ⊢ c2 (⊆ B, Y) ⟹
        Some (C', Z') = (U, False) ⊨ c2 (⊆ B, Y) ⟹ Z ⊆ Z'" and
    C: "(C, Z) = ⊢ c1;; c2 (⊆ A, X)" and
    D: "Some (C', Z') = (U, False) ⊨ c1;; c2 (⊆ A, X)"
  shows "Z ⊆ Z'"
proof -
  let ?f = "foldl (;;) (λx. None)"
  let ?F = "λA S. {r. ∃f s. (∃t. r = (λx. case f x of
    None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i)) ∧
    (∃ys. f = ?f ys ∧ ys ∈ S) ∧ s ∈ A}"
  let ?G = "λX S. {x. ∀f ∈ {?f ys | ys. ys ∈ S}.
    f x ≠ Some None ∧ (f x = None ⟶ x ∈ X)}"
  {
    fix x B Y
    assume "⋀B' B'' C C' Z'. B = B' ⟹ B'' = B' ⟹ C = ?F B' (⊢ c2) ⟹
      Some (C', Z') = (U, False) ⊨ c2 (⊆ B', Y) ⟹
        Univ?? B' (?G Y (⊢ c2)) ⊆ Z'" and
     "Some (C', Z') = (U, False) ⊨ c2 (⊆ B, Y)"
    hence E: "Univ?? B (?G Y (⊢ c2)) ⊆ Z'"
      by simp
    assume "⋀C B'. C = ?F A (⊢ c1) ⟹ B' = B ⟹
      Univ?? A (?G X (⊢ c1)) ⊆ Y"
    hence F: "Univ?? A (?G X (⊢ c1)) ⊆ Y"
      by simp
    assume G: "∀f. (∃zs. f = ?f zs ∧ zs ∈ ⊢ c1 ⊔@ ⊢ c2) ⟶
      f x ≠ Some None ∧ (f x = None ⟶ x ∈ X)"
    {
      fix ys
      have "⊢ c1 ≠ {}"
        by (rule ctyping1_aux_nonempty)
      then obtain xs where "xs ∈ ⊢ c1"
        by blast
      moreover assume "ys ∈ ⊢ c2"
      ultimately have "xs @ ys ∈ ⊢ c1 ⊔@ ⊢ c2"
        by (rule ctyping1_merge_append_in)
      moreover assume "?f ys x = Some None"
      hence "?f (xs @ ys) x = Some None"
        by (simp add: Let_def ctyping1_seq_last split: if_split_asm)
      ultimately have False
        using G by blast
    }
    hence H: "∀ys ∈ ⊢ c2. ?f ys x ≠ Some None"
      by blast
    {
      fix xs ys
      assume "xs ∈ ⊢ c1" and "ys ∈ ⊢ c2"
      hence "xs @ ys ∈ ⊢ c1 ⊔@ ⊢ c2"
        by (rule ctyping1_merge_append_in)
      moreover assume "?f xs x = Some None" and "?f ys x = None"
      hence "?f (xs @ ys) x = Some None"
        by (auto dest: last_in_set simp: Let_def ctyping1_seq_last
         split: if_split_asm)
      ultimately have "(∃ys ∈ ⊢ c2. ?f ys x = None) ⟶
        (∀xs ∈ ⊢ c1. ?f xs x ≠ Some None)"
        using G by blast
    }
    hence I: "(∃ys ∈ ⊢ c2. ?f ys x = None) ⟶
      (∀xs ∈ ⊢ c1. ?f xs x ≠ Some None)"
      by blast
    {
      fix xs ys
      assume "xs ∈ ⊢ c1" and J: "ys ∈ ⊢ c2"
      hence "xs @ ys ∈ ⊢ c1 ⊔@ ⊢ c2"
        by (rule ctyping1_merge_append_in)
      moreover assume "?f xs x = None" and K: "?f ys x = None"
      hence "?f (xs @ ys) x = None"
        by (simp add: Let_def ctyping1_seq_last split: if_split_asm)
      ultimately have "x ∈ X"
        using G by blast
      moreover have "∀xs ∈ ⊢ c1. ?f xs x ≠ Some None"
        using I and J and K by blast
      ultimately have "x ∈ Z'"
        using E and F and H by fastforce
    }
    moreover {
      fix ys
      assume "ys ∈ ⊢ c2" and "?f ys x = None"
      hence "∀xs ∈ ⊢ c1. ?f xs x ≠ Some None"
        using I by blast
      moreover assume "∀xs ∈ ⊢ c1. ∃v. ?f xs x = Some v"
      ultimately have "x ∈ Z'"
        using E and F and H by fastforce
    }
    moreover {
      assume "∀ys ∈ ⊢ c2. ∃v. ?f ys x = Some v"
      hence "x ∈ Z'"
        using E and H by fastforce
    }
    ultimately have "x ∈ Z'"
      by (cases "∃ys ∈ ⊢ c2. ?f ys x = None",
       cases "∃xs ∈ ⊢ c1. ?f xs x = None", auto)
    moreover assume "x ∉ Z'"
    ultimately have False
      by contradiction
  }
  note E = this
  from A and B and C and D show ?thesis
    by (auto dest: ctyping2_fst_empty ctyping2_fst_empty [OF sym]
     simp: ctyping1_def split: option.split_asm, erule_tac E)
qed

lemma ctyping1_ctyping2_snd_if:
  assumes
    A: "⋀U' p B1 B2 C1 C1' Y1 Y1'.
      (U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
        (B1, B2) = p ⟹ (C1, Y1) = ⊢ c1 (⊆ B1, X) ⟹
          Some (C1', Y1') = (U', False) ⊨ c1 (⊆ B1, X) ⟹ Y1 ⊆ Y1'" and
    B: "⋀U' p B1 B2 C2 C2' Y2 Y2'.
      (U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
        (B1, B2) = p ⟹ (C2, Y2) = ⊢ c2 (⊆ B2, X) ⟹
          Some (C2', Y2') = (U', False) ⊨ c2 (⊆ B2, X) ⟹ Y2 ⊆ Y2'" and
    C: "(C, Y) = ⊢ IF b THEN c1 ELSE c2 (⊆ A, X)" and
    D: "Some (C', Y') = (U, False) ⊨ IF b THEN c1 ELSE c2 (⊆ A, X)"
  shows "Y ⊆ Y'"
proof -
  let ?f = "foldl (;;) (λx. None)"
  let ?F = "λA S. {r. ∃f s. (∃t. r = (λx. case f x of
    None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i)) ∧
    (∃ys. f = ?f ys ∧ ys ∈ S) ∧ s ∈ A}"
  let ?G = "λX S. {x. ∀f ∈ {?f ys | ys. ys ∈ S}.
    f x ≠ Some None ∧ (f x = None ⟶ x ∈ X)}"
  let ?S1 = "λf. if f = Some True ∨ f = None then ⊢ c1 else {}"
  let ?S2 = "λf. if f = Some False ∨ f = None then ⊢ c2 else {}"
  let ?P = "λx. ∀f. (∃ys. f = ?f ys ∧ ys ∈ (let f = ⊢ b in ?S1 f ⊔ ?S2 f)) ⟶
    f x ≠ Some None ∧ (f x = None ⟶ x ∈ X)"
  let ?U = "insert (Univ? A X, bvars b) U"
  {
    fix B1 B2 Y1' Y2' and C1' :: "state set" and C2' :: "state set"
    assume "⋀U' B1' C1 C1''. U' = ?U ⟹ B1' = B1 ⟹
      C1 = ?F B1 (⊢ c1) ⟹ C1'' = C1' ⟹ Univ?? B1 (?G X (⊢ c1)) ⊆ Y1'"
    hence E: "Univ?? B1 (?G X (⊢ c1)) ⊆ Y1'"
      by simp
    moreover assume "⋀U' B1' C2 C2''. U' = ?U ⟹ B1' = B1 ⟹
      C2 = ?F B2 (⊢ c2) ⟹ C2'' = C2' ⟹ Univ?? B2 (?G X (⊢ c2)) ⊆ Y2'"
    hence F: "Univ?? B2 (?G X (⊢ c2)) ⊆ Y2'"
      by simp
    moreover assume G: "⊨ b (⊆ A, X) = (B1, B2)"
    moreover {
      fix x
      assume "?P x"
      have "x ∈ Y1'"
      proof (cases "⊢ b = Some False")
        case True
        with E and G show ?thesis
          by (drule_tac btyping1_btyping2 [where A = A and X = X], auto)
      next
        case False
        {
          fix xs
          assume "xs ∈ ⊢ c1"
          with False have "xs ∈ (let f = ⊢ b in ?S1 f ⊔ ?S2 f)"
            by (auto intro: ctyping1_merge_in simp: Let_def)
          hence "?f xs x ≠ Some None ∧ (?f xs x = None ⟶ x ∈ X)"
            using `?P x` by auto
        }
        hence "x ∈ Univ?? B1 (?G X (⊢ c1))"
          by auto
        thus ?thesis
          using E ..
      qed
    }
    moreover {
      fix x
      assume "?P x"
      have "x ∈ Y2'"
      proof (cases "⊢ b = Some True")
        case True
        with F and G show ?thesis
          by (drule_tac btyping1_btyping2 [where A = A and X = X], auto)
      next
        case False
        {
          fix ys
          assume "ys ∈ ⊢ c2"
          with False have "ys ∈ (let f = ⊢ b in ?S1 f ⊔ ?S2 f)"
            by (auto intro: ctyping1_merge_in simp: Let_def)
          hence "?f ys x ≠ Some None ∧ (?f ys x = None ⟶ x ∈ X)"
            using `?P x` by auto
        }
        hence "x ∈ Univ?? B2 (?G X (⊢ c2))"
          by auto
        thus ?thesis
          using F ..
      qed
    }
    ultimately have "(A = {} ⟶ UNIV ⊆ Y1' ∧ UNIV ⊆ Y2') ∧
      (A ≠ {} ⟶ {x. ?P x} ⊆ Y1' ∧ {x. ?P x} ⊆ Y2')"
      by (auto simp: btyping2_fst_empty)
  }
  note E = this
  from A and B and C and D show ?thesis
    by (clarsimp simp: ctyping1_def split: option.split_asm prod.split_asm,
     erule_tac E)
qed

lemma ctyping1_ctyping2_snd_while:
  assumes
    A: "(C, Y) = ⊢ WHILE b DO c (⊆ A, X)" and
    B: "Some (C', Y') = (U, False) ⊨ WHILE b DO c (⊆ A, X)"
  shows "Y ⊆ Y'"
proof -
  let ?f = "foldl (;;) (λx. None)"
  let ?F = "λA S. {r. ∃f s. (∃t. r = (λx. case f x of
    None ⇒ s x | Some None ⇒ t x | Some (Some i) ⇒ i)) ∧
    (∃ys. f = ?f ys ∧ ys ∈ S) ∧ s ∈ A}"
  let ?S1 = "λf. if f = Some False ∨ f = None then {[]} else {}"
  let ?S2 = "λf. if f = Some True ∨ f = None then ⊢ c else {}"
  let ?P = "λx. ∀f. (∃ys. f = ?f ys ∧ ys ∈ (let f = ⊢ b in ?S1 f ∪ ?S2 f)) ⟶
    f x ≠ Some None ∧ (f x = None ⟶ x ∈ X)"
  let ?Y = "λA. Univ?? A {x. ∀f ∈ {?f ys |ys. ys ∈ ⊢ c}.
    f x ≠ Some None ∧ (f x = None ⟶ x ∈ X)}"
  {
    fix B1 B2 B1' B2'
    assume C: "⊨ b (⊆ A, X) = (B1, B2)"
    assume "Some (C', Y') = (if (∀s ∈ Univ? A X ∪
      Univ? (?F B1 (⊢ c)) (?Y B1). ∀x ∈ bvars b. All (interf s (dom x))) ∧
      (∀p ∈ U. ∀B W. p = (B, W) ⟶ (∀s ∈ B. ∀x ∈ W. All (interf s (dom x))))
        then Some (B2 ∪ B2', Univ?? B2 X ∩ ?Y B1)
        else None)"
    hence D: "Y' = Univ?? B2 X ∩ ?Y B1"
      by (simp split: if_split_asm)
    {
      fix x
      assume "A = {}"
      hence "x ∈ Y'"
        using C and D by (simp add: btyping2_fst_empty)
    }
    moreover {
      fix x
      assume "?P x"
      {
        assume "⊢ b ≠ Some True"
        hence "[] ∈ (let f = ⊢ b in ?S1 f ∪ ?S2 f)"
          by (auto simp: Let_def)
        hence "x ∈ X"
          using `?P x` by auto
      }
      hence E: "⊢ b ≠ Some True ⟶ x ∈ Univ?? B2 X"
        by auto
      {
        fix ys
        assume "⊢ b ≠ Some False" and "ys ∈ ⊢ c"
        hence "ys ∈ (let f = ⊢ b in ?S1 f ∪ ?S2 f)"
          by (auto simp: Let_def)
        hence "?f ys x ≠ Some None ∧ (?f ys x = None ⟶ x ∈ X)"
          using `?P x` by auto
      }
      hence F: "⊢ b ≠ Some False ⟶ x ∈ ?Y B1"
        by auto
      have "x ∈ Y'"
      proof (cases "⊢ b")
        case None
        thus ?thesis
          using D and E and F by simp
      next
        case (Some v)
        show ?thesis
        proof (cases v)
          case True
          with C and D and F and Some show ?thesis
            by (drule_tac btyping1_btyping2 [where A = A and X = X], simp)
        next
          case False
          with C and D and E and Some show ?thesis
            by (drule_tac btyping1_btyping2 [where A = A and X = X], simp)
        qed
      qed
    }
    ultimately have "(A = {} ⟶ UNIV ⊆ Y') ∧ (A ≠ {} ⟶ {x. ?P x} ⊆ Y')"
      by auto
  }
  note C = this
  from A and B show ?thesis
    by (auto intro!: C simp: ctyping1_def
     split: option.split_asm prod.split_asm)
qed

lemma ctyping1_ctyping2_snd:
 "⟦(C, Z) = ⊢ c (⊆ A, X); Some (C', Z') = (U, False) ⊨ c (⊆ A, X)⟧ ⟹
    Z ⊆ Z'"
proof (induction "(U, False)" c A X arbitrary: C C' Z Z' U
 rule: ctyping2.induct)
  fix A X C C' Z Z' U c1 c2
  show
   "⟦⋀B B' Y Y'.
      (B, Y) = ⊢ c1 (⊆ A, X) ⟹
      Some (B', Y') = (U, False) ⊨ c1 (⊆ A, X) ⟹
      Y ⊆ Y';
    ⋀p B Y C C' Z Z'. (U, False) ⊨ c1 (⊆ A, X) = Some p ⟹
      (B, Y) = p ⟹ (C, Z) = ⊢ c2 (⊆ B, Y) ⟹
      Some (C', Z') = (U, False) ⊨ c2 (⊆ B, Y) ⟹
      Z ⊆ Z';
    (C, Z) = ⊢ c1;; c2 (⊆ A, X);
    Some (C', Z') = (U, False) ⊨ c1;; c2 (⊆ A, X)⟧ ⟹
      Z ⊆ Z'"
    by (rule ctyping1_ctyping2_snd_seq)
next
  fix A X C C' Z Z' U b c1 c2
  show
   "⟦⋀U' p B1 B2 C C' Z Z'.
      (U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
      (B1, B2) = p ⟹ (C, Z) = ⊢ c1 (⊆ B1, X) ⟹
      Some (C', Z') = (U', False) ⊨ c1 (⊆ B1, X) ⟹
      Z ⊆ Z';
    ⋀U' p B1 B2 C C' Z Z'.
      (U', p) = (insert (Univ? A X, bvars b) U, ⊨ b (⊆ A, X)) ⟹
      (B1, B2) = p ⟹ (C, Z) = ⊢ c2 (⊆ B2, X) ⟹
      Some (C', Z') = (U', False) ⊨ c2 (⊆ B2, X) ⟹
      Z ⊆ Z';
    (C, Z) = ⊢ IF b THEN c1 ELSE c2 (⊆ A, X);
    Some (C', Z') = (U, False) ⊨ IF b THEN c1 ELSE c2 (⊆ A, X)⟧ ⟹
      Z ⊆ Z'"
    by (rule ctyping1_ctyping2_snd_if)
next
  fix A X B B' Z Z' U b c
  show
   "⟦⋀B1 B2 C Y B1' B2' B B' Z Z'.
      (B1, B2) = ⊨ b (⊆ A, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹
      (B1', B2') = ⊨ b (⊆ C, Y) ⟹
      ∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
        B: dom ` W ↝ UNIV ⟹
      (B, Z) = ⊢ c (⊆ B1, X) ⟹
      Some (B', Z') = ({}, False) ⊨ c (⊆ B1, X) ⟹
      Z ⊆ Z';
    ⋀B1 B2 C Y B1' B2' B B' Z Z'.
      (B1, B2) = ⊨ b (⊆ A, X) ⟹
      (C, Y) = ⊢ c (⊆ B1, X) ⟹
      (B1', B2') = ⊨ b (⊆ C, Y) ⟹
      ∀(B, W) ∈ insert (Univ? A X ∪ Univ? C Y, bvars b) U.
        B: dom ` W ↝ UNIV ⟹
      (B, Z) = ⊢ c (⊆ B1', Y) ⟹
      Some (B', Z') = ({}, False) ⊨ c (⊆ B1', Y) ⟹
      Z ⊆ Z';
    (B, Z) = ⊢ WHILE b DO c (⊆ A, X);
    Some (B', Z') = (U, False) ⊨ WHILE b DO c (⊆ A, X)⟧ ⟹
      Z ⊆ Z'"
    by (rule ctyping1_ctyping2_snd_while)
qed (simp add: ctyping1_def, auto)


lemma ctyping1_ctyping2:
 "⟦⊢ c (⊆ A, X) = (C, Z); (U, False) ⊨ c (⊆ A, X) = Some (C', Z')⟧ ⟹
    C' ⊆ C ∧ Z ⊆ Z'"
by (rule conjI, ((rule ctyping1_ctyping2_fst [OF sym sym] |
 rule ctyping1_ctyping2_snd [OF sym sym]), assumption+)+)


lemma btyping2_aux_approx_1 [elim]:
  assumes
    A: "⊫ b1 (⊆ A, X) = Some B1" and
    B: "⊫ b2 (⊆ A, X) = Some B2" and
    C: "bval b1 s" and
    D: "bval b2 s" and
    E: "r ∈ A" and
    F: "s = r (⊆ state ∩ X)"
  shows "∃r' ∈ B1 ∩ B2. r = r' (⊆ state ∩ X)"
proof -
  from A and C and E and F have "r ∈ B1"
    by (frule_tac btyping2_aux_subset, drule_tac btyping2_aux_eq, auto)
  moreover from B and D and E and F have "r ∈ B2"
    by (frule_tac btyping2_aux_subset, drule_tac btyping2_aux_eq, auto)
  ultimately show ?thesis
    by blast
qed

lemma btyping2_aux_approx_2 [elim]:
  assumes
    A: "avars a1 ⊆ state" and
    B: "avars a2 ⊆ state" and
    C: "avars a1 ⊆ X" and
    D: "avars a2 ⊆ X" and
    E: "aval a1 s < aval a2 s" and
    F: "r ∈ A" and
    G: "s = r (⊆ state ∩ X)"
  shows "∃r'. r' ∈ A ∧ aval a1 r' < aval a2 r' ∧ r = r' (⊆ state ∩ X)"
proof -
  have "aval a1 s = aval a1 r ∧ aval a2 s = aval a2 r"
    using A and B and C and D and G by (blast intro: avars_aval)
  thus ?thesis
    using E and F by auto
qed

lemma btyping2_aux_approx_3 [elim]:
  assumes
    A: "avars a1 ⊆ state" and
    B: "avars a2 ⊆ state" and
    C: "avars a1 ⊆ X" and
    D: "avars a2 ⊆ X" and
    E: "¬ aval a1 s < aval a2 s" and
    F: "r ∈ A" and
    G: "s = r (⊆ state ∩ X)"
  shows "∃r' ∈ A - {s ∈ A. aval a1 s < aval a2 s}. r = r' (⊆ state ∩ X)"
proof -
  have "aval a1 s = aval a1 r ∧ aval a2 s = aval a2 r"
    using A and B and C and D and G by (blast intro: avars_aval)
  thus ?thesis
    using E and F by auto
qed

lemma btyping2_aux_approx:
 "⟦⊫ b (⊆ A, X) = Some A'; s ∈ Univ A (⊆ state ∩ X)⟧ ⟹
    s ∈ Univ (if bval b s then A' else A - A') (⊆ state ∩ X)"
by (induction b arbitrary: A', auto dest: btyping2_aux_subset
 split: if_split_asm option.split_asm)

lemma btyping2_approx:
 "⟦⊨ b (⊆ A, X) = (B1, B2); s ∈ Univ A (⊆ state ∩ X)⟧ ⟹
    s ∈ Univ (if bval b s then B1 else B2) (⊆ state ∩ X)"
by (drule sym, simp add: btyping2_def split: option.split_asm,
 drule btyping2_aux_approx, auto)


lemma ctyping2_approx_assign [elim!]:
 "⟦∀t'. aval a s = t' x ⟶ (∀s. t' = s(x := aval a s) ⟶ s ∉ A) ∨
    (∃y ∈ state ∩ X. y ≠ x ∧ t y ≠ t' y);
  v ⊨ a (⊆ X); t ∈ A; s = t (⊆ state ∩ X)⟧ ⟹ False"
by (drule spec [of _ "t(x := aval a t)"], cases a,
 (fastforce simp del: aval.simps(3) intro: avars_aval)+)

lemma ctyping2_approx_if_1:
 "⟦bval b s; ⊨ b (⊆ A, X) = (B1, B2); r ∈ A; s = r (⊆ state ∩ X);
    (insert (Univ? A X, bvars b) U, v) ⊨ c1 (⊆ B1, X) = Some (C1, Y1);
    ⋀A B X Y U v. (U, v) ⊨ c1 (⊆ A, X) = Some (B, Y) ⟹
      ∃r ∈ A. s = r (⊆ state ∩ X) ⟹ ∃r' ∈ B. t = r' (⊆ state ∩ Y)⟧ ⟹
  ∃r' ∈ C1 ∪ C2. t = r' (⊆ state ∩ (Y1 ∩ Y2))"
by (drule btyping2_approx, blast, fastforce)

lemma ctyping2_approx_if_2:
 "⟦¬ bval b s; ⊨ b (⊆ A, X) = (B1, B2); r ∈ A; s = r (⊆ state ∩ X);
    (insert (Univ? A X, bvars b) U, v) ⊨ c2 (⊆ B2, X) = Some (C2, Y2);
    ⋀A B X Y U v. (U, v) ⊨ c2 (⊆ A, X) = Some (B, Y) ⟹
      ∃r ∈ A. s = r (⊆ state ∩ X) ⟹ ∃r' ∈ B. t = r' (⊆ state ∩ Y)⟧ ⟹
  ∃r' ∈ C1 ∪ C2. t = r' (⊆ state ∩ (Y1 ∩ Y2))"
by (drule btyping2_approx, blast, fastforce)

lemma ctyping2_approx_while_1 [elim]:
 "⟦¬ bval b s; r ∈ A; s = r (⊆ state ∩ X); ⊨ b (⊆ A, X) = (B, {})⟧ ⟹
    ∃t ∈ C. s = t (⊆ state ∩ Y)"
by (drule btyping2_approx, blast, simp)

lemma ctyping2_approx_while_2 [elim]:
 "⟦∀t ∈ B2 ∪ B2'. ∃x ∈ state ∩ (X ∩ Y). r x ≠ t x; ¬ bval b s;
    r ∈ A; s = r (⊆ state ∩ X); ⊨ b (⊆ A, X) = (B1, B2)⟧ ⟹ False"
by (drule btyping2_approx, blast, auto)

lemma ctyping2_approx_while_aux:
  assumes
    A: "⊨ b (⊆ A, X) = (B1, B2)" and
    B: "⊢ c (⊆ B1, X) = (C, Y)" and
    C: "⊨ b (⊆ C, Y) = (B1', B2')" and
    D: "({}, False) ⊨ c (⊆ B1, X) = Some (D, Z)" and
    E: "({}, False) ⊨ c (⊆ B1', Y) = Some (D', Z')" and
    F: "r1 ∈ A" and
    G: "s1 = r1 (⊆ state ∩ X)" and
    H: "bval b s1" and
    I: "⋀C B Y W U. (case ⊨ b (⊆ C, Y) of (B1', B2') ⇒
      case ⊢ c (⊆ B1', Y) of (C', Y') ⇒
      case ⊨ b (⊆ C', Y') of (B1'', B2'') ⇒
        if (∀s ∈ Univ? C Y ∪ Univ? C' Y'. ∀x ∈ bvars b. All (interf s (dom x))) ∧
          (∀p ∈ U. case p of (B, W) ⇒ ∀s ∈ B. ∀x ∈ W. All (interf s (dom x)))
        then case ({}, False) ⊨ c (⊆ B1', Y) of
          None ⇒ None | Some _ ⇒ case ({}, False) ⊨ c (⊆ B1'', Y') of
            None ⇒ None | Some _ ⇒ Some (B2' ∪ B2'', Univ?? B2' Y ∩ Y')
        else None) = Some (B, W) ⟹
          ∃r ∈ C. s2 = r (⊆ state ∩ Y) ⟹ ∃r ∈ B. s3 = r (⊆ state ∩ W)"
      (is "⋀C B Y W U. ?P C B Y W U ⟹ _ ⟹ _") and
    J: "⋀A B X Y U v. (U, v) ⊨ c (⊆ A, X) = Some (B, Y) ⟹
      ∃r ∈ A. s1 = r (⊆ state ∩ X) ⟹ ∃r ∈ B. s2 = r (⊆ state ∩ Y)" and
    K: "∀s ∈ Univ? A X ∪ Univ? C Y. ∀x ∈ bvars b. All (interf s (dom x))" and
    L: "∀p ∈ U. ∀B W. p  = (B, W) ⟶
      (∀s ∈ B. ∀x ∈ W. All (interf s (dom x)))"
  shows "∃r ∈ B2 ∪ B2'. s3 = r (⊆ state ∩ Univ?? B2 X ∩ Y)"
proof -
  obtain C' Y' where M: "(C', Y') = ⊢ c (⊆ B1', Y)"
    by (cases "⊢ c (⊆ B1', Y)", simp)
  obtain B1'' B2'' where N: "(B1'', B2'') = ⊨ b (⊆ C', Y')"
    by (cases "⊨ b (⊆ C', Y')", simp)
  let ?B = "B2' ∪ B2''"
  let ?W = "Univ?? B2' Y ∩ Y'"
  have "(C, Y) = ⊢ c (⊆ C, Y)"
    using ctyping1_idem and B by auto
  moreover have "B1' ⊆ C"
    using C by (blast dest: btyping2_un_eq)
  ultimately have O: "C' ⊆ C ∧ Y ⊆ Y'"
    by (rule ctyping1_mono [OF _ M], simp)
  hence "Univ? C' Y' ⊆ Univ? C Y"
    by (auto simp: univ_states_if_def)
  moreover from I have "?P C ?B Y ?W U ⟹
    ∃r ∈ C. s2 = r (⊆ state ∩ Y) ⟹ ∃r ∈ ?B. s3 = r (⊆ state ∩ ?W)" .
  ultimately have "(case ({}, False) ⊨ c (⊆ B1'', Y') of
    None ⇒ None | Some _ ⇒ Some (?B, ?W)) = Some (?B, ?W) ⟹
      ∃r ∈ C. s2 = r (⊆ state ∩ Y) ⟹ ∃r ∈ ?B. s3 = r (⊆ state ∩ ?W)"
    using C and E and K and L and M and N
     by (fastforce split: if_split_asm prod.split_asm)
  moreover have P: "B1'' ⊆ B1' ∧ B2'' ⊆ B2'"
    by (metis btyping2_mono C N O)
  hence "∃D'' Z''. ({}, False) ⊨ c (⊆ B1'', Y') =
    Some (D'', Z'') ∧ D'' ⊆ D' ∧ Z' ⊆ Z''"
    using E and O by (auto intro: ctyping2_mono)
  ultimately have
   "∃r ∈ C. s2 = r (⊆ state ∩ Y) ⟹ ∃r ∈ ?B. s3 = r (⊆ state ∩ ?W)"
    by fastforce
  moreover from A and D and F and G and H and J obtain r2 where
   "r2 ∈ D" and "s2 = r2 (⊆ state ∩ Z)"
    by (drule_tac btyping2_approx, blast, force)
  moreover have "D ⊆ C ∧ Y ⊆ Z"
    using B and D by (rule ctyping1_ctyping2)
  ultimately obtain r3 where Q: "r3 ∈ ?B" and R: "s3 = r3 (⊆ state ∩ ?W)"
    by blast
  show ?thesis
  proof (rule bexI [of _ r3])
    show "s3 = r3 (⊆ state ∩ Univ?? B2 X ∩ Y)"
      using O and R by auto
  next
    show "r3 ∈ B2 ∪ B2'"
      using P and Q by blast
  qed
qed

lemmas ctyping2_approx_while_3 =
  ctyping2_approx_while_aux [where B2 = "{}", simplified]

lemma ctyping2_approx_while_4:
 "⟦⊨ b (⊆ A, X) = (B1, B2);
  ⊢ c (⊆ B1, X) = (C, Y);
  ⊨ b (⊆ C, Y) = (B1', B2');
  ({}, False) ⊨ c (⊆ B1, X) = Some (D, Z);
  ({}, False) ⊨ c (⊆ B1', Y) = Some (D', Z');
  r1 ∈ A; s1 = r1 (⊆ state ∩ X); bval b s1;
  ⋀C B Y W U. (case ⊨ b (⊆ C, Y) of (B1', B2') ⇒
    case ⊢ c (⊆ B1', Y) of (C', Y') ⇒
    case ⊨ b (⊆ C', Y') of (B1'', B2'') ⇒
      if (∀s ∈ Univ? C Y ∪ Univ? C' Y'. ∀x ∈ bvars b. All (interf s (dom x))) ∧
        (∀p ∈ U. case p of (B, W) ⇒ ∀s ∈ B. ∀x ∈ W. All (interf s (dom x)))
      then case ({}, False) ⊨ c (⊆ B1', Y) of
        None ⇒ None | Some _ ⇒ case ({}, False) ⊨ c (⊆ B1'', Y') of
          None ⇒ None | Some _ ⇒ Some (B2' ∪ B2'', Univ?? B2' Y ∩ Y')
      else None) = Some (B, W) ⟹
    ∃r ∈ C. s2 = r (⊆ state ∩ Y) ⟹ ∃r ∈ B. s3 = r (⊆ state ∩ W);
  ⋀A B X Y U v. (U, v) ⊨ c (⊆ A, X) = Some (B, Y) ⟹
    ∃r ∈ A. s1 = r (⊆ state ∩ X) ⟹ ∃r ∈ B. s2 = r (⊆ state ∩ Y);
  ∀s ∈ Univ? A X ∪ Univ? C Y. ∀x ∈ bvars b. All (interf s (dom x));
  ∀p ∈ U. ∀B W. p = (B, W) ⟶ (∀s ∈ B. ∀x ∈ W. All (interf s (dom x)));
  ∀r ∈ B2 ∪ B2'. ∃x ∈ state ∩ (X ∩ Y). s3 x ≠ r x⟧ ⟹
    False"
by (drule ctyping2_approx_while_aux, assumption+, auto)

lemma ctyping2_approx:
 "⟦(c, s) ⇒ t; (U, v) ⊨ c (⊆ A, X) = Some (B, Y);
    s ∈ Univ A (⊆ state ∩ X)⟧ ⟹ t ∈ Univ B (⊆ state ∩ Y)"
proof (induction arbitrary: A B X Y U v rule: big_step_induct)
  fix A B X Y U v b c1 c2 s t
  show
   "⟦bval b s; (c1, s) ⇒ t;
    ⋀A C X Y U v. (U, v) ⊨ c1 (⊆ A, X) = Some (C, Y) ⟹
      s ∈ Univ A (⊆ state ∩ X) ⟹
      t ∈ Univ C (⊆ state ∩ Y);
    (U, v) ⊨ IF b THEN c1 ELSE c2 (⊆ A, X) = Some (B, Y);
    s ∈ Univ A (⊆ state ∩ X)⟧ ⟹
      t ∈ Univ B (⊆ state ∩ Y)"
    by (auto split: option.split_asm prod.split_asm,
     rule ctyping2_approx_if_1)
next
  fix A B X Y U v b c1 c2 s t
  show
   "⟦¬ bval b s; (c2, s) ⇒ t;
    ⋀A C X Y U v. (U, v) ⊨ c2 (⊆ A, X) = Some (C, Y) ⟹
      s ∈ Univ A (⊆ state ∩ X) ⟹
      t ∈ Univ C (⊆ state ∩ Y);
    (U, v) ⊨ IF b THEN c1 ELSE c2 (⊆ A, X) = Some (B, Y);
    s ∈ Univ A (⊆ state ∩ X)⟧ ⟹
      t ∈ Univ B (⊆ state ∩ Y)"
    by (auto split: option.split_asm prod.split_asm,
     rule ctyping2_approx_if_2)
next
  fix A B X Y U v b c s1 s2 s3
  show
   "⟦bval b s1; (c, s1) ⇒ s2;
    ⋀A B X Y U v. (U, v) ⊨ c (⊆ A, X) = Some (B, Y) ⟹
      s1 ∈ Univ A (⊆ state ∩ X) ⟹
      s2 ∈ Univ B (⊆ state ∩ Y);
    (WHILE b DO c, s2) ⇒ s3;
    ⋀A B X Y U v. (U, v) ⊨ WHILE b DO c (⊆ A, X) = Some (B, Y) ⟹
      s2 ∈ Univ A (⊆ state ∩ X) ⟹
      s3 ∈ Univ B (⊆ state ∩ Y);
    (U, v) ⊨ WHILE b DO c (⊆ A, X) = Some (B, Y);
    s1 ∈ Univ A (⊆ state ∩ X)⟧ ⟹
      s3 ∈ Univ B (⊆ state ∩ Y)"
  by (auto split: if_split_asm option.split_asm prod.split_asm,
   erule_tac [2] ctyping2_approx_while_4,
   erule ctyping2_approx_while_3)
qed (auto split: if_split_asm option.split_asm prod.split_asm)

end

end