datatype (set: 'a) list =
Nil (‹[]›)
| Cons (hd: 'a) (tl: "'a list") (infixr‹#› 65) for
map: map
rel: list_all2
pred: list_all where "tl [] = []"
bundle list_syntax begin notation Nil (‹[]›) and Cons (infixr‹#› 65) end
datatype_compat list
lemma [case_names Nil Cons, cases type: list]: 🍋‹for backward compatibility -- names of variables differ› "(y = [] ==> P) ==> (∧a list. y = a # list ==> P) ==> P" by (rule list.exhaust)
lemma [case_names Nil Cons, induct type: list]: 🍋‹for backward compatibility -- names of variables differ› "P [] ==> (∧a list. P list ==> P (a # list)) ==> P list" by (rule list.induct)
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)"
open_bundle filter_syntax 🍋‹Special input syntax for filter› begin
primrec fold :: "('a ==> 'b ==> 'b) ==> 'a list ==> 'b ==> 'b"where
fold_Nil: "fold f [] = id" |
fold_Cons: "fold f (x # xs) = fold f xs ∘ f x"
primrec foldr :: "('a ==> 'b ==> 'b) ==> 'a list ==> 'b ==> 'b"where
foldr_Nil: "foldr f [] = id" |
foldr_Cons: "foldr f (x # xs) = f x ∘ foldr f xs"
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 concat:: "'a list list ==> 'a list"where "concat [] = []" | "concat (x # xs) = x @ concat xs"
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 ‹n = 0› a
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 ‹n = 0›and ‹n = Suc k›\›
primrec (nonexhaustive) 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 ‹n = 0›and ‹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)"
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 ‹xs = []›and ‹xs = z # zs›\›
abbreviation map2 :: "('a ==> 'b ==> 'c) ==> 'a list ==> 'b list ==> 'c list"where "map2 f xs ys ≡ map (λ(x,y). f x y) (zip xs ys)"
primrec product_lists :: "'a list list ==> 'a list list"where "product_lists [] = [[]]" | "product_lists (xs # xss) = concat (map (λx. map (Cons x) (product_lists xss)) xs)"
primrec upt :: "nat ==> nat ==> nat list" (‹(‹indent=1 notation=‹mixfix list interval›\›[_..🚫'])›) where
upt_0: "[i..<0] = []" |
upt_Suc: "[i..<(Suc j)] = (if i ≤ j then [i..
definition insert :: "'a ==> 'a list ==> 'a list"where "insert x xs = (if x ∈ set xs then xs else x # xs)"
definition union :: "'a list ==> 'a list ==> 'a list"where "union = fold insert"
hide_const (open) insert union
hide_fact (open) insert_def union_def
primrec find :: "('a ==> bool) ==> 'a list ==> 'a option"where "find _ [] = None" | "find P (x#xs) = (if P x then Some x else find P xs)"
text‹In the context of multisets, ‹count_list›is equivalent to 🍋‹count ∘ mset›and it is advisable to use the latter.› primrec count_list :: "'a list ==> 'a ==> nat"where "count_list [] y = 0" | "count_list (x#xs) y = (if x=y then count_list xs y + 1 else count_list xs y)"
definition "extract" :: "('a ==> bool) ==> 'a list ==> ('a list * 'a * 'a list) option" where"extract P xs = (case dropWhile (Not ∘ P) xs of [] ==> None | y#ys ==> Some(takeWhile (Not ∘ P) xs, y, ys))"
hide_const (open) "extract"
primrec those :: "'a option list ==> 'a list option" where "those [] = Some []" | "those (x # xs) = (case x of None ==> None | Some y ==> map_option (Cons y) (those xs))"
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)"
definition minus_list_mset :: "'a list ==> 'a list ==> 'a list"where "minus_list_mset xs ys = foldr remove1 ys xs"
definition minus_list_set :: "'a list ==> 'a list ==> 'a list"where "minus_list_set xs ys = foldr removeAll ys xs"
definition inter_list_set :: "'a list ==> 'a list ==> 'a list"where "inter_list_set xs ys = filter (λx. x ∈ set ys) xs"
primrec distinct :: "'a list ==> bool"where "distinct [] ⟷ True" | "distinct (x # xs) ⟷ x ∉ set xs ∧ distinct xs"
fun successively :: "('a ==> 'a ==> bool) ==> 'a list ==> bool"where "successively P [] = True" | "successively P [x] = True" | "successively P (x # y # xs) = (P x y ∧ successively P (y#xs))"
definition distinct_adj where "distinct_adj = successively (≠)"
primrec remdups :: "'a list ==> 'a list"where "remdups [] = []" | "remdups (x # xs) = (if x ∈ set xs then remdups xs else x # remdups xs)"
fun remdups_adj :: "'a list ==> 'a list"where "remdups_adj [] = []" | "remdups_adj [x] = [x]" | "remdups_adj (x # y # xs) = (if x = y then remdups_adj (x # xs) else x # remdups_adj (y # 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 ‹size›is overloaded for all datatypes. Users may refer to the list version as ‹length›.›
abbreviation length :: "'a list ==> nat"where "length ≡ size"
definition enumerate :: "nat ==> 'a list ==> (nat × 'a) list"where
enumerate_eq_zip: "enumerate n xs = zip [n..
definition rotate :: "nat ==> 'a list ==> 'a list"where "rotate n = rotate1 ^^ n"
definition nths :: "'a list => nat set => 'a list"where "nths xs A = map fst (filter (λp. snd p ∈ A) (zip xs [0..
primrec subseqs :: "'a list ==> 'a list list"where "subseqs [] = [[]]" | "subseqs (x#xs) = (let xss = subseqs xs in map (Cons x) xss @ xss)"
primrec n_lists :: "nat ==> 'a list ==> 'a list list"where "n_lists 0 xs = [[]]" | "n_lists (Suc n) xs = concat (map (λys. map (λy. y # ys) xs) (n_lists n xs))"
hide_const (open) n_lists
function splice :: "'a list ==> 'a list ==> 'a list"where "splice [] ys = ys" | "splice (x#xs) ys = x # splice ys xs" by pat_completeness auto
termination by(relation "measure(λ(xs,ys). size xs + size ys)") auto
function shuffles where "shuffles [] ys = {ys}"
| "shuffles xs [] = {xs}"
| "shuffles (x # xs) (y # ys) = (#) x ` shuffles xs (y # ys) ∪ (#) y ` shuffles (x # xs) ys" by pat_completeness simp_all terminationby lexicographic_order
text‹Use only if you cannot use 🍋‹Min›instead:› fun min_list :: "'a::ord list ==> 'a"where "min_list (x # xs) = (case xs of [] ==> x | _ ==> min x (min_list xs))"
text‹Returns first minimum:› fun arg_min_list :: "('a ==> ('b::linorder)) ==> 'a list ==> 'a"where "arg_min_list f [x] = x" | "arg_min_list f (x#y#zs) = (let m = arg_min_list f (y#zs) in if f x ≤ f m then x else m)"
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🚫 [0,2,1] = [0,1]" by simp}\\ @{lemma "concat [[a,b],[c,d,e],[],[f]] = [a,b,c,d,e,f]" by simp}\\ @{lemma "fold f [a,b,c] x = f c (f b (f a x))" by simp}\\ @{lemma "foldr f [a,b,c] x = f a (f b (f c x))" by simp}\\ @{lemma "foldl f x [a,b,c] = f (f (f x a) b) c" by simp}\\ @{lemma "successively (≠) [True,False,True,False]" 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 "enumerate 3 [a,b,c] = [(3,a),(4,b),(5,c)]" by normalization}\\ @{lemma "List.product [a,b] [c,d] = [(a, c), (a, d), (b, c), (b, d)]" by simp}\\ @{lemma "product_lists [[a,b], [c], [d,e]] = [[a,c,d], [a,c,e], [b,c,d], [b,c,e]]" 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 "shuffles [a,b] [c,d] = {[a,b,c,d],[a,c,b,d],[a,c,d,b],[c,a,b,d],[c,a,d,b],[c,d,a,b]}" by (simp add: insert_commute)}\\ @{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🚫 [1,2,3,0] = [1,2]" by simp}\\ @{lemma "dropWhile (%n::nat. n🚫 [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 "remdups_adj [2,2,3,1,1::nat,2,1] = [2,3,1,2,1]" 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 "List.union [2,3,4] [0::int,1,2] = [4,3,0,1,2]" by (simp add: List.insert_def List.union_def)}\\ @{lemma "List.find (%i::int. i>0) [0,0] = None" by simp}\\ @{lemma "List.find (%i::int. i>0) [0,1,0,2] = Some 1" by simp}\\ @{lemma "count_list [0,1,0,2::int] 0 = 2" by (simp)}\\ @{lemma "List.extract (%i::int. i>0) [0,0] = None" by(simp add: extract_def)}\\ @{lemma "List.extract (%i::int. i>0) [0,1,0,2] = Some([0], 1, [0,2])" by(simp add: extract_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 "nths [a,b,c,d,e] {0,2,3} = [a,c,d]" by (simp add:nths_def)}\\ @{lemma "subseqs [a,b] = [[a, b], [a], [b], []]" by simp}\\ @{lemma "List.n_lists 2 [a,b,c] = [[a, a], [b, a], [c, a], [a, b], [b, b], [c, b], [a, c], [b, c], [c, c]]" by (simp add: eval_nat_numeral)}\\ @{lemma "rotate1 [a,b,c,d] = [b,c,d,a]" by simp}\\ @{lemma "rotate 3 [a,b,c,d] = [d,a,b,c]" by (simp add:rotate_def eval_nat_numeral)}\\ @{lemma "replicate 4 a = [a,a,a,a]" by (simp add:eval_nat_numeral)}\\ @{lemma "[2..🚫 = [2,3,4]" by (simp add:eval_nat_numeral)}\\ @{lemma "min_list [3,1,-2::int] = -2" by (simp)}\\ @{lemma "arg_min_list (λi. i*i) [3,-1,1,-2::int] = -1" by (simp)} \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(ed) functions are intended for proofs, not for efficient implementations.›
text‹A sorted predicate w.r.t. a relation:›
fun sorted_wrt :: "('a ==> 'a ==> bool) ==> 'a list ==> bool"where "sorted_wrt P [] = True" | "sorted_wrt P (x # ys) = ((∀y ∈ set ys. P x y) ∧ sorted_wrt P ys)"
lemma sorted_simps: "sorted [] = True""sorted (x # ys) = ((∀y ∈ set ys. x≤y) ∧ sorted ys)" by auto
lemma strict_sorted_simps: "sorted_wrt (<) [] = True""sorted_wrt (<) (x # ys) = ((∀y ∈ set ys. x∧ sorted_wrt (<) ys)" by auto
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 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)"
definition stable_sort_key :: "(('b ==> 'a) ==> 'b list ==> 'b list) ==> bool"where "stable_sort_key sk = (∀f xs k. filter (λy. f y = k) (sk f xs) = filter (λy. f y = k) xs)"
lemma strict_sorted_iff: "sorted_wrt (<) l ⟷ sorted l ∧ distinct l" by (induction l) (auto iff: antisym_conv1)
text‹Input syntax for Haskell-like list comprehension notation. Typical example: ‹[(x,y). x ← xs, y ← ys, x ≠ y]›, the list of all pairs of distinct elements from ‹xs›and ‹ys›. The syntax is as in Haskell, except that ‹|›becomes a dot (like in Isabelle's set comprehension): ‹[e. x ← xs, …]›rather than \verb![e| x 🚫xs, ...]!. The qualifiers after the dot are \begin{description} \item[generators] ‹p ← xs›, where ‹p›is a pattern and ‹xs› an expression of list type, or \item[guards] ‹b›, where ‹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 ‹[e. x ← xs]›is optmized to 🍋‹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.›
syntax (ASCII) "_lc_gen" :: "'a ==> 'a list ==> lc_qual" (‹_ 🚫_›) end
parse_translation‹ let val NilC = Syntax.const 🍋‹Nil›;
val ConsC = Syntax.const 🍋‹Cons›;
val mapC = Syntax.const 🍋‹map›;
val concatC = Syntax.const 🍋‹concat›;
val IfC = Syntax.const 🍋‹If›;
val dummyC = Syntax.const 🍋‹Pure.dummy_pattern›
fun single 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 single e else e;
val case1 = Syntax.const 🍋‹_case1› $ p $ e;
val case2 = Syntax.const 🍋‹_case1› $ dummyC $ NilC;
val cs = Syntax.const 🍋‹_case2› $ case1 $ case2; in Syntax_Trans.abs_tr [x, Case_Translation.case_tr false ctxt [x, cs]] end;
fun pair_pat_tr (x as Free _) e = Syntax_Trans.abs_tr [x, e]
| pair_pat_tr (_ $ p1 $ p2) e = Syntax.const 🍋‹case_prod› $ pair_pat_tr p1 (pair_pat_tr p2 e)
| pair_pat_tr dummy e = Syntax_Trans.abs_tr [Syntax.const "_idtdummy", e]
fun pair_pat ctxt (Const (🍋‹Pair›,_) $ s $ t) =
pair_pat ctxt s andalso pair_pat ctxt t
| pair_pat ctxt (Free (s,_)) = let
val thy = Proof_Context.theory_of ctxt;
val s' = Proof_Context.intern_const ctxt s; in not (Sign.declared_const thy s') end
| pair_pat _ t = (t = dummyC);
fun abs_tr ctxt p e opti = let val p = Term_Position.strip_positions p inif pair_pat ctxt p then (pair_pat_tr p e, true)
else (pat_tr ctxt p e opti, false) end
fun lc_tr ctxt [e, Const (🍋‹_lc_test›, _) $ b, qs] = let
val res =
(case qs of
Const (🍋‹_lc_end›, _) => single e
| Const (🍋‹_lc_quals›, _) $ q $ qs => lc_tr ctxt [e, q, qs]); in IfC $ b $ res $ NilC end
| lc_tr ctxt
[e, Const (🍋‹_lc_gen›, _) $ p $ es,
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 (🍋‹_lc_gen›, _) $ p $ es,
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 [(🍋‹_listcompr›, lc_tr)] end ›
ML_val ‹ let val read = Syntax.read_term 🍋 o Syntax.implode_input; fun check s1 s2 = read s1 aconv read s2 orelse error ("Check failed: " ^ quote (#1 (Input.source_content s1)) ^ Position.here_list [Input.pos_of s1, Input.pos_of s2]); in check ‹[(x,y,z). b]› \
check ‹[(x,y,z). (x,_,y)←xs]›‹map (λ(x,_,y). (x, y, z)) xs›;
check ‹[e x y. (x,_)←xs, y←ys]›‹concat (map (λ(x,_). map (λy. e x y) ys) xs)›;
check ‹[(x,y,z). x🚫 x>b]›‹if x 🚫 then if b 🚫 then [(x, y, z)] else [] else []›;
check ‹[(x,y,z). x←xs, x>b]›‹concat (map (λx. if b 🚫 then [(x, y, z)] else []) xs)›;
check ‹[(x,y,z). x🚫 x←xs]›‹if x 🚫 then map (λx. (x, y, z)) xs else []›;
check ‹[(x,y). Cons True x ← xs]› ‹concat (map (λxa. case xa of [] ==> [] | True # x ==> [(x, y)] | False # x ==> []) xs)›;
check ‹[(x,y,z). Cons x [] ← xs]› ‹concat (map (λxa. case xa of [] ==> [] | [x] ==> [(x, y, z)] | x # aa # lista ==> []) xs)›;
check ‹[(x,y,z). x🚫 x>b, x=d]› ‹if x 🚫 then if b 🚫 then if x = d then [(x, y, z)] else [] else [] else []›;
check ‹[(x,y,z). x🚫 x>b, y←ys]› ‹if x 🚫 then if b 🚫 then map (λy. (x, y, z)) ys else [] else []›;
check ‹[(x,y,z). x🚫 (_,x)←xs,y>b]› ‹if x 🚫 then concat (map (λ(_,x). if b 🚫 then [(x, y, z)] else []) xs) else []›;
check ‹[(x,y,z). x🚫 x←xs, y←ys]› ‹if x 🚫 then concat (map (λx. map (λy. (x, y, z)) ys) xs) else []›;
check ‹[(x,y,z). x←xs, x>b, y🚫› ‹concat (map (λx. if b 🚫 then if y 🚫 then [(x, y, z)] else [] else []) xs)›;
check ‹[(x,y,z). x←xs, x>b, y←ys]› ‹concat (map (λx. if b 🚫 then map (λy. (x, y, z)) ys else []) xs)›;
check ‹[(x,y,z). x←xs, (y,_)←ys,y>x]› ‹concat (map (λx. concat (map (λ(y,_). if x 🚫 then [(x, y, z)] else []) ys)) xs)›;
check ‹[(x,y,z). x←xs, y←ys,z←zs]› ‹concat (map (λx. concat (map (λy. map (λz. (x, y, z)) zs) ys)) xs)› end; ›
ML ‹ (* Simproc for rewriting list comprehensions applied to List.set to set comprehension. *)
signature LIST_TO_SET_COMPREHENSION =
sig
val proc: Simplifier.proc end
fun right_hand_set_comprehension_conv conv ctxt =
HOLogic.Trueprop_conv (HOLogic.eq_conv Conv.all_conv
(Collect_conv (all_exists_conv conv o #2) ctxt))
(* term abstraction of list comprehension patterns *)
datatype termlets = If | Case of typ * int
local
val set_Nil_I = @{lemma"set [] = {x. False}"by (simp add: empty_def [symmetric])}
val set_singleton = @{lemma"set [a] = {x. x = a}"by simp}
val inst_Collect_mem_eq = @{lemma"set A = {x. x ∈ set A}"by simp}
val del_refl_eq = @{lemma"(t = t ∧ P) ≡ P"by simp}
fun mk_set T = Const (🍋‹set›, HOLogic.listT T --> HOLogic.mk_setT T) fun dest_set (Const (🍋‹set›, _) $ xs) = xs
fun dest_singleton_list (Const (🍋‹Cons›, _) $ t $ (Const (🍋‹Nil›, _))) = t
| dest_singleton_list t = raise TERM ("dest_singleton_list", [t])
(*We check that one case returns a singleton list and all other cases return [], and return the index of the one singleton list case.*) fun possible_index_of_singleton_case cases = let fun check (i, case_t) s =
(case strip_abs_body case_t of
(Const (🍋‹Nil›, _)) => s
| _ => (case s of SOME NONE => SOME (SOME i) | _ => NONE)) in
fold_index check cases (SOME NONE) |> the_default NONE end
(*returns condition continuing term option*) fun dest_if (Const (🍋‹If›, _) $ cond $ then_t $ Const (🍋‹Nil›, _)) =
SOME (cond, then_t)
| dest_if _ = NONE
(*returns (case_expr type index chosen_case constr_name) option*) fun dest_case ctxt case_term = let
val (case_const, args) = strip_comb case_term in
(case try dest_Const case_const of
SOME (c, T) =>
(case Ctr_Sugar.ctr_sugar_of_case ctxt c of
SOME {ctrs, ...} =>
(case possible_index_of_singleton_case (fst (split_last args)) of
SOME i => let
val constr_names = map dest_Const_name ctrs
val (Ts, _) = strip_type T
val T' = List.last Ts in SOME (List.last args, T', i, nth args i, nth constr_names i) end
| NONE => NONE)
| NONE => NONE)
| NONE => NONE) end
lemma neq_Nil_conv: "(xs ≠ []) = (∃y ys. xs = y # ys)" by (induct xs) auto
lemma tl_Nil: "tl xs = [] ⟷ xs = [] ∨ (∃x. xs = [x])" by (cases xs) auto
lemmas Nil_tl = tl_Nil[THEN eq_iff_swap]
lemma length_induct: "(∧xs. ∀ys. length ys < length xs ⟶ P ys ==> P xs) ==> P xs" by (fact measure_induct)
lemma induct_list012: "[P []; ∧x. P [x]; ∧x y zs. [ P zs; P (y # zs) ]==> P (x # y # zs)]==> P xs" by induction_schema (pat_completeness, lexicographic_order)
lemma list_nonempty_induct [consumes 1, case_names single cons]: "[ xs ≠ []; ∧x. P [x]; ∧x xs. xs ≠ [] ==> P xs ==> P (x # xs)]==> P xs" by(induction xs rule: induct_list012) auto
lemma Suc_le_length_iff: "(Suc n ≤ length xs) = (∃x ys. xs = x # ys ∧ n ≤ length ys)" by (metis Suc_le_D[of n] Suc_le_mono[of n] Suc_length_conv[of _ xs])
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 (Cons x xs ys) thenshow ?caseby (cases ys) simp_all qed simp
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 thenshow ?caseby simp next case (Cons x xs ys zs) thenshow ?caseby (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 thenshow ?caseby simp next case (Cons x xs ys zs ws) thenshow ?caseby ((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 list_all2_iff: "list_all2 P xs ys ⟷ length xs = length ys ∧ (∀(x, y) ∈ set (zip xs ys). P x y)" by (induct xs ys rule: list_induct2') auto
lemma neq_if_length_neq: "length xs ≠ length ys ==> (xs = ys) == False" by (rule Eq_FalseI) auto
text‹ Simplification procedure for all list equalities. Currently only tries to rearrange ‹@› t
- both lists endin a singleton list,
- or both lists endin the same list. ›
simproc_setup list_eq ("(xs::'a list) = ys") = ‹ let fun last (cons as Const (🍋‹Cons›,
(case xs of Const (🍋‹Nil›, _) => cons | _ => last xs)
| last (Const(🍋‹append›,_) $ _ $ ys) = last ys
| last t = t;
fun list_eq ctxt (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(🍋‹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 ctxt [] [] eq
(K (simp_tac (put_simpset rearr_ss ctxt) 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 K (fn ctxt => fn ct => list_eq ctxt (Thm.term_of ct)) end ›
subsubsection ‹🍋‹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 ∘ g) xs" by (induct xs) auto
lemma ex_map_conv: "(∃xs. ys = map f xs) = (∀y ∈ set ys. ∃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 thenshow ?caseby simp next case (Cons y ys) thenobtain z zs where xs: "xs = z # zs"by auto from Cons xs have"map f zs = map g ys"by simp with Cons have"length zs = length ys"by blast with xs show ?caseby simp qed
lemma map_inj_on: assumes map: "map f xs = map f ys"and inj: "inj_on f (set xs Un set ys)" shows"xs = ys" using map_eq_imp_length_eq [OF map] assms proof (induct rule: list_induct2) case (Cons x xs y ys) thenshow ?case by (auto intro: sym) qed auto
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 (rule list.inj_map)
lemma rev_induct [case_names Nil snoc]: assumes"P []"and"∧x xs. P xs ==> P (xs @ [x])" shows"P xs" proof - have"P (rev (rev xs))" by (rule_tac list = "rev xs"in list.induct, simp_all add: assms) thenshow ?thesis by simp qed
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_nonempty_induct [consumes 1, case_names single snoc]: assumes"xs ≠ []" and single: "∧x. P [x]" and snoc': "∧x xs. xs ≠ [] ==> P xs ==> P (xs@[x])" shows"P xs" using‹xs ≠ []›proof (induct xs rule: rev_induct) case (snoc x xs) thenshow ?case proof (cases xs) case Nil thus ?thesis by (simp add: single) next case Cons with snoc show ?thesis by (fastforce intro!: snoc') qed qed simp
lemma rev_induct2: "[ P [] []; ∧x xs. P (xs @ [x]) []; ∧y ys. P [] (ys @ [y]); ∧x xs y ys. P xs ys ==> P (xs @ [x]) (ys @ [y]) ] ==> P xs ys" proof (induct xs arbitrary: ys rule: rev_induct) case Nil thenshow ?caseusing rev_induct[of "P []"] by presburger next case (snoc x xs) hence"P xs ys'"for ys' by simp thenshow ?caseby (simp add: rev_induct snoc.prems(2,4)) qed
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 (rule list.set_map)
lemma set_filter [simp]: "set (filter P xs) = {x. x ∈ set xs ∧ P x}" by (induct xs) auto
lemma set_upt [simp]: "set[i.. by (induct j) auto
lemma atMost_upto: ‹{..n} = set [0..🚫n]› by auto
lemma atLeast_upt: ‹{..🚫 = set [0..🚫› by auto
lemma greaterThanLessThan_upt: ‹{n🚫🚫 = set [Suc n..🚫› by auto
lemma atLeastLessThan_upt: ‹{i..🚫 = set [i..🚫› by auto
lemma greaterThanAtMost_upt: "{n<..m} = set [Suc n.. by auto
lemma atLeastAtMost_upt: "{n..m} = set [n.. by auto
lemma split_list: "x ∈ set xs ==>∃ys zs. xs = ys @ x # zs" proof (induct xs) case Nil thus ?caseby simp next case Cons thus ?caseby (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 ?caseby simp next case (Cons a xs) show ?case proof cases assume"x = a"thus ?caseusing Cons by fastforce next assume"x ≠ a"thus ?caseusing 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 ?caseby simp next case (snoc a xs) show ?case proof cases assume"x = a"thus ?caseusing snoc by (auto intro!: exI) next assume"x ≠ a"thus ?caseusing 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 ?caseby 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 ?caseby simp next case (Cons x xs) show ?case proof cases assume"P x" hence"x # xs = [] @ x # xs ∧ P x ∧ (∀y∈set []. ¬ P y)"by simp thus ?thesis by fast 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 ?caseby simp next case (snoc x xs) show ?case proof cases assume"P x"thus ?thesis by (auto intro!: exI) 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 rule (erule split_list_last_prop, auto)
lemma finite_list: "finite A ==>∃xs. set xs = A" by (erule finite_induct) (auto simp add: list.set(2)[symmetric] simp del: list.set(2))
lemma hd_concat: "[xs ≠ []; hd xs ≠ []]==> hd (concat xs) = hd (hd xs)" by (metis concat.simps(2) hd_Cons_tl hd_append2)
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(🍋‹Nil›,_)) acc = acc
| len (Const(🍋‹Cons›,_) $ _ $ xs) (ts,n) = len xs (ts,n+1)
| len (Const(🍋‹append›,_) $ xs $ ys) acc = len xs (len ys acc)
| len (Const(🍋‹rev›,_) $ xs) acc = len xs acc
| len (Const(🍋‹map›,_) $ _ $ xs) acc = len xs acc
| len (Const(🍋‹concat›,T) $ (Const(🍋‹rev›,_) $ xss)) acc
= len (Const(🍋‹concat›,T) $ xss) acc
| len t (ts,n) = (t::ts,n);
val ss = simpset_of 🍋;
fun list_neq ctxt 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 ctxt [] [] neq_len
(K (simp_tac (put_simpset ss ctxt) 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 K list_neq end ›
subsubsection ‹🍋‹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 filter_concat: "filter p (concat xs) = concat (map (filter p) 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 filter_id_conv: "(filter P xs = xs) = (∀x∈set xs. P x)" proof (induct xs) case (Cons x xs) thenshow ?case using length_filter_le by (simp add: impossible_Cons) qed auto
lemma filter_map: "filter P (map f xs) = map f (filter (P ∘ f) xs)" by (induct xs) simp_all
lemma length_filter_map[simp]: "length (filter P (map f xs)) = length(filter (P ∘ 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 ?caseby simp next case (Cons x xs) thus ?case using Suc_le_eq by fastforce qed
lemma length_filter_conv_card: "length(filter p xs) = card{i. i < length xs ∧ p(xs!i)}" proof (induct xs) case Nil thus ?caseby 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 alsohave"… = Suc(card(Suc ` ?S))"using fin by (simp add: card_image) alsohave"… = card ?S'"using eq fin by (simp add:card_insert_if) finallyshow ?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 alsohave"… = card(Suc ` ?S)"using fin by (simp add: card_image) alsohave"… = card ?S'"using eq fin by (simp add:card_insert_if) finallyshow ?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 ?caseby 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 thenshow ?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 thenhave"?Q (y#us)"by simp thenshow ?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 inj_on_filter_key_eq: assumes"inj_on f (insert y (set xs))" shows"filter (λx. f y = f x) xs = filter (HOL.eq y) xs" using assms by (induct xs) auto
lemma filter_cong[fundef_cong]: "xs = ys ==> (∧x. x ∈ set ys ==> P x = Q x) ==> filter P xs = filter Q ys" by (induct ys arbitrary: xs) auto
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 ∘ 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 thenshow ?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 thenshow ?thesis by (auto simp add: partition_filter1 partition_filter2) qed
lemma partition_filter_conv[simp]: "partition f xs = (filter f xs,filter (Not ∘ f) xs)" unfolding partition_filter2[symmetric] unfolding partition_filter1[symmetric] by simp
declare partition.simps[simp del]
subsubsection ‹🍋‹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))" proof (induct xs arbitrary: n) case (Cons x xs) thenshow ?case using less_Suc_eq_0_disj by auto qed simp
lemma nth_append_left: "i < length xs ==> (xs @ ys) ! i = xs ! i" by (auto simp: nth_append)
lemma nth_append_right: "i ≥ length xs ==> (xs @ ys) ! i = ys ! (i - length xs)" by (auto simp: nth_append)
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)" proof (induct xs arbitrary: n) case (Cons x xs) thenshow ?case using less_Suc_eq_0_disj by auto qed simp
lemma nth_tl: "n < length (tl xs) ==> tl xs ! n = xs ! Suc n" by (induction xs) auto
lemma list_eq_iff_nth_eq: "(xs = ys) = (length xs = length ys ∧ (∀i proof (induct xs arbitrary: ys) case (Cons x xs ys) show ?case proof (cases ys) case (Cons y ys) with Cons.hyps show ?thesis by fastforce qed simp qed force
lemma map_equality_iff: "map f xs = map g ys ⟷ length xs = length ys ∧ (∀i by (fastforce simp: list_eq_iff_nth_eq)
lemma set_conv_nth: "set xs = {xs!i | i. i < length xs}" proof (induct xs) case (Cons x xs) have"insert x {xs ! i |i. i < length xs} = {(x # xs) ! i |i. i < Suc (length xs)}" (is"?L=?R") proof show"?L ⊆ ?R" by force show"?R ⊆ ?L" using less_Suc_eq_0_disj by auto qed with Cons show ?case by simp qed simp
lemma nth_equal_first_eq: assumes"x ∉ set xs" assumes"n ≤ length xs" shows"(x # xs) ! n = x ⟷ n = 0" (is"?lhs ⟷ ?rhs") proof assume ?lhs show ?rhs proof (rule ccontr) assume"n ≠ 0" thenhave"n > 0"by simp with‹?lhs›have"xs ! (n - 1) = x"by simp moreoverfrom‹n > 0›‹n ≤ length xs›have"n - 1 < length xs"by simp ultimatelyhave"∃iby auto with‹x ∉ set xs› in_set_conv_nth [of x xs] show False by simp qed next assume ?rhs thenshow ?lhs by simp qed
lemma nth_non_equal_first_eq: assumes"x ≠ y" shows"(x # xs) ! n = y ⟷ xs ! (n - 1) = y ∧ n > 0" (is"?lhs ⟷ ?rhs") proof assume"?lhs"with assms have"n > 0"by (cases n) simp_all with‹?lhs›show ?rhs by simp next assume"?rhs"thenshow"?lhs"by simp qed
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 ?caseby simp next case (Cons x xs) hence n: "n < Suc (length xs)"by simp moreover
{ assume"n < length xs" with n obtain n' where n': "length xs - n = Suc n'" by (cases "length xs - n", auto) moreover from n' have"length xs - Suc n = n'"by simp ultimately have"xs ! (length xs - Suc n) = (x # xs) ! (length xs - n)"by simp
} ultimately show ?caseby (clarsimp simp add: Cons nth_append) qed
lemma Skolem_list_nth: "(∀i∃x. P i x) = (∃xs. size xs = k ∧ (∀i
(is"_ = (∃xs. ?P k xs)") proof(induct k) case 0 show ?caseby simp next case (Suc k) show ?case (is"?L = ?R"is"_ = (∃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
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_beyond: "length xs ≤ i ==> xs[i:=x] = xs" proof (induct xs arbitrary: i) case (Cons x xs i) thenshow ?case by (metis leD length_list_update list_eq_iff_nth_eq nth_list_update_neq) qed simp
lemma hd_rev: "hd(rev xs) = last xs" by (metis hd_Cons_tl hd_Nil_eq_last last_snoc rev_eq_Cons_iff rev_is_Nil_conv)
lemma last_rev: "last(rev xs) = hd xs" by (metis hd_rev rev_swap)
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: if_split_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" by (induct xs arbitrary: n)(auto split:nat.split)
lemma nth_butlast: assumes"n < length (butlast xs)"shows"butlast xs ! n = xs ! n" proof (cases xs) case (Cons y ys) moreoverfrom assms have"butlast xs ! n = (butlast xs @ [last xs]) ! n" by (simp add: nth_append) ultimatelyshow ?thesis using append_butlast_last_id by simp qed simp
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_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 hd_take[simp]: "j > 0 ==> hd (take j xs) = hd xs" by (metis gr0_conv_Suc list.sel(1) take.simps(1) take_Suc)
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" by (induct xs arbitrary: n, simp)(auto simp: drop_Cons nth_Cons split: nat.splits)
lemma take_Suc_conv_app_nth: "i < length xs ==> take (Suc i) xs = take i xs @ [xs!i]" proof (induct xs arbitrary: i) case Nil thenshow ?caseby simp next case Cons thenshow ?caseby (cases i) auto qed
lemma Cons_nth_drop_Suc: "i < length xs ==> (xs!i) # (drop (Suc i) xs) = drop i xs" proof (induct xs arbitrary: i) case Nil thenshow ?caseby simp next case Cons thenshow ?caseby (cases i) auto qed
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_all_iff [simp]: "take n xs = xs ⟷ length xs ≤ n" by (metis length_take min.order_iff take_all)
(* Looks like a good simp rule but can cause looping; too much interaction between take and length lemmas take_all_iff2[simp] = take_all_iff[THEN eq_iff_swap] *)
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" proof (induct m arbitrary: xs n) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs; cases n) simp_all qed
lemma drop_drop [simp]: "drop n (drop m xs) = drop (n + m) xs" proof (induct m arbitrary: xs) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs) simp_all qed
lemma take_drop: "take n (drop m xs) = drop m (take (n + m) xs)" proof (induct m arbitrary: xs n) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs; cases n) simp_all qed
lemma drop_take: "drop n (take m xs) = take (m-n) (drop n xs)" by(induct xs arbitrary: m n)(auto simp: take_Cons drop_Cons split: nat.split)
lemma append_take_drop_id [simp]: "take n xs @ drop n xs = xs" proof (induct n arbitrary: xs) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs) simp_all qed
lemma take_map: "take n (map f xs) = map f (take n xs)" proof (induct n arbitrary: xs) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs) simp_all qed
lemma drop_map: "drop n (map f xs) = map f (drop n xs)" proof (induct n arbitrary: xs) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs) simp_all qed
lemma rev_take: "rev (take i xs) = drop (length xs - i) (rev xs)" proof (induct xs arbitrary: i) case Nil thenshow ?caseby simp next case Cons thenshow ?caseby (cases i) auto qed
lemma rev_drop: "rev (drop i xs) = take (length xs - i) (rev xs)" proof (induct xs arbitrary: i) case Nil thenshow ?caseby simp next case Cons thenshow ?caseby (cases i) auto qed
lemma nth_take [simp]: "i < n ==> (take n xs)!i = xs!i" proof (induct xs arbitrary: i n) case Nil thenshow ?caseby simp next case Cons thenshow ?caseby (cases n; cases i) simp_all qed
lemma nth_drop [simp]: "n ≤ length xs ==> (drop n xs)!i = xs!(n + i)" proof (induct n arbitrary: xs) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs) simp_all qed
lemma butlast_take: "n ≤ length xs ==> butlast (take n xs) = take (n - 1) xs" by (simp add: butlast_conv_take)
lemma butlast_drop: "butlast (drop n xs) = drop n (butlast xs)" by (simp add: butlast_conv_take drop_take ac_simps)
lemma take_butlast: "n < length xs ==> take n (butlast xs) = take n xs" by (simp add: butlast_conv_take)
lemma drop_butlast: "drop n (butlast xs) = butlast (drop n xs)" by (simp add: butlast_conv_take drop_take ac_simps)
lemma butlast_power: "(butlast ^^ n) xs = take (length xs - n) xs" by (induct n) (auto simp: butlast_take)
lemma set_take_subset_set_take: "m ≤ n ==> set(take m xs) ≤ set(take n xs)" proof (induct xs arbitrary: m n) case (Cons x xs m n) thenshow ?case by (cases n) (auto simp: take_Cons) qed simp
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)" proof (induct xs arbitrary: m n) case (Cons x xs m n) thenshow ?case by (clarsimp simp: drop_Cons split: nat.split) (metis set_drop_subset subset_iff) qed simp
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)" proof (induct xs arbitrary: zs) case (Cons x xs zs) thenshow ?case by (cases zs, auto) qed auto
lemma map_eq_append_conv: "map f xs = ys @ zs ⟷ (∃us vs. xs = us @ vs ∧ ys = map f us ∧ zs = map f vs)" proof - have"map f xs ≠ ys @ zs ∧ map f xs ≠ ys @ zs ∨ map f xs ≠ ys @ zs ∨ map f xs = ys @ zs ∧ (∃bs bsa. xs = bs @ bsa ∧ ys = map f bs ∧ zs = map f bsa)" by (metis append_eq_conv_conj append_take_drop_id drop_map take_map) thenshow ?thesis using map_append by blast qed
lemma take_add: "take (i+j) xs = take i xs @ take j (drop i xs)" proof (induct xs arbitrary: i) case (Cons x xs i) thenshow ?case by (cases i, auto) qed auto
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)" proof (induct xs🪙1 arbitrary: ys🪙1) case (Cons a xs🪙1 ys🪙1) thenshow ?case by (cases ys🪙1, auto) qed auto
lemma take_hd_drop: "n < length xs ==> take n xs @ [hd (drop n xs)] = take (Suc n) xs" by (induct xs arbitrary: n) (simp_all add:drop_Cons split:nat.split)
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]" using take_Suc_conv_app_nth by blast ultimatelyshow ?thesis by auto qed
lemma take_update_cancel[simp]: "n ≤ m ==> take n (xs[m := y]) = take n xs" by(simp add: list_eq_iff_nth_eq)
lemma drop_update_cancel[simp]: "n < m ==> drop m (xs[n := x]) = drop m xs" by(simp add: list_eq_iff_nth_eq)
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]]) alsohave"… = take i xs @ a # drop (Suc i) xs" using i by (simp add: list_update_append) finallyshow ?thesis . qed
lemma take_update_swap: "take m (xs[n := x]) = (take m xs)[n := x]" proof (cases "n ≥ length xs") case False thenshow ?thesis by (simp add: list_update_beyond upd_conv_take_nth_drop take_Cons drop_take min_def diff_Suc split: nat.split) qed (auto simp: list_update_beyond)
lemma drop_update_swap: assumes"m ≤ n"shows"drop m (xs[n := x]) = (drop m xs)[n-m := x]" proof (cases "n ≥ length xs") case False with assms show ?thesis by (simp add: upd_conv_take_nth_drop drop_take) qed (auto simp: list_update_beyond)
lemma nth_image: "l ≤ size xs ==> nth xs ` {0.. by (simp add: set_conv_nth) force
lemma set_list_update: "set (xs [i := k]) = insert k (set (take i xs) ∪ set (drop (Suc i) xs))" if‹i 🚫 xs› using that proof (induct xs arbitrary: i) case Nil thenshow ?case by simp next case (Cons x xs i) thenshow ?case by (cases i) (simp_all add: insert_commute) qed
subsubsection ‹🍋‹takeWhile›and 🍋‹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_append: "takeWhile P (xs @ ys) = (if ∀x∈set xs. P x then xs @ takeWhile P ys else takeWhile P xs)" using takeWhile_append1[of _ xs P ys] takeWhile_append2[of xs P ys] by auto
lemma takeWhile_tail: "¬ P x ==> takeWhile P (xs @ (x#l)) = takeWhile P xs" by (induct xs) auto
lemma takeWhile_eq_Nil_iff: "takeWhile P xs = [] ⟷ xs = [] ∨¬P (hd xs)" by (cases xs) auto
lemma takeWhile_nth: "j < length (takeWhile P xs) ==> takeWhile P xs ! j = xs ! j" by (metis nth_append takeWhile_dropWhile_id)
lemma takeWhile_takeWhile: "takeWhile Q (takeWhile P xs) = takeWhile (λx. P x ∧ Q x) xs" by(induct xs) simp_all
lemma dropWhile_nth: "j < length (dropWhile P xs) ==> dropWhile P xs ! j = xs ! (j + length (takeWhile P xs))" by (metis add.commute nth_append_length_plus takeWhile_dropWhile_id)
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 dropWhile_id[simp]: "(∧x. x ∈ set xs ==>¬ P x) ==> dropWhile P xs = xs" using takeWhile_dropWhile_id[of P xs] takeWhile_eq_Nil_iff[of P xs] by fastforce
lemma dropWhile_append3: "¬ P y ==>dropWhile P (xs @ y # ys) = dropWhile P xs @ y # ys" by (induct xs) auto
lemma dropWhile_append: "dropWhile P (xs @ ys) = (if ∀x∈set xs. P x then dropWhile P ys else dropWhile P xs @ ys)" using dropWhile_append1[of _ xs P ys] dropWhile_append2[of xs P ys] by auto
lemma dropWhile_last: "x ∈ set xs ==>¬ P x ==> last (dropWhile P xs) = last xs" by (auto simp add: dropWhile_append3 in_set_conv_decomp)
lemma set_dropWhileD: "x ∈ set (dropWhile P xs) ==> x ∈ set xs" by (induct xs) (auto split: if_split_asm)
lemma set_takeWhileD: "x ∈ set (takeWhile P xs) ==> x ∈ set xs ∧ P x" by (induct xs) (auto split: if_split_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 dropWhile_eq_self_iff: "dropWhile P xs = xs ⟷ xs = [] ∨¬P (hd xs)" by (cases xs) (auto simp: dropWhile_eq_Cons_conv)
lemma dropWhile_dropWhile1: "(∧x. Q x ==> P x) ==> dropWhile Q (dropWhile P xs) = dropWhile P xs" by(induct xs) simp_all
lemma dropWhile_dropWhile2: "(∧x. P x ==> Q x) ==> takeWhile P (takeWhile Q xs) = takeWhile P xs" by(induct xs) simp_all
lemma dropWhile_takeWhile: "(∧x. P x ==> Q x) ==> dropWhile P (takeWhile Q xs) = takeWhile Q (dropWhile P xs)" by (induction 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 ∘ f) xs)" by (induct xs) auto
lemma dropWhile_map: "dropWhile P (map f xs) = map f (dropWhile (P ∘ 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))" 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 Nil thus ?caseby simp next case (Cons x xs) show ?case proof (cases n) case 0 with Cons show ?thesis by simp next case [simp]: (Suc n') have"P x"using Cons.prems(1)[of 0] by simp moreoverhave"takeWhile P xs = take n' xs" proof (rule Cons.hyps) fix i assume"i < n'""i < length xs" thus"P (xs ! i)"using Cons.prems(1)[of "Suc i"] by simp next assume"n' < length xs" thus"¬ P (xs ! n')"using Cons by auto qed ultimatelyshow ?thesis by simp qed qed
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
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)" proof (induct xs) case (Cons a xs) thenshow ?case by(auto, subst dropWhile_append2, auto) qed simp
lemma takeWhile_not_last: "distinct xs ==> takeWhile (λy. y ≠ last xs) xs = butlast xs" by(induction xs rule: induct_list012) auto
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)
lemma takeWhile_idem [simp]: "takeWhile P (takeWhile P xs) = takeWhile P xs" by (induct xs) auto
lemma dropWhile_idem [simp]: "dropWhile P (dropWhile P xs) = dropWhile P xs" by (induct xs) auto
subsubsection ‹🍋‹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
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)" by (auto simp: zip_map1)
lemma map_zip_map2: "map f (zip xs (map g ys)) = map (%(x,y). f(x, g y)) (zip xs ys)" by (auto simp: zip_map2)
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)" proof (induct ys arbitrary: i xs) case (Cons y ys) thenshow ?case by (cases xs) (simp_all add: nth.simps split: nat.split) qed auto
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_replicate [simp]: "zip (replicate i x) (replicate j y) = replicate (min i j) (x,y)" proof (induct i arbitrary: j) case (Suc i) thenshow ?case by (cases j, auto) qed auto
lemma zip_replicate1: "zip (replicate n x) ys = map (Pair x) (take n ys)" by(induction ys arbitrary: n)(case_tac [2] n, simp_all)
lemma take_zip: "take n (zip xs ys) = zip (take n xs) (take n ys)" proof (induct n arbitrary: xs ys) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs; cases ys) simp_all qed
lemma drop_zip: "drop n (zip xs ys) = zip (drop n xs) (drop n ys)" proof (induct n arbitrary: xs ys) case 0 thenshow ?caseby simp next case Suc thenshow ?caseby (cases xs; cases ys) simp_all qed
lemma zip_takeWhile_fst: "zip (takeWhile P xs) ys = takeWhile (P ∘ fst) (zip xs ys)" proof (induct xs arbitrary: ys) case Nil thenshow ?caseby simp next case Cons thenshow ?caseby (cases ys) auto qed
lemma zip_takeWhile_snd: "zip xs (takeWhile P ys) = takeWhile (P ∘ snd) (zip xs ys)" proof (induct xs arbitrary: ys) case Nil thenshow ?caseby simp next case Cons thenshow ?caseby (cases ys) auto qed
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 in_set_zip: "p ∈ set (zip xs ys) ⟷ (∃n. xs ! n = fst p ∧ ys ! n = snd p ∧ n < length xs ∧ n < length ys)" by (cases p) (auto simp add: set_zip)
lemma in_set_impl_in_set_zip1: assumes"length xs = length ys" assumes"x ∈ set xs" obtains y where"(x, y) ∈ set (zip xs ys)" proof - from assms have"x ∈ set (map fst (zip xs ys))"by simp from this that show ?thesis by fastforce qed
lemma in_set_impl_in_set_zip2: assumes"length xs = length ys" assumes"y ∈ set ys" obtains x where"(x, y) ∈ set (zip xs ys)" proof - from assms have"y ∈ set (map snd (zip xs ys))"by simp from this that show ?thesis by fastforce qed
lemma zip_eq_ConsE: assumes"zip xs ys = xy # xys" obtains x xs' y ys' where"xs = x # xs'" and"ys = y # ys'"and"xy = (x, y)" and"xys = zip xs' ys'" proof - from assms have"xs ≠ []"and"ys ≠ []" using zip_eq_Nil_iff [of xs ys] by simp_all thenobtain x xs' y ys' where xs: "xs = x # xs'" and ys: "ys = y # ys'" by (cases xs; cases ys) auto with assms have"xy = (x, y)"and"xys = zip xs' ys'" by simp_all with xs ys show ?thesis .. qed
lemma semilattice_map2: "semilattice (map2 (🪙*))"if"semilattice (🪙*)" for f (infixl‹🪙*› 70) proof - from that interpret semilattice f . show ?thesis proof show"map2 (🪙*) (map2 (🪙*) xs ys) zs = map2 (🪙*) xs (map2 (🪙*) ys zs)" for xs ys zs :: "'a list" proof (induction"zip xs (zip ys zs)" arbitrary: xs ys zs) case Nil from Nil [symmetric] show ?case by auto next case (Cons xyz xyzs) from Cons.hyps(2) [symmetric] show ?case by (rule zip_eq_ConsE) (erule zip_eq_ConsE,
auto intro: Cons.hyps(1) simp add: ac_simps) qed show"map2 (🪙*) xs ys = map2 (🪙*) ys xs" for xs ys :: "'a list" proof (induction"zip xs ys" arbitrary: xs ys) case Nil thenshow ?case by auto next case (Cons xy xys) from Cons.hyps(2) [symmetric] show ?case by (rule zip_eq_ConsE) (auto intro: Cons.hyps(1) simp add: ac_simps) qed show"map2 (🪙*) xs xs = xs" for xs :: "'a list" by (induction xs) simp_all qed qed
lemma pair_list_eqI: assumes"map fst xs = map fst ys"and"map snd xs = map snd ys" shows"xs = ys" proof - from assms(1) have"length xs = length ys"by (rule map_eq_imp_length_eq) from this assms show ?thesis by (induct xs ys rule: list_induct2) (simp_all add: prod_eqI) qed
lemma hd_zip: ‹hd (zip xs ys) = (hd xs, hd ys)›if‹xs ≠ []›and‹ys ≠ []› using that by (cases xs; cases ys) simp_all
lemma last_zip: ‹last (zip xs ys) = (last xs, last ys)›if‹xs ≠ []›and‹ys ≠ []› and‹length xs = length ys› using that by (cases xs rule: rev_cases; cases ys rule: rev_cases) simp_all
subsubsection ‹🍋‹list_all2›\›
lemma list_all2_lengthD [intro?]: "list_all2 P xs ys ==> length xs = length ys" by (simp add: list_all2_iff)
lemma list_all2_Nil [iff, code]: "list_all2 P [] ys = (ys = [])" by (simp add: list_all2_iff)
lemma list_all2_Nil2 [iff, code]: "list_all2 P xs [] = (xs = [])" by (simp add: list_all2_iff)
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_iff)
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_induct
[consumes 1, case_names Nil Cons, induct set: list_all2]: assumes P: "list_all2 P xs ys" assumes Nil: "R [] []" assumes Cons: "∧x xs y ys. [P x y; list_all2 P xs ys; R xs ys]==> R (x # xs) (y # ys)" shows"R xs ys" using P by (induct xs arbitrary: ys) (auto simp add: list_all2_Cons1 Nil Cons)
lemma list_all2_rev [iff]: "list_all2 P (rev xs) (rev ys) = list_all2 P xs ys" by (simp add: list_all2_iff 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 = (∃us vs. zs = us @ vs ∧ length us = length xs ∧ length vs = length ys ∧ list_all2 P xs us ∧ list_all2 P ys vs)" (is"?lhs = ?rhs") proof assume ?lhs thenshow ?rhs 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: list_all2_iff zip_append1) done next assume ?rhs thenshow ?lhs by (auto simp add: list_all2_iff) qed
lemma list_all2_append2: "list_all2 P xs (ys @ zs) = (∃us vs. xs = us @ vs ∧ length us = length ys ∧ length vs = length zs ∧ list_all2 P us ys ∧ list_all2 P vs zs)" (is"?lhs = ?rhs") proof assume ?lhs thenshow ?rhs 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: list_all2_iff zip_append2) done next assume ?rhs thenshow ?lhs by (auto simp add: list_all2_iff) qed
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_iff 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). case_prod P x ==> length a = length b ==> list_all2 P a b" by (simp add: list_all2_iff)
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: "[ list_all2 P xs ys; P x y ]==> list_all2 P (xs[i:=x]) (ys[i:=y])" by (cases "i < length ys") (auto simp add: list_all2_conv_all_nth nth_list_update)
lemma list_all2_takeI [simp,intro?]: "list_all2 P xs ys ==> list_all2 P (take n xs) (take n ys)" proof (induct xs arbitrary: n ys) case (Cons x xs) thenshow ?case by (cases n) (auto simp: list_all2_Cons1) qed auto
lemma list_all2_dropI [simp,intro?]: "list_all2 P xs ys ==> list_all2 P (drop n xs) (drop n ys)" proof (induct xs arbitrary: n ys) case (Cons x xs) thenshow ?case by (cases n) (auto simp: list_all2_Cons1) qed auto
lemma list_all2_mono [intro?]: "list_all2 P xs ys ==> (∧xs ys. P xs ys ==> Q xs ys) ==> list_all2 Q xs ys" by (rule list.rel_mono_strong)
lemma list_all2_eq: "xs = ys ⟷ list_all2 (=) xs ys" by (induct xs ys rule: list_induct2') auto
lemma product_nth: assumes"n < length xs * length ys" shows"List.product xs ys ! n = (xs ! (n div length ys), ys ! (n mod length ys))" using assms proof (induct xs arbitrary: n) case Nil thenshow ?caseby simp next case (Cons x xs n) thenhave"length ys > 0"by auto with Cons show ?case by (auto simp add: nth_append not_less le_mod_geq le_div_geq) qed
lemma in_set_product_lists_length: "xs ∈ set (product_lists xss) ==> length xs = length xss" by (induct xss arbitrary: xs) auto
lemma product_lists_set: "set (product_lists xss) = {xs. list_all2 (λx ys. x ∈ set ys) xs xss}" (is"?L = Collect ?R") proof (intro equalityI subsetI, unfold mem_Collect_eq) fix xs assume"xs ∈ ?L" thenhave"length xs = length xss"by (rule in_set_product_lists_length) from this ‹xs ∈ ?L›show"?R xs"by (induct xs xss rule: list_induct2) auto next fix xs assume"?R xs" thenshow"xs ∈ ?L"by induct auto qed
lemma fold_simps [code]: 🍋‹eta-expanded variant for generated code -- enables tail-recursion optimisation in Scala› "fold f [] s = s" "fold f (x # xs) s = fold f xs (f x s)" by simp_all
lemma fold_remove1_split: "[∧x y. x ∈ set xs ==> y ∈ set xs ==> f x ∘ f y = f y ∘ f x; x ∈ set xs ] ==> fold f xs = fold f (remove1 x xs) ∘ f x" by (induct xs) (auto simp add: comp_assoc)
lemma fold_cong [fundef_cong]: "a = b ==> xs = ys ==> (∧x. x ∈ set xs ==> f x = g x) ==> fold f xs a = fold g ys b" by (induct ys arbitrary: a b xs) simp_all
lemma fold_id: "(∧x. x ∈ set xs ==> f x = id) ==> fold f xs = id" by (induct xs) simp_all
lemma fold_commute: "(∧x. x ∈ set xs ==> h ∘ g x = f x ∘ h) ==> h ∘ fold g xs = fold f xs ∘ h" by (induct xs) (simp_all add: fun_eq_iff)
lemma fold_commute_apply: assumes"∧x. x ∈ set xs ==> h ∘ g x = f x ∘ h" shows"h (fold g xs s) = fold f xs (h s)" proof - from assms have"h ∘ fold g xs = fold f xs ∘ h"by (rule fold_commute) thenshow ?thesis by (simp add: fun_eq_iff) qed
lemma fold_invariant: "[∧x. x ∈ set xs ==> Q x; P s; ∧x s. Q x ==> P s ==> P (f x s) ] ==> P (fold f xs s)" by (induct xs arbitrary: s) simp_all
lemma fold_append [simp]: "fold f (xs @ ys) = fold f ys ∘ fold f xs" by (induct xs) simp_all
lemma fold_map [code_unfold]: "fold g (map f xs) = fold (g ∘ f) xs" by (induct xs) simp_all
lemma fold_filter: "fold f (filter P xs) = fold (λx. if P x then f x else id) xs" by (induct xs) simp_all
lemma fold_rev: "(∧x y. x ∈ set xs ==> y ∈ set xs ==> f y ∘ f x = f x ∘ f y) ==> fold f (rev xs) = fold f xs" by (induct xs) (simp_all add: fold_commute_apply fun_eq_iff)
lemma fold_inject: assumes "∧w x y z. f w x = f y z ⟷ w = y ∧ x = z"and "∧x y. f x y ≠ a"and "∧x y. f x y ≠ b" shows"fold f xs a = fold f ys b ⟷ xs = ys ∧ a = b" by (induction xs ys rule: List.rev_induct2) (use assms(2,3,1) in auto)
text‹🍋‹Finite_Set.fold›and 🍋‹fold›\›
lemma (in comp_fun_commute_on) fold_set_fold_remdups: assumes"set xs ⊆ S" shows"Finite_Set.fold f y (set xs) = fold f (remdups xs) y" by (rule sym, use assms in‹induct xs arbitrary: y›)
(simp_all add: insert_absorb fold_fun_left_comm)
lemma (in comp_fun_idem_on) fold_set_fold: assumes"set xs ⊆ S" shows"Finite_Set.fold f y (set xs) = fold f xs y" by (rule sym, use assms in‹induct xs arbitrary: y›) (simp_all add: fold_fun_left_comm)
lemma union_set_fold [code]: "set xs ∪ A = fold Set.insert xs A" proof - interpret comp_fun_idem Set.insert by (fact comp_fun_idem_insert) show ?thesis by (simp add: union_fold_insert fold_set_fold) qed
lemma union_coset_filter [code]: "List.coset xs ∪ A = List.coset (List.filter (λx. x ∉ A) xs)" by auto
lemma minus_set_fold [code]: "A - set xs = fold Set.remove xs A" proof - interpret comp_fun_idem Set.remove by (fact comp_fun_idem_remove) show ?thesis by (simp add: minus_fold_remove [of _ A] fold_set_fold) qed
lemma minus_coset_filter [code]: "A - List.coset xs = set (List.filter (λx. x ∈ A) xs)" by auto
lemma inter_set_filter [code]: "A ∩ set xs = set (List.filter (λx. x ∈ A) xs)" by auto
lemma inter_coset_fold [code]: "A ∩ List.coset xs = fold Set.remove xs A" by (simp add: Diff_eq [symmetric] minus_set_fold)
definition abort_empty_set :: ‹('a set ==> 'a) ==> 'a› where [simp]: ‹abort_empty_set F = F {}›
declare [[code abort: abort_empty_set]]
lemma (in semilattice_set) set_empty_abort [code]: ‹F (set []) = abort_empty_set F› by simp
lemma (in semilattice_set) set_eq_fold [code]: ‹F (set (x # xs)) = fold f xs x› proof - interpret comp_fun_idem f by standard (simp_all add: fun_eq_iff left_commute) show ?thesis by (simp add: eq_fold fold_set_fold) qed
lemma (in complete_lattice) Inf_set_fold: "Inf (set xs) = fold inf xs top" 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_fold inf_commute) qed
declare Inf_set_fold [where 'a = "'a set", code]
lemma (in complete_lattice) Sup_set_fold: "Sup (set xs) = fold sup xs bot" 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_fold sup_commute) qed
declare Sup_set_fold [where 'a = "'a set", code]
lemma (in complete_lattice) INF_set_fold: "⊓(f ` set xs) = fold (inf ∘ f) xs top" using Inf_set_fold [of "map f xs"] by (simp add: fold_map)
lemma (in complete_lattice) SUP_set_fold: "⊔(f ` set xs) = fold (sup ∘ f) xs bot" using Sup_set_fold [of "map f xs"] by (simp add: fold_map)
lemma foldr_conv_fold [code_abbrev]: "foldr f xs = fold f (rev xs)" by (induct xs) simp_all
lemma foldl_conv_fold: "foldl f s xs = fold (λx s. f s x) xs s" by (induct xs arbitrary: s) simp_all
lemma foldr_conv_foldl: 🍋‹The ``Third Duality Theorem'' in Bird \& Wadler:› "foldr f xs a = foldl (λx y. f y x) a (rev xs)" by (simp add: foldr_conv_fold foldl_conv_fold)
lemma foldl_conv_foldr: "foldl f a xs = foldr (λx y. f y x) (rev xs) a" by (simp add: foldr_conv_fold foldl_conv_fold)
lemma foldr_fold: "(∧x y. x ∈ set xs ==> y ∈ set xs ==> f y ∘ f x = f x ∘ f y) ==> foldr f xs = fold f xs" unfolding foldr_conv_fold by (rule fold_rev)
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 (auto simp add: foldr_conv_fold intro!: fold_cong)
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 (auto simp add: foldl_conv_fold intro!: fold_cong)
lemma foldr_append [simp]: "foldr f (xs @ ys) a = foldr f xs (foldr f ys a)" by (simp add: foldr_conv_fold)
lemma foldl_append [simp]: "foldl f a (xs @ ys) = foldl f (foldl f a xs) ys" by (simp add: foldl_conv_fold)
lemma foldr_map [code_unfold]: "foldr g (map f xs) a = foldr (g ∘ f) xs a" by (simp add: foldr_conv_fold fold_map rev_map)
lemma foldr_filter: "foldr f (filter P xs) = foldr (λx. if P x then f x else id) xs" by (simp add: foldr_conv_fold rev_filter fold_filter)
lemma foldl_map [code_unfold]: "foldl g a (map f xs) = foldl (λa x. g a (f x)) a xs" by (simp add: foldl_conv_fold fold_map comp_def)
lemma foldl_inject: assumes "∧w x y z. f w x = f y z ⟷ w = y ∧ x = z"and "∧x y. f x y ≠ a"and "∧x y. f x y ≠ b" shows"foldl f a xs = foldl f b ys ⟷ a = b ∧ xs = ys" by (induction xs ys rule: rev_induct2) (use assms(2,3,1) in auto)
lemma foldr_inject: assumes "∧w x y z. f w x = f y z ⟷ w = y ∧ x = z"and "∧x y. f x y ≠ a"and "∧x y. f x y ≠ b" shows"foldr f xs a = foldr f ys b ⟷ xs = ys ∧ a = b" by (induction xs ys rule: list_induct2') (use assms(2,3,1) in auto)
subsubsection ‹🍋‹upt›\›
lemma upt_rec[code]: "[i.. 🍋‹simp does not terminate!› by (induct j) auto
lemmas upt_rec_numeral[simp] = upt_rec[of "numeral m""numeral n"] for m n
lemma upt_conv_Nil [simp]: "j ≤ i ==> [i.. by (subst upt_rec) simp
lemma upt_eq_Cons_conv: "([i..∧ i = x ∧ [i+1.. proof (induct j arbitrary: x xs) case (Suc j) thenshow ?case by (simp add: upt_rec) qed simp
lemma upt_Suc_append: "i ≤ j ==> [i..<(Suc j)] = [i.. 🍋‹Only needed if ‹upt_Suc›is deleted from the simpset.› by simp
lemma upt_conv_Cons: "i < j ==> [i.. by (simp add: upt_rec)
lemma upt_conv_Cons_Cons: 🍋‹no precondition› "m # n # ns = [m..⟷ n # ns = [Suc m.. proof (cases "m < q") case False thenshow ?thesis by simp next case True thenshow ?thesis by (simp add: upt_conv_Cons) qed
lemma upt_add_eq_append: "i<=j ==> [i.. 🍋‹LOOPS as a simprule, since ‹j ≤ j›.› by (induct k) auto
lemma take_upt [simp]: "i+m ≤ n ==> take m [i.. proof (induct m arbitrary: i) case (Suc m) thenshow ?case by (subst take_Suc_conv_app_nth) auto qed simp
lemma drop_upt[simp]: "drop m [i.. by(induct j) auto
lemma map_Suc_upt: "map Suc [m.. by (induct n) auto
lemma map_add_upt: "map (λi. i + n) [0.. by (induct m) simp_all
lemma nth_map_upt: "i < n-m ==> (map f [m.. proof (induct n m arbitrary: i rule: diff_induct) case (3 x y) thenshow ?case by (metis add.commute length_upt less_diff_conv nth_map nth_upt) qed auto
lemma map_decr_upt: "map (λn. n - Suc 0) [Suc m.. by (induct n) simp_all
lemma map_upt_Suc: "map f [0 ..< Suc n] = f 0 # map (λi. f (Suc i)) [0 ..< n]" by (induct n arbitrary: f) auto
lemma nth_take_lemma: "k ≤ length xs ==> k ≤ length ys ==> (∧i. i < k ⟶ xs!i = ys!i) ==> take k xs = take k ys" by (induct k arbitrary: xs ys) (simp_all add: take_Suc_conv_app_nth)
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" by (simp add: list_all2_conv_all_nth nth_equalityI)
lemma take_equalityI: "(∀i. take i xs = take i ys) ==> xs = ys" 🍋‹The famous take-lemma.› by (metis length_take min.commute order_refl take_all)
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
lemma take_Cons_numeral [simp]: "take (numeral v) (x # xs) = x # take (numeral v - 1) xs" by (simp add: take_Cons')
lemma drop_Cons_numeral [simp]: "drop (numeral v) (x # xs) = drop (numeral v - 1) xs" by (simp add: drop_Cons')
lemma nth_Cons_numeral [simp]: "(x # xs) ! numeral v = xs ! (numeral v - 1)" by (simp add: nth_Cons')
lemma map_upt_eqI: ‹map f [m..🚫 = xs›if‹length xs = n - m› ‹∧i. i 🚫 xs ==> xs ! i = f (m + i)› proof (rule nth_equalityI) from‹length xs = n - m›show‹length (map f [m..🚫) = length xs› by simp next fix i assume‹i 🚫 (map f [m..🚫)› thenhave‹i 🚫 - m› by simp with that have‹xs ! i = f (m + i)› by simp with‹i 🚫 - m›show‹map f [m..🚫 ! i = xs ! i› by simp qed
subsubsection ‹‹upto›: interval-list on 🍋‹int›\›
function upto :: "int ==> int ==> int list" (‹(‹indent=1 notation=‹mixfix list interval›\›[_../_])›) 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[simp del]
lemmas upto_rec_numeral [simp] =
upto.simps[of "numeral m""numeral n"]
upto.simps[of "numeral m""- numeral n"]
upto.simps[of "- numeral m""numeral n"]
upto.simps[of "- numeral m""- numeral n"] for m n
lemma upto_rec2: "i ≤ j ==> [i..j] = [i..j - 1]@[j]" proof(induct "nat(j-i)" arbitrary: i j) case 0 thus ?caseby(simp add: upto.simps) next case (Suc n) hence"n = nat (j - (i + 1))""i < j"by linarith+ from this(2) Suc.hyps(1)[OF this(1)] Suc(2,3) upto_rec1 show ?caseby simp qed
lemma length_upto[simp]: "length [i..j] = nat(j - i + 1)" by(induction i j rule: upto.induct) (auto simp: 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] by auto qed
lemma nth_upto[simp]: "i + int k ≤ j ==> [i..j] ! k = i + int k" proof(induction i j arbitrary: k rule: upto.induct) case (1 i j) thenshow ?case by (auto simp add: upto_rec1 [of i j] nth_Cons') qed
lemma upto_split1: "i ≤ j ==> j ≤ k ==> [i..k] = [i..j-1] @ [j..k]" proof (induction j rule: int_ge_induct) case base thus ?caseby (simp add: upto_rec1) next case step thus ?caseusing upto_rec1 upto_rec2 by simp qed
lemma upto_split2: "i ≤ j ==> j ≤ k ==> [i..k] = [i..j] @ [j+1..k]" using upto_rec1 upto_rec2 upto_split1 by auto
lemma upto_split3: "[ i ≤ j; j ≤ k ]==> [i..k] = [i..j-1] @ j # [j+1..k]" using upto_rec1 upto_split1 by auto
text‹Tail recursive version for code generation:›
definition upto_aux :: "int ==> int ==> int list ==> int list"where "upto_aux i j js = [i..j] @ js"
lemma upto_aux_rec [code]: "upto_aux i j js = (if j by (simp add: upto_aux_def upto_rec2)
lemma successively_Cons: "successively P (x # xs) ⟷ xs = [] ∨ P x (hd xs) ∧ successively P xs" by (cases xs) auto
lemma successively_cong [cong]: assumes"∧x y. x ∈ set xs ==> y ∈ set xs ==> P x y ⟷ Q x y""xs = ys" shows"successively P xs ⟷ successively Q ys" unfolding assms(2) [symmetric] using assms(1) by (induction xs) (auto simp: successively_Cons)
lemma successively_append_iff: "successively P (xs @ ys) ⟷ successively P xs ∧ successively P ys ∧ (xs = [] ∨ ys = [] ∨ P (last xs) (hd ys))" by (induction xs) (auto simp: successively_Cons)
lemma successively_if_sorted_wrt: "sorted_wrt P xs ==> successively P xs" by (induction xs rule: induct_list012) auto
lemma successively_iff_sorted_wrt_strong: assumes"∧x y z. x ∈ set xs ==> y ∈ set xs ==> z ∈ set xs ==> P x y ==> P y z ==> P x z" shows"successively P xs ⟷ sorted_wrt P xs" proof assume"successively P xs" from this and assms show"sorted_wrt P xs" proof (induction xs rule: induct_list012) case (3 x y xs) from"3.prems"have"P x y" by auto have IH: "sorted_wrt P (y # xs)" using"3.prems" by(intro "3.IH"(2) list.set_intros(2))(simp, blast intro: list.set_intros(2)) have"P x z"if asm: "z ∈ set xs"for z proof - from IH and asm have"P y z" by auto with‹P x y›show"P x z" using"3.prems" asm by auto qed with IH and‹P x y›show ?caseby auto qed auto qed (use successively_if_sorted_wrt in blast)
lemma successively_conv_sorted_wrt: assumes"transp P" shows"successively P xs ⟷ sorted_wrt P xs" using assms unfolding transp_def by (intro successively_iff_sorted_wrt_strong) blast
lemma successively_rev [simp]: "successively P (rev xs) ⟷ successively (λx y. P y x) xs" by (induction xs rule: remdups_adj.induct)
(auto simp: successively_append_iff successively_Cons)
lemma successively_map: "successively P (map f xs) ⟷ successively (λx y. P (f x) (f y)) xs" by (induction xs rule: induct_list012) auto
lemma successively_mono: assumes"successively P xs" assumes"∧x y. x ∈ set xs ==> y ∈ set xs ==> P x y ==> Q x y" shows"successively Q xs" using assms by (induction Q xs rule: successively.induct) auto
lemma successively_altdef: "successively = (λP. rec_list True (λx xs b. case xs of [] ==> True | y # _ ==> P x y ∧ b))" proof (intro ext) fix P and xs :: "'a list" show"successively P xs = rec_list True (λx xs b. case xs of [] ==> True | y # _ ==> P x y ∧ b) xs" by (induction xs) (auto simp: successively_Cons split: list.splits) qed
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)" proof (induct xs) case (Cons a xs) thenshow ?case by simp (metis Suc_n_not_le_n impossible_Cons length_remdups_leq) qed auto
lemma remdups_filter: "remdups(filter P xs) = filter P (remdups xs)" by (induct xs) auto
lemma distinct_map: "distinct(map f xs) = (distinct xs ∧ inj_on f (set xs))" by (induct xs) auto
lemma distinct_map_filter: "distinct (map f xs) ==> distinct (map f (filter P 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.. by (induct j) auto
lemma distinct_upto[simp]: "distinct[i..j]" proof (induction i j rule: upto.induct) case (1 i j) thenshow ?case by (simp add: upto.simps [of i]) qed
lemma distinct_take[simp]: "distinct xs ==> distinct (take i xs)" proof (induct xs arbitrary: i) case (Cons a xs) thenshow ?case by (metis Cons.prems append_take_drop_id distinct_append) qed auto
lemma distinct_drop[simp]: "distinct xs ==> distinct (drop i xs)" proof (induct xs arbitrary: i) case (Cons a xs) thenshow ?case by (metis Cons.prems append_take_drop_id distinct_append) qed auto
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 anot: "a ∉ set (take i xs @ xs ! i # drop (Suc i) xs) - {xs!i}" by simp (metis in_set_dropD in_set_takeD) show ?thesis proof (cases "a = xs!i") case True with d show ?thesis by auto next case False have"set (take i xs) ∩ set (drop (Suc i) xs) = {}" by (metis True d disjoint_insert(1) distinct_append id_take_nth_drop list.set(2)) thenshow ?thesis using d False anot ‹i 🚫 xs›by (simp add: upd_conv_take_nth_drop) qed next case False with d show ?thesis by (auto simp: list_update_beyond) qed
lemma distinct_concat_rev[simp]: "distinct (concat (rev xs)) = distinct (concat xs)" by (induction xs) auto
lemma distinct_concat: "[ distinct xs; ∧ ys. ys ∈ set xs ==> distinct ys; ∧ ys zs. [ ys ∈ set xs ; zs ∈ set xs ; ys ≠ zs ]==> set ys ∩ set zs = {} ]==> distinct (concat xs)" by (induct xs) auto
text‹An iff-version of @{thm distinct_concat} is available further down as ‹distinct_concat_iff›.›
text‹It is best to avoid the following 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)" proof (induct xs) case (Cons x xs) show ?case apply (auto simp add: Cons nth_Cons less_Suc_eq_le split: nat.split_asm) apply (metis Suc_leI in_set_conv_nth length_pos_if_in_set lessI less_imp_le_nat less_nat_zero_code) apply (metis Suc_le_eq) done qed auto
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 (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: if_split_asm) moreoverhave"card (set xs) ≤ length xs"by (rule card_length) ultimatelyhave False by simp thus ?thesis .. qed qed simp
lemma distinct_length_filter: "distinct xs ==> length (filter P xs) = card ({x. P x} Int set xs)" by (induct xs) (auto)
lemma not_distinct_decomp: "¬ distinct ws ==>∃xs ys zs y. ws = xs@[y]@ys@[y]@zs" proof (induct n == "length ws" arbitrary:ws) case (Suc n ws) thenshow ?case using length_Suc_conv [of ws n] apply (auto simp: eq_commute) apply (metis append_Nil in_set_conv_decomp_first) by (metis append_Cons) qed simp
lemma not_distinct_conv_prefix: defines"dec as xs y ys ≡ y ∈ set xs ∧ distinct xs ∧ as = xs @ y # ys" shows"¬distinct as ⟷ (∃xs y ys. dec as xs y ys)" (is"?L = ?R") proof assume"?L"thenshow"?R" proof (induct "length as" arbitrary: as rule: less_induct) case less obtain xs ys zs y where decomp: "as = (xs @ y # ys) @ y # zs" using not_distinct_decomp[OF less.prems] by auto show ?case proof (cases "distinct (xs @ y # ys)") case True with decomp have"dec as (xs @ y # ys) y zs"by (simp add: dec_def) thenshow ?thesis by blast next case False with less decomp obtain xs' y' ys' where"dec (xs @ y # ys) xs' y' ys'" by atomize_elim auto with decomp have"dec as xs' y' (ys' @ y # zs)"by (simp add: dec_def) thenshow ?thesis by blast qed qed qed (auto simp: dec_def)
lemma distinct_product_lists: assumes"∀xs ∈ set xss. distinct xs" shows"distinct (product_lists xss)" using assms proof (induction xss) case (Cons xs xss) note * = this thenshow ?case proof (cases "product_lists xss") case Nil thenshow ?thesis by (induct xs) simp_all next case (Cons ps pss) with * show ?thesis by (auto intro!: inj_onI distinct_concat simp add: distinct_map) qed qed simp
lemma length_remdups_concat: "length (remdups (concat xss)) = card (∪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 distinct_butlast: assumes"distinct xs" shows"distinct (butlast xs)" proof (cases "xs = []") case False from‹xs ≠ []›obtain ys y where"xs = ys @ [y]"by (cases xs rule: rev_cases) auto with‹distinct xs›show ?thesis by simp qed (auto)
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
lemma set_take_disj_set_drop_if_distinct: "distinct vs ==> i ≤ j ==> set (take i vs) ∩ set (drop j vs) = {}" by (auto simp: in_set_conv_nth distinct_conv_nth)
(* 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 force
lemma remdups_adj_altdef: "(remdups_adj xs = ys) ⟷ (∃f::nat => nat. mono f ∧ f ` {0 ..< size xs} = {0 ..< size ys} ∧ (∀i < size xs. xs!i = ys!(f i)) ∧ (∀i. i + 1 < size xs ⟶ (xs!i = xs!(i+1) ⟷ f i = f(i+1))))" (is"?L ⟷ (∃f. ?p f xs ys)") proof assume ?L thenshow"∃f. ?p f xs ys" proof (induct xs arbitrary: ys rule: remdups_adj.induct) case (1 ys) thus ?caseby (intro exI[of _ id]) (auto simp: mono_def) next case (2 x ys) thus ?caseby (intro exI[of _ id]) (auto simp: mono_def) next case (3 x1 x2 xs ys) let ?xs = "x1 # x2 # xs" let ?cond = "x1 = x2"
define zs where"zs = remdups_adj (x2 # xs)" from 3(1-2)[of zs] obtain f where p: "?p f (x2 # xs) zs"unfolding zs_def by (cases ?cond) auto thenhave f0: "f 0 = 0" by (intro mono_image_least[where f=f]) blast+ from p have mono: "mono f"and f_xs_zs: "f ` {0..by auto have ys: "ys = (if x1 = x2 then zs else x1 # zs)" unfolding 3(3)[symmetric] zs_def by auto have zs0: "zs ! 0 = x2"unfolding zs_def by (induct xs) auto have zsne: "zs ≠ []"unfolding zs_def by (induct xs) auto let ?Succ = "if ?cond then id else Suc" let ?x1 = "if ?cond then id else Cons x1" let ?f = "λ i. if i = 0 then 0 else ?Succ (f (i - 1))" have ys: "ys = ?x1 zs"unfolding ys by (cases ?cond, auto) have mono: "mono ?f"using‹mono f›unfolding mono_def by auto show ?caseunfolding ys proof (intro exI[of _ ?f] conjI allI impI) show"mono ?f"by fact next fix i assume i: "i < length ?xs" with p show"?xs ! i = ?x1 zs ! (?f i)"using zs0 by auto next fix i assume i: "i + 1 < length ?xs" with p show"(?xs ! i = ?xs ! (i + 1)) = (?f i = ?f (i + 1))" by (cases i) (auto simp: f0) next have id: "{0 ..< length (?x1 zs)} = insert 0 (?Succ ` {0 ..< length zs})" using zsne by (cases ?cond, auto)
{ fix i assume"i < Suc (length xs)" hence"Suc i ∈ {0..∩ Collect ((<) 0)"by auto from imageI[OF this, of "λi. ?Succ (f (i - Suc 0))"] have"?Succ (f i) ∈ (λi. ?Succ (f (i - Suc 0))) ` ({0..∩ Collect ((<) 0))" by auto
} thenshow"?f ` {0 ..< length ?xs} = {0 ..< length (?x1 zs)}" unfolding id f_xs_zs[symmetric] by auto qed qed next assume"∃ f. ?p f xs ys" thenshow ?L proof (induct xs arbitrary: ys rule: remdups_adj.induct) case 1 thenshow ?caseby auto next case (2 x) thenobtain f where f_img: "f ` {0 ..< size [x]} = {0 ..< size ys}" and f_nth: "∧i. i < size [x] ==> [x]!i = ys!(f i)" by blast
have"length ys = card (f ` {0 ..< size [x]})" using f_img by auto thenhave *: "length ys = 1"by auto thenhave"f 0 = 0"using f_img by auto with * show ?caseusing f_nth by (cases ys) auto next case (3 x1 x2 xs) from"3.prems"obtain f where f_mono: "mono f" and f_img: "f ` {0.. and f_nth: "∧i. i < length (x1 # x2 # xs) ==> (x1 # x2 # xs) ! i = ys ! f i" "∧i. i + 1 < length (x1 # x2 #xs) ==> ((x1 # x2 # xs) ! i = (x1 # x2 # xs) ! (i + 1)) = (f i = f (i + 1))" by blast
show ?case proof cases assume"x1 = x2"
let ?f' = "f ∘ Suc"
have"remdups_adj (x1 # xs) = ys" proof (intro "3.hyps" exI conjI impI allI) show"mono ?f'" using f_mono by (simp add: mono_iff_le_Suc) next have"?f' ` {0 ..< length (x1 # xs)} = f ` {Suc 0 ..< length (x1 # x2 # xs)}" using less_Suc_eq_0_disj by auto alsohave"… = f ` {0 ..< length (x1 # x2 # xs)}" proof - have"f 0 = f (Suc 0)"using‹x1 = x2› f_nth[of 0] by simp thenshow ?thesis using less_Suc_eq_0_disj by auto qed alsohave"… = {0 ..< length ys}"by fact finallyshow"?f' ` {0 ..< length (x1 # xs)} = {0 ..< length ys}" . qed (insert f_nth[of "Suc i"for i], auto simp: ‹x1 = x2›) thenshow ?thesis using‹x1 = x2›by simp next assume"x1 ≠ x2"
have two: "Suc (Suc 0) ≤ length ys" proof - have"2 = card {f 0, f 1}"using‹x1 ≠ x2› f_nth[of 0] by auto alsohave"…≤ card (f ` {0..< length (x1 # x2 # xs)})" by (rule card_mono) auto finallyshow ?thesis using f_img by simp qed
have"f 0 = 0"using f_mono f_img by (rule mono_image_least) simp
have"f (Suc 0) = Suc 0" proof (rule ccontr) assume"f (Suc 0) ≠ Suc 0" thenhave"Suc 0 < f (Suc 0)"using f_nth[of 0] ‹x1 ≠ x2›‹f 0 = 0›by auto thenhave"∧i. Suc 0 < f (Suc i)" using f_mono by (meson Suc_le_mono le0 less_le_trans monoD) thenhave"Suc 0 ≠ f i"for i using‹f 0 = 0› by (cases i) fastforce+ thenhave"Suc 0 ∉ f ` {0 ..< length (x1 # x2 # xs)}"by auto thenshow False using f_img two by auto qed obtain ys' where"ys = x1 # x2 # ys'" using two f_nth[of 0] f_nth[of 1] by (auto simp: Suc_le_length_iff ‹f 0 = 0›‹f (Suc 0) = Suc 0›)
have Suc0_le_f_Suc: "Suc 0 ≤ f (Suc i)"for i by (metis Suc_le_mono ‹f (Suc 0) = Suc 0› f_mono le0 mono_def)
define f' where"f' x = f (Suc x) - 1"for x have f_Suc: "f (Suc i) = Suc (f' i)"for i using Suc0_le_f_Suc[of i] by (auto simp: f'_def)
have"remdups_adj (x2 # xs) = (x2 # ys')" proof (intro "3.hyps" exI conjI impI allI) show"mono f'" using Suc0_le_f_Suc f_mono by (auto simp: f'_def mono_iff_le_Suc le_diff_iff) next have"f' ` {0 ..< length (x2 # xs)} = (λx. f x - 1) ` {0 ..< length (x1 # x2 #xs)}" by (auto simp: f'_def‹f 0 = 0›‹f (Suc 0) = Suc 0› image_def Bex_def less_Suc_eq_0_disj) alsohave"… = (λx. x - 1) ` f ` {0 ..< length (x1 # x2 #xs)}" by (auto simp: image_comp) alsohave"… = (λx. x - 1) ` {0 ..< length ys}" by (simp only: f_img) alsohave"… = {0 ..< length (x2 # ys')}" using‹ys = _›by (fastforce intro: rev_image_eqI) finallyshow"f' ` {0 ..< length (x2 # xs)} = {0 ..< length (x2 # ys')}" . qed (insert f_nth[of "Suc i"for i] ‹x1 ≠ x2›, auto simp add: f_Suc ‹ys = _›) thenshow ?caseusing‹ys = _›‹x1 ≠ x2›by simp qed qed qed
lemma hd_remdups_adj[simp]: "hd (remdups_adj xs) = hd xs" by (induction xs rule: remdups_adj.induct) simp_all
lemma remdups_adj_Cons: "remdups_adj (x # xs) = (case remdups_adj xs of [] ==> [x] | y # xs ==> if x = y then y # xs else x # y # xs)" by (induct xs arbitrary: x) (auto split: list.splits)
lemma remdups_adj_append_two: "remdups_adj (xs @ [x,y]) = remdups_adj (xs @ [x]) @ (if x = y then [] else [y])" by (induct xs rule: remdups_adj.induct, simp_all)
lemma remdups_adj_adjacent: "Suc i < length (remdups_adj xs) ==> remdups_adj xs ! i ≠ remdups_adj xs ! Suc i" proof (induction xs arbitrary: i rule: remdups_adj.induct) case (3 x y xs i) thus ?caseby (cases i, cases "x = y") (simp, auto simp: hd_conv_nth[symmetric]) qed simp_all
lemma remdups_adj_map_injective: assumes"inj f" shows"remdups_adj (map f xs) = map f (remdups_adj xs)" by (induct xs rule: remdups_adj.induct) (auto simp add: injD[OF assms])
lemma remdups_adj_replicate: "remdups_adj (replicate n x) = (if n = 0 then [] else [x])" by (induction n) (auto simp: remdups_adj_Cons)
lemma remdups_upt [simp]: "remdups [m.. proof (cases "m ≤ n") case False thenshow ?thesis by simp next case True thenobtain q where"n = m + q" by (auto simp add: le_iff_add) moreoverhave"remdups [m.. by (induct q) simp_all ultimatelyshow ?thesis by simp qed
lemma successively_remdups_adjI: "successively P xs ==> successively P (remdups_adj xs)" by (induction xs rule: remdups_adj.induct) (auto simp: successively_Cons)
lemma successively_remdups_adj_iff: "(∧x. x ∈ set xs ==> P x x) ==> successively P (remdups_adj xs) ⟷ successively P xs" by (induction xs rule: remdups_adj.induct)(auto simp: successively_Cons)
lemma successively_conv_nth: "successively P xs ⟷ (∀i. Suc i < length xs ⟶ P (xs ! i) (xs ! Suc i))" by (induction P xs rule: successively.induct)
(force simp: nth_Cons split: nat.splits)+
lemma successively_nth: "successively P xs ==> Suc i < length xs ==> P (xs ! i) (xs ! Suc i)" unfolding successively_conv_nth by blast
lemma distinct_adj_conv_nth: "distinct_adj xs ⟷ (∀i. Suc i < length xs ⟶ xs ! i ≠ xs ! Suc i)" by (simp add: distinct_adj_def successively_conv_nth)
lemma distinct_adj_nth: "distinct_adj xs ==> Suc i < length xs ==> xs ! i ≠ xs ! Suc i" unfolding distinct_adj_conv_nth by blast
lemma remdups_adj_Cons': "remdups_adj (x # xs) = x # remdups_adj (dropWhile (λy. y = x) xs)" by (induction xs) auto
lemma tl_remdups_adj: "ys ≠ [] ==> tl (remdups_adj ys) = remdups_adj (dropWhile (λx. x = hd ys) (tl ys))" by (cases ys) (simp_all add: remdups_adj_Cons')
lemma remdups_adj_append_dropWhile: "remdups_adj (xs @ y # ys) = remdups_adj (xs @ [y]) @ remdups_adj (dropWhile (λx. x = y) ys)" by (subst remdups_adj_append) (simp add: tl_remdups_adj)
lemma remdups_adj_append': assumes"xs = [] ∨ ys = [] ∨ last xs ≠ hd ys" shows"remdups_adj (xs @ ys) = remdups_adj xs @ remdups_adj ys" proof - have ?thesis if [simp]: "xs ≠ []""ys ≠ []"and"last xs ≠ hd ys" proof - obtain x xs' where xs: "xs = xs' @ [x]" by (cases xs rule: rev_cases) auto have"remdups_adj (xs' @ x # ys) = remdups_adj (xs' @ [x]) @ remdups_adj ys" using‹last xs ≠ hd ys›unfolding xs by (metis (full_types) dropWhile_eq_self_iff last_snoc remdups_adj_append_dropWhile) thus ?thesis by (simp add: xs) qed thus ?thesis using assms by (cases "xs = []"; cases "ys = []") auto qed
lemma remdups_adj_append'': "xs ≠ [] ==> remdups_adj (xs @ ys) = remdups_adj xs @ remdups_adj (dropWhile (λy. y = last xs) ys)" by (induction xs rule: remdups_adj.induct) (auto simp: remdups_adj_Cons')
lemma remdups_filter_last: "last [x←remdups xs. P x] = last [x←xs. P x]" by (induction xs, auto simp: filter_empty_conv)
lemma remdups_append: "set xs ⊆ set ys ==> remdups (xs @ ys) = remdups ys" by (induction xs, simp_all)
lemma remdups_concat: "remdups (concat (remdups xs)) = remdups (concat xs)" proof (induction xs) case Nil thenshow ?caseby simp next case (Cons a xs) show ?case proof (cases "a ∈ set xs") case True thenhave"remdups (concat xs) = remdups (a @ concat xs)" by (metis remdups_append concat.simps(2) insert_absorb set_simps(2) set_append set_concat sup_ge1) thenshow ?thesis by (simp add: Cons True) next case False thenshow ?thesis by (metis Cons remdups_append2 concat.simps(2) remdups.simps(2)) qed qed
subsection‹@{const distinct_adj}›
lemma distinct_adj_Nil [simp]: "distinct_adj []" and distinct_adj_singleton [simp]: "distinct_adj [x]" and distinct_adj_Cons_Cons [simp]: "distinct_adj (x # y # xs) ⟷ x ≠ y ∧ distinct_adj (y # xs)" by (auto simp: distinct_adj_def)
lemma distinct_adj_Cons: "distinct_adj (x # xs) ⟷ xs = [] ∨ x ≠ hd xs ∧ distinct_adj xs" by (cases xs) auto
lemma distinct_adj_ConsD: "distinct_adj (x # xs) ==> distinct_adj xs" by (cases xs) auto
lemma distinct_adj_mapI: "distinct_adj xs ==> inj_on f (set xs) ==> distinct_adj (map f xs)" unfolding distinct_adj_def successively_map by (erule successively_mono) (auto simp: inj_on_def)
lemma distinct_adj_mapD: "distinct_adj (map f xs) ==> distinct_adj xs" unfolding distinct_adj_def successively_map by (erule successively_mono) auto
lemma distinct_adj_map_iff: "inj_on f (set xs) ==> distinct_adj (map f xs) ⟷ distinct_adj xs" using distinct_adj_mapD distinct_adj_mapI by blast
lemma distinct_adj_conv_length_remdups_adj: "distinct_adj xs ⟷ length (remdups_adj xs) = length xs" proof (induction xs rule: remdups_adj.induct) case (3 x y xs) thus ?case using remdups_adj_length[of "y # xs"] by auto qed auto
subsubsection ‹🍋‹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 (List.insert x xs) = distinct 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 ‹🍋‹List.union›\›
text‹This is all one should need to know about union:› lemma set_union[simp]: "set (List.union xs ys) = set xs ∪ set ys" unfolding List.union_def by(induct xs arbitrary: ys) simp_all
lemma find_None_iff: "List.find P xs = None ⟷¬ (∃x. x ∈ set xs ∧ P x)" proof (induction xs) case Nil thus ?caseby simp next case (Cons x xs) thus ?caseby (fastforce split: if_splits) qed
lemma find_Some_iff: "List.find P xs = Some x ⟷ (∃i∧ x = xs!i ∧ (∀j¬ P (xs!j)))" proof (induction xs) case Nil thus ?caseby simp next case (Cons x xs) thus ?case apply(auto simp: nth_Cons' split: if_splits) using diff_Suc_1 less_Suc_eq_0_disj by fastforce qed
lemma find_cong[fundef_cong]: assumes"xs = ys"and"∧x. x ∈ set ys ==> P x = Q x" shows"List.find P xs = List.find Q ys" proof (cases "List.find P xs") case None thus ?thesis by (metis find_None_iff assms) next case (Some x) hence"List.find Q ys = Some x"using assms by (auto simp add: find_Some_iff) thus ?thesis using Some by auto qed
lemma find_dropWhile: "List.find P xs = (case dropWhile (Not ∘ P) xs of [] ==> None | x # _ ==> Some x)" by (induct xs) simp_all
subsubsection ‹🍋‹count_list›\›
text‹This library is intentionally minimal. See the remark about multisets at the point above where @{const count_list} is defined.›
lemma count_list_append[simp]: "count_list (xs @ ys) x = count_list xs x + count_list ys x" by (induction xs) simp_all
lemma count_list_0_iff: "count_list xs x = 0 ⟷ x ∉ set xs" by (induction xs) simp_all
lemma count_notin[simp]: "x ∉ set xs ==> count_list xs x = 0" by(simp add: count_list_0_iff)
lemma count_le_length: "count_list xs x ≤ length xs" by (induction xs) auto
lemma count_list_map_ge: "count_list xs x ≤ count_list (map f xs) (f x)" by (induction xs) auto
lemma count_list_inj_map: "[ inj_on f (set xs); x ∈ set xs ]==> count_list (map f xs) (f x) = count_list xs x" by (induction xs) (simp, fastforce)
lemma count_list_map_conv: assumes"inj f"shows"count_list (map f xs) (f x) = count_list xs x" by (induction xs) (simp_all add: inj_eq[OF assms])
lemma count_list_rev[simp]: "count_list (rev xs) x = count_list xs x" by (induction xs) auto
lemma sum_count_set: "set xs ⊆ X ==> finite X ==> sum (count_list xs) X = length xs" proof (induction xs arbitrary: X) case (Cons x xs) thenshow ?case using sum.remove [of X x "count_list xs"] by (auto simp: sum.If_cases simp flip: diff_eq) qed simp
lemma count_list_Suc_split_first: assumes"count_list xs x = Suc n" shows"∃ pref rest. xs = pref @ x # rest ∧ x ∉ set pref ∧ count_list rest x = n" proof - let ?pref = "takeWhile (λu. u ≠ x) xs" let ?rest = "drop (length ?pref) xs" have"x ∈ set xs"using assms count_notin by fastforce hence rest: "?rest ≠ [] ∧ hd ?rest = x" by (metis (mono_tags, lifting) append_Nil2 dropWhile_eq_drop hd_dropWhile
takeWhile_dropWhile_id takeWhile_eq_all_conv) have 1: "x ∉ set ?pref"by (metis (full_types) set_takeWhileD) have 2: "xs = ?pref @ x # tl ?rest" by (metis rest append_eq_conv_conj hd_Cons_tl takeWhile_eq_take) have"count_list (tl ?rest) x = n" using assms rest 1 2 count_notin count_list_append[of ?pref "x # tl ?rest" x] by simp with 1 2 show ?thesis by blast qed
lemma count_list_eq_length_filter: "count_list xs y = length(filter ((=) y) xs)" by (induction xs) auto
lemma split_list_cycles: "∃pref xss. xs = pref @ concat xss ∧ x ∉ set pref ∧ (∀ys ∈ set xss. ∃zs. ys = x # zs)" proof (induction"count_list xs x" arbitrary: xs) case 0 show ?caseusing 0[symmetric] concat.simps(1) count_list_0_iff by fastforce next case (Suc n) from Suc.hyps(2) obtain pref rest where
*: "xs = pref @ x # rest""x ∉ set pref""count_list rest x = n" by (metis count_list_Suc_split_first) from Suc.hyps(1)[OF *(3)[symmetric]] obtain pref1 xss where
**: "rest = pref1 @ concat xss""x ∉ set pref1""∀ys∈set xss. ∃zs. ys = x # zs" by blast let ?xss = "(x # pref1) # xss" have"xs = pref @ concat ?xss ∧ x ∉ set pref ∧ (∀ys ∈ set ?xss. ∃zs. ys = x # zs)" using *(1,2) ** by auto thus ?caseby blast qed
lemma extract_SomeE: "List.extract P xs = Some (ys, y, zs) ==> xs = ys @ y # zs ∧ P y ∧¬ (∃ y ∈ set ys. P y)" by(auto simp: extract_def dropWhile_eq_Cons_conv split: list.splits)
lemma extract_Some_iff: "List.extract P xs = Some (ys, y, zs) ⟷ xs = ys @ y # zs ∧ P y ∧¬ (∃ y ∈ set ys. P y)" by(auto simp: extract_def dropWhile_eq_Cons_conv dest: set_takeWhileD split: list.splits)
lemma extract_Cons_code [code]: "List.extract P (x # xs) = (if P x then Some ([], x, xs) else (case List.extract P xs of None ==> None | Some (ys, y, zs) ==> Some (x#ys, y, zs)))" by(auto simp add: extract_def comp_def split: list.splits)
(metis dropWhile_eq_Nil_conv list.distinct(1))
subsubsection ‹🍋‹remove1›\›
lemma count_list_remove1[simp]: "count_list (remove1 a xs) b = count_list xs b - (if a=b then 1 else 0)" by(induction xs) auto
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)" by (induct xs) auto
lemma set_remove1_subset: "set(remove1 x xs) ⊆ set xs" by (induct xs) auto
lemma set_remove1_eq [simp]: "distinct xs ==> set(remove1 x xs) = set xs - {x}" by (induct xs) auto
lemma length_remove1: "length(remove1 x xs) = (if x ∈ set xs then length xs - 1 else length xs)" by (induct xs) (auto dest!:length_pos_if_in_set)
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)" by(insert set_remove1_subset) fast
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: "x ∉ set xs ==> remove1 x xs = xs" by (induct xs) simp_all
lemma remove1_split: "a ∈ set xs ==> remove1 a xs = ys ⟷ (∃ls rs. xs = ls @ a # rs ∧ a ∉ set ls ∧ ys = ls @ rs)" by (metis remove1.simps(2) remove1_append split_list_first)
lemma foldr_fold_remove1[code_unfold]: "foldr remove1 = fold remove1" using foldr_fold[of _ remove1] remove1_commute by fastforce
subsubsection ‹🍋‹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 removeAll_commute: "removeAll x (removeAll y zs) = removeAll y (removeAll x zs)" by (induct zs) 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
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 (rule map_removeAll_inj_on, erule inj_on_subset, rule subset_UNIV)
lemma length_removeAll_less_eq [simp]: "length (removeAll x xs) ≤ length xs" by (simp add: removeAll_filter_not_eq)
lemma length_removeAll_less [termination_simp]: "x ∈ set xs ==> length (removeAll x xs) < length xs" by (auto dest: length_filter_less simp add: removeAll_filter_not_eq)
lemma distinct_concat_iff: "distinct (concat xs) ⟷ distinct (removeAll [] xs) ∧ (∀ys. ys ∈ set xs ⟶ distinct ys) ∧ (∀ys zs. ys ∈ set xs ∧ zs ∈ set xs ∧ ys ≠ zs ⟶ set ys ∩ set zs = {})" proof (induct xs) case Nil thenshow ?caseby auto next case (Cons a xs) have"[set a ∩∪ (set ` set xs) = {}; a ∈ set xs]==> a=[]" by (metis Int_iff UN_I empty_iff equals0I set_empty) thenshow ?case by (auto simp: Cons) qed
lemma foldr_fold_removeAll[code_unfold]: "foldr removeAll = fold removeAll" using foldr_fold[of _ removeAll] removeAll_commute by fastforce
subsubsection ‹🍋‹minus_list_mset›\›
text‹The difference of two lists viewed as multisets. Conceptually, the result of 🍋‹minus_list_mset›is only determined up to permutation, i.e. up to the multiset of elements. Thus this function comes into its own in connection with multisets where ‹mset(minus_list_mset xs ys) = mset xs - mset ys›is proved. Lemma ‹count_list_minus_list_mset›is the equivalent on the list level.›
lemma minus_list_mset_Nil1 [simp]: "minus_list_mset [] xs = []" by (induction xs) auto
lemma minus_list_mset_Cons1: "minus_list_mset (x#xs) ys = (if x ∈ set ys then minus_list_mset xs (remove1 x ys) else x # (minus_list_mset xs ys))" proof (induction ys) case Nil thenshow ?caseby simp next case (Cons a ys) thenshow ?case by (metis list.set_intros(1,2) minus_list_mset_Cons2 minus_list_mset_remove1_commute remove1.simps(2)
set_ConsD) qed
lemma length_replicate [simp]: "length (replicate n x) = n" by (induct n) auto
lemma replicate_eqI: assumes"length xs = n"and"∧y. y ∈ set xs ==> y = x" shows"xs = replicate n x" using assms proof (induct xs arbitrary: n) case Nil thenshow ?caseby simp next case (Cons x xs) thenshow ?caseby (cases n) simp_all qed
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" by (metis length_rev map_replicate map_replicate_const rev_map)
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" by (metis add.commute replicate_add)
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]: "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" by (induct n arbitrary: i)(auto simp: nth_Cons split: nat.split)
text‹Courtesy of Matthias Daum (2 lemmas):› lemma take_replicate[simp]: "take i (replicate k x) = replicate (min i k) x" proof (cases "k ≤ i") case True thenshow ?thesis by (simp add: min_def) next case False thenhave"replicate k x = replicate i x @ replicate (k - i) x" by (simp add: replicate_add [symmetric]) thenshow ?thesis by (simp add: min_def) qed
lemma drop_replicate[simp]: "drop i (replicate k x) = replicate (k-i) x" proof (induct k arbitrary: i) case (Suc k) thenshow ?case by (simp add: drop_Cons') qed simp
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 replicate_eq_replicate[simp]: "(replicate m x = replicate n y) ⟷ (m=n ∧ (m≠0 ⟶ x=y))" proof (induct m arbitrary: n) case (Suc m n) thenshow ?case by (induct n) auto qed simp
lemma takeWhile_replicate[simp]: "takeWhile P (replicate n x) = (if P x then replicate n x else [])" using takeWhile_eq_Nil_iff by fastforce
lemma dropWhile_replicate[simp]: "dropWhile P (replicate n x) = (if P x then [] else replicate n x)" using dropWhile_eq_self_iff by fastforce
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: "xs @ ys = ys @ xs ==>∃m n zs. concat (replicate m zs) = xs ∧ concat (replicate n zs) = ys" proof (induction"length (xs @ ys) + length xs" arbitrary: xs ys rule: less_induct) case less
consider (1) "length ys < length xs" | (2) "xs = []" | (3) "length xs ≤ length ys ∧ xs ≠ []" by linarith thenshow ?case proof (cases) case 1 thenshow ?thesis using less.hyps[OF _ less.prems[symmetric]] nat_add_left_cancel_less by auto next case 2 thenhave"concat (replicate 0 ys) = xs ∧ concat (replicate 1 ys) = ys" by simp thenshow ?thesis by blast next case 3 thenhave"length xs ≤ length ys"and"xs ≠ []" by blast+ from‹length xs ≤ length ys›and‹xs @ ys = ys @ xs› obtain ws where"ys = xs @ ws" by (auto simp: append_eq_append_conv2) from this and‹xs ≠ []› have"length ws < length ys" by simp from‹xs @ ys = ys @ xs›[unfolded ‹ys = xs @ ws›] have"xs @ ws = ws @ xs" by simp from less.hyps[OF _ this] ‹length ws 🚫 ys› obtain m n' zs where"concat (replicate m zs) = xs"and"concat (replicate n' zs) = ws" by auto thenhave"concat (replicate (m+n') zs) = ys" using‹ys = xs @ ws› by (simp add: replicate_add) thenshow ?thesis using‹concat (replicate m zs) = xs›by blast qed 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 comm_append_are_replicate[OF assms(3)] by blast thenhave"m + n > 1"and"concat (replicate (m+n) zs) = xs @ ys" using‹xs ≠ []›and‹ys ≠ []› by (auto simp: replicate_add) thenshow ?thesis by blast qed
lemma Cons_replicate_eq: "x # xs = replicate n y ⟷ x = y ∧ n > 0 ∧ xs = replicate (n - 1) x" by (induct n) auto
lemma replicate_length_same: "(∀y∈set xs. y = x) ==> replicate (length xs) x = xs" by (induct xs) simp_all
lemma foldr_replicate [simp]: "foldr f (replicate n x) = f x ^^ n" by (induct n) (simp_all)
lemma fold_replicate [simp]: "fold f (replicate n x) = f x ^^ n" by (subst foldr_fold [symmetric]) simp_all
subsubsection ‹🍋‹enumerate›\›
lemma enumerate_simps [simp, code]: "enumerate n [] = []" "enumerate n (x # xs) = (n, x) # enumerate (Suc n) xs" by (simp_all add: enumerate_eq_zip upt_rec)
lemma length_enumerate [simp]: "length (enumerate n xs) = length xs" by (simp add: enumerate_eq_zip)
lemma map_fst_enumerate [simp]: "map fst (enumerate n xs) = [n.. by (simp add: enumerate_eq_zip)
lemma map_snd_enumerate [simp]: "map snd (enumerate n xs) = xs" by (simp add: enumerate_eq_zip)
lemma in_set_enumerate_eq: "p ∈ set (enumerate n xs) ⟷ n ≤ fst p ∧ fst p < length xs + n ∧ nth xs (fst p - n) = snd p" proof -
{ fix m assume"n ≤ m" moreoverassume"m < length xs + n" ultimatelyhave"[n..∧ xs ! (m - n) = xs ! (m - n) ∧ m - n < length xs"by auto thenhave"∃q. [n..∧ xs ! q = xs ! (m - n) ∧ q < length xs" ..
} thenshow ?thesis by (cases p) (auto simp add: enumerate_eq_zip in_set_zip) qed
lemma nth_enumerate_eq: "m < length xs ==> enumerate n xs ! m = (n + m, xs ! m)" by (simp add: enumerate_eq_zip)
lemma enumerate_replicate_eq: "enumerate n (replicate m a) = map (λq. (q, a)) [n.. by (rule pair_list_eqI)
(simp_all add: enumerate_eq_zip comp_def map_replicate_const)
lemma rotate_drop_take: "rotate n xs = drop (n mod length xs) xs @ take (n mod length xs) xs" proof (induct n) case (Suc n) show ?case proof (cases "xs = []") case False thenshow ?thesis proof (cases "n mod length xs = 0") case True thenshow ?thesis by (auto simp add: mod_Suc False Suc.hyps drop_Suc rotate1_hd_tl take_Suc Suc_length_conv) next case False with‹xs ≠ []› Suc show ?thesis by (simp add: rotate_def mod_Suc rotate1_hd_tl drop_Suc[symmetric] drop_tl[symmetric]
take_hd_drop linorder_not_le) qed qed simp qed simp
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_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 (cases xs) auto
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
lemma set_rotate[simp]: "set(rotate n xs) = set xs" by (induct n) (simp_all add:rotate_def)
lemma rotate1_replicate[simp]: "rotate1 (replicate n a) = replicate n a" by (cases n) (simp_all add: replicate_append_same)
lemma rotate1_is_Nil_conv[simp]: "(rotate1 xs = []) = (xs = [])" by (cases xs) auto
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)" proof (cases "length xs = 0 ∨ n mod length xs = 0") case False thenshow ?thesis by(simp add:rotate_drop_take rev_drop rev_take) qed force
lemma hd_rotate_conv_nth: assumes"xs ≠ []"shows"hd(rotate n xs) = xs!(n mod length xs)" proof - have"n mod length xs < length xs" using assms by simp thenshow ?thesis by (metis drop_eq_Nil hd_append2 hd_drop_conv_nth leD rotate_drop_take) qed
lemma surj_rotate1: "surj rotate1" proof (safe, simp_all) fix xs :: "'a list"show"xs ∈ range rotate1" proof (cases xs rule: rev_exhaust) case Nil hence"xs = rotate1 []"by auto thus ?thesis by fast next case (snoc as a) hence"xs = rotate1 (a#as)"by force thus ?thesis by fast qed qed
lemma bij_rotate1: "bij (rotate1 :: 'a list ==> 'a list)" using bijI inj_rotate1 surj_rotate1 by blast
lemma nths_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)))" proof (induct xs arbitrary: "is") case (Cons x xs "is") show ?case by (cases "is") (auto simp add: Cons.hyps) qed simp
lemma nths_shift_lemma: "map fst (filter (λp. snd p ∈ A) (zip xs [i.. map fst (filter (λp. snd p + i ∈ A) (zip xs [0.. by (induct xs rule: rev_induct) (simp_all add: add.commute)
lemma nths_append: "nths (l @ l') A = nths l A @ nths l' {j. j + length l ∈ A}" unfolding nths_def proof (induct l' rule: rev_induct) case (snoc x xs) thenshow ?case by (simp add: upt_add_eq_append[of 0] nths_shift_lemma add.commute) qed auto
lemma nths_Cons: "nths (x # l) A = (if 0 ∈ A then [x] else []) @ nths l {j. Suc j ∈ A}" proof (induct l rule: rev_induct) case (snoc x xs) thenshow ?case by (simp flip: append_Cons add: nths_append) qed (auto simp: nths_def)
lemma nths_map: "nths (map f xs) I = map f (nths xs I)" by(induction xs arbitrary: I) (simp_all add: nths_Cons)
lemma nths_upt_eq_take [simp]: "nths l {.. by (induct l rule: rev_induct) (simp_all split: nat_diff_split add: nths_append)
lemma nths_nths: "nths (nths xs A) B = nths xs {i ∈ A. ∃j ∈ B. card {i' ∈ A. i' < i} = j}" by (induction xs arbitrary: A B) (auto simp add: nths_Cons card_less_Suc card_less_Suc2)
lemma drop_eq_nths: "drop n xs = nths xs {i. i ≥ n}" by (induction xs arbitrary: n) (auto simp add: nths_Cons nths_all drop_Cons' intro: arg_cong2[where f=nths, OF refl])
lemma nths_drop: "nths (drop n xs) I = nths xs ((+) n ` I)" by(force simp: drop_eq_nths nths_nths simp flip: atLeastLessThan_iff
intro: arg_cong2[where f=nths, OF refl])
lemma filter_in_nths: "distinct xs ==> filter (%x. x ∈ set (nths xs s)) xs = nths xs s" proof (induct xs arbitrary: s) case Nil thus ?caseby simp next case (Cons a xs) thenhave"∀x. x ∈ set xs ⟶ x ≠ a"by auto with Cons show ?caseby(simp add: nths_Cons cong:filter_cong) qed
lemma subseqs_powset: "set ` set (subseqs xs) = Pow (set xs)" proof - have aux: "∧x A. set ` Cons x ` A = insert x ` set ` A" by (auto simp add: image_def) have"set (map set (subseqs xs)) = Pow (set xs)" by (induct xs) (simp_all add: aux Let_def Pow_insert Un_commute comp_def del: map_map) thenshow ?thesis by simp qed
lemma distinct_set_subseqs: assumes"distinct xs" shows"distinct (map set (subseqs xs))" by (simp add: assms card_Pow card_distinct distinct_card length_subseqs subseqs_powset)
lemma n_lists_Nil [simp]: "List.n_lists n [] = (if n = 0 then [[]] else [])" by (induct n) simp_all
lemma length_n_lists_elem: "ys ∈ set (List.n_lists n xs) ==> length ys = n" by (induct n arbitrary: ys) auto
lemma set_n_lists: "set (List.n_lists n xs) = {ys. length ys = n ∧ set ys ⊆ set xs}" proof (rule set_eqI) fix ys :: "'a list" show"ys ∈ set (List.n_lists n xs) ⟷ ys ∈ {ys. length ys = n ∧ set ys ⊆ set xs}" proof - have"ys ∈ set (List.n_lists n xs) ==> length ys = n" by (induct n arbitrary: ys) auto moreoverhave"∧x. ys ∈ set (List.n_lists n xs) ==> x ∈ set ys ==> x ∈ set xs" by (induct n arbitrary: ys) auto moreoverhave"set ys ⊆ set xs ==> ys ∈ set (List.n_lists (length ys) xs)" by (induct ys) auto ultimatelyshow ?thesis by auto qed qed
lemma subseqs_refl: "xs ∈ set (subseqs xs)" by (induct xs) (simp_all add: Let_def)
lemma subset_subseqs: "X ⊆ set xs ==> X ∈ set ` set (subseqs xs)" unfolding subseqs_powset by simp
lemma Cons_in_subseqsD: "y # ys ∈ set (subseqs xs) ==> ys ∈ set (subseqs xs)" by (induct xs) (auto simp: Let_def)
lemma subseqs_distinctD: "[ ys ∈ set (subseqs xs); distinct xs ]==> distinct ys" proof (induct xs arbitrary: ys) case (Cons x xs ys) thenshow ?case by (auto simp: Let_def) (metis Pow_iff contra_subsetD image_eqI subseqs_powset) qed simp
lemma splice_replicate[simp]: "splice (replicate m x) (replicate n x) = replicate (m+n) x" proof (induction"replicate m x""replicate n x" arbitrary: m n rule: splice.induct) case (2 x xs) thenshow ?case by (auto simp add: Cons_replicate_eq dest: gr0_implies_Suc) qed auto
lemma set_shuffles: "zs ∈ shuffles xs ys ==> set zs = set xs ∪ set ys" by (induction xs ys arbitrary: zs rule: shuffles.induct) auto
lemma distinct_disjoint_shuffles: assumes"distinct xs""distinct ys""set xs ∩ set ys = {}""zs ∈ shuffles xs ys" shows"distinct zs" using assms proof (induction xs ys arbitrary: zs rule: shuffles.induct) case (3 x xs y ys) show ?case proof (cases zs) case (Cons z zs') with"3.prems"and"3.IH"[of zs'] show ?thesis by (force dest: set_shuffles) qed simp_all qed simp_all
lemma Cons_shuffles_subset1: "(#) x ` shuffles xs ys ⊆ shuffles (x # xs) ys" by (cases ys) auto
lemma Cons_shuffles_subset2: "(#) y ` shuffles xs ys ⊆ shuffles xs (y # ys)" by (cases xs) auto
lemma filter_shuffles: "filter P ` shuffles xs ys = shuffles (filter P xs) (filter P ys)" proof - have *: "filter P ` (#) x ` A = (if P x then (#) x ` filter P ` A else filter P ` A)"for x A by (auto simp: image_image) show ?thesis by (induction xs ys rule: shuffles.induct)
(simp_all split: if_splits add: image_Un * Un_absorb1 Un_absorb2
Cons_shuffles_subset1 Cons_shuffles_subset2) qed
fix i assume"i < length (transpose (map (map f) xs))" thus"transpose (map (map f) xs) ! i = map (map f) (transpose xs) ! i" by (simp add: nth_transpose filter_map comp_def) qed
subsubsection ‹🍋‹min›and 🍋‹arg_min›\›
lemma min_list_Min: "xs ≠ [] ==> min_list xs = Min (set xs)" by (induction xs rule: induct_list012)(auto)
lemma f_arg_min_list_f: "xs ≠ [] ==> f (arg_min_list f xs) = Min (f ` (set xs))" by(induction f xs rule: arg_min_list.induct) (auto simp: min_def intro!: antisym)
lemma arg_min_list_in: "xs ≠ [] ==> arg_min_list f xs ∈ set xs" by(induction xs rule: induct_list012) (auto simp: Let_def)
subsubsection ‹(In)finiteness›
lemma finite_list_length: "finite {xs::('a::finite) list. length xs = n}" proof(induction n) case (Suc n) have"{xs::'a list. length xs = Suc n} = (∪x. (#) x ` {xs. length xs = n})" by (auto simp: length_Suc_conv) thenshow ?caseusing Suc by simp qed simp
lemma finite_maxlen: "finite (M::'a list set) ==>∃n. ∀s∈M. size s < n" proof (induct rule: finite.induct) case emptyI show ?caseby simp next case (insertI M xs) thenobtain n where"∀s∈M. length s < n"by blast hence"∀s∈insert xs M. size s < max n (size xs) + 1"by auto thus ?case .. qed
lemma lists_length_Suc_eq: "{xs. set xs ⊆ A ∧ length xs = Suc n} = (λ(xs, n). n#xs) ` ({xs. set xs ⊆ A ∧ length xs = n} × A)" by (auto simp: length_Suc_conv)
lemma assumes"finite A" shows finite_lists_length_eq: "finite {xs. set xs ⊆ A ∧ length xs = n}" and card_lists_length_eq: "card {xs. set xs ⊆ A ∧ length xs = n} = (card A)^n" using‹finite A› by (induct n)
(auto simp: card_image inj_split_Cons lists_length_Suc_eq cong: conj_cong)
lemma finite_lists_length_le: assumes"finite A"shows"finite {xs. set xs ⊆ A ∧ length xs ≤ n}"
(is"finite ?S")
proof- have"?S = (∪n∈{0..n}. {xs. set xs ⊆ A ∧ length xs = n})"by auto thus ?thesis by (auto intro!: finite_lists_length_eq[OF ‹finite A›] simp only:) qed
lemma card_lists_length_le: assumes"finite A"shows"card {xs. set xs ⊆ A ∧ length xs ≤ n} = (∑i≤n. card A^i)" proof - have"(∑i≤n. card A^i) = card (∪i≤n. {xs. set xs ⊆ A ∧ length xs = i})" using‹finite A› by (subst card_UN_disjoint)
(auto simp add: card_lists_length_eq finite_lists_length_eq) alsohave"(∪i≤n. {xs. set xs ⊆ A ∧ length xs = i}) = {xs. set xs ⊆ A ∧ length xs ≤ n}" by auto finallyshow ?thesis by simp qed
lemma finite_subset_distinct: assumes"finite A" shows"finite {xs. set xs ⊆ A ∧ distinct xs}" (is"finite ?S") proof (rule finite_subset) from assms show"?S ⊆ {xs. set xs ⊆ A ∧ length xs ≤ card A}" by clarsimp (metis distinct_card card_mono) from assms show"finite ..."by (rule finite_lists_length_le) qed
lemma card_lists_distinct_length_eq: assumes"finite A""k ≤ card A" shows"card {xs. length xs = k ∧ distinct xs ∧ set xs ⊆ A} = ∏{card A - k + 1 .. card A}" using assms proof (induct k) case 0 thenhave"{xs. length xs = 0 ∧ distinct xs ∧ set xs ⊆ A} = {[]}"by auto thenshow ?caseby simp next case (Suc k) let"?k_list" = "λk xs. length xs = k ∧ distinct xs ∧ set xs ⊆ A" have inj_Cons: "∧A. inj_on (λ(xs, n). n # xs) A"by (rule inj_onI) auto
from Suc have"k ≤ card A"by simp moreovernote‹finite A› moreoverhave"finite {xs. ?k_list k xs}" by (rule finite_subset) (use finite_lists_length_eq[OF ‹finite A›, of k] in auto) moreoverhave"∧i j. i ≠ j ⟶ {i} × (A - set i) ∩ {j} × (A - set j) = {}" by auto moreoverhave"∧i. i ∈ {xs. ?k_list k xs} ==> card (A - set i) = card A - k" by (simp add: card_Diff_subset distinct_card) moreoverhave"{xs. ?k_list (Suc k) xs} = (λ(xs, n). n#xs) ` ∪((λxs. {xs} × (A - set xs)) ` {xs. ?k_list k xs})" by (auto simp: length_Suc_conv) moreoverhave"Suc (card A - Suc k) = card A - k"using Suc.prems by simp thenhave"(card A - k) * ∏{Suc (card A - k)..card A} = ∏{Suc (card A - Suc k)..card A}" by (subst prod.insert[symmetric]) (simp add: atLeastAtMost_insertL)+ ultimatelyshow ?case by (simp add: card_image inj_Cons card_UN_disjoint Suc.hyps algebra_simps) qed
lemma card_lists_distinct_length_eq': assumes"k < card A" shows"card {xs. length xs = k ∧ distinct xs ∧ set xs ⊆ A} = ∏{card A - k + 1 .. card A}" proof - from‹k 🚫 A›have"finite A"and"k ≤ card A"using card.infinite by force+ from this show ?thesis by (rule card_lists_distinct_length_eq) qed
lemma infinite_UNIV_listI: "¬ finite(UNIV::'a list set)" by (metis UNIV_I finite_maxlen length_replicate less_irrefl)
lemma same_length_different: assumes"xs ≠ ys"and"length xs = length ys" shows"∃pre x xs' y ys'. x≠y ∧ xs = pre @ [x] @ xs' ∧ ys = pre @ [y] @ ys'" using assms proof (induction xs arbitrary: ys) case Nil thenshow ?caseby auto next case (Cons x xs) thenobtain z zs where ys: "ys = Cons z zs" by (metis length_Suc_conv) show ?case proof (cases "x=z") case True thenhave"xs ≠ zs""length xs = length zs" using Cons.prems ys by auto thenobtainpre u xs' v ys' where"u≠v"and xs: "xs = pre @ [u] @ xs'"and zs: "zs = pre @ [v] @ys'" using Cons.IH by meson thenhave"x # xs = (z#pre) @ [u] @ xs' ∧ ys = (z#pre) @ [v] @ ys'" by (simp add: True ys) with‹u≠v›show ?thesis by blast next case False thenhave"x # xs = [] @ [x] @ xs ∧ ys = [] @ [z] @ zs" by (simp add: ys) thenshow ?thesis using False by blast qed qed
subsection‹Sorting›
subsubsection ‹🍋‹sorted_wrt›\›
text‹Sometimes the second equation in the definition of 🍋‹sorted_wrt›is too aggressive because it relates each list element to \emph{all} its successors. Then this equation should be removed and ‹sorted_wrt2_simps›should be added instead.›
lemma sorted_wrt1: "sorted_wrt P [x] = True" by(simp)
lemma sorted_wrt2: "transp P ==> sorted_wrt P (x # y # zs) = (P x y ∧ sorted_wrt P (y # zs))" proof (induction zs arbitrary: x y) case (Cons z zs) thenshow ?case by simp (meson transpD)+ qed auto
lemma sorted_wrt_append: "sorted_wrt P (xs @ ys) ⟷ sorted_wrt P xs ∧ sorted_wrt P ys ∧ (∀x∈set xs. ∀y∈set ys. P x y)" by (induction xs) auto
lemma sorted_wrt_map: "sorted_wrt R (map f xs) = sorted_wrt (λx y. R (f x) (f y)) xs" by (induction xs) simp_all
lemma assumes"sorted_wrt f xs" shows sorted_wrt_take[simp]: "sorted_wrt f (take n xs)" and sorted_wrt_drop[simp]: "sorted_wrt f (drop n xs)" proof - from assms have"sorted_wrt f (take n xs @ drop n xs)"by simp thus"sorted_wrt f (take n xs)"and"sorted_wrt f (drop n xs)" unfolding sorted_wrt_append by simp_all qed
lemma sorted_wrt_dropWhile[simp]: "sorted_wrt R xs ==> sorted_wrt R (dropWhile P xs)" by (auto dest: sorted_wrt_drop simp: dropWhile_eq_drop)
lemma sorted_wrt_takeWhile[simp]: "sorted_wrt R xs ==> sorted_wrt R (takeWhile P xs)" by (subst takeWhile_eq_take) (auto dest: sorted_wrt_take)
lemma sorted_wrt_filter: "sorted_wrt f xs ==> sorted_wrt f (filter P xs)" by (induction xs) auto
lemma sorted_wrt_rev: "sorted_wrt P (rev xs) = sorted_wrt (λx y. P y x) xs" by (induction xs) (auto simp add: sorted_wrt_append)
lemma sorted_wrt_mono_rel: "(∧x y. [ x ∈ set xs; y ∈ set xs; P x y ]==> Q x y) ==> sorted_wrt P xs ==> sorted_wrt Q xs" by(induction xs)(auto)
lemma sorted_wrt_upto[simp]: "sorted_wrt (<) [i..j]" proof(induct i j rule:upto.induct) case (1 i j) from this show ?case unfolding upto.simps[of i j] by auto qed
text‹Each element is greater or equal to its index:›
lemma sorted_wrt_less_idx: "sorted_wrt (<) ns ==> i < length ns ==> i ≤ ns!i" proof (induction ns arbitrary: i rule: rev_induct) case Nil thus ?caseby simp next case snoc thus ?case by (simp add: nth_append sorted_wrt_append)
(metis less_antisym not_less nth_mem) qed
subsubsection ‹🍋‹sorted›\›
context linorder begin
text‹Sometimes the second equation in the definition of 🍋‹sorted›is too aggressive because it relates each list element to \emph{all} its successors. Then this equation should be removed and ‹sorted2_simps›should be added instead. Executable code is one such use case.›
lemma sorted0: "sorted [] = True" by simp
lemma sorted1: "sorted [x] = True" by simp
lemma sorted2: "sorted (x # y # zs) = (x ≤ y ∧ sorted (y # zs))" by auto
lemmas sorted2_simps = sorted1 sorted2
lemma sorted_append: "sorted (xs@ys) = (sorted xs ∧ sorted ys ∧ (∀x ∈ set xs. ∀y ∈ set ys. x≤y))" by (simp add: sorted_wrt_append)
lemma sorted_map: "sorted (map f xs) = sorted_wrt (λx y. f x ≤ f y) xs" by (simp add: sorted_wrt_map)
lemma sorted_rev_iff_nth_mono: "sorted (rev xs) ⟷ (∀ i j. i ≤ j ⟶ j < length xs ⟶ xs!j ≤ xs!i)" (is"?L = ?R") proof assume ?L thus ?R by (blast intro: sorted_rev_nth_mono) next assume ?R have"rev xs ! k ≤ rev xs ! l"if asms: "k ≤ l""l < length(rev xs)"for k l proof - have"k < length xs""l < length xs" "length xs - Suc l ≤ length xs - Suc k""length xs - Suc k < length xs" using asms by auto thus"rev xs ! k ≤ rev xs ! l" by (simp add: ‹?R› rev_nth) qed thus ?L by (simp add: sorted_iff_nth_mono) qed
lemma sorted_rev_iff_nth_Suc: "sorted (rev xs) ⟷ (∀i. Suc i < length xs ⟶ xs!(Suc i) ≤ xs!i)"
proof- interpret dual: linorder "(λx y. y ≤ x)""(λx y. y < x)" using dual_linorder . show ?thesis using dual_linorder dual.sorted_iff_nth_Suc dual.sorted_iff_nth_mono unfolding sorted_rev_iff_nth_mono by simp qed
lemma sorted_map_remove1: "sorted (map f xs) ==> sorted (map f (remove1 x xs))" by (induct xs) (auto)
lemma sorted_remove1: "sorted xs ==> sorted (remove1 a xs)" using sorted_map_remove1 [of "λx. x"] by simp
lemma sorted_distinct_set_unique: assumes"sorted xs""distinct xs""sorted ys""distinct ys""set xs = set ys" shows"xs = ys" proof - from assms have 1: "length xs = length ys"by (auto dest!: distinct_card) from assms show ?thesis proof(induct rule:list_induct2[OF 1]) case 1 show ?caseby simp next case (2 x xs y ys) thenshow ?case by (cases ‹x = y›) (auto simp add: insert_eq_iff) qed qed
lemma map_sorted_distinct_set_unique: assumes"inj_on f (set xs ∪ set ys)" assumes"sorted (map f xs)""distinct (map f xs)" "sorted (map f ys)""distinct (map f ys)" assumes"set xs = set ys" shows"xs = ys" using assms map_inj_on sorted_distinct_set_unique by fastforce
lemma sorted_dropWhile: "sorted xs ==> sorted (dropWhile P xs)" by (auto dest: sorted_wrt_drop simp add: dropWhile_eq_drop)
lemma sorted_takeWhile: "sorted xs ==> sorted (takeWhile P xs)" by (subst takeWhile_eq_take) (auto dest: sorted_wrt_take)
lemma sorted_filter: "sorted (map f xs) ==> sorted (map f (filter P xs))" by (induct xs) simp_all
lemma foldr_max_sorted: assumes"sorted (rev xs)" shows"foldr max xs y = (if xs = [] then y else max (xs ! 0) y)" using assms proof (induct xs) case (Cons x xs) thenhave"sorted (rev xs)"using sorted_append by auto with Cons show ?case by (cases xs) (auto simp add: sorted_append max_def) qed simp
lemma filter_equals_takeWhile_sorted_rev: assumes sorted: "sorted (rev (map f xs))" shows"filter (λx. t < f x) xs = takeWhile (λ x. t < f x) xs"
(is"filter ?P xs = ?tW") proof (rule takeWhile_eq_filter[symmetric]) let"?dW" = "dropWhile ?P xs" fix x assume x: "x ∈ set ?dW" thenobtain i where i: "i < length ?dW"and nth_i: "x = ?dW ! i" unfolding in_set_conv_nth by auto hence"length ?tW + i < length (?tW @ ?dW)" unfolding length_append by simp hence i': "length (map f ?tW) + i < length (map f xs)"by simp have"(map f ?tW @ map f ?dW) ! (length (map f ?tW) + i) ≤ (map f ?tW @ map f ?dW) ! (length (map f ?tW) + 0)" using sorted_rev_nth_mono[OF sorted _ i', of "length ?tW"] unfolding map_append[symmetric] by simp hence"f x ≤ f (?dW ! 0)" unfolding nth_append_length_plus nth_i using i preorder_class.le_less_trans[OF le0 i] by simp alsohave"... ≤ t" by (metis hd_conv_nth hd_dropWhile length_greater_0_conv length_pos_if_in_set local.leI x) finallyshow"¬ t < f x"by simp qed
lemma sorted_map_same: "sorted (map f (filter (λx. f x = g xs) xs))" proof (induct xs arbitrary: g) case Nil thenshow ?caseby simp next case (Cons x xs) thenhave"sorted (map f (filter (λy. f y = (λxs. f x) xs) xs))" . moreoverfrom Cons have"sorted (map f (filter (λy. f y = (g ∘ Cons x) xs) xs))" . ultimatelyshow ?caseby simp_all qed
lemma sorted_same: "sorted (filter (λx. x = g xs) xs)" using sorted_map_same [of "λx. x"] by simp
text‹Currently it is not shown that 🍋‹sort›returns a permutation of its input because the nicest proof is via multisets, which are not part of Main. Alternatively one could define a function that counts the number of occurrences of an element in a list and use that instead of multisets to state the correctness property.›
context linorder begin
lemma set_insort_key: "set (insort_key f x xs) = insert x (set xs)" by (induct xs) auto
lemma length_insort [simp]: "length (insort_key f x xs) = Suc (length xs)" by (induct xs) simp_all
lemma insort_key_left_comm: assumes"f x ≠ f y" shows"insort_key f y (insort_key f x xs) = insort_key f x (insort_key f y xs)" by (induct xs) (auto simp add: assms dest: order.antisym)
lemma insort_left_comm: "insort x (insort y xs) = insort y (insort x xs)" by (cases "x = y") (auto intro: insort_key_left_comm)
lemma comp_fun_commute_insort: "comp_fun_commute insort" proof qed (simp add: insort_left_comm fun_eq_iff)
lemma sort_key_simps [simp]: "sort_key f [] = []" "sort_key f (x#xs) = insort_key f x (sort_key f xs)" by (simp_all add: sort_key_def)
lemma sort_key_conv_fold: assumes"inj_on f (set xs)" shows"sort_key f xs = fold (insort_key f) xs []" proof - have"fold (insort_key f) (rev xs) = fold (insort_key f) xs" proof (rule fold_rev, rule ext) fix zs fix x y assume"x ∈ set xs""y ∈ set xs" with assms have *: "f y = f x ==> y = x"by (auto dest: inj_onD) have **: "x = y ⟷ y = x"by auto show"(insort_key f y ∘ insort_key f x) zs = (insort_key f x ∘ insort_key f y) zs" by (induct zs) (auto intro: * simp add: **) qed thenshow ?thesis by (simp add: sort_key_def foldr_conv_fold) qed
lemma length_sort[simp]: "length (sort_key f xs) = length xs" by (induct xs, auto)
lemma set_sort[simp]: "set(sort_key f xs) = set xs" by (induct xs) (simp_all add: set_insort_key)
lemma distinct_insort: "distinct (insort_key f x xs) = (x ∉ set xs ∧ distinct xs)" by(induct xs)(auto simp: set_insort_key)
lemma distinct_insort_key: "distinct (map f (insort_key f x xs)) = (f x ∉ f ` set xs ∧ (distinct (map f xs)))" by (induct xs) (auto simp: set_insort_key)
lemma distinct_sort[simp]: "distinct (sort_key f xs) = distinct xs" by (induct xs) (simp_all add: distinct_insort)
lemma sorted_insort_key: "sorted (map f (insort_key f x xs)) = sorted (map f xs)" by (induct xs) (auto simp: set_insort_key)
lemma sorted_insort: "sorted (insort x xs) = sorted xs" using sorted_insort_key [where f="λx. x"] by simp
theorem sorted_sort_key [simp]: "sorted (map f (sort_key f xs))" by (induct xs) (auto simp:sorted_insort_key)
theorem sorted_sort [simp]: "sorted (sort xs)" using sorted_sort_key [where f="λx. x"] by simp
lemma insort_not_Nil [simp]: "insort_key f a xs ≠ []" by (induction xs) simp_all
lemma insort_is_Cons: "∀x∈set xs. f a ≤ f x ==> insort_key f a xs = a # xs" by (cases xs) auto
lemma sort_key_id_if_sorted: "sorted (map f xs) ==> sort_key f xs = xs" by (induction xs) (auto simp add: insort_is_Cons)
text‹Subsumed by @{thm sort_key_id_if_sorted} but easier to find:› lemma sorted_sort_id: "sorted xs ==> sort xs = xs" by (simp add: sort_key_id_if_sorted)
lemma sort_replicate [simp]: "sort (replicate n x) = replicate n x" using sorted_replicate sorted_sort_id by presburger
lemma insort_key_remove1: assumes"a ∈ set xs"and"sorted (map f xs)"and"hd (filter (λx. f a = f x) xs) = a" shows"insort_key f a (remove1 a xs) = xs" using assms proof (induct xs) case (Cons x xs) thenshow ?case proof (cases "x = a") case False thenhave"f x ≠ f a"using Cons.prems by auto thenhave"f x < f a"using Cons.prems by auto with‹f x ≠ f a›show ?thesis using Cons by (auto simp: insort_is_Cons) qed (auto simp: insort_is_Cons) qed simp
lemma insort_remove1: assumes"a ∈ set xs"and"sorted xs" shows"insort a (remove1 a xs) = xs" proof (rule insort_key_remove1)
define n where"n = length (filter ((=) a) xs) - 1" from‹a ∈ set xs›show"a ∈ set xs" . from‹sorted xs›show"sorted (map (λx. x) xs)"by simp from‹a ∈ set xs›have"a ∈ set (filter ((=) a) xs)"by auto thenhave"set (filter ((=) a) xs) ≠ {}"by auto thenhave"filter ((=) a) xs ≠ []"by (auto simp only: set_empty) thenhave"length (filter ((=) a) xs) > 0"by simp thenhave n: "Suc n = length (filter ((=) a) xs)"by (simp add: n_def) moreoverhave"replicate (Suc n) a = a # replicate n a" by simp ultimatelyshow"hd (filter ((=) a) xs) = a"by (simp add: replicate_length_filter) qed
lemma finite_sorted_distinct_unique: assumes"finite A"shows"∃!xs. set xs = A ∧ sorted xs ∧ distinct xs" proof - obtain xs where"distinct xs""A = set xs" using finite_distinct_list [OF assms] by metis thenshow ?thesis by (rule_tac a="sort xs"in ex1I) (auto simp: sorted_distinct_set_unique) qed
lemma insort_insert_key_triv: "f x ∈ f ` set xs ==> insort_insert_key f x xs = xs" by (simp add: insort_insert_key_def)
lemma insort_insert_triv: "x ∈ set xs ==> insort_insert x xs = xs" using insort_insert_key_triv [of "λx. x"] by simp
lemma insort_insert_insort_key: "f x ∉ f ` set xs ==> insort_insert_key f x xs = insort_key f x xs" by (simp add: insort_insert_key_def)
lemma insort_insert_insort: "x ∉ set xs ==> insort_insert x xs = insort x xs" using insort_insert_insort_key [of "λx. x"] by simp
lemma set_insort_insert: "set (insort_insert x xs) = insert x (set xs)" by (auto simp add: insort_insert_key_def set_insort_key)
lemma distinct_insort_insert: assumes"distinct xs" shows"distinct (insort_insert_key f x xs)" using assms by (induct xs) (auto simp add: insort_insert_key_def set_insort_key)
lemma sorted_insort_insert_key: assumes"sorted (map f xs)" shows"sorted (map f (insort_insert_key f x xs))" using assms by (simp add: insort_insert_key_def sorted_insort_key)
lemma sorted_insort_insert: assumes"sorted xs" shows"sorted (insort_insert x xs)" using assms sorted_insort_insert_key [of "λx. x"] by simp
lemma filter_insort_triv: "¬ P x ==> filter P (insort_key f x xs) = filter P xs" by (induct xs) simp_all
lemma filter_insort: "sorted (map f xs) ==> P x ==> filter P (insort_key f x xs) = insort_key f x (filter P xs)" by (induct xs) (auto, subst insort_is_Cons, auto)
lemma filter_sort: "filter P (sort_key f xs) = sort_key f (filter P xs)" by (induct xs) (simp_all add: filter_insort_triv filter_insort)
lemma remove1_insort_key [simp]: "remove1 x (insort_key f x xs) = xs" by (induct xs) simp_all
end
lemma sort_upt [simp]: "sort [m.. by (rule sort_key_id_if_sorted) simp
lemma sorted_find_Min: "sorted xs ==>∃x ∈ set xs. P x ==> List.find P xs = Some (Min {x∈set xs. P x})" proof (induct xs) case Nil thenshow ?caseby simp next case (Cons x xs) show ?caseproof (cases "P x") case True with Cons show ?thesis by (auto intro: Min_eqI [symmetric]) next case False thenhave"{y. (y = x ∨ y ∈ set xs) ∧ P y} = {y ∈ set xs. P y}" by auto with Cons False show ?thesis by (simp_all) qed qed
lemma sorted_enumerate [simp]: "sorted (map fst (enumerate n xs))" by (simp add: enumerate_eq_zip)
lemma sorted_insort_is_snoc: "sorted xs ==>∀x ∈ set xs. a ≥ x ==> insort a xs = xs @ [a]" by (induct xs) (auto dest!: insort_is_Cons)
text‹Stability of 🍋‹sort_key›:›
lemma sort_key_stable: "filter (λy. f y = k) (sort_key f xs) = filter (λy. f y = k) xs" by (induction xs) (auto simp: filter_insort insort_is_Cons filter_insort_triv)
fix j assume j: "j < length ?R" note * = less_le_trans[OF this, unfolded length_map, OF length_filter_le] from j have j_less: "j < length (xs ! i)"using length by simp have i_less_tW: "Suc i ≤ length (takeWhile (λys. Suc j ≤ length ys) xs)" proof (rule length_takeWhile_less_P_nth) show"Suc i ≤ length xs"using‹i 🚫 xs›by simp fix k assume"k < Suc i" hence"k ≤ i"by auto with sorted_rev_nth_mono[OF sorted this] ‹i 🚫 xs› have"length (xs ! i) ≤ length (xs ! k)"by simp thus"Suc j ≤ length (xs ! k)"using j_less by simp qed have i_less_filter: "i < length (filter (λys. j < length ys) xs) " unfolding filter_equals_takeWhile_sorted_rev[OF sorted, of j] using i_less_tW by (simp_all add: Suc_le_eq) from j show"?R ! j = xs ! i ! j" unfolding filter_equals_takeWhile_sorted_rev[OF sorted_transpose, of i] by (simp add: takeWhile_nth nth_nth_transpose_sorted[OF sorted * i_less_filter]) qed
lemma transpose_transpose: fixes xs :: "'a list list" assumes sorted: "sorted (rev (map length xs))" shows"transpose (transpose xs) = takeWhile (λx. x ≠ []) xs" (is"?L = ?R") proof - have len: "length ?L = length ?R" unfolding length_transpose transpose_max_length using filter_equals_takeWhile_sorted_rev[OF sorted, of 0] by simp
{ fix i assume"i < length ?R" with less_le_trans[OF _ length_takeWhile_le[of _ xs]] have"i < length xs"by simp
} note * = this show ?thesis by (rule nth_equalityI)
(simp_all add: len nth_transpose transpose_column[OF sorted] * takeWhile_nth) qed
theorem transpose_rectangle: assumes"xs = [] ==> n = 0" assumes rect: "∧ i. i < length xs ==> length (xs ! i) = n" shows"transpose xs = map (λ i. map (λ j. xs ! j ! i) [0..
(is"?trans = ?map") proof (rule nth_equalityI) have"sorted (rev (map length xs))" by (auto simp: rev_nth rect sorted_iff_nth_mono) from foldr_max_sorted[OF this] assms show len: "length ?trans = length ?map" by (simp_all add: length_transpose foldr_map comp_def) moreover
{ fix i assume"i < n"hence"filter (λys. i < length ys) xs = xs" using rect by (auto simp: in_set_conv_nth intro!: filter_True) } ultimatelyshow"∧i. i < length (transpose xs) ==> ?trans ! i = ?map ! i" by (auto simp: nth_transpose intro: nth_equalityI) qed
subsubsection ‹‹sorted_key_list_of_set›\›
text‹ This function maps (finite) linearly ordered sets to sorted lists. The linear order is obtained by a key function that maps the elements of the set to a type that is linearly ordered. Warning: in most cases it is not a good idea to convert from sets to lists but one should convert in the other direction (via 🍋‹set›). Note: this is a generalisation of the older ‹sorted_list_of_set›that is obtained by setting the key function to the identity. Consequently, new theorems should be added to the locale below. They should also be aliased to more convenient names for use with ‹sorted_list_of_set› as seen further below. ›
definition (in linorder) sorted_key_list_of_set :: "('b ==> 'a) ==> 'b set ==> 'b list" where"sorted_key_list_of_set f ≡ folding_on.F (insort_key f) []"
locale folding_insort_key = lo?: linorder "less_eq :: 'a ==> 'a ==> bool" less for less_eq (infix‹⪯› 50) and less (infix‹≺› 50) + fixes S fixes f :: "'b ==> 'a" assumes inj_on: "inj_on f S" begin
lemma insort_key_commute: "x ∈ S ==> y ∈ S ==> insort_key f y o insort_key f x = insort_key f x o insort_key f y" proof(rule ext, goal_cases) case (1 xs) with inj_on show ?caseby (induction xs) (auto simp: inj_onD) qed
sublocale fold_insort_key: folding_on S "insort_key f""[]"
rewrites "folding_on.F (insort_key f) [] = sorted_key_list_of_set f" proof - show"folding_on S (insort_key f)" by standard (simp add: insort_key_commute) qed (simp add: sorted_key_list_of_set_def)
lemma idem_if_sorted_distinct: assumes"set xs ⊆ S"and"sorted (map f xs)""distinct xs" shows"sorted_key_list_of_set f (set xs) = xs" proof(cases "S = {}") case True thenshow ?thesis using‹set xs ⊆ S›by auto next case False with assms show ?thesis proof(induction xs) case (Cons a xs) with Cons show ?caseby (cases xs) auto qed simp qed
lemma sorted_key_list_of_set_empty: "sorted_key_list_of_set f {} = []" by (fact fold_insort_key.empty)
lemma sorted_key_list_of_set_insert: assumes"insert x A ⊆ S"and"finite A""x ∉ A" shows"sorted_key_list_of_set f (insert x A) = insort_key f x (sorted_key_list_of_set f A)" using assms by (fact fold_insort_key.insert)
lemma sorted_key_list_of_set_insert_remove [simp]: assumes"insert x A ⊆ S"and"finite A" shows"sorted_key_list_of_set f (insert x A) = insort_key f x (sorted_key_list_of_set f (A - {x}))" using assms by (fact fold_insort_key.insert_remove)
lemma sorted_key_list_of_set_eq_Nil_iff [simp]: assumes"A ⊆ S"and"finite A" shows"sorted_key_list_of_set f A = [] ⟷ A = {}" using assms by (auto simp: fold_insort_key.remove)
lemma set_sorted_key_list_of_set [simp]: assumes"A ⊆ S"and"finite A" shows"set (sorted_key_list_of_set f A) = A" using assms(2,1) by (induct A rule: finite_induct) (simp_all add: set_insort_key)
lemma sorted_sorted_key_list_of_set [simp]: assumes"A ⊆ S" shows"sorted (map f (sorted_key_list_of_set f A))" proof (cases "finite A") case True thus ?thesis using‹A ⊆ S› by (induction A) (simp_all add: sorted_insort_key) next case False thus ?thesis by simp qed
lemma distinct_if_distinct_map: "distinct (map f xs) ==> distinct xs" using inj_on by (simp add: distinct_map)
lemma distinct_sorted_key_list_of_set [simp]: assumes"A ⊆ S" shows"distinct (map f (sorted_key_list_of_set f A))" proof (cases "finite A") case True thus ?thesis using‹A ⊆ S› inj_on by (induction A) (force simp: distinct_insort_key dest: inj_onD)+ next case False thus ?thesis by simp qed
lemma length_sorted_key_list_of_set [simp]: assumes"A ⊆ S" shows"length (sorted_key_list_of_set f A) = card A" proof (cases "finite A") case True with assms inj_on show ?thesis using distinct_card[symmetric, OF distinct_sorted_key_list_of_set] by (auto simp: inj_on_subset intro!: card_image) qed auto
lemma sorted_key_list_of_set_remove: assumes"insert x A ⊆ S"and"finite A" shows"sorted_key_list_of_set f (A - {x}) = remove1 x (sorted_key_list_of_set f A)" proof (cases "x ∈ A") case False with assms have"x ∉ set (sorted_key_list_of_set f A)"by simp with False show ?thesis by (simp add: remove1_idem) next case True thenobtain B where A: "A = insert x B"by (rule Set.set_insert) with assms show ?thesis by simp qed
lemma strict_sorted_key_list_of_set [simp]: "A ⊆ S ==> sorted_wrt (≺) (map f (sorted_key_list_of_set f A))" by (cases "finite A") (auto simp: strict_sorted_iff inj_on_subset[OF inj_on])
lemma finite_set_strict_sorted: assumes"A ⊆ S"and"finite A" obtains l where"sorted_wrt (≺) (map f l)""set l = A""length l = card A" using assms by (meson length_sorted_key_list_of_set set_sorted_key_list_of_set strict_sorted_key_list_of_set)
lemma (in linorder) strict_sorted_equal: assumes"sorted_wrt (<) xs" and"sorted_wrt (<) ys" and"set ys = set xs" shows"ys = xs" using assms proof (induction xs arbitrary: ys) case (Cons x xs) show ?case proof (cases ys) case Nil thenshow ?thesis using Cons.prems by auto next case (Cons y ys') thenhave"xs = ys'" by (metis Cons.prems list.inject sorted_distinct_set_unique strict_sorted_iff) moreoverhave"x = y" using Cons.prems ‹xs = ys'›local.Cons by fastforce ultimatelyshow ?thesis usinglocal.Cons by blast qed qed auto
lemma (in linorder) strict_sorted_equal_Uniq: "∃🪙≤🪙1xs. sorted_wrt (<) xs ∧ set xs = A" by (simp add: Uniq_def strict_sorted_equal)
lemma sorted_key_list_of_set_inject: assumes"A ⊆ S""B ⊆ S" assumes"sorted_key_list_of_set f A = sorted_key_list_of_set f B""finite A""finite B" shows"A = B" using assms set_sorted_key_list_of_set by metis
lemma sorted_key_list_of_set_unique: assumes"A ⊆ S"and"finite A" shows"sorted_wrt (≺) (map f l) ∧ set l = A ∧ length l = card A ⟷ sorted_key_list_of_set f A = l" using assms by (auto simp: strict_sorted_iff card_distinct idem_if_sorted_distinct)
text‹ We abuse the ‹rewrites›functionality of locales to remove trivial assumptions that result from instantiating the key function to the identity. ›
sublocale sorted_list_of_set: folding_insort_key "(≤)""(<)" UNIV "(λx. x)"
rewrites "sorted_key_list_of_set (λx. x) = sorted_list_of_set" and"∧xs. map (λx. x) xs ≡ xs" and"∧X. (X ⊆ UNIV) ≡ True" and"∧x. x ∈ UNIV ≡ True" and"∧P. (True ==> P) ≡ Trueprop P" and"∧P Q. (True ==> PROP P ==> PROP Q) ≡ (PROP P ==> True ==> PROP Q)" proof - show"folding_insort_key (≤) (<) UNIV (λx. x)" by standard simp qed (simp_all add: sorted_list_of_set_def)
lemma ex1_sorted_list_for_set_if_finite: "finite X ==>∃!xs. sorted_wrt (<) xs ∧ set xs = X" by (metis sorted_list_of_set.finite_set_strict_sorted strict_sorted_equal)
text‹Alias theorems for backwards compatibility and ease of use.› lemmas sorted_list_of_set = sorted_list_of_set.sorted_key_list_of_set and
sorted_list_of_set_empty = sorted_list_of_set.sorted_key_list_of_set_empty and
sorted_list_of_set_insert = sorted_list_of_set.sorted_key_list_of_set_insert and
sorted_list_of_set_insert_remove = sorted_list_of_set.sorted_key_list_of_set_insert_remove and
sorted_list_of_set_eq_Nil_iff = sorted_list_of_set.sorted_key_list_of_set_eq_Nil_iff and
set_sorted_list_of_set = sorted_list_of_set.set_sorted_key_list_of_set and
sorted_sorted_list_of_set = sorted_list_of_set.sorted_sorted_key_list_of_set and
distinct_sorted_list_of_set = sorted_list_of_set.distinct_sorted_key_list_of_set and
length_sorted_list_of_set = sorted_list_of_set.length_sorted_key_list_of_set and
sorted_list_of_set_remove = sorted_list_of_set.sorted_key_list_of_set_remove and
strict_sorted_list_of_set = sorted_list_of_set.strict_sorted_key_list_of_set and
sorted_list_of_set_inject = sorted_list_of_set.sorted_key_list_of_set_inject and
sorted_list_of_set_unique = sorted_list_of_set.sorted_key_list_of_set_unique and
finite_set_strict_sorted = sorted_list_of_set.finite_set_strict_sorted
lemma sorted_list_of_set_sort_remdups [code]: "sorted_list_of_set (set xs) = sort (remdups xs)" proof - interpret comp_fun_commute insort by (fact comp_fun_commute_insort) show ?thesis by (simp add: sorted_list_of_set.fold_insort_key.eq_fold sort_conv_fold fold_set_fold_remdups) qed
end
lemma sorted_list_of_set_range [simp]: "sorted_list_of_set {m.. by (rule sorted_distinct_set_unique) simp_all
lemma sorted_list_of_set_lessThan_Suc [simp]: "sorted_list_of_set {.. using le0 lessThan_atLeast0 sorted_list_of_set_range upt_Suc_append by presburger
lemma sorted_list_of_set_atMost_Suc [simp]: "sorted_list_of_set {..Suc k} = sorted_list_of_set {..k} @ [Suc k]" using lessThan_Suc_atMost sorted_list_of_set_lessThan_Suc by fastforce
lemma sorted_list_of_set_nonempty: assumes"finite A""A ≠ {}" shows"sorted_list_of_set A = Min A # sorted_list_of_set (A - {Min A})" using assms by (auto simp: less_le simp flip: sorted_list_of_set.sorted_key_list_of_set_unique intro: Min_in)
lemma sorted_list_of_set_greaterThanLessThan: assumes"Suc i < j" shows"sorted_list_of_set {i<.. proof - have"{i<.. using assms by auto thenshow ?thesis by (metis assms atLeastSucLessThan_greaterThanLessThan sorted_list_of_set_range upt_conv_Cons) qed
lemma sorted_list_of_set_greaterThanAtMost: assumes"Suc i ≤ j" shows"sorted_list_of_set {i<..j} = Suc i # sorted_list_of_set {Suc i<..j}" using sorted_list_of_set_greaterThanLessThan [of i "Suc j"] by (metis assms greaterThanAtMost_def greaterThanLessThan_eq le_imp_less_Suc lessThan_Suc_atMost)
lemma nth_sorted_list_of_set_greaterThanLessThan: "n < j - Suc i ==> sorted_list_of_set {i<.. by (induction n arbitrary: i) (auto simp: sorted_list_of_set_greaterThanLessThan)
lemma nth_sorted_list_of_set_greaterThanAtMost: "n < j - i ==> sorted_list_of_set {i<..j} ! n = Suc (i+n)" using nth_sorted_list_of_set_greaterThanLessThan [of n "Suc j" i] by (simp add: greaterThanAtMost_def greaterThanLessThan_eq lessThan_Suc_atMost)
lemma sorted_wrt_induct [consumes 1, case_names Nil Cons]: assumes"sorted_wrt R xs" assumes"P []" "∧x xs. (∧y. y ∈ set xs ==> R x y) ==> P xs ==> P (x # xs)" shows"P xs" using assms(1) by (induction xs) (auto intro: assms)
lemma sorted_wrt_trans_induct [consumes 2, case_names Nil single Cons]: assumes"sorted_wrt R xs""transp R" assumes"P []""∧x. P [x]" "∧x y xs. R x y ==> P (y # xs) ==> P (x # y # xs)" shows"P xs" using assms(1) by (induction xs rule: induct_list012)
(auto intro: assms simp: sorted_wrt2[OF assms(2)])
lemma sorted_wrt_map_mono: assumes"sorted_wrt R xs" assumes"∧x y. x ∈ set xs ==> y ∈ set xs ==> R x y ==> R' (f x) (f y)" shows"sorted_wrt R' (map f xs)" using assms by (induction rule: sorted_wrt_induct) auto
lemma sorted_map_mono: assumes"sorted xs"and"mono_on (set xs) f" shows"sorted (map f xs)" using assms(1) by (rule sorted_wrt_map_mono) (use assms in‹auto simp: mono_on_def›)
subsubsection ‹‹lists›: the list-forming operator over sets›
inductive_set
lists :: "'a set => 'a list set" for A :: "'a set" where
Nil [intro!, simp]: "[] ∈ lists A"
| Cons [intro!, simp]: "[a ∈ A; l ∈ lists A]==> a#l ∈ lists A"
inductive_simps listsp_simps[code]: "listsp A []" "listsp A (x # xs)"
lemma listsp_mono [mono]: "A ≤ B ==> listsp A ≤ listsp B" by (rule predicate1I, erule listsp.induct, blast+)
lemmas lists_mono = listsp_mono [to_set]
lemma listsp_infI: assumes l: "listsp A l"shows"listsp B l ==> listsp (inf A B) l"using l by induct blast+
lemmas lists_IntI = listsp_infI [to_set]
lemma listsp_inf_eq [simp]: "listsp (inf A B) = inf (listsp A) (listsp B)" proof (rule mono_inf [where f=listsp, THEN order_antisym]) show"mono listsp"by (simp add: mono_def listsp_mono) show"inf (listsp A) (listsp B) ≤ listsp (inf A B)"by (blast intro!: listsp_infI) qed
lemma in_listspD [dest!]: "listsp A xs ==>∀x∈set xs. A x" by (rule in_listsp_conv_set [THEN iffD1])
lemmas in_listsD [dest!] = in_listspD [to_set]
lemma in_listspI [intro!]: "∀x∈set xs. A x ==> listsp A xs" by (rule in_listsp_conv_set [THEN iffD2])
lemmas in_listsI [intro!] = in_listspI [to_set]
lemma mono_lists: "mono lists" unfolding mono_def by auto
lemma lists_eq_set: "lists A = {xs. set xs ≤ A}" by auto
lemma lists_empty [simp]: "lists {} = {[]}" by auto
lemma lists_UNIV [simp]: "lists UNIV = UNIV" by auto
lemma lists_image: "lists (f`A) = map f ` lists A" proof -
{ fix xs have"∀x∈set xs. x ∈ f ` A ==> xs ∈ map f ` lists A" by (induct xs) (auto simp del: list.map simp add: list.map[symmetric] intro!: imageI) } thenshow ?thesis by auto qed
lemma inj_on_map_lists: assumes"inj_on f A" shows"inj_on (map f) (lists A)" proof fix xs ys assume"xs ∈ lists A"and"ys ∈ lists A"and"map f xs = map f ys" have"x = y"if"x ∈ set xs"and"y ∈ set ys"and"f x = f y"for x y using in_listsD[OF ‹xs ∈ lists A›, rule_format, OF ‹x ∈ set xs›]
in_listsD[OF ‹ys ∈ lists A›, rule_format, OF ‹y ∈ set ys›] ‹inj_on f A›[unfolded inj_on_def, rule_format, OF _ _ ‹f x = f y›] by blast from list.inj_map_strong[OF this ‹map f xs = map f ys›] show"xs = ys". qed
lemma bij_lists: "bij_betw f X Y ==> bij_betw (map f) (lists X) (lists Y)" unfolding bij_betw_def using inj_on_map_lists lists_image by metis
lemma replicate_in_lists: "a ∈ A ==> replicate k a ∈ lists A" by (induction k) auto
subsubsection ‹Inductive definition for membership›
inductive ListMem :: "'a ==> 'a list ==> bool" where
elem: "ListMem x (x # xs)"
| insert: "ListMem x xs ==> ListMem x (y # xs)"
lemma ListMem_iff: "(ListMem x xs) = (x ∈ set xs)" proof show"ListMem x xs ==> x ∈ set xs" by (induct set: ListMem) auto show"x ∈ set xs ==> ListMem x xs" by (induct xs) (auto intro: ListMem.intros) qed
subsubsection ‹Lists as Cartesian products›
text‹‹set_Cons A Xs›: the set of lists with head drawn from 🍋‹A›and tail drawn from 🍋‹Xs›.›
definition set_Cons :: "'a set ==> 'a list set ==> 'a list set"where "set_Cons A XS = {z. ∃x xs. z = x # xs ∧ x ∈ A ∧ xs ∈ XS}"
lemma set_Cons_sing_Nil [simp]: "set_Cons A {[]} = (%x. [x])`A" by (auto simp add: set_Cons_def)
text‹Yields the set of lists, all of the same length as the argument and with elements drawn from the corresponding element of the argument.›
primrec listset :: "'a set list ==> 'a list set"where "listset [] = {[]}" | "listset (A # As) = set_Cons A (listset As)"
subsubsection ‹Transitive Closure on Lists›
text‹Use ‹🪙+›on binary relations if possible. Transitive closure on lists is useful for executable definitions on the list level. Is not efficient, naive closure computation.›
lemma set_trans_list_step_subset_trancl: "set (trans_list_step ps) ⊆ (set ps)^+" unfolding trans_list_step_def by auto
function trancl_list :: "('a * 'a) list ==> ('a * 'a) list"where "trancl_list ps = (let ps' = trans_list_step ps in if set ps' ⊆ set ps then ps else trancl_list (List.union ps' ps))" by pat_completeness auto
fix ps ps' :: "('a * 'a) list" assume asms: "ps' = trans_list_step ps""¬ set ps' ⊆ set ps" let ?P = "set ps"let ?P' = "set(trans_list_step ps)" have"(?P' ∪ ?P)🪙+ - (?P' ∪ ?P) = ?P🪙+ - (?P' ∪ ?P)" using trancl_absorb_subset_trancl[OF set_trans_list_step_subset_trancl] by (metis Un_commute) alsohave"?P🪙+ - (?P' ∪ ?P) < ?P🪙+ - ?P" using asms(1,2) set_trans_list_step_subset_trancl by fastforce finallyhave"card((?P' ∪ ?P)🪙+ - (?P' ∪ ?P)) < card (?P🪙+ - ?P)" by (meson List.finite_set finite_Diff finite_trancl psubset_card_mono) with asms show"(List.union ps' ps, ps) ∈ measure ?r"by(simp) qed
declare trancl_list.simps[code, simp del]
lemma set_trancl_list: "set(trancl_list ps) = (set ps)^+" proof (induction ps rule: trancl_list.induct) case (1 ps) let ?P = "set ps"let ?P' = "set(trans_list_step ps)" show ?case proof (cases "?P' ⊆ ?P") case True thenhave"(a,b) ∈ set ps ==> (b,c) ∈ set ps ==> (a,c) ∈ set ps"for a b c unfolding trans_list_step_def by fastforce thenshow ?thesis using True trancl_id[OF transI, of ?P] using [[simp_depth_limit=3]] by(simp add: Let_def trancl_list.simps[of ps]) next case False from 1[OF refl False] False show ?thesis using trancl_absorb_subset_trancl[OF set_trans_list_step_subset_trancl] by(auto simp add: Un_commute Let_def trancl_list.simps[of ps]) qed qed
subsection‹Relations on Lists›
subsubsection ‹Length Lexicographic Ordering›
text‹These orderings preserve well-foundedness: shorter lists precede longer lists. These ordering are not used in dictionaries.›
primrec🍋‹The lexicographic ordering for lists of the specified length›
lexn :: "('a × 'a) set ==> nat ==> ('a list × 'a list) set"where "lexn r 0 = {}" | "lexn r (Suc n) = (map_prod (%(x, xs). x#xs) (%(x, xs). x#xs) ` (r <*lex*> lexn r n)) Int {(xs, ys). length xs = Suc n ∧ length ys = Suc n}"
definition lex :: "('a × 'a) set ==> ('a list × 'a list) set"where "lex r = (∪n. lexn r n)"🍋‹Holds only between lists of the same length›
definition lenlex :: "('a × 'a) set => ('a list × 'a list) set"where "lenlex r = inv_image (less_than <*lex*> lex r) (λxs. (length xs, xs))" 🍋‹Compares lists by their length and then lexicographically›
lemma wf_lexn: assumes"wf r"shows"wf (lexn r n)" proof (induct n) case (Suc n) have inj: "inj (λ(x, xs). x # xs)" using assms by (auto simp: inj_on_def) have wf: "wf (map_prod (λ(x, xs). x # xs) (λ(x, xs). x # xs) ` (r <*lex*> lexn r n))" by (simp add: Suc.hyps assms wf_lex_prod wf_map_prod_image [OF _ inj]) thenshow ?case by (rule wf_subset) auto qed auto
lemma lexn_length: "(xs, ys) ∈ lexn r n ==> length xs = n ∧ length ys = n" by (induct n arbitrary: xs ys) auto
lemma wf_lex [intro!]: assumes"wf r"shows"wf (lex r)" unfolding lex_def proof (rule wf_UN) show"wf (lexn r i)"for i by (simp add: assms wf_lexn) show"∧i j. lexn r i ≠ lexn r j ==> Domain (lexn r i) ∩ Range (lexn r j) = {}" by (metis DomainE Int_emptyI RangeE lexn_length) qed
lemma lexn_conv: "lexn r n = {(xs,ys). length xs = n ∧ length ys = n ∧ (∃xys x y xs' ys'. xs = xys @ x#xs' ∧ ys = xys @ y # ys' ∧ (x, y) ∈ r)}"
(is"?L n = ?R n"is"_ = {(xs,ys). ?len n xs ∧ ?len n ys ∧ (∃xys. ?P xs ys xys)}") proof (induction n) case (Suc n) (* A compact proof referring to a system-generated name: then show ?case apply (auto simp add: image_Collect lex_prod_def) apply blast apply (meson Cons_eq_appendI) apply (case_tac xys; fastforce) done *) have"(xs,ys) ∈ ?L (Suc n)"if r: "(xs,ys) ∈ ?R (Suc n)"for xs ys proof - from r obtain xys where r': "?len (Suc n) xs""?len (Suc n) ys""?P xs ys xys"by auto thenshow ?thesis using r' Suc by (cases xys; fastforce simp: image_Collect lex_prod_def) qed moreoverhave"(xs,ys) ∈ ?L (Suc n) ==> (xs,ys) ∈ ?R (Suc n)"for xs ys using Suc by (auto simp add: image_Collect lex_prod_def)(blast, meson Cons_eq_appendI) ultimatelyshow ?caseby (meson pred_equals_eq2) qed auto
text‹By Mathias Fleury:›
proposition lexn_transI: assumes"trans r"shows"trans (lexn r n)" unfolding trans_def proof (intro allI impI) fix as bs cs assume asbs: "(as, bs) ∈ lexn r n"and bscs: "(bs, cs) ∈ lexn r n" obtain abs a b as' bs' where
n: "length as = n"and"length bs = n"and
as: "as = abs @ a # as'"and
bs: "bs = abs @ b # bs'"and
abr: "(a, b) ∈ r" using asbs unfolding lexn_conv by blast obtain bcs b' c' cs' bs' where
n': "length cs = n"and"length bs = n"and
bs': "bs = bcs @ b' # bs'"and
cs: "cs = bcs @ c' # cs'"and
b'c'r: "(b', c') ∈ r" using bscs unfolding lexn_conv by blast
consider (le) "length bcs < length abs"
| (eq) "length bcs = length abs"
| (ge) "length bcs > length abs"by linarith thus"(as, cs) ∈ lexn r n" proof cases let ?k = "length bcs" case le hence"as ! ?k = bs ! ?k"unfolding as bs by (simp add: nth_append) hence"(as ! ?k, cs ! ?k) ∈ r"using b'c'r unfolding bs' cs by auto moreover have"length bcs < length as"using le unfolding as by simp from id_take_nth_drop[OF this] have"as = take ?k as @ as ! ?k # drop (Suc ?k) as" . moreover have"length bcs < length cs"unfolding cs by simp from id_take_nth_drop[OF this] have"cs = take ?k cs @ cs ! ?k # drop (Suc ?k) cs" . moreoverhave"take ?k as = take ?k cs" using le arg_cong[OF bs, of "take (length bcs)"] unfolding cs as bs' by auto ultimatelyshow ?thesis using n n' unfolding lexn_conv by auto next let ?k = "length abs" case ge hence"bs ! ?k = cs ! ?k"unfolding bs' cs by (simp add: nth_append) hence"(as ! ?k, cs ! ?k) ∈ r"using abr unfolding as bs by auto moreover have"length abs < length as"using ge unfolding as by simp from id_take_nth_drop[OF this] have"as = take ?k as @ as ! ?k # drop (Suc ?k) as" . moreoverhave"length abs < length cs"using n n' unfolding as by simp from id_take_nth_drop[OF this] have"cs = take ?k cs @ cs ! ?k # drop (Suc ?k) cs" . moreoverhave"take ?k as = take ?k cs" using ge arg_cong[OF bs', of "take (length abs)"] unfolding cs as bs by auto ultimatelyshow ?thesis using n n' unfolding lexn_conv by auto next let ?k = "length abs" case eq hence *: "abs = bcs""b = b'"using bs bs' by auto hence"(a, c') ∈ r" using abr b'c'r assms unfolding trans_def by blast with * show ?thesis using n n' unfolding lexn_conv as bs cs by auto qed qed
corollary lex_transI: assumes"trans r"shows"trans (lex r)" using lexn_transI [OF assms] by (clarsimp simp add: lex_def trans_def) (metis lexn_length)
lemma lex_conv: "lex r = {(xs,ys). length xs = length ys ∧ (∃xys x y xs' ys'. xs = xys @ x # xs' ∧ ys = xys @ y # ys' ∧ (x, y) ∈ r)}" by (force simp add: lex_def lexn_conv)
lemma wf_lenlex [intro!]: "wf r ==> wf (lenlex r)" by (unfold lenlex_def) blast
lemma lex_take_index: assumes"(xs, ys) ∈ lex r" obtains i where"i < length xs"and"i < length ys"and"take i xs = take i ys" and"(xs ! i, ys ! i) ∈ r" proof - obtain n us x xs' y ys' where"(xs, ys) ∈ lexn r n"and"length xs = n"and"length ys = n" and"xs = us @ x # xs'"and"ys = us @ y # ys'"and"(x, y) ∈ r" using assms by (fastforce simp: lex_def lexn_conv) thenshow ?thesis by (intro that [of "length us"]) auto qed
lemma irrefl_lex: "irrefl r ==> irrefl (lex r)" by (meson irrefl_def lex_take_index)
lemma lexl_not_refl [simp]: "irrefl r ==> (x,x) ∉ lex r" by (meson irrefl_def lex_take_index)
subsubsection ‹Lexicographic Ordering›
text‹Classical lexicographic ordering on lists, ie. "a" 🚫ab" 🚫b". This ordering does \emph{not} preserve well-foundedness. Author: N. Voelker, March 2005.›
definition lexord :: "('a × 'a) set ==> ('a list × 'a list) set"where "lexord r = {(x,y). ∃ a v. y = x @ a # v ∨ (∃ u a b v w. (a,b) ∈ r ∧ x = u @ (a # v) ∧ y = u @ (b # w))}"
lemma lexord_Nil_left[simp]: "([],y) ∈ lexord r = (∃ a x. y = a # x)" by (unfold lexord_def, induct_tac y, auto)
lemma lexord_same_pref_iff: "(xs @ ys, xs @ zs) ∈ lexord r ⟷ (∃x ∈ set xs. (x,x) ∈ r) ∨ (ys, zs) ∈ lexord r" by(induction xs) auto
lemma lexord_same_pref_if_irrefl[simp]: "irrefl r ==> (xs @ ys, xs @ zs) ∈ lexord r ⟷ (ys, zs) ∈ lexord r" by (simp add: irrefl_def lexord_same_pref_iff)
lemma lexord_append_rightI: "∃ b z. y = b # z ==> (x, x @ y) ∈ lexord r" by (metis append_Nil2 lexord_Nil_left lexord_same_pref_iff)
lemma lexord_append_left_rightI: "(a,b) ∈ r ==> (u @ a # x, u @ b # y) ∈ lexord r" by (simp add: lexord_same_pref_iff)
lemma lexord_append_leftI: "(u,v) ∈ lexord r ==> (x @ u, x @ v) ∈ lexord r" by (simp add: lexord_same_pref_iff)
lemma lexord_append_leftD: "[(x @ u, x @ v) ∈ lexord r; (∀a. (a,a) ∉ r) ]==> (u,v) ∈ lexord r" by (simp add: lexord_same_pref_iff)
lemma lexord_take_index_conv: "((x,y) ∈ lexord r) = ((length x < length y ∧ take (length x) y = x) ∨ (∃i. i < min(length x)(length y) ∧ take i x = take i y ∧ (x!i,y!i) ∈ r))" proof - have"(∃a v. y = x @ a # v) = (length x < length y ∧ take (length x) y = x)" by (metis Cons_nth_drop_Suc append_eq_conv_conj drop_all list.simps(3) not_le) moreover have"(∃u a b. (a, b) ∈ r ∧ (∃v. x = u @ a # v) ∧ (∃w. y = u @ b # w)) = (∃i∧ take i x = take i y ∧ (x ! i, y ! i) ∈ r)"
(is"?L=?R") proof show"?L==>?R" by (metis append_eq_conv_conj drop_all leI list.simps(3) nth_append_length) show"?R==>?L" by (metis id_take_nth_drop) qed ultimatelyshow ?thesis by (auto simp: lexord_def Let_def) qed
🍋‹lexord is extension of partial ordering List.lex› lemma lexord_lex: "(x,y) ∈ lex r = ((x,y) ∈ lexord r ∧ length x = length y)" proof (induction x arbitrary: y) case (Cons a x y) thenshow ?case by (cases y) (force+) qed auto
lemma lexord_sufI: assumes"(u,w) ∈ lexord r""length w ≤ length u" shows"(u@v,w@z) ∈ lexord r"
proof- from leD[OF assms(2)] assms(1)[unfolded lexord_take_index_conv[of u w r] min_absorb2[OF assms(2)]] obtain i where"take i u = take i w"and"(u!i,w!i) ∈ r"and"i < length w" by blast hence"((u@v)!i, (w@z)!i) ∈ r" unfolding nth_append using less_le_trans[OF ‹i 🚫 w› assms(2)] ‹(u!i,w!i) ∈ r› by presburger moreoverhave"i < min (length (u@v)) (length (w@z))" using assms(2) ‹i 🚫 w›by simp moreoverhave"take i (u@v) = take i (w@z)" using assms(2) ‹i 🚫 w›‹take i u = take i w›by simp ultimatelyshow ?thesis using lexord_take_index_conv by blast qed
lemma lexord_sufE: assumes"(xs@zs,ys@qs) ∈ lexord r""xs ≠ ys""length xs = length ys""length zs = length qs" shows"(xs,ys) ∈ lexord r"
proof- obtain i where"i < length (xs@zs)"and"i < length (ys@qs)"and"take i (xs@zs) = take i (ys@qs)" and"((xs@zs) ! i, (ys@qs) ! i) ∈ r" using assms(1) lex_take_index[unfolded lexord_lex,of "xs @ zs""ys @ qs" r]
length_append[of xs zs, unfolded assms(3,4), folded length_append[of ys qs]] by blast have"length (take i xs) = length (take i ys)" by (simp add: assms(3)) have"i < length xs" using assms(2,3) le_less_linear take_all[of xs i] take_all[of ys i] ‹take i (xs @ zs) = take i (ys @ qs)› append_eq_append_conv take_append by metis hence"(xs ! i, ys ! i) ∈ r" using‹((xs @ zs) ! i, (ys @ qs) ! i) ∈ r› assms(3) by (simp add: nth_append) moreoverhave"take i xs = take i ys" using assms(3) ‹take i (xs @ zs) = take i (ys @ qs)›by auto ultimatelyshow ?thesis unfolding lexord_take_index_conv using‹i 🚫 xs› assms(3) by fastforce qed
lemma lexord_irreflexive: "∀x. (x,x) ∉ r ==> (xs,xs) ∉ lexord r" by (induct xs) auto
text‹By Ren\'e Thiemann:› lemma lexord_partial_trans: "(∧x y z. x ∈ set xs ==> (x,y) ∈ r ==> (y,z) ∈ r ==> (x,z) ∈ r) ==> (xs,ys) ∈ lexord r ==> (ys,zs) ∈ lexord r ==> (xs,zs) ∈ lexord r" proof (induct xs arbitrary: ys zs) case Nil from Nil(3) show ?caseunfolding lexord_def by (cases zs, auto) next case (Cons x xs yys zzs) from Cons(3) obtain y ys where yys: "yys = y # ys"unfolding lexord_def by (cases yys, auto) note Cons = Cons[unfolded yys] from Cons(3) have one: "(x,y) ∈ r ∨ x = y ∧ (xs,ys) ∈ lexord r"by auto from Cons(4) obtain z zs where zzs: "zzs = z # zs"unfolding lexord_def by (cases zzs, auto) note Cons = Cons[unfolded zzs] from Cons(4) have two: "(y,z) ∈ r ∨ y = z ∧ (ys,zs) ∈ lexord r"by auto
{ assume"(xs,ys) ∈ lexord r"and"(ys,zs) ∈ lexord r" from Cons(1)[OF _ this] Cons(2) have"(xs,zs) ∈ lexord r"by auto
} note ind1 = this
{ assume"(x,y) ∈ r"and"(y,z) ∈ r" from Cons(2)[OF _ this] have"(x,z) ∈ r"by auto
} note ind2 = this from one two ind1 ind2 have"(x,z) ∈ r ∨ x = z ∧ (xs,zs) ∈ lexord r"by blast thus ?caseunfolding zzs by auto qed
lemma lexord_transI: "trans r ==> trans (lexord r)" by (meson lexord_trans transI)
lemma total_lexord: "total r ==> total (lexord r)" unfolding total_on_def proof clarsimp fix x y assume"∀x y. x ≠ y ⟶ (x, y) ∈ r ∨ (y, x) ∈ r" and"(x::'a list) ≠ y" and"(y, x) ∉ lexord r" then show"(x, y) ∈ lexord r" proof (induction x arbitrary: y) case Nil thenshow ?case by (metis lexord_Nil_left list.exhaust) next case (Cons a x y) thenshow ?case by (cases y) (force+) qed qed
corollary lexord_linear: "(∀a b. (a,b) ∈ r ∨ a = b ∨ (b,a) ∈ r) ==> (x,y) ∈ lexord r ∨ x = y ∨ (y,x) ∈ lexord r" using total_lexord by (metis UNIV_I total_on_def)
lemma lexord_irrefl: "irrefl R ==> irrefl (lexord R)" by (simp add: irrefl_def lexord_irreflexive)
lemma lexord_asym: assumes"asym R" shows"asym (lexord R)" proof fix xs ys assume"(xs, ys) ∈ lexord R" thenshow"(ys, xs) ∉ lexord R" proof (induct xs arbitrary: ys) case Nil thenshow ?caseby simp next case (Cons x xs) thenobtain z zs where ys: "ys = z # zs"by (cases ys) auto with assms Cons show ?caseby (auto dest: asymD) qed qed
lemma lexord_asymmetric: assumes"asym R" assumes hyp: "(a, b) ∈ lexord R" shows"(b, a) ∉ lexord R" proof - from‹asym R›have"asym (lexord R)"by (rule lexord_asym) thenshow ?thesis by (auto simp: hyp dest: asymD) qed
lemma asym_lex: "asym R ==> asym (lex R)" by (meson asymI asymD irrefl_lex lexord_asym lexord_lex)
lemma asym_lenlex: "asym R ==> asym (lenlex R)" by (simp add: lenlex_def asym_inv_image asym_less_than asym_lex)
lemma lenlex_append1: assumes len: "(us,xs) ∈ lenlex R"and eq: "length vs = length ys" shows"(us @ vs, xs @ ys) ∈ lenlex R" using len proof (induction us) case Nil thenshow ?case by (simp add: lenlex_def eq) next case (Cons u us) with lex_append_rightI show ?case by (fastforce simp add: lenlex_def eq) qed
lemma lenlex_append2 [simp]: assumes"irrefl R" shows"(us @ xs, us @ ys) ∈ lenlex R ⟷ (xs, ys) ∈ lenlex R" proof (induction us) case Nil thenshow ?case by (simp add: lenlex_def) next case (Cons u us) with assms show ?case by (auto simp: lenlex_def irrefl_def) qed
text‹ Predicate version of lexicographic order integrated with Isabelle's order type classes. Author: Andreas Lochbihler ›
context ord begin
context notes [[inductive_internals]] begin
inductive lexordp :: "'a list ==> 'a list ==> bool" where
Nil: "lexordp [] (y # ys)"
| Cons: "x < y ==> lexordp (x # xs) (y # ys)"
| Cons_eq: "[¬ x < y; ¬ y < x; lexordp xs ys ]==> lexordp (x # xs) (y # ys)"
subsubsection ‹Lexicographic combination of measure functions›
text‹These are useful for termination proofs›
definition"measures fs = inv_image (lex less_than) (%a. map (%f. f a) fs)"
lemma wf_measures[simp]: "wf (measures fs)" unfolding measures_def by blast
lemma in_measures[simp]: "(x, y) ∈ measures [] = False" "(x, y) ∈ measures (f # fs) = (f x < f y ∨ (f x = f y ∧ (x, y) ∈ measures fs))" unfolding measures_def by auto
lemma measures_less: "f x < f y ==> (x, y) ∈ measures (f#fs)" by simp
lemma measures_lesseq: "f x ≤ f y ==> (x, y) ∈ measures fs ==> (x, y) ∈ measures (f#fs)" by auto
subsubsection ‹Lifting Relations to Lists: one element›
definition listrel1 :: "('a × 'a) set ==> ('a list × 'a list) set"where "listrel1 r = {(xs,ys). ∃us z z' vs. xs = us @ z # vs ∧ (z,z') ∈ r ∧ ys = us @ z' # vs}"
lemma listrel1I: "[ (x, y) ∈ r; xs = us @ x # vs; ys = us @ y # vs ]==> (xs, ys) ∈ listrel1 r" unfolding listrel1_def by auto
lemma listrel1E: "[ (xs, ys) ∈ listrel1 r; !!x y us vs. [ (x, y) ∈ r; xs = us @ x # vs; ys = us @ y # vs ]==> P ]==> P" unfolding listrel1_def by auto
lemma listrel1_iff_update: "(xs,ys) ∈ (listrel1 r) ⟷ (∃y n. (xs ! n, y) ∈ r ∧ n < length xs ∧ ys = xs[n:=y])" (is"?L ⟷ ?R") proof assume"?L" thenobtain x y u v where"xs = u @ x # v""ys = u @ y # v""(x,y) ∈ r" unfolding listrel1_def by auto thenhave"ys = xs[length u := y]"and"length u < length xs" and"(xs ! length u, y) ∈ r"by auto thenshow"?R"by auto next assume"?R" thenobtain x y n where"(xs!n, y) ∈ r""n < size xs""ys = xs[n:=y]""x = xs!n" by auto thenobtain u v where"xs = u @ x # v"and"ys = u @ y # v"and"(x, y) ∈ r" by (auto intro: upd_conv_take_nth_drop id_take_nth_drop) thenshow"?L"by (auto simp: listrel1_def) qed
text‹Accessible part and wellfoundedness:›
lemma Cons_acc_listrel1I [intro!]: "x ∈ Wellfounded.acc r ==> xs ∈ Wellfounded.acc (listrel1 r) ==> (x # xs) ∈ Wellfounded.acc (listrel1 r)" proof (induction arbitrary: xs set: Wellfounded.acc) case outer: (1 u) show ?case proof (induct xs rule: acc_induct) case 1 show"xs ∈ Wellfounded.acc (listrel1 r)" by (simp add: outer.prems) qed (metis (no_types, lifting) Cons_listrel1E2 acc.simps outer.IH) qed
lemma lists_accD: "xs ∈ lists (Wellfounded.acc r) ==> xs ∈ Wellfounded.acc (listrel1 r)" proof (induct set: lists) case Nil thenshow ?case by (meson acc.intros not_listrel1_Nil) next case (Cons a l) thenshow ?case by blast qed
lemma lists_accI: "xs ∈ Wellfounded.acc (listrel1 r) ==> xs ∈ lists (Wellfounded.acc r)" proof (induction set: Wellfounded.acc) case (1 x) thenhave"∧u v. [u ∈ set x; (v, u) ∈ r]==> v ∈ Wellfounded.acc r" by (metis in_lists_conv_set in_set_conv_decomp listrel1I) thenshow ?case by (meson acc.intros in_listsI) qed
lemma wf_listrel1_iff[simp]: "wf(listrel1 r) = wf r" by (auto simp: wf_iff_acc
intro: lists_accD lists_accI[THEN Cons_in_lists_iff[THEN iffD1, THEN conjunct1]])
subsubsection ‹Lifting Relations to Lists: all elements›
inductive_set
listrel :: "('a × 'b) set ==> ('a list × 'b list) set" for r :: "('a × 'b) set" where
Nil: "([],[]) ∈ listrel r"
| Cons: "[(x,y) ∈ r; (xs,ys) ∈ listrel r]==> (x#xs, y#ys) ∈ listrel r"
lemma listrel_mono: "r ⊆ s ==> listrel r ⊆ listrel s" by (meson listrel_iff_nth subrelI subset_eq)
lemma listrel_subset: assumes"r ⊆ A × A"shows"listrel r ⊆ lists A × lists A" proof clarify show"a ∈ lists A ∧ b ∈ lists A"if"(a, b) ∈ listrel r"for a b using that assms by (induction rule: listrel.induct, auto) qed
lemma listrel_refl_on: assumes"refl_on A r"shows"refl_on (lists A) (listrel r)" proof - have"l ∈ lists A ==> (l, l) ∈ listrel r"for l using assms unfolding refl_on_def by (induction l, auto intro: listrel.intros) thenshow ?thesis by (meson assms listrel_subset refl_on_def) qed
lemma listrel_sym: "sym r ==> sym (listrel r)" by (simp add: listrel_iff_nth sym_def)
lemma listrel_trans: assumes"trans r"shows"trans (listrel r)" proof - have"(x, z) ∈ listrel r"if"(x, y) ∈ listrel r""(y, z) ∈ listrel r"for x y z using that proofinduction case (Cons x y xs ys) thenshow ?case by clarsimp (metis assms listrel.Cons listrel_iff_nth transD) qed auto thenshow ?thesis using transI by blast qed
theorem equiv_listrel: "equiv A r ==> equiv (lists A) (listrel r)" by (simp add: equiv_def listrel_subset listrel_refl_on listrel_sym listrel_trans)
lemma listrel_rtrancl_refl[iff]: "(xs,xs) ∈ listrel(r🪙*)" using listrel_refl_on[of UNIV, OF refl_rtrancl] by(auto simp: refl_on_def)
lemma listrel_Nil [simp]: "listrel r `` {[]} = {[]}" by (blast intro: listrel.intros)
lemma listrel_Cons: "listrel r `` {x#xs} = set_Cons (r``{x}) (listrel r `` {xs})" by (auto simp add: set_Cons_def intro: listrel.intros)
text‹Relating 🍋‹listrel1›,🍋‹listrel› and closures:›
lemma listrel1_rtrancl_subset_rtrancl_listrel1: "listrel1 (r🪙*) ⊆ (listrel1 r)🪙*" proof (rule subrelI) fix xs ys assume 1: "(xs,ys) ∈ listrel1 (r🪙*)"
{ fix x y us vs have"(x,y) ∈ r🪙* ==> (us @ x # vs, us @ y # vs) ∈ (listrel1 r)🪙*" proof(induct rule: rtrancl.induct) case rtrancl_refl show ?caseby simp next case rtrancl_into_rtrancl thus ?case by (metis listrel1I rtrancl.rtrancl_into_rtrancl) qed } thus"(xs,ys) ∈ (listrel1 r)🪙*"using 1 by(blast elim: listrel1E) qed
lemma rtrancl_listrel1_eq_len: "(x,y) ∈ (listrel1 r)🪙* ==> length x = length y" by (induct rule: rtrancl.induct) (auto intro: listrel1_eq_len)
lemma rtrancl_listrel1_ConsI1: "(xs,ys) ∈ (listrel1 r)🪙* ==> (x#xs,x#ys) ∈ (listrel1 r)🪙*" proof (induction rule: rtrancl.induct) case (rtrancl_into_rtrancl a b c) thenshow ?case by (metis listrel1I2 rtrancl.rtrancl_into_rtrancl) qed auto
lemma listrel_subset_rtrancl_listrel1: "listrel r ⊆ (listrel1 r)🪙*" by(fast intro:rtrancl_listrel1_if_listrel)
subsection‹Size function›
lemma [measure_function]: "is_measure f ==> is_measure (size_list f)" by (rule is_measure_trivial)
lemma [measure_function]: "is_measure f ==> is_measure (size_option f)" by (rule is_measure_trivial)
lemma size_list_estimation[termination_simp]: "x ∈ set xs ==> y < f x ==> y < size_list f xs" by (induct xs) auto
lemma size_list_estimation'[termination_simp]: "x ∈ set xs ==> y ≤ f x ==> y ≤ size_list f xs" by (induct xs) auto
lemma size_list_map[simp]: "size_list f (map g xs) = size_list (f ∘ g) xs" by (induct xs) auto
lemma size_list_append[simp]: "size_list f (xs @ ys) = size_list f xs + size_list f ys" by (induct xs, auto)
lemma size_list_pointwise[termination_simp]: "(∧x. x ∈ set xs ==> f x ≤ g x) ==> size_list f xs ≤ size_list g xs" by (induct xs) force+
subsection‹Monad operation›
definition bind :: "'a list ==> ('a ==> 'b list) ==> 'b list"where "bind xs f = concat (map f xs)"
hide_const (open) bind
lemma bind_simps [simp]: "List.bind [] f = []" "List.bind (x # xs) f = f x @ List.bind xs f" by (simp_all add: bind_def)
lemma list_bind_cong [fundef_cong]: assumes"xs = ys""(∧x. x ∈ set xs ==> f x = g x)" shows"List.bind xs f = List.bind ys g" proof - from assms(2) have"List.bind xs f = List.bind xs g" by (induction xs) simp_all with assms(1) show ?thesis by simp qed
lemma set_list_bind: "set (List.bind xs f) = (∪x∈set xs. set (f x))" by (induction xs) simp_all
subsection‹Code generation›
subsubsection ‹Counterparts for set-related operations›
context begin
qualified definition member :: ‹'a list ==> 'a ==> bool›🍋‹only for code generation› where member_iff [code_abbrev, simp]: ‹member xs x ⟷ x ∈ set xs›
text‹ Use ‹member›only for generating executable code. Otherwise use 🍋‹x ∈ set xs›instead --- it is much easier to reason about. ›
qualified lemma member_code [code, no_atp]: ‹member [] y ⟷ False› ‹member (x # xs) y ⟷ x = y ∨ member xs y› by auto
qualified lemma Collect_member [code_unfold, no_atp]: 🍋‹make preprocessor setup confluent› ‹{x. List.member xs x ∧ P x} = Set.filter P (set xs)› by simp
qualified lemma Collect_pair_member [code_unfold, no_atp]: 🍋‹make preprocessor setup confluent› ‹{(x, y). List.member xs (x, y) ∧ P x y} = Set.filter (λ(x, y). P x y) (set xs)› by auto
qualified lemma Collect_triple_member [code_unfold, no_atp]: 🍋‹make preprocessor setup confluent› ‹{(x, y, z). List.member xs (x, y, z) ∧ P x y z} = Set.filter (λ(x, y, z). P x y z) (set xs)› by auto
end
lemma list_all_iff [code_abbrev]: ‹list_all P xs ⟷ Ball (set xs) P› by (simp add: list.pred_set)
definition list_ex :: ‹('a ==> bool) ==> 'a list ==> bool› where list_ex_iff [code_abbrev]: ‹list_ex P xs ⟷ Bex (set xs) P›
definition list_ex1 :: ‹('a ==> bool) ==> 'a list ==> bool› where list_ex1_iff [code_abbrev]: ‹list_ex1 P xs ⟷ Set.can_select P (set xs)›
text‹ Usually you should prefer ‹∀x∈set xs›,‹∃x∈set xs› and ‹∃!x. x∈set xs ∧ _›over 🍋‹list_all›, 🍋‹list_ex› and 🍋‹list_ex1›in specifications. ›
lemma list_all_Nil_iff [code, no_atp]: ‹list_all P [] ⟷ True› by (simp add: list_all_iff)
lemma list_all_Cons_iff [code, no_atp]: ‹list_all P (x # xs) ⟷ P x ∧ list_all P xs› by (simp add: list_all_iff)
lemma list_ex_Nil_iff [simp, code, no_atp]: ‹list_ex P [] ⟷ False› by (simp add: list_ex_iff)
lemma list_ex_Cons_iff [simp, code, no_atp]: ‹list_ex P (x # xs) ⟷ P x ∨ list_ex P xs› by (simp add: list_ex_iff)
lemma list_ex1_Nil_iff [simp, code, no_atp]: ‹list_ex1 P [] ⟷ False› by (auto simp add: list_ex1_iff)
lemma list_ex1_Cons_iff [simp, code, no_atp]: ‹list_ex1 P (x # xs) ⟷ (if P x then list_all (λy. ¬ P y ∨ x = y) xs else list_ex1 P xs)› by (auto simp add: list_ex1_iff list_all_iff)
lemma list_all_append [simp]: ‹list_all P (xs @ ys) ⟷ list_all P xs ∧ list_all P ys› by (auto simp add: list_all_iff)
lemma list_ex_append [simp]: ‹list_ex P (xs @ ys) ⟷ list_ex P xs ∨ list_ex P ys› by (auto simp add: list_ex_iff)
lemma list_all_rev [simp]: ‹list_all P (rev xs) ⟷ list_all P xs› by (simp add: list_all_iff)
lemma list_ex_rev [simp]: ‹list_ex P (rev xs) ⟷ list_ex P xs› by (simp add: list_ex_iff)
lemma list_all_length: ‹list_all P xs ⟷ (∀n 🚫 xs. P (xs ! n))› by (auto simp add: list_all_iff set_conv_nth)
lemma list_ex_length: ‹list_ex P xs ⟷ (∃n 🚫 xs. P (xs ! n))› by (auto simp add: list_ex_iff set_conv_nth)
lemma list_all_cong [fundef_cong]: ‹list_all f xs = list_all g ys› if‹xs = ys›‹(∧x. x ∈ set ys ==> f x = g x)› using that by (rule list.pred_cong)
lemma list_ex_cong [fundef_cong]: ‹list_ex f xs = list_ex g ys› if‹xs = ys›‹(∧x. x ∈ set ys ==> f x = g x)› using that by (simp add: list_ex_iff)
context begin
qualified definition superset :: ‹'a list ==> 'a list ==> bool› where superset_iff [code_abbrev, simp]: ‹superset ys xs ⟷ set xs ⊆ set ys›
lemma [code, no_atp]: ‹superset xs = list_all (λx. x ∈ set xs)› by (auto simp: fun_eq_iff list_all_iff)
end
text‹Executable checks for relations on sets›
definition listrel1p :: ‹('a ==> 'a ==> bool) ==> 'a list ==> 'a list ==> bool›🍋‹only for code generation› where‹listrel1p r xs ys ⟷ (xs, ys) ∈ listrel1 {(x, y). r x y}›
lemma [code_unfold]: ‹(xs, ys) ∈ listrel1 r ⟷ listrel1p (λx y. (x, y) ∈ r) xs ys› by (simp add: listrel1p_def)
lemma [code]: ‹listrel1p r [] xs ⟷ False› ‹listrel1p r xs [] ⟷ False› ‹listrel1p r (x # xs) (y # ys) ⟷ r x y ∧ xs = ys ∨ x = y ∧ listrel1p r xs ys› by (simp_all add: listrel1p_def)
definition lexordp :: ‹('a ==> 'a ==> bool) ==> 'a list ==> 'a list ==> bool›🍋‹only for code generation› where‹lexordp r xs ys ⟷ (xs, ys) ∈ lexord {(x, y). r x y}›
lemma [code_unfold]: ‹(xs, ys) ∈ lexord r = lexordp (λx y. (x, y) ∈ r) xs ys› by (simp add: lexordp_def)
lemma [code]: ‹lexordp r xs [] ⟷ False› ‹lexordp r [] (y # ys) ⟷ True› ‹lexordp r (x # xs) (y # ys) ⟷ r x y ∨ (x = y ∧ lexordp r xs ys)› by (simp_all add: add: lexordp_def)
text‹Executable intervals›
context preorder begin
lemma forall_less_eq_iff [code_unfold]: ‹(∀n≤b. P n) ⟷ (∀n∈{..b}. P n)› by auto
lemma exists_less_eq_iff [code_unfold]: ‹(∃n≤b. P n) ⟷ (∃n∈{..b}. P n)› by auto
lemma forall_less_iff [code_unfold]: ‹(∀n🚫 P n) ⟷ (∀n∈{..🚫. P n)› by auto
lemma exists_less_iff [code_unfold]: ‹(∃n🚫 P n) ⟷ (∃n∈{..🚫. P n)› by auto
lemma forall_greater_eq_iff [code_unfold]: ‹(∀n≥a. P n) ⟷ (∀n∈{a..}. P n)› by auto
lemma exists_greater_eq_iff [code_unfold]: ‹(∃n≥a. P n) ⟷ (∃n∈{a..}. P n)› by auto
lemma forall_greater_iff [code_unfold]: ‹(∀n>a. P n) ⟷ (∀n∈{a🚫}. P n)› by auto
lemma exists_greater_iff [code_unfold]: ‹(∃n>a. P n) ⟷ (∃n∈{a🚫}. P n)› by auto
end
class interval = linorder + comm_semiring_1_cancel + assumes finite_atLeastAtMost: ‹finite {a..b}› assumes dec_less_imp_less_eq: ‹a - 1 🚫==> a ≤ b› assumes less_inc_imp_less_eq: ‹a 🚫 + 1 ==> a ≤ b› assumes dec_greater_eq_self_imp_bot: ‹a ≤ a - 1 ==> a ≤ c› assumes inc_less_eq_self_imp_top: ‹b + 1 ≤ b ==> d ≤ b› begin
context begin
qualified lemma less_imp_less_eq_dec: ‹c 🚫==> a 🚫==> a ≤ b - 1› usinglocal.dec_less_imp_less_eq local.not_less by blast
qualified lemma less_imp_in_less_eq: ‹a 🚫==> a 🚫==> a + 1 ≤ b› usinglocal.less_inc_imp_less_eq local.not_less by blast
qualified lemma less_eq_dec_imp_less: ‹c 🚫==> a ≤ b - 1 ==> a 🚫› usinglocal.dec_greater_eq_self_imp_bot local.dual_order.trans local.not_le by blast
qualified lemma inc_less_eq_imp_less: ‹a 🚫==> a + 1 ≤ b ==> a 🚫› usinglocal.inc_less_eq_self_imp_top local.not_le local.order.strict_trans2 by blast
qualified definition interval :: ‹'a ==> 'a ==> 'a list›🍋‹only for code generation› where interval_eq: ‹interval a b = sorted_list_of_set {a..b}›
qualified lemma set_interval_eq [simp]: ‹set (interval a b) = {a..b}› using finite_atLeastAtMost [of a b] by (simp add: interval_eq)
qualified lemma distinct_interval [simp]: ‹distinct (interval a b)› by (simp add: interval_eq)
qualified lemma interval_code [code]: ‹interval a b = (if a 🚫 then a # interval (a + 1) b else if a = b then [a] else [])› proof -
consider (less) ‹a 🚫› | (eq) ‹a = b› | (greater) ‹a > b› using less_linear by blast thenshow ?thesis proof cases case less thenhave‹{a..b} = insert a {a + 1..b}› by (auto simp add: not_le dest: less_imp_le local.inc_less_eq_imp_less dest!: less_inc_imp_less_eq) moreoverhave‹{a + 1..b} - {a} = {a + 1..b}› using less by (auto dest: local.inc_less_eq_imp_less) moreoverhave‹insort a (sorted_list_of_set {a + 1..b}) = a # sorted_list_of_set {a + 1..b}› using finite_atLeastAtMost [of ‹a + 1› b] less by (auto intro!: insort_is_Cons dest: local.inc_less_eq_imp_less less_imp_le) ultimatelyshow ?thesis using less finite_atLeastAtMost [of ‹a + 1› b] by (simp add: interval_eq) next case eq thenshow ?thesis by (simp add: interval_eq) next case greater thenshow ?thesis by (auto simp add: interval_eq) qed qed
qualified lemma atLeastAtMost_eq_interval [code]: ‹{a..b} = set (interval a b)› by simp
qualified lemma atLeastLessThan_eq_interval [code]: ‹{a..🚫 = (let d = b - 1 in if d 🚫 then set (interval a d) else {})› by (auto simp add: Let_def not_less local.less_imp_less_eq_dec intro: dec_greater_eq_self_imp_bot)
qualified lemma greaterThanAtMost_eq_interval [code]: ‹{a🚫b} = (let c = a + 1 in if a 🚫 then set (interval c b) else {})› by (auto simp add: Let_def not_less dec_less_imp_less_eq intro: inc_less_eq_self_imp_top)
qualified lemma greaterThanLessThan_eq_interval [code]: ‹{a🚫🚫 = (let c = a + 1; d = b - 1 in if a 🚫∧ d 🚫 then set (interval c d) else {})› by (auto simp add: Let_def not_less dec_less_imp_less_eq
dest: local.less_imp_less_eq_dec local.inc_less_eq_imp_less local.less_eq_dec_imp_less)
qualified definition all_interval :: ‹('a ==> bool) ==> 'a ==> 'a ==> bool›🍋‹only for code generation› where all_interval_iff [code_post, simp]: ‹all_interval P a b ⟷ (∀n∈{a..b}. P n)›
qualified lemma all_interval_code [code]: ‹all_interval P a b ⟷ ((a 🚫⟶ P a ∧ all_interval P (a + 1) b) ∧ (a = b ⟶ P a))› by (simp only: all_interval_iff interval_code [of a b] flip: set_interval_eq) auto
qualified lemma forall_atLeastAtMost_iff [code_unfold]: ‹(∀n∈{a..b}. P n) ⟷ all_interval P a b› by simp
qualified lemma exists_atLeastAtMost_iff [code_unfold]: ‹(∃n∈{a..b}. P n) ⟷¬ all_interval (Not ∘ P) a b› using forall_atLeastAtMost_iff [of a b ‹Not ∘ P›] by simp
qualified lemma forall_atLeastLessThan_iff [code_unfold]: ‹(∀n∈{a..🚫. P n) ⟷ (let d = b - 1 in d 🚫⟶ all_interval P a d)› by (auto simp add: not_less Let_def intro: local.less_eq_dec_imp_less local.less_imp_less_eq_dec elim!: bspec)
qualified lemma exists_atLeastLessThan_iff [code_unfold]: ‹(∃n∈{a..🚫. P n) ⟷ (let d = b - 1 in d 🚫∧¬ all_interval (Not ∘ P) a d)› using forall_atLeastLessThan_iff [of a b ‹Not ∘ P›] by (auto simp add: Let_def)
qualified lemma forall_greaterThanAtMost_iff [code_unfold]: ‹(∀n∈{a🚫b}. P n) ⟷ (let c = a + 1 in a 🚫⟶ all_interval P c b)› by (auto simp add: Let_def not_less intro: local.less_imp_in_less_eq local.inc_less_eq_imp_less elim!: bspec)
qualified lemma exists_greaterThanAtMost_iff [code_unfold]: ‹(∃n∈{a🚫b}. P n) ⟷ (let c = a + 1 in a 🚫∧¬ all_interval (Not ∘ P) c b)› using forall_greaterThanAtMost_iff [of a b ‹Not ∘ P›] by (auto simp add: Let_def)
qualified lemma forall_greaterThanLessThan_iff [code_unfold]: ‹(∀n∈{a🚫🚫. P n) ⟷ (let c = a + 1; d = b - 1 in a 🚫⟶ d 🚫⟶ all_interval P c d)› by (auto simp add: Let_def not_less local.less_imp_in_less_eq local.less_imp_less_eq_dec
intro: local.inc_less_eq_imp_less local.less_eq_dec_imp_less elim!: bspec)
qualified lemma exists_greaterThanLessThan_iff [code_unfold]: ‹(∃n∈{a🚫🚫. P n) ⟷ (let c = a + 1; d = b - 1 in a 🚫∧ d 🚫∧¬ all_interval (Not ∘ P) c d)› using forall_greaterThanLessThan_iff [of a b ‹Not ∘ P›] by (auto simp add: Let_def)
end
end
class interval_top = interval + order_top begin
lemma atLeast_eq_atLeastAtMost_top [code, code_unfold]: ‹{a..} = {a..top}› by auto
lemma greaterThan_eq_greaterThanAtMost_top [code, code_unfold]: ‹{a🚫} = {a🚫top}› by auto
end
class interval_bot = interval + order_bot begin
lemma atMost_eq_atLeastAtMost_bot [code, code_unfold]: ‹{..b} = {bot..b}› by auto
lemma lessThan_eq_atLeastLessThan_bot [code, code_unfold]: ‹{..🚫 = {bot..🚫› by auto
end
instance nat :: interval_bot by standard simp_all
instance int :: interval by standard simp_all
context begin
qualified lemma interval_eq_upt [simp]: ‹List.interval m n = [m..🚫n]› by (simp add: List.interval_eq flip: atLeastLessThanSuc_atLeastAtMost)
qualified lemma interval_eq_upto [simp]: ‹List.interval i k = [i..k]› by (simp add: List.interval_eq)
end
subsubsection ‹Special implementations›
context begin
qualified definition map_tailrec_rev :: ‹('a ==> 'b) ==> 'a list ==> 'b list ==> 'b list›🍋‹only for code generation› where map_tailrec_rev [simp]: ‹map_tailrec_rev f as bs = rev (map f as) @ bs›
text‹ Optional tail recursive version of 🍋‹map›. Can avoid stack overflow in some target languages. Do not use for proving. ›
qualified lemma map_tailrec_rev_code [code, no_atp]: ‹map_tailrec_rev f [] bs = bs› ‹map_tailrec_rev f (a # as) bs = map_tailrec_rev f as (f a # bs)› by simp_all
qualified definition map_tailrec :: ‹('a ==> 'b) ==> 'a list ==> 'b list›🍋‹only for code generation› where map_tailrec_eq [simp]: ‹map_tailrec = map›
qualified lemma map_tailrec_code [code, no_atp]: ‹map_tailrec f as = rev (map_tailrec_rev f as [])› by simp
text‹Potential code equation:›
qualified lemma map_eq_map_tailrec: ‹map = map_tailrec› by simp
end
definition map_filter :: ‹('a ==> 'b option) ==> 'a list ==> 'b list› where [code_post]: "map_filter f xs = map (the ∘ f) (filter (λx. f x ≠ None) xs)"
text‹ Operation 🍋‹map_filter›avoids intermediate lists on execution -- do not use for proving. ›
lemma map_filter_simps [simp, code, no_atp]: ‹map_filter f [] = []› ‹map_filter f (x # xs) = (case f x of None ==> map_filter f xs | Some y ==> y # map_filter f xs)› by (simp_all add: map_filter_def split: option.split)
lemma map_filter_map_filter [code_unfold]: ‹map f (filter P xs) = map_filter (λx. if P x then Some (f x) else None) xs› by (simp add: map_filter_def)
hide_const (open) map_filter
subsubsection ‹Operations for optimization and efficiency›
context begin
qualified definition null :: ‹'a list ==> bool›🍋‹only for code generation› where null_iff [code_abbrev, simp]: ‹null xs ⟷ xs = []›
qualified definition maps :: ‹('a ==> 'b list) ==> 'a list ==> 'b list›🍋‹only for code generation› where maps_eq [code_abbrev, simp]: ‹maps f xs = concat (map f xs)›
text‹ Operation 🍋‹maps›avoids intermediate lists on execution -- do not use for proving. ›
qualified lemma maps_code [code, no_atp]: ‹maps f [] = []› ‹maps f (x # xs) = f x @ maps f xs› by simp_all
lemma UNIV_coset [code]: "UNIV = List.coset []" by simp
lemma compl_set [code]: "- set xs = List.coset xs" by simp
lemma compl_coset [code]: "- List.coset xs = set xs" by simp
lemma [code]: "x ∈ set xs ⟷ List.member xs x" "x ∈ List.coset xs ⟷¬ List.member xs x" by simp_all
lemma insert_code [code]: "insert x (set xs) = set (List.insert x xs)" "insert x (List.coset xs) = List.coset (removeAll x xs)" by simp_all
lemma remove_code [code]: "Set.remove x (set xs) = set (removeAll x xs)" "Set.remove x (List.coset xs) = List.coset (List.insert x xs)" by (simp_all add: set_eq_iff ac_simps)
lemma filter_set [code]: "Set.filter P (set xs) = set (filter P xs)" by simp
lemma image_set [code]: "image f (set xs) = set (map f xs)" by simp
lemma subset_code [code]: "set xs ⊆ B ⟷ (∀x∈set xs. x ∈ B)" "A ⊆ List.coset ys ⟷ (∀y∈set ys. y ∉ A)" "List.coset [] ⊆ set [] ⟷ False" by auto
lemma Ball_set [code]: "Ball (set xs) P ⟷ list_all P xs" by (simp add: list_all_iff)
lemma Bex_set [code]: "Bex (set xs) P ⟷ list_ex P xs" by (simp add: list_ex_iff)
lemma the_elem_set [code]: "the_elem (set [x]) = x" by simp
lemma Pow_set [code]: "Pow (set []) = {{}}" "Pow (set (x # xs)) = (let A = Pow (set xs) in A ∪ insert x ` A)" by (simp_all add: Pow_insert Let_def)
lemma these_set_code [code]: ‹Option.these (set xs) = set (List.map_filter (λx. x) xs)› by (simp add: Option.these_eq Option.is_none_def set_eq_iff map_filter_def)
lemma image_filter_set_eq [code]: ‹Option.image_filter f (set xs) = set (List.map_filter f xs)› apply (simp add: Option.image_filter_eq these_set_code set_eq_iff flip: set_map) apply (auto simp add: map_filter_def image_iff) done
lemma can_select_set_list_ex1 [code]: "Set.can_select P (set A) = list_ex1 P A" by (simp add: list_ex1_iff)
lemma product_code [code]: "Product_Type.product (set xs) (set ys) = set [(x, y). x ← xs, y ← ys]" by (auto simp add: Product_Type.product_def)
lemma Id_on_set [code]: "Id_on (set xs) = set [(x, x). x ← xs]" by (auto simp add: Id_on_def)
lemma Image_code [code]: "R `` S = Option.image_filter (λ(x, y). if x ∈ S then Some y else None) R" apply (simp add: Option.image_filter_eq case_prod_unfold Option.these_eq) apply force done
fun add_literal_list target = let fun pretty literals pr _ vars fxy [(t1, _), (t2, _)] = case Option.map (cons t1) (implode_list t2)
of SOME ts =>
Code_Printer.literal_list literals (map (pr vars Code_Printer.NOBR) ts)
| NONE =>
print_list (Code_Printer.infix_cons literals) (pr vars) fxy t1 t2; in
Code_Target.set_printings (Code_Symbol.Constant (🍋‹Cons›,
[(target, SOME (Code_Printer.complex_const_syntax (2, pretty)))])) end
end; ›
code_printing
type_constructor list ⇀
(SML) "_ list" and (OCaml) "_ list" and (Haskell) "![(_)]" and (Scala) "List[(_)]"
| constant Nil ⇀
(SML) "[]" and (OCaml) "[]" and (Haskell) "[]" and (Scala) "!Nil"
| class_instance list :: equal ⇀
(Haskell) -
| constant "HOL.equal :: 'a list ==> 'a list ==> bool"⇀
(Haskell) infix 4 "=="
subsubsection ‹Transfer rules for the Transfer package›
contextincludes lifting_syntax begin
lemma tl_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A) tl tl" unfolding tl_def[abs_def] by transfer_prover
lemma butlast_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A) butlast butlast" by (rule rel_funI, erule list_all2_induct, auto)
lemma append_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A ===> list_all2 A) append append" unfolding List.append_def by transfer_prover
lemma rev_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A) rev rev" unfolding List.rev_def by transfer_prover
lemma filter_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> list_all2 A) filter filter" unfolding List.filter_def by transfer_prover
lemma fold_transfer [transfer_rule]: "((A ===> B ===> B) ===> list_all2 A ===> B ===> B) fold fold" unfolding List.fold_def by transfer_prover
lemma foldr_transfer [transfer_rule]: "((A ===> B ===> B) ===> list_all2 A ===> B ===> B) foldr foldr" unfolding List.foldr_def by transfer_prover
lemma foldl_transfer [transfer_rule]: "((B ===> A ===> B) ===> B ===> list_all2 A ===> B) foldl foldl" unfolding List.foldl_def by transfer_prover
lemma concat_transfer [transfer_rule]: "(list_all2 (list_all2 A) ===> list_all2 A) concat concat" unfolding List.concat_def by transfer_prover
lemma drop_transfer [transfer_rule]: "((=) ===> list_all2 A ===> list_all2 A) drop drop" unfolding List.drop_def by transfer_prover
lemma take_transfer [transfer_rule]: "((=) ===> list_all2 A ===> list_all2 A) take take" unfolding List.take_def by transfer_prover
lemma list_update_transfer [transfer_rule]: "(list_all2 A ===> (=) ===> A ===> list_all2 A) list_update list_update" unfolding list_update_def by transfer_prover
lemma takeWhile_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> list_all2 A) takeWhile takeWhile" unfolding takeWhile_def by transfer_prover
lemma dropWhile_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> list_all2 A) dropWhile dropWhile" unfolding dropWhile_def by transfer_prover
lemma zip_transfer [transfer_rule]: "(list_all2 A ===> list_all2 B ===> list_all2 (rel_prod A B)) zip zip" unfolding zip_def by transfer_prover
lemma product_transfer [transfer_rule]: "(list_all2 A ===> list_all2 B ===> list_all2 (rel_prod A B)) List.product List.product" unfolding List.product_def by transfer_prover
lemma product_lists_transfer [transfer_rule]: "(list_all2 (list_all2 A) ===> list_all2 (list_all2 A)) product_lists product_lists" unfolding product_lists_def by transfer_prover
lemma insert_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows"(A ===> list_all2 A ===> list_all2 A) List.insert List.insert" unfolding List.insert_def [abs_def] by transfer_prover
lemma find_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> rel_option A) List.find List.find" unfolding List.find_def by transfer_prover
lemma those_transfer [transfer_rule]: "(list_all2 (rel_option P) ===> rel_option (list_all2 P)) those those" unfolding List.those_def by transfer_prover
lemma remove1_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows"(A ===> list_all2 A ===> list_all2 A) remove1 remove1" unfolding remove1_def by transfer_prover
lemma removeAll_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows"(A ===> list_all2 A ===> list_all2 A) removeAll removeAll" unfolding removeAll_def by transfer_prover
lemma successively_transfer [transfer_rule]: "((A ===> A ===> (=)) ===> list_all2 A ===> (=)) successively successively" unfolding successively_altdef by transfer_prover
lemma distinct_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows"(list_all2 A ===> (=)) distinct distinct" unfolding distinct_def by transfer_prover
lemma distinct_adj_transfer [transfer_rule]: assumes"bi_unique A" shows"(list_all2 A ===> (=)) distinct_adj distinct_adj" unfolding rel_fun_def proof (intro allI impI) fix xs ys assume"list_all2 A xs ys" thus"distinct_adj xs ⟷ distinct_adj ys" proof (induction rule: list_all2_induct) case (Cons x xs y ys) show ?case by (metis Cons assms bi_unique_def distinct_adj_Cons list.rel_sel) qed auto qed
lemma remdups_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows"(list_all2 A ===> list_all2 A) remdups remdups" unfolding remdups_def by transfer_prover
lemma remdups_adj_transfer [transfer_rule]: assumes [transfer_rule]: "bi_unique A" shows"(list_all2 A ===> list_all2 A) remdups_adj remdups_adj" proof (rule rel_funI, erule list_all2_induct) qed (auto simp: remdups_adj_Cons assms[unfolded bi_unique_def] split: list.splits)
lemma replicate_transfer [transfer_rule]: "((=) ===> A ===> list_all2 A) replicate replicate" unfolding replicate_def by transfer_prover
lemma length_transfer [transfer_rule]: "(list_all2 A ===> (=)) length length" unfolding size_list_overloaded_def size_list_def by transfer_prover
lemma rotate1_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A) rotate1 rotate1" unfolding rotate1_def by transfer_prover
lemma rotate_transfer [transfer_rule]: "((=) ===> list_all2 A ===> list_all2 A) rotate rotate" unfolding rotate_def [abs_def] by transfer_prover
lemma nths_transfer [transfer_rule]: "(list_all2 A ===> rel_set (=) ===> list_all2 A) nths nths" unfolding nths_def [abs_def] by transfer_prover
lemma subseqs_transfer [transfer_rule]: "(list_all2 A ===> list_all2 (list_all2 A)) subseqs subseqs" unfolding subseqs_def [abs_def] by transfer_prover
lemma partition_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> rel_prod (list_all2 A) (list_all2 A)) partition partition" unfolding partition_def by transfer_prover
lemma lists_transfer [transfer_rule]: "(rel_set A ===> rel_set (list_all2 A)) lists lists" proof (rule rel_funI, rule rel_setI) show"[l ∈ lists X; rel_set A X Y]==>∃y∈lists Y. list_all2 A l y"for X Y l proof (induction l rule: lists.induct) case (Cons a l) thenshow ?case by (simp only: rel_set_def list_all2_Cons1, metis lists.Cons) qed auto show"[l ∈ lists Y; rel_set A X Y]==>∃x∈lists X. list_all2 A x l"for X Y l proof (induction l rule: lists.induct) case (Cons a l) thenshow ?case by (simp only: rel_set_def list_all2_Cons2, metis lists.Cons) qed auto qed
lemma set_Cons_transfer [transfer_rule]: "(rel_set A ===> rel_set (list_all2 A) ===> rel_set (list_all2 A)) set_Cons set_Cons" unfolding rel_fun_def rel_set_def set_Cons_def by (fastforce simp add: list_all2_Cons1 list_all2_Cons2)
lemma listset_transfer [transfer_rule]: "(list_all2 (rel_set A) ===> rel_set (list_all2 A)) listset listset" unfolding listset_def by transfer_prover
lemma null_transfer [transfer_rule]: "(list_all2 A ===> (=)) List.null List.null" unfolding rel_fun_def by auto
lemma list_all_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> (=)) list_all list_all" using list.pred_transfer by blast
lemma list_ex_transfer [transfer_rule]: "((A ===> (=)) ===> list_all2 A ===> (=)) list_ex list_ex" unfolding list_ex_iff [abs_def] by transfer_prover
lemma splice_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A ===> list_all2 A) splice splice" apply (rule rel_funI, erule list_all2_induct, simp add: rel_fun_def, simp) apply (rule rel_funI) apply (erule_tac xs=x in list_all2_induct, simp, simp add: rel_fun_def) done
lemma shuffles_transfer [transfer_rule]: "(list_all2 A ===> list_all2 A ===> rel_set (list_all2 A)) shuffles shuffles" proof (intro rel_funI, goal_cases) case (1 xs xs' ys ys') thus ?case proof (induction xs ys arbitrary: xs' ys' rule: shuffles.induct) case (3 x xs y ys xs' ys') from"3.prems"obtain x' xs'' where xs': "xs' = x' # xs''"by (cases xs') auto from"3.prems"obtain y' ys'' where ys': "ys' = y' # ys''"by (cases ys') auto have [transfer_rule]: "A x x'""A y y'""list_all2 A xs xs''""list_all2 A ys ys''" using"3.prems"by (simp_all add: xs' ys') have [transfer_rule]: "rel_set (list_all2 A) (shuffles xs (y # ys)) (shuffles xs'' ys')"and
[transfer_rule]: "rel_set (list_all2 A) (shuffles (x # xs) ys) (shuffles xs' ys'')" using"3.prems"by (auto intro!: "3.IH" simp: xs' ys') have"rel_set (list_all2 A) ((#) x ` shuffles xs (y # ys) ∪ (#) y ` shuffles (x # xs) ys) ((#) x' ` shuffles xs'' ys' ∪ (#) y' ` shuffles xs' ys'')"by transfer_prover thus ?caseby (simp add: xs' ys') qed (auto simp: rel_set_def) qed
lemma rtrancl_parametric [transfer_rule]: assumes [transfer_rule]: "bi_unique A""bi_total A" shows"(rel_set (rel_prod A A) ===> rel_set (rel_prod A A)) rtrancl rtrancl" unfolding rtrancl_def by transfer_prover
lemma monotone_parametric [transfer_rule]: assumes [transfer_rule]: "bi_total A" shows"((A ===> A ===> (=)) ===> (B ===> B ===> (=)) ===> (A ===> B) ===> (=)) monotone monotone" unfolding monotone_def[abs_def] by transfer_prover
lemma fun_ord_parametric [transfer_rule]: assumes [transfer_rule]: "bi_total C" shows"((A ===> B ===> (=)) ===> (C ===> A) ===> (C ===> B) ===> (=)) fun_ord fun_ord" unfolding fun_ord_def[abs_def] by transfer_prover
lemma fun_lub_parametric [transfer_rule]: assumes [transfer_rule]: "bi_total A""bi_unique A" shows"((rel_set A ===> B) ===> rel_set (C ===> A) ===> C ===> B) fun_lub fun_lub" unfolding fun_lub_def[abs_def] by transfer_prover
end
subsection‹Misc›
lemma Ball_set_list_all: (* FIXME delete candidate *) "Ball (set xs) P ⟷ list_all P xs" by (fact Ball_set)
lemma Bex_set_list_ex: (* FIXME delete candidate *) "Bex (set xs) P ⟷ list_ex P xs" by (fact Bex_set)
end
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.1.98Bemerkung:
(vorverarbeitet am 2026-04-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.