Theory List_Extra
section ‹ Lists: extra functions and properties ›
theory List_Extra
imports
"HOL-Library.Sublist"
"HOL-Library.Monad_Syntax"
"HOL-Library.Prefix_Order"
"Optics.Lens_Instances"
begin
subsection ‹ Useful Abbreviations ›
abbreviation " xs ≡ foldr (+) xs 0"
subsection ‹ Sets ›
lemma [simp]: "set xs ∈ Fpow A ⟷ set xs ⊆ A"
by (auto simp add: Fpow_def)
lemma : "finite A ⟹ Fpow A = Pow A"
by (auto simp add: Pow_def Fpow_def finite_subset)
lemma [code]:
"Fpow (set []) = {{}}"
"Fpow (set (x # xs)) = (let A = Fpow (set xs) in A ∪ insert x ` A)"
by (simp_all add: Fpow_as_Pow Pow_set del: set_simps)
subsection ‹ Folds ›
context abel_semigroup
begin
lemma : "foldr (❙*) (xs @ [x]) k = (foldr (❙*) xs k) ❙* x"
by (induct xs, simp_all add: commute left_commute)
end
subsection ‹ List Lookup ›
text ‹
The following variant of the standard @{text nth} function returns @{text "⊥"} if the index is
out of range.
›
:: "'a list ⇒ nat ⇒ 'a option" ("_⟨_⟩⇩l" [90, 0] 91)
where
"[]⟨i⟩⇩l = None"
| "(x # xs)⟨i⟩⇩l = (case i of 0 ⇒ Some x | Suc j ⇒ xs ⟨j⟩⇩l)"
lemma [simp]: "i < length xs ⟹ (xs @ ys)⟨i⟩⇩l = xs⟨i⟩⇩l"
proof (induct xs arbitrary: i)
case Nil
then show ?case by simp
next
case (Cons a xs)
then show ?case
proof (cases i)
case 0
then show ?thesis by simp
next
case (Suc nat)
with Cons show ?thesis by simp
qed
qed
lemma [simp]: "length xs ≤ i ⟹ (xs @ ys)⟨i⟩⇩l = ys⟨i - length xs⟩⇩l"
proof (induct xs arbitrary: i)
case Nil
then show ?case by simp
next
case (Cons a xs)
then show ?case
proof (cases i)
case 0
with Cons show ?thesis
by fastforce
next
case (Suc nat)
with Cons show ?thesis by simp
qed
qed
subsection ‹ Extra List Theorems ›
subsubsection ‹ Map ›
lemma :
"map (nth (x # xs)) [Suc m..<n] = map (nth xs) [m..<n - 1]"
proof -
have "nth xs = nth (x # xs) ∘ Suc"
by auto
hence "map (nth xs) [m..<n - 1] = map (nth (x # xs) ∘ Suc) [m..<n - 1]"
by simp
also have "... = map (nth (x # xs)) (map Suc [m..<n - 1])"
by simp
also have "... = map (nth (x # xs)) [Suc m..<n]"
by (metis Suc_diff_1 le_0_eq length_upt list.simps(8) list.size(3) map_Suc_upt not_less upt_0)
finally show ?thesis ..
qed
subsubsection ‹ Sorted Lists ›
lemma [simp]: "⟦ x ∈ set xs; sorted xs ⟧ ⟹ x ≤ last xs"
by (induct xs, auto)
lemma :
assumes "xs ≤ ys" "sorted ys"
shows "sorted xs"
proof -
obtain zs where "ys = xs @ zs"
using Prefix_Order.prefixE assms(1) by auto
thus ?thesis
using assms(2) sorted_append by blast
qed
lemma : "⟦ sorted xs; mono f ⟧ ⟹ sorted (map f xs)"
by (simp add: monoD sorted_iff_nth_mono)
lemma [intro]: "⟦ sorted (xs); distinct(xs) ⟧ ⟹ (∀ i<length xs - 1. xs!i < xs!(i + 1))"
apply (induct xs)
apply (simp_all)
apply (metis (no_types, opaque_lifting) Suc_leI Suc_less_eq Suc_pred gr0_conv_Suc not_le not_less_iff_gr_or_eq nth_Cons_Suc nth_mem nth_non_equal_first_eq)
done
text ‹ The concatenation of two lists is sorted provided (1) both the lists are sorted, and (2)
the final and first elements are ordered. ›
lemma :
"sorted(xs@ys) = (sorted xs ∧ sorted ys ∧ (xs ≠ [] ∧ ys ≠ [] ⟶ xs!(length xs - 1) ≤ ys!0))"
proof -
have "⋀x y. ⟦ sorted xs; sorted ys; xs ! (length xs - Suc 0) ≤ ys ! 0 ⟧ ⟹ x ∈ set xs ⟹ y ∈ set ys ⟹ x ≤ y"
proof -
fix x y
assume "sorted xs" "sorted ys" "xs ! (length xs - Suc 0) ≤ ys ! 0" "x ∈ set xs" "y ∈ set ys"
moreover then obtain i j where i: "x = xs!i" "i < length xs" and j: "y = ys!j" "j < length ys"
by (auto simp add: in_set_conv_nth)
moreover have "xs ! i ≤ xs!(length xs - 1)"
by (metis One_nat_def Suc_diff_Suc Suc_leI Suc_le_mono ‹i < length xs› ‹sorted xs› diff_less diff_zero gr_implies_not_zero nat.simps(3) sorted_iff_nth_mono zero_less_iff_neq_zero)
moreover have "ys!0 ≤ ys ! j"
by (simp add: calculation(2) calculation(9) sorted_nth_mono)
ultimately have "xs ! i ≤ ys ! j"
by (metis One_nat_def dual_order.trans)
thus "x ≤ y"
by (simp add: i j)
qed
thus ?thesis
by (auto simp add: sorted_append)
qed
text ‹ Is the given list a permutation of the given set? ›
:: "('a::ord) set ⇒ 'a list ⇒ bool" where
"is_sorted_list_of_set A xs = ((∀ i<length(xs) - 1. xs!i < xs!(i + 1)) ∧ set(xs) = A)"
lemma :
assumes "is_sorted_list_of_set A xs"
shows "sorted(xs)" and "distinct(xs)"
using assms proof (induct xs arbitrary: A)
show "sorted []"
by auto
next
show "distinct []"
by auto
next
fix A :: "'a set"
case (Cons x xs) note hyps = this
assume isl: "is_sorted_list_of_set A (x # xs)"
hence srt: "(∀i<length xs - Suc 0. xs ! i < xs ! Suc i)"
using less_diff_conv by (auto simp add: is_sorted_list_of_set_def)
with hyps(1) have srtd: "sorted xs"
by (simp add: is_sorted_list_of_set_def)
with isl show "sorted (x # xs)"
apply (simp_all add: is_sorted_list_of_set_def)
apply (metis (mono_tags, lifting) all_nth_imp_all_set less_le_trans linorder_not_less not_less_iff_gr_or_eq nth_Cons_0 sorted_iff_nth_mono zero_order(3))
done
from srt hyps(2) have "distinct xs"
by (simp add: is_sorted_list_of_set_def)
with isl show "distinct (x # xs)"
proof -
have "(∀n. ¬ n < length (x # xs) - 1 ∨ (x # xs) ! n < (x # xs) ! (n + 1)) ∧ set (x # xs) = A"
by (meson ‹is_sorted_list_of_set A (x # xs)› is_sorted_list_of_set_def)
then show ?thesis
by (metis ‹distinct xs› add.commute add_diff_cancel_left' distinct.simps(2) leD length_Cons length_greater_0_conv length_pos_if_in_set less_le nth_Cons_0 nth_Cons_Suc plus_1_eq_Suc set_ConsD sorted_wrt.elims(2) srtd)
qed
qed
lemma :
"is_sorted_list_of_set A xs ⟷ sorted (xs) ∧ distinct (xs) ∧ set(xs) = A"
by (metis is_sorted_list_of_set_def sorted_distinct sorted_is_sorted_list_of_set(1,2))
:: "('a::ord) set ⇒ 'a list" where
"sorted_list_of_set_alt A =
(if (A = {}) then [] else (THE xs. is_sorted_list_of_set A xs))"
lemma :
"finite A ⟹ is_sorted_list_of_set A (sorted_list_of_set A)"
using sorted_distinct sorted_list_of_set(2) by (fastforce simp add: is_sorted_list_of_set_def)
lemma :
"finite A ⟹ sorted_list_of_set(A) = (THE xs. sorted(xs) ∧ distinct(xs) ∧ set xs = A)"
by (metis (mono_tags, lifting) sorted_list_of_set.distinct_sorted_key_list_of_set
sorted_list_of_set.idem_if_sorted_distinct sorted_list_of_set.set_sorted_key_list_of_set
sorted_list_of_set.sorted_sorted_key_list_of_set the_equality)
lemma [simp]:
"finite A ⟹ sorted_list_of_set_alt(A) = sorted_list_of_set(A)"
by (metis is_sorted_list_of_set is_sorted_list_of_set_def sorted_is_sorted_list_of_set(1,2)
sorted_list_of_set.idem_if_sorted_distinct sorted_list_of_set_alt_def sorted_list_of_set_eq_Nil_iff
the_equality)
text ‹ Sorting lists according to a relation ›
:: "'a rel ⇒ 'a set ⇒ 'a list ⇒ bool" where
"is_sorted_list_of_set_by R A xs = ((∀ i<length(xs) - 1. (xs!i, xs!(i + 1)) ∈ R) ∧ set(xs) = A)"
:: "'a rel ⇒ 'a set ⇒ 'a list" where
"sorted_list_of_set_by R A = (THE xs. is_sorted_list_of_set_by R A xs)"
:: "'a rel ⇒ 'a set rel" where
"fin_set_lexord R = {(A, B). finite A ∧ finite B ∧
(∃ xs ys. is_sorted_list_of_set_by R A xs ∧ is_sorted_list_of_set_by R B ys
∧ (xs, ys) ∈ lexord R)}"
lemma :
"⟦ R ⊆ S; is_sorted_list_of_set_by R A xs ⟧ ⟹ is_sorted_list_of_set_by S A xs"
by (auto simp add: is_sorted_list_of_set_by_def)
lemma :
"⟦ (⋀ x y. f x y ⟶ g x y); (xs, ys) ∈ lexord {(x, y). f x y} ⟧ ⟹ (xs, ys) ∈ lexord {(x, y). g x y}"
by (metis case_prodD case_prodI lexord_take_index_conv mem_Collect_eq)
lemma [mono]:
"(⋀ x y. f x y ⟶ g x y) ⟹ (xs, ys) ∈ fin_set_lexord {(x, y). f x y} ⟶ (xs, ys) ∈ fin_set_lexord {(x, y). g x y}"
proof
assume
fin: "(xs, ys) ∈ fin_set_lexord {(x, y). f x y}" and
hyp: "(⋀ x y. f x y ⟶ g x y)"
from fin have "finite xs" "finite ys"
using fin_set_lexord_def by fastforce+
with fin hyp show "(xs, ys) ∈ fin_set_lexord {(x, y). g x y}"
by (simp add: fin_set_lexord_def, metis case_prod_conv is_sorted_list_of_set_by_def lexord_mono' mem_Collect_eq)
qed
:: "'a set ⇒ 'a list set" where
"distincts A = {xs ∈ lists A. distinct(xs)}"
lemma :
"⟦ x ∈ set xs; x ≠ hd(xs) ⟧ ⟹ x ∈ set(tl(xs))"
by (metis in_set_insert insert_Nil list.collapse list.distinct(2) set_ConsD)
subsubsection ‹ List Update ›
lemma :
fixes xs :: "'a::ring list"
assumes "i < length xs"
shows "list_sum (xs[i := v]) = list_sum xs - xs ! i + v"
using assms proof (induct xs arbitrary: i)
case Nil
then show ?case by (simp)
next
case (Cons a xs)
then show ?case
proof (cases i)
case 0
thus ?thesis
by (simp add: add.commute)
next
case (Suc i')
with Cons show ?thesis
by (auto)
qed
qed
subsubsection ‹ Drop While and Take While ›
lemma :
"⟦ sorted xs; x ∈ set (dropWhile (λ x. x ≤ n) xs) ⟧ ⟹ x > n"
proof (induct xs)
case Nil
then show ?case
by simp
next
case (Cons a xs)
then show ?case
proof (cases "a ≤ n")
case True
with Cons show ?thesis by simp
next
case False
with Cons show ?thesis
by force
qed
qed
lemma :
"sorted xs ⟹ set (dropWhile (λ x. x ≤ n) xs) = {x∈set xs. x > n}"
proof (induct xs)
case Nil
then show ?case by simp
next
case (Cons a xs)
hence "sorted xs"
using sorted_simps(2) by blast
with Cons show ?case
by force
qed
lemma :
"⟦ sorted I; x ∈ set I; x < n ⟧ ⟹ x ∈ set (takeWhile (λx. x < n) I)"
proof (induct I arbitrary: x)
case Nil thus ?case
by (simp)
next
case (Cons a I) thus ?case
by auto
qed
lemma : "⟦ sorted xs; i ≥ length (takeWhile (λ x. x ≤ n) xs); i < length xs ⟧ ⟹ n ≤ xs ! i"
proof (induct xs arbitrary: i)
case Nil
then show ?case by simp
next
case (Cons a xs)
then show ?case
by (meson dual_order.trans nle_le nth_length_takeWhile order_le_less_trans sorted_iff_nth_mono)
qed
lemma :
"⟦ a ∈ set xs; ¬ P a ⟧ ⟹ length (takeWhile P xs) < length xs"
by (metis in_set_conv_nth length_takeWhile_le nat_neq_iff not_less set_takeWhileD takeWhile_nth)
lemma :
"⟦ sorted xs; distinct xs; (∃ a ∈ set xs. a ≥ n) ⟧ ⟹ xs ! length (takeWhile (λx. x < n) xs) ≥ n"
by (induct xs, auto)
subsubsection ‹ Last and But Last ›
lemma :
assumes "length ys > 0"
shows "butlast (xs @ ys) = xs @ (butlast ys)"
using assms by (metis butlast_append length_greater_0_conv)
lemma :
assumes "length ys = 0"
shows "butlast (xs @ ys) = butlast xs"
using assms by (metis append_Nil2 length_0_conv)
lemma :
shows "butlast [e] = []"
by (metis butlast.simps(2))
lemma :
shows "last [e] = e"
by (metis last.simps)
lemma :
assumes "length t = 0"
shows "last (s @ t) = last s"
by (metis append_Nil2 assms length_0_conv)
lemma :
assumes "length t > 0"
shows "last (s @ t) = last t"
by (metis assms last_append length_greater_0_conv)
subsubsection ‹ Prefixes and Strict Prefixes ›
lemma :
"⟦ length xs = length ys; prefix xs ys ⟧ ⟹ xs = ys"
by (metis not_equal_is_parallel parallel_def)
lemma [elim]:
assumes "prefix (x # xs) ys"
obtains ys' where "ys = x # ys'" "prefix xs ys'"
using assms
by (metis append_Cons prefix_def)
lemma :
"⟦ inj_on f (set xs ∪ set ys); prefix (map f xs) (map f ys) ⟧ ⟹
prefix xs ys"
proof (induct xs arbitrary:ys)
case Nil
then show ?case
by simp
next
case (Cons x xs)
obtain ys' where "map f ys = f x # ys'" "prefix (map f xs) ys'"
using Cons.prems(2) by auto
with Cons show ?case
by (simp, safe, metis Diff_iff Sublist.Cons_prefix_Cons Un_insert_right empty_iff image_eqI inj_on_insert insert_iff list.simps(15))
qed
lemma [simp]:
"inj_on f (set xs ∪ set ys) ⟹
prefix (map f xs) (map f ys) ⟷ prefix xs ys"
using map_mono_prefix prefix_map_inj by blast
lemma [elim]:
assumes "strict_prefix (x # xs) ys"
obtains ys' where "ys = x # ys'" "strict_prefix xs ys'"
using assms
by (metis Sublist.strict_prefixE' Sublist.strict_prefixI' append_Cons)
lemma :
"⟦ inj_on f (set xs ∪ set ys); strict_prefix (map f xs) (map f ys) ⟧ ⟹
strict_prefix xs ys"
apply (induct xs arbitrary:ys)
apply (simp_all)
using prefix_bot.not_eq_extremum apply fastforce
apply (erule strict_prefix_Cons_elim)
apply (safe)
apply (metis Diff_iff Sublist.strict_prefix_simps(3) Un_insert_right empty_iff imageI inj_on_insert insert_iff
list.simps(15))
done
lemma [simp]:
"inj_on f (set xs ∪ set ys) ⟹
strict_prefix (map f xs) (map f ys) ⟷ strict_prefix xs ys"
by (simp add: inj_on_map_eq_map strict_prefix_def)
lemma :
"⟦ drop (length xs) ys = zs; prefix xs ys ⟧
⟹ ys = xs @ zs"
by (metis append_eq_conv_conj prefix_def)
lemma [dest]: "x @ y ≤ z ⟹ x ≤ z"
using append_prefixD less_eq_list_def by blast
lemma :
assumes "strict_prefix xs ys" and "xs ≠ []"
shows "ys ≠ []"
using Sublist.strict_prefix_simps(1) assms(1) by blast
lemma :
assumes "strict_prefix xs ys" and "xs ≠ []"
shows "length ys > 0"
using assms prefix_not_empty by auto
lemma :
assumes "strict_prefix (butlast xs) ys"
shows "ys ≠ []"
using assms prefix_not_empty_length_gt_zero by fastforce
lemma prefix_and_concat_prefix_is_concat_prefix:
assumes "prefix s t" "prefix (e @ t) u"
shows "prefix (e @ s) u"
using Sublist.same_prefix_prefix assms(1) assms(2) prefix_order.dual_order.trans by blast
lemma :
"prefix s t ⟷ (∃xs . s @ xs = t)"
using prefix_def by auto
lemma :
"strict_prefix s t ⟷ (∃xs . s @ xs = t ∧ (length xs) > 0)"
using prefix_def strict_prefix_def by auto
lemma :
assumes "length s = length t" and "strict_prefix (butlast s) t"
shows "strict_prefix (butlast s) t ⟷ (butlast s) = (butlast t)"
by (metis append_butlast_last_id append_eq_append_conv assms(1) assms(2) length_0_conv length_butlast strict_prefix_eq_exists)
lemma butlast_eq_if_eq_length_and_prefix:
assumes "length s > 0" "length z > 0"
"length s = length z" "strict_prefix (butlast s) t" "strict_prefix (butlast z) t"
shows "(butlast s) = (butlast z)"
using assms by (auto simp add:strict_prefix_eq_exists)
lemma :
assumes "prefix s t"
shows "length s ≤ length t"
using assms by (simp add: Sublist.prefix_length_le)
lemma :
assumes "prefix s t"
shows "¬ length t < length s"
using assms by (simp add: Sublist.prefix_length_le leD)
lemma prefix_and_eq_length_imp_eq_list:
assumes "prefix s t" and "length t = length s"
shows "s=t"
using assms by (simp add: prefix_length_eq)
lemma :
assumes "length s > 0" "strict_prefix (butlast s) t"
shows "¬ (length t < length s)"
using assms prefix_length_less by fastforce
lemma :
assumes "length s > 0" and "strict_prefix (butlast s) t"
shows "(¬ (length s < length t)) = (length s = length t)"
proof -
have "(¬ (length s < length t)) = ((length t < length s) ∨ (length s = length t))"
by (metis not_less_iff_gr_or_eq)
also have "... = (length s = length t)"
using assms
by (simp add:butlast_prefix_imp_length_not_gt)
finally show ?thesis .
qed
lemma :
"(prefix xs ys ⟷ (length xs ≤ length ys ∧ (∀ i<length xs. xs!i = ys!i)))"
apply (safe)
apply (simp add: prefix_imp_length_lteq)
apply (metis nth_append prefix_def)
apply (metis nth_take_lemma order_refl take_all take_is_prefix)
done
lemma :
"(xs ≤ ys ⟷ (length xs ≤ length ys ∧ (∀ i<length xs. xs!i = ys!i)))"
by (simp add: less_eq_list_def list_prefix_iff)
text ‹ Greatest common prefix ›
:: "'a list ⇒ 'a list ⇒ 'a list" where
"gcp [] ys = []" |
"gcp (x # xs) (y # ys) = (if (x = y) then x # gcp xs ys else [])" |
"gcp _ _ = []"
lemma [simp]: "gcp xs [] = []"
by (induct xs, auto)
lemma [simp]: "gcp (xs @ ys) (xs @ zs) = xs @ gcp ys zs"
by (induct xs, auto)
lemma : "prefix (gcp xs ys) xs"
proof (induct xs arbitrary: ys)
case Nil
then show ?case by simp
next
case (Cons a xs)
then show ?case
proof (cases ys)
case Nil
then show ?thesis by simp
next
case (Cons a list)
then show ?thesis
by (simp add: Cons.hyps)
qed
qed
lemma : "prefix (gcp xs ys) ys"
proof (induct xs arbitrary: ys)
case Nil
then show ?case by simp
next
case (Cons a xs)
then show ?case
proof (cases ys)
case Nil
then show ?thesis by simp
next
case (Cons a list)
then show ?thesis
by (simp add: Cons.hyps)
qed
qed
prefix_semilattice: semilattice_inf gcp prefix strict_prefix
proof
fix xs ys :: "'a list"
show "prefix (gcp xs ys) xs"
proof (induct xs arbitrary: ys)
case Nil
then show ?case by simp
next
case (Cons a xs)
then show ?case
by (simp add: gcp_lb1)
qed
show "prefix (gcp xs ys) ys"
proof (induct xs arbitrary: ys)
case Nil
then show ?case by simp
next
case (Cons a xs)
then show ?case
by (simp add: gcp_lb2)
qed
next
fix xs ys zs :: "'a list"
assume "prefix xs ys" "prefix xs zs"
thus "prefix xs (gcp ys zs)"
by (simp add: prefix_def, auto)
qed
subsubsection ‹ Lexicographic Order ›
lemma :
assumes "(xs⇩1 @ ys⇩1, xs⇩2 @ ys⇩2) ∈ lexord R" "length(xs⇩1) = length(xs⇩2)"
shows "(xs⇩1, xs⇩2) ∈ lexord R ∨ (xs⇩1 = xs⇩2 ∧ (ys⇩1, ys⇩2) ∈ lexord R)"
using assms
proof (induct xs⇩2 arbitrary: xs⇩1)
case (Cons x⇩2 xs⇩2') note hyps = this
from hyps(3) obtain x⇩1 xs⇩1' where xs⇩1: "xs⇩1 = x⇩1 # xs⇩1'" "length(xs⇩1') = length(xs⇩2')"
by (simp, metis Suc_length_conv)
with hyps(2) have xcases: "(x⇩1, x⇩2) ∈ R ∨ (xs⇩1' @ ys⇩1, xs⇩2' @ ys⇩2) ∈ lexord R"
by (auto)
show ?case
proof (cases "(x⇩1, x⇩2) ∈ R")
case True with xs⇩1 show ?thesis
by (auto)
next
case False
with xcases have "(xs⇩1' @ ys⇩1, xs⇩2' @ ys⇩2) ∈ lexord R"
by (auto)
with hyps(1) xs⇩1 have dichot: "(xs⇩1', xs⇩2') ∈ lexord R ∨ (xs⇩1' = xs⇩2' ∧ (ys⇩1, ys⇩2) ∈ lexord R)"
by (auto)
have "x⇩1 = x⇩2"
using False hyps(2) xs⇩1(1) by auto
with dichot xs⇩1 show ?thesis
by (simp)
qed
next
case Nil thus ?case
by auto
qed
lemma :
"strict_prefix xs ys ⟹ (xs, ys) ∈ lexord R"
by (metis Sublist.strict_prefixE' lexord_append_rightI)
lemma :
assumes "trans R" "(xs, ys) ∈ lexord R" "strict_prefix xs' xs"
shows "(xs', ys) ∈ lexord R"
by (metis assms lexord_trans strict_prefix_lexord_rel)
lemma :
assumes "trans R" "(xs, ys) ∈ lexord R" "strict_prefix ys ys'"
shows "(xs, ys') ∈ lexord R"
by (metis assms lexord_trans strict_prefix_lexord_rel)
lemma :
assumes "(xs, ys) ∈ lexord R" "length xs = length ys"
shows "∃ i. (xs!i, ys!i) ∈ R ∧ i < length xs ∧ (∀ j<i. xs!j = ys!j)"
using assms proof (induct xs arbitrary: ys)
case (Cons x xs) note hyps = this
then obtain y ys' where ys: "ys = y # ys'" "length ys' = length xs"
by (metis Suc_length_conv)
show ?case
proof (cases "(x, y) ∈ R")
case True with ys show ?thesis
by force
next
case False
with ys hyps(2) have xy: "x = y" "(xs, ys') ∈ lexord R"
by auto
with hyps(1,3) ys obtain i where "(xs!i, ys'!i) ∈ R" "i < length xs" "(∀ j<i. xs!j = ys'!j)"
by force
with xy ys have "((x # xs) ! Suc i, ys ! Suc i) ∈ R ∧ Suc i < length (x # xs) ∧ (∀j<Suc i. (x # xs) ! j = ys ! j) "
by (auto simp add: less_Suc_eq_0_disj)
thus ?thesis
by blast
qed
next
case Nil thus ?case by (auto)
qed
lemma :
assumes "length xs > i" "length ys > i" "(xs!i, ys!i) ∈ R" "∀ j<i. xs!j = ys!j"
shows "(xs, ys) ∈ lexord R"
using assms proof (induct i arbitrary: xs ys)
case 0 thus ?case
by (simp, metis lexord_cons_cons list.exhaust nth_Cons_0)
next
case (Suc i) note hyps = this
then obtain x' y' xs' ys' where "xs = x' # xs'" "ys = y' # ys'"
by (metis Suc_length_conv Suc_lessE)
moreover with hyps(5) have "∀j<i. xs' ! j = ys' ! j"
by (auto)
ultimately show ?case using hyps
by (auto)
qed
subsection ‹ Distributed Concatenation ›
:: "('a ⇒ 'b ⇒ 'c) ⇒ ('a × 'b ⇒ 'c)" where
[simp]: "uncurry f = (λ(x, y). f x y)"
::
"'a list set ⇒ 'a list set ⇒ 'a list set" (infixr "⇧⌢" 100) where
"dist_concat ls1 ls2 = (uncurry (@) ` (ls1 × ls2))"
lemma [simp]:
"{} ⇧⌢ ys = {}"
by (simp add: dist_concat_def)
lemma [simp]:
"xs ⇧⌢ {} = {}"
by (simp add: dist_concat_def)
lemma [simp]:
"insert l ls1 ⇧⌢ ls2 = ((@) l ` ( ls2)) ∪ (ls1 ⇧⌢ ls2)"
by (auto simp add: dist_concat_def)
subsection ‹ List Domain and Range ›
abbreviation :: "'a list ⇒ nat set" ("dom⇩l") where
"seq_dom xs ≡ {0..<length xs}"
abbreviation (input) :: "'a list ⇒ 'a set" ("ran⇩l") where
"seq_ran xs ≡ set xs"
subsection ‹ Extracting List Elements ›
:: "nat set ⇒ 'a list ⇒ 'a list" (infix "↿⇩l" 80) where
"seq_extract A xs = nths xs A"
lemma [simp]: "A ↿⇩l [] = []"
by (simp add: seq_extract_def)
lemma :
"A ↿⇩l (x # xs) = (if 0 ∈ A then [x] else []) @ {j. Suc j ∈ A} ↿⇩l xs"
by (simp add: seq_extract_def nths_Cons)
lemma [simp]: "{} ↿⇩l xs = []"
by (simp add: seq_extract_def)
lemma [simp]: "{0..<length xs} ↿⇩l xs = xs"
unfolding list_eq_iff_nth_eq
by (auto simp add: seq_extract_def length_nths atLeast0LessThan)
lemma :
assumes "i ≤ length xs"
shows "{0..<i} ↿⇩l xs @ {i..<length xs} ↿⇩l xs = xs"
using assms
proof (induct xs arbitrary: i)
case Nil thus ?case by (simp add: seq_extract_def)
next
case (Cons x xs) note hyp = this
have "{j. Suc j < i} = {0..<i - 1}"
by (auto)
moreover have "{j. i ≤ Suc j ∧ j < length xs} = {i - 1..<length xs}"
by (auto)
ultimately show ?case
using hyp by (force simp add: seq_extract_def nths_Cons)
qed
lemma :
"A ↿⇩l (xs @ ys) = (A ↿⇩l xs) @ ({j. j + length xs ∈ A} ↿⇩l ys)"
by (simp add: seq_extract_def nths_append)
lemma : "A ↿⇩l xs = (A ∩ dom⇩l(xs)) ↿⇩l xs"
apply (simp add: seq_extract_def nths_def)
apply (metis (no_types, lifting) atLeastLessThan_iff filter_cong in_set_zip nth_mem set_upt)
done
lemma :
"A ∩ dom⇩l(xs) = {} ⟹ A ↿⇩l xs = []"
by (metis seq_extract_def seq_extract_range nths_empty)
lemma [simp]:
"length (A ↿⇩l xs) = card (A ∩ dom⇩l(xs))"
proof -
have "{i. i < length(xs) ∧ i ∈ A} = (A ∩ {0..<length(xs)})"
by (auto)
thus ?thesis
by (simp add: seq_extract_def length_nths)
qed
lemma :
assumes "m < n"
shows "{m..<n} ↿⇩l (x # xs) = (if (m = 0) then x # ({0..<n-1} ↿⇩l xs) else {m-1..<n-1} ↿⇩l xs)"
proof -
have "{j. Suc j < n} = {0..<n - Suc 0}"
by (auto)
moreover have "{j. m ≤ Suc j ∧ Suc j < n} = {m - Suc 0..<n - Suc 0}"
by (auto)
ultimately show ?thesis using assms
by (auto simp add: seq_extract_Cons)
qed
lemma :
assumes "i < length xs"
shows "{i} ↿⇩l xs = [xs ! i]"
using assms
apply (induct xs arbitrary: i)
apply (simp_all add: seq_extract_Cons)
apply safe
apply (rename_tac xs i)
apply (subgoal_tac "{j. Suc j = i} = {i - 1}")
apply (auto)
done
lemma :
assumes "m < n" "n ≤ length xs"
shows "{m..<n} ↿⇩l xs = map (nth xs) [m..<n]"
using assms proof (induct xs arbitrary: m n)
case Nil thus ?case by simp
next
case (Cons x xs)
have "[m..<n] = m # [m+1..<n]"
using Cons.prems(1) upt_eq_Cons_conv by blast
moreover have "map (nth (x # xs)) [Suc m..<n] = map (nth xs) [m..<n-1]"
by (simp add: map_nth_Cons_atLeastLessThan)
ultimately show ?case
using Cons upt_rec
by (auto simp add: seq_extract_Cons_atLeastLessThan)
qed
lemma :
"xs = ys @ zs ⟷ (∃ i≤length(xs). ys = {0..<i} ↿⇩l xs ∧ zs = {i..<length(xs)} ↿⇩l xs)"
proof
assume xs: "xs = ys @ zs"
moreover have "ys = {0..<length ys} ↿⇩l (ys @ zs)"
by (simp add: seq_extract_append)
moreover have "zs = {length ys..<length ys + length zs} ↿⇩l (ys @ zs)"
proof -
have "{length ys..<length ys + length zs} ∩ {0..<length ys} = {}"
by auto
moreover have s1: "{j. j < length zs} = {0..<length zs}"
by auto
ultimately show ?thesis
by (simp add: seq_extract_append seq_extract_out_of_range)
qed
ultimately show "(∃ i≤length(xs). ys = {0..<i} ↿⇩l xs ∧ zs = {i..<length(xs)} ↿⇩l xs)"
using le_iff_add by auto
next
assume "∃i≤length xs. ys = {0..<i} ↿⇩l xs ∧ zs = {i..<length xs} ↿⇩l xs"
thus "xs = ys @ zs"
by (auto simp add: seq_extract_split)
qed
subsection ‹ Filtering a list according to a set ›
:: "'a list ⇒ 'a set ⇒ 'a list" (infix "↾⇩l" 80) where
"seq_filter xs A = filter (λ x. x ∈ A) xs"
lemma [simp]:
"x ∈ cs ⟹ (x # xs) ↾⇩l cs = x # (xs ↾⇩l cs)"
by (simp add: seq_filter_def)
lemma [simp]:
"x ∉ cs ⟹ (x # xs) ↾⇩l cs = (xs ↾⇩l cs)"
by (simp add: seq_filter_def)
lemma [simp]: "[] ↾⇩l A = []"
by (simp add: seq_filter_def)
lemma [simp]: "xs ↾⇩l {} = []"
by (simp add: seq_filter_def)
lemma : "(xs @ ys) ↾⇩l A = (xs ↾⇩l A) @ (ys ↾⇩l A)"
by (simp add: seq_filter_def)
lemma [simp]: "xs ↾⇩l UNIV = xs"
by (simp add: seq_filter_def)
lemma [simp]: "(xs ↾⇩l A) ↾⇩l B = xs ↾⇩l (A ∩ B)"
by (simp add: seq_filter_def)
subsection ‹ Minus on lists ›
instantiation list :: (type) minus
begin
text ‹ We define list minus so that if the second list is not a prefix of the first, then an arbitrary
list longer than the combined length is produced. Thus we can always determined from the output
whether the minus is defined or not. ›
"xs - ys = (if (prefix ys xs) then drop (length ys) xs else [])"
..
end
lemma [simp]: "xs - xs = []"
by (simp add: minus_list_def)
lemma [simp]: "(xs @ ys) - xs = ys"
by (simp add: minus_list_def)
lemma [simp]: "xs - [] = xs"
by (simp add: minus_list_def)
lemma : "(s @ t) - (s @ z) = t - z"
by (simp add: minus_list_def)
lemma : "y ≤ x ⟹ length(x - y) = length(x) - length(y)"
by (simp add: less_eq_list_def minus_list_def)
lemma :
"xs ≤ ys ⟹ map f (ys - xs) = map f ys - map f xs"
by (simp add: drop_map less_eq_list_def map_mono_prefix minus_list_def)
lemma [simp]:
"[x] ≤ xs ⟹ (xs - [x]) = tl xs"
by (metis Prefix_Order.prefixE append.left_neutral append_minus list.sel(3) not_Cons_self2 tl_append2)
text ‹ Extra lemmas about @{term prefix} and @{term strict_prefix} ›
lemma :
assumes "prefix xs ys"
shows "xs @ (ys - xs) = ys"
using assms by (metis minus_list_def prefix_drop)
lemma :
assumes "prefix s t"
shows "(t - s) @ z = (t @ z) - s"
using assms by (simp add: Sublist.prefix_length_le minus_list_def)
lemma :
assumes "strict_prefix xs ys"
shows "ys - xs ≠ []"
using assms by (metis append_Nil2 prefix_concat_minus strict_prefix_def)
lemma :
assumes "prefix xs ys" and "xs ≠ ys"
shows "(ys - xs) ≠ []"
using assms by (simp add: strict_prefix_minus_not_empty)
lemma :
assumes "length s < length t" and "strict_prefix (butlast s) t" and "length s > 0"
shows "length (tl (t - (butlast s))) > 0"
using assms
by (metis Nitpick.size_list_simp(2) butlast_snoc hd_Cons_tl length_butlast length_greater_0_conv length_tl less_trans nat_neq_iff strict_prefix_minus_not_empty prefix_order.dual_order.strict_implies_order prefix_concat_minus)
lemma :
assumes "length t = length s" and "strict_prefix (butlast s) t"
shows "t - (butlast s) = [last t]"
using assms
by (metis append_butlast_last_id append_eq_append_conv butlast.simps(1) length_butlast less_numeral_extra(3) list.size(3) prefix_order.dual_order.strict_implies_order prefix_concat_minus prefix_length_less)
lemma :
assumes "length s > 0" "strict_prefix (butlast s) t" "length s < length t"
shows "last (tl (t - (butlast s))) = (last t)"
using assms by (metis last_append last_tl length_tl_list_minus_butlast_gt_zero less_numeral_extra(3) list.size(3) append_minus strict_prefix_eq_exists)
lemma :
assumes "strict_prefix (butlast s) t" and "length s > 0" and "length t > length s"
shows "tl (t - (butlast s)) ≠ []"
using assms length_tl_list_minus_butlast_gt_zero by fastforce
lemma :
assumes "strict_prefix (butlast s) t" and "length s > 0" and "length t = length s"
shows "tl (t - (butlast s)) = []"
using assms by (simp add: list_minus_butlast_eq_butlast_list)
lemma :
assumes "prefix (butlast u) s"
shows "(t @ s) - (t @ (butlast u)) = s - (butlast u)"
using assms by (metis append_assoc prefix_concat_minus append_minus)
lemma :
assumes "strict_prefix (butlast s) t" and "length s = length t"
shows "tl (t - (butlast s)) = []"
using assms by (metis list.sel(3) list_minus_butlast_eq_butlast_list)
lemma :
assumes "strict_prefix s t"
shows "length (tl (t-s)) = (length (t-s)) - 1"
by (auto)
lemma :
assumes "strict_prefix s t"
shows "length(t - s) = length(t) - length(s)"
using assms by (simp add: minus_list_def prefix_order.dual_order.strict_implies_order)
lemma : "length (ys - xs) ≤ length ys"
by (simp add: minus_list_def)
lemma : "⟦ xs ≤ ys; xs ≠ [] ⟧ ⟹ length (ys - xs) < length ys"
by (simp add: minus_list_def less_eq_list_def)
(metis diff_less length_greater_0_conv prefix_bot.extremum_uniqueI)
lemma [simp]: "ys ≤ xs ⟹ filter P (xs - ys) = filter P xs - filter P ys"
by (simp add: minus_list_def less_eq_list_def filter_mono_prefix)
(metis filter_append filter_mono_prefix prefix_drop same_append_eq)
subsection ‹ Laws on @{term list_update} ›
lemma : "length(xs) > 0 ⟹ xs[0 := x] = x # tl xs"
by (metis length_0_conv list.collapse list_update_code(2) nat_less_le)
lemma : "⟦ length xs > 0; k > 0 ⟧ ⟹ tl(xs[k := v]) = (tl xs)[k-1 := v]"
by (metis One_nat_def Suc_pred length_greater_0_conv list.collapse list.sel(3) list_update_code(3))
subsection ‹ Laws on @{term take}, @{term drop}, and @{term nths} ›
lemma : "m ≤ n ⟹ take m xs ≤ take n xs"
by (metis Prefix_Order.prefixI append_take_drop_id min_absorb2 take_append take_take)
lemma : "nths xs {0..m} = take (Suc m) xs"
by (metis atLeast0AtMost lessThan_Suc_atMost nths_upt_eq_take)
lemma : "nths xs {0..<m} = take m xs"
by (simp add: atLeast0LessThan)
lemma : "m ≤ n ⟹ nths xs {0..m} ≤ nths xs {0..n}"
by (simp add: nths_atLeastAtMost_0_take take_prefix)
lemma : "⟦ m ≤ n; sorted (nths xs {0..n}) ⟧ ⟹ sorted (nths xs {0..m})"
using nths_atLeastAtMost_prefix sorted_prefix by blast
lemma : "⟦ m ≤ n; sorted (nths xs {0..<n}) ⟧ ⟹ sorted (nths xs {0..<m})"
by (metis atLeast0LessThan nths_upt_eq_take sorted_prefix take_prefix)
lemma :
"k < length xs ⟹ list_augment xs k x = list_update xs k x"
by (metis list_augment_def list_augment_idem list_update_overwrite)
lemma : "k ∉ A ⟹ nths (list_update xs k x) A = nths xs A"
proof (induct xs arbitrary: k x A)
case Nil
then show ?case by simp
next
case (Cons a xs)
then show ?case by (cases k, auto simp add: nths_Cons)
qed
lemma : "⟦ k < length xs; k ∉ A ⟧ ⟹ nths (list_augment xs k x) A = nths xs A"
by (simp add: list_augment_as_update nths_list_update_out)
lemma :
assumes "∀i ∈ I. i ≥ length xs"
shows "nths xs I = []"
proof -
from assms have "∀x∈set (zip xs [0..<length xs]). snd x ∉ I"
by (metis atLeastLessThan_iff in_set_zip leD nth_mem set_upt)
thus ?thesis
by (simp add: nths_def)
qed
lemma :
"⟦ m ≤ n; n < length xs ⟧ ⟹ nths xs {m..n} = xs ! m # nths xs {Suc m..n}"
proof (induct xs arbitrary: m n)
case Nil
then show ?case by (simp)
next
case (Cons a xs)
have l1: "⋀ m n. ⟦ 0 < m; m ≤ n ⟧ ⟹ {j. m ≤ Suc j ∧ Suc j ≤ n} = {m-1..n-1}"
by (auto)
have l2: "⋀ m n. ⟦ 0 < m; m ≤ n ⟧ ⟹ {j. m ≤ j ∧ Suc j ≤ n} = {m..n-1}"
by (auto)
from Cons show ?case by (auto simp add: nths_Cons l1 l2)
qed
lemma : "⟦ j < i; i < length xs ⟧ ⟹ (nths xs {0..<i}) ! j = xs ! j"
by (metis lessThan_atLeast0 nth_take nths_upt_eq_take)
lemma : "⟦ m ≤ n; n ≤ length xs ⟧ ⟹ length (nths xs {m..<n}) = n-m"
by (metis atLeastLessThan_empty diff_is_0_eq length_map length_upt list.size(3) not_less nths_empty seq_extract_as_map seq_extract_def)
lemma :
"⟦ m ≤ n; Suc n ≤ length xs ⟧ ⟹ length (nths xs {m..n}) = Suc n - m"
by (metis atLeastLessThanSuc_atLeastAtMost le_SucI nths_upt_length)
lemma : "n > 0 ⟹ {j. Suc j ≤ n} = {0..n-1}"
by (auto)
lemma : "⟦ 0 < m; m ≤ n ⟧ ⟹ {j. m ≤ Suc j ∧ Suc j ≤ n} = {m-1..n-1}"
by auto
lemma : "⟦ m ≤ n; Suc n ≤ length xs; i < Suc n - m ⟧
⟹ (nths xs {m..n}) ! i = xs ! (i + m)"
proof (induct xs arbitrary: m n i)
case Nil
then show ?case by (simp)
next
case (Cons a xs)
then show ?case
proof (cases "i = 0")
case True
with Cons show ?thesis by (auto simp add: nths_Cons sl2)
next
case False
with Cons show ?thesis by (auto simp add: nths_Cons sl1 sl2)
qed
qed
lemma :
assumes "⋀x y. x ∈ A ⟹ y ∈ B ⟹ x < y"
shows "nths l A @ nths l B = nths l (A ∪ B)"
proof (induct l rule: rev_induct)
case Nil
then show ?case by simp
next
case (snoc x xs)
{ assume *: "length xs ∉ (A ∪ B)"
then have L: "nths (xs @ [x]) (A ∪ B) = nths xs (A ∪ B)"
by (simp add: nths_append)
from * have R: "nths (xs @ [x]) A = nths xs A" "nths (xs @ [x]) B = nths xs B"
by (simp add: nths_append)+
have ?case
using L R snoc by presburger
} note length_notin = this
{ assume *: "length xs ∈ (A ∪ B)"
then have new_nths: "nths (xs @ [x]) (A ∪ B) = nths xs (A ∪ B) @ [x]"
by (simp add: nths_append)
from * consider (A) "length xs ∈ A" | (B) "length xs ∈ B"
using assms by auto
then have ?case
proof cases
case A
then have "i ∈ B ⟹ i > length xs" for i
using assms by force
then have nths_B: "nths (xs @ [x]) B = []"
by (metis Suc_less_eq le_simps(2) length_Cons length_rotate1 nths_none rotate1.simps(2))
from A have "nths (xs @ [x]) A = nths xs A @ [x]"
by (simp add: nths_append)
then have "nths (xs @ [x]) A @ nths (xs @ [x]) B = (nths xs A @ nths xs B) @ [x]"
by (metis append_is_Nil_conv nths_B nths_append self_append_conv)
then show ?thesis
using snoc new_nths by presburger
next
case B
then have "length xs ∉ A"
using assms by blast
then have "nths (xs @ [x]) A = nths xs A"
by (simp add: nths_append)
moreover have "nths (xs @ [x]) B = nths xs B @ [x]"
by (simp add: B nths_append)
ultimately show ?thesis
by (simp add: new_nths snoc)
qed
} note length_in=this
show ?case
using length_in length_notin by blast
qed
corollary :
"j ≤ i ⟹ nths xs {0..<j} @ nths xs {j..i} = nths xs {0..i}"
proof -
assume "j ≤ i"
have "⋀x y. x ∈ {0..<j} ⟹ y ∈ {j..i} ⟹ x < y"
by auto
then have "nths xs {0..<j} @ nths xs {j..i} = nths xs ({0..<j} ∪ {j..i})"
by (rule nths_split_union)
moreover have "{0..<j} ∪ {j..i} = {0..i}"
by (simp add: ivl_disj_un_two(7) ‹j ≤ i›)
ultimately show ?thesis
using ‹j ≤ i› by presburger
qed
lemma : "n > m ⟹ nths (x # xs) {m..n} = (if m = 0 then x # nths xs {0..n-1} else nths xs {m-1..n-1})"
apply (simp add: nths_Cons)
apply safe
using One_nat_def sl1 apply presburger
using One_nat_def le_eq_less_or_eq sl2 apply presburger
done
lemma : "nths xs {m..n} = drop m (take (n+1) xs)"
by (induct xs rule: rev_induct, simp_all split: nat_diff_split add: nths_append, linarith)
lemma : "drop m xs = map (nth xs) [m..<length xs]"
by (metis add.commute add.right_neutral drop_map drop_upt map_nth)
lemma : "take m xs = map (nth xs) [0..<min m (length xs)]"
by (metis (no_types, lifting) add_0 map_nth min.cobounded2 min.commute min_def take_all_iff take_map take_upt)
lemma : "nths xs {m..n} = map (λ i. xs ! i) [m..<min (n+1) (length xs)]"
by (simp add: nths_atLeastAtMost_eq_drop_take drop_as_map take_as_map)
lemma : "nths xs {k} = (if k < length xs then [xs ! k] else [])"
using nths_atLeastAtMost_as_map[of xs k k] by simp
lemma : "k ∈ {m..n} ⟹ nths (list_update xs k x) {m..n} = list_update (nths xs {m..n}) (k - m) x"
proof (induct xs arbitrary: k x m n)
case Nil
then show ?case by auto
next
case (Cons a xs)
then show ?case
proof (cases k)
case 0
then show ?thesis apply (simp)
by (smt (verit, best) Cons.prems append_Cons list_update_code(2) nths_Cons)
next
case (Suc nat)
with Cons show ?thesis
proof (cases n m rule: linorder_cases)
case less
then show ?thesis
by force
next
case equal
with Suc show ?thesis
by (cases k, force)
(metis (no_types, opaque_lifting) Cons.prems nths_single atLeastAtMost_singleton diff_is_0_eq' length_list_update list_update_code(2) list_update_code(3) list_update_nonempty nle_le nth_list_update_eq singletonD)
next
case greater
with Suc Cons(1)[of nat "m - Suc 0" "n - Suc 0" x] show ?thesis
by (cases k, simp_all add: nths_Cons_atLeastAtMost nths_atLeastAtMost_0_take take_update_swap, safe)
(metis Cons.prems Suc_le_mono Suc_pred atLeastAtMost_iff diff_Suc_Suc le_zero_eq not_gr_zero)
qed
qed
qed
lemma [simp]: "length (nths xs {m..n}) = min (Suc n) (length xs) - m"
by (simp add: nths_atLeastAtMost_as_map)
lemma : "⟦ m < length xs; m ≤ n ⟧ ⟹ hd (nths xs {m..n}) = xs ! m"
by (simp add: nths_atLeastAtMost_as_map upt_conv_Cons)
lemma : "tl (nths xs {m..n}) = nths xs {Suc m..n}"
by (simp add: nths_atLeastAtMost_as_map, metis map_tl tl_upt)
lemma : "set (nths xs {m..n}) = {xs!i | i. m ≤ i ∧ i ≤ n ∧ i < length xs}"
by (auto simp add: nths_atLeastAtMost_as_map)
lemma [simp]: "⟦ m ≤ n; length xs > m ⟧ ⟹ nths xs {m..n} ≠ []"
by (force simp add: nths_atLeastAtMost_as_map)
lemma : "⟦ m ≤ n; m < length xs ⟧ ⟹ nths xs {m..n} = xs ! m # (nths xs {Suc m..n})"
by (simp add: nths_atLeastAtMost_as_map upt_conv_Cons)
lemma : "⟦ xs ≠ []; sorted xs; x ∈ set xs ⟧ ⟹ hd xs ≤ x"
by (metis Orderings.order_eq_iff list.sel(1) list.set_cases sorted_simps(2))
subsection ‹ List power ›
overloading
listpow ≡ "compow :: nat ⇒ 'a list ⇒ 'a list"
begin
listpow :: "nat ⇒ 'a list ⇒ 'a list" where
"listpow 0 xs = []"
| "listpow (Suc n) xs = xs @ listpow n xs"
end
lemma [simp]: "[] ^^ n = []"
by (induct n) simp_all
lemma : "xs ^^ Suc n = xs ^^ n @ xs"
by (induct n) simp_all
lemma : "xs ^^ (m + n) = xs ^^ m @ xs ^^ n"
by (induct m) simp_all
subsection ‹ Alternative List Lexicographic Order ›
text ‹ Since we can't instantiate the order class twice for lists, and we often want prefix as
the default order, we here add syntax for the lexicographic order relation. ›
:: "'a::linorder list ⇒ 'a list ⇒ bool" (infix "<⇩l" 50)
where "xs <⇩l ys ⟷ (xs, ys) ∈ lexord {(u, v). u < v}"
lemma [simp]: "x <⇩l y ⟹ x ≠ y"
apply (simp add: list_lex_less_def)
apply (meson case_prodD less_irrefl lexord_irreflexive mem_Collect_eq)
done
lemma [simp]: "¬ x <⇩l []"
by (simp add: list_lex_less_def)
lemma [simp]: "[] <⇩l a # x"
by (simp add: list_lex_less_def)
lemma [simp]: "a # x <⇩l b # y ⟷ a < b ∨ a = b ∧ x <⇩l y"
by (simp add: list_lex_less_def)
subsection ‹ Bounded List Universe ›
text ‹ Analogous to @{const List.n_lists}, but includes all lists with a length up to the given number. ›
:: "nat ⇒ 'a list ⇒ 'a list list" where
"b_lists n xs = concat (map (λ n. List.n_lists n xs) [0..<Suc n])"
lemma [simp]: "b_lists n [] = [[]]"
unfolding b_lists_def by (induct n) simp_all
lemma : "ys ∈ set (b_lists n xs) ⟹ length ys ≤ n"
unfolding b_lists_def
by (auto simp add: length_n_lists_elem)
lemma : "ys ∈ set (b_lists n xs) ⟹ ys ∈ lists (set xs)"
by (auto simp add: b_lists_def in_mono set_n_lists)
lemma :
assumes "length xs ≤ n" "xs ∈ lists (set A)"
shows "xs ∈ set (b_lists n A)"
proof -
have "xs ∉ set (List.n_lists n A) ⟹ xs ∈ set (List.n_lists (length xs) A)"
using assms(2) in_lists_conv_set set_n_lists by fastforce
with assms show ?thesis
by (force simp add: set_n_lists subsetI b_lists_def)
qed
lemma :
assumes "A ≠ {}"
obtains xs where "length xs = n" "set xs ⊆ A"
proof -
obtain a where a: "a ∈ A"
using assms by blast
hence "set (replicate n a) ⊆ A"
by (simp add: set_replicate_conv_if)
with that show ?thesis
by (meson length_replicate)
qed
lemma :
assumes "xs ≠ []" "List.n_lists m xs = List.n_lists n xs"
shows "m = n"
proof (rule ccontr)
assume mn: "m ≠ n"
hence "m < n ∨ m > n"
by auto
moreover have "m < n ⟶ False"
proof
assume "m < n"
then obtain ys where ys: "length ys = n" "set ys ⊆ set xs"
by (metis all_not_in_conv assms(1) ex_list_nonempty_carrier length_0_conv neq0_conv nth_mem)
hence "ys ∈ set (List.n_lists n xs)"
by (simp add: set_n_lists)
moreover have "ys ∉ set (List.n_lists m xs)"
using length_n_lists_elem mn ys(1) by blast
ultimately show False
by (simp add: assms(2))
qed
moreover have "m > n ⟶ False"
proof
assume "n < m"
then obtain ys where ys: "length ys = m" "set ys ⊆ set xs"
by (metis all_not_in_conv assms(1) ex_list_nonempty_carrier length_0_conv neq0_conv nth_mem)
hence "ys ∈ set (List.n_lists m xs)"
by (simp add: set_n_lists)
moreover have "ys ∉ set (List.n_lists n xs)"
using length_n_lists_elem mn ys(1) by blast
ultimately show False
by (simp add: assms(2))
qed
ultimately show False
by blast
qed
lemma : "distinct xs ⟹ distinct (b_lists n xs)"
apply (cases "xs = []")
apply (simp)
apply (simp add: b_lists_def, safe)
apply (rule distinct_concat)
apply (simp add: distinct_map)
apply (simp add: inj_onI n_lists_inj)
using distinct_n_lists apply auto[1]
apply (safe)
apply (metis ex_map_conv length_n_lists_elem)
apply (simp add: distinct_n_lists)
apply (metis atLeastLessThan_iff length_n_lists_elem order_less_irrefl)
done
:: "nat ⇒ 'a set ⇒ 'a list set" where
"bounded_lists n A = {xs∈lists A. length xs ≤ n}"
lemma [code]: "bounded_lists n (set xs) = set (b_lists n xs)"
apply (simp add: bounded_lists_def in_blistsI in_listsI, safe)
using in_blistsI apply blast
apply (meson b_lists_in_lists in_lists_conv_set)
apply (meson length_b_lists_elem)
done
subsection ‹ Disjointness and Partitions ›
:: "'a set list ⇒ bool" where
"list_disjoint xs = (∀ i < length xs. ∀ j < length xs. i ≠ j ⟶ xs!i ∩ xs!j = {})"
:: "'a set list ⇒ 'a set ⇒ bool" where
"list_partitions xs T = (list_disjoint xs ∧ ⋃ (set xs) = T)"
lemma [simp]: "list_disjoint []"
by (simp add: list_disjoint_def)
lemma [simp]: "list_disjoint (A # Bs) = ((∀ B ∈ set Bs. A ∩ B = {}) ∧ list_disjoint Bs)"
apply (simp add: list_disjoint_def disjoint_iff)
apply (safe)
apply (metis Suc_less_eq in_set_conv_nth nat.distinct(1) neq0_conv nth_Cons_0 nth_Cons_Suc)
apply (metis lessI lift_Suc_mono_less_iff nat.inject nth_Cons_Suc)
apply (metis less_Suc_eq_0_disj[of _ "length Bs"] nth_Cons_0[of A Bs] nth_Cons_Suc[of A Bs] nth_mem[of _ Bs])
done
subsection ‹ Code Generation ›
lemma : "set xs = {x} ⟷ remdups xs = [x]"
apply (safe)
apply (metis card_set empty_set insert_not_empty length_0_conv length_Suc_conv list.simps(15) remdups.simps(1) remdups.simps(2) set_remdups the_elem_set)
apply (metis empty_iff empty_set set_ConsD set_remdups)
apply (metis list.set_intros(1) set_remdups)
done
lemma : "(∃ x. xs = [x]) ⟷ (length xs = 1)"
by (auto simp add: length_Suc_conv)
end