diff --git a/src/HOL/Library/Sublist.thy b/src/HOL/Library/Sublist.thy
--- a/src/HOL/Library/Sublist.thy
+++ b/src/HOL/Library/Sublist.thy
@@ -1,1497 +1,1503 @@
(* Title: HOL/Library/Sublist.thy
Author: Tobias Nipkow and Markus Wenzel, TU München
Author: Christian Sternagel, JAIST
Author: Manuel Eberl, TU München
*)
section \List prefixes, suffixes, and homeomorphic embedding\
theory Sublist
imports Main
begin
subsection \Prefix order on lists\
definition prefix :: "'a list \ 'a list \ bool"
where "prefix xs ys \ (\zs. ys = xs @ zs)"
definition strict_prefix :: "'a list \ 'a list \ bool"
where "strict_prefix xs ys \ prefix xs ys \ xs \ ys"
interpretation prefix_order: order prefix strict_prefix
by standard (auto simp: prefix_def strict_prefix_def)
interpretation prefix_bot: order_bot Nil prefix strict_prefix
by standard (simp add: prefix_def)
lemma prefixI [intro?]: "ys = xs @ zs \ prefix xs ys"
unfolding prefix_def by blast
lemma prefixE [elim?]:
assumes "prefix xs ys"
obtains zs where "ys = xs @ zs"
using assms unfolding prefix_def by blast
lemma strict_prefixI' [intro?]: "ys = xs @ z # zs \ strict_prefix xs ys"
unfolding strict_prefix_def prefix_def by blast
lemma strict_prefixE' [elim?]:
assumes "strict_prefix xs ys"
obtains z zs where "ys = xs @ z # zs"
proof -
from \strict_prefix xs ys\ obtain us where "ys = xs @ us" and "xs \ ys"
unfolding strict_prefix_def prefix_def by blast
with that show ?thesis by (auto simp add: neq_Nil_conv)
qed
(* FIXME rm *)
lemma strict_prefixI [intro?]: "prefix xs ys \ xs \ ys \ strict_prefix xs ys"
by(fact prefix_order.le_neq_trans)
lemma strict_prefixE [elim?]:
fixes xs ys :: "'a list"
assumes "strict_prefix xs ys"
obtains "prefix xs ys" and "xs \ ys"
using assms unfolding strict_prefix_def by blast
subsection \Basic properties of prefixes\
(* FIXME rm *)
theorem Nil_prefix [simp]: "prefix [] xs"
by (fact prefix_bot.bot_least)
(* FIXME rm *)
theorem prefix_Nil [simp]: "(prefix xs []) = (xs = [])"
by (fact prefix_bot.bot_unique)
lemma prefix_snoc [simp]: "prefix xs (ys @ [y]) \ xs = ys @ [y] \ prefix xs ys"
proof
assume "prefix xs (ys @ [y])"
then obtain zs where zs: "ys @ [y] = xs @ zs" ..
show "xs = ys @ [y] \ prefix xs ys"
by (metis append_Nil2 butlast_append butlast_snoc prefixI zs)
next
assume "xs = ys @ [y] \ prefix xs ys"
then show "prefix xs (ys @ [y])"
by (metis prefix_order.eq_iff prefix_order.order_trans prefixI)
qed
lemma Cons_prefix_Cons [simp]: "prefix (x # xs) (y # ys) = (x = y \ prefix xs ys)"
by (auto simp add: prefix_def)
lemma prefix_code [code]:
"prefix [] xs \ True"
"prefix (x # xs) [] \ False"
"prefix (x # xs) (y # ys) \ x = y \ prefix xs ys"
by simp_all
lemma same_prefix_prefix [simp]: "prefix (xs @ ys) (xs @ zs) = prefix ys zs"
by (induct xs) simp_all
lemma same_prefix_nil [simp]: "prefix (xs @ ys) xs = (ys = [])"
by (metis append_Nil2 append_self_conv prefix_order.eq_iff prefixI)
lemma prefix_prefix [simp]: "prefix xs ys \ prefix xs (ys @ zs)"
unfolding prefix_def by fastforce
lemma append_prefixD: "prefix (xs @ ys) zs \ prefix xs zs"
by (auto simp add: prefix_def)
theorem prefix_Cons: "prefix xs (y # ys) = (xs = [] \ (\zs. xs = y # zs \ prefix zs ys))"
by (cases xs) (auto simp add: prefix_def)
theorem prefix_append:
"prefix xs (ys @ zs) = (prefix xs ys \ (\us. xs = ys @ us \ prefix us zs))"
apply (induct zs rule: rev_induct)
apply force
apply (simp flip: append_assoc)
apply (metis append_eq_appendI)
done
lemma append_one_prefix:
"prefix xs ys \ length xs < length ys \ prefix (xs @ [ys ! length xs]) ys"
proof (unfold prefix_def)
assume a1: "\zs. ys = xs @ zs"
then obtain sk :: "'a list" where sk: "ys = xs @ sk" by fastforce
assume a2: "length xs < length ys"
have f1: "\v. ([]::'a list) @ v = v" using append_Nil2 by simp
have "[] \ sk" using a1 a2 sk less_not_refl by force
hence "\v. xs @ hd sk # v = ys" using sk by (metis hd_Cons_tl)
thus "\zs. ys = (xs @ [ys ! length xs]) @ zs" using f1 by fastforce
qed
theorem prefix_length_le: "prefix xs ys \ length xs \ length ys"
by (auto simp add: prefix_def)
lemma prefix_same_cases:
"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)
lemma take_is_prefix: "prefix (take n xs) xs"
unfolding prefix_def by (metis append_take_drop_id)
lemma takeWhile_is_prefix: "prefix (takeWhile P xs) xs"
unfolding prefix_def by (metis takeWhile_dropWhile_id)
lemma prefixeq_butlast: "prefix (butlast xs) xs"
by (simp add: butlast_conv_take take_is_prefix)
lemma prefix_map_rightE:
assumes "prefix xs (map f ys)"
shows "\xs'. prefix xs' ys \ xs = map f xs'"
proof -
define n where "n = length xs"
have "xs = take n (map f ys)"
using assms by (auto simp: prefix_def n_def)
thus ?thesis
by (intro exI[of _ "take n ys"]) (auto simp: take_map take_is_prefix)
qed
lemma map_mono_prefix: "prefix xs ys \ prefix (map f xs) (map f ys)"
by (auto simp: prefix_def)
lemma filter_mono_prefix: "prefix xs ys \ prefix (filter P xs) (filter P ys)"
by (auto simp: prefix_def)
lemma sorted_antimono_prefix: "prefix xs ys \ sorted ys \ sorted xs"
by (metis sorted_append prefix_def)
lemma prefix_length_less: "strict_prefix xs ys \ length xs < length ys"
by (auto simp: strict_prefix_def prefix_def)
lemma prefix_snocD: "prefix (xs@[x]) ys \ strict_prefix xs ys"
by (simp add: strict_prefixI' prefix_order.dual_order.strict_trans1)
lemma strict_prefix_simps [simp, code]:
"strict_prefix xs [] \ False"
"strict_prefix [] (x # xs) \ True"
"strict_prefix (x # xs) (y # ys) \ x = y \ strict_prefix xs ys"
by (simp_all add: strict_prefix_def cong: conj_cong)
lemma take_strict_prefix: "strict_prefix xs ys \ strict_prefix (take n xs) ys"
proof (induct n arbitrary: xs ys)
case 0
then show ?case by (cases ys) simp_all
next
case (Suc n)
then show ?case by (metis prefix_order.less_trans strict_prefixI take_is_prefix)
qed
lemma prefix_takeWhile:
assumes "prefix xs ys"
shows "prefix (takeWhile P xs) (takeWhile P ys)"
proof -
from assms obtain zs where ys: "ys = xs @ zs"
by (auto simp: prefix_def)
have "prefix (takeWhile P xs) (takeWhile P (xs @ zs))"
by (induction xs) auto
thus ?thesis by (simp add: ys)
qed
lemma prefix_dropWhile:
assumes "prefix xs ys"
shows "prefix (dropWhile P xs) (dropWhile P ys)"
proof -
from assms obtain zs where ys: "ys = xs @ zs"
by (auto simp: prefix_def)
have "prefix (dropWhile P xs) (dropWhile P (xs @ zs))"
by (induction xs) auto
thus ?thesis by (simp add: ys)
qed
lemma prefix_remdups_adj:
assumes "prefix xs ys"
shows "prefix (remdups_adj xs) (remdups_adj ys)"
using assms
proof (induction "length xs" arbitrary: xs ys rule: less_induct)
case (less xs)
show ?case
proof (cases xs)
case [simp]: (Cons x xs')
then obtain y ys' where [simp]: "ys = y # ys'"
using \prefix xs ys\ by (cases ys) auto
from less show ?thesis
by (auto simp: remdups_adj_Cons' less_Suc_eq_le length_dropWhile_le
intro!: less prefix_dropWhile)
qed auto
qed
lemma not_prefix_cases:
assumes pfx: "\ prefix ps ls"
obtains
(c1) "ps \ []" and "ls = []"
| (c2) a as x xs where "ps = a#as" and "ls = x#xs" and "x = a" and "\ prefix as xs"
| (c3) a as x xs where "ps = a#as" and "ls = x#xs" and "x \ a"
proof (cases ps)
case Nil
then show ?thesis using pfx by simp
next
case (Cons a as)
note c = \ps = a#as\
show ?thesis
proof (cases ls)
case Nil then show ?thesis by (metis append_Nil2 pfx c1 same_prefix_nil)
next
case (Cons x xs)
show ?thesis
proof (cases "x = a")
case True
have "\ prefix as xs" using pfx c Cons True by simp
with c Cons True show ?thesis by (rule c2)
next
case False
with c Cons show ?thesis by (rule c3)
qed
qed
qed
lemma not_prefix_induct [consumes 1, case_names Nil Neq Eq]:
assumes np: "\ prefix ps ls"
and base: "\x xs. P (x#xs) []"
and r1: "\x xs y ys. x \ y \ P (x#xs) (y#ys)"
and r2: "\x xs y ys. \ x = y; \ prefix xs ys; P xs ys \ \ P (x#xs) (y#ys)"
shows "P ps ls" using np
proof (induct ls arbitrary: ps)
case Nil
then show ?case
by (auto simp: neq_Nil_conv elim!: not_prefix_cases intro!: base)
next
case (Cons y ys)
then have npfx: "\ prefix ps (y # ys)" by simp
then obtain x xs where pv: "ps = x # xs"
by (rule not_prefix_cases) auto
show ?case by (metis Cons.hyps Cons_prefix_Cons npfx pv r1 r2)
qed
subsection \Prefixes\
primrec prefixes where
"prefixes [] = [[]]" |
"prefixes (x#xs) = [] # map ((#) x) (prefixes xs)"
lemma in_set_prefixes[simp]: "xs \ set (prefixes ys) \ prefix xs ys"
proof (induct xs arbitrary: ys)
case Nil
then show ?case by (cases ys) auto
next
case (Cons a xs)
then show ?case by (cases ys) auto
qed
lemma length_prefixes[simp]: "length (prefixes xs) = length xs+1"
by (induction xs) auto
lemma distinct_prefixes [intro]: "distinct (prefixes xs)"
by (induction xs) (auto simp: distinct_map)
lemma prefixes_snoc [simp]: "prefixes (xs@[x]) = prefixes xs @ [xs@[x]]"
by (induction xs) auto
lemma prefixes_not_Nil [simp]: "prefixes xs \ []"
by (cases xs) auto
lemma hd_prefixes [simp]: "hd (prefixes xs) = []"
by (cases xs) simp_all
lemma last_prefixes [simp]: "last (prefixes xs) = xs"
by (induction xs) (simp_all add: last_map)
lemma prefixes_append:
"prefixes (xs @ ys) = prefixes xs @ map (\ys'. xs @ ys') (tl (prefixes ys))"
proof (induction xs)
case Nil
thus ?case by (cases ys) auto
qed simp_all
lemma prefixes_eq_snoc:
"prefixes ys = xs @ [x] \
(ys = [] \ xs = [] \ (\z zs. ys = zs@[z] \ xs = prefixes zs)) \ x = ys"
by (cases ys rule: rev_cases) auto
lemma prefixes_tailrec [code]:
"prefixes xs = rev (snd (foldl (\(acc1, acc2) x. (x#acc1, rev (x#acc1)#acc2)) ([],[[]]) xs))"
proof -
have "foldl (\(acc1, acc2) x. (x#acc1, rev (x#acc1)#acc2)) (ys, rev ys # zs) xs =
(rev xs @ ys, rev (map (\as. rev ys @ as) (prefixes xs)) @ zs)" for ys zs
proof (induction xs arbitrary: ys zs)
case (Cons x xs ys zs)
from Cons.IH[of "x # ys" "rev ys # zs"]
show ?case by (simp add: o_def)
qed simp_all
from this [of "[]" "[]"] show ?thesis by simp
qed
lemma set_prefixes_eq: "set (prefixes xs) = {ys. prefix ys xs}"
by auto
lemma card_set_prefixes [simp]: "card (set (prefixes xs)) = Suc (length xs)"
by (subst distinct_card) auto
lemma set_prefixes_append:
"set (prefixes (xs @ ys)) = set (prefixes xs) \ {xs @ ys' |ys'. ys' \ set (prefixes ys)}"
by (subst prefixes_append, cases ys) auto
subsection \Longest Common Prefix\
definition Longest_common_prefix :: "'a list set \ 'a list" where
"Longest_common_prefix L = (ARG_MAX length ps. \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 arg_max_def is_arg_max_linorder
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 arg_max_def is_arg_max_linorder
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 arg_max_def is_arg_max_linorder
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 ((#) 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 = (#) 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)
where "(xs \ ys) = (\ prefix xs ys \ \ prefix ys xs)"
lemma parallelI [intro]: "\ prefix xs ys \ \ prefix ys xs \ xs \ ys"
unfolding parallel_def by blast
lemma parallelE [elim]:
assumes "xs \ ys"
obtains "\ prefix xs ys \ \ prefix ys xs"
using assms unfolding parallel_def by blast
theorem prefix_cases:
obtains "prefix xs ys" | "strict_prefix ys xs" | "xs \ ys"
unfolding parallel_def strict_prefix_def by blast
lemma parallel_cancel: "a#xs \ a#ys \ xs \ ys"
by (simp add: parallel_def)
theorem parallel_decomp:
"xs \ ys \ \as b bs c cs. b \ c \