Theory Abstract_Substitution.Substitution
theory Substitution
  imports Monoid_Action
begin
abbreviation set_prod where
  "set_prod ≡ λ(t, t'). {t, t'}"
section ‹Assumption-free Substitution›
locale 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 x⇩G :: 'x
  assumes "x⇩G ∈ ground_instances x"
  obtains γ :: 's where "x⇩G = 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 x⇩G :: 'x and X :: "'x set"
  assumes "x⇩G ∈ ground_instances_set X"
  obtains x :: 'x and γ :: 's where "x ∈ X" and "x⇩G = 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 ⟷ 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_if_finite:
  assumes "finite X"
  shows "is_unifier σ X ⟷ (∀x∈X. ∀y∈X. x ⋅ σ = y ⋅ σ)"
proof (rule iffI)
  show "is_unifier σ X ⟹ (∀x∈X. ∀y∈X. x ⋅ σ = y ⋅ σ)"
    using assms
    unfolding is_unifier_def
    by (metis One_nat_def card_le_Suc0_iff_eq finite_imageI image_eqI subst_set_def)
next
  show "(∀x∈X. ∀y∈X. x ⋅ σ = y ⋅ σ) ⟹ is_unifier σ X"
    unfolding is_unifier_def
    by (smt (verit, del_insts) One_nat_def substitution_ops.subst_set_def card_eq_0_iff
        card_le_Suc0_iff_eq dual_order.eq_iff imageE le_Suc_eq)
qed
lemma is_unifier_singleton[simp]: "is_unifier υ {x}"
  by (simp add: is_unifier_iff_if_finite)
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 (xs⇩1 @ xs⇩2) σ = subst_list xs⇩1 σ @ subst_list xs⇩2 σ"
  by (simp only: subst_list_def map_append)
lemma is_unifier_set_union:
  "is_unifier_set υ (XX⇩1 ∪ XX⇩2) ⟷ is_unifier_set υ XX⇩1 ∧ is_unifier_set υ XX⇩2"
  by (auto simp add: is_unifier_set_def)
lemma is_unifier_subset: "is_unifier υ A ⟹ finite A ⟹ B ⊆ A ⟹ is_unifier υ B"
  by (smt (verit, best) card_mono dual_order.trans finite_imageI image_mono is_unifier_def
      subst_set_def)
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 substitution_monoid = monoid comp_subst id_subst 
  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)
end
locale substitution =
  substitution_monoid comp_subst id_subst +
  comp_subst: right_monoid_action comp_subst id_subst subst +
  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
    
    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_unifier_id_subst_empty[simp]: "is_unifier id_subst {}"
  by (simp add: is_unifier_def)
lemma is_unifier_set_id_subst_empty[simp]: "is_unifier_set id_subst {}"
  by (simp add: is_unifier_set_def)
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 ⟷ card X ≤ 1"
  by (simp add: is_unifier_def)
lemma is_unifier_set_id_subst: "is_unifier_set id_subst XX ⟷ (∀X ∈ XX. 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. 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. 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 υ {t⇩1, t⇩2}" and "is_ground t⇩1" and "is_ground t⇩2"
  shows "t⇩1 = t⇩2"
  using assms by (simp add: card_Suc_eq is_unifier_def le_Suc_eq subst_set_def)
lemma ball_eq_constant_if_unifier:
  assumes "finite X" and "x ∈ X" and "is_unifier υ X" and "is_ground_set X"
  shows "∀y ∈ X. y = x"
  using assms
proof (induction X rule: finite_induct)
  case empty
  show ?case by simp
next
  case (insert z F)
  then show ?case
    by (metis is_ground_set_def finite.insertI is_unifier_iff_if_finite subst_ident_if_ground)
qed
lemma is_mgu_unifies: 
  assumes "is_mgu μ XX" "∀X ∈ XX. finite X"
  shows "∀X ∈ XX. ∀t ∈ X. ∀t' ∈ X. t ⋅ μ = t' ⋅ μ"
  using assms is_unifier_iff_if_finite
  unfolding is_mgu_def is_unifier_set_def
  by blast
corollary is_mgu_unifies_pair:  
  assumes "is_mgu μ {{t, t'}}"
  shows "t ⋅ μ = t' ⋅ μ"
  using is_mgu_unifies[OF assms]
  by (metis finite.emptyI finite.insertI insertCI singletonD)
lemmas subst_mgu_eq_subst_mgu = is_mgu_unifies_pair
lemma is_imgu_unifies: 
  assumes "is_imgu μ XX" "∀X ∈ XX. finite X"
  shows "∀X ∈ XX. ∀t ∈ X. ∀t' ∈ X. t ⋅ μ = t' ⋅ μ"
  using assms is_unifier_iff_if_finite
  unfolding is_imgu_def is_unifier_set_def
  by blast
corollary is_imgu_unifies_pair: 
  assumes "is_imgu μ {{t, t'}}"
  shows "t ⋅ μ = t' ⋅ μ"
  using is_imgu_unifies[OF assms]
  by (metis finite.emptyI finite.insertI insertCI singletonD)
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