Up to index of Isabelle/HOL
theory List(* Title: HOL/List.thy
Author: Tobias Nipkow
*)
header {* The datatype of finite lists *}
theory List
imports Plain Presburger Code_Numeral Quotient ATP
uses
("Tools/list_code.ML")
("Tools/list_to_set_comprehension.ML")
begin
datatype 'a list =
Nil ("[]")
| Cons 'a "'a list" (infixr "#" 65)
syntax
-- {* list Enumeration *}
"_list" :: "args => 'a list" ("[(_)]")
translations
"[x, xs]" == "x#[xs]"
"[x]" == "x#[]"
subsection {* Basic list processing functions *}
primrec
hd :: "'a list => 'a" where
"hd (x # xs) = x"
primrec
tl :: "'a list => 'a list" where
"tl [] = []"
| "tl (x # xs) = xs"
primrec
last :: "'a list => 'a" where
"last (x # xs) = (if xs = [] then x else last xs)"
primrec
butlast :: "'a list => 'a list" where
"butlast []= []"
| "butlast (x # xs) = (if xs = [] then [] else x # butlast xs)"
primrec
set :: "'a list => 'a set" where
"set [] = {}"
| "set (x # xs) = insert x (set xs)"
primrec
map :: "('a => 'b) => 'a list => 'b list" where
"map f [] = []"
| "map f (x # xs) = f x # map f xs"
primrec
append :: "'a list => 'a list => 'a list" (infixr "@" 65) where
append_Nil:"[] @ ys = ys"
| append_Cons: "(x#xs) @ ys = x # xs @ ys"
primrec
rev :: "'a list => 'a list" where
"rev [] = []"
| "rev (x # xs) = rev xs @ [x]"
primrec
filter:: "('a => bool) => 'a list => 'a list" where
"filter P [] = []"
| "filter P (x # xs) = (if P x then x # filter P xs else filter P xs)"
syntax
-- {* Special syntax for filter *}
"_filter" :: "[pttrn, 'a list, bool] => 'a list" ("(1[_<-_./ _])")
translations
"[x<-xs . P]"== "CONST filter (%x. P) xs"
syntax (xsymbols)
"_filter" :: "[pttrn, 'a list, bool] => 'a list"("(1[_\<leftarrow>_ ./ _])")
syntax (HTML output)
"_filter" :: "[pttrn, 'a list, bool] => 'a list"("(1[_\<leftarrow>_ ./ _])")
primrec
foldl :: "('b => 'a => 'b) => 'b => 'a list => 'b" where
foldl_Nil: "foldl f a [] = a"
| foldl_Cons: "foldl f a (x # xs) = foldl f (f a x) xs"
primrec
foldr :: "('a => 'b => 'b) => 'a list => 'b => 'b" where
"foldr f [] a = a"
| "foldr f (x # xs) a = f x (foldr f xs a)"
primrec
concat:: "'a list list => 'a list" where
"concat [] = []"
| "concat (x # xs) = x @ concat xs"
definition (in monoid_add)
listsum :: "'a list => 'a" where
"listsum xs = foldr plus xs 0"
primrec
drop:: "nat => 'a list => 'a list" where
drop_Nil: "drop n [] = []"
| drop_Cons: "drop n (x # xs) = (case n of 0 => x # xs | Suc m => drop m xs)"
-- {*Warning: simpset does not contain this definition, but separate
theorems for @{text "n = 0"} and @{text "n = Suc k"} *}
primrec
take:: "nat => 'a list => 'a list" where
take_Nil:"take n [] = []"
| take_Cons: "take n (x # xs) = (case n of 0 => [] | Suc m => x # take m xs)"
-- {*Warning: simpset does not contain this definition, but separate
theorems for @{text "n = 0"} and @{text "n = Suc k"} *}
primrec
nth :: "'a list => nat => 'a" (infixl "!" 100) where
nth_Cons: "(x # xs) ! n = (case n of 0 => x | Suc k => xs ! k)"
-- {*Warning: simpset does not contain this definition, but separate
theorems for @{text "n = 0"} and @{text "n = Suc k"} *}
primrec
list_update :: "'a list => nat => 'a => 'a list" where
"list_update [] i v = []"
| "list_update (x # xs) i v = (case i of 0 => v # xs | Suc j => x # list_update xs j v)"
nonterminal lupdbinds and lupdbind
syntax
"_lupdbind":: "['a, 'a] => lupdbind" ("(2_ :=/ _)")
"" :: "lupdbind => lupdbinds" ("_")
"_lupdbinds" :: "[lupdbind, lupdbinds] => lupdbinds" ("_,/ _")
"_LUpdate" :: "['a, lupdbinds] => 'a" ("_/[(_)]" [900,0] 900)
translations
"_LUpdate xs (_lupdbinds b bs)" == "_LUpdate (_LUpdate xs b) bs"
"xs[i:=x]" == "CONST list_update xs i x"
primrec
takeWhile :: "('a => bool) => 'a list => 'a list" where
"takeWhile P [] = []"
| "takeWhile P (x # xs) = (if P x then x # takeWhile P xs else [])"
primrec
dropWhile :: "('a => bool) => 'a list => 'a list" where
"dropWhile P [] = []"
| "dropWhile P (x # xs) = (if P x then dropWhile P xs else x # xs)"
primrec
zip :: "'a list => 'b list => ('a × 'b) list" where
"zip xs [] = []"
| zip_Cons: "zip xs (y # ys) = (case xs of [] => [] | z # zs => (z, y) # zip zs ys)"
-- {*Warning: simpset does not contain this definition, but separate
theorems for @{text "xs = []"} and @{text "xs = z # zs"} *}
primrec
upt :: "nat => nat => nat list" ("(1[_..</_'])") where
upt_0: "[i..<0] = []"
| upt_Suc: "[i..<(Suc j)] = (if i <= j then [i..<j] @ [j] else [])"
definition
insert :: "'a => 'a list => 'a list" where
"insert x xs = (if x ∈ set xs then xs else x # xs)"
hide_const (open) insert
hide_fact (open) insert_def
primrec
remove1 :: "'a => 'a list => 'a list" where
"remove1 x [] = []"
| "remove1 x (y # xs) = (if x = y then xs else y # remove1 x xs)"
primrec
removeAll :: "'a => 'a list => 'a list" where
"removeAll x [] = []"
| "removeAll x (y # xs) = (if x = y then removeAll x xs else y # removeAll x xs)"
primrec
distinct :: "'a list => bool" where
"distinct [] <-> True"
| "distinct (x # xs) <-> x ∉ set xs ∧ distinct xs"
primrec
remdups :: "'a list => 'a list" where
"remdups [] = []"
| "remdups (x # xs) = (if x ∈ set xs then remdups xs else x # remdups xs)"
primrec
replicate :: "nat => 'a => 'a list" where
replicate_0: "replicate 0 x = []"
| replicate_Suc: "replicate (Suc n) x = x # replicate n x"
text {*
Function @{text size} is overloaded for all datatypes. Users may
refer to the list version as @{text length}. *}
abbreviation
length :: "'a list => nat" where
"length ≡ size"
definition
rotate1 :: "'a list => 'a list" where
"rotate1 xs = (case xs of [] => [] | x#xs => xs @ [x])"
definition
rotate :: "nat => 'a list => 'a list" where
"rotate n = rotate1 ^^ n"
definition
list_all2 :: "('a => 'b => bool) => 'a list => 'b list => bool" where
"list_all2 P xs ys =
(length xs = length ys ∧ (∀(x, y) ∈ set (zip xs ys). P x y))"
definition
sublist :: "'a list => nat set => 'a list" where
"sublist xs A = map fst (filter (λp. snd p ∈ A) (zip xs [0..<size xs]))"
fun splice :: "'a list => 'a list => 'a list" where
"splice [] ys = ys" |
"splice xs [] = xs" |
"splice (x#xs) (y#ys) = x # y # splice xs ys"
text{*
\begin{figure}[htbp]
\fbox{
\begin{tabular}{l}
@{lemma "[a,b]@[c,d] = [a,b,c,d]" by simp}\\
@{lemma "length [a,b,c] = 3" by simp}\\
@{lemma "set [a,b,c] = {a,b,c}" by simp}\\
@{lemma "map f [a,b,c] = [f a, f b, f c]" by simp}\\
@{lemma "rev [a,b,c] = [c,b,a]" by simp}\\
@{lemma "hd [a,b,c,d] = a" by simp}\\
@{lemma "tl [a,b,c,d] = [b,c,d]" by simp}\\
@{lemma "last [a,b,c,d] = d" by simp}\\
@{lemma "butlast [a,b,c,d] = [a,b,c]" by simp}\\
@{lemma[source] "filter (λn::nat. n<2) [0,2,1] = [0,1]" by simp}\\
@{lemma "concat [[a,b],[c,d,e],[],[f]] = [a,b,c,d,e,f]" by simp}\\
@{lemma "foldl f x [a,b,c] = f (f (f x a) b) c" by simp}\\
@{lemma "foldr f [a,b,c] x = f a (f b (f c x))" by simp}\\
@{lemma "zip [a,b,c] [x,y,z] = [(a,x),(b,y),(c,z)]" by simp}\\
@{lemma "zip [a,b] [x,y,z] = [(a,x),(b,y)]" by simp}\\
@{lemma "splice [a,b,c] [x,y,z] = [a,x,b,y,c,z]" by simp}\\
@{lemma "splice [a,b,c,d] [x,y] = [a,x,b,y,c,d]" by simp}\\
@{lemma "take 2 [a,b,c,d] = [a,b]" by simp}\\
@{lemma "take 6 [a,b,c,d] = [a,b,c,d]" by simp}\\
@{lemma "drop 2 [a,b,c,d] = [c,d]" by simp}\\
@{lemma "drop 6 [a,b,c,d] = []" by simp}\\
@{lemma "takeWhile (%n::nat. n<3) [1,2,3,0] = [1,2]" by simp}\\
@{lemma "dropWhile (%n::nat. n<3) [1,2,3,0] = [3,0]" by simp}\\
@{lemma "distinct [2,0,1::nat]" by simp}\\
@{lemma "remdups [2,0,2,1::nat,2] = [0,1,2]" by simp}\\
@{lemma "List.insert 2 [0::nat,1,2] = [0,1,2]" by (simp add: List.insert_def)}\\
@{lemma "List.insert 3 [0::nat,1,2] = [3,0,1,2]" by (simp add: List.insert_def)}\\
@{lemma "remove1 2 [2,0,2,1::nat,2] = [0,2,1,2]" by simp}\\
@{lemma "removeAll 2 [2,0,2,1::nat,2] = [0,1]" by simp}\\
@{lemma "nth [a,b,c,d] 2 = c" by simp}\\
@{lemma "[a,b,c,d][2 := x] = [a,b,x,d]" by simp}\\
@{lemma "sublist [a,b,c,d,e] {0,2,3} = [a,c,d]" by (simp add:sublist_def)}\\
@{lemma "rotate1 [a,b,c,d] = [b,c,d,a]" by (simp add:rotate1_def)}\\
@{lemma "rotate 3 [a,b,c,d] = [d,a,b,c]" by (simp add:rotate1_def rotate_def eval_nat_numeral)}\\
@{lemma "replicate 4 a = [a,a,a,a]" by (simp add:eval_nat_numeral)}\\
@{lemma "[2..<5] = [2,3,4]" by (simp add:eval_nat_numeral)}\\
@{lemma "listsum [1,2,3::nat] = 6" by (simp add: listsum_def)}
\end{tabular}}
\caption{Characteristic examples}
\label{fig:Characteristic}
\end{figure}
Figure~\ref{fig:Characteristic} shows characteristic examples
that should give an intuitive understanding of the above functions.
*}
text{* The following simple sort functions are intended for proofs,
not for efficient implementations. *}
context linorder
begin
inductive sorted :: "'a list => bool" where
Nil [iff]: "sorted []"
| Cons: "∀y∈set xs. x ≤ y ==> sorted xs ==> sorted (x # xs)"
lemma sorted_single [iff]:
"sorted [x]"
by (rule sorted.Cons) auto
lemma sorted_many:
"x ≤ y ==> sorted (y # zs) ==> sorted (x # y # zs)"
by (rule sorted.Cons) (cases "y # zs" rule: sorted.cases, auto)
lemma sorted_many_eq [simp, code]:
"sorted (x # y # zs) <-> x ≤ y ∧ sorted (y # zs)"
by (auto intro: sorted_many elim: sorted.cases)
lemma [code]:
"sorted [] <-> True"
"sorted [x] <-> True"
by simp_all
primrec insort_key :: "('b => 'a) => 'b => 'b list => 'b list" where
"insort_key f x [] = [x]" |
"insort_key f x (y#ys) = (if f x ≤ f y then (x#y#ys) else y#(insort_key f x ys))"
definition sort_key :: "('b => 'a) => 'b list => 'b list" where
"sort_key f xs = foldr (insort_key f) xs []"
definition insort_insert_key :: "('b => 'a) => 'b => 'b list => 'b list" where
"insort_insert_key f x xs = (if f x ∈ f ` set xs then xs else insort_key f x xs)"
abbreviation "sort ≡ sort_key (λx. x)"
abbreviation "insort ≡ insort_key (λx. x)"
abbreviation "insort_insert ≡ insort_insert_key (λx. x)"
end
subsubsection {* List comprehension *}
text{* Input syntax for Haskell-like list comprehension notation.
Typical example: @{text"[(x,y). x \<leftarrow> xs, y \<leftarrow> ys, x ≠ y]"},
the list of all pairs of distinct elements from @{text xs} and @{text ys}.
The syntax is as in Haskell, except that @{text"|"} becomes a dot
(like in Isabelle's set comprehension): @{text"[e. x \<leftarrow> xs, …]"} rather than
\verb![e| x <- xs, ...]!.
The qualifiers after the dot are
\begin{description}
\item[generators] @{text"p \<leftarrow> xs"},
where @{text p} is a pattern and @{text xs} an expression of list type, or
\item[guards] @{text"b"}, where @{text b} is a boolean expression.
%\item[local bindings] @ {text"let x = e"}.
\end{description}
Just like in Haskell, list comprehension is just a shorthand. To avoid
misunderstandings, the translation into desugared form is not reversed
upon output. Note that the translation of @{text"[e. x \<leftarrow> xs]"} is
optmized to @{term"map (%x. e) xs"}.
It is easy to write short list comprehensions which stand for complex
expressions. During proofs, they may become unreadable (and
mangled). In such cases it can be advisable to introduce separate
definitions for the list comprehensions in question. *}
nonterminal lc_gen and lc_qual and lc_quals
syntax
"_listcompr" :: "'a => lc_qual => lc_quals => 'a list" ("[_ . __")
"_lc_gen" :: "lc_gen => 'a list => lc_qual" ("_ <- _")
"_lc_test" :: "bool => lc_qual" ("_")
(*"_lc_let" :: "letbinds => lc_qual" ("let _")*)
"_lc_end" :: "lc_quals" ("]")
"_lc_quals" :: "lc_qual => lc_quals => lc_quals" (", __")
"_lc_abs" :: "'a => 'b list => 'b list"
"_strip_positions" :: "'a => lc_gen" ("_")
(* These are easier than ML code but cannot express the optimized
translation of [e. p<-xs]
translations
"[e. p<-xs]" => "concat(map (_lc_abs p [e]) xs)"
"_listcompr e (_lc_gen p xs) (_lc_quals Q Qs)"
=> "concat (map (_lc_abs p (_listcompr e Q Qs)) xs)"
"[e. P]" => "if P then [e] else []"
"_listcompr e (_lc_test P) (_lc_quals Q Qs)"
=> "if P then (_listcompr e Q Qs) else []"
"_listcompr e (_lc_let b) (_lc_quals Q Qs)"
=> "_Let b (_listcompr e Q Qs)"
*)
syntax (xsymbols)
"_lc_gen" :: "lc_gen => 'a list => lc_qual" ("_ \<leftarrow> _")
syntax (HTML output)
"_lc_gen" :: "lc_gen => 'a list => lc_qual" ("_ \<leftarrow> _")
parse_translation (advanced) {*
let
val NilC = Syntax.const @{const_syntax Nil};
val ConsC = Syntax.const @{const_syntax Cons};
val mapC = Syntax.const @{const_syntax map};
val concatC = Syntax.const @{const_syntax concat};
val IfC = Syntax.const @{const_syntax If};
fun singl x = ConsC $ x $ NilC;
fun pat_tr ctxt p e opti = (* %x. case x of p => e | _ => [] *)
let
(* FIXME proper name context!? *)
val x = Free (singleton (Name.variant_list (fold Term.add_free_names [p, e] [])) "x", dummyT);
val e = if opti then singl e else e;
val case1 = Syntax.const @{syntax_const "_case1"} $ Term_Position.strip_positions p $ e;
val case2 =
Syntax.const @{syntax_const "_case1"} $
Syntax.const @{const_syntax dummy_pattern} $ NilC;
val cs = Syntax.const @{syntax_const "_case2"} $ case1 $ case2;
val ft = Datatype_Case.case_tr false Datatype.info_of_constr_permissive ctxt [x, cs];
in lambda x ft end;
fun abs_tr ctxt (p as Free (s, T)) e opti =
let
val thy = Proof_Context.theory_of ctxt;
val s' = Proof_Context.intern_const ctxt s;
in
if Sign.declared_const thy s'
then (pat_tr ctxt p e opti, false)
else (lambda p e, true)
end
| abs_tr ctxt p e opti = (pat_tr ctxt p e opti, false);
fun lc_tr ctxt [e, Const (@{syntax_const "_lc_test"}, _) $ b, qs] =
let
val res =
(case qs of
Const (@{syntax_const "_lc_end"}, _) => singl e
| Const (@{syntax_const "_lc_quals"}, _) $ q $ qs => lc_tr ctxt [e, q, qs]);
in IfC $ b $ res $ NilC end
| lc_tr ctxt
[e, Const (@{syntax_const "_lc_gen"}, _) $ p $ es,
Const(@{syntax_const "_lc_end"}, _)] =
(case abs_tr ctxt p e true of
(f, true) => mapC $ f $ es
| (f, false) => concatC $ (mapC $ f $ es))
| lc_tr ctxt
[e, Const (@{syntax_const "_lc_gen"}, _) $ p $ es,
Const (@{syntax_const "_lc_quals"}, _) $ q $ qs] =
let val e' = lc_tr ctxt [e, q, qs];
in concatC $ (mapC $ (fst (abs_tr ctxt p e' false)) $ es) end;
in [(@{syntax_const "_listcompr"}, lc_tr)] end
*}
ML {*
let
val read = Syntax.read_term @{context};
fun check s1 s2 = read s1 aconv read s2 orelse error ("Check failed: " ^ quote s1);
in
check "[(x,y,z). b]" "if b then [(x, y, z)] else []";
check "[(x,y,z). x\<leftarrow>xs]" "map (λx. (x, y, z)) xs";
check "[e x y. x\<leftarrow>xs, y\<leftarrow>ys]" "concat (map (λx. map (λy. e x y) ys) xs)";
check "[(x,y,z). x<a, x>b]" "if x < a then if b < x then [(x, y, z)] else [] else []";
check "[(x,y,z). x\<leftarrow>xs, x>b]" "concat (map (λx. if b < x then [(x, y, z)] else []) xs)";
check "[(x,y,z). x<a, x\<leftarrow>xs]" "if x < a then map (λx. (x, y, z)) xs else []";
check "[(x,y). Cons True x \<leftarrow> xs]"
"concat (map (λxa. case xa of [] => [] | True # x => [(x, y)] | False # x => []) xs)";
check "[(x,y,z). Cons x [] \<leftarrow> xs]"
"concat (map (λxa. case xa of [] => [] | [x] => [(x, y, z)] | x # aa # lista => []) xs)";
check "[(x,y,z). x<a, x>b, x=d]"
"if x < a then if b < x then if x = d then [(x, y, z)] else [] else [] else []";
check "[(x,y,z). x<a, x>b, y\<leftarrow>ys]"
"if x < a then if b < x then map (λy. (x, y, z)) ys else [] else []";
check "[(x,y,z). x<a, x\<leftarrow>xs,y>b]"
"if x < a then concat (map (λx. if b < y then [(x, y, z)] else []) xs) else []";
check "[(x,y,z). x<a, x\<leftarrow>xs, y\<leftarrow>ys]"
"if x < a then concat (map (λx. map (λy. (x, y, z)) ys) xs) else []";
check "[(x,y,z). x\<leftarrow>xs, x>b, y<a]"
"concat (map (λx. if b < x then if y < a then [(x, y, z)] else [] else []) xs)";
check "[(x,y,z). x\<leftarrow>xs, x>b, y\<leftarrow>ys]"
"concat (map (λx. if b < x then map (λy. (x, y, z)) ys else []) xs)";
check "[(x,y,z). x\<leftarrow>xs, y\<leftarrow>ys,y>x]"
"concat (map (λx. concat (map (λy. if x < y then [(x, y, z)] else []) ys)) xs)";
check "[(x,y,z). x\<leftarrow>xs, y\<leftarrow>ys,z\<leftarrow>zs]"
"concat (map (λx. concat (map (λy. map (λz. (x, y, z)) zs) ys)) xs)"
end;
*}
(*
term "[(x,y). x\<leftarrow>xs, let xx = x+x, y\<leftarrow>ys, y ≠ xx]"
*)
use "Tools/list_to_set_comprehension.ML"
simproc_setup list_to_set_comprehension ("set xs") = {* K List_to_Set_Comprehension.simproc *}
subsubsection {* @{const Nil} and @{const Cons} *}
lemma not_Cons_self [simp]:
"xs ≠ x # xs"
by (induct xs) auto
lemma not_Cons_self2 [simp]:
"x # xs ≠ xs"
by (rule not_Cons_self [symmetric])
lemma neq_Nil_conv: "(xs ≠ []) = (∃y ys. xs = y # ys)"
by (induct xs) auto
lemma length_induct:
"(!!xs. ∀ys. length ys < length xs --> P ys ==> P xs) ==> P xs"
by (rule measure_induct [of length]) iprover
lemma list_nonempty_induct [consumes 1, case_names single cons]:
assumes "xs ≠ []"
assumes single: "!!x. P [x]"
assumes cons: "!!x xs. xs ≠ [] ==> P xs ==> P (x # xs)"
shows "P xs"
using `xs ≠ []` proof (induct xs)
case Nil then show ?case by simp
next
case (Cons x xs) show ?case proof (cases xs)
case Nil with single show ?thesis by simp
next
case Cons then have "xs ≠ []" by simp
moreover with Cons.hyps have "P xs" .
ultimately show ?thesis by (rule cons)
qed
qed
subsubsection {* @{const length} *}
text {*
Needs to come before @{text "@"} because of theorem @{text
append_eq_append_conv}.
*}
lemma length_append [simp]: "length (xs @ ys) = length xs + length ys"
by (induct xs) auto
lemma length_map [simp]: "length (map f xs) = length xs"
by (induct xs) auto
lemma length_rev [simp]: "length (rev xs) = length xs"
by (induct xs) auto
lemma length_tl [simp]: "length (tl xs) = length xs - 1"
by (cases xs) auto
lemma length_0_conv [iff]: "(length xs = 0) = (xs = [])"
by (induct xs) auto
lemma length_greater_0_conv [iff]: "(0 < length xs) = (xs ≠ [])"
by (induct xs) auto
lemma length_pos_if_in_set: "x : set xs ==> length xs > 0"
by auto
lemma length_Suc_conv:
"(length xs = Suc n) = (∃y ys. xs = y # ys ∧ length ys = n)"
by (induct xs) auto
lemma Suc_length_conv:
"(Suc n = length xs) = (∃y ys. xs = y # ys ∧ length ys = n)"
apply (induct xs, simp, simp)
apply blast
done
lemma impossible_Cons: "length xs <= length ys ==> xs = x # ys = False"
by (induct xs) auto
lemma list_induct2 [consumes 1, case_names Nil Cons]:
"length xs = length ys ==> P [] [] ==>
(!!x xs y ys. length xs = length ys ==> P xs ys ==> P (x#xs) (y#ys))
==> P xs ys"
proof (induct xs arbitrary: ys)
case Nil then show ?case by simp
next
case (Cons x xs ys) then show ?case by (cases ys) simp_all
qed
lemma list_induct3 [consumes 2, case_names Nil Cons]:
"length xs = length ys ==> length ys = length zs ==> P [] [] [] ==>
(!!x xs y ys z zs. length xs = length ys ==> length ys = length zs ==> P xs ys zs ==> P (x#xs) (y#ys) (z#zs))
==> P xs ys zs"
proof (induct xs arbitrary: ys zs)
case Nil then show ?case by simp
next
case (Cons x xs ys zs) then show ?case by (cases ys, simp_all)
(cases zs, simp_all)
qed
lemma list_induct4 [consumes 3, case_names Nil Cons]:
"length xs = length ys ==> length ys = length zs ==> length zs = length ws ==>
P [] [] [] [] ==> (!!x xs y ys z zs w ws. length xs = length ys ==>
length ys = length zs ==> length zs = length ws ==> P xs ys zs ws ==>
P (x#xs) (y#ys) (z#zs) (w#ws)) ==> P xs ys zs ws"
proof (induct xs arbitrary: ys zs ws)
case Nil then show ?case by simp
next
case (Cons x xs ys zs ws) then show ?case by ((cases ys, simp_all), (cases zs,simp_all)) (cases ws, simp_all)
qed
lemma list_induct2':
"[| P [] [];
!!x xs. P (x#xs) [];
!!y ys. P [] (y#ys);
!!x xs y ys. P xs ys ==> P (x#xs) (y#ys) |]
==> P xs ys"
by (induct xs arbitrary: ys) (case_tac x, auto)+
lemma neq_if_length_neq: "length xs ≠ length ys ==> (xs = ys) == False"
by (rule Eq_FalseI) auto
simproc_setup list_neq ("(xs::'a list) = ys") = {*
(*
Reduces xs=ys to False if xs and ys cannot be of the same length.
This is the case if the atomic sublists of one are a submultiset
of those of the other list and there are fewer Cons's in one than the other.
*)
let
fun len (Const(@{const_name Nil},_)) acc = acc
| len (Const(@{const_name Cons},_) $ _ $ xs) (ts,n) = len xs (ts,n+1)
| len (Const(@{const_name append},_) $ xs $ ys) acc = len xs (len ys acc)
| len (Const(@{const_name rev},_) $ xs) acc = len xs acc
| len (Const(@{const_name map},_) $ _ $ xs) acc = len xs acc
| len t (ts,n) = (t::ts,n);
fun list_neq _ ss ct =
let
val (Const(_,eqT) $ lhs $ rhs) = Thm.term_of ct;
val (ls,m) = len lhs ([],0) and (rs,n) = len rhs ([],0);
fun prove_neq() =
let
val Type(_,listT::_) = eqT;
val size = HOLogic.size_const listT;
val eq_len = HOLogic.mk_eq (size $ lhs, size $ rhs);
val neq_len = HOLogic.mk_Trueprop (HOLogic.Not $ eq_len);
val thm = Goal.prove (Simplifier.the_context ss) [] [] neq_len
(K (simp_tac (Simplifier.inherit_context ss @{simpset}) 1));
in SOME (thm RS @{thm neq_if_length_neq}) end
in
if m < n andalso submultiset (op aconv) (ls,rs) orelse
n < m andalso submultiset (op aconv) (rs,ls)
then prove_neq() else NONE
end;
in list_neq end;
*}
subsubsection {* @{text "@"} -- append *}
lemma append_assoc [simp]: "(xs @ ys) @ zs = xs @ (ys @ zs)"
by (induct xs) auto
lemma append_Nil2 [simp]: "xs @ [] = xs"
by (induct xs) auto
lemma append_is_Nil_conv [iff]: "(xs @ ys = []) = (xs = [] ∧ ys = [])"
by (induct xs) auto
lemma Nil_is_append_conv [iff]: "([] = xs @ ys) = (xs = [] ∧ ys = [])"
by (induct xs) auto
lemma append_self_conv [iff]: "(xs @ ys = xs) = (ys = [])"
by (induct xs) auto
lemma self_append_conv [iff]: "(xs = xs @ ys) = (ys = [])"
by (induct xs) auto
lemma append_eq_append_conv [simp, no_atp]:
"length xs = length ys ∨ length us = length vs
==> (xs@us = ys@vs) = (xs=ys ∧ us=vs)"
apply (induct xs arbitrary: ys)
apply (case_tac ys, simp, force)
apply (case_tac ys, force, simp)
done
lemma append_eq_append_conv2: "(xs @ ys = zs @ ts) =
(EX us. xs = zs @ us & us @ ys = ts | xs @ us = zs & ys = us@ ts)"
apply (induct xs arbitrary: ys zs ts)
apply fastforce
apply(case_tac zs)
apply simp
apply fastforce
done
lemma same_append_eq [iff, induct_simp]: "(xs @ ys = xs @ zs) = (ys = zs)"
by simp
lemma append1_eq_conv [iff]: "(xs @ [x] = ys @ [y]) = (xs = ys ∧ x = y)"
by simp
lemma append_same_eq [iff, induct_simp]: "(ys @ xs = zs @ xs) = (ys = zs)"
by simp
lemma append_self_conv2 [iff]: "(xs @ ys = ys) = (xs = [])"
using append_same_eq [of _ _ "[]"] by auto
lemma self_append_conv2 [iff]: "(ys = xs @ ys) = (xs = [])"
using append_same_eq [of "[]"] by auto
lemma hd_Cons_tl [simp,no_atp]: "xs ≠ [] ==> hd xs # tl xs = xs"
by (induct xs) auto
lemma hd_append: "hd (xs @ ys) = (if xs = [] then hd ys else hd xs)"
by (induct xs) auto
lemma hd_append2 [simp]: "xs ≠ [] ==> hd (xs @ ys) = hd xs"
by (simp add: hd_append split: list.split)
lemma tl_append: "tl (xs @ ys) = (case xs of [] => tl ys | z#zs => zs @ ys)"
by (simp split: list.split)
lemma tl_append2 [simp]: "xs ≠ [] ==> tl (xs @ ys) = tl xs @ ys"
by (simp add: tl_append split: list.split)
lemma Cons_eq_append_conv: "x#xs = ys@zs =
(ys = [] & x#xs = zs | (EX ys'. x#ys' = ys & xs = ys'@zs))"
by(cases ys) auto
lemma append_eq_Cons_conv: "(ys@zs = x#xs) =
(ys = [] & zs = x#xs | (EX ys'. ys = x#ys' & ys'@zs = xs))"
by(cases ys) auto
text {* Trivial rules for solving @{text "@"}-equations automatically. *}
lemma eq_Nil_appendI: "xs = ys ==> xs = [] @ ys"
by simp
lemma Cons_eq_appendI:
"[| x # xs1 = ys; xs = xs1 @ zs |] ==> x # xs = ys @ zs"
by (drule sym) simp
lemma append_eq_appendI:
"[| xs @ xs1 = zs; ys = xs1 @ us |] ==> xs @ ys = zs @ us"
by (drule sym) simp
text {*
Simplification procedure for all list equalities.
Currently only tries to rearrange @{text "@"} to see if
- both lists end in a singleton list,
- or both lists end in the same list.
*}
simproc_setup list_eq ("(xs::'a list) = ys") = {*
let
fun last (cons as Const (@{const_name Cons}, _) $ _ $ xs) =
(case xs of Const (@{const_name Nil}, _) => cons | _ => last xs)
| last (Const(@{const_name append},_) $ _ $ ys) = last ys
| last t = t;
fun list1 (Const(@{const_name Cons},_) $ _ $ Const(@{const_name Nil},_)) = true
| list1 _ = false;
fun butlast ((cons as Const(@{const_name Cons},_) $ x) $ xs) =
(case xs of Const (@{const_name Nil}, _) => xs | _ => cons $ butlast xs)
| butlast ((app as Const (@{const_name append}, _) $ xs) $ ys) = app $ butlast ys
| butlast xs = Const(@{const_name Nil}, fastype_of xs);
val rearr_ss =
HOL_basic_ss addsimps [@{thm append_assoc}, @{thm append_Nil}, @{thm append_Cons}];
fun list_eq ss (F as (eq as Const(_,eqT)) $ lhs $ rhs) =
let
val lastl = last lhs and lastr = last rhs;
fun rearr conv =
let
val lhs1 = butlast lhs and rhs1 = butlast rhs;
val Type(_,listT::_) = eqT
val appT = [listT,listT] ---> listT
val app = Const(@{const_name append},appT)
val F2 = eq $ (app$lhs1$lastl) $ (app$rhs1$lastr)
val eq = HOLogic.mk_Trueprop (HOLogic.mk_eq (F,F2));
val thm = Goal.prove (Simplifier.the_context ss) [] [] eq
(K (simp_tac (Simplifier.inherit_context ss rearr_ss) 1));
in SOME ((conv RS (thm RS trans)) RS eq_reflection) end;
in
if list1 lastl andalso list1 lastr then rearr @{thm append1_eq_conv}
else if lastl aconv lastr then rearr @{thm append_same_eq}
else NONE
end;
in fn _ => fn ss => fn ct => list_eq ss (term_of ct) end;
*}
subsubsection {* @{text map} *}
lemma hd_map:
"xs ≠ [] ==> hd (map f xs) = f (hd xs)"
by (cases xs) simp_all
lemma map_tl:
"map f (tl xs) = tl (map f xs)"
by (cases xs) simp_all
lemma map_ext: "(!!x. x : set xs --> f x = g x) ==> map f xs = map g xs"
by (induct xs) simp_all
lemma map_ident [simp]: "map (λx. x) = (λxs. xs)"
by (rule ext, induct_tac xs) auto
lemma map_append [simp]: "map f (xs @ ys) = map f xs @ map f ys"
by (induct xs) auto
lemma map_map [simp]: "map f (map g xs) = map (f o g) xs"
by (induct xs) auto
lemma map_comp_map[simp]: "((map f) o (map g)) = map(f o g)"
apply(rule ext)
apply(simp)
done
lemma rev_map: "rev (map f xs) = map f (rev xs)"
by (induct xs) auto
lemma map_eq_conv[simp]: "(map f xs = map g xs) = (!x : set xs. f x = g x)"
by (induct xs) auto
lemma map_cong [fundef_cong]:
"xs = ys ==> (!!x. x ∈ set ys ==> f x = g x) ==> map f xs = map g ys"
by simp
lemma map_is_Nil_conv [iff]: "(map f xs = []) = (xs = [])"
by (cases xs) auto
lemma Nil_is_map_conv [iff]: "([] = map f xs) = (xs = [])"
by (cases xs) auto
lemma map_eq_Cons_conv:
"(map f xs = y#ys) = (∃z zs. xs = z#zs ∧ f z = y ∧ map f zs = ys)"
by (cases xs) auto
lemma Cons_eq_map_conv:
"(x#xs = map f ys) = (∃z zs. ys = z#zs ∧ x = f z ∧ xs = map f zs)"
by (cases ys) auto
lemmas map_eq_Cons_D = map_eq_Cons_conv [THEN iffD1]
lemmas Cons_eq_map_D = Cons_eq_map_conv [THEN iffD1]
declare map_eq_Cons_D [dest!] Cons_eq_map_D [dest!]
lemma ex_map_conv:
"(EX xs. ys = map f xs) = (ALL y : set ys. EX x. y = f x)"
by(induct ys, auto simp add: Cons_eq_map_conv)
lemma map_eq_imp_length_eq:
assumes "map f xs = map g ys"
shows "length xs = length ys"
using assms proof (induct ys arbitrary: xs)
case Nil then show ?case by simp
next
case (Cons y ys) then obtain z zs where xs: "xs = z # zs" by auto
from Cons xs have "map f zs = map g ys" by simp
moreover with Cons have "length zs = length ys" by blast
with xs show ?case by simp
qed
lemma map_inj_on:
"[| map f xs = map f ys; inj_on f (set xs Un set ys) |]
==> xs = ys"
apply(frule map_eq_imp_length_eq)
apply(rotate_tac -1)
apply(induct rule:list_induct2)
apply simp
apply(simp)
apply (blast intro:sym)
done
lemma inj_on_map_eq_map:
"inj_on f (set xs Un set ys) ==> (map f xs = map f ys) = (xs = ys)"
by(blast dest:map_inj_on)
lemma map_injective:
"map f xs = map f ys ==> inj f ==> xs = ys"
by (induct ys arbitrary: xs) (auto dest!:injD)
lemma inj_map_eq_map[simp]: "inj f ==> (map f xs = map f ys) = (xs = ys)"
by(blast dest:map_injective)
lemma inj_mapI: "inj f ==> inj (map f)"
by (iprover dest: map_injective injD intro: inj_onI)
lemma inj_mapD: "inj (map f) ==> inj f"
apply (unfold inj_on_def, clarify)
apply (erule_tac x = "[x]" in ballE)
apply (erule_tac x = "[y]" in ballE, simp, blast)
apply blast
done
lemma inj_map[iff]: "inj (map f) = inj f"
by (blast dest: inj_mapD intro: inj_mapI)
lemma inj_on_mapI: "inj_on f (\<Union>(set ` A)) ==> inj_on (map f) A"
apply(rule inj_onI)
apply(erule map_inj_on)
apply(blast intro:inj_onI dest:inj_onD)
done
lemma map_idI: "(!!x. x ∈ set xs ==> f x = x) ==> map f xs = xs"
by (induct xs, auto)
lemma map_fun_upd [simp]: "y ∉ set xs ==> map (f(y:=v)) xs = map f xs"
by (induct xs) auto
lemma map_fst_zip[simp]:
"length xs = length ys ==> map fst (zip xs ys) = xs"
by (induct rule:list_induct2, simp_all)
lemma map_snd_zip[simp]:
"length xs = length ys ==> map snd (zip xs ys) = ys"
by (induct rule:list_induct2, simp_all)
enriched_type map: map
by (simp_all add: fun_eq_iff id_def)
subsubsection {* @{text rev} *}
lemma rev_append [simp]: "rev (xs @ ys) = rev ys @ rev xs"
by (induct xs) auto
lemma rev_rev_ident [simp]: "rev (rev xs) = xs"
by (induct xs) auto
lemma rev_swap: "(rev xs = ys) = (xs = rev ys)"
by auto
lemma rev_is_Nil_conv [iff]: "(rev xs = []) = (xs = [])"
by (induct xs) auto
lemma Nil_is_rev_conv [iff]: "([] = rev xs) = (xs = [])"
by (induct xs) auto
lemma rev_singleton_conv [simp]: "(rev xs = [x]) = (xs = [x])"
by (cases xs) auto
lemma singleton_rev_conv [simp]: "([x] = rev xs) = (xs = [x])"
by (cases xs) auto
lemma rev_is_rev_conv [iff]: "(rev xs = rev ys) = (xs = ys)"
apply (induct xs arbitrary: ys, force)
apply (case_tac ys, simp, force)
done
lemma inj_on_rev[iff]: "inj_on rev A"
by(simp add:inj_on_def)
lemma rev_induct [case_names Nil snoc]:
"[| P []; !!x xs. P xs ==> P (xs @ [x]) |] ==> P xs"
apply(simplesubst rev_rev_ident[symmetric])
apply(rule_tac list = "rev xs" in list.induct, simp_all)
done
lemma rev_exhaust [case_names Nil snoc]:
"(xs = [] ==> P) ==>(!!ys y. xs = ys @ [y] ==> P) ==> P"
by (induct xs rule: rev_induct) auto
lemmas rev_cases = rev_exhaust
lemma rev_eq_Cons_iff[iff]: "(rev xs = y#ys) = (xs = rev ys @ [y])"
by(rule rev_cases[of xs]) auto
subsubsection {* @{text set} *}
lemma finite_set [iff]: "finite (set xs)"
by (induct xs) auto
lemma set_append [simp]: "set (xs @ ys) = (set xs ∪ set ys)"
by (induct xs) auto
lemma hd_in_set[simp]: "xs ≠ [] ==> hd xs : set xs"
by(cases xs) auto
lemma set_subset_Cons: "set xs ⊆ set (x # xs)"
by auto
lemma set_ConsD: "y ∈ set (x # xs) ==> y=x ∨ y ∈ set xs"
by auto
lemma set_empty [iff]: "(set xs = {}) = (xs = [])"
by (induct xs) auto
lemma set_empty2[iff]: "({} = set xs) = (xs = [])"
by(induct xs) auto
lemma set_rev [simp]: "set (rev xs) = set xs"
by (induct xs) auto
lemma set_map [simp]: "set (map f xs) = f`(set xs)"
by (induct xs) auto
lemma set_filter [simp]: "set (filter P xs) = {x. x : set xs ∧ P x}"
by (induct xs) auto
lemma set_upt [simp]: "set[i..<j] = {i..<j}"
by (induct j) auto
lemma split_list: "x : set xs ==> ∃ys zs. xs = ys @ x # zs"
proof (induct xs)
case Nil thus ?case by simp
next
case Cons thus ?case by (auto intro: Cons_eq_appendI)
qed
lemma in_set_conv_decomp: "x ∈ set xs <-> (∃ys zs. xs = ys @ x # zs)"
by (auto elim: split_list)
lemma split_list_first: "x : set xs ==> ∃ys zs. xs = ys @ x # zs ∧ x ∉ set ys"
proof (induct xs)
case Nil thus ?case by simp
next
case (Cons a xs)
show ?case
proof cases
assume "x = a" thus ?case using Cons by fastforce
next
assume "x ≠ a" thus ?case using Cons by(fastforce intro!: Cons_eq_appendI)
qed
qed
lemma in_set_conv_decomp_first:
"(x : set xs) = (∃ys zs. xs = ys @ x # zs ∧ x ∉ set ys)"
by (auto dest!: split_list_first)
lemma split_list_last: "x ∈ set xs ==> ∃ys zs. xs = ys @ x # zs ∧ x ∉ set zs"
proof (induct xs rule: rev_induct)
case Nil thus ?case by simp
next
case (snoc a xs)
show ?case
proof cases
assume "x = a" thus ?case using snoc by (metis List.set.simps(1) emptyE)
next
assume "x ≠ a" thus ?case using snoc by fastforce
qed
qed
lemma in_set_conv_decomp_last:
"(x : set xs) = (∃ys zs. xs = ys @ x # zs ∧ x ∉ set zs)"
by (auto dest!: split_list_last)
lemma split_list_prop: "∃x ∈ set xs. P x ==> ∃ys x zs. xs = ys @ x # zs & P x"
proof (induct xs)
case Nil thus ?case by simp
next
case Cons thus ?case
by(simp add:Bex_def)(metis append_Cons append.simps(1))
qed
lemma split_list_propE:
assumes "∃x ∈ set xs. P x"
obtains ys x zs where "xs = ys @ x # zs" and "P x"
using split_list_prop [OF assms] by blast
lemma split_list_first_prop:
"∃x ∈ set xs. P x ==>
∃ys x zs. xs = ys@x#zs ∧ P x ∧ (∀y ∈ set ys. ¬ P y)"
proof (induct xs)
case Nil thus ?case by simp
next
case (Cons x xs)
show ?case
proof cases
assume "P x"
thus ?thesis by simp (metis Un_upper1 contra_subsetD in_set_conv_decomp_first self_append_conv2 set_append)
next
assume "¬ P x"
hence "∃x∈set xs. P x" using Cons(2) by simp
thus ?thesis using `¬ P x` Cons(1) by (metis append_Cons set_ConsD)
qed
qed
lemma split_list_first_propE:
assumes "∃x ∈ set xs. P x"
obtains ys x zs where "xs = ys @ x # zs" and "P x" and "∀y ∈ set ys. ¬ P y"
using split_list_first_prop [OF assms] by blast
lemma split_list_first_prop_iff:
"(∃x ∈ set xs. P x) <->
(∃ys x zs. xs = ys@x#zs ∧ P x ∧ (∀y ∈ set ys. ¬ P y))"
by (rule, erule split_list_first_prop) auto
lemma split_list_last_prop:
"∃x ∈ set xs. P x ==>
∃ys x zs. xs = ys@x#zs ∧ P x ∧ (∀z ∈ set zs. ¬ P z)"
proof(induct xs rule:rev_induct)
case Nil thus ?case by simp
next
case (snoc x xs)
show ?case
proof cases
assume "P x" thus ?thesis by (metis emptyE set_empty)
next
assume "¬ P x"
hence "∃x∈set xs. P x" using snoc(2) by simp
thus ?thesis using `¬ P x` snoc(1) by fastforce
qed
qed
lemma split_list_last_propE:
assumes "∃x ∈ set xs. P x"
obtains ys x zs where "xs = ys @ x # zs" and "P x" and "∀z ∈ set zs. ¬ P z"
using split_list_last_prop [OF assms] by blast
lemma split_list_last_prop_iff:
"(∃x ∈ set xs. P x) <->
(∃ys x zs. xs = ys@x#zs ∧ P x ∧ (∀z ∈ set zs. ¬ P z))"
by (metis split_list_last_prop [where P=P] in_set_conv_decomp)
lemma finite_list: "finite A ==> EX xs. set xs = A"
by (erule finite_induct)
(auto simp add: set.simps(2) [symmetric] simp del: set.simps(2))
lemma card_length: "card (set xs) ≤ length xs"
by (induct xs) (auto simp add: card_insert_if)
lemma set_minus_filter_out:
"set xs - {y} = set (filter (λx. ¬ (x = y)) xs)"
by (induct xs) auto
subsubsection {* @{text filter} *}
lemma filter_append [simp]: "filter P (xs @ ys) = filter P xs @ filter P ys"
by (induct xs) auto
lemma rev_filter: "rev (filter P xs) = filter P (rev xs)"
by (induct xs) simp_all
lemma filter_filter [simp]: "filter P (filter Q xs) = filter (λx. Q x ∧ P x) xs"
by (induct xs) auto
lemma length_filter_le [simp]: "length (filter P xs) ≤ length xs"
by (induct xs) (auto simp add: le_SucI)
lemma sum_length_filter_compl:
"length(filter P xs) + length(filter (%x. ~P x) xs) = length xs"
by(induct xs) simp_all
lemma filter_True [simp]: "∀x ∈ set xs. P x ==> filter P xs = xs"
by (induct xs) auto
lemma filter_False [simp]: "∀x ∈ set xs. ¬ P x ==> filter P xs = []"
by (induct xs) auto
lemma filter_empty_conv: "(filter P xs = []) = (∀x∈set xs. ¬ P x)"
by (induct xs) simp_all
lemma filter_id_conv: "(filter P xs = xs) = (∀x∈set xs. P x)"
apply (induct xs)
apply auto
apply(cut_tac P=P and xs=xs in length_filter_le)
apply simp
done
lemma filter_map:
"filter P (map f xs) = map f (filter (P o f) xs)"
by (induct xs) simp_all
lemma length_filter_map[simp]:
"length (filter P (map f xs)) = length(filter (P o f) xs)"
by (simp add:filter_map)
lemma filter_is_subset [simp]: "set (filter P xs) ≤ set xs"
by auto
lemma length_filter_less:
"[| x : set xs; ~ P x |] ==> length(filter P xs) < length xs"
proof (induct xs)
case Nil thus ?case by simp
next
case (Cons x xs) thus ?case
apply (auto split:split_if_asm)
using length_filter_le[of P xs] apply arith
done
qed
lemma length_filter_conv_card:
"length(filter p xs) = card{i. i < length xs & p(xs!i)}"
proof (induct xs)
case Nil thus ?case by simp
next
case (Cons x xs)
let ?S = "{i. i < length xs & p(xs!i)}"
have fin: "finite ?S" by(fast intro: bounded_nat_set_is_finite)
show ?case (is "?l = card ?S'")
proof (cases)
assume "p x"
hence eq: "?S' = insert 0 (Suc ` ?S)"
by(auto simp: image_def split:nat.split dest:gr0_implies_Suc)
have "length (filter p (x # xs)) = Suc(card ?S)"
using Cons `p x` by simp
also have "… = Suc(card(Suc ` ?S))" using fin
by (simp add: card_image)
also have "… = card ?S'" using eq fin
by (simp add:card_insert_if) (simp add:image_def)
finally show ?thesis .
next
assume "¬ p x"
hence eq: "?S' = Suc ` ?S"
by(auto simp add: image_def split:nat.split elim:lessE)
have "length (filter p (x # xs)) = card ?S"
using Cons `¬ p x` by simp
also have "… = card(Suc ` ?S)" using fin
by (simp add: card_image)
also have "… = card ?S'" using eq fin
by (simp add:card_insert_if)
finally show ?thesis .
qed
qed
lemma Cons_eq_filterD:
"x#xs = filter P ys ==>
∃us vs. ys = us @ x # vs ∧ (∀u∈set us. ¬ P u) ∧ P x ∧ xs = filter P vs"
(is "_ ==> ∃us vs. ?P ys us vs")
proof(induct ys)
case Nil thus ?case by simp
next
case (Cons y ys)
show ?case (is "∃x. ?Q x")
proof cases
assume Py: "P y"
show ?thesis
proof cases
assume "x = y"
with Py Cons.prems have "?Q []" by simp
then show ?thesis ..
next
assume "x ≠ y"
with Py Cons.prems show ?thesis by simp
qed
next
assume "¬ P y"
with Cons obtain us vs where "?P (y#ys) (y#us) vs" by fastforce
then have "?Q (y#us)" by simp
then show ?thesis ..
qed
qed
lemma filter_eq_ConsD:
"filter P ys = x#xs ==>
∃us vs. ys = us @ x # vs ∧ (∀u∈set us. ¬ P u) ∧ P x ∧ xs = filter P vs"
by(rule Cons_eq_filterD) simp
lemma filter_eq_Cons_iff:
"(filter P ys = x#xs) =
(∃us vs. ys = us @ x # vs ∧ (∀u∈set us. ¬ P u) ∧ P x ∧ xs = filter P vs)"
by(auto dest:filter_eq_ConsD)
lemma Cons_eq_filter_iff:
"(x#xs = filter P ys) =
(∃us vs. ys = us @ x # vs ∧ (∀u∈set us. ¬ P u) ∧ P x ∧ xs = filter P vs)"
by(auto dest:Cons_eq_filterD)
lemma filter_cong[fundef_cong]:
"xs = ys ==> (!!x. x ∈ set ys ==> P x = Q x) ==> filter P xs = filter Q ys"
apply simp
apply(erule thin_rl)
by (induct ys) simp_all
subsubsection {* List partitioning *}
primrec partition :: "('a => bool) =>'a list => 'a list × 'a list" where
"partition P [] = ([], [])"
| "partition P (x # xs) =
(let (yes, no) = partition P xs
in if P x then (x # yes, no) else (yes, x # no))"
lemma partition_filter1:
"fst (partition P xs) = filter P xs"
by (induct xs) (auto simp add: Let_def split_def)
lemma partition_filter2:
"snd (partition P xs) = filter (Not o P) xs"
by (induct xs) (auto simp add: Let_def split_def)
lemma partition_P:
assumes "partition P xs = (yes, no)"
shows "(∀p ∈ set yes. P p) ∧ (∀p ∈ set no. ¬ P p)"
proof -
from assms have "yes = fst (partition P xs)" and "no = snd (partition P xs)"
by simp_all
then show ?thesis by (simp_all add: partition_filter1 partition_filter2)
qed
lemma partition_set:
assumes "partition P xs = (yes, no)"
shows "set yes ∪ set no = set xs"
proof -
from assms have "yes = fst (partition P xs)" and "no = snd (partition P xs)"
by simp_all
then show ?thesis by (auto simp add: partition_filter1 partition_filter2)
qed
lemma partition_filter_conv[simp]:
"partition f xs = (filter f xs,filter (Not o f) xs)"
unfolding partition_filter2[symmetric]
unfolding partition_filter1[symmetric] by simp
declare partition.simps[simp del]
subsubsection {* @{text concat} *}
lemma concat_append [simp]: "concat (xs @ ys) = concat xs @ concat ys"
by (induct xs) auto
lemma concat_eq_Nil_conv [simp]: "(concat xss = []) = (∀xs ∈ set xss. xs = [])"
by (induct xss) auto
lemma Nil_eq_concat_conv [simp]: "([] = concat xss) = (∀xs ∈ set xss. xs = [])"
by (induct xss) auto
lemma set_concat [simp]: "set (concat xs) = (UN x:set xs. set x)"
by (induct xs) auto
lemma concat_map_singleton[simp]: "concat(map (%x. [f x]) xs) = map f xs"
by (induct xs) auto
lemma map_concat: "map f (concat xs) = concat (map (map f) xs)"
by (induct xs) auto
lemma filter_concat: "filter p (concat xs) = concat (map (filter p) xs)"
by (induct xs) auto
lemma rev_concat: "rev (concat xs) = concat (map rev (rev xs))"
by (induct xs) auto
lemma concat_eq_concat_iff: "∀(x, y) ∈ set (zip xs ys). length x = length y ==> length xs = length ys ==> (concat xs = concat ys) = (xs = ys)"
proof (induct xs arbitrary: ys)
case (Cons x xs ys)
thus ?case by (cases ys) auto
qed (auto)
lemma concat_injective: "concat xs = concat ys ==> length xs = length ys ==> ∀(x, y) ∈ set (zip xs ys). length x = length y ==> xs = ys"
by (simp add: concat_eq_concat_iff)
subsubsection {* @{text nth} *}
lemma nth_Cons_0 [simp, code]: "(x # xs)!0 = x"
by auto
lemma nth_Cons_Suc [simp, code]: "(x # xs)!(Suc n) = xs!n"
by auto
declare nth.simps [simp del]
lemma nth_Cons_pos[simp]: "0 < n ==> (x#xs) ! n = xs ! (n - 1)"
by(auto simp: Nat.gr0_conv_Suc)
lemma nth_append:
"(xs @ ys)!n = (if n < length xs then xs!n else ys!(n - length xs))"
apply (induct xs arbitrary: n, simp)
apply (case_tac n, auto)
done
lemma nth_append_length [simp]: "(xs @ x # ys) ! length xs = x"
by (induct xs) auto
lemma nth_append_length_plus[simp]: "(xs @ ys) ! (length xs + n) = ys ! n"
by (induct xs) auto
lemma nth_map [simp]: "n < length xs ==> (map f xs)!n = f(xs!n)"
apply (induct xs arbitrary: n, simp)
apply (case_tac n, auto)
done
lemma hd_conv_nth: "xs ≠ [] ==> hd xs = xs!0"
by(cases xs) simp_all
lemma list_eq_iff_nth_eq:
"(xs = ys) = (length xs = length ys ∧ (ALL i<length xs. xs!i = ys!i))"
apply(induct xs arbitrary: ys)
apply force
apply(case_tac ys)
apply simp
apply(simp add:nth_Cons split:nat.split)apply blast
done
lemma set_conv_nth: "set xs = {xs!i | i. i < length xs}"
apply (induct xs, simp, simp)
apply safe
apply (metis nat_case_0 nth.simps zero_less_Suc)
apply (metis less_Suc_eq_0_disj nth_Cons_Suc)
apply (case_tac i, simp)
apply (metis diff_Suc_Suc nat_case_Suc nth.simps zero_less_diff)
done
lemma in_set_conv_nth: "(x ∈ set xs) = (∃i < length xs. xs!i = x)"
by(auto simp:set_conv_nth)
lemma list_ball_nth: "[| n < length xs; !x : set xs. P x|] ==> P(xs!n)"
by (auto simp add: set_conv_nth)
lemma nth_mem [simp]: "n < length xs ==> xs!n : set xs"
by (auto simp add: set_conv_nth)
lemma all_nth_imp_all_set:
"[| !i < length xs. P(xs!i); x : set xs|] ==> P x"
by (auto simp add: set_conv_nth)
lemma all_set_conv_all_nth:
"(∀x ∈ set xs. P x) = (∀i. i < length xs --> P (xs ! i))"
by (auto simp add: set_conv_nth)
lemma rev_nth:
"n < size xs ==> rev xs ! n = xs ! (length xs - Suc n)"
proof (induct xs arbitrary: n)
case Nil thus ?case by simp
next
case (Cons x xs)
hence n: "n < Suc (length xs)" by simp
moreover
{ assume "n < length xs"
with n obtain n' where "length xs - n = Suc n'"
by (cases "length xs - n", auto)
moreover
then have "length xs - Suc n = n'" by simp
ultimately
have "xs ! (length xs - Suc n) = (x # xs) ! (length xs - n)" by simp
}
ultimately
show ?case by (clarsimp simp add: Cons nth_append)
qed
lemma Skolem_list_nth:
"(ALL i<k. EX x. P i x) = (EX xs. size xs = k & (ALL i<k. P i (xs!i)))"
(is "_ = (EX xs. ?P k xs)")
proof(induct k)
case 0 show ?case by simp
next
case (Suc k)
show ?case (is "?L = ?R" is "_ = (EX xs. ?P' xs)")
proof
assume "?R" thus "?L" using Suc by auto
next
assume "?L"
with Suc obtain x xs where "?P k xs & P k x" by (metis less_Suc_eq)
hence "?P'(xs@[x])" by(simp add:nth_append less_Suc_eq)
thus "?R" ..
qed
qed
subsubsection {* @{text list_update} *}
lemma length_list_update [simp]: "length(xs[i:=x]) = length xs"
by (induct xs arbitrary: i) (auto split: nat.split)
lemma nth_list_update:
"i < length xs==> (xs[i:=x])!j = (if i = j then x else xs!j)"
by (induct xs arbitrary: i j) (auto simp add: nth_Cons split: nat.split)
lemma nth_list_update_eq [simp]: "i < length xs ==> (xs[i:=x])!i = x"
by (simp add: nth_list_update)
lemma nth_list_update_neq [simp]: "i ≠ j ==> xs[i:=x]!j = xs!j"
by (induct xs arbitrary: i j) (auto simp add: nth_Cons split: nat.split)
lemma list_update_id[simp]: "xs[i := xs!i] = xs"
by (induct xs arbitrary: i) (simp_all split:nat.splits)
lemma list_update_beyond[simp]: "length xs ≤ i ==> xs[i:=x] = xs"
apply (induct xs arbitrary: i)
apply simp
apply (case_tac i)
apply simp_all
done
lemma list_update_nonempty[simp]: "xs[k:=x] = [] <-> xs=[]"
by(metis length_0_conv length_list_update)
lemma list_update_same_conv:
"i < length xs ==> (xs[i := x] = xs) = (xs!i = x)"
by (induct xs arbitrary: i) (auto split: nat.split)
lemma list_update_append1:
"i < size xs ==> (xs @ ys)[i:=x] = xs[i:=x] @ ys"
apply (induct xs arbitrary: i, simp)
apply(simp split:nat.split)
done
lemma list_update_append:
"(xs @ ys) [n:= x] =
(if n < length xs then xs[n:= x] @ ys else xs @ (ys [n-length xs:= x]))"
by (induct xs arbitrary: n) (auto split:nat.splits)
lemma list_update_length [simp]:
"(xs @ x # ys)[length xs := y] = (xs @ y # ys)"
by (induct xs, auto)
lemma map_update: "map f (xs[k:= y]) = (map f xs)[k := f y]"
by(induct xs arbitrary: k)(auto split:nat.splits)
lemma rev_update:
"k < length xs ==> rev (xs[k:= y]) = (rev xs)[length xs - k - 1 := y]"
by (induct xs arbitrary: k) (auto simp: list_update_append split:nat.splits)
lemma update_zip:
"(zip xs ys)[i:=xy] = zip (xs[i:=fst xy]) (ys[i:=snd xy])"
by (induct ys arbitrary: i xy xs) (auto, case_tac xs, auto split: nat.split)
lemma set_update_subset_insert: "set(xs[i:=x]) <= insert x (set xs)"
by (induct xs arbitrary: i) (auto split: nat.split)
lemma set_update_subsetI: "[| set xs <= A; x:A |] ==> set(xs[i := x]) <= A"
by (blast dest!: set_update_subset_insert [THEN subsetD])
lemma set_update_memI: "n < length xs ==> x ∈ set (xs[n := x])"
by (induct xs arbitrary: n) (auto split:nat.splits)
lemma list_update_overwrite[simp]:
"xs [i := x, i := y] = xs [i := y]"
apply (induct xs arbitrary: i) apply simp
apply (case_tac i, simp_all)
done
lemma list_update_swap:
"i ≠ i' ==> xs [i := x, i' := x'] = xs [i' := x', i := x]"
apply (induct xs arbitrary: i i')
apply simp
apply (case_tac i, case_tac i')
apply auto
apply (case_tac i')
apply auto
done
lemma list_update_code [code]:
"[][i := y] = []"
"(x # xs)[0 := y] = y # xs"
"(x # xs)[Suc i := y] = x # xs[i := y]"
by simp_all
subsubsection {* @{text last} and @{text butlast} *}
lemma last_snoc [simp]: "last (xs @ [x]) = x"
by (induct xs) auto
lemma butlast_snoc [simp]: "butlast (xs @ [x]) = xs"
by (induct xs) auto
lemma last_ConsL: "xs = [] ==> last(x#xs) = x"
by simp
lemma last_ConsR: "xs ≠ [] ==> last(x#xs) = last xs"
by simp
lemma last_append: "last(xs @ ys) = (if ys = [] then last xs else last ys)"
by (induct xs) (auto)
lemma last_appendL[simp]: "ys = [] ==> last(xs @ ys) = last xs"
by(simp add:last_append)
lemma last_appendR[simp]: "ys ≠ [] ==> last(xs @ ys) = last ys"
by(simp add:last_append)
lemma hd_rev: "xs ≠ [] ==> hd(rev xs) = last xs"
by(rule rev_exhaust[of xs]) simp_all
lemma last_rev: "xs ≠ [] ==> last(rev xs) = hd xs"
by(cases xs) simp_all
lemma last_in_set[simp]: "as ≠ [] ==> last as ∈ set as"
by (induct as) auto
lemma length_butlast [simp]: "length (butlast xs) = length xs - 1"
by (induct xs rule: rev_induct) auto
lemma butlast_append:
"butlast (xs @ ys) = (if ys = [] then butlast xs else xs @ butlast ys)"
by (induct xs arbitrary: ys) auto
lemma append_butlast_last_id [simp]:
"xs ≠ [] ==> butlast xs @ [last xs] = xs"
by (induct xs) auto
lemma in_set_butlastD: "x : set (butlast xs) ==> x : set xs"
by (induct xs) (auto split: split_if_asm)
lemma in_set_butlast_appendI:
"x : set (butlast xs) | x : set (butlast ys) ==> x : set (butlast (xs @ ys))"
by (auto dest: in_set_butlastD simp add: butlast_append)
lemma last_drop[simp]: "n < length xs ==> last (drop n xs) = last xs"
apply (induct xs arbitrary: n)
apply simp
apply (auto split:nat.split)
done
lemma last_conv_nth: "xs≠[] ==> last xs = xs!(length xs - 1)"
by(induct xs)(auto simp:neq_Nil_conv)
lemma butlast_conv_take: "butlast xs = take (length xs - 1) xs"
by (induct xs, simp, case_tac xs, simp_all)
lemma last_list_update:
"xs ≠ [] ==> last(xs[k:=x]) = (if k = size xs - 1 then x else last xs)"
by (auto simp: last_conv_nth)
lemma butlast_list_update:
"butlast(xs[k:=x]) =
(if k = size xs - 1 then butlast xs else (butlast xs)[k:=x])"
apply(cases xs rule:rev_cases)
apply simp
apply(simp add:list_update_append split:nat.splits)
done
lemma last_map:
"xs ≠ [] ==> last (map f xs) = f (last xs)"
by (cases xs rule: rev_cases) simp_all
lemma map_butlast:
"map f (butlast xs) = butlast (map f xs)"
by (induct xs) simp_all
lemma snoc_eq_iff_butlast:
"xs @ [x] = ys <-> (ys ≠ [] & butlast ys = xs & last ys = x)"
by (metis append_butlast_last_id append_is_Nil_conv butlast_snoc last_snoc not_Cons_self)
subsubsection {* @{text take} and @{text drop} *}
lemma take_0 [simp]: "take 0 xs = []"
by (induct xs) auto
lemma drop_0 [simp]: "drop 0 xs = xs"
by (induct xs) auto
lemma take_Suc_Cons [simp]: "take (Suc n) (x # xs) = x # take n xs"
by simp
lemma drop_Suc_Cons [simp]: "drop (Suc n) (x # xs) = drop n xs"
by simp
declare take_Cons [simp del] and drop_Cons [simp del]
lemma take_1_Cons [simp]: "take 1 (x # xs) = [x]"
unfolding One_nat_def by simp
lemma drop_1_Cons [simp]: "drop 1 (x # xs) = xs"
unfolding One_nat_def by simp
lemma take_Suc: "xs ~= [] ==> take (Suc n) xs = hd xs # take n (tl xs)"
by(clarsimp simp add:neq_Nil_conv)
lemma drop_Suc: "drop (Suc n) xs = drop n (tl xs)"
by(cases xs, simp_all)
lemma take_tl: "take n (tl xs) = tl (take (Suc n) xs)"
by (induct xs arbitrary: n) simp_all
lemma drop_tl: "drop n (tl xs) = tl(drop n xs)"
by(induct xs arbitrary: n, simp_all add:drop_Cons drop_Suc split:nat.split)
lemma tl_take: "tl (take n xs) = take (n - 1) (tl xs)"
by (cases n, simp, cases xs, auto)
lemma tl_drop: "tl (drop n xs) = drop n (tl xs)"
by (simp only: drop_tl)
lemma nth_via_drop: "drop n xs = y#ys ==> xs!n = y"
apply (induct xs arbitrary: n, simp)
apply(simp add:drop_Cons nth_Cons split:nat.splits)
done
lemma take_Suc_conv_app_nth:
"i < length xs ==> take (Suc i) xs = take i xs @ [xs!i]"
apply (induct xs arbitrary: i, simp)
apply (case_tac i, auto)
done
lemma drop_Suc_conv_tl:
"i < length xs ==> (xs!i) # (drop (Suc i) xs) = drop i xs"
apply (induct xs arbitrary: i, simp)
apply (case_tac i, auto)
done
lemma length_take [simp]: "length (take n xs) = min (length xs) n"
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
lemma length_drop [simp]: "length (drop n xs) = (length xs - n)"
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
lemma take_all [simp]: "length xs <= n ==> take n xs = xs"
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
lemma drop_all [simp]: "length xs <= n ==> drop n xs = []"
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
lemma take_append [simp]:
"take n (xs @ ys) = (take n xs @ take (n - length xs) ys)"
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
lemma drop_append [simp]:
"drop n (xs @ ys) = drop n xs @ drop (n - length xs) ys"
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
lemma take_take [simp]: "take n (take m xs) = take (min n m) xs"
apply (induct m arbitrary: xs n, auto)
apply (case_tac xs, auto)
apply (case_tac n, auto)
done
lemma drop_drop [simp]: "drop n (drop m xs) = drop (n + m) xs"
apply (induct m arbitrary: xs, auto)
apply (case_tac xs, auto)
done
lemma take_drop: "take n (drop m xs) = drop m (take (n + m) xs)"
apply (induct m arbitrary: xs n, auto)
apply (case_tac xs, auto)
done
lemma drop_take: "drop n (take m xs) = take (m-n) (drop n xs)"
apply(induct xs arbitrary: m n)
apply simp
apply(simp add: take_Cons drop_Cons split:nat.split)
done
lemma append_take_drop_id [simp]: "take n xs @ drop n xs = xs"
apply (induct n arbitrary: xs, auto)
apply (case_tac xs, auto)
done
lemma take_eq_Nil[simp]: "(take n xs = []) = (n = 0 ∨ xs = [])"
apply(induct xs arbitrary: n)
apply simp
apply(simp add:take_Cons split:nat.split)
done
lemma drop_eq_Nil[simp]: "(drop n xs = []) = (length xs <= n)"
apply(induct xs arbitrary: n)
apply simp
apply(simp add:drop_Cons split:nat.split)
done
lemma take_map: "take n (map f xs) = map f (take n xs)"
apply (induct n arbitrary: xs, auto)
apply (case_tac xs, auto)
done
lemma drop_map: "drop n (map f xs) = map f (drop n xs)"
apply (induct n arbitrary: xs, auto)
apply (case_tac xs, auto)
done
lemma rev_take: "rev (take i xs) = drop (length xs - i) (rev xs)"
apply (induct xs arbitrary: i, auto)
apply (case_tac i, auto)
done
lemma rev_drop: "rev (drop i xs) = take (length xs - i) (rev xs)"
apply (induct xs arbitrary: i, auto)
apply (case_tac i, auto)
done
lemma nth_take [simp]: "i < n ==> (take n xs)!i = xs!i"
apply (induct xs arbitrary: i n, auto)
apply (case_tac n, blast)
apply (case_tac i, auto)
done
lemma nth_drop [simp]:
"n + i <= length xs ==> (drop n xs)!i = xs!(n + i)"
apply (induct n arbitrary: xs i, auto)
apply (case_tac xs, auto)
done
lemma butlast_take:
"n <= length xs ==> butlast (take n xs) = take (n - 1) xs"
by (simp add: butlast_conv_take min_max.inf_absorb1 min_max.inf_absorb2)
lemma butlast_drop: "butlast (drop n xs) = drop n (butlast xs)"
by (simp add: butlast_conv_take drop_take add_ac)
lemma take_butlast: "n < length xs ==> take n (butlast xs) = take n xs"
by (simp add: butlast_conv_take min_max.inf_absorb1)
lemma drop_butlast: "drop n (butlast xs) = butlast (drop n xs)"
by (simp add: butlast_conv_take drop_take add_ac)
lemma hd_drop_conv_nth: "[| xs ≠ []; n < length xs |] ==> hd(drop n xs) = xs!n"
by(simp add: hd_conv_nth)
lemma set_take_subset_set_take:
"m <= n ==> set(take m xs) <= set(take n xs)"
apply (induct xs arbitrary: m n)
apply simp
apply (case_tac n)
apply (auto simp: take_Cons)
done
lemma set_take_subset: "set(take n xs) ⊆ set xs"
by(induct xs arbitrary: n)(auto simp:take_Cons split:nat.split)
lemma set_drop_subset: "set(drop n xs) ⊆ set xs"
by(induct xs arbitrary: n)(auto simp:drop_Cons split:nat.split)
lemma set_drop_subset_set_drop:
"m >= n ==> set(drop m xs) <= set(drop n xs)"
apply(induct xs arbitrary: m n)
apply(auto simp:drop_Cons split:nat.split)
apply (metis set_drop_subset subset_iff)
done
lemma in_set_takeD: "x : set(take n xs) ==> x : set xs"
using set_take_subset by fast
lemma in_set_dropD: "x : set(drop n xs) ==> x : set xs"
using set_drop_subset by fast
lemma append_eq_conv_conj:
"(xs @ ys = zs) = (xs = take (length xs) zs ∧ ys = drop (length xs) zs)"
apply (induct xs arbitrary: zs, simp, clarsimp)
apply (case_tac zs, auto)
done
lemma take_add:
"take (i+j) xs = take i xs @ take j (drop i xs)"
apply (induct xs arbitrary: i, auto)
apply (case_tac i, simp_all)
done
lemma append_eq_append_conv_if:
"(xs⇣1 @ xs⇣2 = ys⇣1 @ ys⇣2) =
(if size xs⇣1 ≤ size ys⇣1
then xs⇣1 = take (size xs⇣1) ys⇣1 ∧ xs⇣2 = drop (size xs⇣1) ys⇣1 @ ys⇣2
else take (size ys⇣1) xs⇣1 = ys⇣1 ∧ drop (size ys⇣1) xs⇣1 @ xs⇣2 = ys⇣2)"
apply(induct xs⇣1 arbitrary: ys⇣1)
apply simp
apply(case_tac ys⇣1)
apply simp_all
done
lemma take_hd_drop:
"n < length xs ==> take n xs @ [hd (drop n xs)] = take (Suc n) xs"
apply(induct xs arbitrary: n)
apply simp
apply(simp add:drop_Cons split:nat.split)
done
lemma id_take_nth_drop:
"i < length xs ==> xs = take i xs @ xs!i # drop (Suc i) xs"
proof -
assume si: "i < length xs"
hence "xs = take (Suc i) xs @ drop (Suc i) xs" by auto
moreover
from si have "take (Suc i) xs = take i xs @ [xs!i]"
apply (rule_tac take_Suc_conv_app_nth) by arith
ultimately show ?thesis by auto
qed
lemma upd_conv_take_nth_drop:
"i < length xs ==> xs[i:=a] = take i xs @ a # drop (Suc i) xs"
proof -
assume i: "i < length xs"
have "xs[i:=a] = (take i xs @ xs!i # drop (Suc i) xs)[i:=a]"
by(rule arg_cong[OF id_take_nth_drop[OF i]])
also have "… = take i xs @ a # drop (Suc i) xs"
using i by (simp add: list_update_append)
finally show ?thesis .
qed
lemma nth_drop':
"i < length xs ==> xs ! i # drop (Suc i) xs = drop i xs"
apply (induct i arbitrary: xs)
apply (simp add: neq_Nil_conv)
apply (erule exE)+
apply simp
apply (case_tac xs)
apply simp_all
done
subsubsection {* @{text takeWhile} and @{text dropWhile} *}
lemma length_takeWhile_le: "length (takeWhile P xs) ≤ length xs"
by (induct xs) auto
lemma takeWhile_dropWhile_id [simp]: "takeWhile P xs @ dropWhile P xs = xs"
by (induct xs) auto
lemma takeWhile_append1 [simp]:
"[| x:set xs; ~P(x)|] ==> takeWhile P (xs @ ys) = takeWhile P xs"
by (induct xs) auto
lemma takeWhile_append2 [simp]:
"(!!x. x : set xs ==> P x) ==> takeWhile P (xs @ ys) = xs @ takeWhile P ys"
by (induct xs) auto
lemma takeWhile_tail: "¬ P x ==> takeWhile P (xs @ (x#l)) = takeWhile P xs"
by (induct xs) auto
lemma takeWhile_nth: "j < length (takeWhile P xs) ==> takeWhile P xs ! j = xs ! j"
apply (subst (3) takeWhile_dropWhile_id[symmetric]) unfolding nth_append by auto
lemma dropWhile_nth: "j < length (dropWhile P xs) ==> dropWhile P xs ! j = xs ! (j + length (takeWhile P xs))"
apply (subst (3) takeWhile_dropWhile_id[symmetric]) unfolding nth_append by auto
lemma length_dropWhile_le: "length (dropWhile P xs) ≤ length xs"
by (induct xs) auto
lemma dropWhile_append1 [simp]:
"[| x : set xs; ~P(x)|] ==> dropWhile P (xs @ ys) = (dropWhile P xs)@ys"
by (induct xs) auto
lemma dropWhile_append2 [simp]:
"(!!x. x:set xs ==> P(x)) ==> dropWhile P (xs @ ys) = dropWhile P ys"
by (induct xs) auto
lemma set_takeWhileD: "x : set (takeWhile P xs) ==> x : set xs ∧ P x"
by (induct xs) (auto split: split_if_asm)
lemma takeWhile_eq_all_conv[simp]:
"(takeWhile P xs = xs) = (∀x ∈ set xs. P x)"
by(induct xs, auto)
lemma dropWhile_eq_Nil_conv[simp]:
"(dropWhile P xs = []) = (∀x ∈ set xs. P x)"
by(induct xs, auto)
lemma dropWhile_eq_Cons_conv:
"(dropWhile P xs = y#ys) = (xs = takeWhile P xs @ y # ys & ¬ P y)"
by(induct xs, auto)
lemma distinct_takeWhile[simp]: "distinct xs ==> distinct (takeWhile P xs)"
by (induct xs) (auto dest: set_takeWhileD)
lemma distinct_dropWhile[simp]: "distinct xs ==> distinct (dropWhile P xs)"
by (induct xs) auto
lemma takeWhile_map: "takeWhile P (map f xs) = map f (takeWhile (P o f) xs)"
by (induct xs) auto
lemma dropWhile_map: "dropWhile P (map f xs) = map f (dropWhile (P o f) xs)"
by (induct xs) auto
lemma takeWhile_eq_take: "takeWhile P xs = take (length (takeWhile P xs)) xs"
by (induct xs) auto
lemma dropWhile_eq_drop: "dropWhile P xs = drop (length (takeWhile P xs)) xs"
by (induct xs) auto
lemma hd_dropWhile:
"dropWhile P xs ≠ [] ==> ¬ P (hd (dropWhile P xs))"
using assms by (induct xs) auto
lemma takeWhile_eq_filter:
assumes "!! x. x ∈ set (dropWhile P xs) ==> ¬ P x"
shows "takeWhile P xs = filter P xs"
proof -
have A: "filter P xs = filter P (takeWhile P xs @ dropWhile P xs)"
by simp
have B: "filter P (dropWhile P xs) = []"
unfolding filter_empty_conv using assms by blast
have "filter P xs = takeWhile P xs"
unfolding A filter_append B
by (auto simp add: filter_id_conv dest: set_takeWhileD)
thus ?thesis ..
qed
lemma takeWhile_eq_take_P_nth:
"[| !! i. [| i < n ; i < length xs |] ==> P (xs ! i) ; n < length xs ==> ¬ P (xs ! n) |] ==>
takeWhile P xs = take n xs"
proof (induct xs arbitrary: n)
case (Cons x xs)
thus ?case
proof (cases n)
case (Suc n') note this[simp]
have "P x" using Cons.prems(1)[of 0] by simp
moreover have "takeWhile P xs = take n' xs"
proof (rule Cons.hyps)
case goal1 thus "P (xs ! i)" using Cons.prems(1)[of "Suc i"] by simp
next case goal2 thus ?case using Cons by auto
qed
ultimately show ?thesis by simp
qed simp
qed simp
lemma nth_length_takeWhile:
"length (takeWhile P xs) < length xs ==> ¬ P (xs ! length (takeWhile P xs))"
by (induct xs) auto
lemma length_takeWhile_less_P_nth:
assumes all: "!! i. i < j ==> P (xs ! i)" and "j ≤ length xs"
shows "j ≤ length (takeWhile P xs)"
proof (rule classical)
assume "¬ ?thesis"
hence "length (takeWhile P xs) < length xs" using assms by simp
thus ?thesis using all `¬ ?thesis` nth_length_takeWhile[of P xs] by auto
qed
text{* The following two lemmmas could be generalized to an arbitrary
property. *}
lemma takeWhile_neq_rev: "[|distinct xs; x ∈ set xs|] ==>
takeWhile (λy. y ≠ x) (rev xs) = rev (tl (dropWhile (λy. y ≠ x) xs))"
by(induct xs) (auto simp: takeWhile_tail[where l="[]"])
lemma dropWhile_neq_rev: "[|distinct xs; x ∈ set xs|] ==>
dropWhile (λy. y ≠ x) (rev xs) = x # rev (takeWhile (λy. y ≠ x) xs)"
apply(induct xs)
apply simp
apply auto
apply(subst dropWhile_append2)
apply auto
done
lemma takeWhile_not_last:
"[| xs ≠ []; distinct xs|] ==> takeWhile (λy. y ≠ last xs) xs = butlast xs"
apply(induct xs)
apply simp
apply(case_tac xs)
apply(auto)
done
lemma takeWhile_cong [fundef_cong]:
"[| l = k; !!x. x : set l ==> P x = Q x |]
==> takeWhile P l = takeWhile Q k"
by (induct k arbitrary: l) (simp_all)
lemma dropWhile_cong [fundef_cong]:
"[| l = k; !!x. x : set l ==> P x = Q x |]
==> dropWhile P l = dropWhile Q k"
by (induct k arbitrary: l, simp_all)
subsubsection {* @{text zip} *}
lemma zip_Nil [simp]: "zip [] ys = []"
by (induct ys) auto
lemma zip_Cons_Cons [simp]: "zip (x # xs) (y # ys) = (x, y) # zip xs ys"
by simp
declare zip_Cons [simp del]
lemma [code]:
"zip [] ys = []"
"zip xs [] = []"
"zip (x # xs) (y # ys) = (x, y) # zip xs ys"
by (fact zip_Nil zip.simps(1) zip_Cons_Cons)+
lemma zip_Cons1:
"zip (x#xs) ys = (case ys of [] => [] | y#ys => (x,y)#zip xs ys)"
by(auto split:list.split)
lemma length_zip [simp]:
"length (zip xs ys) = min (length xs) (length ys)"
by (induct xs ys rule:list_induct2') auto
lemma zip_obtain_same_length:
assumes "!!zs ws n. length zs = length ws ==> n = min (length xs) (length ys)
==> zs = take n xs ==> ws = take n ys ==> P (zip zs ws)"
shows "P (zip xs ys)"
proof -
let ?n = "min (length xs) (length ys)"
have "P (zip (take ?n xs) (take ?n ys))"
by (rule assms) simp_all
moreover have "zip xs ys = zip (take ?n xs) (take ?n ys)"
proof (induct xs arbitrary: ys)
case Nil then show ?case by simp
next
case (Cons x xs) then show ?case by (cases ys) simp_all
qed
ultimately show ?thesis by simp
qed
lemma zip_append1:
"zip (xs @ ys) zs =
zip xs (take (length xs) zs) @ zip ys (drop (length xs) zs)"
by (induct xs zs rule:list_induct2') auto
lemma zip_append2:
"zip xs (ys @ zs) =
zip (take (length ys) xs) ys @ zip (drop (length ys) xs) zs"
by (induct xs ys rule:list_induct2') auto
lemma zip_append [simp]:
"[| length xs = length us; length ys = length vs |] ==>
zip (xs@ys) (us@vs) = zip xs us @ zip ys vs"
by (simp add: zip_append1)
lemma zip_rev:
"length xs = length ys ==> zip (rev xs) (rev ys) = rev (zip xs ys)"
by (induct rule:list_induct2, simp_all)
lemma zip_map_map:
"zip (map f xs) (map g ys) = map (λ (x, y). (f x, g y)) (zip xs ys)"
proof (induct xs arbitrary: ys)
case (Cons x xs) note Cons_x_xs = Cons.hyps
show ?case
proof (cases ys)
case (Cons y ys')
show ?thesis unfolding Cons using Cons_x_xs by simp
qed simp
qed simp
lemma zip_map1:
"zip (map f xs) ys = map (λ(x, y). (f x, y)) (zip xs ys)"
using zip_map_map[of f xs "λx. x" ys] by simp
lemma zip_map2:
"zip xs (map f ys) = map (λ(x, y). (x, f y)) (zip xs ys)"
using zip_map_map[of "λx. x" xs f ys] by simp
lemma map_zip_map:
"map f (zip (map g xs) ys) = map (%(x,y). f(g x, y)) (zip xs ys)"
unfolding zip_map1 by auto
lemma map_zip_map2:
"map f (zip xs (map g ys)) = map (%(x,y). f(x, g y)) (zip xs ys)"
unfolding zip_map2 by auto
text{* Courtesy of Andreas Lochbihler: *}
lemma zip_same_conv_map: "zip xs xs = map (λx. (x, x)) xs"
by(induct xs) auto
lemma nth_zip [simp]:
"[| i < length xs; i < length ys|] ==> (zip xs ys)!i = (xs!i, ys!i)"
apply (induct ys arbitrary: i xs, simp)
apply (case_tac xs)
apply (simp_all add: nth.simps split: nat.split)
done
lemma set_zip:
"set (zip xs ys) = {(xs!i, ys!i) | i. i < min (length xs) (length ys)}"
by(simp add: set_conv_nth cong: rev_conj_cong)
lemma zip_same: "((a,b) ∈ set (zip xs xs)) = (a ∈ set xs ∧ a = b)"
by(induct xs) auto
lemma zip_update:
"zip (xs[i:=x]) (ys[i:=y]) = (zip xs ys)[i:=(x,y)]"
by(rule sym, simp add: update_zip)
lemma zip_replicate [simp]:
"zip (replicate i x) (replicate j y) = replicate (min i j) (x,y)"
apply (induct i arbitrary: j, auto)
apply (case_tac j, auto)
done
lemma take_zip:
"take n (zip xs ys) = zip (take n xs) (take n ys)"
apply (induct n arbitrary: xs ys)
apply simp
apply (case_tac xs, simp)
apply (case_tac ys, simp_all)
done
lemma drop_zip:
"drop n (zip xs ys) = zip (drop n xs) (drop n ys)"
apply (induct n arbitrary: xs ys)
apply simp
apply (case_tac xs, simp)
apply (case_tac ys, simp_all)
done
lemma zip_takeWhile_fst: "zip (takeWhile P xs) ys = takeWhile (P o fst) (zip xs ys)"
proof (induct xs arbitrary: ys)
case (Cons x xs) thus ?case by (cases ys) auto
qed simp
lemma zip_takeWhile_snd: "zip xs (takeWhile P ys) = takeWhile (P o snd) (zip xs ys)"
proof (induct xs arbitrary: ys)
case (Cons x xs) thus ?case by (cases ys) auto
qed simp
lemma set_zip_leftD:
"(x,y)∈ set (zip xs ys) ==> x ∈ set xs"
by (induct xs ys rule:list_induct2') auto
lemma set_zip_rightD:
"(x,y)∈ set (zip xs ys) ==> y ∈ set ys"
by (induct xs ys rule:list_induct2') auto
lemma in_set_zipE:
"(x,y) : set(zip xs ys) ==> ([| x : set xs; y : set ys |] ==> R) ==> R"
by(blast dest: set_zip_leftD set_zip_rightD)
lemma zip_map_fst_snd:
"zip (map fst zs) (map snd zs) = zs"
by (induct zs) simp_all
lemma zip_eq_conv:
"length xs = length ys ==> zip xs ys = zs <-> map fst zs = xs ∧ map snd zs = ys"
by (auto simp add: zip_map_fst_snd)
subsubsection {* @{text list_all2} *}
lemma list_all2_lengthD [intro?]:
"list_all2 P xs ys ==> length xs = length ys"
by (simp add: list_all2_def)
lemma list_all2_Nil [iff, code]: "list_all2 P [] ys = (ys = [])"
by (simp add: list_all2_def)
lemma list_all2_Nil2 [iff, code]: "list_all2 P xs [] = (xs = [])"
by (simp add: list_all2_def)
lemma list_all2_Cons [iff, code]:
"list_all2 P (x # xs) (y # ys) = (P x y ∧ list_all2 P xs ys)"
by (auto simp add: list_all2_def)
lemma list_all2_Cons1:
"list_all2 P (x # xs) ys = (∃z zs. ys = z # zs ∧ P x z ∧ list_all2 P xs zs)"
by (cases ys) auto
lemma list_all2_Cons2:
"list_all2 P xs (y # ys) = (∃z zs. xs = z # zs ∧ P z y ∧ list_all2 P zs ys)"
by (cases xs) auto
lemma list_all2_rev [iff]:
"list_all2 P (rev xs) (rev ys) = list_all2 P xs ys"
by (simp add: list_all2_def zip_rev cong: conj_cong)
lemma list_all2_rev1:
"list_all2 P (rev xs) ys = list_all2 P xs (rev ys)"
by (subst list_all2_rev [symmetric]) simp
lemma list_all2_append1:
"list_all2 P (xs @ ys) zs =
(EX us vs. zs = us @ vs ∧ length us = length xs ∧ length vs = length ys ∧
list_all2 P xs us ∧ list_all2 P ys vs)"
apply (simp add: list_all2_def zip_append1)
apply (rule iffI)
apply (rule_tac x = "take (length xs) zs" in exI)
apply (rule_tac x = "drop (length xs) zs" in exI)
apply (force split: nat_diff_split simp add: min_def, clarify)
apply (simp add: ball_Un)
done
lemma list_all2_append2:
"list_all2 P xs (ys @ zs) =
(EX us vs. xs = us @ vs ∧ length us = length ys ∧ length vs = length zs ∧
list_all2 P us ys ∧ list_all2 P vs zs)"
apply (simp add: list_all2_def zip_append2)
apply (rule iffI)
apply (rule_tac x = "take (length ys) xs" in exI)
apply (rule_tac x = "drop (length ys) xs" in exI)
apply (force split: nat_diff_split simp add: min_def, clarify)
apply (simp add: ball_Un)
done
lemma list_all2_append:
"length xs = length ys ==>
list_all2 P (xs@us) (ys@vs) = (list_all2 P xs ys ∧ list_all2 P us vs)"
by (induct rule:list_induct2, simp_all)
lemma list_all2_appendI [intro?, trans]:
"[| list_all2 P a b; list_all2 P c d |] ==> list_all2 P (a@c) (b@d)"
by (simp add: list_all2_append list_all2_lengthD)
lemma list_all2_conv_all_nth:
"list_all2 P xs ys =
(length xs = length ys ∧ (∀i < length xs. P (xs!i) (ys!i)))"
by (force simp add: list_all2_def set_zip)
lemma list_all2_trans:
assumes tr: "!!a b c. P1 a b ==> P2 b c ==> P3 a c"
shows "!!bs cs. list_all2 P1 as bs ==> list_all2 P2 bs cs ==> list_all2 P3 as cs"
(is "!!bs cs. PROP ?Q as bs cs")
proof (induct as)
fix x xs bs assume I1: "!!bs cs. PROP ?Q xs bs cs"
show "!!cs. PROP ?Q (x # xs) bs cs"
proof (induct bs)
fix y ys cs assume I2: "!!cs. PROP ?Q (x # xs) ys cs"
show "PROP ?Q (x # xs) (y # ys) cs"
by (induct cs) (auto intro: tr I1 I2)
qed simp
qed simp
lemma list_all2_all_nthI [intro?]:
"length a = length b ==> (!!n. n < length a ==> P (a!n) (b!n)) ==> list_all2 P a b"
by (simp add: list_all2_conv_all_nth)
lemma list_all2I:
"∀x ∈ set (zip a b). split P x ==> length a = length b ==> list_all2 P a b"
by (simp add: list_all2_def)
lemma list_all2_nthD:
"[| list_all2 P xs ys; p < size xs |] ==> P (xs!p) (ys!p)"
by (simp add: list_all2_conv_all_nth)
lemma list_all2_nthD2:
"[|list_all2 P xs ys; p < size ys|] ==> P (xs!p) (ys!p)"
by (frule list_all2_lengthD) (auto intro: list_all2_nthD)
lemma list_all2_map1:
"list_all2 P (map f as) bs = list_all2 (λx y. P (f x) y) as bs"
by (simp add: list_all2_conv_all_nth)
lemma list_all2_map2:
"list_all2 P as (map f bs) = list_all2 (λx y. P x (f y)) as bs"
by (auto simp add: list_all2_conv_all_nth)
lemma list_all2_refl [intro?]:
"(!!x. P x x) ==> list_all2 P xs xs"
by (simp add: list_all2_conv_all_nth)
lemma list_all2_update_cong:
"[| i<size xs; list_all2 P xs ys; P x y |] ==> list_all2 P (xs[i:=x]) (ys[i:=y])"
by (simp add: list_all2_conv_all_nth nth_list_update)
lemma list_all2_update_cong2:
"[|list_all2 P xs ys; P x y; i < length ys|] ==> list_all2 P (xs[i:=x]) (ys[i:=y])"
by (simp add: list_all2_lengthD list_all2_update_cong)
lemma list_all2_takeI [simp,intro?]:
"list_all2 P xs ys ==> list_all2 P (take n xs) (take n ys)"
apply (induct xs arbitrary: n ys)
apply simp
apply (clarsimp simp add: list_all2_Cons1)
apply (case_tac n)
apply auto
done
lemma list_all2_dropI [simp,intro?]:
"list_all2 P as bs ==> list_all2 P (drop n as) (drop n bs)"
apply (induct as arbitrary: n bs, simp)
apply (clarsimp simp add: list_all2_Cons1)
apply (case_tac n, simp, simp)
done
lemma list_all2_mono [intro?]:
"list_all2 P xs ys ==> (!!xs ys. P xs ys ==> Q xs ys) ==> list_all2 Q xs ys"
apply (induct xs arbitrary: ys, simp)
apply (case_tac ys, auto)
done
lemma list_all2_eq:
"xs = ys <-> list_all2 (op =) xs ys"
by (induct xs ys rule: list_induct2') auto
lemma list_eq_iff_zip_eq:
"xs = ys <-> length xs = length ys ∧ (∀(x,y) ∈ set (zip xs ys). x = y)"
by(auto simp add: set_zip list_all2_eq list_all2_conv_all_nth cong: conj_cong)
subsubsection {* @{text foldl} and @{text foldr} *}
lemma foldl_append [simp]:
"foldl f a (xs @ ys) = foldl f (foldl f a xs) ys"
by (induct xs arbitrary: a) auto
lemma foldr_append[simp]: "foldr f (xs @ ys) a = foldr f xs (foldr f ys a)"
by (induct xs) auto
lemma foldr_map: "foldr g (map f xs) a = foldr (g o f) xs a"
by(induct xs) simp_all
text{* For efficient code generation: avoid intermediate list. *}
lemma foldl_map[code_unfold]:
"foldl g a (map f xs) = foldl (%a x. g a (f x)) a xs"
by(induct xs arbitrary:a) simp_all
lemma foldl_apply:
assumes "!!x. x ∈ set xs ==> f x o h = h o g x"
shows "foldl (λs x. f x s) (h s) xs = h (foldl (λs x. g x s) s xs)"
by (rule sym, insert assms, induct xs arbitrary: s) (simp_all add: fun_eq_iff)
lemma foldl_cong [fundef_cong]:
"[| a = b; l = k; !!a x. x : set l ==> f a x = g a x |]
==> foldl f a l = foldl g b k"
by (induct k arbitrary: a b l) simp_all
lemma foldr_cong [fundef_cong]:
"[| a = b; l = k; !!a x. x : set l ==> f x a = g x a |]
==> foldr f l a = foldr g k b"
by (induct k arbitrary: a b l) simp_all
lemma foldl_fun_comm:
assumes "!!x y s. f (f s x) y = f (f s y) x"
shows "f (foldl f s xs) x = foldl f (f s x) xs"
by (induct xs arbitrary: s)
(simp_all add: assms)
lemma (in semigroup_add) foldl_assoc:
shows "foldl op+ (x+y) zs = x + (foldl op+ y zs)"
by (induct zs arbitrary: y) (simp_all add:add_assoc)
lemma (in monoid_add) foldl_absorb0:
shows "x + (foldl op+ 0 zs) = foldl op+ x zs"
by (induct zs) (simp_all add:foldl_assoc)
lemma foldl_rev:
assumes "!!x y s. f (f s x) y = f (f s y) x"
shows "foldl f s (rev xs) = foldl f s xs"
proof (induct xs arbitrary: s)
case Nil then show ?case by simp
next
case (Cons x xs) with assms show ?case by (simp add: foldl_fun_comm)
qed
lemma rev_foldl_cons [code]:
"rev xs = foldl (λxs x. x # xs) [] xs"
proof (induct xs)
case Nil then show ?case by simp
next
case Cons
{
fix x xs ys
have "foldl (λxs x. x # xs) ys xs @ [x]
= foldl (λxs x. x # xs) (ys @ [x]) xs"
by (induct xs arbitrary: ys) auto
}
note aux = this
show ?case by (induct xs) (auto simp add: Cons aux)
qed
text{* The ``Third Duality Theorem'' in Bird \& Wadler: *}
lemma foldr_foldl:
"foldr f xs a = foldl (%x y. f y x) a (rev xs)"
by (induct xs) auto
lemma foldl_foldr:
"foldl f a xs = foldr (%x y. f y x) (rev xs) a"
by (simp add: foldr_foldl [of "%x y. f y x" "rev xs"])
text{* The ``First Duality Theorem'' in Bird \& Wadler: *}
lemma (in monoid_add) foldl_foldr1_lemma:
"foldl op + a xs = a + foldr op + xs 0"
by (induct xs arbitrary: a) (auto simp: add_assoc)
corollary (in monoid_add) foldl_foldr1:
"foldl op + 0 xs = foldr op + xs 0"
by (simp add: foldl_foldr1_lemma)
lemma (in ab_semigroup_add) foldr_conv_foldl:
"foldr op + xs a = foldl op + a xs"
by (induct xs) (simp_all add: foldl_assoc add.commute)
text {*
Note: @{text "n ≤ foldl (op +) n ns"} looks simpler, but is more
difficult to use because it requires an additional transitivity step.
*}
lemma start_le_sum: "(m::nat) <= n ==> m <= foldl (op +) n ns"
by (induct ns arbitrary: n) auto
lemma elem_le_sum: "(n::nat) : set ns ==> n <= foldl (op +) 0 ns"
by (force intro: start_le_sum simp add: in_set_conv_decomp)
lemma sum_eq_0_conv [iff]:
"(foldl (op +) (m::nat) ns = 0) = (m = 0 ∧ (∀n ∈ set ns. n = 0))"
by (induct ns arbitrary: m) auto
lemma foldr_invariant:
"[|Q x ; ∀ x∈ set xs. P x; ∀ x y. P x ∧ Q y --> Q (f x y) |] ==> Q (foldr f xs x)"
by (induct xs, simp_all)
lemma foldl_invariant:
"[|Q x ; ∀ x∈ set xs. P x; ∀ x y. P x ∧ Q y --> Q (f y x) |] ==> Q (foldl f x xs)"
by (induct xs arbitrary: x, simp_all)
lemma foldl_weak_invariant:
assumes "P s"
and "!!s x. x ∈ set xs ==> P s ==> P (f s x)"
shows "P (foldl f s xs)"
using assms by (induct xs arbitrary: s) simp_all
text {* @{const foldl} and @{const concat} *}
lemma foldl_conv_concat:
"foldl (op @) xs xss = xs @ concat xss"
proof (induct xss arbitrary: xs)
case Nil show ?case by simp
next
interpret monoid_add "op @" "[]" proof qed simp_all
case Cons then show ?case by (simp add: foldl_absorb0)
qed
lemma concat_conv_foldl: "concat xss = foldl (op @) [] xss"
by (simp add: foldl_conv_concat)
text {* @{const Finite_Set.fold} and @{const foldl} *}
lemma (in comp_fun_commute) fold_set_remdups:
"fold f y (set xs) = foldl (λy x. f x y) y (remdups xs)"
by (rule sym, induct xs arbitrary: y) (simp_all add: fold_fun_comm insert_absorb)
lemma (in comp_fun_idem) fold_set:
"fold f y (set xs) = foldl (λy x. f x y) y xs"
by (rule sym, induct xs arbitrary: y) (simp_all add: fold_fun_comm)
lemma (in ab_semigroup_idem_mult) fold1_set:
assumes "xs ≠ []"
shows "fold1 times (set xs) = foldl times (hd xs) (tl xs)"
proof -
interpret comp_fun_idem times by (fact comp_fun_idem)
from assms obtain y ys where xs: "xs = y # ys"
by (cases xs) auto
show ?thesis
proof (cases "set ys = {}")
case True with xs show ?thesis by simp
next
case False
then have "fold1 times (insert y (set ys)) = fold times y (set ys)"
by (simp only: finite_set fold1_eq_fold_idem)
with xs show ?thesis by (simp add: fold_set mult_commute)
qed
qed
lemma (in lattice) Inf_fin_set_fold [code_unfold]:
"Inf_fin (set (x # xs)) = foldl inf x xs"
proof -
interpret ab_semigroup_idem_mult "inf :: 'a => 'a => 'a"
by (fact ab_semigroup_idem_mult_inf)
show ?thesis
by (simp add: Inf_fin_def fold1_set del: set.simps)
qed
lemma (in lattice) Sup_fin_set_fold [code_unfold]:
"Sup_fin (set (x # xs)) = foldl sup x xs"
proof -
interpret ab_semigroup_idem_mult "sup :: 'a => 'a => 'a"
by (fact ab_semigroup_idem_mult_sup)
show ?thesis
by (simp add: Sup_fin_def fold1_set del: set.simps)
qed
lemma (in linorder) Min_fin_set_fold [code_unfold]:
"Min (set (x # xs)) = foldl min x xs"
proof -
interpret ab_semigroup_idem_mult "min :: 'a => 'a => 'a"
by (fact ab_semigroup_idem_mult_min)
show ?thesis
by (simp add: Min_def fold1_set del: set.simps)
qed
lemma (in linorder) Max_fin_set_fold [code_unfold]:
"Max (set (x # xs)) = foldl max x xs"
proof -
interpret ab_semigroup_idem_mult "max :: 'a => 'a => 'a"
by (fact ab_semigroup_idem_mult_max)
show ?thesis
by (simp add: Max_def fold1_set del: set.simps)
qed
lemma (in complete_lattice) Inf_set_fold [code_unfold]:
"Inf (set xs) = foldl inf top xs"
proof -
interpret comp_fun_idem "inf :: 'a => 'a => 'a"
by (fact comp_fun_idem_inf)
show ?thesis by (simp add: Inf_fold_inf fold_set inf_commute)
qed
lemma (in complete_lattice) Sup_set_fold [code_unfold]:
"Sup (set xs) = foldl sup bot xs"
proof -
interpret comp_fun_idem "sup :: 'a => 'a => 'a"
by (fact comp_fun_idem_sup)
show ?thesis by (simp add: Sup_fold_sup fold_set sup_commute)
qed
lemma (in complete_lattice) INFI_set_fold:
"INFI (set xs) f = foldl (λy x. inf (f x) y) top xs"
unfolding INF_def set_map [symmetric] Inf_set_fold foldl_map
by (simp add: inf_commute)
lemma (in complete_lattice) SUPR_set_fold:
"SUPR (set xs) f = foldl (λy x. sup (f x) y) bot xs"
unfolding SUP_def set_map [symmetric] Sup_set_fold foldl_map
by (simp add: sup_commute)
subsubsection {* @{text upt} *}
lemma upt_rec[code]: "[i..<j] = (if i<j then i#[Suc i..<j] else [])"
-- {* simp does not terminate! *}
by (induct j) auto
lemmas upt_rec_number_of[simp] = upt_rec[of "number_of m" "number_of n", standard]
lemma upt_conv_Nil [simp]: "j <= i ==> [i..<j] = []"
by (subst upt_rec) simp
lemma upt_eq_Nil_conv[simp]: "([i..<j] = []) = (j = 0 ∨ j <= i)"
by(induct j)simp_all
lemma upt_eq_Cons_conv:
"([i..<j] = x#xs) = (i < j & i = x & [i+1..<j] = xs)"
apply(induct j arbitrary: x xs)
apply simp
apply(clarsimp simp add: append_eq_Cons_conv)
apply arith
done
lemma upt_Suc_append: "i <= j ==> [i..<(Suc j)] = [i..<j]@[j]"
-- {* Only needed if @{text upt_Suc} is deleted from the simpset. *}
by simp
lemma upt_conv_Cons: "i < j ==> [i..<j] = i # [Suc i..<j]"
by (simp add: upt_rec)
lemma upt_add_eq_append: "i<=j ==> [i..<j+k] = [i..<j]@[j..<j+k]"
-- {* LOOPS as a simprule, since @{text "j <= j"}. *}
by (induct k) auto
lemma length_upt [simp]: "length [i..<j] = j - i"
by (induct j) (auto simp add: Suc_diff_le)
lemma nth_upt [simp]: "i + k < j ==> [i..<j] ! k = i + k"
apply (induct j)
apply (auto simp add: less_Suc_eq nth_append split: nat_diff_split)
done
lemma hd_upt[simp]: "i < j ==> hd[i..<j] = i"
by(simp add:upt_conv_Cons)
lemma last_upt[simp]: "i < j ==> last[i..<j] = j - 1"
apply(cases j)
apply simp
by(simp add:upt_Suc_append)
lemma take_upt [simp]: "i+m <= n ==> take m [i..<n] = [i..<i+m]"
apply (induct m arbitrary: i, simp)
apply (subst upt_rec)
apply (rule sym)
apply (subst upt_rec)
apply (simp del: upt.simps)
done
lemma drop_upt[simp]: "drop m [i..<j] = [i+m..<j]"
apply(induct j)
apply auto
done
lemma map_Suc_upt: "map Suc [m..<n] = [Suc m..<Suc n]"
by (induct n) auto
lemma nth_map_upt: "i < n-m ==> (map f [m..<n]) ! i = f(m+i)"
apply (induct n m arbitrary: i rule: diff_induct)
prefer 3 apply (subst map_Suc_upt[symmetric])
apply (auto simp add: less_diff_conv)
done
lemma nth_take_lemma:
"k <= length xs ==> k <= length ys ==>
(!!i. i < k --> xs!i = ys!i) ==> take k xs = take k ys"
apply (atomize, induct k arbitrary: xs ys)
apply (simp_all add: less_Suc_eq_0_disj all_conj_distrib, clarify)
txt {* Both lists must be non-empty *}
apply (case_tac xs, simp)
apply (case_tac ys, clarify)
apply (simp (no_asm_use))
apply clarify
txt {* prenexing's needed, not miniscoping *}
apply (simp (no_asm_use) add: all_simps [symmetric] del: all_simps)
apply blast
done
lemma nth_equalityI:
"[| length xs = length ys; ALL i < length xs. xs!i = ys!i |] ==> xs = ys"
by (frule nth_take_lemma [OF le_refl eq_imp_le]) simp_all
lemma map_nth:
"map (λi. xs ! i) [0..<length xs] = xs"
by (rule nth_equalityI, auto)
(* needs nth_equalityI *)
lemma list_all2_antisym:
"[| (!!x y. [|P x y; Q y x|] ==> x = y); list_all2 P xs ys; list_all2 Q ys xs |]
==> xs = ys"
apply (simp add: list_all2_conv_all_nth)
apply (rule nth_equalityI, blast, simp)
done
lemma take_equalityI: "(∀i. take i xs = take i ys) ==> xs = ys"
-- {* The famous take-lemma. *}
apply (drule_tac x = "max (length xs) (length ys)" in spec)
apply (simp add: le_max_iff_disj)
done
lemma take_Cons':
"take n (x # xs) = (if n = 0 then [] else x # take (n - 1) xs)"
by (cases n) simp_all
lemma drop_Cons':
"drop n (x # xs) = (if n = 0 then x # xs else drop (n - 1) xs)"
by (cases n) simp_all
lemma nth_Cons': "(x # xs)!n = (if n = 0 then x else xs!(n - 1))"
by (cases n) simp_all
lemmas take_Cons_number_of = take_Cons'[of "number_of v",standard]
lemmas drop_Cons_number_of = drop_Cons'[of "number_of v",standard]
lemmas nth_Cons_number_of = nth_Cons'[of _ _ "number_of v",standard]
declare take_Cons_number_of [simp]
drop_Cons_number_of [simp]
nth_Cons_number_of [simp]
subsubsection {* @{text upto}: interval-list on @{typ int} *}
(* FIXME make upto tail recursive? *)
function upto :: "int => int => int list" ("(1[_../_])") where
"upto i j = (if i ≤ j then i # [i+1..j] else [])"
by auto
termination
by(relation "measure(%(i::int,j). nat(j - i + 1))") auto
declare upto.simps[code, simp del]
lemmas upto_rec_number_of[simp] =
upto.simps[of "number_of m" "number_of n", standard]
lemma upto_empty[simp]: "j < i ==> [i..j] = []"
by(simp add: upto.simps)
lemma set_upto[simp]: "set[i..j] = {i..j}"
proof(induct i j rule:upto.induct)
case (1 i j)
from this show ?case
unfolding upto.simps[of i j] simp_from_to[of i j] by auto
qed
subsubsection {* @{text "distinct"} and @{text remdups} *}
lemma distinct_tl:
"distinct xs ==> distinct (tl xs)"
by (cases xs) simp_all
lemma distinct_append [simp]:
"distinct (xs @ ys) = (distinct xs ∧ distinct ys ∧ set xs ∩ set ys = {})"
by (induct xs) auto
lemma distinct_rev[simp]: "distinct(rev xs) = distinct xs"
by(induct xs) auto
lemma set_remdups [simp]: "set (remdups xs) = set xs"
by (induct xs) (auto simp add: insert_absorb)
lemma distinct_remdups [iff]: "distinct (remdups xs)"
by (induct xs) auto
lemma distinct_remdups_id: "distinct xs ==> remdups xs = xs"
by (induct xs, auto)
lemma remdups_id_iff_distinct [simp]: "remdups xs = xs <-> distinct xs"
by (metis distinct_remdups distinct_remdups_id)
lemma finite_distinct_list: "finite A ==> EX xs. set xs = A & distinct xs"
by (metis distinct_remdups finite_list set_remdups)
lemma remdups_eq_nil_iff [simp]: "(remdups x = []) = (x = [])"
by (induct x, auto)
lemma remdups_eq_nil_right_iff [simp]: "([] = remdups x) = (x = [])"
by (induct x, auto)
lemma length_remdups_leq[iff]: "length(remdups xs) <= length xs"
by (induct xs) auto
lemma length_remdups_eq[iff]:
"(length (remdups xs) = length xs) = (remdups xs = xs)"
apply(induct xs)
apply auto
apply(subgoal_tac "length (remdups xs) <= length xs")
apply arith
apply(rule length_remdups_leq)
done
lemma remdups_filter: "remdups(filter P xs) = filter P (remdups xs)"
apply(induct xs)
apply auto
done
lemma distinct_map:
"distinct(map f xs) = (distinct xs & inj_on f (set xs))"
by (induct xs) auto
lemma distinct_filter [simp]: "distinct xs ==> distinct (filter P xs)"
by (induct xs) auto
lemma distinct_upt[simp]: "distinct[i..<j]"
by (induct j) auto
lemma distinct_upto[simp]: "distinct[i..j]"
apply(induct i j rule:upto.induct)
apply(subst upto.simps)
apply(simp)
done
lemma distinct_take[simp]: "distinct xs ==> distinct (take i xs)"
apply(induct xs arbitrary: i)
apply simp
apply (case_tac i)
apply simp_all
apply(blast dest:in_set_takeD)
done
lemma distinct_drop[simp]: "distinct xs ==> distinct (drop i xs)"
apply(induct xs arbitrary: i)
apply simp
apply (case_tac i)
apply simp_all
done
lemma distinct_list_update:
assumes d: "distinct xs" and a: "a ∉ set xs - {xs!i}"
shows "distinct (xs[i:=a])"
proof (cases "i < length xs")
case True
with a have "a ∉ set (take i xs @ xs ! i # drop (Suc i) xs) - {xs!i}"
apply (drule_tac id_take_nth_drop) by simp
with d True show ?thesis
apply (simp add: upd_conv_take_nth_drop)
apply (drule subst [OF id_take_nth_drop]) apply assumption
apply simp apply (cases "a = xs!i") apply simp by blast
next
case False with d show ?thesis by auto
qed
lemma distinct_concat:
assumes "distinct xs"
and "!! ys. ys ∈ set xs ==> distinct ys"
and "!! ys zs. [| ys ∈ set xs ; zs ∈ set xs ; ys ≠ zs |] ==> set ys ∩ set zs = {}"
shows "distinct (concat xs)"
using assms by (induct xs) auto
text {* It is best to avoid this indexed version of distinct, but
sometimes it is useful. *}
lemma distinct_conv_nth:
"distinct xs = (∀i < size xs. ∀j < size xs. i ≠ j --> xs!i ≠ xs!j)"
apply (induct xs, simp, simp)
apply (rule iffI, clarsimp)
apply (case_tac i)
apply (case_tac j, simp)
apply (simp add: set_conv_nth)
apply (case_tac j)
apply (clarsimp simp add: set_conv_nth, simp)
apply (rule conjI)
(*TOO SLOW
apply (metis Zero_neq_Suc gr0_conv_Suc in_set_conv_nth lessI less_trans_Suc nth_Cons' nth_Cons_Suc)
*)
apply (clarsimp simp add: set_conv_nth)
apply (erule_tac x = 0 in allE, simp)
apply (erule_tac x = "Suc i" in allE, simp, clarsimp)
(*TOO SLOW
apply (metis Suc_Suc_eq lessI less_trans_Suc nth_Cons_Suc)
*)
apply (erule_tac x = "Suc i" in allE, simp)
apply (erule_tac x = "Suc j" in allE, simp)
done
lemma nth_eq_iff_index_eq:
"[| distinct xs; i < length xs; j < length xs |] ==> (xs!i = xs!j) = (i = j)"
by(auto simp: distinct_conv_nth)
lemma distinct_card: "distinct xs ==> card (set xs) = size xs"
by (induct xs) auto
lemma card_distinct: "card (set xs) = size xs ==> distinct xs"
proof (induct xs)
case Nil thus ?case by simp
next
case (Cons x xs)
show ?case
proof (cases "x ∈ set xs")
case False with Cons show ?thesis by simp
next
case True with Cons.prems
have "card (set xs) = Suc (length xs)"
by (simp add: card_insert_if split: split_if_asm)
moreover have "card (set xs) ≤ length xs" by (rule card_length)
ultimately have False by simp
thus ?thesis ..
qed
qed
lemma not_distinct_decomp: "~ distinct ws ==> EX xs ys zs y. ws = xs@[y]@ys@[y]@zs"
apply (induct n == "length ws" arbitrary:ws) apply simp
apply(case_tac ws) apply simp
apply (simp split:split_if_asm)
apply (metis Cons_eq_appendI eq_Nil_appendI split_list)
done
lemma length_remdups_concat:
"length (remdups (concat xss)) = card (\<Union>xs∈set xss. set xs)"
by (simp add: distinct_card [symmetric])
lemma length_remdups_card_conv: "length(remdups xs) = card(set xs)"
proof -
have xs: "concat[xs] = xs" by simp
from length_remdups_concat[of "[xs]"] show ?thesis unfolding xs by simp
qed
lemma remdups_remdups:
"remdups (remdups xs) = remdups xs"
by (induct xs) simp_all
lemma distinct_butlast:
assumes "xs ≠ []" and "distinct xs"
shows "distinct (butlast xs)"
proof -
from `xs ≠ []` obtain ys y where "xs = ys @ [y]" by (cases xs rule: rev_cases) auto
with `distinct xs` show ?thesis by simp
qed
lemma remdups_map_remdups:
"remdups (map f (remdups xs)) = remdups (map f xs)"
by (induct xs) simp_all
lemma distinct_zipI1:
assumes "distinct xs"
shows "distinct (zip xs ys)"
proof (rule zip_obtain_same_length)
fix xs' :: "'a list" and ys' :: "'b list" and n
assume "length xs' = length ys'"
assume "xs' = take n xs"
with assms have "distinct xs'" by simp
with `length xs' = length ys'` show "distinct (zip xs' ys')"
by (induct xs' ys' rule: list_induct2) (auto elim: in_set_zipE)
qed
lemma distinct_zipI2:
assumes "distinct ys"
shows "distinct (zip xs ys)"
proof (rule zip_obtain_same_length)
fix xs' :: "'b list" and ys' :: "'a list" and n
assume "length xs' = length ys'"
assume "ys' = take n ys"
with assms have "distinct ys'" by simp
with `length xs' = length ys'` show "distinct (zip xs' ys')"
by (induct xs' ys' rule: list_induct2) (auto elim: in_set_zipE)
qed
(* The next two lemmas help Sledgehammer. *)
lemma distinct_singleton: "distinct [x]" by simp
lemma distinct_length_2_or_more:
"distinct (a # b # xs) <-> (a ≠ b ∧ distinct (a # xs) ∧ distinct (b # xs))"
by (metis distinct.simps(2) hd.simps hd_in_set list.simps(2) set_ConsD set_rev_mp set_subset_Cons)
subsubsection {* List summation: @{const listsum} and @{text"∑"}*}
lemma (in monoid_add) listsum_foldl [code]:
"listsum = foldl (op +) 0"
by (simp add: listsum_def foldl_foldr1 fun_eq_iff)
lemma (in monoid_add) listsum_simps [simp]:
"listsum [] = 0"
"listsum (x#xs) = x + listsum xs"
by (simp_all add: listsum_def)
lemma (in monoid_add) listsum_append [simp]:
"listsum (xs @ ys) = listsum xs + listsum ys"
by (induct xs) (simp_all add: add.assoc)
lemma (in comm_monoid_add) listsum_rev [simp]:
"listsum (rev xs) = listsum xs"
by (simp add: listsum_def [of "rev xs"]) (simp add: listsum_foldl foldr_foldl add.commute)
lemma (in comm_monoid_add) listsum_map_remove1:
"x ∈ set xs ==> listsum (map f xs) = f x + listsum (map f (remove1 x xs))"
by (induct xs) (auto simp add: ac_simps)
lemma (in monoid_add) list_size_conv_listsum:
"list_size f xs = listsum (map f xs) + size xs"
by (induct xs) auto
lemma (in monoid_add) length_concat:
"length (concat xss) = listsum (map length xss)"
by (induct xss) simp_all
lemma (in monoid_add) listsum_map_filter:
assumes "!!x. x ∈ set xs ==> ¬ P x ==> f x = 0"
shows "listsum (map f (filter P xs)) = listsum (map f xs)"
using assms by (induct xs) auto
lemma (in monoid_add) distinct_listsum_conv_Setsum:
"distinct xs ==> listsum xs = Setsum (set xs)"
by (induct xs) simp_all
lemma listsum_eq_0_nat_iff_nat [simp]:
"listsum ns = (0::nat) <-> (∀n ∈ set ns. n = 0)"
by (simp add: listsum_foldl)
lemma elem_le_listsum_nat:
"k < size ns ==> ns ! k ≤ listsum (ns::nat list)"
apply(induct ns arbitrary: k)
apply simp
apply(fastforce simp add:nth_Cons split: nat.split)
done
lemma listsum_update_nat:
"k<size ns ==> listsum (ns[k := (n::nat)]) = listsum ns + n - ns ! k"
apply(induct ns arbitrary:k)
apply (auto split:nat.split)
apply(drule elem_le_listsum_nat)
apply arith
done
text{* Some syntactic sugar for summing a function over a list: *}
syntax
"_listsum" :: "pttrn => 'a list => 'b => 'b" ("(3SUM _<-_. _)" [0, 51, 10] 10)
syntax (xsymbols)
"_listsum" :: "pttrn => 'a list => 'b => 'b" ("(3∑_\<leftarrow>_. _)" [0, 51, 10] 10)
syntax (HTML output)
"_listsum" :: "pttrn => 'a list => 'b => 'b" ("(3∑_\<leftarrow>_. _)" [0, 51, 10] 10)
translations -- {* Beware of argument permutation! *}
"SUM x<-xs. b" == "CONST listsum (CONST map (%x. b) xs)"
"∑x\<leftarrow>xs. b" == "CONST listsum (CONST map (%x. b) xs)"
lemma (in monoid_add) listsum_triv:
"(∑x\<leftarrow>xs. r) = of_nat (length xs) * r"
by (induct xs) (simp_all add: left_distrib)
lemma (in monoid_add) listsum_0 [simp]:
"(∑x\<leftarrow>xs. 0) = 0"
by (induct xs) (simp_all add: left_distrib)
text{* For non-Abelian groups @{text xs} needs to be reversed on one side: *}
lemma (in ab_group_add) uminus_listsum_map:
"- listsum (map f xs) = listsum (map (uminus o f) xs)"
by (induct xs) simp_all
lemma (in comm_monoid_add) listsum_addf:
"(∑x\<leftarrow>xs. f x + g x) = listsum (map f xs) + listsum (map g xs)"
by (induct xs) (simp_all add: algebra_simps)
lemma (in ab_group_add) listsum_subtractf:
"(∑x\<leftarrow>xs. f x - g x) = listsum (map f xs) - listsum (map g xs)"
by (induct xs) (simp_all add: algebra_simps)
lemma (in semiring_0) listsum_const_mult:
"(∑x\<leftarrow>xs. c * f x) = c * (∑x\<leftarrow>xs. f x)"
by (induct xs) (simp_all add: algebra_simps)
lemma (in semiring_0) listsum_mult_const:
"(∑x\<leftarrow>xs. f x * c) = (∑x\<leftarrow>xs. f x) * c"
by (induct xs) (simp_all add: algebra_simps)
lemma (in ordered_ab_group_add_abs) listsum_abs:
"¦listsum xs¦ ≤ listsum (map abs xs)"
by (induct xs) (simp_all add: order_trans [OF abs_triangle_ineq])
lemma listsum_mono:
fixes f g :: "'a => 'b::{monoid_add, ordered_ab_semigroup_add}"
shows "(!!x. x ∈ set xs ==> f x ≤ g x) ==> (∑x\<leftarrow>xs. f x) ≤ (∑x\<leftarrow>xs. g x)"
by (induct xs) (simp, simp add: add_mono)
lemma (in monoid_add) listsum_distinct_conv_setsum_set:
"distinct xs ==> listsum (map f xs) = setsum f (set xs)"
by (induct xs) simp_all
lemma (in monoid_add) interv_listsum_conv_setsum_set_nat:
"listsum (map f [m..<n]) = setsum f (set [m..<n])"
by (simp add: listsum_distinct_conv_setsum_set)
lemma (in monoid_add) interv_listsum_conv_setsum_set_int:
"listsum (map f [k..l]) = setsum f (set [k..l])"
by (simp add: listsum_distinct_conv_setsum_set)
text {* General equivalence between @{const listsum} and @{const setsum} *}
lemma (in monoid_add) listsum_setsum_nth:
"listsum xs = (∑ i = 0 ..< length xs. xs ! i)"
using interv_listsum_conv_setsum_set_nat [of "op ! xs" 0 "length xs"] by (simp add: map_nth)
subsubsection {* @{const insert} *}
lemma in_set_insert [simp]:
"x ∈ set xs ==> List.insert x xs = xs"
by (simp add: List.insert_def)
lemma not_in_set_insert [simp]:
"x ∉ set xs ==> List.insert x xs = x # xs"
by (simp add: List.insert_def)
lemma insert_Nil [simp]:
"List.insert x [] = [x]"
by simp
lemma set_insert [simp]:
"set (List.insert x xs) = insert x (set xs)"
by (auto simp add: List.insert_def)
lemma distinct_insert [simp]:
"distinct xs ==> distinct (List.insert x xs)"
by (simp add: List.insert_def)
lemma insert_remdups:
"List.insert x (remdups xs) = remdups (List.insert x xs)"
by (simp add: List.insert_def)
subsubsection {* @{text remove1} *}
lemma remove1_append:
"remove1 x (xs @ ys) =
(if x ∈ set xs then remove1 x xs @ ys else xs @ remove1 x ys)"
by (induct xs) auto
lemma remove1_commute: "remove1 x (remove1 y zs) = remove1 y (remove1 x zs)"
by (induct zs) auto
lemma in_set_remove1[simp]:
"a ≠ b ==> a : set(remove1 b xs) = (a : set xs)"
apply (induct xs)
apply auto
done
lemma set_remove1_subset: "set(remove1 x xs) <= set xs"
apply(induct xs)
apply simp
apply simp
apply blast
done
lemma set_remove1_eq [simp]: "distinct xs ==> set(remove1 x xs) = set xs - {x}"
apply(induct xs)
apply simp
apply simp
apply blast
done
lemma length_remove1:
"length(remove1 x xs) = (if x : set xs then length xs - 1 else length xs)"
apply (induct xs)
apply (auto dest!:length_pos_if_in_set)
done
lemma remove1_filter_not[simp]:
"¬ P x ==> remove1 x (filter P xs) = filter P xs"
by(induct xs) auto
lemma filter_remove1:
"filter Q (remove1 x xs) = remove1 x (filter Q xs)"
by (induct xs) auto
lemma notin_set_remove1[simp]: "x ~: set xs ==> x ~: set(remove1 y xs)"
apply(insert set_remove1_subset)
apply fast
done
lemma distinct_remove1[simp]: "distinct xs ==> distinct(remove1 x xs)"
by (induct xs) simp_all
lemma remove1_remdups:
"distinct xs ==> remove1 x (remdups xs) = remdups (remove1 x xs)"
by (induct xs) simp_all
lemma remove1_idem:
assumes "x ∉ set xs"
shows "remove1 x xs = xs"
using assms by (induct xs) simp_all
subsubsection {* @{text removeAll} *}
lemma removeAll_filter_not_eq:
"removeAll x = filter (λy. x ≠ y)"
proof
fix xs
show "removeAll x xs = filter (λy. x ≠ y) xs"
by (induct xs) auto
qed
lemma removeAll_append[simp]:
"removeAll x (xs @ ys) = removeAll x xs @ removeAll x ys"
by (induct xs) auto
lemma set_removeAll[simp]: "set(removeAll x xs) = set xs - {x}"
by (induct xs) auto
lemma removeAll_id[simp]: "x ∉ set xs ==> removeAll x xs = xs"
by (induct xs) auto
(* Needs count:: 'a => a' list => nat
lemma length_removeAll:
"length(removeAll x xs) = length xs - count x xs"
*)
lemma removeAll_filter_not[simp]:
"¬ P x ==> removeAll x (filter P xs) = filter P xs"
by(induct xs) auto
lemma distinct_removeAll:
"distinct xs ==> distinct (removeAll x xs)"
by (simp add: removeAll_filter_not_eq)
lemma distinct_remove1_removeAll:
"distinct xs ==> remove1 x xs = removeAll x xs"
by (induct xs) simp_all
lemma map_removeAll_inj_on: "inj_on f (insert x (set xs)) ==>
map f (removeAll x xs) = removeAll (f x) (map f xs)"
by (induct xs) (simp_all add:inj_on_def)
lemma map_removeAll_inj: "inj f ==>
map f (removeAll x xs) = removeAll (f x) (map f xs)"
by(metis map_removeAll_inj_on subset_inj_on subset_UNIV)
subsubsection {* @{text replicate} *}
lemma length_replicate [simp]: "length (replicate n x) = n"
by (induct n) auto
lemma Ex_list_of_length: "∃xs. length xs = n"
by (rule exI[of _ "replicate n undefined"]) simp
lemma map_replicate [simp]: "map f (replicate n x) = replicate n (f x)"
by (induct n) auto
lemma map_replicate_const:
"map (λ x. k) lst = replicate (length lst) k"
by (induct lst) auto
lemma replicate_app_Cons_same:
"(replicate n x) @ (x # xs) = x # replicate n x @ xs"
by (induct n) auto
lemma rev_replicate [simp]: "rev (replicate n x) = replicate n x"
apply (induct n, simp)
apply (simp add: replicate_app_Cons_same)
done
lemma replicate_add: "replicate (n + m) x = replicate n x @ replicate m x"
by (induct n) auto
text{* Courtesy of Matthias Daum: *}
lemma append_replicate_commute:
"replicate n x @ replicate k x = replicate k x @ replicate n x"
apply (simp add: replicate_add [THEN sym])
apply (simp add: add_commute)
done
text{* Courtesy of Andreas Lochbihler: *}
lemma filter_replicate:
"filter P (replicate n x) = (if P x then replicate n x else [])"
by(induct n) auto
lemma hd_replicate [simp]: "n ≠ 0 ==> hd (replicate n x) = x"
by (induct n) auto
lemma tl_replicate [simp]: "n ≠ 0 ==> tl (replicate n x) = replicate (n - 1) x"
by (induct n) auto
lemma last_replicate [simp]: "n ≠ 0 ==> last (replicate n x) = x"
by (atomize (full), induct n) auto
lemma nth_replicate[simp]: "i < n ==> (replicate n x)!i = x"
apply (induct n arbitrary: i, simp)
apply (simp add: nth_Cons split: nat.split)
done
text{* Courtesy of Matthias Daum (2 lemmas): *}
lemma take_replicate[simp]: "take i (replicate k x) = replicate (min i k) x"
apply (case_tac "k ≤ i")
apply (simp add: min_def)
apply (drule not_leE)
apply (simp add: min_def)
apply (subgoal_tac "replicate k x = replicate i x @ replicate (k - i) x")
apply simp
apply (simp add: replicate_add [symmetric])
done
lemma drop_replicate[simp]: "drop i (replicate k x) = replicate (k-i) x"
apply (induct k arbitrary: i)
apply simp
apply clarsimp
apply (case_tac i)
apply simp
apply clarsimp
done
lemma set_replicate_Suc: "set (replicate (Suc n) x) = {x}"
by (induct n) auto
lemma set_replicate [simp]: "n ≠ 0 ==> set (replicate n x) = {x}"
by (fast dest!: not0_implies_Suc intro!: set_replicate_Suc)
lemma set_replicate_conv_if: "set (replicate n x) = (if n = 0 then {} else {x})"
by auto
lemma in_set_replicate[simp]: "(x : set (replicate n y)) = (x = y & n ≠ 0)"
by (simp add: set_replicate_conv_if)
lemma Ball_set_replicate[simp]:
"(ALL x : set(replicate n a). P x) = (P a | n=0)"
by(simp add: set_replicate_conv_if)
lemma Bex_set_replicate[simp]:
"(EX x : set(replicate n a). P x) = (P a & n≠0)"
by(simp add: set_replicate_conv_if)
lemma replicate_append_same:
"replicate i x @ [x] = x # replicate i x"
by (induct i) simp_all
lemma map_replicate_trivial:
"map (λi. x) [0..<i] = replicate i x"
by (induct i) (simp_all add: replicate_append_same)
lemma concat_replicate_trivial[simp]:
"concat (replicate i []) = []"
by (induct i) (auto simp add: map_replicate_const)
lemma replicate_empty[simp]: "(replicate n x = []) <-> n=0"
by (induct n) auto
lemma empty_replicate[simp]: "([] = replicate n x) <-> n=0"
by (induct n) auto
lemma replicate_eq_replicate[simp]:
"(replicate m x = replicate n y) <-> (m=n & (m≠0 --> x=y))"
apply(induct m arbitrary: n)
apply simp
apply(induct_tac n)
apply auto
done
lemma replicate_length_filter:
"replicate (length (filter (λy. x = y) xs)) x = filter (λy. x = y) xs"
by (induct xs) auto
lemma comm_append_are_replicate:
fixes xs ys :: "'a list"
assumes "xs ≠ []" "ys ≠ []"
assumes "xs @ ys = ys @ xs"
shows "∃m n zs. concat (replicate m zs) = xs ∧ concat (replicate n zs) = ys"
using assms
proof (induct "length (xs @ ys)" arbitrary: xs ys rule: less_induct)
case less
def xs' ≡ "if (length xs ≤ length ys) then xs else ys"
and ys' ≡ "if (length xs ≤ length ys) then ys else xs"
then have
prems': "length xs' ≤ length ys'"
"xs' @ ys' = ys' @ xs'"
and "xs' ≠ []"
and len: "length (xs @ ys) = length (xs' @ ys')"
using less by (auto intro: less.hyps)
from prems'
obtain ws where "ys' = xs' @ ws"
by (auto simp: append_eq_append_conv2)
have "∃m n zs. concat (replicate m zs) = xs' ∧ concat (replicate n zs) = ys'"
proof (cases "ws = []")
case True
then have "concat (replicate 1 xs') = xs'"
and "concat (replicate 1 xs') = ys'"
using `ys' = xs' @ ws` by auto
then show ?thesis by blast
next
case False
from `ys' = xs' @ ws` and `xs' @ ys' = ys' @ xs'`
have "xs' @ ws = ws @ xs'" by simp
then have "∃m n zs. concat (replicate m zs) = xs' ∧ concat (replicate n zs) = ws"
using False and `xs' ≠ []` and `ys' = xs' @ ws` and len
by (intro less.hyps) auto
then obtain m n zs where "concat (replicate m zs) = xs'"
and "concat (replicate n zs) = ws" by blast
moreover
then have "concat (replicate (m + n) zs) = ys'"
using `ys' = xs' @ ws`
by (simp add: replicate_add)
ultimately
show ?thesis by blast
qed
then show ?case
using xs'_def ys'_def by metis
qed
lemma comm_append_is_replicate:
fixes xs ys :: "'a list"
assumes "xs ≠ []" "ys ≠ []"
assumes "xs @ ys = ys @ xs"
shows "∃n zs. n > 1 ∧ concat (replicate n zs) = xs @ ys"
proof -
obtain m n zs where "concat (replicate m zs) = xs"
and "concat (replicate n zs) = ys"
using assms by (metis comm_append_are_replicate)
then have "m + n > 1" and "concat (replicate (m+n) zs) = xs @ ys"
using `xs ≠ []` and `ys ≠ []`
by (auto simp: replicate_add)
then show ?thesis by blast
qed
subsubsection{*@{text rotate1} and @{text rotate}*}
lemma rotate_simps[simp]: "rotate1 [] = [] ∧ rotate1 (x#xs) = xs @ [x]"
by(simp add:rotate1_def)
lemma rotate0[simp]: "rotate 0 = id"
by(simp add:rotate_def)
lemma rotate_Suc[simp]: "rotate (Suc n) xs = rotate1(rotate n xs)"
by(simp add:rotate_def)
lemma rotate_add:
"rotate (m+n) = rotate m o rotate n"
by(simp add:rotate_def funpow_add)
lemma rotate_rotate: "rotate m (rotate n xs) = rotate (m+n) xs"
by(simp add:rotate_add)
lemma rotate1_rotate_swap: "rotate1 (rotate n xs) = rotate n (rotate1 xs)"
by(simp add:rotate_def funpow_swap1)
lemma rotate1_length01[simp]: "length xs <= 1 ==> rotate1 xs = xs"
by(cases xs) simp_all
lemma rotate_length01[simp]: "length xs <= 1 ==> rotate n xs = xs"
apply(induct n)
apply simp
apply (simp add:rotate_def)
done
lemma rotate1_hd_tl: "xs ≠ [] ==> rotate1 xs = tl xs @ [hd xs]"
by(simp add:rotate1_def split:list.split)
lemma rotate_drop_take:
"rotate n xs = drop (n mod length xs) xs @ take (n mod length xs) xs"
apply(induct n)
apply simp
apply(simp add:rotate_def)
apply(cases "xs = []")
apply (simp)
apply(case_tac "n mod length xs = 0")
apply(simp add:mod_Suc)
apply(simp add: rotate1_hd_tl drop_Suc take_Suc)
apply(simp add:mod_Suc rotate1_hd_tl drop_Suc[symmetric] drop_tl[symmetric]
take_hd_drop linorder_not_le)
done
lemma rotate_conv_mod: "rotate n xs = rotate (n mod length xs) xs"
by(simp add:rotate_drop_take)
lemma rotate_id[simp]: "n mod length xs = 0 ==> rotate n xs = xs"
by(simp add:rotate_drop_take)
lemma length_rotate1[simp]: "length(rotate1 xs) = length xs"
by(simp add:rotate1_def split:list.split)
lemma length_rotate[simp]: "length(rotate n xs) = length xs"
by (induct n arbitrary: xs) (simp_all add:rotate_def)
lemma distinct1_rotate[simp]: "distinct(rotate1 xs) = distinct xs"
by(simp add:rotate1_def split:list.split) blast
lemma distinct_rotate[simp]: "distinct(rotate n xs) = distinct xs"
by (induct n) (simp_all add:rotate_def)
lemma rotate_map: "rotate n (map f xs) = map f (rotate n xs)"
by(simp add:rotate_drop_take take_map drop_map)
lemma set_rotate1[simp]: "set(rotate1 xs) = set xs"
by (cases xs) (auto simp add:rotate1_def)
lemma set_rotate[simp]: "set(rotate n xs) = set xs"
by (induct n) (simp_all add:rotate_def)
lemma rotate1_is_Nil_conv[simp]: "(rotate1 xs = []) = (xs = [])"
by(simp add:rotate1_def split:list.split)
lemma rotate_is_Nil_conv[simp]: "(rotate n xs = []) = (xs = [])"
by (induct n) (simp_all add:rotate_def)
lemma rotate_rev:
"rotate n (rev xs) = rev(rotate (length xs - (n mod length xs)) xs)"
apply(simp add:rotate_drop_take rev_drop rev_take)
apply(cases "length xs = 0")
apply simp
apply(cases "n mod length xs = 0")
apply simp
apply(simp add:rotate_drop_take rev_drop rev_take)
done
lemma hd_rotate_conv_nth: "xs ≠ [] ==> hd(rotate n xs) = xs!(n mod length xs)"
apply(simp add:rotate_drop_take hd_append hd_drop_conv_nth hd_conv_nth)
apply(subgoal_tac "length xs ≠ 0")
prefer 2 apply simp
using mod_less_divisor[of "length xs" n] by arith
subsubsection {* @{text sublist} --- a generalization of @{text nth} to sets *}
lemma sublist_empty [simp]: "sublist xs {} = []"
by (auto simp add: sublist_def)
lemma sublist_nil [simp]: "sublist [] A = []"
by (auto simp add: sublist_def)
lemma length_sublist:
"length(sublist xs I) = card{i. i < length xs ∧ i : I}"
by(simp add: sublist_def length_filter_conv_card cong:conj_cong)
lemma sublist_shift_lemma_Suc:
"map fst (filter (%p. P(Suc(snd p))) (zip xs is)) =
map fst (filter (%p. P(snd p)) (zip xs (map Suc is)))"
apply(induct xs arbitrary: "is")
apply simp
apply (case_tac "is")
apply simp
apply simp
done
lemma sublist_shift_lemma:
"map fst [p<-zip xs [i..<i + length xs] . snd p : A] =
map fst [p<-zip xs [0..<length xs] . snd p + i : A]"
by (induct xs rule: rev_induct) (simp_all add: add_commute)
lemma sublist_append:
"sublist (l @ l') A = sublist l A @ sublist l' {j. j + length l : A}"
apply (unfold sublist_def)
apply (induct l' rule: rev_induct, simp)
apply (simp add: upt_add_eq_append[of 0] sublist_shift_lemma)
apply (simp add: add_commute)
done
lemma sublist_Cons:
"sublist (x # l) A = (if 0:A then [x] else []) @ sublist l {j. Suc j : A}"
apply (induct l rule: rev_induct)
apply (simp add: sublist_def)
apply (simp del: append_Cons add: append_Cons[symmetric] sublist_append)
done
lemma set_sublist: "set(sublist xs I) = {xs!i|i. i<size xs ∧ i ∈ I}"
apply(induct xs arbitrary: I)
apply(auto simp: sublist_Cons nth_Cons split:nat.split dest!: gr0_implies_Suc)
done
lemma set_sublist_subset: "set(sublist xs I) ⊆ set xs"
by(auto simp add:set_sublist)
lemma notin_set_sublistI[simp]: "x ∉ set xs ==> x ∉ set(sublist xs I)"
by(auto simp add:set_sublist)
lemma in_set_sublistD: "x ∈ set(sublist xs I) ==> x ∈ set xs"
by(auto simp add:set_sublist)
lemma sublist_singleton [simp]: "sublist [x] A = (if 0 : A then [x] else [])"
by (simp add: sublist_Cons)
lemma distinct_sublistI[simp]: "distinct xs ==> distinct(sublist xs I)"
apply(induct xs arbitrary: I)
apply simp
apply(auto simp add:sublist_Cons)
done
lemma sublist_upt_eq_take [simp]: "sublist l {..<n} = take n l"
apply (induct l rule: rev_in