Theory MLSS_Typing_Urelems

(*<*)
theory MLSS_Typing_Urelems
  imports MLSS_Suc_Theory MLSS_Typing
begin
(*>*)

section ‹Typing the Urelements›
text ‹
  We define a recursive procedure that generates typing
  constraints. We then prove that the constraints can be solved with
  const‹MLSS_Suc_Theory.assign›. The solution then gives us the urelements.
›

abbreviation (input) "SVar ≡ MLSS_Suc_Theory.Var"
abbreviation (input) "SEq ≡ MLSS_Suc_Theory.Eq"
abbreviation (input) "SNEq ≡ MLSS_Suc_Theory.NEq"
abbreviation (input) "ssolve ≡ MLSS_Suc_Theory.solve"
abbreviation (input) "sassign ≡ MLSS_Suc_Theory.assign"

fun constrs_term :: "('a pset_term ⇒ 'b) ⇒ 'a pset_term ⇒ 'b suc_atom list" where
  "constrs_term n (Var x) = [SEq (SVar (n (Var x))) (SVar (n (Var x)))]"
| "constrs_term n (∅ k) = [SEq (SVar (n (∅ k))) (Succ (Suc k) Zero)]"
| "constrs_term n (t1 ⊔s t2) =
    [SEq (SVar (n (t1 ⊔s t2))) (SVar (n t1)), SEq (SVar (n t1)) (SVar (n t2)), SNEq (SVar (n t1)) Zero]
    @ constrs_term n t1 @ constrs_term n t2"
| "constrs_term n (t1 ⊓s t2) =
    [SEq (SVar (n (t1 ⊓s t2))) (SVar (n t1)), SEq (SVar (n t1)) (SVar (n t2)), SNEq (SVar (n t1)) Zero]
    @ constrs_term n t1 @ constrs_term n t2"
| "constrs_term n (t1 -s t2) =
    [SEq (SVar (n (t1 -s t2))) (SVar (n t1)), SEq (SVar (n t1)) (SVar (n t2)), SNEq (SVar (n t1)) Zero]
    @ constrs_term n t1 @ constrs_term n t2"
| "constrs_term n (Single t) =
    [SEq (SVar (n (Single t))) (Succ 1 (SVar (n t)))]
    @ constrs_term n t"
      
fun constrs_atom :: "('a pset_term ⇒ 'b) ⇒ 'a pset_atom ⇒ 'b suc_atom list" where
  "constrs_atom n (t1 =s t2) =
    [SEq (SVar (n t1)) (SVar (n t2))]
    @ constrs_term n t1 @ constrs_term n t2"
| "constrs_atom n (t1 ∈s t2) =
    [SEq (SVar (n t2)) (Succ 1 (SVar (n t1)))]
    @ constrs_term n t1 @ constrs_term n t2"

fun constrs_fm :: "('a pset_term ⇒ 'b) ⇒ 'a pset_fm ⇒ 'b suc_atom list" where
  "constrs_fm n (Atom a) = constrs_atom n a"
| "constrs_fm n (And p q) = constrs_fm n p @ constrs_fm n q"
| "constrs_fm n (Or p q) = constrs_fm n p @ constrs_fm n q"
| "constrs_fm n (Neg p) = constrs_fm n p"

lemma is_Succ_normal_constrs_term:
  "∀a ∈ set (constrs_term n t). MLSS_Suc_Theory.is_Eq a ⟶ is_Succ_normal a"
  by (induction t) auto

lemma is_Succ_normal_constrs_atom:
  "∀a ∈ set (constrs_atom n a). MLSS_Suc_Theory.is_Eq a ⟶ is_Succ_normal a"
  by (cases a) (use is_Succ_normal_constrs_term in auto)

lemma is_Succ_normal_constrs_fm:
  "∀a ∈ set (constrs_fm n φ). MLSS_Suc_Theory.is_Eq a ⟶ is_Succ_normal a"
  by (induction φ) (use is_Succ_normal_constrs_atom in auto)

lemma is_Var_Eq_Zero_if_is_NEq_constrs_term:
  "∀a ∈ set (constrs_term n t). MLSS_Suc_Theory.is_NEq a ⟶ (∃x. a = SNEq (SVar x) Zero)"
  by (induction t) auto

lemma is_Var_Eq_Zero_if_is_NEq_constrs_atom:
  "∀a ∈ set (constrs_atom n a). MLSS_Suc_Theory.is_NEq a ⟶ (∃x. a = SNEq (SVar x) Zero)"
  by (cases a) (use is_Var_Eq_Zero_if_is_NEq_constrs_term in auto)

lemma is_Var_Eq_Zero_if_is_NEq_constrs_fm:
  "∀a ∈ set (constrs_fm n φ). MLSS_Suc_Theory.is_NEq a ⟶ (∃x. a = SNEq (SVar x) Zero)"
  by (induction φ) (use is_Var_Eq_Zero_if_is_NEq_constrs_atom in auto)

lemma types_term_if_I_atom_constrs_term:
  includes no member_ASCII_syntax
  assumes "(∀e ∈ set (constrs_term n t). MLSS_Suc_Theory.I_atom v e)"
  shows "(λx. v (n (Var x))) ⊢ t : v (n t)"
  using assms
  by (induction t) (auto intro: types_pset_term.intros)

lemma types_pset_atom_if_I_atom_constrs_atom:
  fixes a :: "'a pset_atom"
  assumes "(∀e ∈ set (constrs_atom n a). MLSS_Suc_Theory.I_atom v e)"
  shows "(λx. v (n (Var x))) ⊢ a"
  using assms
  by (cases a)
     (auto simp: types_pset_atom.simps ball_Un dest!: types_term_if_I_atom_constrs_term)

lemma types_pset_fm_if_I_atom_constrs_fm:
  fixes φ :: "'a pset_fm"
  assumes "(∀e ∈ set (constrs_fm n φ). MLSS_Suc_Theory.I_atom v e)"
  shows "(λx. v (n (Var x))) ⊢ φ"
  using assms
  by (induction φ)
     (auto intro: types_fmI types_pset_atom_if_I_atom_constrs_atom)

lemma I_atom_constrs_term_if_types_term:
  includes no member_ASCII_syntax
  assumes "inj_on n T" "subterms t ⊆ T"
  assumes "v ⊢ t : k"
  shows "(∀e ∈ set (constrs_term n t).
    MLSS_Suc_Theory.I_atom (λx. type_of_term v (inv_into T n x)) e)"
  using assms inv_into_f_f[OF assms(1) subsetD[OF assms(2)]]
  by (induction t arbitrary: T k)
     (auto elim!: types_pset_term_cases intro!: type_of_term_if_types_term
           simp: type_of_term_if_types_term)

lemma I_atom_constrs_atom_if_types_pset_atom:
  fixes a :: "'a pset_atom"
  assumes "inj_on n T" "subterms a ⊆ T"
  assumes "v ⊢ a"
  shows "(∀e ∈ set (constrs_atom n a).
    MLSS_Suc_Theory.I_atom (λx. type_of_term v (inv_into T n x)) e)"
  using assms I_atom_constrs_term_if_types_term
  by (cases a)
     (force simp: types_pset_atom.simps type_of_term_if_types_term subsetD)+

lemma I_atom_constrs_fm_if_types_pset_fm:
  fixes φ :: "'a pset_fm"
  assumes "inj_on n T" "subterms φ ⊆ T"
  assumes "v ⊢ φ"
  shows "(∀e ∈ set (constrs_fm n φ).
    MLSS_Suc_Theory.I_atom (λx. type_of_term v (inv_into T n x)) e)"
  using assms
  by (induction φ)
     (auto dest: types_fmD simp: I_atom_constrs_atom_if_types_pset_atom)

lemma inv_into_f_eq_if_subs:
  assumes "inj_on f B" "A ⊆ B" "y ∈ f ` A"
  shows "inv_into B f y = inv_into A f y"
  using assms inv_into_f_eq
  by (metis f_inv_into_f inv_into_into subset_eq)

lemma UN_set_suc_atom_constrs_term_eq_image_subterms:
  "⋃(set_suc_atom ` set (constrs_term n t)) = n ` subterms t"
  by (induction t) auto

lemma UN_set_suc_atom_constrs_atom_eq_image_subterms:
  "⋃(set_suc_atom ` set (constrs_atom n a)) = n ` subterms a"
  by (induction a) (auto simp: UN_set_suc_atom_constrs_term_eq_image_subterms)

lemma UN_set_suc_atom_constrs_fm_eq_image_subterms:
  "⋃(set_suc_atom ` set (constrs_fm n φ)) = n ` subterms φ"
  by (induction φ) (auto simp: UN_set_suc_atom_constrs_atom_eq_image_subterms)

lemma
  fixes φ :: "'a pset_fm"
  assumes "inj_on n (subterms φ)"
  assumes "ssolve (MLSS_Suc_Theory.elim_NEq_Zero (constrs_fm n φ)) = Some ss"
  shows types_pset_fm_assign_solve: "(λx. sassign ss (n (Var x))) ⊢ φ"
    and minimal_assign_solve: "⟦ v ⊢ φ; z ∈ vars φ ⟧ ⟹ sassign ss (n (Var z)) ≤ v z"
proof -
  note I_atom_assign_if_solve_elim_NEq_Zero_Some[OF _ _ assms(2)]
  then have "∀e ∈ set (constrs_fm n φ). MLSS_Suc_Theory.I_atom (sassign ss) e"
    using is_Succ_normal_constrs_fm is_Var_Eq_Zero_if_is_NEq_constrs_fm by blast
  note types_pset_fm_if_I_atom_constrs_fm[OF this]
  then show "(λx. sassign ss (n (Var x))) ⊢ φ" .

  let ?v' = "λx. type_of_term v (inv_into (subterms φ) n x)"
  note I_atom_assign_minimal_if_solve_elim_NEq_Zero_Some[OF _ _ assms(2)]
  then have assign_leq: "sassign ss z ≤ v z"
    if "∀a ∈ set (constrs_fm n φ). MLSS_Suc_Theory.I_atom v a"
       "z ∈ ⋃ (set_suc_atom ` set (constrs_fm n φ))" for v z
    using that is_Succ_normal_constrs_fm is_Var_Eq_Zero_if_is_NEq_constrs_fm
    by blast
  show "sassign ss (n (Var z)) ≤ v z" if "v ⊢ φ" "z ∈ vars φ"
  proof -
    note assign_leq[unfolded UN_set_suc_atom_constrs_fm_eq_image_subterms, where ?v="?v'"]
    note assign_leq' = this[OF I_atom_constrs_fm_if_types_pset_fm[OF assms(1) _ ‹v ⊢ φ›, simplified]]

    from ‹z ∈ vars φ› have "n (Var z) ∈ n ` subterms φ"
      by (simp add: vars_fm_subs_subterms_fm)
    from assign_leq'[OF this] ‹inj_on n (subterms φ)› ‹z ∈ vars φ› show ?thesis
      using vars_fm_subs_subterms_fm
      by (metis inv_into_f_f type_of_term_if_types_term types_pset_term.intros(2))
  qed
qed

  
lemma types_term_minimal:
  includes no member_ASCII_syntax
  assumes "⋀z. z ∈ vars t ⟹ v_min z ≤ v z"
  assumes "v_min ⊢ t : k'" "v ⊢ t : k"
  shows "k' ≤ k"
  using assms
  by (induction t arbitrary: k' k) (auto elim!: types_pset_term_cases)

lemma constrs_term_subs_constrs_term:
  assumes "s ∈ subterms t"
  shows "set (constrs_term n s) ⊆ set (constrs_term n t)"
  using assms
  by (induction t) auto

lemma constrs_term_subs_constrs_atom:
  assumes "t ∈ subterms a"
  shows "set (constrs_term n t) ⊆ set (constrs_atom n a)"
  using assms constrs_term_subs_constrs_term by (cases a) force+

lemma constrs_term_subs_constrs_fm:
  assumes "t ∈ subterms φ"
  shows "set (constrs_term n t) ⊆ set (constrs_fm n φ)"
  using assms
  by (induction φ) (auto simp: constrs_term_subs_constrs_atom)

lemma urelem_iff_assign_eq_0:
  includes no member_ASCII_syntax
  assumes "inj_on n (subterms φ)"
  assumes "t ∈ subterms φ"
  assumes "ssolve (MLSS_Suc_Theory.elim_NEq_Zero (constrs_fm n φ)) = Some ss"
  shows "urelem φ t ⟷ sassign ss (n t) = 0"
proof -
  note types = types_pset_fm_assign_solve[OF assms(1,3)]

  note I_atom_assign_if_solve_elim_NEq_Zero_Some[OF _ _ assms(3)]
  then have "∀e ∈ set (constrs_fm n φ). MLSS_Suc_Theory.I_atom (sassign ss) e"
    using is_Succ_normal_constrs_fm is_Var_Eq_Zero_if_is_NEq_constrs_fm by blast
  then have "∀e ∈ set (constrs_term n t). MLSS_Suc_Theory.I_atom (sassign ss) e"
    using constrs_term_subs_constrs_fm[OF ‹t ∈ subterms φ›] by blast
  note type_term_t = types_term_if_I_atom_constrs_term[OF this]

  note minimal = minimal_assign_solve[OF assms(1,3)]
  have "∃lt'. v ⊢ t : lt' ∧ sassign ss (n t) ≤ lt'"
    if "v ⊢ φ" for v
  proof -
    from that obtain lt' where "v ⊢ t : lt'"
      using ‹t ∈ subterms φ›
      by (meson not_Some_eq subterms_type_pset_fm_not_None)
    moreover note minimal[OF that] types_term_minimal[OF _ type_term_t]
    ultimately show ?thesis
      by (metis assms(2) mem_vars_fm_if_mem_subterms_fm)
  qed
  
  then show "urelem φ t ⟷ sassign ss (n t) = 0"
    using types type_term_t types_term_unique unfolding urelem_def
    by (metis le_zero_eq)
qed

lemma not_types_fm_if_solve_eq_None:
  fixes φ :: "'a pset_fm"
  assumes "inj_on n (subterms φ)"
  assumes "ssolve (MLSS_Suc_Theory.elim_NEq_Zero (constrs_fm n φ)) = None"
  shows "¬ v ⊢ φ"
proof
  assume "v ⊢ φ"
  note I_atom_constrs_fm_if_types_pset_fm[OF assms(1) _ this]
  moreover
  note not_I_atom_if_solve_elim_NEq_Zero_None[OF _ _ assms(2)]
  then have "∃a∈set (constrs_fm n φ). ¬ MLSS_Suc_Theory.I_atom v a" for v
    using is_Succ_normal_constrs_fm is_Var_Eq_Zero_if_is_NEq_constrs_fm by blast
  ultimately show False
    by blast
qed

(*<*)
end
(*>*)