Theory Unification_Theorem

section ‹The Unification Theorem›

theory Unification_Theorem imports
  First_Order_Terms.Unification Resolution
begin

definition set_to_list :: "'a set  'a list" where
  "set_to_list  inv set"

lemma set_set_to_list: "finite xs  set (set_to_list xs) = xs"
proof (induction rule: finite.induct)
  case (emptyI) 
  have "set [] = {}" by auto
  then show ?case unfolding set_to_list_def inv_into_def by auto
next
  case (insertI A a)
  then have "set (a#set_to_list A) = insert a A" by auto
  then show ?case unfolding set_to_list_def inv_into_def by (metis (mono_tags, lifting) UNIV_I someI) 
qed

fun iterm_to_fterm :: "(fun_sym, var_sym) term  fterm" where
  "iterm_to_fterm (Term.Var x) = Var x"
| "iterm_to_fterm (Term.Fun f ts) = Fun f (map iterm_to_fterm ts)"

fun fterm_to_iterm :: "fterm  (fun_sym, var_sym) term" where
  "fterm_to_iterm (Var x) = Term.Var x"
| "fterm_to_iterm (Fun f ts) = Term.Fun f (map fterm_to_iterm ts)"

lemma iterm_to_fterm_cancel[simp]: "iterm_to_fterm (fterm_to_iterm t) = t"
  by (induction t) (auto simp add: map_idI)

lemma fterm_to_iterm_cancel[simp]: "fterm_to_iterm (iterm_to_fterm t) = t"
  by (induction t) (auto simp add: map_idI)

abbreviation(input) fsub_to_isub :: "substitution  (fun_sym, var_sym) subst" where
  "fsub_to_isub σ  λx. fterm_to_iterm (σ x)"

abbreviation(input) isub_to_fsub :: "(fun_sym, var_sym) subst  substitution" where
  "isub_to_fsub σ  λx. iterm_to_fterm (σ x)"

lemma iterm_to_fterm_subt: "(iterm_to_fterm t1) t σ = iterm_to_fterm (t1  (λx. fterm_to_iterm (σ x)))"
  by (induction t1) auto

lemma unifiert_unifiers:
  assumes "unifierts σ ts"
  shows "fsub_to_isub σ  unifiers (fterm_to_iterm ` ts × fterm_to_iterm ` ts)"
proof -
  have "t1  fterm_to_iterm ` ts. t2  fterm_to_iterm ` ts. t1  (fsub_to_isub σ) = t2  (fsub_to_isub σ)"
    proof (rule ballI;rule ballI)
      fix t1 t2 
      assume t1_p: "t1  fterm_to_iterm ` ts" assume t2_p: "t2  fterm_to_iterm ` ts"
      from t1_p t2_p have "iterm_to_fterm t1  ts  iterm_to_fterm t2  ts" by auto 
      then have "(iterm_to_fterm t1) t σ = (iterm_to_fterm t2) t σ" using assms unfolding unifierts_def by auto
      then have "iterm_to_fterm (t1  fsub_to_isub σ) = iterm_to_fterm (t2  fsub_to_isub σ)" using iterm_to_fterm_subt by auto 
      then have "fterm_to_iterm (iterm_to_fterm (t1  fsub_to_isub σ)) = fterm_to_iterm (iterm_to_fterm (t2  fsub_to_isub σ))" by auto
      then show "t1  fsub_to_isub σ = t2  fsub_to_isub σ" using fterm_to_iterm_cancel by auto
    qed
  then have "pfterm_to_iterm ` ts × fterm_to_iterm ` ts. fst p  fsub_to_isub σ = snd p  fsub_to_isub σ" by (metis mem_Times_iff) 
  then show ?thesis unfolding unifiers_def by blast
qed

abbreviation(input) get_mgut :: "fterm list  substitution option" where
  "get_mgut ts  map_option (isub_to_fsub  subst_of) (unify (List.product (map fterm_to_iterm ts) (map fterm_to_iterm ts)) [])"

lemma unify_unification:
  assumes "σ  unifiers (set E)"
  shows "θ. is_imgu θ (set E)"
proof -
  from assms have "cs. unify E [] = Some cs" using unify_complete by auto
  then show ?thesis using unify_sound by auto
qed

lemma fterm_to_iterm_subst: "(fterm_to_iterm t1)  σ =fterm_to_iterm (t1 t isub_to_fsub σ)"
  by (induction t1) auto

lemma unifiers_unifiert:
  assumes "σ  unifiers (fterm_to_iterm ` ts × fterm_to_iterm ` ts)"
  shows "unifierts (isub_to_fsub σ) ts"
proof (cases "ts={}")
  assume "ts = {}"
  then show "unifierts (isub_to_fsub σ) ts" unfolding unifierts_def by auto
next
  assume "ts  {}"
  then obtain t' where t'_p: "t'  ts" by auto

  have "t1ts. t2ts. t1 t isub_to_fsub σ = t2 t isub_to_fsub σ"
    proof (rule ballI ; rule ballI)
      fix t1 t2 
      assume "t1  ts" "t2  ts" 
      then have "fterm_to_iterm t1  fterm_to_iterm ` ts" "fterm_to_iterm t2  fterm_to_iterm ` ts" by auto
      then have "(fterm_to_iterm t1, fterm_to_iterm t2)  (fterm_to_iterm ` ts × fterm_to_iterm ` ts)" by auto
      then have "(fterm_to_iterm t1)  σ = (fterm_to_iterm t2)  σ" using assms unfolding unifiers_def
         by (metis (no_types, lifting) assms fst_conv in_unifiersE snd_conv)
      then have "fterm_to_iterm (t1 t isub_to_fsub σ) = fterm_to_iterm (t2 t isub_to_fsub σ)" using fterm_to_iterm_subst by auto
      then have "iterm_to_fterm (fterm_to_iterm (t1 t (isub_to_fsub σ))) = iterm_to_fterm (fterm_to_iterm (t2 t isub_to_fsub σ))" by auto
      then show "t1 t isub_to_fsub σ = t2 t isub_to_fsub σ" by auto
    qed
  then have "t2ts. t' t isub_to_fsub σ = t2 t isub_to_fsub σ" using t'_p by blast            
  then show "unifierts (isub_to_fsub σ) ts" unfolding unifierts_def by metis
qed

lemma icomp_fcomp: "θ s i = fsub_to_isub (isub_to_fsub θ  isub_to_fsub i)"
  unfolding composition_def subst_compose_def
proof
  fix x
  show "θ x  i = fterm_to_iterm (iterm_to_fterm (θ x) t (λx. iterm_to_fterm (i x)))" using iterm_to_fterm_subt by auto
qed


lemma is_mgu_mguts: 
  assumes "finite ts"
  assumes "is_imgu θ (fterm_to_iterm ` ts × fterm_to_iterm ` ts)"
  shows "mguts (isub_to_fsub θ) ts"
proof -
  from assms have "unifierts (isub_to_fsub θ) ts" unfolding is_imgu_def using unifiers_unifiert by auto
  moreover have "u. unifierts u ts  (i. u = (isub_to_fsub θ)  i)"
    proof (rule allI; rule impI)
      fix u
      assume "unifierts u ts"
      then have "fsub_to_isub u  unifiers (fterm_to_iterm ` ts × fterm_to_iterm ` ts)" using unifiert_unifiers by auto
      then have "i. fsub_to_isub u = θ s i" using assms unfolding is_imgu_def by auto
      then obtain i where "fsub_to_isub u = θ s i" by auto 
      then have "fsub_to_isub u =  fsub_to_isub (isub_to_fsub θ  isub_to_fsub i)" using icomp_fcomp by auto
      then have "isub_to_fsub (fsub_to_isub u) = isub_to_fsub (fsub_to_isub (isub_to_fsub θ  isub_to_fsub i))" by metis
      then have "u = isub_to_fsub θ  isub_to_fsub i" by auto
      then show "i. u = isub_to_fsub θ  i" by metis
    qed
  ultimately show ?thesis unfolding mguts_def by auto
qed

lemma unification':
  assumes "finite ts"
  assumes  "unifierts σ ts"
  shows "θ. mguts θ ts"
proof -
  let ?E = "fterm_to_iterm ` ts × fterm_to_iterm ` ts"
  let ?lE = "set_to_list ?E"
  from assms have "fsub_to_isub σ  unifiers ?E" using unifiert_unifiers by auto
  then have "θ. is_imgu θ ?E"
    using unify_unification[of "fsub_to_isub σ" ?lE] assms by (simp add: set_set_to_list)
  then obtain θ where "is_imgu θ ?E" unfolding set_to_list_def by auto
  then have "mguts (isub_to_fsub θ) ts" using assms is_mgu_mguts by auto
  then show ?thesis by auto
qed

fun literal_to_term :: "fterm literal  fterm" where
  "literal_to_term (Pos p ts) = Fun ''Pos'' [Fun p ts]"
| "literal_to_term (Neg p ts) = Fun ''Neg'' [Fun p ts]"

fun term_to_literal :: "fterm  fterm literal" where
  "term_to_literal (Fun s [Fun p ts]) = (if s=''Pos'' then Pos else Neg) p ts"

lemma term_to_literal_cancel[simp]: "term_to_literal (literal_to_term l) = l"
  by (cases l) auto

lemma literal_to_term_sub: "literal_to_term (l l σ) = (literal_to_term l) t σ"
  by (induction l) auto


lemma unifierls_unifierts:
  assumes "unifierls σ L"
  shows "unifierts σ (literal_to_term `  L)"
proof -
  from assms obtain l' where "lL. l l σ = l'" unfolding unifierls_def by auto
  then have "lL. literal_to_term (l l σ) = literal_to_term l'" by auto
  then have "lL. (literal_to_term l) t σ = literal_to_term l'" using literal_to_term_sub by auto
  then have "tliteral_to_term ` L. t t σ = literal_to_term l'" by auto 
  then show ?thesis unfolding unifierts_def by auto
qed

lemma unifiert_unifierls:
  assumes "unifierts σ (literal_to_term `  L)"
  shows "unifierls σ L"
proof -
  from assms obtain t' where "tliteral_to_term ` L. t t σ = t'" unfolding unifierts_def by auto
  then have "tliteral_to_term ` L. term_to_literal (t t σ) = term_to_literal t'"  by auto
  then have "l L. term_to_literal ((literal_to_term l) t σ) = term_to_literal t'" by auto
  then have "l L. term_to_literal ((literal_to_term (l l σ))) = term_to_literal t'" using literal_to_term_sub by auto
  then have "l L. l l σ = term_to_literal t'" by auto 
  then show ?thesis unfolding unifierls_def by auto
qed

lemma mguts_mguls:
  assumes "mguts θ (literal_to_term `  L)"
  shows "mguls θ L"
proof -
  from assms have "unifierts θ (literal_to_term `  L)" unfolding mguts_def by auto
  then have "unifierls θ L" using unifiert_unifierls by auto
  moreover
  {
    fix u
    assume "unifierls u L"
    then have "unifierts u (literal_to_term `  L)" using unifierls_unifierts by auto
    then have "i. u = θ  i" using assms unfolding mguts_def by auto
  }
  ultimately show ?thesis unfolding mguls_def by auto
qed

theorem unification:
  assumes fin: "finite L"
  assumes uni: "unifierls σ L"
  shows "θ. mguls θ L"
proof -
  from uni have "unifierts σ (literal_to_term `  L)" using unifierls_unifierts by auto
  then obtain θ where "mguts θ (literal_to_term `  L)" using fin unification' by blast
  then have "mguls θ L" using mguts_mguls by auto
  then show ?thesis by auto
qed

end