src/HOL/List.thy
author hoelzl
Mon, 18 Nov 2013 17:14:01 +0100
changeset 55869 178922b63b58
parent 55777 9f0f1152c875
child 55871 f7fef6b00bfe
permissions -rw-r--r--
add lemmas Suc_funpow and id_funpow to simpset; add lemma map_add_upt
wenzelm@13462
     1
(*  Title:      HOL/List.thy
wenzelm@13462
     2
    Author:     Tobias Nipkow
clasohm@923
     3
*)
clasohm@923
     4
wenzelm@13114
     5
header {* The datatype of finite lists *}
wenzelm@13122
     6
nipkow@15131
     7
theory List
kuncar@54149
     8
imports Presburger Code_Numeral Quotient ATP Lifting_Set Lifting_Option Lifting_Product
nipkow@15131
     9
begin
clasohm@923
    10
wenzelm@13142
    11
datatype 'a list =
wenzelm@13366
    12
    Nil    ("[]")
wenzelm@13366
    13
  | Cons 'a  "'a list"    (infixr "#" 65)
clasohm@923
    14
clasohm@923
    15
syntax
wenzelm@13366
    16
  -- {* list Enumeration *}
wenzelm@35118
    17
  "_list" :: "args => 'a list"    ("[(_)]")
clasohm@923
    18
haftmann@34928
    19
translations
haftmann@34928
    20
  "[x, xs]" == "x#[xs]"
haftmann@34928
    21
  "[x]" == "x#[]"
haftmann@34928
    22
wenzelm@35118
    23
wenzelm@35118
    24
subsection {* Basic list processing functions *}
haftmann@34928
    25
nipkow@51563
    26
primrec hd :: "'a list \<Rightarrow> 'a" where
nipkow@51563
    27
"hd (x # xs) = x"
nipkow@51563
    28
nipkow@51563
    29
primrec tl :: "'a list \<Rightarrow> 'a list" where
nipkow@51563
    30
"tl [] = []" |
nipkow@51563
    31
"tl (x # xs) = xs"
nipkow@51563
    32
nipkow@51563
    33
primrec last :: "'a list \<Rightarrow> 'a" where
nipkow@51563
    34
"last (x # xs) = (if xs = [] then x else last xs)"
nipkow@51563
    35
nipkow@51563
    36
primrec butlast :: "'a list \<Rightarrow> 'a list" where
nipkow@51563
    37
"butlast []= []" |
nipkow@51563
    38
"butlast (x # xs) = (if xs = [] then [] else x # butlast xs)"
nipkow@51563
    39
nipkow@51563
    40
primrec set :: "'a list \<Rightarrow> 'a set" where
nipkow@51563
    41
"set [] = {}" |
nipkow@51563
    42
"set (x # xs) = insert x (set xs)"
nipkow@51563
    43
nipkow@51563
    44
definition coset :: "'a list \<Rightarrow> 'a set" where
nipkow@51563
    45
[simp]: "coset xs = - set xs"
nipkow@51563
    46
nipkow@51563
    47
primrec map :: "('a \<Rightarrow> 'b) \<Rightarrow> 'a list \<Rightarrow> 'b list" where
nipkow@51563
    48
"map f [] = []" |
nipkow@51563
    49
"map f (x # xs) = f x # map f xs"
nipkow@51563
    50
nipkow@51563
    51
primrec append :: "'a list \<Rightarrow> 'a list \<Rightarrow> 'a list" (infixr "@" 65) where
nipkow@51563
    52
append_Nil: "[] @ ys = ys" |
nipkow@51563
    53
append_Cons: "(x#xs) @ ys = x # xs @ ys"
nipkow@51563
    54
nipkow@51563
    55
primrec rev :: "'a list \<Rightarrow> 'a list" where
nipkow@51563
    56
"rev [] = []" |
nipkow@51563
    57
"rev (x # xs) = rev xs @ [x]"
nipkow@51563
    58
nipkow@51563
    59
primrec filter:: "('a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
    60
"filter P [] = []" |
nipkow@51563
    61
"filter P (x # xs) = (if P x then x # filter P xs else filter P xs)"
haftmann@34928
    62
haftmann@34928
    63
syntax
wenzelm@13366
    64
  -- {* Special syntax for filter *}
wenzelm@35118
    65
  "_filter" :: "[pttrn, 'a list, bool] => 'a list"    ("(1[_<-_./ _])")
clasohm@923
    66
haftmann@34928
    67
translations
haftmann@34928
    68
  "[x<-xs . P]"== "CONST filter (%x. P) xs"
haftmann@34928
    69
haftmann@34928
    70
syntax (xsymbols)
wenzelm@35118
    71
  "_filter" :: "[pttrn, 'a list, bool] => 'a list"("(1[_\<leftarrow>_ ./ _])")
haftmann@34928
    72
syntax (HTML output)
wenzelm@35118
    73
  "_filter" :: "[pttrn, 'a list, bool] => 'a list"("(1[_\<leftarrow>_ ./ _])")
haftmann@34928
    74
nipkow@51563
    75
primrec fold :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'a list \<Rightarrow> 'b \<Rightarrow> 'b" where
nipkow@51563
    76
fold_Nil:  "fold f [] = id" |
nipkow@51563
    77
fold_Cons: "fold f (x # xs) = fold f xs \<circ> f x"
nipkow@51563
    78
nipkow@51563
    79
primrec foldr :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'a list \<Rightarrow> 'b \<Rightarrow> 'b" where
nipkow@51563
    80
foldr_Nil:  "foldr f [] = id" |
nipkow@51563
    81
foldr_Cons: "foldr f (x # xs) = f x \<circ> foldr f xs"
nipkow@51563
    82
nipkow@51563
    83
primrec foldl :: "('b \<Rightarrow> 'a \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a list \<Rightarrow> 'b" where
nipkow@51563
    84
foldl_Nil:  "foldl f a [] = a" |
nipkow@51563
    85
foldl_Cons: "foldl f a (x # xs) = foldl f (f a x) xs"
nipkow@51563
    86
nipkow@51563
    87
primrec concat:: "'a list list \<Rightarrow> 'a list" where
nipkow@51563
    88
"concat [] = []" |
nipkow@51563
    89
"concat (x # xs) = x @ concat xs"
nipkow@51563
    90
nipkow@51563
    91
definition (in monoid_add) listsum :: "'a list \<Rightarrow> 'a" where
nipkow@51563
    92
"listsum xs = foldr plus xs 0"
nipkow@51563
    93
nipkow@51563
    94
primrec drop:: "nat \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
    95
drop_Nil: "drop n [] = []" |
nipkow@51563
    96
drop_Cons: "drop n (x # xs) = (case n of 0 \<Rightarrow> x # xs | Suc m \<Rightarrow> drop m xs)"
haftmann@34928
    97
  -- {*Warning: simpset does not contain this definition, but separate
haftmann@34928
    98
       theorems for @{text "n = 0"} and @{text "n = Suc k"} *}
haftmann@34928
    99
nipkow@51563
   100
primrec take:: "nat \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
   101
take_Nil:"take n [] = []" |
nipkow@51563
   102
take_Cons: "take n (x # xs) = (case n of 0 \<Rightarrow> [] | Suc m \<Rightarrow> x # take m xs)"
haftmann@34928
   103
  -- {*Warning: simpset does not contain this definition, but separate
haftmann@34928
   104
       theorems for @{text "n = 0"} and @{text "n = Suc k"} *}
haftmann@34928
   105
nipkow@51563
   106
primrec nth :: "'a list => nat => 'a" (infixl "!" 100) where
nipkow@51563
   107
nth_Cons: "(x # xs) ! n = (case n of 0 \<Rightarrow> x | Suc k \<Rightarrow> xs ! k)"
haftmann@34928
   108
  -- {*Warning: simpset does not contain this definition, but separate
haftmann@34928
   109
       theorems for @{text "n = 0"} and @{text "n = Suc k"} *}
haftmann@34928
   110
nipkow@51563
   111
primrec list_update :: "'a list \<Rightarrow> nat \<Rightarrow> 'a \<Rightarrow> 'a list" where
nipkow@51563
   112
"list_update [] i v = []" |
nipkow@51563
   113
"list_update (x # xs) i v =
nipkow@51563
   114
  (case i of 0 \<Rightarrow> v # xs | Suc j \<Rightarrow> x # list_update xs j v)"
haftmann@34928
   115
wenzelm@41495
   116
nonterminal lupdbinds and lupdbind
haftmann@34928
   117
haftmann@34928
   118
syntax
wenzelm@13366
   119
  "_lupdbind":: "['a, 'a] => lupdbind"    ("(2_ :=/ _)")
wenzelm@13366
   120
  "" :: "lupdbind => lupdbinds"    ("_")
wenzelm@13366
   121
  "_lupdbinds" :: "[lupdbind, lupdbinds] => lupdbinds"    ("_,/ _")
wenzelm@13366
   122
  "_LUpdate" :: "['a, lupdbinds] => 'a"    ("_/[(_)]" [900,0] 900)
nipkow@5077
   123
clasohm@923
   124
translations
wenzelm@35118
   125
  "_LUpdate xs (_lupdbinds b bs)" == "_LUpdate (_LUpdate xs b) bs"
haftmann@34928
   126
  "xs[i:=x]" == "CONST list_update xs i x"
haftmann@34928
   127
nipkow@51563
   128
primrec takeWhile :: "('a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
   129
"takeWhile P [] = []" |
nipkow@51563
   130
"takeWhile P (x # xs) = (if P x then x # takeWhile P xs else [])"
nipkow@51563
   131
nipkow@51563
   132
primrec dropWhile :: "('a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
   133
"dropWhile P [] = []" |
nipkow@51563
   134
"dropWhile P (x # xs) = (if P x then dropWhile P xs else x # xs)"
nipkow@51563
   135
nipkow@51563
   136
primrec zip :: "'a list \<Rightarrow> 'b list \<Rightarrow> ('a \<times> 'b) list" where
nipkow@51563
   137
"zip xs [] = []" |
nipkow@51563
   138
zip_Cons: "zip xs (y # ys) =
nipkow@51563
   139
  (case xs of [] => [] | z # zs => (z, y) # zip zs ys)"
haftmann@34928
   140
  -- {*Warning: simpset does not contain this definition, but separate
haftmann@34928
   141
       theorems for @{text "xs = []"} and @{text "xs = z # zs"} *}
haftmann@34928
   142
nipkow@51563
   143
primrec product :: "'a list \<Rightarrow> 'b list \<Rightarrow> ('a \<times> 'b) list" where
nipkow@51563
   144
"product [] _ = []" |
nipkow@51563
   145
"product (x#xs) ys = map (Pair x) ys @ product xs ys"
haftmann@50963
   146
haftmann@50963
   147
hide_const (open) product
haftmann@50963
   148
traytel@54858
   149
primrec product_lists :: "'a list list \<Rightarrow> 'a list list" where
traytel@54858
   150
"product_lists [] = [[]]" |
traytel@54858
   151
"product_lists (xs # xss) = concat (map (\<lambda>x. map (Cons x) (product_lists xss)) xs)"
traytel@54858
   152
nipkow@51563
   153
primrec upt :: "nat \<Rightarrow> nat \<Rightarrow> nat list" ("(1[_..</_'])") where
nipkow@51563
   154
upt_0: "[i..<0] = []" |
nipkow@51563
   155
upt_Suc: "[i..<(Suc j)] = (if i <= j then [i..<j] @ [j] else [])"
nipkow@51563
   156
nipkow@51563
   157
definition insert :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
   158
"insert x xs = (if x \<in> set xs then xs else x # xs)"
haftmann@40096
   159
haftmann@40096
   160
hide_const (open) insert
haftmann@40096
   161
hide_fact (open) insert_def
haftmann@40096
   162
nipkow@47992
   163
primrec find :: "('a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> 'a option" where
nipkow@51563
   164
"find _ [] = None" |
nipkow@51563
   165
"find P (x#xs) = (if P x then Some x else find P xs)"
nipkow@47992
   166
nipkow@47992
   167
hide_const (open) find
nipkow@47992
   168
haftmann@52233
   169
primrec those :: "'a option list \<Rightarrow> 'a list option"
haftmann@52233
   170
where
haftmann@52233
   171
"those [] = Some []" |
haftmann@52233
   172
"those (x # xs) = (case x of
haftmann@52233
   173
  None \<Rightarrow> None
haftmann@52233
   174
| Some y \<Rightarrow> Option.map (Cons y) (those xs))"
haftmann@52233
   175
nipkow@51563
   176
primrec remove1 :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
   177
"remove1 x [] = []" |
nipkow@51563
   178
"remove1 x (y # xs) = (if x = y then xs else y # remove1 x xs)"
nipkow@51563
   179
nipkow@51563
   180
primrec removeAll :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
   181
"removeAll x [] = []" |
nipkow@51563
   182
"removeAll x (y # xs) = (if x = y then removeAll x xs else y # removeAll x xs)"
nipkow@51563
   183
nipkow@51563
   184
primrec distinct :: "'a list \<Rightarrow> bool" where
nipkow@51563
   185
"distinct [] \<longleftrightarrow> True" |
nipkow@51563
   186
"distinct (x # xs) \<longleftrightarrow> x \<notin> set xs \<and> distinct xs"
nipkow@51563
   187
nipkow@51563
   188
primrec remdups :: "'a list \<Rightarrow> 'a list" where
nipkow@51563
   189
"remdups [] = []" |
nipkow@51563
   190
"remdups (x # xs) = (if x \<in> set xs then remdups xs else x # remdups xs)"
nipkow@51563
   191
traytel@54858
   192
fun remdups_adj :: "'a list \<Rightarrow> 'a list" where
traytel@54858
   193
"remdups_adj [] = []" |
traytel@54858
   194
"remdups_adj [x] = [x]" |
traytel@54858
   195
"remdups_adj (x # y # xs) = (if x = y then remdups_adj (x # xs) else x # remdups_adj (y # xs))"
traytel@54858
   196
nipkow@51563
   197
primrec replicate :: "nat \<Rightarrow> 'a \<Rightarrow> 'a list" where
nipkow@51563
   198
replicate_0: "replicate 0 x = []" |
nipkow@51563
   199
replicate_Suc: "replicate (Suc n) x = x # replicate n x"
wenzelm@2262
   200
wenzelm@13142
   201
text {*
wenzelm@14589
   202
  Function @{text size} is overloaded for all datatypes. Users may
wenzelm@13366
   203
  refer to the list version as @{text length}. *}
paulson@3342
   204
nipkow@51563
   205
abbreviation length :: "'a list \<Rightarrow> nat" where
nipkow@51563
   206
"length \<equiv> size"
paulson@15307
   207
haftmann@52310
   208
definition enumerate :: "nat \<Rightarrow> 'a list \<Rightarrow> (nat \<times> 'a) list" where
haftmann@52310
   209
enumerate_eq_zip: "enumerate n xs = zip [n..<n + length xs] xs"
haftmann@52310
   210
blanchet@47268
   211
primrec rotate1 :: "'a list \<Rightarrow> 'a list" where
nipkow@51563
   212
"rotate1 [] = []" |
nipkow@51563
   213
"rotate1 (x # xs) = xs @ [x]"
nipkow@51563
   214
nipkow@51563
   215
definition rotate :: "nat \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@51563
   216
"rotate n = rotate1 ^^ n"
nipkow@51563
   217
nipkow@51563
   218
definition list_all2 :: "('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> bool" where
nipkow@51563
   219
"list_all2 P xs ys =
nipkow@51563
   220
  (length xs = length ys \<and> (\<forall>(x, y) \<in> set (zip xs ys). P x y))"
nipkow@51563
   221
nipkow@51563
   222
definition sublist :: "'a list => nat set => 'a list" where
nipkow@51563
   223
"sublist xs A = map fst (filter (\<lambda>p. snd p \<in> A) (zip xs [0..<size xs]))"
nipkow@51563
   224
nipkow@51563
   225
primrec sublists :: "'a list \<Rightarrow> 'a list list" where
nipkow@51563
   226
"sublists [] = [[]]" |
nipkow@51563
   227
"sublists (x#xs) = (let xss = sublists xs in map (Cons x) xss @ xss)"
nipkow@51563
   228
nipkow@51563
   229
primrec n_lists :: "nat \<Rightarrow> 'a list \<Rightarrow> 'a list list" where
nipkow@51563
   230
"n_lists 0 xs = [[]]" |
nipkow@51563
   231
"n_lists (Suc n) xs = concat (map (\<lambda>ys. map (\<lambda>y. y # ys) xs) (n_lists n xs))"
haftmann@50963
   232
haftmann@50963
   233
hide_const (open) n_lists
haftmann@50963
   234
nipkow@40841
   235
fun splice :: "'a list \<Rightarrow> 'a list \<Rightarrow> 'a list" where
nipkow@40841
   236
"splice [] ys = ys" |
nipkow@40841
   237
"splice xs [] = xs" |
nipkow@40841
   238
"splice (x#xs) (y#ys) = x # y # splice xs ys"
haftmann@21061
   239
nipkow@26771
   240
text{*
nipkow@26771
   241
\begin{figure}[htbp]
nipkow@26771
   242
\fbox{
nipkow@26771
   243
\begin{tabular}{l}
wenzelm@27381
   244
@{lemma "[a,b]@[c,d] = [a,b,c,d]" by simp}\\
wenzelm@27381
   245
@{lemma "length [a,b,c] = 3" by simp}\\
wenzelm@27381
   246
@{lemma "set [a,b,c] = {a,b,c}" by simp}\\
wenzelm@27381
   247
@{lemma "map f [a,b,c] = [f a, f b, f c]" by simp}\\
wenzelm@27381
   248
@{lemma "rev [a,b,c] = [c,b,a]" by simp}\\
wenzelm@27381
   249
@{lemma "hd [a,b,c,d] = a" by simp}\\
wenzelm@27381
   250
@{lemma "tl [a,b,c,d] = [b,c,d]" by simp}\\
wenzelm@27381
   251
@{lemma "last [a,b,c,d] = d" by simp}\\
wenzelm@27381
   252
@{lemma "butlast [a,b,c,d] = [a,b,c]" by simp}\\
wenzelm@27381
   253
@{lemma[source] "filter (\<lambda>n::nat. n<2) [0,2,1] = [0,1]" by simp}\\
wenzelm@27381
   254
@{lemma "concat [[a,b],[c,d,e],[],[f]] = [a,b,c,d,e,f]" by simp}\\
haftmann@47004
   255
@{lemma "fold f [a,b,c] x = f c (f b (f a x))" by simp}\\
haftmann@48259
   256
@{lemma "foldr f [a,b,c] x = f a (f b (f c x))" by simp}\\
haftmann@48259
   257
@{lemma "foldl f x [a,b,c] = f (f (f x a) b) c" by simp}\\
wenzelm@27381
   258
@{lemma "zip [a,b,c] [x,y,z] = [(a,x),(b,y),(c,z)]" by simp}\\
wenzelm@27381
   259
@{lemma "zip [a,b] [x,y,z] = [(a,x),(b,y)]" by simp}\\
haftmann@52310
   260
@{lemma "enumerate 3 [a,b,c] = [(3,a),(4,b),(5,c)]" by normalization}\\
haftmann@50963
   261
@{lemma "List.product [a,b] [c,d] = [(a, c), (a, d), (b, c), (b, d)]" by simp}\\
traytel@54858
   262
@{lemma "product_lists [[a,b], [c], [d,e]] = [[a,c,d], [a,c,e], [b,c,d], [b,c,e]]" by simp}\\
wenzelm@27381
   263
@{lemma "splice [a,b,c] [x,y,z] = [a,x,b,y,c,z]" by simp}\\
wenzelm@27381
   264
@{lemma "splice [a,b,c,d] [x,y] = [a,x,b,y,c,d]" by simp}\\
wenzelm@27381
   265
@{lemma "take 2 [a,b,c,d] = [a,b]" by simp}\\
wenzelm@27381
   266
@{lemma "take 6 [a,b,c,d] = [a,b,c,d]" by simp}\\
wenzelm@27381
   267
@{lemma "drop 2 [a,b,c,d] = [c,d]" by simp}\\
wenzelm@27381
   268
@{lemma "drop 6 [a,b,c,d] = []" by simp}\\
wenzelm@27381
   269
@{lemma "takeWhile (%n::nat. n<3) [1,2,3,0] = [1,2]" by simp}\\
wenzelm@27381
   270
@{lemma "dropWhile (%n::nat. n<3) [1,2,3,0] = [3,0]" by simp}\\
wenzelm@27381
   271
@{lemma "distinct [2,0,1::nat]" by simp}\\
wenzelm@27381
   272
@{lemma "remdups [2,0,2,1::nat,2] = [0,1,2]" by simp}\\
traytel@54858
   273
@{lemma "remdups_adj [2,2,3,1,1::nat,2,1] = [2,3,1,2,1]" by simp}\\
haftmann@34965
   274
@{lemma "List.insert 2 [0::nat,1,2] = [0,1,2]" by (simp add: List.insert_def)}\\
haftmann@35295
   275
@{lemma "List.insert 3 [0::nat,1,2] = [3,0,1,2]" by (simp add: List.insert_def)}\\
nipkow@47992
   276
@{lemma "List.find (%i::int. i>0) [0,0] = None" by simp}\\
nipkow@47992
   277
@{lemma "List.find (%i::int. i>0) [0,1,0,2] = Some 1" by simp}\\
wenzelm@27381
   278
@{lemma "remove1 2 [2,0,2,1::nat,2] = [0,2,1,2]" by simp}\\
nipkow@27693
   279
@{lemma "removeAll 2 [2,0,2,1::nat,2] = [0,1]" by simp}\\
wenzelm@27381
   280
@{lemma "nth [a,b,c,d] 2 = c" by simp}\\
wenzelm@27381
   281
@{lemma "[a,b,c,d][2 := x] = [a,b,x,d]" by simp}\\
wenzelm@27381
   282
@{lemma "sublist [a,b,c,d,e] {0,2,3} = [a,c,d]" by (simp add:sublist_def)}\\
haftmann@50963
   283
@{lemma "sublists [a,b] = [[a, b], [a], [b], []]" by simp}\\
haftmann@50963
   284
@{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)}\\
blanchet@47268
   285
@{lemma "rotate1 [a,b,c,d] = [b,c,d,a]" by simp}\\
blanchet@47268
   286
@{lemma "rotate 3 [a,b,c,d] = [d,a,b,c]" by (simp add:rotate_def eval_nat_numeral)}\\
nipkow@40258
   287
@{lemma "replicate 4 a = [a,a,a,a]" by (simp add:eval_nat_numeral)}\\
nipkow@40258
   288
@{lemma "[2..<5] = [2,3,4]" by (simp add:eval_nat_numeral)}\\
haftmann@48259
   289
@{lemma "listsum [1,2,3::nat] = 6" by (simp add: listsum_def)}
nipkow@26771
   290
\end{tabular}}
nipkow@26771
   291
\caption{Characteristic examples}
nipkow@26771
   292
\label{fig:Characteristic}
nipkow@26771
   293
\end{figure}
blanchet@29864
   294
Figure~\ref{fig:Characteristic} shows characteristic examples
nipkow@26771
   295
that should give an intuitive understanding of the above functions.
nipkow@26771
   296
*}
nipkow@26771
   297
nipkow@24616
   298
text{* The following simple sort functions are intended for proofs,
nipkow@24616
   299
not for efficient implementations. *}
nipkow@24616
   300
wenzelm@25221
   301
context linorder
wenzelm@25221
   302
begin
wenzelm@25221
   303
haftmann@40096
   304
inductive sorted :: "'a list \<Rightarrow> bool" where
haftmann@40096
   305
  Nil [iff]: "sorted []"
haftmann@40096
   306
| Cons: "\<forall>y\<in>set xs. x \<le> y \<Longrightarrow> sorted xs \<Longrightarrow> sorted (x # xs)"
haftmann@40096
   307
haftmann@40096
   308
lemma sorted_single [iff]:
haftmann@40096
   309
  "sorted [x]"
haftmann@40096
   310
  by (rule sorted.Cons) auto
haftmann@40096
   311
haftmann@40096
   312
lemma sorted_many:
haftmann@40096
   313
  "x \<le> y \<Longrightarrow> sorted (y # zs) \<Longrightarrow> sorted (x # y # zs)"
haftmann@40096
   314
  by (rule sorted.Cons) (cases "y # zs" rule: sorted.cases, auto)
haftmann@40096
   315
haftmann@40096
   316
lemma sorted_many_eq [simp, code]:
haftmann@40096
   317
  "sorted (x # y # zs) \<longleftrightarrow> x \<le> y \<and> sorted (y # zs)"
haftmann@40096
   318
  by (auto intro: sorted_many elim: sorted.cases)
haftmann@40096
   319
haftmann@40096
   320
lemma [code]:
haftmann@40096
   321
  "sorted [] \<longleftrightarrow> True"
haftmann@40096
   322
  "sorted [x] \<longleftrightarrow> True"
haftmann@40096
   323
  by simp_all
nipkow@24697
   324
hoelzl@33639
   325
primrec insort_key :: "('b \<Rightarrow> 'a) \<Rightarrow> 'b \<Rightarrow> 'b list \<Rightarrow> 'b list" where
nipkow@51563
   326
"insort_key f x [] = [x]" |
nipkow@51563
   327
"insort_key f x (y#ys) =
nipkow@51563
   328
  (if f x \<le> f y then (x#y#ys) else y#(insort_key f x ys))"
hoelzl@33639
   329
haftmann@35195
   330
definition sort_key :: "('b \<Rightarrow> 'a) \<Rightarrow> 'b list \<Rightarrow> 'b list" where
nipkow@51563
   331
"sort_key f xs = foldr (insort_key f) xs []"
hoelzl@33639
   332
haftmann@40451
   333
definition insort_insert_key :: "('b \<Rightarrow> 'a) \<Rightarrow> 'b \<Rightarrow> 'b list \<Rightarrow> 'b list" where
nipkow@51563
   334
"insort_insert_key f x xs =
nipkow@51563
   335
  (if f x \<in> f ` set xs then xs else insort_key f x xs)"
haftmann@40451
   336
hoelzl@33639
   337
abbreviation "sort \<equiv> sort_key (\<lambda>x. x)"
hoelzl@33639
   338
abbreviation "insort \<equiv> insort_key (\<lambda>x. x)"
haftmann@40451
   339
abbreviation "insort_insert \<equiv> insort_insert_key (\<lambda>x. x)"
haftmann@35608
   340
wenzelm@25221
   341
end
wenzelm@25221
   342
nipkow@24616
   343
wenzelm@23388
   344
subsubsection {* List comprehension *}
nipkow@23192
   345
nipkow@24349
   346
text{* Input syntax for Haskell-like list comprehension notation.
nipkow@24349
   347
Typical example: @{text"[(x,y). x \<leftarrow> xs, y \<leftarrow> ys, x \<noteq> y]"},
nipkow@24349
   348
the list of all pairs of distinct elements from @{text xs} and @{text ys}.
nipkow@24349
   349
The syntax is as in Haskell, except that @{text"|"} becomes a dot
nipkow@24349
   350
(like in Isabelle's set comprehension): @{text"[e. x \<leftarrow> xs, \<dots>]"} rather than
nipkow@24349
   351
\verb![e| x <- xs, ...]!.
nipkow@24349
   352
nipkow@24349
   353
The qualifiers after the dot are
nipkow@24349
   354
\begin{description}
nipkow@24349
   355
\item[generators] @{text"p \<leftarrow> xs"},
nipkow@24476
   356
 where @{text p} is a pattern and @{text xs} an expression of list type, or
nipkow@24476
   357
\item[guards] @{text"b"}, where @{text b} is a boolean expression.
nipkow@24476
   358
%\item[local bindings] @ {text"let x = e"}.
nipkow@24349
   359
\end{description}
nipkow@23240
   360
nipkow@24476
   361
Just like in Haskell, list comprehension is just a shorthand. To avoid
nipkow@24476
   362
misunderstandings, the translation into desugared form is not reversed
nipkow@24476
   363
upon output. Note that the translation of @{text"[e. x \<leftarrow> xs]"} is
nipkow@24476
   364
optmized to @{term"map (%x. e) xs"}.
nipkow@23240
   365
nipkow@24349
   366
It is easy to write short list comprehensions which stand for complex
nipkow@24349
   367
expressions. During proofs, they may become unreadable (and
nipkow@24349
   368
mangled). In such cases it can be advisable to introduce separate
nipkow@24349
   369
definitions for the list comprehensions in question.  *}
nipkow@24349
   370
wenzelm@47009
   371
nonterminal lc_qual and lc_quals
nipkow@23192
   372
nipkow@23192
   373
syntax
wenzelm@47009
   374
  "_listcompr" :: "'a \<Rightarrow> lc_qual \<Rightarrow> lc_quals \<Rightarrow> 'a list"  ("[_ . __")
wenzelm@47009
   375
  "_lc_gen" :: "'a \<Rightarrow> 'a list \<Rightarrow> lc_qual"  ("_ <- _")
wenzelm@47009
   376
  "_lc_test" :: "bool \<Rightarrow> lc_qual" ("_")
wenzelm@47009
   377
  (*"_lc_let" :: "letbinds => lc_qual"  ("let _")*)
wenzelm@47009
   378
  "_lc_end" :: "lc_quals" ("]")
wenzelm@47009
   379
  "_lc_quals" :: "lc_qual \<Rightarrow> lc_quals \<Rightarrow> lc_quals"  (", __")
wenzelm@47009
   380
  "_lc_abs" :: "'a => 'b list => 'b list"
nipkow@23192
   381
nipkow@24476
   382
(* These are easier than ML code but cannot express the optimized
nipkow@24476
   383
   translation of [e. p<-xs]
nipkow@23192
   384
translations
wenzelm@47009
   385
  "[e. p<-xs]" => "concat(map (_lc_abs p [e]) xs)"
wenzelm@47009
   386
  "_listcompr e (_lc_gen p xs) (_lc_quals Q Qs)"
wenzelm@47009
   387
   => "concat (map (_lc_abs p (_listcompr e Q Qs)) xs)"
wenzelm@47009
   388
  "[e. P]" => "if P then [e] else []"
wenzelm@47009
   389
  "_listcompr e (_lc_test P) (_lc_quals Q Qs)"
wenzelm@47009
   390
   => "if P then (_listcompr e Q Qs) else []"
wenzelm@47009
   391
  "_listcompr e (_lc_let b) (_lc_quals Q Qs)"
wenzelm@47009
   392
   => "_Let b (_listcompr e Q Qs)"
nipkow@24476
   393
*)
nipkow@23240
   394
nipkow@23279
   395
syntax (xsymbols)
wenzelm@47009
   396
  "_lc_gen" :: "'a \<Rightarrow> 'a list \<Rightarrow> lc_qual"  ("_ \<leftarrow> _")
nipkow@23279
   397
syntax (HTML output)
wenzelm@47009
   398
  "_lc_gen" :: "'a \<Rightarrow> 'a list \<Rightarrow> lc_qual"  ("_ \<leftarrow> _")
nipkow@24349
   399
wenzelm@53280
   400
parse_translation {*
wenzelm@47009
   401
  let
wenzelm@47009
   402
    val NilC = Syntax.const @{const_syntax Nil};
wenzelm@47009
   403
    val ConsC = Syntax.const @{const_syntax Cons};
wenzelm@47009
   404
    val mapC = Syntax.const @{const_syntax map};
wenzelm@47009
   405
    val concatC = Syntax.const @{const_syntax concat};
wenzelm@47009
   406
    val IfC = Syntax.const @{const_syntax If};
wenzelm@47009
   407
wenzelm@47009
   408
    fun single x = ConsC $ x $ NilC;
wenzelm@47009
   409
wenzelm@47009
   410
    fun pat_tr ctxt p e opti = (* %x. case x of p => e | _ => [] *)
wenzelm@47009
   411
      let
wenzelm@47009
   412
        (* FIXME proper name context!? *)
wenzelm@47009
   413
        val x =
wenzelm@47009
   414
          Free (singleton (Name.variant_list (fold Term.add_free_names [p, e] [])) "x", dummyT);
wenzelm@47009
   415
        val e = if opti then single e else e;
wenzelm@47009
   416
        val case1 = Syntax.const @{syntax_const "_case1"} $ p $ e;
wenzelm@47009
   417
        val case2 =
wenzelm@47009
   418
          Syntax.const @{syntax_const "_case1"} $
wenzelm@47009
   419
            Syntax.const @{const_syntax dummy_pattern} $ NilC;
wenzelm@47009
   420
        val cs = Syntax.const @{syntax_const "_case2"} $ case1 $ case2;
traytel@52815
   421
      in Syntax_Trans.abs_tr [x, Case_Translation.case_tr false ctxt [x, cs]] end;
wenzelm@47009
   422
wenzelm@47009
   423
    fun abs_tr ctxt p e opti =
wenzelm@47009
   424
      (case Term_Position.strip_positions p of
wenzelm@47009
   425
        Free (s, T) =>
wenzelm@47009
   426
          let
wenzelm@47009
   427
            val thy = Proof_Context.theory_of ctxt;
wenzelm@47009
   428
            val s' = Proof_Context.intern_const ctxt s;
wenzelm@47009
   429
          in
wenzelm@47009
   430
            if Sign.declared_const thy s'
wenzelm@47009
   431
            then (pat_tr ctxt p e opti, false)
wenzelm@47009
   432
            else (Syntax_Trans.abs_tr [p, e], true)
wenzelm@47009
   433
          end
wenzelm@47009
   434
      | _ => (pat_tr ctxt p e opti, false));
wenzelm@47009
   435
wenzelm@47009
   436
    fun lc_tr ctxt [e, Const (@{syntax_const "_lc_test"}, _) $ b, qs] =
wenzelm@47009
   437
          let
wenzelm@47009
   438
            val res =
wenzelm@47009
   439
              (case qs of
wenzelm@47009
   440
                Const (@{syntax_const "_lc_end"}, _) => single e
wenzelm@47009
   441
              | Const (@{syntax_const "_lc_quals"}, _) $ q $ qs => lc_tr ctxt [e, q, qs]);
wenzelm@47009
   442
          in IfC $ b $ res $ NilC end
wenzelm@47009
   443
      | lc_tr ctxt
wenzelm@47009
   444
            [e, Const (@{syntax_const "_lc_gen"}, _) $ p $ es,
wenzelm@47009
   445
              Const(@{syntax_const "_lc_end"}, _)] =
wenzelm@47009
   446
          (case abs_tr ctxt p e true of
wenzelm@47009
   447
            (f, true) => mapC $ f $ es
wenzelm@47009
   448
          | (f, false) => concatC $ (mapC $ f $ es))
wenzelm@47009
   449
      | lc_tr ctxt
wenzelm@47009
   450
            [e, Const (@{syntax_const "_lc_gen"}, _) $ p $ es,
wenzelm@47009
   451
              Const (@{syntax_const "_lc_quals"}, _) $ q $ qs] =
wenzelm@47009
   452
          let val e' = lc_tr ctxt [e, q, qs];
wenzelm@47009
   453
          in concatC $ (mapC $ (fst (abs_tr ctxt p e' false)) $ es) end;
wenzelm@47009
   454
wenzelm@47009
   455
  in [(@{syntax_const "_listcompr"}, lc_tr)] end
nipkow@24349
   456
*}
nipkow@23279
   457
wenzelm@52409
   458
ML_val {*
wenzelm@43038
   459
  let
wenzelm@43038
   460
    val read = Syntax.read_term @{context};
wenzelm@43038
   461
    fun check s1 s2 = read s1 aconv read s2 orelse error ("Check failed: " ^ quote s1);
wenzelm@43038
   462
  in
wenzelm@43038
   463
    check "[(x,y,z). b]" "if b then [(x, y, z)] else []";
wenzelm@43038
   464
    check "[(x,y,z). x\<leftarrow>xs]" "map (\<lambda>x. (x, y, z)) xs";
wenzelm@43038
   465
    check "[e x y. x\<leftarrow>xs, y\<leftarrow>ys]" "concat (map (\<lambda>x. map (\<lambda>y. e x y) ys) xs)";
wenzelm@43038
   466
    check "[(x,y,z). x<a, x>b]" "if x < a then if b < x then [(x, y, z)] else [] else []";
wenzelm@43038
   467
    check "[(x,y,z). x\<leftarrow>xs, x>b]" "concat (map (\<lambda>x. if b < x then [(x, y, z)] else []) xs)";
wenzelm@43038
   468
    check "[(x,y,z). x<a, x\<leftarrow>xs]" "if x < a then map (\<lambda>x. (x, y, z)) xs else []";
wenzelm@43038
   469
    check "[(x,y). Cons True x \<leftarrow> xs]"
wenzelm@43038
   470
      "concat (map (\<lambda>xa. case xa of [] \<Rightarrow> [] | True # x \<Rightarrow> [(x, y)] | False # x \<Rightarrow> []) xs)";
wenzelm@43038
   471
    check "[(x,y,z). Cons x [] \<leftarrow> xs]"
wenzelm@43038
   472
      "concat (map (\<lambda>xa. case xa of [] \<Rightarrow> [] | [x] \<Rightarrow> [(x, y, z)] | x # aa # lista \<Rightarrow> []) xs)";
wenzelm@43038
   473
    check "[(x,y,z). x<a, x>b, x=d]"
wenzelm@43038
   474
      "if x < a then if b < x then if x = d then [(x, y, z)] else [] else [] else []";
wenzelm@43038
   475
    check "[(x,y,z). x<a, x>b, y\<leftarrow>ys]"
wenzelm@43038
   476
      "if x < a then if b < x then map (\<lambda>y. (x, y, z)) ys else [] else []";
wenzelm@43038
   477
    check "[(x,y,z). x<a, x\<leftarrow>xs,y>b]"
wenzelm@43038
   478
      "if x < a then concat (map (\<lambda>x. if b < y then [(x, y, z)] else []) xs) else []";
wenzelm@43038
   479
    check "[(x,y,z). x<a, x\<leftarrow>xs, y\<leftarrow>ys]"
wenzelm@43038
   480
      "if x < a then concat (map (\<lambda>x. map (\<lambda>y. (x, y, z)) ys) xs) else []";
wenzelm@43038
   481
    check "[(x,y,z). x\<leftarrow>xs, x>b, y<a]"
wenzelm@43038
   482
      "concat (map (\<lambda>x. if b < x then if y < a then [(x, y, z)] else [] else []) xs)";
wenzelm@43038
   483
    check "[(x,y,z). x\<leftarrow>xs, x>b, y\<leftarrow>ys]"
wenzelm@43038
   484
      "concat (map (\<lambda>x. if b < x then map (\<lambda>y. (x, y, z)) ys else []) xs)";
wenzelm@43038
   485
    check "[(x,y,z). x\<leftarrow>xs, y\<leftarrow>ys,y>x]"
wenzelm@43038
   486
      "concat (map (\<lambda>x. concat (map (\<lambda>y. if x < y then [(x, y, z)] else []) ys)) xs)";
wenzelm@43038
   487
    check "[(x,y,z). x\<leftarrow>xs, y\<leftarrow>ys,z\<leftarrow>zs]"
wenzelm@43038
   488
      "concat (map (\<lambda>x. concat (map (\<lambda>y. map (\<lambda>z. (x, y, z)) zs) ys)) xs)"
wenzelm@43038
   489
  end;
wenzelm@43038
   490
*}
wenzelm@43038
   491
wenzelm@35118
   492
(*
nipkow@24349
   493
term "[(x,y). x\<leftarrow>xs, let xx = x+x, y\<leftarrow>ys, y \<noteq> xx]"
nipkow@23192
   494
*)
nipkow@23192
   495
wenzelm@43038
   496
wenzelm@51437
   497
ML {*
wenzelm@51437
   498
(* Simproc for rewriting list comprehensions applied to List.set to set
wenzelm@51437
   499
   comprehension. *)
wenzelm@51437
   500
wenzelm@51437
   501
signature LIST_TO_SET_COMPREHENSION =
wenzelm@51437
   502
sig
wenzelm@52854
   503
  val simproc : Proof.context -> cterm -> thm option
wenzelm@51437
   504
end
wenzelm@51437
   505
wenzelm@51437
   506
structure List_to_Set_Comprehension : LIST_TO_SET_COMPREHENSION =
wenzelm@51437
   507
struct
wenzelm@51437
   508
wenzelm@51437
   509
(* conversion *)
wenzelm@51437
   510
wenzelm@51437
   511
fun all_exists_conv cv ctxt ct =
wenzelm@51437
   512
  (case Thm.term_of ct of
wenzelm@51437
   513
    Const (@{const_name HOL.Ex}, _) $ Abs _ =>
wenzelm@51437
   514
      Conv.arg_conv (Conv.abs_conv (all_exists_conv cv o #2) ctxt) ct
wenzelm@51437
   515
  | _ => cv ctxt ct)
wenzelm@51437
   516
wenzelm@51437
   517
fun all_but_last_exists_conv cv ctxt ct =
wenzelm@51437
   518
  (case Thm.term_of ct of
wenzelm@51437
   519
    Const (@{const_name HOL.Ex}, _) $ Abs (_, _, Const (@{const_name HOL.Ex}, _) $ _) =>
wenzelm@51437
   520
      Conv.arg_conv (Conv.abs_conv (all_but_last_exists_conv cv o #2) ctxt) ct
wenzelm@51437
   521
  | _ => cv ctxt ct)
wenzelm@51437
   522
wenzelm@51437
   523
fun Collect_conv cv ctxt ct =
wenzelm@51437
   524
  (case Thm.term_of ct of
wenzelm@51437
   525
    Const (@{const_name Set.Collect}, _) $ Abs _ => Conv.arg_conv (Conv.abs_conv cv ctxt) ct
wenzelm@51437
   526
  | _ => raise CTERM ("Collect_conv", [ct]))
wenzelm@51437
   527
wenzelm@51437
   528
fun rewr_conv' th = Conv.rewr_conv (mk_meta_eq th)
wenzelm@51437
   529
wenzelm@51437
   530
fun conjunct_assoc_conv ct =
wenzelm@51437
   531
  Conv.try_conv
wenzelm@52452
   532
    (rewr_conv' @{thm conj_assoc} then_conv HOLogic.conj_conv Conv.all_conv conjunct_assoc_conv) ct
wenzelm@51437
   533
wenzelm@51437
   534
fun right_hand_set_comprehension_conv conv ctxt =
wenzelm@52452
   535
  HOLogic.Trueprop_conv (HOLogic.eq_conv Conv.all_conv
wenzelm@51437
   536
    (Collect_conv (all_exists_conv conv o #2) ctxt))
wenzelm@51437
   537
wenzelm@51437
   538
wenzelm@51437
   539
(* term abstraction of list comprehension patterns *)
wenzelm@51437
   540
wenzelm@51437
   541
datatype termlets = If | Case of (typ * int)
wenzelm@51437
   542
wenzelm@52854
   543
fun simproc ctxt redex =
wenzelm@51437
   544
  let
wenzelm@51437
   545
    val set_Nil_I = @{thm trans} OF [@{thm set.simps(1)}, @{thm empty_def}]
wenzelm@51437
   546
    val set_singleton = @{lemma "set [a] = {x. x = a}" by simp}
wenzelm@51437
   547
    val inst_Collect_mem_eq = @{lemma "set A = {x. x : set A}" by simp}
wenzelm@51437
   548
    val del_refl_eq = @{lemma "(t = t & P) == P" by simp}
wenzelm@51437
   549
    fun mk_set T = Const (@{const_name List.set}, HOLogic.listT T --> HOLogic.mk_setT T)
wenzelm@51437
   550
    fun dest_set (Const (@{const_name List.set}, _) $ xs) = xs
wenzelm@51437
   551
    fun dest_singleton_list (Const (@{const_name List.Cons}, _)
wenzelm@51437
   552
          $ t $ (Const (@{const_name List.Nil}, _))) = t
wenzelm@51437
   553
      | dest_singleton_list t = raise TERM ("dest_singleton_list", [t])
wenzelm@51437
   554
    (* We check that one case returns a singleton list and all other cases
wenzelm@51437
   555
       return [], and return the index of the one singleton list case *)
wenzelm@51437
   556
    fun possible_index_of_singleton_case cases =
wenzelm@51437
   557
      let
wenzelm@51437
   558
        fun check (i, case_t) s =
wenzelm@51437
   559
          (case strip_abs_body case_t of
wenzelm@51437
   560
            (Const (@{const_name List.Nil}, _)) => s
traytel@54549
   561
          | _ => (case s of SOME NONE => SOME (SOME i) | _ => NONE))
wenzelm@51437
   562
      in
traytel@54549
   563
        fold_index check cases (SOME NONE) |> the_default NONE
wenzelm@51437
   564
      end
blanchet@55777
   565
    (* returns (case_expr type index chosen_case constr_name) option  *)
wenzelm@51437
   566
    fun dest_case case_term =
wenzelm@51437
   567
      let
wenzelm@51437
   568
        val (case_const, args) = strip_comb case_term
wenzelm@51437
   569
      in
wenzelm@51437
   570
        (case try dest_Const case_const of
wenzelm@51437
   571
          SOME (c, T) =>
blanchet@55777
   572
            (case Ctr_Sugar.ctr_sugar_of_case ctxt c of
blanchet@55777
   573
              SOME {ctrs, ...} =>
wenzelm@51437
   574
                (case possible_index_of_singleton_case (fst (split_last args)) of
wenzelm@51437
   575
                  SOME i =>
wenzelm@51437
   576
                    let
blanchet@55777
   577
                      val constr_names = map (fst o dest_Const) ctrs
wenzelm@51437
   578
                      val (Ts, _) = strip_type T
wenzelm@51437
   579
                      val T' = List.last Ts
blanchet@55777
   580
                    in SOME (List.last args, T', i, nth args i, nth constr_names i) end
wenzelm@51437
   581
                | NONE => NONE)
wenzelm@51437
   582
            | NONE => NONE)
wenzelm@51437
   583
        | NONE => NONE)
wenzelm@51437
   584
      end
wenzelm@51437
   585
    (* returns condition continuing term option *)
wenzelm@51437
   586
    fun dest_if (Const (@{const_name If}, _) $ cond $ then_t $ Const (@{const_name Nil}, _)) =
wenzelm@51437
   587
          SOME (cond, then_t)
wenzelm@51437
   588
      | dest_if _ = NONE
wenzelm@51437
   589
    fun tac _ [] = rtac set_singleton 1 ORELSE rtac inst_Collect_mem_eq 1
wenzelm@51437
   590
      | tac ctxt (If :: cont) =
wenzelm@51437
   591
          Splitter.split_tac [@{thm split_if}] 1
wenzelm@51437
   592
          THEN rtac @{thm conjI} 1
wenzelm@51437
   593
          THEN rtac @{thm impI} 1
wenzelm@51437
   594
          THEN Subgoal.FOCUS (fn {prems, context, ...} =>
wenzelm@51437
   595
            CONVERSION (right_hand_set_comprehension_conv (K
wenzelm@52452
   596
              (HOLogic.conj_conv (Conv.rewr_conv (List.last prems RS @{thm Eq_TrueI})) Conv.all_conv
wenzelm@51437
   597
               then_conv
wenzelm@51437
   598
               rewr_conv' @{lemma "(True & P) = P" by simp})) context) 1) ctxt 1
wenzelm@51437
   599
          THEN tac ctxt cont
wenzelm@51437
   600
          THEN rtac @{thm impI} 1
wenzelm@51437
   601
          THEN Subgoal.FOCUS (fn {prems, context, ...} =>
wenzelm@51437
   602
              CONVERSION (right_hand_set_comprehension_conv (K
wenzelm@52452
   603
                (HOLogic.conj_conv (Conv.rewr_conv (List.last prems RS @{thm Eq_FalseI})) Conv.all_conv
wenzelm@51437
   604
                 then_conv rewr_conv' @{lemma "(False & P) = False" by simp})) context) 1) ctxt 1
wenzelm@51437
   605
          THEN rtac set_Nil_I 1
wenzelm@51437
   606
      | tac ctxt (Case (T, i) :: cont) =
wenzelm@51437
   607
          let
blanchet@55777
   608
            val SOME {injects, distincts, case_thms, split, ...} =
blanchet@55777
   609
              Ctr_Sugar.ctr_sugar_of ctxt (fst (dest_Type T))
wenzelm@51437
   610
          in
wenzelm@51437
   611
            (* do case distinction *)
blanchet@55777
   612
            Splitter.split_tac [split] 1
wenzelm@51437
   613
            THEN EVERY (map_index (fn (i', _) =>
blanchet@55777
   614
              (if i' < length case_thms - 1 then rtac @{thm conjI} 1 else all_tac)
wenzelm@51437
   615
              THEN REPEAT_DETERM (rtac @{thm allI} 1)
wenzelm@51437
   616
              THEN rtac @{thm impI} 1
wenzelm@51437
   617
              THEN (if i' = i then
wenzelm@51437
   618
                (* continue recursively *)
wenzelm@51437
   619
                Subgoal.FOCUS (fn {prems, context, ...} =>
wenzelm@51437
   620
                  CONVERSION (Thm.eta_conversion then_conv right_hand_set_comprehension_conv (K
wenzelm@52452
   621
                      ((HOLogic.conj_conv
wenzelm@52452
   622
                        (HOLogic.eq_conv Conv.all_conv (rewr_conv' (List.last prems)) then_conv
blanchet@55777
   623
                          (Conv.try_conv (Conv.rewrs_conv (map mk_meta_eq injects))))
wenzelm@51437
   624
                        Conv.all_conv)
wenzelm@51437
   625
                        then_conv (Conv.try_conv (Conv.rewr_conv del_refl_eq))
wenzelm@51437
   626
                        then_conv conjunct_assoc_conv)) context
wenzelm@52452
   627
                    then_conv (HOLogic.Trueprop_conv (HOLogic.eq_conv Conv.all_conv (Collect_conv (fn (_, ctxt) =>
wenzelm@51437
   628
                      Conv.repeat_conv
wenzelm@51437
   629
                        (all_but_last_exists_conv
wenzelm@51437
   630
                          (K (rewr_conv'
wenzelm@51437
   631
                            @{lemma "(EX x. x = t & P x) = P t" by simp})) ctxt)) context)))) 1) ctxt 1
wenzelm@51437
   632
                THEN tac ctxt cont
wenzelm@51437
   633
              else
wenzelm@51437
   634
                Subgoal.FOCUS (fn {prems, context, ...} =>
wenzelm@51437
   635
                  CONVERSION
wenzelm@51437
   636
                    (right_hand_set_comprehension_conv (K
wenzelm@52452
   637
                      (HOLogic.conj_conv
wenzelm@52452
   638
                        ((HOLogic.eq_conv Conv.all_conv
wenzelm@51437
   639
                          (rewr_conv' (List.last prems))) then_conv
blanchet@55777
   640
                          (Conv.rewrs_conv (map (fn th => th RS @{thm Eq_FalseI}) distincts)))
wenzelm@51437
   641
                        Conv.all_conv then_conv
wenzelm@51437
   642
                        (rewr_conv' @{lemma "(False & P) = False" by simp}))) context then_conv
wenzelm@52451
   643
                      HOLogic.Trueprop_conv
wenzelm@52452
   644
                        (HOLogic.eq_conv Conv.all_conv
wenzelm@51437
   645
                          (Collect_conv (fn (_, ctxt) =>
wenzelm@51437
   646
                            Conv.repeat_conv
wenzelm@51437
   647
                              (Conv.bottom_conv
wenzelm@51437
   648
                                (K (rewr_conv'
wenzelm@51437
   649
                                  @{lemma "(EX x. P) = P" by simp})) ctxt)) context))) 1) ctxt 1
blanchet@55777
   650
                THEN rtac set_Nil_I 1)) case_thms)
wenzelm@51437
   651
          end
wenzelm@51437
   652
    fun make_inner_eqs bound_vs Tis eqs t =
wenzelm@51437
   653
      (case dest_case t of
blanchet@55777
   654
        SOME (x, T, i, cont, constr_name) =>
wenzelm@51437
   655
          let
wenzelm@53268
   656
            val (vs, body) = strip_abs (Envir.eta_long (map snd bound_vs) cont)
wenzelm@51437
   657
            val x' = incr_boundvars (length vs) x
wenzelm@51437
   658
            val eqs' = map (incr_boundvars (length vs)) eqs
wenzelm@51437
   659
            val constr_t =
wenzelm@51437
   660
              list_comb
wenzelm@51437
   661
                (Const (constr_name, map snd vs ---> T), map Bound (((length vs) - 1) downto 0))
wenzelm@51437
   662
            val constr_eq = Const (@{const_name HOL.eq}, T --> T --> @{typ bool}) $ constr_t $ x'
wenzelm@51437
   663
          in
wenzelm@51437
   664
            make_inner_eqs (rev vs @ bound_vs) (Case (T, i) :: Tis) (constr_eq :: eqs') body
wenzelm@51437
   665
          end
wenzelm@51437
   666
      | NONE =>
wenzelm@51437
   667
          (case dest_if t of
wenzelm@51437
   668
            SOME (condition, cont) => make_inner_eqs bound_vs (If :: Tis) (condition :: eqs) cont
wenzelm@51437
   669
          | NONE =>
wenzelm@51437
   670
            if eqs = [] then NONE (* no rewriting, nothing to be done *)
wenzelm@51437
   671
            else
wenzelm@51437
   672
              let
wenzelm@51437
   673
                val Type (@{type_name List.list}, [rT]) = fastype_of1 (map snd bound_vs, t)
wenzelm@51437
   674
                val pat_eq =
wenzelm@51437
   675
                  (case try dest_singleton_list t of
wenzelm@51437
   676
                    SOME t' =>
wenzelm@51437
   677
                      Const (@{const_name HOL.eq}, rT --> rT --> @{typ bool}) $
wenzelm@51437
   678
                        Bound (length bound_vs) $ t'
wenzelm@51437
   679
                  | NONE =>
wenzelm@51437
   680
                      Const (@{const_name Set.member}, rT --> HOLogic.mk_setT rT --> @{typ bool}) $
wenzelm@51437
   681
                        Bound (length bound_vs) $ (mk_set rT $ t))
wenzelm@51437
   682
                val reverse_bounds = curry subst_bounds
wenzelm@51437
   683
                  ((map Bound ((length bound_vs - 1) downto 0)) @ [Bound (length bound_vs)])
wenzelm@51437
   684
                val eqs' = map reverse_bounds eqs
wenzelm@51437
   685
                val pat_eq' = reverse_bounds pat_eq
wenzelm@51437
   686
                val inner_t =
wenzelm@51437
   687
                  fold (fn (_, T) => fn t => HOLogic.exists_const T $ absdummy T t)
wenzelm@51437
   688
                    (rev bound_vs) (fold (curry HOLogic.mk_conj) eqs' pat_eq')
wenzelm@51437
   689
                val lhs = term_of redex
wenzelm@51437
   690
                val rhs = HOLogic.mk_Collect ("x", rT, inner_t)
wenzelm@51437
   691
                val rewrite_rule_t = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs))
wenzelm@51437
   692
              in
wenzelm@51437
   693
                SOME
wenzelm@51437
   694
                  ((Goal.prove ctxt [] [] rewrite_rule_t
wenzelm@51437
   695
                    (fn {context, ...} => tac context (rev Tis))) RS @{thm eq_reflection})
wenzelm@51437
   696
              end))
wenzelm@51437
   697
  in
wenzelm@51437
   698
    make_inner_eqs [] [] [] (dest_set (term_of redex))
wenzelm@51437
   699
  end
wenzelm@51437
   700
wenzelm@51437
   701
end
wenzelm@51437
   702
*}
bulwahn@41695
   703
bulwahn@41695
   704
simproc_setup list_to_set_comprehension ("set xs") = {* K List_to_Set_Comprehension.simproc *}
bulwahn@41695
   705
haftmann@47004
   706
code_datatype set coset
haftmann@47004
   707
haftmann@47004
   708
hide_const (open) coset
wenzelm@35118
   709
haftmann@50963
   710
haftmann@21061
   711
subsubsection {* @{const Nil} and @{const Cons} *}
haftmann@21061
   712
haftmann@21061
   713
lemma not_Cons_self [simp]:
haftmann@21061
   714
  "xs \<noteq> x # xs"
nipkow@13145
   715
by (induct xs) auto
nipkow@3507
   716
wenzelm@42571
   717
lemma not_Cons_self2 [simp]:
wenzelm@42571
   718
  "x # xs \<noteq> xs"
wenzelm@42571
   719
by (rule not_Cons_self [symmetric])
wenzelm@13114
   720
wenzelm@13142
   721
lemma neq_Nil_conv: "(xs \<noteq> []) = (\<exists>y ys. xs = y # ys)"
nipkow@13145
   722
by (induct xs) auto
wenzelm@13114
   723
nipkow@54826
   724
lemma tl_Nil: "tl xs = [] \<longleftrightarrow> xs = [] \<or> (EX x. xs = [x])"
nipkow@54826
   725
by (cases xs) auto
nipkow@54826
   726
nipkow@54826
   727
lemma Nil_tl: "[] = tl xs \<longleftrightarrow> xs = [] \<or> (EX x. xs = [x])"
nipkow@54826
   728
by (cases xs) auto
nipkow@54826
   729
wenzelm@13142
   730
lemma length_induct:
haftmann@21061
   731
  "(\<And>xs. \<forall>ys. length ys < length xs \<longrightarrow> P ys \<Longrightarrow> P xs) \<Longrightarrow> P xs"
nipkow@54826
   732
by (fact measure_induct)
wenzelm@13114
   733
haftmann@37289
   734
lemma list_nonempty_induct [consumes 1, case_names single cons]:
haftmann@37289
   735
  assumes "xs \<noteq> []"
haftmann@37289
   736
  assumes single: "\<And>x. P [x]"
haftmann@37289
   737
  assumes cons: "\<And>x xs. xs \<noteq> [] \<Longrightarrow> P xs \<Longrightarrow> P (x # xs)"
haftmann@37289
   738
  shows "P xs"
haftmann@37289
   739
using `xs \<noteq> []` proof (induct xs)
haftmann@37289
   740
  case Nil then show ?case by simp
haftmann@37289
   741
next
wenzelm@54511
   742
  case (Cons x xs)
wenzelm@54511
   743
  show ?case
wenzelm@54511
   744
  proof (cases xs)
wenzelm@54511
   745
    case Nil
wenzelm@54511
   746
    with single show ?thesis by simp
haftmann@37289
   747
  next
wenzelm@54511
   748
    case Cons
wenzelm@54511
   749
    show ?thesis
wenzelm@54511
   750
    proof (rule cons)
wenzelm@54511
   751
      from Cons show "xs \<noteq> []" by simp
wenzelm@54511
   752
      with Cons.hyps show "P xs" .
wenzelm@54511
   753
    qed
haftmann@37289
   754
  qed
haftmann@37289
   755
qed
haftmann@37289
   756
hoelzl@46584
   757
lemma inj_split_Cons: "inj_on (\<lambda>(xs, n). n#xs) X"
hoelzl@46584
   758
  by (auto intro!: inj_onI)
wenzelm@13114
   759
haftmann@50963
   760
haftmann@21061
   761
subsubsection {* @{const length} *}
wenzelm@13114
   762
wenzelm@13142
   763
text {*
haftmann@21061
   764
  Needs to come before @{text "@"} because of theorem @{text
haftmann@21061
   765
  append_eq_append_conv}.
wenzelm@13142
   766
*}
wenzelm@13114
   767
wenzelm@13142
   768
lemma length_append [simp]: "length (xs @ ys) = length xs + length ys"
nipkow@13145
   769
by (induct xs) auto
wenzelm@13114
   770
wenzelm@13142
   771
lemma length_map [simp]: "length (map f xs) = length xs"
nipkow@13145
   772
by (induct xs) auto
wenzelm@13114
   773
wenzelm@13142
   774
lemma length_rev [simp]: "length (rev xs) = length xs"
nipkow@13145
   775
by (induct xs) auto
wenzelm@13114
   776
wenzelm@13142
   777
lemma length_tl [simp]: "length (tl xs) = length xs - 1"
nipkow@13145
   778
by (cases xs) auto
wenzelm@13142
   779
wenzelm@13142
   780
lemma length_0_conv [iff]: "(length xs = 0) = (xs = [])"
nipkow@13145
   781
by (induct xs) auto
wenzelm@13142
   782
wenzelm@13142
   783
lemma length_greater_0_conv [iff]: "(0 < length xs) = (xs \<noteq> [])"
nipkow@13145
   784
by (induct xs) auto
wenzelm@13114
   785
nipkow@23479
   786
lemma length_pos_if_in_set: "x : set xs \<Longrightarrow> length xs > 0"
nipkow@23479
   787
by auto
nipkow@23479
   788
wenzelm@13114
   789
lemma length_Suc_conv:
nipkow@13145
   790
"(length xs = Suc n) = (\<exists>y ys. xs = y # ys \<and> length ys = n)"
nipkow@13145
   791
by (induct xs) auto
wenzelm@13114
   792
nipkow@14025
   793
lemma Suc_length_conv:
nipkow@14025
   794
"(Suc n = length xs) = (\<exists>y ys. xs = y # ys \<and> length ys = n)"
paulson@14208
   795
apply (induct xs, simp, simp)
nipkow@14025
   796
apply blast
nipkow@14025
   797
done
nipkow@14025
   798
wenzelm@25221
   799
lemma impossible_Cons: "length xs <= length ys ==> xs = x # ys = False"
wenzelm@25221
   800
  by (induct xs) auto
wenzelm@25221
   801
haftmann@26442
   802
lemma list_induct2 [consumes 1, case_names Nil Cons]:
haftmann@26442
   803
  "length xs = length ys \<Longrightarrow> P [] [] \<Longrightarrow>
haftmann@26442
   804
   (\<And>x xs y ys. length xs = length ys \<Longrightarrow> P xs ys \<Longrightarrow> P (x#xs) (y#ys))
haftmann@26442
   805
   \<Longrightarrow> P xs ys"
haftmann@26442
   806
proof (induct xs arbitrary: ys)
haftmann@26442
   807
  case Nil then show ?case by simp
haftmann@26442
   808
next
haftmann@26442
   809
  case (Cons x xs ys) then show ?case by (cases ys) simp_all
haftmann@26442
   810
qed
haftmann@26442
   811
haftmann@26442
   812
lemma list_induct3 [consumes 2, case_names Nil Cons]:
haftmann@26442
   813
  "length xs = length ys \<Longrightarrow> length ys = length zs \<Longrightarrow> P [] [] [] \<Longrightarrow>
haftmann@26442
   814
   (\<And>x xs y ys z zs. length xs = length ys \<Longrightarrow> length ys = length zs \<Longrightarrow> P xs ys zs \<Longrightarrow> P (x#xs) (y#ys) (z#zs))
haftmann@26442
   815
   \<Longrightarrow> P xs ys zs"
haftmann@26442
   816
proof (induct xs arbitrary: ys zs)
haftmann@26442
   817
  case Nil then show ?case by simp
haftmann@26442
   818
next
haftmann@26442
   819
  case (Cons x xs ys zs) then show ?case by (cases ys, simp_all)
haftmann@26442
   820
    (cases zs, simp_all)
haftmann@26442
   821
qed
wenzelm@13114
   822
kaliszyk@36148
   823
lemma list_induct4 [consumes 3, case_names Nil Cons]:
kaliszyk@36148
   824
  "length xs = length ys \<Longrightarrow> length ys = length zs \<Longrightarrow> length zs = length ws \<Longrightarrow>
kaliszyk@36148
   825
   P [] [] [] [] \<Longrightarrow> (\<And>x xs y ys z zs w ws. length xs = length ys \<Longrightarrow>
kaliszyk@36148
   826
   length ys = length zs \<Longrightarrow> length zs = length ws \<Longrightarrow> P xs ys zs ws \<Longrightarrow>
kaliszyk@36148
   827
   P (x#xs) (y#ys) (z#zs) (w#ws)) \<Longrightarrow> P xs ys zs ws"
kaliszyk@36148
   828
proof (induct xs arbitrary: ys zs ws)
kaliszyk@36148
   829
  case Nil then show ?case by simp
kaliszyk@36148
   830
next
kaliszyk@36148
   831
  case (Cons x xs ys zs ws) then show ?case by ((cases ys, simp_all), (cases zs,simp_all)) (cases ws, simp_all)
kaliszyk@36148
   832
qed
kaliszyk@36148
   833
krauss@22493
   834
lemma list_induct2': 
krauss@22493
   835
  "\<lbrakk> P [] [];
krauss@22493
   836
  \<And>x xs. P (x#xs) [];
krauss@22493
   837
  \<And>y ys. P [] (y#ys);
krauss@22493
   838
   \<And>x xs y ys. P xs ys  \<Longrightarrow> P (x#xs) (y#ys) \<rbrakk>
krauss@22493
   839
 \<Longrightarrow> P xs ys"
krauss@22493
   840
by (induct xs arbitrary: ys) (case_tac x, auto)+
krauss@22493
   841
nipkow@22143
   842
lemma neq_if_length_neq: "length xs \<noteq> length ys \<Longrightarrow> (xs = ys) == False"
nipkow@24349
   843
by (rule Eq_FalseI) auto
wenzelm@24037
   844
wenzelm@24037
   845
simproc_setup list_neq ("(xs::'a list) = ys") = {*
nipkow@22143
   846
(*
nipkow@22143
   847
Reduces xs=ys to False if xs and ys cannot be of the same length.
nipkow@22143
   848
This is the case if the atomic sublists of one are a submultiset
nipkow@22143
   849
of those of the other list and there are fewer Cons's in one than the other.
nipkow@22143
   850
*)
wenzelm@24037
   851
wenzelm@24037
   852
let
nipkow@22143
   853
huffman@29793
   854
fun len (Const(@{const_name Nil},_)) acc = acc
huffman@29793
   855
  | len (Const(@{const_name Cons},_) $ _ $ xs) (ts,n) = len xs (ts,n+1)
huffman@29793
   856
  | len (Const(@{const_name append},_) $ xs $ ys) acc = len xs (len ys acc)
huffman@29793
   857
  | len (Const(@{const_name rev},_) $ xs) acc = len xs acc
huffman@29793
   858
  | len (Const(@{const_name map},_) $ _ $ xs) acc = len xs acc
nipkow@22143
   859
  | len t (ts,n) = (t::ts,n);
nipkow@22143
   860
wenzelm@52854
   861
val ss = simpset_of @{context};
wenzelm@52854
   862
wenzelm@52854
   863
fun list_neq ctxt ct =
nipkow@22143
   864
  let
wenzelm@24037
   865
    val (Const(_,eqT) $ lhs $ rhs) = Thm.term_of ct;
nipkow@22143
   866
    val (ls,m) = len lhs ([],0) and (rs,n) = len rhs ([],0);
nipkow@22143
   867
    fun prove_neq() =
nipkow@22143
   868
      let
nipkow@22143
   869
        val Type(_,listT::_) = eqT;
haftmann@22994
   870
        val size = HOLogic.size_const listT;
nipkow@22143
   871
        val eq_len = HOLogic.mk_eq (size $ lhs, size $ rhs);
nipkow@22143
   872
        val neq_len = HOLogic.mk_Trueprop (HOLogic.Not $ eq_len);
wenzelm@52854
   873
        val thm = Goal.prove ctxt [] [] neq_len
wenzelm@52854
   874
          (K (simp_tac (put_simpset ss ctxt) 1));
haftmann@22633
   875
      in SOME (thm RS @{thm neq_if_length_neq}) end
nipkow@22143
   876
  in
wenzelm@23214
   877
    if m < n andalso submultiset (op aconv) (ls,rs) orelse
wenzelm@23214
   878
       n < m andalso submultiset (op aconv) (rs,ls)
nipkow@22143
   879
    then prove_neq() else NONE
nipkow@22143
   880
  end;
wenzelm@52854
   881
in K list_neq end;
nipkow@22143
   882
*}
nipkow@22143
   883
nipkow@22143
   884
nipkow@15392
   885
subsubsection {* @{text "@"} -- append *}
wenzelm@13114
   886
wenzelm@13142
   887
lemma append_assoc [simp]: "(xs @ ys) @ zs = xs @ (ys @ zs)"
nipkow@13145
   888
by (induct xs) auto
wenzelm@13114
   889
wenzelm@13142
   890
lemma append_Nil2 [simp]: "xs @ [] = xs"
nipkow@13145
   891
by (induct xs) auto
wenzelm@13114
   892
wenzelm@13142
   893
lemma append_is_Nil_conv [iff]: "(xs @ ys = []) = (xs = [] \<and> ys = [])"
nipkow@13145
   894
by (induct xs) auto
wenzelm@13114
   895
wenzelm@13142
   896
lemma Nil_is_append_conv [iff]: "([] = xs @ ys) = (xs = [] \<and> ys = [])"
nipkow@13145
   897
by (induct xs) auto
wenzelm@13114
   898
wenzelm@13142
   899
lemma append_self_conv [iff]: "(xs @ ys = xs) = (ys = [])"
nipkow@13145
   900
by (induct xs) auto
wenzelm@13114
   901
wenzelm@13142
   902
lemma self_append_conv [iff]: "(xs = xs @ ys) = (ys = [])"
nipkow@13145
   903
by (induct xs) auto
wenzelm@13114
   904
blanchet@55599
   905
lemma append_eq_append_conv [simp]:
nipkow@24526
   906
 "length xs = length ys \<or> length us = length vs
berghofe@13883
   907
 ==> (xs@us = ys@vs) = (xs=ys \<and> us=vs)"
nipkow@24526
   908
apply (induct xs arbitrary: ys)
paulson@14208
   909
 apply (case_tac ys, simp, force)
paulson@14208
   910
apply (case_tac ys, force, simp)
nipkow@13145
   911
done
wenzelm@13114
   912
nipkow@24526
   913
lemma append_eq_append_conv2: "(xs @ ys = zs @ ts) =
nipkow@24526
   914
  (EX us. xs = zs @ us & us @ ys = ts | xs @ us = zs & ys = us@ ts)"
nipkow@24526
   915
apply (induct xs arbitrary: ys zs ts)
nipkow@45761
   916
 apply fastforce
nipkow@14495
   917
apply(case_tac zs)
nipkow@14495
   918
 apply simp
nipkow@45761
   919
apply fastforce
nipkow@14495
   920
done
nipkow@14495
   921
berghofe@34910
   922
lemma same_append_eq [iff, induct_simp]: "(xs @ ys = xs @ zs) = (ys = zs)"
nipkow@13145
   923
by simp
wenzelm@13114
   924
wenzelm@13142
   925
lemma append1_eq_conv [iff]: "(xs @ [x] = ys @ [y]) = (xs = ys \<and> x = y)"
nipkow@13145
   926
by simp
wenzelm@13114
   927
berghofe@34910
   928
lemma append_same_eq [iff, induct_simp]: "(ys @ xs = zs @ xs) = (ys = zs)"
nipkow@13145
   929
by simp
wenzelm@13114
   930
wenzelm@13142
   931
lemma append_self_conv2 [iff]: "(xs @ ys = ys) = (xs = [])"
nipkow@13145
   932
using append_same_eq [of _ _ "[]"] by auto
wenzelm@13114
   933
wenzelm@13142
   934
lemma self_append_conv2 [iff]: "(ys = xs @ ys) = (xs = [])"
nipkow@13145
   935
using append_same_eq [of "[]"] by auto
wenzelm@13114
   936
blanchet@55599
   937
lemma hd_Cons_tl [simp]: "xs \<noteq> [] ==> hd xs # tl xs = xs"
nipkow@13145
   938
by (induct xs) auto
wenzelm@13114
   939
wenzelm@13142
   940
lemma hd_append: "hd (xs @ ys) = (if xs = [] then hd ys else hd xs)"
nipkow@13145
   941
by (induct xs) auto
wenzelm@13114
   942
wenzelm@13142
   943
lemma hd_append2 [simp]: "xs \<noteq> [] ==> hd (xs @ ys) = hd xs"
nipkow@13145
   944
by (simp add: hd_append split: list.split)
wenzelm@13114
   945
wenzelm@13142
   946
lemma tl_append: "tl (xs @ ys) = (case xs of [] => tl ys | z#zs => zs @ ys)"
nipkow@13145
   947
by (simp split: list.split)
wenzelm@13114
   948
wenzelm@13142
   949
lemma tl_append2 [simp]: "xs \<noteq> [] ==> tl (xs @ ys) = tl xs @ ys"
nipkow@13145
   950
by (simp add: tl_append split: list.split)
wenzelm@13114
   951
wenzelm@13142
   952
nipkow@14300
   953
lemma Cons_eq_append_conv: "x#xs = ys@zs =
nipkow@14300
   954
 (ys = [] & x#xs = zs | (EX ys'. x#ys' = ys & xs = ys'@zs))"
nipkow@14300
   955
by(cases ys) auto
nipkow@14300
   956
nipkow@15281
   957
lemma append_eq_Cons_conv: "(ys@zs = x#xs) =
nipkow@15281
   958
 (ys = [] & zs = x#xs | (EX ys'. ys = x#ys' & ys'@zs = xs))"
nipkow@15281
   959
by(cases ys) auto
nipkow@15281
   960
nipkow@14300
   961
wenzelm@13142
   962
text {* Trivial rules for solving @{text "@"}-equations automatically. *}
wenzelm@13114
   963
wenzelm@13114
   964
lemma eq_Nil_appendI: "xs = ys ==> xs = [] @ ys"
nipkow@13145
   965
by simp
wenzelm@13114
   966
wenzelm@13142
   967
lemma Cons_eq_appendI:
nipkow@13145
   968
"[| x # xs1 = ys; xs = xs1 @ zs |] ==> x # xs = ys @ zs"
nipkow@13145
   969
by (drule sym) simp
wenzelm@13114
   970
wenzelm@13142
   971
lemma append_eq_appendI:
nipkow@13145
   972
"[| xs @ xs1 = zs; ys = xs1 @ us |] ==> xs @ ys = zs @ us"
nipkow@13145
   973
by (drule sym) simp
wenzelm@13114
   974
wenzelm@13114
   975
wenzelm@13142
   976
text {*
nipkow@13145
   977
Simplification procedure for all list equalities.
nipkow@13145
   978
Currently only tries to rearrange @{text "@"} to see if
nipkow@13145
   979
- both lists end in a singleton list,
nipkow@13145
   980
- or both lists end in the same list.
wenzelm@13142
   981
*}
wenzelm@13142
   982
wenzelm@44467
   983
simproc_setup list_eq ("(xs::'a list) = ys")  = {*
wenzelm@13462
   984
  let
wenzelm@44467
   985
    fun last (cons as Const (@{const_name Cons}, _) $ _ $ xs) =
wenzelm@44467
   986
          (case xs of Const (@{const_name Nil}, _) => cons | _ => last xs)
wenzelm@44467
   987
      | last (Const(@{const_name append},_) $ _ $ ys) = last ys
wenzelm@44467
   988
      | last t = t;
wenzelm@44467
   989
    
wenzelm@44467
   990
    fun list1 (Const(@{const_name Cons},_) $ _ $ Const(@{const_name Nil},_)) = true
wenzelm@44467
   991
      | list1 _ = false;
wenzelm@44467
   992
    
wenzelm@44467
   993
    fun butlast ((cons as Const(@{const_name Cons},_) $ x) $ xs) =
wenzelm@44467
   994
          (case xs of Const (@{const_name Nil}, _) => xs | _ => cons $ butlast xs)
wenzelm@44467
   995
      | butlast ((app as Const (@{const_name append}, _) $ xs) $ ys) = app $ butlast ys
wenzelm@44467
   996
      | butlast xs = Const(@{const_name Nil}, fastype_of xs);
wenzelm@44467
   997
    
wenzelm@44467
   998
    val rearr_ss =
wenzelm@52854
   999
      simpset_of (put_simpset HOL_basic_ss @{context}
wenzelm@52854
  1000
        addsimps [@{thm append_assoc}, @{thm append_Nil}, @{thm append_Cons}]);
wenzelm@44467
  1001
    
wenzelm@52854
  1002
    fun list_eq ctxt (F as (eq as Const(_,eqT)) $ lhs $ rhs) =
wenzelm@13462
  1003
      let
wenzelm@44467
  1004
        val lastl = last lhs and lastr = last rhs;
wenzelm@44467
  1005
        fun rearr conv =
wenzelm@44467
  1006
          let
wenzelm@44467
  1007
            val lhs1 = butlast lhs and rhs1 = butlast rhs;
wenzelm@44467
  1008
            val Type(_,listT::_) = eqT
wenzelm@44467
  1009
            val appT = [listT,listT] ---> listT
wenzelm@44467
  1010
            val app = Const(@{const_name append},appT)
wenzelm@44467
  1011
            val F2 = eq $ (app$lhs1$lastl) $ (app$rhs1$lastr)
wenzelm@44467
  1012
            val eq = HOLogic.mk_Trueprop (HOLogic.mk_eq (F,F2));
wenzelm@52854
  1013
            val thm = Goal.prove ctxt [] [] eq
wenzelm@52854
  1014
              (K (simp_tac (put_simpset rearr_ss ctxt) 1));
wenzelm@44467
  1015
          in SOME ((conv RS (thm RS trans)) RS eq_reflection) end;
wenzelm@44467
  1016
      in
wenzelm@44467
  1017
        if list1 lastl andalso list1 lastr then rearr @{thm append1_eq_conv}
wenzelm@44467
  1018
        else if lastl aconv lastr then rearr @{thm append_same_eq}
wenzelm@44467
  1019
        else NONE
wenzelm@44467
  1020
      end;
wenzelm@52854
  1021
  in fn _ => fn ctxt => fn ct => list_eq ctxt (term_of ct) end;
wenzelm@13114
  1022
*}
wenzelm@13114
  1023
wenzelm@13114
  1024
haftmann@50963
  1025
subsubsection {* @{const map} *}
wenzelm@13114
  1026
haftmann@40451
  1027
lemma hd_map:
haftmann@40451
  1028
  "xs \<noteq> [] \<Longrightarrow> hd (map f xs) = f (hd xs)"
haftmann@40451
  1029
  by (cases xs) simp_all
haftmann@40451
  1030
haftmann@40451
  1031
lemma map_tl:
haftmann@40451
  1032
  "map f (tl xs) = tl (map f xs)"
haftmann@40451
  1033
  by (cases xs) simp_all
haftmann@40451
  1034
wenzelm@13142
  1035
lemma map_ext: "(!!x. x : set xs --> f x = g x) ==> map f xs = map g xs"
nipkow@13145
  1036
by (induct xs) simp_all
wenzelm@13114
  1037
wenzelm@13142
  1038
lemma map_ident [simp]: "map (\<lambda>x. x) = (\<lambda>xs. xs)"
nipkow@13145
  1039
by (rule ext, induct_tac xs) auto
wenzelm@13114
  1040
wenzelm@13142
  1041
lemma map_append [simp]: "map f (xs @ ys) = map f xs @ map f ys"
nipkow@13145
  1042
by (induct xs) auto
wenzelm@13114
  1043
hoelzl@33639
  1044
lemma map_map [simp]: "map f (map g xs) = map (f \<circ> g) xs"
hoelzl@33639
  1045
by (induct xs) auto
hoelzl@33639
  1046
nipkow@35200
  1047
lemma map_comp_map[simp]: "((map f) o (map g)) = map(f o g)"
nipkow@35200
  1048
apply(rule ext)
nipkow@35200
  1049
apply(simp)
nipkow@35200
  1050
done
nipkow@35200
  1051
wenzelm@13142
  1052
lemma rev_map: "rev (map f xs) = map f (rev xs)"
nipkow@13145
  1053
by (induct xs) auto
wenzelm@13114
  1054
nipkow@13737
  1055
lemma map_eq_conv[simp]: "(map f xs = map g xs) = (!x : set xs. f x = g x)"
nipkow@13737
  1056
by (induct xs) auto
nipkow@13737
  1057
krauss@44884
  1058
lemma map_cong [fundef_cong]:
haftmann@40366
  1059
  "xs = ys \<Longrightarrow> (\<And>x. x \<in> set ys \<Longrightarrow> f x = g x) \<Longrightarrow> map f xs = map g ys"
haftmann@40366
  1060
  by simp
wenzelm@13114
  1061
wenzelm@13142
  1062
lemma map_is_Nil_conv [iff]: "(map f xs = []) = (xs = [])"
nipkow@13145
  1063
by (cases xs) auto
wenzelm@13114
  1064
wenzelm@13142
  1065
lemma Nil_is_map_conv [iff]: "([] = map f xs) = (xs = [])"
nipkow@13145
  1066
by (cases xs) auto
wenzelm@13114
  1067
paulson@18447
  1068
lemma map_eq_Cons_conv:
nipkow@14025
  1069
 "(map f xs = y#ys) = (\<exists>z zs. xs = z#zs \<and> f z = y \<and> map f zs = ys)"
nipkow@13145
  1070
by (cases xs) auto
wenzelm@13114
  1071
paulson@18447
  1072
lemma Cons_eq_map_conv:
nipkow@14025
  1073
 "(x#xs = map f ys) = (\<exists>z zs. ys = z#zs \<and> x = f z \<and> xs = map f zs)"
nipkow@14025
  1074
by (cases ys) auto
nipkow@14025
  1075
paulson@18447
  1076
lemmas map_eq_Cons_D = map_eq_Cons_conv [THEN iffD1]
paulson@18447
  1077
lemmas Cons_eq_map_D = Cons_eq_map_conv [THEN iffD1]
paulson@18447
  1078
declare map_eq_Cons_D [dest!]  Cons_eq_map_D [dest!]
paulson@18447
  1079
nipkow@14111
  1080
lemma ex_map_conv:
nipkow@14111
  1081
  "(EX xs. ys = map f xs) = (ALL y : set ys. EX x. y = f x)"
paulson@18447
  1082
by(induct ys, auto simp add: Cons_eq_map_conv)
nipkow@14111
  1083
nipkow@15110
  1084
lemma map_eq_imp_length_eq:
paulson@35496
  1085
  assumes "map f xs = map g ys"
haftmann@26734
  1086
  shows "length xs = length ys"
wenzelm@54511
  1087
  using assms
wenzelm@54511
  1088
proof (induct ys arbitrary: xs)
haftmann@26734
  1089
  case Nil then show ?case by simp
haftmann@26734
  1090
next
haftmann@26734
  1091
  case (Cons y ys) then obtain z zs where xs: "xs = z # zs" by auto
paulson@35496
  1092
  from Cons xs have "map f zs = map g ys" by simp
wenzelm@54511
  1093
  with Cons have "length zs = length ys" by blast
haftmann@26734
  1094
  with xs show ?case by simp
haftmann@26734
  1095
qed
haftmann@26734
  1096
  
nipkow@15110
  1097
lemma map_inj_on:
nipkow@15110
  1098
 "[| map f xs = map f ys; inj_on f (set xs Un set ys) |]
nipkow@15110
  1099
  ==> xs = ys"
nipkow@15110
  1100
apply(frule map_eq_imp_length_eq)
nipkow@15110
  1101
apply(rotate_tac -1)
nipkow@15110
  1102
apply(induct rule:list_induct2)
nipkow@15110
  1103
 apply simp
nipkow@15110
  1104
apply(simp)
nipkow@15110
  1105
apply (blast intro:sym)
nipkow@15110
  1106
done
nipkow@15110
  1107
nipkow@15110
  1108
lemma inj_on_map_eq_map:
nipkow@15110
  1109
 "inj_on f (set xs Un set ys) \<Longrightarrow> (map f xs = map f ys) = (xs = ys)"
nipkow@15110
  1110
by(blast dest:map_inj_on)
nipkow@15110
  1111
wenzelm@13114
  1112
lemma map_injective:
nipkow@24526
  1113
 "map f xs = map f ys ==> inj f ==> xs = ys"
nipkow@24526
  1114
by (induct ys arbitrary: xs) (auto dest!:injD)
wenzelm@13114
  1115
nipkow@14339
  1116
lemma inj_map_eq_map[simp]: "inj f \<Longrightarrow> (map f xs = map f ys) = (xs = ys)"
nipkow@14339
  1117
by(blast dest:map_injective)
nipkow@14339
  1118
wenzelm@13114
  1119
lemma inj_mapI: "inj f ==> inj (map f)"
nipkow@17589
  1120
by (iprover dest: map_injective injD intro: inj_onI)
wenzelm@13114
  1121
wenzelm@13114
  1122
lemma inj_mapD: "inj (map f) ==> inj f"
paulson@14208
  1123
apply (unfold inj_on_def, clarify)
nipkow@13145
  1124
apply (erule_tac x = "[x]" in ballE)
paulson@14208
  1125
 apply (erule_tac x = "[y]" in ballE, simp, blast)
nipkow@13145
  1126
apply blast
nipkow@13145
  1127
done
wenzelm@13114
  1128
nipkow@14339
  1129
lemma inj_map[iff]: "inj (map f) = inj f"
nipkow@13145
  1130
by (blast dest: inj_mapD intro: inj_mapI)
wenzelm@13114
  1131
nipkow@15303
  1132
lemma inj_on_mapI: "inj_on f (\<Union>(set ` A)) \<Longrightarrow> inj_on (map f) A"
nipkow@15303
  1133
apply(rule inj_onI)
nipkow@15303
  1134
apply(erule map_inj_on)
nipkow@15303
  1135
apply(blast intro:inj_onI dest:inj_onD)
nipkow@15303
  1136
done
nipkow@15303
  1137
kleing@14343
  1138
lemma map_idI: "(\<And>x. x \<in> set xs \<Longrightarrow> f x = x) \<Longrightarrow> map f xs = xs"
kleing@14343
  1139
by (induct xs, auto)
wenzelm@13114
  1140
nipkow@14402
  1141
lemma map_fun_upd [simp]: "y \<notin> set xs \<Longrightarrow> map (f(y:=v)) xs = map f xs"
nipkow@14402
  1142
by (induct xs) auto
nipkow@14402
  1143
nipkow@15110
  1144
lemma map_fst_zip[simp]:
nipkow@15110
  1145
  "length xs = length ys \<Longrightarrow> map fst (zip xs ys) = xs"
nipkow@15110
  1146
by (induct rule:list_induct2, simp_all)
nipkow@15110
  1147
nipkow@15110
  1148
lemma map_snd_zip[simp]:
nipkow@15110
  1149
  "length xs = length ys \<Longrightarrow> map snd (zip xs ys) = ys"
nipkow@15110
  1150
by (induct rule:list_induct2, simp_all)
nipkow@15110
  1151
haftmann@41752
  1152
enriched_type map: map
nipkow@47992
  1153
by (simp_all add: id_def)
nipkow@47992
  1154
haftmann@50963
  1155
declare map.id [simp]
haftmann@50963
  1156
haftmann@50963
  1157
haftmann@50963
  1158
subsubsection {* @{const rev} *}
wenzelm@13114
  1159
wenzelm@13142
  1160
lemma rev_append [simp]: "rev (xs @ ys) = rev ys @ rev xs"
nipkow@13145
  1161
by (induct xs) auto
wenzelm@13114
  1162
wenzelm@13142
  1163
lemma rev_rev_ident [simp]: "rev (rev xs) = xs"
nipkow@13145
  1164
by (induct xs) auto
wenzelm@13114
  1165
kleing@15870
  1166
lemma rev_swap: "(rev xs = ys) = (xs = rev ys)"
kleing@15870
  1167
by auto
kleing@15870
  1168
wenzelm@13142
  1169
lemma rev_is_Nil_conv [iff]: "(rev xs = []) = (xs = [])"
nipkow@13145
  1170
by (induct xs) auto
wenzelm@13114
  1171
wenzelm@13142
  1172
lemma Nil_is_rev_conv [iff]: "([] = rev xs) = (xs = [])"
nipkow@13145
  1173
by (induct xs) auto
wenzelm@13114
  1174
kleing@15870
  1175
lemma rev_singleton_conv [simp]: "(rev xs = [x]) = (xs = [x])"
kleing@15870
  1176
by (cases xs) auto
kleing@15870
  1177
kleing@15870
  1178
lemma singleton_rev_conv [simp]: "([x] = rev xs) = (xs = [x])"
kleing@15870
  1179
by (cases xs) auto
kleing@15870
  1180
blanchet@55599
  1181
lemma rev_is_rev_conv [iff]: "(rev xs = rev ys) = (xs = ys)"
haftmann@21061
  1182
apply (induct xs arbitrary: ys, force)
paulson@14208
  1183
apply (case_tac ys, simp, force)
nipkow@13145
  1184
done
wenzelm@13114
  1185
nipkow@15439
  1186
lemma inj_on_rev[iff]: "inj_on rev A"
nipkow@15439
  1187
by(simp add:inj_on_def)
nipkow@15439
  1188
wenzelm@13366
  1189
lemma rev_induct [case_names Nil snoc]:
wenzelm@13366
  1190
  "[| P []; !!x xs. P xs ==> P (xs @ [x]) |] ==> P xs"
berghofe@15489
  1191
apply(simplesubst rev_rev_ident[symmetric])
nipkow@13145
  1192
apply(rule_tac list = "rev xs" in list.induct, simp_all)
nipkow@13145
  1193
done
wenzelm@13114
  1194
wenzelm@13366
  1195
lemma rev_exhaust [case_names Nil snoc]:
wenzelm@13366
  1196
  "(xs = [] ==> P) ==>(!!ys y. xs = ys @ [y] ==> P) ==> P"
nipkow@13145
  1197
by (induct xs rule: rev_induct) auto
wenzelm@13114
  1198
wenzelm@13366
  1199
lemmas rev_cases = rev_exhaust
wenzelm@13366
  1200
nipkow@18423
  1201
lemma rev_eq_Cons_iff[iff]: "(rev xs = y#ys) = (xs = rev ys @ [y])"
nipkow@18423
  1202
by(rule rev_cases[of xs]) auto
nipkow@18423
  1203
wenzelm@13114
  1204
haftmann@50963
  1205
subsubsection {* @{const set} *}
wenzelm@13114
  1206
nipkow@47569
  1207
declare set.simps [code_post]  --"pretty output"
nipkow@47569
  1208
wenzelm@13142
  1209
lemma finite_set [iff]: "finite (set xs)"
nipkow@13145
  1210
by (induct xs) auto
wenzelm@13114
  1211
wenzelm@13142
  1212
lemma set_append [simp]: "set (xs @ ys) = (set xs \<union> set ys)"
nipkow@13145
  1213
by (induct xs) auto
wenzelm@13114
  1214
nipkow@17830
  1215
lemma hd_in_set[simp]: "xs \<noteq> [] \<Longrightarrow> hd xs : set xs"
nipkow@17830
  1216
by(cases xs) auto
oheimb@14099
  1217
wenzelm@13142
  1218
lemma set_subset_Cons: "set xs \<subseteq> set (x # xs)"
nipkow@13145
  1219
by auto
wenzelm@13114
  1220
oheimb@14099
  1221
lemma set_ConsD: "y \<in> set (x # xs) \<Longrightarrow> y=x \<or> y \<in> set xs" 
oheimb@14099
  1222
by auto
oheimb@14099
  1223
wenzelm@13142
  1224
lemma set_empty [iff]: "(set xs = {}) = (xs = [])"
nipkow@13145
  1225
by (induct xs) auto
wenzelm@13114
  1226
nipkow@15245
  1227
lemma set_empty2[iff]: "({} = set xs) = (xs = [])"
nipkow@15245
  1228
by(induct xs) auto
nipkow@15245
  1229
wenzelm@13142
  1230
lemma set_rev [simp]: "set (rev xs) = set xs"
nipkow@13145
  1231
by (induct xs) auto
wenzelm@13114
  1232
wenzelm@13142
  1233
lemma set_map [simp]: "set (map f xs) = f`(set xs)"
nipkow@13145
  1234
by (induct xs) auto
wenzelm@13114
  1235
wenzelm@13142
  1236
lemma set_filter [simp]: "set (filter P xs) = {x. x : set xs \<and> P x}"
nipkow@13145
  1237
by (induct xs) auto
wenzelm@13114
  1238
nipkow@32417
  1239
lemma set_upt [simp]: "set[i..<j] = {i..<j}"
bulwahn@41695
  1240
by (induct j) auto
wenzelm@13114
  1241
nipkow@26073
  1242
nipkow@26073
  1243
lemma split_list: "x : set xs \<Longrightarrow> \<exists>ys zs. xs = ys @ x # zs"
nipkow@26073
  1244
proof (induct xs)
nipkow@26073
  1245
  case Nil thus ?case by simp
nipkow@26073
  1246
next
nipkow@26073
  1247
  case Cons thus ?case by (auto intro: Cons_eq_appendI)
nipkow@26073
  1248
qed
nipkow@26073
  1249
haftmann@26734
  1250
lemma in_set_conv_decomp: "x \<in> set xs \<longleftrightarrow> (\<exists>ys zs. xs = ys @ x # zs)"
haftmann@26734
  1251
  by (auto elim: split_list)
nipkow@26073
  1252
nipkow@26073
  1253
lemma split_list_first: "x : set xs \<Longrightarrow> \<exists>ys zs. xs = ys @ x # zs \<and> x \<notin> set ys"
paulson@15113
  1254
proof (induct xs)
nipkow@26073
  1255
  case Nil thus ?case by simp
nipkow@18049
  1256
next
nipkow@18049
  1257
  case (Cons a xs)
nipkow@18049
  1258
  show ?case
nipkow@18049
  1259
  proof cases
nipkow@45761
  1260
    assume "x = a" thus ?case using Cons by fastforce
nipkow@18049
  1261
  next
nipkow@45761
  1262
    assume "x \<noteq> a" thus ?case using Cons by(fastforce intro!: Cons_eq_appendI)
nipkow@18049
  1263
  qed
nipkow@18049
  1264
qed
nipkow@18049
  1265
nipkow@26073
  1266
lemma in_set_conv_decomp_first:
nipkow@26073
  1267
  "(x : set xs) = (\<exists>ys zs. xs = ys @ x # zs \<and> x \<notin> set ys)"
haftmann@26734
  1268
  by (auto dest!: split_list_first)
nipkow@26073
  1269
haftmann@40366
  1270
lemma split_list_last: "x \<in> set xs \<Longrightarrow> \<exists>ys zs. xs = ys @ x # zs \<and> x \<notin> set zs"
haftmann@40366
  1271
proof (induct xs rule: rev_induct)
nipkow@26073
  1272
  case Nil thus ?case by simp
nipkow@26073
  1273
next
nipkow@26073
  1274
  case (snoc a xs)
nipkow@26073
  1275
  show ?case
nipkow@26073
  1276
  proof cases
haftmann@40366
  1277
    assume "x = a" thus ?case using snoc by (metis List.set.simps(1) emptyE)
nipkow@26073
  1278
  next
nipkow@45761
  1279
    assume "x \<noteq> a" thus ?case using snoc by fastforce
nipkow@26073
  1280
  qed
nipkow@26073
  1281
qed
nipkow@26073
  1282
nipkow@26073
  1283
lemma in_set_conv_decomp_last:
nipkow@26073
  1284
  "(x : set xs) = (\<exists>ys zs. xs = ys @ x # zs \<and> x \<notin> set zs)"
haftmann@26734
  1285
  by (auto dest!: split_list_last)
nipkow@26073
  1286
nipkow@26073
  1287
lemma split_list_prop: "\<exists>x \<in> set xs. P x \<Longrightarrow> \<exists>ys x zs. xs = ys @ x # zs & P x"
nipkow@26073
  1288
proof (induct xs)
nipkow@26073
  1289
  case Nil thus ?case by simp
nipkow@26073
  1290
next
nipkow@26073
  1291
  case Cons thus ?case
nipkow@26073
  1292
    by(simp add:Bex_def)(metis append_Cons append.simps(1))
nipkow@26073
  1293
qed
nipkow@26073
  1294
nipkow@26073
  1295
lemma split_list_propE:
haftmann@26734
  1296
  assumes "\<exists>x \<in> set xs. P x"
haftmann@26734
  1297
  obtains ys x zs where "xs = ys @ x # zs" and "P x"
haftmann@26734
  1298
using split_list_prop [OF assms] by blast
nipkow@26073
  1299
nipkow@26073
  1300
lemma split_list_first_prop:
nipkow@26073
  1301
  "\<exists>x \<in> set xs. P x \<Longrightarrow>
nipkow@26073
  1302
   \<exists>ys x zs. xs = ys@x#zs \<and> P x \<and> (\<forall>y \<in> set ys. \<not> P y)"
haftmann@26734
  1303
proof (induct xs)
nipkow@26073
  1304
  case Nil thus ?case by simp
nipkow@26073
  1305
next
nipkow@26073
  1306
  case (Cons x xs)
nipkow@26073
  1307
  show ?case
nipkow@26073
  1308
  proof cases
nipkow@26073
  1309
    assume "P x"
haftmann@40366
  1310
    thus ?thesis by simp (metis Un_upper1 contra_subsetD in_set_conv_decomp_first self_append_conv2 set_append)
nipkow@26073
  1311
  next
nipkow@26073
  1312
    assume "\<not> P x"
nipkow@26073
  1313
    hence "\<exists>x\<in>set xs. P x" using Cons(2) by simp
nipkow@26073
  1314
    thus ?thesis using `\<not> P x` Cons(1) by (metis append_Cons set_ConsD)
nipkow@26073
  1315
  qed
nipkow@26073
  1316
qed
nipkow@26073
  1317
nipkow@26073
  1318
lemma split_list_first_propE:
haftmann@26734
  1319
  assumes "\<exists>x \<in> set xs. P x"
haftmann@26734
  1320
  obtains ys x zs where "xs = ys @ x # zs" and "P x" and "\<forall>y \<in> set ys. \<not> P y"
haftmann@26734
  1321
using split_list_first_prop [OF assms] by blast
nipkow@26073
  1322
nipkow@26073
  1323
lemma split_list_first_prop_iff:
nipkow@26073
  1324
  "(\<exists>x \<in> set xs. P x) \<longleftrightarrow>
nipkow@26073
  1325
   (\<exists>ys x zs. xs = ys@x#zs \<and> P x \<and> (\<forall>y \<in> set ys. \<not> P y))"
haftmann@26734
  1326
by (rule, erule split_list_first_prop) auto
nipkow@26073
  1327
nipkow@26073
  1328
lemma split_list_last_prop:
nipkow@26073
  1329
  "\<exists>x \<in> set xs. P x \<Longrightarrow>
nipkow@26073
  1330
   \<exists>ys x zs. xs = ys@x#zs \<and> P x \<and> (\<forall>z \<in> set zs. \<not> P z)"
nipkow@26073
  1331
proof(induct xs rule:rev_induct)
nipkow@26073
  1332
  case Nil thus ?case by simp
nipkow@26073
  1333
next
nipkow@26073
  1334
  case (snoc x xs)
nipkow@26073
  1335
  show ?case
nipkow@26073
  1336
  proof cases
nipkow@26073
  1337
    assume "P x" thus ?thesis by (metis emptyE set_empty)
nipkow@26073
  1338
  next
nipkow@26073
  1339
    assume "\<not> P x"
nipkow@26073
  1340
    hence "\<exists>x\<in>set xs. P x" using snoc(2) by simp
nipkow@45761
  1341
    thus ?thesis using `\<not> P x` snoc(1) by fastforce
nipkow@26073
  1342
  qed
nipkow@26073
  1343
qed
nipkow@26073
  1344
nipkow@26073
  1345
lemma split_list_last_propE:
haftmann@26734
  1346
  assumes "\<exists>x \<in> set xs. P x"
haftmann@26734
  1347
  obtains ys x zs where "xs = ys @ x # zs" and "P x" and "\<forall>z \<in> set zs. \<not> P z"
haftmann@26734
  1348
using split_list_last_prop [OF assms] by blast
nipkow@26073
  1349
nipkow@26073
  1350
lemma split_list_last_prop_iff:
nipkow@26073
  1351
  "(\<exists>x \<in> set xs. P x) \<longleftrightarrow>
nipkow@26073
  1352
   (\<exists>ys x zs. xs = ys@x#zs \<and> P x \<and> (\<forall>z \<in> set zs. \<not> P z))"
haftmann@26734
  1353
by (metis split_list_last_prop [where P=P] in_set_conv_decomp)
nipkow@26073
  1354
nipkow@26073
  1355
lemma finite_list: "finite A ==> EX xs. set xs = A"
haftmann@26734
  1356
  by (erule finite_induct)
haftmann@26734
  1357
    (auto simp add: set.simps(2) [symmetric] simp del: set.simps(2))
paulson@13508
  1358
kleing@14388
  1359
lemma card_length: "card (set xs) \<le> length xs"
kleing@14388
  1360
by (induct xs) (auto simp add: card_insert_if)
wenzelm@13114
  1361
haftmann@26442
  1362
lemma set_minus_filter_out:
haftmann@26442
  1363
  "set xs - {y} = set (filter (\<lambda>x. \<not> (x = y)) xs)"
haftmann@26442
  1364
  by (induct xs) auto
paulson@15168
  1365
wenzelm@35118
  1366
haftmann@50963
  1367
subsubsection {* @{const filter} *}
wenzelm@13114
  1368
wenzelm@13142
  1369
lemma filter_append [simp]: "filter P (xs @ ys) = filter P xs @ filter P ys"
nipkow@13145
  1370
by (induct xs) auto
wenzelm@13114
  1371
nipkow@15305
  1372
lemma rev_filter: "rev (filter P xs) = filter P (rev xs)"
nipkow@15305
  1373
by (induct xs) simp_all
nipkow@15305
  1374
wenzelm@13142
  1375
lemma filter_filter [simp]: "filter P (filter Q xs) = filter (\<lambda>x. Q x \<and> P x) xs"
nipkow@13145
  1376
by (induct xs) auto
wenzelm@13114
  1377
nipkow@16998
  1378
lemma length_filter_le [simp]: "length (filter P xs) \<le> length xs"
nipkow@16998
  1379
by (induct xs) (auto simp add: le_SucI)
nipkow@16998
  1380
nipkow@18423
  1381
lemma sum_length_filter_compl:
nipkow@18423
  1382
  "length(filter P xs) + length(filter (%x. ~P x) xs) = length xs"
nipkow@18423
  1383
by(induct xs) simp_all
nipkow@18423
  1384
wenzelm@13142
  1385
lemma filter_True [simp]: "\<forall>x \<in> set xs. P x ==> filter P xs = xs"
nipkow@13145
  1386
by (induct xs) auto
wenzelm@13114
  1387
wenzelm@13142
  1388
lemma filter_False [simp]: "\<forall>x \<in> set xs. \<not> P x ==> filter P xs = []"
nipkow@13145
  1389
by (induct xs) auto
wenzelm@13114
  1390
nipkow@16998
  1391
lemma filter_empty_conv: "(filter P xs = []) = (\<forall>x\<in>set xs. \<not> P x)" 
nipkow@24349
  1392
by (induct xs) simp_all
nipkow@16998
  1393
nipkow@16998
  1394
lemma filter_id_conv: "(filter P xs = xs) = (\<forall>x\<in>set xs. P x)"
nipkow@16998
  1395
apply (induct xs)
nipkow@16998
  1396
 apply auto
nipkow@16998
  1397
apply(cut_tac P=P and xs=xs in length_filter_le)
nipkow@16998
  1398
apply simp
nipkow@16998
  1399
done
wenzelm@13114
  1400
nipkow@16965
  1401
lemma filter_map:
nipkow@16965
  1402
  "filter P (map f xs) = map f (filter (P o f) xs)"
nipkow@16965
  1403
by (induct xs) simp_all
nipkow@16965
  1404
nipkow@16965
  1405
lemma length_filter_map[simp]:
nipkow@16965
  1406
  "length (filter P (map f xs)) = length(filter (P o f) xs)"
nipkow@16965
  1407
by (simp add:filter_map)
nipkow@16965
  1408
wenzelm@13142
  1409
lemma filter_is_subset [simp]: "set (filter P xs) \<le> set xs"
nipkow@13145
  1410
by auto
wenzelm@13114
  1411
nipkow@15246
  1412
lemma length_filter_less:
nipkow@15246
  1413
  "\<lbrakk> x : set xs; ~ P x \<rbrakk> \<Longrightarrow> length(filter P xs) < length xs"
nipkow@15246
  1414
proof (induct xs)
nipkow@15246
  1415
  case Nil thus ?case by simp
nipkow@15246
  1416
next
nipkow@15246
  1417
  case (Cons x xs) thus ?case
nipkow@15246
  1418
    apply (auto split:split_if_asm)
nipkow@15246
  1419
    using length_filter_le[of P xs] apply arith
nipkow@15246
  1420
  done
nipkow@15246
  1421
qed
wenzelm@13114
  1422
nipkow@15281
  1423
lemma length_filter_conv_card:
nipkow@15281
  1424
 "length(filter p xs) = card{i. i < length xs & p(xs!i)}"
nipkow@15281
  1425
proof (induct xs)
nipkow@15281
  1426
  case Nil thus ?case by simp
nipkow@15281
  1427
next
nipkow@15281
  1428
  case (Cons x xs)
nipkow@15281
  1429
  let ?S = "{i. i < length xs & p(xs!i)}"
nipkow@15281
  1430
  have fin: "finite ?S" by(fast intro: bounded_nat_set_is_finite)
nipkow@15281
  1431
  show ?case (is "?l = card ?S'")
nipkow@15281
  1432
  proof (cases)
nipkow@15281
  1433
    assume "p x"
nipkow@15281
  1434
    hence eq: "?S' = insert 0 (Suc ` ?S)"
nipkow@25162
  1435
      by(auto simp: image_def split:nat.split dest:gr0_implies_Suc)
nipkow@15281
  1436
    have "length (filter p (x # xs)) = Suc(card ?S)"
wenzelm@23388
  1437
      using Cons `p x` by simp
nipkow@15281
  1438
    also have "\<dots> = Suc(card(Suc ` ?S))" using fin
huffman@45792
  1439
      by (simp add: card_image)
nipkow@15281
  1440
    also have "\<dots> = card ?S'" using eq fin
nipkow@15281
  1441
      by (simp add:card_insert_if) (simp add:image_def)
nipkow@15281
  1442
    finally show ?thesis .
nipkow@15281
  1443
  next
nipkow@15281
  1444
    assume "\<not> p x"
nipkow@15281
  1445
    hence eq: "?S' = Suc ` ?S"
nipkow@25162
  1446
      by(auto simp add: image_def split:nat.split elim:lessE)
nipkow@15281
  1447
    have "length (filter p (x # xs)) = card ?S"
wenzelm@23388
  1448
      using Cons `\<not> p x` by simp
nipkow@15281
  1449
    also have "\<dots> = card(Suc ` ?S)" using fin
huffman@45792
  1450
      by (simp add: card_image)
nipkow@15281
  1451
    also have "\<dots> = card ?S'" using eq fin
nipkow@15281
  1452
      by (simp add:card_insert_if)
nipkow@15281
  1453
    finally show ?thesis .
nipkow@15281
  1454
  qed
nipkow@15281
  1455
qed
nipkow@15281
  1456
nipkow@17629
  1457
lemma Cons_eq_filterD:
nipkow@17629
  1458
 "x#xs = filter P ys \<Longrightarrow>
nipkow@17629
  1459
  \<exists>us vs. ys = us @ x # vs \<and> (\<forall>u\<in>set us. \<not> P u) \<and> P x \<and> xs = filter P vs"
wenzelm@19585
  1460
  (is "_ \<Longrightarrow> \<exists>us vs. ?P ys us vs")
nipkow@17629
  1461
proof(induct ys)
nipkow@17629
  1462
  case Nil thus ?case by simp
nipkow@17629
  1463
next
nipkow@17629
  1464
  case (Cons y ys)
nipkow@17629
  1465
  show ?case (is "\<exists>x. ?Q x")
nipkow@17629
  1466
  proof cases
nipkow@17629
  1467
    assume Py: "P y"
nipkow@17629
  1468
    show ?thesis
nipkow@17629
  1469
    proof cases
wenzelm@25221
  1470
      assume "x = y"
wenzelm@25221
  1471
      with Py Cons.prems have "?Q []" by simp
wenzelm@25221
  1472
      then show ?thesis ..
nipkow@17629
  1473
    next
wenzelm@25221
  1474
      assume "x \<noteq> y"
wenzelm@25221
  1475
      with Py Cons.prems show ?thesis by simp
nipkow@17629
  1476
    qed
nipkow@17629
  1477
  next
wenzelm@25221
  1478
    assume "\<not> P y"
nipkow@45761
  1479
    with Cons obtain us vs where "?P (y#ys) (y#us) vs" by fastforce
wenzelm@25221
  1480
    then have "?Q (y#us)" by simp
wenzelm@25221
  1481
    then show ?thesis ..
nipkow@17629
  1482
  qed
nipkow@17629
  1483
qed
nipkow@17629
  1484
nipkow@17629
  1485
lemma filter_eq_ConsD:
nipkow@17629
  1486
 "filter P ys = x#xs \<Longrightarrow>
nipkow@17629
  1487
  \<exists>us vs. ys = us @ x # vs \<and> (\<forall>u\<in>set us. \<not> P u) \<and> P x \<and> xs = filter P vs"
nipkow@17629
  1488
by(rule Cons_eq_filterD) simp
nipkow@17629
  1489
nipkow@17629
  1490
lemma filter_eq_Cons_iff:
nipkow@17629
  1491
 "(filter P ys = x#xs) =
nipkow@17629
  1492
  (\<exists>us vs. ys = us @ x # vs \<and> (\<forall>u\<in>set us. \<not> P u) \<and> P x \<and> xs = filter P vs)"
nipkow@17629
  1493
by(auto dest:filter_eq_ConsD)
nipkow@17629
  1494
nipkow@17629
  1495
lemma Cons_eq_filter_iff:
nipkow@17629
  1496
 "(x#xs = filter P ys) =
nipkow@17629
  1497
  (\<exists>us vs. ys = us @ x # vs \<and> (\<forall>u\<in>set us. \<not> P u) \<and> P x \<and> xs = filter P vs)"
nipkow@17629
  1498
by(auto dest:Cons_eq_filterD)
nipkow@17629
  1499
krauss@44884
  1500
lemma filter_cong[fundef_cong]:
nipkow@17501
  1501
 "xs = ys \<Longrightarrow> (\<And>x. x \<in> set ys \<Longrightarrow> P x = Q x) \<Longrightarrow> filter P xs = filter Q ys"
nipkow@17501
  1502
apply simp
nipkow@17501
  1503
apply(erule thin_rl)
nipkow@17501
  1504
by (induct ys) simp_all
nipkow@17501
  1505
nipkow@15281
  1506
haftmann@26442
  1507
subsubsection {* List partitioning *}
haftmann@26442
  1508
haftmann@26442
  1509
primrec partition :: "('a \<Rightarrow> bool) \<Rightarrow>'a list \<Rightarrow> 'a list \<times> 'a list" where
nipkow@51563
  1510
"partition P [] = ([], [])" |
nipkow@51563
  1511
"partition P (x # xs) = 
nipkow@51563
  1512
  (let (yes, no) = partition P xs
nipkow@51563
  1513
   in if P x then (x # yes, no) else (yes, x # no))"
haftmann@26442
  1514
haftmann@26442
  1515
lemma partition_filter1:
haftmann@26442
  1516
    "fst (partition P xs) = filter P xs"
haftmann@26442
  1517
by (induct xs) (auto simp add: Let_def split_def)
haftmann@26442
  1518
haftmann@26442
  1519
lemma partition_filter2:
haftmann@26442
  1520
    "snd (partition P xs) = filter (Not o P) xs"
haftmann@26442
  1521
by (induct xs) (auto simp add: Let_def split_def)
haftmann@26442
  1522
haftmann@26442
  1523
lemma partition_P:
haftmann@26442
  1524
  assumes "partition P xs = (yes, no)"
haftmann@26442
  1525
  shows "(\<forall>p \<in> set yes.  P p) \<and> (\<forall>p  \<in> set no. \<not> P p)"
haftmann@26442
  1526
proof -
haftmann@26442
  1527
  from assms have "yes = fst (partition P xs)" and "no = snd (partition P xs)"
haftmann@26442
  1528
    by simp_all
haftmann@26442
  1529
  then show ?thesis by (simp_all add: partition_filter1 partition_filter2)
haftmann@26442
  1530
qed
haftmann@26442
  1531
haftmann@26442
  1532
lemma partition_set:
haftmann@26442
  1533
  assumes "partition P xs = (yes, no)"
haftmann@26442
  1534
  shows "set yes \<union> set no = set xs"
haftmann@26442
  1535
proof -
haftmann@26442
  1536
  from assms have "yes = fst (partition P xs)" and "no = snd (partition P xs)"
haftmann@26442
  1537
    by simp_all
haftmann@26442
  1538
  then show ?thesis by (auto simp add: partition_filter1 partition_filter2) 
haftmann@26442
  1539
qed
haftmann@26442
  1540
hoelzl@33639
  1541
lemma partition_filter_conv[simp]:
hoelzl@33639
  1542
  "partition f xs = (filter f xs,filter (Not o f) xs)"
hoelzl@33639
  1543
unfolding partition_filter2[symmetric]
hoelzl@33639
  1544
unfolding partition_filter1[symmetric] by simp
hoelzl@33639
  1545
hoelzl@33639
  1546
declare partition.simps[simp del]
haftmann@26442
  1547
wenzelm@35118
  1548
haftmann@50963
  1549
subsubsection {* @{const concat} *}
wenzelm@13114
  1550
wenzelm@13142
  1551
lemma concat_append [simp]: "concat (xs @ ys) = concat xs @ concat ys"
nipkow@13145
  1552
by (induct xs) auto
wenzelm@13114
  1553
paulson@18447
  1554
lemma concat_eq_Nil_conv [simp]: "(concat xss = []) = (\<forall>xs \<in> set xss. xs = [])"
nipkow@13145
  1555
by (induct xss) auto
wenzelm@13114
  1556
paulson@18447
  1557
lemma Nil_eq_concat_conv [simp]: "([] = concat xss) = (\<forall>xs \<in> set xss. xs = [])"
nipkow@13145
  1558
by (induct xss) auto
wenzelm@13114
  1559
nipkow@24308
  1560
lemma set_concat [simp]: "set (concat xs) = (UN x:set xs. set x)"
nipkow@13145
  1561
by (induct xs) auto
wenzelm@13114
  1562
nipkow@24476
  1563
lemma concat_map_singleton[simp]: "concat(map (%x. [f x]) xs) = map f xs"
nipkow@24349
  1564
by (induct xs) auto
nipkow@24349
  1565
wenzelm@13142
  1566
lemma map_concat: "map f (concat xs) = concat (map (map f) xs)"
nipkow@13145
  1567
by (induct xs) auto
wenzelm@13114
  1568
wenzelm@13142
  1569
lemma filter_concat: "filter p (concat xs) = concat (map (filter p) xs)"
nipkow@13145
  1570
by (induct xs) auto
wenzelm@13114
  1571
wenzelm@13142
  1572
lemma rev_concat: "rev (concat xs) = concat (map rev (rev xs))"
nipkow@13145
  1573
by (induct xs) auto
wenzelm@13114
  1574
bulwahn@40611
  1575
lemma concat_eq_concat_iff: "\<forall>(x, y) \<in> set (zip xs ys). length x = length y ==> length xs = length ys ==> (concat xs = concat ys) = (xs = ys)"
bulwahn@40611
  1576
proof (induct xs arbitrary: ys)
bulwahn@40611
  1577
  case (Cons x xs ys)
bulwahn@40611
  1578
  thus ?case by (cases ys) auto
bulwahn@40611
  1579
qed (auto)
bulwahn@40611
  1580
bulwahn@40611
  1581
lemma concat_injective: "concat xs = concat ys ==> length xs = length ys ==> \<forall>(x, y) \<in> set (zip xs ys). length x = length y ==> xs = ys"
bulwahn@40611
  1582
by (simp add: concat_eq_concat_iff)
bulwahn@40611
  1583
wenzelm@13114
  1584
haftmann@50963
  1585
subsubsection {* @{const nth} *}
wenzelm@13114
  1586
haftmann@29764
  1587
lemma nth_Cons_0 [simp, code]: "(x # xs)!0 = x"
nipkow@13145
  1588
by auto
wenzelm@13114
  1589
haftmann@29764
  1590
lemma nth_Cons_Suc [simp, code]: "(x # xs)!(Suc n) = xs!n"
nipkow@13145
  1591
by auto
wenzelm@13114
  1592
wenzelm@13142
  1593
declare nth.simps [simp del]
wenzelm@13114
  1594
nipkow@42713
  1595
lemma nth_Cons_pos[simp]: "0 < n \<Longrightarrow> (x#xs) ! n = xs ! (n - 1)"
nipkow@42713
  1596
by(auto simp: Nat.gr0_conv_Suc)
nipkow@42713
  1597
wenzelm@13114
  1598
lemma nth_append:
nipkow@24526
  1599
  "(xs @ ys)!n = (if n < length xs then xs!n else ys!(n - length xs))"
nipkow@24526
  1600
apply (induct xs arbitrary: n, simp)
paulson@14208
  1601
apply (case_tac n, auto)
nipkow@13145
  1602
done
wenzelm@13114
  1603
nipkow@14402
  1604
lemma nth_append_length [simp]: "(xs @ x # ys) ! length xs = x"
wenzelm@25221
  1605
by (induct xs) auto
nipkow@14402
  1606
nipkow@14402
  1607
lemma nth_append_length_plus[simp]: "(xs @ ys) ! (length xs + n) = ys ! n"
wenzelm@25221
  1608
by (induct xs) auto
nipkow@14402
  1609
nipkow@24526
  1610
lemma nth_map [simp]: "n < length xs ==> (map f xs)!n = f(xs!n)"
nipkow@24526
  1611
apply (induct xs arbitrary: n, simp)
paulson@14208
  1612
apply (case_tac n, auto)
nipkow@13145
  1613
done
wenzelm@13114
  1614
noschinl@46707
  1615
lemma nth_tl:
noschinl@46707
  1616
  assumes "n < length (tl x)" shows "tl x ! n = x ! Suc n"
noschinl@46707
  1617
using assms by (induct x) auto
noschinl@46707
  1618
nipkow@18423
  1619
lemma hd_conv_nth: "xs \<noteq> [] \<Longrightarrow> hd xs = xs!0"
nipkow@18423
  1620
by(cases xs) simp_all
nipkow@18423
  1621
nipkow@18049
  1622
nipkow@18049
  1623
lemma list_eq_iff_nth_eq:
nipkow@24526
  1624
 "(xs = ys) = (length xs = length ys \<and> (ALL i<length xs. xs!i = ys!i))"
nipkow@24526
  1625
apply(induct xs arbitrary: ys)
paulson@24632
  1626
 apply force
nipkow@18049
  1627
apply(case_tac ys)
nipkow@18049
  1628
 apply simp
nipkow@18049
  1629
apply(simp add:nth_Cons split:nat.split)apply blast
nipkow@18049
  1630
done
nipkow@18049
  1631
wenzelm@13142
  1632
lemma set_conv_nth: "set xs = {xs!i | i. i < length xs}"
paulson@15251
  1633
apply (induct xs, simp, simp)
nipkow@13145
  1634
apply safe
paulson@24632
  1635
apply (metis nat_case_0 nth.simps zero_less_Suc)
paulson@24632
  1636
apply (metis less_Suc_eq_0_disj nth_Cons_Suc)
paulson@14208
  1637
apply (case_tac i, simp)
paulson@24632
  1638
apply (metis diff_Suc_Suc nat_case_Suc nth.simps zero_less_diff)
nipkow@13145
  1639
done
wenzelm@13114
  1640
nipkow@17501
  1641
lemma in_set_conv_nth: "(x \<in> set xs) = (\<exists>i < length xs. xs!i = x)"
nipkow@17501
  1642
by(auto simp:set_conv_nth)
nipkow@17501
  1643
haftmann@52297
  1644
lemma nth_equal_first_eq:
haftmann@52297
  1645
  assumes "x \<notin> set xs"
haftmann@52297
  1646
  assumes "n \<le> length xs"
haftmann@52297
  1647
  shows "(x # xs) ! n = x \<longleftrightarrow> n = 0" (is "?lhs \<longleftrightarrow> ?rhs")
haftmann@52297
  1648
proof
haftmann@52297
  1649
  assume ?lhs
haftmann@52297
  1650
  show ?rhs
haftmann@52297
  1651
  proof (rule ccontr)
haftmann@52297
  1652
    assume "n \<noteq> 0"
haftmann@52297
  1653
    then have "n > 0" by simp
haftmann@52297
  1654
    with `?lhs` have "xs ! (n - 1) = x" by simp
haftmann@52297
  1655
    moreover from `n > 0` `n \<le> length xs` have "n - 1 < length xs" by simp
haftmann@52297
  1656
    ultimately have "\<exists>i<length xs. xs ! i = x" by auto
haftmann@52297
  1657
    with `x \<notin> set xs` in_set_conv_nth [of x xs] show False by simp
haftmann@52297
  1658
  qed
haftmann@52297
  1659
next
haftmann@52297
  1660
  assume ?rhs then show ?lhs by simp
haftmann@52297
  1661
qed
haftmann@52297
  1662
haftmann@52297
  1663
lemma nth_non_equal_first_eq:
haftmann@52297
  1664
  assumes "x \<noteq> y"
haftmann@52297
  1665
  shows "(x # xs) ! n = y \<longleftrightarrow> xs ! (n - 1) = y \<and> n > 0" (is "?lhs \<longleftrightarrow> ?rhs")
haftmann@52297
  1666
proof
haftmann@52297
  1667
  assume "?lhs" with assms have "n > 0" by (cases n) simp_all
haftmann@52297
  1668
  with `?lhs` show ?rhs by simp
haftmann@52297
  1669
next
haftmann@52297
  1670
  assume "?rhs" then show "?lhs" by simp
haftmann@52297
  1671
qed
haftmann@52297
  1672
nipkow@13145
  1673
lemma list_ball_nth: "[| n < length xs; !x : set xs. P x|] ==> P(xs!n)"
nipkow@13145
  1674
by (auto simp add: set_conv_nth)
wenzelm@13114
  1675
wenzelm@13142
  1676
lemma nth_mem [simp]: "n < length xs ==> xs!n : set xs"
nipkow@13145
  1677
by (auto simp add: set_conv_nth)
wenzelm@13114
  1678
wenzelm@13114
  1679
lemma all_nth_imp_all_set:
nipkow@13145
  1680
"[| !i < length xs. P(xs!i); x : set xs|] ==> P x"
nipkow@13145
  1681
by (auto simp add: set_conv_nth)
wenzelm@13114
  1682
wenzelm@13114
  1683
lemma all_set_conv_all_nth:
nipkow@13145
  1684
"(\<forall>x \<in> set xs. P x) = (\<forall>i. i < length xs --> P (xs ! i))"
nipkow@13145
  1685
by (auto simp add: set_conv_nth)
wenzelm@13114
  1686
kleing@25296
  1687
lemma rev_nth:
kleing@25296
  1688
  "n < size xs \<Longrightarrow> rev xs ! n = xs ! (length xs - Suc n)"
kleing@25296
  1689
proof (induct xs arbitrary: n)
kleing@25296
  1690
  case Nil thus ?case by simp
kleing@25296
  1691
next
kleing@25296
  1692
  case (Cons x xs)
kleing@25296
  1693
  hence n: "n < Suc (length xs)" by simp
kleing@25296
  1694
  moreover
kleing@25296
  1695
  { assume "n < length xs"
wenzelm@54511
  1696
    with n obtain n' where n': "length xs - n = Suc n'"
kleing@25296
  1697
      by (cases "length xs - n", auto)
kleing@25296
  1698
    moreover
wenzelm@54511
  1699
    from n' have "length xs - Suc n = n'" by simp
kleing@25296
  1700
    ultimately
kleing@25296
  1701
    have "xs ! (length xs - Suc n) = (x # xs) ! (length xs - n)" by simp
kleing@25296
  1702
  }
kleing@25296
  1703
  ultimately
kleing@25296
  1704
  show ?case by (clarsimp simp add: Cons nth_append)
kleing@25296
  1705
qed
wenzelm@13114
  1706
nipkow@31159
  1707
lemma Skolem_list_nth:
nipkow@31159
  1708
  "(ALL i<k. EX x. P i x) = (EX xs. size xs = k & (ALL i<k. P i (xs!i)))"
nipkow@31159
  1709
  (is "_ = (EX xs. ?P k xs)")
nipkow@31159
  1710
proof(induct k)
nipkow@31159
  1711
  case 0 show ?case by simp
nipkow@31159
  1712
next
nipkow@31159
  1713
  case (Suc k)
nipkow@31159
  1714
  show ?case (is "?L = ?R" is "_ = (EX xs. ?P' xs)")
nipkow@31159
  1715
  proof
nipkow@31159
  1716
    assume "?R" thus "?L" using Suc by auto
nipkow@31159
  1717
  next
nipkow@31159
  1718
    assume "?L"
nipkow@31159
  1719
    with Suc obtain x xs where "?P k xs & P k x" by (metis less_Suc_eq)
nipkow@31159
  1720
    hence "?P'(xs@[x])" by(simp add:nth_append less_Suc_eq)
nipkow@31159
  1721
    thus "?R" ..
nipkow@31159
  1722
  qed
nipkow@31159
  1723
qed
nipkow@31159
  1724
nipkow@31159
  1725
haftmann@50963
  1726
subsubsection {* @{const list_update} *}
wenzelm@13114
  1727
nipkow@24526
  1728
lemma length_list_update [simp]: "length(xs[i:=x]) = length xs"
nipkow@24526
  1729
by (induct xs arbitrary: i) (auto split: nat.split)
wenzelm@13114
  1730
wenzelm@13114
  1731
lemma nth_list_update:
nipkow@24526
  1732
"i < length xs==> (xs[i:=x])!j = (if i = j then x else xs!j)"
nipkow@24526
  1733
by (induct xs arbitrary: i j) (auto simp add: nth_Cons split: nat.split)
wenzelm@13114
  1734
wenzelm@13142
  1735
lemma nth_list_update_eq [simp]: "i < length xs ==> (xs[i:=x])!i = x"
nipkow@13145
  1736
by (simp add: nth_list_update)
wenzelm@13114
  1737
nipkow@24526
  1738
lemma nth_list_update_neq [simp]: "i \<noteq> j ==> xs[i:=x]!j = xs!j"
nipkow@24526
  1739
by (induct xs arbitrary: i j) (auto simp add: nth_Cons split: nat.split)
wenzelm@13114
  1740
nipkow@24526
  1741
lemma list_update_id[simp]: "xs[i := xs!i] = xs"
nipkow@24526
  1742
by (induct xs arbitrary: i) (simp_all split:nat.splits)
nipkow@24526
  1743
nipkow@24526
  1744
lemma list_update_beyond[simp]: "length xs \<le> i \<Longrightarrow> xs[i:=x] = xs"
nipkow@24526
  1745
apply (induct xs arbitrary: i)
nipkow@17501
  1746
 apply simp
nipkow@17501
  1747
apply (case_tac i)
nipkow@17501
  1748
apply simp_all
nipkow@17501
  1749
done
nipkow@17501
  1750
nipkow@31077
  1751
lemma list_update_nonempty[simp]: "xs[k:=x] = [] \<longleftrightarrow> xs=[]"
nipkow@31077
  1752
by(metis length_0_conv length_list_update)
nipkow@31077
  1753
wenzelm@13114
  1754
lemma list_update_same_conv:
nipkow@24526
  1755
"i < length xs ==> (xs[i := x] = xs) = (xs!i = x)"
nipkow@24526
  1756
by (induct xs arbitrary: i) (auto split: nat.split)
wenzelm@13114
  1757
nipkow@14187
  1758
lemma list_update_append1:
nipkow@24526
  1759
 "i < size xs \<Longrightarrow> (xs @ ys)[i:=x] = xs[i:=x] @ ys"
nipkow@24526
  1760
apply (induct xs arbitrary: i, simp)
nipkow@14187
  1761
apply(simp split:nat.split)
nipkow@14187
  1762
done
nipkow@14187
  1763
kleing@15868
  1764
lemma list_update_append:
nipkow@24526
  1765
  "(xs @ ys) [n:= x] = 
kleing@15868
  1766
  (if n < length xs then xs[n:= x] @ ys else xs @ (ys [n-length xs:= x]))"
nipkow@24526
  1767
by (induct xs arbitrary: n) (auto split:nat.splits)
kleing@15868
  1768
nipkow@14402
  1769
lemma list_update_length [simp]:
nipkow@14402
  1770
 "(xs @ x # ys)[length xs := y] = (xs @ y # ys)"
nipkow@14402
  1771
by (induct xs, auto)
nipkow@14402
  1772
nipkow@31258
  1773
lemma map_update: "map f (xs[k:= y]) = (map f xs)[k := f y]"
nipkow@31258
  1774
by(induct xs arbitrary: k)(auto split:nat.splits)
nipkow@31258
  1775
nipkow@31258
  1776
lemma rev_update:
nipkow@31258
  1777
  "k < length xs \<Longrightarrow> rev (xs[k:= y]) = (rev xs)[length xs - k - 1 := y]"
nipkow@31258
  1778
by (induct xs arbitrary: k) (auto simp: list_update_append split:nat.splits)
nipkow@31258
  1779
wenzelm@13114
  1780
lemma update_zip:
nipkow@31080
  1781
  "(zip xs ys)[i:=xy] = zip (xs[i:=fst xy]) (ys[i:=snd xy])"
nipkow@24526
  1782
by (induct ys arbitrary: i xy xs) (auto, case_tac xs, auto split: nat.split)
nipkow@24526
  1783
nipkow@24526
  1784
lemma set_update_subset_insert: "set(xs[i:=x]) <= insert x (set xs)"
nipkow@24526
  1785
by (induct xs arbitrary: i) (auto split: nat.split)
wenzelm@13114
  1786
wenzelm@13114
  1787
lemma set_update_subsetI: "[| set xs <= A; x:A |] ==> set(xs[i := x]) <= A"
nipkow@13145
  1788
by (blast dest!: set_update_subset_insert [THEN subsetD])
wenzelm@13114
  1789
nipkow@24526
  1790
lemma set_update_memI: "n < length xs \<Longrightarrow> x \<in> set (xs[n := x])"
nipkow@24526
  1791
by (induct xs arbitrary: n) (auto split:nat.splits)
kleing@15868
  1792
nipkow@31077
  1793
lemma list_update_overwrite[simp]:
haftmann@24796
  1794
  "xs [i := x, i := y] = xs [i := y]"
nipkow@31077
  1795
apply (induct xs arbitrary: i) apply simp
nipkow@31077
  1796
apply (case_tac i, simp_all)
haftmann@24796
  1797
done
haftmann@24796
  1798
haftmann@24796
  1799
lemma list_update_swap:
haftmann@24796
  1800
  "i \<noteq> i' \<Longrightarrow> xs [i := x, i' := x'] = xs [i' := x', i := x]"
haftmann@24796
  1801
apply (induct xs arbitrary: i i')
haftmann@24796
  1802
apply simp
haftmann@24796
  1803
apply (case_tac i, case_tac i')
haftmann@24796
  1804
apply auto
haftmann@24796
  1805
apply (case_tac i')
haftmann@24796
  1806
apply auto
haftmann@24796
  1807
done
haftmann@24796
  1808
haftmann@29764
  1809
lemma list_update_code [code]:
haftmann@29764
  1810
  "[][i := y] = []"
haftmann@29764
  1811
  "(x # xs)[0 := y] = y # xs"
haftmann@29764
  1812
  "(x # xs)[Suc i := y] = x # xs[i := y]"
haftmann@29764
  1813
  by simp_all
haftmann@29764
  1814
wenzelm@13114
  1815
haftmann@50963
  1816
subsubsection {* @{const last} and @{const butlast} *}
wenzelm@13114
  1817
wenzelm@13142
  1818
lemma last_snoc [simp]: "last (xs @ [x]) = x"
nipkow@13145
  1819
by (induct xs) auto
wenzelm@13114
  1820
wenzelm@13142
  1821
lemma butlast_snoc [simp]: "butlast (xs @ [x]) = xs"
nipkow@13145
  1822
by (induct xs) auto
wenzelm@13114
  1823
nipkow@14302
  1824
lemma last_ConsL: "xs = [] \<Longrightarrow> last(x#xs) = x"
huffman@45792
  1825
  by simp
nipkow@14302
  1826
nipkow@14302
  1827
lemma last_ConsR: "xs \<noteq> [] \<Longrightarrow> last(x#xs) = last xs"
huffman@45792
  1828
  by simp
nipkow@14302
  1829
nipkow@14302
  1830
lemma last_append: "last(xs @ ys) = (if ys = [] then last xs else last ys)"
nipkow@14302
  1831
by (induct xs) (auto)
nipkow@14302
  1832
nipkow@14302
  1833
lemma last_appendL[simp]: "ys = [] \<Longrightarrow> last(xs @ ys) = last xs"
nipkow@14302
  1834
by(simp add:last_append)
nipkow@14302
  1835
nipkow@14302
  1836
lemma last_appendR[simp]: "ys \<noteq> [] \<Longrightarrow> last(xs @ ys) = last ys"
nipkow@14302
  1837
by(simp add:last_append)
nipkow@14302
  1838
noschinl@46707
  1839
lemma last_tl: "xs = [] \<or> tl xs \<noteq> [] \<Longrightarrow>last (tl xs) = last xs"
noschinl@46707
  1840
by (induct xs) simp_all
noschinl@46707
  1841
noschinl@46707
  1842
lemma butlast_tl: "butlast (tl xs) = tl (butlast xs)"
noschinl@46707
  1843
by (induct xs) simp_all
noschinl@46707
  1844
nipkow@17762
  1845
lemma hd_rev: "xs \<noteq> [] \<Longrightarrow> hd(rev xs) = last xs"
nipkow@17762
  1846
by(rule rev_exhaust[of xs]) simp_all
nipkow@17762
  1847
nipkow@17762
  1848
lemma last_rev: "xs \<noteq> [] \<Longrightarrow> last(rev xs) = hd xs"
nipkow@17762
  1849
by(cases xs) simp_all
nipkow@17762
  1850
nipkow@17765
  1851
lemma last_in_set[simp]: "as \<noteq> [] \<Longrightarrow> last as \<in> set as"
nipkow@17765
  1852
by (induct as) auto
nipkow@17762
  1853
wenzelm@13142
  1854
lemma length_butlast [simp]: "length (butlast xs) = length xs - 1"
nipkow@13145
  1855
by (induct xs rule: rev_induct) auto
wenzelm@13114
  1856
wenzelm@13114
  1857
lemma butlast_append:
nipkow@24526
  1858
  "butlast (xs @ ys) = (if ys = [] then butlast xs else xs @ butlast ys)"
nipkow@24526
  1859
by (induct xs arbitrary: ys) auto
wenzelm@13114
  1860
wenzelm@13142
  1861
lemma append_butlast_last_id [simp]:
nipkow@13145
  1862
"xs \<noteq> [] ==> butlast xs @ [last xs] = xs"
nipkow@13145
  1863
by (induct xs) auto
wenzelm@13114
  1864
wenzelm@13142
  1865
lemma in_set_butlastD: "x : set (butlast xs) ==> x : set xs"
nipkow@13145
  1866
by (induct xs) (auto split: split_if_asm)
wenzelm@13114
  1867
wenzelm@13114
  1868
lemma in_set_butlast_appendI:
nipkow@13145
  1869
"x : set (butlast xs) | x : set (butlast ys) ==> x : set (butlast (xs @ ys))"
nipkow@13145
  1870
by (auto dest: in_set_butlastD simp add: butlast_append)
wenzelm@13114
  1871
nipkow@24526
  1872
lemma last_drop[simp]: "n < length xs \<Longrightarrow> last (drop n xs) = last xs"
nipkow@24526
  1873
apply (induct xs arbitrary: n)
nipkow@17501
  1874
 apply simp
nipkow@17501
  1875
apply (auto split:nat.split)
nipkow@17501
  1876
done
nipkow@17501
  1877
noschinl@46707
  1878
lemma nth_butlast:
noschinl@46707
  1879
  assumes "n < length (butlast xs)" shows "butlast xs ! n = xs ! n"
noschinl@46707
  1880
proof (cases xs)
noschinl@46707
  1881
  case (Cons y ys)
noschinl@46707
  1882
  moreover from assms have "butlast xs ! n = (butlast xs @ [last xs]) ! n"
noschinl@46707
  1883
    by (simp add: nth_append)
noschinl@46707
  1884
  ultimately show ?thesis using append_butlast_last_id by simp
noschinl@46707
  1885
qed simp
noschinl@46707
  1886
huffman@30128
  1887
lemma last_conv_nth: "xs\<noteq>[] \<Longrightarrow> last xs = xs!(length xs - 1)"
nipkow@17589
  1888
by(induct xs)(auto simp:neq_Nil_conv)
nipkow@17589
  1889
huffman@30128
  1890
lemma butlast_conv_take: "butlast xs = take (length xs - 1) xs"
huffman@26584
  1891
by (induct xs, simp, case_tac xs, simp_all)
huffman@26584
  1892
nipkow@31077
  1893
lemma last_list_update:
nipkow@31077
  1894
  "xs \<noteq> [] \<Longrightarrow> last(xs[k:=x]) = (if k = size xs - 1 then x else last xs)"
nipkow@31077
  1895
by (auto simp: last_conv_nth)
nipkow@31077
  1896
nipkow@31077
  1897
lemma butlast_list_update:
nipkow@31077
  1898
  "butlast(xs[k:=x]) =
nipkow@31077
  1899
 (if k = size xs - 1 then butlast xs else (butlast xs)[k:=x])"
nipkow@31077
  1900
apply(cases xs rule:rev_cases)
nipkow@31077
  1901
apply simp
nipkow@31077
  1902
apply(simp add:list_update_append split:nat.splits)
nipkow@31077
  1903
done
nipkow@31077
  1904
haftmann@36846
  1905
lemma last_map:
haftmann@36846
  1906
  "xs \<noteq> [] \<Longrightarrow> last (map f xs) = f (last xs)"
haftmann@36846
  1907
  by (cases xs rule: rev_cases) simp_all
haftmann@36846
  1908
haftmann@36846
  1909
lemma map_butlast:
haftmann@36846
  1910
  "map f (butlast xs) = butlast (map f xs)"
haftmann@36846
  1911
  by (induct xs) simp_all
haftmann@36846
  1912
nipkow@40476
  1913
lemma snoc_eq_iff_butlast:
nipkow@40476
  1914
  "xs @ [x] = ys \<longleftrightarrow> (ys \<noteq> [] & butlast ys = xs & last ys = x)"
nipkow@40476
  1915
by (metis append_butlast_last_id append_is_Nil_conv butlast_snoc last_snoc not_Cons_self)
nipkow@40476
  1916
haftmann@24796
  1917
haftmann@50963
  1918
subsubsection {* @{const take} and @{const drop} *}
wenzelm@13114
  1919
wenzelm@13142
  1920
lemma take_0 [simp]: "take 0 xs = []"
nipkow@13145
  1921
by (induct xs) auto
wenzelm@13114
  1922
wenzelm@13142
  1923
lemma drop_0 [simp]: "drop 0 xs = xs"
nipkow@13145
  1924
by (induct xs) auto
wenzelm@13114
  1925
wenzelm@13142
  1926
lemma take_Suc_Cons [simp]: "take (Suc n) (x # xs) = x # take n xs"
nipkow@13145
  1927
by simp
wenzelm@13114
  1928
wenzelm@13142
  1929
lemma drop_Suc_Cons [simp]: "drop (Suc n) (x # xs) = drop n xs"
nipkow@13145
  1930
by simp
wenzelm@13114
  1931
wenzelm@13142
  1932
declare take_Cons [simp del] and drop_Cons [simp del]
wenzelm@13114
  1933
huffman@30128
  1934
lemma take_1_Cons [simp]: "take 1 (x # xs) = [x]"
huffman@30128
  1935
  unfolding One_nat_def by simp
huffman@30128
  1936
huffman@30128
  1937
lemma drop_1_Cons [simp]: "drop 1 (x # xs) = xs"
huffman@30128
  1938
  unfolding One_nat_def by simp
huffman@30128
  1939
nipkow@15110
  1940
lemma take_Suc: "xs ~= [] ==> take (Suc n) xs = hd xs # take n (tl xs)"
nipkow@15110
  1941
by(clarsimp simp add:neq_Nil_conv)
nipkow@15110
  1942
nipkow@14187
  1943
lemma drop_Suc: "drop (Suc n) xs = drop n (tl xs)"
nipkow@14187
  1944
by(cases xs, simp_all)
nipkow@14187
  1945
huffman@26584
  1946
lemma take_tl: "take n (tl xs) = tl (take (Suc n) xs)"
huffman@26584
  1947
by (induct xs arbitrary: n) simp_all
huffman@26584
  1948
nipkow@24526
  1949
lemma drop_tl: "drop n (tl xs) = tl(drop n xs)"
nipkow@24526
  1950
by(induct xs arbitrary: n, simp_all add:drop_Cons drop_Suc split:nat.split)
nipkow@24526
  1951
huffman@26584
  1952
lemma tl_take: "tl (take n xs) = take (n - 1) (tl xs)"
huffman@26584
  1953
by (cases n, simp, cases xs, auto)
huffman@26584
  1954
huffman@26584
  1955
lemma tl_drop: "tl (drop n xs) = drop n (tl xs)"
huffman@26584
  1956
by (simp only: drop_tl)
huffman@26584
  1957
nipkow@24526
  1958
lemma nth_via_drop: "drop n xs = y#ys \<Longrightarrow> xs!n = y"
nipkow@24526
  1959
apply (induct xs arbitrary: n, simp)
nipkow@14187
  1960
apply(simp add:drop_Cons nth_Cons split:nat.splits)
nipkow@14187
  1961
done
nipkow@14187
  1962
nipkow@13913
  1963
lemma take_Suc_conv_app_nth:
nipkow@24526
  1964
  "i < length xs \<Longrightarrow> take (Suc i) xs = take i xs @ [xs!i]"
nipkow@24526
  1965
apply (induct xs arbitrary: i, simp)
paulson@14208
  1966
apply (case_tac i, auto)
nipkow@13913
  1967
done
nipkow@13913
  1968
mehta@14591
  1969
lemma drop_Suc_conv_tl:
nipkow@24526
  1970
  "i < length xs \<Longrightarrow> (xs!i) # (drop (Suc i) xs) = drop i xs"
nipkow@24526
  1971
apply (induct xs arbitrary: i, simp)
mehta@14591
  1972
apply (case_tac i, auto)
mehta@14591
  1973
done
mehta@14591
  1974
nipkow@24526
  1975
lemma length_take [simp]: "length (take n xs) = min (length xs) n"
nipkow@24526
  1976
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
nipkow@24526
  1977
nipkow@24526
  1978
lemma length_drop [simp]: "length (drop n xs) = (length xs - n)"
nipkow@24526
  1979
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
nipkow@24526
  1980
nipkow@24526
  1981
lemma take_all [simp]: "length xs <= n ==> take n xs = xs"
nipkow@24526
  1982
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
nipkow@24526
  1983
nipkow@24526
  1984
lemma drop_all [simp]: "length xs <= n ==> drop n xs = []"
nipkow@24526
  1985
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
wenzelm@13114
  1986
wenzelm@13142
  1987
lemma take_append [simp]:
nipkow@24526
  1988
  "take n (xs @ ys) = (take n xs @ take (n - length xs) ys)"
nipkow@24526
  1989
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
wenzelm@13114
  1990
wenzelm@13142
  1991
lemma drop_append [simp]:
nipkow@24526
  1992
  "drop n (xs @ ys) = drop n xs @ drop (n - length xs) ys"
nipkow@24526
  1993
by (induct n arbitrary: xs) (auto, case_tac xs, auto)
nipkow@24526
  1994
nipkow@24526
  1995
lemma take_take [simp]: "take n (take m xs) = take (min n m) xs"
nipkow@24526
  1996
apply (induct m arbitrary: xs n, auto)
paulson@14208
  1997
apply (case_tac xs, auto)
nipkow@15236
  1998
apply (case_tac n, auto)
nipkow@13145
  1999
done
wenzelm@13142
  2000
nipkow@24526
  2001
lemma drop_drop [simp]: "drop n (drop m xs) = drop (n + m) xs"
nipkow@24526
  2002
apply (induct m arbitrary: xs, auto)
paulson@14208
  2003
apply (case_tac xs, auto)
nipkow@13145
  2004
done
wenzelm@13114
  2005
nipkow@24526
  2006
lemma take_drop: "take n (drop m xs) = drop m (take (n + m) xs)"
nipkow@24526
  2007
apply (induct m arbitrary: xs n, auto)
paulson@14208
  2008
apply (case_tac xs, auto)
nipkow@13145
  2009
done
wenzelm@13114
  2010
nipkow@24526
  2011
lemma drop_take: "drop n (take m xs) = take (m-n) (drop n xs)"
nipkow@24526
  2012
apply(induct xs arbitrary: m n)
nipkow@14802
  2013
 apply simp
nipkow@14802
  2014
apply(simp add: take_Cons drop_Cons split:nat.split)
nipkow@14802
  2015
done
nipkow@14802
  2016
nipkow@24526
  2017
lemma append_take_drop_id [simp]: "take n xs @ drop n xs = xs"
nipkow@24526
  2018
apply (induct n arbitrary: xs, auto)
paulson@14208
  2019
apply (case_tac xs, auto)
nipkow@13145
  2020
done
wenzelm@13114
  2021
nipkow@24526
  2022
lemma take_eq_Nil[simp]: "(take n xs = []) = (n = 0 \<or> xs = [])"
nipkow@24526
  2023
apply(induct xs arbitrary: n)
nipkow@15110
  2024
 apply simp
nipkow@15110
  2025
apply(simp add:take_Cons split:nat.split)
nipkow@15110
  2026
done
nipkow@15110
  2027
nipkow@24526
  2028
lemma drop_eq_Nil[simp]: "(drop n xs = []) = (length xs <= n)"
nipkow@24526
  2029
apply(induct xs arbitrary: n)
nipkow@15110
  2030
apply simp
nipkow@15110
  2031
apply(simp add:drop_Cons split:nat.split)
nipkow@15110
  2032
done
nipkow@15110
  2033
nipkow@24526
  2034
lemma take_map: "take n (map f xs) = map f (take n xs)"
nipkow@24526
  2035
apply (induct n arbitrary: xs, auto)
paulson@14208
  2036
apply (case_tac xs, auto)
nipkow@13145
  2037
done
wenzelm@13114
  2038
nipkow@24526
  2039
lemma drop_map: "drop n (map f xs) = map f (drop n xs)"
nipkow@24526
  2040
apply (induct n arbitrary: xs, auto)
paulson@14208
  2041
apply (case_tac xs, auto)
nipkow@13145
  2042
done
wenzelm@13114
  2043
nipkow@24526
  2044
lemma rev_take: "rev (take i xs) = drop (length xs - i) (rev xs)"
nipkow@24526
  2045
apply (induct xs arbitrary: i, auto)
paulson@14208
  2046
apply (case_tac i, auto)
nipkow@13145
  2047
done
wenzelm@13114
  2048
nipkow@24526
  2049
lemma rev_drop: "rev (drop i xs) = take (length xs - i) (rev xs)"
nipkow@24526
  2050
apply (induct xs arbitrary: i, auto)
paulson@14208
  2051
apply (case_tac i, auto)
nipkow@13145
  2052
done
wenzelm@13114
  2053
nipkow@24526
  2054
lemma nth_take [simp]: "i < n ==> (take n xs)!i = xs!i"
nipkow@24526
  2055
apply (induct xs arbitrary: i n, auto)
paulson@14208
  2056
apply (case_tac n, blast)
paulson@14208
  2057
apply (case_tac i, auto)
nipkow@13145
  2058
done
wenzelm@13114
  2059
wenzelm@13142
  2060
lemma nth_drop [simp]:
nipkow@24526
  2061
  "n + i <= length xs ==> (drop n xs)!i = xs!(n + i)"
nipkow@24526
  2062
apply (induct n arbitrary: xs i, auto)
paulson@14208
  2063
apply (case_tac xs, auto)
nipkow@13145
  2064
done
wenzelm@13114
  2065
huffman@26584
  2066
lemma butlast_take:
huffman@30128
  2067
  "n <= length xs ==> butlast (take n xs) = take (n - 1) xs"
huffman@26584
  2068
by (simp add: butlast_conv_take min_max.inf_absorb1 min_max.inf_absorb2)
huffman@26584
  2069
huffman@26584
  2070
lemma butlast_drop: "butlast (drop n xs) = drop n (butlast xs)"
huffman@30128
  2071
by (simp add: butlast_conv_take drop_take add_ac)
huffman@26584
  2072
huffman@26584
  2073
lemma take_butlast: "n < length xs ==> take n (butlast xs) = take n xs"
huffman@26584
  2074
by (simp add: butlast_conv_take min_max.inf_absorb1)
huffman@26584
  2075
huffman@26584
  2076
lemma drop_butlast: "drop n (butlast xs) = butlast (drop n xs)"
huffman@30128
  2077
by (simp add: butlast_conv_take drop_take add_ac)
huffman@26584
  2078
bulwahn@47371
  2079
lemma hd_drop_conv_nth: "n < length xs \<Longrightarrow> hd(drop n xs) = xs!n"
nipkow@18423
  2080
by(simp add: hd_conv_nth)
nipkow@18423
  2081
nipkow@35248
  2082
lemma set_take_subset_set_take:
nipkow@35248
  2083
  "m <= n \<Longrightarrow> set(take m xs) <= set(take n xs)"
bulwahn@41695
  2084
apply (induct xs arbitrary: m n)
bulwahn@41695
  2085
apply simp
bulwahn@41695
  2086
apply (case_tac n)
bulwahn@41695
  2087
apply (auto simp: take_Cons)
bulwahn@41695
  2088
done
nipkow@35248
  2089
nipkow@24526
  2090
lemma set_take_subset: "set(take n xs) \<subseteq> set xs"
nipkow@24526
  2091
by(induct xs arbitrary: n)(auto simp:take_Cons split:nat.split)
nipkow@24526
  2092
nipkow@24526
  2093
lemma set_drop_subset: "set(drop n xs) \<subseteq> set xs"
nipkow@24526
  2094
by(induct xs arbitrary: n)(auto simp:drop_Cons split:nat.split)
nipkow@14025
  2095
nipkow@35248
  2096
lemma set_drop_subset_set_drop:
nipkow@35248
  2097
  "m >= n \<Longrightarrow> set(drop m xs) <= set(drop n xs)"
nipkow@35248
  2098
apply(induct xs arbitrary: m n)
nipkow@35248
  2099
apply(auto simp:drop_Cons split:nat.split)
nipkow@35248
  2100
apply (metis set_drop_subset subset_iff)
nipkow@35248
  2101
done
nipkow@35248
  2102
nipkow@14187
  2103
lemma in_set_takeD: "x : set(take n xs) \<Longrightarrow> x : set xs"
nipkow@14187
  2104
using set_take_subset by fast
nipkow@14187
  2105
nipkow@14187
  2106
lemma in_set_dropD: "x : set(drop n xs) \<Longrightarrow> x : set xs"
nipkow@14187
  2107
using set_drop_subset by fast
nipkow@14187
  2108
wenzelm@13114
  2109
lemma append_eq_conv_conj:
nipkow@24526
  2110
  "(xs @ ys = zs) = (xs = take (length xs) zs \<and> ys = drop (length xs) zs)"
nipkow@24526
  2111
apply (induct xs arbitrary: zs, simp, clarsimp)
paulson@14208
  2112
apply (case_tac zs, auto)
nipkow@13145
  2113
done
wenzelm@13114
  2114
nipkow@24526
  2115
lemma take_add: 
noschinl@43584
  2116
  "take (i+j) xs = take i xs @ take j (drop i xs)"
nipkow@24526
  2117
apply (induct xs arbitrary: i, auto) 
nipkow@24526
  2118
apply (case_tac i, simp_all)
paulson@14050
  2119
done
paulson@14050
  2120
nipkow@14300
  2121
lemma append_eq_append_conv_if:
wenzelm@54152
  2122
 "(xs\<^sub>1 @ xs\<^sub>2 = ys\<^sub>1 @ ys\<^sub>2) =
wenzelm@54152
  2123
  (if size xs\<^sub>1 \<le> size ys\<^sub>1
wenzelm@54152
  2124
   then xs\<^sub>1 = take (size xs\<^sub>1) ys\<^sub>1 \<and> xs\<^sub>2 = drop (size xs\<^sub>1) ys\<^sub>1 @ ys\<^sub>2
wenzelm@54152
  2125
   else take (size ys\<^sub>1) xs\<^sub>1 = ys\<^sub>1 \<and> drop (size ys\<^sub>1) xs\<^sub>1 @ xs\<^sub>2 = ys\<^sub>2)"
wenzelm@54152
  2126
apply(induct xs\<^sub>1 arbitrary: ys\<^sub>1)
nipkow@14300
  2127
 apply simp
wenzelm@54152
  2128
apply(case_tac ys\<^sub>1)
nipkow@14300
  2129
apply simp_all
nipkow@14300
  2130
done
nipkow@14300
  2131
nipkow@15110
  2132
lemma take_hd_drop:
huffman@30016
  2133
  "n < length xs \<Longrightarrow> take n xs @ [hd (drop n xs)] = take (Suc n) xs"
nipkow@24526
  2134
apply(induct xs arbitrary: n)
nipkow@15110
  2135
apply simp
nipkow@15110
  2136
apply(simp add:drop_Cons split:nat.split)
nipkow@15110
  2137
done
nipkow@15110
  2138
nipkow@17501
  2139
lemma id_take_nth_drop:
nipkow@17501
  2140
 "i < length xs \<Longrightarrow> xs = take i xs @ xs!i # drop (Suc i) xs" 
nipkow@17501
  2141
proof -
nipkow@17501
  2142
  assume si: "i < length xs"
nipkow@17501
  2143
  hence "xs = take (Suc i) xs @ drop (Suc i) xs" by auto
nipkow@17501
  2144
  moreover
nipkow@17501
  2145
  from si have "take (Suc i) xs = take i xs @ [xs!i]"
nipkow@17501
  2146
    apply (rule_tac take_Suc_conv_app_nth) by arith
nipkow@17501
  2147
  ultimately show ?thesis by auto
nipkow@17501
  2148
qed
nipkow@17501
  2149
  
nipkow@17501
  2150
lemma upd_conv_take_nth_drop:
nipkow@17501
  2151
 "i < length xs \<Longrightarrow> xs[i:=a] = take i xs @ a # drop (Suc i) xs"
nipkow@17501
  2152
proof -
nipkow@17501
  2153
  assume i: "i < length xs"
nipkow@17501
  2154
  have "xs[i:=a] = (take i xs @ xs!i # drop (Suc i) xs)[i:=a]"
nipkow@17501
  2155
    by(rule arg_cong[OF id_take_nth_drop[OF i]])
nipkow@17501
  2156
  also have "\<dots> = take i xs @ a # drop (Suc i) xs"
nipkow@17501
  2157
    using i by (simp add: list_update_append)
nipkow@17501
  2158
  finally show ?thesis .
nipkow@17501
  2159
qed
nipkow@17501
  2160
haftmann@24796
  2161
lemma nth_drop':
haftmann@24796
  2162
  "i < length xs \<Longrightarrow> xs ! i # drop (Suc i) xs = drop i xs"
haftmann@24796
  2163
apply (induct i arbitrary: xs)
haftmann@24796
  2164
apply (simp add: neq_Nil_conv)
haftmann@24796
  2165
apply (erule exE)+
haftmann@24796
  2166
apply simp
haftmann@24796
  2167
apply (case_tac xs)
haftmann@24796
  2168
apply simp_all
haftmann@24796
  2169
done
haftmann@24796
  2170
wenzelm@13114
  2171
haftmann@50963
  2172
subsubsection {* @{const takeWhile} and @{const dropWhile} *}
wenzelm@13114
  2173
hoelzl@33639
  2174
lemma length_takeWhile_le: "length (takeWhile P xs) \<le> length xs"
hoelzl@33639
  2175
  by (induct xs) auto
hoelzl@33639
  2176
wenzelm@13142
  2177
lemma takeWhile_dropWhile_id [simp]: "takeWhile P xs @ dropWhile P xs = xs"
nipkow@13145
  2178
by (induct xs) auto
wenzelm@13114
  2179
wenzelm@13142
  2180
lemma takeWhile_append1 [simp]:
nipkow@13145
  2181
"[| x:set xs; ~P(x)|] ==> takeWhile P (xs @ ys) = takeWhile P xs"
nipkow@13145
  2182
by (induct xs) auto
wenzelm@13114
  2183
wenzelm@13142
  2184
lemma takeWhile_append2 [simp]:
nipkow@13145
  2185
"(!!x. x : set xs ==> P x) ==> takeWhile P (xs @ ys) = xs @ takeWhile P ys"
nipkow@13145
  2186
by (induct xs) auto
wenzelm@13114
  2187
wenzelm@13142
  2188
lemma takeWhile_tail: "\<not> P x ==> takeWhile P (xs @ (x#l)) = takeWhile P xs"
nipkow@13145
  2189
by (induct xs) auto
wenzelm@13114
  2190
hoelzl@33639
  2191
lemma takeWhile_nth: "j < length (takeWhile P xs) \<Longrightarrow> takeWhile P xs ! j = xs ! j"
hoelzl@33639
  2192
apply (subst (3) takeWhile_dropWhile_id[symmetric]) unfolding nth_append by auto
hoelzl@33639
  2193
hoelzl@33639
  2194
lemma dropWhile_nth: "j < length (dropWhile P xs) \<Longrightarrow> dropWhile P xs ! j = xs ! (j + length (takeWhile P xs))"
hoelzl@33639
  2195
apply (subst (3) takeWhile_dropWhile_id[symmetric]) unfolding nth_append by auto
hoelzl@33639
  2196
hoelzl@33639
  2197
lemma length_dropWhile_le: "length (dropWhile P xs) \<le> length xs"
hoelzl@33639
  2198
by (induct xs) auto
hoelzl@33639
  2199
wenzelm@13142
  2200
lemma dropWhile_append1 [simp]:
nipkow@13145
  2201
"[| x : set xs; ~P(x)|] ==> dropWhile P (xs @ ys) = (dropWhile P xs)@ys"
nipkow@13145
  2202
by (induct xs) auto
wenzelm@13114
  2203
wenzelm@13142
  2204
lemma dropWhile_append2 [simp]:
nipkow@13145
  2205
"(!!x. x:set xs ==> P(x)) ==> dropWhile P (xs @ ys) = dropWhile P ys"
nipkow@13145
  2206
by (induct xs) auto
wenzelm@13114
  2207
noschinl@46707
  2208
lemma dropWhile_append3:
noschinl@46707
  2209
  "\<not> P y \<Longrightarrow>dropWhile P (xs @ y # ys) = dropWhile P xs @ y # ys"
noschinl@46707
  2210
by (induct xs) auto
noschinl@46707
  2211
noschinl@46707
  2212
lemma dropWhile_last:
noschinl@46707
  2213
  "x \<in> set xs \<Longrightarrow> \<not> P x \<Longrightarrow> last (dropWhile P xs) = last xs"
noschinl@46707
  2214
by (auto simp add: dropWhile_append3 in_set_conv_decomp)
noschinl@46707
  2215
noschinl@46707
  2216
lemma set_dropWhileD: "x \<in> set (dropWhile P xs) \<Longrightarrow> x \<in> set xs"
noschinl@46707
  2217
by (induct xs) (auto split: split_if_asm)
noschinl@46707
  2218
krauss@23971
  2219
lemma set_takeWhileD: "x : set (takeWhile P xs) ==> x : set xs \<and> P x"
nipkow@13145
  2220
by (induct xs) (auto split: split_if_asm)
wenzelm@13114
  2221
nipkow@13913
  2222
lemma takeWhile_eq_all_conv[simp]:
nipkow@13913
  2223
 "(takeWhile P xs = xs) = (\<forall>x \<in> set xs. P x)"
nipkow@13913
  2224
by(induct xs, auto)
nipkow@13913
  2225
nipkow@13913
  2226
lemma dropWhile_eq_Nil_conv[simp]:
nipkow@13913
  2227
 "(dropWhile P xs = []) = (\<forall>x \<in> set xs. P x)"
nipkow@13913
  2228
by(induct xs, auto)
nipkow@13913
  2229
nipkow@13913
  2230
lemma dropWhile_eq_Cons_conv:
nipkow@13913
  2231
 "(dropWhile P xs = y#ys) = (xs = takeWhile P xs @ y # ys & \<not> P y)"
nipkow@13913
  2232
by(induct xs, auto)
nipkow@13913
  2233
nipkow@31077
  2234
lemma distinct_takeWhile[simp]: "distinct xs ==> distinct (takeWhile P xs)"
nipkow@31077
  2235
by (induct xs) (auto dest: set_takeWhileD)
nipkow@31077
  2236
nipkow@31077
  2237
lemma distinct_dropWhile[simp]: "distinct xs ==> distinct (dropWhile P xs)"
nipkow@31077
  2238
by (induct xs) auto
nipkow@31077
  2239
hoelzl@33639
  2240
lemma takeWhile_map: "takeWhile P (map f xs) = map f (takeWhile (P \<circ> f) xs)"
hoelzl@33639
  2241
by (induct xs) auto
hoelzl@33639
  2242
hoelzl@33639
  2243
lemma dropWhile_map: "dropWhile P (map f xs) = map f (dropWhile (P \<circ> f) xs)"
hoelzl@33639
  2244
by (induct xs) auto
hoelzl@33639
  2245
hoelzl@33639
  2246
lemma takeWhile_eq_take: "takeWhile P xs = take (length (takeWhile P xs)) xs"
hoelzl@33639
  2247
by (induct xs) auto
hoelzl@33639
  2248
hoelzl@33639
  2249
lemma dropWhile_eq_drop: "dropWhile P xs = drop (length (takeWhile P xs)) xs"
hoelzl@33639
  2250
by (induct xs) auto
hoelzl@33639
  2251
hoelzl@33639
  2252
lemma hd_dropWhile:
hoelzl@33639
  2253
  "dropWhile P xs \<noteq> [] \<Longrightarrow> \<not> P (hd (dropWhile P xs))"
hoelzl@33639
  2254
using assms by (induct xs) auto
hoelzl@33639
  2255
hoelzl@33639
  2256
lemma takeWhile_eq_filter:
hoelzl@33639
  2257
  assumes "\<And> x. x \<in> set (dropWhile P xs) \<Longrightarrow> \<not> P x"
hoelzl@33639
  2258
  shows "takeWhile P xs = filter P xs"
hoelzl@33639
  2259
proof -
hoelzl@33639
  2260
  have A: "filter P xs = filter P (takeWhile P xs @ dropWhile P xs)"
hoelzl@33639
  2261
    by simp
hoelzl@33639
  2262
  have B: "filter P (dropWhile P xs) = []"
hoelzl@33639
  2263
    unfolding filter_empty_conv using assms by blast
hoelzl@33639
  2264
  have "filter P xs = takeWhile P xs"
hoelzl@33639
  2265
    unfolding A filter_append B
hoelzl@33639
  2266
    by (auto simp add: filter_id_conv dest: set_takeWhileD)
hoelzl@33639
  2267
  thus ?thesis ..
hoelzl@33639
  2268
qed
hoelzl@33639
  2269
hoelzl@33639
  2270
lemma takeWhile_eq_take_P_nth:
hoelzl@33639
  2271
  "\<lbrakk> \<And> i. \<lbrakk> i < n ; i < length xs \<rbrakk> \<Longrightarrow> P (xs ! i) ; n < length xs \<Longrightarrow> \<not> P (xs ! n) \<rbrakk> \<Longrightarrow>
hoelzl@33639
  2272
  takeWhile P xs = take n xs"
hoelzl@33639
  2273
proof (induct xs arbitrary: n)
hoelzl@33639
  2274
  case (Cons x xs)
hoelzl@33639
  2275
  thus ?case
hoelzl@33639
  2276
  proof (cases n)
hoelzl@33639
  2277
    case (Suc n') note this[simp]
hoelzl@33639
  2278
    have "P x" using Cons.prems(1)[of 0] by simp
hoelzl@33639
  2279
    moreover have "takeWhile P xs = take n' xs"
hoelzl@33639
  2280
    proof (rule Cons.hyps)
hoelzl@33639
  2281
      case goal1 thus "P (xs ! i)" using Cons.prems(1)[of "Suc i"] by simp
hoelzl@33639
  2282
    next case goal2 thus ?case using Cons by auto
hoelzl@33639
  2283
    qed
hoelzl@33639
  2284
    ultimately show ?thesis by simp
hoelzl@33639
  2285
   qed simp
hoelzl@33639
  2286
qed simp
hoelzl@33639
  2287
hoelzl@33639
  2288
lemma nth_length_takeWhile:
hoelzl@33639
  2289
  "length (takeWhile P xs) < length xs \<Longrightarrow> \<not> P (xs ! length (takeWhile P xs))"
hoelzl@33639
  2290
by (induct xs) auto
hoelzl@33639
  2291
hoelzl@33639
  2292
lemma length_takeWhile_less_P_nth:
hoelzl@33639
  2293
  assumes all: "\<And> i. i < j \<Longrightarrow> P (xs ! i)" and "j \<le> length xs"
hoelzl@33639
  2294
  shows "j \<le> length (takeWhile P xs)"
hoelzl@33639
  2295
proof (rule classical)
hoelzl@33639
  2296
  assume "\<not> ?thesis"
hoelzl@33639
  2297
  hence "length (takeWhile P xs) < length xs" using assms by simp
hoelzl@33639
  2298
  thus ?thesis using all `\<not> ?thesis` nth_length_takeWhile[of P xs] by auto
hoelzl@33639
  2299
qed
nipkow@31077
  2300
nipkow@17501
  2301
text{* The following two lemmmas could be generalized to an arbitrary
nipkow@17501
  2302
property. *}
nipkow@17501
  2303
nipkow@17501
  2304
lemma takeWhile_neq_rev: "\<lbrakk>distinct xs; x \<in> set xs\<rbrakk> \<Longrightarrow>
nipkow@17501
  2305
 takeWhile (\<lambda>y. y \<noteq> x) (rev xs) = rev (tl (dropWhile (\<lambda>y. y \<noteq> x) xs))"
nipkow@17501
  2306
by(induct xs) (auto simp: takeWhile_tail[where l="[]"])
nipkow@17501
  2307
nipkow@17501
  2308
lemma dropWhile_neq_rev: "\<lbrakk>distinct xs; x \<in> set xs\<rbrakk> \<Longrightarrow>
nipkow@17501
  2309
  dropWhile (\<lambda>y. y \<noteq> x) (rev xs) = x # rev (takeWhile (\<lambda>y. y \<noteq> x) xs)"
nipkow@17501
  2310
apply(induct xs)
nipkow@17501
  2311
 apply simp
nipkow@17501
  2312
apply auto
nipkow@17501
  2313
apply(subst dropWhile_append2)
nipkow@17501
  2314
apply auto
nipkow@17501
  2315
done
nipkow@17501
  2316
nipkow@18423
  2317
lemma takeWhile_not_last:
bulwahn@47371
  2318
 "distinct xs \<Longrightarrow> takeWhile (\<lambda>y. y \<noteq> last xs) xs = butlast xs"
nipkow@18423
  2319
apply(induct xs)
nipkow@18423
  2320
 apply simp
nipkow@18423
  2321
apply(case_tac xs)
nipkow@18423
  2322
apply(auto)
nipkow@18423
  2323
done
nipkow@18423
  2324
krauss@44884
  2325
lemma takeWhile_cong [fundef_cong]:
krauss@18336
  2326
  "[| l = k; !!x. x : set l ==> P x = Q x |] 
krauss@18336
  2327
  ==> takeWhile P l = takeWhile Q k"
nipkow@24349
  2328
by (induct k arbitrary: l) (simp_all)
krauss@18336
  2329
krauss@44884
  2330
lemma dropWhile_cong [fundef_cong]:
krauss@18336
  2331
  "[| l = k; !!x. x : set l ==> P x = Q x |] 
krauss@18336
  2332
  ==> dropWhile P l = dropWhile Q k"
nipkow@24349
  2333
by (induct k arbitrary: l, simp_all)
krauss@18336
  2334
haftmann@53517
  2335
lemma takeWhile_idem [simp]:
haftmann@53517
  2336
  "takeWhile P (takeWhile P xs) = takeWhile P xs"
haftmann@53517
  2337
  by (induct xs) auto
haftmann@53517
  2338
haftmann@53517
  2339
lemma dropWhile_idem [simp]:
haftmann@53517
  2340
  "dropWhile P (dropWhile P xs) = dropWhile P xs"
haftmann@53517
  2341
  by (induct xs) auto
haftmann@53517
  2342
wenzelm@13114
  2343
haftmann@50963
  2344
subsubsection {* @{const zip} *}
wenzelm@13114
  2345
wenzelm@13142
  2346
lemma zip_Nil [simp]: "zip [] ys = []"
nipkow@13145
  2347
by (induct ys) auto
wenzelm@13114
  2348
wenzelm@13142
  2349
lemma zip_Cons_Cons [simp]: "zip (x # xs) (y # ys) = (x, y) # zip xs ys"
nipkow@13145
  2350
by simp
wenzelm@13114
  2351
wenzelm@13142
  2352
declare zip_Cons [simp del]
wenzelm@13114
  2353
haftmann@36198
  2354
lemma [code]:
haftmann@36198
  2355
  "zip [] ys = []"
haftmann@36198
  2356
  "zip xs [] = []"
haftmann@36198
  2357
  "zip (x # xs) (y # ys) = (x, y) # zip xs ys"
haftmann@36198
  2358
  by (fact zip_Nil zip.simps(1) zip_Cons_Cons)+
haftmann@36198
  2359
nipkow@15281
  2360
lemma zip_Cons1:
nipkow@15281
  2361
 "zip (x#xs) ys = (case ys of [] \<Rightarrow> [] | y#ys \<Rightarrow> (x,y)#zip xs ys)"
nipkow@15281
  2362
by(auto split:list.split)
nipkow@15281
  2363
wenzelm@13142
  2364
lemma length_zip [simp]:
krauss@22493
  2365
"length (zip xs ys) = min (length xs) (length ys)"
krauss@22493
  2366
by (induct xs ys rule:list_induct2') auto
wenzelm@13114
  2367
haftmann@34965
  2368
lemma zip_obtain_same_length:
haftmann@34965
  2369
  assumes "\<And>zs ws n. length zs = length ws \<Longrightarrow> n = min (length xs) (length ys)
haftmann@34965
  2370
    \<Longrightarrow> zs = take n xs \<Longrightarrow> ws = take n ys \<Longrightarrow> P (zip zs ws)"
haftmann@34965
  2371
  shows "P (zip xs ys)"
haftmann@34965
  2372
proof -
haftmann@34965
  2373
  let ?n = "min (length xs) (length ys)"
haftmann@34965
  2374
  have "P (zip (take ?n xs) (take ?n ys))"
haftmann@34965
  2375
    by (rule assms) simp_all
haftmann@34965
  2376
  moreover have "zip xs ys = zip (take ?n xs) (take ?n ys)"
haftmann@34965
  2377
  proof (induct xs arbitrary: ys)
haftmann@34965
  2378
    case Nil then show ?case by simp
haftmann@34965
  2379
  next
haftmann@34965
  2380
    case (Cons x xs) then show ?case by (cases ys) simp_all
haftmann@34965
  2381
  qed
haftmann@34965
  2382
  ultimately show ?thesis by simp
haftmann@34965
  2383
qed
haftmann@34965
  2384
wenzelm@13114
  2385
lemma zip_append1:
krauss@22493
  2386
"zip (xs @ ys) zs =
nipkow@13145
  2387
zip xs (take (length xs) zs) @ zip ys (drop (length xs) zs)"
krauss@22493
  2388
by (induct xs zs rule:list_induct2') auto
wenzelm@13114
  2389
wenzelm@13114
  2390
lemma zip_append2:
krauss@22493
  2391
"zip xs (ys @ zs) =
nipkow@13145
  2392
zip (take (length ys) xs) ys @ zip (drop (length ys) xs) zs"
krauss@22493
  2393
by (induct xs ys rule:list_induct2') auto
wenzelm@13114
  2394
wenzelm@13142
  2395
lemma zip_append [simp]:
bulwahn@47371
  2396
 "[| length xs = length us |] ==>
nipkow@13145
  2397
zip (xs@ys) (us@vs) = zip xs us @ zip ys vs"
nipkow@13145
  2398
by (simp add: zip_append1)
wenzelm@13114
  2399
wenzelm@13114
  2400
lemma zip_rev:
nipkow@14247
  2401
"length xs = length ys ==> zip (rev xs) (rev ys) = rev (zip xs ys)"
nipkow@14247
  2402
by (induct rule:list_induct2, simp_all)
wenzelm@13114
  2403
hoelzl@33639
  2404
lemma zip_map_map:
hoelzl@33639
  2405
  "zip (map f xs) (map g ys) = map (\<lambda> (x, y). (f x, g y)) (zip xs ys)"
hoelzl@33639
  2406
proof (induct xs arbitrary: ys)
hoelzl@33639
  2407
  case (Cons x xs) note Cons_x_xs = Cons.hyps
hoelzl@33639
  2408
  show ?case
hoelzl@33639
  2409
  proof (cases ys)
hoelzl@33639
  2410
    case (Cons y ys')
hoelzl@33639
  2411
    show ?thesis unfolding Cons using Cons_x_xs by simp
hoelzl@33639
  2412
  qed simp
hoelzl@33639
  2413
qed simp
hoelzl@33639
  2414
hoelzl@33639
  2415
lemma zip_map1:
hoelzl@33639
  2416
  "zip (map f xs) ys = map (\<lambda>(x, y). (f x, y)) (zip xs ys)"
hoelzl@33639
  2417
using zip_map_map[of f xs "\<lambda>x. x" ys] by simp
hoelzl@33639
  2418
hoelzl@33639
  2419
lemma zip_map2:
hoelzl@33639
  2420
  "zip xs (map f ys) = map (\<lambda>(x, y). (x, f y)) (zip xs ys)"
hoelzl@33639
  2421
using zip_map_map[of "\<lambda>x. x" xs f ys] by simp
hoelzl@33639
  2422
nipkow@23096
  2423
lemma map_zip_map:
hoelzl@33639
  2424
  "map f (zip (map g xs) ys) = map (%(x,y). f(g x, y)) (zip xs ys)"
hoelzl@33639
  2425
unfolding zip_map1 by auto
nipkow@23096
  2426
nipkow@23096
  2427
lemma map_zip_map2:
hoelzl@33639
  2428
  "map f (zip xs (map g ys)) = map (%(x,y). f(x, g y)) (zip xs ys)"
hoelzl@33639
  2429
unfolding zip_map2 by auto
nipkow@23096
  2430
nipkow@31080
  2431
text{* Courtesy of Andreas Lochbihler: *}
nipkow@31080
  2432
lemma zip_same_conv_map: "zip xs xs = map (\<lambda>x. (x, x)) xs"
nipkow@31080
  2433
by(induct xs) auto
nipkow@31080
  2434
wenzelm@13142
  2435
lemma nth_zip [simp]:
nipkow@24526
  2436
"[| i < length xs; i < length ys|] ==> (zip xs ys)!i = (xs!i, ys!i)"
nipkow@24526
  2437
apply (induct ys arbitrary: i xs, simp)
nipkow@13145
  2438
apply (case_tac xs)
nipkow@13145
  2439
 apply (simp_all add: nth.simps split: nat.split)
nipkow@13145
  2440
done
wenzelm@13114
  2441
wenzelm@13114
  2442
lemma set_zip:
nipkow@13145
  2443
"set (zip xs ys) = {(xs!i, ys!i) | i. i < min (length xs) (length ys)}"
nipkow@31080
  2444
by(simp add: set_conv_nth cong: rev_conj_cong)
wenzelm@13114
  2445
hoelzl@33639
  2446
lemma zip_same: "((a,b) \<in> set (zip xs xs)) = (a \<in> set xs \<and> a = b)"
hoelzl@33639
  2447
by(induct xs) auto
hoelzl@33639
  2448
wenzelm@13114
  2449
lemma zip_update:
nipkow@31080
  2450
  "zip (xs[i:=x]) (ys[i:=y]) = (zip xs ys)[i:=(x,y)]"
nipkow@31080
  2451
by(rule sym, simp add: update_zip)
wenzelm@13114
  2452
wenzelm@13142
  2453
lemma zip_replicate [simp]:
nipkow@24526
  2454
  "zip (replicate i x) (replicate j y) = replicate (min i j) (x,y)"
nipkow@24526
  2455
apply (induct i arbitrary: j, auto)
paulson@14208
  2456
apply (case_tac j, auto)
nipkow@13145
  2457
done
wenzelm@13114
  2458
nipkow@19487
  2459
lemma take_zip:
nipkow@24526
  2460
  "take n (zip xs ys) = zip (take n xs) (take n ys)"
nipkow@24526
  2461
apply (induct n arbitrary: xs ys)
nipkow@19487
  2462
 apply simp
nipkow@19487
  2463
apply (case_tac xs, simp)
nipkow@19487
  2464
apply (case_tac ys, simp_all)
nipkow@19487
  2465
done
nipkow@19487
  2466
nipkow@19487
  2467
lemma drop_zip:
nipkow@24526
  2468
  "drop n (zip xs ys) = zip (drop n xs) (drop n ys)"
nipkow@24526
  2469
apply (induct n arbitrary: xs ys)
nipkow@19487
  2470
 apply simp
nipkow@19487
  2471
apply (case_tac xs, simp)
nipkow@19487
  2472
apply (case_tac ys, simp_all)
nipkow@19487
  2473
done
nipkow@19487
  2474
hoelzl@33639
  2475
lemma zip_takeWhile_fst: "zip (takeWhile P xs) ys = takeWhile (P \<circ> fst) (zip xs ys)"
hoelzl@33639
  2476
proof (induct xs arbitrary: ys)
hoelzl@33639
  2477
  case (Cons x xs) thus ?case by (cases ys) auto
hoelzl@33639
  2478
qed simp
hoelzl@33639
  2479
hoelzl@33639
  2480
lemma zip_takeWhile_snd: "zip xs (takeWhile P ys) = takeWhile (P \<circ> snd) (zip xs ys)"
hoelzl@33639
  2481
proof (induct xs arbitrary: ys)
hoelzl@33639
  2482
  case (Cons x xs) thus ?case by (cases ys) auto
hoelzl@33639
  2483
qed simp
hoelzl@33639
  2484
krauss@22493
  2485
lemma set_zip_leftD:
krauss@22493
  2486
  "(x,y)\<in> set (zip xs ys) \<Longrightarrow> x \<in> set xs"
krauss@22493
  2487
by (induct xs ys rule:list_induct2') auto
krauss@22493
  2488
krauss@22493
  2489
lemma set_zip_rightD:
krauss@22493
  2490
  "(x,y)\<in> set (zip xs ys) \<Longrightarrow> y \<in> set ys"
krauss@22493
  2491
by (induct xs ys rule:list_induct2') auto
wenzelm@13142
  2492
nipkow@23983
  2493
lemma in_set_zipE:
nipkow@23983
  2494
  "(x,y) : set(zip xs ys) \<Longrightarrow> (\<lbrakk> x : set xs; y : set ys \<rbrakk> \<Longrightarrow> R) \<Longrightarrow> R"
nipkow@23983
  2495
by(blast dest: set_zip_leftD set_zip_rightD)
nipkow@23983
  2496
haftmann@29766
  2497
lemma zip_map_fst_snd:
haftmann@29766
  2498
  "zip (map fst zs) (map snd zs) = zs"
haftmann@29766
  2499
  by (induct zs) simp_all
haftmann@29766
  2500
haftmann@29766
  2501
lemma zip_eq_conv:
haftmann@29766
  2502
  "length xs = length ys \<Longrightarrow> zip xs ys = zs \<longleftrightarrow> map fst zs = xs \<and> map snd zs = ys"
haftmann@29766
  2503
  by (auto simp add: zip_map_fst_snd)
haftmann@29766
  2504
haftmann@52310
  2505
lemma in_set_zip:
haftmann@52310
  2506
  "p \<in> set (zip xs ys) \<longleftrightarrow> (\<exists>n. xs ! n = fst p \<and> ys ! n = snd p
haftmann@52310
  2507
    \<and> n < length xs \<and> n < length ys)"
haftmann@52310
  2508
  by (cases p) (auto simp add: set_zip)
haftmann@52310
  2509
haftmann@52310
  2510
lemma pair_list_eqI:
haftmann@52310
  2511
  assumes "map fst xs = map fst ys" and "map snd xs = map snd ys"
haftmann@52310
  2512
  shows "xs = ys"
haftmann@52310
  2513
proof -
haftmann@52310
  2514
  from assms(1) have "length xs = length ys" by (rule map_eq_imp_length_eq)
haftmann@52310
  2515
  from this assms show ?thesis
haftmann@52310
  2516
    by (induct xs ys rule: list_induct2) (simp_all add: prod_eqI)
haftmann@52310
  2517
qed
haftmann@52310
  2518
wenzelm@35118
  2519
haftmann@50963
  2520
subsubsection {* @{const list_all2} *}
wenzelm@13114
  2521
kleing@14316
  2522
lemma list_all2_lengthD [intro?]: 
kleing@14316
  2523
  "list_all2 P xs ys ==> length xs = length ys"
nipkow@24349
  2524
by (simp add: list_all2_def)
haftmann@19607
  2525
haftmann@19787
  2526
lemma list_all2_Nil [iff, code]: "list_all2 P [] ys = (ys = [])"
nipkow@24349
  2527
by (simp add: list_all2_def)
haftmann@19607
  2528
haftmann@19787
  2529
lemma list_all2_Nil2 [iff, code]: "list_all2 P xs [] = (xs = [])"
nipkow@24349
  2530
by (simp add: list_all2_def)
haftmann@19607
  2531
haftmann@19607
  2532
lemma list_all2_Cons [iff, code]:
haftmann@19607
  2533
  "list_all2 P (x # xs) (y # ys) = (P x y \<and> list_all2 P xs ys)"
nipkow@24349
  2534
by (auto simp add: list_all2_def)
wenzelm@13114
  2535
wenzelm@13114
  2536
lemma list_all2_Cons1:
nipkow@13145
  2537
"list_all2 P (x # xs) ys = (\<exists>z zs. ys = z # zs \<and> P x z \<and> list_all2 P xs zs)"
nipkow@13145
  2538
by (cases ys) auto
wenzelm@13114
  2539
wenzelm@13114
  2540
lemma list_all2_Cons2:
nipkow@13145
  2541
"list_all2 P xs (y # ys) = (\<exists>z zs. xs = z # zs \<and> P z y \<and> list_all2 P zs ys)"
nipkow@13145
  2542
by (cases xs) auto
wenzelm@13114
  2543
huffman@46665
  2544
lemma list_all2_induct
huffman@46665
  2545
  [consumes 1, case_names Nil Cons, induct set: list_all2]:
huffman@46665
  2546
  assumes P: "list_all2 P xs ys"
huffman@46665
  2547
  assumes Nil: "R [] []"
huffman@48511
  2548
  assumes Cons: "\<And>x xs y ys.
huffman@48511
  2549
    \<lbrakk>P x y; list_all2 P xs ys; R xs ys\<rbrakk> \<Longrightarrow> R (x # xs) (y # ys)"
huffman@46665
  2550
  shows "R xs ys"
huffman@46665
  2551
using P
huffman@46665
  2552
by (induct xs arbitrary: ys) (auto simp add: list_all2_Cons1 Nil Cons)
huffman@46665
  2553
wenzelm@13142
  2554
lemma list_all2_rev [iff]:
nipkow@13145
  2555
"list_all2 P (rev xs) (rev ys) = list_all2 P xs ys"
nipkow@13145
  2556
by (simp add: list_all2_def zip_rev cong: conj_cong)
wenzelm@13114
  2557
kleing@13863
  2558
lemma list_all2_rev1:
kleing@13863
  2559
"list_all2 P (rev xs) ys = list_all2 P xs (rev ys)"
kleing@13863
  2560
by (subst list_all2_rev [symmetric]) simp
kleing@13863
  2561
wenzelm@13114
  2562
lemma list_all2_append1:
nipkow@13145
  2563
"list_all2 P (xs @ ys) zs =
nipkow@13145
  2564
(EX us vs. zs = us @ vs \<and> length us = length xs \<and> length vs = length ys \<and>
nipkow@13145
  2565
list_all2 P xs us \<and> list_all2 P ys vs)"
nipkow@13145
  2566
apply (simp add: list_all2_def zip_append1)
nipkow@13145
  2567
apply (rule iffI)
nipkow@13145
  2568
 apply (rule_tac x = "take (length xs) zs" in exI)
nipkow@13145
  2569
 apply (rule_tac x = "drop (length xs) zs" in exI)
paulson@14208
  2570
 apply (force split: nat_diff_split simp add: min_def, clarify)
nipkow@13145
  2571
apply (simp add: ball_Un)
nipkow@13145
  2572
done
wenzelm@13114
  2573
wenzelm@13114
  2574
lemma list_all2_append2:
nipkow@13145
  2575
"list_all2 P xs (ys @ zs) =
nipkow@13145
  2576
(EX us vs. xs = us @ vs \<and> length us = length ys \<and> length vs = length zs \<and>
nipkow@13145
  2577
list_all2 P us ys \<and> list_all2 P vs zs)"
nipkow@13145
  2578
apply (simp add: list_all2_def zip_append2)
nipkow@13145
  2579
apply (rule iffI)
nipkow@13145
  2580
 apply (rule_tac x = "take (length ys) xs" in exI)
nipkow@13145
  2581
 apply (rule_tac x = "drop (length ys) xs" in exI)
paulson@14208
  2582
 apply (force split: nat_diff_split simp add: min_def, clarify)
nipkow@13145
  2583
apply (simp add: ball_Un)
nipkow@13145
  2584
done
wenzelm@13114
  2585
kleing@13863
  2586
lemma list_all2_append:
nipkow@14247
  2587
  "length xs = length ys \<Longrightarrow>
nipkow@14247
  2588
  list_all2 P (xs@us) (ys@vs) = (list_all2 P xs ys \<and> list_all2 P us vs)"
nipkow@14247
  2589
by (induct rule:list_induct2, simp_all)
kleing@13863
  2590
kleing@13863
  2591
lemma list_all2_appendI [intro?, trans]:
kleing@13863
  2592
  "\<lbrakk> list_all2 P a b; list_all2 P c d \<rbrakk> \<Longrightarrow> list_all2 P (a@c) (b@d)"
nipkow@24349
  2593
by (simp add: list_all2_append list_all2_lengthD)
kleing@13863
  2594
wenzelm@13114
  2595
lemma list_all2_conv_all_nth:
nipkow@13145
  2596
"list_all2 P xs ys =
nipkow@13145
  2597
(length xs = length ys \<and> (\<forall>i < length xs. P (xs!i) (ys!i)))"
nipkow@13145
  2598
by (force simp add: list_all2_def set_zip)
wenzelm@13114
  2599
berghofe@13883
  2600
lemma list_all2_trans:
berghofe@13883
  2601
  assumes tr: "!!a b c. P1 a b ==> P2 b c ==> P3 a c"
berghofe@13883
  2602
  shows "!!bs cs. list_all2 P1 as bs ==> list_all2 P2 bs cs ==> list_all2 P3 as cs"
berghofe@13883
  2603
        (is "!!bs cs. PROP ?Q as bs cs")
berghofe@13883
  2604
proof (induct as)
berghofe@13883
  2605
  fix x xs bs assume I1: "!!bs cs. PROP ?Q xs bs cs"
berghofe@13883
  2606
  show "!!cs. PROP ?Q (x # xs) bs cs"
berghofe@13883
  2607
  proof (induct bs)
berghofe@13883
  2608
    fix y ys cs assume I2: "!!cs. PROP ?Q (x # xs) ys cs"
berghofe@13883
  2609
    show "PROP ?Q (x # xs) (y # ys) cs"
berghofe@13883
  2610
      by (induct cs) (auto intro: tr I1 I2)
berghofe@13883
  2611
  qed simp
berghofe@13883
  2612
qed simp
berghofe@13883
  2613
kleing@13863
  2614
lemma list_all2_all_nthI [intro?]:
kleing@13863
  2615
  "length a = length b \<Longrightarrow> (\<And>n. n < length a \<Longrightarrow> P (a!n) (b!n)) \<Longrightarrow> list_all2 P a b"
nipkow@24349
  2616
by (simp add: list_all2_conv_all_nth)
kleing@13863
  2617
paulson@14395
  2618
lemma list_all2I:
paulson@14395
  2619
  "\<forall>x \<in> set (zip a b). split P x \<Longrightarrow> length a = length b \<Longrightarrow> list_all2 P a b"
nipkow@24349
  2620
by (simp add: list_all2_def)
paulson@14395
  2621
kleing@14328
  2622
lemma list_all2_nthD:
kleing@13863
  2623
  "\<lbrakk> list_all2 P xs ys; p < size xs \<rbrakk> \<Longrightarrow> P (xs!p) (ys!p)"
nipkow@24349
  2624
by (simp add: list_all2_conv_all_nth)
kleing@13863
  2625
nipkow@14302
  2626
lemma list_all2_nthD2:
nipkow@14302
  2627
  "\<lbrakk>list_all2 P xs ys; p < size ys\<rbrakk> \<Longrightarrow> P (xs!p) (ys!p)"
nipkow@24349
  2628
by (frule list_all2_lengthD) (auto intro: list_all2_nthD)
nipkow@14302
  2629
kleing@13863
  2630
lemma list_all2_map1: 
kleing@13863
  2631
  "list_all2 P (map f as) bs = list_all2 (\<lambda>x y. P (f x) y) as bs"
nipkow@24349
  2632
by (simp add: list_all2_conv_all_nth)
kleing@13863
  2633
kleing@13863
  2634
lemma list_all2_map2: 
kleing@13863
  2635
  "list_all2 P as (map f bs) = list_all2 (\<lambda>x y. P x (f y)) as bs"
nipkow@24349
  2636
by (auto simp add: list_all2_conv_all_nth)
kleing@13863
  2637
kleing@14316
  2638
lemma list_all2_refl [intro?]:
kleing@13863
  2639
  "(\<And>x. P x x) \<Longrightarrow> list_all2 P xs xs"
nipkow@24349
  2640
by (simp add: list_all2_conv_all_nth)
kleing@13863
  2641
kleing@13863
  2642
lemma list_all2_update_cong:
bulwahn@47536
  2643
  "\<lbrakk> list_all2 P xs ys; P x y \<rbrakk> \<Longrightarrow> list_all2 P (xs[i:=x]) (ys[i:=y])"
bulwahn@47536
  2644
by (cases "i < length ys") (auto simp add: list_all2_conv_all_nth nth_list_update)
kleing@13863
  2645
nipkow@14302
  2646
lemma list_all2_takeI [simp,intro?]:
nipkow@24526
  2647
  "list_all2 P xs ys \<Longrightarrow> list_all2 P (take n xs) (take n ys)"
nipkow@24526
  2648
apply (induct xs arbitrary: n ys)
nipkow@24526
  2649
 apply simp
nipkow@24526
  2650
apply (clarsimp simp add: list_all2_Cons1)
nipkow@24526
  2651
apply (case_tac n)
nipkow@24526
  2652
apply auto
nipkow@24526
  2653
done
nipkow@14302
  2654
nipkow@14302
  2655
lemma list_all2_dropI [simp,intro?]:
nipkow@24526
  2656
  "list_all2 P as bs \<Longrightarrow> list_all2 P (drop n as) (drop n bs)"
nipkow@24526
  2657
apply (induct as arbitrary: n bs, simp)
nipkow@24526
  2658
apply (clarsimp simp add: list_all2_Cons1)
nipkow@24526
  2659
apply (case_tac n, simp, simp)
nipkow@24526
  2660
done
kleing@13863
  2661
kleing@14327
  2662
lemma list_all2_mono [intro?]:
nipkow@24526
  2663
  "list_all2 P xs ys \<Longrightarrow> (\<And>xs ys. P xs ys \<Longrightarrow> Q xs ys) \<Longrightarrow> list_all2 Q xs ys"
nipkow@24526
  2664
apply (induct xs arbitrary: ys, simp)
nipkow@24526
  2665
apply (case_tac ys, auto)
nipkow@24526
  2666
done
kleing@13863
  2667
haftmann@22551
  2668
lemma list_all2_eq:
haftmann@22551
  2669
  "xs = ys \<longleftrightarrow> list_all2 (op =) xs ys"
nipkow@24349
  2670
by (induct xs ys rule: list_induct2') auto
haftmann@22551
  2671
nipkow@40476
  2672
lemma list_eq_iff_zip_eq:
nipkow@40476
  2673
  "xs = ys \<longleftrightarrow> length xs = length ys \<and> (\<forall>(x,y) \<in> set (zip xs ys). x = y)"
nipkow@40476
  2674
by(auto simp add: set_zip list_all2_eq list_all2_conv_all_nth cong: conj_cong)
nipkow@40476
  2675
wenzelm@13114
  2676
traytel@54858
  2677
subsubsection {* @{const List.product} and @{const product_lists} *}
haftmann@50963
  2678
haftmann@50963
  2679
lemma product_list_set:
haftmann@50963
  2680
  "set (List.product xs ys) = set xs \<times> set ys"
haftmann@50963
  2681
  by (induct xs) auto
haftmann@50963
  2682
haftmann@52297
  2683
lemma length_product [simp]:
haftmann@52297
  2684
  "length (List.product xs ys) = length xs * length ys"
haftmann@52297
  2685
  by (induct xs) simp_all
haftmann@52297
  2686
haftmann@52297
  2687
lemma product_nth:
haftmann@52297
  2688
  assumes "n < length xs * length ys"
haftmann@52297
  2689
  shows "List.product xs ys ! n = (xs ! (n div length ys), ys ! (n mod length ys))"
haftmann@52297
  2690
using assms proof (induct xs arbitrary: n)
haftmann@52297
  2691
  case Nil then show ?case by simp
haftmann@52297
  2692
next
haftmann@52297
  2693
  case (Cons x xs n)
haftmann@52297
  2694
  then have "length ys > 0" by auto
haftmann@52297
  2695
  with Cons show ?case
haftmann@52297
  2696
    by (auto simp add: nth_append not_less le_mod_geq le_div_geq)
haftmann@52297
  2697
qed
haftmann@52297
  2698
traytel@54858
  2699
lemma in_set_product_lists_length: 
traytel@54858
  2700
  "xs \<in> set (product_lists xss) \<Longrightarrow> length xs = length xss"
traytel@54858
  2701
  by (induct xss arbitrary: xs) auto
traytel@54858
  2702
traytel@54858
  2703
lemma product_lists_set:
traytel@54858
  2704
  "set (product_lists xss) = {xs. list_all2 (\<lambda>x ys. x \<in> set ys) xs xss}" (is "?L = Collect ?R")
traytel@54858
  2705
proof (intro equalityI subsetI, unfold mem_Collect_eq)
traytel@54858
  2706
  fix xs assume "xs \<in> ?L"
traytel@54858
  2707
  then have "length xs = length xss" by (rule in_set_product_lists_length)
traytel@54858
  2708
  from this `xs \<in> ?L` show "?R xs" by (induct xs xss rule: list_induct2) auto
traytel@54858
  2709
next
traytel@54858
  2710
  fix xs assume "?R xs"
traytel@54858
  2711
  then show "xs \<in> ?L" by induct auto
traytel@54858
  2712
qed
traytel@54858
  2713
haftmann@50963
  2714
haftmann@48259
  2715
subsubsection {* @{const fold} with natural argument order *}
haftmann@47004
  2716
haftmann@49843
  2717
lemma fold_simps [code]: -- {* eta-expanded variant for generated code -- enables tail-recursion optimisation in Scala *}
haftmann@49843
  2718
  "fold f [] s = s"
haftmann@49843
  2719
  "fold f (x # xs) s = fold f xs (f x s)" 
haftmann@49843
  2720
  by simp_all
haftmann@49843
  2721
haftmann@47004
  2722
lemma fold_remove1_split:
haftmann@47004
  2723
  assumes f: "\<And>x y. x \<in> set xs \<Longrightarrow> y \<in> set xs \<Longrightarrow> f x \<circ> f y = f y \<circ> f x"
haftmann@47004
  2724
    and x: "x \<in> set xs"
haftmann@47004
  2725
  shows "fold f xs = fold f (remove1 x xs) \<circ> f x"
haftmann@50754
  2726
  using assms by (induct xs) (auto simp add: comp_assoc)
haftmann@47004
  2727
haftmann@47004
  2728
lemma fold_cong [fundef_cong]:
haftmann@47004
  2729
  "a = b \<Longrightarrow> xs = ys \<Longrightarrow> (\<And>x. x \<in> set xs \<Longrightarrow> f x = g x)
haftmann@47004
  2730
    \<Longrightarrow> fold f xs a = fold g ys b"
haftmann@47004
  2731
  by (induct ys arbitrary: a b xs) simp_all
haftmann@47004
  2732
haftmann@47004
  2733
lemma fold_id:
haftmann@47004
  2734
  assumes "\<And>x. x \<in> set xs \<Longrightarrow> f x = id"
haftmann@47004
  2735
  shows "fold f xs = id"
haftmann@47004
  2736
  using assms by (induct xs) simp_all
haftmann@47004
  2737
haftmann@47004
  2738
lemma fold_commute:
haftmann@47004
  2739
  assumes "\<And>x. x \<in> set xs \<Longrightarrow> h \<circ> g x = f x \<circ> h"
haftmann@47004
  2740
  shows "h \<circ> fold g xs = fold f xs \<circ> h"
haftmann@47004
  2741
  using assms by (induct xs) (simp_all add: fun_eq_iff)
haftmann@47004
  2742
haftmann@47004
  2743
lemma fold_commute_apply:
haftmann@47004
  2744
  assumes "\<And>x. x \<in> set xs \<Longrightarrow> h \<circ> g x = f x \<circ> h"
haftmann@47004
  2745
  shows "h (fold g xs s) = fold f xs (h s)"
haftmann@47004
  2746
proof -
haftmann@47004
  2747
  from assms have "h \<circ> fold g xs = fold f xs \<circ> h" by (rule fold_commute)
haftmann@47004
  2748
  then show ?thesis by (simp add: fun_eq_iff)
haftmann@35195
  2749
qed
haftmann@35195
  2750
haftmann@47004
  2751
lemma fold_invariant: 
haftmann@47004
  2752
  assumes "\<And>x. x \<in> set xs \<Longrightarrow> Q x" and "P s"
haftmann@47004
  2753
    and "\<And>x s. Q x \<Longrightarrow> P s \<Longrightarrow> P (f x s)"
haftmann@47004
  2754
  shows "P (fold f xs s)"
haftmann@34965
  2755
  using assms by (induct xs arbitrary: s) simp_all
haftmann@34965
  2756
haftmann@47004
  2757
lemma fold_append [simp]:
haftmann@47004
  2758
  "fold f (xs @ ys) = fold f ys \<circ> fold f xs"
haftmann@47004
  2759
  by (induct xs) simp_all
haftmann@47004
  2760
haftmann@47004
  2761
lemma fold_map [code_unfold]:
haftmann@47004
  2762
  "fold g (map f xs) = fold (g o f) xs"
haftmann@47004
  2763
  by (induct xs) simp_all
haftmann@47004
  2764
haftmann@47004
  2765
lemma fold_rev:
haftmann@47004
  2766
  assumes "\<And>x y. x \<in> set xs \<Longrightarrow> y \<in> set xs \<Longrightarrow> f y \<circ> f x = f x \<circ> f y"
haftmann@47004
  2767
  shows "fold f (rev xs) = fold f xs"
haftmann@47004
  2768
using assms by (induct xs) (simp_all add: fold_commute_apply fun_eq_iff)
haftmann@47004
  2769
haftmann@47004
  2770
lemma fold_Cons_rev:
haftmann@47004
  2771
  "fold Cons xs = append (rev xs)"
haftmann@47004
  2772
  by (induct xs) simp_all
haftmann@47004
  2773
haftmann@47004
  2774
lemma rev_conv_fold [code]:
haftmann@47004
  2775
  "rev xs = fold Cons xs []"
haftmann@47004
  2776
  by (simp add: fold_Cons_rev)
haftmann@47004
  2777
haftmann@47004
  2778
lemma fold_append_concat_rev:
haftmann@47004
  2779
  "fold append xss = append (concat (rev xss))"
haftmann@47004
  2780
  by (induct xss) simp_all
haftmann@47004
  2781
haftmann@47004
  2782
text {* @{const Finite_Set.fold} and @{const fold} *}
haftmann@47004
  2783
haftmann@47004
  2784
lemma (in comp_fun_commute) fold_set_fold_remdups:
haftmann@47004
  2785
  "Finite_Set.fold f y (set xs) = fold f (remdups xs) y"
haftmann@52626
  2786
  by (rule sym, induct xs arbitrary: y) (simp_all add: fold_fun_left_comm insert_absorb)
kuncar@49634
  2787
haftmann@47004
  2788
lemma (in comp_fun_idem) fold_set_fold:
haftmann@47004
  2789
  "Finite_Set.fold f y (set xs) = fold f xs y"
haftmann@52626
  2790
  by (rule sym, induct xs arbitrary: y) (simp_all add: fold_fun_left_comm)
haftmann@32681
  2791
haftmann@48259
  2792
lemma union_set_fold [code]:
haftmann@47018
  2793
  "set xs \<union> A = fold Set.insert xs A"
haftmann@47018
  2794
proof -
haftmann@47018
  2795
  interpret comp_fun_idem Set.insert
haftmann@47018
  2796
    by (fact comp_fun_idem_insert)
haftmann@47018
  2797
  show ?thesis by (simp add: union_fold_insert fold_set_fold)
haftmann@47018
  2798
qed
haftmann@47018
  2799
haftmann@48259
  2800
lemma union_coset_filter [code]:
haftmann@48259
  2801
  "List.coset xs \<union> A = List.coset (List.filter (\<lambda>x. x \<notin> A) xs)"
haftmann@48259
  2802
  by auto
haftmann@48259
  2803
haftmann@48259
  2804
lemma minus_set_fold [code]:
haftmann@47018
  2805
  "A - set xs = fold Set.remove xs A"
haftmann@47018
  2806
proof -
haftmann@47018
  2807
  interpret comp_fun_idem Set.remove
haftmann@47018
  2808
    by (fact comp_fun_idem_remove)
haftmann@47018
  2809
  show ?thesis
haftmann@47018
  2810
    by (simp add: minus_fold_remove [of _ A] fold_set_fold)
haftmann@47018
  2811
qed
haftmann@47018
  2812
haftmann@48259
  2813
lemma minus_coset_filter [code]:
haftmann@48259
  2814
  "A - List.coset xs = set (List.filter (\<lambda>x. x \<in> A) xs)"
haftmann@48259
  2815
  by auto
haftmann@48259
  2816
haftmann@48259
  2817
lemma inter_set_filter [code]:
haftmann@48259
  2818
  "A \<inter> set xs = set (List.filter (\<lambda>x. x \<in> A) xs)"
haftmann@48259
  2819
  by auto
haftmann@48259
  2820
haftmann@48259
  2821
lemma inter_coset_fold [code]:
haftmann@48259
  2822
  "A \<inter> List.coset xs = fold Set.remove xs A"
haftmann@48259
  2823
  by (simp add: Diff_eq [symmetric] minus_set_fold)
haftmann@48259
  2824
haftmann@52626
  2825
lemma (in semilattice_set) set_eq_fold:
haftmann@52626
  2826
  "F (set (x # xs)) = fold f xs x"
haftmann@47004
  2827
proof -
haftmann@52626
  2828
  interpret comp_fun_idem f
haftmann@52626
  2829
    by default (simp_all add: fun_eq_iff left_commute)
haftmann@52626
  2830
  show ?thesis by (simp add: eq_fold fold_set_fold)
haftmann@47004
  2831
qed
haftmann@47004
  2832
haftmann@52626
  2833
declare Inf_fin.set_eq_fold [code]
haftmann@52626
  2834
declare Sup_fin.set_eq_fold [code]
haftmann@52677
  2835
declare Min.set_eq_fold [code]
haftmann@52677
  2836
declare Max.set_eq_fold [code]
haftmann@48259
  2837
haftmann@47004
  2838
lemma (in complete_lattice) Inf_set_fold:
haftmann@47004
  2839
  "Inf (set xs) = fold inf xs top"
haftmann@47004
  2840
proof -
haftmann@47004
  2841
  interpret comp_fun_idem "inf :: 'a \<Rightarrow> 'a \<Rightarrow> 'a"
haftmann@47004
  2842
    by (fact comp_fun_idem_inf)
haftmann@47004
  2843
  show ?thesis by (simp add: Inf_fold_inf fold_set_fold inf_commute)
haftmann@47004
  2844
qed
haftmann@47004
  2845
haftmann@48259
  2846
declare Inf_set_fold [where 'a = "'a set", code]
haftmann@48259
  2847
haftmann@47004
  2848
lemma (in complete_lattice) Sup_set_fold:
haftmann@47004
  2849
  "Sup (set xs) = fold sup xs bot"
haftmann@47004
  2850
proof -
haftmann@47004
  2851
  interpret comp_fun_idem "sup :: 'a \<Rightarrow> 'a \<Rightarrow> 'a"
haftmann@47004
  2852
    by (fact comp_fun_idem_sup)
haftmann@47004
  2853
  show ?thesis by (simp add: Sup_fold_sup fold_set_fold sup_commute)
haftmann@47004
  2854
qed
haftmann@47004
  2855
haftmann@48259
  2856
declare Sup_set_fold [where 'a = "'a set", code]
haftmann@48259
  2857
haftmann@47004
  2858
lemma (in complete_lattice) INF_set_fold:
haftmann@47004
  2859
  "INFI (set xs) f = fold (inf \<circ> f) xs top"
haftmann@47004
  2860
  unfolding INF_def set_map [symmetric] Inf_set_fold fold_map ..
haftmann@47004
  2861
haftmann@48259
  2862
declare INF_set_fold [code]
haftmann@48259
  2863
haftmann@47004
  2864
lemma (in complete_lattice) SUP_set_fold:
haftmann@47004
  2865
  "SUPR (set xs) f = fold (sup \<circ> f) xs bot"
haftmann@47004
  2866
  unfolding SUP_def set_map [symmetric] Sup_set_fold fold_map ..
haftmann@47004
  2867
haftmann@48259
  2868
declare SUP_set_fold [code]
haftmann@47004
  2869
haftmann@50963
  2870
haftmann@47004
  2871
subsubsection {* Fold variants: @{const foldr} and @{const foldl} *}
haftmann@47004
  2872
haftmann@47004
  2873
text {* Correspondence *}
haftmann@47004
  2874
haftmann@48259
  2875
lemma foldr_conv_fold [code_abbrev]:
haftmann@48259
  2876
  "foldr f xs = fold f (rev xs)"
haftmann@48259
  2877
  by (induct xs) simp_all
haftmann@48259
  2878
haftmann@48259
  2879
lemma foldl_conv_fold:
haftmann@48259
  2880
  "foldl f s xs = fold (\<lambda>x s. f s x) xs s"
haftmann@48259
  2881
  by (induct xs arbitrary: s) simp_all
haftmann@48259
  2882
haftmann@48259
  2883
lemma foldr_conv_foldl: -- {* The ``Third Duality Theorem'' in Bird \& Wadler: *}
haftmann@47004
  2884
  "foldr f xs a = foldl (\<lambda>x y. f y x) a (rev xs)"
haftmann@48259
  2885
  by (simp add: foldr_conv_fold foldl_conv_fold)
haftmann@48259
  2886
haftmann@48259
  2887
lemma foldl_conv_foldr:
haftmann@47004
  2888
  "foldl f a xs = foldr (\<lambda>x y. f y x) (rev xs) a"
haftmann@48259
  2889
  by (simp add: foldr_conv_fold foldl_conv_fold)
haftmann@47004
  2890
haftmann@47004
  2891
lemma foldr_fold:
haftmann@47004
  2892
  assumes "\<And>x y. x \<in> set xs \<Longrightarrow> y \<in> set xs \<Longrightarrow> f y \<circ> f x = f x \<circ> f y"
haftmann@47004
  2893
  shows "foldr f xs = fold f xs"
haftmann@48259
  2894
  using assms unfolding foldr_conv_fold by (rule fold_rev)
haftmann@47004
  2895
haftmann@47004
  2896
lemma foldr_cong [fundef_cong]:
haftmann@47004
  2897
  "a = b \<Longrightarrow> l = k \<Longrightarrow> (\<And>a x. x \<in> set l \<Longrightarrow> f x a = g x a) \<Longrightarrow> foldr f l a = foldr g k b"
haftmann@48259
  2898
  by (auto simp add: foldr_conv_fold intro!: fold_cong)
haftmann@47004
  2899
haftmann@47004
  2900
lemma foldl_cong [fundef_cong]:
haftmann@47004
  2901
  "a = b \<Longrightarrow> l = k \<Longrightarrow> (\<And>a x. x \<in> set l \<Longrightarrow> f a x = g a x) \<Longrightarrow> foldl f a l = foldl g b k"
haftmann@48259
  2902
  by (auto simp add: foldl_conv_fold intro!: fold_cong)
haftmann@47004
  2903
haftmann@47004
  2904
lemma foldr_append [simp]:
haftmann@47004
  2905
  "foldr f (xs @ ys) a = foldr f xs (foldr f ys a)"
haftmann@48259
  2906
  by (simp add: foldr_conv_fold)
haftmann@47004
  2907
haftmann@47004
  2908
lemma foldl_append [simp]:
haftmann@47004
  2909
  "foldl f a (xs @ ys) = foldl f (foldl f a xs) ys"
haftmann@48259
  2910
  by (simp add: foldl_conv_fold)
haftmann@47004
  2911
haftmann@47004
  2912
lemma foldr_map [code_unfold]:
haftmann@47004
  2913
  "foldr g (map f xs) a = foldr (g o f) xs a"
haftmann@48259
  2914
  by (simp add: foldr_conv_fold fold_map rev_map)
haftmann@47004
  2915
haftmann@47004
  2916
lemma foldl_map [code_unfold]:
haftmann@47004
  2917
  "foldl g a (map f xs) = foldl (\<lambda>a x. g a (f x)) a xs"
haftmann@48259
  2918
  by (simp add: foldl_conv_fold fold_map comp_def)
haftmann@47004
  2919
haftmann@47004
  2920
lemma concat_conv_foldr [code]:
haftmann@47004
  2921
  "concat xss = foldr append xss []"
haftmann@48259
  2922
  by (simp add: fold_append_concat_rev foldr_conv_fold)
haftmann@47004
  2923
wenzelm@35118
  2924
haftmann@50963
  2925
subsubsection {* @{const upt} *}
wenzelm@13142
  2926
nipkow@17090
  2927
lemma upt_rec[code]: "[i..<j] = (if i<j then i#[Suc i..<j] else [])"
nipkow@17090
  2928
-- {* simp does not terminate! *}
nipkow@13145
  2929
by (induct j) auto
wenzelm@13114
  2930
huffman@47978
  2931
lemmas upt_rec_numeral[simp] = upt_rec[of "numeral m" "numeral n"] for m n
nipkow@32005
  2932
nipkow@15425
  2933
lemma upt_conv_Nil [simp]: "j <= i ==> [i..<j] = []"
nipkow@13145
  2934
by (subst upt_rec) simp
wenzelm@13114
  2935
nipkow@15425
  2936
lemma upt_eq_Nil_conv[simp]: "([i..<j] = []) = (j = 0 \<or> j <= i)"
nipkow@15281
  2937
by(induct j)simp_all
nipkow@15281
  2938
nipkow@15281
  2939
lemma upt_eq_Cons_conv:
nipkow@24526
  2940
 "([i..<j] = x#xs) = (i < j & i = x & [i+1..<j] = xs)"
nipkow@24526
  2941
apply(induct j arbitrary: x xs)
nipkow@15281
  2942
 apply simp
nipkow@15281
  2943
apply(clarsimp simp add: append_eq_Cons_conv)
nipkow@15281
  2944
apply arith
nipkow@15281
  2945
done
nipkow@15281
  2946
nipkow@15425
  2947
lemma upt_Suc_append: "i <= j ==> [i..<(Suc j)] = [i..<j]@[j]"
nipkow@13145
  2948
-- {* Only needed if @{text upt_Suc} is deleted from the simpset. *}
nipkow@13145
  2949
by simp
wenzelm@13114
  2950
nipkow@15425
  2951
lemma upt_conv_Cons: "i < j ==> [i..<j] = i # [Suc i..<j]"
haftmann@26734
  2952
  by (simp add: upt_rec)
wenzelm@13114
  2953
nipkow@15425
  2954
lemma upt_add_eq_append: "i<=j ==> [i..<j+k] = [i..<j]@[j..<j+k]"
nipkow@13145
  2955
-- {* LOOPS as a simprule, since @{text "j <= j"}. *}
nipkow@13145
  2956
by (induct k) auto
wenzelm@13114
  2957
nipkow@15425
  2958
lemma length_upt [simp]: "length [i..<j] = j - i"
nipkow@13145
  2959
by (induct j) (auto simp add: Suc_diff_le)
wenzelm@13114
  2960
nipkow@15425
  2961
lemma nth_upt [simp]: "i + k < j ==> [i..<j] ! k = i + k"
nipkow@13145
  2962
apply (induct j)
nipkow@13145
  2963
apply (auto simp add: less_Suc_eq nth_append split: nat_diff_split)
nipkow@13145
  2964
done
wenzelm@13114
  2965
nipkow@17906
  2966
nipkow@17906
  2967
lemma hd_upt[simp]: "i < j \<Longrightarrow> hd[i..<j] = i"
nipkow@17906
  2968
by(simp add:upt_conv_Cons)
nipkow@17906
  2969
nipkow@17906
  2970
lemma last_upt[simp]: "i < j \<Longrightarrow> last[i..<j] = j - 1"
nipkow@17906
  2971
apply(cases j)
nipkow@17906
  2972
 apply simp
nipkow@17906
  2973
by(simp add:upt_Suc_append)
nipkow@17906
  2974
nipkow@24526
  2975
lemma take_upt [simp]: "i+m <= n ==> take m [i..<n] = [i..<i+m]"
nipkow@24526
  2976
apply (induct m arbitrary: i, simp)
nipkow@13145
  2977
apply (subst upt_rec)
nipkow@13145
  2978
apply (rule sym)
nipkow@13145
  2979
apply (subst upt_rec)
nipkow@13145
  2980
apply (simp del: upt.simps)
nipkow@13145
  2981
done
wenzelm@13114
  2982
nipkow@17501
  2983
lemma drop_upt[simp]: "drop m [i..<j] = [i+m..<j]"
nipkow@17501
  2984
apply(induct j)
nipkow@17501
  2985
apply auto
nipkow@17501
  2986
done
nipkow@17501
  2987
nipkow@24645
  2988
lemma map_Suc_upt: "map Suc [m..<n] = [Suc m..<Suc n]"
nipkow@13145
  2989
by (induct n) auto
wenzelm@13114
  2990
hoelzl@55869
  2991
lemma map_add_upt: "map (\<lambda>i. i + n) [0..<m] = [n..<m + n]"
hoelzl@55869
  2992
  by (induct m) simp_all
hoelzl@55869
  2993
nipkow@24526
  2994
lemma nth_map_upt: "i < n-m ==> (map f [m..<n]) ! i = f(m+i)"
nipkow@24526
  2995
apply (induct n m  arbitrary: i rule: diff_induct)
nipkow@13145
  2996
prefer 3 apply (subst map_Suc_upt[symmetric])
huffman@45792
  2997
apply (auto simp add: less_diff_conv)
nipkow@13145
  2998
done
wenzelm@13114
  2999
haftmann@53517
  3000
lemma map_decr_upt:
haftmann@53517
  3001
  "map (\<lambda>n. n - Suc 0) [Suc m..<Suc n] = [m..<n]"
haftmann@53517
  3002
  by (induct n) simp_all
haftmann@53517
  3003
berghofe@13883
  3004
lemma nth_take_lemma:
nipkow@24526
  3005
  "k <= length xs ==> k <= length ys ==>
berghofe@13883
  3006
     (!!i. i < k --> xs!i = ys!i) ==> take k xs = take k ys"
nipkow@24526
  3007
apply (atomize, induct k arbitrary: xs ys)
paulson@14208
  3008
apply (simp_all add: less_Suc_eq_0_disj all_conj_distrib, clarify)
nipkow@13145
  3009
txt {* Both lists must be non-empty *}
paulson@14208
  3010
apply (case_tac xs, simp)
paulson@14208
  3011
apply (case_tac ys, clarify)
nipkow@13145
  3012
 apply (simp (no_asm_use))
nipkow@13145
  3013
apply clarify
nipkow@13145
  3014
txt {* prenexing's needed, not miniscoping *}
nipkow@13145
  3015
apply (simp (no_asm_use) add: all_simps [symmetric] del: all_simps)
nipkow@13145
  3016
apply blast
nipkow@13145
  3017
done
wenzelm@13114
  3018
wenzelm@13114
  3019
lemma nth_equalityI:
wenzelm@13114
  3020
 "[| length xs = length ys; ALL i < length xs. xs!i = ys!i |] ==> xs = ys"
huffman@45792
  3021
  by (frule nth_take_lemma [OF le_refl eq_imp_le]) simp_all
wenzelm@13114
  3022
haftmann@24796
  3023
lemma map_nth:
haftmann@24796
  3024
  "map (\<lambda>i. xs ! i) [0..<length xs] = xs"
haftmann@24796
  3025
  by (rule nth_equalityI, auto)
haftmann@24796
  3026
kleing@13863
  3027
(* needs nth_equalityI *)
kleing@13863
  3028
lemma list_all2_antisym:
kleing@13863
  3029
  "\<lbrakk> (\<And>x y. \<lbrakk>P x y; Q y x\<rbrakk> \<Longrightarrow> x = y); list_all2 P xs ys; list_all2 Q ys xs \<rbrakk> 
kleing@13863
  3030
  \<Longrightarrow> xs = ys"
kleing@13863
  3031
  apply (simp add: list_all2_conv_all_nth) 
paulson@14208
  3032
  apply (rule nth_equalityI, blast, simp)
kleing@13863
  3033
  done
kleing@13863
  3034
wenzelm@13142
  3035
lemma take_equalityI: "(\<forall>i. take i xs = take i ys) ==> xs = ys"
nipkow@13145
  3036
-- {* The famous take-lemma. *}
nipkow@13145
  3037
apply (drule_tac x = "max (length xs) (length ys)" in spec)
huffman@45792
  3038
apply (simp add: le_max_iff_disj)
nipkow@13145
  3039
done
wenzelm@13114
  3040
wenzelm@13114
  3041
nipkow@15302
  3042
lemma take_Cons':
nipkow@15302
  3043
     "take n (x # xs) = (if n = 0 then [] else x # take (n - 1) xs)"
nipkow@15302
  3044
by (cases n) simp_all
nipkow@15302
  3045
nipkow@15302
  3046
lemma drop_Cons':
nipkow@15302
  3047
     "drop n (x # xs) = (if n = 0 then x # xs else drop (n - 1) xs)"
nipkow@15302
  3048
by (cases n) simp_all
nipkow@15302
  3049
nipkow@15302
  3050
lemma nth_Cons': "(x # xs)!n = (if n = 0 then x else xs!(n - 1))"
nipkow@15302
  3051
by (cases n) simp_all
nipkow@15302
  3052
huffman@47978
  3053
lemma take_Cons_numeral [simp]:
huffman@47978
  3054
  "take (numeral v) (x # xs) = x # take (numeral v - 1) xs"
huffman@47978
  3055
by (simp add: take_Cons')
huffman@47978
  3056
huffman@47978
  3057
lemma drop_Cons_numeral [simp]:
huffman@47978
  3058
  "drop (numeral v) (x # xs) = drop (numeral v - 1) xs"
huffman@47978
  3059
by (simp add: drop_Cons')
huffman@47978
  3060
huffman@47978
  3061
lemma nth_Cons_numeral [simp]:
huffman@47978
  3062
  "(x # xs) ! numeral v = xs ! (numeral v - 1)"
huffman@47978
  3063
by (simp add: nth_Cons')
nipkow@15302
  3064
nipkow@15302
  3065
nipkow@32415
  3066
subsubsection {* @{text upto}: interval-list on @{typ int} *}
nipkow@32415
  3067
nipkow@32415
  3068
function upto :: "int \<Rightarrow> int \<Rightarrow> int list" ("(1[_../_])") where
nipkow@52303
  3069
  "upto i j = (if i \<le> j then i # [i+1..j] else [])"
nipkow@32415
  3070
by auto
nipkow@32415
  3071
termination
nipkow@32415
  3072
by(relation "measure(%(i::int,j). nat(j - i + 1))") auto
nipkow@32415
  3073
nipkow@52303
  3074
declare upto.simps[simp del]
nipkow@32415
  3075
huffman@47978
  3076
lemmas upto_rec_numeral [simp] =
huffman@47978
  3077
  upto.simps[of "numeral m" "numeral n"]
huffman@47978
  3078
  upto.simps[of "numeral m" "neg_numeral n"]
huffman@47978
  3079
  upto.simps[of "neg_numeral m" "numeral n"]
huffman@47978
  3080
  upto.simps[of "neg_numeral m" "neg_numeral n"] for m n
nipkow@32415
  3081
nipkow@32415
  3082
lemma upto_empty[simp]: "j < i \<Longrightarrow> [i..j] = []"
nipkow@32415
  3083
by(simp add: upto.simps)
nipkow@32415
  3084
nipkow@52303
  3085
lemma upto_rec1: "i \<le> j \<Longrightarrow> [i..j] = i#[i+1..j]"
nipkow@52303
  3086
by(simp add: upto.simps)
nipkow@52303
  3087
nipkow@52303
  3088
lemma upto_rec2: "i \<le> j \<Longrightarrow> [i..j] = [i..j - 1]@[j]"
nipkow@52303
  3089
proof(induct "nat(j-i)" arbitrary: i j)
nipkow@52303
  3090
  case 0 thus ?case by(simp add: upto.simps)
nipkow@52303
  3091
next
nipkow@52303
  3092
  case (Suc n)
nipkow@52303
  3093
  hence "n = nat (j - (i + 1))" "i < j" by linarith+
nipkow@52303
  3094
  from this(2) Suc.hyps(1)[OF this(1)] Suc(2,3) upto_rec1 show ?case by simp
nipkow@52303
  3095
qed
nipkow@52303
  3096
nipkow@32415
  3097
lemma set_upto[simp]: "set[i..j] = {i..j}"
bulwahn@41695
  3098
proof(induct i j rule:upto.induct)
bulwahn@41695
  3099
  case (1 i j)
bulwahn@41695
  3100
  from this show ?case
bulwahn@41695
  3101
    unfolding upto.simps[of i j] simp_from_to[of i j] by auto
bulwahn@41695
  3102
qed
nipkow@32415
  3103
nipkow@52303
  3104
text{* Tail recursive version for code generation: *}
nipkow@52303
  3105
haftmann@52307
  3106
definition upto_aux :: "int \<Rightarrow> int \<Rightarrow> int list \<Rightarrow> int list" where
haftmann@52307
  3107
  "upto_aux i j js = [i..j] @ js"
haftmann@52307
  3108
haftmann@52307
  3109
lemma upto_aux_rec [code]:
nipkow@52303
  3110
  "upto_aux i j js = (if j<i then js else upto_aux i (j - 1) (j#js))"
haftmann@52307
  3111
  by (simp add: upto_aux_def upto_rec2)
nipkow@52303
  3112
nipkow@52303
  3113
lemma upto_code[code]: "[i..j] = upto_aux i j []"
haftmann@52307
  3114
by(simp add: upto_aux_def)
nipkow@52303
  3115
nipkow@32415
  3116
traytel@54858
  3117
subsubsection {* @{const distinct} and @{const remdups} and @{const remdups_adj} *}
wenzelm@13114
  3118
haftmann@40451
  3119
lemma distinct_tl:
haftmann@40451
  3120
  "distinct xs \<Longrightarrow> distinct (tl xs)"
haftmann@40451
  3121
  by (cases xs) simp_all
haftmann@40451
  3122
wenzelm@13142
  3123
lemma distinct_append [simp]:
nipkow@13145
  3124
"distinct (xs @ ys) = (distinct xs \<and> distinct ys \<and> set xs \<inter> set ys = {})"
nipkow@13145
  3125
by (induct xs) auto
wenzelm@13114
  3126
nipkow@15305
  3127
lemma distinct_rev[simp]: "distinct(rev xs) = distinct xs"
nipkow@15305
  3128
by(induct xs) auto
nipkow@15305
  3129
wenzelm@13142
  3130
lemma set_remdups [simp]: "set (remdups xs) = set xs"
nipkow@13145
  3131
by (induct xs) (auto simp add: insert_absorb)
wenzelm@13114
  3132
wenzelm@13142
  3133
lemma distinct_remdups [iff]: "distinct (remdups xs)"
nipkow@13145
  3134
by (induct xs) auto
wenzelm@13114
  3135
nipkow@25287
  3136
lemma distinct_remdups_id: "distinct xs ==> remdups xs = xs"
nipkow@25287
  3137
by (induct xs, auto)
nipkow@25287
  3138
haftmann@26734
  3139
lemma remdups_id_iff_distinct [simp]: "remdups xs = xs \<longleftrightarrow> distinct xs"
haftmann@26734
  3140
by (metis distinct_remdups distinct_remdups_id)
nipkow@25287
  3141
nipkow@24566
  3142
lemma finite_distinct_list: "finite A \<Longrightarrow> EX xs. set xs = A & distinct xs"
paulson@24632
  3143
by (metis distinct_remdups finite_list set_remdups)
nipkow@24566
  3144
paulson@15072
  3145
lemma remdups_eq_nil_iff [simp]: "(remdups x = []) = (x = [])"
blanchet@47268
  3146
by (induct x, auto)
paulson@15072
  3147
paulson@15072
  3148
lemma remdups_eq_nil_right_iff [simp]: "([] = remdups x) = (x = [])"
nipkow@24349
  3149
by (induct x, auto)
paulson@15072
  3150
nipkow@15245
  3151
lemma length_remdups_leq[iff]: "length(remdups xs) <= length xs"
nipkow@15245
  3152
by (induct xs) auto
nipkow@15245
  3153
nipkow@15245
  3154
lemma length_remdups_eq[iff]:
nipkow@15245
  3155
  "(length (remdups xs) = length xs) = (remdups xs = xs)"
nipkow@15245
  3156
apply(induct xs)
nipkow@15245
  3157
 apply auto
nipkow@15245
  3158
apply(subgoal_tac "length (remdups xs) <= length xs")
nipkow@15245
  3159
 apply arith
nipkow@15245
  3160
apply(rule length_remdups_leq)
nipkow@15245
  3161
done
nipkow@15245
  3162
nipkow@33911
  3163
lemma remdups_filter: "remdups(filter P xs) = filter P (remdups xs)"
nipkow@33911
  3164
apply(induct xs)
nipkow@33911
  3165
apply auto
nipkow@33911
  3166
done
nipkow@18490
  3167
nipkow@18490
  3168
lemma distinct_map:
nipkow@18490
  3169
  "distinct(map f xs) = (distinct xs & inj_on f (set xs))"
nipkow@18490
  3170
by (induct xs) auto
nipkow@18490
  3171
wenzelm@13142
  3172
lemma distinct_filter [simp]: "distinct xs ==> distinct (filter P xs)"
nipkow@13145
  3173
by (induct xs) auto
wenzelm@13114
  3174
nipkow@17501
  3175
lemma distinct_upt[simp]: "distinct[i..<j]"
nipkow@17501
  3176
by (induct j) auto
nipkow@17501
  3177
nipkow@32415
  3178
lemma distinct_upto[simp]: "distinct[i..j]"
nipkow@32415
  3179
apply(induct i j rule:upto.induct)
nipkow@32415
  3180
apply(subst upto.simps)
nipkow@32415
  3181
apply(simp)
nipkow@32415
  3182
done
nipkow@32415
  3183
nipkow@24526
  3184
lemma distinct_take[simp]: "distinct xs \<Longrightarrow> distinct (take i xs)"
nipkow@24526
  3185
apply(induct xs arbitrary: i)
nipkow@17501
  3186
 apply simp
nipkow@17501
  3187
apply (case_tac i)
nipkow@17501
  3188
 apply simp_all
nipkow@17501
  3189
apply(blast dest:in_set_takeD)
nipkow@17501
  3190
done
nipkow@17501
  3191
nipkow@24526
  3192
lemma distinct_drop[simp]: "distinct xs \<Longrightarrow> distinct (drop i xs)"
nipkow@24526
  3193
apply(induct xs arbitrary: i)
nipkow@17501
  3194
 apply simp
nipkow@17501
  3195
apply (case_tac i)
nipkow@17501
  3196
 apply simp_all
nipkow@17501
  3197
done
nipkow@17501
  3198
nipkow@17501
  3199
lemma distinct_list_update:
nipkow@17501
  3200
assumes d: "distinct xs" and a: "a \<notin> set xs - {xs!i}"
nipkow@17501
  3201
shows "distinct (xs[i:=a])"
nipkow@17501
  3202
proof (cases "i < length xs")
nipkow@17501
  3203
  case True
nipkow@17501
  3204
  with a have "a \<notin> set (take i xs @ xs ! i # drop (Suc i) xs) - {xs!i}"
nipkow@17501
  3205
    apply (drule_tac id_take_nth_drop) by simp
nipkow@17501
  3206
  with d True show ?thesis
nipkow@17501
  3207
    apply (simp add: upd_conv_take_nth_drop)
nipkow@17501
  3208
    apply (drule subst [OF id_take_nth_drop]) apply assumption
nipkow@17501
  3209
    apply simp apply (cases "a = xs!i") apply simp by blast
nipkow@17501
  3210
next
nipkow@17501
  3211
  case False with d show ?thesis by auto
nipkow@17501
  3212
qed
nipkow@17501
  3213
hoelzl@31350
  3214
lemma distinct_concat:
hoelzl@31350
  3215
  assumes "distinct xs"
hoelzl@31350
  3216
  and "\<And> ys. ys \<in> set xs \<Longrightarrow> distinct ys"
hoelzl@31350
  3217
  and "\<And> ys zs. \<lbrakk> ys \<in> set xs ; zs \<in> set xs ; ys \<noteq> zs \<rbrakk> \<Longrightarrow> set ys \<inter> set zs = {}"
hoelzl@31350
  3218
  shows "distinct (concat xs)"
hoelzl@31350
  3219
  using assms by (induct xs) auto
nipkow@17501
  3220
nipkow@17501
  3221
text {* It is best to avoid this indexed version of distinct, but
nipkow@17501
  3222
sometimes it is useful. *}
nipkow@17501
  3223
nipkow@13124
  3224
lemma distinct_conv_nth:
nipkow@17501
  3225
"distinct xs = (\<forall>i < size xs. \<forall>j < size xs. i \<noteq> j --> xs!i \<noteq> xs!j)"
paulson@15251
  3226
apply (induct xs, simp, simp)
paulson@14208
  3227
apply (rule iffI, clarsimp)
nipkow@13145
  3228
 apply (case_tac i)
paulson@14208
  3229
apply (case_tac j, simp)
nipkow@13145
  3230
apply (simp add: set_conv_nth)
nipkow@13145
  3231
 apply (case_tac j)
blanchet@47268
  3232
apply (clarsimp simp add: set_conv_nth, simp)
nipkow@13145
  3233
apply (rule conjI)
paulson@24648
  3234
(*TOO SLOW
paulson@24632
  3235
apply (metis Zero_neq_Suc gr0_conv_Suc in_set_conv_nth lessI less_trans_Suc nth_Cons' nth_Cons_Suc)
paulson@24648
  3236
*)
paulson@24648
  3237
 apply (clarsimp simp add: set_conv_nth)
paulson@24648
  3238
 apply (erule_tac x = 0 in allE, simp)
paulson@24648
  3239
 apply (erule_tac x = "Suc i" in allE, simp, clarsimp)
wenzelm@25130
  3240
(*TOO SLOW
paulson@24632
  3241
apply (metis Suc_Suc_eq lessI less_trans_Suc nth_Cons_Suc)
wenzelm@25130
  3242
*)
wenzelm@25130
  3243
apply (erule_tac x = "Suc i" in allE, simp)
wenzelm@25130
  3244
apply (erule_tac x = "Suc j" in allE, simp)
nipkow@13145
  3245
done
nipkow@13124
  3246
nipkow@18490
  3247
lemma nth_eq_iff_index_eq:
nipkow@18490
  3248
 "\<lbrakk> distinct xs; i < length xs; j < length xs \<rbrakk> \<Longrightarrow> (xs!i = xs!j) = (i = j)"
nipkow@18490
  3249
by(auto simp: distinct_conv_nth)
nipkow@18490
  3250
nipkow@15110
  3251
lemma distinct_card: "distinct xs ==> card (set xs) = size xs"
nipkow@24349
  3252
by (induct xs) auto
kleing@14388
  3253
nipkow@15110
  3254
lemma card_distinct: "card (set xs) = size xs ==> distinct xs"
kleing@14388
  3255
proof (induct xs)
kleing@14388
  3256
  case Nil thus ?case by simp
kleing@14388
  3257
next
kleing@14388
  3258
  case (Cons x xs)
kleing@14388
  3259
  show ?case
kleing@14388
  3260
  proof (cases "x \<in> set xs")
kleing@14388
  3261
    case False with Cons show ?thesis by simp
kleing@14388
  3262
  next
kleing@14388
  3263
    case True with Cons.prems
blanchet@47268
  3264
    have "card (set xs) = Suc (length xs)"
kleing@14388
  3265
      by (simp add: card_insert_if split: split_if_asm)
kleing@14388
  3266
    moreover have "card (set xs) \<le> length xs" by (rule card_length)
kleing@14388
  3267
    ultimately have False by simp
kleing@14388
  3268
    thus ?thesis ..
kleing@14388
  3269
  qed
kleing@14388
  3270
qed
kleing@14388
  3271
bulwahn@45967
  3272
lemma distinct_length_filter: "distinct xs \<Longrightarrow> length (filter P xs) = card ({x. P x} Int set xs)"
bulwahn@45967
  3273
by (induct xs) (auto)
bulwahn@45967
  3274
nipkow@25287
  3275
lemma not_distinct_decomp: "~ distinct ws ==> EX xs ys zs y. ws = xs@[y]@ys@[y]@zs"
nipkow@25287
  3276
apply (induct n == "length ws" arbitrary:ws) apply simp
nipkow@25287
  3277
apply(case_tac ws) apply simp
nipkow@25287
  3278
apply (simp split:split_if_asm)
nipkow@25287
  3279
apply (metis Cons_eq_appendI eq_Nil_appendI split_list)
nipkow@25287
  3280
done
nipkow@18490
  3281
noschinl@46707
  3282
lemma not_distinct_conv_prefix:
noschinl@46707
  3283
  defines "dec as xs y ys \<equiv> y \<in> set xs \<and> distinct xs \<and> as = xs @ y # ys"
noschinl@46707
  3284
  shows "\<not>distinct as \<longleftrightarrow> (\<exists>xs y ys. dec as xs y ys)" (is "?L = ?R")
noschinl@46707
  3285
proof
noschinl@46707
  3286
  assume "?L" then show "?R"
noschinl@46707
  3287
  proof (induct "length as" arbitrary: as rule: less_induct)
noschinl@46707
  3288
    case less
noschinl@46707
  3289
    obtain xs ys zs y where decomp: "as = (xs @ y # ys) @ y # zs"
noschinl@46707
  3290
      using not_distinct_decomp[OF less.prems] by auto
noschinl@46707
  3291
    show ?case
noschinl@46707
  3292
    proof (cases "distinct (xs @ y # ys)")
noschinl@46707
  3293
      case True
noschinl@46707
  3294
      with decomp have "dec as (xs @ y # ys) y zs" by (simp add: dec_def)
noschinl@46707
  3295
      then show ?thesis by blast
noschinl@46707
  3296
    next
noschinl@46707
  3297
      case False
noschinl@46707
  3298
      with less decomp obtain xs' y' ys' where "dec (xs @ y # ys) xs' y' ys'"
noschinl@46707
  3299
        by atomize_elim auto
noschinl@46707
  3300
      with decomp have "dec as xs' y' (ys' @ y # zs)" by (simp add: dec_def)
noschinl@46707
  3301
      then show ?thesis by blast
noschinl@46707
  3302
    qed
noschinl@46707
  3303
  qed
noschinl@46707
  3304
qed (auto simp: dec_def)
noschinl@46707
  3305
haftmann@50963
  3306
lemma distinct_product:
haftmann@50963
  3307
  assumes "distinct xs" and "distinct ys"
haftmann@50963
  3308
  shows "distinct (List.product xs ys)"
haftmann@50963
  3309
  using assms by (induct xs)
haftmann@50963
  3310
    (auto intro: inj_onI simp add: product_list_set distinct_map)
haftmann@50963
  3311
traytel@54858
  3312
lemma distinct_product_lists:
traytel@54858
  3313
  assumes "\<forall>xs \<in> set xss. distinct xs"
traytel@54858
  3314
  shows "distinct (product_lists xss)"
traytel@54858
  3315
using assms proof (induction xss)
traytel@54858
  3316
  case (Cons xs xss) note * = this
traytel@54858
  3317
  then show ?case
traytel@54858
  3318
  proof (cases "product_lists xss")
traytel@54858
  3319
    case Nil then show ?thesis by (induct xs) simp_all
traytel@54858
  3320
  next
traytel@54858
  3321
    case (Cons ps pss) with * show ?thesis 
traytel@54858
  3322
      by (auto intro!: inj_onI distinct_concat simp add: distinct_map)
traytel@54858
  3323
  qed
traytel@54858
  3324
qed simp
traytel@54858
  3325
nipkow@18490
  3326
lemma length_remdups_concat:
huffman@45792
  3327
  "length (remdups (concat xss)) = card (\<Union>xs\<in>set xss. set xs)"
huffman@45792
  3328
  by (simp add: distinct_card [symmetric])
nipkow@17906
  3329
hoelzl@33639
  3330
lemma length_remdups_card_conv: "length(remdups xs) = card(set xs)"
hoelzl@33639
  3331
proof -
hoelzl@33639
  3332
  have xs: "concat[xs] = xs" by simp
hoelzl@33639
  3333
  from length_remdups_concat[of "[xs]"] show ?thesis unfolding xs by simp
hoelzl@33639
  3334
qed
nipkow@17906
  3335
haftmann@36275
  3336
lemma remdups_remdups:
haftmann@36275
  3337
  "remdups (remdups xs) = remdups xs"
haftmann@36275
  3338
  by (induct xs) simp_all
haftmann@36275
  3339
haftmann@36846
  3340
lemma distinct_butlast:
bulwahn@47371
  3341
  assumes "distinct xs"
haftmann@36846
  3342
  shows "distinct (butlast xs)"
bulwahn@47371
  3343
proof (cases "xs = []")
bulwahn@47371
  3344
  case False
bulwahn@47371
  3345
    from `xs \<noteq> []` obtain ys y where "xs = ys @ [y]" by (cases xs rule: rev_cases) auto
bulwahn@47371
  3346
    with `distinct xs` show ?thesis by simp
bulwahn@47371
  3347
qed (auto)
haftmann@36846
  3348
haftmann@39960
  3349
lemma remdups_map_remdups:
haftmann@39960
  3350
  "remdups (map f (remdups xs)) = remdups (map f xs)"
haftmann@39960
  3351
  by (induct xs) simp_all
haftmann@39960
  3352
haftmann@40096
  3353
lemma distinct_zipI1:
haftmann@40096
  3354
  assumes "distinct xs"
haftmann@40096
  3355
  shows "distinct (zip xs ys)"
haftmann@40096
  3356
proof (rule zip_obtain_same_length)
haftmann@40096
  3357
  fix xs' :: "'a list" and ys' :: "'b list" and n
haftmann@40096
  3358
  assume "length xs' = length ys'"
haftmann@40096
  3359
  assume "xs' = take n xs"
haftmann@40096
  3360
  with assms have "distinct xs'" by simp
haftmann@40096
  3361
  with `length xs' = length ys'` show "distinct (zip xs' ys')"
haftmann@40096
  3362
    by (induct xs' ys' rule: list_induct2) (auto elim: in_set_zipE)
haftmann@40096
  3363
qed
haftmann@40096
  3364
haftmann@40096
  3365
lemma distinct_zipI2:
haftmann@40096
  3366
  assumes "distinct ys"
haftmann@40096
  3367
  shows "distinct (zip xs ys)"
haftmann@40096
  3368
proof (rule zip_obtain_same_length)
haftmann@40096
  3369
  fix xs' :: "'b list" and ys' :: "'a list" and n
haftmann@40096
  3370
  assume "length xs' = length ys'"
haftmann@40096
  3371
  assume "ys' = take n ys"
haftmann@40096
  3372
  with assms have "distinct ys'" by simp
haftmann@40096
  3373
  with `length xs' = length ys'` show "distinct (zip xs' ys')"
haftmann@40096
  3374
    by (induct xs' ys' rule: list_induct2) (auto elim: in_set_zipE)
haftmann@40096
  3375
qed
haftmann@40096
  3376
nipkow@47992
  3377
lemma set_take_disj_set_drop_if_distinct:
nipkow@47992
  3378
  "distinct vs \<Longrightarrow> i \<le> j \<Longrightarrow> set (take i vs) \<inter> set (drop j vs) = {}"
nipkow@47992
  3379
by (auto simp: in_set_conv_nth distinct_conv_nth)
nipkow@47992
  3380
blanchet@45493
  3381
(* The next two lemmas help Sledgehammer. *)
blanchet@45493
  3382
blanchet@45493
  3383
lemma distinct_singleton: "distinct [x]" by simp
blanchet@45493
  3384
blanchet@45493
  3385
lemma distinct_length_2_or_more:
blanchet@45493
  3386
"distinct (a # b # xs) \<longleftrightarrow> (a \<noteq> b \<and> distinct (a # xs) \<and> distinct (b # xs))"
blanchet@45493
  3387
by (metis distinct.simps(2) hd.simps hd_in_set list.simps(2) set_ConsD set_rev_mp set_subset_Cons)
blanchet@45493
  3388
traytel@54858
  3389
lemma remdups_adj_Cons: "remdups_adj (x # xs) =
traytel@54858
  3390
  (case remdups_adj xs of [] \<Rightarrow> [x] | y # xs \<Rightarrow> if x = y then y # xs else x # y # xs)"
traytel@54858
  3391
  by (induct xs arbitrary: x) (auto split: list.splits)
traytel@54858
  3392
traytel@54858
  3393
lemma remdups_adj_append_two: 
traytel@54858
  3394
  "remdups_adj (xs @ [x,y]) = remdups_adj (xs @ [x]) @ (if x = y then [] else [y])"
traytel@54858
  3395
  by (induct xs rule: remdups_adj.induct, simp_all)
traytel@54858
  3396
traytel@54858
  3397
lemma remdups_adj_rev[simp]: "remdups_adj (rev xs) = rev (remdups_adj xs)"
traytel@54858
  3398
  by (induct xs rule: remdups_adj.induct, simp_all add: remdups_adj_append_two)
traytel@54858
  3399
traytel@54858
  3400
lemma remdups_adj_length[simp]: "length (remdups_adj xs) \<le> length xs"
traytel@54858
  3401
  by (induct xs rule: remdups_adj.induct, auto)
traytel@54858
  3402
traytel@54858
  3403
lemma remdups_adj_length_ge1[simp]: "xs \<noteq> [] \<Longrightarrow> length (remdups_adj xs) \<ge> Suc 0"
traytel@54858
  3404
  by (induct xs rule: remdups_adj.induct, simp_all)
traytel@54858
  3405
traytel@54858
  3406
lemma remdups_adj_Nil_iff[simp]: "remdups_adj xs = [] \<longleftrightarrow> xs = []"
traytel@54858
  3407
  by (induct xs rule: remdups_adj.induct, simp_all)
traytel@54858
  3408
traytel@54858
  3409
lemma remdups_adj_set[simp]: "set (remdups_adj xs) = set xs"
traytel@54858
  3410
  by (induct xs rule: remdups_adj.induct, simp_all)
traytel@54858
  3411
traytel@54858
  3412
lemma remdups_adj_Cons_alt[simp]: "x # tl (remdups_adj (x # xs)) = remdups_adj (x # xs)"
traytel@54858
  3413
    by (induct xs rule: remdups_adj.induct, auto)
traytel@54858
  3414
traytel@54858
  3415
lemma remdups_adj_distinct: "distinct xs \<Longrightarrow> remdups_adj xs = xs"
traytel@54858
  3416
    by (induct xs rule: remdups_adj.induct, simp_all)
traytel@54858
  3417
traytel@54858
  3418
lemma remdups_adj_append: 
traytel@54858
  3419
  "remdups_adj (xs\<^sub>1 @ x # xs\<^sub>2) = remdups_adj (xs\<^sub>1 @ [x]) @ tl (remdups_adj (x # xs\<^sub>2))"
traytel@54858
  3420
  by (induct xs\<^sub>1 rule: remdups_adj.induct, simp_all)
traytel@54858
  3421
traytel@54858
  3422
lemma remdups_adj_singleton:
traytel@54858
  3423
  "remdups_adj xs = [x] \<Longrightarrow> xs = replicate (length xs) x"
traytel@54858
  3424
  by (induct xs rule: remdups_adj.induct, auto split: split_if_asm)
traytel@54858
  3425
traytel@54858
  3426
lemma remdups_adj_map_injective:
traytel@54858
  3427
  assumes "inj f"
traytel@54858
  3428
  shows "remdups_adj (map f xs) = map f (remdups_adj xs)"
traytel@54858
  3429
  by (induct xs rule: remdups_adj.induct, 
traytel@54858
  3430
      auto simp add: injD[OF assms])
traytel@54858
  3431
haftmann@50963
  3432
haftmann@37605
  3433
subsubsection {* List summation: @{const listsum} and @{text"\<Sum>"}*}
haftmann@37605
  3434
haftmann@40007
  3435
lemma (in monoid_add) listsum_simps [simp]:
haftmann@40007
  3436
  "listsum [] = 0"
haftmann@47004
  3437
  "listsum (x # xs) = x + listsum xs"
haftmann@40007
  3438
  by (simp_all add: listsum_def)
haftmann@40007
  3439
haftmann@40007
  3440
lemma (in monoid_add) listsum_append [simp]:
haftmann@40007
  3441
  "listsum (xs @ ys) = listsum xs + listsum ys"
haftmann@40007
  3442
  by (induct xs) (simp_all add: add.assoc)
haftmann@40007
  3443
haftmann@40007
  3444
lemma (in comm_monoid_add) listsum_rev [simp]:
haftmann@40007
  3445
  "listsum (rev xs) = listsum xs"
haftmann@48259
  3446
  by (simp add: listsum_def foldr_fold fold_rev fun_eq_iff add_ac)
haftmann@47004
  3447
haftmann@47004
  3448
lemma (in monoid_add) fold_plus_listsum_rev:
haftmann@47004
  3449
  "fold plus xs = plus (listsum (rev xs))"
haftmann@47004
  3450
proof
haftmann@47004
  3451
  fix x
haftmann@47004
  3452
  have "fold plus xs x = fold plus xs (x + 0)" by simp
haftmann@47004
  3453
  also have "\<dots> = fold plus (x # xs) 0" by simp
haftmann@48259
  3454
  also have "\<dots> = foldr plus (rev xs @ [x]) 0" by (simp add: foldr_conv_fold)
haftmann@47004
  3455
  also have "\<dots> = listsum (rev xs @ [x])" by (simp add: listsum_def)
haftmann@47004
  3456
  also have "\<dots> = listsum (rev xs) + listsum [x]" by simp
haftmann@47004
  3457
  finally show "fold plus xs x = listsum (rev xs) + x" by simp
haftmann@47004
  3458
qed
haftmann@47004
  3459
haftmann@47004
  3460
text{* Some syntactic sugar for summing a function over a list: *}
haftmann@47004
  3461
haftmann@47004
  3462
syntax
haftmann@47004
  3463
  "_listsum" :: "pttrn => 'a list => 'b => 'b"    ("(3SUM _<-_. _)" [0, 51, 10] 10)
haftmann@47004
  3464
syntax (xsymbols)
haftmann@47004
  3465
  "_listsum" :: "pttrn => 'a list => 'b => 'b"    ("(3\<Sum>_\<leftarrow>_. _)" [0, 51, 10] 10)
haftmann@47004
  3466
syntax (HTML output)
haftmann@47004
  3467
  "_listsum" :: "pttrn => 'a list => 'b => 'b"    ("(3\<Sum>_\<leftarrow>_. _)" [0, 51, 10] 10)
haftmann@47004
  3468
haftmann@47004
  3469
translations -- {* Beware of argument permutation! *}
haftmann@47004
  3470
  "SUM x<-xs. b" == "CONST listsum (CONST map (%x. b) xs)"
haftmann@47004
  3471
  "\<Sum>x\<leftarrow>xs. b" == "CONST listsum (CONST map (%x. b) xs)"
haftmann@40007
  3472
haftmann@40007
  3473
lemma (in comm_monoid_add) listsum_map_remove1:
haftmann@40007
  3474
  "x \<in> set xs \<Longrightarrow> listsum (map f xs) = f x + listsum (map f (remove1 x xs))"
haftmann@40007
  3475
  by (induct xs) (auto simp add: ac_simps)
haftmann@40007
  3476
haftmann@40007
  3477
lemma (in monoid_add) list_size_conv_listsum:
haftmann@37605
  3478
  "list_size f xs = listsum (map f xs) + size xs"
haftmann@40007
  3479
  by (induct xs) auto
haftmann@40007
  3480
haftmann@40007
  3481
lemma (in monoid_add) length_concat:
haftmann@40007
  3482
  "length (concat xss) = listsum (map length xss)"
haftmann@40007
  3483
  by (induct xss) simp_all
haftmann@40007
  3484
traytel@54858
  3485
lemma (in monoid_add) length_product_lists:
traytel@54858
  3486
  "length (product_lists xss) = foldr op * (map length xss) 1"
traytel@54858
  3487
proof (induct xss)
traytel@54858
  3488
  case (Cons xs xss) then show ?case by (induct xs) (auto simp: length_concat o_def)
traytel@54858
  3489
qed simp
traytel@54858
  3490
haftmann@40007
  3491
lemma (in monoid_add) listsum_map_filter:
haftmann@40007
  3492
  assumes "\<And>x. x \<in> set xs \<Longrightarrow> \<not> P x \<Longrightarrow> f x = 0"
haftmann@37605
  3493
  shows "listsum (map f (filter P xs)) = listsum (map f xs)"
haftmann@40007
  3494
  using assms by (induct xs) auto
haftmann@40007
  3495
haftmann@52875
  3496
lemma (in comm_monoid_add) distinct_listsum_conv_Setsum:
haftmann@40007
  3497
  "distinct xs \<Longrightarrow> listsum xs = Setsum (set xs)"
haftmann@40007
  3498
  by (induct xs) simp_all
haftmann@40007
  3499
haftmann@40007
  3500
lemma listsum_eq_0_nat_iff_nat [simp]:
haftmann@40007
  3501
  "listsum ns = (0::nat) \<longleftrightarrow> (\<forall>n \<in> set ns. n = 0)"
haftmann@48259
  3502
  by (induct ns) simp_all
haftmann@48259
  3503
haftmann@48259
  3504
lemma member_le_listsum_nat:
haftmann@48259
  3505
  "(n :: nat) \<in> set ns \<Longrightarrow> n \<le> listsum ns"
haftmann@48259
  3506
  by (induct ns) auto
haftmann@40007
  3507
haftmann@40007
  3508
lemma elem_le_listsum_nat:
haftmann@40007
  3509
  "k < size ns \<Longrightarrow> ns ! k \<le> listsum (ns::nat list)"
haftmann@48259
  3510
  by (rule member_le_listsum_nat) simp
haftmann@37605
  3511
haftmann@40007
  3512
lemma listsum_update_nat:
haftmann@48259
  3513
  "k < size ns \<Longrightarrow> listsum (ns[k := (n::nat)]) = listsum ns + n - ns ! k"
haftmann@37605
  3514
apply(induct ns arbitrary:k)
haftmann@37605
  3515
 apply (auto split:nat.split)
haftmann@37605
  3516
apply(drule elem_le_listsum_nat)
haftmann@37605
  3517
apply arith
haftmann@37605
  3518
done
haftmann@37605
  3519
haftmann@40007
  3520
lemma (in monoid_add) listsum_triv:
haftmann@40007
  3521
  "(\<Sum>x\<leftarrow>xs. r) = of_nat (length xs) * r"
webertj@50977
  3522
  by (induct xs) (simp_all add: distrib_right)
haftmann@37605
  3523
haftmann@40007
  3524
lemma (in monoid_add) listsum_0 [simp]:
haftmann@40007
  3525
  "(\<Sum>x\<leftarrow>xs. 0) = 0"
webertj@50977
  3526
  by (induct xs) (simp_all add: distrib_right)
haftmann@37605
  3527
haftmann@37605
  3528
text{* For non-Abelian groups @{text xs} needs to be reversed on one side: *}
haftmann@40007
  3529
lemma (in ab_group_add) uminus_listsum_map:
haftmann@40007
  3530
  "- listsum (map f xs) = listsum (map (uminus \<circ> f) xs)"
haftmann@40007
  3531
  by (induct xs) simp_all
haftmann@40007
  3532
haftmann@40007
  3533
lemma (in comm_monoid_add) listsum_addf:
haftmann@40007
  3534
  "(\<Sum>x\<leftarrow>xs. f x + g x) = listsum (map f xs) + listsum (map g xs)"
haftmann@40007
  3535
  by (induct xs) (simp_all add: algebra_simps)
haftmann@40007
  3536
haftmann@40007
  3537
lemma (in ab_group_add) listsum_subtractf:
haftmann@40007
  3538
  "(\<Sum>x\<leftarrow>xs. f x - g x) = listsum (map f xs) - listsum (map g xs)"
haftmann@40007
  3539
  by (induct xs) (simp_all add: algebra_simps)
haftmann@40007
  3540
haftmann@40007
  3541
lemma (in semiring_0) listsum_const_mult:
haftmann@40007
  3542
  "(\<Sum>x\<leftarrow>xs. c * f x) = c * (\<Sum>x\<leftarrow>xs. f x)"
haftmann@40007
  3543
  by (induct xs) (simp_all add: algebra_simps)
haftmann@40007
  3544
haftmann@40007
  3545
lemma (in semiring_0) listsum_mult_const:
haftmann@40007
  3546
  "(\<Sum>x\<leftarrow>xs. f x * c) = (\<Sum>x\<leftarrow>xs. f x) * c"
haftmann@40007
  3547
  by (induct xs) (simp_all add: algebra_simps)
haftmann@40007
  3548
haftmann@40007
  3549
lemma (in ordered_ab_group_add_abs) listsum_abs:
haftmann@40007
  3550
  "\<bar>listsum xs\<bar> \<le> listsum (map abs xs)"
haftmann@40007
  3551
  by (induct xs) (simp_all add: order_trans [OF abs_triangle_ineq])
haftmann@37605
  3552
haftmann@37605
  3553
lemma listsum_mono:
haftmann@40007
  3554
  fixes f g :: "'a \<Rightarrow> 'b::{monoid_add, ordered_ab_semigroup_add}"
haftmann@37605
  3555
  shows "(\<And>x. x \<in> set xs \<Longrightarrow> f x \<le> g x) \<Longrightarrow> (\<Sum>x\<leftarrow>xs. f x) \<le> (\<Sum>x\<leftarrow>xs. g x)"
haftmann@40007
  3556
  by (induct xs) (simp, simp add: add_mono)
haftmann@40007
  3557
haftmann@40007
  3558
lemma (in monoid_add) listsum_distinct_conv_setsum_set:
haftmann@37605
  3559
  "distinct xs \<Longrightarrow> listsum (map f xs) = setsum f (set xs)"
haftmann@37605
  3560
  by (induct xs) simp_all
haftmann@37605
  3561
haftmann@40007
  3562
lemma (in monoid_add) interv_listsum_conv_setsum_set_nat:
haftmann@37605
  3563
  "listsum (map f [m..<n]) = setsum f (set [m..<n])"
haftmann@37605
  3564
  by (simp add: listsum_distinct_conv_setsum_set)
haftmann@37605
  3565
haftmann@40007
  3566
lemma (in monoid_add) interv_listsum_conv_setsum_set_int:
haftmann@37605
  3567
  "listsum (map f [k..l]) = setsum f (set [k..l])"
haftmann@37605
  3568
  by (simp add: listsum_distinct_conv_setsum_set)
haftmann@37605
  3569
haftmann@37605
  3570
text {* General equivalence between @{const listsum} and @{const setsum} *}
haftmann@40007
  3571
lemma (in monoid_add) listsum_setsum_nth:
haftmann@37605
  3572
  "listsum xs = (\<Sum> i = 0 ..< length xs. xs ! i)"
haftmann@37605
  3573
  using interv_listsum_conv_setsum_set_nat [of "op ! xs" 0 "length xs"] by (simp add: map_nth)
haftmann@37605
  3574
haftmann@37605
  3575
haftmann@34965
  3576
subsubsection {* @{const insert} *}
haftmann@34965
  3577
haftmann@34965
  3578
lemma in_set_insert [simp]:
haftmann@34965
  3579
  "x \<in> set xs \<Longrightarrow> List.insert x xs = xs"
haftmann@34965
  3580
  by (simp add: List.insert_def)
haftmann@34965
  3581
haftmann@34965
  3582
lemma not_in_set_insert [simp]:
haftmann@34965
  3583
  "x \<notin> set xs \<Longrightarrow> List.insert x xs = x # xs"
haftmann@34965
  3584
  by (simp add: List.insert_def)
haftmann@34965
  3585
haftmann@34965
  3586
lemma insert_Nil [simp]:
haftmann@34965
  3587
  "List.insert x [] = [x]"
haftmann@34965
  3588
  by simp
haftmann@34965
  3589
haftmann@35295
  3590
lemma set_insert [simp]:
haftmann@34965
  3591
  "set (List.insert x xs) = insert x (set xs)"
haftmann@34965
  3592
  by (auto simp add: List.insert_def)
haftmann@34965
  3593
haftmann@35295
  3594
lemma distinct_insert [simp]:
haftmann@35295
  3595
  "distinct xs \<Longrightarrow> distinct (List.insert x xs)"
haftmann@35295
  3596
  by (simp add: List.insert_def)
haftmann@35295
  3597
haftmann@36275
  3598
lemma insert_remdups:
haftmann@36275
  3599
  "List.insert x (remdups xs) = remdups (List.insert x xs)"
haftmann@36275
  3600
  by (simp add: List.insert_def)
haftmann@36275
  3601
haftmann@34965
  3602
nipkow@47992
  3603
subsubsection {* @{const List.find} *}
nipkow@47992
  3604
nipkow@47992
  3605
lemma find_None_iff: "List.find P xs = None \<longleftrightarrow> \<not> (\<exists>x. x \<in> set xs \<and> P x)"
nipkow@47992
  3606
proof (induction xs)
nipkow@47992
  3607
  case Nil thus ?case by simp
nipkow@47992
  3608
next
nipkow@47992
  3609
  case (Cons x xs) thus ?case by (fastforce split: if_splits)
nipkow@47992
  3610
qed
nipkow@47992
  3611
nipkow@47992
  3612
lemma find_Some_iff:
nipkow@47992
  3613
  "List.find P xs = Some x \<longleftrightarrow>
nipkow@47992
  3614
  (\<exists>i<length xs. P (xs!i) \<and> x = xs!i \<and> (\<forall>j<i. \<not> P (xs!j)))"
nipkow@47992
  3615
proof (induction xs)
nipkow@47992
  3616
  case Nil thus ?case by simp
nipkow@47992
  3617
next
nipkow@47992
  3618
  case (Cons x xs) thus ?case
nipkow@47992
  3619
    by(auto simp: nth_Cons' split: if_splits)
nipkow@47992
  3620
      (metis One_nat_def diff_Suc_1 less_Suc_eq_0_disj)
nipkow@47992
  3621
qed
nipkow@47992
  3622
nipkow@47992
  3623
lemma find_cong[fundef_cong]:
nipkow@47992
  3624
  assumes "xs = ys" and "\<And>x. x \<in> set ys \<Longrightarrow> P x = Q x" 
nipkow@47992
  3625
  shows "List.find P xs = List.find Q ys"
nipkow@47992
  3626
proof (cases "List.find P xs")
nipkow@47992
  3627
  case None thus ?thesis by (metis find_None_iff assms)
nipkow@47992
  3628
next
nipkow@47992
  3629
  case (Some x)
nipkow@47992
  3630
  hence "List.find Q ys = Some x" using assms
nipkow@47992
  3631
    by (auto simp add: find_Some_iff)
nipkow@47992
  3632
  thus ?thesis using Some by auto
nipkow@47992
  3633
qed
nipkow@47992
  3634
haftmann@53516
  3635
lemma find_dropWhile:
haftmann@53516
  3636
  "List.find P xs = (case dropWhile (Not \<circ> P) xs
haftmann@53516
  3637
   of [] \<Rightarrow> None
haftmann@53516
  3638
    | x # _ \<Rightarrow> Some x)"
haftmann@53516
  3639
  by (induct xs) simp_all
haftmann@53516
  3640
nipkow@47992
  3641
nipkow@47992
  3642
subsubsection {* @{const remove1} *}
nipkow@15110
  3643
nipkow@18049
  3644
lemma remove1_append:
nipkow@18049
  3645
  "remove1 x (xs @ ys) =
nipkow@18049
  3646
  (if x \<in> set xs then remove1 x xs @ ys else xs @ remove1 x ys)"
nipkow@18049
  3647
by (induct xs) auto
nipkow@18049
  3648
nipkow@36895
  3649
lemma remove1_commute: "remove1 x (remove1 y zs) = remove1 y (remove1 x zs)"
nipkow@36895
  3650
by (induct zs) auto
nipkow@36895
  3651
nipkow@23479
  3652
lemma in_set_remove1[simp]:
nipkow@23479
  3653
  "a \<noteq> b \<Longrightarrow> a : set(remove1 b xs) = (a : set xs)"
nipkow@23479
  3654
apply (induct xs)
nipkow@23479
  3655
apply auto
nipkow@23479
  3656
done
nipkow@23479
  3657
nipkow@15110
  3658
lemma set_remove1_subset: "set(remove1 x xs) <= set xs"
nipkow@15110
  3659
apply(induct xs)
nipkow@15110
  3660
 apply simp
nipkow@15110
  3661
apply simp
nipkow@15110
  3662
apply blast
nipkow@15110
  3663
done
nipkow@15110
  3664
paulson@17724
  3665
lemma set_remove1_eq [simp]: "distinct xs ==> set(remove1 x xs) = set xs - {x}"
nipkow@15110
  3666
apply(induct xs)
nipkow@15110
  3667
 apply simp
nipkow@15110
  3668
apply simp
nipkow@15110
  3669
apply blast
nipkow@15110
  3670
done
nipkow@15110
  3671
nipkow@23479
  3672
lemma length_remove1:
huffman@30128
  3673
  "length(remove1 x xs) = (if x : set xs then length xs - 1 else length xs)"
nipkow@23479
  3674
apply (induct xs)
nipkow@23479
  3675
 apply (auto dest!:length_pos_if_in_set)
nipkow@23479
  3676
done
nipkow@23479
  3677
nipkow@18049
  3678
lemma remove1_filter_not[simp]:
nipkow@18049
  3679
  "\<not> P x \<Longrightarrow> remove1 x (filter P xs) = filter P xs"
nipkow@18049
  3680
by(induct xs) auto
nipkow@18049
  3681
hoelzl@39307
  3682
lemma filter_remove1:
hoelzl@39307
  3683
  "filter Q (remove1 x xs) = remove1 x (filter Q xs)"
hoelzl@39307
  3684
by (induct xs) auto
hoelzl@39307
  3685
nipkow@15110
  3686
lemma notin_set_remove1[simp]: "x ~: set xs ==> x ~: set(remove1 y xs)"
nipkow@15110
  3687
apply(insert set_remove1_subset)
nipkow@15110
  3688
apply fast
nipkow@15110
  3689
done
nipkow@15110
  3690
nipkow@15110
  3691
lemma distinct_remove1[simp]: "distinct xs ==> distinct(remove1 x xs)"
nipkow@15110
  3692
by (induct xs) simp_all
nipkow@15110
  3693
haftmann@36275
  3694
lemma remove1_remdups:
haftmann@36275
  3695
  "distinct xs \<Longrightarrow> remove1 x (remdups xs) = remdups (remove1 x xs)"
haftmann@36275
  3696
  by (induct xs) simp_all
haftmann@36275
  3697
haftmann@37091
  3698
lemma remove1_idem:
haftmann@37091
  3699
  assumes "x \<notin> set xs"
haftmann@37091
  3700
  shows "remove1 x xs = xs"
haftmann@37091
  3701
  using assms by (induct xs) simp_all
haftmann@37091
  3702
wenzelm@13114
  3703
haftmann@50963
  3704
subsubsection {* @{const removeAll} *}
nipkow@27693
  3705
haftmann@34965
  3706
lemma removeAll_filter_not_eq:
haftmann@34965
  3707
  "removeAll x = filter (\<lambda>y. x \<noteq> y)"
haftmann@34965
  3708
proof
haftmann@34965
  3709
  fix xs
haftmann@34965
  3710
  show "removeAll x xs = filter (\<lambda>y. x \<noteq> y) xs"
haftmann@34965
  3711
    by (induct xs) auto
haftmann@34965
  3712
qed
haftmann@34965
  3713
nipkow@27693
  3714
lemma removeAll_append[simp]:
nipkow@27693
  3715
  "removeAll x (xs @ ys) = removeAll x xs @ removeAll x ys"
nipkow@27693
  3716
by (induct xs) auto
nipkow@27693
  3717
nipkow@27693
  3718
lemma set_removeAll[simp]: "set(removeAll x xs) = set xs - {x}"
nipkow@27693
  3719
by (induct xs) auto
nipkow@27693
  3720
nipkow@27693
  3721
lemma removeAll_id[simp]: "x \<notin> set xs \<Longrightarrow> removeAll x xs = xs"
nipkow@27693
  3722
by (induct xs) auto
nipkow@27693
  3723
cezarykaliszyk@47276
  3724
(* Needs count:: 'a \<Rightarrow> 'a list \<Rightarrow> nat
nipkow@27693
  3725
lemma length_removeAll:
nipkow@27693
  3726
  "length(removeAll x xs) = length xs - count x xs"
nipkow@27693
  3727
*)
nipkow@27693
  3728
nipkow@27693
  3729
lemma removeAll_filter_not[simp]:
nipkow@27693
  3730
  "\<not> P x \<Longrightarrow> removeAll x (filter P xs) = filter P xs"
nipkow@27693
  3731
by(induct xs) auto
nipkow@27693
  3732
haftmann@34965
  3733
lemma distinct_removeAll:
haftmann@34965
  3734
  "distinct xs \<Longrightarrow> distinct (removeAll x xs)"
haftmann@34965
  3735
  by (simp add: removeAll_filter_not_eq)
nipkow@27693
  3736
nipkow@27693
  3737
lemma distinct_remove1_removeAll:
nipkow@27693
  3738
  "distinct xs ==> remove1 x xs = removeAll x xs"
nipkow@27693
  3739
by (induct xs) simp_all
nipkow@27693
  3740
nipkow@27693
  3741
lemma map_removeAll_inj_on: "inj_on f (insert x (set xs)) \<Longrightarrow>
nipkow@27693
  3742
  map f (removeAll x xs) = removeAll (f x) (map f xs)"
nipkow@27693
  3743
by (induct xs) (simp_all add:inj_on_def)
nipkow@27693
  3744
nipkow@27693
  3745
lemma map_removeAll_inj: "inj f \<Longrightarrow>
nipkow@27693
  3746
  map f (removeAll x xs) = removeAll (f x) (map f xs)"
nipkow@27693
  3747
by(metis map_removeAll_inj_on subset_inj_on subset_UNIV)
nipkow@27693
  3748
nipkow@27693
  3749
haftmann@50963
  3750
subsubsection {* @{const replicate} *}
wenzelm@13114
  3751
wenzelm@13142
  3752
lemma length_replicate [simp]: "length (replicate n x) = n"
nipkow@13145
  3753
by (induct n) auto
wenzelm@13142
  3754
hoelzl@36610
  3755
lemma Ex_list_of_length: "\<exists>xs. length xs = n"
hoelzl@36610
  3756
by (rule exI[of _ "replicate n undefined"]) simp
hoelzl@36610
  3757
wenzelm@13142
  3758
lemma map_replicate [simp]: "map f (replicate n x) = replicate n (f x)"
nipkow@13145
  3759
by (induct n) auto
wenzelm@13114
  3760
hoelzl@31350
  3761
lemma map_replicate_const:
hoelzl@31350
  3762
  "map (\<lambda> x. k) lst = replicate (length lst) k"
hoelzl@31350
  3763
  by (induct lst) auto
hoelzl@31350
  3764
wenzelm@13114
  3765
lemma replicate_app_Cons_same:
nipkow@13145
  3766
"(replicate n x) @ (x # xs) = x # replicate n x @ xs"
nipkow@13145
  3767
by (induct n) auto
wenzelm@13114
  3768
wenzelm@13142
  3769
lemma rev_replicate [simp]: "rev (replicate n x) = replicate n x"
paulson@14208
  3770
apply (induct n, simp)
nipkow@13145
  3771
apply (simp add: replicate_app_Cons_same)
nipkow@13145
  3772
done
wenzelm@13114
  3773
wenzelm@13142
  3774
lemma replicate_add: "replicate (n + m) x = replicate n x @ replicate m x"
nipkow@13145
  3775
by (induct n) auto
wenzelm@13114
  3776
nipkow@16397
  3777
text{* Courtesy of Matthias Daum: *}
nipkow@16397
  3778
lemma append_replicate_commute:
nipkow@16397
  3779
  "replicate n x @ replicate k x = replicate k x @ replicate n x"
nipkow@16397
  3780
apply (simp add: replicate_add [THEN sym])
nipkow@16397
  3781
apply (simp add: add_commute)
nipkow@16397
  3782
done
nipkow@16397
  3783
nipkow@31080
  3784
text{* Courtesy of Andreas Lochbihler: *}
nipkow@31080
  3785
lemma filter_replicate:
nipkow@31080
  3786
  "filter P (replicate n x) = (if P x then replicate n x else [])"
nipkow@31080
  3787
by(induct n) auto
nipkow@31080
  3788
wenzelm@13142
  3789
lemma hd_replicate [simp]: "n \<noteq> 0 ==> hd (replicate n x) = x"
nipkow@13145
  3790
by (induct n) auto
wenzelm@13114
  3791
bulwahn@47371
  3792
lemma tl_replicate [simp]: "tl (replicate n x) = replicate (n - 1) x"
nipkow@13145
  3793
by (induct n) auto
wenzelm@13114
  3794
wenzelm@13142
  3795
lemma last_replicate [simp]: "n \<noteq> 0 ==> last (replicate n x) = x"
nipkow@13145
  3796
by (atomize (full), induct n) auto
wenzelm@13114
  3797
nipkow@24526
  3798
lemma nth_replicate[simp]: "i < n ==> (replicate n x)!i = x"
nipkow@24526
  3799
apply (induct n arbitrary: i, simp)
nipkow@13145
  3800
apply (simp add: nth_Cons split: nat.split)
nipkow@13145
  3801
done
wenzelm@13114
  3802
nipkow@16397
  3803
text{* Courtesy of Matthias Daum (2 lemmas): *}
nipkow@16397
  3804
lemma take_replicate[simp]: "take i (replicate k x) = replicate (min i k) x"
nipkow@16397
  3805
apply (case_tac "k \<le> i")
nipkow@16397
  3806
 apply  (simp add: min_def)
nipkow@16397
  3807
apply (drule not_leE)
nipkow@16397
  3808
apply (simp add: min_def)
nipkow@16397
  3809
apply (subgoal_tac "replicate k x = replicate i x @ replicate (k - i) x")
nipkow@16397
  3810
 apply  simp
nipkow@16397
  3811
apply (simp add: replicate_add [symmetric])
nipkow@16397
  3812
done
nipkow@16397
  3813
nipkow@24526
  3814
lemma drop_replicate[simp]: "drop i (replicate k x) = replicate (k-i) x"
nipkow@24526
  3815
apply (induct k arbitrary: i)
nipkow@16397
  3816
 apply simp
nipkow@16397
  3817
apply clarsimp
nipkow@16397
  3818
apply (case_tac i)
nipkow@16397
  3819
 apply simp
nipkow@16397
  3820
apply clarsimp
nipkow@16397
  3821
done
nipkow@16397
  3822
wenzelm@13142
  3823
lemma set_replicate_Suc: "set (replicate (Suc n) x) = {x}"
nipkow@13145
  3824
by (induct n) auto
wenzelm@13114
  3825
wenzelm@13142
  3826
lemma set_replicate [simp]: "n \<noteq> 0 ==> set (replicate n x) = {x}"
nipkow@13145
  3827
by (fast dest!: not0_implies_Suc intro!: set_replicate_Suc)
wenzelm@13114
  3828
wenzelm@13142
  3829
lemma set_replicate_conv_if: "set (replicate n x) = (if n = 0 then {} else {x})"
nipkow@13145
  3830
by auto
wenzelm@13114
  3831
nipkow@37431
  3832
lemma in_set_replicate[simp]: "(x : set (replicate n y)) = (x = y & n \<noteq> 0)"
nipkow@37431
  3833
by (simp add: set_replicate_conv_if)
nipkow@37431
  3834
nipkow@37429
  3835
lemma Ball_set_replicate[simp]:
nipkow@37429
  3836
  "(ALL x : set(replicate n a). P x) = (P a | n=0)"
nipkow@37429
  3837
by(simp add: set_replicate_conv_if)
nipkow@37429
  3838
nipkow@37429
  3839
lemma Bex_set_replicate[simp]:
nipkow@37429
  3840
  "(EX x : set(replicate n a). P x) = (P a & n\<noteq>0)"
nipkow@37429
  3841
by(simp add: set_replicate_conv_if)
wenzelm@13114
  3842
haftmann@24796
  3843
lemma replicate_append_same:
haftmann@24796
  3844
  "replicate i x @ [x] = x # replicate i x"
haftmann@24796
  3845
  by (induct i) simp_all
haftmann@24796
  3846
haftmann@24796
  3847
lemma map_replicate_trivial:
haftmann@24796
  3848
  "map (\<lambda>i. x) [0..<i] = replicate i x"
haftmann@24796
  3849
  by (induct i) (simp_all add: replicate_append_same)
haftmann@24796
  3850
hoelzl@31350
  3851
lemma concat_replicate_trivial[simp]:
hoelzl@31350
  3852
  "concat (replicate i []) = []"
hoelzl@31350
  3853
  by (induct i) (auto simp add: map_replicate_const)
wenzelm@13114
  3854
nipkow@28642
  3855
lemma replicate_empty[simp]: "(replicate n x = []) \<longleftrightarrow> n=0"
nipkow@28642
  3856
by (induct n) auto
nipkow@28642
  3857
nipkow@28642
  3858
lemma empty_replicate[simp]: "([] = replicate n x) \<longleftrightarrow> n=0"
nipkow@28642
  3859
by (induct n) auto
nipkow@28642
  3860
nipkow@28642
  3861
lemma replicate_eq_replicate[simp]:
nipkow@28642
  3862
  "(replicate m x = replicate n y) \<longleftrightarrow> (m=n & (m\<noteq>0 \<longrightarrow> x=y))"
nipkow@28642
  3863
apply(induct m arbitrary: n)
nipkow@28642
  3864
 apply simp
nipkow@28642
  3865
apply(induct_tac n)
nipkow@28642
  3866
apply auto
nipkow@28642
  3867
done
nipkow@28642
  3868
haftmann@39756
  3869
lemma replicate_length_filter:
haftmann@39756
  3870
  "replicate (length (filter (\<lambda>y. x = y) xs)) x = filter (\<lambda>y. x = y) xs"
haftmann@39756
  3871
  by (induct xs) auto
haftmann@39756
  3872
noschinl@43585
  3873
lemma comm_append_are_replicate:
noschinl@43585
  3874
  fixes xs ys :: "'a list"
noschinl@43585
  3875
  assumes "xs \<noteq> []" "ys \<noteq> []"
noschinl@43585
  3876
  assumes "xs @ ys = ys @ xs"
noschinl@43585
  3877
  shows "\<exists>m n zs. concat (replicate m zs) = xs \<and> concat (replicate n zs) = ys"
noschinl@43585
  3878
  using assms
noschinl@43585
  3879
proof (induct "length (xs @ ys)" arbitrary: xs ys rule: less_induct)
noschinl@43585
  3880
  case less
noschinl@43585
  3881
noschinl@43585
  3882
  def xs' \<equiv> "if (length xs \<le> length ys) then xs else ys"
noschinl@43585
  3883
    and ys' \<equiv> "if (length xs \<le> length ys) then ys else xs"
noschinl@43585
  3884
  then have
noschinl@43585
  3885
    prems': "length xs' \<le> length ys'"
noschinl@43585
  3886
            "xs' @ ys' = ys' @ xs'"
noschinl@43585
  3887
      and "xs' \<noteq> []"
noschinl@43585
  3888
      and len: "length (xs @ ys) = length (xs' @ ys')"
noschinl@43585
  3889
    using less by (auto intro: less.hyps)
noschinl@43585
  3890
noschinl@43585
  3891
  from prems'
noschinl@43585
  3892
  obtain ws where "ys' = xs' @ ws"
noschinl@43585
  3893
    by (auto simp: append_eq_append_conv2)
noschinl@43585
  3894
noschinl@43585
  3895
  have "\<exists>m n zs. concat (replicate m zs) = xs' \<and> concat (replicate n zs) = ys'"
noschinl@43585
  3896
  proof (cases "ws = []")
noschinl@43585
  3897
    case True
noschinl@43585
  3898
    then have "concat (replicate 1 xs') = xs'"
noschinl@43585
  3899
      and "concat (replicate 1 xs') = ys'"
noschinl@43585
  3900
      using `ys' = xs' @ ws` by auto
noschinl@43585
  3901
    then show ?thesis by blast
noschinl@43585
  3902
  next
noschinl@43585
  3903
    case False
noschinl@43585
  3904
    from `ys' = xs' @ ws` and `xs' @ ys' = ys' @ xs'`
noschinl@43585
  3905
    have "xs' @ ws = ws @ xs'" by simp
noschinl@43585
  3906
    then have "\<exists>m n zs. concat (replicate m zs) = xs' \<and> concat (replicate n zs) = ws"
noschinl@43585
  3907
      using False and `xs' \<noteq> []` and `ys' = xs' @ ws` and len
noschinl@43585
  3908
      by (intro less.hyps) auto
wenzelm@54511
  3909
    then obtain m n zs where *: "concat (replicate m zs) = xs'"
noschinl@43585
  3910
      and "concat (replicate n zs) = ws" by blast
noschinl@43585
  3911
    then have "concat (replicate (m + n) zs) = ys'"
noschinl@43585
  3912
      using `ys' = xs' @ ws`
noschinl@43585
  3913
      by (simp add: replicate_add)
wenzelm@54511
  3914
    with * show ?thesis by blast
noschinl@43585
  3915
  qed
noschinl@43585
  3916
  then show ?case
noschinl@43585
  3917
    using xs'_def ys'_def by metis
noschinl@43585
  3918
qed
noschinl@43585
  3919
noschinl@43585
  3920
lemma comm_append_is_replicate:
noschinl@43585
  3921
  fixes xs ys :: "'a list"
noschinl@43585
  3922
  assumes "xs \<noteq> []" "ys \<noteq> []"
noschinl@43585
  3923
  assumes "xs @ ys = ys @ xs"
noschinl@43585
  3924
  shows "\<exists>n zs. n > 1 \<and> concat (replicate n zs) = xs @ ys"
noschinl@43585
  3925
noschinl@43585
  3926
proof -
noschinl@43585
  3927
  obtain m n zs where "concat (replicate m zs) = xs"
noschinl@43585
  3928
    and "concat (replicate n zs) = ys"
noschinl@43585
  3929
    using assms by (metis comm_append_are_replicate)
noschinl@43585
  3930
  then have "m + n > 1" and "concat (replicate (m+n) zs) = xs @ ys"
noschinl@43585
  3931
    using `xs \<noteq> []` and `ys \<noteq> []`
noschinl@43585
  3932
    by (auto simp: replicate_add)
noschinl@43585
  3933
  then show ?thesis by blast
noschinl@43585
  3934
qed
noschinl@43585
  3935
haftmann@53517
  3936
lemma Cons_replicate_eq:
haftmann@53517
  3937
  "x # xs = replicate n y \<longleftrightarrow> x = y \<and> n > 0 \<and> xs = replicate (n - 1) x"
haftmann@53517
  3938
  by (induct n) auto
haftmann@53517
  3939
haftmann@53517
  3940
lemma replicate_length_same:
haftmann@53517
  3941
  "(\<forall>y\<in>set xs. y = x) \<Longrightarrow> replicate (length xs) x = xs"
haftmann@53517
  3942
  by (induct xs) simp_all
haftmann@53517
  3943
haftmann@53517
  3944
lemma foldr_replicate [simp]:
haftmann@53517
  3945
  "foldr f (replicate n x) = f x ^^ n"
haftmann@53517
  3946
  by (induct n) (simp_all)
haftmann@53517
  3947
haftmann@53517
  3948
lemma fold_replicate [simp]:
haftmann@53517
  3949
  "fold f (replicate n x) = f x ^^ n"
haftmann@53517
  3950
  by (subst foldr_fold [symmetric]) simp_all
haftmann@53517
  3951
nipkow@28642
  3952
haftmann@52310
  3953
subsubsection {* @{const enumerate} *}
haftmann@52310
  3954
haftmann@52310
  3955
lemma enumerate_simps [simp, code]:
haftmann@52310
  3956
  "enumerate n [] = []"
haftmann@52310
  3957
  "enumerate n (x # xs) = (n, x) # enumerate (Suc n) xs"
haftmann@52310
  3958
  apply (auto simp add: enumerate_eq_zip not_le)
haftmann@52310
  3959
  apply (cases "n < n + length xs")
haftmann@52310
  3960
  apply (auto simp add: upt_conv_Cons)
haftmann@52310
  3961
  done
haftmann@52310
  3962
haftmann@52310
  3963
lemma length_enumerate [simp]:
haftmann@52310
  3964
  "length (enumerate n xs) = length xs"
haftmann@52310
  3965
  by (simp add: enumerate_eq_zip)
haftmann@52310
  3966
haftmann@52310
  3967
lemma map_fst_enumerate [simp]:
haftmann@52310
  3968
  "map fst (enumerate n xs) = [n..<n + length xs]"
haftmann@52310
  3969
  by (simp add: enumerate_eq_zip)
haftmann@52310
  3970
haftmann@52310
  3971
lemma map_snd_enumerate [simp]:
haftmann@52310
  3972
  "map snd (enumerate n xs) = xs"
haftmann@52310
  3973
  by (simp add: enumerate_eq_zip)
haftmann@52310
  3974
  
haftmann@52310
  3975
lemma in_set_enumerate_eq:
haftmann@52310
  3976
  "p \<in> set (enumerate n xs) \<longleftrightarrow> n \<le> fst p \<and> fst p < length xs + n \<and> nth xs (fst p - n) = snd p"
haftmann@52310
  3977
proof -
haftmann@52310
  3978
  { fix m
haftmann@52310
  3979
    assume "n \<le> m"
haftmann@52310
  3980
    moreover assume "m < length xs + n"
haftmann@52310
  3981
    ultimately have "[n..<n + length xs] ! (m - n) = m \<and>
haftmann@52310
  3982
      xs ! (m - n) = xs ! (m - n) \<and> m - n < length xs" by auto
haftmann@52310
  3983
    then have "\<exists>q. [n..<n + length xs] ! q = m \<and>
haftmann@52310
  3984
        xs ! q = xs ! (m - n) \<and> q < length xs" ..
haftmann@52310
  3985
  } then show ?thesis by (cases p) (auto simp add: enumerate_eq_zip in_set_zip)
haftmann@52310
  3986
qed
haftmann@52310
  3987
haftmann@52310
  3988
lemma nth_enumerate_eq:
haftmann@52310
  3989
  assumes "m < length xs"
haftmann@52310
  3990
  shows "enumerate n xs ! m = (n + m, xs ! m)"
haftmann@52310
  3991
  using assms by (simp add: enumerate_eq_zip)
haftmann@52310
  3992
haftmann@52310
  3993
lemma enumerate_replicate_eq:
haftmann@52310
  3994
  "enumerate n (replicate m a) = map (\<lambda>q. (q, a)) [n..<n + m]"
haftmann@52310
  3995
  by (rule pair_list_eqI)
haftmann@52310
  3996
    (simp_all add: enumerate_eq_zip comp_def map_replicate_const)
haftmann@52310
  3997
haftmann@52310
  3998
lemma enumerate_Suc_eq:
haftmann@52310
  3999
  "enumerate (Suc n) xs = map (apfst Suc) (enumerate n xs)"
haftmann@52310
  4000
  by (rule pair_list_eqI)
haftmann@52310
  4001
    (simp_all add: not_le, simp del: map_map [simp del] add: map_Suc_upt map_map [symmetric])
haftmann@52310
  4002
haftmann@53516
  4003
lemma distinct_enumerate [simp]:
haftmann@53516
  4004
  "distinct (enumerate n xs)"
haftmann@53516
  4005
  by (simp add: enumerate_eq_zip distinct_zipI1)
haftmann@53516
  4006
haftmann@52310
  4007
haftmann@50963
  4008
subsubsection {* @{const rotate1} and @{const rotate} *}
nipkow@15302
  4009
nipkow@15302
  4010
lemma rotate0[simp]: "rotate 0 = id"
nipkow@15302
  4011
by(simp add:rotate_def)
nipkow@15302
  4012
nipkow@15302
  4013
lemma rotate_Suc[simp]: "rotate (Suc n) xs = rotate1(rotate n xs)"
nipkow@15302
  4014
by(simp add:rotate_def)
nipkow@15302
  4015
nipkow@15302
  4016
lemma rotate_add:
nipkow@15302
  4017
  "rotate (m+n) = rotate m o rotate n"
nipkow@15302
  4018
by(simp add:rotate_def funpow_add)
nipkow@15302
  4019
nipkow@15302
  4020
lemma rotate_rotate: "rotate m (rotate n xs) = rotate (m+n) xs"
nipkow@15302
  4021
by(simp add:rotate_add)
nipkow@15302
  4022
nipkow@18049
  4023
lemma rotate1_rotate_swap: "rotate1 (rotate n xs) = rotate n (rotate1 xs)"
nipkow@18049
  4024
by(simp add:rotate_def funpow_swap1)
nipkow@18049
  4025
nipkow@15302
  4026
lemma rotate1_length01[simp]: "length xs <= 1 \<Longrightarrow> rotate1 xs = xs"
nipkow@15302
  4027
by(cases xs) simp_all
nipkow@15302
  4028
nipkow@15302
  4029
lemma rotate_length01[simp]: "length xs <= 1 \<Longrightarrow> rotate n xs = xs"
nipkow@15302
  4030
apply(induct n)
nipkow@15302
  4031
 apply simp
nipkow@15302
  4032
apply (simp add:rotate_def)
nipkow@15302
  4033
done
nipkow@15302
  4034
nipkow@15302
  4035
lemma rotate1_hd_tl: "xs \<noteq> [] \<Longrightarrow> rotate1 xs = tl xs @ [hd xs]"
blanchet@47268
  4036
by (cases xs) simp_all
nipkow@15302
  4037
nipkow@15302
  4038
lemma rotate_drop_take:
nipkow@15302
  4039
  "rotate n xs = drop (n mod length xs) xs @ take (n mod length xs) xs"
nipkow@15302
  4040
apply(induct n)
nipkow@15302
  4041
 apply simp
nipkow@15302
  4042
apply(simp add:rotate_def)
nipkow@15302
  4043
apply(cases "xs = []")
nipkow@15302
  4044
 apply (simp)
nipkow@15302
  4045
apply(case_tac "n mod length xs = 0")
nipkow@15302
  4046
 apply(simp add:mod_Suc)
nipkow@15302
  4047
 apply(simp add: rotate1_hd_tl drop_Suc take_Suc)
nipkow@15302
  4048
apply(simp add:mod_Suc rotate1_hd_tl drop_Suc[symmetric] drop_tl[symmetric]
nipkow@15302
  4049
                take_hd_drop linorder_not_le)
nipkow@15302
  4050
done
nipkow@15302
  4051
nipkow@15302
  4052
lemma rotate_conv_mod: "rotate n xs = rotate (n mod length xs) xs"
nipkow@15302
  4053
by(simp add:rotate_drop_take)
nipkow@15302
  4054
nipkow@15302
  4055
lemma rotate_id[simp]: "n mod length xs = 0 \<Longrightarrow> rotate n xs = xs"
nipkow@15302
  4056
by(simp add:rotate_drop_take)
nipkow@15302
  4057
nipkow@15302
  4058
lemma length_rotate1[simp]: "length(rotate1 xs) = length xs"
blanchet@47268
  4059
by (cases xs) simp_all
nipkow@15302
  4060
nipkow@24526
  4061
lemma length_rotate[simp]: "length(rotate n xs) = length xs"
nipkow@24526
  4062
by (induct n arbitrary: xs) (simp_all add:rotate_def)
nipkow@15302
  4063
nipkow@15302
  4064
lemma distinct1_rotate[simp]: "distinct(rotate1 xs) = distinct xs"
blanchet@47268
  4065
by (cases xs) auto
nipkow@15302
  4066
nipkow@15302
  4067
lemma distinct_rotate[simp]: "distinct(rotate n xs) = distinct xs"
nipkow@15302
  4068
by (induct n) (simp_all add:rotate_def)
nipkow@15302
  4069
nipkow@15302
  4070
lemma rotate_map: "rotate n (map f xs) = map f (rotate n xs)"
nipkow@15302
  4071
by(simp add:rotate_drop_take take_map drop_map)
nipkow@15302
  4072
nipkow@15302
  4073
lemma set_rotate1[simp]: "set(rotate1 xs) = set xs"
blanchet@47268
  4074
by (cases xs) auto
nipkow@15302
  4075
nipkow@15302
  4076
lemma set_rotate[simp]: "set(rotate n xs) = set xs"
nipkow@15302
  4077
by (induct n) (simp_all add:rotate_def)
nipkow@15302
  4078
nipkow@15302
  4079
lemma rotate1_is_Nil_conv[simp]: "(rotate1 xs = []) = (xs = [])"
blanchet@47268
  4080
by (cases xs) auto
nipkow@15302
  4081
nipkow@15302
  4082
lemma rotate_is_Nil_conv[simp]: "(rotate n xs = []) = (xs = [])"
nipkow@15302
  4083
by (induct n) (simp_all add:rotate_def)
nipkow@15302
  4084
nipkow@15439
  4085
lemma rotate_rev:
nipkow@15439
  4086
  "rotate n (rev xs) = rev(rotate (length xs - (n mod length xs)) xs)"
nipkow@15439
  4087
apply(simp add:rotate_drop_take rev_drop rev_take)
nipkow@15439
  4088
apply(cases "length xs = 0")
nipkow@15439
  4089
 apply simp
nipkow@15439
  4090
apply(cases "n mod length xs = 0")
nipkow@15439
  4091
 apply simp
nipkow@15439
  4092
apply(simp add:rotate_drop_take rev_drop rev_take)
nipkow@15439
  4093
done
nipkow@15439
  4094
nipkow@18423
  4095
lemma hd_rotate_conv_nth: "xs \<noteq> [] \<Longrightarrow> hd(rotate n xs) = xs!(n mod length xs)"
nipkow@18423
  4096
apply(simp add:rotate_drop_take hd_append hd_drop_conv_nth hd_conv_nth)
nipkow@18423
  4097
apply(subgoal_tac "length xs \<noteq> 0")
nipkow@18423
  4098
 prefer 2 apply simp
nipkow@18423
  4099
using mod_less_divisor[of "length xs" n] by arith
nipkow@18423
  4100
nipkow@15302
  4101
haftmann@50963
  4102
subsubsection {* @{const sublist} --- a generalization of @{const nth} to sets *}
nipkow@15302
  4103
nipkow@15302
  4104
lemma sublist_empty [simp]: "sublist xs {} = []"
nipkow@15302
  4105
by (auto simp add: sublist_def)
nipkow@15302
  4106
nipkow@15302
  4107
lemma sublist_nil [simp]: "sublist [] A = []"
nipkow@15302
  4108
by (auto simp add: sublist_def)
nipkow@15302
  4109
nipkow@15302
  4110
lemma length_sublist:
nipkow@15302
  4111
  "length(sublist xs I) = card{i. i < length xs \<and> i : I}"
nipkow@15302
  4112
by(simp add: sublist_def length_filter_conv_card cong:conj_cong)
nipkow@15302
  4113
nipkow@15302
  4114
lemma sublist_shift_lemma_Suc:
nipkow@24526
  4115
  "map fst (filter (%p. P(Suc(snd p))) (zip xs is)) =
nipkow@24526
  4116
   map fst (filter (%p. P(snd p)) (zip xs (map Suc is)))"
nipkow@24526
  4117
apply(induct xs arbitrary: "is")
nipkow@15302
  4118
 apply simp
nipkow@15302
  4119
apply (case_tac "is")
nipkow@15302
  4120
 apply simp
nipkow@15302
  4121
apply simp
nipkow@15302
  4122
done
nipkow@15302
  4123
nipkow@15302
  4124
lemma sublist_shift_lemma:
nipkow@23279
  4125
     "map fst [p<-zip xs [i..<i + length xs] . snd p : A] =
nipkow@23279
  4126
      map fst [p<-zip xs [0..<length xs] . snd p + i : A]"
nipkow@15302
  4127
by (induct xs rule: rev_induct) (simp_all add: add_commute)
nipkow@15302
  4128
nipkow@15302
  4129
lemma sublist_append:
nipkow@15302
  4130
     "sublist (l @ l') A = sublist l A @ sublist l' {j. j + length l : A}"
nipkow@15302
  4131
apply (unfold sublist_def)
nipkow@15302
  4132
apply (induct l' rule: rev_induct, simp)
huffman@45792
  4133
apply (simp add: upt_add_eq_append[of 0] sublist_shift_lemma)
nipkow@15302
  4134
apply (simp add: add_commute)
nipkow@15302
  4135
done
nipkow@15302
  4136
nipkow@15302
  4137
lemma sublist_Cons:
nipkow@15302
  4138
"sublist (x # l) A = (if 0:A then [x] else []) @ sublist l {j. Suc j : A}"
nipkow@15302
  4139
apply (induct l rule: rev_induct)
nipkow@15302
  4140
 apply (simp add: sublist_def)
nipkow@15302
  4141
apply (simp del: append_Cons add: append_Cons[symmetric] sublist_append)
nipkow@15302
  4142
done
nipkow@15302
  4143
nipkow@24526
  4144
lemma set_sublist: "set(sublist xs I) = {xs!i|i. i<size xs \<and> i \<in> I}"
nipkow@24526
  4145
apply(induct xs arbitrary: I)
nipkow@25162
  4146
apply(auto simp: sublist_Cons nth_Cons split:nat.split dest!: gr0_implies_Suc)
nipkow@15302
  4147
done
nipkow@15302
  4148
nipkow@15302
  4149
lemma set_sublist_subset: "set(sublist xs I) \<subseteq> set xs"
nipkow@15302
  4150
by(auto simp add:set_sublist)
nipkow@15302
  4151
nipkow@15302
  4152
lemma notin_set_sublistI[simp]: "x \<notin> set xs \<Longrightarrow> x \<notin> set(sublist xs I)"
nipkow@15302
  4153
by(auto simp add:set_sublist)
nipkow@15302
  4154
nipkow@15302
  4155
lemma in_set_sublistD: "x \<in> set(sublist xs I) \<Longrightarrow> x \<in> set xs"
nipkow@15302
  4156
by(auto simp add:set_sublist)
nipkow@15302
  4157
nipkow@15302
  4158
lemma sublist_singleton [simp]: "sublist [x] A = (if 0 : A then [x] else [])"
nipkow@15302
  4159
by (simp add: sublist_Cons)
nipkow@15302
  4160
nipkow@15302
  4161
nipkow@24526
  4162
lemma distinct_sublistI[simp]: "distinct xs \<Longrightarrow> distinct(sublist xs I)"
nipkow@24526
  4163
apply(induct xs arbitrary: I)
nipkow@15302
  4164
 apply simp
nipkow@15302
  4165
apply(auto simp add:sublist_Cons)
nipkow@15302
  4166
done
nipkow@15302
  4167
nipkow@15302
  4168
nipkow@15302
  4169
lemma sublist_upt_eq_take [simp]: "sublist l {..<n} = take n l"
nipkow@15302
  4170
apply (induct l rule: rev_induct, simp)
nipkow@15302
  4171
apply (simp split: nat_diff_split add: sublist_append)
nipkow@15302
  4172
done
nipkow@15302
  4173
nipkow@24526
  4174
lemma filter_in_sublist:
nipkow@24526
  4175
 "distinct xs \<Longrightarrow> filter (%x. x \<in> set(sublist xs s)) xs = sublist xs s"
nipkow@24526
  4176
proof (induct xs arbitrary: s)
nipkow@17501
  4177
  case Nil thus ?case by simp
nipkow@17501
  4178
next
nipkow@17501
  4179
  case (Cons a xs)
wenzelm@54511
  4180
  then have "!x. x: set xs \<longrightarrow> x \<noteq> a" by auto
wenzelm@54511
  4181
  with Cons show ?case by(simp add: sublist_Cons cong:filter_cong)
nipkow@17501
  4182
qed
nipkow@17501
  4183
nipkow@15302
  4184
haftmann@50963
  4185
subsubsection {* @{const sublists} and @{const List.n_lists} *}
haftmann@50963
  4186
haftmann@50963
  4187
lemma length_sublists:
haftmann@50963
  4188
  "length (sublists xs) = 2 ^ length xs"
haftmann@50963
  4189
  by (induct xs) (simp_all add: Let_def)
haftmann@50963
  4190
haftmann@50963
  4191
lemma sublists_powset:
haftmann@50963
  4192
  "set ` set (sublists xs) = Pow (set xs)"
haftmann@50963
  4193
proof -
haftmann@50963
  4194
  have aux: "\<And>x A. set ` Cons x ` A = insert x ` set ` A"
haftmann@50963
  4195
    by (auto simp add: image_def)
haftmann@50963
  4196
  have "set (map set (sublists xs)) = Pow (set xs)"
haftmann@50963
  4197
    by (induct xs)
haftmann@50963
  4198
      (simp_all add: aux Let_def Pow_insert Un_commute comp_def del: map_map)
haftmann@50963
  4199
  then show ?thesis by simp
haftmann@50963
  4200
qed
haftmann@50963
  4201
haftmann@50963
  4202
lemma distinct_set_sublists:
haftmann@50963
  4203
  assumes "distinct xs"
haftmann@50963
  4204
  shows "distinct (map set (sublists xs))"
haftmann@50963
  4205
proof (rule card_distinct)
haftmann@50963
  4206
  have "finite (set xs)" by rule
haftmann@50963
  4207
  then have "card (Pow (set xs)) = 2 ^ card (set xs)" by (rule card_Pow)
haftmann@50963
  4208
  with assms distinct_card [of xs]
haftmann@50963
  4209
    have "card (Pow (set xs)) = 2 ^ length xs" by simp
haftmann@50963
  4210
  then show "card (set (map set (sublists xs))) = length (map set (sublists xs))"
haftmann@50963
  4211
    by (simp add: sublists_powset length_sublists)
haftmann@50963
  4212
qed
haftmann@50963
  4213
haftmann@50963
  4214
lemma n_lists_Nil [simp]: "List.n_lists n [] = (if n = 0 then [[]] else [])"
haftmann@50963
  4215
  by (induct n) simp_all
haftmann@50963
  4216
haftmann@50963
  4217
lemma length_n_lists: "length (List.n_lists n xs) = length xs ^ n"
haftmann@50963
  4218
  by (induct n) (auto simp add: length_concat o_def listsum_triv)
haftmann@50963
  4219
haftmann@50963
  4220
lemma length_n_lists_elem: "ys \<in> set (List.n_lists n xs) \<Longrightarrow> length ys = n"
haftmann@50963
  4221
  by (induct n arbitrary: ys) auto
haftmann@50963
  4222
haftmann@50963
  4223
lemma set_n_lists: "set (List.n_lists n xs) = {ys. length ys = n \<and> set ys \<subseteq> set xs}"
haftmann@50963
  4224
proof (rule set_eqI)
haftmann@50963
  4225
  fix ys :: "'a list"
haftmann@50963
  4226
  show "ys \<in> set (List.n_lists n xs) \<longleftrightarrow> ys \<in> {ys. length ys = n \<and> set ys \<subseteq> set xs}"
haftmann@50963
  4227
  proof -
haftmann@50963
  4228
    have "ys \<in> set (List.n_lists n xs) \<Longrightarrow> length ys = n"
haftmann@50963
  4229
      by (induct n arbitrary: ys) auto
haftmann@50963
  4230
    moreover have "\<And>x. ys \<in> set (List.n_lists n xs) \<Longrightarrow> x \<in> set ys \<Longrightarrow> x \<in> set xs"
haftmann@50963
  4231
      by (induct n arbitrary: ys) auto
haftmann@50963
  4232
    moreover have "set ys \<subseteq> set xs \<Longrightarrow> ys \<in> set (List.n_lists (length ys) xs)"
haftmann@50963
  4233
      by (induct ys) auto
haftmann@50963
  4234
    ultimately show ?thesis by auto
haftmann@50963
  4235
  qed
haftmann@50963
  4236
qed
haftmann@50963
  4237
haftmann@50963
  4238
lemma distinct_n_lists:
haftmann@50963
  4239
  assumes "distinct xs"
haftmann@50963
  4240
  shows "distinct (List.n_lists n xs)"
haftmann@50963
  4241
proof (rule card_distinct)
haftmann@50963
  4242
  from assms have card_length: "card (set xs) = length xs" by (rule distinct_card)
haftmann@50963
  4243
  have "card (set (List.n_lists n xs)) = card (set xs) ^ n"
haftmann@50963
  4244
  proof (induct n)
haftmann@50963
  4245
    case 0 then show ?case by simp
haftmann@50963
  4246
  next
haftmann@50963
  4247
    case (Suc n)
haftmann@50963
  4248
    moreover have "card (\<Union>ys\<in>set (List.n_lists n xs). (\<lambda>y. y # ys) ` set xs)
haftmann@50963
  4249
      = (\<Sum>ys\<in>set (List.n_lists n xs). card ((\<lambda>y. y # ys) ` set xs))"
haftmann@50963
  4250
      by (rule card_UN_disjoint) auto
haftmann@50963
  4251
    moreover have "\<And>ys. card ((\<lambda>y. y # ys) ` set xs) = card (set xs)"
haftmann@50963
  4252
      by (rule card_image) (simp add: inj_on_def)
haftmann@50963
  4253
    ultimately show ?case by auto
haftmann@50963
  4254
  qed
haftmann@50963
  4255
  also have "\<dots> = length xs ^ n" by (simp add: card_length)
haftmann@50963
  4256
  finally show "card (set (List.n_lists n xs)) = length (List.n_lists n xs)"
haftmann@50963
  4257
    by (simp add: length_n_lists)
haftmann@50963
  4258
qed
haftmann@50963
  4259
haftmann@50963
  4260
nipkow@19390
  4261
subsubsection {* @{const splice} *}
nipkow@19390
  4262
nipkow@40841
  4263
lemma splice_Nil2 [simp, code]: "splice xs [] = xs"
nipkow@19390
  4264
by (cases xs) simp_all
nipkow@19390
  4265
nipkow@40841
  4266
declare splice.simps(1,3)[code]
nipkow@40841
  4267
declare splice.simps(2)[simp del]
nipkow@19390
  4268
nipkow@24526
  4269
lemma length_splice[simp]: "length(splice xs ys) = length xs + length ys"
nipkow@40841
  4270
by (induct xs ys rule: splice.induct) auto
nipkow@22793
  4271
wenzelm@35118
  4272
wenzelm@35118
  4273
subsubsection {* Transpose *}
hoelzl@34920
  4274
hoelzl@34920
  4275
function transpose where
hoelzl@34920
  4276
"transpose []             = []" |
hoelzl@34920
  4277
"transpose ([]     # xss) = transpose xss" |
hoelzl@34920
  4278
"transpose ((x#xs) # xss) =
hoelzl@34920
  4279
  (x # [h. (h#t) \<leftarrow> xss]) # transpose (xs # [t. (h#t) \<leftarrow> xss])"
hoelzl@34920
  4280
by pat_completeness auto
hoelzl@34920
  4281
hoelzl@34920
  4282
lemma transpose_aux_filter_head:
hoelzl@34920
  4283
  "concat (map (list_case [] (\<lambda>h t. [h])) xss) =
hoelzl@34920
  4284
  map (\<lambda>xs. hd xs) [ys\<leftarrow>xss . ys \<noteq> []]"
hoelzl@34920
  4285
  by (induct xss) (auto split: list.split)
hoelzl@34920
  4286
hoelzl@34920
  4287
lemma transpose_aux_filter_tail:
hoelzl@34920
  4288
  "concat (map (list_case [] (\<lambda>h t. [t])) xss) =
hoelzl@34920
  4289
  map (\<lambda>xs. tl xs) [ys\<leftarrow>xss . ys \<noteq> []]"
hoelzl@34920
  4290
  by (induct xss) (auto split: list.split)
hoelzl@34920
  4291
hoelzl@34920
  4292
lemma transpose_aux_max:
hoelzl@34920
  4293
  "max (Suc (length xs)) (foldr (\<lambda>xs. max (length xs)) xss 0) =
hoelzl@34920
  4294
  Suc (max (length xs) (foldr (\<lambda>x. max (length x - Suc 0)) [ys\<leftarrow>xss . ys\<noteq>[]] 0))"
hoelzl@34920
  4295
  (is "max _ ?foldB = Suc (max _ ?foldA)")
hoelzl@34920
  4296
proof (cases "[ys\<leftarrow>xss . ys\<noteq>[]] = []")
hoelzl@34920
  4297
  case True
hoelzl@34920
  4298
  hence "foldr (\<lambda>xs. max (length xs)) xss 0 = 0"
hoelzl@34920
  4299
  proof (induct xss)
hoelzl@34920
  4300
    case (Cons x xs)
wenzelm@54511
  4301
    then have "x = []" by (cases x) auto
wenzelm@54511
  4302
    with Cons show ?case by auto
hoelzl@34920
  4303
  qed simp
hoelzl@34920
  4304
  thus ?thesis using True by simp
hoelzl@34920
  4305
next
hoelzl@34920
  4306
  case False
hoelzl@34920
  4307
hoelzl@34920
  4308
  have foldA: "?foldA = foldr (\<lambda>x. max (length x)) [ys\<leftarrow>xss . ys \<noteq> []] 0 - 1"
hoelzl@34920
  4309
    by (induct xss) auto
hoelzl@34920
  4310
  have foldB: "?foldB = foldr (\<lambda>x. max (length x)) [ys\<leftarrow>xss . ys \<noteq> []] 0"
hoelzl@34920
  4311
    by (induct xss) auto
hoelzl@34920
  4312
hoelzl@34920
  4313
  have "0 < ?foldB"
hoelzl@34920
  4314
  proof -
hoelzl@34920
  4315
    from False
hoelzl@34920
  4316
    obtain z zs where zs: "[ys\<leftarrow>xss . ys \<noteq> []] = z#zs" by (auto simp: neq_Nil_conv)
hoelzl@34920
  4317
    hence "z \<in> set ([ys\<leftarrow>xss . ys \<noteq> []])" by auto
hoelzl@34920
  4318
    hence "z \<noteq> []" by auto
hoelzl@34920
  4319
    thus ?thesis
hoelzl@34920
  4320
      unfolding foldB zs
hoelzl@34920
  4321
      by (auto simp: max_def intro: less_le_trans)
hoelzl@34920
  4322
  qed
hoelzl@34920
  4323
  thus ?thesis
hoelzl@34920
  4324
    unfolding foldA foldB max_Suc_Suc[symmetric]
hoelzl@34920
  4325
    by simp
hoelzl@34920
  4326
qed
hoelzl@34920
  4327
hoelzl@34920
  4328
termination transpose
hoelzl@34920
  4329
  by (relation "measure (\<lambda>xs. foldr (\<lambda>xs. max (length xs)) xs 0 + length xs)")
hoelzl@34920
  4330
     (auto simp: transpose_aux_filter_tail foldr_map comp_def transpose_aux_max less_Suc_eq_le)
hoelzl@34920
  4331
hoelzl@34920
  4332
lemma transpose_empty: "(transpose xs = []) \<longleftrightarrow> (\<forall>x \<in> set xs. x = [])"
hoelzl@34920
  4333
  by (induct rule: transpose.induct) simp_all
hoelzl@34920
  4334
hoelzl@34920
  4335
lemma length_transpose:
hoelzl@34920
  4336
  fixes xs :: "'a list list"
hoelzl@34920
  4337
  shows "length (transpose xs) = foldr (\<lambda>xs. max (length xs)) xs 0"
hoelzl@34920
  4338
  by (induct rule: transpose.induct)
hoelzl@34920
  4339
    (auto simp: transpose_aux_filter_tail foldr_map comp_def transpose_aux_max
hoelzl@34920
  4340
                max_Suc_Suc[symmetric] simp del: max_Suc_Suc)
hoelzl@34920
  4341
hoelzl@34920
  4342
lemma nth_transpose:
hoelzl@34920
  4343
  fixes xs :: "'a list list"
hoelzl@34920
  4344
  assumes "i < length (transpose xs)"
hoelzl@34920
  4345
  shows "transpose xs ! i = map (\<lambda>xs. xs ! i) [ys \<leftarrow> xs. i < length ys]"
hoelzl@34920
  4346
using assms proof (induct arbitrary: i rule: transpose.induct)
hoelzl@34920
  4347
  case (3 x xs xss)
hoelzl@34920
  4348
  def XS == "(x # xs) # xss"
hoelzl@34920
  4349
  hence [simp]: "XS \<noteq> []" by auto
hoelzl@34920
  4350
  thus ?case
hoelzl@34920
  4351
  proof (cases i)
hoelzl@34920
  4352
    case 0
hoelzl@34920
  4353
    thus ?thesis by (simp add: transpose_aux_filter_head hd_conv_nth)
hoelzl@34920
  4354
  next
hoelzl@34920
  4355
    case (Suc j)
hoelzl@34920
  4356
    have *: "\<And>xss. xs # map tl xss = map tl ((x#xs)#xss)" by simp
hoelzl@34920
  4357
    have **: "\<And>xss. (x#xs) # filter (\<lambda>ys. ys \<noteq> []) xss = filter (\<lambda>ys. ys \<noteq> []) ((x#xs)#xss)" by simp
hoelzl@34920
  4358
    { fix x have "Suc j < length x \<longleftrightarrow> x \<noteq> [] \<and> j < length x - Suc 0"
hoelzl@34920
  4359
      by (cases x) simp_all
hoelzl@34920
  4360
    } note *** = this
hoelzl@34920
  4361
hoelzl@34920
  4362
    have j_less: "j < length (transpose (xs # concat (map (list_case [] (\<lambda>h t. [t])) xss)))"
hoelzl@34920
  4363
      using "3.prems" by (simp add: transpose_aux_filter_tail length_transpose Suc)
hoelzl@34920
  4364
hoelzl@34920
  4365
    show ?thesis
hoelzl@34920
  4366
      unfolding transpose.simps `i = Suc j` nth_Cons_Suc "3.hyps"[OF j_less]
hoelzl@34920
  4367
      apply (auto simp: transpose_aux_filter_tail filter_map comp_def length_transpose * ** *** XS_def[symmetric])
hoelzl@34920
  4368
      apply (rule_tac y=x in list.exhaust)
hoelzl@34920
  4369
      by auto
hoelzl@34920
  4370
  qed
hoelzl@34920
  4371
qed simp_all
hoelzl@34920
  4372
hoelzl@34920
  4373
lemma transpose_map_map:
hoelzl@34920
  4374
  "transpose (map (map f) xs) = map (map f) (transpose xs)"
hoelzl@34920
  4375
proof (rule nth_equalityI, safe)
hoelzl@34920
  4376
  have [simp]: "length (transpose (map (map f) xs)) = length (transpose xs)"
hoelzl@34920
  4377
    by (simp add: length_transpose foldr_map comp_def)
hoelzl@34920
  4378
  show "length (transpose (map (map f) xs)) = length (map (map f) (transpose xs))" by simp
hoelzl@34920
  4379
hoelzl@34920
  4380
  fix i assume "i < length (transpose (map (map f) xs))"
hoelzl@34920
  4381
  thus "transpose (map (map f) xs) ! i = map (map f) (transpose xs) ! i"
hoelzl@34920
  4382
    by (simp add: nth_transpose filter_map comp_def)
hoelzl@34920
  4383
qed
nipkow@24616
  4384
wenzelm@35118
  4385
nipkow@31557
  4386
subsubsection {* (In)finiteness *}
nipkow@28642
  4387
nipkow@28642
  4388
lemma finite_maxlen:
nipkow@28642
  4389
  "finite (M::'a list set) ==> EX n. ALL s:M. size s < n"
nipkow@28642
  4390
proof (induct rule: finite.induct)
nipkow@28642
  4391
  case emptyI show ?case by simp
nipkow@28642
  4392
next
nipkow@28642
  4393
  case (insertI M xs)
nipkow@28642
  4394
  then obtain n where "\<forall>s\<in>M. length s < n" by blast
nipkow@28642
  4395
  hence "ALL s:insert xs M. size s < max n (size xs) + 1" by auto
nipkow@28642
  4396
  thus ?case ..
nipkow@28642
  4397
qed
nipkow@28642
  4398
hoelzl@46584
  4399
lemma lists_length_Suc_eq:
hoelzl@46584
  4400
  "{xs. set xs \<subseteq> A \<and> length xs = Suc n} =
hoelzl@46584
  4401
    (\<lambda>(xs, n). n#xs) ` ({xs. set xs \<subseteq> A \<and> length xs = n} \<times> A)"
hoelzl@46584
  4402
  by (auto simp: length_Suc_conv)
hoelzl@46584
  4403
hoelzl@46584
  4404
lemma
hoelzl@46584
  4405
  assumes "finite A"
hoelzl@46584
  4406
  shows finite_lists_length_eq: "finite {xs. set xs \<subseteq> A \<and> length xs = n}"
hoelzl@46584
  4407
  and card_lists_length_eq: "card {xs. set xs \<subseteq> A \<and> length xs = n} = (card A)^n"
hoelzl@46584
  4408
  using `finite A`
hoelzl@46584
  4409
  by (induct n)
hoelzl@46584
  4410
     (auto simp: card_image inj_split_Cons lists_length_Suc_eq cong: conj_cong)
nipkow@31557
  4411
nipkow@31557
  4412
lemma finite_lists_length_le:
nipkow@31557
  4413
  assumes "finite A" shows "finite {xs. set xs \<subseteq> A \<and> length xs \<le> n}"
nipkow@31557
  4414
 (is "finite ?S")
nipkow@31557
  4415
proof-
nipkow@31557
  4416
  have "?S = (\<Union>n\<in>{0..n}. {xs. set xs \<subseteq> A \<and> length xs = n})" by auto
bulwahn@51042
  4417
  thus ?thesis by (auto intro!: finite_lists_length_eq[OF `finite A`] simp only:)
nipkow@31557
  4418
qed
nipkow@31557
  4419
hoelzl@46584
  4420
lemma card_lists_length_le:
hoelzl@46584
  4421
  assumes "finite A" shows "card {xs. set xs \<subseteq> A \<and> length xs \<le> n} = (\<Sum>i\<le>n. card A^i)"
hoelzl@46584
  4422
proof -
hoelzl@46584
  4423
  have "(\<Sum>i\<le>n. card A^i) = card (\<Union>i\<le>n. {xs. set xs \<subseteq> A \<and> length xs = i})"
hoelzl@46584
  4424
    using `finite A`
hoelzl@46584
  4425
    by (subst card_UN_disjoint)
hoelzl@46584
  4426
       (auto simp add: card_lists_length_eq finite_lists_length_eq)
hoelzl@46584
  4427
  also have "(\<Union>i\<le>n. {xs. set xs \<subseteq> A \<and> length xs = i}) = {xs. set xs \<subseteq> A \<and> length xs \<le> n}"
hoelzl@46584
  4428
    by auto
hoelzl@46584
  4429
  finally show ?thesis by simp
hoelzl@46584
  4430
qed
hoelzl@46584
  4431
noschinl@46803
  4432
lemma card_lists_distinct_length_eq:
noschinl@46803
  4433
  assumes "k < card A"
noschinl@46803
  4434
  shows "card {xs. length xs = k \<and> distinct xs \<and> set xs \<subseteq> A} = \<Prod>{card A - k + 1 .. card A}"
noschinl@46803
  4435
using assms
noschinl@46803
  4436
proof (induct k)
noschinl@46803
  4437
  case 0
noschinl@46803
  4438
  then have "{xs. length xs = 0 \<and> distinct xs \<and> set xs \<subseteq> A} = {[]}" by auto
noschinl@46803
  4439
  then show ?case by simp
noschinl@46803
  4440
next
noschinl@46803
  4441
  case (Suc k)
noschinl@46803
  4442
  let "?k_list" = "\<lambda>k xs. length xs = k \<and> distinct xs \<and> set xs \<subseteq> A"
noschinl@46803
  4443
  have inj_Cons: "\<And>A. inj_on (\<lambda>(xs, n). n # xs) A"  by (rule inj_onI) auto
noschinl@46803
  4444
noschinl@46803
  4445
  from Suc have "k < card A" by simp
noschinl@46803
  4446
  moreover have "finite A" using assms by (simp add: card_ge_0_finite)
noschinl@46803
  4447
  moreover have "finite {xs. ?k_list k xs}"
noschinl@46803
  4448
    using finite_lists_length_eq[OF `finite A`, of k]
noschinl@46803
  4449
    by - (rule finite_subset, auto)
noschinl@46803
  4450
  moreover have "\<And>i j. i \<noteq> j \<longrightarrow> {i} \<times> (A - set i) \<inter> {j} \<times> (A - set j) = {}"
noschinl@46803
  4451
    by auto
noschinl@46803
  4452
  moreover have "\<And>i. i \<in>Collect (?k_list k) \<Longrightarrow> card (A - set i) = card A - k"
noschinl@46803
  4453
    by (simp add: card_Diff_subset distinct_card)
noschinl@46803
  4454
  moreover have "{xs. ?k_list (Suc k) xs} =
haftmann@53278
  4455
      (\<lambda>(xs, n). n#xs) ` \<Union>((\<lambda>xs. {xs} \<times> (A - set xs)) ` {xs. ?k_list k xs})"
noschinl@46803
  4456
    by (auto simp: length_Suc_conv)
noschinl@46803
  4457
  moreover
noschinl@46803
  4458
  have "Suc (card A - Suc k) = card A - k" using Suc.prems by simp
noschinl@46803
  4459
  then have "(card A - k) * \<Prod>{Suc (card A - k)..card A} = \<Prod>{Suc (card A - Suc k)..card A}"
noschinl@46803
  4460
    by (subst setprod_insert[symmetric]) (simp add: atLeastAtMost_insertL)+
noschinl@46803
  4461
  ultimately show ?case
noschinl@46803
  4462
    by (simp add: card_image inj_Cons card_UN_disjoint Suc.hyps algebra_simps)
noschinl@46803
  4463
qed
noschinl@46803
  4464
nipkow@28642
  4465
lemma infinite_UNIV_listI: "~ finite(UNIV::'a list set)"
nipkow@28642
  4466
apply(rule notI)
nipkow@28642
  4467
apply(drule finite_maxlen)
nipkow@28642
  4468
apply (metis UNIV_I length_replicate less_not_refl)
nipkow@28642
  4469
done
nipkow@28642
  4470
nipkow@28642
  4471
wenzelm@35118
  4472
subsection {* Sorting *}
nipkow@24616
  4473
nipkow@24617
  4474
text{* Currently it is not shown that @{const sort} returns a
nipkow@24617
  4475
permutation of its input because the nicest proof is via multisets,
nipkow@24617
  4476
which are not yet available. Alternatively one could define a function
nipkow@24617
  4477
that counts the number of occurrences of an element in a list and use
nipkow@24617
  4478
that instead of multisets to state the correctness property. *}
nipkow@24617
  4479
nipkow@24616
  4480
context linorder
nipkow@24616
  4481
begin
nipkow@24616
  4482
haftmann@52685
  4483
lemma set_insort_key:
haftmann@52685
  4484
  "set (insort_key f x xs) = insert x (set xs)"
haftmann@52685
  4485
  by (induct xs) auto
haftmann@52685
  4486
haftmann@40451
  4487
lemma length_insort [simp]:
haftmann@40451
  4488
  "length (insort_key f x xs) = Suc (length xs)"
haftmann@40451
  4489
  by (induct xs) simp_all
haftmann@40451
  4490
haftmann@40451
  4491
lemma insort_key_left_comm:
haftmann@40451
  4492
  assumes "f x \<noteq> f y"
haftmann@40451
  4493
  shows "insort_key f y (insort_key f x xs) = insort_key f x (insort_key f y xs)"
haftmann@40451
  4494
  by (induct xs) (auto simp add: assms dest: antisym)
hoelzl@33639
  4495
haftmann@35195
  4496
lemma insort_left_comm:
haftmann@35195
  4497
  "insort x (insort y xs) = insort y (insort x xs)"
haftmann@40451
  4498
  by (cases "x = y") (auto intro: insort_key_left_comm)
haftmann@35195
  4499
haftmann@43740
  4500
lemma comp_fun_commute_insort:
haftmann@43740
  4501
  "comp_fun_commute insort"
haftmann@35195
  4502
proof
haftmann@43670
  4503
qed (simp add: insort_left_comm fun_eq_iff)
haftmann@35195
  4504
haftmann@35195
  4505
lemma sort_key_simps [simp]:
haftmann@35195
  4506
  "sort_key f [] = []"
haftmann@35195
  4507
  "sort_key f (x#xs) = insort_key f x (sort_key f xs)"
haftmann@35195
  4508
  by (simp_all add: sort_key_def)
haftmann@35195
  4509
haftmann@47004
  4510
lemma (in linorder) sort_key_conv_fold:
haftmann@47004
  4511
  assumes "inj_on f (set xs)"
haftmann@47004
  4512
  shows "sort_key f xs = fold (insort_key f) xs []"
haftmann@47004
  4513
proof -
haftmann@47004
  4514
  have "fold (insort_key f) (rev xs) = fold (insort_key f) xs"
haftmann@47004
  4515
  proof (rule fold_rev, rule ext)
haftmann@47004
  4516
    fix zs
haftmann@47004
  4517
    fix x y
haftmann@47004
  4518
    assume "x \<in> set xs" "y \<in> set xs"
haftmann@47004
  4519
    with assms have *: "f y = f x \<Longrightarrow> y = x" by (auto dest: inj_onD)
haftmann@47004
  4520
    have **: "x = y \<longleftrightarrow> y = x" by auto
haftmann@47004
  4521
    show "(insort_key f y \<circ> insort_key f x) zs = (insort_key f x \<circ> insort_key f y) zs"
haftmann@47004
  4522
      by (induct zs) (auto intro: * simp add: **)
haftmann@47004
  4523
  qed
haftmann@48259
  4524
  then show ?thesis by (simp add: sort_key_def foldr_conv_fold)
haftmann@47004
  4525
qed
haftmann@47004
  4526
haftmann@47004
  4527
lemma (in linorder) sort_conv_fold:
haftmann@47004
  4528
  "sort xs = fold insort xs []"
haftmann@47004
  4529
  by (rule sort_key_conv_fold) simp
haftmann@35195
  4530
hoelzl@33639
  4531
lemma length_sort[simp]: "length (sort_key f xs) = length xs"
hoelzl@33639
  4532
by (induct xs, auto)
hoelzl@33639
  4533
haftmann@25062
  4534
lemma sorted_Cons: "sorted (x#xs) = (sorted xs & (ALL y:set xs. x <= y))"
nipkow@24616
  4535
apply(induct xs arbitrary: x) apply simp
nipkow@24616
  4536
by simp (blast intro: order_trans)
nipkow@24616
  4537
haftmann@40451
  4538
lemma sorted_tl:
haftmann@40451
  4539
  "sorted xs \<Longrightarrow> sorted (tl xs)"
haftmann@40451
  4540
  by (cases xs) (simp_all add: sorted_Cons)
haftmann@40451
  4541
nipkow@24616
  4542
lemma sorted_append:
haftmann@25062
  4543
  "sorted (xs@ys) = (sorted xs & sorted ys & (\<forall>x \<in> set xs. \<forall>y \<in> set ys. x\<le>y))"
nipkow@24616
  4544
by (induct xs) (auto simp add:sorted_Cons)
nipkow@24616
  4545
nipkow@31201
  4546
lemma sorted_nth_mono:
hoelzl@33639
  4547
  "sorted xs \<Longrightarrow> i \<le> j \<Longrightarrow> j < length xs \<Longrightarrow> xs!i \<le> xs!j"
nipkow@31201
  4548
by (induct xs arbitrary: i j) (auto simp:nth_Cons' sorted_Cons)
nipkow@31201
  4549
hoelzl@33639
  4550
lemma sorted_rev_nth_mono:
hoelzl@33639
  4551
  "sorted (rev xs) \<Longrightarrow> i \<le> j \<Longrightarrow> j < length xs \<Longrightarrow> xs!j \<le> xs!i"
hoelzl@33639
  4552
using sorted_nth_mono[ of "rev xs" "length xs - j - 1" "length xs - i - 1"]
hoelzl@33639
  4553
      rev_nth[of "length xs - i - 1" "xs"] rev_nth[of "length xs - j - 1" "xs"]
hoelzl@33639
  4554
by auto
hoelzl@33639
  4555
hoelzl@33639
  4556
lemma sorted_nth_monoI:
hoelzl@33639
  4557
  "(\<And> i j. \<lbrakk> i \<le> j ; j < length xs \<rbrakk> \<Longrightarrow> xs ! i \<le> xs ! j) \<Longrightarrow> sorted xs"
hoelzl@33639
  4558
proof (induct xs)
hoelzl@33639
  4559
  case (Cons x xs)
hoelzl@33639
  4560
  have "sorted xs"
hoelzl@33639
  4561
  proof (rule Cons.hyps)
hoelzl@33639
  4562
    fix i j assume "i \<le> j" and "j < length xs"
hoelzl@33639
  4563
    with Cons.prems[of "Suc i" "Suc j"]
hoelzl@33639
  4564
    show "xs ! i \<le> xs ! j" by auto
hoelzl@33639
  4565
  qed
hoelzl@33639
  4566
  moreover
hoelzl@33639
  4567
  {
hoelzl@33639
  4568
    fix y assume "y \<in> set xs"
hoelzl@33639
  4569
    then obtain j where "j < length xs" and "xs ! j = y"
hoelzl@33639
  4570
      unfolding in_set_conv_nth by blast
hoelzl@33639
  4571
    with Cons.prems[of 0 "Suc j"]
hoelzl@33639
  4572
    have "x \<le> y"
hoelzl@33639
  4573
      by auto
hoelzl@33639
  4574
  }
hoelzl@33639
  4575
  ultimately
hoelzl@33639
  4576
  show ?case
hoelzl@33639
  4577
    unfolding sorted_Cons by auto
hoelzl@33639
  4578
qed simp
hoelzl@33639
  4579
hoelzl@33639
  4580
lemma sorted_equals_nth_mono:
hoelzl@33639
  4581
  "sorted xs = (\<forall>j < length xs. \<forall>i \<le> j. xs ! i \<le> xs ! j)"
hoelzl@33639
  4582
by (auto intro: sorted_nth_monoI sorted_nth_mono)
hoelzl@33639
  4583
hoelzl@33639
  4584
lemma set_insort: "set(insort_key f x xs) = insert x (set xs)"
nipkow@24616
  4585
by (induct xs) auto
nipkow@24616
  4586
hoelzl@33639
  4587
lemma set_sort[simp]: "set(sort_key f xs) = set xs"
nipkow@24616
  4588
by (induct xs) (simp_all add:set_insort)
nipkow@24616
  4589
hoelzl@33639
  4590
lemma distinct_insort: "distinct (insort_key f x xs) = (x \<notin> set xs \<and> distinct xs)"
nipkow@24616
  4591
by(induct xs)(auto simp:set_insort)
nipkow@24616
  4592
hoelzl@33639
  4593
lemma distinct_sort[simp]: "distinct (sort_key f xs) = distinct xs"
huffman@45792
  4594
  by (induct xs) (simp_all add: distinct_insort)
nipkow@24616
  4595
hoelzl@33639
  4596
lemma sorted_insort_key: "sorted (map f (insort_key f x xs)) = sorted (map f xs)"
haftmann@40451
  4597
  by (induct xs) (auto simp:sorted_Cons set_insort)
hoelzl@33639
  4598
nipkow@24616
  4599
lemma sorted_insort: "sorted (insort x xs) = sorted xs"
haftmann@40451
  4600
  using sorted_insort_key [where f="\<lambda>x. x"] by simp
haftmann@40451
  4601
haftmann@40451
  4602
theorem sorted_sort_key [simp]: "sorted (map f (sort_key f xs))"
haftmann@40451
  4603
  by (induct xs) (auto simp:sorted_insort_key)
haftmann@40451
  4604
haftmann@40451
  4605
theorem sorted_sort [simp]: "sorted (sort xs)"
haftmann@40451
  4606
  using sorted_sort_key [where f="\<lambda>x. x"] by simp
hoelzl@33639
  4607
haftmann@36846
  4608
lemma sorted_butlast:
haftmann@36846
  4609
  assumes "xs \<noteq> []" and "sorted xs"
haftmann@36846
  4610
  shows "sorted (butlast xs)"
haftmann@36846
  4611
proof -
haftmann@36846
  4612
  from `xs \<noteq> []` obtain ys y where "xs = ys @ [y]" by (cases xs rule: rev_cases) auto
haftmann@36846
  4613
  with `sorted xs` show ?thesis by (simp add: sorted_append)
haftmann@36846
  4614
qed
haftmann@36846
  4615
  
haftmann@36846
  4616
lemma insort_not_Nil [simp]:
haftmann@36846
  4617
  "insort_key f a xs \<noteq> []"
haftmann@36846
  4618
  by (induct xs) simp_all
haftmann@36846
  4619
hoelzl@33639
  4620
lemma insort_is_Cons: "\<forall>x\<in>set xs. f a \<le> f x \<Longrightarrow> insort_key f a xs = a # xs"
bulwahn@26143
  4621
by (cases xs) auto
bulwahn@26143
  4622
bulwahn@45787
  4623
lemma sorted_sort_id: "sorted xs \<Longrightarrow> sort xs = xs"
bulwahn@45787
  4624
  by (induct xs) (auto simp add: sorted_Cons insort_is_Cons)
bulwahn@45787
  4625
haftmann@39756
  4626
lemma sorted_map_remove1:
haftmann@39756
  4627
  "sorted (map f xs) \<Longrightarrow> sorted (map f (remove1 x xs))"
haftmann@39756
  4628
  by (induct xs) (auto simp add: sorted_Cons)
haftmann@39756
  4629
bulwahn@26143
  4630
lemma sorted_remove1: "sorted xs \<Longrightarrow> sorted (remove1 a xs)"
haftmann@39756
  4631
  using sorted_map_remove1 [of "\<lambda>x. x"] by simp
haftmann@39756
  4632
haftmann@39756
  4633
lemma insort_key_remove1:
haftmann@39756
  4634
  assumes "a \<in> set xs" and "sorted (map f xs)" and "hd (filter (\<lambda>x. f a = f x) xs) = a"
haftmann@39756
  4635
  shows "insort_key f a (remove1 a xs) = xs"
haftmann@39756
  4636
using assms proof (induct xs)
hoelzl@33639
  4637
  case (Cons x xs)
haftmann@39756
  4638
  then show ?case
hoelzl@33639
  4639
  proof (cases "x = a")
hoelzl@33639
  4640
    case False
haftmann@39756
  4641
    then have "f x \<noteq> f a" using Cons.prems by auto
haftmann@39756
  4642
    then have "f x < f a" using Cons.prems by (auto simp: sorted_Cons)
haftmann@39756
  4643
    with `f x \<noteq> f a` show ?thesis using Cons by (auto simp: sorted_Cons insort_is_Cons)
hoelzl@33639
  4644
  qed (auto simp: sorted_Cons insort_is_Cons)
hoelzl@33639
  4645
qed simp
bulwahn@26143
  4646
haftmann@39756
  4647
lemma insort_remove1:
haftmann@39756
  4648
  assumes "a \<in> set xs" and "sorted xs"
haftmann@39756
  4649
  shows "insort a (remove1 a xs) = xs"
haftmann@39756
  4650
proof (rule insort_key_remove1)
haftmann@39756
  4651
  from `a \<in> set xs` show "a \<in> set xs" .
haftmann@39756
  4652
  from `sorted xs` show "sorted (map (\<lambda>x. x) xs)" by simp
haftmann@39756
  4653
  from `a \<in> set xs` have "a \<in> set (filter (op = a) xs)" by auto
haftmann@39756
  4654
  then have "set (filter (op = a) xs) \<noteq> {}" by auto
haftmann@39756
  4655
  then have "filter (op = a) xs \<noteq> []" by (auto simp only: set_empty)
haftmann@39756
  4656
  then have "length (filter (op = a) xs) > 0" by simp
haftmann@39756
  4657
  then obtain n where n: "Suc n = length (filter (op = a) xs)"
haftmann@39756
  4658
    by (cases "length (filter (op = a) xs)") simp_all
haftmann@39756
  4659
  moreover have "replicate (Suc n) a = a # replicate n a"
haftmann@39756
  4660
    by simp
haftmann@39756
  4661
  ultimately show "hd (filter (op = a) xs) = a" by (simp add: replicate_length_filter)
haftmann@39756
  4662
qed
bulwahn@26143
  4663
bulwahn@26143
  4664
lemma sorted_remdups[simp]:
bulwahn@26143
  4665
  "sorted l \<Longrightarrow> sorted (remdups l)"
bulwahn@26143
  4666
by (induct l) (auto simp: sorted_Cons)
bulwahn@26143
  4667
traytel@54858
  4668
lemma sorted_remdups_adj[simp]:
traytel@54858
  4669
  "sorted xs \<Longrightarrow> sorted (remdups_adj xs)"
traytel@54858
  4670
by (induct xs rule: remdups_adj.induct, simp_all split: split_if_asm add: sorted_Cons)
traytel@54858
  4671
nipkow@24645
  4672
lemma sorted_distinct_set_unique:
nipkow@24645
  4673
assumes "sorted xs" "distinct xs" "sorted ys" "distinct ys" "set xs = set ys"
nipkow@24645
  4674
shows "xs = ys"
nipkow@24645
  4675
proof -
haftmann@26734
  4676
  from assms have 1: "length xs = length ys" by (auto dest!: distinct_card)
nipkow@24645
  4677
  from assms show ?thesis
nipkow@24645
  4678
  proof(induct rule:list_induct2[OF 1])
nipkow@24645
  4679
    case 1 show ?case by simp
nipkow@24645
  4680
  next
nipkow@24645
  4681
    case 2 thus ?case by (simp add:sorted_Cons)
nipkow@24645
  4682
       (metis Diff_insert_absorb antisym insertE insert_iff)
nipkow@24645
  4683
  qed
nipkow@24645
  4684
qed
nipkow@24645
  4685
haftmann@35603
  4686
lemma map_sorted_distinct_set_unique:
haftmann@35603
  4687
  assumes "inj_on f (set xs \<union> set ys)"
haftmann@35603
  4688
  assumes "sorted (map f xs)" "distinct (map f xs)"
haftmann@35603
  4689
    "sorted (map f ys)" "distinct (map f ys)"
haftmann@35603
  4690
  assumes "set xs = set ys"
haftmann@35603
  4691
  shows "xs = ys"
haftmann@35603
  4692
proof -
haftmann@35603
  4693
  from assms have "map f xs = map f ys"
haftmann@35603
  4694
    by (simp add: sorted_distinct_set_unique)
wenzelm@54511
  4695
  with `inj_on f (set xs \<union> set ys)` show "xs = ys"
haftmann@35603
  4696
    by (blast intro: map_inj_on)
haftmann@35603
  4697
qed
haftmann@35603
  4698
nipkow@24645
  4699
lemma finite_sorted_distinct_unique:
nipkow@24645
  4700
shows "finite A \<Longrightarrow> EX! xs. set xs = A & sorted xs & distinct xs"
nipkow@24645
  4701
apply(drule finite_distinct_list)
nipkow@24645
  4702
apply clarify
nipkow@24645
  4703
apply(rule_tac a="sort xs" in ex1I)
nipkow@24645
  4704
apply (auto simp: sorted_distinct_set_unique)
nipkow@24645
  4705
done
nipkow@24645
  4706
haftmann@40096
  4707
lemma
haftmann@40096
  4708
  assumes "sorted xs"
haftmann@40096
  4709
  shows sorted_take: "sorted (take n xs)"
haftmann@40096
  4710
  and sorted_drop: "sorted (drop n xs)"
haftmann@40096
  4711
proof -
haftmann@40096
  4712
  from assms have "sorted (take n xs @ drop n xs)" by simp
haftmann@40096
  4713
  then show "sorted (take n xs)" and "sorted (drop n xs)"
haftmann@40096
  4714
    unfolding sorted_append by simp_all
haftmann@29626
  4715
qed
haftmann@29626
  4716
hoelzl@33639
  4717
lemma sorted_dropWhile: "sorted xs \<Longrightarrow> sorted (dropWhile P xs)"
haftmann@40096
  4718
  by (auto dest: sorted_drop simp add: dropWhile_eq_drop)
hoelzl@33639
  4719
hoelzl@33639
  4720
lemma sorted_takeWhile: "sorted xs \<Longrightarrow> sorted (takeWhile P xs)"
haftmann@40096
  4721
  by (subst takeWhile_eq_take) (auto dest: sorted_take)
haftmann@29626
  4722
hoelzl@34920
  4723
lemma sorted_filter:
hoelzl@34920
  4724
  "sorted (map f xs) \<Longrightarrow> sorted (map f (filter P xs))"
hoelzl@34920
  4725
  by (induct xs) (simp_all add: sorted_Cons)
hoelzl@34920
  4726
hoelzl@34920
  4727
lemma foldr_max_sorted:
hoelzl@34920
  4728
  assumes "sorted (rev xs)"
hoelzl@34920
  4729
  shows "foldr max xs y = (if xs = [] then y else max (xs ! 0) y)"
wenzelm@54511
  4730
  using assms
wenzelm@54511
  4731
proof (induct xs)
hoelzl@34920
  4732
  case (Cons x xs)
wenzelm@54511
  4733
  then have "sorted (rev xs)" using sorted_append by auto
wenzelm@54511
  4734
  with Cons show ?case
wenzelm@54511
  4735
    by (cases xs) (auto simp add: sorted_append max_def)
hoelzl@34920
  4736
qed simp
hoelzl@34920
  4737
hoelzl@34920
  4738
lemma filter_equals_takeWhile_sorted_rev:
hoelzl@34920
  4739
  assumes sorted: "sorted (rev (map f xs))"
hoelzl@34920
  4740
  shows "[x \<leftarrow> xs. t < f x] = takeWhile (\<lambda> x. t < f x) xs"
hoelzl@34920
  4741
    (is "filter ?P xs = ?tW")
hoelzl@34920
  4742
proof (rule takeWhile_eq_filter[symmetric])
hoelzl@34920
  4743
  let "?dW" = "dropWhile ?P xs"
hoelzl@34920
  4744
  fix x assume "x \<in> set ?dW"
hoelzl@34920
  4745
  then obtain i where i: "i < length ?dW" and nth_i: "x = ?dW ! i"
hoelzl@34920
  4746
    unfolding in_set_conv_nth by auto
hoelzl@34920
  4747
  hence "length ?tW + i < length (?tW @ ?dW)"
hoelzl@34920
  4748
    unfolding length_append by simp
hoelzl@34920
  4749
  hence i': "length (map f ?tW) + i < length (map f xs)" by simp
hoelzl@34920
  4750
  have "(map f ?tW @ map f ?dW) ! (length (map f ?tW) + i) \<le>
hoelzl@34920
  4751
        (map f ?tW @ map f ?dW) ! (length (map f ?tW) + 0)"
hoelzl@34920
  4752
    using sorted_rev_nth_mono[OF sorted _ i', of "length ?tW"]
hoelzl@34920
  4753
    unfolding map_append[symmetric] by simp
hoelzl@34920
  4754
  hence "f x \<le> f (?dW ! 0)"
hoelzl@34920
  4755
    unfolding nth_append_length_plus nth_i
hoelzl@34920
  4756
    using i preorder_class.le_less_trans[OF le0 i] by simp
hoelzl@34920
  4757
  also have "... \<le> t"
hoelzl@34920
  4758
    using hd_dropWhile[of "?P" xs] le0[THEN preorder_class.le_less_trans, OF i]
hoelzl@34920
  4759
    using hd_conv_nth[of "?dW"] by simp
hoelzl@34920
  4760
  finally show "\<not> t < f x" by simp
hoelzl@34920
  4761
qed
hoelzl@34920
  4762
haftmann@40451
  4763
lemma insort_insert_key_triv:
haftmann@40451
  4764
  "f x \<in> f ` set xs \<Longrightarrow> insort_insert_key f x xs = xs"
haftmann@40451
  4765
  by (simp add: insort_insert_key_def)
haftmann@40451
  4766
haftmann@40451
  4767
lemma insort_insert_triv:
haftmann@40451
  4768
  "x \<in> set xs \<Longrightarrow> insort_insert x xs = xs"
haftmann@40451
  4769
  using insort_insert_key_triv [of "\<lambda>x. x"] by simp
haftmann@40451
  4770
haftmann@40451
  4771
lemma insort_insert_insort_key:
haftmann@40451
  4772
  "f x \<notin> f ` set xs \<Longrightarrow> insort_insert_key f x xs = insort_key f x xs"
haftmann@40451
  4773
  by (simp add: insort_insert_key_def)
haftmann@40451
  4774
haftmann@40451
  4775
lemma insort_insert_insort:
haftmann@40451
  4776
  "x \<notin> set xs \<Longrightarrow> insort_insert x xs = insort x xs"
haftmann@40451
  4777
  using insort_insert_insort_key [of "\<lambda>x. x"] by simp
haftmann@40451
  4778
haftmann@35608
  4779
lemma set_insort_insert:
haftmann@35608
  4780
  "set (insort_insert x xs) = insert x (set xs)"
haftmann@40451
  4781
  by (auto simp add: insort_insert_key_def set_insort)
haftmann@35608
  4782
haftmann@35608
  4783
lemma distinct_insort_insert:
haftmann@35608
  4784
  assumes "distinct xs"
haftmann@40451
  4785
  shows "distinct (insort_insert_key f x xs)"
haftmann@40451
  4786
  using assms by (induct xs) (auto simp add: insort_insert_key_def set_insort)
haftmann@40451
  4787
haftmann@40451
  4788
lemma sorted_insort_insert_key:
haftmann@40451
  4789
  assumes "sorted (map f xs)"
haftmann@40451
  4790
  shows "sorted (map f (insort_insert_key f x xs))"
haftmann@40451
  4791
  using assms by (simp add: insort_insert_key_def sorted_insort_key)
haftmann@35608
  4792
haftmann@35608
  4793
lemma sorted_insort_insert:
haftmann@35608
  4794
  assumes "sorted xs"
haftmann@35608
  4795
  shows "sorted (insort_insert x xs)"
haftmann@40451
  4796
  using assms sorted_insort_insert_key [of "\<lambda>x. x"] by simp
haftmann@40451
  4797
haftmann@40451
  4798
lemma filter_insort_triv:
haftmann@37091
  4799
  "\<not> P x \<Longrightarrow> filter P (insort_key f x xs) = filter P xs"
haftmann@37091
  4800
  by (induct xs) simp_all
haftmann@37091
  4801
haftmann@40451
  4802
lemma filter_insort:
haftmann@37091
  4803
  "sorted (map f xs) \<Longrightarrow> P x \<Longrightarrow> filter P (insort_key f x xs) = insort_key f x (filter P xs)"
haftmann@37091
  4804
  using assms by (induct xs)
haftmann@37091
  4805
    (auto simp add: sorted_Cons, subst insort_is_Cons, auto)
haftmann@37091
  4806
haftmann@40451
  4807
lemma filter_sort:
haftmann@37091
  4808
  "filter P (sort_key f xs) = sort_key f (filter P xs)"
haftmann@40451
  4809
  by (induct xs) (simp_all add: filter_insort_triv filter_insort)
haftmann@37091
  4810
haftmann@40547
  4811
lemma sorted_map_same:
haftmann@40547
  4812
  "sorted (map f [x\<leftarrow>xs. f x = g xs])"
haftmann@40547
  4813
proof (induct xs arbitrary: g)
haftmann@37091
  4814
  case Nil then show ?case by simp
haftmann@37091
  4815
next
haftmann@37091
  4816
  case (Cons x xs)
haftmann@40547
  4817
  then have "sorted (map f [y\<leftarrow>xs . f y = (\<lambda>xs. f x) xs])" .
haftmann@40547
  4818
  moreover from Cons have "sorted (map f [y\<leftarrow>xs . f y = (g \<circ> Cons x) xs])" .
haftmann@37091
  4819
  ultimately show ?case by (simp_all add: sorted_Cons)
haftmann@37091
  4820
qed
haftmann@37091
  4821
haftmann@40547
  4822
lemma sorted_same:
haftmann@40547
  4823
  "sorted [x\<leftarrow>xs. x = g xs]"
haftmann@40547
  4824
  using sorted_map_same [of "\<lambda>x. x"] by simp
haftmann@40547
  4825
haftmann@37091
  4826
lemma remove1_insort [simp]:
haftmann@37091
  4827
  "remove1 x (insort x xs) = xs"
haftmann@37091
  4828
  by (induct xs) simp_all
haftmann@37091
  4829
nipkow@24616
  4830
end
nipkow@24616
  4831
nipkow@25277
  4832
lemma sorted_upt[simp]: "sorted[i..<j]"
nipkow@25277
  4833
by (induct j) (simp_all add:sorted_append)
nipkow@25277
  4834
nipkow@32415
  4835
lemma sorted_upto[simp]: "sorted[i..j]"
nipkow@32415
  4836
apply(induct i j rule:upto.induct)
nipkow@32415
  4837
apply(subst upto.simps)
nipkow@32415
  4838
apply(simp add:sorted_Cons)
nipkow@32415
  4839
done
nipkow@32415
  4840
haftmann@53516
  4841
lemma sorted_find_Min:
haftmann@53516
  4842
  assumes "sorted xs"
haftmann@53516
  4843
  assumes "\<exists>x \<in> set xs. P x"
haftmann@53516
  4844
  shows "List.find P xs = Some (Min {x\<in>set xs. P x})"
haftmann@53516
  4845
using assms proof (induct xs rule: sorted.induct)
haftmann@53516
  4846
  case Nil then show ?case by simp
haftmann@53516
  4847
next
haftmann@53516
  4848
  case (Cons xs x) show ?case proof (cases "P x")
haftmann@53516
  4849
    case True with Cons show ?thesis by (auto intro: Min_eqI [symmetric])
haftmann@53516
  4850
  next
haftmann@53516
  4851
    case False then have "{y. (y = x \<or> y \<in> set xs) \<and> P y} = {y \<in> set xs. P y}"
haftmann@53516
  4852
      by auto
haftmann@53516
  4853
    with Cons False show ?thesis by simp_all
haftmann@53516
  4854
  qed
haftmann@53516
  4855
qed
haftmann@53516
  4856
wenzelm@35118
  4857
wenzelm@35118
  4858
subsubsection {* @{const transpose} on sorted lists *}
hoelzl@34920
  4859
hoelzl@34920
  4860
lemma sorted_transpose[simp]:
hoelzl@34920
  4861
  shows "sorted (rev (map length (transpose xs)))"
hoelzl@34920
  4862
  by (auto simp: sorted_equals_nth_mono rev_nth nth_transpose
hoelzl@34920
  4863
    length_filter_conv_card intro: card_mono)
hoelzl@34920
  4864
hoelzl@34920
  4865
lemma transpose_max_length:
hoelzl@34920
  4866
  "foldr (\<lambda>xs. max (length xs)) (transpose xs) 0 = length [x \<leftarrow> xs. x \<noteq> []]"
hoelzl@34920
  4867
  (is "?L = ?R")
hoelzl@34920
  4868
proof (cases "transpose xs = []")
hoelzl@34920
  4869
  case False
hoelzl@34920
  4870
  have "?L = foldr max (map length (transpose xs)) 0"
hoelzl@34920
  4871
    by (simp add: foldr_map comp_def)
hoelzl@34920
  4872
  also have "... = length (transpose xs ! 0)"
hoelzl@34920
  4873
    using False sorted_transpose by (simp add: foldr_max_sorted)
hoelzl@34920
  4874
  finally show ?thesis
hoelzl@34920
  4875
    using False by (simp add: nth_transpose)
hoelzl@34920
  4876
next
hoelzl@34920
  4877
  case True
hoelzl@34920
  4878
  hence "[x \<leftarrow> xs. x \<noteq> []] = []"
hoelzl@34920
  4879
    by (auto intro!: filter_False simp: transpose_empty)
hoelzl@34920
  4880
  thus ?thesis by (simp add: transpose_empty True)
hoelzl@34920
  4881
qed
hoelzl@34920
  4882
hoelzl@34920
  4883
lemma length_transpose_sorted:
hoelzl@34920
  4884
  fixes xs :: "'a list list"
hoelzl@34920
  4885
  assumes sorted: "sorted (rev (map length xs))"
hoelzl@34920
  4886
  shows "length (transpose xs) = (if xs = [] then 0 else length (xs ! 0))"
hoelzl@34920
  4887
proof (cases "xs = []")
hoelzl@34920
  4888
  case False
hoelzl@34920
  4889
  thus ?thesis
hoelzl@34920
  4890
    using foldr_max_sorted[OF sorted] False
hoelzl@34920
  4891
    unfolding length_transpose foldr_map comp_def
hoelzl@34920
  4892
    by simp
hoelzl@34920
  4893
qed simp
hoelzl@34920
  4894
hoelzl@34920
  4895
lemma nth_nth_transpose_sorted[simp]:
hoelzl@34920
  4896
  fixes xs :: "'a list list"
hoelzl@34920
  4897
  assumes sorted: "sorted (rev (map length xs))"
hoelzl@34920
  4898
  and i: "i < length (transpose xs)"
hoelzl@34920
  4899
  and j: "j < length [ys \<leftarrow> xs. i < length ys]"
hoelzl@34920
  4900
  shows "transpose xs ! i ! j = xs ! j  ! i"
hoelzl@34920
  4901
  using j filter_equals_takeWhile_sorted_rev[OF sorted, of i]
hoelzl@34920
  4902
    nth_transpose[OF i] nth_map[OF j]
hoelzl@34920
  4903
  by (simp add: takeWhile_nth)
hoelzl@34920
  4904
hoelzl@34920
  4905
lemma transpose_column_length:
hoelzl@34920
  4906
  fixes xs :: "'a list list"
hoelzl@34920
  4907
  assumes sorted: "sorted (rev (map length xs))" and "i < length xs"
hoelzl@34920
  4908
  shows "length (filter (\<lambda>ys. i < length ys) (transpose xs)) = length (xs ! i)"
hoelzl@34920
  4909
proof -
hoelzl@34920
  4910
  have "xs \<noteq> []" using `i < length xs` by auto
hoelzl@34920
  4911
  note filter_equals_takeWhile_sorted_rev[OF sorted, simp]
hoelzl@34920
  4912
  { fix j assume "j \<le> i"
hoelzl@34920
  4913
    note sorted_rev_nth_mono[OF sorted, of j i, simplified, OF this `i < length xs`]
hoelzl@34920
  4914
  } note sortedE = this[consumes 1]
hoelzl@34920
  4915
hoelzl@34920
  4916
  have "{j. j < length (transpose xs) \<and> i < length (transpose xs ! j)}
hoelzl@34920
  4917
    = {..< length (xs ! i)}"
hoelzl@34920
  4918
  proof safe
hoelzl@34920
  4919
    fix j
hoelzl@34920
  4920
    assume "j < length (transpose xs)" and "i < length (transpose xs ! j)"
hoelzl@34920
  4921
    with this(2) nth_transpose[OF this(1)]
hoelzl@34920
  4922
    have "i < length (takeWhile (\<lambda>ys. j < length ys) xs)" by simp
hoelzl@34920
  4923
    from nth_mem[OF this] takeWhile_nth[OF this]
hoelzl@34920
  4924
    show "j < length (xs ! i)" by (auto dest: set_takeWhileD)
hoelzl@34920
  4925
  next
hoelzl@34920
  4926
    fix j assume "j < length (xs ! i)"
hoelzl@34920
  4927
    thus "j < length (transpose xs)"
hoelzl@34920
  4928
      using foldr_max_sorted[OF sorted] `xs \<noteq> []` sortedE[OF le0]
hoelzl@34920
  4929
      by (auto simp: length_transpose comp_def foldr_map)
hoelzl@34920
  4930
hoelzl@34920
  4931
    have "Suc i \<le> length (takeWhile (\<lambda>ys. j < length ys) xs)"
hoelzl@34920
  4932
      using `i < length xs` `j < length (xs ! i)` less_Suc_eq_le
hoelzl@34920
  4933
      by (auto intro!: length_takeWhile_less_P_nth dest!: sortedE)
hoelzl@34920
  4934
    with nth_transpose[OF `j < length (transpose xs)`]
hoelzl@34920
  4935
    show "i < length (transpose xs ! j)" by simp
hoelzl@34920
  4936
  qed
hoelzl@34920
  4937
  thus ?thesis by (simp add: length_filter_conv_card)
hoelzl@34920
  4938
qed
hoelzl@34920
  4939
hoelzl@34920
  4940
lemma transpose_column:
hoelzl@34920
  4941
  fixes xs :: "'a list list"
hoelzl@34920
  4942
  assumes sorted: "sorted (rev (map length xs))" and "i < length xs"
hoelzl@34920
  4943
  shows "map (\<lambda>ys. ys ! i) (filter (\<lambda>ys. i < length ys) (transpose xs))
hoelzl@34920
  4944
    = xs ! i" (is "?R = _")
hoelzl@34920
  4945
proof (rule nth_equalityI, safe)
hoelzl@34920
  4946
  show length: "length ?R = length (xs ! i)"
hoelzl@34920
  4947
    using transpose_column_length[OF assms] by simp
hoelzl@34920
  4948
hoelzl@34920
  4949
  fix j assume j: "j < length ?R"
hoelzl@34920
  4950
  note * = less_le_trans[OF this, unfolded length_map, OF length_filter_le]
hoelzl@34920
  4951
  from j have j_less: "j < length (xs ! i)" using length by simp
hoelzl@34920
  4952
  have i_less_tW: "Suc i \<le> length (takeWhile (\<lambda>ys. Suc j \<le> length ys) xs)"
hoelzl@34920
  4953
  proof (rule length_takeWhile_less_P_nth)
hoelzl@34920
  4954
    show "Suc i \<le> length xs" using `i < length xs` by simp
hoelzl@34920
  4955
    fix k assume "k < Suc i"
hoelzl@34920
  4956
    hence "k \<le> i" by auto
hoelzl@34920
  4957
    with sorted_rev_nth_mono[OF sorted this] `i < length xs`
hoelzl@34920
  4958
    have "length (xs ! i) \<le> length (xs ! k)" by simp
hoelzl@34920
  4959
    thus "Suc j \<le> length (xs ! k)" using j_less by simp
hoelzl@34920
  4960
  qed
hoelzl@34920
  4961
  have i_less_filter: "i < length [ys\<leftarrow>xs . j < length ys]"
hoelzl@34920
  4962
    unfolding filter_equals_takeWhile_sorted_rev[OF sorted, of j]
hoelzl@34920
  4963
    using i_less_tW by (simp_all add: Suc_le_eq)
hoelzl@34920
  4964
  from j show "?R ! j = xs ! i ! j"
hoelzl@34920
  4965
    unfolding filter_equals_takeWhile_sorted_rev[OF sorted_transpose, of i]
hoelzl@34920
  4966
    by (simp add: takeWhile_nth nth_nth_transpose_sorted[OF sorted * i_less_filter])
hoelzl@34920
  4967
qed
hoelzl@34920
  4968
hoelzl@34920
  4969
lemma transpose_transpose:
hoelzl@34920
  4970
  fixes xs :: "'a list list"
hoelzl@34920
  4971
  assumes sorted: "sorted (rev (map length xs))"
hoelzl@34920
  4972
  shows "transpose (transpose xs) = takeWhile (\<lambda>x. x \<noteq> []) xs" (is "?L = ?R")
hoelzl@34920
  4973
proof -
hoelzl@34920
  4974
  have len: "length ?L = length ?R"
hoelzl@34920
  4975
    unfolding length_transpose transpose_max_length
hoelzl@34920
  4976
    using filter_equals_takeWhile_sorted_rev[OF sorted, of 0]
hoelzl@34920
  4977
    by simp
hoelzl@34920
  4978
hoelzl@34920
  4979
  { fix i assume "i < length ?R"
hoelzl@34920
  4980
    with less_le_trans[OF _ length_takeWhile_le[of _ xs]]
hoelzl@34920
  4981
    have "i < length xs" by simp
hoelzl@34920
  4982
  } note * = this
hoelzl@34920
  4983
  show ?thesis
hoelzl@34920
  4984
    by (rule nth_equalityI)
hoelzl@34920
  4985
       (simp_all add: len nth_transpose transpose_column[OF sorted] * takeWhile_nth)
hoelzl@34920
  4986
qed
haftmann@34064
  4987
hoelzl@34921
  4988
theorem transpose_rectangle:
hoelzl@34921
  4989
  assumes "xs = [] \<Longrightarrow> n = 0"
hoelzl@34921
  4990
  assumes rect: "\<And> i. i < length xs \<Longrightarrow> length (xs ! i) = n"
hoelzl@34921
  4991
  shows "transpose xs = map (\<lambda> i. map (\<lambda> j. xs ! j ! i) [0..<length xs]) [0..<n]"
hoelzl@34921
  4992
    (is "?trans = ?map")
hoelzl@34921
  4993
proof (rule nth_equalityI)
hoelzl@34921
  4994
  have "sorted (rev (map length xs))"
hoelzl@34921
  4995
    by (auto simp: rev_nth rect intro!: sorted_nth_monoI)
hoelzl@34921
  4996
  from foldr_max_sorted[OF this] assms
hoelzl@34921
  4997
  show len: "length ?trans = length ?map"
hoelzl@34921
  4998
    by (simp_all add: length_transpose foldr_map comp_def)
hoelzl@34921
  4999
  moreover
hoelzl@34921
  5000
  { fix i assume "i < n" hence "[ys\<leftarrow>xs . i < length ys] = xs"
hoelzl@34921
  5001
      using rect by (auto simp: in_set_conv_nth intro!: filter_True) }
hoelzl@34921
  5002
  ultimately show "\<forall>i < length ?trans. ?trans ! i = ?map ! i"
hoelzl@34921
  5003
    by (auto simp: nth_transpose intro: nth_equalityI)
hoelzl@34921
  5004
qed
nipkow@24616
  5005
wenzelm@35118
  5006
nipkow@25069
  5007
subsubsection {* @{text sorted_list_of_set} *}
nipkow@25069
  5008
nipkow@25069
  5009
text{* This function maps (finite) linearly ordered sets to sorted
nipkow@25069
  5010
lists. Warning: in most cases it is not a good idea to convert from
nipkow@25069
  5011
sets to lists but one should convert in the other direction (via
nipkow@25069
  5012
@{const set}). *}
nipkow@25069
  5013
haftmann@52626
  5014
subsubsection {* @{text sorted_list_of_set} *}
haftmann@52626
  5015
haftmann@52626
  5016
text{* This function maps (finite) linearly ordered sets to sorted
haftmann@52626
  5017
lists. Warning: in most cases it is not a good idea to convert from
haftmann@52626
  5018
sets to lists but one should convert in the other direction (via
haftmann@52626
  5019
@{const set}). *}
haftmann@52626
  5020
haftmann@52626
  5021
definition (in linorder) sorted_list_of_set :: "'a set \<Rightarrow> 'a list" where
haftmann@52626
  5022
  "sorted_list_of_set = folding.F insort []"
haftmann@52626
  5023
haftmann@52626
  5024
sublocale linorder < sorted_list_of_set!: folding insort Nil
haftmann@52626
  5025
where
haftmann@52626
  5026
  "folding.F insort [] = sorted_list_of_set"
haftmann@52626
  5027
proof -
haftmann@52626
  5028
  interpret comp_fun_commute insort by (fact comp_fun_commute_insort)
haftmann@52626
  5029
  show "folding insort" by default (fact comp_fun_commute)
haftmann@52626
  5030
  show "folding.F insort [] = sorted_list_of_set" by (simp only: sorted_list_of_set_def)
haftmann@52626
  5031
qed
haftmann@52626
  5032
nipkow@25069
  5033
context linorder
nipkow@25069
  5034
begin
nipkow@25069
  5035
haftmann@52626
  5036
lemma sorted_list_of_set_empty:
haftmann@35195
  5037
  "sorted_list_of_set {} = []"
haftmann@52626
  5038
  by (fact sorted_list_of_set.empty)
haftmann@35195
  5039
haftmann@35195
  5040
lemma sorted_list_of_set_insert [simp]:
haftmann@35195
  5041
  assumes "finite A"
haftmann@35195
  5042
  shows "sorted_list_of_set (insert x A) = insort x (sorted_list_of_set (A - {x}))"
haftmann@52626
  5043
  using assms by (fact sorted_list_of_set.insert_remove)
haftmann@35195
  5044
noschinl@53259
  5045
lemma sorted_list_of_set_eq_Nil_iff [simp]:
noschinl@53259
  5046
  "finite A \<Longrightarrow> sorted_list_of_set A = [] \<longleftrightarrow> A = {}"
noschinl@53259
  5047
  using assms by (auto simp: sorted_list_of_set.remove)
noschinl@53259
  5048
haftmann@35195
  5049
lemma sorted_list_of_set [simp]:
haftmann@35195
  5050
  "finite A \<Longrightarrow> set (sorted_list_of_set A) = A \<and> sorted (sorted_list_of_set A) 
haftmann@35195
  5051
    \<and> distinct (sorted_list_of_set A)"
haftmann@35195
  5052
  by (induct A rule: finite_induct) (simp_all add: set_insort sorted_insort distinct_insort)
haftmann@35195
  5053
noschinl@53259
  5054
lemma distinct_sorted_list_of_set:
noschinl@53259
  5055
  "distinct (sorted_list_of_set A)"
noschinl@53259
  5056
  using sorted_list_of_set by (cases "finite A") auto
noschinl@53259
  5057
bulwahn@48712
  5058
lemma sorted_list_of_set_sort_remdups [code]:
haftmann@35195
  5059
  "sorted_list_of_set (set xs) = sort (remdups xs)"
haftmann@35195
  5060
proof -
haftmann@43740
  5061
  interpret comp_fun_commute insort by (fact comp_fun_commute_insort)
haftmann@52626
  5062
  show ?thesis by (simp add: sorted_list_of_set.eq_fold sort_conv_fold fold_set_fold_remdups)
haftmann@35195
  5063
qed
nipkow@25069
  5064
haftmann@37091
  5065
lemma sorted_list_of_set_remove:
haftmann@37091
  5066
  assumes "finite A"
haftmann@37091
  5067
  shows "sorted_list_of_set (A - {x}) = remove1 x (sorted_list_of_set A)"
haftmann@37091
  5068
proof (cases "x \<in> A")
haftmann@37091
  5069
  case False with assms have "x \<notin> set (sorted_list_of_set A)" by simp
haftmann@37091
  5070
  with False show ?thesis by (simp add: remove1_idem)
haftmann@37091
  5071
next
haftmann@37091
  5072
  case True then obtain B where A: "A = insert x B" by (rule Set.set_insert)
haftmann@37091
  5073
  with assms show ?thesis by simp
haftmann@37091
  5074
qed
haftmann@37091
  5075
nipkow@25069
  5076
end
nipkow@25069
  5077
haftmann@37091
  5078
lemma sorted_list_of_set_range [simp]:
haftmann@37091
  5079
  "sorted_list_of_set {m..<n} = [m..<n]"
haftmann@37091
  5080
  by (rule sorted_distinct_set_unique) simp_all
haftmann@37091
  5081
haftmann@37091
  5082
nipkow@15392
  5083
subsubsection {* @{text lists}: the list-forming operator over sets *}
nipkow@15302
  5084
berghofe@23740
  5085
inductive_set
berghofe@23740
  5086
  lists :: "'a set => 'a list set"
berghofe@23740
  5087
  for A :: "'a set"
berghofe@22262
  5088
where
nipkow@39859
  5089
    Nil [intro!, simp]: "[]: lists A"
blanchet@55599
  5090
  | Cons [intro!, simp]: "[| a: A; l: lists A|] ==> a#l : lists A"
blanchet@55599
  5091
blanchet@55599
  5092
inductive_cases listsE [elim!]: "x#l : lists A"
blanchet@55599
  5093
inductive_cases listspE [elim!]: "listsp A (x # l)"
berghofe@23740
  5094
bulwahn@47141
  5095
inductive_simps listsp_simps[code]:
bulwahn@47141
  5096
  "listsp A []"
bulwahn@47141
  5097
  "listsp A (x # xs)"
bulwahn@47141
  5098
berghofe@23740
  5099
lemma listsp_mono [mono]: "A \<le> B ==> listsp A \<le> listsp B"
noschinl@47752
  5100
by (rule predicate1I, erule listsp.induct, blast+)
berghofe@26795
  5101
berghofe@47047
  5102
lemmas lists_mono = listsp_mono [to_set]
berghofe@22262
  5103
haftmann@22422
  5104
lemma listsp_infI:
haftmann@22422
  5105
  assumes l: "listsp A l" shows "listsp B l ==> listsp (inf A B) l" using l
nipkow@24349
  5106
by induct blast+
nipkow@15302
  5107
haftmann@22422
  5108
lemmas lists_IntI = listsp_infI [to_set]
haftmann@22422
  5109
haftmann@22422
  5110
lemma listsp_inf_eq [simp]: "listsp (inf A B) = inf (listsp A) (listsp B)"
haftmann@22422
  5111
proof (rule mono_inf [where f=listsp, THEN order_antisym])
berghofe@22262
  5112
  show "mono listsp" by (simp add: mono_def listsp_mono)
haftmann@48259
  5113
  show "inf (listsp A) (listsp B) \<le> listsp (inf A B)" by (blast intro!: listsp_infI)
nipkow@15302
  5114
qed
nipkow@15302
  5115
haftmann@41323
  5116
lemmas listsp_conj_eq [simp] = listsp_inf_eq [simplified inf_fun_def inf_bool_def]
haftmann@22422
  5117
berghofe@47047
  5118
lemmas lists_Int_eq [simp] = listsp_inf_eq [to_set]
berghofe@22262
  5119
nipkow@39859
  5120
lemma Cons_in_lists_iff[simp]: "x#xs : lists A \<longleftrightarrow> x:A \<and> xs : lists A"
nipkow@39859
  5121
by auto
nipkow@39859
  5122
berghofe@22262
  5123
lemma append_in_listsp_conv [iff]:
berghofe@22262
  5124
     "(listsp A (xs @ ys)) = (listsp A xs \<and> listsp A ys)"
nipkow@15302
  5125
by (induct xs) auto
nipkow@15302
  5126
berghofe@22262
  5127
lemmas append_in_lists_conv [iff] = append_in_listsp_conv [to_set]
berghofe@22262
  5128
berghofe@22262
  5129
lemma in_listsp_conv_set: "(listsp A xs) = (\<forall>x \<in> set xs. A x)"
berghofe@22262
  5130
-- {* eliminate @{text listsp} in favour of @{text set} *}
nipkow@15302
  5131
by (induct xs) auto
nipkow@15302
  5132
bulwahn@47141
  5133
lemmas in_lists_conv_set [code_unfold] = in_listsp_conv_set [to_set]
berghofe@22262
  5134
blanchet@55599
  5135
lemma in_listspD [dest!]: "listsp A xs ==> \<forall>x\<in>set xs. A x"
berghofe@22262
  5136
by (rule in_listsp_conv_set [THEN iffD1])
berghofe@22262
  5137
blanchet@55599
  5138
lemmas in_listsD [dest!] = in_listspD [to_set]
blanchet@55599
  5139
blanchet@55599
  5140
lemma in_listspI [intro!]: "\<forall>x\<in>set xs. A x ==> listsp A xs"
berghofe@22262
  5141
by (rule in_listsp_conv_set [THEN iffD2])
berghofe@22262
  5142
blanchet@55599
  5143
lemmas in_listsI [intro!] = in_listspI [to_set]
nipkow@15302
  5144
nipkow@39821
  5145
lemma lists_eq_set: "lists A = {xs. set xs <= A}"
nipkow@39821
  5146
by auto
nipkow@39821
  5147
nipkow@39859
  5148
lemma lists_empty [simp]: "lists {} = {[]}"
nipkow@39859
  5149
by auto
nipkow@39859
  5150
nipkow@15302
  5151
lemma lists_UNIV [simp]: "lists UNIV = UNIV"
nipkow@15302
  5152
by auto
nipkow@15302
  5153
hoelzl@51149
  5154
lemma lists_image: "lists (f`A) = map f ` lists A"
hoelzl@51149
  5155
proof -
hoelzl@51149
  5156
  { fix xs have "\<forall>x\<in>set xs. x \<in> f ` A \<Longrightarrow> xs \<in> map f ` lists A"
hoelzl@51149
  5157
      by (induct xs) (auto simp del: map.simps simp add: map.simps[symmetric] intro!: imageI) }
hoelzl@51149
  5158
  then show ?thesis by auto
hoelzl@51149
  5159
qed
nipkow@17086
  5160
wenzelm@35118
  5161
subsubsection {* Inductive definition for membership *}
nipkow@17086
  5162
berghofe@23740
  5163
inductive ListMem :: "'a \<Rightarrow> 'a list \<Rightarrow> bool"
berghofe@22262
  5164
where
berghofe@22262
  5165
    elem:  "ListMem x (x # xs)"
berghofe@22262
  5166
  | insert:  "ListMem x xs \<Longrightarrow> ListMem x (y # xs)"
berghofe@22262
  5167
berghofe@22262
  5168
lemma ListMem_iff: "(ListMem x xs) = (x \<in> set xs)"
nipkow@17086
  5169
apply (rule iffI)
nipkow@17086
  5170
 apply (induct set: ListMem)
nipkow@17086
  5171
  apply auto
nipkow@17086
  5172
apply (induct xs)
nipkow@17086
  5173
 apply (auto intro: ListMem.intros)
nipkow@17086
  5174
done
nipkow@17086
  5175
nipkow@17086
  5176
wenzelm@35118
  5177
subsubsection {* Lists as Cartesian products *}
nipkow@15302
  5178
nipkow@15302
  5179
text{*@{text"set_Cons A Xs"}: the set of lists with head drawn from
nipkow@15302
  5180
@{term A} and tail drawn from @{term Xs}.*}
nipkow@15302
  5181
nipkow@51563
  5182
definition set_Cons :: "'a set \<Rightarrow> 'a list set \<Rightarrow> 'a list set" where
nipkow@51563
  5183
"set_Cons A XS = {z. \<exists>x xs. z = x # xs \<and> x \<in> A \<and> xs \<in> XS}"
nipkow@15302
  5184
paulson@17724
  5185
lemma set_Cons_sing_Nil [simp]: "set_Cons A {[]} = (%x. [x])`A"
nipkow@15302
  5186
by (auto simp add: set_Cons_def)
nipkow@15302
  5187
nipkow@15302
  5188
text{*Yields the set of lists, all of the same length as the argument and
nipkow@15302
  5189
with elements drawn from the corresponding element of the argument.*}
nipkow@15302
  5190
nipkow@51563
  5191
primrec listset :: "'a set list \<Rightarrow> 'a list set" where
nipkow@51563
  5192
"listset [] = {[]}" |
nipkow@51563
  5193
"listset (A # As) = set_Cons A (listset As)"
nipkow@15302
  5194
nipkow@15302
  5195
wenzelm@35118
  5196
subsection {* Relations on Lists *}
paulson@15656
  5197
paulson@15656
  5198
subsubsection {* Length Lexicographic Ordering *}
paulson@15656
  5199
paulson@15656
  5200
text{*These orderings preserve well-foundedness: shorter lists 
paulson@15656
  5201
  precede longer lists. These ordering are not used in dictionaries.*}
haftmann@34928
  5202
        
haftmann@34928
  5203
primrec -- {*The lexicographic ordering for lists of the specified length*}
haftmann@34928
  5204
  lexn :: "('a \<times> 'a) set \<Rightarrow> nat \<Rightarrow> ('a list \<times> 'a list) set" where
nipkow@51563
  5205
"lexn r 0 = {}" |
nipkow@51563
  5206
"lexn r (Suc n) =
nipkow@51563
  5207
  (map_pair (%(x, xs). x#xs) (%(x, xs). x#xs) ` (r <*lex*> lexn r n)) Int
nipkow@51563
  5208
  {(xs, ys). length xs = Suc n \<and> length ys = Suc n}"
nipkow@51563
  5209
nipkow@51563
  5210
definition lex :: "('a \<times> 'a) set \<Rightarrow> ('a list \<times> 'a list) set" where
nipkow@51563
  5211
"lex r = (\<Union>n. lexn r n)" -- {*Holds only between lists of the same length*}
nipkow@51563
  5212
nipkow@51563
  5213
definition lenlex :: "('a \<times> 'a) set => ('a list \<times> 'a list) set" where
nipkow@51563
  5214
"lenlex r = inv_image (less_than <*lex*> lex r) (\<lambda>xs. (length xs, xs))"
haftmann@34928
  5215
        -- {*Compares lists by their length and then lexicographically*}
nipkow@15302
  5216
wenzelm@13142
  5217
lemma wf_lexn: "wf r ==> wf (lexn r n)"
paulson@15251
  5218
apply (induct n, simp, simp)
nipkow@13145
  5219
apply(rule wf_subset)
nipkow@13145
  5220
 prefer 2 apply (rule Int_lower1)
haftmann@40856
  5221
apply(rule wf_map_pair_image)
paulson@14208
  5222
 prefer 2 apply (rule inj_onI, auto)
nipkow@13145
  5223
done
wenzelm@13114
  5224
wenzelm@13114
  5225
lemma lexn_length:
nipkow@24526
  5226
  "(xs, ys) : lexn r n ==> length xs = n \<and> length ys = n"
nipkow@24526
  5227
by (induct n arbitrary: xs ys) auto
wenzelm@13114
  5228
wenzelm@13142
  5229
lemma wf_lex [intro!]: "wf r ==> wf (lex r)"
nipkow@13145
  5230
apply (unfold lex_def)
nipkow@13145
  5231
apply (rule wf_UN)
paulson@14208
  5232
apply (blast intro: wf_lexn, clarify)
nipkow@13145
  5233
apply (rename_tac m n)
nipkow@13145
  5234
apply (subgoal_tac "m \<noteq> n")
nipkow@13145
  5235
 prefer 2 apply blast
nipkow@13145
  5236
apply (blast dest: lexn_length not_sym)
nipkow@13145
  5237
done
wenzelm@13114
  5238
wenzelm@13114
  5239
lemma lexn_conv:
paulson@15656
  5240
  "lexn r n =
paulson@15656
  5241
    {(xs,ys). length xs = n \<and> length ys = n \<and>
paulson@15656
  5242
    (\<exists>xys x y xs' ys'. xs= xys @ x#xs' \<and> ys= xys @ y # ys' \<and> (x, y):r)}"
nipkow@18423
  5243
apply (induct n, simp)
paulson@14208
  5244
apply (simp add: image_Collect lex_prod_def, safe, blast)
paulson@14208
  5245
 apply (rule_tac x = "ab # xys" in exI, simp)
paulson@14208
  5246
apply (case_tac xys, simp_all, blast)
nipkow@13145
  5247
done
wenzelm@13114
  5248
wenzelm@13114
  5249
lemma lex_conv:
paulson@15656
  5250
  "lex r =
paulson@15656
  5251
    {(xs,ys). length xs = length ys \<and>
paulson@15656
  5252
    (\<exists>xys x y xs' ys'. xs = xys @ x # xs' \<and> ys = xys @ y # ys' \<and> (x, y):r)}"
nipkow@13145
  5253
by (force simp add: lex_def lexn_conv)
wenzelm@13114
  5254
nipkow@15693
  5255
lemma wf_lenlex [intro!]: "wf r ==> wf (lenlex r)"
nipkow@15693
  5256
by (unfold lenlex_def) blast
nipkow@15693
  5257
nipkow@15693
  5258
lemma lenlex_conv:
nipkow@15693
  5259
    "lenlex r = {(xs,ys). length xs < length ys |
paulson@15656
  5260
                 length xs = length ys \<and> (xs, ys) : lex r}"
nipkow@30198
  5261
by (simp add: lenlex_def Id_on_def lex_prod_def inv_image_def)
wenzelm@13114
  5262
wenzelm@13142
  5263
lemma Nil_notin_lex [iff]: "([], ys) \<notin> lex r"
nipkow@13145
  5264
by (simp add: lex_conv)
wenzelm@13114
  5265
wenzelm@13142
  5266
lemma Nil2_notin_lex [iff]: "(xs, []) \<notin> lex r"
nipkow@13145
  5267
by (simp add:lex_conv)
wenzelm@13114
  5268
paulson@18447
  5269
lemma Cons_in_lex [simp]:
paulson@15656
  5270
    "((x # xs, y # ys) : lex r) =
paulson@15656
  5271
      ((x, y) : r \<and> length xs = length ys | x = y \<and> (xs, ys) : lex r)"
nipkow@13145
  5272
apply (simp add: lex_conv)
nipkow@13145
  5273
apply (rule iffI)
paulson@14208
  5274
 prefer 2 apply (blast intro: Cons_eq_appendI, clarify)
paulson@14208
  5275
apply (case_tac xys, simp, simp)
nipkow@13145
  5276
apply blast
nipkow@13145
  5277
done
wenzelm@13114
  5278
wenzelm@13114
  5279
paulson@15656
  5280
subsubsection {* Lexicographic Ordering *}
paulson@15656
  5281
paulson@15656
  5282
text {* Classical lexicographic ordering on lists, ie. "a" < "ab" < "b".
paulson@15656
  5283
    This ordering does \emph{not} preserve well-foundedness.
nipkow@17090
  5284
     Author: N. Voelker, March 2005. *} 
paulson@15656
  5285
nipkow@51563
  5286
definition lexord :: "('a \<times> 'a) set \<Rightarrow> ('a list \<times> 'a list) set" where
nipkow@51563
  5287
"lexord r = {(x,y). \<exists> a v. y = x @ a # v \<or>
paulson@15656
  5288
            (\<exists> u a b v w. (a,b) \<in> r \<and> x = u @ (a # v) \<and> y = u @ (b # w))}"
paulson@15656
  5289
paulson@15656
  5290
lemma lexord_Nil_left[simp]:  "([],y) \<in> lexord r = (\<exists> a x. y = a # x)"
nipkow@24349
  5291
by (unfold lexord_def, induct_tac y, auto) 
paulson@15656
  5292
paulson@15656
  5293
lemma lexord_Nil_right[simp]: "(x,[]) \<notin> lexord r"
nipkow@24349
  5294
by (unfold lexord_def, induct_tac x, auto)
paulson@15656
  5295
paulson@15656
  5296
lemma lexord_cons_cons[simp]:
paulson@15656
  5297
     "((a # x, b # y) \<in> lexord r) = ((a,b)\<in> r | (a = b & (x,y)\<in> lexord r))"
paulson@15656
  5298
  apply (unfold lexord_def, safe, simp_all)
paulson@15656
  5299
  apply (case_tac u, simp, simp)
paulson@15656
  5300
  apply (case_tac u, simp, clarsimp, blast, blast, clarsimp)
paulson@15656
  5301
  apply (erule_tac x="b # u" in allE)
paulson@15656
  5302
  by force
paulson@15656
  5303
paulson@15656
  5304
lemmas lexord_simps = lexord_Nil_left lexord_Nil_right lexord_cons_cons
paulson@15656
  5305
paulson@15656
  5306
lemma lexord_append_rightI: "\<exists> b z. y = b # z \<Longrightarrow> (x, x @ y) \<in> lexord r"
nipkow@24349
  5307
by (induct_tac x, auto)  
paulson@15656
  5308
paulson@15656
  5309
lemma lexord_append_left_rightI:
paulson@15656
  5310
     "(a,b) \<in> r \<Longrightarrow> (u @ a # x, u @ b # y) \<in> lexord r"
nipkow@24349
  5311
by (induct_tac u, auto)
paulson@15656
  5312
paulson@15656
  5313
lemma lexord_append_leftI: " (u,v) \<in> lexord r \<Longrightarrow> (x @ u, x @ v) \<in> lexord r"
nipkow@24349
  5314
by (induct x, auto)
paulson@15656
  5315
paulson@15656
  5316
lemma lexord_append_leftD:
paulson@15656
  5317
     "\<lbrakk> (x @ u, x @ v) \<in> lexord r; (! a. (a,a) \<notin> r) \<rbrakk> \<Longrightarrow> (u,v) \<in> lexord r"
nipkow@24349
  5318
by (erule rev_mp, induct_tac x, auto)
paulson@15656
  5319
paulson@15656
  5320
lemma lexord_take_index_conv: 
paulson@15656
  5321
   "((x,y) : lexord r) = 
paulson@15656
  5322
    ((length x < length y \<and> take (length x) y = x) \<or> 
paulson@15656
  5323
     (\<exists>i. i < min(length x)(length y) & take i x = take i y & (x!i,y!i) \<in> r))"
paulson@15656
  5324
  apply (unfold lexord_def Let_def, clarsimp) 
paulson@15656
  5325
  apply (rule_tac f = "(% a b. a \<or> b)" in arg_cong2)
paulson@15656
  5326
  apply auto 
paulson@15656
  5327
  apply (rule_tac x="hd (drop (length x) y)" in exI)
paulson@15656
  5328
  apply (rule_tac x="tl (drop (length x) y)" in exI)
paulson@15656
  5329
  apply (erule subst, simp add: min_def) 
paulson@15656
  5330
  apply (rule_tac x ="length u" in exI, simp) 
paulson@15656
  5331
  apply (rule_tac x ="take i x" in exI) 
paulson@15656
  5332
  apply (rule_tac x ="x ! i" in exI) 
paulson@15656
  5333
  apply (rule_tac x ="y ! i" in exI, safe) 
paulson@15656
  5334
  apply (rule_tac x="drop (Suc i) x" in exI)
paulson@15656
  5335
  apply (drule sym, simp add: drop_Suc_conv_tl) 
paulson@15656
  5336
  apply (rule_tac x="drop (Suc i) y" in exI)
paulson@15656
  5337
  by (simp add: drop_Suc_conv_tl) 
paulson@15656
  5338
paulson@15656
  5339
-- {* lexord is extension of partial ordering List.lex *} 
nipkow@42857
  5340
lemma lexord_lex: "(x,y) \<in> lex r = ((x,y) \<in> lexord r \<and> length x = length y)"
paulson@15656
  5341
  apply (rule_tac x = y in spec) 
paulson@15656
  5342
  apply (induct_tac x, clarsimp) 
paulson@15656
  5343
  by (clarify, case_tac x, simp, force)
paulson@15656
  5344
nipkow@42857
  5345
lemma lexord_irreflexive: "ALL x. (x,x) \<notin> r \<Longrightarrow> (xs,xs) \<notin> lexord r"
nipkow@42857
  5346
by (induct xs) auto
nipkow@42857
  5347
nipkow@42857
  5348
text{* By Ren\'e Thiemann: *}
nipkow@42857
  5349
lemma lexord_partial_trans: 
nipkow@42857
  5350
  "(\<And>x y z. x \<in> set xs \<Longrightarrow> (x,y) \<in> r \<Longrightarrow> (y,z) \<in> r \<Longrightarrow> (x,z) \<in> r)
nipkow@42857
  5351
   \<Longrightarrow>  (xs,ys) \<in> lexord r  \<Longrightarrow>  (ys,zs) \<in> lexord r \<Longrightarrow>  (xs,zs) \<in> lexord r"
nipkow@42857
  5352
proof (induct xs arbitrary: ys zs)
nipkow@42857
  5353
  case Nil
nipkow@42857
  5354
  from Nil(3) show ?case unfolding lexord_def by (cases zs, auto)
nipkow@42857
  5355
next
nipkow@42857
  5356
  case (Cons x xs yys zzs)
nipkow@42857
  5357
  from Cons(3) obtain y ys where yys: "yys = y # ys" unfolding lexord_def
nipkow@42857
  5358
    by (cases yys, auto)
nipkow@42857
  5359
  note Cons = Cons[unfolded yys]
nipkow@42857
  5360
  from Cons(3) have one: "(x,y) \<in> r \<or> x = y \<and> (xs,ys) \<in> lexord r" by auto
nipkow@42857
  5361
  from Cons(4) obtain z zs where zzs: "zzs = z # zs" unfolding lexord_def
nipkow@42857
  5362
    by (cases zzs, auto)
nipkow@42857
  5363
  note Cons = Cons[unfolded zzs]
nipkow@42857
  5364
  from Cons(4) have two: "(y,z) \<in> r \<or> y = z \<and> (ys,zs) \<in> lexord r" by auto
nipkow@42857
  5365
  {
nipkow@42857
  5366
    assume "(xs,ys) \<in> lexord r" and "(ys,zs) \<in> lexord r"
nipkow@42857
  5367
    from Cons(1)[OF _ this] Cons(2)
nipkow@42857
  5368
    have "(xs,zs) \<in> lexord r" by auto
nipkow@42857
  5369
  } note ind1 = this
nipkow@42857
  5370
  {
nipkow@42857
  5371
    assume "(x,y) \<in> r" and "(y,z) \<in> r"
nipkow@42857
  5372
    from Cons(2)[OF _ this] have "(x,z) \<in> r" by auto
nipkow@42857
  5373
  } note ind2 = this
nipkow@42857
  5374
  from one two ind1 ind2
nipkow@42857
  5375
  have "(x,z) \<in> r \<or> x = z \<and> (xs,zs) \<in> lexord r" by blast
nipkow@42857
  5376
  thus ?case unfolding zzs by auto
nipkow@42857
  5377
qed
paulson@15656
  5378
paulson@15656
  5379
lemma lexord_trans: 
paulson@15656
  5380
    "\<lbrakk> (x, y) \<in> lexord r; (y, z) \<in> lexord r; trans r \<rbrakk> \<Longrightarrow> (x, z) \<in> lexord r"
nipkow@42857
  5381
by(auto simp: trans_def intro:lexord_partial_trans)
paulson@15656
  5382
paulson@15656
  5383
lemma lexord_transI:  "trans r \<Longrightarrow> trans (lexord r)"
nipkow@24349
  5384
by (rule transI, drule lexord_trans, blast) 
paulson@15656
  5385
paulson@15656
  5386
lemma lexord_linear: "(! a b. (a,b)\<in> r | a = b | (b,a) \<in> r) \<Longrightarrow> (x,y) : lexord r | x = y | (y,x) : lexord r"
paulson@15656
  5387
  apply (rule_tac x = y in spec) 
paulson@15656
  5388
  apply (induct_tac x, rule allI) 
paulson@15656
  5389
  apply (case_tac x, simp, simp) 
paulson@15656
  5390
  apply (rule allI, case_tac x, simp, simp) 
paulson@15656
  5391
  by blast
paulson@15656
  5392
paulson@15656
  5393
nipkow@40476
  5394
subsubsection {* Lexicographic combination of measure functions *}
krauss@21103
  5395
krauss@21103
  5396
text {* These are useful for termination proofs *}
krauss@21103
  5397
nipkow@51563
  5398
definition "measures fs = inv_image (lex less_than) (%a. map (%f. f a) fs)"
krauss@21103
  5399
krauss@44884
  5400
lemma wf_measures[simp]: "wf (measures fs)"
nipkow@24349
  5401
unfolding measures_def
nipkow@24349
  5402
by blast
krauss@21103
  5403
krauss@21103
  5404
lemma in_measures[simp]: 
krauss@21103
  5405
  "(x, y) \<in> measures [] = False"
krauss@21103
  5406
  "(x, y) \<in> measures (f # fs)
krauss@21103
  5407
         = (f x < f y \<or> (f x = f y \<and> (x, y) \<in> measures fs))"  
nipkow@24349
  5408
unfolding measures_def
nipkow@24349
  5409
by auto
krauss@21103
  5410
krauss@21103
  5411
lemma measures_less: "f x < f y ==> (x, y) \<in> measures (f#fs)"
nipkow@24349
  5412
by simp
krauss@21103
  5413
krauss@21103
  5414
lemma measures_lesseq: "f x <= f y ==> (x, y) \<in> measures fs ==> (x, y) \<in> measures (f#fs)"
nipkow@24349
  5415
by auto
krauss@21103
  5416
krauss@21103
  5417
nipkow@40476
  5418
subsubsection {* Lifting Relations to Lists: one element *}
nipkow@40476
  5419
nipkow@40476
  5420
definition listrel1 :: "('a \<times> 'a) set \<Rightarrow> ('a list \<times> 'a list) set" where
nipkow@40476
  5421
"listrel1 r = {(xs,ys).
nipkow@40476
  5422
   \<exists>us z z' vs. xs = us @ z # vs \<and> (z,z') \<in> r \<and> ys = us @ z' # vs}"
nipkow@40476
  5423
nipkow@40476
  5424
lemma listrel1I:
nipkow@40476
  5425
  "\<lbrakk> (x, y) \<in> r;  xs = us @ x # vs;  ys = us @ y # vs \<rbrakk> \<Longrightarrow>
nipkow@40476
  5426
  (xs, ys) \<in> listrel1 r"
nipkow@40476
  5427
unfolding listrel1_def by auto
nipkow@40476
  5428
nipkow@40476
  5429
lemma listrel1E:
nipkow@40476
  5430
  "\<lbrakk> (xs, ys) \<in> listrel1 r;
nipkow@40476
  5431
     !!x y us vs. \<lbrakk> (x, y) \<in> r;  xs = us @ x # vs;  ys = us @ y # vs \<rbrakk> \<Longrightarrow> P
nipkow@40476
  5432
   \<rbrakk> \<Longrightarrow> P"
nipkow@40476
  5433
unfolding listrel1_def by auto
nipkow@40476
  5434
nipkow@40476
  5435
lemma not_Nil_listrel1 [iff]: "([], xs) \<notin> listrel1 r"
nipkow@40476
  5436
unfolding listrel1_def by blast
nipkow@40476
  5437
nipkow@40476
  5438
lemma not_listrel1_Nil [iff]: "(xs, []) \<notin> listrel1 r"
nipkow@40476
  5439
unfolding listrel1_def by blast
nipkow@40476
  5440
nipkow@40476
  5441
lemma Cons_listrel1_Cons [iff]:
nipkow@40476
  5442
  "(x # xs, y # ys) \<in> listrel1 r \<longleftrightarrow>
nipkow@40476
  5443
   (x,y) \<in> r \<and> xs = ys \<or> x = y \<and> (xs, ys) \<in> listrel1 r"
nipkow@40476
  5444
by (simp add: listrel1_def Cons_eq_append_conv) (blast)
nipkow@40476
  5445
nipkow@40476
  5446
lemma listrel1I1: "(x,y) \<in> r \<Longrightarrow> (x # xs, y # xs) \<in> listrel1 r"
nipkow@40476
  5447
by (metis Cons_listrel1_Cons)
nipkow@40476
  5448
nipkow@40476
  5449
lemma listrel1I2: "(xs, ys) \<in> listrel1 r \<Longrightarrow> (x # xs, x # ys) \<in> listrel1 r"
nipkow@40476
  5450
by (metis Cons_listrel1_Cons)
nipkow@40476
  5451
nipkow@40476
  5452
lemma append_listrel1I:
nipkow@40476
  5453
  "(xs, ys) \<in> listrel1 r \<and> us = vs \<or> xs = ys \<and> (us, vs) \<in> listrel1 r
nipkow@40476
  5454
    \<Longrightarrow> (xs @ us, ys @ vs) \<in> listrel1 r"
nipkow@40476
  5455
unfolding listrel1_def
nipkow@40476
  5456
by auto (blast intro: append_eq_appendI)+
nipkow@40476
  5457
nipkow@40476
  5458
lemma Cons_listrel1E1[elim!]:
nipkow@40476
  5459
  assumes "(x # xs, ys) \<in> listrel1 r"
nipkow@40476
  5460
    and "\<And>y. ys = y # xs \<Longrightarrow> (x, y) \<in> r \<Longrightarrow> R"
nipkow@40476
  5461
    and "\<And>zs. ys = x # zs \<Longrightarrow> (xs, zs) \<in> listrel1 r \<Longrightarrow> R"
nipkow@40476
  5462
  shows R
nipkow@40476
  5463
using assms by (cases ys) blast+
nipkow@40476
  5464
nipkow@40476
  5465
lemma Cons_listrel1E2[elim!]:
nipkow@40476
  5466
  assumes "(xs, y # ys) \<in> listrel1 r"
nipkow@40476
  5467
    and "\<And>x. xs = x # ys \<Longrightarrow> (x, y) \<in> r \<Longrightarrow> R"
nipkow@40476
  5468
    and "\<And>zs. xs = y # zs \<Longrightarrow> (zs, ys) \<in> listrel1 r \<Longrightarrow> R"
nipkow@40476
  5469
  shows R
nipkow@40476
  5470
using assms by (cases xs) blast+
nipkow@40476
  5471
nipkow@40476
  5472
lemma snoc_listrel1_snoc_iff:
nipkow@40476
  5473
  "(xs @ [x], ys @ [y]) \<in> listrel1 r
nipkow@40476
  5474
    \<longleftrightarrow> (xs, ys) \<in> listrel1 r \<and> x = y \<or> xs = ys \<and> (x,y) \<in> r" (is "?L \<longleftrightarrow> ?R")
nipkow@40476
  5475
proof
nipkow@40476
  5476
  assume ?L thus ?R
nipkow@45761
  5477
    by (fastforce simp: listrel1_def snoc_eq_iff_butlast butlast_append)
nipkow@40476
  5478
next
nipkow@40476
  5479
  assume ?R then show ?L unfolding listrel1_def by force
nipkow@40476
  5480
qed
nipkow@40476
  5481
nipkow@40476
  5482
lemma listrel1_eq_len: "(xs,ys) \<in> listrel1 r \<Longrightarrow> length xs = length ys"
nipkow@40476
  5483
unfolding listrel1_def by auto
nipkow@40476
  5484
nipkow@40476
  5485
lemma listrel1_mono:
nipkow@40476
  5486
  "r \<subseteq> s \<Longrightarrow> listrel1 r \<subseteq> listrel1 s"
nipkow@40476
  5487
unfolding listrel1_def by blast
nipkow@40476
  5488
nipkow@40476
  5489
nipkow@40476
  5490
lemma listrel1_converse: "listrel1 (r^-1) = (listrel1 r)^-1"
nipkow@40476
  5491
unfolding listrel1_def by blast
nipkow@40476
  5492
nipkow@40476
  5493
lemma in_listrel1_converse:
nipkow@40476
  5494
  "(x,y) : listrel1 (r^-1) \<longleftrightarrow> (x,y) : (listrel1 r)^-1"
nipkow@40476
  5495
unfolding listrel1_def by blast
nipkow@40476
  5496
nipkow@40476
  5497
lemma listrel1_iff_update:
nipkow@40476
  5498
  "(xs,ys) \<in> (listrel1 r)
nipkow@40476
  5499
   \<longleftrightarrow> (\<exists>y n. (xs ! n, y) \<in> r \<and> n < length xs \<and> ys = xs[n:=y])" (is "?L \<longleftrightarrow> ?R")
nipkow@40476
  5500
proof
nipkow@40476
  5501
  assume "?L"
nipkow@40476
  5502
  then obtain x y u v where "xs = u @ x # v"  "ys = u @ y # v"  "(x,y) \<in> r"
nipkow@40476
  5503
    unfolding listrel1_def by auto
nipkow@40476
  5504
  then have "ys = xs[length u := y]" and "length u < length xs"
nipkow@40476
  5505
    and "(xs ! length u, y) \<in> r" by auto
nipkow@40476
  5506
  then show "?R" by auto
nipkow@40476
  5507
next
nipkow@40476
  5508
  assume "?R"
nipkow@40476
  5509
  then obtain x y n where "(xs!n, y) \<in> r" "n < size xs" "ys = xs[n:=y]" "x = xs!n"
nipkow@40476
  5510
    by auto
nipkow@40476
  5511
  then obtain u v where "xs = u @ x # v" and "ys = u @ y # v" and "(x, y) \<in> r"
nipkow@40476
  5512
    by (auto intro: upd_conv_take_nth_drop id_take_nth_drop)
nipkow@40476
  5513
  then show "?L" by (auto simp: listrel1_def)
nipkow@40476
  5514
qed
nipkow@40476
  5515
nipkow@40476
  5516
nipkow@45365
  5517
text{* Accessible part and wellfoundedness: *}
nipkow@40476
  5518
nipkow@40476
  5519
lemma Cons_acc_listrel1I [intro!]:
haftmann@55747
  5520
  "x \<in> Wellfounded.acc r \<Longrightarrow> xs \<in> Wellfounded.acc (listrel1 r) \<Longrightarrow> (x # xs) \<in> Wellfounded.acc (listrel1 r)"
haftmann@55747
  5521
apply (induct arbitrary: xs set: Wellfounded.acc)
nipkow@40476
  5522
apply (erule thin_rl)
nipkow@40476
  5523
apply (erule acc_induct)
nipkow@40476
  5524
apply (rule accI)
nipkow@40476
  5525
apply (blast)
nipkow@40476
  5526
done
nipkow@40476
  5527
haftmann@55747
  5528
lemma lists_accD: "xs \<in> lists (Wellfounded.acc r) \<Longrightarrow> xs \<in> Wellfounded.acc (listrel1 r)"
nipkow@40476
  5529
apply (induct set: lists)
nipkow@40476
  5530
 apply (rule accI)
nipkow@40476
  5531
 apply simp
nipkow@40476
  5532
apply (rule accI)
nipkow@40476
  5533
apply (fast dest: acc_downward)
nipkow@40476
  5534
done
nipkow@40476
  5535
haftmann@55747
  5536
lemma lists_accI: "xs \<in> Wellfounded.acc (listrel1 r) \<Longrightarrow> xs \<in> lists (Wellfounded.acc r)"
haftmann@55747
  5537
apply (induct set: Wellfounded.acc)
nipkow@40476
  5538
apply clarify
nipkow@40476
  5539
apply (rule accI)
nipkow@45761
  5540
apply (fastforce dest!: in_set_conv_decomp[THEN iffD1] simp: listrel1_def)
nipkow@40476
  5541
done
nipkow@40476
  5542
nipkow@45365
  5543
lemma wf_listrel1_iff[simp]: "wf(listrel1 r) = wf r"
nipkow@45365
  5544
by(metis wf_acc_iff in_lists_conv_set lists_accI lists_accD Cons_in_lists_iff)
nipkow@45365
  5545
nipkow@40476
  5546
nipkow@40476
  5547
subsubsection {* Lifting Relations to Lists: all elements *}
nipkow@15302
  5548
berghofe@23740
  5549
inductive_set
huffman@47145
  5550
  listrel :: "('a \<times> 'b) set \<Rightarrow> ('a list \<times> 'b list) set"
huffman@47145
  5551
  for r :: "('a \<times> 'b) set"
berghofe@22262
  5552
where
berghofe@23740
  5553
    Nil:  "([],[]) \<in> listrel r"
berghofe@23740
  5554
  | Cons: "[| (x,y) \<in> r; (xs,ys) \<in> listrel r |] ==> (x#xs, y#ys) \<in> listrel r"
berghofe@23740
  5555
berghofe@23740
  5556
inductive_cases listrel_Nil1 [elim!]: "([],xs) \<in> listrel r"
berghofe@23740
  5557
inductive_cases listrel_Nil2 [elim!]: "(xs,[]) \<in> listrel r"
berghofe@23740
  5558
inductive_cases listrel_Cons1 [elim!]: "(y#ys,xs) \<in> listrel r"
berghofe@23740
  5559
inductive_cases listrel_Cons2 [elim!]: "(xs,y#ys) \<in> listrel r"
nipkow@15302
  5560
nipkow@15302
  5561
nipkow@40476
  5562
lemma listrel_eq_len:  "(xs, ys) \<in> listrel r \<Longrightarrow> length xs = length ys"
nipkow@40476
  5563
by(induct rule: listrel.induct) auto
nipkow@40476
  5564
bulwahn@47141
  5565
lemma listrel_iff_zip [code_unfold]: "(xs,ys) : listrel r \<longleftrightarrow>
nipkow@40476
  5566
  length xs = length ys & (\<forall>(x,y) \<in> set(zip xs ys). (x,y) \<in> r)" (is "?L \<longleftrightarrow> ?R")
nipkow@40476
  5567
proof
nipkow@40476
  5568
  assume ?L thus ?R by induct (auto intro: listrel_eq_len)
nipkow@40476
  5569
next
nipkow@40476
  5570
  assume ?R thus ?L
nipkow@40476
  5571
    apply (clarify)
nipkow@40476
  5572
    by (induct rule: list_induct2) (auto intro: listrel.intros)
nipkow@40476
  5573
qed
nipkow@40476
  5574
nipkow@40476
  5575
lemma listrel_iff_nth: "(xs,ys) : listrel r \<longleftrightarrow>
nipkow@40476
  5576
  length xs = length ys & (\<forall>n < length xs. (xs!n, ys!n) \<in> r)" (is "?L \<longleftrightarrow> ?R")
nipkow@40476
  5577
by (auto simp add: all_set_conv_all_nth listrel_iff_zip)
nipkow@40476
  5578
nipkow@40476
  5579
nipkow@15302
  5580
lemma listrel_mono: "r \<subseteq> s \<Longrightarrow> listrel r \<subseteq> listrel s"
nipkow@15302
  5581
apply clarify  
berghofe@23740
  5582
apply (erule listrel.induct)
berghofe@23740
  5583
apply (blast intro: listrel.intros)+
nipkow@15281
  5584
done
nipkow@15281
  5585
nipkow@15302
  5586
lemma listrel_subset: "r \<subseteq> A \<times> A \<Longrightarrow> listrel r \<subseteq> lists A \<times> lists A"
nipkow@15302
  5587
apply clarify 
berghofe@23740
  5588
apply (erule listrel.induct, auto) 
nipkow@13145
  5589
done
wenzelm@13114
  5590
nipkow@30198
  5591
lemma listrel_refl_on: "refl_on A r \<Longrightarrow> refl_on (lists A) (listrel r)" 
nipkow@30198
  5592
apply (simp add: refl_on_def listrel_subset Ball_def)
nipkow@15302
  5593
apply (rule allI) 
nipkow@15302
  5594
apply (induct_tac x) 
berghofe@23740
  5595
apply (auto intro: listrel.intros)
nipkow@13145
  5596
done
wenzelm@13114
  5597
nipkow@15302
  5598
lemma listrel_sym: "sym r \<Longrightarrow> sym (listrel r)" 
nipkow@15302
  5599
apply (auto simp add: sym_def)
berghofe@23740
  5600
apply (erule listrel.induct) 
berghofe@23740
  5601
apply (blast intro: listrel.intros)+
nipkow@15281
  5602
done
nipkow@15281
  5603
nipkow@15302
  5604
lemma listrel_trans: "trans r \<Longrightarrow> trans (listrel r)" 
nipkow@15302
  5605
apply (simp add: trans_def)
nipkow@15302
  5606
apply (intro allI) 
nipkow@15302
  5607
apply (rule impI) 
berghofe@23740
  5608
apply (erule listrel.induct) 
berghofe@23740
  5609
apply (blast intro: listrel.intros)+
nipkow@15281
  5610
done
nipkow@15281
  5611
nipkow@15302
  5612
theorem equiv_listrel: "equiv A r \<Longrightarrow> equiv (lists A) (listrel r)"
nipkow@30198
  5613
by (simp add: equiv_def listrel_refl_on listrel_sym listrel_trans) 
nipkow@15302
  5614
nipkow@40476
  5615
lemma listrel_rtrancl_refl[iff]: "(xs,xs) : listrel(r^*)"
nipkow@40476
  5616
using listrel_refl_on[of UNIV, OF refl_rtrancl]
nipkow@40476
  5617
by(auto simp: refl_on_def)
nipkow@40476
  5618
nipkow@40476
  5619
lemma listrel_rtrancl_trans:
nipkow@40476
  5620
  "\<lbrakk> (xs,ys) : listrel(r^*);  (ys,zs) : listrel(r^*) \<rbrakk>
nipkow@40476
  5621
  \<Longrightarrow> (xs,zs) : listrel(r^*)"
nipkow@40476
  5622
by (metis listrel_trans trans_def trans_rtrancl)
nipkow@40476
  5623
nipkow@40476
  5624
nipkow@15302
  5625
lemma listrel_Nil [simp]: "listrel r `` {[]} = {[]}"
berghofe@23740
  5626
by (blast intro: listrel.intros)
nipkow@15302
  5627
nipkow@15302
  5628
lemma listrel_Cons:
haftmann@33301
  5629
     "listrel r `` {x#xs} = set_Cons (r``{x}) (listrel r `` {xs})"
haftmann@33301
  5630
by (auto simp add: set_Cons_def intro: listrel.intros)
nipkow@15302
  5631
nipkow@40476
  5632
text {* Relating @{term listrel1}, @{term listrel} and closures: *}
nipkow@40476
  5633
nipkow@40476
  5634
lemma listrel1_rtrancl_subset_rtrancl_listrel1:
nipkow@40476
  5635
  "listrel1 (r^*) \<subseteq> (listrel1 r)^*"
nipkow@40476
  5636
proof (rule subrelI)
nipkow@40476
  5637
  fix xs ys assume 1: "(xs,ys) \<in> listrel1 (r^*)"
nipkow@40476
  5638
  { fix x y us vs
nipkow@40476
  5639
    have "(x,y) : r^* \<Longrightarrow> (us @ x # vs, us @ y # vs) : (listrel1 r)^*"
nipkow@40476
  5640
    proof(induct rule: rtrancl.induct)
nipkow@40476
  5641
      case rtrancl_refl show ?case by simp
nipkow@40476
  5642
    next
nipkow@40476
  5643
      case rtrancl_into_rtrancl thus ?case
nipkow@40476
  5644
        by (metis listrel1I rtrancl.rtrancl_into_rtrancl)
nipkow@40476
  5645
    qed }
nipkow@40476
  5646
  thus "(xs,ys) \<in> (listrel1 r)^*" using 1 by(blast elim: listrel1E)
nipkow@40476
  5647
qed
nipkow@40476
  5648
nipkow@40476
  5649
lemma rtrancl_listrel1_eq_len: "(x,y) \<in> (listrel1 r)^* \<Longrightarrow> length x = length y"
nipkow@40476
  5650
by (induct rule: rtrancl.induct) (auto intro: listrel1_eq_len)
nipkow@40476
  5651
nipkow@40476
  5652
lemma rtrancl_listrel1_ConsI1:
nipkow@40476
  5653
  "(xs,ys) : (listrel1 r)^* \<Longrightarrow> (x#xs,x#ys) : (listrel1 r)^*"
nipkow@40476
  5654
apply(induct rule: rtrancl.induct)
nipkow@40476
  5655
 apply simp
nipkow@40476
  5656
by (metis listrel1I2 rtrancl.rtrancl_into_rtrancl)
nipkow@40476
  5657
nipkow@40476
  5658
lemma rtrancl_listrel1_ConsI2:
nipkow@40476
  5659
  "(x,y) \<in> r^* \<Longrightarrow> (xs, ys) \<in> (listrel1 r)^*
nipkow@40476
  5660
  \<Longrightarrow> (x # xs, y # ys) \<in> (listrel1 r)^*"
nipkow@40476
  5661
  by (blast intro: rtrancl_trans rtrancl_listrel1_ConsI1 
nipkow@40476
  5662
    subsetD[OF listrel1_rtrancl_subset_rtrancl_listrel1 listrel1I1])
nipkow@40476
  5663
nipkow@40476
  5664
lemma listrel1_subset_listrel:
nipkow@40476
  5665
  "r \<subseteq> r' \<Longrightarrow> refl r' \<Longrightarrow> listrel1 r \<subseteq> listrel(r')"
nipkow@40476
  5666
by(auto elim!: listrel1E simp add: listrel_iff_zip set_zip refl_on_def)
nipkow@40476
  5667
nipkow@40476
  5668
lemma listrel_reflcl_if_listrel1:
nipkow@40476
  5669
  "(xs,ys) : listrel1 r \<Longrightarrow> (xs,ys) : listrel(r^*)"
nipkow@40476
  5670
by(erule listrel1E)(auto simp add: listrel_iff_zip set_zip)
nipkow@40476
  5671
nipkow@40476
  5672
lemma listrel_rtrancl_eq_rtrancl_listrel1: "listrel (r^*) = (listrel1 r)^*"
nipkow@40476
  5673
proof
nipkow@40476
  5674
  { fix x y assume "(x,y) \<in> listrel (r^*)"
nipkow@40476
  5675
    then have "(x,y) \<in> (listrel1 r)^*"
nipkow@40476
  5676
    by induct (auto intro: rtrancl_listrel1_ConsI2) }
nipkow@40476
  5677
  then show "listrel (r^*) \<subseteq> (listrel1 r)^*"
nipkow@40476
  5678
    by (rule subrelI)
nipkow@40476
  5679
next
nipkow@40476
  5680
  show "listrel (r^*) \<supseteq> (listrel1 r)^*"
nipkow@40476
  5681
  proof(rule subrelI)
nipkow@40476
  5682
    fix xs ys assume "(xs,ys) \<in> (listrel1 r)^*"
nipkow@40476
  5683
    then show "(xs,ys) \<in> listrel (r^*)"
nipkow@40476
  5684
    proof induct
nipkow@40476
  5685
      case base show ?case by(auto simp add: listrel_iff_zip set_zip)
nipkow@40476
  5686
    next
nipkow@40476
  5687
      case (step ys zs)
nipkow@40476
  5688
      thus ?case  by (metis listrel_reflcl_if_listrel1 listrel_rtrancl_trans)
nipkow@40476
  5689
    qed
nipkow@40476
  5690
  qed
nipkow@40476
  5691
qed
nipkow@40476
  5692
nipkow@40476
  5693
lemma rtrancl_listrel1_if_listrel:
nipkow@40476
  5694
  "(xs,ys) : listrel r \<Longrightarrow> (xs,ys) : (listrel1 r)^*"
nipkow@40476
  5695
by(metis listrel_rtrancl_eq_rtrancl_listrel1 subsetD[OF listrel_mono] r_into_rtrancl subsetI)
nipkow@40476
  5696
nipkow@40476
  5697
lemma listrel_subset_rtrancl_listrel1: "listrel r \<subseteq> (listrel1 r)^*"
nipkow@40476
  5698
by(fast intro:rtrancl_listrel1_if_listrel)
nipkow@40476
  5699
nipkow@15302
  5700
krauss@26749
  5701
subsection {* Size function *}
krauss@26749
  5702
krauss@26875
  5703
lemma [measure_function]: "is_measure f \<Longrightarrow> is_measure (list_size f)"
krauss@26875
  5704
by (rule is_measure_trivial)
krauss@26875
  5705
krauss@26875
  5706
lemma [measure_function]: "is_measure f \<Longrightarrow> is_measure (option_size f)"
krauss@26875
  5707
by (rule is_measure_trivial)
krauss@26875
  5708
krauss@26875
  5709
lemma list_size_estimation[termination_simp]: 
krauss@26875
  5710
  "x \<in> set xs \<Longrightarrow> y < f x \<Longrightarrow> y < list_size f xs"
krauss@26749
  5711
by (induct xs) auto
krauss@26749
  5712
krauss@26875
  5713
lemma list_size_estimation'[termination_simp]: 
krauss@26875
  5714
  "x \<in> set xs \<Longrightarrow> y \<le> f x \<Longrightarrow> y \<le> list_size f xs"
krauss@26875
  5715
by (induct xs) auto
krauss@26875
  5716
krauss@26875
  5717
lemma list_size_map[simp]: "list_size f (map g xs) = list_size (f o g) xs"
krauss@26875
  5718
by (induct xs) auto
krauss@26875
  5719
bulwahn@45477
  5720
lemma list_size_append[simp]: "list_size f (xs @ ys) = list_size f xs + list_size f ys"
bulwahn@45477
  5721
by (induct xs, auto)
bulwahn@45477
  5722
krauss@26875
  5723
lemma list_size_pointwise[termination_simp]: 
bulwahn@45476
  5724
  "(\<And>x. x \<in> set xs \<Longrightarrow> f x \<le> g x) \<Longrightarrow> list_size f xs \<le> list_size g xs"
krauss@26875
  5725
by (induct xs) force+
krauss@26749
  5726
haftmann@31048
  5727
haftmann@47012
  5728
subsection {* Monad operation *}
haftmann@47012
  5729
haftmann@47012
  5730
definition bind :: "'a list \<Rightarrow> ('a \<Rightarrow> 'b list) \<Rightarrow> 'b list" where
nipkow@51563
  5731
"bind xs f = concat (map f xs)"
haftmann@47012
  5732
haftmann@47012
  5733
hide_const (open) bind
haftmann@47012
  5734
haftmann@47012
  5735
lemma bind_simps [simp]:
haftmann@47012
  5736
  "List.bind [] f = []"
haftmann@47012
  5737
  "List.bind (x # xs) f = f x @ List.bind xs f"
haftmann@47012
  5738
  by (simp_all add: bind_def)
haftmann@47012
  5739
haftmann@47012
  5740
haftmann@33301
  5741
subsection {* Transfer *}
haftmann@33301
  5742
nipkow@51563
  5743
definition embed_list :: "nat list \<Rightarrow> int list" where
nipkow@51563
  5744
"embed_list l = map int l"
nipkow@51563
  5745
nipkow@51563
  5746
definition nat_list :: "int list \<Rightarrow> bool" where
nipkow@51563
  5747
"nat_list l = nat_set (set l)"
nipkow@51563
  5748
nipkow@51563
  5749
definition return_list :: "int list \<Rightarrow> nat list" where
nipkow@51563
  5750
"return_list l = map nat l"
haftmann@33301
  5751
haftmann@33301
  5752
lemma transfer_nat_int_list_return_embed: "nat_list l \<longrightarrow>
haftmann@33301
  5753
    embed_list (return_list l) = l"
haftmann@33301
  5754
  unfolding embed_list_def return_list_def nat_list_def nat_set_def
haftmann@33301
  5755
  apply (induct l)
haftmann@33301
  5756
  apply auto
haftmann@33301
  5757
done
haftmann@33301
  5758
haftmann@33301
  5759
lemma transfer_nat_int_list_functions:
haftmann@33301
  5760
  "l @ m = return_list (embed_list l @ embed_list m)"
haftmann@33301
  5761
  "[] = return_list []"
haftmann@33301
  5762
  unfolding return_list_def embed_list_def
haftmann@33301
  5763
  apply auto
haftmann@33301
  5764
  apply (induct l, auto)
haftmann@33301
  5765
  apply (induct m, auto)
haftmann@33301
  5766
done
haftmann@33301
  5767
haftmann@33301
  5768
(*
haftmann@33301
  5769
lemma transfer_nat_int_fold1: "fold f l x =
haftmann@33301
  5770
    fold (%x. f (nat x)) (embed_list l) x";
haftmann@33301
  5771
*)
haftmann@33301
  5772
haftmann@33301
  5773
haftmann@37605
  5774
subsection {* Code generation *}
haftmann@37605
  5775
nipkow@53012
  5776
nipkow@53012
  5777
text{* Optional tail recursive version of @{const map}. Can avoid
nipkow@53012
  5778
stack overflow in some target languages. *}
nipkow@53012
  5779
nipkow@53012
  5780
fun map_tailrec_rev ::  "('a \<Rightarrow> 'b) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> 'b list" where
nipkow@53012
  5781
"map_tailrec_rev f [] bs = bs" |
nipkow@53012
  5782
"map_tailrec_rev f (a#as) bs = map_tailrec_rev f as (f a # bs)"
nipkow@53012
  5783
nipkow@53012
  5784
lemma map_tailrec_rev:
nipkow@53012
  5785
  "map_tailrec_rev f as bs = rev(map f as) @ bs"
nipkow@53012
  5786
by(induction as arbitrary: bs) simp_all
nipkow@53012
  5787
nipkow@53012
  5788
definition map_tailrec :: "('a \<Rightarrow> 'b) \<Rightarrow> 'a list \<Rightarrow> 'b list" where
nipkow@53012
  5789
"map_tailrec f as = rev (map_tailrec_rev f as [])"
nipkow@53012
  5790
nipkow@53012
  5791
text{* Code equation: *}
nipkow@53012
  5792
lemma map_eq_map_tailrec: "map = map_tailrec"
nipkow@53012
  5793
by(simp add: fun_eq_iff map_tailrec_def map_tailrec_rev)
nipkow@53012
  5794
nipkow@53012
  5795
haftmann@37605
  5796
subsubsection {* Counterparts for set-related operations *}
haftmann@37605
  5797
haftmann@37605
  5798
definition member :: "'a list \<Rightarrow> 'a \<Rightarrow> bool" where
nipkow@51563
  5799
[code_abbrev]: "member xs x \<longleftrightarrow> x \<in> set xs"
haftmann@37605
  5800
haftmann@37605
  5801
text {*
haftmann@46901
  5802
  Use @{text member} only for generating executable code.  Otherwise use
haftmann@37605
  5803
  @{prop "x \<in> set xs"} instead --- it is much easier to reason about.
haftmann@37605
  5804
*}
haftmann@37605
  5805
haftmann@37605
  5806
lemma member_rec [code]:
haftmann@37605
  5807
  "member (x # xs) y \<longleftrightarrow> x = y \<or> member xs y"
haftmann@37605
  5808
  "member [] y \<longleftrightarrow> False"
haftmann@37605
  5809
  by (auto simp add: member_def)
haftmann@37605
  5810
haftmann@46901
  5811
lemma in_set_member (* FIXME delete candidate *):
haftmann@37605
  5812
  "x \<in> set xs \<longleftrightarrow> member xs x"
haftmann@37605
  5813
  by (simp add: member_def)
haftmann@37605
  5814
haftmann@37605
  5815
definition list_all :: "('a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> bool" where
nipkow@51563
  5816
list_all_iff [code_abbrev]: "list_all P xs \<longleftrightarrow> Ball (set xs) P"
haftmann@37605
  5817
haftmann@37605
  5818
definition list_ex :: "('a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> bool" where
nipkow@51563
  5819
list_ex_iff [code_abbrev]: "list_ex P xs \<longleftrightarrow> Bex (set xs) P"
haftmann@46901
  5820
haftmann@46901
  5821
definition list_ex1 :: "('a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> bool" where
nipkow@51563
  5822
list_ex1_iff [code_abbrev]: "list_ex1 P xs \<longleftrightarrow> (\<exists>! x. x \<in> set xs \<and> P x)"
bulwahn@40900
  5823
haftmann@37605
  5824
text {*
haftmann@46901
  5825
  Usually you should prefer @{text "\<forall>x\<in>set xs"}, @{text "\<exists>x\<in>set xs"}
haftmann@46901
  5826
  and @{text "\<exists>!x. x\<in>set xs \<and> _"} over @{const list_all}, @{const list_ex}
haftmann@46901
  5827
  and @{const list_ex1} in specifications.
haftmann@37605
  5828
*}
haftmann@37605
  5829
haftmann@37605
  5830
lemma list_all_simps [simp, code]:
haftmann@37605
  5831
  "list_all P (x # xs) \<longleftrightarrow> P x \<and> list_all P xs"
haftmann@37605
  5832
  "list_all P [] \<longleftrightarrow> True"
haftmann@37605
  5833
  by (simp_all add: list_all_iff)
haftmann@37605
  5834
haftmann@37605
  5835
lemma list_ex_simps [simp, code]:
haftmann@37605
  5836
  "list_ex P (x # xs) \<longleftrightarrow> P x \<or> list_ex P xs"
haftmann@37605
  5837
  "list_ex P [] \<longleftrightarrow> False"
haftmann@37605
  5838
  by (simp_all add: list_ex_iff)
haftmann@37605
  5839
bulwahn@40900
  5840
lemma list_ex1_simps [simp, code]:
bulwahn@40900
  5841
  "list_ex1 P [] = False"
bulwahn@40900
  5842
  "list_ex1 P (x # xs) = (if P x then list_all (\<lambda>y. \<not> P y \<or> x = y) xs else list_ex1 P xs)"
haftmann@46901
  5843
  by (auto simp add: list_ex1_iff list_all_iff)
haftmann@46901
  5844
haftmann@46901
  5845
lemma Ball_set_list_all: (* FIXME delete candidate *)
haftmann@37605
  5846
  "Ball (set xs) P \<longleftrightarrow> list_all P xs"
haftmann@37605
  5847
  by (simp add: list_all_iff)
haftmann@37605
  5848
haftmann@46901
  5849
lemma Bex_set_list_ex: (* FIXME delete candidate *)
haftmann@37605
  5850
  "Bex (set xs) P \<longleftrightarrow> list_ex P xs"
haftmann@37605
  5851
  by (simp add: list_ex_iff)
haftmann@37605
  5852
haftmann@37605
  5853
lemma list_all_append [simp]:
haftmann@37605
  5854
  "list_all P (xs @ ys) \<longleftrightarrow> list_all P xs \<and> list_all P ys"
haftmann@37605
  5855
  by (auto simp add: list_all_iff)
haftmann@37605
  5856
haftmann@37605
  5857
lemma list_ex_append [simp]:
haftmann@37605
  5858
  "list_ex P (xs @ ys) \<longleftrightarrow> list_ex P xs \<or> list_ex P ys"
haftmann@37605
  5859
  by (auto simp add: list_ex_iff)
haftmann@37605
  5860
haftmann@37605
  5861
lemma list_all_rev [simp]:
haftmann@37605
  5862
  "list_all P (rev xs) \<longleftrightarrow> list_all P xs"
haftmann@37605
  5863
  by (simp add: list_all_iff)
haftmann@37605
  5864
haftmann@37605
  5865
lemma list_ex_rev [simp]:
haftmann@37605
  5866
  "list_ex P (rev xs) \<longleftrightarrow> list_ex P xs"
haftmann@37605
  5867
  by (simp add: list_ex_iff)
haftmann@37605
  5868
haftmann@37605
  5869
lemma list_all_length:
haftmann@37605
  5870
  "list_all P xs \<longleftrightarrow> (\<forall>n < length xs. P (xs ! n))"
haftmann@37605
  5871
  by (auto simp add: list_all_iff set_conv_nth)
haftmann@37605
  5872
haftmann@37605
  5873
lemma list_ex_length:
haftmann@37605
  5874
  "list_ex P xs \<longleftrightarrow> (\<exists>n < length xs. P (xs ! n))"
haftmann@37605
  5875
  by (auto simp add: list_ex_iff set_conv_nth)
haftmann@37605
  5876
haftmann@37605
  5877
lemma list_all_cong [fundef_cong]:
haftmann@37605
  5878
  "xs = ys \<Longrightarrow> (\<And>x. x \<in> set ys \<Longrightarrow> f x = g x) \<Longrightarrow> list_all f xs = list_all g ys"
haftmann@37605
  5879
  by (simp add: list_all_iff)
haftmann@37605
  5880
nipkow@48000
  5881
lemma list_ex_cong [fundef_cong]:
haftmann@37605
  5882
  "xs = ys \<Longrightarrow> (\<And>x. x \<in> set ys \<Longrightarrow> f x = g x) \<Longrightarrow> list_ex f xs = list_ex g ys"
nipkow@48000
  5883
by (simp add: list_ex_iff)
haftmann@37605
  5884
nipkow@51563
  5885
definition can_select :: "('a \<Rightarrow> bool) \<Rightarrow> 'a set \<Rightarrow> bool" where
nipkow@51563
  5886
[code_abbrev]: "can_select P A = (\<exists>!x\<in>A. P x)"
haftmann@50963
  5887
haftmann@50963
  5888
lemma can_select_set_list_ex1 [code]:
haftmann@50963
  5889
  "can_select P (set A) = list_ex1 P A"
haftmann@50963
  5890
  by (simp add: list_ex1_iff can_select_def)
haftmann@50963
  5891
haftmann@50963
  5892
bulwahn@47141
  5893
text {* Executable checks for relations on sets *}
bulwahn@47141
  5894
bulwahn@47141
  5895
definition listrel1p :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> 'a list \<Rightarrow> bool" where
bulwahn@47141
  5896
"listrel1p r xs ys = ((xs, ys) \<in> listrel1 {(x, y). r x y})"
bulwahn@47141
  5897
bulwahn@47141
  5898
lemma [code_unfold]:
bulwahn@47141
  5899
  "(xs, ys) \<in> listrel1 r = listrel1p (\<lambda>x y. (x, y) \<in> r) xs ys"
bulwahn@47141
  5900
unfolding listrel1p_def by auto
bulwahn@47141
  5901
bulwahn@47141
  5902
lemma [code]:
bulwahn@47141
  5903
  "listrel1p r [] xs = False"
bulwahn@47141
  5904
  "listrel1p r xs [] =  False"
bulwahn@47141
  5905
  "listrel1p r (x # xs) (y # ys) \<longleftrightarrow>
bulwahn@47141
  5906
     r x y \<and> xs = ys \<or> x = y \<and> listrel1p r xs ys"
bulwahn@47141
  5907
by (simp add: listrel1p_def)+
bulwahn@47141
  5908
bulwahn@47141
  5909
definition
bulwahn@47141
  5910
  lexordp :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> 'a list \<Rightarrow> bool" where
bulwahn@47141
  5911
  "lexordp r xs ys = ((xs, ys) \<in> lexord {(x, y). r x y})"
bulwahn@47141
  5912
bulwahn@47141
  5913
lemma [code_unfold]:
bulwahn@47141
  5914
  "(xs, ys) \<in> lexord r = lexordp (\<lambda>x y. (x, y) \<in> r) xs ys"
bulwahn@47141
  5915
unfolding lexordp_def by auto
bulwahn@47141
  5916
bulwahn@47141
  5917
lemma [code]:
bulwahn@47141
  5918
  "lexordp r xs [] = False"
bulwahn@47141
  5919
  "lexordp r [] (y#ys) = True"
bulwahn@47141
  5920
  "lexordp r (x # xs) (y # ys) = (r x y | (x = y & lexordp r xs ys))"
bulwahn@47141
  5921
unfolding lexordp_def by auto
bulwahn@47141
  5922
haftmann@37605
  5923
text {* Bounded quantification and summation over nats. *}
haftmann@37605
  5924
haftmann@37605
  5925
lemma atMost_upto [code_unfold]:
haftmann@37605
  5926
  "{..n} = set [0..<Suc n]"
haftmann@37605
  5927
  by auto
haftmann@37605
  5928
haftmann@37605
  5929
lemma atLeast_upt [code_unfold]:
haftmann@37605
  5930
  "{..<n} = set [0..<n]"
haftmann@37605
  5931
  by auto
haftmann@37605
  5932
haftmann@37605
  5933
lemma greaterThanLessThan_upt [code_unfold]:
haftmann@37605
  5934
  "{n<..<m} = set [Suc n..<m]"
haftmann@37605
  5935
  by auto
haftmann@37605
  5936
haftmann@37605
  5937
lemmas atLeastLessThan_upt [code_unfold] = set_upt [symmetric]
haftmann@37605
  5938
haftmann@37605
  5939
lemma greaterThanAtMost_upt [code_unfold]:
haftmann@37605
  5940
  "{n<..m} = set [Suc n..<Suc m]"
haftmann@37605
  5941
  by auto
haftmann@37605
  5942
haftmann@37605
  5943
lemma atLeastAtMost_upt [code_unfold]:
haftmann@37605
  5944
  "{n..m} = set [n..<Suc m]"
haftmann@37605
  5945
  by auto
haftmann@37605
  5946
haftmann@37605
  5947
lemma all_nat_less_eq [code_unfold]:
haftmann@37605
  5948
  "(\<forall>m<n\<Colon>nat. P m) \<longleftrightarrow> (\<forall>m \<in> {0..<n}. P m)"
haftmann@37605
  5949
  by auto
haftmann@37605
  5950
haftmann@37605
  5951
lemma ex_nat_less_eq [code_unfold]:
haftmann@37605
  5952
  "(\<exists>m<n\<Colon>nat. P m) \<longleftrightarrow> (\<exists>m \<in> {0..<n}. P m)"
haftmann@37605
  5953
  by auto
haftmann@37605
  5954
haftmann@37605
  5955
lemma all_nat_less [code_unfold]:
haftmann@37605
  5956
  "(\<forall>m\<le>n\<Colon>nat. P m) \<longleftrightarrow> (\<forall>m \<in> {0..n}. P m)"
haftmann@37605
  5957
  by auto
haftmann@37605
  5958
haftmann@37605
  5959
lemma ex_nat_less [code_unfold]:
haftmann@37605
  5960
  "(\<exists>m\<le>n\<Colon>nat. P m) \<longleftrightarrow> (\<exists>m \<in> {0..n}. P m)"
haftmann@37605
  5961
  by auto
haftmann@37605
  5962
haftmann@37605
  5963
lemma setsum_set_upt_conv_listsum_nat [code_unfold]:
haftmann@37605
  5964
  "setsum f (set [m..<n]) = listsum (map f [m..<n])"
haftmann@37605
  5965
  by (simp add: interv_listsum_conv_setsum_set_nat)
haftmann@37605
  5966
nipkow@55091
  5967
text{* Bounded @{text LEAST} operator: *}
nipkow@55091
  5968
nipkow@55091
  5969
definition "Bleast S P = (LEAST x. x \<in> S \<and> P x)"
nipkow@55091
  5970
nipkow@55091
  5971
definition "abort_Bleast S P = (LEAST x. x \<in> S \<and> P x)"
nipkow@55091
  5972
nipkow@55091
  5973
code_abort abort_Bleast
nipkow@55091
  5974
nipkow@55091
  5975
lemma Bleast_code [code]:
nipkow@55091
  5976
 "Bleast (set xs) P = (case filter P (sort xs) of
nipkow@55091
  5977
    x#xs \<Rightarrow> x |
nipkow@55091
  5978
    [] \<Rightarrow> abort_Bleast (set xs) P)"
nipkow@55091
  5979
proof (cases "filter P (sort xs)")
nipkow@55091
  5980
  case Nil thus ?thesis by (simp add: Bleast_def abort_Bleast_def)
nipkow@55091
  5981
next
nipkow@55091
  5982
  case (Cons x ys)
nipkow@55091
  5983
  have "(LEAST x. x \<in> set xs \<and> P x) = x"
nipkow@55091
  5984
  proof (rule Least_equality)
nipkow@55091
  5985
    show "x \<in> set xs \<and> P x"
nipkow@55091
  5986
      by (metis Cons Cons_eq_filter_iff in_set_conv_decomp set_sort)
nipkow@55091
  5987
    next
nipkow@55091
  5988
      fix y assume "y : set xs \<and> P y"
nipkow@55091
  5989
      hence "y : set (filter P xs)" by auto
nipkow@55091
  5990
      thus "x \<le> y"
nipkow@55091
  5991
        by (metis Cons eq_iff filter_sort set_ConsD set_sort sorted_Cons sorted_sort)
nipkow@55091
  5992
  qed
nipkow@55091
  5993
  thus ?thesis using Cons by (simp add: Bleast_def)
nipkow@55091
  5994
qed
nipkow@55091
  5995
nipkow@55091
  5996
declare Bleast_def[symmetric, code_unfold]
nipkow@55091
  5997
haftmann@37605
  5998
text {* Summation over ints. *}
haftmann@37605
  5999
haftmann@37605
  6000
lemma greaterThanLessThan_upto [code_unfold]:
haftmann@37605
  6001
  "{i<..<j::int} = set [i+1..j - 1]"
haftmann@37605
  6002
by auto
haftmann@37605
  6003
haftmann@37605
  6004
lemma atLeastLessThan_upto [code_unfold]:
haftmann@37605
  6005
  "{i..<j::int} = set [i..j - 1]"
haftmann@37605
  6006
by auto
haftmann@37605
  6007
haftmann@37605
  6008
lemma greaterThanAtMost_upto [code_unfold]:
haftmann@37605
  6009
  "{i<..j::int} = set [i+1..j]"
haftmann@37605
  6010
by auto
haftmann@37605
  6011
haftmann@37605
  6012
lemmas atLeastAtMost_upto [code_unfold] = set_upto [symmetric]
haftmann@37605
  6013
haftmann@37605
  6014
lemma setsum_set_upto_conv_listsum_int [code_unfold]:
haftmann@37605
  6015
  "setsum f (set [i..j::int]) = listsum (map f [i..j])"
haftmann@37605
  6016
  by (simp add: interv_listsum_conv_setsum_set_int)
haftmann@37605
  6017
haftmann@37605
  6018
haftmann@37605
  6019
subsubsection {* Optimizing by rewriting *}
haftmann@37605
  6020
haftmann@37605
  6021
definition null :: "'a list \<Rightarrow> bool" where
haftmann@46901
  6022
  [code_abbrev]: "null xs \<longleftrightarrow> xs = []"
haftmann@37605
  6023
haftmann@37605
  6024
text {*
haftmann@37605
  6025
  Efficient emptyness check is implemented by @{const null}.
haftmann@37605
  6026
*}
haftmann@37605
  6027
haftmann@37605
  6028
lemma null_rec [code]:
haftmann@37605
  6029
  "null (x # xs) \<longleftrightarrow> False"
haftmann@37605
  6030
  "null [] \<longleftrightarrow> True"
haftmann@37605
  6031
  by (simp_all add: null_def)
haftmann@37605
  6032
haftmann@46901
  6033
lemma eq_Nil_null: (* FIXME delete candidate *)
haftmann@37605
  6034
  "xs = [] \<longleftrightarrow> null xs"
haftmann@37605
  6035
  by (simp add: null_def)
haftmann@37605
  6036
haftmann@37605
  6037
lemma equal_Nil_null [code_unfold]:
haftmann@39086
  6038
  "HOL.equal xs [] \<longleftrightarrow> null xs"
lammich@55077
  6039
  "HOL.equal [] = null"
lammich@55077
  6040
  by (auto simp add: equal null_def)
haftmann@37605
  6041
haftmann@37605
  6042
definition maps :: "('a \<Rightarrow> 'b list) \<Rightarrow> 'a list \<Rightarrow> 'b list" where
haftmann@46901
  6043
  [code_abbrev]: "maps f xs = concat (map f xs)"
haftmann@37605
  6044
haftmann@37605
  6045
definition map_filter :: "('a \<Rightarrow> 'b option) \<Rightarrow> 'a list \<Rightarrow> 'b list" where
haftmann@37605
  6046
  [code_post]: "map_filter f xs = map (the \<circ> f) (filter (\<lambda>x. f x \<noteq> None) xs)"
haftmann@37605
  6047
haftmann@37605
  6048
text {*
haftmann@37605
  6049
  Operations @{const maps} and @{const map_filter} avoid
haftmann@37605
  6050
  intermediate lists on execution -- do not use for proving.
haftmann@37605
  6051
*}
haftmann@37605
  6052
haftmann@37605
  6053
lemma maps_simps [code]:
haftmann@37605
  6054
  "maps f (x # xs) = f x @ maps f xs"
haftmann@37605
  6055
  "maps f [] = []"
haftmann@37605
  6056
  by (simp_all add: maps_def)
haftmann@37605
  6057
haftmann@37605
  6058
lemma map_filter_simps [code]:
haftmann@37605
  6059
  "map_filter f (x # xs) = (case f x of None \<Rightarrow> map_filter f xs | Some y \<Rightarrow> y # map_filter f xs)"
haftmann@37605
  6060
  "map_filter f [] = []"
haftmann@37605
  6061
  by (simp_all add: map_filter_def split: option.split)
haftmann@37605
  6062
haftmann@46901
  6063
lemma concat_map_maps: (* FIXME delete candidate *)
haftmann@37605
  6064
  "concat (map f xs) = maps f xs"
haftmann@37605
  6065
  by (simp add: maps_def)
haftmann@37605
  6066
haftmann@37605
  6067
lemma map_filter_map_filter [code_unfold]:
haftmann@37605
  6068
  "map f (filter P xs) = map_filter (\<lambda>x. if P x then Some (f x) else None) xs"
haftmann@37605
  6069
  by (simp add: map_filter_def)
haftmann@37605
  6070
haftmann@37605
  6071
text {* Optimized code for @{text"\<forall>i\<in>{a..b::int}"} and @{text"\<forall>n:{a..<b::nat}"}
haftmann@37605
  6072
and similiarly for @{text"\<exists>"}. *}
haftmann@37605
  6073
haftmann@37605
  6074
definition all_interval_nat :: "(nat \<Rightarrow> bool) \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> bool" where
haftmann@37605
  6075
  "all_interval_nat P i j \<longleftrightarrow> (\<forall>n \<in> {i..<j}. P n)"
haftmann@37605
  6076
haftmann@37605
  6077
lemma [code]:
haftmann@37605
  6078
  "all_interval_nat P i j \<longleftrightarrow> i \<ge> j \<or> P i \<and> all_interval_nat P (Suc i) j"
haftmann@37605
  6079
proof -
haftmann@37605
  6080
  have *: "\<And>n. P i \<Longrightarrow> \<forall>n\<in>{Suc i..<j}. P n \<Longrightarrow> i \<le> n \<Longrightarrow> n < j \<Longrightarrow> P n"
haftmann@37605
  6081
  proof -
haftmann@37605
  6082
    fix n
haftmann@37605
  6083
    assume "P i" "\<forall>n\<in>{Suc i..<j}. P n" "i \<le> n" "n < j"
haftmann@37605
  6084
    then show "P n" by (cases "n = i") simp_all
haftmann@37605
  6085
  qed
haftmann@37605
  6086
  show ?thesis by (auto simp add: all_interval_nat_def intro: *)
haftmann@37605
  6087
qed
haftmann@37605
  6088
haftmann@37605
  6089
lemma list_all_iff_all_interval_nat [code_unfold]:
haftmann@37605
  6090
  "list_all P [i..<j] \<longleftrightarrow> all_interval_nat P i j"
haftmann@37605
  6091
  by (simp add: list_all_iff all_interval_nat_def)
haftmann@37605
  6092
haftmann@37605
  6093
lemma list_ex_iff_not_all_inverval_nat [code_unfold]:
haftmann@37605
  6094
  "list_ex P [i..<j] \<longleftrightarrow> \<not> (all_interval_nat (Not \<circ> P) i j)"
haftmann@37605
  6095
  by (simp add: list_ex_iff all_interval_nat_def)
haftmann@37605
  6096
haftmann@37605
  6097
definition all_interval_int :: "(int \<Rightarrow> bool) \<Rightarrow> int \<Rightarrow> int \<Rightarrow> bool" where
haftmann@37605
  6098
  "all_interval_int P i j \<longleftrightarrow> (\<forall>k \<in> {i..j}. P k)"
haftmann@37605
  6099
haftmann@37605
  6100
lemma [code]:
haftmann@37605
  6101
  "all_interval_int P i j \<longleftrightarrow> i > j \<or> P i \<and> all_interval_int P (i + 1) j"
haftmann@37605
  6102
proof -
haftmann@37605
  6103
  have *: "\<And>k. P i \<Longrightarrow> \<forall>k\<in>{i+1..j}. P k \<Longrightarrow> i \<le> k \<Longrightarrow> k \<le> j \<Longrightarrow> P k"
haftmann@37605
  6104
  proof -
haftmann@37605
  6105
    fix k
haftmann@37605
  6106
    assume "P i" "\<forall>k\<in>{i+1..j}. P k" "i \<le> k" "k \<le> j"
haftmann@37605
  6107
    then show "P k" by (cases "k = i") simp_all
haftmann@37605
  6108
  qed
haftmann@37605
  6109
  show ?thesis by (auto simp add: all_interval_int_def intro: *)
haftmann@37605
  6110
qed
haftmann@37605
  6111
haftmann@37605
  6112
lemma list_all_iff_all_interval_int [code_unfold]:
haftmann@37605
  6113
  "list_all P [i..j] \<longleftrightarrow> all_interval_int P i j"
haftmann@37605
  6114
  by (simp add: list_all_iff all_interval_int_def)
haftmann@37605
  6115
haftmann@37605
  6116
lemma list_ex_iff_not_all_inverval_int [code_unfold]:
haftmann@37605
  6117
  "list_ex P [i..j] \<longleftrightarrow> \<not> (all_interval_int (Not \<circ> P) i j)"
haftmann@37605
  6118
  by (simp add: list_ex_iff all_interval_int_def)
haftmann@37605
  6119
Andreas@50823
  6120
text {* optimized code (tail-recursive) for @{term length} *}
Andreas@50823
  6121
Andreas@50823
  6122
definition gen_length :: "nat \<Rightarrow> 'a list \<Rightarrow> nat"
Andreas@50823
  6123
where "gen_length n xs = n + length xs"
Andreas@50823
  6124
Andreas@50823
  6125
lemma gen_length_code [code]:
Andreas@50823
  6126
  "gen_length n [] = n"
Andreas@50823
  6127
  "gen_length n (x # xs) = gen_length (Suc n) xs"
Andreas@50823
  6128
by(simp_all add: gen_length_def)
Andreas@50823
  6129
Andreas@50823
  6130
declare list.size(3-4)[code del]
Andreas@50823
  6131
Andreas@50823
  6132
lemma length_code [code]: "length = gen_length 0"
Andreas@50823
  6133
by(simp add: gen_length_def fun_eq_iff)
Andreas@50823
  6134
Andreas@50823
  6135
hide_const (open) member null maps map_filter all_interval_nat all_interval_int gen_length
haftmann@37605
  6136
haftmann@50963
  6137
haftmann@37605
  6138
subsubsection {* Pretty lists *}
berghofe@15064
  6139
wenzelm@51437
  6140
ML {*
wenzelm@51437
  6141
(* Code generation for list literals. *)
wenzelm@51437
  6142
wenzelm@51437
  6143
signature LIST_CODE =
wenzelm@51437
  6144
sig
wenzelm@51437
  6145
  val implode_list: string -> string -> Code_Thingol.iterm -> Code_Thingol.iterm list option
wenzelm@51437
  6146
  val default_list: int * string
wenzelm@51437
  6147
    -> (Code_Printer.fixity -> Code_Thingol.iterm -> Pretty.T)
wenzelm@51437
  6148
    -> Code_Printer.fixity -> Code_Thingol.iterm -> Code_Thingol.iterm -> Pretty.T
wenzelm@51437
  6149
  val add_literal_list: string -> theory -> theory
wenzelm@51437
  6150
end;
wenzelm@51437
  6151
wenzelm@51437
  6152
structure List_Code : LIST_CODE =
wenzelm@51437
  6153
struct
wenzelm@51437
  6154
wenzelm@51437
  6155
open Basic_Code_Thingol;
wenzelm@51437
  6156
wenzelm@51437
  6157
fun implode_list nil' cons' t =
wenzelm@51437
  6158
  let
wenzelm@51437
  6159
    fun dest_cons (IConst { name = c, ... } `$ t1 `$ t2) =
wenzelm@51437
  6160
          if c = cons'
wenzelm@51437
  6161
          then SOME (t1, t2)
wenzelm@51437
  6162
          else NONE
wenzelm@51437
  6163
      | dest_cons _ = NONE;
wenzelm@51437
  6164
    val (ts, t') = Code_Thingol.unfoldr dest_cons t;
wenzelm@51437
  6165
  in case t'
wenzelm@51437
  6166
   of IConst { name = c, ... } => if c = nil' then SOME ts else NONE
wenzelm@51437
  6167
    | _ => NONE
wenzelm@51437
  6168
  end;
wenzelm@51437
  6169
wenzelm@51437
  6170
fun default_list (target_fxy, target_cons) pr fxy t1 t2 =
wenzelm@51437
  6171
  Code_Printer.brackify_infix (target_fxy, Code_Printer.R) fxy (
wenzelm@51437
  6172
    pr (Code_Printer.INFX (target_fxy, Code_Printer.X)) t1,
wenzelm@51437
  6173
    Code_Printer.str target_cons,
wenzelm@51437
  6174
    pr (Code_Printer.INFX (target_fxy, Code_Printer.R)) t2
wenzelm@51437
  6175
  );
wenzelm@51437
  6176
wenzelm@51437
  6177
fun add_literal_list target =
wenzelm@51437
  6178
  let
wenzelm@51437
  6179
    fun pretty literals [nil', cons'] pr thm vars fxy [(t1, _), (t2, _)] =
wenzelm@51437
  6180
      case Option.map (cons t1) (implode_list nil' cons' t2)
wenzelm@51437
  6181
       of SOME ts =>
wenzelm@51437
  6182
            Code_Printer.literal_list literals (map (pr vars Code_Printer.NOBR) ts)
wenzelm@51437
  6183
        | NONE =>
wenzelm@51437
  6184
            default_list (Code_Printer.infix_cons literals) (pr vars) fxy t1 t2;
haftmann@53572
  6185
  in
haftmann@53572
  6186
    Code_Target.set_printings (Code_Symbol.Constant (@{const_name Cons},
haftmann@53572
  6187
      [(target, SOME (Code_Printer.complex_const_syntax (2, ([@{const_name Nil}, @{const_name Cons}], pretty))))]))
wenzelm@51437
  6188
  end
wenzelm@51437
  6189
wenzelm@51437
  6190
end;
wenzelm@51437
  6191
*}
haftmann@31055
  6192
haftmann@53572
  6193
code_printing
haftmann@53572
  6194
  type_constructor list \<rightharpoonup>
haftmann@53572
  6195
    (SML) "_ list"
haftmann@53572
  6196
    and (OCaml) "_ list"
haftmann@53572
  6197
    and (Haskell) "![(_)]"
haftmann@53572
  6198
    and (Scala) "List[(_)]"
haftmann@53572
  6199
| constant Nil \<rightharpoonup>
haftmann@53572
  6200
    (SML) "[]"
haftmann@53572
  6201
    and (OCaml) "[]"
haftmann@53572
  6202
    and (Haskell) "[]"
haftmann@53572
  6203
    and (Scala) "!Nil"
haftmann@53572
  6204
| class_instance list :: equal \<rightharpoonup>
haftmann@53572
  6205
    (Haskell) -
haftmann@53572
  6206
| constant "HOL.equal :: 'a list \<Rightarrow> 'a list \<Rightarrow> bool" \<rightharpoonup>
haftmann@53572
  6207
    (Haskell) infix 4 "=="
haftmann@53572
  6208
haftmann@53572
  6209
setup {* fold (List_Code.add_literal_list) ["SML", "OCaml", "Haskell", "Scala"] *}
haftmann@31048
  6210
haftmann@31048
  6211
code_reserved SML
haftmann@31048
  6212
  list
haftmann@31048
  6213
haftmann@31048
  6214
code_reserved OCaml
haftmann@31048
  6215
  list
haftmann@31048
  6216
haftmann@21061
  6217
haftmann@37399
  6218
subsubsection {* Use convenient predefined operations *}
haftmann@37399
  6219
haftmann@53572
  6220
code_printing
haftmann@53572
  6221
  constant "op @" \<rightharpoonup>
haftmann@53572
  6222
    (SML) infixr 7 "@"
haftmann@53572
  6223
    and (OCaml) infixr 6 "@"
haftmann@53572
  6224
    and (Haskell) infixr 5 "++"
haftmann@53572
  6225
    and (Scala) infixl 7 "++"
haftmann@53572
  6226
| constant map \<rightharpoonup>
haftmann@53572
  6227
    (Haskell) "map"
haftmann@53572
  6228
| constant filter \<rightharpoonup>
haftmann@53572
  6229
    (Haskell) "filter"
haftmann@53572
  6230
| constant concat \<rightharpoonup>
haftmann@53572
  6231
    (Haskell) "concat"
haftmann@53572
  6232
| constant List.maps \<rightharpoonup>
haftmann@53572
  6233
    (Haskell) "concatMap"
haftmann@53572
  6234
| constant rev \<rightharpoonup>
haftmann@53572
  6235
    (Haskell) "reverse"
haftmann@53572
  6236
| constant zip \<rightharpoonup>
haftmann@53572
  6237
    (Haskell) "zip"
haftmann@53572
  6238
| constant List.null \<rightharpoonup>
haftmann@53572
  6239
    (Haskell) "null"
haftmann@53572
  6240
| constant takeWhile \<rightharpoonup>
haftmann@53572
  6241
    (Haskell) "takeWhile"
haftmann@53572
  6242
| constant dropWhile \<rightharpoonup>
haftmann@53572
  6243
    (Haskell) "dropWhile"
haftmann@53572
  6244
| constant list_all \<rightharpoonup>
haftmann@53572
  6245
    (Haskell) "all"
haftmann@53572
  6246
| constant list_ex \<rightharpoonup>
haftmann@53572
  6247
    (Haskell) "any"
haftmann@37605
  6248
haftmann@47018
  6249
haftmann@47018
  6250
subsubsection {* Implementation of sets by lists *}
haftmann@47018
  6251
haftmann@47018
  6252
lemma is_empty_set [code]:
haftmann@47018
  6253
  "Set.is_empty (set xs) \<longleftrightarrow> List.null xs"
haftmann@47018
  6254
  by (simp add: Set.is_empty_def null_def)
haftmann@47018
  6255
haftmann@47018
  6256
lemma empty_set [code]:
haftmann@47018
  6257
  "{} = set []"
haftmann@47018
  6258
  by simp
haftmann@47018
  6259
haftmann@47027
  6260
lemma UNIV_coset [code]:
haftmann@47027
  6261
  "UNIV = List.coset []"
haftmann@47027
  6262
  by simp
haftmann@47027
  6263
haftmann@47027
  6264
lemma compl_set [code]:
haftmann@47027
  6265
  "- set xs = List.coset xs"
haftmann@47027
  6266
  by simp
haftmann@47027
  6267
haftmann@47027
  6268
lemma compl_coset [code]:
haftmann@47027
  6269
  "- List.coset xs = set xs"
haftmann@47027
  6270
  by simp
haftmann@47027
  6271
haftmann@47018
  6272
lemma [code]:
haftmann@47018
  6273
  "x \<in> set xs \<longleftrightarrow> List.member xs x"
haftmann@47018
  6274
  "x \<in> List.coset xs \<longleftrightarrow> \<not> List.member xs x"
haftmann@47018
  6275
  by (simp_all add: member_def)
haftmann@47018
  6276
haftmann@47018
  6277
lemma insert_code [code]:
haftmann@47018
  6278
  "insert x (set xs) = set (List.insert x xs)"
haftmann@47018
  6279
  "insert x (List.coset xs) = List.coset (removeAll x xs)"
haftmann@47018
  6280
  by simp_all
haftmann@47018
  6281
haftmann@47018
  6282
lemma remove_code [code]:
haftmann@47018
  6283
  "Set.remove x (set xs) = set (removeAll x xs)"
haftmann@47018
  6284
  "Set.remove x (List.coset xs) = List.coset (List.insert x xs)"
haftmann@47018
  6285
  by (simp_all add: remove_def Compl_insert)
haftmann@47018
  6286
kuncar@50772
  6287
lemma filter_set [code]:
kuncar@50772
  6288
  "Set.filter P (set xs) = set (filter P xs)"
haftmann@47027
  6289
  by auto
haftmann@47027
  6290
haftmann@47027
  6291
lemma image_set [code]:
haftmann@47027
  6292
  "image f (set xs) = set (map f xs)"
haftmann@47027
  6293
  by simp
haftmann@47027
  6294
haftmann@48260
  6295
lemma subset_code [code]:
haftmann@48260
  6296
  "set xs \<le> B \<longleftrightarrow> (\<forall>x\<in>set xs. x \<in> B)"
haftmann@48260
  6297
  "A \<le> List.coset ys \<longleftrightarrow> (\<forall>y\<in>set ys. y \<notin> A)"
haftmann@48260
  6298
  "List.coset [] \<le> set [] \<longleftrightarrow> False"
haftmann@48260
  6299
  by auto
haftmann@48260
  6300
haftmann@48260
  6301
text {* A frequent case – avoid intermediate sets *}
haftmann@48260
  6302
lemma [code_unfold]:
haftmann@48260
  6303
  "set xs \<subseteq> set ys \<longleftrightarrow> list_all (\<lambda>x. x \<in> set ys) xs"
haftmann@48260
  6304
  by (auto simp: list_all_iff)
haftmann@48260
  6305
haftmann@47018
  6306
lemma Ball_set [code]:
haftmann@47018
  6307
  "Ball (set xs) P \<longleftrightarrow> list_all P xs"
haftmann@47018
  6308
  by (simp add: list_all_iff)
haftmann@47018
  6309
haftmann@47018
  6310
lemma Bex_set [code]:
haftmann@47018
  6311
  "Bex (set xs) P \<longleftrightarrow> list_ex P xs"
haftmann@47018
  6312
  by (simp add: list_ex_iff)
haftmann@47018
  6313
haftmann@47018
  6314
lemma card_set [code]:
haftmann@47018
  6315
  "card (set xs) = length (remdups xs)"
haftmann@47018
  6316
proof -
haftmann@47018
  6317
  have "card (set (remdups xs)) = length (remdups xs)"
haftmann@47018
  6318
    by (rule distinct_card) simp
haftmann@47018
  6319
  then show ?thesis by simp
haftmann@47018
  6320
qed
haftmann@47018
  6321
haftmann@47027
  6322
lemma the_elem_set [code]:
haftmann@47027
  6323
  "the_elem (set [x]) = x"
haftmann@47027
  6324
  by simp
haftmann@47027
  6325
haftmann@47027
  6326
lemma Pow_set [code]:
haftmann@47027
  6327
  "Pow (set []) = {{}}"
haftmann@47027
  6328
  "Pow (set (x # xs)) = (let A = Pow (set xs) in A \<union> insert x ` A)"
haftmann@47027
  6329
  by (simp_all add: Pow_insert Let_def)
haftmann@47027
  6330
bulwahn@47211
  6331
lemma setsum_code [code]:
bulwahn@47211
  6332
  "setsum f (set xs) = listsum (map f (remdups xs))"
bulwahn@47211
  6333
by (simp add: listsum_distinct_conv_setsum_set)
haftmann@47018
  6334
bulwahn@47252
  6335
definition map_project :: "('a \<Rightarrow> 'b option) \<Rightarrow> 'a set \<Rightarrow> 'b set" where
bulwahn@47252
  6336
  "map_project f A = {b. \<exists> a \<in> A. f a = Some b}"
bulwahn@47252
  6337
bulwahn@47252
  6338
lemma [code]:
bulwahn@47252
  6339
  "map_project f (set xs) = set (List.map_filter f xs)"
haftmann@48260
  6340
  by (auto simp add: map_project_def map_filter_def image_def)
bulwahn@47252
  6341
bulwahn@47252
  6342
hide_const (open) map_project
bulwahn@47252
  6343
haftmann@50963
  6344
haftmann@47018
  6345
text {* Operations on relations *}
haftmann@47018
  6346
haftmann@47018
  6347
lemma product_code [code]:
haftmann@47018
  6348
  "Product_Type.product (set xs) (set ys) = set [(x, y). x \<leftarrow> xs, y \<leftarrow> ys]"
haftmann@47018
  6349
  by (auto simp add: Product_Type.product_def)
haftmann@47018
  6350
haftmann@47018
  6351
lemma Id_on_set [code]:
haftmann@47018
  6352
  "Id_on (set xs) = set [(x, x). x \<leftarrow> xs]"
haftmann@47018
  6353
  by (auto simp add: Id_on_def)
haftmann@47018
  6354
bulwahn@47252
  6355
lemma [code]:
bulwahn@47252
  6356
  "R `` S = List.map_project (%(x, y). if x : S then Some y else None) R"
bulwahn@47252
  6357
unfolding map_project_def by (auto split: prod.split split_if_asm)
bulwahn@47252
  6358
haftmann@47018
  6359
lemma trancl_set_ntrancl [code]:
haftmann@47018
  6360
  "trancl (set xs) = ntrancl (card (set xs) - 1) (set xs)"
haftmann@47018
  6361
  by (simp add: finite_trancl_ntranl)
haftmann@47018
  6362
griff@48301
  6363
lemma set_relcomp [code]:
haftmann@47018
  6364
  "set xys O set yzs = set ([(fst xy, snd yz). xy \<leftarrow> xys, yz \<leftarrow> yzs, snd xy = fst yz])"
haftmann@47018
  6365
  by (auto simp add: Bex_def)
haftmann@47018
  6366
haftmann@47018
  6367
lemma wf_set [code]:
haftmann@47018
  6368
  "wf (set xs) = acyclic (set xs)"
haftmann@47018
  6369
  by (simp add: wf_iff_acyclic_if_finite)
haftmann@47018
  6370
kuncar@54149
  6371
subsection {* Setup for Lifting/Transfer *}
kuncar@54149
  6372
kuncar@54149
  6373
subsubsection {* Relator and predicator properties *}
kuncar@54149
  6374
kuncar@54149
  6375
lemma list_all2_eq'[relator_eq]:
kuncar@54149
  6376
  "list_all2 (op =) = (op =)"
kuncar@54149
  6377
by (rule ext)+ (simp add: list_all2_eq)
kuncar@54149
  6378
kuncar@54149
  6379
lemma list_all2_mono'[relator_mono]:
kuncar@54149
  6380
  assumes "A \<le> B"
kuncar@54149
  6381
  shows "(list_all2 A) \<le> (list_all2 B)"
kuncar@54149
  6382
using assms by (auto intro: list_all2_mono)
kuncar@54149
  6383
kuncar@54149
  6384
lemma list_all2_OO[relator_distr]: "list_all2 A OO list_all2 B = list_all2 (A OO B)"
kuncar@54149
  6385
proof (intro ext iffI)
kuncar@54149
  6386
  fix xs ys
kuncar@54149
  6387
  assume "list_all2 (A OO B) xs ys"
kuncar@54149
  6388
  thus "(list_all2 A OO list_all2 B) xs ys"
kuncar@54149
  6389
    unfolding OO_def
kuncar@54149
  6390
    by (induct, simp, simp add: list_all2_Cons1 list_all2_Cons2, fast)
kuncar@54149
  6391
next
kuncar@54149
  6392
  fix xs ys
kuncar@54149
  6393
  assume "(list_all2 A OO list_all2 B) xs ys"
kuncar@54149
  6394
  then obtain zs where "list_all2 A xs zs" and "list_all2 B zs ys" ..
kuncar@54149
  6395
  thus "list_all2 (A OO B) xs ys"
kuncar@54149
  6396
    by (induct arbitrary: ys, simp, clarsimp simp add: list_all2_Cons1, fast)
kuncar@54149
  6397
qed
kuncar@54149
  6398
kuncar@54149
  6399
lemma Domainp_list[relator_domain]:
kuncar@54149
  6400
  assumes "Domainp A = P"
kuncar@54149
  6401
  shows "Domainp (list_all2 A) = (list_all P)"
kuncar@54149
  6402
proof -
kuncar@54149
  6403
  {
kuncar@54149
  6404
    fix x
kuncar@54149
  6405
    have *: "\<And>x. (\<exists>y. A x y) = P x" using assms unfolding Domainp_iff by blast
kuncar@54149
  6406
    have "(\<exists>y. (list_all2 A x y)) = list_all P x"
kuncar@54149
  6407
    by (induction x) (simp_all add: * list_all2_Cons1)
kuncar@54149
  6408
  }
kuncar@54149
  6409
  then show ?thesis
kuncar@54149
  6410
  unfolding Domainp_iff[abs_def]
kuncar@54149
  6411
  by (auto iff: fun_eq_iff)
kuncar@54149
  6412
qed 
kuncar@54149
  6413
kuncar@54149
  6414
lemma reflp_list_all2[reflexivity_rule]:
kuncar@54149
  6415
  assumes "reflp R"
kuncar@54149
  6416
  shows "reflp (list_all2 R)"
kuncar@54149
  6417
proof (rule reflpI)
kuncar@54149
  6418
  from assms have *: "\<And>xs. R xs xs" by (rule reflpE)
kuncar@54149
  6419
  fix xs
kuncar@54149
  6420
  show "list_all2 R xs xs"
kuncar@54149
  6421
    by (induct xs) (simp_all add: *)
kuncar@54149
  6422
qed
kuncar@54149
  6423
kuncar@54149
  6424
lemma left_total_list_all2[reflexivity_rule]:
kuncar@54149
  6425
  "left_total R \<Longrightarrow> left_total (list_all2 R)"
kuncar@54149
  6426
  unfolding left_total_def
kuncar@54149
  6427
  apply safe
kuncar@54149
  6428
  apply (rename_tac xs, induct_tac xs, simp, simp add: list_all2_Cons1)
kuncar@54149
  6429
done
kuncar@54149
  6430
kuncar@54149
  6431
lemma left_unique_list_all2 [reflexivity_rule]:
kuncar@54149
  6432
  "left_unique R \<Longrightarrow> left_unique (list_all2 R)"
kuncar@54149
  6433
  unfolding left_unique_def
kuncar@54149
  6434
  apply (subst (2) all_comm, subst (1) all_comm)
kuncar@54149
  6435
  apply (rule allI, rename_tac zs, induct_tac zs)
kuncar@54149
  6436
  apply (auto simp add: list_all2_Cons2)
kuncar@54149
  6437
  done
kuncar@54149
  6438
kuncar@54149
  6439
lemma right_total_list_all2 [transfer_rule]:
kuncar@54149
  6440
  "right_total R \<Longrightarrow> right_total (list_all2 R)"
kuncar@54149
  6441
  unfolding right_total_def
kuncar@54149
  6442
  by (rule allI, induct_tac y, simp, simp add: list_all2_Cons2)
kuncar@54149
  6443
kuncar@54149
  6444
lemma right_unique_list_all2 [transfer_rule]:
kuncar@54149
  6445
  "right_unique R \<Longrightarrow> right_unique (list_all2 R)"
kuncar@54149
  6446
  unfolding right_unique_def
kuncar@54149
  6447
  apply (rule allI, rename_tac xs, induct_tac xs)
kuncar@54149
  6448
  apply (auto simp add: list_all2_Cons1)
kuncar@54149
  6449
  done
kuncar@54149
  6450
kuncar@54149
  6451
lemma bi_total_list_all2 [transfer_rule]:
kuncar@54149
  6452
  "bi_total A \<Longrightarrow> bi_total (list_all2 A)"
kuncar@54149
  6453
  unfolding bi_total_def
kuncar@54149
  6454
  apply safe
kuncar@54149
  6455
  apply (rename_tac xs, induct_tac xs, simp, simp add: list_all2_Cons1)
kuncar@54149
  6456
  apply (rename_tac ys, induct_tac ys, simp, simp add: list_all2_Cons2)
kuncar@54149
  6457
  done
kuncar@54149
  6458
kuncar@54149
  6459
lemma bi_unique_list_all2 [transfer_rule]:
kuncar@54149
  6460
  "bi_unique A \<Longrightarrow> bi_unique (list_all2 A)"
kuncar@54149
  6461
  unfolding bi_unique_def
kuncar@54149
  6462
  apply (rule conjI)
kuncar@54149
  6463
  apply (rule allI, rename_tac xs, induct_tac xs)
kuncar@54149
  6464
  apply (simp, force simp add: list_all2_Cons1)
kuncar@54149
  6465
  apply (subst (2) all_comm, subst (1) all_comm)
kuncar@54149
  6466
  apply (rule allI, rename_tac xs, induct_tac xs)
kuncar@54149
  6467
  apply (simp, force simp add: list_all2_Cons2)
kuncar@54149
  6468
  done
kuncar@54149
  6469
kuncar@54149
  6470
lemma list_invariant_commute [invariant_commute]:
kuncar@54149
  6471
  "list_all2 (Lifting.invariant P) = Lifting.invariant (list_all P)"
kuncar@54149
  6472
  apply (simp add: fun_eq_iff list_all2_def list_all_iff Lifting.invariant_def Ball_def) 
kuncar@54149
  6473
  apply (intro allI) 
kuncar@54149
  6474
  apply (induct_tac rule: list_induct2') 
kuncar@54149
  6475
  apply simp_all 
kuncar@54149
  6476
  apply fastforce
kuncar@54149
  6477
done
kuncar@54149
  6478
kuncar@54149
  6479
subsubsection {* Quotient theorem for the Lifting package *}
kuncar@54149
  6480
kuncar@54149
  6481
lemma Quotient_list[quot_map]:
kuncar@54149
  6482
  assumes "Quotient R Abs Rep T"
kuncar@54149
  6483
  shows "Quotient (list_all2 R) (map Abs) (map Rep) (list_all2 T)"
kuncar@54149
  6484
proof (unfold Quotient_alt_def, intro conjI allI impI)
kuncar@54149
  6485
  from assms have 1: "\<And>x y. T x y \<Longrightarrow> Abs x = y"
kuncar@54149
  6486
    unfolding Quotient_alt_def by simp
kuncar@54149
  6487
  fix xs ys assume "list_all2 T xs ys" thus "map Abs xs = ys"
kuncar@54149
  6488
    by (induct, simp, simp add: 1)
kuncar@54149
  6489
next
kuncar@54149
  6490
  from assms have 2: "\<And>x. T (Rep x) x"
kuncar@54149
  6491
    unfolding Quotient_alt_def by simp
kuncar@54149
  6492
  fix xs show "list_all2 T (map Rep xs) xs"
kuncar@54149
  6493
    by (induct xs, simp, simp add: 2)
kuncar@54149
  6494
next
kuncar@54149
  6495
  from assms have 3: "\<And>x y. R x y \<longleftrightarrow> T x (Abs x) \<and> T y (Abs y) \<and> Abs x = Abs y"
kuncar@54149
  6496
    unfolding Quotient_alt_def by simp
kuncar@54149
  6497
  fix xs ys show "list_all2 R xs ys \<longleftrightarrow> list_all2 T xs (map Abs xs) \<and>
kuncar@54149
  6498
    list_all2 T ys (map Abs ys) \<and> map Abs xs = map Abs ys"
kuncar@54149
  6499
    by (induct xs ys rule: list_induct2', simp_all, metis 3)
kuncar@54149
  6500
qed
kuncar@54149
  6501
kuncar@54149
  6502
subsubsection {* Transfer rules for the Transfer package *}
kuncar@54149
  6503
kuncar@54149
  6504
context
kuncar@54149
  6505
begin
kuncar@54149
  6506
interpretation lifting_syntax .
kuncar@54149
  6507
kuncar@54149
  6508
lemma Nil_transfer [transfer_rule]: "(list_all2 A) [] []"
kuncar@54149
  6509
  by simp
kuncar@54149
  6510
kuncar@54149
  6511
lemma Cons_transfer [transfer_rule]:
kuncar@54149
  6512
  "(A ===> list_all2 A ===> list_all2 A) Cons Cons"
kuncar@54149
  6513
  unfolding fun_rel_def by simp
kuncar@54149
  6514
kuncar@54149
  6515
lemma list_case_transfer [transfer_rule]:
kuncar@54149
  6516
  "(B ===> (A ===> list_all2 A ===> B) ===> list_all2 A ===> B)
kuncar@54149
  6517
    list_case list_case"
kuncar@54149
  6518
  unfolding fun_rel_def by (simp split: list.split)
kuncar@54149
  6519
kuncar@54149
  6520
lemma list_rec_transfer [transfer_rule]:
kuncar@54149
  6521
  "(B ===> (A ===> list_all2 A ===> B ===> B) ===> list_all2 A ===> B)
kuncar@54149
  6522
    list_rec list_rec"
kuncar@54149
  6523
  unfolding fun_rel_def by (clarify, erule list_all2_induct, simp_all)
kuncar@54149
  6524
kuncar@54149
  6525
lemma tl_transfer [transfer_rule]:
kuncar@54149
  6526
  "(list_all2 A ===> list_all2 A) tl tl"
kuncar@54149
  6527
  unfolding tl_def by transfer_prover
kuncar@54149
  6528
kuncar@54149
  6529
lemma butlast_transfer [transfer_rule]:
kuncar@54149
  6530
  "(list_all2 A ===> list_all2 A) butlast butlast"
kuncar@54149
  6531
  by (rule fun_relI, erule list_all2_induct, auto)
kuncar@54149
  6532
kuncar@54149
  6533
lemma set_transfer [transfer_rule]:
kuncar@54149
  6534
  "(list_all2 A ===> set_rel A) set set"
kuncar@54149
  6535
  unfolding set_def by transfer_prover
kuncar@54149
  6536
kuncar@54149
  6537
lemma map_transfer [transfer_rule]:
kuncar@54149
  6538
  "((A ===> B) ===> list_all2 A ===> list_all2 B) map map"
kuncar@54149
  6539
  unfolding List.map_def by transfer_prover
kuncar@54149
  6540
kuncar@54149
  6541
lemma append_transfer [transfer_rule]:
kuncar@54149
  6542
  "(list_all2 A ===> list_all2 A ===> list_all2 A) append append"
kuncar@54149
  6543
  unfolding List.append_def by transfer_prover
kuncar@54149
  6544
kuncar@54149
  6545
lemma rev_transfer [transfer_rule]:
kuncar@54149
  6546
  "(list_all2 A ===> list_all2 A) rev rev"
kuncar@54149
  6547
  unfolding List.rev_def by transfer_prover
kuncar@54149
  6548
kuncar@54149
  6549
lemma filter_transfer [transfer_rule]:
kuncar@54149
  6550
  "((A ===> op =) ===> list_all2 A ===> list_all2 A) filter filter"
kuncar@54149
  6551
  unfolding List.filter_def by transfer_prover
kuncar@54149
  6552
kuncar@54149
  6553
lemma fold_transfer [transfer_rule]:
kuncar@54149
  6554
  "((A ===> B ===> B) ===> list_all2 A ===> B ===> B) fold fold"
kuncar@54149
  6555
  unfolding List.fold_def by transfer_prover
kuncar@54149
  6556
kuncar@54149
  6557
lemma foldr_transfer [transfer_rule]:
kuncar@54149
  6558
  "((A ===> B ===> B) ===> list_all2 A ===> B ===> B) foldr foldr"
kuncar@54149
  6559
  unfolding List.foldr_def by transfer_prover
kuncar@54149
  6560
kuncar@54149
  6561
lemma foldl_transfer [transfer_rule]:
kuncar@54149
  6562
  "((B ===> A ===> B) ===> B ===> list_all2 A ===> B) foldl foldl"
kuncar@54149
  6563
  unfolding List.foldl_def by transfer_prover
kuncar@54149
  6564
kuncar@54149
  6565
lemma concat_transfer [transfer_rule]:
kuncar@54149
  6566
  "(list_all2 (list_all2 A) ===> list_all2 A) concat concat"
kuncar@54149
  6567
  unfolding List.concat_def by transfer_prover
kuncar@54149
  6568
kuncar@54149
  6569
lemma drop_transfer [transfer_rule]:
kuncar@54149
  6570
  "(op = ===> list_all2 A ===> list_all2 A) drop drop"
kuncar@54149
  6571
  unfolding List.drop_def by transfer_prover
kuncar@54149
  6572
kuncar@54149
  6573
lemma take_transfer [transfer_rule]:
kuncar@54149
  6574
  "(op = ===> list_all2 A ===> list_all2 A) take take"
kuncar@54149
  6575
  unfolding List.take_def by transfer_prover
kuncar@54149
  6576
kuncar@54149
  6577
lemma list_update_transfer [transfer_rule]:
kuncar@54149
  6578
  "(list_all2 A ===> op = ===> A ===> list_all2 A) list_update list_update"
kuncar@54149
  6579
  unfolding list_update_def by transfer_prover
kuncar@54149
  6580
kuncar@54149
  6581
lemma takeWhile_transfer [transfer_rule]:
kuncar@54149
  6582
  "((A ===> op =) ===> list_all2 A ===> list_all2 A) takeWhile takeWhile"
kuncar@54149
  6583
  unfolding takeWhile_def by transfer_prover
kuncar@54149
  6584
kuncar@54149
  6585
lemma dropWhile_transfer [transfer_rule]:
kuncar@54149
  6586
  "((A ===> op =) ===> list_all2 A ===> list_all2 A) dropWhile dropWhile"
kuncar@54149
  6587
  unfolding dropWhile_def by transfer_prover
kuncar@54149
  6588
kuncar@54149
  6589
lemma zip_transfer [transfer_rule]:
kuncar@54149
  6590
  "(list_all2 A ===> list_all2 B ===> list_all2 (prod_rel A B)) zip zip"
kuncar@54149
  6591
  unfolding zip_def by transfer_prover
kuncar@54149
  6592
traytel@54858
  6593
lemma product_transfer [transfer_rule]:
traytel@54858
  6594
  "(list_all2 A ===> list_all2 B ===> list_all2 (prod_rel A B)) List.product List.product"
traytel@54858
  6595
  unfolding List.product_def by transfer_prover
traytel@54858
  6596
traytel@54858
  6597
lemma product_lists_transfer [transfer_rule]:
traytel@54858
  6598
  "(list_all2 (list_all2 A) ===> list_all2 (list_all2 A)) product_lists product_lists"
traytel@54858
  6599
  unfolding product_lists_def by transfer_prover
traytel@54858
  6600
kuncar@54149
  6601
lemma insert_transfer [transfer_rule]:
kuncar@54149
  6602
  assumes [transfer_rule]: "bi_unique A"
kuncar@54149
  6603
  shows "(A ===> list_all2 A ===> list_all2 A) List.insert List.insert"
kuncar@54149
  6604
  unfolding List.insert_def [abs_def] by transfer_prover
kuncar@54149
  6605
kuncar@54149
  6606
lemma find_transfer [transfer_rule]:
kuncar@54149
  6607
  "((A ===> op =) ===> list_all2 A ===> option_rel A) List.find List.find"
kuncar@54149
  6608
  unfolding List.find_def by transfer_prover
kuncar@54149
  6609
kuncar@54149
  6610
lemma remove1_transfer [transfer_rule]:
kuncar@54149
  6611
  assumes [transfer_rule]: "bi_unique A"
kuncar@54149
  6612
  shows "(A ===> list_all2 A ===> list_all2 A) remove1 remove1"
kuncar@54149
  6613
  unfolding remove1_def by transfer_prover
kuncar@54149
  6614
kuncar@54149
  6615
lemma removeAll_transfer [transfer_rule]:
kuncar@54149
  6616
  assumes [transfer_rule]: "bi_unique A"
kuncar@54149
  6617
  shows "(A ===> list_all2 A ===> list_all2 A) removeAll removeAll"
kuncar@54149
  6618
  unfolding removeAll_def by transfer_prover
kuncar@54149
  6619
kuncar@54149
  6620
lemma distinct_transfer [transfer_rule]:
kuncar@54149
  6621
  assumes [transfer_rule]: "bi_unique A"
kuncar@54149
  6622
  shows "(list_all2 A ===> op =) distinct distinct"
kuncar@54149
  6623
  unfolding distinct_def by transfer_prover
kuncar@54149
  6624
kuncar@54149
  6625
lemma remdups_transfer [transfer_rule]:
kuncar@54149
  6626
  assumes [transfer_rule]: "bi_unique A"
kuncar@54149
  6627
  shows "(list_all2 A ===> list_all2 A) remdups remdups"
kuncar@54149
  6628
  unfolding remdups_def by transfer_prover
kuncar@54149
  6629
traytel@54858
  6630
lemma remdups_adj_transfer [transfer_rule]:
traytel@54858
  6631
  assumes [transfer_rule]: "bi_unique A"
traytel@54858
  6632
  shows "(list_all2 A ===> list_all2 A) remdups_adj remdups_adj"
traytel@54858
  6633
  proof (rule fun_relI, erule list_all2_induct)
traytel@54858
  6634
  qed (auto simp: remdups_adj_Cons assms[unfolded bi_unique_def] split: list.splits)
traytel@54858
  6635
kuncar@54149
  6636
lemma replicate_transfer [transfer_rule]:
kuncar@54149
  6637
  "(op = ===> A ===> list_all2 A) replicate replicate"
kuncar@54149
  6638
  unfolding replicate_def by transfer_prover
kuncar@54149
  6639
kuncar@54149
  6640
lemma length_transfer [transfer_rule]:
kuncar@54149
  6641
  "(list_all2 A ===> op =) length length"
kuncar@54149
  6642
  unfolding list_size_overloaded_def by transfer_prover
kuncar@54149
  6643
kuncar@54149
  6644
lemma rotate1_transfer [transfer_rule]:
kuncar@54149
  6645
  "(list_all2 A ===> list_all2 A) rotate1 rotate1"
kuncar@54149
  6646
  unfolding rotate1_def by transfer_prover
kuncar@54149
  6647
kuncar@54149
  6648
lemma rotate_transfer [transfer_rule]:
kuncar@54149
  6649
  "(op = ===> list_all2 A ===> list_all2 A) rotate rotate"
kuncar@54149
  6650
  unfolding rotate_def [abs_def] by transfer_prover
kuncar@54149
  6651
kuncar@54149
  6652
lemma list_all2_transfer [transfer_rule]:
kuncar@54149
  6653
  "((A ===> B ===> op =) ===> list_all2 A ===> list_all2 B ===> op =)
kuncar@54149
  6654
    list_all2 list_all2"
kuncar@54149
  6655
  apply (subst (4) list_all2_def [abs_def])
kuncar@54149
  6656
  apply (subst (3) list_all2_def [abs_def])
kuncar@54149
  6657
  apply transfer_prover
kuncar@54149
  6658
  done
kuncar@54149
  6659
kuncar@54149
  6660
lemma sublist_transfer [transfer_rule]:
kuncar@54149
  6661
  "(list_all2 A ===> set_rel (op =) ===> list_all2 A) sublist sublist"
kuncar@54149
  6662
  unfolding sublist_def [abs_def] by transfer_prover
kuncar@54149
  6663
kuncar@54149
  6664
lemma partition_transfer [transfer_rule]:
kuncar@54149
  6665
  "((A ===> op =) ===> list_all2 A ===> prod_rel (list_all2 A) (list_all2 A))
kuncar@54149
  6666
    partition partition"
kuncar@54149
  6667
  unfolding partition_def by transfer_prover
kuncar@54149
  6668
kuncar@54149
  6669
lemma lists_transfer [transfer_rule]:
kuncar@54149
  6670
  "(set_rel A ===> set_rel (list_all2 A)) lists lists"
kuncar@54149
  6671
  apply (rule fun_relI, rule set_relI)
kuncar@54149
  6672
  apply (erule lists.induct, simp)
kuncar@54149
  6673
  apply (simp only: set_rel_def list_all2_Cons1, metis lists.Cons)
kuncar@54149
  6674
  apply (erule lists.induct, simp)
kuncar@54149
  6675
  apply (simp only: set_rel_def list_all2_Cons2, metis lists.Cons)
kuncar@54149
  6676
  done
kuncar@54149
  6677
kuncar@54149
  6678
lemma set_Cons_transfer [transfer_rule]:
kuncar@54149
  6679
  "(set_rel A ===> set_rel (list_all2 A) ===> set_rel (list_all2 A))
kuncar@54149
  6680
    set_Cons set_Cons"
kuncar@54149
  6681
  unfolding fun_rel_def set_rel_def set_Cons_def
kuncar@54149
  6682
  apply safe
kuncar@54149
  6683
  apply (simp add: list_all2_Cons1, fast)
kuncar@54149
  6684
  apply (simp add: list_all2_Cons2, fast)
kuncar@54149
  6685
  done
kuncar@54149
  6686
kuncar@54149
  6687
lemma listset_transfer [transfer_rule]:
kuncar@54149
  6688
  "(list_all2 (set_rel A) ===> set_rel (list_all2 A)) listset listset"
kuncar@54149
  6689
  unfolding listset_def by transfer_prover
kuncar@54149
  6690
kuncar@54149
  6691
lemma null_transfer [transfer_rule]:
kuncar@54149
  6692
  "(list_all2 A ===> op =) List.null List.null"
kuncar@54149
  6693
  unfolding fun_rel_def List.null_def by auto
kuncar@54149
  6694
kuncar@54149
  6695
lemma list_all_transfer [transfer_rule]:
kuncar@54149
  6696
  "((A ===> op =) ===> list_all2 A ===> op =) list_all list_all"
kuncar@54149
  6697
  unfolding list_all_iff [abs_def] by transfer_prover
kuncar@54149
  6698
kuncar@54149
  6699
lemma list_ex_transfer [transfer_rule]:
kuncar@54149
  6700
  "((A ===> op =) ===> list_all2 A ===> op =) list_ex list_ex"
kuncar@54149
  6701
  unfolding list_ex_iff [abs_def] by transfer_prover
kuncar@54149
  6702
kuncar@54149
  6703
lemma splice_transfer [transfer_rule]:
kuncar@54149
  6704
  "(list_all2 A ===> list_all2 A ===> list_all2 A) splice splice"
kuncar@54149
  6705
  apply (rule fun_relI, erule list_all2_induct, simp add: fun_rel_def, simp)
kuncar@54149
  6706
  apply (rule fun_relI)
kuncar@54149
  6707
  apply (erule_tac xs=x in list_all2_induct, simp, simp add: fun_rel_def)
kuncar@54149
  6708
  done
kuncar@54149
  6709
kuncar@54149
  6710
lemma listsum_transfer[transfer_rule]:
kuncar@54149
  6711
  assumes [transfer_rule]: "A 0 0"
kuncar@54149
  6712
  assumes [transfer_rule]: "(A ===> A ===> A) op + op +"
kuncar@54149
  6713
  shows "(list_all2 A ===> A) listsum listsum"
kuncar@54149
  6714
  unfolding listsum_def[abs_def]
kuncar@54149
  6715
  by transfer_prover
kuncar@54149
  6716
wenzelm@23388
  6717
end
haftmann@48259
  6718
kuncar@54149
  6719
end