# HG changeset patch # User nipkow # Date 1464523848 -7200 # Node ID 3413b1cf30cd651caafc104381712da27f75653a # Parent d4f459eb7ed044715abc2106885050acfda16193 added subtheory of longest common prefix diff -r d4f459eb7ed0 -r 3413b1cf30cd NEWS --- a/NEWS Fri May 27 23:58:24 2016 +0200 +++ b/NEWS Sun May 29 14:10:48 2016 +0200 @@ -227,10 +227,11 @@ for polynomials over factorial rings. INCOMPATIBILITY. * Library/Sublist.thy: added function "prefixes" and renamed - prefixeq -> prefix - prefix -> strict_prefix - suffixeq -> suffix - suffix -> strict_suffix + prefixeq -> prefix + prefix -> strict_prefix + suffixeq -> suffix + suffix -> strict_suffix + Added theory of longest common prefixes. * Dropped various legacy fact bindings, whose replacements are often of a more general type also: diff -r d4f459eb7ed0 -r 3413b1cf30cd src/HOL/Library/Sublist.thy --- a/src/HOL/Library/Sublist.thy Fri May 27 23:58:24 2016 +0200 +++ b/src/HOL/Library/Sublist.thy Sun May 29 14:10:48 2016 +0200 @@ -127,6 +127,10 @@ "prefix (xs\<^sub>1::'a list) ys \ prefix xs\<^sub>2 ys \ prefix xs\<^sub>1 xs\<^sub>2 \ prefix xs\<^sub>2 xs\<^sub>1" unfolding prefix_def by (force simp: append_eq_append_conv2) +lemma prefix_length_prefix: + "prefix ps xs \ prefix qs xs \ length ps \ length qs \ prefix ps qs" +by (auto simp: prefix_def) (metis append_Nil2 append_eq_append_conv_if) + lemma set_mono_prefix: "prefix xs ys \ set xs \ set ys" by (auto simp add: prefix_def) @@ -226,6 +230,128 @@ by (cases ys rule: rev_cases) auto +subsection \Longest Common Prefix\ + +definition Longest_common_prefix :: "'a list set \ 'a list" where +"Longest_common_prefix L = (GREATEST ps WRT length. \xs \ L. prefix ps xs)" + +lemma Longest_common_prefix_ex: "L \ {} \ + \ps. (\xs \ L. prefix ps xs) \ (\qs. (\xs \ L. prefix qs xs) \ size qs \ size ps)" + (is "_ \ \ps. ?P L ps") +proof(induction "LEAST n. \xs \L. n = length xs" arbitrary: L) + case 0 + have "[] : L" using "0.hyps" LeastI[of "\n. \xs\L. n = length xs"] \L \ {}\ + by auto + hence "?P L []" by(auto) + thus ?case .. +next + case (Suc n) + let ?EX = "\n. \xs\L. n = length xs" + obtain x xs where xxs: "x#xs \ L" "size xs = n" using Suc.prems Suc.hyps(2) + by(metis LeastI_ex[of ?EX] Suc_length_conv ex_in_conv) + hence "[] \ L" using Suc.hyps(2) by auto + show ?case + proof (cases "\xs \ L. \ys. xs = x#ys") + case True + let ?L = "{ys. x#ys \ L}" + have 1: "(LEAST n. \xs \ ?L. n = length xs) = n" + using xxs Suc.prems Suc.hyps(2) Least_le[of "?EX"] + by - (rule Least_equality, fastforce+) + have 2: "?L \ {}" using \x # xs \ L\ by auto + from Suc.hyps(1)[OF 1[symmetric] 2] obtain ps where IH: "?P ?L ps" .. + { fix qs + assume "\qs. (\xa. x # xa \ L \ prefix qs xa) \ length qs \ length ps" + and "\xs\L. prefix qs xs" + hence "length (tl qs) \ length ps" + by (metis Cons_prefix_Cons hd_Cons_tl list.sel(2) Nil_prefix) + hence "length qs \ Suc (length ps)" by auto + } + hence "?P L (x#ps)" using True IH by auto + thus ?thesis .. + next + case False + then obtain y ys where yys: "x\y" "y#ys \ L" using \[] \ L\ + by (auto) (metis list.exhaust) + have "\qs. (\xs\L. prefix qs xs) \ qs = []" using yys \x#xs \ L\ + by auto (metis Cons_prefix_Cons prefix_Cons) + hence "?P L []" by auto + thus ?thesis .. + qed +qed + +lemma Longest_common_prefix_unique: "L \ {} \ + \! ps. (\xs \ L. prefix ps xs) \ (\qs. (\xs \ L. prefix qs xs) \ size qs \ size ps)" +by(rule ex_ex1I[OF Longest_common_prefix_ex]; + meson equals0I prefix_length_prefix prefix_order.antisym) + +lemma Longest_common_prefix_eq: + "\ L \ {}; \xs \ L. prefix ps xs; + \qs. (\xs \ L. prefix qs xs) \ size qs \ size ps \ + \ Longest_common_prefix L = ps" +unfolding Longest_common_prefix_def GreatestM_def +by(rule some1_equality[OF Longest_common_prefix_unique]) auto + +lemma Longest_common_prefix_prefix: + "xs \ L \ prefix (Longest_common_prefix L) xs" +unfolding Longest_common_prefix_def GreatestM_def +by(rule someI2_ex[OF Longest_common_prefix_ex]) auto + +lemma Longest_common_prefix_longest: + "L \ {} \ \xs\L. prefix ps xs \ length ps \ length(Longest_common_prefix L)" +unfolding Longest_common_prefix_def GreatestM_def +by(rule someI2_ex[OF Longest_common_prefix_ex]) auto + +lemma Longest_common_prefix_max_prefix: + "L \ {} \ \xs\L. prefix ps xs \ prefix ps (Longest_common_prefix L)" +by(metis Longest_common_prefix_prefix Longest_common_prefix_longest + prefix_length_prefix ex_in_conv) + +lemma Longest_common_prefix_Nil: "[] \ L \ Longest_common_prefix L = []" +using Longest_common_prefix_prefix prefix_Nil by blast + +lemma Longest_common_prefix_image_Cons: "L \ {} \ + Longest_common_prefix (op # x ` L) = x # Longest_common_prefix L" +apply(rule Longest_common_prefix_eq) + apply(simp) + apply (simp add: Longest_common_prefix_prefix) +apply simp +by(metis Longest_common_prefix_longest[of L] Cons_prefix_Cons Nitpick.size_list_simp(2) + Suc_le_mono hd_Cons_tl order.strict_implies_order zero_less_Suc) + +lemma Longest_common_prefix_eq_Cons: assumes "L \ {}" "[] \ L" "\xs\L. hd xs = x" +shows "Longest_common_prefix L = x # Longest_common_prefix {ys. x#ys \ L}" +proof - + have "L = op # x ` {ys. x#ys \ L}" using assms(2,3) + by (auto simp: image_def)(metis hd_Cons_tl) + thus ?thesis + by (metis Longest_common_prefix_image_Cons image_is_empty assms(1)) +qed + +lemma Longest_common_prefix_eq_Nil: + "\x#ys \ L; y#zs \ L; x \ y \ \ Longest_common_prefix L = []" +by (metis Longest_common_prefix_prefix list.inject prefix_Cons) + + +fun longest_common_prefix :: "'a list \ 'a list \ 'a list" where +"longest_common_prefix (x#xs) (y#ys) = + (if x=y then x # longest_common_prefix xs ys else [])" | +"longest_common_prefix _ _ = []" + +lemma longest_common_prefix_prefix1: + "prefix (longest_common_prefix xs ys) xs" +by(induction xs ys rule: longest_common_prefix.induct) auto + +lemma longest_common_prefix_prefix2: + "prefix (longest_common_prefix xs ys) ys" +by(induction xs ys rule: longest_common_prefix.induct) auto + +lemma longest_common_prefix_max_prefix: + "\ prefix ps xs; prefix ps ys \ + \ prefix ps (longest_common_prefix xs ys)" +by(induction xs ys arbitrary: ps rule: longest_common_prefix.induct) + (auto simp: prefix_Cons) + + subsection \Parallel lists\ definition parallel :: "'a list \ 'a list \ bool" (infixl "\" 50) diff -r d4f459eb7ed0 -r 3413b1cf30cd src/HOL/List.thy --- a/src/HOL/List.thy Fri May 27 23:58:24 2016 +0200 +++ b/src/HOL/List.thy Sun May 29 14:10:48 2016 +0200 @@ -1002,6 +1002,12 @@ (ys = [] & zs = x#xs | (EX ys'. ys = x#ys' & ys'@zs = xs))" by(cases ys) auto +lemma longest_common_prefix: + "\ps xs' ys'. xs = ps @ xs' \ ys = ps @ ys' + \ (xs' = [] \ ys' = [] \ hd xs' \ hd ys')" +by (induct xs ys rule: list_induct2') + (blast, blast, blast, + metis (no_types, hide_lams) append_Cons append_Nil list.sel(1)) text \Trivial rules for solving \@\-equations automatically.\ @@ -1961,6 +1967,12 @@ "xs @ [x] = ys \ (ys \ [] & butlast ys = xs & last ys = x)" by fastforce +corollary longest_common_suffix: + "\ss xs' ys'. xs = xs' @ ss \ ys = ys' @ ss + \ (xs' = [] \ ys' = [] \ last xs' \ last ys')" +using longest_common_prefix[of "rev xs" "rev ys"] +unfolding rev_swap rev_append by (metis last_rev rev_is_Nil_conv) + subsubsection \@{const take} and @{const drop}\