data.list.dedupMathlib.Data.List.Dedup

This file has been ported!

Changes since the initial port

The following section lists changes to this file in mathlib3 and mathlib4 that occured after the initial port. Most recent changes are shown first. Hovering over a commit will show all commits associated with the same mathlib3 commit.

Changes in mathlib3

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(last sync)

feat(data/list/dedup): Lemmas about list.dedup (#19142)

Basic lemmas about dedup applied with cons, nil, head, and tail.

Co-authored-by: Devon Tuma <devontuma@pop-os.localdomain>

Diff
@@ -57,8 +57,45 @@ theorem subset_dedup (l : list α) : l ⊆ dedup l :=
 
 theorem nodup_dedup : ∀ l : list α, nodup (dedup l) := pairwise_pw_filter
 
+theorem head_dedup [inhabited α] (l : list α) :
+  l.dedup.head = if l.head ∈ l.tail then l.tail.dedup.head else l.head :=
+match l with
+| [] := rfl
+| (a :: l) := by { by_cases ha : a ∈ l; simp [ha, list.dedup_cons_of_mem] }
+end
+
+theorem tail_dedup [inhabited α] (l : list α) :
+  l.dedup.tail = if l.head ∈ l.tail then l.tail.dedup.tail else l.tail.dedup :=
+match l with
+| [] := rfl
+| (a :: l) := by { by_cases ha : a ∈ l; simp [ha, list.dedup_cons_of_mem] }
+end
+
 theorem dedup_eq_self {l : list α} : dedup l = l ↔ nodup l := pw_filter_eq_self
 
+theorem dedup_eq_cons (l : list α) (a : α) (l' : list α) :
+  l.dedup = a :: l' ↔ a ∈ l ∧ a ∉ l' ∧ l.dedup.tail = l' :=
+begin
+  refine ⟨λ h, _, λ h, _⟩,
+  { refine ⟨mem_dedup.1 (h.symm ▸ mem_cons_self _ _), λ ha, _, by rw [h, tail_cons]⟩,
+    have : count a l.dedup ≤ 1 := nodup_iff_count_le_one.1 (nodup_dedup l) a,
+    rw [h, count_cons_self, add_le_iff_nonpos_left] at this,
+    exact (not_le_of_lt (count_pos.2 ha) this) },
+  { have := @cons_head_tail α ⟨a⟩ _ (ne_nil_of_mem (mem_dedup.2 h.1)),
+    have hal : a ∈ l.dedup := mem_dedup.2 h.1,
+    rw [← this, mem_cons_iff, or_iff_not_imp_right] at hal,
+    exact this ▸ h.2.2.symm ▸ (cons_eq_cons.2 ⟨(hal (h.2.2.symm ▸ h.2.1)).symm, rfl⟩) }
+end
+
+@[simp] theorem dedup_eq_nil (l : list α) : l.dedup = [] ↔ l = [] :=
+begin
+  induction l with a l hl,
+  { exact iff.rfl },
+  { by_cases h : a ∈ l,
+    { simp only [list.dedup_cons_of_mem h, hl, list.ne_nil_of_mem h] },
+    { simp only [list.dedup_cons_of_not_mem h, list.cons_ne_nil] } }
+end
+
 protected lemma nodup.dedup {l : list α} (h : l.nodup) : l.dedup = l :=
 list.dedup_eq_self.2 h
 

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

refactor(*): define list.replicate and migrate to it (#18127)

This definition differs from list.repeat by the order of arguments. The new order is in sync with the Lean 4 version.

Diff
@@ -74,11 +74,11 @@ begin
     rw [dedup_cons_of_not_mem' h, insert_of_not_mem h]]
 end
 
-lemma repeat_dedup {x : α} : ∀ {k}, k ≠ 0 → (repeat x k).dedup = [x]
+lemma replicate_dedup {x : α} : ∀ {k}, k ≠ 0 → (replicate k x).dedup = [x]
 | 0 h := (h rfl).elim
 | 1 _ := rfl
-| (n+2) _ := by rw [repeat_succ, dedup_cons_of_mem (mem_repeat.2 ⟨n.succ_ne_zero, rfl⟩),
-    repeat_dedup n.succ_ne_zero]
+| (n+2) _ := by rw [replicate_succ, dedup_cons_of_mem (mem_replicate.2 ⟨n.succ_ne_zero, rfl⟩),
+    replicate_dedup n.succ_ne_zero]
 
 lemma count_dedup (l : list α) (a : α) :
   l.dedup.count a = if a ∈ l then 1 else 0 :=

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

chore: remove uses of and.rec (#18123)
Diff
@@ -35,7 +35,7 @@ pw_filter_cons_of_pos $ by simpa only [forall_mem_ne] using h
 
 @[simp] theorem mem_dedup {a : α} {l : list α} : a ∈ dedup l ↔ a ∈ l :=
 by simpa only [dedup, forall_mem_ne, not_not] using not_congr (@forall_mem_pw_filter α (≠) _
-  (λ x y z xz, not_and_distrib.1 $ mt (and.rec eq.trans) xz) a l)
+  (λ x y z xz, not_and_distrib.1 $ mt (λ h, eq.trans h.1 h.2) xz) a l)
 
 @[simp] theorem dedup_cons_of_mem {a : α} {l : list α} (h : a ∈ l) :
   dedup (a :: l) = dedup l :=

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(first ported)

Changes in mathlib3port

mathlib3
mathlib3port
Diff
@@ -127,11 +127,11 @@ theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
   refine' ⟨fun h => _, fun h => _⟩
   · refine' ⟨mem_dedup.1 (h.symm ▸ mem_cons_self _ _), fun ha => _, by rw [h, tail_cons]⟩
     have : count a l.dedup ≤ 1 := nodup_iff_count_le_one.1 (nodup_dedup l) a
-    rw [h, count_cons_self, add_le_iff_nonpos_left] at this 
+    rw [h, count_cons_self, add_le_iff_nonpos_left] at this
     exact not_le_of_lt (count_pos.2 ha) this
   · have := @cons_head_tail α ⟨a⟩ _ (ne_nil_of_mem (mem_dedup.2 h.1))
     have hal : a ∈ l.dedup := mem_dedup.2 h.1
-    rw [← this, mem_cons_iff, Classical.or_iff_not_imp_right] at hal 
+    rw [← this, mem_cons_iff, Classical.or_iff_not_imp_right] at hal
     exact this ▸ h.2.2.symm ▸ cons_eq_cons.2 ⟨(hal (h.2.2.symm ▸ h.2.1)).symm, rfl⟩
 #align list.dedup_eq_cons List.dedup_eq_cons
 -/
@@ -206,7 +206,7 @@ theorem sum_map_count_dedup_filter_eq_countP (p : α → Prop) [DecidablePred p]
         simp [hp, count_dedup]
       · refine' trans (List.sum_eq_zero fun n hn => _) (by simp [hp])
         obtain ⟨a', ha'⟩ := List.mem_map.1 hn
-        simp only [(fun h => hp (h ▸ (List.mem_filter.1 ha'.1).2) : a' ≠ a), if_false] at ha' 
+        simp only [(fun h => hp (h ▸ (List.mem_filter.1 ha'.1).2) : a' ≠ a), if_false] at ha'
         exact ha'.2.symm
 #align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countP
 -/
Diff
@@ -131,7 +131,7 @@ theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
     exact not_le_of_lt (count_pos.2 ha) this
   · have := @cons_head_tail α ⟨a⟩ _ (ne_nil_of_mem (mem_dedup.2 h.1))
     have hal : a ∈ l.dedup := mem_dedup.2 h.1
-    rw [← this, mem_cons_iff, or_iff_not_imp_right] at hal 
+    rw [← this, mem_cons_iff, Classical.or_iff_not_imp_right] at hal 
     exact this ▸ h.2.2.symm ▸ cons_eq_cons.2 ⟨(hal (h.2.2.symm ▸ h.2.1)).symm, rfl⟩
 #align list.dedup_eq_cons List.dedup_eq_cons
 -/
Diff
@@ -3,7 +3,7 @@ Copyright (c) 2018 Mario Carneiro. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
 -/
-import Mathbin.Data.List.Nodup
+import Data.List.Nodup
 
 #align_import data.list.dedup from "leanprover-community/mathlib"@"d9e96a3e3e0894e93e10aff5244f4c96655bac1c"
 
Diff
@@ -154,11 +154,11 @@ protected theorem Nodup.dedup {l : List α} (h : l.Nodup) : l.dedup = l :=
 #align list.nodup.dedup List.Nodup.dedup
 -/
 
-#print List.dedup_idempotent /-
+#print List.dedup_idem /-
 @[simp]
-theorem dedup_idempotent {l : List α} : dedup (dedup l) = dedup l :=
-  pwFilter_idempotent
-#align list.dedup_idempotent List.dedup_idempotent
+theorem dedup_idem {l : List α} : dedup (dedup l) = dedup l :=
+  pwFilter_idem
+#align list.dedup_idempotent List.dedup_idem
 -/
 
 #print List.dedup_append /-
Diff
@@ -187,14 +187,14 @@ theorem count_dedup (l : List α) (a : α) : l.dedup.count a = if a ∈ l then 1
 #align list.count_dedup List.count_dedup
 -/
 
-#print List.sum_map_count_dedup_filter_eq_countp /-
+#print List.sum_map_count_dedup_filter_eq_countP /-
 /-- Summing the count of `x` over a list filtered by some `p` is just `countp` applied to `p` -/
-theorem sum_map_count_dedup_filter_eq_countp (p : α → Prop) [DecidablePred p] (l : List α) :
-    ((l.dedup.filterₓ p).map fun x => l.count x).Sum = l.countp p :=
+theorem sum_map_count_dedup_filter_eq_countP (p : α → Prop) [DecidablePred p] (l : List α) :
+    ((l.dedup.filterₓ p).map fun x => l.count x).Sum = l.countP p :=
   by
   induction' l with a as h
   · simp
-  · simp_rw [List.countp_cons, List.count_cons', List.sum_map_add]
+  · simp_rw [List.countP_cons, List.count_cons', List.sum_map_add]
     congr 1
     · refine' trans _ h
       by_cases ha : a ∈ as
@@ -208,7 +208,7 @@ theorem sum_map_count_dedup_filter_eq_countp (p : α → Prop) [DecidablePred p]
         obtain ⟨a', ha'⟩ := List.mem_map.1 hn
         simp only [(fun h => hp (h ▸ (List.mem_filter.1 ha'.1).2) : a' ≠ a), if_false] at ha' 
         exact ha'.2.symm
-#align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countp
+#align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countP
 -/
 
 #print List.sum_map_count_dedup_eq_length /-
Diff
@@ -2,14 +2,11 @@
 Copyright (c) 2018 Mario Carneiro. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
-
-! This file was ported from Lean 3 source module data.list.dedup
-! leanprover-community/mathlib commit d9e96a3e3e0894e93e10aff5244f4c96655bac1c
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathbin.Data.List.Nodup
 
+#align_import data.list.dedup from "leanprover-community/mathlib"@"d9e96a3e3e0894e93e10aff5244f4c96655bac1c"
+
 /-!
 # Erasure of duplicates in a list
 
Diff
@@ -99,19 +99,23 @@ theorem nodup_dedup : ∀ l : List α, Nodup (dedup l) :=
 #align list.nodup_dedup List.nodup_dedup
 -/
 
+#print List.headI_dedup /-
 theorem headI_dedup [Inhabited α] (l : List α) :
     l.dedup.headI = if l.headI ∈ l.tail then l.tail.dedup.headI else l.headI :=
   match l with
   | [] => rfl
   | a :: l => by by_cases ha : a ∈ l <;> simp [ha, List.dedup_cons_of_mem]
 #align list.head_dedup List.headI_dedup
+-/
 
+#print List.tail_dedup /-
 theorem tail_dedup [Inhabited α] (l : List α) :
     l.dedup.tail = if l.headI ∈ l.tail then l.tail.dedup.tail else l.tail.dedup :=
   match l with
   | [] => rfl
   | a :: l => by by_cases ha : a ∈ l <;> simp [ha, List.dedup_cons_of_mem]
 #align list.tail_dedup List.tail_dedup
+-/
 
 #print List.dedup_eq_self /-
 theorem dedup_eq_self {l : List α} : dedup l = l ↔ Nodup l :=
@@ -119,6 +123,7 @@ theorem dedup_eq_self {l : List α} : dedup l = l ↔ Nodup l :=
 #align list.dedup_eq_self List.dedup_eq_self
 -/
 
+#print List.dedup_eq_cons /-
 theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
     l.dedup = a :: l' ↔ a ∈ l ∧ a ∉ l' ∧ l.dedup.tail = l' :=
   by
@@ -132,7 +137,9 @@ theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
     rw [← this, mem_cons_iff, or_iff_not_imp_right] at hal 
     exact this ▸ h.2.2.symm ▸ cons_eq_cons.2 ⟨(hal (h.2.2.symm ▸ h.2.1)).symm, rfl⟩
 #align list.dedup_eq_cons List.dedup_eq_cons
+-/
 
+#print List.dedup_eq_nil /-
 @[simp]
 theorem dedup_eq_nil (l : List α) : l.dedup = [] ↔ l = [] :=
   by
@@ -142,6 +149,7 @@ theorem dedup_eq_nil (l : List α) : l.dedup = [] ↔ l = [] :=
     · simp only [List.dedup_cons_of_mem h, hl, List.ne_nil_of_mem h]
     · simp only [List.dedup_cons_of_not_mem h, List.cons_ne_nil]
 #align list.dedup_eq_nil List.dedup_eq_nil
+-/
 
 #print List.Nodup.dedup /-
 protected theorem Nodup.dedup {l : List α} (h : l.Nodup) : l.dedup = l :=
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
 
 ! This file was ported from Lean 3 source module data.list.dedup
-! leanprover-community/mathlib commit f694c7dead66f5d4c80f446c796a5aad14707f0e
+! leanprover-community/mathlib commit d9e96a3e3e0894e93e10aff5244f4c96655bac1c
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -99,12 +99,50 @@ theorem nodup_dedup : ∀ l : List α, Nodup (dedup l) :=
 #align list.nodup_dedup List.nodup_dedup
 -/
 
+theorem headI_dedup [Inhabited α] (l : List α) :
+    l.dedup.headI = if l.headI ∈ l.tail then l.tail.dedup.headI else l.headI :=
+  match l with
+  | [] => rfl
+  | a :: l => by by_cases ha : a ∈ l <;> simp [ha, List.dedup_cons_of_mem]
+#align list.head_dedup List.headI_dedup
+
+theorem tail_dedup [Inhabited α] (l : List α) :
+    l.dedup.tail = if l.headI ∈ l.tail then l.tail.dedup.tail else l.tail.dedup :=
+  match l with
+  | [] => rfl
+  | a :: l => by by_cases ha : a ∈ l <;> simp [ha, List.dedup_cons_of_mem]
+#align list.tail_dedup List.tail_dedup
+
 #print List.dedup_eq_self /-
 theorem dedup_eq_self {l : List α} : dedup l = l ↔ Nodup l :=
   pwFilter_eq_self
 #align list.dedup_eq_self List.dedup_eq_self
 -/
 
+theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
+    l.dedup = a :: l' ↔ a ∈ l ∧ a ∉ l' ∧ l.dedup.tail = l' :=
+  by
+  refine' ⟨fun h => _, fun h => _⟩
+  · refine' ⟨mem_dedup.1 (h.symm ▸ mem_cons_self _ _), fun ha => _, by rw [h, tail_cons]⟩
+    have : count a l.dedup ≤ 1 := nodup_iff_count_le_one.1 (nodup_dedup l) a
+    rw [h, count_cons_self, add_le_iff_nonpos_left] at this 
+    exact not_le_of_lt (count_pos.2 ha) this
+  · have := @cons_head_tail α ⟨a⟩ _ (ne_nil_of_mem (mem_dedup.2 h.1))
+    have hal : a ∈ l.dedup := mem_dedup.2 h.1
+    rw [← this, mem_cons_iff, or_iff_not_imp_right] at hal 
+    exact this ▸ h.2.2.symm ▸ cons_eq_cons.2 ⟨(hal (h.2.2.symm ▸ h.2.1)).symm, rfl⟩
+#align list.dedup_eq_cons List.dedup_eq_cons
+
+@[simp]
+theorem dedup_eq_nil (l : List α) : l.dedup = [] ↔ l = [] :=
+  by
+  induction' l with a l hl
+  · exact Iff.rfl
+  · by_cases h : a ∈ l
+    · simp only [List.dedup_cons_of_mem h, hl, List.ne_nil_of_mem h]
+    · simp only [List.dedup_cons_of_not_mem h, List.cons_ne_nil]
+#align list.dedup_eq_nil List.dedup_eq_nil
+
 #print List.Nodup.dedup /-
 protected theorem Nodup.dedup {l : List α} (h : l.Nodup) : l.dedup = l :=
   List.dedup_eq_self.2 h
Diff
@@ -144,6 +144,7 @@ theorem count_dedup (l : List α) (a : α) : l.dedup.count a = if a ∈ l then 1
 #align list.count_dedup List.count_dedup
 -/
 
+#print List.sum_map_count_dedup_filter_eq_countp /-
 /-- Summing the count of `x` over a list filtered by some `p` is just `countp` applied to `p` -/
 theorem sum_map_count_dedup_filter_eq_countp (p : α → Prop) [DecidablePred p] (l : List α) :
     ((l.dedup.filterₓ p).map fun x => l.count x).Sum = l.countp p :=
@@ -165,6 +166,7 @@ theorem sum_map_count_dedup_filter_eq_countp (p : α → Prop) [DecidablePred p]
         simp only [(fun h => hp (h ▸ (List.mem_filter.1 ha'.1).2) : a' ≠ a), if_false] at ha' 
         exact ha'.2.symm
 #align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countp
+-/
 
 #print List.sum_map_count_dedup_eq_length /-
 theorem sum_map_count_dedup_eq_length (l : List α) :
Diff
@@ -123,8 +123,8 @@ theorem dedup_append (l₁ l₂ : List α) : dedup (l₁ ++ l₂) = l₁ ∪ ded
   by
   induction' l₁ with a l₁ IH; · rfl; rw [cons_union, ← IH]
   show dedup (a :: (l₁ ++ l₂)) = insert a (dedup (l₁ ++ l₂))
-  by_cases a ∈ dedup (l₁ ++ l₂) <;>
-    [rw [dedup_cons_of_mem' h, insert_of_mem h];rw [dedup_cons_of_not_mem' h, insert_of_not_mem h]]
+  by_cases a ∈ dedup (l₁ ++ l₂) <;> [rw [dedup_cons_of_mem' h, insert_of_mem h];
+    rw [dedup_cons_of_not_mem' h, insert_of_not_mem h]]
 #align list.dedup_append List.dedup_append
 -/
 
@@ -162,7 +162,7 @@ theorem sum_map_count_dedup_filter_eq_countp (p : α → Prop) [DecidablePred p]
         simp [hp, count_dedup]
       · refine' trans (List.sum_eq_zero fun n hn => _) (by simp [hp])
         obtain ⟨a', ha'⟩ := List.mem_map.1 hn
-        simp only [(fun h => hp (h ▸ (List.mem_filter.1 ha'.1).2) : a' ≠ a), if_false] at ha'
+        simp only [(fun h => hp (h ▸ (List.mem_filter.1 ha'.1).2) : a' ≠ a), if_false] at ha' 
         exact ha'.2.symm
 #align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countp
 
Diff
@@ -144,12 +144,6 @@ theorem count_dedup (l : List α) (a : α) : l.dedup.count a = if a ∈ l then 1
 #align list.count_dedup List.count_dedup
 -/
 
-/- warning: list.sum_map_count_dedup_filter_eq_countp -> List.sum_map_count_dedup_filter_eq_countp is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (p : α -> Prop) [_inst_2 : DecidablePred.{succ u1} α p] (l : List.{u1} α), Eq.{1} Nat (List.sum.{0} Nat Nat.hasAdd Nat.hasZero (List.map.{u1, 0} α Nat (fun (x : α) => List.count.{u1} α (fun (a : α) (b : α) => _inst_1 a b) x l) (List.filterₓ.{u1} α p (fun (a : α) => _inst_2 a) (List.dedup.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l)))) (List.countp.{u1} α p (fun (a : α) => _inst_2 a) l)
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (p : α -> Bool) (_inst_2 : List.{u1} α), Eq.{1} Nat (List.sum.{0} Nat instAddNat (LinearOrderedCommMonoidWithZero.toZero.{0} Nat Nat.linearOrderedCommMonoidWithZero) (List.map.{u1, 0} α Nat (fun (x : α) => List.count.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) x _inst_2) (List.filter.{u1} α p (List.dedup.{u1} α (fun (a : α) (b : α) => _inst_1 a b) _inst_2)))) (List.countp.{u1} α p _inst_2)
-Case conversion may be inaccurate. Consider using '#align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countpₓ'. -/
 /-- Summing the count of `x` over a list filtered by some `p` is just `countp` applied to `p` -/
 theorem sum_map_count_dedup_filter_eq_countp (p : α → Prop) [DecidablePred p] (l : List α) :
     ((l.dedup.filterₓ p).map fun x => l.count x).Sum = l.countp p :=
Diff
@@ -123,8 +123,8 @@ theorem dedup_append (l₁ l₂ : List α) : dedup (l₁ ++ l₂) = l₁ ∪ ded
   by
   induction' l₁ with a l₁ IH; · rfl; rw [cons_union, ← IH]
   show dedup (a :: (l₁ ++ l₂)) = insert a (dedup (l₁ ++ l₂))
-  by_cases a ∈ dedup (l₁ ++ l₂) <;> [rw [dedup_cons_of_mem' h, insert_of_mem h],
-    rw [dedup_cons_of_not_mem' h, insert_of_not_mem h]]
+  by_cases a ∈ dedup (l₁ ++ l₂) <;>
+    [rw [dedup_cons_of_mem' h, insert_of_mem h];rw [dedup_cons_of_not_mem' h, insert_of_not_mem h]]
 #align list.dedup_append List.dedup_append
 -/
 
Diff
@@ -167,7 +167,7 @@ theorem sum_map_count_dedup_filter_eq_countp (p : α → Prop) [DecidablePred p]
       · refine' trans (sum_map_eq_nsmul_single a _ fun _ h _ => by simp [h]) _
         simp [hp, count_dedup]
       · refine' trans (List.sum_eq_zero fun n hn => _) (by simp [hp])
-        obtain ⟨a', ha'⟩ := List.mem_map'.1 hn
+        obtain ⟨a', ha'⟩ := List.mem_map.1 hn
         simp only [(fun h => hp (h ▸ (List.mem_filter.1 ha'.1).2) : a' ≠ a), if_false] at ha'
         exact ha'.2.symm
 #align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countp

Changes in mathlib4

mathlib3
mathlib4
chore: adapt to multiple goal linter 1 (#12338)

A PR accompanying #12339.

Zulip discussion

Diff
@@ -43,9 +43,9 @@ theorem dedup_cons_of_not_mem' {a : α} {l : List α} (h : a ∉ dedup l) :
 @[simp]
 theorem mem_dedup {a : α} {l : List α} : a ∈ dedup l ↔ a ∈ l := by
   have := not_congr (@forall_mem_pwFilter α (· ≠ ·) _ ?_ a l)
-  simpa only [dedup, forall_mem_ne, not_not] using this
-  intros x y z xz
-  exact not_and_or.1 <| mt (fun h ↦ h.1.trans h.2) xz
+  · simpa only [dedup, forall_mem_ne, not_not] using this
+  · intros x y z xz
+    exact not_and_or.1 <| mt (fun h ↦ h.1.trans h.2) xz
 #align list.mem_dedup List.mem_dedup
 
 @[simp]
chore(Data/List): Depend less on big operators (#11741)
  • Make Data.List.Count, Data.List.Dedup, Data.List.ProdSigma, Data.List.Range, Data.List.Rotate, Data.List.Zip not depend on Data.List.BigOperators.Basic.
  • As a consequence, move the big operators lemmas that were in there to Data.List.BigOperators.Basic. For the lemmas that were Nat-specific, keep a version of them in the original file but stated using Nat.sum.
  • To help with this, add Nat.sum_eq_listSum (l : List Nat) : Nat.sum l = l.sum.
Diff
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
 -/
 import Mathlib.Data.List.Nodup
-import Mathlib.Data.List.Count
 
 #align_import data.list.dedup from "leanprover-community/mathlib"@"d9e96a3e3e0894e93e10aff5244f4c96655bac1c"
 
@@ -96,9 +95,10 @@ theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
     l.dedup = a :: l' ↔ a ∈ l ∧ a ∉ l' ∧ l.dedup.tail = l' := by
   refine' ⟨fun h => _, fun h => _⟩
   · refine' ⟨mem_dedup.1 (h.symm ▸ mem_cons_self _ _), fun ha => _, by rw [h, tail_cons]⟩
+    have := count_pos_iff_mem.2 ha
     have : count a l.dedup ≤ 1 := nodup_iff_count_le_one.1 (nodup_dedup l) a
-    rw [h, count_cons_self, add_le_iff_nonpos_left] at this
-    exact not_le_of_lt (count_pos_iff_mem.2 ha) this
+    rw [h, count_cons_self] at this
+    omega
   · have := @List.cons_head!_tail α ⟨a⟩ _ (ne_nil_of_mem (mem_dedup.2 h.1))
     have hal : a ∈ l.dedup := mem_dedup.2 h.1
     rw [← this, mem_cons, or_iff_not_imp_right] at hal
@@ -144,34 +144,4 @@ theorem count_dedup (l : List α) (a : α) : l.dedup.count a = if a ∈ l then 1
   simp_rw [count_eq_of_nodup <| nodup_dedup l, mem_dedup]
 #align list.count_dedup List.count_dedup
 
-/-- Summing the count of `x` over a list filtered by some `p` is just `countP` applied to `p` -/
-theorem sum_map_count_dedup_filter_eq_countP (p : α → Bool) (l : List α) :
-    ((l.dedup.filter p).map fun x => l.count x).sum = l.countP p := by
-  induction' l with a as h
-  · simp
-  · simp_rw [List.countP_cons, List.count_cons, List.sum_map_add]
-    congr 1
-    · refine' _root_.trans _ h
-      by_cases ha : a ∈ as
-      · simp [dedup_cons_of_mem ha]
-      · simp only [dedup_cons_of_not_mem ha, List.filter]
-        match p a with
-        | true => simp only [List.map_cons, List.sum_cons, List.count_eq_zero.2 ha, zero_add]
-        | false => simp only
-    · by_cases hp : p a
-      · refine' _root_.trans (sum_map_eq_nsmul_single a _ fun _ h _ => by simp [h]) _
-        simp [hp, count_dedup]
-      · refine' _root_.trans (List.sum_eq_zero fun n hn => _) (by simp [hp])
-        obtain ⟨a', ha'⟩ := List.mem_map.1 hn
-        split_ifs at ha' with ha
-        · simp only [ha, mem_filter, mem_dedup, find?, mem_cons, true_or, hp,
-            and_false, false_and] at ha'
-        · exact ha'.2.symm
-#align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countP
-
-theorem sum_map_count_dedup_eq_length (l : List α) :
-    (l.dedup.map fun x => l.count x).sum = l.length := by
-  simpa using sum_map_count_dedup_filter_eq_countP (fun _ => True) l
-#align list.sum_map_count_dedup_eq_length List.sum_map_count_dedup_eq_length
-
 end List
chore: reduce imports (#9830)

This uses the improved shake script from #9772 to reduce imports across mathlib. The corresponding noshake.json file has been added to #9772.

Co-authored-by: Mario Carneiro <di.gama@gmail.com>

Diff
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
 -/
 import Mathlib.Data.List.Nodup
+import Mathlib.Data.List.Count
 
 #align_import data.list.dedup from "leanprover-community/mathlib"@"d9e96a3e3e0894e93e10aff5244f4c96655bac1c"
 
chore: update to std4#100 (#6743)

Std bump patch for https://github.com/leanprover/std4/pull/100

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -118,9 +118,9 @@ protected theorem Nodup.dedup {l : List α} (h : l.Nodup) : l.dedup = l :=
 #align list.nodup.dedup List.Nodup.dedup
 
 @[simp]
-theorem dedup_idempotent {l : List α} : dedup (dedup l) = dedup l :=
-  pwFilter_idempotent
-#align list.dedup_idempotent List.dedup_idempotent
+theorem dedup_idem {l : List α} : dedup (dedup l) = dedup l :=
+  pwFilter_idem
+#align list.dedup_idempotent List.dedup_idem
 
 theorem dedup_append (l₁ l₂ : List α) : dedup (l₁ ++ l₂) = l₁ ∪ dedup l₂ := by
   induction' l₁ with a l₁ IH; · rfl
chore: bump Std (#6721)

This incorporates changes from https://github.com/leanprover-community/mathlib4/pull/6575

I have also renamed Multiset.countp to Multiset.countP for consistency.

Co-authored-by: James Gallichio <jamesgallicchio@gmail.com>

Co-authored-by: James <jamesgallicchio@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -97,7 +97,7 @@ theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
   · refine' ⟨mem_dedup.1 (h.symm ▸ mem_cons_self _ _), fun ha => _, by rw [h, tail_cons]⟩
     have : count a l.dedup ≤ 1 := nodup_iff_count_le_one.1 (nodup_dedup l) a
     rw [h, count_cons_self, add_le_iff_nonpos_left] at this
-    exact not_le_of_lt (count_pos.2 ha) this
+    exact not_le_of_lt (count_pos_iff_mem.2 ha) this
   · have := @List.cons_head!_tail α ⟨a⟩ _ (ne_nil_of_mem (mem_dedup.2 h.1))
     have hal : a ∈ l.dedup := mem_dedup.2 h.1
     rw [← this, mem_cons, or_iff_not_imp_right] at hal
@@ -143,12 +143,12 @@ theorem count_dedup (l : List α) (a : α) : l.dedup.count a = if a ∈ l then 1
   simp_rw [count_eq_of_nodup <| nodup_dedup l, mem_dedup]
 #align list.count_dedup List.count_dedup
 
-/-- Summing the count of `x` over a list filtered by some `p` is just `countp` applied to `p` -/
-theorem sum_map_count_dedup_filter_eq_countp (p : α → Bool) (l : List α) :
-    ((l.dedup.filter p).map fun x => l.count x).sum = l.countp p := by
+/-- Summing the count of `x` over a list filtered by some `p` is just `countP` applied to `p` -/
+theorem sum_map_count_dedup_filter_eq_countP (p : α → Bool) (l : List α) :
+    ((l.dedup.filter p).map fun x => l.count x).sum = l.countP p := by
   induction' l with a as h
   · simp
-  · simp_rw [List.countp_cons, List.count_cons', List.sum_map_add]
+  · simp_rw [List.countP_cons, List.count_cons, List.sum_map_add]
     congr 1
     · refine' _root_.trans _ h
       by_cases ha : a ∈ as
@@ -166,11 +166,11 @@ theorem sum_map_count_dedup_filter_eq_countp (p : α → Bool) (l : List α) :
         · simp only [ha, mem_filter, mem_dedup, find?, mem_cons, true_or, hp,
             and_false, false_and] at ha'
         · exact ha'.2.symm
-#align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countp
+#align list.sum_map_count_dedup_filter_eq_countp List.sum_map_count_dedup_filter_eq_countP
 
 theorem sum_map_count_dedup_eq_length (l : List α) :
     (l.dedup.map fun x => l.count x).sum = l.length := by
-  simpa using sum_map_count_dedup_filter_eq_countp (fun _ => True) l
+  simpa using sum_map_count_dedup_filter_eq_countP (fun _ => True) l
 #align list.sum_map_count_dedup_eq_length List.sum_map_count_dedup_eq_length
 
 end List
chore: ensure all instances referred to directly have explicit names (#6423)

Per https://github.com/leanprover/lean4/issues/2343, we are going to need to change the automatic generation of instance names, as they become too long.

This PR ensures that everywhere in Mathlib that refers to an instance by name, that name is given explicitly, rather than being automatically generated.

There are four exceptions, which are now commented, with links to https://github.com/leanprover/lean4/issues/2343.

This was implemented by running Mathlib against a modified Lean that appended _ᾰ to all automatically generated names, and fixing everything.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -124,7 +124,7 @@ theorem dedup_idempotent {l : List α} : dedup (dedup l) = dedup l :=
 
 theorem dedup_append (l₁ l₂ : List α) : dedup (l₁ ++ l₂) = l₁ ∪ dedup l₂ := by
   induction' l₁ with a l₁ IH; · rfl
-  simp only [instUnionList, cons_union] at *
+  simp only [cons_union] at *
   rw [← IH, cons_append]
   by_cases h : a ∈ dedup (l₁ ++ l₂)
   · rw [dedup_cons_of_mem' h, insert_of_mem h]
chore: script to replace headers with #align_import statements (#5979)

Open in Gitpod

Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -2,14 +2,11 @@
 Copyright (c) 2018 Mario Carneiro. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
-
-! This file was ported from Lean 3 source module data.list.dedup
-! leanprover-community/mathlib commit d9e96a3e3e0894e93e10aff5244f4c96655bac1c
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathlib.Data.List.Nodup
 
+#align_import data.list.dedup from "leanprover-community/mathlib"@"d9e96a3e3e0894e93e10aff5244f4c96655bac1c"
+
 /-!
 # Erasure of duplicates in a list
 
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
 
 ! This file was ported from Lean 3 source module data.list.dedup
-! leanprover-community/mathlib commit f694c7dead66f5d4c80f446c796a5aad14707f0e
+! leanprover-community/mathlib commit d9e96a3e3e0894e93e10aff5244f4c96655bac1c
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -76,10 +76,46 @@ theorem nodup_dedup : ∀ l : List α, Nodup (dedup l) :=
   pairwise_pwFilter
 #align list.nodup_dedup List.nodup_dedup
 
+theorem headI_dedup [Inhabited α] (l : List α) :
+    l.dedup.headI = if l.headI ∈ l.tail then l.tail.dedup.headI else l.headI :=
+  match l with
+  | [] => rfl
+  | a :: l => by by_cases ha : a ∈ l <;> simp [ha, List.dedup_cons_of_mem]
+#align list.head_dedup List.headI_dedup
+
+theorem tail_dedup [Inhabited α] (l : List α) :
+    l.dedup.tail = if l.headI ∈ l.tail then l.tail.dedup.tail else l.tail.dedup :=
+  match l with
+  | [] => rfl
+  | a :: l => by by_cases ha : a ∈ l <;> simp [ha, List.dedup_cons_of_mem]
+#align list.tail_dedup List.tail_dedup
+
 theorem dedup_eq_self {l : List α} : dedup l = l ↔ Nodup l :=
   pwFilter_eq_self
 #align list.dedup_eq_self List.dedup_eq_self
 
+theorem dedup_eq_cons (l : List α) (a : α) (l' : List α) :
+    l.dedup = a :: l' ↔ a ∈ l ∧ a ∉ l' ∧ l.dedup.tail = l' := by
+  refine' ⟨fun h => _, fun h => _⟩
+  · refine' ⟨mem_dedup.1 (h.symm ▸ mem_cons_self _ _), fun ha => _, by rw [h, tail_cons]⟩
+    have : count a l.dedup ≤ 1 := nodup_iff_count_le_one.1 (nodup_dedup l) a
+    rw [h, count_cons_self, add_le_iff_nonpos_left] at this
+    exact not_le_of_lt (count_pos.2 ha) this
+  · have := @List.cons_head!_tail α ⟨a⟩ _ (ne_nil_of_mem (mem_dedup.2 h.1))
+    have hal : a ∈ l.dedup := mem_dedup.2 h.1
+    rw [← this, mem_cons, or_iff_not_imp_right] at hal
+    exact this ▸ h.2.2.symm ▸ cons_eq_cons.2 ⟨(hal (h.2.2.symm ▸ h.2.1)).symm, rfl⟩
+#align list.dedup_eq_cons List.dedup_eq_cons
+
+@[simp]
+theorem dedup_eq_nil (l : List α) : l.dedup = [] ↔ l = [] := by
+  induction' l with a l hl
+  · exact Iff.rfl
+  · by_cases h : a ∈ l
+    · simp only [List.dedup_cons_of_mem h, hl, List.ne_nil_of_mem h]
+    · simp only [List.dedup_cons_of_not_mem h, List.cons_ne_nil]
+#align list.dedup_eq_nil List.dedup_eq_nil
+
 protected theorem Nodup.dedup {l : List α} (h : l.Nodup) : l.dedup = l :=
   List.dedup_eq_self.2 h
 #align list.nodup.dedup List.Nodup.dedup
chore: fix #align lines (#3640)

This PR fixes two things:

  • Most align statements for definitions and theorems and instances that are separated by two newlines from the relevant declaration (s/\n\n#align/\n#align). This is often seen in the mathport output after ending calc blocks.
  • All remaining more-than-one-line #align statements. (This was needed for a script I wrote for #3630.)
Diff
@@ -49,7 +49,6 @@ theorem mem_dedup {a : α} {l : List α} : a ∈ dedup l ↔ a ∈ l := by
   simpa only [dedup, forall_mem_ne, not_not] using this
   intros x y z xz
   exact not_and_or.1 <| mt (fun h ↦ h.1.trans h.2) xz
-
 #align list.mem_dedup List.mem_dedup
 
 @[simp]
chore: bump Std (#3113)

Notably incorporates https://github.com/leanprover/std4/pull/98 and https://github.com/leanprover/std4/pull/109.

https://github.com/leanprover/std4/pull/98 moves a number of lemmas from Mathlib to Std, so the bump requires deleting them in Mathlib. I did check on each lemma whether its attributes were kept in the move (and gave attribute markings in Mathlib if they were not present in Std), but a reviewer may wish to re-check.

List.mem_map changed statement from b ∈ l.map f ↔ ∃ a, a ∈ l ∧ b = f a to b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b. Similarly for List.exists_of_mem_map. This was a deliberate change, so I have simply adjusted proofs (many become simpler, which supports the change). I also deleted List.mem_map', List.exists_of_mem_map', which were temporary versions in Mathlib while waiting for this change (replacing their uses with the unprimed versions).

Also, the lemma sublist_nil_iff_eq_nil seems to have been renamed to sublist_nil during the move, so I added an alias for the old name.

(another issue fixed during review by @digama0) List.Sublist.filter had an argument change from explicit to implicit. This appears to have been an oversight (cc @JamesGallicchio). I have temporarily introduced List.Sublist.filter' with the argument explicit, and replaced Mathlib uses of Sublist.filter with Sublist.filter'. Later we can fix the argument in Std, and then delete List.Sublist.filter'.

Diff
@@ -129,7 +129,7 @@ theorem sum_map_count_dedup_filter_eq_countp (p : α → Bool) (l : List α) :
       · refine' _root_.trans (sum_map_eq_nsmul_single a _ fun _ h _ => by simp [h]) _
         simp [hp, count_dedup]
       · refine' _root_.trans (List.sum_eq_zero fun n hn => _) (by simp [hp])
-        obtain ⟨a', ha'⟩ := List.mem_map'.1 hn
+        obtain ⟨a', ha'⟩ := List.mem_map.1 hn
         split_ifs at ha' with ha
         · simp only [ha, mem_filter, mem_dedup, find?, mem_cons, true_or, hp,
             and_false, false_and] at ha'
chore: add missing hypothesis names to by_cases (#2679)
Diff
@@ -93,10 +93,10 @@ theorem dedup_idempotent {l : List α} : dedup (dedup l) = dedup l :=
 theorem dedup_append (l₁ l₂ : List α) : dedup (l₁ ++ l₂) = l₁ ∪ dedup l₂ := by
   induction' l₁ with a l₁ IH; · rfl
   simp only [instUnionList, cons_union] at *
-  rw [← IH]
-  show dedup (a :: (l₁ ++ l₂)) = List.insert a (dedup (l₁ ++ l₂))
-  by_cases a ∈ dedup (l₁ ++ l₂) <;> [rw [dedup_cons_of_mem' h, insert_of_mem h],
-    rw [dedup_cons_of_not_mem' h, insert_of_not_mem h]]
+  rw [← IH, cons_append]
+  by_cases h : a ∈ dedup (l₁ ++ l₂)
+  · rw [dedup_cons_of_mem' h, insert_of_mem h]
+  · rw [dedup_cons_of_not_mem' h, insert_of_not_mem h]
 #align list.dedup_append List.dedup_append
 
 theorem replicate_dedup {x : α} : ∀ {k}, k ≠ 0 → (replicate k x).dedup = [x]
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
 
 ! This file was ported from Lean 3 source module data.list.dedup
-! leanprover-community/mathlib commit 6133ae2da6ae6693248bb5451de703f1ef154cc8
+! leanprover-community/mathlib commit f694c7dead66f5d4c80f446c796a5aad14707f0e
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
fix: to_additive translates pow to nsmul (#1502)
  • I tried translating it to smul in #715, but that was a bad decision
  • It is possible that some lemmas that want to be called smul now use nsmul. This doesn't raise an error unless they are aligned or explicitly used elsewhere.
  • Rename some lemmas from smul to nsmul.
  • Zulip

Co-authored-by: Reid Barton <rwbarton@gmail.com>

Diff
@@ -126,7 +126,7 @@ theorem sum_map_count_dedup_filter_eq_countp (p : α → Bool) (l : List α) :
         | true => simp only [List.map_cons, List.sum_cons, List.count_eq_zero.2 ha, zero_add]
         | false => simp only
     · by_cases hp : p a
-      · refine' _root_.trans (sum_map_eq_smul_single a _ fun _ h _ => by simp [h]) _
+      · refine' _root_.trans (sum_map_eq_nsmul_single a _ fun _ h _ => by simp [h]) _
         simp [hp, count_dedup]
       · refine' _root_.trans (List.sum_eq_zero fun n hn => _) (by simp [hp])
         obtain ⟨a', ha'⟩ := List.mem_map'.1 hn
chore: format by line breaks (#1523)

During porting, I usually fix the desired format we seem to want for the line breaks around by with

awk '{do {{if (match($0, "^  by$") && length(p) < 98) {p=p " by";} else {if (NR!=1) {print p}; p=$0}}} while (getline == 1) if (getline==0) print p}' Mathlib/File/Im/Working/On.lean

I noticed there are some more files that slipped through.

This pull request is the result of running this command:

grep -lr "^  by\$" Mathlib | xargs -n 1 awk -i inplace '{do {{if (match($0, "^  by$") && length(p) < 98 && not (match(p, "^[ \t]*--"))) {p=p " by";} else {if (NR!=1) {print p}; p=$0}}} while (getline == 1) if (getline==0) print p}'

Co-authored-by: Moritz Firsching <firsching@google.com>

Diff
@@ -90,8 +90,7 @@ theorem dedup_idempotent {l : List α} : dedup (dedup l) = dedup l :=
   pwFilter_idempotent
 #align list.dedup_idempotent List.dedup_idempotent
 
-theorem dedup_append (l₁ l₂ : List α) : dedup (l₁ ++ l₂) = l₁ ∪ dedup l₂ :=
-  by
+theorem dedup_append (l₁ l₂ : List α) : dedup (l₁ ++ l₂) = l₁ ∪ dedup l₂ := by
   induction' l₁ with a l₁ IH; · rfl
   simp only [instUnionList, cons_union] at *
   rw [← IH]
@@ -114,8 +113,7 @@ theorem count_dedup (l : List α) (a : α) : l.dedup.count a = if a ∈ l then 1
 
 /-- Summing the count of `x` over a list filtered by some `p` is just `countp` applied to `p` -/
 theorem sum_map_count_dedup_filter_eq_countp (p : α → Bool) (l : List α) :
-    ((l.dedup.filter p).map fun x => l.count x).sum = l.countp p :=
-  by
+    ((l.dedup.filter p).map fun x => l.count x).sum = l.countp p := by
   induction' l with a as h
   · simp
   · simp_rw [List.countp_cons, List.count_cons', List.sum_map_add]
Refactor: drop List.repeat (#1579)

Mathlib 3 migrated to list.replicate in leanprover-community/mathlib#18127 (merged) and leanprover-community/mathlib#18181 (awaiting review).

Diff
@@ -106,12 +106,7 @@ theorem replicate_dedup {x : α} : ∀ {k}, k ≠ 0 → (replicate k x).dedup =
   | n + 2, _ => by
     rw [replicate_succ, dedup_cons_of_mem (mem_replicate.2 ⟨n.succ_ne_zero, rfl⟩),
       replicate_dedup n.succ_ne_zero]
-
-set_option linter.deprecated false in
-@[deprecated replicate_dedup]
-theorem repeat_dedup {x : α} : ∀ {k}, k ≠ 0 → (List.repeat x k).dedup = [x] :=
-  replicate_dedup
-#align list.repeat_dedup List.repeat_dedup
+#align list.replicate_dedup List.replicate_dedup
 
 theorem count_dedup (l : List α) (a : α) : l.dedup.count a = if a ∈ l then 1 else 0 := by
   simp_rw [count_eq_of_nodup <| nodup_dedup l, mem_dedup]
chore Data.List.Dedup : Update SHA (#1484)
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Mario Carneiro
 
 ! This file was ported from Lean 3 source module data.list.dedup
-! leanprover-community/mathlib commit 7b78d1776212a91ecc94cf601f83bdcc46b04213
+! leanprover-community/mathlib commit 6133ae2da6ae6693248bb5451de703f1ef154cc8
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
feat: port Mathlib.Data.List.Dedup (#1460)

Dependencies 2 + 104

105 files ported (98.1%)
51309 lines ported (99.7%)
Show graph

The unported dependencies are