Theory Abstract_Substitution.Abstract_Substitution

theory Abstract_Substitution
  imports Monoid_Action
begin

abbreviation set_prod where
  "set_prod ≡ λ(t, t'). {t, t'}"


section ‹Assumption-free Substitution›

locale abstract_substitution_ops =
  fixes
    subst :: "'x ⇒ 's ⇒ 'x" (infixl ‹⋅› 67) and
    id_subst :: 's and
    comp_subst :: "'s ⇒ 's ⇒ 's" (infixl ‹⊙› 67) and
    is_ground :: "'x ⇒ bool"
begin

definition subst_set :: "'x set ⇒ 's ⇒ 'x set" where
  "subst_set X σ = (λx. subst x σ) ` X"

definition subst_list :: "'x list ⇒ 's ⇒ 'x list" where
  "subst_list xs σ = map (λx. subst x σ) xs"

definition is_ground_set :: "'x set ⇒ bool" where
  "is_ground_set X ⟷ (∀x ∈ X. is_ground x)"

definition is_ground_subst :: "'s ⇒ bool" where
  "is_ground_subst γ ⟷ (∀x. is_ground (x ⋅ γ))"

definition generalizes :: "'x ⇒ 'x ⇒ bool" where
  "generalizes x y ⟷ (∃σ. x ⋅ σ = y)"

definition specializes :: "'x ⇒ 'x ⇒ bool" where
  "specializes x y ≡ generalizes y x"

definition strictly_generalizes :: "'x ⇒ 'x ⇒ bool" where
  "strictly_generalizes x y ⟷ generalizes x y ∧ ¬ generalizes y x"

definition strictly_specializes :: "'x ⇒ 'x ⇒ bool" where
  "strictly_specializes x y ≡ strictly_generalizes y x"

definition instances :: "'x ⇒ 'x set" where
  "instances x = {y. generalizes x y}"

definition instances_set :: "'x set ⇒ 'x set" where
  "instances_set X = (⋃x ∈ X. instances x)"

definition ground_instances :: "'x ⇒ 'x set" where
  "ground_instances x = {x𝒢 ∈ instances x. is_ground x𝒢}"

definition ground_instances_set :: "'x set ⇒ 'x set" where
  "ground_instances_set X = {x𝒢 ∈ instances_set X. is_ground x𝒢}"

lemma ground_instances_set_eq_Union_ground_instances:
  "ground_instances_set X = (⋃x ∈ X. ground_instances x)"
  unfolding ground_instances_set_def ground_instances_def
  unfolding instances_set_def
  by auto

lemma ground_instances_eq_Collect_subst_grounding:
  "ground_instances x = {x ⋅ γ | γ. is_ground (x ⋅ γ)}"
  by (auto simp: ground_instances_def instances_def generalizes_def)

lemma mem_ground_instancesE[elim]:
  fixes x xG :: 'x
  assumes "xG ∈ ground_instances x"
  obtains γ :: 's where "xG = x ⋅ γ" and "is_ground (x ⋅ γ)"
  using assms
  unfolding ground_instances_eq_Collect_subst_grounding mem_Collect_eq
  by iprover

lemma mem_ground_instances_setE[elim]:
  fixes xG :: 'x and X :: "'x set"
  assumes "xG ∈ ground_instances_set X"
  obtains x :: 'x and γ :: 's where "x ∈ X" and "xG = x ⋅ γ" and "is_ground (x ⋅ γ)"
  using assms
  unfolding ground_instances_set_eq_Union_ground_instances
  by blast

definition is_unifier :: "'s ⇒ 'x set ⇒ bool" where
  "is_unifier υ X ⟷ X = {} ∨ card (subst_set X υ) = 1"

definition is_unifier_set :: "'s ⇒ 'x set set ⇒ bool" where
  "is_unifier_set υ XX ⟷ (∀X ∈ XX. is_unifier υ X)"

definition is_mgu :: "'s ⇒ 'x set set ⇒ bool" where
  "is_mgu μ XX ⟷ is_unifier_set μ XX ∧ (∀υ. is_unifier_set υ XX ⟶ (∃σ. μ ⊙ σ = υ))"

definition is_imgu :: "'s ⇒ 'x set set ⇒ bool" where
  "is_imgu μ XX ⟷ is_unifier_set μ XX ∧ (∀τ. is_unifier_set τ XX ⟶ μ ⊙ τ = τ)"

lemma is_unifier_iff:  "is_unifier σ X ⟷ (∀x∈X. ∀y∈X. x ⋅ σ = y ⋅ σ)" 
proof (rule iffI)

  show "is_unifier σ X ⟹ (∀x∈X. ∀y∈X. x ⋅ σ = y ⋅ σ)"
    unfolding is_unifier_def subst_set_def
    by (smt (verit, best) all_not_in_conv card_1_singletonE imageI singletonD)
next

  show "(∀x∈X. ∀y∈X. x ⋅ σ = y ⋅ σ) ⟹ is_unifier σ X"
    unfolding is_unifier_def subst_set_def
    by (smt (verit, del_insts) ex_in_conv image_iff is_singletonI' is_singleton_altdef)
qed

lemma is_unifier_singleton[simp]: "is_unifier υ {x}"
  by (simp add: is_unifier_iff)

lemma is_unifier_empty[simp]: "is_unifier σ {}"
  by (simp add: is_unifier_iff)

lemma is_unifier_set_empty[simp]: "is_unifier_set σ {}"
  by (simp add: is_unifier_set_def)

lemma is_unifier_set_insert:
  "is_unifier_set σ (insert X XX) ⟷ is_unifier σ X ∧ is_unifier_set σ XX"
  by (simp add: is_unifier_set_def)

lemma is_unifier_set_insert_singleton[simp]:
  "is_unifier_set σ (insert {x} XX) ⟷ is_unifier_set σ XX"
  by (simp add: is_unifier_set_def)

lemma is_mgu_insert_singleton[simp]: "is_mgu μ (insert {x} XX) ⟷ is_mgu μ XX"
  by (simp add: is_mgu_def)

lemma is_imgu_insert_singleton[simp]: "is_imgu μ (insert {x} XX) ⟷ is_imgu μ XX"
  by (simp add: is_imgu_def)

lemma subst_set_empty[simp]: "subst_set {} σ = {}"
  by (simp only: subst_set_def image_empty)

lemma subst_set_insert[simp]: "subst_set (insert x X) σ = insert (x ⋅ σ) (subst_set X σ)"
  by (simp only: subst_set_def image_insert)

lemma subst_set_union[simp]: "subst_set (X1 ∪ X2) σ = subst_set X1 σ ∪ subst_set X2 σ"
  by (simp only: subst_set_def image_Un)

lemma subst_list_Nil[simp]: "subst_list [] σ = []"
  by (simp only: subst_list_def list.map)

lemma subst_list_insert[simp]: "subst_list (x # xs) σ = (x ⋅ σ) # (subst_list xs σ)"
  by (simp only: subst_list_def list.map)

lemma subst_list_append[simp]: "subst_list (xs1 @ xs2) σ = subst_list xs1 σ @ subst_list xs2 σ"
  by (simp only: subst_list_def map_append)

lemma is_unifier_set_union:
  "is_unifier_set υ (XX1 ∪ XX2) ⟷ is_unifier_set υ XX1 ∧ is_unifier_set υ XX2"
  by (auto simp add: is_unifier_set_def)

lemma is_unifier_subset: "is_unifier υ A ⟹ B ⊆ A ⟹ is_unifier υ B"
  unfolding is_unifier_iff
  by auto

lemma is_ground_set_subset: "is_ground_set A ⟹ B ⊆ A ⟹ is_ground_set B"
  by (auto simp: is_ground_set_def)

lemma is_ground_set_ground_instances[simp]: "is_ground_set (ground_instances x)"
  by (simp add: ground_instances_def is_ground_set_def)

lemma is_ground_set_ground_instances_set[simp]: "is_ground_set (ground_instances_set x)"
  by (simp add: ground_instances_set_def is_ground_set_def)

end


section ‹Basic Substitution›

locale abstract_substitution_monoid = monoid comp_subst id_subst ✐‹contributor ‹Balazs Toth››
  for
    comp_subst :: "'s ⇒ 's ⇒ 's" and
    id_subst :: 's
begin

abbreviation is_renaming where
 "is_renaming ≡ is_right_invertible"

lemmas is_renaming_def = is_right_invertible_def

abbreviation renaming_inverse where
  "renaming_inverse ≡ right_inverse"

lemmas renaming_inverse_def = right_inverse_def

lemmas is_renaming_id_subst = neutral_is_right_invertible

definition is_idem :: "'s ⇒ bool" where
  "is_idem a ⟷ comp_subst a a = a"

lemma is_idem_id_subst [simp]: "is_idem id_subst"
  by (simp add: is_idem_def)

lemma exists_renaming [intro]: "∃ρ. is_renaming ρ"
  using neutral_is_right_invertible
  by blast

lemma exists_idem [intro]: "∃σ. is_idem σ"
  using is_idem_id_subst
  by blast

end

locale abstract_substitution =
  abstract_substitution_monoid comp_subst id_subst +
  comp_subst: right_monoid_action comp_subst id_subst subst +
  abstract_substitution_ops subst id_subst comp_subst is_ground
  for
    comp_subst :: "'s ⇒ 's ⇒ 's" (infixl ‹⊙› 70) and
    id_subst :: 's and
    subst :: "'x ⇒ 's ⇒ 'x" (infixl ‹⋅› 69) and

    ― ‹Predicate identifying the fixed elements w.r.t. the monoid action›
    is_ground :: "'x ⇒ bool" +
  assumes
    all_subst_ident_if_ground: "is_ground x ⟹ (∀σ. x ⋅ σ = x)"
begin

sublocale comp_subst_set: right_monoid_action comp_subst id_subst subst_set
  using comp_subst.lifting_monoid_action_to_set unfolding subst_set_def .

sublocale comp_subst_list: right_monoid_action comp_subst id_subst subst_list
  using comp_subst.lifting_monoid_action_to_list unfolding subst_list_def .


subsection ‹Substitution Composition›

lemmas subst_comp_subst = comp_subst.action_compatibility
lemmas subst_set_comp_subst = comp_subst_set.action_compatibility
lemmas subst_list_comp_subst = comp_subst_list.action_compatibility


subsection ‹Substitution Identity›

lemmas subst_id_subst = comp_subst.action_neutral
lemmas subst_set_id_subst = comp_subst_set.action_neutral
lemmas subst_list_id_subst = comp_subst_list.action_neutral

lemma is_mgu_id_subst_empty[simp]: "is_mgu id_subst {}"
  by (simp add: is_mgu_def)

lemma is_imgu_id_subst_empty[simp]: "is_imgu id_subst {}"
  by (simp add: is_imgu_def)

lemma is_unifier_id_subst: "is_unifier id_subst X ⟷ X = {} ∨ card X = 1"
  unfolding is_unifier_def
  by auto

lemma is_unifier_set_id_subst: "is_unifier_set id_subst XX ⟷ (∀X ∈ XX. X = {} ∨ card X = 1)"
  by (simp add: is_unifier_set_def is_unifier_id_subst)

lemma is_mgu_id_subst: "is_mgu id_subst XX ⟷ (∀X ∈ XX. X = {} ∨ card X = 1)"
  by (simp add: is_mgu_def is_unifier_set_id_subst)

lemma is_imgu_id_subst: "is_imgu id_subst XX ⟷ (∀X ∈ XX. X = {} ∨ card X = 1)"
  by (simp add: is_imgu_def is_unifier_set_id_subst)


subsection ‹Generalization›

sublocale generalizes: preorder generalizes strictly_generalizes
proof unfold_locales
  show "⋀x y. strictly_generalizes x y = (generalizes x y ∧ ¬ generalizes y x)"
    unfolding strictly_generalizes_def generalizes_def by blast
next
  show "⋀x. generalizes x x"
    unfolding generalizes_def using subst_id_subst by metis
next
  show "⋀x y z. generalizes x y ⟹ generalizes y z ⟹ generalizes x z"
    unfolding generalizes_def using subst_comp_subst by metis
qed

lemma generalizes_antisym_if:
  assumes "⋀σ1 σ2 x. x ⋅ (σ1 ⊙ σ2) = x ⟹ x ⋅ σ1 = x"
  shows "⋀x y. generalizes x y ⟹ generalizes y x ⟹ x = y"
  using assms
  by (metis generalizes_def subst_comp_subst)

lemma order_generalizes_if:
  assumes "⋀σ1 σ2 x. x ⋅ (σ1 ⊙ σ2) = x ⟹ x ⋅ σ1 = x"
  shows "class.order generalizes strictly_generalizes"
proof unfold_locales
  show "⋀x y. generalizes x y ⟹ generalizes y x ⟹ x = y"
    using generalizes_antisym_if assms by iprover
qed


subsection ‹Substituting on Ground Expressions›

lemma subst_ident_if_ground[simp]: "is_ground x ⟹ x ⋅ σ = x"
  using all_subst_ident_if_ground by simp

lemma subst_set_ident_if_ground[simp]: "is_ground_set X ⟹ subst_set X σ = X"
  unfolding is_ground_set_def subst_set_def by simp


subsection ‹Instances of Ground Expressions›

lemma instances_ident_if_ground[simp]: "is_ground x ⟹ instances x = {x}"
  unfolding instances_def generalizes_def by simp

lemma instances_set_ident_if_ground[simp]: "is_ground_set X ⟹ instances_set X = X"
  unfolding instances_set_def is_ground_set_def by simp

lemma ground_instances_ident_if_ground[simp]: "is_ground x ⟹ ground_instances x = {x}"
  unfolding ground_instances_def by auto

lemma ground_instances_set_ident_if_ground[simp]: "is_ground_set X ⟹ ground_instances_set X = X"
  unfolding is_ground_set_def ground_instances_set_eq_Union_ground_instances by simp


subsection ‹Unifier of Ground Expressions›

lemma ground_eq_ground_if_unifiable:
  assumes "is_unifier υ {t1, t2}" and "is_ground t1" and "is_ground t2"
  shows "t1 = t2"
  using assms 
  by (simp add: card_Suc_eq is_unifier_def le_Suc_eq subst_set_def)

corollary ground_eq_ground_if_mgu:
  assumes "is_mgu μ {{t1, t2}}" "is_ground t1" "is_ground t2" 
  shows "t1 = t2"
  using assms ground_eq_ground_if_unifiable
  unfolding is_mgu_def is_unifier_set_insert
  by blast

corollary ground_eq_ground_if_imgu:
  assumes "is_imgu μ {{t1, t2}}" "is_ground t1" "is_ground t2" 
  shows "t1 = t2"
  using assms ground_eq_ground_if_unifiable
  unfolding is_imgu_def is_unifier_set_insert
  by blast

lemma ball_eq_constant_if_unifier:
  assumes "x ∈ X" and "is_unifier υ X" and "is_ground_set X"
  shows "∀y ∈ X. y = x"
  using assms
  by (simp add: is_ground_set_def is_unifier_iff)

lemma is_mgu_unifies: ✐‹contributor ‹Balazs Toth››
  assumes "is_mgu μ XX"
  shows "∀X ∈ XX. ∀t ∈ X. ∀t' ∈ X. t ⋅ μ = t' ⋅ μ"
  using assms is_unifier_iff
  unfolding is_mgu_def is_unifier_set_def
  by blast

corollary is_mgu_unifies_pair: ✐‹contributor ‹Balazs Toth›› 
  assumes "is_mgu μ {{t, t'}}"
  shows "t ⋅ μ = t' ⋅ μ"
  using is_mgu_unifies[OF assms]
  by (meson insert_iff)

lemmas subst_mgu_eq_subst_mgu = is_mgu_unifies_pair

lemma is_imgu_unifies: ✐‹contributor ‹Balazs Toth››
  assumes "is_imgu μ XX"
  shows "∀X ∈ XX. ∀t ∈ X. ∀t' ∈ X. t ⋅ μ = t' ⋅ μ"
  using assms is_unifier_iff
  unfolding is_imgu_def is_unifier_set_def
  by blast

corollary is_imgu_unifies_pair: ✐‹contributor ‹Balazs Toth››
  assumes "is_imgu μ {{t, t'}}"
  shows "t ⋅ μ = t' ⋅ μ"
  using is_imgu_unifies[OF assms]
  by (metis insertCI)

lemmas subst_imgu_eq_subst_imgu = is_imgu_unifies_pair


subsection ‹Ground Substitutions›

lemma is_ground_subst_comp_left: "is_ground_subst σ ⟹ is_ground_subst (σ ⊙ τ)"
  by (simp add: is_ground_subst_def)

lemma is_ground_subst_comp_right: "is_ground_subst τ ⟹ is_ground_subst (σ ⊙ τ)"
  by (simp add: is_ground_subst_def)

lemma is_ground_subst_is_ground:
  assumes "is_ground_subst γ"
  shows "is_ground (t ⋅ γ)"
  using assms is_ground_subst_def by blast


subsection ‹IMGU is Idempotent and an MGU›

lemma is_imgu_iff_is_idem_and_is_mgu: "is_imgu μ XX ⟷ is_idem μ ∧ is_mgu μ XX"
  by (auto simp add: is_imgu_def is_idem_def is_mgu_def simp flip: assoc)


subsection ‹IMGU can be used before unification›

lemma subst_imgu_subst_unifier:
  assumes unif: "is_unifier υ X" and imgu: "is_imgu μ {X}" and "x ∈ X"
  shows "x ⋅ μ ⋅ υ = x ⋅ υ"
proof -
  have "x ⋅ μ ⋅ υ = x ⋅ (μ ⊙ υ)"
    by simp

  also have "… = x ⋅ υ"
    using imgu unif by (simp add: is_imgu_def is_unifier_set_def)

  finally show ?thesis .
qed


subsection ‹Groundings Idempotence›

lemma image_ground_instances_ground_instances:
  "ground_instances ` ground_instances x = (λx. {x}) ` ground_instances x"
proof (rule image_cong)
  show "⋀x𝒢. x𝒢 ∈ ground_instances x ⟹ ground_instances x𝒢 = {x𝒢}"
    using ground_instances_ident_if_ground ground_instances_def by auto
qed simp

lemma grounding_of_set_grounding_of_set_idem[simp]:
  "ground_instances_set (ground_instances_set X) = ground_instances_set X"
  unfolding ground_instances_set_eq_Union_ground_instances UN_UN_flatten
  unfolding image_ground_instances_ground_instances
  by simp


subsection ‹Instances of Substitution›

lemma instances_subst:
  "instances (x ⋅ σ) ⊆ instances x"
proof (rule subsetI)
  fix xσ assume "xσ ∈ instances (x ⋅ σ)"
  thus "xσ ∈ instances x"
    by (metis CollectD CollectI generalizes_def instances_def subst_comp_subst)
qed

lemma instances_set_subst_set:
  "instances_set (subst_set X σ) ⊆ instances_set X"
  unfolding instances_set_def subst_set_def
  using instances_subst by auto

lemma ground_instances_subst:
  "ground_instances (x ⋅ σ) ⊆ ground_instances x"
  unfolding ground_instances_def
  using instances_subst by auto

lemma ground_instances_set_subst_set:
  "ground_instances_set (subst_set X σ) ⊆ ground_instances_set X"
  unfolding ground_instances_set_def
  using instances_set_subst_set by auto


subsection ‹Instances of Renamed Expressions›

lemma instances_subst_ident_if_renaming[simp]:
  "is_renaming ρ ⟹ instances (x ⋅ ρ) = instances x"
  by (metis instances_subst is_renaming_def subset_antisym subst_comp_subst subst_id_subst)

lemma instances_set_subst_set_ident_if_renaming[simp]:
  "is_renaming ρ ⟹ instances_set (subst_set X ρ) = instances_set X"
  by (simp add: instances_set_def subst_set_def)

lemma ground_instances_subst_ident_if_renaming[simp]:
  "is_renaming ρ ⟹ ground_instances (x ⋅ ρ) = ground_instances x"
  by (simp add: ground_instances_def)

lemma ground_instances_set_subst_set_ident_if_renaming[simp]:
  "is_renaming ρ ⟹ ground_instances_set (subst_set X ρ) = ground_instances_set X"
  by (simp add: ground_instances_set_def)

end

end