diff --git a/thys/First_Order_Terms/Lists_are_Infinite.thy b/thys/First_Order_Terms/Lists_are_Infinite.thy new file mode 100644 --- /dev/null +++ b/thys/First_Order_Terms/Lists_are_Infinite.thy @@ -0,0 +1,15 @@ +(* +Author: Christian Sternagel +Author: René Thiemann +License: LGPL +*) +subsection \Make lists instances of the infinite-class.\ + +theory Lists_are_Infinite + imports Fresh_Identifiers.Fresh +begin + +instance list :: (type) infinite + by (intro_classes, rule infinite_UNIV_listI) + +end \ No newline at end of file diff --git a/thys/First_Order_Terms/ROOT b/thys/First_Order_Terms/ROOT --- a/thys/First_Order_Terms/ROOT +++ b/thys/First_Order_Terms/ROOT @@ -1,21 +1,24 @@ chapter AFP session First_Order_Terms = "Abstract-Rewriting" + description "First-Order Terms" options [timeout = 300] sessions "HOL-Library" + Fresh_Identifiers theories Transitive_Closure_More theories + Renaming2_String + theories Seq_More Fun_More Option_Monad theories Matching - Unification + Unification_String Subsumption Subterm_and_Context document_files "root.tex" "root.bib" diff --git a/thys/First_Order_Terms/Renaming2.thy b/thys/First_Order_Terms/Renaming2.thy new file mode 100644 --- /dev/null +++ b/thys/First_Order_Terms/Renaming2.thy @@ -0,0 +1,45 @@ +(* +Author: Christian Sternagel +Author: René Thiemann +License: LGPL +*) + +subsection \Rename names in two ways.\ + +theory Renaming2 + imports + Fresh_Identifiers.Fresh +begin + +typedef ('v :: infinite) renaming2 = "{ (v1 :: 'v \ 'v, v2 :: 'v \ 'v) | v1 v2. inj v1 \ inj v2 \ range v1 \ range v2 = {} }" +proof - + let ?U = "UNIV :: 'v set" + have inf: "infinite ?U" by (rule infinite_UNIV) + have "ordLeq3 (card_of ?U) (card_of ?U)" + using card_of_refl ordIso_iff_ordLeq by blast + from card_of_Plus_infinite1[OF inf this, folded card_of_ordIso] + obtain f where bij: "bij_betw f (?U <+> ?U) ?U" by auto + hence injf: "inj f" by (simp add: bij_is_inj) + define v1 where "v1 = f o Inl" + define v2 where "v2 = f o Inr" + have inj: "inj v1" "inj v2" unfolding v1_def v2_def by (intro inj_compose[OF injf], auto)+ + have "range v1 \ range v2 = {}" + proof (rule ccontr) + assume "\ ?thesis" + then obtain x where "v1 x = v2 x" + using injD injf v1_def v2_def by fastforce + hence "f (Inl x) = f (Inr x)" unfolding v1_def v2_def by auto + with injf show False unfolding inj_on_def by blast + qed + with inj show ?thesis by blast +qed + +setup_lifting type_definition_renaming2 + +lift_definition rename_1 :: "'v :: infinite renaming2 \ 'v \ 'v" is fst . +lift_definition rename_2 :: "'v :: infinite renaming2 \ 'v \ 'v" is snd . + +lemma rename_12: "inj (rename_1 r)" "inj (rename_2 r)" "range (rename_1 r) \ range (rename_2 r) = {}" + by (transfer, auto)+ + +end diff --git a/thys/First_Order_Terms/Renaming2_String.thy b/thys/First_Order_Terms/Renaming2_String.thy new file mode 100644 --- /dev/null +++ b/thys/First_Order_Terms/Renaming2_String.thy @@ -0,0 +1,14 @@ +subsection \Renaming strings apart\ + +theory Renaming2_String + imports + Renaming2 + Lists_are_Infinite +begin + +lift_definition string_rename :: "string renaming2" is "(Cons (CHR ''x''), Cons (CHR ''y''))" + by auto + +end + + diff --git a/thys/First_Order_Terms/Term.thy b/thys/First_Order_Terms/Term.thy --- a/thys/First_Order_Terms/Term.thy +++ b/thys/First_Order_Terms/Term.thy @@ -1,718 +1,749 @@ (* Author: Christian Sternagel Author: René Thiemann License: LGPL *) section \First-Order Terms\ theory Term imports Main "HOL-Library.Multiset" begin datatype (funs_term : 'f, vars_term : 'v) "term" = is_Var: Var (the_Var: 'v) | Fun 'f (args : "('f, 'v) term list") where "args (Var _) = []" abbreviation "is_Fun t \ \ is_Var t" lemma is_VarE [elim]: "is_Var t \ (\x. t = Var x \ P) \ P" by (cases t) auto lemma is_FunE [elim]: "is_Fun t \ (\f ts. t = Fun f ts \ P) \ P" by (cases t) auto lemma inj_on_Var[simp]: \<^marker>\contributor \Martin Desharnais\\ "inj_on Var A" by (rule inj_onI) simp lemma member_image_the_Var_image_subst: \<^marker>\contributor \Martin Desharnais\\ assumes is_var_\: "\x. is_Var (\ x)" shows "x \ the_Var ` \ ` V \ Var x \ \ ` V" using is_var_\ image_iff by (metis (no_types, opaque_lifting) term.collapse(1) term.sel(1)) lemma image_the_Var_image_subst_renaming_eq: \<^marker>\contributor \Martin Desharnais\\ assumes is_var_\: "\x. is_Var (\ x)" shows "the_Var ` \ ` V = (\x \ V. vars_term (\ x))" proof (rule Set.equalityI; rule Set.subsetI) from is_var_\ show "\x. x \ the_Var ` \ ` V \ x \ (\x\V. vars_term (\ x))" using term.set_sel(3) by force next from is_var_\ show "\x. x \ (\x\V. vars_term (\ x)) \ x \ the_Var ` \ ` V" by (smt (verit, best) Term.term.simps(17) UN_iff image_eqI singletonD term.collapse(1)) qed text \The variables of a term as multiset.\ fun vars_term_ms :: "('f, 'v) term \ 'v multiset" where "vars_term_ms (Var x) = {#x#}" | "vars_term_ms (Fun f ts) = \\<^sub># (mset (map vars_term_ms ts))" lemma set_mset_vars_term_ms [simp]: "set_mset (vars_term_ms t) = vars_term t" by (induct t) auto text \Reorient equations of the form @{term "Var x = t"} and @{term "Fun f ss = t"} to facilitate simplification.\ setup \ Reorient_Proc.add (fn Const (@{const_name Var}, _) $ _ => true | _ => false) #> Reorient_Proc.add (fn Const (@{const_name Fun}, _) $ _ $ _ => true | _ => false) \ simproc_setup reorient_Var ("Var x = t") = \K Reorient_Proc.proc\ simproc_setup reorient_Fun ("Fun f ss = t") = \K Reorient_Proc.proc\ text \The \emph{root symbol} of a term is defined by:\ fun root :: "('f, 'v) term \ ('f \ nat) option" where "root (Var x) = None" | "root (Fun f ts) = Some (f, length ts)" lemma finite_vars_term [simp]: "finite (vars_term t)" by (induct t) simp_all lemma finite_Union_vars_term: "finite (\t \ set ts. vars_term t)" by auto text \A substitution is a mapping \\\ from variables to terms. We call a substitution that alters the type of variables a generalized substitution, since it does not have all properties that are expected of (standard) substitutions (e.g., there is no empty substitution).\ type_synonym ('f, 'v, 'w) gsubst = "'v \ ('f, 'w) term" type_synonym ('f, 'v) subst = "('f, 'v, 'v) gsubst" fun subst_apply_term :: "('f, 'v) term \ ('f, 'v, 'w) gsubst \ ('f, 'w) term" (infixl "\" 67) where "Var x \ \ = \ x" | "Fun f ss \ \ = Fun f (map (\t. t \ \) ss)" definition subst_compose :: "('f, 'u, 'v) gsubst \ ('f, 'v, 'w) gsubst \ ('f, 'u, 'w) gsubst" (infixl "\\<^sub>s" 75) where "\ \\<^sub>s \ = (\x. (\ x) \ \)" lemma subst_subst_compose [simp]: "t \ (\ \\<^sub>s \) = t \ \ \ \" by (induct t \ rule: subst_apply_term.induct) (simp_all add: subst_compose_def) lemma subst_compose_assoc: "\ \\<^sub>s \ \\<^sub>s \ = \ \\<^sub>s (\ \\<^sub>s \)" proof (rule ext) fix x show "(\ \\<^sub>s \ \\<^sub>s \) x = (\ \\<^sub>s (\ \\<^sub>s \)) x" proof - have "(\ \\<^sub>s \ \\<^sub>s \) x = \(x) \ \ \ \" by (simp add: subst_compose_def) also have "\ = \(x) \ (\ \\<^sub>s \)" by simp finally show ?thesis by (simp add: subst_compose_def) qed qed lemma subst_apply_term_empty [simp]: "t \ Var = t" proof (induct t) case (Fun f ts) from map_ext [rule_format, of ts _ id, OF Fun] show ?case by simp qed simp interpretation subst_monoid_mult: monoid_mult "Var" "(\\<^sub>s)" by (unfold_locales) (simp add: subst_compose_assoc, simp_all add: subst_compose_def) lemma term_subst_eq: assumes "\x. x \ vars_term t \ \ x = \ x" shows "t \ \ = t \ \" using assms by (induct t) (auto) lemma term_subst_eq_rev: "t \ \ = t \ \ \ \x \ vars_term t. \ x = \ x" by (induct t) simp_all lemma term_subst_eq_conv: "t \ \ = t \ \ \ (\x \ vars_term t. \ x = \ x)" using term_subst_eq [of t \ \] and term_subst_eq_rev [of t \ \] by auto lemma subst_term_eqI: assumes "(\t. t \ \ = t \ \)" shows "\ = \" using assms [of "Var x" for x] by (intro ext) simp definition subst_domain :: "('f, 'v) subst \ 'v set" where "subst_domain \ = {x. \ x \ Var x}" fun subst_range :: "('f, 'v) subst \ ('f, 'v) term set" where "subst_range \ = \ ` subst_domain \" lemma vars_term_ms_subst [simp]: "vars_term_ms (t \ \) = (\x\#vars_term_ms t. vars_term_ms (\ x))" (is "_ = ?V t") proof (induct t) case (Fun f ts) have IH: "map (\ t. vars_term_ms (t \ \)) ts = map (\ t. ?V t) ts" by (rule map_cong[OF refl Fun]) show ?case by (simp add: o_def IH, induct ts, auto) qed simp lemma vars_term_ms_subst_mono: assumes "vars_term_ms s \# vars_term_ms t" shows "vars_term_ms (s \ \) \# vars_term_ms (t \ \)" proof - from assms[unfolded mset_subset_eq_exists_conv] obtain u where t: "vars_term_ms t = vars_term_ms s + u" by auto show ?thesis unfolding vars_term_ms_subst unfolding t by auto qed text \The variables introduced by a substitution.\ definition range_vars :: "('f, 'v) subst \ 'v set" where "range_vars \ = \(vars_term ` subst_range \)" lemma mem_range_varsI: \<^marker>\contributor \Martin Desharnais\\ assumes "\ x = Var y" and "x \ y" shows "y \ range_vars \" unfolding range_vars_def UN_iff proof (rule bexI[of _ "Var y"]) show "y \ vars_term (Var y)" by simp next from assms show "Var y \ subst_range \" by (simp_all add: subst_domain_def) qed lemma subst_domain_Var [simp]: "subst_domain Var = {}" by (simp add: subst_domain_def) lemma subst_range_Var[simp]: \<^marker>\contributor \Martin Desharnais\\ "subst_range Var = {}" by simp lemma range_vars_Var[simp]: \<^marker>\contributor \Martin Desharnais\\ "range_vars Var = {}" by (simp add: range_vars_def) lemma subst_apply_term_ident: \<^marker>\contributor \Martin Desharnais\\ "vars_term t \ subst_domain \ = {} \ t \ \ = t" proof (induction t) case (Var x) thus ?case by (simp add: subst_domain_def) next case (Fun f ts) thus ?case by (auto intro: list.map_ident_strong) qed lemma vars_term_subst_apply_term: \<^marker>\contributor \Martin Desharnais\\ "vars_term (t \ \) = (\x \ vars_term t. vars_term (\ x))" by (induction t) (auto simp add: insert_Diff_if subst_domain_def) corollary vars_term_subst_apply_term_subset: \<^marker>\contributor \Martin Desharnais\\ "vars_term (t \ \) \ vars_term t - subst_domain \ \ range_vars \" unfolding vars_term_subst_apply_term proof (induction t) case (Var x) show ?case by (cases "\ x = Var x") (auto simp add: range_vars_def subst_domain_def) next case (Fun f xs) thus ?case by auto qed definition is_renaming :: "('f, 'v) subst \ bool" where "is_renaming \ \ (\x. is_Var (\ x)) \ inj_on \ (subst_domain \)" lemma inv_renaming_sound: \<^marker>\contributor \Martin Desharnais\\ assumes is_var_\: "\x. is_Var (\ x)" and "inj \" shows "\ \\<^sub>s (Var \ (inv (the_Var \ \))) = Var" proof - define \' where "\' = the_Var \ \" have \_def: "\ = Var \ \'" unfolding \'_def using is_var_\ by auto from is_var_\ \inj \\ have "inj \'" unfolding inj_def \_def comp_def by fast hence "inv \' \ \' = id" using inv_o_cancel[of \'] by simp hence "Var \ (inv \' \ \') = Var" by simp hence "\x. (Var \ (inv \' \ \')) x = Var x" by metis hence "\x. ((Var \ \') \\<^sub>s (Var \ (inv \'))) x = Var x" unfolding subst_compose_def by auto thus "\ \\<^sub>s (Var \ (inv \')) = Var" using \_def by auto qed lemma ex_inverse_of_renaming: \<^marker>\contributor \Martin Desharnais\\ assumes "\x. is_Var (\ x)" and "inj \" shows "\\. \ \\<^sub>s \ = Var" using inv_renaming_sound[OF assms] by blast lemma vars_term_subst: "vars_term (t \ \) = \(vars_term ` \ ` vars_term t)" by (induct t) simp_all lemma range_varsE [elim]: assumes "x \ range_vars \" and "\t. x \ vars_term t \ t \ subst_range \ \ P" shows "P" using assms by (auto simp: range_vars_def) lemma range_vars_subst_compose_subset: "range_vars (\ \\<^sub>s \) \ (range_vars \ - subst_domain \) \ range_vars \" (is "?L \ ?R") proof fix x assume "x \ ?L" then obtain y where "y \ subst_domain (\ \\<^sub>s \)" and "x \ vars_term ((\ \\<^sub>s \) y)" by (auto simp: range_vars_def) then show "x \ ?R" proof (cases) assume "y \ subst_domain \" and "x \ vars_term ((\ \\<^sub>s \) y)" moreover then obtain v where "v \ vars_term (\ y)" and "x \ vars_term (\ v)" by (auto simp: subst_compose_def vars_term_subst) ultimately show ?thesis by (cases "v \ subst_domain \") (auto simp: range_vars_def subst_domain_def) qed (auto simp: range_vars_def subst_compose_def subst_domain_def) qed definition "subst x t = Var (x := t)" lemma subst_simps [simp]: "subst x t x = t" "subst x (Var x) = Var" by (auto simp: subst_def) lemma subst_subst_domain [simp]: "subst_domain (subst x t) = (if t = Var x then {} else {x})" proof - { fix y have "y \ {y. subst x t y \ Var y} \ y \ (if t = Var x then {} else {x})" by (cases "x = y", auto simp: subst_def) } then show ?thesis by (simp add: subst_domain_def) qed lemma subst_subst_range [simp]: "subst_range (subst x t) = (if t = Var x then {} else {t})" by (cases "t = Var x") (auto simp: subst_domain_def subst_def) lemma subst_apply_left_idemp [simp]: assumes "\ x = t \ \" shows "s \ subst x t \ \ = s \ \" using assms by (induct s) (auto simp: subst_def) lemma subst_compose_left_idemp [simp]: assumes "\ x = t \ \" shows "subst x t \\<^sub>s \ = \" by (rule subst_term_eqI) (simp add: assms) lemma subst_ident [simp]: assumes "x \ vars_term t" shows "t \ subst x u = t" proof - have "t \ subst x u = t \ Var" by (rule term_subst_eq) (auto simp: assms subst_def) then show ?thesis by simp qed lemma subst_self_idemp [simp]: "x \ vars_term t \ subst x t \\<^sub>s subst x t = subst x t" by (metis subst_simps(1) subst_compose_left_idemp subst_ident) type_synonym ('f, 'v) terms = "('f, 'v) term set" text \Applying a substitution to every term of a given set.\ abbreviation subst_apply_set :: "('f, 'v) terms \ ('f, 'v, 'w) gsubst \ ('f, 'w) terms" (infixl "\\<^sub>s\<^sub>e\<^sub>t" 60) where "T \\<^sub>s\<^sub>e\<^sub>t \ \ (\t. t \ \) ` T" text \Composition of substitutions\ lemma subst_compose: "(\ \\<^sub>s \) x = \ x \ \" by (auto simp: subst_compose_def) lemmas subst_subst = subst_subst_compose [symmetric] lemma subst_apply_eq_Var: assumes "s \ \ = Var x" obtains y where "s = Var y" and "\ y = Var x" using assms by (induct s) auto lemma subst_domain_subst_compose: "subst_domain (\ \\<^sub>s \) = (subst_domain \ - {x. \y. \ x = Var y \ \ y = Var x}) \ (subst_domain \ - subst_domain \)" by (auto simp: subst_domain_def subst_compose_def elim: subst_apply_eq_Var) text \A substitution is idempotent iff the variables in its range are disjoint from its domain. (See also "Term Rewriting and All That" \<^cite>\\Lemma 4.5.7\ in "AllThat"\.)\ lemma subst_idemp_iff: "\ \\<^sub>s \ = \ \ subst_domain \ \ range_vars \ = {}" proof assume "\ \\<^sub>s \ = \" then have "\x. \ x \ \ = \ x \ Var" by simp (metis subst_compose_def) then have *: "\x. \y\vars_term (\ x). \ y = Var y" unfolding term_subst_eq_conv by simp { fix x y assume "\ x \ Var x" and "x \ vars_term (\ y)" with * [of y] have False by simp } then show "subst_domain \ \ range_vars \ = {}" by (auto simp: subst_domain_def range_vars_def) next assume "subst_domain \ \ range_vars \ = {}" then have *: "\x y. \ x = Var x \ \ y = Var y \ x \ vars_term (\ y)" by (auto simp: subst_domain_def range_vars_def) have "\x. \y\vars_term (\ x). \ y = Var y" proof fix x y assume "y \ vars_term (\ x)" with * [of y x] show "\ y = Var y" by auto qed then show "\ \\<^sub>s \ = \" by (simp add: subst_compose_def term_subst_eq_conv [symmetric]) qed lemma subst_compose_apply_eq_apply_lhs: \<^marker>\contributor \Martin Desharnais\\ assumes "range_vars \ \ subst_domain \ = {}" "x \ subst_domain \" shows "(\ \\<^sub>s \) x = \ x" proof (cases "\ x") case (Var y) show ?thesis proof (cases "x = y") case True with Var have \\ x = Var x\ by simp moreover from \x \ subst_domain \\ have "\ x = Var x" by (simp add: disjoint_iff subst_domain_def) ultimately show ?thesis by (simp add: subst_compose_def) next case False have "y \ range_vars \" unfolding range_vars_def UN_iff proof (rule bexI) show "y \ vars_term (Var y)" by simp next from Var False show "Var y \ subst_range \" by (simp_all add: subst_domain_def) qed hence "y \ subst_domain \" using \range_vars \ \ subst_domain \ = {}\ by (simp add: disjoint_iff) with Var show ?thesis unfolding subst_compose_def by (simp add: subst_domain_def) qed next case (Fun f ys) hence "Fun f ys \ subst_range \ \ (\y\set ys. y \ subst_range \)" using subst_domain_def by fastforce hence "\x \ vars_term (Fun f ys). x \ range_vars \" by (metis UN_I range_vars_def term.distinct(1) term.sel(4) term.set_cases(2)) hence "Fun f ys \ \ = Fun f ys \ Var" unfolding term_subst_eq_conv using \range_vars \ \ subst_domain \ = {}\ by (simp add: disjoint_iff subst_domain_def) hence "Fun f ys \ \ = Fun f ys" by simp with Fun show ?thesis by (simp add: subst_compose_def) qed lemma subst_apply_term_subst_apply_term_eq_subst_apply_term_lhs: \<^marker>\contributor \Martin Desharnais\\ assumes "range_vars \ \ subst_domain \ = {}" and "vars_term t \ subst_domain \ = {}" shows "t \ \ \ \ = t \ \" proof - from assms have "\x. x \ vars_term t \ (\ \\<^sub>s \) x = \ x" using subst_compose_apply_eq_apply_lhs by fastforce hence "t \ \ \\<^sub>s \ = t \ \" using term_subst_eq_conv[of t "\ \\<^sub>s \" \] by metis thus ?thesis by simp qed fun num_funs :: "('f, 'v) term \ nat" where "num_funs (Var x) = 0" | "num_funs (Fun f ts) = Suc (sum_list (map num_funs ts))" lemma num_funs_0: assumes "num_funs t = 0" obtains x where "t = Var x" using assms by (induct t) auto lemma num_funs_subst: "num_funs (t \ \) \ num_funs t" by (induct t) (simp_all, metis comp_apply sum_list_mono) lemma sum_list_map_num_funs_subst: assumes "sum_list (map (num_funs \ (\t. t \ \)) ts) = sum_list (map num_funs ts)" shows "\i < length ts. num_funs (ts ! i \ \) = num_funs (ts ! i)" using assms proof (induct ts) case (Cons t ts) then have "num_funs (t \ \) + sum_list (map (num_funs \ (\t. t \ \)) ts) = num_funs t + sum_list (map num_funs ts)" by (simp add: o_def) moreover have "num_funs (t \ \) \ num_funs t" by (metis num_funs_subst) moreover have "sum_list (map (num_funs \ (\t. t \ \)) ts) \ sum_list (map num_funs ts)" using num_funs_subst [of _ \] by (induct ts) (auto intro: add_mono) ultimately show ?case using Cons by (auto) (case_tac i, auto) qed simp lemma is_Fun_num_funs_less: assumes "x \ vars_term t" and "is_Fun t" shows "num_funs (\ x) < num_funs (t \ \)" using assms proof (induct t) case (Fun f ts) then obtain u where u: "u \ set ts" "x \ vars_term u" by auto then have "num_funs (u \ \) \ sum_list (map (num_funs \ (\t. t \ \)) ts)" by (intro member_le_sum_list) simp moreover have "num_funs (\ x) \ num_funs (u \ \)" using Fun.hyps [OF u] and u by (cases u; simp) ultimately show ?case by simp qed simp lemma finite_subst_domain_subst: "finite (subst_domain (subst x y))" by simp lemma subst_domain_compose: "subst_domain (\ \\<^sub>s \) \ subst_domain \ \ subst_domain \" by (auto simp: subst_domain_def subst_compose_def) lemma vars_term_disjoint_imp_unifier: fixes \ :: "('f, 'v, 'w) gsubst" assumes "vars_term s \ vars_term t = {}" and "s \ \ = t \ \" shows "\\ :: ('f, 'v, 'w) gsubst. s \ \ = t \ \" proof - let ?\ = "\x. if x \ vars_term s then \ x else \ x" have "s \ \ = s \ ?\" unfolding term_subst_eq_conv by (induct s) (simp_all) moreover have "t \ \ = t \ ?\" using assms(1) unfolding term_subst_eq_conv by (induct s arbitrary: t) (auto) ultimately have "s \ ?\ = t \ ?\" using assms(2) by simp then show ?thesis by blast qed lemma vars_term_subset_subst_eq: assumes "vars_term t \ vars_term s" and "s \ \ = s \ \" shows "t \ \ = t \ \" using assms by (induct t) (induct s, auto) subsection \Restrict the Domain of a Substitution\ definition restrict_subst_domain where \<^marker>\contributor \Martin Desharnais\\ "restrict_subst_domain V \ x \ (if x \ V then \ x else Var x)" lemma restrict_subst_domain_empty[simp]: \<^marker>\contributor \Martin Desharnais\\ "restrict_subst_domain {} \ = Var" unfolding restrict_subst_domain_def by auto lemma restrict_subst_domain_Var[simp]: \<^marker>\contributor \Martin Desharnais\\ "restrict_subst_domain V Var = Var" unfolding restrict_subst_domain_def by auto lemma subst_domain_restrict_subst_domain[simp]: \<^marker>\contributor \Martin Desharnais\\ "subst_domain (restrict_subst_domain V \) = V \ subst_domain \" unfolding restrict_subst_domain_def subst_domain_def by auto lemma subst_apply_term_restrict_subst_domain: \<^marker>\contributor \Martin Desharnais\\ "vars_term t \ V \ t \ restrict_subst_domain V \ = t \ \" by (rule term_subst_eq) (simp add: restrict_subst_domain_def subsetD) subsection \Rename the Domain of a Substitution\ definition rename_subst_domain where \<^marker>\contributor \Martin Desharnais\\ "rename_subst_domain \ \ x = (if Var x \ \ ` subst_domain \ then \ (the_inv \ (Var x)) else Var x)" lemma rename_subst_domain_Var_lhs[simp]: \<^marker>\contributor \Martin Desharnais\\ "rename_subst_domain Var \ = \" by (rule ext) (simp add: rename_subst_domain_def inj_image_mem_iff the_inv_f_f subst_domain_def) lemma rename_subst_domain_Var_rhs[simp]: \<^marker>\contributor \Martin Desharnais\\ "rename_subst_domain \ Var = Var" by (rule ext) (simp add: rename_subst_domain_def) lemma subst_domain_rename_subst_domain_subset: \<^marker>\contributor \Martin Desharnais\\ assumes is_var_\: "\x. is_Var (\ x)" shows "subst_domain (rename_subst_domain \ \) \ the_Var ` \ ` subst_domain \" by (auto simp add: subst_domain_def rename_subst_domain_def member_image_the_Var_image_subst[OF is_var_\]) lemma subst_range_rename_subst_domain_subset: \<^marker>\contributor \Martin Desharnais\\ assumes "inj \" shows "subst_range (rename_subst_domain \ \) \ subst_range \" proof (intro Set.equalityI Set.subsetI) fix t assume "t \ subst_range (rename_subst_domain \ \)" then obtain x where t_def: "t = rename_subst_domain \ \ x" and "rename_subst_domain \ \ x \ Var x" by (auto simp: image_iff subst_domain_def) show "t \ subst_range \" proof (cases \Var x \ \ ` subst_domain \\) case True then obtain x' where "\ x' = Var x" and "x' \ subst_domain \" by auto then show ?thesis using the_inv_f_f[OF \inj \\, of x'] by (simp add: t_def rename_subst_domain_def) next case False hence False using \rename_subst_domain \ \ x \ Var x\ by (simp add: t_def rename_subst_domain_def) thus ?thesis .. qed qed lemma range_vars_rename_subst_domain_subset: \<^marker>\contributor \Martin Desharnais\\ assumes "inj \" shows "range_vars (rename_subst_domain \ \) \ range_vars \" unfolding range_vars_def using subst_range_rename_subst_domain_subset[OF \inj \\] by (metis Union_mono image_mono) lemma renaming_cancels_rename_subst_domain: \<^marker>\contributor \Martin Desharnais\\ assumes is_var_\: "\x. is_Var (\ x)" and "inj \" and vars_t: "vars_term t \ subst_domain \" shows "t \ \ \ rename_subst_domain \ \ = t \ \" unfolding subst_subst proof (intro term_subst_eq ballI) fix x assume "x \ vars_term t" with vars_t have x_in: "x \ subst_domain \" by blast obtain x' where \_x: "\ x = Var x'" using is_var_\ by (meson is_Var_def) with x_in have x'_in: "Var x' \ \ ` subst_domain \" by (metis image_eqI) have "(\ \\<^sub>s rename_subst_domain \ \) x = \ x \ rename_subst_domain \ \" by (simp add: subst_compose_def) also have "\ = rename_subst_domain \ \ x'" using \_x by simp also have "\ = \ (the_inv \ (Var x'))" by (simp add: rename_subst_domain_def if_P[OF x'_in]) also have "\ = \ (the_inv \ (\ x))" by (simp add: \_x) also have "\ = \ x" using \inj \\ by (simp add: the_inv_f_f) finally show "(\ \\<^sub>s rename_subst_domain \ \) x = \ x" by simp qed subsection \Rename the Domain and Range of a Substitution\ definition rename_subst_domain_range where \<^marker>\contributor \Martin Desharnais\\ "rename_subst_domain_range \ \ x = (if Var x \ \ ` subst_domain \ then ((Var o the_inv \) \\<^sub>s \ \\<^sub>s \) (Var x) else Var x)" lemma rename_subst_domain_range_Var_lhs[simp]: \<^marker>\contributor \Martin Desharnais\\ "rename_subst_domain_range Var \ = \" by (rule ext) (simp add: rename_subst_domain_range_def inj_image_mem_iff the_inv_f_f subst_domain_def subst_compose_def) lemma rename_subst_domain_range_Var_rhs[simp]: \<^marker>\contributor \Martin Desharnais\\ "rename_subst_domain_range \ Var = Var" by (rule ext) (simp add: rename_subst_domain_range_def) lemma subst_compose_renaming_rename_subst_domain_range: \<^marker>\contributor \Martin Desharnais\\ fixes \ \ :: "('f, 'v) subst" assumes is_var_\: "\x. is_Var (\ x)" and "inj \" shows "\ \\<^sub>s rename_subst_domain_range \ \ = \ \\<^sub>s \" proof (rule ext) fix x from is_var_\ obtain x' where "\ x = Var x'" by (meson is_Var_def is_renaming_def) with \inj \\ have inv_\_x': "the_inv \ (Var x') = x" by (metis the_inv_f_f) show "(\ \\<^sub>s rename_subst_domain_range \ \) x = (\ \\<^sub>s \) x" proof (cases "x \ subst_domain \") case True hence "Var x' \ \ ` subst_domain \" using \\ x = Var x'\ by (metis imageI) thus ?thesis by (simp add: \\ x = Var x'\ rename_subst_domain_range_def subst_compose_def inv_\_x') next case False hence "Var x' \ \ ` subst_domain \" proof (rule contrapos_nn) assume "Var x' \ \ ` subst_domain \" hence "\ x \ \ ` subst_domain \" unfolding \\ x = Var x'\ . thus "x \ subst_domain \" unfolding inj_image_mem_iff[OF \inj \\] . qed with False \\ x = Var x'\ show ?thesis by (simp add: subst_compose_def subst_domain_def rename_subst_domain_range_def) qed qed corollary subst_apply_term_renaming_rename_subst_domain_range: \<^marker>\contributor \Martin Desharnais\\ \ \This might be easier to find with @{command find_theorems}.\ fixes t :: "('f, 'v) term" and \ \ :: "('f, 'v) subst" assumes is_var_\: "\x. is_Var (\ x)" and "inj \" shows "t \ \ \ rename_subst_domain_range \ \ = t \ \ \ \" unfolding subst_subst unfolding subst_compose_renaming_rename_subst_domain_range[OF assms] by (rule refl) text \A term is called \<^emph>\ground\ if it does not contain any variables.\ fun ground :: "('f, 'v) term \ bool" where "ground (Var x) \ False" | "ground (Fun f ts) \ (\t \ set ts. ground t)" lemma ground_vars_term_empty: "ground t \ vars_term t = {}" by (induct t) simp_all lemma ground_subst [simp]: "ground (t \ \) \ (\x \ vars_term t. ground (\ x))" by (induct t) simp_all lemma ground_subst_apply: assumes "ground t" shows "t \ \ = t" proof - have "t = t \ Var" by simp also have "\ = t \ \" by (rule term_subst_eq, insert assms[unfolded ground_vars_term_empty], auto) finally show ?thesis by simp qed +text \Just changing the variables in a term\ + +abbreviation "map_vars_term f \ term.map_term (\x. x) f" + +lemma map_vars_term_as_subst: + "map_vars_term f t = t \ (\ x. Var (f x))" + by (induct t) simp_all + +lemma map_vars_term_eq: + "map_vars_term f s = s \ (Var \ f)" +by (induct s) auto + +lemma ground_map_vars_term [simp]: + "ground (map_vars_term f t) = ground t" + by (induct t) simp_all + +lemma map_vars_term_subst [simp]: + "map_vars_term f (t \ \) = t \ (\ x. map_vars_term f (\ x))" + by (induct t) simp_all + +lemma map_vars_term_compose: + "map_vars_term m1 (map_vars_term m2 t) = map_vars_term (m1 o m2) t" + by (induct t) simp_all + +lemma map_vars_term_id [simp]: + "map_vars_term id t = t" + by (induct t) (auto intro: map_idI) + +lemma apply_subst_map_vars_term: + "map_vars_term m t \ \ = t \ (\ \ m)" + by (induct t) (auto) end diff --git a/thys/First_Order_Terms/Unification.thy b/thys/First_Order_Terms/Unification.thy --- a/thys/First_Order_Terms/Unification.thy +++ b/thys/First_Order_Terms/Unification.thy @@ -1,704 +1,894 @@ (* Author: Christian Sternagel Author: René Thiemann License: LGPL *) subsection \A Concrete Unification Algorithm\ theory Unification imports Abstract_Unification Option_Monad + Renaming2 begin definition "decompose s t = (case (s, t) of (Fun f ss, Fun g ts) \ if f = g then zip_option ss ts else None | _ \ None)" lemma decompose_same_Fun[simp]: \<^marker>\contributor \Martin Desharnais\\ "decompose (Fun f ss) (Fun f ss) = Some (zip ss ss)" by (simp add: decompose_def) lemma decompose_Some [dest]: "decompose (Fun f ss) (Fun g ts) = Some E \ f = g \ length ss = length ts \ E = zip ss ts" by (cases "f = g") (auto simp: decompose_def) lemma decompose_None [dest]: "decompose (Fun f ss) (Fun g ts) = None \ f \ g \ length ss \ length ts" by (cases "f = g") (auto simp: decompose_def) text \Applying a substitution to a list of equations.\ definition subst_list :: "('f, 'v) subst \ ('f, 'v) equation list \ ('f, 'v) equation list" where "subst_list \ ys = map (\p. (fst p \ \, snd p \ \)) ys" lemma mset_subst_list [simp]: "mset (subst_list (subst x t) ys) = subst_mset (subst x t) (mset ys)" by (auto simp: subst_mset_def subst_list_def) lemma subst_list_append: "subst_list \ (xs @ ys) = subst_list \ xs @ subst_list \ ys" by (auto simp: subst_list_def) function (sequential) unify :: "('f, 'v) equation list \ ('v \ ('f, 'v) term) list \ ('v \ ('f, 'v) term) list option" where "unify [] bs = Some bs" | "unify ((Fun f ss, Fun g ts) # E) bs = (case decompose (Fun f ss) (Fun g ts) of None \ None | Some us \ unify (us @ E) bs)" | "unify ((Var x, t) # E) bs = (if t = Var x then unify E bs else if x \ vars_term t then None else unify (subst_list (subst x t) E) ((x, t) # bs))" | "unify ((t, Var x) # E) bs = (if x \ vars_term t then None else unify (subst_list (subst x t) E) ((x, t) # bs))" by pat_completeness auto termination by (standard, rule wf_inv_image [of "unif\" "mset \ fst", OF wf_converse_unif]) (force intro: UNIF1.intros simp: unif_def union_commute)+ lemma unify_append_prefix_same: \<^marker>\contributor \Martin Desharnais\\ "(\e \ set es1. fst e = snd e) \ unify (es1 @ es2) bs = unify es2 bs" proof (induction "es1 @ es2" bs arbitrary: es1 es2 bs rule: unify.induct) case (1 bs) thus ?case by simp next case (2 f ss g ts E bs) show ?case proof (cases es1) case Nil thus ?thesis by simp next case (Cons e es1') hence e_def: "e = (Fun f ss, Fun g ts)" and E_def: "E = es1' @ es2" using "2" by simp_all hence "f = g" and "ss = ts" using "2.prems" local.Cons by auto hence "unify (es1 @ es2) bs = unify ((zip ts ts @ es1') @ es2) bs" by (simp add: Cons e_def) also have "\ = unify es2 bs" proof (rule "2.hyps"(1)) show "decompose (Fun f ss) (Fun g ts) = Some (zip ts ts)" by (simp add: \f = g\ \ss = ts\) next show "zip ts ts @ E = (zip ts ts @ es1') @ es2" by (simp add: E_def) next show "\e\set (zip ts ts @ es1'). fst e = snd e" using "2.prems" by (auto simp: Cons zip_same) qed finally show ?thesis . qed next case (3 x t E bs) show ?case proof (cases es1) case Nil thus ?thesis by simp next case (Cons e es1') hence e_def: "e = (Var x, t)" and E_def: "E = es1' @ es2" using 3 by simp_all show ?thesis proof (cases "t = Var x") case True show ?thesis using 3(1)[OF True E_def] using "3.hyps"(3) "3.prems" local.Cons by fastforce next case False thus ?thesis using "3.prems" e_def local.Cons by force qed qed next case (4 v va x E bs) then show ?case proof (cases es1) case Nil thus ?thesis by simp next case (Cons e es1') hence e_def: "e = (Fun v va, Var x)" and E_def: "E = es1' @ es2" using 4 by simp_all thus ?thesis using "4.prems" local.Cons by fastforce qed qed corollary unify_Cons_same: \<^marker>\contributor \Martin Desharnais\\ "fst e = snd e \ unify (e # es) bs = unify es bs" by (rule unify_append_prefix_same[of "[_]", simplified]) corollary unify_same: \<^marker>\contributor \Martin Desharnais\\ "(\e \ set es. fst e = snd e) \ unify es bs = Some bs" by (rule unify_append_prefix_same[of _ "[]", simplified]) definition subst_of :: "('v \ ('f, 'v) term) list \ ('f, 'v) subst" where "subst_of ss = List.foldr (\(x, t) \. \ \\<^sub>s subst x t) ss Var" text \Computing the mgu of two terms.\ definition mgu :: "('f, 'v) term \ ('f, 'v) term \ ('f, 'v) subst option" where "mgu s t = (case unify [(s, t)] [] of None \ None | Some res \ Some (subst_of res))" lemma subst_of_simps [simp]: "subst_of [] = Var" "subst_of ((x, Var x) # ss) = subst_of ss" "subst_of (b # ss) = subst_of ss \\<^sub>s subst (fst b) (snd b)" by (simp_all add: subst_of_def split: prod.splits) lemma subst_of_append [simp]: "subst_of (ss @ ts) = subst_of ts \\<^sub>s subst_of ss" by (induct ss) (auto simp: ac_simps) text \The concrete algorithm \unify\ can be simulated by the inference rules of \UNIF\.\ lemma unify_Some_UNIF: assumes "unify E bs = Some cs" shows "\ds ss. cs = ds @ bs \ subst_of ds = compose ss \ UNIF ss (mset E) {#}" using assms proof (induction E bs arbitrary: cs rule: unify.induct) case (2 f ss g ts E bs) then obtain us where "decompose (Fun f ss) (Fun g ts) = Some us" and [simp]: "f = g" "length ss = length ts" "us = zip ss ts" and "unify (us @ E) bs = Some cs" by (auto split: option.splits) from "2.IH" [OF this(1, 5)] obtain xs ys where "cs = xs @ bs" and [simp]: "subst_of xs = compose ys" and *: "UNIF ys (mset (us @ E)) {#}" by auto then have "UNIF (Var # ys) (mset ((Fun f ss, Fun g ts) # E)) {#}" by (force intro: UNIF1.decomp simp: ac_simps) moreover have "cs = xs @ bs" by fact moreover have "subst_of xs = compose (Var # ys)" by simp ultimately show ?case by blast next case (3 x t E bs) show ?case proof (cases "t = Var x") assume "t = Var x" then show ?case using 3 by auto (metis UNIF.step compose_simps(2) UNIF1.trivial) next assume "t \ Var x" with 3 obtain xs ys where [simp]: "cs = (ys @ [(x, t)]) @ bs" and [simp]: "subst_of ys = compose xs" and "x \ vars_term t" and "UNIF xs (mset (subst_list (subst x t) E)) {#}" by (cases "x \ vars_term t") force+ then have "UNIF (subst x t # xs) (mset ((Var x, t) # E)) {#}" by (force intro: UNIF1.Var_left simp: ac_simps) moreover have "cs = (ys @ [(x, t)]) @ bs" by simp moreover have "subst_of (ys @ [(x, t)]) = compose (subst x t # xs)" by simp ultimately show ?case by blast qed next case (4 f ss x E bs) with 4 obtain xs ys where [simp]: "cs = (ys @ [(x, Fun f ss)]) @ bs" and [simp]: "subst_of ys = compose xs" and "x \ vars_term (Fun f ss)" and "UNIF xs (mset (subst_list (subst x (Fun f ss)) E)) {#}" by (cases "x \ vars_term (Fun f ss)") force+ then have "UNIF (subst x (Fun f ss) # xs) (mset ((Fun f ss, Var x) # E)) {#}" by (force intro: UNIF1.Var_right simp: ac_simps) moreover have "cs = (ys @ [(x, Fun f ss)]) @ bs" by simp moreover have "subst_of (ys @ [(x, Fun f ss)]) = compose (subst x (Fun f ss) # xs)" by simp ultimately show ?case by blast qed force lemma unify_sound: assumes "unify E [] = Some cs" shows "is_imgu (subst_of cs) (set E)" proof - from unify_Some_UNIF [OF assms] obtain ss where "subst_of cs = compose ss" and "UNIF ss (mset E) {#}" by auto with UNIF_empty_imp_is_mgu_compose [OF this(2)] and UNIF_idemp [OF this(2)] show ?thesis by (auto simp add: is_imgu_def is_mgu_def) (metis subst_compose_assoc) qed lemma mgu_sound: assumes "mgu s t = Some \" shows "is_imgu \ {(s, t)}" proof - obtain ss where "unify [(s, t)] [] = Some ss" and "\ = subst_of ss" using assms by (auto simp: mgu_def split: option.splits) then have "is_imgu \ (set [(s, t)])" by (metis unify_sound) then show ?thesis by simp qed text \If \unify\ gives up, then the given set of equations cannot be reduced to the empty set by \UNIF\.\ lemma unify_None: assumes "unify E ss = None" shows "\E'. E' \ {#} \ (mset E, E') \ unif\<^sup>!" using assms proof (induction E ss rule: unify.induct) case (1 bs) then show ?case by simp next case (2 f ss g ts E bs) moreover { assume *: "decompose (Fun f ss) (Fun g ts) = None" have ?case proof (cases "unifiable (set E)") case True then have "(mset E, {#}) \ unif\<^sup>*" by (simp add: unifiable_imp_empty) from unif_rtrancl_mono [OF this, of "{#(Fun f ss, Fun g ts)#}"] obtain \ where "(mset E + {#(Fun f ss, Fun g ts)#}, {#(Fun f ss \ \, Fun g ts \ \)#}) \ unif\<^sup>*" by (auto simp: subst_mset_def) moreover have "{#(Fun f ss \ \, Fun g ts \ \)#} \ NF unif" using decompose_None [OF *] by (auto simp: single_is_union NF_def unif_def elim!: UNIF1.cases) (metis length_map) ultimately show ?thesis by auto (metis normalizability_I add_mset_not_empty) next case False moreover have "\ unifiable {(Fun f ss, Fun g ts)}" using * by (auto simp: unifiable_def) ultimately have "\ unifiable (set ((Fun f ss, Fun g ts) # E))" by (auto simp: unifiable_def unifiers_def) then show ?thesis by (simp add: not_unifiable_imp_not_empty_NF) qed } moreover { fix us assume *: "decompose (Fun f ss) (Fun g ts) = Some us" and "unify (us @ E) bs = None" from "2.IH" [OF this] obtain E' where "E' \ {#}" and "(mset (us @ E), E') \ unif\<^sup>!" by blast moreover have "(mset ((Fun f ss, Fun g ts) # E), mset (us @ E)) \ unif" proof - have "g = f" and "length ss = length ts" and "us = zip ss ts" using * by auto then show ?thesis by (auto intro: UNIF1.decomp simp: unif_def ac_simps) qed ultimately have ?case by auto } ultimately show ?case by (auto split: option.splits) next case (3 x t E bs) { assume [simp]: "t = Var x" obtain E' where "E' \ {#}" and "(mset E, E') \ unif\<^sup>!" using 3 by auto moreover have "(mset ((Var x, t) # E), mset E) \ unif" by (auto intro: UNIF1.trivial simp: unif_def) ultimately have ?case by auto } moreover { assume *: "t \ Var x" "x \ vars_term t" then obtain E' where "E' \ {#}" and "(mset (subst_list (subst x t) E), E') \ unif\<^sup>!" using 3 by auto moreover have "(mset ((Var x, t) # E), mset (subst_list (subst x t) E)) \ unif" using * by (auto intro: UNIF1.Var_left simp: unif_def) ultimately have ?case by auto } moreover { assume *: "t \ Var x" "x \ vars_term t" then have "x \ vars_term t" "is_Fun t" by auto then have "\ unifiable {(Var x, t)}" by (rule in_vars_is_Fun_not_unifiable) then have **: "\ unifiable {(Var x \ \, t \ \)}" for \ :: "('b, 'a) subst" using subst_set_reflects_unifiable [of \ "{(Var x, t)}"] by (auto simp: subst_set_def) have ?case proof (cases "unifiable (set E)") case True then have "(mset E, {#}) \ unif\<^sup>*" by (simp add: unifiable_imp_empty) from unif_rtrancl_mono [OF this, of "{#(Var x, t)#}"] obtain \ where "(mset E + {#(Var x, t)#}, {#(Var x \ \, t \ \)#}) \ unif\<^sup>*" by (auto simp: subst_mset_def) moreover obtain E' where "E' \ {#}" and "({#(Var x \ \, t \ \)#}, E') \ unif\<^sup>!" using not_unifiable_imp_not_empty_NF and ** by (metis set_mset_single) ultimately show ?thesis by auto next case False moreover have "\ unifiable {(Var x, t)}" using * by (force simp: unifiable_def) ultimately have "\ unifiable (set ((Var x, t) # E))" by (auto simp: unifiable_def unifiers_def) then show ?thesis by (simp add: not_unifiable_imp_not_empty_NF) qed } ultimately show ?case by blast next case (4 f ss x E bs) define t where "t = Fun f ss" { assume *: "x \ vars_term t" then obtain E' where "E' \ {#}" and "(mset (subst_list (subst x t) E), E') \ unif\<^sup>!" using 4 by (auto simp: t_def) moreover have "(mset ((t, Var x) # E), mset (subst_list (subst x t) E)) \ unif" using * by (auto intro: UNIF1.Var_right simp: unif_def) ultimately have ?case by (auto simp: t_def) } moreover { assume "x \ vars_term t" then have *: "x \ vars_term t" "t \ Var x" by (auto simp: t_def) then have "x \ vars_term t" "is_Fun t" by auto then have "\ unifiable {(Var x, t)}" by (rule in_vars_is_Fun_not_unifiable) then have **: "\ unifiable {(Var x \ \, t \ \)}" for \ :: "('b, 'a) subst" using subst_set_reflects_unifiable [of \ "{(Var x, t)}"] by (auto simp: subst_set_def) have ?case proof (cases "unifiable (set E)") case True then have "(mset E, {#}) \ unif\<^sup>*" by (simp add: unifiable_imp_empty) from unif_rtrancl_mono [OF this, of "{#(t, Var x)#}"] obtain \ where "(mset E + {#(t, Var x)#}, {#(t \ \, Var x \ \)#}) \ unif\<^sup>*" by (auto simp: subst_mset_def) moreover obtain E' where "E' \ {#}" and "({#(t \ \, Var x \ \)#}, E') \ unif\<^sup>!" using not_unifiable_imp_not_empty_NF and ** by (metis unifiable_insert_swap set_mset_single) ultimately show ?thesis by (auto simp: t_def) next case False moreover have "\ unifiable {(t, Var x)}" using * by (simp add: unifiable_def) ultimately have "\ unifiable (set ((t, Var x) # E))" by (auto simp: unifiable_def unifiers_def) then show ?thesis by (simp add: not_unifiable_imp_not_empty_NF t_def) qed } ultimately show ?case by blast qed lemma unify_complete: assumes "unify E bs = None" shows "unifiers (set E) = {}" proof - from unify_None [OF assms] obtain E' where "E' \ {#}" and "(mset E, E') \ unif\<^sup>!" by blast then have "\ unifiable (set E)" using irreducible_reachable_imp_not_unifiable by force then show ?thesis by (auto simp: unifiable_def) qed corollary ex_unify_if_unifiers_not_empty: \<^marker>\contributor \Martin Desharnais\\ "unifiers es \ {} \ set xs = es \ \ys. unify xs [] = Some ys" using unify_complete by auto lemma mgu_complete: "mgu s t = None \ unifiers {(s, t)} = {}" proof - assume "mgu s t = None" then have "unify [(s, t)] [] = None" by (cases "unify [(s, t)] []", auto simp: mgu_def) then have "unifiers (set [(s, t)]) = {}" by (rule unify_complete) then show ?thesis by simp qed corollary ex_mgu_if_unifiers_not_empty: \<^marker>\contributor \Martin Desharnais\\ "unifiers {(t,u)} \ {} \ \\. mgu t u = Some \" using mgu_complete by auto corollary ex_mgu_if_subst_apply_term_eq_subst_apply_term: \<^marker>\contributor \Martin Desharnais\\ fixes t u :: "('f, 'v) Term.term" and \ :: "('f, 'v) subst" assumes t_eq_u: "t \ \ = u \ \" shows "\\ :: ('f, 'v) subst. Unification.mgu t u = Some \" proof - from t_eq_u have "unifiers {(t, u)} \ {}" unfolding unifiers_def by auto thus ?thesis by (rule ex_mgu_if_unifiers_not_empty) qed lemma finite_subst_domain_subst_of: "finite (subst_domain (subst_of xs))" proof (induct xs) case (Cons x xs) moreover have "finite (subst_domain (subst (fst x) (snd x)))" by (metis finite_subst_domain_subst) ultimately show ?case using subst_domain_compose [of "subst_of xs" "subst (fst x) (snd x)"] by (simp del: subst_subst_domain) (metis finite_subset infinite_Un) qed simp lemma unify_subst_domain: \<^marker>\contributor \Martin Desharnais\\ assumes unif: "unify E [] = Some xs" shows "subst_domain (subst_of xs) \ (\e \ set E. vars_term (fst e) \ vars_term (snd e))" proof - from unify_Some_UNIF[OF unif] obtain xs' where "subst_of xs = compose xs'" and "UNIF xs' (mset E) {#}" by auto thus ?thesis using UNIF_subst_domain_subset by (metis (mono_tags, lifting) multiset.set_map set_mset_mset vars_mset_def) qed lemma mgu_subst_domain: assumes "mgu s t = Some \" shows "subst_domain \ \ vars_term s \ vars_term t" proof - obtain xs where "unify [(s, t)] [] = Some xs" and "\ = subst_of xs" using assms by (simp add: mgu_def split: option.splits) thus ?thesis using unify_subst_domain by fastforce qed lemma mgu_finite_subst_domain: "mgu s t = Some \ \ finite (subst_domain \)" by (drule mgu_subst_domain) (simp add: finite_subset) lemma unify_range_vars: \<^marker>\contributor \Martin Desharnais\\ assumes unif: "unify E [] = Some xs" shows "range_vars (subst_of xs) \ (\e \ set E. vars_term (fst e) \ vars_term (snd e))" proof - from unify_Some_UNIF[OF unif] obtain xs' where "subst_of xs = compose xs'" and "UNIF xs' (mset E) {#}" by auto thus ?thesis using UNIF_range_vars_subset by (metis (mono_tags, lifting) multiset.set_map set_mset_mset vars_mset_def) qed lemma mgu_range_vars: \<^marker>\contributor \Martin Desharnais\\ assumes "mgu s t = Some \" shows "range_vars \ \ vars_term s \ vars_term t" proof - obtain xs where "unify [(s, t)] [] = Some xs" and "\ = subst_of xs" using assms by (simp add: mgu_def split: option.splits) thus ?thesis using unify_range_vars by fastforce qed lemma unify_subst_domain_range_vars_disjoint: \<^marker>\contributor \Martin Desharnais\\ assumes unif: "unify E [] = Some xs" shows "subst_domain (subst_of xs) \ range_vars (subst_of xs) = {}" proof - from unify_Some_UNIF[OF unif] obtain xs' where "subst_of xs = compose xs'" and "UNIF xs' (mset E) {#}" by auto thus ?thesis using UNIF_subst_domain_range_vars_Int by metis qed lemma mgu_subst_domain_range_vars_disjoint: \<^marker>\contributor \Martin Desharnais\\ assumes "mgu s t = Some \" shows "subst_domain \ \ range_vars \ = {}" proof - obtain xs where "unify [(s, t)] [] = Some xs" and "\ = subst_of xs" using assms by (simp add: mgu_def split: option.splits) thus ?thesis using unify_subst_domain_range_vars_disjoint by metis qed corollary subst_apply_term_eq_subst_apply_term_if_mgu: \<^marker>\contributor \Martin Desharnais\\ assumes mgu_t_u: "mgu t u = Some \" shows "t \ \ = u \ \" using mgu_sound[OF mgu_t_u] by (simp add: is_imgu_def unifiers_def) lemma mgu_same: "mgu t t = Some Var" \<^marker>\contributor \Martin Desharnais\\ by (simp add: mgu_def unify_same) lemma mgu_is_Var_if_not_in_equations: \<^marker>\contributor \Martin Desharnais\\ fixes \ :: "('f, 'v) subst" and E :: "('f, 'v) equations" and x :: 'v assumes mgu_\: "is_mgu \ E" and x_not_in: "x \ (\e\E. vars_term (fst e) \ vars_term (snd e))" shows "is_Var (\ x)" proof - from mgu_\ have unif_\: "\ \ unifiers E" and minimal_\: "\\ \ unifiers E. \\. \ = \ \\<^sub>s \" by (simp_all add: is_mgu_def) define \ :: "('f, 'v) subst" where "\ = (\x. if x \ (\e \ E. vars_term (fst e) \ vars_term (snd e)) then \ x else Var x)" have \\ \ unifiers E\ unfolding unifiers_def mem_Collect_eq proof (rule ballI) fix e assume "e \ E" with unif_\ have "fst e \ \ = snd e \ \" by blast moreover from \e \ E\ have "fst e \ \ = fst e \ \" and "snd e \ \ = snd e \ \" unfolding term_subst_eq_conv by (auto simp: \_def) ultimately show "fst e \ \ = snd e \ \" by simp qed with minimal_\ obtain \ where "\ \\<^sub>s \ = \" by auto with x_not_in have "(\ \\<^sub>s \) x = Var x" by (simp add: \_def) thus "is_Var (\ x)" by (metis subst_apply_eq_Var subst_compose term.disc(1)) qed corollary mgu_ball_is_Var: \<^marker>\contributor \Martin Desharnais\\ "is_mgu \ E \ \x \ - (\e\E. vars_term (fst e) \ vars_term (snd e)). is_Var (\ x)" by (rule ballI) (rule mgu_is_Var_if_not_in_equations[folded Compl_iff]) lemma mgu_inj_on: \<^marker>\contributor \Martin Desharnais\\ fixes \ :: "('f, 'v) subst" and E :: "('f, 'v) equations" assumes mgu_\: "is_mgu \ E" shows "inj_on \ (- (\e \ E. vars_term (fst e) \ vars_term (snd e)))" proof (rule inj_onI) fix x y assume x_in: "x \ - (\e\E. vars_term (fst e) \ vars_term (snd e))" and y_in: "y \ - (\e\E. vars_term (fst e) \ vars_term (snd e))" and "\ x = \ y" from mgu_\ have unif_\: "\ \ unifiers E" and minimal_\: "\\ \ unifiers E. \\. \ = \ \\<^sub>s \" by (simp_all add: is_mgu_def) define \ :: "('f, 'v) subst" where "\ = (\x. if x \ (\e \ E. vars_term (fst e) \ vars_term (snd e)) then \ x else Var x)" have \\ \ unifiers E\ unfolding unifiers_def mem_Collect_eq proof (rule ballI) fix e assume "e \ E" with unif_\ have "fst e \ \ = snd e \ \" by blast moreover from \e \ E\ have "fst e \ \ = fst e \ \" and "snd e \ \ = snd e \ \" unfolding term_subst_eq_conv by (auto simp: \_def) ultimately show "fst e \ \ = snd e \ \" by simp qed with minimal_\ obtain \ where "\ \\<^sub>s \ = \" by auto hence "(\ \\<^sub>s \) x = Var x" and "(\ \\<^sub>s \) y = Var y" using ComplD[OF x_in] ComplD[OF y_in] by (simp_all add: \_def) with \\ x = \ y\ show "x = y" by (simp add: subst_compose_def) qed lemma imgu_subst_domain_subset: \<^marker>\contributor \Martin Desharnais\\ fixes \ :: "('f, 'v) subst" and E :: "('f, 'v) equations" and Evars :: "'v set" assumes imgu_\: "is_imgu \ E" and fin_E: "finite E" defines "Evars \ (\e \ E. vars_term (fst e) \ vars_term (snd e))" shows "subst_domain \ \ Evars" proof (intro Set.subsetI) from imgu_\ have unif_\: "\ \ unifiers E" and minimal_\: "\\ \ unifiers E. \ \\<^sub>s \ = \" by (simp_all add: is_imgu_def) from fin_E obtain es :: "('f, 'v) equation list" where "set es = E" using finite_list by auto then obtain xs :: "('v \ ('f, 'v) Term.term) list" where unify_es: "unify es [] = Some xs" using unif_\ ex_unify_if_unifiers_not_empty by blast define \ :: "('f, 'v) subst" where "\ = subst_of xs" have dom_\: "subst_domain \ \ Evars" using unify_subst_domain[OF unify_es, unfolded \set es = E\, folded Evars_def \_def] . have range_vars_\: "range_vars \ \ Evars" using unify_range_vars[OF unify_es, unfolded \set es = E\, folded Evars_def \_def] . have "\ \ unifiers E" using \set es = E\ unify_es \_def is_imgu_def unify_sound by blast with minimal_\ have \_comp_\: "\x. (\ \\<^sub>s \) x = \ x" by auto fix x :: 'v assume "x \ subst_domain \" hence "\ x \ Var x" by (simp add: subst_domain_def) show "x \ Evars" proof (cases "x \ subst_domain \") case True thus ?thesis using dom_\ by auto next case False hence "\ x = Var x" by (simp add: subst_domain_def) hence "\ x \ \ = Var x" using \_comp_\[of x] by (simp add: subst_compose) thus ?thesis proof (rule subst_apply_eq_Var[of "\ x" \ x]) show "\y. \ x = Var y \ \ y = Var x \ ?thesis" using \\ x \ Var x\ range_vars_\ mem_range_varsI[of \ _ x] by auto qed qed qed lemma imgu_range_vars_of_equations_vars_subset: \<^marker>\contributor \Martin Desharnais\\ fixes \ :: "('f, 'v) subst" and E :: "('f, 'v) equations" and Evars :: "'v set" assumes imgu_\: "is_imgu \ E" and fin_E: "finite E" defines "Evars \ (\e \ E. vars_term (fst e) \ vars_term (snd e))" shows "(\x \ Evars. vars_term (\ x)) \ Evars" proof (rule Set.subsetI) from imgu_\ have unif_\: "\ \ unifiers E" and minimal_\: "\\ \ unifiers E. \ \\<^sub>s \ = \" by (simp_all add: is_imgu_def) from fin_E obtain es :: "('f, 'v) equation list" where "set es = E" using finite_list by auto then obtain xs :: "('v \ ('f, 'v) Term.term) list" where unify_es: "unify es [] = Some xs" using unif_\ ex_unify_if_unifiers_not_empty by blast define \ :: "('f, 'v) subst" where "\ = subst_of xs" have dom_\: "subst_domain \ \ Evars" using unify_subst_domain[OF unify_es, unfolded \set es = E\, folded Evars_def \_def] . have range_vars_\: "range_vars \ \ Evars" using unify_range_vars[OF unify_es, unfolded \set es = E\, folded Evars_def \_def] . hence ball_vars_apply_\_subset: "\x \ subst_domain \. vars_term (\ x) \ Evars" unfolding range_vars_def by (simp add: SUP_le_iff) have "\ \ unifiers E" using \set es = E\ unify_es \_def is_imgu_def unify_sound by blast with minimal_\ have \_comp_\: "\x. (\ \\<^sub>s \) x = \ x" by auto fix y :: 'v assume "y \ (\x \ Evars. vars_term (\ x))" then obtain x :: 'v where x_in: "x \ Evars" and y_in: "y \ vars_term (\ x)" by (auto simp: subst_domain_def) have vars_\_x: "vars_term (\ x) \ Evars" using ball_vars_apply_\_subset subst_domain_def x_in by fastforce show "y \ Evars" proof (rule ccontr) assume "y \ Evars" hence "y \ vars_term (\ x)" using vars_\_x by blast moreover have "y \ vars_term ((\ \\<^sub>s \) x)" proof - have "\ y = Var y" using \y \ Evars\ dom_\ by (auto simp add: subst_domain_def) thus ?thesis unfolding subst_compose_def vars_term_subst_apply_term UN_iff using y_in by force qed ultimately show False using \_comp_\[of x] by simp qed qed lemma imgu_range_vars_subset: \<^marker>\contributor \Martin Desharnais\\ fixes \ :: "('f, 'v) subst" and E :: "('f, 'v) equations" assumes imgu_\: "is_imgu \ E" and fin_E: "finite E" shows "range_vars \ \ (\e \ E. vars_term (fst e) \ vars_term (snd e))" proof - have "range_vars \ = (\x \ subst_domain \. vars_term (\ x))" by (simp add: range_vars_def) also have "\ \ (\x \ (\e \ E. vars_term (fst e) \ vars_term (snd e)). vars_term (\ x))" using imgu_subst_domain_subset[OF imgu_\ fin_E] by fast also have "\ \ (\e \ E. vars_term (fst e) \ vars_term (snd e))" using imgu_range_vars_of_equations_vars_subset[OF imgu_\ fin_E] by metis finally show ?thesis . qed + +definition the_mgu :: "('f, 'v) term \ ('f, 'v) term \ ('f ,'v) subst" where + "the_mgu s t = (case mgu s t of None \ Var | Some \ \ \)" + +lemma the_mgu_is_imgu: + fixes \ :: "('f, 'v) subst" + assumes "s \ \ = t \ \" + shows "is_imgu (the_mgu s t) {(s, t)}" +proof - + from assms have "unifiers {(s, t)} \ {}" by (force simp: unifiers_def) + then obtain \ where "mgu s t = Some \" + and "the_mgu s t = \" + using mgu_complete by (auto simp: the_mgu_def) + with mgu_sound show ?thesis by blast +qed + +lemma the_mgu: + fixes \ :: "('f, 'v) subst" + assumes "s \ \ = t \ \" + shows "s \ the_mgu s t = t \ the_mgu s t \ \ = the_mgu s t \\<^sub>s \" +proof - + have *: "\ \ unifiers {(s, t)}" by (force simp: assms unifiers_def) + show ?thesis + proof (cases "mgu s t") + assume "mgu s t = None" + then have "unifiers {(s, t)} = {}" by (rule mgu_complete) + with * show ?thesis by simp + next + fix \ + assume "mgu s t = Some \" + moreover then have "is_imgu \ {(s, t)}" by (rule mgu_sound) + ultimately have "is_imgu (the_mgu s t) {(s, t)}" by (unfold the_mgu_def, simp) + with * show ?thesis by (auto simp: is_imgu_def unifiers_def) + qed +qed + +subsubsection \Unification of two terms where variables should be considered disjoint\ + +definition + mgu_var_disjoint_generic :: + "('v \ 'u) \ ('w \ 'u) \ ('f, 'v) term \ ('f, 'w) term \ + (('f, 'v, 'u) gsubst \ ('f, 'w, 'u) gsubst) option" +where + "mgu_var_disjoint_generic vu wu s t = + (case mgu (map_vars_term vu s) (map_vars_term wu t) of + None \ None + | Some \ \ Some (\ \ vu, \ \ wu))" + +lemma mgu_var_disjoint_generic_sound: + assumes unif: "mgu_var_disjoint_generic vu wu s t = Some (\1, \2)" + shows "s \ \1 = t \ \2" +proof - + from unif[unfolded mgu_var_disjoint_generic_def] obtain \ where + unif2: "mgu (map_vars_term vu s) (map_vars_term wu t) = Some \" + by (cases "mgu (map_vars_term vu s) (map_vars_term wu t)", auto) + from mgu_sound[OF unif2[unfolded mgu_var_disjoint_generic_def], unfolded is_imgu_def unifiers_def] + have "map_vars_term vu s \ \ = map_vars_term wu t \ \" by auto + from this[unfolded apply_subst_map_vars_term] unif[unfolded mgu_var_disjoint_generic_def unif2] + show ?thesis by simp +qed + +(* if terms s and t can become identical via two substitutions \ and \ + then mgu_var_disjoint yields two more general substitutions \1 \2 *) +lemma mgu_var_disjoint_generic_complete: + fixes \ :: "('f, 'v, 'u) gsubst" and \ :: "('f, 'w, 'u) gsubst" + and vu :: "'v \ 'u" and wu:: "'w \ 'u" + assumes inj: "inj vu" "inj wu" + and vwu: "range vu \ range wu = {}" + and unif_disj: "s \ \ = t \ \" + shows "\\1 \2 \. mgu_var_disjoint_generic vu wu s t = Some (\1, \2) \ + \ = \1 \\<^sub>s \ \ + \ = \2 \\<^sub>s \ \ + s \ \1 = t \ \2" +proof - + note inv1[simp] = the_inv_f_f[OF inj(1)] + note inv2[simp] = the_inv_f_f[OF inj(2)] + obtain \ :: "('f,'u)subst" where gamma: "\ = (\ x. if x \ range vu then \ (the_inv vu x) else \ (the_inv wu x))" by auto + have ids: "s \ \ = map_vars_term vu s \ \" unfolding gamma + by (induct s, auto) + have idt: "t \ \ = map_vars_term wu t \ \" unfolding gamma + by (induct t, insert vwu, auto) + from unif_disj ids idt + have unif: "map_vars_term vu s \ \ = map_vars_term wu t \ \" (is "?s \ \ = ?t \ \") by auto + from the_mgu[OF unif] have unif2: "?s \ the_mgu ?s ?t = ?t \ the_mgu ?s ?t" and inst: "\ = the_mgu ?s ?t \\<^sub>s \" by auto + have "mgu ?s ?t = Some (the_mgu ?s ?t)" unfolding the_mgu_def + using mgu_complete[unfolded unifiers_def] unif + by (cases "mgu ?s ?t", auto) + with inst obtain \ where mu: "mgu ?s ?t = Some \" and gamma_mu: "\ = \ \\<^sub>s \" by auto + let ?tau1 = "\ \ vu" + let ?tau2 = "\ \ wu" + show ?thesis unfolding mgu_var_disjoint_generic_def mu option.simps + proof (intro exI conjI, rule refl) + show "\ = ?tau1 \\<^sub>s \" + proof (rule ext) + fix x + have "(?tau1 \\<^sub>s \) x = \ (vu x)" using fun_cong[OF gamma_mu, of "vu x"] by (simp add: subst_compose_def) + also have "... = \ x" unfolding gamma by simp + finally show "\ x = (?tau1 \\<^sub>s \) x" by simp + qed + next + show "\ = ?tau2 \\<^sub>s \" + proof (rule ext) + fix x + have "(?tau2 \\<^sub>s \) x = \ (wu x)" using fun_cong[OF gamma_mu, of "wu x"] by (simp add: subst_compose_def) + also have "... = \ x" unfolding gamma using vwu by auto + finally show "\ x = (?tau2 \\<^sub>s \) x" by simp + qed + next + have "s \ ?tau1 = map_vars_term vu s \ \" unfolding apply_subst_map_vars_term .. + also have "... = map_vars_term wu t \ \" + unfolding unif2[unfolded the_mgu_def mu option.simps] .. + also have "... = t \ ?tau2" unfolding apply_subst_map_vars_term .. + finally show "s \ ?tau1 = t \ ?tau2" . + qed +qed + +abbreviation "mgu_var_disjoint_sum \ mgu_var_disjoint_generic Inl Inr" + +lemma mgu_var_disjoint_sum_sound: + "mgu_var_disjoint_sum s t = Some (\1, \2) \ s \ \1 = t \ \2" + by (rule mgu_var_disjoint_generic_sound) + +lemma mgu_var_disjoint_sum_complete: + fixes \ :: "('f, 'v, 'v + 'w) gsubst" and \ :: "('f, 'w, 'v + 'w) gsubst" + assumes unif_disj: "s \ \ = t \ \" + shows "\\1 \2 \. mgu_var_disjoint_sum s t = Some (\1, \2) \ + \ = \1 \\<^sub>s \ \ + \ = \2 \\<^sub>s \ \ + s \ \1 = t \ \2" + by (rule mgu_var_disjoint_generic_complete[OF _ _ _ unif_disj], auto simp: inj_on_def) + +fun map_vars_subst_ran :: "('w \ 'u) \ ('f, 'v, 'w) gsubst \ ('f, 'v, 'u) gsubst" where + "map_vars_subst_ran m \ = (\v. map_vars_term m (\ v))" + +lemma map_vars_subst_ran: + shows "map_vars_term m (t \ \) = t \ map_vars_subst_ran m \" + by (induct t) (auto) + +lemma mgu_var_disjoint_sum_instance: + fixes \ :: "('f, 'v) subst" and \ :: "('f, 'v) subst" + assumes unif_disj: "s \ \ = t \ \" + shows "\\1 \2 \. mgu_var_disjoint_sum s t = Some (\1, \2) \ + \ = \1 \\<^sub>s \ \ + \ = \2 \\<^sub>s \ \ + s \ \1 = t \ \2" +proof - + let ?m = "map_vars_subst_ran (Inl :: ('v \ 'v + 'v))" + let ?m' = "map_vars_subst_ran (case_sum (\ x. x) (\ x. x))" + from unif_disj have id: "map_vars_term Inl (s \ \) = map_vars_term Inl (t \ \)" by simp + from mgu_var_disjoint_sum_complete[OF id[unfolded map_vars_subst_ran]] + obtain \1 \2 \ where mgu: "mgu_var_disjoint_sum s t = Some (\1,\2)" + and \: "?m \ = \1 \\<^sub>s \" + and \: "?m \ = \2 \\<^sub>s \" + and unif: "s \ \1 = t \ \2" by blast + { + fix \ :: "('f, 'v) subst" + have "?m' (?m \) = \" by (simp add: map_vars_term_compose o_def term.map_ident) + } note id = this + { + fix \ :: "('f,'v,'v+'v)gsubst" and \ :: "('f,'v + 'v)subst" + have "?m' (\ \\<^sub>s \) = \ \\<^sub>s ?m' \" + by (rule ext, unfold subst_compose_def, simp add: map_vars_subst_ran) + } note id' = this + from arg_cong[OF \, of ?m', unfolded id id'] have \: "\ = \1 \\<^sub>s ?m' \" . + from arg_cong[OF \, of ?m', unfolded id id'] have \: "\ = \2 \\<^sub>s ?m' \" . + show ?thesis + by (intro exI conjI, rule mgu, rule \, rule \, rule unif) +qed + +subsubsection \A variable disjoint unification algorithm without changing the type\ + +text \We pass the renaming function as additional argument\ + +definition mgu_vd :: "'v :: infinite renaming2 \ _ \ _" where + "mgu_vd r = mgu_var_disjoint_generic (rename_1 r) (rename_2 r)" + +lemma mgu_vd_sound: "mgu_vd r s t = Some (\1, \2) \ s \ \1 = t \ \2" + unfolding mgu_vd_def by (rule mgu_var_disjoint_generic_sound) + +lemma mgu_vd_complete: + fixes \ :: "('f, 'v :: infinite) subst" and \ :: "('f, 'v) subst" + assumes unif_disj: "s \ \ = t \ \" + shows "\\1 \2 \. mgu_vd r s t = Some (\1, \2) \ + \ = \1 \\<^sub>s \ \ + \ = \2 \\<^sub>s \ \ + s \ \1 = t \ \2" + unfolding mgu_vd_def + by (rule mgu_var_disjoint_generic_complete[OF rename_12 unif_disj]) + end diff --git a/thys/First_Order_Terms/Unification_String.thy b/thys/First_Order_Terms/Unification_String.thy new file mode 100644 --- /dev/null +++ b/thys/First_Order_Terms/Unification_String.thy @@ -0,0 +1,27 @@ +subsection \A variable disjoint unification algorithm for terms with string variables\ + +theory Unification_String +imports + Unification + Renaming2_String +begin +definition "mgu_vd_string = mgu_vd string_rename" + +lemma mgu_vd_string_code[code]: "mgu_vd_string = mgu_var_disjoint_generic (Cons (CHR ''x'')) (Cons (CHR ''y''))" + unfolding mgu_vd_string_def mgu_vd_def + by (transfer, auto) + +lemma mgu_vd_string_sound: + "mgu_vd_string s t = Some (\1, \2) \ s \ \1 = t \ \2" + unfolding mgu_vd_string_def by (rule mgu_vd_sound) + +lemma mgu_vd_string_complete: + fixes \ :: "('f, string) subst" and \ :: "('f, string) subst" + assumes "s \ \ = t \ \" + shows "\\1 \2 \. mgu_vd_string s t = Some (\1, \2) \ + \ = \1 \\<^sub>s \ \ + \ = \2 \\<^sub>s \ \ + s \ \1 = t \ \2" + unfolding mgu_vd_string_def + by (rule mgu_vd_complete[OF assms]) +end \ No newline at end of file diff --git a/thys/Regular_Tree_Relations/Util/Term_Context.thy b/thys/Regular_Tree_Relations/Util/Term_Context.thy --- a/thys/Regular_Tree_Relations/Util/Term_Context.thy +++ b/thys/Regular_Tree_Relations/Util/Term_Context.thy @@ -1,526 +1,525 @@ section \Preliminaries\ theory Term_Context imports First_Order_Terms.Term First_Order_Terms.Subterm_and_Context Polynomial_Factorization.Missing_List begin subsection \Additional functionality on @{type term} and @{type ctxt}\ subsubsection \Positions\ type_synonym pos = "nat list" context notes conj_cong [fundef_cong] begin fun poss :: "('f, 'v) term \ pos set" where "poss (Var x) = {[]}" | "poss (Fun f ss) = {[]} \ {i # p | i p. i < length ss \ p \ poss (ss ! i)}" end fun hole_pos where "hole_pos \ = []" | "hole_pos (More f ss D ts) = length ss # hole_pos D" definition position_less_eq (infixl "\\<^sub>p" 67) where "p \\<^sub>p q \ (\ r. p @ r = q)" abbreviation position_less (infixl "<\<^sub>p" 67) where "p <\<^sub>p q \ p \ q \ p \\<^sub>p q" definition position_par (infixl "\" 67) where "p \ q \ \ (p \\<^sub>p q) \ \ (q \\<^sub>p p)" fun remove_prefix where "remove_prefix (x # xs) (y # ys) = (if x = y then remove_prefix xs ys else None)" | "remove_prefix [] ys = Some ys" | "remove_prefix xs [] = None" definition pos_diff (infixl "-\<^sub>p" 67) where "p -\<^sub>p q = the (remove_prefix q p)" fun subt_at :: "('f, 'v) term \ pos \ ('f, 'v) term" (infixl "|'_" 67) where "s |_ [] = s" | "Fun f ss |_ (i # p) = (ss ! i) |_ p" | "Var x |_ _ = undefined" fun ctxt_at_pos where "ctxt_at_pos s [] = \" | "ctxt_at_pos (Fun f ss) (i # p) = More f (take i ss) (ctxt_at_pos (ss ! i) p) (drop (Suc i) ss)" | "ctxt_at_pos (Var x) _ = undefined" fun replace_term_at ("_[_ \ _]" [1000, 0, 0] 1000) where "replace_term_at s [] t = t" | "replace_term_at (Var x) ps t = (Var x)" | "replace_term_at (Fun f ts) (i # ps) t = (if i < length ts then Fun f (ts[i:=(replace_term_at (ts ! i) ps t)]) else Fun f ts)" fun fun_at :: "('f, 'v) term \ pos \ ('f + 'v) option" where "fun_at (Var x) [] = Some (Inr x)" | "fun_at (Fun f ts) [] = Some (Inl f)" | "fun_at (Fun f ts) (i # p) = (if i < length ts then fun_at (ts ! i) p else None)" | "fun_at _ _ = None" subsubsection \Computing the signature\ fun funas_term where "funas_term (Var x) = {}" | "funas_term (Fun f ts) = insert (f, length ts) (\ (set (map funas_term ts)))" fun funas_ctxt where "funas_ctxt \ = {}" | "funas_ctxt (More f ss C ts) = (\ (set (map funas_term ss))) \ insert (f, Suc (length ss + length ts)) (funas_ctxt C) \ (\ (set (map funas_term ts)))" subsubsection \Groundness\ fun ground where "ground (Var x) = False" | "ground (Fun f ts) = (\ t \ set ts. ground t)" fun ground_ctxt where "ground_ctxt \ \ True" | "ground_ctxt (More f ss C ts) \ (\ t \ set ss. ground t) \ ground_ctxt C \ (\ t \ set ts. ground t)" subsubsection \Depth\ fun depth where "depth (Var x) = 0" | "depth (Fun f []) = 0" | "depth (Fun f ts) = Suc (Max (depth ` set ts))" subsubsection \Type conversion\ text \We require a function which adapts the type of variables of a term, so that states of the automaton and variables in the term language can be chosen independently.\ -abbreviation "map_vars_term f \ map_term (\ x. x) f" abbreviation "map_funs_term f \ map_term f (\ x. x)" abbreviation "map_both f \ map_prod f f" definition adapt_vars :: "('f, 'q) term \ ('f,'v)term" where [code del]: "adapt_vars \ map_vars_term (\_. undefined)" abbreviation "map_vars_ctxt f \ map_ctxt (\x. x) f" definition adapt_vars_ctxt :: "('f,'q)ctxt \ ('f,'v)ctxt" where [code del]: "adapt_vars_ctxt = map_vars_ctxt (\_. undefined)" subsection \Properties of @{type pos}\ lemma position_less_eq_induct [consumes 1]: assumes "p \\<^sub>p q" and "\ p. P p p" and "\ p q r. p \\<^sub>p q \ P p q \ P p (q @ r)" shows "P p q" using assms proof (induct p arbitrary: q) case Nil then show ?case by (metis append_Nil position_less_eq_def) next case (Cons a p) then show ?case by (metis append_Nil2 position_less_eq_def) qed text \We show the correspondence between the function @{const remove_prefix} and the order on positions @{const position_less_eq}. Moreover how it can be used to compute the difference of positions.\ lemma remove_prefix_Nil [simp]: "remove_prefix xs xs = Some []" by (induct xs) auto lemma remove_prefix_Some: assumes "remove_prefix xs ys = Some zs" shows "ys = xs @ zs" using assms proof (induct xs arbitrary: ys) case (Cons x xs) show ?case using Cons(1)[of "tl ys"] Cons(2) by (cases ys) (auto split: if_splits) qed auto lemma remove_prefix_append: "remove_prefix xs (xs @ ys) = Some ys" by (induct xs) auto lemma remove_prefix_iff: "remove_prefix xs ys = Some zs \ ys = xs @ zs" using remove_prefix_Some remove_prefix_append by blast lemma position_less_eq_remove_prefix: "p \\<^sub>p q \ remove_prefix p q \ None" by (induct rule: position_less_eq_induct) (auto simp: remove_prefix_iff) text \Simplification rules on @{const position_less_eq}, @{const pos_diff}, and @{const position_par}.\ lemma position_less_refl [simp]: "p \\<^sub>p p" by (auto simp: position_less_eq_def) lemma position_less_eq_Cons [simp]: "(i # ps) \\<^sub>p (j # qs) \ i = j \ ps \\<^sub>p qs" by (auto simp: position_less_eq_def) lemma position_less_Nil_is_bot [simp]: "[] \\<^sub>p p" by (auto simp: position_less_eq_def) lemma position_less_Nil_is_bot2 [simp]: "p \\<^sub>p [] \ p = []" by (auto simp: position_less_eq_def) lemma position_diff_Nil [simp]: "q -\<^sub>p [] = q" by (auto simp: pos_diff_def) lemma position_diff_Cons [simp]: "(i # ps) -\<^sub>p (i # qs) = ps -\<^sub>p qs" by (auto simp: pos_diff_def) lemma Nil_not_par [simp]: "[] \ p \ False" "p \ [] \ False" by (auto simp: position_par_def) lemma par_not_refl [simp]: "p \ p \ False" by (auto simp: position_par_def) lemma par_Cons_iff: "(i # ps) \ (j # qs) \ (i \ j \ ps \ qs)" by (auto simp: position_par_def) text \Simplification rules on @{const poss}.\ lemma Nil_in_poss [simp]: "[] \ poss t" by (cases t) auto lemma poss_Cons [simp]: "i # p \ poss t \ [i] \ poss t" by (cases t) auto lemma poss_Cons_poss: "i # q \ poss t \ i < length (args t) \ q \ poss (args t ! i)" by (cases t) auto lemma poss_append_poss: "p @ q \ poss t \ p \ poss t \ q \ poss (t |_ p)" proof (induct p arbitrary: t) case (Cons i p) from Cons[of "args t ! i"] show ?case by (cases t) auto qed auto text \Simplification rules on @{const hole_pos}\ lemma hole_pos_map_vars [simp]: "hole_pos (map_vars_ctxt f C) = hole_pos C" by (induct C) auto lemma hole_pos_in_ctxt_apply [simp]: "hole_pos C \ poss C\u\" by (induct C) auto subsection \Properties of @{const ground} and @{const ground_ctxt}\ lemma ground_vars_term_empty [simp]: "ground t \ vars_term t = {}" by (induct t) auto lemma ground_map_term [simp]: "ground (map_term f h t) = ground t" by (induct t) auto lemma ground_ctxt_apply [simp]: "ground C\t\ \ ground_ctxt C \ ground t" by (induct C) auto lemma ground_ctxt_comp [intro]: "ground_ctxt C \ ground_ctxt D \ ground_ctxt (C \\<^sub>c D)" by (induct C) auto lemma ctxt_comp_n_pres_ground [intro]: "ground_ctxt C \ ground_ctxt (C^n)" by (induct n arbitrary: C) auto lemma subterm_eq_pres_ground: assumes "ground s" and "s \ t" shows "ground t" using assms(2,1) by (induct) auto lemma ground_substD: "ground (l \ \) \ x \ vars_term l \ ground (\ x)" by (induct l) auto lemma ground_substI: "(\ x. x \ vars_term s \ ground (\ x)) \ ground (s \ \)" by (induct s) auto subsection \Properties on signature induced by a term @{type term}/context @{type ctxt}\ lemma funas_ctxt_apply [simp]: "funas_term C\t\ = funas_ctxt C \ funas_term t" by (induct C) auto lemma funas_term_map [simp]: "funas_term (map_term f h t) = (\ (g, n). (f g, n)) ` funas_term t" by (induct t) auto lemma funas_term_subst: "funas_term (l \ \) = funas_term l \ (\ (funas_term ` \ ` vars_term l))" by (induct l) auto lemma funas_ctxt_comp [simp]: "funas_ctxt (C \\<^sub>c D) = funas_ctxt C \ funas_ctxt D" by (induct C) auto lemma ctxt_comp_n_funas [simp]: "(f, v) \ funas_ctxt (C^n) \ (f, v) \ funas_ctxt C" by (induct n arbitrary: C) auto lemma ctxt_comp_n_pres_funas [intro]: "funas_ctxt C \ \ \ funas_ctxt (C^n) \ \" by (induct n arbitrary: C) auto subsection \Properties on subterm at given position @{const subt_at}\ lemma subt_at_Cons_comp: "i # p \ poss s \ (s |_ [i]) |_ p = s |_ (i # p)" by (cases s) auto lemma ctxt_at_pos_subt_at_pos: "p \ poss t \ (ctxt_at_pos t p)\u\ |_ p = u" proof (induct p arbitrary: t) case (Cons i p) then show ?case using id_take_nth_drop by (cases t) (auto simp: nth_append) qed auto lemma ctxt_at_pos_subt_at_id: "p \ poss t \ (ctxt_at_pos t p)\t |_ p\ = t" proof (induct p arbitrary: t) case (Cons i p) then show ?case using id_take_nth_drop by (cases t) force+ qed auto lemma subst_at_ctxt_at_eq_termD: assumes "s = t" "p \ poss t" shows "s |_ p = t |_ p \ ctxt_at_pos s p = ctxt_at_pos t p" using assms by auto lemma subst_at_ctxt_at_eq_termI: assumes "p \ poss s" "p \ poss t" and "s |_p = t |_ p" and "ctxt_at_pos s p = ctxt_at_pos t p" shows "s = t" using assms by (metis ctxt_at_pos_subt_at_id) lemma subt_at_subterm_eq [intro!]: "p \ poss t \ t \ t |_ p" proof (induct p arbitrary: t) case (Cons i p) from Cons(1)[of "args t ! i"] Cons(2) show ?case by (cases t) force+ qed auto lemma subt_at_subterm [intro!]: "p \ poss t \ p \ [] \ t \ t |_ p" proof (induct p arbitrary: t) case (Cons i p) from Cons(1)[of "args t ! i"] Cons(2) show ?case by (cases t) force+ qed auto lemma ctxt_at_pos_hole_pos [simp]: "ctxt_at_pos C\s\ (hole_pos C) = C" by (induct C) auto subsection \Properties on replace terms at a given position @{const replace_term_at}\ lemma replace_term_at_not_poss [simp]: "p \ poss s \ s[p \ t] = s" proof (induct s arbitrary: p) case (Var x) then show ?case by (cases p) auto next case (Fun f ts) show ?case using Fun(1)[OF nth_mem] Fun(2) by (cases p) (auto simp: min_def intro!: nth_equalityI) qed lemma replace_term_at_replace_at_conv: "p \ poss s \ (ctxt_at_pos s p)\t\ = s[p \ t]" by (induct s arbitrary: p) (auto simp: upd_conv_take_nth_drop) lemma parallel_replace_term_commute [ac_simps]: "p \ q \ s[p \ t][q \ u] = s[q \ u][p \ t]" proof (induct s arbitrary: p q) case (Var x) then show ?case by (cases p; cases q) auto next case (Fun f ts) from Fun(2) have "p \ []" "q \ []" by auto then obtain i j ps qs where [simp]: "p = i # ps" "q = j # qs" by (cases p; cases q) auto have "i \ j \ (Fun f ts)[p \ t][q \ u] = (Fun f ts)[q \ u][p \ t]" by (auto simp: list_update_swap) then show ?case using Fun(1)[OF nth_mem, of j ps qs] Fun(2) by (cases "i = j") (auto simp: par_Cons_iff) qed lemma replace_term_at_above [simp]: "p \\<^sub>p q \ s[q \ t][p \ u] = s[p \ u]" proof (induct p arbitrary: s q) case (Cons i p) show ?case using Cons(1)[of "tl q" "args s ! i"] Cons(2) by (cases q; cases s) auto qed auto lemma replace_term_at_below [simp]: "p <\<^sub>p q \ s[p \ t][q \ u] = s[p \ t[q -\<^sub>p p \ u]]" proof (induct p arbitrary: s q) case (Cons i p) show ?case using Cons(1)[of "tl q" "args s ! i"] Cons(2) by (cases q; cases s) auto qed auto lemma replace_at_hole_pos [simp]: "C\s\[hole_pos C \ t] = C\t\" by (induct C) auto subsection \Properties on @{const adapt_vars} and @{const adapt_vars_ctxt}\ lemma adapt_vars2: "adapt_vars (adapt_vars t) = adapt_vars t" by (induct t) (auto simp add: adapt_vars_def) lemma adapt_vars_simps[code, simp]: "adapt_vars (Fun f ts) = Fun f (map adapt_vars ts)" by (induct ts, auto simp: adapt_vars_def) lemma adapt_vars_reverse: "ground t \ adapt_vars t' = t \ adapt_vars t = t'" unfolding adapt_vars_def proof (induct t arbitrary: t') case (Fun f ts) then show ?case by (cases t') (auto simp add: map_idI) qed auto lemma ground_adapt_vars [simp]: "ground (adapt_vars t) = ground t" by (simp add: adapt_vars_def) lemma funas_term_adapt_vars[simp]: "funas_term (adapt_vars t) = funas_term t" by (simp add: adapt_vars_def) lemma adapt_vars_adapt_vars[simp]: fixes t :: "('f,'v)term" assumes g: "ground t" shows "adapt_vars (adapt_vars t :: ('f,'w)term) = t" proof - let ?t' = "adapt_vars t :: ('f,'w)term" have gt': "ground ?t'" using g by auto from adapt_vars_reverse[OF gt', of t] show ?thesis by blast qed lemma adapt_vars_inj: assumes "adapt_vars x = adapt_vars y" "ground x" "ground y" shows "x = y" using adapt_vars_adapt_vars assms by metis lemma adapt_vars_ctxt_simps[simp, code]: "adapt_vars_ctxt (More f bef C aft) = More f (map adapt_vars bef) (adapt_vars_ctxt C) (map adapt_vars aft)" "adapt_vars_ctxt Hole = Hole" unfolding adapt_vars_ctxt_def adapt_vars_def by auto lemma adapt_vars_ctxt[simp]: "adapt_vars (C \ t \ ) = (adapt_vars_ctxt C) \ adapt_vars t \" by (induct C, auto) lemma adapt_vars_subst[simp]: "adapt_vars (l \ \) = l \ (\ x. adapt_vars (\ x))" unfolding adapt_vars_def by (induct l) auto lemma adapt_vars_gr_map_vars [simp]: "ground t \ map_vars_term f t = adapt_vars t" by (induct t) auto lemma adapt_vars_gr_ctxt_of_map_vars [simp]: "ground_ctxt C \ map_vars_ctxt f C = adapt_vars_ctxt C" by (induct C) auto subsubsection \Equality on ground terms/contexts by positions and symbols\ lemma fun_at_def': "fun_at t p = (if p \ poss t then (case t |_ p of Var x \ Some (Inr x) | Fun f ts \ Some (Inl f)) else None)" by (induct t p rule: fun_at.induct) auto lemma fun_at_None_nposs_iff: "fun_at t p = None \ p \ poss t" by (auto simp: fun_at_def') (meson term.case_eq_if) lemma eq_term_by_poss_fun_at: assumes "poss s = poss t" "\p. p \ poss s \ fun_at s p = fun_at t p" shows "s = t" using assms proof (induct s arbitrary: t) case (Var x) then show ?case by (cases t) simp_all next case (Fun f ss) note Fun' = this show ?case proof (cases t) case (Var x) show ?thesis using Fun'(3)[of "[]"] by (simp add: Var) next case (Fun g ts) have *: "length ss = length ts" using Fun'(3) arg_cong[OF Fun'(2), of "\P. card {i |i p. i # p \ P}"] by (auto simp: Fun exI[of "\x. x \ poss _", OF Nil_in_poss]) then have "i < length ss \ poss (ss ! i) = poss (ts ! i)" for i using arg_cong[OF Fun'(2), of "\P. {p. i # p \ P}"] by (auto simp: Fun) then show ?thesis using * Fun'(2) Fun'(3)[of "[]"] Fun'(3)[of "_ # _ :: pos"] by (auto simp: Fun intro!: nth_equalityI Fun'(1)[OF nth_mem, of n "ts ! n" for n]) qed qed lemma eq_ctxt_at_pos_by_poss: assumes "p \ poss s" "p \ poss t" and "\ q. \ (p \\<^sub>p q) \ q \ poss s \ q \ poss t" and "(\ q. q \ poss s \ \ (p \\<^sub>p q) \ fun_at s q = fun_at t q)" shows "ctxt_at_pos s p = ctxt_at_pos t p" using assms proof (induct p arbitrary: s t) case (Cons i p) from Cons(2, 3) Cons(4, 5)[of "[]"] obtain f ss ts where [simp]: "s = Fun f ss" "t = Fun f ts" by (cases s; cases t) auto have flt: "j < i \ j # q \ poss s \ fun_at s (j # q) = fun_at t (j # q)" for j q by (intro Cons(5)) auto have fgt: "i < j \ j # q \ poss s \ fun_at s (j # q) = fun_at t (j # q)" for j q by (intro Cons(5)) auto have lt: "j < i \ j # q \ poss s \ j # q \ poss t" for j q by (intro Cons(4)) auto have gt: "i < j \ j # q \ poss s \ j # q \ poss t" for j q by (intro Cons(4)) auto from this[of _ "[]"] have "i < j \ j < length ss \ j < length ts" for j by auto from this Cons(2, 3) have l: "length ss = length ts" by auto (meson nat_neq_iff) have "ctxt_at_pos (ss ! i) p = ctxt_at_pos (ts ! i) p" using Cons(2, 3) Cons(4-)[of "i # q" for q] by (intro Cons(1)[of "ss ! i" "ts ! i"]) auto moreover have "take i ss = take i ts" using l lt Cons(2, 3) flt by (intro nth_equalityI) (auto intro!: eq_term_by_poss_fun_at) moreover have "drop (Suc i) ss = drop (Suc i) ts" using l Cons(2, 3) fgt gt[of "Suc i + j" for j] by (intro nth_equalityI) (auto simp: nth_map intro!: eq_term_by_poss_fun_at, fastforce+) ultimately show ?case by auto qed auto subsection \Misc\ lemma fun_at_hole_pos_ctxt_apply [simp]: "fun_at C\t\ (hole_pos C) = fun_at t []" by (induct C) auto lemma vars_term_ctxt_apply [simp]: "vars_term C\t\ = vars_ctxt C \ vars_term t" by (induct C arbitrary: t) auto lemma map_vars_term_ctxt_apply: "map_vars_term f C\t\ = (map_vars_ctxt f C)\map_vars_term f t\" by (induct C) auto lemma map_term_replace_at_dist: "p \ poss s \ (map_term f g s)[p \ (map_term f g t)] = map_term f g (s[p \ t])" proof (induct p arbitrary: s) case (Cons i p) then show ?case by (cases s) (auto simp: nth_list_update intro!: nth_equalityI) qed auto end