Theory MLSS_Typing

theory MLSS_Typing
  imports MLSS_Calculus
begin

section ‹Typing and Branch Expansion›
text ‹
  We prove that the branch expansion rules
  preserve well-typedness.
›

(*<*)
context includes no member_ASCII_syntax
begin
(*>*)

lemma types_term_unique:
  shows "v ⊢ t : l1 ⟹ v ⊢ t : l2 ⟹ l2 = l1"
  apply(induction arbitrary: l2 rule: types_pset_term.induct)
       apply (metis types_pset_term_cases)+
  done

lemma type_of_term_if_types_term:
  shows "v ⊢ t : l ⟹ type_of_term v t = l"
  using types_term_unique unfolding type_of_term_def by blast

lemma types_term_if_mem_subterms_term:
  assumes "s ∈ subterms t"
  assumes "v ⊢ t : lt"
  shows "∃ls. v ⊢ s : ls"
  using assms
  by (induction t arbitrary: s lt) (auto elim: types_pset_term_cases)

lemma is_Var_if_types_term_0:
  shows "v ⊢ t : 0 ⟹ is_Var t"
  by (induction t) (auto elim: types_pset_term_cases)

lemma is_Var_if_urelem': "urelem' v φ t ⟹ is_Var t"
  using is_Var_if_types_term_0 by blast

lemma is_Var_if_urelem: "urelem φ t ⟹ is_Var t"
  unfolding urelem_def using is_Var_if_urelem' by blast

lemma types_fmD:
  "v ⊢ And p q ⟹ v ⊢ p"
  "v ⊢ And p q ⟹ v ⊢ q"
  "v ⊢ Or p q ⟹ v ⊢ p"
  "v ⊢ Or p q ⟹ v ⊢ q"
  "v ⊢ Neg p ⟹ v ⊢ p"
  "v ⊢ Atom a ⟹ v ⊢ a"
  unfolding types_pset_fm_def using fm.set_intros by auto

lemma types_fmI:
  "v ⊢ p ⟹ v ⊢ q ⟹ v ⊢ And p q"
  "v ⊢ p ⟹ v ⊢ q ⟹ v ⊢ Or p q"
  "v ⊢ p ⟹ v ⊢ Neg p"
  "v ⊢ a ⟹ v ⊢ Atom a"
  unfolding types_pset_fm_def using fm.set_intros by auto

lemma types_pset_atom_Member_D:
  includes no member_ASCII_syntax
  assumes "v ⊢ s ∈s f t1 t2" "f ∈ {(⊔s), (⊓s), (-s)}"
  shows "v ⊢ s ∈s t1" "v ⊢ s ∈s t2"
proof -
  from assms obtain ls where
    "v ⊢ s : ls" "v ⊢ f t1 t2 : Suc ls"
    using types_pset_atom.simps by fastforce
  with assms have "v ⊢ s ∈s t1 ∧ v ⊢ s ∈s t2"
    by (auto simp: types_pset_atom.simps elim: types_pset_term_cases)
  then show "v ⊢ s ∈s t1" "v ⊢ s ∈s t2"
    by blast+
qed

lemmas types_pset_atom_Member_Union_D = types_pset_atom_Member_D[where ?f="(⊔s)", simplified]
   and types_pset_atom_Member_Inter_D = types_pset_atom_Member_D[where ?f="(⊓s)", simplified]
   and types_pset_atom_Member_Diff_D = types_pset_atom_Member_D[where ?f="(-s)", simplified]

lemma types_term_if_mem_subterms:
  includes no member_ASCII_syntax
  fixes φ :: "'a pset_fm"
  assumes "v ⊢ φ"
  assumes "f t1 t2 ∈ subterms φ" "f ∈ {(⊔s), (⊓s), (-s)}"
  obtains lt where "v ⊢ t1 : lt" "v ⊢ t2 : lt"
proof -
  from assms obtain a :: "'a pset_atom" where atom: "v ⊢ a" "f t1 t2 ∈ subterms a"
    unfolding types_pset_fm_def by (induction φ) auto
  obtain t' l where "v ⊢ t' : l" "f t1 t2 ∈ subterms t'"
    apply(rule types_pset_atom.cases[OF ‹v ⊢ a›])
    using atom(2) by auto
  then obtain lt where "v ⊢ t1 : lt ∧ v ⊢ t2 : lt"
    by (induction t' arbitrary: l)
       (use assms(3) in ‹auto elim: types_pset_term_cases›)
  with that show ?thesis
    by blast
qed

lemma types_if_types_Member_and_subterms:
  fixes φ :: "'a pset_fm"
  assumes "v ⊢ s ∈s t1 ∨ v ⊢ s ∈s t2" "v ⊢ φ"
  assumes "f t1 t2 ∈ subterms φ" "f ∈ {(⊔s), (⊓s), (-s)}"
  shows "v ⊢ s ∈s f t1 t2"
proof -
  from types_term_if_mem_subterms[OF assms(2-)] obtain lt where lt:
    "v ⊢ t1 : lt" "v ⊢ t2 : lt"
    by blast
  moreover from assms(1) lt(1,2) obtain ls where "v ⊢ s : ls" "lt = Suc ls"
    by (auto simp: types_pset_atom.simps dest: types_term_unique)
  ultimately show ?thesis
    using assms
    by (auto simp: types_pset_term.intros types_pset_atom.simps)
qed

lemma types_subst_tlvl:
  includes no member_ASCII_syntax
  fixes l :: "'a pset_atom"
  assumes "v ⊢ AT (t1 =s t2)" "v ⊢ l"
  shows "v ⊢ subst_tlvl t1 t2 l"
proof -
  from assms obtain lt where "v ⊢ t1 : lt" "v ⊢ t2 : lt"
    by (auto simp: types_pset_atom.simps dest!: types_fmD(6))
  with assms(2) show ?thesis
    by (cases "(t1, t2, l)" rule: subst_tlvl.cases)
       (auto simp: types_pset_atom.simps dest: types_term_unique)
qed

lemma types_sym_Equal:
  assumes "v ⊢ t1 =s t2"
  shows "v ⊢ t2 =s t1"
  using assms by (auto simp: types_pset_atom.simps)

lemma types_lexpands:
  fixes φ :: "'a pset_fm"
  assumes "lexpands b' b" "b ≠ []" "φ ∈ set b'"
  assumes "⋀(φ :: 'a pset_fm). φ ∈ set b ⟹ v ⊢ φ"
  shows "v ⊢ φ"
  using assms
proof(induction rule: lexpands.induct)
  case (1 b' b)
  then show ?case
    apply(induction rule: lexpands_fm.induct)
          apply(force dest: types_fmD intro: types_fmI(3))+
    done
next
  case (2 b' b)
  then show ?case
  proof(induction rule: lexpands_un.induct)
    case (1 s t1 t2 b)
    then show ?thesis
      by (auto dest!: types_fmD(5,6) "1"(4) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Union_D)
  next
    case (2 s t1 b t2)
    then have "v ⊢ last b"
      by auto
    from types_if_types_Member_and_subterms[OF _ this] 2 show ?case
      by (auto dest!: "2"(5) types_fmD(6) intro: types_fmI(4))
  next
    case (3 s t2 b t1)
    then have "v ⊢ last b"
      by auto
    from types_if_types_Member_and_subterms[OF _ this] 3 show ?case
      by (auto dest!: "3"(5) types_fmD(6) intro: types_fmI(4))
  next
    case (4 s t1 t2 b)
    then show ?case
      by (auto dest!: types_fmD(5,6) "4"(5) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Union_D)
  next
    case (5 s t1 t2 b)
    then show ?case
      by (auto dest!: types_fmD(5,6) "5"(5) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Union_D)
  next
    case (6 s t1 b t2)
    then have "v ⊢ last b"
      by auto
    note types_if_types_Member_and_subterms[where ?f="(⊔s)", OF _ this "6"(3), simplified]
    with 6 show ?case
      by (auto dest!: types_fmD(5,6) "6"(6) intro!: types_fmI(2,3,4))
  qed
next
  case (3 b' b)
  then show ?case
  proof(induction rule: lexpands_int.induct)
    case (1 s t1 t2 b)
    then show ?thesis
      by (auto dest!: types_fmD(5,6) "1"(4) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Inter_D)
  next
    case (2 s t1 b t2)
    then have "v ⊢ last b"
      by auto
    from types_if_types_Member_and_subterms[OF _ this] 2 show ?case
      by (auto dest!: "2"(5) types_fmD(5,6) intro!: types_fmI(3,4))
  next
    case (3 s t2 b t1)
    then have "v ⊢ last b"
      by auto
    from types_if_types_Member_and_subterms[OF _ this] 3 show ?case
      by (auto dest!: "3"(5) types_fmD(5,6) intro!: types_fmI(3,4))
  next
    case (4 s t1 t2 b)
    then show ?case
      by (auto dest!: types_fmD(5,6) "4"(5) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Inter_D)
  next
    case (5 s t1 t2 b)
    then show ?case
      by (auto dest!: types_fmD(5,6) "5"(5) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Inter_D)
  next
    case (6 s t1 b t2)
    then have "v ⊢ last b"
      by auto
    note types_if_types_Member_and_subterms[where ?f="(⊓s)", OF _ this "6"(3), simplified]
    with 6 show ?case
      by (auto dest!: types_fmD(5,6) "6"(6) intro!: types_fmI(2,3,4))
  qed
next
  case (4 b' b)
  then show ?case
    proof(induction rule: lexpands_diff.induct)
    case (1 s t1 t2 b)
    then show ?thesis
      by (auto dest!: types_fmD(5,6) "1"(4) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Diff_D)
  next
    case (2 s t1 b t2)
    then have "v ⊢ last b"
      by auto
    from types_if_types_Member_and_subterms[OF _ this] 2 show ?case
      by (auto dest!: "2"(5) types_fmD(5,6) intro!: types_fmI(3,4))
  next
    case (3 s t2 b t1)
    then have "v ⊢ last b"
      by auto
    from types_if_types_Member_and_subterms[OF _ this] 3 show ?case
      by (auto dest!: "3"(5) types_fmD(5,6) intro!: types_fmI(3,4))
  next
    case (4 s t1 t2 b)
    then show ?case
      by (auto dest!: types_fmD(5,6) "4"(5) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Diff_D)
  next
    case (5 s t1 t2 b)
    then show ?case
      by (auto dest!: types_fmD(5,6) "5"(5) intro!: types_fmI(2,3,4)
               intro: types_pset_atom_Member_Diff_D)
  next
    case (6 s t1 b t2)
    then have "v ⊢ last b"
      by auto
    note types_if_types_Member_and_subterms[where ?f="(-s)", OF _ this "6"(3), simplified]
    with 6 show ?case
      by (auto dest!: types_fmD(5,6) "6"(6) intro!: types_fmI(2,3,4))
  qed
next
  case (5 b' b)
  then show ?case
  proof(cases rule: lexpands_single.cases)
    case (1 t1)
    with 5 have "v ⊢ last b"
      by auto
    with ‹Single t1 ∈ subterms (last b)› obtain a :: "'a pset_atom"
      where atom: "a ∈ atoms (last b)" "Single t1 ∈ subterms a" "v ⊢ a"
      unfolding types_pset_fm_def by (metis UN_E subterms_fm_def)
    obtain t' l where "Single t1 ∈ subterms t'" "v ⊢ t' : l" 
      apply(rule types_pset_atom.cases[OF ‹v ⊢ a›])
      using atom(2) by auto
    note types_term_if_mem_subterms_term[OF this]
    then obtain lt1 where "v ⊢ t1 : lt1" "v ⊢ Single t1 : Suc lt1"
      by (metis types_pset_term_cases(3))
    with 5 1 show ?thesis
      using types_pset_atom.intros(2) types_pset_fm_def by fastforce
  qed (auto simp: types_pset_atom.simps elim!: types_pset_term_cases
            dest!: types_fmD(5,6) "5"(4) intro!: types_fmI(3,4))
next
  case (6 b' b)
  then show ?case
  proof(cases rule: lexpands_eq.cases)
    case (5 s t s')
    with 6 show ?thesis
      by (auto 0 3 dest!: "6"(4) types_fmD(5,6) dest: types_term_unique
                   simp: types_pset_atom.simps types_term_unique intro!: types_fmI(3,4))
  qed (auto simp: types_sym_Equal dest!: "6"(4) types_fmD(5,6)
            intro!: types_fmI(3,4) types_subst_tlvl)
qed

lemma types_bexpands_nowit:
  fixes φ :: "'a pset_fm"
  assumes "bexpands_nowit bs' b" "b' ∈ bs'" "φ ∈ set b'"
  assumes "⋀(φ :: 'a pset_fm). φ ∈ set b ⟹ v ⊢ φ"
  shows "v ⊢ φ"
  using assms(1)
proof(cases rule: bexpands_nowit.cases)
  case (1 p q)
  from assms "1"(2) show ?thesis
    unfolding "1"(1)
    by (auto dest!: assms(4) types_fmD(3) intro!: types_fmI(3))
next
  case (2 p q)
  from assms "2"(2) show ?thesis
    unfolding "2"(1)
    by (auto dest!: assms(4) types_fmD(5) dest: types_fmD(1,2) intro!: types_fmI(3))
next
  case (3 s t1 t2)
  from assms "3"(2,3) show ?thesis
    unfolding "3"(1) using types_pset_atom_Member_Union_D(1)[of v s t1 t2]
    by (auto dest!: types_fmD(6) assms(4) intro!: types_fmI(3,4))
next
  case (4 s t1 t2)
  with assms have "v ⊢ last b"
    by (metis empty_iff empty_set last_in_set)
  from assms "4"(2,3) show ?thesis
    unfolding "4"(1)
    using types_if_types_Member_and_subterms[where ?f="(⊓s)", OF _ ‹v ⊢ last b› "4"(3),
                                             THEN types_pset_atom_Member_Inter_D(2)]
    by (force dest!: types_fmD(6) assms(4) intro!: types_fmI(3,4))
next
  case (5 s t1 t2)
  with assms have "v ⊢ last b"
    by (metis empty_iff empty_set last_in_set)
  from assms "5"(2,3) show ?thesis
    unfolding "5"(1)
    using types_if_types_Member_and_subterms[where ?f="(-s)", OF _ ‹v ⊢ last b› "5"(3),
                                             THEN types_pset_atom_Member_Diff_D(2)]
    by (force dest!: types_fmD(6) assms(4) intro!: types_fmI(3,4))
qed

lemma types_term_if_on_vars_eq:
  assumes "∀x ∈ vars t. v' x = v x"
  shows "v' ⊢ t : l ⟷ v ⊢ t : l"
  using assms
  apply(induction t arbitrary: l)
       apply(auto intro!: types_pset_term_intros' types_pset_term.intros(4-) 
                  elim!: types_pset_term_cases) 
  done

lemma types_pset_atom_if_on_vars_eq:
  fixes a :: "'a pset_atom"
  assumes "∀x ∈ vars a. v' x = v x"
  shows "v' ⊢ a ⟷ v ⊢ a"
  using assms
  by (auto simp: ball_Un types_pset_atom.simps dest!: types_term_if_on_vars_eq)

lemma types_pset_fm_if_on_vars_eq:
  fixes φ :: "'a pset_fm"
  assumes "∀x ∈ vars φ. v' x = v x"
  shows "v' ⊢ φ ⟷ v ⊢ φ"
  using assms types_pset_atom_if_on_vars_eq
  unfolding types_pset_fm_def vars_fm_def by fastforce

lemma types_term_fun_upd:
  assumes "x ∉ vars t"
  shows "v(x := l) ⊢ t : l ⟷ v ⊢ t : l"
  using assms types_term_if_on_vars_eq by (metis fun_upd_other)

lemma types_pset_atom_fun_upd:
  fixes a :: "'a pset_atom"
  assumes "x ∉ vars a"
  shows "v(x := l) ⊢ a ⟷ v ⊢ a"
  using assms types_pset_atom_if_on_vars_eq by (metis fun_upd_other)

lemma types_pset_fm_fun_upd:
  fixes φ :: "'a pset_fm"
  assumes "x ∉ vars φ"
  shows "v(x := l) ⊢ φ ⟷ v ⊢ φ"
  using assms types_pset_fm_if_on_vars_eq by (metis fun_upd_other)

lemma types_bexpands_wit:
  fixes b :: "'a branch" and bs' :: "'a branch set"
  assumes "bexpands_wit t1 t2 x bs' b" "b ≠ []"
  assumes "⋀(φ :: 'a pset_fm). φ ∈ set b ⟹ v ⊢ φ"
  obtains l where "∀φ ∈ set b. v(x := l) ⊢ φ"
                  "∀b' ∈ bs'. ∀φ ∈ set b'. v(x := l) ⊢ φ"
  using assms(1)
proof(cases rule: bexpands_wit.cases)
  case 1
  from assms(3)[OF "1"(2)] obtain lt where lt: "v ⊢ t1 : lt" "v ⊢ t2 : lt"
    by (auto dest!: types_fmD simp: types_pset_atom.simps)
  with 1 assms(2,3) have "lt ≠ 0"
    unfolding urelem_def using last_in_set by metis
  with lt obtain ltp where ltp: "v ⊢ t1 : Suc ltp" "v ⊢ t2 : Suc ltp"
    using not0_implies_Suc by blast
  with assms(3) have "∀φ ∈ set b. v(x := ltp) ⊢ φ"
    using types_pset_fm_fun_upd ‹x ∉ vars b› by (metis vars_fm_vars_branchI)
  moreover from ‹x ∉ vars b› ‹AF (t1 =s t2) ∈ set b› have not_in_vars: "x ∉ vars t1" "x ∉ vars t2"
    using assms(2) by (auto simp: vars_fm_vars_branchI)
  from this[THEN types_term_fun_upd] have "∀b' ∈ bs'. ∀φ ∈ set b'. v(x := ltp) ⊢ φ"
    using ltp unfolding "1"(1) 
    apply(auto intro!: types_fmI types_pset_term_intros'(2) simp: types_pset_atom.simps)
    apply (metis fun_upd_same fun_upd_upd types_pset_term.intros(2))+
    done
  ultimately show ?thesis
    using that by blast
qed

lemma types_expandss:
  fixes b b' :: "'a branch"
  assumes "expandss b' b" "b ≠ []"
  assumes "⋀φ. φ ∈ set b ⟹ v ⊢ φ"
  obtains v' where "∀x ∈ vars b. v' x = v x" "∀φ ∈ set b'. v' ⊢ φ"
  using assms
proof(induction b' b arbitrary: thesis rule: expandss.induct)
  case (1 b)
  then show ?case by blast
next
  case (2 b3 b2 b1)
  then obtain v' where v': "∀x ∈ vars b1. v' x = v x" "∀φ ∈ set b2. v' ⊢ φ"
    by blast
  with types_lexpands[OF ‹lexpands b3 b2›] have "∀φ ∈ set b3. v' ⊢ φ"
    using expandss_not_Nil[OF ‹expandss b2 b1› ‹b1 ≠ []›] by blast
  with v' "2.prems" show ?case
    by force
next
  case (3 bs b2 b3 b1)
  then obtain v' where v': "∀x ∈ vars b1. v' x = v x" "∀φ ∈ set b2. v' ⊢ φ"
    by blast
  from ‹bexpands bs b2› show ?case
  proof(cases rule: bexpands.cases)
    case 1
    from types_bexpands_nowit[OF this] v' ‹b3 ∈ bs› have "∀φ ∈ set b3. v' ⊢ φ"
      by blast
    with v' "3.prems" show ?thesis
      by force
  next
    case (2 t1 t2 x)
    from types_bexpands_wit[OF this] v' ‹b3 ∈ bs› obtain l
      where "∀φ ∈ set b3. v'(x := l) ⊢ φ"
      using expandss_not_Nil[OF ‹expandss b2 b1› ‹b1 ≠ []›] by metis
    moreover from bexpands_witD(9)[OF 2] have "x ∉ vars b1"
      using expandss_mono[OF ‹expandss b2 b1›] unfolding vars_branch_def by blast
    then have "∀y ∈ vars b1. (v'(x := l)) y = v y"
      using v'(1) by simp
    moreover from ‹x ∉ vars b2› v'(2) have "∀φ ∈ set b2. v'(x := l) ⊢ φ"
      by (meson types_pset_fm_fun_upd vars_fm_vars_branchI)
    ultimately show ?thesis
      using v' "3.prems"(1)[where ?v'="v'(x := l)"] by fastforce
  qed
qed

lemma urelem_invar_if_wf_branch:
  assumes "wf_branch b"
  assumes "urelem (last b) x" "x ∈ subterms (last b)"
  shows "∃v. ∀φ ∈ set b. urelem' v φ x"
proof -
  from assms obtain v where v: "v ⊢ last b" "v ⊢ x : 0"
    unfolding urelem_def by blast
  moreover from assms have "expandss b [last b]"
    by (metis expandss_last_eq last.simps list.distinct(1) wf_branch_def)
  from types_expandss[OF this, simplified] v obtain v' where
    "∀x ∈ vars (last b). v' x = v x" "∀φ ∈ set b. v' ⊢ φ"
    by (metis list.set_intros(1) vars_fm_vars_branchI)
  ultimately show ?thesis
    unfolding urelem_def using assms
    by (metis mem_vars_fm_if_mem_subterms_fm types_term_if_on_vars_eq)
qed

lemma not_types_term_0_if_types_term:
  fixes s :: "'a pset_term"
  assumes "f t1 t2 ∈ subterms s" "f ∈ {(⊓s), (⊔s), (-s)}"
  assumes "v ⊢ f t1 t2 : l"
  shows "¬ v ⊢ t1 : 0" "¬ v ⊢ t2 : 0"
  using assms
  by (induction s arbitrary: l)
     (auto elim: types_pset_term_cases dest: types_term_unique)

lemma types_term_subterms:
  assumes "t ∈ subterms s"
  assumes "v ⊢ s : ls"
  obtains lt where "v ⊢ t : lt"
  using assms
  by (induction s arbitrary: ls) (auto elim: types_pset_term_cases dest: types_term_unique)

lemma types_atom_subterms:
  fixes a :: "'a pset_atom"
  assumes "t ∈ subterms a"
  assumes "v ⊢ a"
  obtains lt where "v ⊢ t : lt"
  using assms
  by (cases a) (fastforce elim: types_term_subterms simp: types_pset_atom.simps)+

lemma subterms_type_pset_fm_not_None:
  fixes φ :: "'a pset_fm"
  assumes "t ∈ subterms φ"
  assumes "v ⊢ φ"
  obtains lt where "v ⊢ t : lt"
  using assms 
  by (induction φ) (auto elim: types_atom_subterms dest: types_fmD(1-5) dest!: types_fmD(6))

lemma not_urelem_comps_if_compound:
  assumes "f t1 t2 ∈ subterms φ" "f ∈ {(⊓s), (⊔s), (-s)}"
  shows "¬ urelem φ t1" "¬ urelem φ t2"
proof -
  from assms have "¬ v ⊢ t1 : 0" "¬ v ⊢ t2 : 0" if "v ⊢ φ" for v
    using that not_types_term_0_if_types_term[OF _ _ subterms_type_pset_fm_not_None]
    using subterms_refl by metis+
  then show "¬ urelem φ t1" "¬ urelem φ t2"
    unfolding urelem_def by blast+
qed

(*<*)
end

end
(*>*)