-
Notifications
You must be signed in to change notification settings - Fork 546
/
Copy pathLemmas.lean
3831 lines (3018 loc) · 148 KB
/
Lemmas.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/-
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro
-/
prelude
import Init.Data.Bool
import Init.Data.Option.Lemmas
import Init.Data.List.BasicAux
import Init.Data.List.Control
import Init.PropLemmas
import Init.Control.Lawful.Basic
import Init.Hints
/-! # Theorems about `List` operations.
For each `List` operation, we would like theorems describing the following, when relevant:
* if it is a "convenience" function, a `@[simp]` lemma reducing it to more basic operations
(e.g. `List.partition_eq_filter_filter`), and otherwise:
* any special cases of equational lemmas that require additional hypotheses
* lemmas for special cases of the arguments (e.g. `List.map_id`)
* the length of the result `(f L).length`
* the `i`-th element, described via `(f L)[i]` and/or `(f L)[i]?` (these should typically be `@[simp]`)
* consequences for `f L` of the fact `x ∈ L` or `x ∉ L`
* conditions characterising `x ∈ f L` (often but not always `@[simp]`)
* injectivity statements, or congruence statements of the form `p L M → f L = f M`.
* conditions characterising the result, i.e. of the form `f L = M ↔ p M` for some predicate `p`,
along with special cases of `M` (e.g. `List.append_eq_nil : L ++ M = [] ↔ L = [] ∧ M = []`)
* negative characterisations are also useful, e.g. `List.cons_ne_nil`
* interactions with all previously described `List` operations where possible
(some of these should be `@[simp]`, particularly if the result can be described by a single operation)
* characterising `(∀ (i) (_ : i ∈ f L), P i)`, for some predicate `P`
Of course for any individual operation, not all of these will be relevant or helpful, so some judgement is required.
General principles for `simp` normal forms for `List` operations:
* Conversion operations (e.g. `toArray`, or `length`) should be moved inwards aggressively,
to make the conversion effective.
* Similarly, operation which work on elements should be moved inwards in preference to
"structural" operations on the list, e.g. we prefer to simplify
`List.map f (L ++ M) ~> (List.map f L) ++ (List.map f M)`,
`List.map f L.reverse ~> (List.map f L).reverse`, and
`List.map f (L.take n) ~> (List.map f L).take n`.
* Arithmetic operations are "light", so e.g. we prefer to simplify `drop i (drop j L)` to `drop (i + j) L`,
rather than the other way round.
* Function compositions are "light", so we prefer to simplify `(L.map f).map g` to `L.map (g ∘ f)`.
* We try to avoid non-linear left hand sides (i.e. with subexpressions appearing multiple times),
but this is only a weak preference.
* Generally, we prefer that the right hand side does not introduce duplication,
however generally duplication of higher order arguments (functions, predicates, etc) is allowed,
as we expect to be able to compute these once they reach ground terms.
-/
namespace List
open Nat
/-! ## Preliminaries -/
-- We may want to replace these `simp` attributes with explicit equational lemmas,
-- as we already have for all the non-monadic functions.
attribute [simp] mapA forA filterAuxM firstM anyM allM findM? findSomeM?
-- Previously `range.loop`, `mapM.loop`, `filterMapM.loop`, `forIn.loop`, `forIn'.loop`
-- had attribute `@[simp]`.
-- We don't currently provide simp lemmas,
-- as this is an internal implementation and they don't seem to be needed.
/-! ### cons -/
theorem cons_ne_nil (a : α) (l : List α) : a :: l ≠ [] := nofun
@[simp]
theorem cons_ne_self (a : α) (l : List α) : a :: l ≠ l := mt (congrArg length) (Nat.succ_ne_self _)
theorem head_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : h₁ = h₂ := (cons.inj H).1
theorem tail_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂ := (cons.inj H).2
theorem cons_inj_right (a : α) {l l' : List α} : a :: l = a :: l' ↔ l = l' :=
⟨tail_eq_of_cons_eq, congrArg _⟩
@[deprecated (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' ↔ a = b ∧ l = l' :=
List.cons.injEq .. ▸ .rfl
theorem exists_cons_of_ne_nil : ∀ {l : List α}, l ≠ [] → ∃ b L, l = b :: L
| c :: l', _ => ⟨c, l', rfl⟩
/-! ### length -/
theorem eq_nil_of_length_eq_zero (_ : length l = 0) : l = [] := match l with | [] => rfl
theorem ne_nil_of_length_eq_add_one (_ : length l = n + 1) : l ≠ [] := fun _ => nomatch l
@[deprecated ne_nil_of_length_eq_add_one (since := "2024-06-16")]
abbrev ne_nil_of_length_eq_succ := @ne_nil_of_length_eq_add_one
theorem ne_nil_of_length_pos (_ : 0 < length l) : l ≠ [] := fun _ => nomatch l
@[simp] theorem length_eq_zero : length l = 0 ↔ l = [] :=
⟨eq_nil_of_length_eq_zero, fun h => h ▸ rfl⟩
theorem length_pos_of_mem {a : α} : ∀ {l : List α}, a ∈ l → 0 < length l
| _::_, _ => Nat.zero_lt_succ _
theorem exists_mem_of_length_pos : ∀ {l : List α}, 0 < length l → ∃ a, a ∈ l
| _::_, _ => ⟨_, .head ..⟩
theorem length_pos_iff_exists_mem {l : List α} : 0 < length l ↔ ∃ a, a ∈ l :=
⟨exists_mem_of_length_pos, fun ⟨_, h⟩ => length_pos_of_mem h⟩
theorem exists_cons_of_length_pos : ∀ {l : List α}, 0 < l.length → ∃ h t, l = h :: t
| _::_, _ => ⟨_, _, rfl⟩
theorem length_pos_iff_exists_cons :
∀ {l : List α}, 0 < l.length ↔ ∃ h t, l = h :: t :=
⟨exists_cons_of_length_pos, fun ⟨_, _, eq⟩ => eq ▸ Nat.succ_pos _⟩
theorem exists_cons_of_length_eq_add_one :
∀ {l : List α}, l.length = n + 1 → ∃ h t, l = h :: t
| _::_, _ => ⟨_, _, rfl⟩
theorem length_pos {l : List α} : 0 < length l ↔ l ≠ [] :=
Nat.pos_iff_ne_zero.trans (not_congr length_eq_zero)
theorem length_eq_one {l : List α} : length l = 1 ↔ ∃ a, l = [a] :=
⟨fun h => match l, h with | [_], _ => ⟨_, rfl⟩, fun ⟨_, h⟩ => by simp [h]⟩
/-! ### `isEmpty` -/
theorem isEmpty_iff {l : List α} : l.isEmpty ↔ l = [] := by
cases l <;> simp
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty ↔ l.length = 0 := by
rw [isEmpty_iff, length_eq_zero]
/-! ## L[i] and L[i]? -/
/-! ### `get` and `get?`.
We simplify `l.get i` to `l[i.1]'i.2` and `l.get? i` to `l[i]?`.
-/
@[simp] theorem get_cons_zero : get (a::l) (0 : Fin (l.length + 1)) = a := rfl
@[simp] theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
(a :: as).get ⟨i+1, h⟩ = as.get ⟨i, Nat.lt_of_succ_lt_succ h⟩ := rfl
@[simp] theorem get_cons_succ' {as : List α} {i : Fin as.length} :
(a :: as).get i.succ = as.get i := rfl
@[deprecated (since := "2024-07-09")]
theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl
theorem get_mk_zero : ∀ {l : List α} (h : 0 < l.length), l.get ⟨0, h⟩ = l.head (length_pos.mp h)
| _::_, _ => rfl
/--
If one has `l.get i` in an expression (with `i : Fin l.length`) and `h : l = l'`,
`rw [h]` will give a "motive it not type correct" error, as it cannot rewrite the
`i : Fin l.length` to `Fin l'.length` directly. The theorem `get_of_eq` can be used to make
such a rewrite, with `rw [get_of_eq h]`.
-/
theorem get_of_eq {l l' : List α} (h : l = l') (i : Fin l.length) :
get l i = get l' ⟨i, h ▸ i.2⟩ := by cases h; rfl
theorem get?_zero (l : List α) : l.get? 0 = l.head? := by cases l <;> rfl
theorem get?_len_le : ∀ {l : List α} {n}, length l ≤ n → l.get? n = none
| [], _, _ => rfl
| _ :: l, _+1, h => get?_len_le (l := l) <| Nat.le_of_succ_le_succ h
theorem get?_eq_get : ∀ {l : List α} {n} (h : n < l.length), l.get? n = some (get l ⟨n, h⟩)
| _ :: _, 0, _ => rfl
| _ :: l, _+1, _ => get?_eq_get (l := l) _
theorem get?_eq_some : l.get? n = some a ↔ ∃ h, get l ⟨n, h⟩ = a :=
⟨fun e =>
have : n < length l := Nat.gt_of_not_le fun hn => by cases get?_len_le hn ▸ e
⟨this, by rwa [get?_eq_get this, Option.some.injEq] at e⟩,
fun ⟨h, e⟩ => e ▸ get?_eq_get _⟩
theorem get?_eq_none : l.get? n = none ↔ length l ≤ n :=
⟨fun e => Nat.ge_of_not_lt (fun h' => by cases e ▸ get?_eq_some.2 ⟨h', rfl⟩), get?_len_le⟩
@[simp] theorem get?_eq_getElem? (l : List α) (i : Nat) : l.get? i = l[i]? := by
simp only [getElem?, decidableGetElem?]; split
· exact (get?_eq_get ‹_›)
· exact (get?_eq_none.2 <| Nat.not_lt.1 ‹_›)
@[simp] theorem get_eq_getElem (l : List α) (i : Fin l.length) : l.get i = l[i.1]'i.2 := rfl
/-! ### getD
We simplify away `getD`, replacing `getD l n a` with `(l[n]?).getD a`.
Because of this, there is only minimal API for `getD`.
-/
@[simp] theorem getD_eq_getElem?_getD (l) (n) (a : α) : getD l n a = (l[n]?).getD a := by
simp [getD]
@[deprecated getD_eq_getElem?_getD (since := "2024-06-12")]
theorem getD_eq_get? : ∀ l n (a : α), getD l n a = (get? l n).getD a := by simp
/-! ### get!
We simplify `l.get! n` to `l[n]!`.
-/
theorem get!_of_get? [Inhabited α] : ∀ {l : List α} {n}, get? l n = some a → get! l n = a
| _a::_, 0, rfl => rfl
| _::l, _+1, e => get!_of_get? (l := l) e
theorem get!_eq_getD [Inhabited α] : ∀ (l : List α) n, l.get! n = l.getD n default
| [], _ => rfl
| _a::_, 0 => rfl
| _a::l, n+1 => get!_eq_getD l n
theorem get!_len_le [Inhabited α] : ∀ {l : List α} {n}, length l ≤ n → l.get! n = (default : α)
| [], _, _ => rfl
| _ :: l, _+1, h => get!_len_le (l := l) <| Nat.le_of_succ_le_succ h
@[simp] theorem get!_eq_getElem! [Inhabited α] (l : List α) (n) : l.get! n = l[n]! := by
simp [get!_eq_getD]
rfl
/-! ### getElem! -/
@[simp] theorem getElem!_nil [Inhabited α] {n : Nat} : ([] : List α)[n]! = default := rfl
@[simp] theorem getElem!_cons_zero [Inhabited α] {l : List α} : (a::l)[0]! = a := by
rw [getElem!_pos] <;> simp
@[simp] theorem getElem!_cons_succ [Inhabited α] {l : List α} : (a::l)[n+1]! = l[n]! := by
by_cases h : n < l.length
· rw [getElem!_pos, getElem!_pos] <;> simp_all [Nat.succ_lt_succ_iff]
· rw [getElem!_neg, getElem!_neg] <;> simp_all [Nat.succ_lt_succ_iff]
/-! ### getElem? and getElem -/
@[simp] theorem getElem?_eq_getElem {l : List α} {n} (h : n < l.length) : l[n]? = some l[n] := by
simp only [← get?_eq_getElem?, get?_eq_get, h, get_eq_getElem]
theorem getElem?_eq_some {l : List α} : l[n]? = some a ↔ ∃ h : n < l.length, l[n] = a := by
simp only [← get?_eq_getElem?, get?_eq_some, get_eq_getElem]
@[simp] theorem getElem?_eq_none_iff : l[n]? = none ↔ length l ≤ n := by
simp only [← get?_eq_getElem?, get?_eq_none]
theorem getElem?_eq_none (h : length l ≤ n) : l[n]? = none := getElem?_eq_none_iff.mpr h
@[simp] theorem getElem?_nil {n : Nat} : ([] : List α)[n]? = none := rfl
theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := by simp
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[n+1]? = l[n]? := by
simp only [← get?_eq_getElem?]
rfl
theorem getElem?_len_le : ∀ {l : List α} {n}, length l ≤ n → l[n]? = none
| [], _, _ => rfl
| _ :: l, _+1, h => by
rw [getElem?_cons_succ, getElem?_len_le (l := l) <| Nat.le_of_succ_le_succ h]
/--
If one has `l[i]` in an expression and `h : l = l'`,
`rw [h]` will give a "motive it not type correct" error, as it cannot rewrite the
implicit `i < l.length` to `i < l'.length` directly. The theorem `getElem_of_eq` can be used to make
such a rewrite, with `rw [getElem_of_eq h]`.
-/
theorem getElem_of_eq {l l' : List α} (h : l = l') {i : Nat} (w : i < l.length) :
l[i] = l'[i]'(h ▸ w) := by cases h; rfl
@[simp] theorem getElem_singleton (a : α) (h : i < 1) : [a][i] = a :=
match i, h with
| 0, _ => rfl
@[deprecated getElem_singleton (since := "2024-06-12")]
theorem get_singleton (a : α) (n : Fin 1) : get [a] n = a := by simp
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos.mp h) :=
match l, h with
| _ :: _, _ => rfl
theorem getElem!_of_getElem? [Inhabited α] : ∀ {l : List α} {n : Nat}, l[n]? = some a → l[n]! = a
| _a::_, 0, _ => by
rw [getElem!_pos] <;> simp_all
| _::l, _+1, e => by
simp at e
simp_all [getElem!_of_getElem? (l := l) e]
@[ext] theorem ext_getElem? {l₁ l₂ : List α} (h : ∀ n : Nat, l₁[n]? = l₂[n]?) : l₁ = l₂ :=
ext_get? fun n => by simp_all
theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
(h : ∀ (n : Nat) (h₁ : n < l₁.length) (h₂ : n < l₂.length), l₁[n]'h₁ = l₂[n]'h₂) : l₁ = l₂ :=
ext_getElem? fun n =>
if h₁ : n < length l₁ then by
simp_all [getElem?_eq_getElem]
else by
have h₁ := Nat.le_of_not_lt h₁
rw [getElem?_len_le h₁, getElem?_len_le]; rwa [← hl]
theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
(h : ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩) : l₁ = l₂ :=
ext_getElem hl (by simp_all)
@[simp] theorem getElem_concat_length : ∀ (l : List α) (a : α) (i) (_ : i = l.length) (w), (l ++ [a])[i]'w = a
| [], a, _, h, _ => by subst h; simp
| _ :: l, a, _, h, _ => by simp [getElem_concat_length, h]
theorem getElem?_concat_length (l : List α) (a : α) : (l ++ [a])[l.length]? = some a := by
simp
@[deprecated getElem?_concat_length (since := "2024-06-12")]
theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = some a := by simp
/-! ### mem -/
@[simp] theorem not_mem_nil (a : α) : ¬ a ∈ [] := nofun
@[simp] theorem mem_cons : a ∈ (b :: l) ↔ a = b ∨ a ∈ l :=
⟨fun h => by cases h <;> simp [Membership.mem, *],
fun | Or.inl rfl => by constructor | Or.inr h => by constructor; assumption⟩
theorem mem_cons_self (a : α) (l : List α) : a ∈ a :: l := .head ..
theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a ∈ l → a ∈ y :: l := .tail _
theorem exists_mem_of_ne_nil (l : List α) (h : l ≠ []) : ∃ x, x ∈ l :=
exists_mem_of_length_pos (length_pos.2 h)
theorem eq_nil_iff_forall_not_mem {l : List α} : l = [] ↔ ∀ a, a ∉ l := by
cases l <;> simp [-not_or]
theorem eq_of_mem_singleton : a ∈ [b] → a = b
| .head .. => rfl
@[simp 1100] theorem mem_singleton {a b : α} : a ∈ [b] ↔ a = b :=
⟨eq_of_mem_singleton, (by simp [·])⟩
theorem forall_mem_cons {p : α → Prop} {a : α} {l : List α} :
(∀ x, x ∈ a :: l → p x) ↔ p a ∧ ∀ x, x ∈ l → p x :=
⟨fun H => ⟨H _ (.head ..), fun _ h => H _ (.tail _ h)⟩,
fun ⟨H₁, H₂⟩ _ => fun | .head .. => H₁ | .tail _ h => H₂ _ h⟩
@[simp]
theorem forall_mem_ne {a : α} {l : List α} : (∀ a' : α, a' ∈ l → ¬a = a') ↔ a ∉ l :=
⟨fun h m => h _ m rfl, fun h _ m e => h (e.symm ▸ m)⟩
@[simp]
theorem forall_mem_ne' {a : α} {l : List α} : (∀ a' : α, a' ∈ l → ¬a' = a) ↔ a ∉ l :=
⟨fun h m => h _ m rfl, fun h _ m e => h (e.symm ▸ m)⟩
@[simp]
theorem any_beq [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => a == x) ↔ a ∈ l := by
induction l <;> simp_all
@[simp]
theorem any_beq' [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => x == a) ↔ a ∈ l := by
induction l <;> simp_all [eq_comm (a := a)]
@[simp]
theorem all_bne [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => a != x) ↔ a ∉ l := by
induction l <;> simp_all
@[simp]
theorem all_bne' [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => x != a) ↔ a ∉ l := by
induction l <;> simp_all [eq_comm (a := a)]
theorem exists_mem_nil (p : α → Prop) : ¬ (∃ x, ∃ _ : x ∈ @nil α, p x) := nofun
theorem forall_mem_nil (p : α → Prop) : ∀ (x) (_ : x ∈ @nil α), p x := nofun
theorem exists_mem_cons {p : α → Prop} {a : α} {l : List α} :
(∃ x, ∃ _ : x ∈ a :: l, p x) ↔ p a ∨ ∃ x, ∃ _ : x ∈ l, p x := by simp
theorem forall_mem_singleton {p : α → Prop} {a : α} : (∀ (x) (_ : x ∈ [a]), p x) ↔ p a := by
simp only [mem_singleton, forall_eq]
theorem mem_nil_iff (a : α) : a ∈ ([] : List α) ↔ False := by simp
theorem mem_singleton_self (a : α) : a ∈ [a] := mem_cons_self _ _
theorem mem_of_mem_cons_of_mem : ∀ {a b : α} {l : List α}, a ∈ b :: l → b ∈ l → a ∈ l
| _, _, _, .head .., h | _, _, _, .tail _ h, _ => h
theorem eq_or_ne_mem_of_mem {a b : α} {l : List α} (h' : a ∈ b :: l) : a = b ∨ (a ≠ b ∧ a ∈ l) :=
(Classical.em _).imp_right fun h => ⟨h, (mem_cons.1 h').resolve_left h⟩
theorem ne_nil_of_mem {a : α} {l : List α} (h : a ∈ l) : l ≠ [] := by cases h <;> nofun
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
elem a as = true ↔ a ∈ as := ⟨mem_of_elem_eq_true, elem_eq_true_of_mem⟩
@[simp] theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
elem a as = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
theorem mem_of_ne_of_mem {a y : α} {l : List α} (h₁ : a ≠ y) (h₂ : a ∈ y :: l) : a ∈ l :=
Or.elim (mem_cons.mp h₂) (absurd · h₁) (·)
theorem ne_of_not_mem_cons {a b : α} {l : List α} : a ∉ b::l → a ≠ b := mt (· ▸ .head _)
theorem not_mem_of_not_mem_cons {a b : α} {l : List α} : a ∉ b::l → a ∉ l := mt (.tail _)
theorem not_mem_cons_of_ne_of_not_mem {a y : α} {l : List α} : a ≠ y → a ∉ l → a ∉ y::l :=
mt ∘ mem_of_ne_of_mem
theorem ne_and_not_mem_of_not_mem_cons {a y : α} {l : List α} : a ∉ y::l → a ≠ y ∧ a ∉ l :=
fun p => ⟨ne_of_not_mem_cons p, not_mem_of_not_mem_cons p⟩
theorem getElem_of_mem : ∀ {a} {l : List α}, a ∈ l → ∃ (n : Nat) (h : n < l.length), l[n]'h = a
| _, _ :: _, .head .. => ⟨0, Nat.succ_pos _, rfl⟩
| _, _ :: _, .tail _ m => let ⟨n, h, e⟩ := getElem_of_mem m; ⟨n+1, Nat.succ_lt_succ h, e⟩
theorem get_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, get l n = a := by
obtain ⟨n, h, e⟩ := getElem_of_mem h
exact ⟨⟨n, h⟩, e⟩
theorem getElem_mem : ∀ (l : List α) n (h : n < l.length), l[n]'h ∈ l
| _ :: _, 0, _ => .head ..
| _ :: l, _+1, _ => .tail _ (getElem_mem l ..)
theorem get_mem : ∀ (l : List α) n h, get l ⟨n, h⟩ ∈ l
| _ :: _, 0, _ => .head ..
| _ :: l, _+1, _ => .tail _ (get_mem l ..)
theorem mem_iff_getElem {a} {l : List α} : a ∈ l ↔ ∃ (n : Nat) (h : n < l.length), l[n]'h = a :=
⟨getElem_of_mem, fun ⟨_, _, e⟩ => e ▸ getElem_mem ..⟩
theorem mem_iff_get {a} {l : List α} : a ∈ l ↔ ∃ n, get l n = a :=
⟨get_of_mem, fun ⟨_, e⟩ => e ▸ get_mem ..⟩
theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n : Nat, l[n]? = some a :=
let ⟨n, _, e⟩ := getElem_of_mem h; ⟨n, e ▸ getElem?_eq_getElem _⟩
theorem get?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, l.get? n = some a :=
let ⟨⟨n, _⟩, e⟩ := get_of_mem h; ⟨n, e ▸ get?_eq_get _⟩
theorem getElem?_mem {l : List α} {n : Nat} {a : α} (e : l[n]? = some a) : a ∈ l :=
let ⟨_, e⟩ := getElem?_eq_some.1 e; e ▸ getElem_mem ..
theorem get?_mem {l : List α} {n a} (e : l.get? n = some a) : a ∈ l :=
let ⟨_, e⟩ := get?_eq_some.1 e; e ▸ get_mem ..
theorem mem_iff_getElem? {a} {l : List α} : a ∈ l ↔ ∃ n : Nat, l[n]? = some a := by
simp [getElem?_eq_some, mem_iff_getElem]
theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a := by
simp [getElem?_eq_some, Fin.exists_iff, mem_iff_get]
theorem forall_getElem (l : List α) (p : α → Prop) :
(∀ (n : Nat) h, p (l[n]'h)) ↔ ∀ a, a ∈ l → p a := by
induction l with
| nil => simp
| cons a l ih =>
simp only [length_cons, mem_cons, forall_eq_or_imp]
constructor
· intro w
constructor
· exact w 0 (by simp)
· apply ih.1
intro n h
simpa using w (n+1) (Nat.add_lt_add_right h 1)
· rintro ⟨h, w⟩
rintro (_ | n) h
· simpa
· apply w
simp only [getElem_cons_succ]
exact getElem_mem l n (lt_of_succ_lt_succ h)
@[simp] theorem decide_mem_cons [BEq α] [LawfulBEq α] {l : List α} :
decide (y ∈ a :: l) = (y == a || decide (y ∈ l)) := by
cases h : y == a <;> simp_all
/-! ### any / all -/
theorem any_eq {l : List α} : l.any p = decide (∃ x, x ∈ l ∧ p x) := by induction l <;> simp [*]
theorem all_eq {l : List α} : l.all p = decide (∀ x, x ∈ l → p x) := by induction l <;> simp [*]
@[simp] theorem any_eq_true {l : List α} : l.any p ↔ ∃ x, x ∈ l ∧ p x := by simp [any_eq]
@[simp] theorem all_eq_true {l : List α} : l.all p ↔ ∀ x, x ∈ l → p x := by simp [all_eq]
/-! ### set -/
-- As `List.set` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
@[simp] theorem set_nil (n : Nat) (a : α) : [].set n a = [] := rfl
@[simp] theorem set_cons_zero (x : α) (xs : List α) (a : α) :
(x :: xs).set 0 a = a :: xs := rfl
@[simp] theorem set_cons_succ (x : α) (xs : List α) (n : Nat) (a : α) :
(x :: xs).set (n + 1) a = x :: xs.set n a := rfl
@[simp] theorem getElem_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
(l.set i a)[i] = a :=
match l, i with
| [], _ => by
simp at h
| _ :: _, 0 => by simp
| _ :: l, i + 1 => by simp [getElem_set_eq]
@[deprecated getElem_set_eq (since := "2024-06-12")]
theorem get_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
(l.set i a).get ⟨i, h⟩ = a := by
simp
@[simp] theorem getElem?_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
(l.set i a)[i]? = some a := by
simp_all [getElem?_eq_some]
@[simp] theorem getElem_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α}
(hj : j < (l.set i a).length) :
(l.set i a)[j] = l[j]'(by simp at hj; exact hj) :=
match l, i, j with
| [], _, _ => by simp
| _ :: _, 0, 0 => by contradiction
| _ :: _, 0, _ + 1 => by simp
| _ :: _, _ + 1, 0 => by simp
| _ :: l, i + 1, j + 1 => by
have g : i ≠ j := h ∘ congrArg (· + 1)
simp [getElem_set_ne g]
@[deprecated getElem_set_ne (since := "2024-06-12")]
theorem get_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α}
(hj : j < (l.set i a).length) :
(l.set i a).get ⟨j, hj⟩ = l.get ⟨j, by simp at hj; exact hj⟩ := by
simp [h]
@[simp] theorem getElem?_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α} :
(l.set i a)[j]? = l[j]? := by
by_cases hj : j < (l.set i a).length
· rw [getElem?_eq_getElem hj, getElem?_eq_getElem (by simp_all)]
simp_all
· rw [getElem?_eq_none (by simp_all), getElem?_eq_none (by simp_all)]
theorem getElem_set {l : List α} {m n} {a} (h) :
(set l m a)[n]'h = if m = n then a else l[n]'(length_set .. ▸ h) := by
if h : m = n then
subst m; simp only [getElem_set_eq, ↓reduceIte]
else
simp [h]
@[deprecated getElem_set (since := "2024-06-12")]
theorem get_set {l : List α} {m n} {a : α} (h) :
(set l m a).get ⟨n, h⟩ = if m = n then a else l.get ⟨n, length_set .. ▸ h⟩ := by
simp [getElem_set]
theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
(l.set i a)[j]? = if i = j then if i < l.length then some a else none else l[j]? := by
if h : i = j then
subst h
rw [if_pos rfl]
split <;> rename_i h
· simp only [getElem?_set_eq (by simpa), h]
· simp_all
else
simp [h]
theorem set_eq_of_length_le {l : List α} {n : Nat} (h : l.length ≤ n) {a : α} :
l.set n a = l := by
induction l generalizing n with
| nil => simp_all
| cons a l ih =>
induction n
· simp_all
· simp only [set_cons_succ, cons.injEq, true_and]
rw [ih]
exact Nat.succ_le_succ_iff.mp h
@[simp] theorem set_eq_nil (l : List α) (n : Nat) (a : α) : l.set n a = [] ↔ l = [] := by
cases l <;> cases n <;> simp only [set]
theorem set_comm (a b : α) : ∀ {n m : Nat} (l : List α), n ≠ m →
(l.set n a).set m b = (l.set m b).set n a
| _, _, [], _ => by simp
| n+1, 0, _ :: _, _ => by simp [set]
| 0, m+1, _ :: _, _ => by simp [set]
| n+1, m+1, x :: t, h =>
congrArg _ <| set_comm a b t fun h' => h <| Nat.succ_inj'.mpr h'
@[simp]
theorem set_set (a b : α) : ∀ (l : List α) (n : Nat), (l.set n a).set n b = l.set n b
| [], _ => by simp
| _ :: _, 0 => by simp [set]
| _ :: _, _+1 => by simp [set, set_set]
theorem mem_set (l : List α) (n : Nat) (h : n < l.length) (a : α) :
a ∈ l.set n a := by
simp [mem_iff_getElem]
exact ⟨n, (by simpa using h), by simp⟩
theorem mem_or_eq_of_mem_set : ∀ {l : List α} {n : Nat} {a b : α}, a ∈ l.set n b → a ∈ l ∨ a = b
| _ :: _, 0, _, _, h => ((mem_cons ..).1 h).symm.imp_left (.tail _)
| _ :: _, _+1, _, _, .head .. => .inl (.head ..)
| _ :: _, _+1, _, _, .tail _ h => (mem_or_eq_of_mem_set h).imp_left (.tail _)
-- See also `set_eq_take_append_cons_drop` in `Init.Data.List.TakeDrop`.
/-! ### Lexicographic ordering -/
theorem lt_irrefl' [LT α] (lt_irrefl : ∀ x : α, ¬x < x) (l : List α) : ¬l < l := by
induction l with
| nil => nofun
| cons a l ih => intro
| .head _ _ h => exact lt_irrefl _ h
| .tail _ _ h => exact ih h
theorem lt_trans' [LT α] [DecidableRel (@LT.lt α _)]
(lt_trans : ∀ {x y z : α}, x < y → y < z → x < z)
(le_trans : ∀ {x y z : α}, ¬x < y → ¬y < z → ¬x < z)
{l₁ l₂ l₃ : List α} (h₁ : l₁ < l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
induction h₁ generalizing l₃ with
| nil => let _::_ := l₃; exact List.lt.nil ..
| @head a l₁ b l₂ ab =>
match h₂ with
| .head l₂ l₃ bc => exact List.lt.head _ _ (lt_trans ab bc)
| .tail _ cb ih =>
exact List.lt.head _ _ <| Decidable.by_contra (le_trans · cb ab)
| @tail a l₁ b l₂ ab ba h₁ ih2 =>
match h₂ with
| .head l₂ l₃ bc =>
exact List.lt.head _ _ <| Decidable.by_contra (le_trans ba · bc)
| .tail bc cb ih =>
exact List.lt.tail (le_trans ab bc) (le_trans cb ba) (ih2 ih)
theorem lt_antisymm' [LT α]
(lt_antisymm : ∀ {x y : α}, ¬x < y → ¬y < x → x = y)
{l₁ l₂ : List α} (h₁ : ¬l₁ < l₂) (h₂ : ¬l₂ < l₁) : l₁ = l₂ := by
induction l₁ generalizing l₂ with
| nil =>
cases l₂ with
| nil => rfl
| cons b l₂ => cases h₁ (.nil ..)
| cons a l₁ ih =>
cases l₂ with
| nil => cases h₂ (.nil ..)
| cons b l₂ =>
have ab : ¬a < b := fun ab => h₁ (.head _ _ ab)
cases lt_antisymm ab (fun ba => h₂ (.head _ _ ba))
rw [ih (fun ll => h₁ (.tail ab ab ll)) (fun ll => h₂ (.tail ab ab ll))]
/-! ### foldlM and foldrM -/
@[simp] theorem foldlM_reverse [Monad m] (l : List α) (f : β → α → m β) (b) :
l.reverse.foldlM f b = l.foldrM (fun x y => f y x) b := rfl
@[simp] theorem foldlM_append [Monad m] [LawfulMonad m] (f : β → α → m β) (b) (l l' : List α) :
(l ++ l').foldlM f b = l.foldlM f b >>= l'.foldlM f := by
induction l generalizing b <;> simp [*]
@[simp] theorem foldrM_cons [Monad m] [LawfulMonad m] (a : α) (l) (f : α → β → m β) (b) :
(a :: l).foldrM f b = l.foldrM f b >>= f a := by
simp only [foldrM]
induction l <;> simp_all
theorem foldl_eq_foldlM (f : β → α → β) (b) (l : List α) :
l.foldl f b = l.foldlM (m := Id) f b := by
induction l generalizing b <;> simp [*, foldl]
theorem foldr_eq_foldrM (f : α → β → β) (b) (l : List α) :
l.foldr f b = l.foldrM (m := Id) f b := by
induction l <;> simp [*, foldr]
/-! ### foldl and foldr -/
@[simp] theorem foldrM_append [Monad m] [LawfulMonad m] (f : α → β → m β) (b) (l l' : List α) :
(l ++ l').foldrM f b = l'.foldrM f b >>= l.foldrM f := by
induction l <;> simp [*]
@[simp] theorem foldl_append {β : Type _} (f : β → α → β) (b) (l l' : List α) :
(l ++ l').foldl f b = l'.foldl f (l.foldl f b) := by simp [foldl_eq_foldlM]
@[simp] theorem foldr_append (f : α → β → β) (b) (l l' : List α) :
(l ++ l').foldr f b = l.foldr f (l'.foldr f b) := by simp [foldr_eq_foldrM]
@[simp] theorem foldr_self_append (l : List α) : l.foldr cons l' = l ++ l' := by
induction l <;> simp [*]
theorem foldr_self (l : List α) : l.foldr cons [] = l := by simp
theorem foldl_map (f : β₁ → β₂) (g : α → β₂ → α) (l : List β₁) (init : α) :
(l.map f).foldl g init = l.foldl (fun x y => g x (f y)) init := by
induction l generalizing init <;> simp [*]
theorem foldr_map (f : α₁ → α₂) (g : α₂ → β → β) (l : List α₁) (init : β) :
(l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
induction l generalizing init <;> simp [*]
theorem foldl_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
induction l generalizing a
· simp
· simp [*, h]
theorem foldr_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
induction l generalizing a
· simp
· simp [*, h]
/-! ### getLast -/
theorem getLast_eq_getElem : ∀ (l : List α) (h : l ≠ []),
getLast l h = l[l.length - 1]'(by
match l with
| [] => contradiction
| a :: l => exact Nat.le_refl _)
| [a], h => rfl
| a :: b :: l, h => by
simp [getLast, get, Nat.succ_sub_succ, getLast_eq_getElem]
@[deprecated getLast_eq_getElem (since := "2024-07-15")]
theorem getLast_eq_get (l : List α) (h : l ≠ []) :
getLast l h = l.get ⟨l.length - 1, by
match l with
| [] => contradiction
| a :: l => exact Nat.le_refl _⟩ := by
simp [getLast_eq_getElem]
theorem getLast_cons' {a : α} {l : List α} : ∀ (h₁ : a :: l ≠ nil) (h₂ : l ≠ nil),
getLast (a :: l) h₁ = getLast l h₂ := by
induction l <;> intros; {contradiction}; rfl
theorem getLast_eq_getLastD (a l h) : @getLast α (a::l) h = getLastD l a := by
cases l <;> rfl
theorem getLastD_eq_getLast? (a l) : @getLastD α l a = (getLast? l).getD a := by
cases l <;> rfl
@[simp] theorem getLast_singleton (a h) : @getLast α [a] h = a := rfl
theorem getLast!_cons [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
simp [getLast!, getLast_eq_getLastD]
theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l
| [], h => absurd rfl h
| [_], _ => .head ..
| _::a::l, _ => .tail _ <| getLast_mem (cons_ne_nil a l)
theorem getLastD_mem_cons : ∀ (l : List α) (a : α), getLastD l a ∈ a::l
| [], _ => .head ..
| _::_, _ => .tail _ <| getLast_mem _
theorem getElem_cons_length (x : α) (xs : List α) (n : Nat) (h : n = xs.length) :
(x :: xs)[n]'(by simp [h]) = (x :: xs).getLast (cons_ne_nil x xs) := by
rw [getLast_eq_getElem]; cases h; rfl
@[deprecated getElem_cons_length (since := "2024-06-12")]
theorem get_cons_length (x : α) (xs : List α) (n : Nat) (h : n = xs.length) :
(x :: xs).get ⟨n, by simp [h]⟩ = (x :: xs).getLast (cons_ne_nil x xs) := by
simp [getElem_cons_length, h]
/-! ### getLast? -/
theorem getLast?_cons : @getLast? α (a::l) = getLastD l a := by
simp [getLast?, getLast_eq_getLastD]
@[simp] theorem getLast?_singleton (a : α) : getLast? [a] = a := rfl
theorem getLast?_eq_getLast : ∀ l h, @getLast? α l = some (getLast l h)
| [], h => nomatch h rfl
| _::_, _ => rfl
theorem getLast?_eq_getElem? : ∀ (l : List α), getLast? l = l[l.length - 1]?
| [] => rfl
| a::l => by
rw [getLast?_eq_getLast (a::l) nofun, getLast_eq_getElem, getElem?_eq_getElem]
@[deprecated getLast?_eq_getElem? (since := "2024-07-07")]
theorem getLast?_eq_get? (l : List α) : getLast? l = l.get? (l.length - 1) := by
simp [getLast?_eq_getElem?]
@[simp] theorem getLast?_concat (l : List α) : getLast? (l ++ [a]) = some a := by
simp [getLast?_eq_getElem?, Nat.succ_sub_succ]
@[simp] theorem getLastD_concat (a b l) : @getLastD α (l ++ [b]) a = b := by
rw [getLastD_eq_getLast?, getLast?_concat]; rfl
/-! ## Head and tail -/
/-! ### head -/
theorem head!_of_head? [Inhabited α] : ∀ {l : List α}, head? l = some a → head! l = a
| _a::_l, rfl => rfl
theorem head?_eq_head : ∀ l h, @head? α l = some (head l h)
| _::_, _ => rfl
theorem head?_eq_getElem? : ∀ l : List α, head? l = l[0]?
| [] => rfl
| a::l => by simp
@[simp] theorem head?_eq_none_iff : l.head? = none ↔ l = [] := by
cases l <;> simp
@[simp] theorem head_mem : ∀ {l : List α} (h : l ≠ []), head l h ∈ l
| [], h => absurd rfl h
| _::_, _ => .head ..
/-! ### headD -/
/-- `simp` unfolds `headD` in terms of `head?` and `Option.getD`. -/
@[simp] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
cases l <;> simp [headD]
/-! ### tail -/
/-- `simp` unfolds `tailD` in terms of `tail?` and `Option.getD`. -/
@[simp] theorem tailD_eq_tail? (l l' : List α) : tailD l l' = (tail? l).getD l' := by
cases l <;> rfl
/-! ## Basic operations -/
/-! ### map -/
@[simp] theorem map_id (l : List α) : map id l = l := by induction l <;> simp_all
@[simp] theorem map_id' (l : List α) : map (fun a => a) l = l := by induction l <;> simp_all
theorem map_id'' {f : α → α} (h : ∀ x, f x = x) (l : List α) : map f l = l := by
simp [show f = id from funext h]
theorem map_singleton (f : α → β) (a : α) : map f [a] = [f a] := rfl
@[simp] theorem length_map (as : List α) (f : α → β) : (as.map f).length = as.length := by
induction as with
| nil => simp [List.map]
| cons _ as ih => simp [List.map, ih]
@[simp] theorem getElem?_map (f : α → β) : ∀ (l : List α) (n : Nat), (map f l)[n]? = Option.map f l[n]?
| [], _ => rfl
| _ :: _, 0 => by simp
| _ :: l, n+1 => by simp [getElem?_map f l n]
@[deprecated getElem?_map (since := "2024-06-12")]
theorem get?_map (f : α → β) : ∀ l n, (map f l).get? n = (l.get? n).map f
| [], _ => rfl
| _ :: _, 0 => rfl
| _ :: l, n+1 => get?_map f l n
@[simp] theorem getElem_map (f : α → β) {l} {n : Nat} {h : n < (map f l).length} :
(map f l)[n] = f (l[n]'(length_map l f ▸ h)) :=
Option.some.inj <| by rw [← getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
@[deprecated getElem_map (since := "2024-06-12")]
theorem get_map (f : α → β) {l n} :
get (map f l) n = f (get l ⟨n, length_map l f ▸ n.2⟩) := by
simp
@[simp] theorem mem_map {f : α → β} : ∀ {l : List α}, b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b
| [] => by simp
| _ :: l => by simp [mem_map (l := l), eq_comm (a := b)]
theorem exists_of_mem_map (h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b := mem_map.1 h
theorem mem_map_of_mem (f : α → β) (h : a ∈ l) : f a ∈ map f l := mem_map.2 ⟨_, h, rfl⟩
@[simp] theorem map_inj_left {f g : α → β} : map f l = map g l ↔ ∀ a ∈ l, f a = g a := by
induction l <;> simp_all
theorem map_congr_left (h : ∀ a ∈ l, f a = g a) : map f l = map g l :=
map_inj_left.2 h
theorem map_inj : map f = map g ↔ f = g := by
constructor
· intro h; ext a; replace h := congrFun h [a]; simpa using h
· intro h; subst h; rfl
@[simp] theorem map_eq_nil {f : α → β} {l : List α} : map f l = [] ↔ l = [] := by
constructor <;> exact fun _ => match l with | [] => rfl
theorem eq_nil_of_map_eq_nil {f : α → β} {l : List α} (h : map f l = []) : l = [] :=
map_eq_nil.mp h
theorem map_eq_cons {f : α → β} {l : List α} :
map f l = b :: l₂ ↔ l.head?.map f = some b ∧ l.tail?.map (map f) = some l₂ := by
induction l <;> simp_all
theorem map_eq_cons' {f : α → β} {l : List α} :
map f l = b :: l₂ ↔ ∃ a l₁, l = a :: l₁ ∧ f a = b ∧ map f l₁ = l₂ := by
cases l
case nil => simp
case cons a l₁ =>
simp only [map_cons, cons.injEq]
constructor
· rintro ⟨rfl, rfl⟩
exact ⟨a, l₁, ⟨rfl, rfl⟩, ⟨rfl, rfl⟩⟩
· rintro ⟨a, l₁, ⟨rfl, rfl⟩, ⟨rfl, rfl⟩⟩
constructor <;> rfl
theorem map_eq_foldr (f : α → β) (l : List α) : map f l = foldr (fun a bs => f a :: bs) [] l := by
induction l <;> simp [*]
@[simp] theorem set_map {f : α → β} {l : List α} {n : Nat} {a : α} :
(map f l).set n (f a) = map f (l.set n a) := by
induction l generalizing n with
| nil => simp
| cons b l ih => cases n <;> simp_all
@[simp] theorem head_map (f : α → β) (l : List α) (w) :
head (map f l) w = f (head l (by simpa using w)) := by
cases l
· simp at w
· simp_all
@[simp] theorem head?_map (f : α → β) (l : List α) : head? (map f l) = (head? l).map f := by
cases l <;> rfl
@[simp] theorem headD_map (f : α → β) (l : List α) (a : α) : headD (map f l) (f a) = f (headD l a) := by
cases l <;> rfl
@[simp] theorem tail?_map (f : α → β) (l : List α) : tail? (map f l) = (tail? l).map (map f) := by
cases l <;> rfl
theorem tailD_map (f : α → β) (l : List α) (l' : List α) :
tailD (map f l) (map f l') = map f (tailD l l') := by simp
@[simp] theorem getLast_map (f : α → β) (l : List α) (h) :
getLast (map f l) h = f (getLast l (by simpa using h)) := by
cases l
· simp at h
· simp only [← getElem_cons_length _ _ _ rfl]
simp only [map_cons]
simp only [← getElem_cons_length _ _ _ rfl]
simp only [← map_cons, getElem_map]
simp
@[simp] theorem getLast?_map (f : α → β) (l : List α) : getLast? (map f l) = (getLast? l).map f := by
cases l
· simp
· rw [getLast?_eq_getLast, getLast?_eq_getLast, getLast_map] <;> simp
@[simp] theorem getLastD_map (f : α → β) (l : List α) (a : α) : getLastD (map f l) (f a) = f (getLastD l a) := by
cases l
· simp
· rw [getLastD_eq_getLast?, getLastD_eq_getLast?, getLast?_map] <;> simp
@[simp] theorem map_append (f : α → β) : ∀ l₁ l₂, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
intro l₁; induction l₁ <;> intros <;> simp_all
@[simp] theorem map_map (g : β → γ) (f : α → β) (l : List α) :
map g (map f l) = map (g ∘ f) l := by induction l <;> simp_all
theorem forall_mem_map_iff {f : α → β} {l : List α} {P : β → Prop} :
(∀ (i) (_ : i ∈ l.map f), P i) ↔ ∀ (j) (_ : j ∈ l), P (f j) := by
simp
/-! ### filter -/
@[simp] theorem filter_cons_of_pos {p : α → Bool} {a : α} {l} (pa : p a) :
filter p (a :: l) = a :: filter p l := by rw [filter, pa]
@[simp] theorem filter_cons_of_neg {p : α → Bool} {a : α} {l} (pa : ¬ p a) :
filter p (a :: l) = filter p l := by rw [filter, eq_false_of_ne_true pa]
theorem filter_cons :
(x :: xs : List α).filter p = if p x then x :: (xs.filter p) else xs.filter p := by
split <;> simp [*]
theorem length_filter_le (p : α → Bool) (l : List α) :
(l.filter p).length ≤ l.length := by
induction l with
| nil => simp
| cons a l ih =>
simp only [filter_cons, length_cons, succ_eq_add_one]
split
· simp only [length_cons, succ_eq_add_one]
exact Nat.succ_le_succ ih
· exact Nat.le_trans ih (Nat.le_add_right _ _)
@[simp]
theorem filter_eq_self {l} : filter p l = l ↔ ∀ a ∈ l, p a := by
induction l with simp
| cons a l ih =>
cases h : p a <;> simp [*]
intro h; exact Nat.lt_irrefl _ (h ▸ length_filter_le p l)
@[simp]
theorem filter_length_eq_length {l} : (filter p l).length = l.length ↔ ∀ a ∈ l, p a := by
induction l with
| nil => simp
| cons a l ih =>
simp only [filter_cons, length_cons, succ_eq_add_one, mem_cons, forall_eq_or_imp]
split <;> rename_i h
· simp_all [Nat.add_one_inj] -- Why does the simproc not fire here?
· have := Nat.ne_of_lt (Nat.lt_succ.mpr (length_filter_le p l))
simp_all
theorem mem_filter : x ∈ filter p as ↔ x ∈ as ∧ p x := by
induction as with
| nil => simp [filter]
| cons a as ih =>
by_cases h : p a
· simp_all [or_and_left]
· simp_all [or_and_right]