data.list.permMathlib.Data.List.Perm

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

(last sync)

feat(data/{list,multiset,finset}/*): attach and filter lemmas (#18087)

Left commutativity and cardinality of list.filter/multiset.filter/finset.filter. Interaction of count/countp and attach.

Diff
@@ -396,7 +396,7 @@ theorem subperm.countp_le (p : α → Prop) [decidable_pred p]
 | ⟨l, p', s⟩ := p'.countp_eq p ▸ s.countp_le p
 
 theorem perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [decidable_pred p] [decidable_pred p']
-  (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countp p = l₂.countp p' :=
+  (hp : ∀ x ∈ l₁, p x ↔ p' x) : l₁.countp p = l₂.countp p' :=
 begin
   rw ← s.countp_eq p',
   clear s,

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(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(*): sync list.replicate with Mathlib 4 (#18181)

Sync arguments order and golfs with leanprover-community/mathlib4#1579

Diff
@@ -150,21 +150,21 @@ theorem perm_cons_append_cons {l l₁ l₂ : list α} (a : α) (p : l ~ l₁++l
   a::l ~ l₁++(a::l₂) :=
 (p.cons a).trans perm_middle.symm
 
-@[simp] theorem perm_replicate {a : α} {n : ℕ} {l : list α} :
+@[simp] theorem perm_replicate {n : ℕ} {a : α} {l : list α} :
   l ~ replicate n a ↔ l = replicate n a :=
 ⟨λ p, eq_replicate.2
   ⟨p.length_eq.trans $ length_replicate _ _, λ b m, eq_of_mem_replicate $ p.subset m⟩,
   λ h, h ▸ perm.refl _⟩
 
-@[simp] theorem replicate_perm {a : α} {n : ℕ} {l : list α} :
+@[simp] theorem replicate_perm {n : ℕ} {a : α} {l : list α} :
   replicate n a ~ l ↔ replicate n a = l :=
 (perm_comm.trans perm_replicate).trans eq_comm
 
 @[simp] theorem perm_singleton {a : α} {l : list α} : l ~ [a] ↔ l = [a] :=
-@perm_replicate α a 1 l
+@perm_replicate α 1 a l
 
 @[simp] theorem singleton_perm {a : α} {l : list α} : [a] ~ l ↔ [a] = l :=
-@replicate_perm α a 1 l
+@replicate_perm α 1 a l
 
 alias perm_singleton ↔ perm.eq_singleton _
 alias singleton_perm ↔ perm.singleton_eq _

(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
@@ -150,26 +150,24 @@ theorem perm_cons_append_cons {l l₁ l₂ : list α} (a : α) (p : l ~ l₁++l
   a::l ~ l₁++(a::l₂) :=
 (p.cons a).trans perm_middle.symm
 
-@[simp] theorem perm_repeat {a : α} {n : ℕ} {l : list α} : l ~ repeat a n ↔ l = repeat a n :=
-⟨λ p, (eq_repeat.2
-  ⟨p.length_eq.trans $ length_repeat _ _,
-   λ b m, eq_of_mem_repeat $ p.subset m⟩),
- λ h, h ▸ perm.refl _⟩
+@[simp] theorem perm_replicate {a : α} {n : ℕ} {l : list α} :
+  l ~ replicate n a ↔ l = replicate n a :=
+⟨λ p, eq_replicate.2
+  ⟨p.length_eq.trans $ length_replicate _ _, λ b m, eq_of_mem_replicate $ p.subset m⟩,
+  λ h, h ▸ perm.refl _⟩
 
-@[simp] theorem repeat_perm {a : α} {n : ℕ} {l : list α} : repeat a n ~ l ↔ repeat a n = l :=
-(perm_comm.trans perm_repeat).trans eq_comm
+@[simp] theorem replicate_perm {a : α} {n : ℕ} {l : list α} :
+  replicate n a ~ l ↔ replicate n a = l :=
+(perm_comm.trans perm_replicate).trans eq_comm
 
 @[simp] theorem perm_singleton {a : α} {l : list α} : l ~ [a] ↔ l = [a] :=
-@perm_repeat α a 1 l
+@perm_replicate α a 1 l
 
 @[simp] theorem singleton_perm {a : α} {l : list α} : [a] ~ l ↔ [a] = l :=
-@repeat_perm α a 1 l
+@replicate_perm α a 1 l
 
-theorem perm.eq_singleton {a : α} {l : list α} (p : l ~ [a]) : l = [a] :=
-perm_singleton.1 p
-
-theorem perm.singleton_eq {a : α} {l : list α} (p : [a] ~ l) : [a] = l :=
-p.symm.eq_singleton.symm
+alias perm_singleton ↔ perm.eq_singleton _
+alias singleton_perm ↔ perm.singleton_eq _
 
 theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b :=
 by simp
@@ -736,12 +734,12 @@ theorem perm_iff_count {l₁ l₂ : list α} : l₁ ~ l₂ ↔ ∀ a, count a l
     by_cases b = a; simp [h] at H ⊢; assumption }
 end⟩
 
-theorem perm_repeat_append_repeat {l : list α} {a b : α} {m n : ℕ} (h : a ≠ b) :
-  l ~ repeat a m ++ repeat b n ↔ count a l = m ∧ count b l = n ∧ l ⊆ [a, b] :=
+theorem perm_replicate_append_replicate {l : list α} {a b : α} {m n : ℕ} (h : a ≠ b) :
+  l ~ replicate m a ++ replicate n b ↔ count a l = m ∧ count b l = n ∧ l ⊆ [a, b] :=
 begin
   rw [perm_iff_count, ← decidable.and_forall_ne a, ← decidable.and_forall_ne b],
   suffices : l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l,
-  { simp [count_repeat, h, h.symm, this] { contextual := tt } },
+  { simp [count_replicate, h, h.symm, this] { contextual := tt } },
   simp_rw [ne.def, ← and_imp, ← not_or_distrib, decidable.not_imp_not, subset_def, mem_cons_iff,
     not_mem_nil, or_false, or_comm],
 end

(no changes)

(no changes)

(no changes)

(no changes)

chore(archive/100-theorems-list/30_ballot_problem): golf (#18126)

Also add some supporting lemmas.

Diff
@@ -79,6 +79,12 @@ theorem perm.subset {l₁ l₂ : list α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ :=
 theorem perm.mem_iff {a : α} {l₁ l₂ : list α} (h : l₁ ~ l₂) : a ∈ l₁ ↔ a ∈ l₂ :=
 iff.intro (λ m, h.subset m) (λ m, h.symm.subset m)
 
+lemma perm.subset_congr_left {l₁ l₂ l₃ : list α} (h : l₁ ~ l₂) : l₁ ⊆ l₃ ↔ l₂ ⊆ l₃ :=
+⟨h.symm.subset.trans, h.subset.trans⟩
+
+lemma perm.subset_congr_right {l₁ l₂ l₃ : list α} (h : l₁ ~ l₂) : l₃ ⊆ l₁ ↔ l₃ ⊆ l₂ :=
+⟨λ h', h'.trans h.subset, λ h', h'.trans h.symm.subset⟩
+
 theorem perm.append_right {l₁ l₂ : list α} (t₁ : list α) (p : l₁ ~ l₂) : l₁++t₁ ~ l₂++t₁ :=
 perm.rec_on p
   (perm.refl ([] ++ t₁))
@@ -730,6 +736,16 @@ theorem perm_iff_count {l₁ l₂ : list α} : l₁ ~ l₂ ↔ ∀ a, count a l
     by_cases b = a; simp [h] at H ⊢; assumption }
 end⟩
 
+theorem perm_repeat_append_repeat {l : list α} {a b : α} {m n : ℕ} (h : a ≠ b) :
+  l ~ repeat a m ++ repeat b n ↔ count a l = m ∧ count b l = n ∧ l ⊆ [a, b] :=
+begin
+  rw [perm_iff_count, ← decidable.and_forall_ne a, ← decidable.and_forall_ne b],
+  suffices : l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l,
+  { simp [count_repeat, h, h.symm, this] { contextual := tt } },
+  simp_rw [ne.def, ← and_imp, ← not_or_distrib, decidable.not_imp_not, subset_def, mem_cons_iff,
+    not_mem_nil, or_false, or_comm],
+end
+
 lemma subperm.cons_right {α : Type*} {l l' : list α} (x : α) (h : l <+~ l') : l <+~ x :: l' :=
 h.trans (sublist_cons x l').subperm
 

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(first ported)

Changes in mathlib3port

mathlib3
mathlib3port
Diff
@@ -1055,7 +1055,7 @@ theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h
   suffices l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l by
     simp (config := { contextual := true }) [count_replicate, h, h.symm, this]
   simp_rw [Ne.def, ← and_imp, ← not_or, Decidable.not_imp_not, subset_def, mem_cons_iff,
-    not_mem_nil, or_false_iff, or_comm']
+    not_mem_nil, or_false_iff, or_comm]
 #align list.perm_replicate_append_replicate List.perm_replicate_append_replicate
 -/
 
Diff
@@ -343,7 +343,7 @@ theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
 #align list.filter_append_perm List.filter_append_perm
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (l₁' list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:642:2: warning: expanding binder collection (l₁' list.perm l₁) -/
 #print List.exists_perm_sublist /-
 theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
     ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' :=
@@ -458,7 +458,7 @@ end Rel
 
 section Subperm
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (l list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:642:2: warning: expanding binder collection (l list.perm l₁) -/
 #print List.Subperm /-
 /-- `subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
   a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
@@ -1519,7 +1519,7 @@ theorem length_permutations (l : List α) : length (permutations l) = (length l)
 #align list.length_permutations List.length_permutations
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:642:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
 #print List.mem_permutations_of_perm_lemma /-
 theorem mem_permutations_of_perm_lemma {is l : List α}
     (H : l ~ [] ++ is → (∃ (ts' : _) (_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
@@ -1527,7 +1527,7 @@ theorem mem_permutations_of_perm_lemma {is l : List α}
 #align list.mem_permutations_of_perm_lemma List.mem_permutations_of_perm_lemma
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (is' list.perm is) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:642:2: warning: expanding binder collection (is' list.perm is) -/
 #print List.mem_permutationsAux_of_perm /-
 theorem mem_permutationsAux_of_perm :
     ∀ {ts is l : List α},
Diff
@@ -440,7 +440,7 @@ theorem rel_perm_imp (hr : RightUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ Imp
   fun a b h₁ c d h₂ h =>
   have : (flip (Forall₂ r) ∘r Perm ∘r Forall₂ r) b d := ⟨a, h₁, c, h, h₂⟩
   have : ((flip (Forall₂ r) ∘r Forall₂ r) ∘r Perm) b d := by
-    rwa [← forall₂_comp_perm_eq_perm_comp_forall₂, ← Relation.comp_assoc] at this 
+    rwa [← forall₂_comp_perm_eq_perm_comp_forall₂, ← Relation.comp_assoc] at this
   let ⟨b', ⟨c', hbc, hcb⟩, hbd⟩ := this
   have : b' = b := right_unique_forall₂' hr hcb hbc
   this ▸ hbd
@@ -587,7 +587,7 @@ theorem Perm.countP_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred
   clear s
   induction' l₁ with y s hs
   · rfl
-  · simp only [mem_cons_iff, forall_eq_or_imp] at hp 
+  · simp only [mem_cons_iff, forall_eq_or_imp] at hp
     simp only [countp_cons, hs hp.2, hp.1]
 #align list.perm.countp_congr List.Perm.countP_congr
 -/
@@ -721,13 +721,13 @@ theorem perm_inv_core {a : α} {l₁ l₂ r₁ r₂ : List α} :
         fun t₁ t₂ t₃ p₁ p₂ IH₁ IH₂ => _ <;>
     intro l₁ l₂ r₁ r₂ e₁ e₂
   · apply (not_mem_nil a).elim; rw [← e₁]; simp
-  · cases' l₁ with y l₁ <;> cases' l₂ with z l₂ <;> dsimp at e₁ e₂  <;> injections <;> subst x
+  · cases' l₁ with y l₁ <;> cases' l₂ with z l₂ <;> dsimp at e₁ e₂ <;> injections <;> subst x
     · substs t₁ t₂; exact p
     · substs z t₁ t₂; exact p.trans perm_middle
     · substs y t₁ t₂; exact perm_middle.symm.trans p
     · substs z t₁ t₂; exact (IH rfl rfl).cons y
   · rcases l₁ with (_ | ⟨y, _ | ⟨z, l₁⟩⟩) <;> rcases l₂ with (_ | ⟨u, _ | ⟨v, l₂⟩⟩) <;>
-          dsimp at e₁ e₂  <;> injections <;> substs x y
+          dsimp at e₁ e₂ <;> injections <;> substs x y
     · substs r₁ r₂; exact p.cons a
     · substs r₁ r₂; exact p.cons u
     · substs r₁ v t₂; exact (p.trans perm_middle).cons u
@@ -805,7 +805,7 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (
   induction s generalizing l₁
   case slnil => cases h₂
   case cons r₁ r₂ b s' ih =>
-    simp at h₂ 
+    simp at h₂
     cases' h₂ with e m
     · subst b; exact ⟨a :: r₁, p.cons a, s'.cons2 _ _ _⟩
     · rcases ih m d₁ h₁ p with ⟨t, p', s'⟩; exact ⟨t, p', s'.cons _ _ _⟩
@@ -862,7 +862,7 @@ protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~
   induction' d with a l₁' h d IH
   · exact ⟨nil, perm.nil, nil_sublist _⟩
   · cases' forall_mem_cons.1 H with H₁ H₂
-    simp at h 
+    simp at h
     exact cons_subperm_of_mem d h H₁ (IH H₂)
 #align list.nodup.subperm List.Nodup.subperm
 -/
@@ -881,12 +881,12 @@ theorem Nodup.perm_iff_eq_of_sublist {l₁ l₂ l : List α} (d : Nodup l) (s₁
   ⟨fun h => by
     induction' s₂ with l₂ l a s₂ IH l₂ l a s₂ IH generalizing l₁
     · exact h.eq_nil
-    · simp at d 
+    · simp at d
       cases' s₁ with _ _ _ s₁ l₁ _ _ s₁
       · exact IH d.2 s₁ h
       · apply d.1.elim
         exact subperm.subset ⟨_, h.symm, s₂⟩ (mem_cons_self _ _)
-    · simp at d 
+    · simp at d
       cases' s₁ with _ _ _ s₁ l₁ _ _ s₁
       · apply d.1.elim
         exact subperm.subset ⟨_, h, s₁⟩ (mem_cons_self _ _)
@@ -1038,11 +1038,11 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
   ⟨Perm.count_eq, fun H => by
     induction' l₁ with a l₁ IH generalizing l₂
     · cases' l₂ with b l₂; · rfl
-      specialize H b; simp at H ; contradiction
+      specialize H b; simp at H; contradiction
     · have : a ∈ l₂ := count_pos.1 (by rw [← H] <;> simp <;> apply Nat.succ_pos)
       refine' ((IH fun b => _).cons a).trans (perm_cons_erase this).symm
       specialize H b
-      rw [(perm_cons_erase this).count_eq] at H 
+      rw [(perm_cons_erase this).count_eq] at H
       by_cases b = a <;> simp [h] at H ⊢ <;> assumption⟩
 #align list.perm_iff_count List.perm_iff_count
 -/
@@ -1080,7 +1080,7 @@ theorem subperm_append_diff_self_of_count_le {l₁ l₂ : List α}
     rw [cons_append, diff_cons, perm_cons]
     refine' IH fun x hx => _
     specialize h x (mem_cons_of_mem _ hx)
-    rw [perm_iff_count.mp this] at h 
+    rw [perm_iff_count.mp this] at h
     by_cases hx : x = hd
     · subst hd
       simpa [Nat.succ_le_succ_iff] using h
@@ -1110,7 +1110,7 @@ instance decidableSubperm : DecidableRel ((· <+~ ·) : List α → List α →
 #print List.singleton_subperm_iff /-
 @[simp]
 theorem singleton_subperm_iff {α} {l : List α} {a : α} : [a] <+~ l ↔ a ∈ l :=
-  ⟨fun ⟨s, hla, h⟩ => by rwa [perm_singleton.mp hla, singleton_sublist] at h , fun h =>
+  ⟨fun ⟨s, hla, h⟩ => by rwa [perm_singleton.mp hla, singleton_sublist] at h, fun h =>
     ⟨[a], Perm.refl _, singleton_sublist.mpr h⟩⟩
 #align list.subperm_singleton_iff List.singleton_subperm_iff
 -/
@@ -1357,7 +1357,7 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
     lookmap f l₁ ~ lookmap f l₂ :=
   by
   let F a b := ∀ c ∈ f a, ∀ d ∈ f b, a = b ∧ c = d
-  change Pairwise F l₁ at H 
+  change Pairwise F l₁ at H
   induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ p₂ IH₁ IH₂; · simp
   · cases h : f a
     · simp [h]; exact IH (pairwise_cons.1 H).2
@@ -1379,7 +1379,7 @@ theorem Perm.eraseP (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
     (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ :=
   by
   let F a b := f a → f b → False
-  change Pairwise F l₁ at H 
+  change Pairwise F l₁ at H
   induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ p₂ IH₁ IH₂; · simp
   · by_cases h : f a
     · simp [h, p]
@@ -1479,12 +1479,12 @@ theorem perm_of_mem_permutationsAux :
   by
   refine' permutations_aux.rec (by simp) _
   introv IH1 IH2 m
-  rw [permutations_aux_cons, permutations, mem_foldr_permutations_aux2] at m 
+  rw [permutations_aux_cons, permutations, mem_foldr_permutations_aux2] at m
   rcases m with (m | ⟨l₁, l₂, m, _, e⟩)
   · exact (IH1 m).trans perm_middle
   · subst e
     have p : l₁ ++ l₂ ~ is := by
-      simp [permutations] at m 
+      simp [permutations] at m
       cases' m with e m; · simp [e]
       exact is.append_nil ▸ IH2 m
     exact ((perm_middle.trans (p.cons _)).append_right _).trans (perm_append_comm.cons _)
@@ -1505,7 +1505,7 @@ theorem length_permutationsAux :
   refine' permutations_aux.rec (by simp) _
   intro t ts is IH1 IH2
   have IH2 : length (permutations_aux is nil) + 1 = is.length ! := by simpa using IH2
-  simp [-add_comm, Nat.factorial, Nat.add_succ, mul_comm] at IH1 
+  simp [-add_comm, Nat.factorial, Nat.add_succ, mul_comm] at IH1
   rw [permutations_aux_cons,
     length_foldr_permutations_aux2' _ _ _ _ _ fun l m => (perm_of_mem_permutations m).length_eq,
     permutations, length, length, IH2, Nat.succ_add, Nat.factorial_succ, mul_comm (Nat.succ _), ←
@@ -1598,7 +1598,7 @@ theorem permutations_perm_permutations' (ts : List α) : ts.permutations ~ ts.pe
   obtain ⟨n, h⟩ : ∃ n, length ts < n := ⟨_, Nat.lt_succ_self _⟩
   induction' n with n IH generalizing ts; · cases h
   refine' List.reverseRecOn ts (fun h => _) (fun ts t _ h => _) h; · simp [permutations]
-  rw [← concat_eq_append, length_concat, Nat.succ_lt_succ_iff] at h 
+  rw [← concat_eq_append, length_concat, Nat.succ_lt_succ_iff] at h
   have IH₂ := (IH ts.reverse (by rwa [length_reverse])).trans (reverse_perm _).permutations'
   simp only [permutations_append, foldr_permutations_aux2, permutations_aux_nil,
     permutations_aux_cons, append_nil]
@@ -1647,7 +1647,7 @@ theorem nthLe_permutations'Aux (s : List α) (x : α) (n : ℕ)
     (permutations'Aux x s).nthLe n hn = s.insertNth n x :=
   by
   induction' s with y s IH generalizing n
-  · simp only [length, permutations'_aux, Nat.lt_one_iff] at hn 
+  · simp only [length, permutations'_aux, Nat.lt_one_iff] at hn
     simp [hn]
   · cases n
     · simp
@@ -1711,7 +1711,7 @@ theorem nodup_permutations'Aux_of_not_mem (s : List α) (x : α) (hx : x ∉ s)
     Nodup (permutations'Aux x s) := by
   induction' s with y s IH
   · simp
-  · simp only [not_or, mem_cons_iff] at hx 
+  · simp only [not_or, mem_cons_iff] at hx
     simp only [not_and, exists_eq_right_right, mem_map, permutations'_aux, nodup_cons]
     refine' ⟨fun _ => Ne.symm hx.left, _⟩
     rw [nodup_map_iff]
@@ -1726,7 +1726,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
   refine' ⟨fun h => _, nodup_permutations'_aux_of_not_mem _ _⟩
   intro H
   obtain ⟨k, hk, hk'⟩ := nth_le_of_mem H
-  rw [nodup_iff_nth_le_inj] at h 
+  rw [nodup_iff_nth_le_inj] at h
   suffices k = k + 1 by simpa using this
   refine' h k (k + 1) _ _ _
   · simpa [Nat.lt_succ_iff] using hk.le
@@ -1748,7 +1748,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
       convert nth_le_insert_nth_add_succ _ _ _ 0 _
       simpa using hk
     · obtain ⟨m, rfl⟩ := Nat.exists_eq_add_of_lt H'
-      rw [length_insert_nth _ _ hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn 
+      rw [length_insert_nth _ _ hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn
       rw [nth_le_insert_nth_add_succ]
       convert nth_le_insert_nth_add_succ s x k m.succ _ using 2
       · simp [Nat.add_succ, Nat.succ_add]
@@ -1768,7 +1768,7 @@ theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations :
     rw [nodup_bind]
     constructor
     · intro ys hy
-      rw [mem_permutations'] at hy 
+      rw [mem_permutations'] at hy
       rw [nodup_permutations'_aux_iff, hy.mem_iff]
       exact fun H => h x H rfl
     · refine' IH.pairwise_of_forall_ne fun as ha bs hb H => _
@@ -1776,10 +1776,10 @@ theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations :
       rintro a ha' b hb' rfl
       obtain ⟨n, hn, hn'⟩ := nth_le_of_mem ha'
       obtain ⟨m, hm, hm'⟩ := nth_le_of_mem hb'
-      rw [mem_permutations'] at ha hb 
+      rw [mem_permutations'] at ha hb
       have hl : as.length = bs.length := (ha.trans hb.symm).length_eq
-      simp only [Nat.lt_succ_iff, length_permutations'_aux] at hn hm 
-      rw [nth_le_permutations'_aux] at hn' hm' 
+      simp only [Nat.lt_succ_iff, length_permutations'_aux] at hn hm
+      rw [nth_le_permutations'_aux] at hn' hm'
       have hx :
         nth_le (insert_nth n x as) m (by rwa [length_insert_nth _ _ hn, Nat.lt_succ_iff, hl]) = x :=
         by simp [hn', ← hm', hm]
@@ -1791,8 +1791,8 @@ theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations :
       · suffices x ∈ bs by exact h x (hb.subset this) rfl
         rw [← hx', nth_le_insert_nth_of_lt _ _ _ _ ht (ht.trans_le hm)]
         exact nth_le_mem _ _ _
-      · simp only [ht] at hm' hn' 
-        rw [← hm'] at hn' 
+      · simp only [ht] at hm' hn'
+        rw [← hm'] at hn'
         exact H (insert_nth_injective _ _ hn')
       · suffices x ∈ as by exact h x (ha.subset this) rfl
         rw [← hx, nth_le_insert_nth_of_lt _ _ _ _ ht (ht.trans_le hn)]
Diff
@@ -659,7 +659,7 @@ theorem Perm.rec_heq {β : List α → Sort _} {f : ∀ a l, β l → β (a :: l
 
 section
 
-variable {op : α → α → α} [IsAssociative α op] [IsCommutative α op]
+variable {op : α → α → α} [Std.Associative α op] [Std.Commutative α op]
 
 local notation a " * " b => op a b
 
@@ -667,7 +667,7 @@ local notation l " <*> " a => foldl op a l
 
 #print List.Perm.fold_op_eq /-
 theorem Perm.fold_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : (l₁ <*> a) = l₂ <*> a :=
-  h.foldl_eq (right_comm _ IsCommutative.comm IsAssociative.assoc) _
+  h.foldl_eq (right_comm _ Std.Commutative.comm Std.Associative.assoc) _
 #align list.perm.fold_op_eq List.Perm.fold_op_eq
 -/
 
Diff
@@ -1664,7 +1664,7 @@ theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) :
   · rw [permutations'_aux, count_cons_self]
     by_cases hx : x = y
     · subst hx
-      simpa [take_while, Nat.succ_inj'] using IH _
+      simpa [take_while, Nat.succ_inj] using IH _
     · rw [take_while]
       rw [if_neg hx]
       cases' permutations'_aux x l with a as
Diff
@@ -278,14 +278,16 @@ theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) :
 #align list.perm_cons_erase List.perm_cons_erase
 -/
 
+#print List.Perm.recOnSwap' /-
 @[elab_as_elim]
-theorem perm_induction_on {P : List α → List α → Prop} {l₁ l₂ : List α} (p : l₁ ~ l₂) (h₁ : P [] [])
-    (h₂ : ∀ x l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (x :: l₁) (x :: l₂))
+theorem List.Perm.recOnSwap' {P : List α → List α → Prop} {l₁ l₂ : List α} (p : l₁ ~ l₂)
+    (h₁ : P [] []) (h₂ : ∀ x l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (x :: l₁) (x :: l₂))
     (h₃ : ∀ x y l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (y :: x :: l₁) (x :: y :: l₂))
     (h₄ : ∀ l₁ l₂ l₃, l₁ ~ l₂ → l₂ ~ l₃ → P l₁ l₂ → P l₂ l₃ → P l₁ l₃) : P l₁ l₂ :=
   have P_refl : ∀ l, P l l := fun l => List.recOn l h₁ fun x xs ih => h₂ x xs xs (Perm.refl xs) ih
   Perm.rec_on p h₁ h₂ (fun x y l => h₃ x y l l (Perm.refl l) (P_refl l)) h₄
-#align list.perm_induction_on List.perm_induction_onₓ
+#align list.perm_induction_on List.Perm.recOnSwap'
+-/
 
 #print List.Perm.filterMap /-
 @[congr]
@@ -614,7 +616,7 @@ theorem Subperm.count_le [DecidableEq α] {l₁ l₂ : List α} (s : l₁ <+~ l
 #print List.Perm.foldl_eq' /-
 theorem Perm.foldl_eq' {f : β → α → β} {l₁ l₂ : List α} (p : l₁ ~ l₂) :
     (∀ x ∈ l₁, ∀ y ∈ l₁, ∀ (z), f (f z x) y = f (f z y) x) → ∀ b, foldl f b l₁ = foldl f b l₂ :=
-  perm_induction_on p (fun H b => rfl)
+  List.Perm.recOnSwap' p (fun H b => rfl)
     (fun x t₁ t₂ p r H b => r (fun x hx y hy => H _ (Or.inr hx) _ (Or.inr hy)) _)
     (fun x y t₁ t₂ p r H b => by
       simp only [foldl]
@@ -635,7 +637,7 @@ theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : Righ
 #print List.Perm.foldr_eq /-
 theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
     ∀ b, foldr f b l₁ = foldr f b l₂ :=
-  perm_induction_on p (fun b => rfl) (fun x t₁ t₂ p r b => by simp <;> rw [r b])
+  List.Perm.recOnSwap' p (fun b => rfl) (fun x t₁ t₂ p r b => by simp <;> rw [r b])
     (fun x y t₁ t₂ p r b => by simp <;> rw [lcomm, r b]) fun t₁ t₂ t₃ p₁ p₂ r₁ r₂ a =>
     Eq.trans (r₁ a) (r₂ a)
 #align list.perm.foldr_eq List.Perm.foldr_eq
@@ -865,17 +867,17 @@ protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~
 #align list.nodup.subperm List.Nodup.subperm
 -/
 
-#print List.perm_ext /-
-theorem perm_ext {l₁ l₂ : List α} (d₁ : Nodup l₁) (d₂ : Nodup l₂) :
+#print List.perm_ext_iff_of_nodup /-
+theorem perm_ext_iff_of_nodup {l₁ l₂ : List α} (d₁ : Nodup l₁) (d₂ : Nodup l₂) :
     l₁ ~ l₂ ↔ ∀ a, a ∈ l₁ ↔ a ∈ l₂ :=
   ⟨fun p a => p.mem_iff, fun H =>
     (d₁.Subperm fun a => (H a).1).antisymm <| d₂.Subperm fun a => (H a).2⟩
-#align list.perm_ext List.perm_ext
+#align list.perm_ext List.perm_ext_iff_of_nodup
 -/
 
-#print List.Nodup.sublist_ext /-
-theorem Nodup.sublist_ext {l₁ l₂ l : List α} (d : Nodup l) (s₁ : l₁ <+ l) (s₂ : l₂ <+ l) :
-    l₁ ~ l₂ ↔ l₁ = l₂ :=
+#print List.Nodup.perm_iff_eq_of_sublist /-
+theorem Nodup.perm_iff_eq_of_sublist {l₁ l₂ l : List α} (d : Nodup l) (s₁ : l₁ <+ l)
+    (s₂ : l₂ <+ l) : l₁ ~ l₂ ↔ l₁ = l₂ :=
   ⟨fun h => by
     induction' s₂ with l₂ l a s₂ IH l₂ l a s₂ IH generalizing l₁
     · exact h.eq_nil
@@ -889,7 +891,7 @@ theorem Nodup.sublist_ext {l₁ l₂ l : List α} (d : Nodup l) (s₁ : l₁ <+
       · apply d.1.elim
         exact subperm.subset ⟨_, h, s₁⟩ (mem_cons_self _ _)
       · rw [IH d.2 s₁ h.cons_inv], fun h => by rw [h]⟩
-#align list.nodup.sublist_ext List.Nodup.sublist_ext
+#align list.nodup.sublist_ext List.Nodup.perm_iff_eq_of_sublist
 -/
 
 section
@@ -1372,8 +1374,8 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
 #align list.perm_lookmap List.perm_lookmap
 -/
 
-#print List.Perm.erasep /-
-theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
+#print List.Perm.eraseP /-
+theorem Perm.eraseP (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
     (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ :=
   by
   let F a b := f a → f b → False
@@ -1387,7 +1389,7 @@ theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
     · apply swap
   · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H))
     exact fun a b h h₁ h₂ => h h₂ h₁
-#align list.perm.erasep List.Perm.erasep
+#align list.perm.erasep List.Perm.eraseP
 -/
 
 #print List.Perm.take_inter /-
Diff
@@ -1105,12 +1105,12 @@ instance decidableSubperm : DecidableRel ((· <+~ ·) : List α → List α →
 #align list.decidable_subperm List.decidableSubperm
 -/
 
-#print List.subperm_singleton_iff /-
+#print List.singleton_subperm_iff /-
 @[simp]
-theorem subperm_singleton_iff {α} {l : List α} {a : α} : [a] <+~ l ↔ a ∈ l :=
+theorem singleton_subperm_iff {α} {l : List α} {a : α} : [a] <+~ l ↔ a ∈ l :=
   ⟨fun ⟨s, hla, h⟩ => by rwa [perm_singleton.mp hla, singleton_sublist] at h , fun h =>
     ⟨[a], Perm.refl _, singleton_sublist.mpr h⟩⟩
-#align list.subperm_singleton_iff List.subperm_singleton_iff
+#align list.subperm_singleton_iff List.singleton_subperm_iff
 -/
 
 #print List.Subperm.cons_left /-
Diff
@@ -8,7 +8,7 @@ import Data.List.Permutation
 import Data.List.Range
 import Data.Nat.Factorial.Basic
 
-#align_import data.list.perm from "leanprover-community/mathlib"@"f2f413b9d4be3a02840d0663dace76e8fe3da053"
+#align_import data.list.perm from "leanprover-community/mathlib"@"65a1391a0106c9204fe45bc73a039f056558cb83"
 
 /-!
 # List Permutations
@@ -579,7 +579,7 @@ theorem Subperm.countP_le (p : α → Prop) [DecidablePred p] {l₁ l₂ : List
 
 #print List.Perm.countP_congr /-
 theorem Perm.countP_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred p] [DecidablePred p']
-    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countP p = l₂.countP p' :=
+    (hp : ∀ x ∈ l₁, p x ↔ p' x) : l₁.countP p = l₂.countP p' :=
   by
   rw [← s.countp_eq p']
   clear s
Diff
@@ -3,10 +3,10 @@ Copyright (c) 2015 Microsoft Corporation. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
 -/
-import Mathbin.Data.List.Dedup
-import Mathbin.Data.List.Permutation
-import Mathbin.Data.List.Range
-import Mathbin.Data.Nat.Factorial.Basic
+import Data.List.Dedup
+import Data.List.Permutation
+import Data.List.Range
+import Data.Nat.Factorial.Basic
 
 #align_import data.list.perm from "leanprover-community/mathlib"@"f2f413b9d4be3a02840d0663dace76e8fe3da053"
 
@@ -341,7 +341,7 @@ theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
 #align list.filter_append_perm List.filter_append_perm
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l₁' list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (l₁' list.perm l₁) -/
 #print List.exists_perm_sublist /-
 theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
     ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' :=
@@ -456,7 +456,7 @@ end Rel
 
 section Subperm
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (l list.perm l₁) -/
 #print List.Subperm /-
 /-- `subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
   a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
@@ -1517,7 +1517,7 @@ theorem length_permutations (l : List α) : length (permutations l) = (length l)
 #align list.length_permutations List.length_permutations
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
 #print List.mem_permutations_of_perm_lemma /-
 theorem mem_permutations_of_perm_lemma {is l : List α}
     (H : l ~ [] ++ is → (∃ (ts' : _) (_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
@@ -1525,7 +1525,7 @@ theorem mem_permutations_of_perm_lemma {is l : List α}
 #align list.mem_permutations_of_perm_lemma List.mem_permutations_of_perm_lemma
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (is' list.perm is) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (is' list.perm is) -/
 #print List.mem_permutationsAux_of_perm /-
 theorem mem_permutationsAux_of_perm :
     ∀ {ts is l : List α},
Diff
@@ -260,10 +260,10 @@ theorem singleton_perm {a : α} {l : List α} : [a] ~ l ↔ [a] = l :=
 #align list.singleton_perm List.singleton_perm
 -/
 
-alias perm_singleton ↔ perm.eq_singleton _
+alias ⟨perm.eq_singleton, _⟩ := perm_singleton
 #align list.perm.eq_singleton List.Perm.eq_singleton
 
-alias singleton_perm ↔ perm.singleton_eq _
+alias ⟨perm.singleton_eq, _⟩ := singleton_perm
 #align list.perm.singleton_eq List.Perm.singleton_eq
 
 #print List.singleton_perm_singleton /-
@@ -563,23 +563,23 @@ theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ →
 #align list.sublist.exists_perm_append List.Sublist.exists_perm_append
 -/
 
-#print List.Perm.countp_eq /-
-theorem Perm.countp_eq (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
-    countp p l₁ = countp p l₂ := by
+#print List.Perm.countP_eq /-
+theorem Perm.countP_eq (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
+    countP p l₁ = countP p l₂ := by
   rw [countp_eq_length_filter, countp_eq_length_filter] <;> exact (s.filter _).length_eq
-#align list.perm.countp_eq List.Perm.countp_eq
+#align list.perm.countp_eq List.Perm.countP_eq
 -/
 
-#print List.Subperm.countp_le /-
-theorem Subperm.countp_le (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} :
-    l₁ <+~ l₂ → countp p l₁ ≤ countp p l₂
-  | ⟨l, p', s⟩ => p'.countp_eq p ▸ s.countp_le p
-#align list.subperm.countp_le List.Subperm.countp_le
+#print List.Subperm.countP_le /-
+theorem Subperm.countP_le (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} :
+    l₁ <+~ l₂ → countP p l₁ ≤ countP p l₂
+  | ⟨l, p', s⟩ => p'.countP_eq p ▸ s.countP_le p
+#align list.subperm.countp_le List.Subperm.countP_le
 -/
 
-#print List.Perm.countp_congr /-
-theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred p] [DecidablePred p']
-    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countp p = l₂.countp p' :=
+#print List.Perm.countP_congr /-
+theorem Perm.countP_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred p] [DecidablePred p']
+    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countP p = l₂.countP p' :=
   by
   rw [← s.countp_eq p']
   clear s
@@ -587,27 +587,27 @@ theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred
   · rfl
   · simp only [mem_cons_iff, forall_eq_or_imp] at hp 
     simp only [countp_cons, hs hp.2, hp.1]
-#align list.perm.countp_congr List.Perm.countp_congr
+#align list.perm.countp_congr List.Perm.countP_congr
 -/
 
-#print List.countp_eq_countp_filter_add /-
-theorem countp_eq_countp_filter_add (l : List α) (p q : α → Prop) [DecidablePred p]
-    [DecidablePred q] : l.countp p = (l.filterₓ q).countp p + (l.filterₓ fun a => ¬q a).countp p :=
+#print List.countP_eq_countP_filter_add /-
+theorem countP_eq_countP_filter_add (l : List α) (p q : α → Prop) [DecidablePred p]
+    [DecidablePred q] : l.countP p = (l.filterₓ q).countP p + (l.filterₓ fun a => ¬q a).countP p :=
   by rw [← countp_append]; exact perm.countp_eq _ (filter_append_perm _ _).symm
-#align list.countp_eq_countp_filter_add List.countp_eq_countp_filter_add
+#align list.countp_eq_countp_filter_add List.countP_eq_countP_filter_add
 -/
 
 #print List.Perm.count_eq /-
 theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
     count a l₁ = count a l₂ :=
-  p.countp_eq _
+  p.countP_eq _
 #align list.perm.count_eq List.Perm.count_eq
 -/
 
 #print List.Subperm.count_le /-
 theorem Subperm.count_le [DecidableEq α] {l₁ l₂ : List α} (s : l₁ <+~ l₂) (a) :
     count a l₁ ≤ count a l₂ :=
-  s.countp_le _
+  s.countP_le _
 #align list.subperm.count_le List.Subperm.count_le
 -/
 
@@ -789,7 +789,7 @@ theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ 
 #align list.subperm_cons List.subperm_cons
 -/
 
-alias subperm_cons ↔ subperm.of_cons subperm.cons
+alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons
 #align list.subperm.of_cons List.subperm.of_cons
 #align list.subperm.cons List.subperm.cons
 
Diff
@@ -2,17 +2,14 @@
 Copyright (c) 2015 Microsoft Corporation. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
-
-! This file was ported from Lean 3 source module data.list.perm
-! leanprover-community/mathlib commit f2f413b9d4be3a02840d0663dace76e8fe3da053
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathbin.Data.List.Dedup
 import Mathbin.Data.List.Permutation
 import Mathbin.Data.List.Range
 import Mathbin.Data.Nat.Factorial.Basic
 
+#align_import data.list.perm from "leanprover-community/mathlib"@"f2f413b9d4be3a02840d0663dace76e8fe3da053"
+
 /-!
 # List Permutations
 
@@ -344,7 +341,7 @@ theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
 #align list.filter_append_perm List.filter_append_perm
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (l₁' list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l₁' list.perm l₁) -/
 #print List.exists_perm_sublist /-
 theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
     ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' :=
@@ -459,7 +456,7 @@ end Rel
 
 section Subperm
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (l list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l list.perm l₁) -/
 #print List.Subperm /-
 /-- `subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
   a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
@@ -1520,7 +1517,7 @@ theorem length_permutations (l : List α) : length (permutations l) = (length l)
 #align list.length_permutations List.length_permutations
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
 #print List.mem_permutations_of_perm_lemma /-
 theorem mem_permutations_of_perm_lemma {is l : List α}
     (H : l ~ [] ++ is → (∃ (ts' : _) (_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
@@ -1528,7 +1525,7 @@ theorem mem_permutations_of_perm_lemma {is l : List α}
 #align list.mem_permutations_of_perm_lemma List.mem_permutations_of_perm_lemma
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (is' list.perm is) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (is' list.perm is) -/
 #print List.mem_permutationsAux_of_perm /-
 theorem mem_permutationsAux_of_perm :
     ∀ {ts is l : List α},
Diff
@@ -49,7 +49,6 @@ inductive Perm : List α → List α → Prop
 
 open Perm (symm)
 
--- mathport name: list.perm
 infixl:50 " ~ " => Perm
 
 #print List.Perm.refl /-
@@ -275,10 +274,12 @@ theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp
 #align list.singleton_perm_singleton List.singleton_perm_singleton
 -/
 
+#print List.perm_cons_erase /-
 theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : l ~ a :: l.eraseₓ a :=
   let ⟨l₁, l₂, _, e₁, e₂⟩ := exists_erase_eq h
   e₂.symm ▸ e₁.symm ▸ perm_middle
 #align list.perm_cons_erase List.perm_cons_erase
+-/
 
 @[elab_as_elim]
 theorem perm_induction_on {P : List α → List α → Prop} {l₁ l₂ : List α} (p : l₁ ~ l₂) (h₁ : P [] [])
@@ -322,10 +323,13 @@ theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α
 #align list.perm.pmap List.Perm.pmap
 -/
 
+#print List.Perm.filter /-
 theorem Perm.filter (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
     filter p l₁ ~ filter p l₂ := by rw [← filter_map_eq_filter] <;> apply s.filter_map _
 #align list.perm.filter List.Perm.filter
+-/
 
+#print List.filter_append_perm /-
 theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
     filter p l ++ filter (fun x => ¬p x) l ~ l :=
   by
@@ -338,6 +342,7 @@ theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
       refine' perm.trans _ (ih.cons x)
       exact perm_append_comm.trans (perm_append_comm.cons _)
 #align list.filter_append_perm List.filter_append_perm
+-/
 
 /- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (l₁' list.perm l₁) -/
 #print List.exists_perm_sublist /-
@@ -368,6 +373,7 @@ theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p :
 #align list.exists_perm_sublist List.exists_perm_sublist
 -/
 
+#print List.Perm.sizeOf_eq_sizeOf /-
 theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂) : l₁.sizeOf = l₂.sizeOf :=
   by
   induction' h with hd l₁ l₂ h₁₂ h_sz₁₂ a b l l₁ l₂ l₃ h₁₂ h₂₃ h_sz₁₂ h_sz₂₃
@@ -376,6 +382,7 @@ theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂
   · simp only [List.sizeof, add_left_comm]
   · simp only [h_sz₁₂, h_sz₂₃]
 #align list.perm.sizeof_eq_sizeof List.Perm.sizeOf_eq_sizeOf
+-/
 
 section Rel
 
@@ -383,7 +390,6 @@ open Relator
 
 variable {γ : Type _} {δ : Type _} {r : α → β → Prop} {p : γ → δ → Prop}
 
--- mathport name: «expr ∘r »
 local infixr:80 " ∘r " => Relation.Comp
 
 #print List.perm_comp_perm /-
@@ -463,7 +469,6 @@ def Subperm (l₁ l₂ : List α) : Prop :=
 #align list.subperm List.Subperm
 -/
 
--- mathport name: «expr <+~ »
 infixl:50 " <+~ " => Subperm
 
 #print List.nil_subperm /-
@@ -539,11 +544,13 @@ theorem Subperm.subset {l₁ l₂ : List α} : l₁ <+~ l₂ → l₁ ⊆ l₂
 #align list.subperm.subset List.Subperm.subset
 -/
 
+#print List.Subperm.filter /-
 theorem Subperm.filter (p : α → Prop) [DecidablePred p] ⦃l l' : List α⦄ (h : l <+~ l') :
     filter p l <+~ filter p l' := by
   obtain ⟨xs, hp, h⟩ := h
   exact ⟨_, hp.filter p, h.filter p⟩
 #align list.subperm.filter List.Subperm.filter
+-/
 
 end Subperm
 
@@ -559,16 +566,21 @@ theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ →
 #align list.sublist.exists_perm_append List.Sublist.exists_perm_append
 -/
 
+#print List.Perm.countp_eq /-
 theorem Perm.countp_eq (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
     countp p l₁ = countp p l₂ := by
   rw [countp_eq_length_filter, countp_eq_length_filter] <;> exact (s.filter _).length_eq
 #align list.perm.countp_eq List.Perm.countp_eq
+-/
 
+#print List.Subperm.countp_le /-
 theorem Subperm.countp_le (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} :
     l₁ <+~ l₂ → countp p l₁ ≤ countp p l₂
   | ⟨l, p', s⟩ => p'.countp_eq p ▸ s.countp_le p
 #align list.subperm.countp_le List.Subperm.countp_le
+-/
 
+#print List.Perm.countp_congr /-
 theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred p] [DecidablePred p']
     (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countp p = l₂.countp p' :=
   by
@@ -579,11 +591,14 @@ theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred
   · simp only [mem_cons_iff, forall_eq_or_imp] at hp 
     simp only [countp_cons, hs hp.2, hp.1]
 #align list.perm.countp_congr List.Perm.countp_congr
+-/
 
+#print List.countp_eq_countp_filter_add /-
 theorem countp_eq_countp_filter_add (l : List α) (p q : α → Prop) [DecidablePred p]
     [DecidablePred q] : l.countp p = (l.filterₓ q).countp p + (l.filterₓ fun a => ¬q a).countp p :=
   by rw [← countp_append]; exact perm.countp_eq _ (filter_append_perm _ _).symm
 #align list.countp_eq_countp_filter_add List.countp_eq_countp_filter_add
+-/
 
 #print List.Perm.count_eq /-
 theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
@@ -629,6 +644,7 @@ theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : Left
 #align list.perm.foldr_eq List.Perm.foldr_eq
 -/
 
+#print List.Perm.rec_heq /-
 theorem Perm.rec_heq {β : List α → Sort _} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α}
     (hl : Perm l l') (f_congr : ∀ {a l l' b b'}, Perm l l' → HEq b b' → HEq (f a l b) (f a l' b'))
     (f_swap : ∀ {a a' l b}, HEq (f a (a' :: l) (f a' l b)) (f a' (a :: l) (f a l b))) :
@@ -640,15 +656,14 @@ theorem Perm.rec_heq {β : List α → Sort _} {f : ∀ a l, β l → β (a :: l
   case swap a a' l => exact f_swap
   case trans l₁ l₂ l₃ h₁ h₂ ih₁ ih₂ => exact HEq.trans ih₁ ih₂
 #align list.perm.rec_heq List.Perm.rec_heq
+-/
 
 section
 
 variable {op : α → α → α} [IsAssociative α op] [IsCommutative α op]
 
--- mathport name: op
 local notation a " * " b => op a b
 
--- mathport name: foldl
 local notation l " <*> " a => foldl op a l
 
 #print List.Perm.fold_op_eq /-
@@ -661,6 +676,7 @@ end
 
 section CommMonoid
 
+#print List.Perm.prod_eq' /-
 /-- If elements of a list commute with each other, then their product does not
 depend on the order of elements. -/
 @[to_additive
@@ -673,20 +689,25 @@ theorem Perm.prod_eq' [Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (hc :
     _
 #align list.perm.prod_eq' List.Perm.prod_eq'
 #align list.perm.sum_eq' List.Perm.sum_eq'
+-/
 
 variable [CommMonoid α]
 
+#print List.Perm.prod_eq /-
 @[to_additive]
 theorem Perm.prod_eq {l₁ l₂ : List α} (h : Perm l₁ l₂) : prod l₁ = prod l₂ :=
   h.fold_op_eq
 #align list.perm.prod_eq List.Perm.prod_eq
 #align list.perm.sum_eq List.Perm.sum_eq
+-/
 
+#print List.prod_reverse /-
 @[to_additive]
 theorem prod_reverse (l : List α) : prod l.reverse = prod l :=
   (reverse_perm l).prod_eq
 #align list.prod_reverse List.prod_reverse
 #align list.sum_reverse List.sum_reverse
+-/
 
 end CommMonoid
 
@@ -878,6 +899,7 @@ section
 
 variable [DecidableEq α]
 
+#print List.Perm.erase /-
 -- attribute [congr]
 theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.eraseₓ a ~ l₂.eraseₓ a :=
   if h₁ : a ∈ l₁ then
@@ -887,7 +909,9 @@ theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase
     have h₂ : a ∉ l₂ := mt p.mem_iff.2 h₁
     rw [erase_of_not_mem h₁, erase_of_not_mem h₂] <;> exact p
 #align list.perm.erase List.Perm.erase
+-/
 
+#print List.subperm_cons_erase /-
 theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.eraseₓ a :=
   by
   by_cases h : a ∈ l
@@ -895,36 +919,50 @@ theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.eraseₓ a :=
   · rw [erase_of_not_mem h]
     exact (sublist_cons _ _).Subperm
 #align list.subperm_cons_erase List.subperm_cons_erase
+-/
 
+#print List.erase_subperm /-
 theorem erase_subperm (a : α) (l : List α) : l.eraseₓ a <+~ l :=
   (erase_sublist _ _).Subperm
 #align list.erase_subperm List.erase_subperm
+-/
 
+#print List.Subperm.erase /-
 theorem Subperm.erase {l₁ l₂ : List α} (a : α) (h : l₁ <+~ l₂) : l₁.eraseₓ a <+~ l₂.eraseₓ a :=
   let ⟨l, hp, hs⟩ := h
   ⟨l.eraseₓ a, hp.eraseₓ _, hs.eraseₓ _⟩
 #align list.subperm.erase List.Subperm.erase
+-/
 
+#print List.Perm.diff_right /-
 theorem Perm.diff_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : l₁.diffₓ t ~ l₂.diffₓ t := by
   induction t generalizing l₁ l₂ h <;> simp [*, perm.erase]
 #align list.perm.diff_right List.Perm.diff_right
+-/
 
+#print List.Perm.diff_left /-
 theorem Perm.diff_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l.diffₓ t₁ = l.diffₓ t₂ := by
   induction h generalizing l <;>
     first
     | simp [*, perm.erase, erase_comm]
     | exact (ih_1 _).trans (ih_2 _)
 #align list.perm.diff_left List.Perm.diff_left
+-/
 
+#print List.Perm.diff /-
 theorem Perm.diff {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) :
     l₁.diffₓ t₁ ~ l₂.diffₓ t₂ :=
   ht.diff_left l₂ ▸ hl.diff_right _
 #align list.perm.diff List.Perm.diff
+-/
 
+#print List.Subperm.diff_right /-
 theorem Subperm.diff_right {l₁ l₂ : List α} (h : l₁ <+~ l₂) (t : List α) :
     l₁.diffₓ t <+~ l₂.diffₓ t := by induction t generalizing l₁ l₂ h <;> simp [*, subperm.erase]
 #align list.subperm.diff_right List.Subperm.diff_right
+-/
 
+#print List.erase_cons_subperm_cons_erase /-
 theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) :
     (a :: l).eraseₓ b <+~ a :: l.eraseₓ b :=
   by
@@ -934,7 +972,9 @@ theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) :
     apply subperm_cons_erase
   · rw [erase_cons_tail _ h]
 #align list.erase_cons_subperm_cons_erase List.erase_cons_subperm_cons_erase
+-/
 
+#print List.subperm_cons_diff /-
 theorem subperm_cons_diff {a : α} : ∀ {l₁ l₂ : List α}, (a :: l₁).diffₓ l₂ <+~ a :: l₁.diffₓ l₂
   | l₁, [] => ⟨a :: l₁, by simp⟩
   | l₁, b :: l₂ => by
@@ -942,11 +982,15 @@ theorem subperm_cons_diff {a : α} : ∀ {l₁ l₂ : List α}, (a :: l₁).diff
     refine' ((erase_cons_subperm_cons_erase a b l₁).diff_right l₂).trans _
     apply subperm_cons_diff
 #align list.subperm_cons_diff List.subperm_cons_diff
+-/
 
+#print List.subset_cons_diff /-
 theorem subset_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diffₓ l₂ ⊆ a :: l₁.diffₓ l₂ :=
   subperm_cons_diff.Subset
 #align list.subset_cons_diff List.subset_cons_diff
+-/
 
+#print List.Perm.bagInter_right /-
 theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) :
     l₁.bagInterₓ t ~ l₂.bagInterₓ t :=
   by
@@ -960,7 +1004,9 @@ theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂
     · simp [xt, yt]
   · exact (ih_1 _).trans (ih_2 _)
 #align list.perm.bag_inter_right List.Perm.bagInter_right
+-/
 
+#print List.Perm.bagInter_left /-
 theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) :
     l.bagInterₓ t₁ = l.bagInterₓ t₂ :=
   by
@@ -969,12 +1015,16 @@ theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂)
   · simp [h, p.subset h, IH (p.erase _)]
   · simp [h, mt p.mem_iff.2 h, IH p]
 #align list.perm.bag_inter_left List.Perm.bagInter_left
+-/
 
+#print List.Perm.bagInter /-
 theorem Perm.bagInter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) :
     l₁.bagInterₓ t₁ ~ l₂.bagInterₓ t₂ :=
   ht.bagInter_left l₂ ▸ hl.bagInter_right _
 #align list.perm.bag_inter List.Perm.bagInter
+-/
 
+#print List.cons_perm_iff_perm_erase /-
 theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} :
     a :: l₁ ~ l₂ ↔ a ∈ l₂ ∧ l₁ ~ l₂.eraseₓ a :=
   ⟨fun h =>
@@ -982,6 +1032,7 @@ theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} :
     ⟨this, (h.trans <| perm_cons_erase this).cons_inv⟩,
     fun ⟨m, h⟩ => (h.cons a).trans (perm_cons_erase m).symm⟩
 #align list.cons_perm_iff_perm_erase List.cons_perm_iff_perm_erase
+-/
 
 #print List.perm_iff_count /-
 theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l₁ = count a l₂ :=
@@ -1324,6 +1375,7 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
 #align list.perm_lookmap List.perm_lookmap
 -/
 
+#print List.Perm.erasep /-
 theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
     (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ :=
   by
@@ -1339,6 +1391,7 @@ theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
   · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H))
     exact fun a b h h₁ h₂ => h h₂ h₁
 #align list.perm.erasep List.Perm.erasep
+-/
 
 #print List.Perm.take_inter /-
 theorem Perm.take_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys) (h' : ys.Nodup) :
Diff
@@ -339,7 +339,7 @@ theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
       exact perm_append_comm.trans (perm_append_comm.cons _)
 #align list.filter_append_perm List.filter_append_perm
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l₁' list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (l₁' list.perm l₁) -/
 #print List.exists_perm_sublist /-
 theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
     ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' :=
@@ -453,7 +453,7 @@ end Rel
 
 section Subperm
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (l list.perm l₁) -/
 #print List.Subperm /-
 /-- `subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
   a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
@@ -1467,7 +1467,7 @@ theorem length_permutations (l : List α) : length (permutations l) = (length l)
 #align list.length_permutations List.length_permutations
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
 #print List.mem_permutations_of_perm_lemma /-
 theorem mem_permutations_of_perm_lemma {is l : List α}
     (H : l ~ [] ++ is → (∃ (ts' : _) (_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
@@ -1475,7 +1475,7 @@ theorem mem_permutations_of_perm_lemma {is l : List α}
 #align list.mem_permutations_of_perm_lemma List.mem_permutations_of_perm_lemma
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (is' list.perm is) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (is' list.perm is) -/
 #print List.mem_permutationsAux_of_perm /-
 theorem mem_permutationsAux_of_perm :
     ∀ {ts is l : List α},
Diff
@@ -1047,7 +1047,7 @@ theorem subperm_ext_iff {l₁ l₂ : List α} : l₁ <+~ l₂ ↔ ∀ x ∈ l₁
     by
     refine' this.trans (perm.subperm _)
     exact perm_append_comm.trans (subperm_append_diff_self_of_count_le h)
-  convert(subperm_append_right _).mpr nil_subperm using 1
+  convert (subperm_append_right _).mpr nil_subperm using 1
 #align list.subperm_ext_iff List.subperm_ext_iff
 -/
 
Diff
@@ -342,7 +342,7 @@ theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
 /- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l₁' list.perm l₁) -/
 #print List.exists_perm_sublist /-
 theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
-    ∃ (l₁' : _)(_ : l₁' ~ l₁), l₁' <+ l₂' :=
+    ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' :=
   by
   induction' p with x l₂ l₂' p IH x y l₂ l₂ m₂ r₂ p₁ p₂ IH₁ IH₂ generalizing l₁ s
   · exact ⟨[], eq_nil_of_sublist_nil s ▸ perm.refl _, nil_sublist _⟩
@@ -409,8 +409,8 @@ theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) :
     cases' h₂₃ with _ b₁ _ l₂ h₁ hr_₂₃
     cases' hr_₂₃ with _ b₂ _ l₂ h₂ h₁₂
     exact ⟨b₂ :: b₁ :: l₂, forall₂.cons h₂ (forall₂.cons h₁ h₁₂), perm.swap _ _ _⟩
-  case
-    trans la₁ la₂ la₃ _ _ ih₁ ih₂ =>
+  case trans la₁ la₂ la₃ _ _ ih₁
+    ih₂ =>
     rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩
     rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩
     exact ⟨lb₁, hab₁, perm.trans h₁₂ h₂₃⟩
@@ -435,7 +435,7 @@ theorem rel_perm_imp (hr : RightUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ Imp
   fun a b h₁ c d h₂ h =>
   have : (flip (Forall₂ r) ∘r Perm ∘r Forall₂ r) b d := ⟨a, h₁, c, h, h₂⟩
   have : ((flip (Forall₂ r) ∘r Forall₂ r) ∘r Perm) b d := by
-    rwa [← forall₂_comp_perm_eq_perm_comp_forall₂, ← Relation.comp_assoc] at this
+    rwa [← forall₂_comp_perm_eq_perm_comp_forall₂, ← Relation.comp_assoc] at this 
   let ⟨b', ⟨c', hbc, hcb⟩, hbd⟩ := this
   have : b' = b := right_unique_forall₂' hr hcb hbc
   this ▸ hbd
@@ -459,7 +459,7 @@ section Subperm
   a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
   multiplicities of elements, and is used for the `≤` relation on multisets. -/
 def Subperm (l₁ l₂ : List α) : Prop :=
-  ∃ (l : _)(_ : l ~ l₁), l <+ l₂
+  ∃ (l : _) (_ : l ~ l₁), l <+ l₂
 #align list.subperm List.Subperm
 -/
 
@@ -576,7 +576,7 @@ theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred
   clear s
   induction' l₁ with y s hs
   · rfl
-  · simp only [mem_cons_iff, forall_eq_or_imp] at hp
+  · simp only [mem_cons_iff, forall_eq_or_imp] at hp 
     simp only [countp_cons, hs hp.2, hp.1]
 #align list.perm.countp_congr List.Perm.countp_congr
 
@@ -701,13 +701,13 @@ theorem perm_inv_core {a : α} {l₁ l₂ r₁ r₂ : List α} :
         fun t₁ t₂ t₃ p₁ p₂ IH₁ IH₂ => _ <;>
     intro l₁ l₂ r₁ r₂ e₁ e₂
   · apply (not_mem_nil a).elim; rw [← e₁]; simp
-  · cases' l₁ with y l₁ <;> cases' l₂ with z l₂ <;> dsimp at e₁ e₂ <;> injections <;> subst x
+  · cases' l₁ with y l₁ <;> cases' l₂ with z l₂ <;> dsimp at e₁ e₂  <;> injections <;> subst x
     · substs t₁ t₂; exact p
     · substs z t₁ t₂; exact p.trans perm_middle
     · substs y t₁ t₂; exact perm_middle.symm.trans p
     · substs z t₁ t₂; exact (IH rfl rfl).cons y
   · rcases l₁ with (_ | ⟨y, _ | ⟨z, l₁⟩⟩) <;> rcases l₂ with (_ | ⟨u, _ | ⟨v, l₂⟩⟩) <;>
-          dsimp at e₁ e₂ <;> injections <;> substs x y
+          dsimp at e₁ e₂  <;> injections <;> substs x y
     · substs r₁ r₂; exact p.cons a
     · substs r₁ r₂; exact p.cons u
     · substs r₁ v t₂; exact (p.trans perm_middle).cons u
@@ -785,12 +785,12 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (
   induction s generalizing l₁
   case slnil => cases h₂
   case cons r₁ r₂ b s' ih =>
-    simp at h₂
+    simp at h₂ 
     cases' h₂ with e m
     · subst b; exact ⟨a :: r₁, p.cons a, s'.cons2 _ _ _⟩
     · rcases ih m d₁ h₁ p with ⟨t, p', s'⟩; exact ⟨t, p', s'.cons _ _ _⟩
-  case
-    cons2 r₁ r₂ b s' ih =>
+  case cons2 r₁ r₂ b s'
+    ih =>
     have bm : b ∈ l₁ := p.subset <| mem_cons_self _ _
     have am : a ∈ r₂ := h₂.resolve_left fun e => h₁ <| e.symm ▸ bm
     rcases mem_split bm with ⟨t₁, t₂, rfl⟩
@@ -842,7 +842,7 @@ protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~
   induction' d with a l₁' h d IH
   · exact ⟨nil, perm.nil, nil_sublist _⟩
   · cases' forall_mem_cons.1 H with H₁ H₂
-    simp at h
+    simp at h 
     exact cons_subperm_of_mem d h H₁ (IH H₂)
 #align list.nodup.subperm List.Nodup.subperm
 -/
@@ -861,12 +861,12 @@ theorem Nodup.sublist_ext {l₁ l₂ l : List α} (d : Nodup l) (s₁ : l₁ <+
   ⟨fun h => by
     induction' s₂ with l₂ l a s₂ IH l₂ l a s₂ IH generalizing l₁
     · exact h.eq_nil
-    · simp at d
+    · simp at d 
       cases' s₁ with _ _ _ s₁ l₁ _ _ s₁
       · exact IH d.2 s₁ h
       · apply d.1.elim
         exact subperm.subset ⟨_, h.symm, s₂⟩ (mem_cons_self _ _)
-    · simp at d
+    · simp at d 
       cases' s₁ with _ _ _ s₁ l₁ _ _ s₁
       · apply d.1.elim
         exact subperm.subset ⟨_, h, s₁⟩ (mem_cons_self _ _)
@@ -911,7 +911,9 @@ theorem Perm.diff_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) :
 
 theorem Perm.diff_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l.diffₓ t₁ = l.diffₓ t₂ := by
   induction h generalizing l <;>
-    first |simp [*, perm.erase, erase_comm]|exact (ih_1 _).trans (ih_2 _)
+    first
+    | simp [*, perm.erase, erase_comm]
+    | exact (ih_1 _).trans (ih_2 _)
 #align list.perm.diff_left List.Perm.diff_left
 
 theorem Perm.diff {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) :
@@ -986,12 +988,12 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
   ⟨Perm.count_eq, fun H => by
     induction' l₁ with a l₁ IH generalizing l₂
     · cases' l₂ with b l₂; · rfl
-      specialize H b; simp at H; contradiction
+      specialize H b; simp at H ; contradiction
     · have : a ∈ l₂ := count_pos.1 (by rw [← H] <;> simp <;> apply Nat.succ_pos)
       refine' ((IH fun b => _).cons a).trans (perm_cons_erase this).symm
       specialize H b
-      rw [(perm_cons_erase this).count_eq] at H
-      by_cases b = a <;> simp [h] at H⊢ <;> assumption⟩
+      rw [(perm_cons_erase this).count_eq] at H 
+      by_cases b = a <;> simp [h] at H ⊢ <;> assumption⟩
 #align list.perm_iff_count List.perm_iff_count
 -/
 
@@ -1028,7 +1030,7 @@ theorem subperm_append_diff_self_of_count_le {l₁ l₂ : List α}
     rw [cons_append, diff_cons, perm_cons]
     refine' IH fun x hx => _
     specialize h x (mem_cons_of_mem _ hx)
-    rw [perm_iff_count.mp this] at h
+    rw [perm_iff_count.mp this] at h 
     by_cases hx : x = hd
     · subst hd
       simpa [Nat.succ_le_succ_iff] using h
@@ -1058,7 +1060,7 @@ instance decidableSubperm : DecidableRel ((· <+~ ·) : List α → List α →
 #print List.subperm_singleton_iff /-
 @[simp]
 theorem subperm_singleton_iff {α} {l : List α} {a : α} : [a] <+~ l ↔ a ∈ l :=
-  ⟨fun ⟨s, hla, h⟩ => by rwa [perm_singleton.mp hla, singleton_sublist] at h, fun h =>
+  ⟨fun ⟨s, hla, h⟩ => by rwa [perm_singleton.mp hla, singleton_sublist] at h , fun h =>
     ⟨[a], Perm.refl _, singleton_sublist.mpr h⟩⟩
 #align list.subperm_singleton_iff List.subperm_singleton_iff
 -/
@@ -1066,7 +1068,7 @@ theorem subperm_singleton_iff {α} {l : List α} {a : α} : [a] <+~ l ↔ a ∈
 #print List.Subperm.cons_left /-
 theorem Subperm.cons_left {l₁ l₂ : List α} (h : l₁ <+~ l₂) (x : α) (hx : count x l₁ < count x l₂) :
     x :: l₁ <+~ l₂ := by
-  rw [subperm_ext_iff] at h⊢
+  rw [subperm_ext_iff] at h ⊢
   intro y hy
   by_cases hy' : y = x
   · subst x
@@ -1305,7 +1307,7 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
     lookmap f l₁ ~ lookmap f l₂ :=
   by
   let F a b := ∀ c ∈ f a, ∀ d ∈ f b, a = b ∧ c = d
-  change Pairwise F l₁ at H
+  change Pairwise F l₁ at H 
   induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ p₂ IH₁ IH₂; · simp
   · cases h : f a
     · simp [h]; exact IH (pairwise_cons.1 H).2
@@ -1326,7 +1328,7 @@ theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
     (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ :=
   by
   let F a b := f a → f b → False
-  change Pairwise F l₁ at H
+  change Pairwise F l₁ at H 
   induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ p₂ IH₁ IH₂; · simp
   · by_cases h : f a
     · simp [h, p]
@@ -1345,8 +1347,8 @@ theorem Perm.take_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : x
   simp only [List.inter] at *
   induction h generalizing n
   case nil n => simp only [not_mem_nil, filter_false, take_nil]
-  case
-    cons h_x h_l₁ h_l₂ h_a h_ih n =>
+  case cons h_x h_l₁ h_l₂ h_a h_ih
+    n =>
     cases n <;>
       simp only [mem_cons_iff, true_or_iff, eq_self_iff_true, filter_cons_of_pos, perm_cons, take,
         not_mem_nil, filter_false]
@@ -1362,7 +1364,7 @@ theorem Perm.take_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : x
     cases n <;>
       simp only [mem_cons_iff, false_or_iff, true_or_iff, Filter, *, Nat.zero_eq, if_true,
         not_mem_nil, eq_self_iff_true, or_false_iff, if_false, perm_cons, take]
-    · rw [filter_eq_nil.2]; intros ; solve_by_elim [Ne.symm]
+    · rw [filter_eq_nil.2]; intros; solve_by_elim [Ne.symm]
     · convert perm.swap _ _ _; rw [@filter_congr' _ _ (· ∈ take n h_l)]
       · clear h₁; induction n generalizing h_l; · simp
         cases h_l <;>
@@ -1425,12 +1427,12 @@ theorem perm_of_mem_permutationsAux :
   by
   refine' permutations_aux.rec (by simp) _
   introv IH1 IH2 m
-  rw [permutations_aux_cons, permutations, mem_foldr_permutations_aux2] at m
+  rw [permutations_aux_cons, permutations, mem_foldr_permutations_aux2] at m 
   rcases m with (m | ⟨l₁, l₂, m, _, e⟩)
   · exact (IH1 m).trans perm_middle
   · subst e
     have p : l₁ ++ l₂ ~ is := by
-      simp [permutations] at m
+      simp [permutations] at m 
       cases' m with e m; · simp [e]
       exact is.append_nil ▸ IH2 m
     exact ((perm_middle.trans (p.cons _)).append_right _).trans (perm_append_comm.cons _)
@@ -1451,7 +1453,7 @@ theorem length_permutationsAux :
   refine' permutations_aux.rec (by simp) _
   intro t ts is IH1 IH2
   have IH2 : length (permutations_aux is nil) + 1 = is.length ! := by simpa using IH2
-  simp [-add_comm, Nat.factorial, Nat.add_succ, mul_comm] at IH1
+  simp [-add_comm, Nat.factorial, Nat.add_succ, mul_comm] at IH1 
   rw [permutations_aux_cons,
     length_foldr_permutations_aux2' _ _ _ _ _ fun l m => (perm_of_mem_permutations m).length_eq,
     permutations, length, length, IH2, Nat.succ_add, Nat.factorial_succ, mul_comm (Nat.succ _), ←
@@ -1468,7 +1470,7 @@ theorem length_permutations (l : List α) : length (permutations l) = (length l)
 /- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
 #print List.mem_permutations_of_perm_lemma /-
 theorem mem_permutations_of_perm_lemma {is l : List α}
-    (H : l ~ [] ++ is → (∃ (ts' : _)(_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
+    (H : l ~ [] ++ is → (∃ (ts' : _) (_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
     l ~ is → l ∈ permutations is := by simpa [permutations, perm_nil] using H
 #align list.mem_permutations_of_perm_lemma List.mem_permutations_of_perm_lemma
 -/
@@ -1477,7 +1479,7 @@ theorem mem_permutations_of_perm_lemma {is l : List α}
 #print List.mem_permutationsAux_of_perm /-
 theorem mem_permutationsAux_of_perm :
     ∀ {ts is l : List α},
-      l ~ is ++ ts → (∃ (is' : _)(_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is :=
+      l ~ is ++ ts → (∃ (is' : _) (_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is :=
   by
   refine' permutations_aux.rec (by simp) _
   intro t ts is IH1 IH2 l p
@@ -1544,7 +1546,7 @@ theorem permutations_perm_permutations' (ts : List α) : ts.permutations ~ ts.pe
   obtain ⟨n, h⟩ : ∃ n, length ts < n := ⟨_, Nat.lt_succ_self _⟩
   induction' n with n IH generalizing ts; · cases h
   refine' List.reverseRecOn ts (fun h => _) (fun ts t _ h => _) h; · simp [permutations]
-  rw [← concat_eq_append, length_concat, Nat.succ_lt_succ_iff] at h
+  rw [← concat_eq_append, length_concat, Nat.succ_lt_succ_iff] at h 
   have IH₂ := (IH ts.reverse (by rwa [length_reverse])).trans (reverse_perm _).permutations'
   simp only [permutations_append, foldr_permutations_aux2, permutations_aux_nil,
     permutations_aux_cons, append_nil]
@@ -1593,7 +1595,7 @@ theorem nthLe_permutations'Aux (s : List α) (x : α) (n : ℕ)
     (permutations'Aux x s).nthLe n hn = s.insertNth n x :=
   by
   induction' s with y s IH generalizing n
-  · simp only [length, permutations'_aux, Nat.lt_one_iff] at hn
+  · simp only [length, permutations'_aux, Nat.lt_one_iff] at hn 
     simp [hn]
   · cases n
     · simp
@@ -1657,7 +1659,7 @@ theorem nodup_permutations'Aux_of_not_mem (s : List α) (x : α) (hx : x ∉ s)
     Nodup (permutations'Aux x s) := by
   induction' s with y s IH
   · simp
-  · simp only [not_or, mem_cons_iff] at hx
+  · simp only [not_or, mem_cons_iff] at hx 
     simp only [not_and, exists_eq_right_right, mem_map, permutations'_aux, nodup_cons]
     refine' ⟨fun _ => Ne.symm hx.left, _⟩
     rw [nodup_map_iff]
@@ -1672,7 +1674,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
   refine' ⟨fun h => _, nodup_permutations'_aux_of_not_mem _ _⟩
   intro H
   obtain ⟨k, hk, hk'⟩ := nth_le_of_mem H
-  rw [nodup_iff_nth_le_inj] at h
+  rw [nodup_iff_nth_le_inj] at h 
   suffices k = k + 1 by simpa using this
   refine' h k (k + 1) _ _ _
   · simpa [Nat.lt_succ_iff] using hk.le
@@ -1694,7 +1696,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
       convert nth_le_insert_nth_add_succ _ _ _ 0 _
       simpa using hk
     · obtain ⟨m, rfl⟩ := Nat.exists_eq_add_of_lt H'
-      rw [length_insert_nth _ _ hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn
+      rw [length_insert_nth _ _ hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn 
       rw [nth_le_insert_nth_add_succ]
       convert nth_le_insert_nth_add_succ s x k m.succ _ using 2
       · simp [Nat.add_succ, Nat.succ_add]
@@ -1714,7 +1716,7 @@ theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations :
     rw [nodup_bind]
     constructor
     · intro ys hy
-      rw [mem_permutations'] at hy
+      rw [mem_permutations'] at hy 
       rw [nodup_permutations'_aux_iff, hy.mem_iff]
       exact fun H => h x H rfl
     · refine' IH.pairwise_of_forall_ne fun as ha bs hb H => _
@@ -1722,10 +1724,10 @@ theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations :
       rintro a ha' b hb' rfl
       obtain ⟨n, hn, hn'⟩ := nth_le_of_mem ha'
       obtain ⟨m, hm, hm'⟩ := nth_le_of_mem hb'
-      rw [mem_permutations'] at ha hb
+      rw [mem_permutations'] at ha hb 
       have hl : as.length = bs.length := (ha.trans hb.symm).length_eq
-      simp only [Nat.lt_succ_iff, length_permutations'_aux] at hn hm
-      rw [nth_le_permutations'_aux] at hn' hm'
+      simp only [Nat.lt_succ_iff, length_permutations'_aux] at hn hm 
+      rw [nth_le_permutations'_aux] at hn' hm' 
       have hx :
         nth_le (insert_nth n x as) m (by rwa [length_insert_nth _ _ hn, Nat.lt_succ_iff, hl]) = x :=
         by simp [hn', ← hm', hm]
@@ -1737,8 +1739,8 @@ theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations :
       · suffices x ∈ bs by exact h x (hb.subset this) rfl
         rw [← hx', nth_le_insert_nth_of_lt _ _ _ _ ht (ht.trans_le hm)]
         exact nth_le_mem _ _ _
-      · simp only [ht] at hm' hn'
-        rw [← hm'] at hn'
+      · simp only [ht] at hm' hn' 
+        rw [← hm'] at hn' 
         exact H (insert_nth_injective _ _ hn')
       · suffices x ∈ as by exact h x (ha.subset this) rfl
         rw [← hx, nth_le_insert_nth_of_lt _ _ _ _ ht (ht.trans_le hn)]
Diff
@@ -28,7 +28,7 @@ The notation `~` is used for permutation equivalence.
 -/
 
 
-open Nat
+open scoped Nat
 
 universe uu vv
 
Diff
@@ -275,12 +275,6 @@ theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp
 #align list.singleton_perm_singleton List.singleton_perm_singleton
 -/
 
-/- warning: list.perm_cons_erase -> List.perm_cons_erase is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {a : α} {l : List.{u1} α}, (Membership.Mem.{u1, u1} α (List.{u1} α) (List.hasMem.{u1} α) a l) -> (List.Perm.{u1} α l (List.cons.{u1} α a (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l a)))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {a : α} {l : List.{u1} α}, (Membership.mem.{u1, u1} α (List.{u1} α) (List.instMembershipList.{u1} α) a l) -> (List.Perm.{u1} α l (List.cons.{u1} α a (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l a)))
-Case conversion may be inaccurate. Consider using '#align list.perm_cons_erase List.perm_cons_eraseₓ'. -/
 theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : l ~ a :: l.eraseₓ a :=
   let ⟨l₁, l₂, _, e₁, e₂⟩ := exists_erase_eq h
   e₂.symm ▸ e₁.symm ▸ perm_middle
@@ -328,22 +322,10 @@ theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α
 #align list.perm.pmap List.Perm.pmap
 -/
 
-/- warning: list.perm.filter -> List.Perm.filter is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} (p : α -> Prop) [_inst_1 : DecidablePred.{succ u1} α p] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.filterₓ.{u1} α p (fun (a : α) => _inst_1 a) l₁) (List.filterₓ.{u1} α p (fun (a : α) => _inst_1 a) l₂))
-but is expected to have type
-  forall {α : Type.{u1}} (p : α -> Bool) {_inst_1 : List.{u1} α} {l₁ : List.{u1} α}, (List.Perm.{u1} α _inst_1 l₁) -> (List.Perm.{u1} α (List.filter.{u1} α p _inst_1) (List.filter.{u1} α p l₁))
-Case conversion may be inaccurate. Consider using '#align list.perm.filter List.Perm.filterₓ'. -/
 theorem Perm.filter (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
     filter p l₁ ~ filter p l₂ := by rw [← filter_map_eq_filter] <;> apply s.filter_map _
 #align list.perm.filter List.Perm.filter
 
-/- warning: list.filter_append_perm -> List.filter_append_perm is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} (p : α -> Prop) [_inst_1 : DecidablePred.{succ u1} α p] (l : List.{u1} α), List.Perm.{u1} α (Append.append.{u1} (List.{u1} α) (List.hasAppend.{u1} α) (List.filterₓ.{u1} α p (fun (a : α) => _inst_1 a) l) (List.filterₓ.{u1} α (fun (x : α) => Not (p x)) (fun (a : α) => Not.decidable (p a) (_inst_1 a)) l)) l
-but is expected to have type
-  forall {α : Type.{u1}} (p : α -> Bool) (_inst_1 : List.{u1} α), List.Perm.{u1} α (HAppend.hAppend.{u1, u1, u1} (List.{u1} α) (List.{u1} α) (List.{u1} α) (instHAppend.{u1} (List.{u1} α) (List.instAppendList.{u1} α)) (List.filter.{u1} α p _inst_1) (List.filter.{u1} α (fun (x : α) => Decidable.decide (Not (Eq.{1} Bool (p x) Bool.true)) (instDecidableNot (Eq.{1} Bool (p x) Bool.true) (instDecidableEqBool (p x) Bool.true))) _inst_1)) _inst_1
-Case conversion may be inaccurate. Consider using '#align list.filter_append_perm List.filter_append_permₓ'. -/
 theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
     filter p l ++ filter (fun x => ¬p x) l ~ l :=
   by
@@ -386,12 +368,6 @@ theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p :
 #align list.exists_perm_sublist List.exists_perm_sublist
 -/
 
-/- warning: list.perm.sizeof_eq_sizeof -> List.Perm.sizeOf_eq_sizeOf is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : SizeOf.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (Eq.{1} Nat (List.sizeof.{u1} α _inst_1 l₁) (List.sizeof.{u1} α _inst_1 l₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : SizeOf.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (Eq.{1} Nat (SizeOf.sizeOf.{succ u1} (List.{u1} α) (List._sizeOf_inst.{u1} α _inst_1) l₁) (SizeOf.sizeOf.{succ u1} (List.{u1} α) (List._sizeOf_inst.{u1} α _inst_1) l₂))
-Case conversion may be inaccurate. Consider using '#align list.perm.sizeof_eq_sizeof List.Perm.sizeOf_eq_sizeOfₓ'. -/
 theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂) : l₁.sizeOf = l₂.sizeOf :=
   by
   induction' h with hd l₁ l₂ h₁₂ h_sz₁₂ a b l l₁ l₂ l₃ h₁₂ h₂₃ h_sz₁₂ h_sz₂₃
@@ -563,12 +539,6 @@ theorem Subperm.subset {l₁ l₂ : List α} : l₁ <+~ l₂ → l₁ ⊆ l₂
 #align list.subperm.subset List.Subperm.subset
 -/
 
-/- warning: list.subperm.filter -> List.Subperm.filter is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} (p : α -> Prop) [_inst_1 : DecidablePred.{succ u1} α p] {{l : List.{u1} α}} {{l' : List.{u1} α}}, (List.Subperm.{u1} α l l') -> (List.Subperm.{u1} α (List.filterₓ.{u1} α p (fun (a : α) => _inst_1 a) l) (List.filterₓ.{u1} α p (fun (a : α) => _inst_1 a) l'))
-but is expected to have type
-  forall {α : Type.{u1}} (p : α -> Bool) {{_inst_1 : List.{u1} α}} {{l : List.{u1} α}}, (List.Subperm.{u1} α _inst_1 l) -> (List.Subperm.{u1} α (List.filter.{u1} α p _inst_1) (List.filter.{u1} α p l))
-Case conversion may be inaccurate. Consider using '#align list.subperm.filter List.Subperm.filterₓ'. -/
 theorem Subperm.filter (p : α → Prop) [DecidablePred p] ⦃l l' : List α⦄ (h : l <+~ l') :
     filter p l <+~ filter p l' := by
   obtain ⟨xs, hp, h⟩ := h
@@ -589,34 +559,16 @@ theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ →
 #align list.sublist.exists_perm_append List.Sublist.exists_perm_append
 -/
 
-/- warning: list.perm.countp_eq -> List.Perm.countp_eq is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} (p : α -> Prop) [_inst_1 : DecidablePred.{succ u1} α p] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (Eq.{1} Nat (List.countp.{u1} α p (fun (a : α) => _inst_1 a) l₁) (List.countp.{u1} α p (fun (a : α) => _inst_1 a) l₂))
-but is expected to have type
-  forall {α : Type.{u1}} (p : α -> Bool) {_inst_1 : List.{u1} α} {l₁ : List.{u1} α}, (List.Perm.{u1} α _inst_1 l₁) -> (Eq.{1} Nat (List.countp.{u1} α p _inst_1) (List.countp.{u1} α p l₁))
-Case conversion may be inaccurate. Consider using '#align list.perm.countp_eq List.Perm.countp_eqₓ'. -/
 theorem Perm.countp_eq (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
     countp p l₁ = countp p l₂ := by
   rw [countp_eq_length_filter, countp_eq_length_filter] <;> exact (s.filter _).length_eq
 #align list.perm.countp_eq List.Perm.countp_eq
 
-/- warning: list.subperm.countp_le -> List.Subperm.countp_le is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} (p : α -> Prop) [_inst_1 : DecidablePred.{succ u1} α p] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Subperm.{u1} α l₁ l₂) -> (LE.le.{0} Nat Nat.hasLe (List.countp.{u1} α p (fun (a : α) => _inst_1 a) l₁) (List.countp.{u1} α p (fun (a : α) => _inst_1 a) l₂))
-but is expected to have type
-  forall {α : Type.{u1}} (p : α -> Bool) {_inst_1 : List.{u1} α} {l₁ : List.{u1} α}, (List.Subperm.{u1} α _inst_1 l₁) -> (LE.le.{0} Nat instLENat (List.countp.{u1} α p _inst_1) (List.countp.{u1} α p l₁))
-Case conversion may be inaccurate. Consider using '#align list.subperm.countp_le List.Subperm.countp_leₓ'. -/
 theorem Subperm.countp_le (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} :
     l₁ <+~ l₂ → countp p l₁ ≤ countp p l₂
   | ⟨l, p', s⟩ => p'.countp_eq p ▸ s.countp_le p
 #align list.subperm.countp_le List.Subperm.countp_le
 
-/- warning: list.perm.countp_congr -> List.Perm.countp_congr is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (forall {p : α -> Prop} {p' : α -> Prop} [_inst_1 : DecidablePred.{succ u1} α p] [_inst_2 : DecidablePred.{succ u1} α p'], (forall (x : α), (Membership.Mem.{u1, u1} α (List.{u1} α) (List.hasMem.{u1} α) x l₁) -> (Eq.{1} Prop (p x) (p' x))) -> (Eq.{1} Nat (List.countp.{u1} α p (fun (a : α) => _inst_1 a) l₁) (List.countp.{u1} α p' (fun (a : α) => _inst_2 a) l₂)))
-but is expected to have type
-  forall {α : Type.{u1}} {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (forall {p : α -> Bool} {p' : α -> Bool}, (forall (x : α), (Membership.mem.{u1, u1} α (List.{u1} α) (List.instMembershipList.{u1} α) x l₁) -> (Eq.{1} Bool (p x) (p' x))) -> (Eq.{1} Nat (List.countp.{u1} α p l₁) (List.countp.{u1} α p' l₂)))
-Case conversion may be inaccurate. Consider using '#align list.perm.countp_congr List.Perm.countp_congrₓ'. -/
 theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred p] [DecidablePred p']
     (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countp p = l₂.countp p' :=
   by
@@ -628,12 +580,6 @@ theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred
     simp only [countp_cons, hs hp.2, hp.1]
 #align list.perm.countp_congr List.Perm.countp_congr
 
-/- warning: list.countp_eq_countp_filter_add -> List.countp_eq_countp_filter_add is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} (l : List.{u1} α) (p : α -> Prop) (q : α -> Prop) [_inst_1 : DecidablePred.{succ u1} α p] [_inst_2 : DecidablePred.{succ u1} α q], Eq.{1} Nat (List.countp.{u1} α p (fun (a : α) => _inst_1 a) l) (HAdd.hAdd.{0, 0, 0} Nat Nat Nat (instHAdd.{0} Nat Nat.hasAdd) (List.countp.{u1} α p (fun (a : α) => _inst_1 a) (List.filterₓ.{u1} α q (fun (a : α) => _inst_2 a) l)) (List.countp.{u1} α p (fun (a : α) => _inst_1 a) (List.filterₓ.{u1} α (fun (a : α) => Not (q a)) (fun (a : α) => Not.decidable (q a) (_inst_2 a)) l)))
-but is expected to have type
-  forall {α : Type.{u1}} (l : List.{u1} α) (p : α -> Bool) (q : α -> Bool), Eq.{1} Nat (List.countp.{u1} α p l) (HAdd.hAdd.{0, 0, 0} Nat Nat Nat (instHAdd.{0} Nat instAddNat) (List.countp.{u1} α p (List.filter.{u1} α q l)) (List.countp.{u1} α p (List.filter.{u1} α (fun (a : α) => Decidable.decide (Not (Eq.{1} Bool (q a) Bool.true)) (instDecidableNot (Eq.{1} Bool (q a) Bool.true) (instDecidableEqBool (q a) Bool.true))) l)))
-Case conversion may be inaccurate. Consider using '#align list.countp_eq_countp_filter_add List.countp_eq_countp_filter_addₓ'. -/
 theorem countp_eq_countp_filter_add (l : List α) (p q : α → Prop) [DecidablePred p]
     [DecidablePred q] : l.countp p = (l.filterₓ q).countp p + (l.filterₓ fun a => ¬q a).countp p :=
   by rw [← countp_append]; exact perm.countp_eq _ (filter_append_perm _ _).symm
@@ -683,12 +629,6 @@ theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : Left
 #align list.perm.foldr_eq List.Perm.foldr_eq
 -/
 
-/- warning: list.perm.rec_heq -> List.Perm.rec_heq is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} {β : (List.{u1} α) -> Sort.{u2}} {f : forall (a : α) (l : List.{u1} α), (β l) -> (β (List.cons.{u1} α a l))} {b : β (List.nil.{u1} α)} {l : List.{u1} α} {l' : List.{u1} α}, (List.Perm.{u1} α l l') -> (forall {a : α} {l : List.{u1} α} {l' : List.{u1} α} {b : β l} {b' : β l'}, (List.Perm.{u1} α l l') -> (HEq.{u2} (β l) b (β l') b') -> (HEq.{u2} (β (List.cons.{u1} α a l)) (f a l b) (β (List.cons.{u1} α a l')) (f a l' b'))) -> (forall {a : α} {a' : α} {l : List.{u1} α} {b : β l}, HEq.{u2} (β (List.cons.{u1} α a (List.cons.{u1} α a' l))) (f a (List.cons.{u1} α a' l) (f a' l b)) (β (List.cons.{u1} α a' (List.cons.{u1} α a l))) (f a' (List.cons.{u1} α a l) (f a l b))) -> (HEq.{u2} (β l) (List.rec.{u2, u1} α β b f l) (β l') (List.rec.{u2, u1} α β b f l'))
-but is expected to have type
-  forall {α : Type.{u2}} {β : (List.{u2} α) -> Sort.{u1}} {f : forall (a : α) (l : List.{u2} α), (β l) -> (β (List.cons.{u2} α a l))} {b : β (List.nil.{u2} α)} {l : List.{u2} α} {l' : List.{u2} α}, (List.Perm.{u2} α l l') -> (forall {a : α} {l : List.{u2} α} {l' : List.{u2} α} {b : β l} {b' : β l'}, (List.Perm.{u2} α l l') -> (HEq.{u1} (β l) b (β l') b') -> (HEq.{u1} (β (List.cons.{u2} α a l)) (f a l b) (β (List.cons.{u2} α a l')) (f a l' b'))) -> (forall {a : α} {a' : α} {l : List.{u2} α} {b : β l}, HEq.{u1} (β (List.cons.{u2} α a (List.cons.{u2} α a' l))) (f a (List.cons.{u2} α a' l) (f a' l b)) (β (List.cons.{u2} α a' (List.cons.{u2} α a l))) (f a' (List.cons.{u2} α a l) (f a l b))) -> (HEq.{u1} (β l) (List.rec.{u1, u2} α β b f l) (β l') (List.rec.{u1, u2} α β b f l'))
-Case conversion may be inaccurate. Consider using '#align list.perm.rec_heq List.Perm.rec_heqₓ'. -/
 theorem Perm.rec_heq {β : List α → Sort _} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α}
     (hl : Perm l l') (f_congr : ∀ {a l l' b b'}, Perm l l' → HEq b b' → HEq (f a l b) (f a l' b'))
     (f_swap : ∀ {a a' l b}, HEq (f a (a' :: l) (f a' l b)) (f a' (a :: l) (f a l b))) :
@@ -721,12 +661,6 @@ end
 
 section CommMonoid
 
-/- warning: list.perm.prod_eq' -> List.Perm.prod_eq' is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Pairwise.{u1} α (Commute.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))) l₁) -> (Eq.{succ u1} α (List.prod.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) (MulOneClass.toHasOne.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) l₁) (List.prod.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) (MulOneClass.toHasOne.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) l₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : Monoid.{u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Pairwise.{u1} α (Commute.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1))) l₁) -> (Eq.{succ u1} α (List.prod.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) (Monoid.toOne.{u1} α _inst_1) l₁) (List.prod.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α _inst_1)) (Monoid.toOne.{u1} α _inst_1) l₂))
-Case conversion may be inaccurate. Consider using '#align list.perm.prod_eq' List.Perm.prod_eq'ₓ'. -/
 /-- If elements of a list commute with each other, then their product does not
 depend on the order of elements. -/
 @[to_additive
@@ -742,24 +676,12 @@ theorem Perm.prod_eq' [Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (hc :
 
 variable [CommMonoid α]
 
-/- warning: list.perm.prod_eq -> List.Perm.prod_eq is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : CommMonoid.{u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (Eq.{succ u1} α (List.prod.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (MulOneClass.toHasOne.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) l₁) (List.prod.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (MulOneClass.toHasOne.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) l₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : CommMonoid.{u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (Eq.{succ u1} α (List.prod.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (Monoid.toOne.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1)) l₁) (List.prod.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (Monoid.toOne.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1)) l₂))
-Case conversion may be inaccurate. Consider using '#align list.perm.prod_eq List.Perm.prod_eqₓ'. -/
 @[to_additive]
 theorem Perm.prod_eq {l₁ l₂ : List α} (h : Perm l₁ l₂) : prod l₁ = prod l₂ :=
   h.fold_op_eq
 #align list.perm.prod_eq List.Perm.prod_eq
 #align list.perm.sum_eq List.Perm.sum_eq
 
-/- warning: list.prod_reverse -> List.prod_reverse is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : CommMonoid.{u1} α] (l : List.{u1} α), Eq.{succ u1} α (List.prod.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (MulOneClass.toHasOne.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (List.reverse.{u1} α l)) (List.prod.{u1} α (MulOneClass.toHasMul.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (MulOneClass.toHasOne.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) l)
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : CommMonoid.{u1} α] (l : List.{u1} α), Eq.{succ u1} α (List.prod.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (Monoid.toOne.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1)) (List.reverse.{u1} α l)) (List.prod.{u1} α (MulOneClass.toMul.{u1} α (Monoid.toMulOneClass.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1))) (Monoid.toOne.{u1} α (CommMonoid.toMonoid.{u1} α _inst_1)) l)
-Case conversion may be inaccurate. Consider using '#align list.prod_reverse List.prod_reverseₓ'. -/
 @[to_additive]
 theorem prod_reverse (l : List α) : prod l.reverse = prod l :=
   (reverse_perm l).prod_eq
@@ -956,12 +878,6 @@ section
 
 variable [DecidableEq α]
 
-/- warning: list.perm.erase -> List.Perm.erase is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (a : α) {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ a) (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₂ a))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (a : α) {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ a) (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₂ a))
-Case conversion may be inaccurate. Consider using '#align list.perm.erase List.Perm.eraseₓ'. -/
 -- attribute [congr]
 theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.eraseₓ a ~ l₂.eraseₓ a :=
   if h₁ : a ∈ l₁ then
@@ -972,12 +888,6 @@ theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase
     rw [erase_of_not_mem h₁, erase_of_not_mem h₂] <;> exact p
 #align list.perm.erase List.Perm.erase
 
-/- warning: list.subperm_cons_erase -> List.subperm_cons_erase is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (a : α) (l : List.{u1} α), List.Subperm.{u1} α l (List.cons.{u1} α a (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l a))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (a : α) (l : List.{u1} α), List.Subperm.{u1} α l (List.cons.{u1} α a (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l a))
-Case conversion may be inaccurate. Consider using '#align list.subperm_cons_erase List.subperm_cons_eraseₓ'. -/
 theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.eraseₓ a :=
   by
   by_cases h : a ∈ l
@@ -986,75 +896,33 @@ theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.eraseₓ a :=
     exact (sublist_cons _ _).Subperm
 #align list.subperm_cons_erase List.subperm_cons_erase
 
-/- warning: list.erase_subperm -> List.erase_subperm is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (a : α) (l : List.{u1} α), List.Subperm.{u1} α (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l a) l
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (a : α) (l : List.{u1} α), List.Subperm.{u1} α (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l a) l
-Case conversion may be inaccurate. Consider using '#align list.erase_subperm List.erase_subpermₓ'. -/
 theorem erase_subperm (a : α) (l : List α) : l.eraseₓ a <+~ l :=
   (erase_sublist _ _).Subperm
 #align list.erase_subperm List.erase_subperm
 
-/- warning: list.subperm.erase -> List.Subperm.erase is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} (a : α), (List.Subperm.{u1} α l₁ l₂) -> (List.Subperm.{u1} α (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ a) (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₂ a))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} (a : α), (List.Subperm.{u1} α l₁ l₂) -> (List.Subperm.{u1} α (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ a) (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₂ a))
-Case conversion may be inaccurate. Consider using '#align list.subperm.erase List.Subperm.eraseₓ'. -/
 theorem Subperm.erase {l₁ l₂ : List α} (a : α) (h : l₁ <+~ l₂) : l₁.eraseₓ a <+~ l₂.eraseₓ a :=
   let ⟨l, hp, hs⟩ := h
   ⟨l.eraseₓ a, hp.eraseₓ _, hs.eraseₓ _⟩
 #align list.subperm.erase List.Subperm.erase
 
-/- warning: list.perm.diff_right -> List.Perm.diff_right is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} (t : List.{u1} α), (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ t) (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₂ t))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} (t : List.{u1} α), (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ t) (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₂ t))
-Case conversion may be inaccurate. Consider using '#align list.perm.diff_right List.Perm.diff_rightₓ'. -/
 theorem Perm.diff_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : l₁.diffₓ t ~ l₂.diffₓ t := by
   induction t generalizing l₁ l₂ h <;> simp [*, perm.erase]
 #align list.perm.diff_right List.Perm.diff_right
 
-/- warning: list.perm.diff_left -> List.Perm.diff_left is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (l : List.{u1} α) {t₁ : List.{u1} α} {t₂ : List.{u1} α}, (List.Perm.{u1} α t₁ t₂) -> (Eq.{succ u1} (List.{u1} α) (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l t₁) (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l t₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (l : List.{u1} α) {t₁ : List.{u1} α} {t₂ : List.{u1} α}, (List.Perm.{u1} α t₁ t₂) -> (Eq.{succ u1} (List.{u1} α) (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l t₁) (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l t₂))
-Case conversion may be inaccurate. Consider using '#align list.perm.diff_left List.Perm.diff_leftₓ'. -/
 theorem Perm.diff_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l.diffₓ t₁ = l.diffₓ t₂ := by
   induction h generalizing l <;>
     first |simp [*, perm.erase, erase_comm]|exact (ih_1 _).trans (ih_2 _)
 #align list.perm.diff_left List.Perm.diff_left
 
-/- warning: list.perm.diff -> List.Perm.diff is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} {t₁ : List.{u1} α} {t₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α t₁ t₂) -> (List.Perm.{u1} α (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ t₁) (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₂ t₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} {t₁ : List.{u1} α} {t₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α t₁ t₂) -> (List.Perm.{u1} α (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ t₁) (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₂ t₂))
-Case conversion may be inaccurate. Consider using '#align list.perm.diff List.Perm.diffₓ'. -/
 theorem Perm.diff {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) :
     l₁.diffₓ t₁ ~ l₂.diffₓ t₂ :=
   ht.diff_left l₂ ▸ hl.diff_right _
 #align list.perm.diff List.Perm.diff
 
-/- warning: list.subperm.diff_right -> List.Subperm.diff_right is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Subperm.{u1} α l₁ l₂) -> (forall (t : List.{u1} α), List.Subperm.{u1} α (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ t) (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₂ t))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Subperm.{u1} α l₁ l₂) -> (forall (t : List.{u1} α), List.Subperm.{u1} α (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ t) (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₂ t))
-Case conversion may be inaccurate. Consider using '#align list.subperm.diff_right List.Subperm.diff_rightₓ'. -/
 theorem Subperm.diff_right {l₁ l₂ : List α} (h : l₁ <+~ l₂) (t : List α) :
     l₁.diffₓ t <+~ l₂.diffₓ t := by induction t generalizing l₁ l₂ h <;> simp [*, subperm.erase]
 #align list.subperm.diff_right List.Subperm.diff_right
 
-/- warning: list.erase_cons_subperm_cons_erase -> List.erase_cons_subperm_cons_erase is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (a : α) (b : α) (l : List.{u1} α), List.Subperm.{u1} α (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) (List.cons.{u1} α a l) b) (List.cons.{u1} α a (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l b))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (a : α) (b : α) (l : List.{u1} α), List.Subperm.{u1} α (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) (List.cons.{u1} α a l) b) (List.cons.{u1} α a (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l b))
-Case conversion may be inaccurate. Consider using '#align list.erase_cons_subperm_cons_erase List.erase_cons_subperm_cons_eraseₓ'. -/
 theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) :
     (a :: l).eraseₓ b <+~ a :: l.eraseₓ b :=
   by
@@ -1065,12 +933,6 @@ theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) :
   · rw [erase_cons_tail _ h]
 #align list.erase_cons_subperm_cons_erase List.erase_cons_subperm_cons_erase
 
-/- warning: list.subperm_cons_diff -> List.subperm_cons_diff is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {a : α} {l₁ : List.{u1} α} {l₂ : List.{u1} α}, List.Subperm.{u1} α (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) (List.cons.{u1} α a l₁) l₂) (List.cons.{u1} α a (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ l₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {a : α} {l₁ : List.{u1} α} {l₂ : List.{u1} α}, List.Subperm.{u1} α (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) (List.cons.{u1} α a l₁) l₂) (List.cons.{u1} α a (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ l₂))
-Case conversion may be inaccurate. Consider using '#align list.subperm_cons_diff List.subperm_cons_diffₓ'. -/
 theorem subperm_cons_diff {a : α} : ∀ {l₁ l₂ : List α}, (a :: l₁).diffₓ l₂ <+~ a :: l₁.diffₓ l₂
   | l₁, [] => ⟨a :: l₁, by simp⟩
   | l₁, b :: l₂ => by
@@ -1079,22 +941,10 @@ theorem subperm_cons_diff {a : α} : ∀ {l₁ l₂ : List α}, (a :: l₁).diff
     apply subperm_cons_diff
 #align list.subperm_cons_diff List.subperm_cons_diff
 
-/- warning: list.subset_cons_diff -> List.subset_cons_diff is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {a : α} {l₁ : List.{u1} α} {l₂ : List.{u1} α}, HasSubset.Subset.{u1} (List.{u1} α) (List.hasSubset.{u1} α) (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) (List.cons.{u1} α a l₁) l₂) (List.cons.{u1} α a (List.diffₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ l₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {a : α} {l₁ : List.{u1} α} {l₂ : List.{u1} α}, HasSubset.Subset.{u1} (List.{u1} α) (List.instHasSubsetList.{u1} α) (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) (List.cons.{u1} α a l₁) l₂) (List.cons.{u1} α a (List.diff.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ l₂))
-Case conversion may be inaccurate. Consider using '#align list.subset_cons_diff List.subset_cons_diffₓ'. -/
 theorem subset_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diffₓ l₂ ⊆ a :: l₁.diffₓ l₂ :=
   subperm_cons_diff.Subset
 #align list.subset_cons_diff List.subset_cons_diff
 
-/- warning: list.perm.bag_inter_right -> List.Perm.bagInter_right is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} (t : List.{u1} α), (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.bagInterₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ t) (List.bagInterₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₂ t))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} (t : List.{u1} α), (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.bagInter.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ t) (List.bagInter.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₂ t))
-Case conversion may be inaccurate. Consider using '#align list.perm.bag_inter_right List.Perm.bagInter_rightₓ'. -/
 theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) :
     l₁.bagInterₓ t ~ l₂.bagInterₓ t :=
   by
@@ -1109,12 +959,6 @@ theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂
   · exact (ih_1 _).trans (ih_2 _)
 #align list.perm.bag_inter_right List.Perm.bagInter_right
 
-/- warning: list.perm.bag_inter_left -> List.Perm.bagInter_left is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (l : List.{u1} α) {t₁ : List.{u1} α} {t₂ : List.{u1} α}, (List.Perm.{u1} α t₁ t₂) -> (Eq.{succ u1} (List.{u1} α) (List.bagInterₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l t₁) (List.bagInterₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l t₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] (l : List.{u1} α) {t₁ : List.{u1} α} {t₂ : List.{u1} α}, (List.Perm.{u1} α t₁ t₂) -> (Eq.{succ u1} (List.{u1} α) (List.bagInter.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l t₁) (List.bagInter.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l t₂))
-Case conversion may be inaccurate. Consider using '#align list.perm.bag_inter_left List.Perm.bagInter_leftₓ'. -/
 theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) :
     l.bagInterₓ t₁ = l.bagInterₓ t₂ :=
   by
@@ -1124,23 +968,11 @@ theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂)
   · simp [h, mt p.mem_iff.2 h, IH p]
 #align list.perm.bag_inter_left List.Perm.bagInter_left
 
-/- warning: list.perm.bag_inter -> List.Perm.bagInter is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} {t₁ : List.{u1} α} {t₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α t₁ t₂) -> (List.Perm.{u1} α (List.bagInterₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₁ t₁) (List.bagInterₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₂ t₂))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {l₁ : List.{u1} α} {l₂ : List.{u1} α} {t₁ : List.{u1} α} {t₂ : List.{u1} α}, (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α t₁ t₂) -> (List.Perm.{u1} α (List.bagInter.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₁ t₁) (List.bagInter.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₂ t₂))
-Case conversion may be inaccurate. Consider using '#align list.perm.bag_inter List.Perm.bagInterₓ'. -/
 theorem Perm.bagInter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) :
     l₁.bagInterₓ t₁ ~ l₂.bagInterₓ t₂ :=
   ht.bagInter_left l₂ ▸ hl.bagInter_right _
 #align list.perm.bag_inter List.Perm.bagInter
 
-/- warning: list.cons_perm_iff_perm_erase -> List.cons_perm_iff_perm_erase is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {a : α} {l₁ : List.{u1} α} {l₂ : List.{u1} α}, Iff (List.Perm.{u1} α (List.cons.{u1} α a l₁) l₂) (And (Membership.Mem.{u1, u1} α (List.{u1} α) (List.hasMem.{u1} α) a l₂) (List.Perm.{u1} α l₁ (List.eraseₓ.{u1} α (fun (a : α) (b : α) => _inst_1 a b) l₂ a)))
-but is expected to have type
-  forall {α : Type.{u1}} [_inst_1 : DecidableEq.{succ u1} α] {a : α} {l₁ : List.{u1} α} {l₂ : List.{u1} α}, Iff (List.Perm.{u1} α (List.cons.{u1} α a l₁) l₂) (And (Membership.mem.{u1, u1} α (List.{u1} α) (List.instMembershipList.{u1} α) a l₂) (List.Perm.{u1} α l₁ (List.erase.{u1} α (instBEq.{u1} α (fun (a : α) (b : α) => _inst_1 a b)) l₂ a)))
-Case conversion may be inaccurate. Consider using '#align list.cons_perm_iff_perm_erase List.cons_perm_iff_perm_eraseₓ'. -/
 theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} :
     a :: l₁ ~ l₂ ↔ a ∈ l₂ ∧ l₁ ~ l₂.eraseₓ a :=
   ⟨fun h =>
@@ -1490,12 +1322,6 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
 #align list.perm_lookmap List.perm_lookmap
 -/
 
-/- warning: list.perm.erasep -> List.Perm.erasep is a dubious translation:
-lean 3 declaration is
-  forall {α : Type.{u1}} (f : α -> Prop) [_inst_1 : DecidablePred.{succ u1} α f] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Pairwise.{u1} α (fun (a : α) (b : α) => (f a) -> (f b) -> False) l₁) -> (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.erasePₓ.{u1} α f (fun (a : α) => _inst_1 a) l₁) (List.erasePₓ.{u1} α f (fun (a : α) => _inst_1 a) l₂))
-but is expected to have type
-  forall {α : Type.{u1}} (f : α -> Prop) [_inst_1 : DecidablePred.{succ u1} α f] {l₁ : List.{u1} α} {l₂ : List.{u1} α}, (List.Pairwise.{u1} α (fun (a : α) (b : α) => (f a) -> (f b) -> False) l₁) -> (List.Perm.{u1} α l₁ l₂) -> (List.Perm.{u1} α (List.eraseP.{u1} α (fun (a : α) => Decidable.decide (f a) ((fun (a : α) => _inst_1 a) a)) l₁) (List.eraseP.{u1} α (fun (a : α) => Decidable.decide (f a) ((fun (a : α) => _inst_1 a) a)) l₂))
-Case conversion may be inaccurate. Consider using '#align list.perm.erasep List.Perm.erasepₓ'. -/
 theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
     (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ :=
   by
Diff
@@ -302,10 +302,8 @@ theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~
   by
   induction' p with x l₂ l₂' p IH x y l₂ l₂ m₂ r₂ p₁ p₂ IH₁ IH₂
   · simp
-  · simp only [filter_map]
-    cases' f x with a <;> simp [filter_map, IH, perm.cons]
-  · simp only [filter_map]
-    cases' f x with a <;> cases' f y with b <;> simp [filter_map, swap]
+  · simp only [filter_map]; cases' f x with a <;> simp [filter_map, IH, perm.cons]
+  · simp only [filter_map]; cases' f x with a <;> cases' f y with b <;> simp [filter_map, swap]
   · exact IH₁.trans IH₂
 #align list.perm.filter_map List.Perm.filterMap
 -/
@@ -448,8 +446,7 @@ theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Per
   by
   funext l₁ l₃; apply propext
   constructor
-  · intro h
-    rcases h with ⟨l₂, h₁₂, h₂₃⟩
+  · intro h; rcases h with ⟨l₂, h₁₂, h₂₃⟩
     have : forall₂ (flip r) l₂ l₁ := h₁₂.flip
     rcases perm_comp_forall₂ h₂₃.symm this with ⟨l', h₁, h₂⟩
     exact ⟨l', h₂.symm, h₁.flip⟩
@@ -639,9 +636,7 @@ but is expected to have type
 Case conversion may be inaccurate. Consider using '#align list.countp_eq_countp_filter_add List.countp_eq_countp_filter_addₓ'. -/
 theorem countp_eq_countp_filter_add (l : List α) (p q : α → Prop) [DecidablePred p]
     [DecidablePred q] : l.countp p = (l.filterₓ q).countp p + (l.filterₓ fun a => ¬q a).countp p :=
-  by
-  rw [← countp_append]
-  exact perm.countp_eq _ (filter_append_perm _ _).symm
+  by rw [← countp_append]; exact perm.countp_eq _ (filter_append_perm _ _).symm
 #align list.countp_eq_countp_filter_add List.countp_eq_countp_filter_add
 
 #print List.Perm.count_eq /-
@@ -783,43 +778,27 @@ theorem perm_inv_core {a : α} {l₁ l₂ r₁ r₂ : List α} :
       perm_induction_on p _ (fun x t₁ t₂ p IH => _) (fun x y t₁ t₂ p IH => _)
         fun t₁ t₂ t₃ p₁ p₂ IH₁ IH₂ => _ <;>
     intro l₁ l₂ r₁ r₂ e₁ e₂
-  · apply (not_mem_nil a).elim
-    rw [← e₁]
-    simp
+  · apply (not_mem_nil a).elim; rw [← e₁]; simp
   · cases' l₁ with y l₁ <;> cases' l₂ with z l₂ <;> dsimp at e₁ e₂ <;> injections <;> subst x
-    · substs t₁ t₂
-      exact p
-    · substs z t₁ t₂
-      exact p.trans perm_middle
-    · substs y t₁ t₂
-      exact perm_middle.symm.trans p
-    · substs z t₁ t₂
-      exact (IH rfl rfl).cons y
+    · substs t₁ t₂; exact p
+    · substs z t₁ t₂; exact p.trans perm_middle
+    · substs y t₁ t₂; exact perm_middle.symm.trans p
+    · substs z t₁ t₂; exact (IH rfl rfl).cons y
   · rcases l₁ with (_ | ⟨y, _ | ⟨z, l₁⟩⟩) <;> rcases l₂ with (_ | ⟨u, _ | ⟨v, l₂⟩⟩) <;>
           dsimp at e₁ e₂ <;> injections <;> substs x y
-    · substs r₁ r₂
-      exact p.cons a
-    · substs r₁ r₂
-      exact p.cons u
-    · substs r₁ v t₂
-      exact (p.trans perm_middle).cons u
-    · substs r₁ r₂
-      exact p.cons y
-    · substs r₁ r₂ y u
-      exact p.cons a
-    · substs r₁ u v t₂
-      exact ((p.trans perm_middle).cons y).trans (swap _ _ _)
-    · substs r₂ z t₁
-      exact (perm_middle.symm.trans p).cons y
-    · substs r₂ y z t₁
-      exact (swap _ _ _).trans ((perm_middle.symm.trans p).cons u)
-    · substs u v t₁ t₂
-      exact (IH rfl rfl).swap' _ _
+    · substs r₁ r₂; exact p.cons a
+    · substs r₁ r₂; exact p.cons u
+    · substs r₁ v t₂; exact (p.trans perm_middle).cons u
+    · substs r₁ r₂; exact p.cons y
+    · substs r₁ r₂ y u; exact p.cons a
+    · substs r₁ u v t₂; exact ((p.trans perm_middle).cons y).trans (swap _ _ _)
+    · substs r₂ z t₁; exact (perm_middle.symm.trans p).cons y
+    · substs r₂ y z t₁; exact (swap _ _ _).trans ((perm_middle.symm.trans p).cons u)
+    · substs u v t₁ t₂; exact (IH rfl rfl).swap' _ _
   · substs t₁ t₃
     have : a ∈ t₂ := p₁.subset (by simp)
     rcases mem_split this with ⟨l₂, r₂, e₂⟩
-    subst t₂
-    exact (IH₁ rfl rfl).trans (IH₂ rfl rfl)
+    subst t₂; exact (IH₁ rfl rfl).trans (IH₂ rfl rfl)
 #align list.perm_inv_core List.perm_inv_core
 -/
 
@@ -886,10 +865,8 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (
   case cons r₁ r₂ b s' ih =>
     simp at h₂
     cases' h₂ with e m
-    · subst b
-      exact ⟨a :: r₁, p.cons a, s'.cons2 _ _ _⟩
-    · rcases ih m d₁ h₁ p with ⟨t, p', s'⟩
-      exact ⟨t, p', s'.cons _ _ _⟩
+    · subst b; exact ⟨a :: r₁, p.cons a, s'.cons2 _ _ _⟩
+    · rcases ih m d₁ h₁ p with ⟨t, p', s'⟩; exact ⟨t, p', s'.cons _ _ _⟩
   case
     cons2 r₁ r₂ b s' ih =>
     have bm : b ∈ l₁ := p.subset <| mem_cons_self _ _
@@ -1123,8 +1100,7 @@ theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂
   by
   induction' h with x _ _ _ _ x y _ _ _ _ _ _ ih_1 ih_2 generalizing t; · simp
   · by_cases x ∈ t <;> simp [*, perm.cons]
-  · by_cases x = y
-    · simp [h]
+  · by_cases x = y; · simp [h]
     by_cases xt : x ∈ t <;> by_cases yt : y ∈ t
     · simp [xt, yt, mem_erase_of_ne h, mem_erase_of_ne (Ne.symm h), erase_comm, swap]
     · simp [xt, yt, mt mem_of_mem_erase, perm.cons]
@@ -1177,11 +1153,8 @@ theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} :
 theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l₁ = count a l₂ :=
   ⟨Perm.count_eq, fun H => by
     induction' l₁ with a l₁ IH generalizing l₂
-    · cases' l₂ with b l₂
-      · rfl
-      specialize H b
-      simp at H
-      contradiction
+    · cases' l₂ with b l₂; · rfl
+      specialize H b; simp at H; contradiction
     · have : a ∈ l₂ := count_pos.1 (by rw [← H] <;> simp <;> apply Nat.succ_pos)
       refine' ((IH fun b => _).cons a).trans (perm_cons_erase this).symm
       specialize H b
@@ -1312,15 +1285,12 @@ theorem perm_insert_swap (x y : α) (l : List α) : insert x (insert y l) ~ inse
 theorem perm_insertNth {α} (x : α) (l : List α) {n} (h : n ≤ l.length) : insertNth n x l ~ x :: l :=
   by
   induction l generalizing n
-  · cases n
-    rfl
-    cases h
+  · cases n; rfl; cases h
   cases n
   · simp [insert_nth]
   · simp only [insert_nth, modify_nth_tail]
     trans
-    · apply perm.cons
-      apply l_ih
+    · apply perm.cons; apply l_ih
       apply Nat.le_of_succ_le_succ h
     · apply perm.swap
 #align list.perm_insert_nth List.perm_insertNth
@@ -1398,8 +1368,7 @@ theorem Perm.pairwise_iff {R : α → α → Prop} (S : Symmetric R) :
     ⟨this p, this p.symm⟩
   fun l₁ l₂ p d => by
   induction' d with a l₁ h d IH generalizing l₂
-  · rw [← p.nil_eq]
-    constructor
+  · rw [← p.nil_eq]; constructor
   · have : a ∈ l₂ := p.subset (mem_cons_self _ _)
     rcases mem_split this with ⟨s₂, t₂, rfl⟩
     have p' := (p.trans perm_middle).cons_inv
@@ -1507,16 +1476,12 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
   change Pairwise F l₁ at H
   induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ p₂ IH₁ IH₂; · simp
   · cases h : f a
-    · simp [h]
-      exact IH (pairwise_cons.1 H).2
+    · simp [h]; exact IH (pairwise_cons.1 H).2
     · simp [lookmap_cons_some _ _ h, p]
   · cases' h₁ : f a with c <;> cases' h₂ : f b with d
-    · simp [h₁, h₂]
-      apply swap
-    · simp [h₁, lookmap_cons_some _ _ h₂]
-      apply swap
-    · simp [lookmap_cons_some _ _ h₁, h₂]
-      apply swap
+    · simp [h₁, h₂]; apply swap
+    · simp [h₁, lookmap_cons_some _ _ h₂]; apply swap
+    · simp [lookmap_cons_some _ _ h₁, h₂]; apply swap
     · simp [lookmap_cons_some _ _ h₁, lookmap_cons_some _ _ h₂]
       rcases(pairwise_cons.1 H).1 _ (Or.inl rfl) _ h₂ _ h₁ with ⟨rfl, rfl⟩
       rfl
@@ -1539,8 +1504,7 @@ theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
   induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ p₂ IH₁ IH₂; · simp
   · by_cases h : f a
     · simp [h, p]
-    · simp [h]
-      exact IH (pairwise_cons.1 H).2
+    · simp [h]; exact IH (pairwise_cons.1 H).2
   · by_cases h₁ : f a <;> by_cases h₂ : f b <;> simp [h₁, h₂]
     · cases (pairwise_cons.1 H).1 _ (Or.inl rfl) h₂ h₁
     · apply swap
@@ -1572,29 +1536,20 @@ theorem Perm.take_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : x
     cases n <;>
       simp only [mem_cons_iff, false_or_iff, true_or_iff, Filter, *, Nat.zero_eq, if_true,
         not_mem_nil, eq_self_iff_true, or_false_iff, if_false, perm_cons, take]
-    · rw [filter_eq_nil.2]
-      intros
-      solve_by_elim [Ne.symm]
-    · convert perm.swap _ _ _
-      rw [@filter_congr' _ _ (· ∈ take n h_l)]
-      · clear h₁
-        induction n generalizing h_l
-        · simp
+    · rw [filter_eq_nil.2]; intros ; solve_by_elim [Ne.symm]
+    · convert perm.swap _ _ _; rw [@filter_congr' _ _ (· ∈ take n h_l)]
+      · clear h₁; induction n generalizing h_l; · simp
         cases h_l <;>
           simp only [mem_cons_iff, true_or_iff, eq_self_iff_true, filter_cons_of_pos, true_and_iff,
             take, not_mem_nil, filter_false, take_nil]
         cases' h₃ with _ _ h₃ h₄
         rwa [@filter_congr' _ _ (· ∈ take n_n h_l_tl), n_ih]
-        · introv h
-          apply h₂ _ (Or.inr h)
-        · introv h
-          simp only [(h₃ x h).symm, false_or_iff]
-      · introv h
-        simp only [(h₂ x h).symm, (h₁ x (Or.inr h)).symm, false_or_iff]
+        · introv h; apply h₂ _ (Or.inr h)
+        · introv h; simp only [(h₃ x h).symm, false_or_iff]
+      · introv h; simp only [(h₂ x h).symm, (h₁ x (Or.inr h)).symm, false_or_iff]
   case trans h_l₁ h_l₂ h_l₃ h₀ h₁ h_ih₀ h_ih₁ n =>
     trans
-    · apply h_ih₀
-      rwa [h₁.nodup_iff]
+    · apply h_ih₀; rwa [h₁.nodup_iff]
     · apply perm.filter _ h₁
 #align list.perm.take_inter List.Perm.take_inter
 -/
@@ -1605,9 +1560,7 @@ theorem Perm.drop_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : x
   by
   by_cases h'' : n ≤ xs.length
   · let n' := xs.length - n
-    have h₀ : n = xs.length - n' := by
-      dsimp [n']
-      rwa [tsub_tsub_cancel_of_le]
+    have h₀ : n = xs.length - n' := by dsimp [n']; rwa [tsub_tsub_cancel_of_le]
     have h₁ : n' ≤ xs.length := by apply tsub_le_self
     have h₂ : xs.drop n = (xs.reverse.take n').reverse := by
       rw [reverse_take _ h₁, h₀, reverse_reverse]
@@ -1652,8 +1605,7 @@ theorem perm_of_mem_permutationsAux :
   · subst e
     have p : l₁ ++ l₂ ~ is := by
       simp [permutations] at m
-      cases' m with e m
-      · simp [e]
+      cases' m with e m; · simp [e]
       exact is.append_nil ▸ IH2 m
     exact ((perm_middle.trans (p.cons _)).append_right _).trans (perm_append_comm.cons _)
 #align list.perm_of_mem_permutations_aux List.perm_of_mem_permutationsAux
@@ -1705,8 +1657,7 @@ theorem mem_permutationsAux_of_perm :
   intro t ts is IH1 IH2 l p
   rw [permutations_aux_cons, mem_foldr_permutations_aux2]
   rcases IH1 (p.trans perm_middle) with (⟨is', p', e⟩ | m)
-  · clear p
-    subst e
+  · clear p; subst e
     rcases mem_split (p'.symm.subset (mem_cons_self _ _)) with ⟨l₁, l₂, e⟩
     subst is'
     have p := (perm_middle.symm.trans p').cons_inv
@@ -1729,10 +1680,8 @@ theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
     (permutations'Aux a l).bind (permutations'Aux b) ~
       (permutations'Aux b l).bind (permutations'Aux a) :=
   by
-  induction' l with c l ih
-  · simp [swap]
-  simp [permutations'_aux]
-  apply perm.swap'
+  induction' l with c l ih; · simp [swap]
+  simp [permutations'_aux]; apply perm.swap'
   have :
     ∀ a b,
       (map (cons c) (permutations'_aux a l)).bind (permutations'_aux b) ~
@@ -1753,8 +1702,7 @@ theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
 theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t :=
   by
   induction' p with a s t p IH a b l s t u p₁ p₂ IH₁ IH₂; · simp
-  · simp only [permutations']
-    exact IH.bind_right _
+  · simp only [permutations']; exact IH.bind_right _
   · simp only [permutations']
     rw [bind_assoc, bind_assoc]
     apply perm.bind_left
Diff
@@ -1240,7 +1240,7 @@ theorem subperm_ext_iff {l₁ l₂ : List α} : l₁ <+~ l₂ ↔ ∀ x ∈ l₁
     by
     refine' this.trans (perm.subperm _)
     exact perm_append_comm.trans (subperm_append_diff_self_of_count_le h)
-  convert (subperm_append_right _).mpr nil_subperm using 1
+  convert(subperm_append_right _).mpr nil_subperm using 1
 #align list.subperm_ext_iff List.subperm_ext_iff
 -/
 
Diff
@@ -359,7 +359,7 @@ theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
       exact perm_append_comm.trans (perm_append_comm.cons _)
 #align list.filter_append_perm List.filter_append_perm
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:628:2: warning: expanding binder collection (l₁' list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l₁' list.perm l₁) -/
 #print List.exists_perm_sublist /-
 theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
     ∃ (l₁' : _)(_ : l₁' ~ l₁), l₁' <+ l₂' :=
@@ -480,7 +480,7 @@ end Rel
 
 section Subperm
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:628:2: warning: expanding binder collection (l list.perm l₁) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (l list.perm l₁) -/
 #print List.Subperm /-
 /-- `subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
   a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
@@ -1687,7 +1687,7 @@ theorem length_permutations (l : List α) : length (permutations l) = (length l)
 #align list.length_permutations List.length_permutations
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:628:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ts' list.perm «expr[ ,]»([])) -/
 #print List.mem_permutations_of_perm_lemma /-
 theorem mem_permutations_of_perm_lemma {is l : List α}
     (H : l ~ [] ++ is → (∃ (ts' : _)(_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
@@ -1695,7 +1695,7 @@ theorem mem_permutations_of_perm_lemma {is l : List α}
 #align list.mem_permutations_of_perm_lemma List.mem_permutations_of_perm_lemma
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:628:2: warning: expanding binder collection (is' list.perm is) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (is' list.perm is) -/
 #print List.mem_permutationsAux_of_perm /-
 theorem mem_permutationsAux_of_perm :
     ∀ {ts is l : List α},

Changes in mathlib4

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

A PR accompanying #12339.

Zulip discussion

Diff
@@ -853,9 +853,9 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
     · obtain ⟨m, rfl⟩ := Nat.exists_eq_add_of_lt H'
       erw [length_insertNth _ _ hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn
       rw [nthLe_insertNth_add_succ]
-      convert nthLe_insertNth_add_succ s x k m.succ (by simpa using hn) using 2
-      · simp [Nat.add_succ, Nat.succ_add]
-      · simp [Nat.add_left_comm, Nat.add_comm]
+      · convert nthLe_insertNth_add_succ s x k m.succ (by simpa using hn) using 2
+        · simp [Nat.add_succ, Nat.succ_add]
+        · simp [Nat.add_left_comm, Nat.add_comm]
       · simpa [Nat.succ_add] using hn
 #align list.nodup_permutations'_aux_iff List.nodup_permutations'Aux_iff
 
chore: reduce proof dependencies for Nat.factors_count_eq (#12105)

This is a bit longer, partially duplicating the argument from UniqueFactorizationMonoid.multiplicity_eq_count_normalizedFactors, but it means we no longer need to depend on RingTheory.Int.Basic at this point.

The other added lemmas seem useful regardless.

Diff
@@ -241,6 +241,19 @@ lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
   · rintro (rfl | rfl)
     exacts [nil_subperm, Subperm.refl _]
 
+attribute [simp] nil_subperm
+
+@[simp]
+theorem subperm_nil : List.Subperm l [] ↔ l = [] :=
+  match l with
+  | [] => by simp
+  | head :: tail => by
+    simp only [iff_false]
+    intro h
+    have := h.length_le
+    simp only [List.length_cons, List.length_nil, Nat.succ_ne_zero, ← Nat.not_lt, Nat.zero_lt_succ,
+      not_true_eq_false] at this
+
 #align list.perm.countp_eq List.Perm.countP_eq
 
 #align list.subperm.countp_le List.Subperm.countP_le
chore(Data/List/Basic): remove some long-deprecated unused lemmas (#12367)
Diff
@@ -559,11 +559,6 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
     apply h d hd c hc
 #align list.perm_lookmap List.perm_lookmap
 
-@[deprecated Perm.eraseP]
-theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
-    (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) :
-    List.eraseP f l₁ ~ List.eraseP f l₂ :=
-  p.eraseP f (by simp [H])
 #align list.perm.erasep List.Perm.eraseP
 
 theorem Perm.take_inter {α : Type*} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys)
chore: backports from #11997, adaptations for nightly-2024-04-07 (#12176)

These are changes from #11997, the latest adaptation PR for nightly-2024-04-07, which can be made directly on master.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com>

Diff
@@ -422,7 +422,7 @@ theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h
   rw [perm_iff_count, ← Decidable.and_forall_ne a, ← Decidable.and_forall_ne b]
   suffices l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l by
     simp (config := { contextual := true }) [count_replicate, h, h.symm, this, count_eq_zero]
-  simp_rw [Ne.def, ← and_imp, ← not_or, Decidable.not_imp_not, subset_def, mem_cons,
+  simp_rw [Ne, ← and_imp, ← not_or, Decidable.not_imp_not, subset_def, mem_cons,
     not_mem_nil, or_false, or_comm]
 #align list.perm_replicate_append_replicate List.perm_replicate_append_replicate
 
chore(Data/List): Do not depend on algebra (#11845)

Remove dependencies on algebra in the Data.List folder except for:

  • Data.List.EditDistance: Actually relies on algebra. Maybe should be moved?
  • Data.List.Card: Completely unused and redundant.
  • Data.List.Cycle: Relies on Fintype, which shouldn't rely on algebra but it's hard to fix right now. Maybe should be moved?
  • Data.List.Func: Completely unused and redundant.
  • Data.List.Lex: That's order theory. Could be moved.
  • Data.List.Prime. That's algebra. Should definitely be moved.
  • Data.List.Sym: Relies on Multiset, which shouldn't rely on algebra but it's hard to fix right now. Maybe should be moved?
  • Data.List.ToFinsupp: That's algebra. Should definitely be moved.

As a consequence, move the big operators lemmas that were in there to Algebra.BigOperators.List.Basic. For the lemmas that were Nat-specific and not about auxiliary definitions, keep a version of them in the original file but stated using Nat.sum.

Before pre_11845

After post_11845

Diff
@@ -5,12 +5,10 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
 -/
 import Mathlib.Data.List.Count
 import Mathlib.Data.List.Dedup
-import Mathlib.Data.List.Permutation
-import Mathlib.Data.List.Pairwise
 import Mathlib.Data.List.InsertNth
 import Mathlib.Data.List.Lattice
+import Mathlib.Data.List.Permutation
 import Mathlib.Data.Nat.Factorial.Basic
-import Mathlib.Data.List.Count
 
 #align_import data.list.perm from "leanprover-community/mathlib"@"65a1391a0106c9204fe45bc73a039f056558cb83"
 
@@ -25,6 +23,8 @@ another.
 The notation `~` is used for permutation equivalence.
 -/
 
+-- Make sure we don't import algebra
+assert_not_exists Monoid
 
 open Nat
 
@@ -292,42 +292,6 @@ theorem Perm.fold_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : (l₁
 
 end
 
-section CommMonoid
-
-/-- If elements of a list commute with each other, then their product does not
-depend on the order of elements. -/
-@[to_additive
-      "If elements of a list additively commute with each other, then their sum does not
-      depend on the order of elements."]
-theorem Perm.prod_eq' [M : Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (hc : l₁.Pairwise Commute) :
-    l₁.prod = l₂.prod := by
-  refine h.foldl_eq' ?_ _
-  apply Pairwise.forall_of_forall
-  · intro x y h z
-    exact (h z).symm
-  · intros; rfl
-  · apply hc.imp
-    intro a b h z
-    rw [mul_assoc z, mul_assoc z, h]
-#align list.perm.prod_eq' List.Perm.prod_eq'
-#align list.perm.sum_eq' List.Perm.sum_eq'
-
-variable [CommMonoid α]
-
-@[to_additive]
-theorem Perm.prod_eq {l₁ l₂ : List α} (h : Perm l₁ l₂) : prod l₁ = prod l₂ :=
-  h.fold_op_eq
-#align list.perm.prod_eq List.Perm.prod_eq
-#align list.perm.sum_eq List.Perm.sum_eq
-
-@[to_additive]
-theorem prod_reverse (l : List α) : prod l.reverse = prod l :=
-  (reverse_perm l).prod_eq
-#align list.prod_reverse List.prod_reverse
-#align list.sum_reverse List.sum_reverse
-
-end CommMonoid
-
 #align list.perm_inv_core List.perm_inv_core
 
 #align list.perm.cons_inv List.Perm.cons_inv
@@ -669,12 +633,12 @@ theorem length_permutationsAux :
   refine' permutationsAux.rec (by simp) _
   intro t ts is IH1 IH2
   have IH2 : length (permutationsAux is nil) + 1 = is.length ! := by simpa using IH2
-  simp? [Nat.factorial, Nat.add_succ, mul_comm] at IH1 says
-    simp only [factorial, add_eq, add_zero, mul_comm] at IH1
+  simp? [Nat.factorial, Nat.add_succ, Nat.mul_comm] at IH1 says
+    simp only [factorial, add_eq, Nat.add_zero, Nat.mul_comm] at IH1
   rw [permutationsAux_cons,
     length_foldr_permutationsAux2' _ _ _ _ _ fun l m => (perm_of_mem_permutations m).length_eq,
-    permutations, length, length, IH2, Nat.succ_add, Nat.factorial_succ, mul_comm (_ + 1),
-    ← Nat.succ_eq_add_one, ← IH1, add_comm (_ * _), add_assoc, Nat.mul_succ, mul_comm]
+    permutations, length, length, IH2, Nat.succ_add, Nat.factorial_succ, Nat.mul_comm (_ + 1),
+    ← Nat.succ_eq_add_one, ← IH1, Nat.add_comm (_ * _), Nat.add_assoc, Nat.mul_succ, Nat.mul_comm]
 #align list.length_permutations_aux List.length_permutationsAux
 
 theorem length_permutations (l : List α) : length (permutations l) = (length l)! :=
@@ -800,7 +764,7 @@ theorem nthLe_permutations'Aux (s : List α) (x : α) (n : ℕ)
     (hn : n < length (permutations'Aux x s)) :
     (permutations'Aux x s).nthLe n hn = s.insertNth n x := by
   induction' s with y s IH generalizing n
-  · simp only [length, zero_add, Nat.lt_one_iff] at hn
+  · simp only [length, Nat.zero_add, Nat.lt_one_iff] at hn
     simp [hn]
   · cases n
     · simp [nthLe]
@@ -817,7 +781,7 @@ theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) :
       simpa [takeWhile, Nat.succ_inj', DecEq_eq] using IH _
     · rw [takeWhile]
       simp only [mem_map, cons.injEq, Ne.symm hx, false_and, and_false, exists_false,
-        not_false_iff, count_eq_zero_of_not_mem, zero_add, hx, decide_False, length_nil]
+        not_false_iff, count_eq_zero_of_not_mem, Nat.zero_add, hx, decide_False, length_nil]
 #align list.count_permutations'_aux_self List.count_permutations'Aux_self
 
 @[simp]
@@ -883,7 +847,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
       rw [nthLe_insertNth_add_succ]
       convert nthLe_insertNth_add_succ s x k m.succ (by simpa using hn) using 2
       · simp [Nat.add_succ, Nat.succ_add]
-      · simp [add_left_comm, add_comm]
+      · simp [Nat.add_left_comm, Nat.add_comm]
       · simpa [Nat.succ_add] using hn
 #align list.nodup_permutations'_aux_iff List.nodup_permutations'Aux_iff
 
chore: remove mathport name: <expression> lines (#11928)

Quoting [@digama0](https://github.com/digama0):

These were actually never meant to go in the file, they are basically debugging information and only useful on significantly broken mathport files. You can safely remove all of them.

Diff
@@ -137,7 +137,6 @@ open Relator
 
 variable {γ : Type*} {δ : Type*} {r : α → β → Prop} {p : γ → δ → Prop}
 
--- mathport name: «expr ∘r »
 local infixr:80 " ∘r " => Relation.Comp
 
 theorem perm_comp_perm : (Perm ∘r Perm : List α → List α → Prop) = Perm := by
@@ -283,10 +282,8 @@ section
 
 variable {op : α → α → α} [IA : Std.Associative op] [IC : Std.Commutative op]
 
--- mathport name: op
 local notation a " * " b => op a b
 
--- mathport name: foldl
 local notation l " <*> " a => foldl op a l
 
 theorem Perm.fold_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : (l₁ <*> a) = l₂ <*> a :=
chore(Algebra/BigOperators/List): Use Std lemmas (#11725)
  • Make Algebra.BigOperators.List.Basic, Data.List.Chain not depend on Data.Nat.Order.Basic by using Nat-specific Std lemmas rather than general mathlib ones. I leave the Data.Nat.Basic import since Algebra.BigOperators.List.Basic is algebra territory.
  • Make Algebra.BigOperators.List.Basic not depend on Algebra.Divisibility.Basic. I'm not too sure about that one since they already are algebra. My motivation is that they involve ring-like objects while big operators are about group-like objects, but this is in some sense a second order refactor.
  • As a consequence, move the divisibility and MonoidWithZero lemmas from Algebra.BigOperators.List.Basic to Algebra.BigOperators.List.Lemmas.
  • Move the content of Algebra.BigOperators.List.Defs to Algebra.BigOperators.List.Basic since no file imported the former without the latter and their imports are becoming very close after this PR.
  • Make Data.List.Count, Data.List.Dedup, Data.List.ProdSigma, Data.List.Zip not depend on Algebra.BigOperators.List.Basic.
  • As a consequence, move the big operators lemmas that were in there to Algebra.BigOperators.List.Basic. For the lemmas that were Nat -specific, keep a version of them stated using Nat.sum.
  • To help with this, add Nat.sum_eq_listSum (l : List Nat) : Nat.sum l = l.sum.
Diff
@@ -3,6 +3,7 @@ Copyright (c) 2015 Microsoft Corporation. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
 -/
+import Mathlib.Data.List.Count
 import Mathlib.Data.List.Dedup
 import Mathlib.Data.List.Permutation
 import Mathlib.Data.List.Pairwise
chore: update Std (#11858)

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

Diff
@@ -607,7 +607,7 @@ theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
 theorem Perm.take_inter {α : Type*} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys)
     (h' : ys.Nodup) : xs.take n ~ ys.inter (xs.take n) := by
   simp only [List.inter]
-  exact Perm.trans (show xs.take n ~ xs.filter (· ∈ xs.take n) by
+  exact Perm.trans (show xs.take n ~ xs.filter (xs.take n).elem by
       conv_lhs => rw [Nodup.take_eq_filter_mem ((Perm.nodup_iff h).2 h')])
     (Perm.filter _ h)
 #align list.perm.take_inter List.Perm.take_inter
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
@@ -9,6 +9,7 @@ import Mathlib.Data.List.Pairwise
 import Mathlib.Data.List.InsertNth
 import Mathlib.Data.List.Lattice
 import Mathlib.Data.Nat.Factorial.Basic
+import Mathlib.Data.List.Count
 
 #align_import data.list.perm from "leanprover-community/mathlib"@"65a1391a0106c9204fe45bc73a039f056558cb83"
 
chore(Data/Nat): Use Std lemmas (#11661)

Move basic Nat lemmas from Data.Nat.Order.Basic and Data.Nat.Pow to Data.Nat.Defs. Most proofs need adapting, but that's easily solved by replacing the general mathlib lemmas by the new Std Nat-specific lemmas and using omega.

Other changes

  • Move the last few lemmas left in Data.Nat.Pow to Algebra.GroupPower.Order
  • Move the deprecated aliases from Data.Nat.Pow to Algebra.GroupPower.Order
  • Move the bit/bit0/bit1 lemmas from Data.Nat.Order.Basic to Data.Nat.Bits
  • Fix some fallout from not importing Data.Nat.Order.Basic anymore
  • Add a few Nat-specific lemmas to help fix the fallout (look for nolint simpNF)
  • Turn Nat.mul_self_le_mul_self_iff and Nat.mul_self_lt_mul_self_iff around (they were misnamed)
  • Make more arguments to Nat.one_lt_pow implicit
Diff
@@ -615,9 +615,8 @@ theorem Perm.drop_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : x
     xs.drop n ~ ys.inter (xs.drop n) := by
   by_cases h'' : n ≤ xs.length
   · let n' := xs.length - n
-    have h₀ : n = xs.length - n' := by
-      rwa [tsub_tsub_cancel_of_le]
-    have h₁ : n' ≤ xs.length := by apply tsub_le_self
+    have h₀ : n = xs.length - n' := by rwa [Nat.sub_sub_self]
+    have h₁ : n' ≤ xs.length := Nat.sub_le ..
     have h₂ : xs.drop n = (xs.reverse.take n').reverse := by
       rw [reverse_take _ h₁, h₀, reverse_reverse]
     rw [h₂]
@@ -627,7 +626,7 @@ theorem Perm.drop_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : x
     apply (reverse_perm _).trans; assumption
   · have : drop n xs = [] := by
       apply eq_nil_of_length_eq_zero
-      rw [length_drop, tsub_eq_zero_iff_le]
+      rw [length_drop, Nat.sub_eq_zero_iff_le]
       apply le_of_not_ge h''
     simp [this, List.inter]
 #align list.perm.drop_inter List.Perm.drop_inter
@@ -802,7 +801,7 @@ theorem nthLe_permutations'Aux (s : List α) (x : α) (n : ℕ)
     (hn : n < length (permutations'Aux x s)) :
     (permutations'Aux x s).nthLe n hn = s.insertNth n x := by
   induction' s with y s IH generalizing n
-  · simp only [length, zero_add, lt_one_iff] at hn
+  · simp only [length, zero_add, Nat.lt_one_iff] at hn
     simp [hn]
   · cases n
     · simp [nthLe]
@@ -864,8 +863,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
   intro H
   obtain ⟨k, hk, hk'⟩ := nthLe_of_mem H
   rw [nodup_iff_nthLe_inj] at h
-  suffices k = k + 1 by simp at this
-  refine' h k (k + 1) _ _ _
+  refine k.succ_ne_self.symm $ h k (k + 1) ?_ ?_ ?_
   · simpa [Nat.lt_succ_iff] using hk.le
   · simpa using hk
   rw [nthLe_permutations'Aux, nthLe_permutations'Aux]
chore: make List.mem_split an alias of List.append_of_mem (#11060)

List.mem_split duplicates List.append_of_mem from Std: https://github.com/leanprover/std4/blob/a756b7d643ae5dcd7bf314e99f8e493e5d81b9ed/Std/Data/List/Lemmas.lean#L94-L96

This PR makes it an alias.

Co-authored-by: Yaël Dillies <yael.dillies@gmail.com>

Diff
@@ -373,7 +373,7 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (
     have am : a ∈ r₂ := by
       simp only [find?, mem_cons] at h₂
       exact h₂.resolve_left fun e => h₁ <| e.symm ▸ bm
-    rcases mem_split bm with ⟨t₁, t₂, rfl⟩
+    rcases append_of_mem bm with ⟨t₁, t₂, rfl⟩
     have st : t₁ ++ t₂ <+ t₁ ++ b :: t₂ := by simp
     rcases ih (d₁.sublist st) (mt (fun x => st.subset x) h₁) am
         (Perm.cons_inv <| p.trans perm_middle) with
@@ -699,7 +699,7 @@ theorem mem_permutationsAux_of_perm :
   rcases IH1 _ (p.trans perm_middle) with (⟨is', p', e⟩ | m)
   · clear p
     subst e
-    rcases mem_split (p'.symm.subset (mem_cons_self _ _)) with ⟨l₁, l₂, e⟩
+    rcases append_of_mem (p'.symm.subset (mem_cons_self _ _)) with ⟨l₁, l₂, e⟩
     subst is'
     have p := (perm_middle.symm.trans p').cons_inv
     cases' l₂ with a l₂'
chore: split insertNth lemmas from List.Basic (#11542)

Removes the insertNth section of this long file to its own new file. This section seems to be completely independent of the rest of the file, so this is a fairly easy split to make.

Diff
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
 import Mathlib.Data.List.Dedup
 import Mathlib.Data.List.Permutation
 import Mathlib.Data.List.Pairwise
+import Mathlib.Data.List.InsertNth
 import Mathlib.Data.List.Lattice
 import Mathlib.Data.Nat.Factorial.Basic
 
chore: more squeeze_simps arising from linter (#11259)

The squeezing continues! All found by the linter at #11246.

Diff
@@ -653,7 +653,7 @@ theorem perm_of_mem_permutationsAux :
   rcases m with (m | ⟨l₁, l₂, m, _, rfl⟩)
   · exact (IH1 _ m).trans perm_middle
   · have p : l₁ ++ l₂ ~ is := by
-      simp [permutations] at m
+      simp only [mem_cons] at m
       cases' m with e m
       · simp [e]
       exact is.append_nil ▸ IH2 _ m
style: homogenise porting notes (#11145)

Homogenises porting notes via capitalisation and addition of whitespace.

It makes the following changes:

  • converts "--porting note" into "-- Porting note";
  • converts "porting note" into "Porting note".
Diff
@@ -352,7 +352,7 @@ alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons
 #align list.subperm.of_cons List.subperm.of_cons
 #align list.subperm.cons List.subperm.cons
 
---Porting note: commented out
+-- Porting note: commented out
 --attribute [protected] subperm.cons
 
 theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (h₁ : a ∉ l₁) (h₂ : a ∈ l₂)
@@ -712,7 +712,7 @@ theorem mem_permutations {s t : List α} : s ∈ permutations t ↔ s ~ t :=
   ⟨perm_of_mem_permutations, mem_permutations_of_perm_lemma mem_permutationsAux_of_perm⟩
 #align list.mem_permutations List.mem_permutations
 
---Porting note: temporary theorem to solve diamond issue
+-- Porting note: temporary theorem to solve diamond issue
 private theorem DecEq_eq {α : Type*} [DecidableEq α] :
      instBEqList = @instBEq (List α) instDecidableEqList :=
   congr_arg BEq.mk <| by
chore: move to v4.6.0-rc1, merging adaptations from bump/v4.6.0 (#10176)

Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>

Diff
@@ -278,7 +278,7 @@ theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : Left
 
 section
 
-variable {op : α → α → α} [IA : IsAssociative α op] [IC : IsCommutative α op]
+variable {op : α → α → α} [IA : Std.Associative op] [IC : Std.Commutative op]
 
 -- mathport name: op
 local notation a " * " b => op a b
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
@@ -5,7 +5,8 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
 -/
 import Mathlib.Data.List.Dedup
 import Mathlib.Data.List.Permutation
-import Mathlib.Data.List.Range
+import Mathlib.Data.List.Pairwise
+import Mathlib.Data.List.Lattice
 import Mathlib.Data.Nat.Factorial.Basic
 
 #align_import data.list.perm from "leanprover-community/mathlib"@"65a1391a0106c9204fe45bc73a039f056558cb83"
chore: remove redundant dsimp args (#9835)

This is needed to work with leanprover/lean4#3087

Diff
@@ -746,7 +746,7 @@ theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
 theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t := by
   induction' p with a s t _ IH a b l s t u _ _ IH₁ IH₂; · simp
   · exact IH.bind_right _
-  · dsimp [permutations']
+  · dsimp
     rw [bind_assoc, bind_assoc]
     apply Perm.bind_left
     intro l' _
style: use cases x with | ... instead of cases x; case => ... (#9321)

This converts usages of the pattern

cases h
case inl h' => ...
case inr h' => ...

which derive from mathported code, to the "structured cases" syntax:

cases h with
| inl h' => ...
| inr h' => ...

The case where the subgoals are handled with · instead of case is more contentious (and much more numerous) so I left those alone. This pattern also appears with cases', induction, induction', and rcases. Furthermore, there is a similar transformation for by_cases:

by_cases h : cond
case pos => ...
case neg => ...

is replaced by:

if h : cond then
  ...
else
  ...

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

Diff
@@ -145,18 +145,17 @@ theorem perm_comp_perm : (Perm ∘r Perm : List α → List α → Prop) = Perm
 
 theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) :
     (Forall₂ r ∘r Perm) l v := by
-  induction hlu generalizing v
-  case nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩
-  case cons a l u _hlu ih =>
+  induction hlu generalizing v with
+  | nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩
+  | cons u _hlu ih =>
     cases' huv with _ b _ v hab huv'
     rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩
     exact ⟨b :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩
-  case swap a₁ a₂ h₂₃ =>
+  | swap a₁ a₂ h₂₃ =>
     cases' huv with _ b₁ _ l₂ h₁ hr₂₃
     cases' hr₂₃ with _ b₂ _ l₂ h₂ h₁₂
     exact ⟨b₂ :: b₁ :: l₂, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩
-  case
-    trans la₁ la₂ la₃ _ _ ih₁ ih₂ =>
+  | trans _ _ ih₁ ih₂ =>
     rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩
     rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩
     exact ⟨lb₁, hab₁, Perm.trans h₁₂ h₂₃⟩
@@ -267,11 +266,11 @@ theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : Righ
 theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
     ∀ b, foldr f b l₁ = foldr f b l₂ := by
   intro b
-  induction p using Perm.recOnSwap' generalizing b
-  case nil => rfl
-  case cons r  => simp; rw [r b]
-  case swap' r => simp; rw [lcomm, r b]
-  case trans r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b)
+  induction p using Perm.recOnSwap' generalizing b with
+  | nil => rfl
+  | cons _ _ r  => simp; rw [r b]
+  | swap' _ _ _ r => simp; rw [lcomm, r b]
+  | trans _ _ r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b)
 #align list.perm.foldr_eq List.Perm.foldr_eq
 
 #align list.perm.rec_heq List.Perm.rec_heq
@@ -358,16 +357,16 @@ alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons
 theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (h₁ : a ∉ l₁) (h₂ : a ∈ l₂)
     (s : l₁ <+~ l₂) : a :: l₁ <+~ l₂ := by
   rcases s with ⟨l, p, s⟩
-  induction s generalizing l₁
-  case slnil => cases h₂
-  case cons r₁ r₂ b s' ih =>
+  induction s generalizing l₁ with
+  | slnil => cases h₂
+  | @cons r₁ r₂ b s' ih =>
     simp? at h₂ says simp only [mem_cons] at h₂
     cases' h₂ with e m
     · subst b
       exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩
     · rcases ih d₁ h₁ m p with ⟨t, p', s'⟩
       exact ⟨t, p', s'.cons _⟩
-  case cons₂ r₁ r₂ b _ ih =>
+  | @cons₂ r₁ r₂ b _ ih =>
     have bm : b ∈ l₁ := p.subset <| mem_cons_self _ _
     have am : a ∈ r₂ := by
       simp only [find?, mem_cons] at h₂
@@ -503,9 +502,9 @@ theorem Perm.dedup {l₁ l₂ : List α} (p : l₁ ~ l₂) : dedup l₁ ~ dedup
 
 theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) :
     l ∩ (t₁ ++ t₂) ~ l ∩ t₁ ++ l ∩ t₂ := by
-  induction l
-  case nil => simp
-  case cons x xs l_ih =>
+  induction l with
+  | nil => simp
+  | cons x xs l_ih =>
     by_cases h₁ : x ∈ t₁
     · have h₂ : x ∉ t₂ := h h₁
       simp [*]
chore: move to v4.5.0-rc1, and merge changes from bump/v4.5.0 branch. (#9188)

This PR:

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

Diff
@@ -361,7 +361,7 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (
   induction s generalizing l₁
   case slnil => cases h₂
   case cons r₁ r₂ b s' ih =>
-    simp? at h₂ says simp only [Bool.not_eq_true, mem_cons] at h₂
+    simp? at h₂ says simp only [mem_cons] at h₂
     cases' h₂ with e m
     · subst b
       exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩
chore: Remove nonterminal simp at (#7795)

Removes nonterminal uses of simp at. Replaces most of these with instances of simp? ... says.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Mario Carneiro <di.gama@gmail.com>

Diff
@@ -361,7 +361,7 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (
   induction s generalizing l₁
   case slnil => cases h₂
   case cons r₁ r₂ b s' ih =>
-    simp at h₂
+    simp? at h₂ says simp only [Bool.not_eq_true, mem_cons] at h₂
     cases' h₂ with e m
     · subst b
       exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩
@@ -670,7 +670,8 @@ theorem length_permutationsAux :
   refine' permutationsAux.rec (by simp) _
   intro t ts is IH1 IH2
   have IH2 : length (permutationsAux is nil) + 1 = is.length ! := by simpa using IH2
-  simp [Nat.factorial, Nat.add_succ, mul_comm] at IH1
+  simp? [Nat.factorial, Nat.add_succ, mul_comm] at IH1 says
+    simp only [factorial, add_eq, add_zero, mul_comm] at IH1
   rw [permutationsAux_cons,
     length_foldr_permutationsAux2' _ _ _ _ _ fun l m => (perm_of_mem_permutations m).length_eq,
     permutations, length, length, IH2, Nat.succ_add, Nat.factorial_succ, mul_comm (_ + 1),
chore: bump std to leanprover/lean4#429 (#8990)

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

Diff
@@ -229,14 +229,9 @@ lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
   obtain ⟨l', h₂⟩ := h₂.exists_perm_append
   exact ⟨l₁ ++ l', (h₂.trans (h₁.append_right _)).symm, (prefix_append _ _).sublist⟩
 
--- This is now in `Std`, but apparently misnamed as `List.subperm_singleton_iff`.
-lemma singleton_subperm_iff : [a] <+~ l ↔ a ∈ l :=
-  ⟨fun ⟨s, hla, h⟩ ↦ by rwa [perm_singleton.1 hla, singleton_sublist] at h,
-    fun h ↦ ⟨[a], perm_rfl, singleton_sublist.2 h⟩⟩
 #align list.subperm_singleton_iff List.singleton_subperm_iff
 
--- The prime could be removed if `List.subperm_singleton_iff` is renamed in Std.
-@[simp] lemma subperm_singleton_iff' : l <+~ [a] ↔ l = [] ∨ l = [a] := by
+@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
   constructor
   · rw [subperm_iff]
     rintro ⟨s, hla, h⟩
chore: update std4 to b197bd2, catching up to leanprover/std4#427 (#8888)

Co-authored-by: James <jamesgallicchio@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Mario Carneiro <di.gama@gmail.com> Co-authored-by: Siddharth Bhat <siddu.druid@gmail.com>

Diff
@@ -229,7 +229,6 @@ lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
   obtain ⟨l', h₂⟩ := h₂.exists_perm_append
   exact ⟨l₁ ++ l', (h₂.trans (h₁.append_right _)).symm, (prefix_append _ _).sublist⟩
 
-
 -- This is now in `Std`, but apparently misnamed as `List.subperm_singleton_iff`.
 lemma singleton_subperm_iff : [a] <+~ l ↔ a ∈ l :=
   ⟨fun ⟨s, hla, h⟩ ↦ by rwa [perm_singleton.1 hla, singleton_sublist] at h,
chore: patch std4#89 (#8566)

Co-authored-by: Mario Carneiro <di.gama@gmail.com> Co-authored-by: Tobias Grosser <tobias@grosser.es> Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Scott Morrison <scott@tqft.net>

Diff
@@ -27,13 +27,6 @@ open Nat
 namespace List
 variable {α β : Type*} {l l₁ l₂ : List α} {a : α}
 
-/-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations
-  of each other. This is defined by induction using pairwise swaps. -/
-inductive Perm : List α → List α → Prop
-  | nil : Perm [] []
-  | cons (x : α) {l₁ l₂ : List α} : Perm l₁ l₂ → Perm (x :: l₁) (x :: l₂)
-  | swap (x y : α) (l : List α) : Perm (y :: x :: l) (x :: y :: l)
-  | trans {l₁ l₂ l₃ : List α} : Perm l₁ l₂ → Perm l₂ l₃ → Perm l₁ l₃
 #align list.perm List.Perm
 
 instance {α : Type*} : Trans (@List.Perm α) (@List.Perm α) List.Perm where
@@ -41,61 +34,27 @@ instance {α : Type*} : Trans (@List.Perm α) (@List.Perm α) List.Perm where
 
 open Perm (swap)
 
-/-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations
-  of each other. This is defined by induction using pairwise swaps. -/
-infixl:50 " ~ " => Perm
-
-@[simp, refl]
-protected theorem Perm.refl : ∀ l : List α, l ~ l
-  | [] => Perm.nil
-  | x :: xs => (Perm.refl xs).cons x
+attribute [refl] Perm.refl
 #align list.perm.refl List.Perm.refl
 
 lemma perm_rfl : l ~ l := Perm.refl _
 
 -- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it
-@[symm]
-protected theorem Perm.symm {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₂ ~ l₁ :=
-  p.rec
-    .nil
-    (fun x _ _ _ r₁ => .cons x r₁)
-    (fun x y l => .swap y x l)
-    (fun _ _ r₁ r₂ => .trans r₂ r₁)
+attribute [symm] Perm.symm
 #align list.perm.symm List.Perm.symm
 
-theorem perm_comm {l₁ l₂ : List α} : l₁ ~ l₂ ↔ l₂ ~ l₁ :=
-  ⟨Perm.symm, Perm.symm⟩
 #align list.perm_comm List.perm_comm
 
-theorem Perm.swap' (x y : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : y :: x :: l₁ ~ x :: y :: l₂ :=
-  (swap _ _ _).trans ((p.cons _).cons _)
 #align list.perm.swap' List.Perm.swap'
 
 attribute [trans] Perm.trans
 
-theorem Perm.eqv (α) : Equivalence (@Perm α) :=
-  ⟨Perm.refl, Perm.symm, Perm.trans⟩
 #align list.perm.eqv List.Perm.eqv
 
---Porting note: new theorem
-theorem Perm.of_eq (h : l₁ = l₂) : l₁ ~ l₂ :=
-  h ▸ Perm.refl l₁
-
-instance isSetoid (α) : Setoid (List α) :=
-  Setoid.mk (@Perm α) (Perm.eqv α)
 #align list.is_setoid List.isSetoid
 
--- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it
-theorem Perm.mem_iff {a : α} {l₁ l₂ : List α} (p : l₁ ~ l₂) : a ∈ l₁ ↔ a ∈ l₂ :=
-  p.rec
-    Iff.rfl
-    (fun _ _ _ _ hs => by simp only [mem_cons, hs])
-    (fun _ _ _ => by simp only [mem_cons, or_left_comm])
-    (fun _ _ => Iff.trans)
 #align list.perm.mem_iff List.Perm.mem_iff
 
-theorem Perm.subset {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ :=
-  fun _ => p.mem_iff.mp
 #align list.perm.subset List.Perm.subset
 
 theorem Perm.subset_congr_left {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₁ ⊆ l₃ ↔ l₂ ⊆ l₃ :=
@@ -106,219 +65,66 @@ theorem Perm.subset_congr_right {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l
   ⟨fun h' => h'.trans h.subset, fun h' => h'.trans h.symm.subset⟩
 #align list.perm.subset_congr_right List.Perm.subset_congr_right
 
-theorem Perm.append_right {l₁ l₂ : List α} (t₁ : List α) (p : l₁ ~ l₂) : l₁ ++ t₁ ~ l₂ ++ t₁ :=
-  p.rec
-    (Perm.refl ([] ++ t₁))
-    (fun x _ _ _ r₁ => r₁.cons x)
-    (fun x y _ => swap x y _)
-    (fun _ _ r₁ r₂ => r₁.trans r₂)
 #align list.perm.append_right List.Perm.append_right
 
-theorem Perm.append_left {t₁ t₂ : List α} : ∀ l : List α, t₁ ~ t₂ → l ++ t₁ ~ l ++ t₂
-  | [], p => p
-  | x :: xs, p => (p.append_left xs).cons x
 #align list.perm.append_left List.Perm.append_left
 
-theorem Perm.append {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ++ t₁ ~ l₂ ++ t₂ :=
-  (p₁.append_right t₁).trans (p₂.append_left l₂)
 #align list.perm.append List.Perm.append
 
-theorem Perm.append_cons (a : α) {h₁ h₂ t₁ t₂ : List α} (p₁ : h₁ ~ h₂) (p₂ : t₁ ~ t₂) :
-    h₁ ++ a :: t₁ ~ h₂ ++ a :: t₂ :=
-  p₁.append (p₂.cons a)
 #align list.perm.append_cons List.Perm.append_cons
 
-@[simp]
-theorem perm_middle {a : α} : ∀ {l₁ l₂ : List α}, l₁ ++ a :: l₂ ~ a :: (l₁ ++ l₂)
-  | [], _ => Perm.refl _
-  | b :: l₁, l₂ => ((@perm_middle a l₁ l₂).cons _).trans (swap a b _)
 #align list.perm_middle List.perm_middle
 
-@[simp]
-theorem perm_append_singleton (a : α) (l : List α) : l ++ [a] ~ a :: l :=
-  perm_middle.trans <| by rw [append_nil]
 #align list.perm_append_singleton List.perm_append_singleton
 
-theorem perm_append_comm : ∀ {l₁ l₂ : List α}, l₁ ++ l₂ ~ l₂ ++ l₁
-  | [], l₂ => by simp
-  | a :: t, l₂ => (perm_append_comm.cons _).trans perm_middle.symm
 #align list.perm_append_comm List.perm_append_comm
 
-theorem concat_perm (l : List α) (a : α) : concat l a ~ a :: l := by simp
 #align list.concat_perm List.concat_perm
 
-theorem Perm.length_eq {l₁ l₂ : List α} (p : l₁ ~ l₂) : length l₁ = length l₂ :=
-  p.rec
-    rfl
-    (fun _x l₁ l₂ _p r => by simp [r])
-    (fun _x _y l => by simp)
-    (fun _p₁ _p₂ r₁ r₂ => Eq.trans r₁ r₂)
 #align list.perm.length_eq List.Perm.length_eq
 
-theorem Perm.eq_nil {l : List α} (p : l ~ []) : l = [] :=
-  eq_nil_of_length_eq_zero p.length_eq
 #align list.perm.eq_nil List.Perm.eq_nil
 
-theorem Perm.nil_eq {l : List α} (p : [] ~ l) : [] = l :=
-  p.symm.eq_nil.symm
 #align list.perm.nil_eq List.Perm.nil_eq
 
-@[simp]
-theorem perm_nil {l₁ : List α} : l₁ ~ [] ↔ l₁ = [] :=
-  ⟨fun p => p.eq_nil, fun e => e ▸ Perm.refl _⟩
 #align list.perm_nil List.perm_nil
 
-@[simp]
-theorem nil_perm {l₁ : List α} : [] ~ l₁ ↔ l₁ = [] :=
-  perm_comm.trans perm_nil
 #align list.nil_perm List.nil_perm
 
-theorem not_perm_nil_cons (x : α) (l : List α) : ¬[] ~ x :: l
-  | p => by injection p.symm.eq_nil
 #align list.not_perm_nil_cons List.not_perm_nil_cons
 
-@[simp]
-theorem reverse_perm : ∀ l : List α, reverse l ~ l
-  | [] => Perm.nil
-  | a :: l => by
-    rw [reverse_cons]
-    exact (perm_append_singleton _ _).trans ((reverse_perm l).cons a)
 #align list.reverse_perm List.reverse_perm
 
-theorem perm_cons_append_cons {l l₁ l₂ : List α} (a : α) (p : l ~ l₁ ++ l₂) :
-    a :: l ~ l₁ ++ a :: l₂ :=
-  (p.cons a).trans perm_middle.symm
 #align list.perm_cons_append_cons List.perm_cons_append_cons
 
-@[simp]
-theorem perm_replicate {n : ℕ} {a : α} {l : List α} :
-    l ~ replicate n a ↔ l = replicate n a :=
-  ⟨fun p => eq_replicate.2
-    ⟨p.length_eq.trans <| length_replicate _ _, fun _b m => eq_of_mem_replicate <| p.subset m⟩,
-    fun h => h ▸ Perm.refl _⟩
 #align list.perm_replicate List.perm_replicate
 
-@[simp]
-theorem replicate_perm {n : ℕ} {a : α} {l : List α} :
-    replicate n a ~ l ↔ replicate n a = l :=
-  (perm_comm.trans perm_replicate).trans eq_comm
 #align list.replicate_perm List.replicate_perm
 
-@[simp]
-theorem perm_singleton {a : α} {l : List α} : l ~ [a] ↔ l = [a] :=
-  @perm_replicate α 1 a l
 #align list.perm_singleton List.perm_singleton
 
-@[simp]
-theorem singleton_perm {a : α} {l : List α} : [a] ~ l ↔ [a] = l :=
-  @replicate_perm α 1 a l
 #align list.singleton_perm List.singleton_perm
 
-alias ⟨Perm.eq_singleton, _⟩ := perm_singleton
-alias ⟨Perm.singleton_eq, _⟩ := singleton_perm
-
-theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp
 #align list.singleton_perm_singleton List.singleton_perm_singleton
 
-theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : l ~ a :: l.erase a :=
-  let ⟨_l₁, _l₂, _, e₁, e₂⟩ := exists_erase_eq h
-  e₂.symm ▸ e₁.symm ▸ perm_middle
 #align list.perm_cons_erase List.perm_cons_erase
 
-@[elab_as_elim]
-theorem perm_induction_on {P : List α → List α → Prop} {l₁ l₂ : List α} (p : l₁ ~ l₂) (h₁ : P [] [])
-    (h₂ : ∀ x l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (x :: l₁) (x :: l₂))
-    (h₃ : ∀ x y l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (y :: x :: l₁) (x :: y :: l₂))
-    (h₄ : ∀ l₁ l₂ l₃, l₁ ~ l₂ → l₂ ~ l₃ → P l₁ l₂ → P l₂ l₃ → P l₁ l₃) : P l₁ l₂ :=
-  have P_refl : ∀ l, P l l := fun l => List.recOn l h₁ fun x xs ih => h₂ x xs xs (Perm.refl xs) ih
-  p.rec h₁ h₂ (fun x y l => h₃ x y l l (Perm.refl l) (P_refl l)) @h₄
-#align list.perm_induction_on List.perm_induction_onₓ
+#align list.perm_induction_on List.Perm.recOnSwap'
 
--- Porting note: TODO figure out why invalid congr
--- @[congr]
-theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~ l₂) :
-    filterMap f l₁ ~ filterMap f l₂ := by
-  induction p with
-  | nil => simp
-  | cons x _p IH =>
-    cases h : f x
-      <;> simp [h, filterMap, IH, Perm.cons]
-  | swap x y l₂ =>
-    cases hx : f x
-      <;> cases hy : f y
-        <;> simp [hx, hy, filterMap, swap]
-  | trans _p₁ _p₂ IH₁ IH₂ =>
-    exact IH₁.trans IH₂
+-- Porting note: used to be @[congr]
 #align list.perm.filter_map List.Perm.filterMap
 
--- Porting note: TODO figure out why invalid congr
--- @[congr]
-theorem Perm.map (f : α → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : map f l₁ ~ map f l₂ :=
-  filterMap_eq_map f ▸ p.filterMap _
+-- Porting note: used to be @[congr]
 #align list.perm.map List.Perm.map
 
-theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) {H₁ H₂} :
-    pmap f l₁ H₁ ~ pmap f l₂ H₂ := by
-  induction p with
-  | nil => simp
-  | cons x _p IH => simp [IH, Perm.cons]
-  | swap x y => simp [swap]
-  | trans _p₁ p₂ IH₁ IH₂ =>
-    refine' IH₁.trans IH₂
-    exact fun a m => H₂ a (p₂.subset m)
 #align list.perm.pmap List.Perm.pmap
 
-theorem Perm.filter (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
-    filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap _
 #align list.perm.filter List.Perm.filter
 
-theorem filter_append_perm (p : α → Bool) (l : List α) :
-    filter p l ++ filter (fun x => ¬p x) l ~ l := by
-  induction' l with x l ih
-  · rfl
-  · by_cases h : p x
-    · simp only [h, filter_cons_of_pos, filter_cons_of_neg, not_true, not_false_iff, cons_append,
-        decide_False]
-      exact ih.cons x
-    · simp only [h, filter_cons_of_neg, not_false_iff, filter_cons_of_pos, cons_append,
-        not_false_eq_true, decide_True]
-      refine' Perm.trans _ (ih.cons x)
-      exact perm_append_comm.trans (perm_append_comm.cons _)
 #align list.filter_append_perm List.filter_append_perm
 
-theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
-    ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' := by
-  induction p generalizing l₁ with
-  | nil =>
-    exact ⟨[], eq_nil_of_sublist_nil s ▸ Perm.refl _, nil_sublist _⟩
-  | cons x _ IH =>
-    cases' s with _ _ _ s l₁ _ _ s
-    · exact
-        let ⟨l₁', p', s'⟩ := IH s
-        ⟨l₁', p', s'.cons _⟩
-    · exact
-        let ⟨l₁', p', s'⟩ := IH s
-        ⟨x :: l₁', p'.cons x, s'.cons₂ _⟩
-  | swap x y _ =>
-    cases' s with _ _ _ s l₁ _ _ s <;> cases' s with _ _ _ s l₁ _ _ s
-    · exact ⟨l₁, Perm.refl _, (s.cons _).cons _⟩
-    · exact ⟨x :: l₁, Perm.refl _, (s.cons _).cons₂ _⟩
-    · exact ⟨y :: l₁, Perm.refl _, (s.cons₂ _).cons _⟩
-    · exact ⟨x :: y :: l₁, Perm.swap _ _ _, (s.cons₂ _).cons₂ _⟩
-  | trans _ _ IH₁ IH₂ =>
-    exact
-      let ⟨m₁, pm, sm⟩ := IH₁ s
-      let ⟨r₁, pr, sr⟩ := IH₂ sm
-      ⟨r₁, pr.trans pm, sr⟩
 #align list.exists_perm_sublist List.exists_perm_sublist
 
-theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂) :
-    sizeOf l₁ = sizeOf l₂ := by
-  induction h with -- hd l₁ l₂ h₁₂ h_sz₁₂ a b l l₁ l₂ l₃ h₁₂ h₂₃ h_sz₁₂ h_sz₂₃
-  | nil => rfl
-  | cons _ _ h_sz₁₂ => simp [h_sz₁₂]
-  | swap => simp [add_left_comm]
-  | trans _ _ h_sz₁₂ h_sz₂₃ => simp [h_sz₁₂, h_sz₂₃]
 #align list.perm.sizeof_eq_sizeof List.Perm.sizeOf_eq_sizeOf
 
 section Rel
@@ -387,85 +193,34 @@ end Rel
 section Subperm
 
 
-/-- `Subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
-  a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
-  multiplicities of elements, and is used for the `≤` relation on multisets. -/
-def Subperm (l₁ l₂ : List α) : Prop :=
-  ∃ (l : _) (_ : l ~ l₁), l <+ l₂
-#align list.subperm List.Subperm
-
-/-- `Subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
-  a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
-  multiplicities of elements, and is used for the `≤` relation on multisets. -/
-infixl:50 " <+~ " => Subperm
-
-theorem nil_subperm {l : List α} : [] <+~ l :=
-  ⟨[], Perm.nil, by simp⟩
 #align list.nil_subperm List.nil_subperm
 
-theorem Perm.subperm_left {l l₁ l₂ : List α} (p : l₁ ~ l₂) : l <+~ l₁ ↔ l <+~ l₂ :=
-  suffices ∀ {l₁ l₂ : List α}, l₁ ~ l₂ → l <+~ l₁ → l <+~ l₂ from ⟨this p, this p.symm⟩
-  fun p ⟨_u, pu, su⟩ =>
-  let ⟨v, pv, sv⟩ := exists_perm_sublist su p
-  ⟨v, pv.trans pu, sv⟩
 #align list.perm.subperm_left List.Perm.subperm_left
 
-theorem Perm.subperm_right {l₁ l₂ l : List α} (p : l₁ ~ l₂) : l₁ <+~ l ↔ l₂ <+~ l :=
-  ⟨fun ⟨u, pu, su⟩ => ⟨u, pu.trans p, su⟩, fun ⟨u, pu, su⟩ => ⟨u, pu.trans p.symm, su⟩⟩
 #align list.perm.subperm_right List.Perm.subperm_right
 
-theorem Sublist.subperm {l₁ l₂ : List α} (s : l₁ <+ l₂) : l₁ <+~ l₂ :=
-  ⟨l₁, Perm.refl _, s⟩
 #align list.sublist.subperm List.Sublist.subperm
 
-theorem Perm.subperm {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ <+~ l₂ :=
-  ⟨l₂, p.symm, Sublist.refl _⟩
 #align list.perm.subperm List.Perm.subperm
 
-@[refl]
-theorem Subperm.refl (l : List α) : l <+~ l :=
-  (Perm.refl _).subperm
+attribute [refl] Subperm.refl
 #align list.subperm.refl List.Subperm.refl
 
-@[trans]
-theorem Subperm.trans {l₁ l₂ l₃ : List α} : l₁ <+~ l₂ → l₂ <+~ l₃ → l₁ <+~ l₃
-  | s, ⟨_l₂', p₂, s₂⟩ =>
-    let ⟨l₁', p₁, s₁⟩ := p₂.subperm_left.2 s
-    ⟨l₁', p₁, s₁.trans s₂⟩
+attribute [trans] Subperm.trans
 #align list.subperm.trans List.Subperm.trans
 
-theorem Subperm.length_le {l₁ l₂ : List α} : l₁ <+~ l₂ → length l₁ ≤ length l₂
-  | ⟨_l, p, s⟩ => p.length_eq ▸ s.length_le
 #align list.subperm.length_le List.Subperm.length_le
 
-theorem Subperm.perm_of_length_le {l₁ l₂ : List α} : l₁ <+~ l₂ → length l₂ ≤ length l₁ → l₁ ~ l₂
-  | ⟨_l, p, s⟩, h => (s.eq_of_length_le <| p.symm.length_eq ▸ h) ▸ p.symm
 #align list.subperm.perm_of_length_le List.Subperm.perm_of_length_le
 
-theorem Subperm.antisymm {l₁ l₂ : List α} (h₁ : l₁ <+~ l₂) (h₂ : l₂ <+~ l₁) : l₁ ~ l₂ :=
-  h₁.perm_of_length_le h₂.length_le
 #align list.subperm.antisymm List.Subperm.antisymm
 
-theorem Subperm.subset {l₁ l₂ : List α} : l₁ <+~ l₂ → l₁ ⊆ l₂
-  | ⟨_l, p, s⟩ => Subset.trans p.symm.subset s.subset
 #align list.subperm.subset List.Subperm.subset
 
-theorem Subperm.filter (p : α → Bool) ⦃l l' : List α⦄ (h : l <+~ l') :
-    filter p l <+~ filter p l' := by
-  obtain ⟨xs, hp, h⟩ := h
-  exact ⟨_, hp.filter p, h.filter p⟩
 #align list.subperm.filter List.Subperm.filter
 
 end Subperm
 
-theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∃ l, l₂ ~ l₁ ++ l
-  | _, _, Sublist.slnil => ⟨nil, Perm.refl _⟩
-  | _, _, Sublist.cons a s =>
-    let ⟨l, p⟩ := Sublist.exists_perm_append s
-    ⟨a :: l, (p.cons a).trans perm_middle.symm⟩
-  | _, _, Sublist.cons₂ a s =>
-    let ⟨l, p⟩ := Sublist.exists_perm_append s
-    ⟨l, p.cons a⟩
 #align list.sublist.exists_perm_append List.Sublist.exists_perm_append
 
 lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
@@ -474,12 +229,15 @@ lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
   obtain ⟨l', h₂⟩ := h₂.exists_perm_append
   exact ⟨l₁ ++ l', (h₂.trans (h₁.append_right _)).symm, (prefix_append _ _).sublist⟩
 
-@[simp] lemma singleton_subperm_iff : [a] <+~ l ↔ a ∈ l :=
+
+-- This is now in `Std`, but apparently misnamed as `List.subperm_singleton_iff`.
+lemma singleton_subperm_iff : [a] <+~ l ↔ a ∈ l :=
   ⟨fun ⟨s, hla, h⟩ ↦ by rwa [perm_singleton.1 hla, singleton_sublist] at h,
     fun h ↦ ⟨[a], perm_rfl, singleton_sublist.2 h⟩⟩
 #align list.subperm_singleton_iff List.singleton_subperm_iff
 
-@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
+-- The prime could be removed if `List.subperm_singleton_iff` is renamed in Std.
+@[simp] lemma subperm_singleton_iff' : l <+~ [a] ↔ l = [] ∨ l = [a] := by
   constructor
   · rw [subperm_iff]
     rintro ⟨s, hla, h⟩
@@ -487,58 +245,24 @@ lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
   · rintro (rfl | rfl)
     exacts [nil_subperm, Subperm.refl _]
 
-theorem Perm.countP_eq (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
-    countP p l₁ = countP p l₂ := by
-  rw [countP_eq_length_filter, countP_eq_length_filter]; exact (s.filter _).length_eq
 #align list.perm.countp_eq List.Perm.countP_eq
 
-theorem Subperm.countP_le (p : α → Bool) {l₁ l₂ : List α} :
-    l₁ <+~ l₂ → countP p l₁ ≤ countP p l₂
-  | ⟨_l, p', s⟩ => p'.countP_eq p ▸ s.countP_le p
 #align list.subperm.countp_le List.Subperm.countP_le
 
-theorem Perm.countP_congr (s : l₁ ~ l₂) {p p' : α → Bool}
-    (hp : ∀ x ∈ l₁, p x ↔ p' x) : l₁.countP p = l₂.countP p' := by
-  rw [← s.countP_eq p']
-  clear s
-  induction' l₁ with y s hs
-  · rfl
-  · simp only [mem_cons, forall_eq_or_imp] at hp
-    simp only [countP_cons, hs hp.2, hp.1]
 #align list.perm.countp_congr List.Perm.countP_congr
 
-theorem countP_eq_countP_filter_add (l : List α) (p q : α → Bool) :
-    l.countP p = (l.filter q).countP p + (l.filter fun a => ¬q a).countP p := by
-  rw [← countP_append]
-  exact Perm.countP_eq _ (filter_append_perm _ _).symm
 #align list.countp_eq_countp_filter_add List.countP_eq_countP_filter_add
 
 lemma count_eq_count_filter_add [DecidableEq α] (P : α → Prop) [DecidablePred P]
     (l : List α) (a : α) :
     count a l = count a (l.filter P) + count a (l.filter (¬ P ·)) := by
   convert countP_eq_countP_filter_add l _ P
-  simp only [decide_eq_true_eq]
+  simp only [decide_not]
 
-theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
-    count a l₁ = count a l₂ :=
-  p.countP_eq _
 #align list.perm.count_eq List.Perm.count_eq
 
-theorem Subperm.count_le [DecidableEq α] {l₁ l₂ : List α} (s : l₁ <+~ l₂) (a) :
-    count a l₁ ≤ count a l₂ :=
-  s.countP_le _
 #align list.subperm.count_le List.Subperm.count_le
 
-theorem Perm.foldl_eq' {f : β → α → β} {l₁ l₂ : List α} (p : l₁ ~ l₂) :
-    (∀ x ∈ l₁, ∀ y ∈ l₁, ∀ (z), f (f z x) y = f (f z y) x) → ∀ b, foldl f b l₁ = foldl f b l₂ :=
-  perm_induction_on p (fun _H b => rfl)
-    (fun x t₁ t₂ _p r H b => r (fun x hx y hy => H _ (.tail _ hx) _ (.tail _ hy)) _)
-    (fun x y t₁ t₂ _p r H b => by
-      simp only [foldl]
-      rw [H x (.tail _ <| .head _) y (.head _)]
-      exact r (fun x hx y hy => H _ (.tail _ <| .tail _ hx) _ (.tail _ <| .tail _ hy)) _)
-    fun t₁ t₂ t₃ p₁ _p₂ r₁ r₂ H b =>
-    Eq.trans (r₁ H b) (r₂ (fun x hx y hy => H _ (p₁.symm.subset hx) _ (p₁.symm.subset hy)) b)
 #align list.perm.foldl_eq' List.Perm.foldl_eq'
 
 theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : RightCommutative f) (p : l₁ ~ l₂) :
@@ -547,21 +271,15 @@ theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : Righ
 #align list.perm.foldl_eq List.Perm.foldl_eq
 
 theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
-    ∀ b, foldr f b l₁ = foldr f b l₂ :=
-  perm_induction_on p (fun b => rfl) (fun x t₁ t₂ _p r b => by simp; rw [r b])
-    (fun x y t₁ t₂ _p r b => by simp; rw [lcomm, r b]) fun t₁ t₂ t₃ _p₁ _p₂ r₁ r₂ a =>
-    Eq.trans (r₁ a) (r₂ a)
+    ∀ b, foldr f b l₁ = foldr f b l₂ := by
+  intro b
+  induction p using Perm.recOnSwap' generalizing b
+  case nil => rfl
+  case cons r  => simp; rw [r b]
+  case swap' r => simp; rw [lcomm, r b]
+  case trans r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b)
 #align list.perm.foldr_eq List.Perm.foldr_eq
 
-theorem Perm.rec_heq {β : List α → Sort*} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α}
-    (hl : Perm l l') (f_congr : ∀ {a l l' b b'}, Perm l l' → HEq b b' → HEq (f a l b) (f a l' b'))
-    (f_swap : ∀ {a a' l b}, HEq (f a (a' :: l) (f a' l b)) (f a' (a :: l) (f a l b))) :
-    HEq (@List.rec α β b f l) (@List.rec α β b f l') := by
-  induction hl
-  case nil => rfl
-  case cons a l l' h ih => exact f_congr h ih
-  case swap a a' l => exact f_swap
-  case trans l₁ l₂ l₃ _h₁ _h₂ ih₁ ih₂ => exact HEq.trans ih₁ ih₂
 #align list.perm.rec_heq List.Perm.rec_heq
 
 section
@@ -616,71 +334,14 @@ theorem prod_reverse (l : List α) : prod l.reverse = prod l :=
 
 end CommMonoid
 
-theorem perm_inv_core {a : α} {l₁ l₂ r₁ r₂ : List α} :
-    l₁ ++ a :: r₁ ~ l₂ ++ a :: r₂ → l₁ ++ r₁ ~ l₂ ++ r₂ := by
-  generalize e₁ : l₁ ++ a :: r₁ = s₁; generalize e₂ : l₂ ++ a :: r₂ = s₂
-  intro p; revert l₁ l₂ r₁ r₂ e₁ e₂; clear l₁ l₂ β
-  show ∀ _ _ _ _, _
-  refine
-      perm_induction_on p ?_ (fun x t₁ t₂ p IH => ?_) (fun x y t₁ t₂ p IH => ?_)
-        fun t₁ t₂ t₃ p₁ p₂ IH₁ IH₂ => ?_
-    <;> intro l₁ l₂ r₁ r₂ e₁ e₂
-  · apply (not_mem_nil a).elim
-    rw [← e₁]
-    simp
-  · cases' l₁ with y l₁ <;> cases' l₂ with z l₂ <;> dsimp at e₁ e₂ <;> injections <;> subst x
-    · substs t₁ t₂
-      exact p
-    · substs z t₁ t₂
-      exact p.trans perm_middle
-    · substs y t₁ t₂
-      exact perm_middle.symm.trans p
-    · substs z t₁ t₂
-      exact (IH _ _ _ _ rfl rfl).cons y
-  · rcases l₁ with (_ | ⟨y, _ | ⟨z, l₁⟩⟩) <;> rcases l₂ with (_ | ⟨u, _ | ⟨v, l₂⟩⟩) <;>
-          dsimp at e₁ e₂ <;> injections <;> substs x y
-    · substs r₁ r₂
-      exact p.cons a
-    · substs r₁ r₂
-      exact p.cons u
-    · substs r₁ v t₂
-      exact (p.trans perm_middle).cons u
-    · substs r₁ r₂
-      exact p.cons y
-    · substs r₁ r₂ y u
-      exact p.cons a
-    · substs r₁ u v t₂
-      exact ((p.trans perm_middle).cons y).trans (swap _ _ _)
-    · substs r₂ z t₁
-      exact (perm_middle.symm.trans p).cons y
-    · substs r₂ y z t₁
-      exact (swap _ _ _).trans ((perm_middle.symm.trans p).cons u)
-    · substs u v t₁ t₂
-      exact (IH _ _ _ _ rfl rfl).swap' _ _
-  · substs t₁ t₃
-    have : a ∈ t₂ := p₁.subset (by simp)
-    rcases mem_split this with ⟨l₂, r₂, e₂⟩
-    subst t₂
-    exact (IH₁ _ _ _ _ rfl rfl).trans (IH₂ _ _ _ _ rfl rfl)
 #align list.perm_inv_core List.perm_inv_core
 
-theorem Perm.cons_inv {a : α} {l₁ l₂ : List α} : a :: l₁ ~ a :: l₂ → l₁ ~ l₂ :=
-  @perm_inv_core _ _ [] [] _ _
 #align list.perm.cons_inv List.Perm.cons_inv
 
-@[simp]
-theorem perm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ ~ a :: l₂ ↔ l₁ ~ l₂ :=
-  ⟨Perm.cons_inv, Perm.cons a⟩
 #align list.perm_cons List.perm_cons
 
-theorem perm_append_left_iff {l₁ l₂ : List α} : ∀ l, l ++ l₁ ~ l ++ l₂ ↔ l₁ ~ l₂
-  | [] => Iff.rfl
-  | a :: l => (perm_cons a).trans (perm_append_left_iff l)
 #align list.perm_append_left_iff List.perm_append_left_iff
 
-theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l ↔ l₁ ~ l₂ :=
-  ⟨fun p => (perm_append_left_iff _).1 <| perm_append_comm.trans <| p.trans perm_append_comm,
-    Perm.append_right _⟩
 #align list.perm_append_right_iff List.perm_append_right_iff
 
 theorem perm_option_to_list {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList ↔ o₁ = o₂ := by
@@ -691,11 +352,6 @@ theorem perm_option_to_list {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList
   · exact Option.mem_toList.1 (p.symm.subset <| by simp)
 #align list.perm_option_to_list List.perm_option_to_list
 
-theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ ↔ l₁ <+~ l₂ :=
-  ⟨fun ⟨l, p, s⟩ => by
-    cases' s with _ _ _ s' u _ _ s'
-    · exact (p.subperm_left.2 <| (sublist_cons _ _).subperm).trans s'.subperm
-    · exact ⟨u, p.cons_inv, s'⟩, fun ⟨l, p, s⟩ => ⟨a :: l, p.cons a, s.cons₂ _⟩⟩
 #align list.subperm_cons List.subperm_cons
 
 alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons
@@ -731,127 +387,45 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (
       ⟨b :: t, (p'.cons b).trans <| (swap _ _ _).trans (perm_middle.symm.cons a), s'.cons₂ _⟩
 #align list.cons_subperm_of_mem List.cons_subperm_of_mem
 
-theorem subperm_append_left {l₁ l₂ : List α} : ∀ l, l ++ l₁ <+~ l ++ l₂ ↔ l₁ <+~ l₂
-  | [] => Iff.rfl
-  | a :: l => (subperm_cons a).trans (subperm_append_left l)
 #align list.subperm_append_left List.subperm_append_left
 
-theorem subperm_append_right {l₁ l₂ : List α} (l) : l₁ ++ l <+~ l₂ ++ l ↔ l₁ <+~ l₂ :=
-  (perm_append_comm.subperm_left.trans perm_append_comm.subperm_right).trans (subperm_append_left l)
 #align list.subperm_append_right List.subperm_append_right
 
-theorem Subperm.exists_of_length_lt {l₁ l₂ : List α} :
-    l₁ <+~ l₂ → length l₁ < length l₂ → ∃ a, a :: l₁ <+~ l₂
-  | ⟨l, p, s⟩, h => by
-    suffices length l < length l₂ → ∃ a : α, a :: l <+~ l₂ from
-      (this <| p.symm.length_eq ▸ h).imp fun a => (p.cons a).subperm_right.1
-    clear h p l₁
-    induction' s with l₁ l₂ a s IH _ _ b _ IH <;> intro h
-    · cases h
-    · cases' lt_or_eq_of_le (Nat.le_of_lt_succ h : length l₁ ≤ length l₂) with h h
-      · exact (IH h).imp fun a s => s.trans (sublist_cons _ _).subperm
-      · exact ⟨a, s.eq_of_length h ▸ Subperm.refl _⟩
-    · exact (IH <| Nat.lt_of_succ_lt_succ h).imp fun a s =>
-          (swap _ _ _).subperm_right.1 <| (subperm_cons _).2 s
 #align list.subperm.exists_of_length_lt List.Subperm.exists_of_length_lt
 
-protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ := by
-  induction' d with a l₁' h d IH
-  · exact ⟨nil, Perm.nil, nil_sublist _⟩
-  · cases' forall_mem_cons.1 H with H₁ H₂
-    simp at h
-    exact cons_subperm_of_mem d h H₁ (IH H₂)
+protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ :=
+  subperm_of_subset d H
 #align list.nodup.subperm List.Nodup.subperm
 
-theorem perm_ext {l₁ l₂ : List α} (d₁ : Nodup l₁) (d₂ : Nodup l₂) :
-    l₁ ~ l₂ ↔ ∀ a, a ∈ l₁ ↔ a ∈ l₂ :=
-  ⟨fun p _ => p.mem_iff, fun H =>
-    (d₁.subperm fun a => (H a).1).antisymm <| d₂.subperm fun a => (H a).2⟩
-#align list.perm_ext List.perm_ext
-
-theorem Nodup.sublist_ext {l₁ l₂ l : List α} (d : Nodup l) (s₁ : l₁ <+ l) (s₂ : l₂ <+ l) :
-    l₁ ~ l₂ ↔ l₁ = l₂ :=
-  ⟨fun h => by
-    induction' s₂ with l₂ l a s₂ IH l₂ l a _ IH generalizing l₁
-    · exact h.eq_nil
-    · simp at d
-      cases' s₁ with _ _ _ s₁ l₁ _ _ s₁
-      · exact IH d.2 s₁ h
-      · apply d.1.elim
-        exact Subperm.subset ⟨_, h.symm, s₂⟩ (mem_cons_self _ _)
-    · simp at d
-      cases' s₁ with _ _ _ s₁ l₁ _ _ s₁
-      · apply d.1.elim
-        exact Subperm.subset ⟨_, h, s₁⟩ (mem_cons_self _ _)
-      · rw [IH d.2 s₁ h.cons_inv], fun h => by rw [h]⟩
-#align list.nodup.sublist_ext List.Nodup.sublist_ext
+#align list.perm_ext List.perm_ext_iff_of_nodup
+
+#align list.nodup.sublist_ext List.Nodup.perm_iff_eq_of_sublist
 
 section
 
 variable [DecidableEq α]
 
 -- attribute [congr]
-theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase a ~ l₂.erase a :=
-  if h₁ : a ∈ l₁ then
-    have h₂ : a ∈ l₂ := p.subset h₁
-    Perm.cons_inv <| (perm_cons_erase h₁).symm.trans <| p.trans (perm_cons_erase h₂)
-  else by
-    have h₂ : a ∉ l₂ := mt p.mem_iff.2 h₁
-    rw [erase_of_not_mem h₁, erase_of_not_mem h₂]; exact p
 #align list.perm.erase List.Perm.erase
 
-theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a := by
-  by_cases h : a ∈ l
-  · exact (perm_cons_erase h).subperm
-  · rw [erase_of_not_mem h]
-    exact (sublist_cons _ _).subperm
 #align list.subperm_cons_erase List.subperm_cons_erase
 
-theorem erase_subperm (a : α) (l : List α) : l.erase a <+~ l :=
-  (erase_sublist _ _).subperm
 #align list.erase_subperm List.erase_subperm
 
-theorem Subperm.erase {l₁ l₂ : List α} (a : α) (h : l₁ <+~ l₂) : l₁.erase a <+~ l₂.erase a :=
-  let ⟨l, hp, hs⟩ := h
-  ⟨l.erase a, hp.erase _, hs.erase _⟩
 #align list.subperm.erase List.Subperm.erase
 
-theorem Perm.diff_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : l₁.diff t ~ l₂.diff t := by
-  induction t generalizing l₁ l₂ h <;> simp [*, Perm.erase]
 #align list.perm.diff_right List.Perm.diff_right
 
-theorem Perm.diff_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l.diff t₁ = l.diff t₂ := by
-  induction h generalizing l <;>
-    first |simp [*, Perm.erase, erase_comm]
 #align list.perm.diff_left List.Perm.diff_left
 
-theorem Perm.diff {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) : l₁.diff t₁ ~ l₂.diff t₂ :=
-  ht.diff_left l₂ ▸ hl.diff_right _
 #align list.perm.diff List.Perm.diff
 
-theorem Subperm.diff_right {l₁ l₂ : List α} (h : l₁ <+~ l₂) (t : List α) :
-    l₁.diff t <+~ l₂.diff t := by induction t generalizing l₁ l₂ h <;> simp [*, Subperm.erase]
 #align list.subperm.diff_right List.Subperm.diff_right
 
-theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) :
-    (a :: l).erase b <+~ a :: l.erase b := by
-  by_cases h : a = b
-  · subst b
-    rw [erase_cons_head]
-    apply subperm_cons_erase
-  · rw [erase_cons_tail _ h]
 #align list.erase_cons_subperm_cons_erase List.erase_cons_subperm_cons_erase
 
-theorem subperm_cons_diff {a : α} : ∀ {l₁ l₂ : List α}, (a :: l₁).diff l₂ <+~ a :: l₁.diff l₂
-  | l₁, [] => ⟨a :: l₁, by simp⟩
-  | l₁, b :: l₂ => by
-    simp only [diff_cons]
-    refine' ((erase_cons_subperm_cons_erase a b l₁).diff_right l₂).trans _
-    apply subperm_cons_diff
 #align list.subperm_cons_diff List.subperm_cons_diff
 
-theorem subset_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂ ⊆ a :: l₁.diff l₂ :=
-  subperm_cons_diff.subset
 #align list.subset_cons_diff List.subset_cons_diff
 
 theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) :
@@ -881,27 +455,8 @@ theorem Perm.bagInter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t
   ht.bagInter_left l₂ ▸ hl.bagInter_right _
 #align list.perm.bag_inter List.Perm.bagInter
 
-theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} :
-    a :: l₁ ~ l₂ ↔ a ∈ l₂ ∧ l₁ ~ l₂.erase a :=
-  ⟨fun h =>
-    have : a ∈ l₂ := h.subset (mem_cons_self a l₁)
-    ⟨this, (h.trans <| perm_cons_erase this).cons_inv⟩,
-    fun ⟨m, h⟩ => (h.cons a).trans (perm_cons_erase m).symm⟩
 #align list.cons_perm_iff_perm_erase List.cons_perm_iff_perm_erase
 
-theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l₁ = count a l₂ :=
-  ⟨Perm.count_eq, fun H => by
-    induction' l₁ with a l₁ IH generalizing l₂
-    · cases' l₂ with b l₂
-      · rfl
-      specialize H b
-      simp at H
-      contradiction
-    · have : a ∈ l₂ := count_pos_iff_mem.1 (by rw [← H, count_pos_iff_mem]; simp)
-      refine' ((IH fun b => _).cons a).trans (perm_cons_erase this).symm
-      specialize H b
-      rw [(perm_cons_erase this).count_eq] at H
-      by_cases h : b = a <;> simpa [h] using H⟩
 #align list.perm_iff_count List.perm_iff_count
 
 theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h : a ≠ b) :
@@ -913,61 +468,16 @@ theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h
     not_mem_nil, or_false, or_comm]
 #align list.perm_replicate_append_replicate List.perm_replicate_append_replicate
 
-theorem Subperm.cons_right {α : Type*} {l l' : List α} (x : α) (h : l <+~ l') : l <+~ x :: l' :=
-  h.trans (sublist_cons x l').subperm
 #align list.subperm.cons_right List.Subperm.cons_right
 
-/-- The list version of `add_tsub_cancel_of_le` for multisets. -/
-theorem subperm_append_diff_self_of_count_le {l₁ l₂ : List α}
-    (h : ∀ x ∈ l₁, count x l₁ ≤ count x l₂) : l₁ ++ l₂.diff l₁ ~ l₂ := by
-  induction' l₁ with hd tl IH generalizing l₂
-  · simp
-  · have : hd ∈ l₂ := by
-      rw [← count_pos_iff_mem]
-      exact lt_of_lt_of_le (count_pos_iff_mem.mpr (mem_cons_self _ _)) (h hd (mem_cons_self _ _))
-    replace := perm_cons_erase this
-    refine' Perm.trans _ this.symm
-    rw [cons_append, diff_cons, perm_cons]
-    refine' IH fun x hx => _
-    specialize h x (mem_cons_of_mem _ hx)
-    rw [perm_iff_count.mp this] at h
-    by_cases hx : x = hd
-    · subst hd
-      simpa [Nat.succ_le_succ_iff] using h
-    · simpa [hx] using h
 #align list.subperm_append_diff_self_of_count_le List.subperm_append_diff_self_of_count_le
 
-/-- The list version of `Multiset.le_iff_count`. -/
-theorem subperm_ext_iff {l₁ l₂ : List α} : l₁ <+~ l₂ ↔ ∀ x ∈ l₁, count x l₁ ≤ count x l₂ := by
-  refine' ⟨fun h x _ => Subperm.count_le h x, fun h => _⟩
-  suffices l₁ <+~ l₂.diff l₁ ++ l₁ by
-    refine' this.trans (Perm.subperm _)
-    exact perm_append_comm.trans (subperm_append_diff_self_of_count_le h)
-  exact (subperm_append_right l₁).mpr nil_subperm
 #align list.subperm_ext_iff List.subperm_ext_iff
 
-instance decidableSubperm : DecidableRel ((· <+~ ·) : List α → List α → Prop) := fun _ _ =>
-  decidable_of_iff _ List.subperm_ext_iff.symm
 #align list.decidable_subperm List.decidableSubperm
 
-theorem Subperm.cons_left {l₁ l₂ : List α} (h : l₁ <+~ l₂) (x : α) (hx : count x l₁ < count x l₂) :
-    x :: l₁ <+~ l₂ := by
-  rw [subperm_ext_iff] at h ⊢
-  intro y hy
-  by_cases hy' : y = x
-  · subst x
-    simpa using Nat.succ_le_of_lt hx
-  · rw [count_cons_of_ne hy']
-    refine' h y _
-    simpa [hy'] using hy
 #align list.subperm.cons_left List.Subperm.cons_left
 
-instance decidablePerm : ∀ l₁ l₂ : List α, Decidable (l₁ ~ l₂)
-  | [], [] => isTrue <| Perm.refl _
-  | [], b :: l₂ => isFalse fun h => by have := h.nil_eq; contradiction
-  | a :: l₁, l₂ =>
-    haveI := decidablePerm l₁ (l₂.erase a)
-    decidable_of_iff' _ cons_perm_iff_perm_erase
 #align list.decidable_perm List.decidablePerm
 
 -- @[congr]
@@ -977,62 +487,24 @@ theorem Perm.dedup {l₁ l₂ : List α} (p : l₁ ~ l₂) : dedup l₁ ~ dedup
 #align list.perm.dedup List.Perm.dedup
 
 -- attribute [congr]
-protected theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.insert a ~ l₂.insert a :=
-  if h : a ∈ l₁ then by simpa [h, p.subset h] using p
-  else by simpa [h, mt p.mem_iff.2 h] using p.cons a
 #align list.perm.insert List.Perm.insert
 
-theorem perm_insert_swap (x y : α) (l : List α) :
-    List.insert x (List.insert y l) ~ List.insert y (List.insert x l) := by
-  by_cases xl : x ∈ l <;> by_cases yl : y ∈ l <;> simp [xl, yl]
-  by_cases xy : x = y; · simp [xy]
-  simp only [List.insert, Bool.not_eq_true, mem_cons, xy, xl, or_self, ite_false, Ne.symm xy, yl]
-  constructor
 #align list.perm_insert_swap List.perm_insert_swap
 
-theorem perm_insertNth {α} (x : α) (l : List α) {n} (h : n ≤ l.length) :
-    insertNth n x l ~ x :: l := by
-  induction' l with _ _ l_ih generalizing n
-  · cases n
-    rfl
-    cases h
-  cases n
-  · simp [insertNth]
-  · simp only [insertNth, modifyNthTail]
-    refine' Perm.trans (Perm.cons _ (l_ih _)) _
-    · apply Nat.le_of_succ_le_succ h
-    · apply Perm.swap
 #align list.perm_insert_nth List.perm_insertNth
 
-theorem Perm.union_right {l₁ l₂ : List α} (t₁ : List α) (h : l₁ ~ l₂) :
-    l₁ ∪ t₁ ~ l₂ ∪ t₁ := by
-  induction' h with a _ _ _ ih _ _ _ _ _ _ _ _ ih_1 ih_2 <;> try simp
-  · exact ih.insert a
-  · apply perm_insert_swap
-  · exact ih_1.trans ih_2
 #align list.perm.union_right List.Perm.union_right
 
-theorem Perm.union_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l ∪ t₁ ~ l ∪ t₂ := by
-  induction l <;> simp [*, Perm.insert]
 #align list.perm.union_left List.Perm.union_left
 
 -- @[congr]
-theorem Perm.union {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) :
-    l₁ ∪ t₁ ~ l₂ ∪ t₂ :=
-  (p₁.union_right t₁).trans (p₂.union_left l₂)
 #align list.perm.union List.Perm.union
 
-theorem Perm.inter_right {l₁ l₂ : List α} (t₁ : List α) : l₁ ~ l₂ → l₁ ∩ t₁ ~ l₂ ∩ t₁ :=
-  Perm.filter _
 #align list.perm.inter_right List.Perm.inter_right
 
-theorem Perm.inter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) : l ∩ t₁ = l ∩ t₂ :=
-  filter_congr' fun a _ => by simpa using p.mem_iff
 #align list.perm.inter_left List.Perm.inter_left
 
 -- @[congr]
-theorem Perm.inter {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ∩ t₁ ~ l₂ ∩ t₂ :=
-  p₂.inter_left l₂ ▸ p₁.inter_right t₁
 #align list.perm.inter List.Perm.inter
 
 theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) :
@@ -1055,50 +527,19 @@ theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) :
 
 end
 
-theorem Perm.pairwise_iff {R : α → α → Prop} (S : Symmetric R) :
-    ∀ {l₁ l₂ : List α} (_p : l₁ ~ l₂), Pairwise R l₁ ↔ Pairwise R l₂ :=
-  suffices ∀ {l₁ l₂}, l₁ ~ l₂ → Pairwise R l₁ → Pairwise R l₂
-    from fun p => ⟨this p, this p.symm⟩
-  @fun l₁ l₂ p d => by
-  induction' d with a l₁ h _ IH generalizing l₂
-  · rw [← p.nil_eq]
-    constructor
-  · have : a ∈ l₂ := p.subset (mem_cons_self _ _)
-    rcases mem_split this with ⟨s₂, t₂, rfl⟩
-    have p' := (p.trans perm_middle).cons_inv
-    refine' (pairwise_middle @S).2 (pairwise_cons.2 ⟨fun b m => _, IH _ p'⟩)
-    exact h _ (p'.symm.subset m)
 #align list.perm.pairwise_iff List.Perm.pairwise_iff
 
 
-theorem Pairwise.perm {R : α → α → Prop} {l l' : List α} (hR : l.Pairwise R) (hl : l ~ l')
-    (hsymm : Symmetric R) : l'.Pairwise R :=
-  (hl.pairwise_iff hsymm).mp hR
 #align list.pairwise.perm List.Pairwise.perm
 
-theorem Perm.pairwise {R : α → α → Prop} {l l' : List α} (hl : l ~ l') (hR : l.Pairwise R)
-    (hsymm : Symmetric R) : l'.Pairwise R :=
-  hR.perm hl hsymm
 #align list.perm.pairwise List.Perm.pairwise
 
-theorem Perm.nodup_iff {l₁ l₂ : List α} : l₁ ~ l₂ → (Nodup l₁ ↔ Nodup l₂) :=
-  Perm.pairwise_iff <| @Ne.symm α
 #align list.perm.nodup_iff List.Perm.nodup_iff
 
-theorem Perm.join {l₁ l₂ : List (List α)} (h : l₁ ~ l₂) : l₁.join ~ l₂.join :=
-  Perm.recOn h (Perm.refl _) (fun x xs₁ xs₂ _ ih => ih.append_left x)
-    (fun x₁ x₂ xs => by simpa only [join, append_assoc] using perm_append_comm.append_right _)
-    @fun xs₁ xs₂ xs₃ _ _ => Perm.trans
 #align list.perm.join List.Perm.join
 
-theorem Perm.bind_right {l₁ l₂ : List α} (f : α → List β) (p : l₁ ~ l₂) : l₁.bind f ~ l₂.bind f :=
-  (p.map _).join
 #align list.perm.bind_right List.Perm.bind_right
 
-theorem Perm.join_congr :
-    ∀ {l₁ l₂ : List (List α)} (_ : List.Forall₂ (· ~ ·) l₁ l₂), l₁.join ~ l₂.join
-  | _, _, Forall₂.nil => Perm.refl _
-  | _ :: _, _ :: _, Forall₂.cons h₁ h₂ => h₁.append (Perm.join_congr h₂)
 #align list.perm.join_congr List.Perm.join_congr
 
 theorem Perm.bind_left (l : List α) {f g : α → List β} (h : ∀ a ∈ l, f a ~ g a) :
@@ -1155,22 +596,17 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
       rcases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) _ h₂ _ h₁ with ⟨rfl, rfl⟩
       exact Perm.refl _
   · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H))
-    exact fun a b h c h₁ d h₂ => (h d h₂ c h₁).imp Eq.symm Eq.symm
+    intro x y h c hc d hd
+    rw [@eq_comm _ y, @eq_comm _ c]
+    apply h d hd c hc
 #align list.perm_lookmap List.perm_lookmap
 
+@[deprecated Perm.eraseP]
 theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
-    (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ := by
-  induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ _ IH₁ IH₂; · simp
-  · by_cases h : f a
-    · simp [h, p]
-    · simp [h]
-      exact IH (pairwise_cons.1 H).2
-  · by_cases h₁ : f a <;> by_cases h₂ : f b <;> simp [h₁, h₂]
-    · cases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) h₂ h₁
-    · apply swap
-  · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H))
-    exact fun a b h h₁ h₂ => h h₂ h₁
-#align list.perm.erasep List.Perm.erasep
+    (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) :
+    List.eraseP f l₁ ~ List.eraseP f l₂ :=
+  p.eraseP f (by simp [H])
+#align list.perm.erasep List.Perm.eraseP
 
 theorem Perm.take_inter {α : Type*} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys)
     (h' : ys.Nodup) : xs.take n ~ ys.inter (xs.take n) := by
feat: Finsets and multisets are graded (#8892)

Characterise IsAtom, IsCoatom, Covby in Set α, Multiset α, Finset α and deduce that Multiset α, Finset α are graded orders.

Note I am moving some existing characterisations to here because it makes sense thematically, but I could be convinced otherwise.

Diff
@@ -24,11 +24,8 @@ The notation `~` is used for permutation equivalence.
 
 open Nat
 
-universe uu vv
-
 namespace List
-
-variable {α : Type uu} {β : Type vv} {l₁ l₂ : List α}
+variable {α β : Type*} {l l₁ l₂ : List α} {a : α}
 
 /-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations
   of each other. This is defined by induction using pairwise swaps. -/
@@ -54,6 +51,8 @@ protected theorem Perm.refl : ∀ l : List α, l ~ l
   | x :: xs => (Perm.refl xs).cons x
 #align list.perm.refl List.Perm.refl
 
+lemma perm_rfl : l ~ l := Perm.refl _
+
 -- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it
 @[symm]
 protected theorem Perm.symm {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₂ ~ l₁ :=
@@ -469,6 +468,25 @@ theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ →
     ⟨l, p.cons a⟩
 #align list.sublist.exists_perm_append List.Sublist.exists_perm_append
 
+lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
+  refine ⟨?_, fun ⟨l, h₁, h₂⟩ ↦ h₂.subperm.trans h₁.subperm⟩
+  rintro ⟨l, h₁, h₂⟩
+  obtain ⟨l', h₂⟩ := h₂.exists_perm_append
+  exact ⟨l₁ ++ l', (h₂.trans (h₁.append_right _)).symm, (prefix_append _ _).sublist⟩
+
+@[simp] lemma singleton_subperm_iff : [a] <+~ l ↔ a ∈ l :=
+  ⟨fun ⟨s, hla, h⟩ ↦ by rwa [perm_singleton.1 hla, singleton_sublist] at h,
+    fun h ↦ ⟨[a], perm_rfl, singleton_sublist.2 h⟩⟩
+#align list.subperm_singleton_iff List.singleton_subperm_iff
+
+@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
+  constructor
+  · rw [subperm_iff]
+    rintro ⟨s, hla, h⟩
+    rwa [perm_singleton.mp hla, sublist_singleton] at h
+  · rintro (rfl | rfl)
+    exacts [nil_subperm, Subperm.refl _]
+
 theorem Perm.countP_eq (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
     countP p l₁ = countP p l₂ := by
   rw [countP_eq_length_filter, countP_eq_length_filter]; exact (s.filter _).length_eq
@@ -932,12 +950,6 @@ instance decidableSubperm : DecidableRel ((· <+~ ·) : List α → List α →
   decidable_of_iff _ List.subperm_ext_iff.symm
 #align list.decidable_subperm List.decidableSubperm
 
-@[simp]
-theorem subperm_singleton_iff {α} {l : List α} {a : α} : [a] <+~ l ↔ a ∈ l :=
-  ⟨fun ⟨s, hla, h⟩ => by rwa [perm_singleton.mp hla, singleton_sublist] at h, fun h =>
-    ⟨[a], Perm.refl _, singleton_sublist.mpr h⟩⟩
-#align list.subperm_singleton_iff List.subperm_singleton_iff
-
 theorem Subperm.cons_left {l₁ l₂ : List α} (h : l₁ <+~ l₂) (x : α) (hx : count x l₁ < count x l₂) :
     x :: l₁ <+~ l₂ := by
   rw [subperm_ext_iff] at h ⊢
chore: Replace (· op ·) a by (a op ·) (#8843)

I used the regex \(\(· (.) ·\) (.)\), replacing with ($2 $1 ·).

Diff
@@ -1366,7 +1366,7 @@ theorem nthLe_permutations'Aux (s : List α) (x : α) (n : ℕ)
 #align list.nth_le_permutations'_aux List.nthLe_permutations'Aux
 
 theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) :
-    count (x :: l) (permutations'Aux x l) = length (takeWhile ((· = ·) x) l) + 1 := by
+    count (x :: l) (permutations'Aux x l) = length (takeWhile (x = ·) l) + 1 := by
   induction' l with y l IH generalizing x
   · simp [takeWhile, count]
   · rw [permutations'Aux, DecEq_eq, count_cons_self]
chore: bump to v4.3.0-rc2 (#8366)

PR contents

This is the supremum of

along with some minor fixes from failures on nightly-testing as Mathlib master is merged into it.

Note that some PRs for changes that are already compatible with the current toolchain and will be necessary have already been split out: #8380.

I am hopeful that in future we will be able to progressively merge adaptation PRs into a bump/v4.X.0 branch, so we never end up with a "big merge" like this. However one of these adaptation PRs (#8056) predates my new scheme for combined CI, and it wasn't possible to keep that PR viable in the meantime.

Lean PRs involved in this bump

In particular this includes adjustments for the Lean PRs

leanprover/lean4#2778

We can get rid of all the

local macro_rules | `($x ^ $y) => `(HPow.hPow $x $y) -- Porting note: See issue [lean4#2220](https://github.com/leanprover/lean4/pull/2220)

macros across Mathlib (and in any projects that want to write natural number powers of reals).

leanprover/lean4#2722

Changes the default behaviour of simp to (config := {decide := false}). This makes simp (and consequentially norm_num) less powerful, but also more consistent, and less likely to blow up in long failures. This requires a variety of changes: changing some previously by simp or norm_num to decide or rfl, or adding (config := {decide := true}).

leanprover/lean4#2783

This changed the behaviour of simp so that simp [f] will only unfold "fully applied" occurrences of f. The old behaviour can be recovered with simp (config := { unfoldPartialApp := true }). We may in future add a syntax for this, e.g. simp [!f]; please provide feedback! In the meantime, we have made the following changes:

  • switching to using explicit lemmas that have the intended level of application
  • (config := { unfoldPartialApp := true }) in some places, to recover the old behaviour
  • Using @[eqns] to manually adjust the equation lemmas for a particular definition, recovering the old behaviour just for that definition. See #8371, where we do this for Function.comp and Function.flip.

This change in Lean may require further changes down the line (e.g. adding the !f syntax, and/or upstreaming the special treatment for Function.comp and Function.flip, and/or removing this special treatment). Please keep an open and skeptical mind about these changes!

Co-authored-by: leanprover-community-mathlib4-bot <leanprover-community-mathlib4-bot@users.noreply.github.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Mauricio Collares <mauricio@collares.org>

Diff
@@ -278,9 +278,11 @@ theorem filter_append_perm (p : α → Bool) (l : List α) :
   induction' l with x l ih
   · rfl
   · by_cases h : p x
-    · simp only [h, filter_cons_of_pos, filter_cons_of_neg, not_true, not_false_iff, cons_append]
+    · simp only [h, filter_cons_of_pos, filter_cons_of_neg, not_true, not_false_iff, cons_append,
+        decide_False]
       exact ih.cons x
-    · simp only [h, filter_cons_of_neg, not_false_iff, filter_cons_of_pos]
+    · simp only [h, filter_cons_of_neg, not_false_iff, filter_cons_of_pos, cons_append,
+        not_false_eq_true, decide_True]
       refine' Perm.trans _ (ih.cons x)
       exact perm_append_comm.trans (perm_append_comm.cons _)
 #align list.filter_append_perm List.filter_append_perm
feat: add Trans instance for List.Perm and a lemma on Lists (#8189)

This PR adds

  • a lemma List.count_filter_add_count_filter in Data.List.Count
  • an instance Trans ([@List](https://github.com/List).Perm α) ([@List](https://github.com/List).Perm α) ([@List](https://github.com/List).Perm α) to allow using permutation equivalence of Lists in a calc block in Data.List.Perm

See here on Zulip.

Co-authored-by: Michael Stoll <99838730+MichaelStollBayreuth@users.noreply.github.com>

Diff
@@ -39,6 +39,9 @@ inductive Perm : List α → List α → Prop
   | trans {l₁ l₂ l₃ : List α} : Perm l₁ l₂ → Perm l₂ l₃ → Perm l₁ l₃
 #align list.perm List.Perm
 
+instance {α : Type*} : Trans (@List.Perm α) (@List.Perm α) List.Perm where
+  trans := @List.Perm.trans α
+
 open Perm (swap)
 
 /-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations
@@ -490,6 +493,12 @@ theorem countP_eq_countP_filter_add (l : List α) (p q : α → Bool) :
   exact Perm.countP_eq _ (filter_append_perm _ _).symm
 #align list.countp_eq_countp_filter_add List.countP_eq_countP_filter_add
 
+lemma count_eq_count_filter_add [DecidableEq α] (P : α → Prop) [DecidablePred P]
+    (l : List α) (a : α) :
+    count a l = count a (l.filter P) + count a (l.filter (¬ P ·)) := by
+  convert countP_eq_countP_filter_add l _ P
+  simp only [decide_eq_true_eq]
+
 theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
     count a l₁ = count a l₂ :=
   p.countP_eq _
Diff
@@ -8,7 +8,7 @@ import Mathlib.Data.List.Permutation
 import Mathlib.Data.List.Range
 import Mathlib.Data.Nat.Factorial.Basic
 
-#align_import data.list.perm from "leanprover-community/mathlib"@"47adfab39a11a072db552f47594bf8ed2cf8a722"
+#align_import data.list.perm from "leanprover-community/mathlib"@"65a1391a0106c9204fe45bc73a039f056558cb83"
 
 /-!
 # List Permutations
@@ -475,7 +475,7 @@ theorem Subperm.countP_le (p : α → Bool) {l₁ l₂ : List α} :
 #align list.subperm.countp_le List.Subperm.countP_le
 
 theorem Perm.countP_congr (s : l₁ ~ l₂) {p p' : α → Bool}
-    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countP p = l₂.countP p' := by
+    (hp : ∀ x ∈ l₁, p x ↔ p' x) : l₁.countP p = l₂.countP p' := by
   rw [← s.countP_eq p']
   clear s
   induction' l₁ with y s hs
chore: avoid subst by rfl (#8145)

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

Diff
@@ -1197,10 +1197,9 @@ theorem perm_of_mem_permutationsAux :
   refine' permutationsAux.rec (by simp) _
   introv IH1 IH2 m
   rw [permutationsAux_cons, permutations, mem_foldr_permutationsAux2] at m
-  rcases m with (m | ⟨l₁, l₂, m, _, e⟩)
+  rcases m with (m | ⟨l₁, l₂, m, _, rfl⟩)
   · exact (IH1 _ m).trans perm_middle
-  · subst e
-    have p : l₁ ++ l₂ ~ is := by
+  · have p : l₁ ++ l₂ ~ is := by
       simp [permutations] at m
       cases' m with e m
       · simp [e]
chore: remove nonterminal simp (#7580)

Removes nonterminal simps on lines looking like simp [...]

Diff
@@ -963,7 +963,7 @@ theorem perm_insert_swap (x y : α) (l : List α) :
     List.insert x (List.insert y l) ~ List.insert y (List.insert x l) := by
   by_cases xl : x ∈ l <;> by_cases yl : y ∈ l <;> simp [xl, yl]
   by_cases xy : x = y; · simp [xy]
-  simp [List.insert, xl, yl, xy, Ne.symm xy]
+  simp only [List.insert, Bool.not_eq_true, mem_cons, xy, xl, or_self, ite_false, Ne.symm xy, yl]
   constructor
 #align list.perm_insert_swap List.perm_insert_swap
 
@@ -1272,7 +1272,7 @@ theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
       (permutations'Aux b l).bind (permutations'Aux a) := by
   induction' l with c l ih
   · simp [swap]
-  simp [permutations'Aux]
+  simp only [permutations'Aux, cons_bind, map_cons, map_map, cons_append]
   apply Perm.swap'
   have :
     ∀ a b,
chore: missing spaces after rcases, convert and congrm (#7725)

Replace rcases( with rcases (. Same thing for convert( and congrm(. No other change.

Diff
@@ -1129,7 +1129,7 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
     · simp [lookmap_cons_some _ _ h₁, h₂]
       apply swap
     · simp [lookmap_cons_some _ _ h₁, lookmap_cons_some _ _ h₂]
-      rcases(pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) _ h₂ _ h₁ with ⟨rfl, rfl⟩
+      rcases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) _ h₂ _ h₁ with ⟨rfl, rfl⟩
       exact Perm.refl _
   · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H))
     exact fun a b h c h₁ d h₂ => (h d h₂ c h₁).imp Eq.symm Eq.symm
@@ -1423,7 +1423,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
       nthLe_insertNth_of_lt _ _ _ _ (H.trans (Nat.lt_succ_self _))]
   · rw [nthLe_insertNth_self _ _ _ hk.le, nthLe_insertNth_of_lt _ _ _ _ (Nat.lt_succ_self _) hk,
       hk']
-  · rcases(Nat.succ_le_of_lt H).eq_or_lt with (rfl | H')
+  · rcases (Nat.succ_le_of_lt H).eq_or_lt with (rfl | H')
     · rw [nthLe_insertNth_self _ _ _ (Nat.succ_le_of_lt hk)]
       convert hk' using 1
       exact nthLe_insertNth_add_succ _ _ _ 0 _
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
@@ -1043,7 +1043,7 @@ theorem Perm.pairwise_iff {R : α → α → Prop} (S : Symmetric R) :
   · have : a ∈ l₂ := p.subset (mem_cons_self _ _)
     rcases mem_split this with ⟨s₂, t₂, rfl⟩
     have p' := (p.trans perm_middle).cons_inv
-    refine' (pairwise_middle S).2 (pairwise_cons.2 ⟨fun b m => _, IH _ p'⟩)
+    refine' (pairwise_middle @S).2 (pairwise_cons.2 ⟨fun b m => _, IH _ p'⟩)
     exact h _ (p'.symm.subset m)
 #align list.perm.pairwise_iff List.Perm.pairwise_iff
 
chore: avoid lean3 style have/suffices (#6964)

Many proofs use the "stream of consciousness" style from Lean 3, rather than have ... := or suffices ... from/by.

This PR updates a fraction of these to the preferred Lean 4 style.

I think a good goal would be to delete the "deferred" versions of have, suffices, and let at the bottom of Mathlib.Tactic.Have

(Anyone who would like to contribute more cleanup is welcome to push directly to this branch.)

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

Diff
@@ -878,8 +878,8 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
 theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h : a ≠ b) :
     l ~ replicate m a ++ replicate n b ↔ count a l = m ∧ count b l = n ∧ l ⊆ [a, b] := by
   rw [perm_iff_count, ← Decidable.and_forall_ne a, ← Decidable.and_forall_ne b]
-  suffices : l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l
-  { simp (config := { contextual := true }) [count_replicate, h, h.symm, this, count_eq_zero] }
+  suffices l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l by
+    simp (config := { contextual := true }) [count_replicate, h, h.symm, this, count_eq_zero]
   simp_rw [Ne.def, ← and_imp, ← not_or, Decidable.not_imp_not, subset_def, mem_cons,
     not_mem_nil, or_false, or_comm]
 #align list.perm_replicate_append_replicate List.perm_replicate_append_replicate
feat: patch for new alias command (#6172)
Diff
@@ -212,8 +212,8 @@ theorem singleton_perm {a : α} {l : List α} : [a] ~ l ↔ [a] = l :=
   @replicate_perm α 1 a l
 #align list.singleton_perm List.singleton_perm
 
-alias perm_singleton ↔ Perm.eq_singleton _
-alias singleton_perm ↔ Perm.singleton_eq _
+alias ⟨Perm.eq_singleton, _⟩ := perm_singleton
+alias ⟨Perm.singleton_eq, _⟩ := singleton_perm
 
 theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp
 #align list.singleton_perm_singleton List.singleton_perm_singleton
@@ -669,7 +669,7 @@ theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ 
     · exact ⟨u, p.cons_inv, s'⟩, fun ⟨l, p, s⟩ => ⟨a :: l, p.cons a, s.cons₂ _⟩⟩
 #align list.subperm_cons List.subperm_cons
 
-alias subperm_cons ↔ subperm.of_cons subperm.cons
+alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons
 #align list.subperm.of_cons List.subperm.of_cons
 #align list.subperm.cons List.subperm.cons
 
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
@@ -464,40 +464,40 @@ theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ →
     ⟨l, p.cons a⟩
 #align list.sublist.exists_perm_append List.Sublist.exists_perm_append
 
-theorem Perm.countp_eq (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
-    countp p l₁ = countp p l₂ := by
-  rw [countp_eq_length_filter, countp_eq_length_filter]; exact (s.filter _).length_eq
-#align list.perm.countp_eq List.Perm.countp_eq
-
-theorem Subperm.countp_le (p : α → Bool) {l₁ l₂ : List α} :
-    l₁ <+~ l₂ → countp p l₁ ≤ countp p l₂
-  | ⟨_l, p', s⟩ => p'.countp_eq p ▸ s.countp_le p
-#align list.subperm.countp_le List.Subperm.countp_le
-
-theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Bool}
-    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countp p = l₂.countp p' := by
-  rw [← s.countp_eq p']
+theorem Perm.countP_eq (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
+    countP p l₁ = countP p l₂ := by
+  rw [countP_eq_length_filter, countP_eq_length_filter]; exact (s.filter _).length_eq
+#align list.perm.countp_eq List.Perm.countP_eq
+
+theorem Subperm.countP_le (p : α → Bool) {l₁ l₂ : List α} :
+    l₁ <+~ l₂ → countP p l₁ ≤ countP p l₂
+  | ⟨_l, p', s⟩ => p'.countP_eq p ▸ s.countP_le p
+#align list.subperm.countp_le List.Subperm.countP_le
+
+theorem Perm.countP_congr (s : l₁ ~ l₂) {p p' : α → Bool}
+    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countP p = l₂.countP p' := by
+  rw [← s.countP_eq p']
   clear s
   induction' l₁ with y s hs
   · rfl
   · simp only [mem_cons, forall_eq_or_imp] at hp
-    simp only [countp_cons, hs hp.2, hp.1]
-#align list.perm.countp_congr List.Perm.countp_congr
+    simp only [countP_cons, hs hp.2, hp.1]
+#align list.perm.countp_congr List.Perm.countP_congr
 
-theorem countp_eq_countp_filter_add (l : List α) (p q : α → Bool) :
-    l.countp p = (l.filter q).countp p + (l.filter fun a => ¬q a).countp p := by
-  rw [← countp_append]
-  exact Perm.countp_eq _ (filter_append_perm _ _).symm
-#align list.countp_eq_countp_filter_add List.countp_eq_countp_filter_add
+theorem countP_eq_countP_filter_add (l : List α) (p q : α → Bool) :
+    l.countP p = (l.filter q).countP p + (l.filter fun a => ¬q a).countP p := by
+  rw [← countP_append]
+  exact Perm.countP_eq _ (filter_append_perm _ _).symm
+#align list.countp_eq_countp_filter_add List.countP_eq_countP_filter_add
 
 theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
     count a l₁ = count a l₂ :=
-  p.countp_eq _
+  p.countP_eq _
 #align list.perm.count_eq List.Perm.count_eq
 
 theorem Subperm.count_le [DecidableEq α] {l₁ l₂ : List α} (s : l₁ <+~ l₂) (a) :
     count a l₁ ≤ count a l₂ :=
-  s.countp_le _
+  s.countP_le _
 #align list.subperm.count_le List.Subperm.count_le
 
 theorem Perm.foldl_eq' {f : β → α → β} {l₁ l₂ : List α} (p : l₁ ~ l₂) :
@@ -868,7 +868,7 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
       specialize H b
       simp at H
       contradiction
-    · have : a ∈ l₂ := count_pos.1 (by rw [← H]; simp)
+    · have : a ∈ l₂ := count_pos_iff_mem.1 (by rw [← H, count_pos_iff_mem]; simp)
       refine' ((IH fun b => _).cons a).trans (perm_cons_erase this).symm
       specialize H b
       rw [(perm_cons_erase this).count_eq] at H
@@ -879,7 +879,7 @@ theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h
     l ~ replicate m a ++ replicate n b ↔ count a l = m ∧ count b l = n ∧ l ⊆ [a, b] := by
   rw [perm_iff_count, ← Decidable.and_forall_ne a, ← Decidable.and_forall_ne b]
   suffices : l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l
-  { simp (config := { contextual := true }) [count_replicate, h, h.symm, this] }
+  { simp (config := { contextual := true }) [count_replicate, h, h.symm, this, count_eq_zero] }
   simp_rw [Ne.def, ← and_imp, ← not_or, Decidable.not_imp_not, subset_def, mem_cons,
     not_mem_nil, or_false, or_comm]
 #align list.perm_replicate_append_replicate List.perm_replicate_append_replicate
@@ -894,8 +894,8 @@ theorem subperm_append_diff_self_of_count_le {l₁ l₂ : List α}
   induction' l₁ with hd tl IH generalizing l₂
   · simp
   · have : hd ∈ l₂ := by
-      rw [← count_pos]
-      exact lt_of_lt_of_le (count_pos.mpr (mem_cons_self _ _)) (h hd (mem_cons_self _ _))
+      rw [← count_pos_iff_mem]
+      exact lt_of_lt_of_le (count_pos_iff_mem.mpr (mem_cons_self _ _)) (h hd (mem_cons_self _ _))
     replace := perm_cons_erase this
     refine' Perm.trans _ this.symm
     rw [cons_append, diff_cons, perm_cons]
chore: remove unused simps (#6632)

Co-authored-by: Eric Wieser <wieser.eric@gmail.com>

Diff
@@ -239,11 +239,9 @@ theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~
   induction p with
   | nil => simp
   | cons x _p IH =>
-    simp only [filterMap]
     cases h : f x
       <;> simp [h, filterMap, IH, Perm.cons]
   | swap x y l₂ =>
-    simp only [filterMap]
     cases hx : f x
       <;> cases hy : f y
         <;> simp [hx, hy, filterMap, swap]
@@ -1295,8 +1293,7 @@ theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
 
 theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t := by
   induction' p with a s t _ IH a b l s t u _ _ IH₁ IH₂; · simp
-  · simp only [permutations']
-    exact IH.bind_right _
+  · exact IH.bind_right _
   · dsimp [permutations']
     rw [bind_assoc, bind_assoc]
     apply Perm.bind_left
chore: banish Type _ and Sort _ (#6499)

We remove all possible occurences of Type _ and Sort _ in favor of Type* and Sort*.

This has nice performance benefits.

Diff
@@ -323,7 +323,7 @@ section Rel
 
 open Relator
 
-variable {γ : Type _} {δ : Type _} {r : α → β → Prop} {p : γ → δ → Prop}
+variable {γ : Type*} {δ : Type*} {r : α → β → Prop} {p : γ → δ → Prop}
 
 -- mathport name: «expr ∘r »
 local infixr:80 " ∘r " => Relation.Comp
@@ -526,7 +526,7 @@ theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : Left
     Eq.trans (r₁ a) (r₂ a)
 #align list.perm.foldr_eq List.Perm.foldr_eq
 
-theorem Perm.rec_heq {β : List α → Sort _} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α}
+theorem Perm.rec_heq {β : List α → Sort*} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α}
     (hl : Perm l l') (f_congr : ∀ {a l l' b b'}, Perm l l' → HEq b b' → HEq (f a l b) (f a l' b'))
     (f_swap : ∀ {a a' l b}, HEq (f a (a' :: l) (f a' l b)) (f a' (a :: l) (f a l b))) :
     HEq (@List.rec α β b f l) (@List.rec α β b f l') := by
@@ -886,7 +886,7 @@ theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h
     not_mem_nil, or_false, or_comm]
 #align list.perm_replicate_append_replicate List.perm_replicate_append_replicate
 
-theorem Subperm.cons_right {α : Type _} {l l' : List α} (x : α) (h : l <+~ l') : l <+~ x :: l' :=
+theorem Subperm.cons_right {α : Type*} {l l' : List α} (x : α) (h : l <+~ l') : l <+~ x :: l' :=
   h.trans (sublist_cons x l').subperm
 #align list.subperm.cons_right List.Subperm.cons_right
 
@@ -1151,7 +1151,7 @@ theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
     exact fun a b h h₁ h₂ => h h₂ h₁
 #align list.perm.erasep List.Perm.erasep
 
-theorem Perm.take_inter {α : Type _} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys)
+theorem Perm.take_inter {α : Type*} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys)
     (h' : ys.Nodup) : xs.take n ~ ys.inter (xs.take n) := by
   simp only [List.inter]
   exact Perm.trans (show xs.take n ~ xs.filter (· ∈ xs.take n) by
@@ -1262,7 +1262,7 @@ theorem mem_permutations {s t : List α} : s ∈ permutations t ↔ s ~ t :=
 #align list.mem_permutations List.mem_permutations
 
 --Porting note: temporary theorem to solve diamond issue
-private theorem DecEq_eq {α : Type _} [DecidableEq α] :
+private theorem DecEq_eq {α : Type*} [DecidableEq α] :
      instBEqList = @instBEq (List α) instDecidableEqList :=
   congr_arg BEq.mk <| by
     funext l₁ l₂
chore: bump Std version (#6435)

Notably there is now a l1 ∪ l2 notation for List.union.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Bulhwi Cha <chabulhwi@semmalgil.com>

Diff
@@ -984,20 +984,20 @@ theorem perm_insertNth {α} (x : α) (l : List α) {n} (h : n ≤ l.length) :
 #align list.perm_insert_nth List.perm_insertNth
 
 theorem Perm.union_right {l₁ l₂ : List α} (t₁ : List α) (h : l₁ ~ l₂) :
-    l₁.union t₁ ~ l₂.union t₁ := by
+    l₁ ∪ t₁ ~ l₂ ∪ t₁ := by
   induction' h with a _ _ _ ih _ _ _ _ _ _ _ _ ih_1 ih_2 <;> try simp
   · exact ih.insert a
   · apply perm_insert_swap
   · exact ih_1.trans ih_2
 #align list.perm.union_right List.Perm.union_right
 
-theorem Perm.union_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l.union t₁ ~ l.union t₂ := by
+theorem Perm.union_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l ∪ t₁ ~ l ∪ t₂ := by
   induction l <;> simp [*, Perm.insert]
 #align list.perm.union_left List.Perm.union_left
 
 -- @[congr]
 theorem Perm.union {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) :
-    l₁.union t₁ ~ l₂.union t₂ :=
+    l₁ ∪ t₁ ~ l₂ ∪ t₂ :=
   (p₁.union_right t₁).trans (p₂.union_left l₂)
 #align list.perm.union List.Perm.union
 
chore: tidy various files (#6291)
Diff
@@ -572,7 +572,6 @@ theorem Perm.prod_eq' [M : Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (h
     rw [mul_assoc z, mul_assoc z, h]
 #align list.perm.prod_eq' List.Perm.prod_eq'
 #align list.perm.sum_eq' List.Perm.sum_eq'
--- Porting note: TODO do I need to do anything to handle the to_additive instance?
 
 variable [CommMonoid α]
 
chore(*): add protected to *.insert theorems (#6142)

Otherwise code like

theorem ContMDiffWithinAt.mythm (h : x ∈ insert y s) : _ = _

interprets insert as ContMDiffWithinAt.insert, not Insert.insert.

Diff
@@ -957,7 +957,7 @@ theorem Perm.dedup {l₁ l₂ : List α} (p : l₁ ~ l₂) : dedup l₁ ~ dedup
 #align list.perm.dedup List.Perm.dedup
 
 -- attribute [congr]
-theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.insert a ~ l₂.insert a :=
+protected theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.insert a ~ l₂.insert a :=
   if h : a ∈ l₁ then by simpa [h, p.subset h] using p
   else by simpa [h, mt p.mem_iff.2 h] using p.cons a
 #align list.perm.insert List.Perm.insert
chore: use · instead of . (#6085)
Diff
@@ -1155,7 +1155,7 @@ theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
 theorem Perm.take_inter {α : Type _} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys)
     (h' : ys.Nodup) : xs.take n ~ ys.inter (xs.take n) := by
   simp only [List.inter]
-  exact Perm.trans (show xs.take n ~ xs.filter (. ∈ xs.take n) by
+  exact Perm.trans (show xs.take n ~ xs.filter (· ∈ xs.take n) by
       conv_lhs => rw [Nodup.take_eq_filter_mem ((Perm.nodup_iff h).2 h')])
     (Perm.filter _ h)
 #align list.perm.take_inter List.Perm.take_inter
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,17 +2,14 @@
 Copyright (c) 2015 Microsoft Corporation. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
-
-! This file was ported from Lean 3 source module data.list.perm
-! leanprover-community/mathlib commit 47adfab39a11a072db552f47594bf8ed2cf8a722
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathlib.Data.List.Dedup
 import Mathlib.Data.List.Permutation
 import Mathlib.Data.List.Range
 import Mathlib.Data.Nat.Factorial.Basic
 
+#align_import data.list.perm from "leanprover-community/mathlib"@"47adfab39a11a072db552f47594bf8ed2cf8a722"
+
 /-!
 # List Permutations
 
chore: remove occurrences of semicolon after space (#5713)

This is the second half of the changes originally in #5699, removing all occurrences of ; after a space and implementing a linter rule to enforce it.

In most cases this 2-character substring has a space after it, so the following command was run first:

find . -type f -name "*.lean" -exec sed -i -E 's/ ; /; /g' {} \;

The remaining cases were few enough in number that they were done manually.

Diff
@@ -272,7 +272,7 @@ theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α
 #align list.perm.pmap List.Perm.pmap
 
 theorem Perm.filter (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
-    filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter] ; apply s.filterMap _
+    filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap _
 #align list.perm.filter List.Perm.filter
 
 theorem filter_append_perm (p : α → Bool) (l : List α) :
@@ -471,7 +471,7 @@ theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ →
 
 theorem Perm.countp_eq (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
     countp p l₁ = countp p l₂ := by
-  rw [countp_eq_length_filter, countp_eq_length_filter] ; exact (s.filter _).length_eq
+  rw [countp_eq_length_filter, countp_eq_length_filter]; exact (s.filter _).length_eq
 #align list.perm.countp_eq List.Perm.countp_eq
 
 theorem Subperm.countp_le (p : α → Bool) {l₁ l₂ : List α} :
@@ -524,8 +524,8 @@ theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : Righ
 
 theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
     ∀ b, foldr f b l₁ = foldr f b l₂ :=
-  perm_induction_on p (fun b => rfl) (fun x t₁ t₂ _p r b => by simp ; rw [r b])
-    (fun x y t₁ t₂ _p r b => by simp ; rw [lcomm, r b]) fun t₁ t₂ t₃ _p₁ _p₂ r₁ r₂ a =>
+  perm_induction_on p (fun b => rfl) (fun x t₁ t₂ _p r b => by simp; rw [r b])
+    (fun x y t₁ t₂ _p r b => by simp; rw [lcomm, r b]) fun t₁ t₂ t₃ _p₁ _p₂ r₁ r₂ a =>
     Eq.trans (r₁ a) (r₂ a)
 #align list.perm.foldr_eq List.Perm.foldr_eq
 
@@ -774,7 +774,7 @@ theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase
     Perm.cons_inv <| (perm_cons_erase h₁).symm.trans <| p.trans (perm_cons_erase h₂)
   else by
     have h₂ : a ∉ l₂ := mt p.mem_iff.2 h₁
-    rw [erase_of_not_mem h₁, erase_of_not_mem h₂] ; exact p
+    rw [erase_of_not_mem h₁, erase_of_not_mem h₂]; exact p
 #align list.perm.erase List.Perm.erase
 
 theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a := by
chore: fix focusing dots (#5708)

This PR is the result of running

find . -type f -name "*.lean" -exec sed -i -E 's/^( +)\. /\1· /' {} \;
find . -type f -name "*.lean" -exec sed -i -E 'N;s/^( +·)\n +(.*)$/\1 \2/;P;D' {} \;

which firstly replaces . focusing dots with · and secondly removes isolated instances of such dots, unifying them with the following line. A new rule is placed in the style linter to verify this.

Diff
@@ -567,10 +567,10 @@ theorem Perm.prod_eq' [M : Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (h
     l₁.prod = l₂.prod := by
   refine h.foldl_eq' ?_ _
   apply Pairwise.forall_of_forall
-  . intro x y h z
+  · intro x y h z
     exact (h z).symm
-  . intros; rfl
-  . apply hc.imp
+  · intros; rfl
+  · apply hc.imp
     intro a b h z
     rw [mul_assoc z, mul_assoc z, h]
 #align list.perm.prod_eq' List.Perm.prod_eq'
@@ -1190,8 +1190,8 @@ theorem Perm.dropSlice_inter {α} [DecidableEq α] {xs ys : List α} (n m : ℕ)
   have : n ≤ n + m := Nat.le_add_right _ _
   have h₂ := h.nodup_iff.2 h'
   apply Perm.trans _ (Perm.inter_append _).symm
-  . exact Perm.append (Perm.take_inter _ h h') (Perm.drop_inter _ h h')
-  . exact disjoint_take_drop h₂ this
+  · exact Perm.append (Perm.take_inter _ h h') (Perm.drop_inter _ h h')
+  · exact disjoint_take_drop h₂ this
 #align list.perm.slice_inter List.Perm.dropSlice_inter
 
 -- enumerating permutations
@@ -1426,11 +1426,9 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
     rw [length_insertNth _ _ hk.le, length_insertNth _ _ (Nat.succ_le_of_lt hk)]
   refine' ext_nthLe hl fun n hn hn' => _
   rcases lt_trichotomy n k with (H | rfl | H)
-  ·
-    rw [nthLe_insertNth_of_lt _ _ _ _ H (H.trans hk),
+  · rw [nthLe_insertNth_of_lt _ _ _ _ H (H.trans hk),
       nthLe_insertNth_of_lt _ _ _ _ (H.trans (Nat.lt_succ_self _))]
-  ·
-    rw [nthLe_insertNth_self _ _ _ hk.le, nthLe_insertNth_of_lt _ _ _ _ (Nat.lt_succ_self _) hk,
+  · rw [nthLe_insertNth_self _ _ _ hk.le, nthLe_insertNth_of_lt _ _ _ _ (Nat.lt_succ_self _) hk,
       hk']
   · rcases(Nat.succ_le_of_lt H).eq_or_lt with (rfl | H')
     · rw [nthLe_insertNth_self _ _ _ (Nat.succ_le_of_lt hk)]
chore: clean up spacing around at and goals (#5387)

Changes are of the form

  • some_tactic at h⊢ -> some_tactic at h ⊢
  • some_tactic at h -> some_tactic at h
Diff
@@ -935,7 +935,7 @@ theorem subperm_singleton_iff {α} {l : List α} {a : α} : [a] <+~ l ↔ a ∈
 
 theorem Subperm.cons_left {l₁ l₂ : List α} (h : l₁ <+~ l₂) (x : α) (hx : count x l₁ < count x l₂) :
     x :: l₁ <+~ l₂ := by
-  rw [subperm_ext_iff] at h⊢
+  rw [subperm_ext_iff] at h ⊢
   intro y hy
   by_cases hy' : y = x
   · subst x
chore: formatting issues (#4947)

Co-authored-by: Scott Morrison <scott.morrison@anu.edu.au> Co-authored-by: Parcly Taxel <reddeloostw@gmail.com>

Diff
@@ -392,7 +392,7 @@ section Subperm
   a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
   multiplicities of elements, and is used for the `≤` relation on multisets. -/
 def Subperm (l₁ l₂ : List α) : Prop :=
-  ∃ (l : _)(_ : l ~ l₁), l <+ l₂
+  ∃ (l : _) (_ : l ~ l₁), l <+ l₂
 #align list.subperm List.Subperm
 
 /-- `Subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
@@ -1236,15 +1236,15 @@ theorem length_permutations (l : List α) : length (permutations l) = (length l)
 #align list.length_permutations List.length_permutations
 
 theorem mem_permutations_of_perm_lemma {is l : List α}
-    (H : l ~ [] ++ is → (∃ (ts' : _)(_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
+    (H : l ~ [] ++ is → (∃ (ts' : _) (_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
     l ~ is → l ∈ permutations is := by simpa [permutations, perm_nil] using H
 #align list.mem_permutations_of_perm_lemma List.mem_permutations_of_perm_lemma
 
 theorem mem_permutationsAux_of_perm :
     ∀ {ts is l : List α},
-      l ~ is ++ ts → (∃ (is' : _)(_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is := by
+      l ~ is ++ ts → (∃ (is' : _) (_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is := by
   show ∀ (ts is l : List α),
-      l ~ is ++ ts → (∃ (is' : _)(_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is
+      l ~ is ++ ts → (∃ (is' : _) (_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is
   refine' permutationsAux.rec (by simp) _
   intro t ts is IH1 IH2 l p
   rw [permutationsAux_cons, mem_foldr_permutationsAux2]
chore: reenable eta, bump to nightly 2023-05-16 (#3414)

Now that leanprover/lean4#2210 has been merged, this PR:

  • removes all the set_option synthInstance.etaExperiment true commands (and some etaExperiment% term elaborators)
  • removes many but not quite all set_option maxHeartbeats commands
  • makes various other changes required to cope with leanprover/lean4#2210.

Co-authored-by: Scott Morrison <scott.morrison@anu.edu.au> Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Matthew Ballard <matt@mrb.email>

Diff
@@ -1270,8 +1270,8 @@ private theorem DecEq_eq {α : Type _} [DecidableEq α] :
      instBEqList = @instBEq (List α) instDecidableEqList :=
   congr_arg BEq.mk <| by
     funext l₁ l₂
-    rw [Bool.eq_iff_eq_true_iff, @beq_iff_eq _ (instBEqList),
-      @beq_iff_eq _ (@instBEq (List α) instDecidableEqList)]
+    show (l₁ == l₂) = _
+    rw [Bool.eq_iff_eq_true_iff, @beq_iff_eq _ (_), decide_eq_true_iff]
 
 theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
     (permutations'Aux a l).bind (permutations'Aux b) ~
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
@@ -730,7 +730,6 @@ theorem Subperm.exists_of_length_lt {l₁ l₂ : List α} :
       · exact ⟨a, s.eq_of_length h ▸ Subperm.refl _⟩
     · exact (IH <| Nat.lt_of_succ_lt_succ h).imp fun a s =>
           (swap _ _ _).subperm_right.1 <| (subperm_cons _).2 s
-
 #align list.subperm.exists_of_length_lt List.Subperm.exists_of_length_lt
 
 protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ := by
@@ -1162,7 +1161,6 @@ theorem Perm.take_inter {α : Type _} [DecidableEq α] {xs ys : List α} (n : 
   exact Perm.trans (show xs.take n ~ xs.filter (. ∈ xs.take n) by
       conv_lhs => rw [Nodup.take_eq_filter_mem ((Perm.nodup_iff h).2 h')])
     (Perm.filter _ h)
-
 #align list.perm.take_inter List.Perm.take_inter
 
 theorem Perm.drop_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys) (h' : ys.Nodup) :
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
@@ -1373,7 +1373,7 @@ theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) :
     · subst hx
       simpa [takeWhile, Nat.succ_inj', DecEq_eq] using IH _
     · rw [takeWhile]
-      simp only [mem_map', cons.injEq, Ne.symm hx, false_and, and_false, exists_false,
+      simp only [mem_map, cons.injEq, Ne.symm hx, false_and, and_false, exists_false,
         not_false_iff, count_eq_zero_of_not_mem, zero_add, hx, decide_False, length_nil]
 #align list.count_permutations'_aux_self List.count_permutations'Aux_self
 
@@ -1406,7 +1406,7 @@ theorem nodup_permutations'Aux_of_not_mem (s : List α) (x : α) (hx : x ∉ s)
   induction' s with y s IH
   · simp
   · simp only [not_or, mem_cons] at hx
-    simp only [permutations'Aux, nodup_cons, mem_map', cons.injEq, exists_eq_right_right, not_and]
+    simp only [permutations'Aux, nodup_cons, mem_map, cons.injEq, exists_eq_right_right, not_and]
     refine' ⟨fun _ => Ne.symm hx.left, _⟩
     rw [nodup_map_iff]
     · exact IH hx.right
chore: sync Data.List.Perm (#3076)
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
 
 ! This file was ported from Lean 3 source module data.list.perm
-! leanprover-community/mathlib commit 7b78d1776212a91ecc94cf601f83bdcc46b04213
+! leanprover-community/mathlib commit 47adfab39a11a072db552f47594bf8ed2cf8a722
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -215,13 +215,8 @@ theorem singleton_perm {a : α} {l : List α} : [a] ~ l ↔ [a] = l :=
   @replicate_perm α 1 a l
 #align list.singleton_perm List.singleton_perm
 
-theorem Perm.eq_singleton {a : α} {l : List α} (p : l ~ [a]) : l = [a] :=
-  perm_singleton.1 p
-#align list.perm.eq_singleton List.Perm.eq_singleton
-
-theorem Perm.singleton_eq {a : α} {l : List α} (p : [a] ~ l) : [a] = l :=
-  p.symm.eq_singleton.symm
-#align list.perm.singleton_eq List.Perm.singleton_eq
+alias perm_singleton ↔ Perm.eq_singleton _
+alias singleton_perm ↔ Perm.singleton_eq _
 
 theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp
 #align list.singleton_perm_singleton List.singleton_perm_singleton
chore: add missing hypothesis names to by_cases (#2679)
Diff
@@ -841,7 +841,7 @@ theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂
     l₁.bagInter t ~ l₂.bagInter t := by
   induction' h with x _ _ _ _ x y _ _ _ _ _ _ ih_1 ih_2 generalizing t; · simp
   · by_cases x ∈ t <;> simp [*, Perm.cons]
-  · by_cases x = y
+  · by_cases h : x = y
     · simp [h]
     by_cases xt : x ∈ t <;> by_cases yt : y ∈ t
     · simp [xt, yt, mem_erase_of_ne h, mem_erase_of_ne (Ne.symm h), erase_comm, swap]
@@ -854,7 +854,7 @@ theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂
 theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) :
     l.bagInter t₁ = l.bagInter t₂ := by
   induction' l with a l IH generalizing t₁ t₂ p; · simp
-  by_cases a ∈ t₁
+  by_cases h : a ∈ t₁
   · simp [h, p.subset h, IH (p.erase _)]
   · simp [h, mt p.mem_iff.2 h, IH p]
 #align list.perm.bag_inter_left List.Perm.bagInter_left
@@ -880,11 +880,11 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
       specialize H b
       simp at H
       contradiction
-    · have : a ∈ l₂ := count_pos.1 (by rw [← H] ; simp)
+    · have : a ∈ l₂ := count_pos.1 (by rw [← H]; simp)
       refine' ((IH fun b => _).cons a).trans (perm_cons_erase this).symm
       specialize H b
       rw [(perm_cons_erase this).count_eq] at H
-      by_cases b = a <;> simp [h] at H⊢ <;> assumption⟩
+      by_cases h : b = a <;> simpa [h] using H⟩
 #align list.perm_iff_count List.perm_iff_count
 
 theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h : a ≠ b) :
chore: add missing #align statements (#1902)

This PR is the result of a slight variant on the following "algorithm"

  • take all mathlib 3 names, remove _ and make all uppercase letters into lowercase
  • take all mathlib 4 names, remove _ and make all uppercase letters into lowercase
  • look for matches, and create pairs (original_lean3_name, OriginalLean4Name)
  • for pairs that do not have an align statement:
    • use Lean 4 to lookup the file + position of the Lean 4 name
    • add an #align statement just before the next empty line
  • manually fix some tiny mistakes (e.g., empty lines in proofs might cause the #align statement to have been inserted too early)
Diff
@@ -681,6 +681,8 @@ theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ 
 #align list.subperm_cons List.subperm_cons
 
 alias subperm_cons ↔ subperm.of_cons subperm.cons
+#align list.subperm.of_cons List.subperm.of_cons
+#align list.subperm.cons List.subperm.cons
 
 --Porting note: commented out
 --attribute [protected] subperm.cons
Feat: add List.perm_replicate_append_replicate (#1509)

This is a forward-port of leanprover-community/mathlib#18126

Also golf a proof.

Diff
@@ -87,29 +87,25 @@ instance isSetoid (α) : Setoid (List α) :=
 #align list.is_setoid List.isSetoid
 
 -- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it
-theorem Perm.subset {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ := fun a =>
+theorem Perm.mem_iff {a : α} {l₁ l₂ : List α} (p : l₁ ~ l₂) : a ∈ l₁ ↔ a ∈ l₂ :=
   p.rec
-  (fun h => h)
-  (fun x l₁ l₂ _r hs h => by
-    cases h
-    . apply Mem.head
-    . apply Mem.tail
-      apply hs
-      assumption)
-  (fun x y l h => by
-    match h with
-    | .head _ => exact Mem.tail x (Mem.head l)
-    | .tail _ (.head _) => apply Mem.head
-    | .tail _ (.tail _ h) => exact Mem.tail x (Mem.tail y h))
-  (fun _ _ h₁ h₂ h => by
-    apply h₂
-    apply h₁
-    assumption)
+    Iff.rfl
+    (fun _ _ _ _ hs => by simp only [mem_cons, hs])
+    (fun _ _ _ => by simp only [mem_cons, or_left_comm])
+    (fun _ _ => Iff.trans)
+#align list.perm.mem_iff List.Perm.mem_iff
+
+theorem Perm.subset {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ :=
+  fun _ => p.mem_iff.mp
 #align list.perm.subset List.Perm.subset
 
-theorem Perm.mem_iff {a : α} {l₁ l₂ : List α} (h : l₁ ~ l₂) : a ∈ l₁ ↔ a ∈ l₂ :=
-  Iff.intro (fun m => h.subset m) fun m => h.symm.subset m
-#align list.perm.mem_iff List.Perm.mem_iff
+theorem Perm.subset_congr_left {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₁ ⊆ l₃ ↔ l₂ ⊆ l₃ :=
+  ⟨h.symm.subset.trans, h.subset.trans⟩
+#align list.perm.subset_congr_left List.Perm.subset_congr_left
+
+theorem Perm.subset_congr_right {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₃ ⊆ l₁ ↔ l₃ ⊆ l₂ :=
+  ⟨fun h' => h'.trans h.subset, fun h' => h'.trans h.symm.subset⟩
+#align list.perm.subset_congr_right List.Perm.subset_congr_right
 
 theorem Perm.append_right {l₁ l₂ : List α} (t₁ : List α) (p : l₁ ~ l₂) : l₁ ++ t₁ ~ l₂ ++ t₁ :=
   p.rec
@@ -889,6 +885,15 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
       by_cases b = a <;> simp [h] at H⊢ <;> assumption⟩
 #align list.perm_iff_count List.perm_iff_count
 
+theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h : a ≠ b) :
+    l ~ replicate m a ++ replicate n b ↔ count a l = m ∧ count b l = n ∧ l ⊆ [a, b] := by
+  rw [perm_iff_count, ← Decidable.and_forall_ne a, ← Decidable.and_forall_ne b]
+  suffices : l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l
+  { simp (config := { contextual := true }) [count_replicate, h, h.symm, this] }
+  simp_rw [Ne.def, ← and_imp, ← not_or, Decidable.not_imp_not, subset_def, mem_cons,
+    not_mem_nil, or_false, or_comm]
+#align list.perm_replicate_append_replicate List.perm_replicate_append_replicate
+
 theorem Subperm.cons_right {α : Type _} {l l' : List α} (x : α) (h : l <+~ l') : l <+~ x :: l' :=
   h.trans (sublist_cons x l').subperm
 #align list.subperm.cons_right List.Subperm.cons_right
chore: add #align statements for to_additive decls (#1816)

Co-authored-by: Floris van Doorn <fpvdoorn@gmail.com>

Diff
@@ -583,6 +583,7 @@ theorem Perm.prod_eq' [M : Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (h
     intro a b h z
     rw [mul_assoc z, mul_assoc z, h]
 #align list.perm.prod_eq' List.Perm.prod_eq'
+#align list.perm.sum_eq' List.Perm.sum_eq'
 -- Porting note: TODO do I need to do anything to handle the to_additive instance?
 
 variable [CommMonoid α]
@@ -591,11 +592,13 @@ variable [CommMonoid α]
 theorem Perm.prod_eq {l₁ l₂ : List α} (h : Perm l₁ l₂) : prod l₁ = prod l₂ :=
   h.fold_op_eq
 #align list.perm.prod_eq List.Perm.prod_eq
+#align list.perm.sum_eq List.Perm.sum_eq
 
 @[to_additive]
 theorem prod_reverse (l : List α) : prod l.reverse = prod l :=
   (reverse_perm l).prod_eq
 #align list.prod_reverse List.prod_reverse
+#align list.sum_reverse List.sum_reverse
 
 end CommMonoid
 
chore: format by line breaks with long lines (#1529)

This was done semi-automatically with some regular expressions in vim in contrast to the fully automatic https://github.com/leanprover-community/mathlib4/pull/1523.

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

Diff
@@ -322,8 +322,8 @@ theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p :
       ⟨r₁, pr.trans pm, sr⟩
 #align list.exists_perm_sublist List.exists_perm_sublist
 
-theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂) : sizeOf l₁ = sizeOf l₂ :=
-  by
+theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂) :
+    sizeOf l₁ = sizeOf l₂ := by
   induction h with -- hd l₁ l₂ h₁₂ h_sz₁₂ a b l l₁ l₂ l₃ h₁₂ h₂₃ h_sz₁₂ h_sz₂₃
   | nil => rfl
   | cons _ _ h_sz₁₂ => simp [h_sz₁₂]
@@ -983,8 +983,8 @@ theorem perm_insertNth {α} (x : α) (l : List α) {n} (h : n ≤ l.length) :
     · apply Perm.swap
 #align list.perm_insert_nth List.perm_insertNth
 
-theorem Perm.union_right {l₁ l₂ : List α} (t₁ : List α) (h : l₁ ~ l₂) : l₁.union t₁ ~ l₂.union t₁ :=
-  by
+theorem Perm.union_right {l₁ l₂ : List α} (t₁ : List α) (h : l₁ ~ l₂) :
+    l₁.union t₁ ~ l₂.union t₁ := by
   induction' h with a _ _ _ ih _ _ _ _ _ _ _ _ ih_1 ih_2 <;> try simp
   · exact ih.insert a
   · apply perm_insert_swap
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
@@ -247,8 +247,7 @@ theorem perm_induction_on {P : List α → List α → Prop} {l₁ l₂ : List 
 -- Porting note: TODO figure out why invalid congr
 -- @[congr]
 theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~ l₂) :
-    filterMap f l₁ ~ filterMap f l₂ :=
-  by
+    filterMap f l₁ ~ filterMap f l₂ := by
   induction p with
   | nil => simp
   | cons x _p IH =>
@@ -271,8 +270,7 @@ theorem Perm.map (f : α → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : map f
 #align list.perm.map List.Perm.map
 
 theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) {H₁ H₂} :
-    pmap f l₁ H₁ ~ pmap f l₂ H₂ :=
-  by
+    pmap f l₁ H₁ ~ pmap f l₂ H₂ := by
   induction p with
   | nil => simp
   | cons x _p IH => simp [IH, Perm.cons]
@@ -287,8 +285,7 @@ theorem Perm.filter (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
 #align list.perm.filter List.Perm.filter
 
 theorem filter_append_perm (p : α → Bool) (l : List α) :
-    filter p l ++ filter (fun x => ¬p x) l ~ l :=
-  by
+    filter p l ++ filter (fun x => ¬p x) l ~ l := by
   induction' l with x l ih
   · rfl
   · by_cases h : p x
@@ -300,8 +297,7 @@ theorem filter_append_perm (p : α → Bool) (l : List α) :
 #align list.filter_append_perm List.filter_append_perm
 
 theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
-    ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' :=
-  by
+    ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' := by
   induction p generalizing l₁ with
   | nil =>
     exact ⟨[], eq_nil_of_sublist_nil s ▸ Perm.refl _, nil_sublist _⟩
@@ -344,8 +340,7 @@ variable {γ : Type _} {δ : Type _} {r : α → β → Prop} {p : γ → δ →
 -- mathport name: «expr ∘r »
 local infixr:80 " ∘r " => Relation.Comp
 
-theorem perm_comp_perm : (Perm ∘r Perm : List α → List α → Prop) = Perm :=
-  by
+theorem perm_comp_perm : (Perm ∘r Perm : List α → List α → Prop) = Perm := by
   funext a c; apply propext
   constructor
   · exact fun ⟨b, hab, hba⟩ => Perm.trans hab hba
@@ -371,8 +366,7 @@ theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) :
     exact ⟨lb₁, hab₁, Perm.trans h₁₂ h₂₃⟩
 #align list.perm_comp_forall₂ List.perm_comp_forall₂
 
-theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r :=
-  by
+theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
   funext l₁ l₃; apply propext
   constructor
   · intro h
@@ -547,8 +541,7 @@ theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : Left
 theorem Perm.rec_heq {β : List α → Sort _} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α}
     (hl : Perm l l') (f_congr : ∀ {a l l' b b'}, Perm l l' → HEq b b' → HEq (f a l b) (f a l' b'))
     (f_swap : ∀ {a a' l b}, HEq (f a (a' :: l) (f a' l b)) (f a' (a :: l) (f a l b))) :
-    HEq (@List.rec α β b f l) (@List.rec α β b f l') :=
-  by
+    HEq (@List.rec α β b f l) (@List.rec α β b f l') := by
   induction hl
   case nil => rfl
   case cons a l l' h ih => exact f_congr h ih
@@ -607,8 +600,7 @@ theorem prod_reverse (l : List α) : prod l.reverse = prod l :=
 end CommMonoid
 
 theorem perm_inv_core {a : α} {l₁ l₂ r₁ r₂ : List α} :
-    l₁ ++ a :: r₁ ~ l₂ ++ a :: r₂ → l₁ ++ r₁ ~ l₂ ++ r₂ :=
-  by
+    l₁ ++ a :: r₁ ~ l₂ ++ a :: r₂ → l₁ ++ r₁ ~ l₂ ++ r₂ := by
   generalize e₁ : l₁ ++ a :: r₁ = s₁; generalize e₂ : l₂ ++ a :: r₂ = s₂
   intro p; revert l₁ l₂ r₁ r₂ e₁ e₂; clear l₁ l₂ β
   show ∀ _ _ _ _, _
@@ -674,8 +666,7 @@ theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l
     Perm.append_right _⟩
 #align list.perm_append_right_iff List.perm_append_right_iff
 
-theorem perm_option_to_list {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList ↔ o₁ = o₂ :=
-  by
+theorem perm_option_to_list {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList ↔ o₁ = o₂ := by
   refine' ⟨fun p => _, fun e => e ▸ Perm.refl _⟩
   cases' o₁ with a <;> cases' o₂ with b; · rfl
   · cases p.length_eq
@@ -696,8 +687,7 @@ alias subperm_cons ↔ subperm.of_cons subperm.cons
 --attribute [protected] subperm.cons
 
 theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (h₁ : a ∉ l₁) (h₂ : a ∈ l₂)
-    (s : l₁ <+~ l₂) : a :: l₁ <+~ l₂ :=
-  by
+    (s : l₁ <+~ l₂) : a :: l₁ <+~ l₂ := by
   rcases s with ⟨l, p, s⟩
   induction s generalizing l₁
   case slnil => cases h₂
@@ -747,8 +737,7 @@ theorem Subperm.exists_of_length_lt {l₁ l₂ : List α} :
 
 #align list.subperm.exists_of_length_lt List.Subperm.exists_of_length_lt
 
-protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ :=
-  by
+protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ := by
   induction' d with a l₁' h d IH
   · exact ⟨nil, Perm.nil, nil_sublist _⟩
   · cases' forall_mem_cons.1 H with H₁ H₂
@@ -793,8 +782,7 @@ theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase
     rw [erase_of_not_mem h₁, erase_of_not_mem h₂] ; exact p
 #align list.perm.erase List.Perm.erase
 
-theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a :=
-  by
+theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a := by
   by_cases h : a ∈ l
   · exact (perm_cons_erase h).subperm
   · rw [erase_of_not_mem h]
@@ -828,8 +816,7 @@ theorem Subperm.diff_right {l₁ l₂ : List α} (h : l₁ <+~ l₂) (t : List 
 #align list.subperm.diff_right List.Subperm.diff_right
 
 theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) :
-    (a :: l).erase b <+~ a :: l.erase b :=
-  by
+    (a :: l).erase b <+~ a :: l.erase b := by
   by_cases h : a = b
   · subst b
     rw [erase_cons_head]
@@ -850,8 +837,7 @@ theorem subset_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂
 #align list.subset_cons_diff List.subset_cons_diff
 
 theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) :
-    l₁.bagInter t ~ l₂.bagInter t :=
-  by
+    l₁.bagInter t ~ l₂.bagInter t := by
   induction' h with x _ _ _ _ x y _ _ _ _ _ _ ih_1 ih_2 generalizing t; · simp
   · by_cases x ∈ t <;> simp [*, Perm.cons]
   · by_cases x = y
@@ -865,8 +851,7 @@ theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂
 #align list.perm.bag_inter_right List.Perm.bagInter_right
 
 theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) :
-    l.bagInter t₁ = l.bagInter t₂ :=
-  by
+    l.bagInter t₁ = l.bagInter t₂ := by
   induction' l with a l IH generalizing t₁ t₂ p; · simp
   by_cases a ∈ t₁
   · simp [h, p.subset h, IH (p.erase _)]
@@ -907,8 +892,7 @@ theorem Subperm.cons_right {α : Type _} {l l' : List α} (x : α) (h : l <+~ l'
 
 /-- The list version of `add_tsub_cancel_of_le` for multisets. -/
 theorem subperm_append_diff_self_of_count_le {l₁ l₂ : List α}
-    (h : ∀ x ∈ l₁, count x l₁ ≤ count x l₂) : l₁ ++ l₂.diff l₁ ~ l₂ :=
-  by
+    (h : ∀ x ∈ l₁, count x l₁ ≤ count x l₂) : l₁ ++ l₂.diff l₁ ~ l₂ := by
   induction' l₁ with hd tl IH generalizing l₂
   · simp
   · have : hd ∈ l₂ := by
@@ -1103,8 +1087,7 @@ theorem Perm.bind_left (l : List α) {f g : α → List β} (h : ∀ a ∈ l, f
 #align list.perm.bind_left List.Perm.bind_left
 
 theorem bind_append_perm (l : List α) (f g : α → List β) :
-    l.bind f ++ l.bind g ~ l.bind fun x => f x ++ g x :=
-  by
+    l.bind f ++ l.bind g ~ l.bind fun x => f x ++ g x := by
   induction' l with a l IH <;> simp
   refine' (Perm.trans _ (IH.append_left _)).append_left _
   rw [← append_assoc, ← append_assoc]
@@ -1178,8 +1161,7 @@ theorem Perm.take_inter {α : Type _} [DecidableEq α] {xs ys : List α} (n : 
 #align list.perm.take_inter List.Perm.take_inter
 
 theorem Perm.drop_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys) (h' : ys.Nodup) :
-    xs.drop n ~ ys.inter (xs.drop n) :=
-  by
+    xs.drop n ~ ys.inter (xs.drop n) := by
   by_cases h'' : n ≤ xs.length
   · let n' := xs.length - n
     have h₀ : n = xs.length - n' := by
@@ -1235,8 +1217,7 @@ theorem perm_of_mem_permutations {l₁ l₂ : List α} (h : l₁ ∈ permutation
 #align list.perm_of_mem_permutations List.perm_of_mem_permutations
 
 theorem length_permutationsAux :
-    ∀ ts is : List α, length (permutationsAux ts is) + is.length ! = (length ts + length is)! :=
-  by
+    ∀ ts is : List α, length (permutationsAux ts is) + is.length ! = (length ts + length is)! := by
   refine' permutationsAux.rec (by simp) _
   intro t ts is IH1 IH2
   have IH2 : length (permutationsAux is nil) + 1 = is.length ! := by simpa using IH2
@@ -1291,8 +1272,7 @@ private theorem DecEq_eq {α : Type _} [DecidableEq α] :
 
 theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
     (permutations'Aux a l).bind (permutations'Aux b) ~
-      (permutations'Aux b l).bind (permutations'Aux a) :=
-  by
+      (permutations'Aux b l).bind (permutations'Aux a) := by
   induction' l with c l ih
   · simp [swap]
   simp [permutations'Aux]
@@ -1314,8 +1294,7 @@ theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
   exact perm_append_comm.append (ih.map _)
 #align list.perm_permutations'_aux_comm List.perm_permutations'Aux_comm
 
-theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t :=
-  by
+theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t := by
   induction' p with a s t _ IH a b l s t u _ _ IH₁ IH₂; · simp
   · simp only [permutations']
     exact IH.bind_right _
@@ -1381,8 +1360,7 @@ theorem nthLe_permutations'Aux (s : List α) (x : α) (n : ℕ)
 #align list.nth_le_permutations'_aux List.nthLe_permutations'Aux
 
 theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) :
-    count (x :: l) (permutations'Aux x l) = length (takeWhile ((· = ·) x) l) + 1 :=
-  by
+    count (x :: l) (permutations'Aux x l) = length (takeWhile ((· = ·) x) l) + 1 := by
   induction' l with y l IH generalizing x
   · simp [takeWhile, count]
   · rw [permutations'Aux, DecEq_eq, count_cons_self]
@@ -1396,8 +1374,7 @@ theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) :
 
 @[simp]
 theorem length_permutations'Aux (s : List α) (x : α) :
-    length (permutations'Aux x s) = length s + 1 :=
-  by
+    length (permutations'Aux x s) = length s + 1 := by
   induction' s with y s IH
   · simp
   · simpa using IH
@@ -1410,8 +1387,7 @@ theorem permutations'Aux_nthLe_zero (s : List α) (x : α)
   nthLe_permutations'Aux _ _ _ _
 #align list.permutations'_aux_nth_le_zero List.permutations'Aux_nthLe_zero
 
-theorem injective_permutations'Aux (x : α) : Function.Injective (permutations'Aux x) :=
-  by
+theorem injective_permutations'Aux (x : α) : Function.Injective (permutations'Aux x) := by
   intro s t h
   apply insertNth_injective s.length x
   have hl : s.length = t.length := by simpa using congr_arg length h
@@ -1433,8 +1409,7 @@ theorem nodup_permutations'Aux_of_not_mem (s : List α) (x : α) (hx : x ∉ s)
 #align list.nodup_permutations'_aux_of_not_mem List.nodup_permutations'Aux_of_not_mem
 
 set_option linter.deprecated false in
-theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'Aux x s) ↔ x ∉ s :=
-  by
+theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'Aux x s) ↔ x ∉ s := by
   refine' ⟨fun h => _, nodup_permutations'Aux_of_not_mem _ _⟩
   intro H
   obtain ⟨k, hk, hk'⟩ := nthLe_of_mem H
@@ -1468,8 +1443,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'
 #align list.nodup_permutations'_aux_iff List.nodup_permutations'Aux_iff
 
 set_option linter.deprecated false in
-theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations :=
-  by
+theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations := by
   rw [(permutations_perm_permutations' s).nodup_iff]
   induction' hs with x l h h' IH
   · simp
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
@@ -196,37 +196,27 @@ theorem perm_cons_append_cons {l l₁ l₂ : List α} (a : α) (p : l ~ l₁ ++
 #align list.perm_cons_append_cons List.perm_cons_append_cons
 
 @[simp]
-theorem perm_replicate {a : α} {n : ℕ} {l : List α} :
-    l ~ List.replicate n a ↔ l = List.replicate n a :=
+theorem perm_replicate {n : ℕ} {a : α} {l : List α} :
+    l ~ replicate n a ↔ l = replicate n a :=
   ⟨fun p => eq_replicate.2
     ⟨p.length_eq.trans <| length_replicate _ _, fun _b m => eq_of_mem_replicate <| p.subset m⟩,
     fun h => h ▸ Perm.refl _⟩
-
-set_option linter.deprecated false in
-@[deprecated perm_replicate]
-theorem perm_repeat {a : α} {n : ℕ} {l : List α} : l ~ List.repeat a n ↔ l = List.repeat a n :=
-  perm_replicate
-#align list.perm_repeat List.perm_repeat
+#align list.perm_replicate List.perm_replicate
 
 @[simp]
-theorem replicate_perm {a : α} {n : ℕ} {l : List α} :
-    List.replicate n a ~ l ↔ List.replicate n a = l :=
+theorem replicate_perm {n : ℕ} {a : α} {l : List α} :
+    replicate n a ~ l ↔ replicate n a = l :=
   (perm_comm.trans perm_replicate).trans eq_comm
-
-set_option linter.deprecated false in
-@[deprecated replicate_perm]
-theorem repeat_perm {a : α} {n : ℕ} {l : List α} : List.repeat a n ~ l ↔ List.repeat a n = l :=
-  replicate_perm
-#align list.repeat_perm List.repeat_perm
+#align list.replicate_perm List.replicate_perm
 
 @[simp]
 theorem perm_singleton {a : α} {l : List α} : l ~ [a] ↔ l = [a] :=
-  @perm_replicate α a 1 l
+  @perm_replicate α 1 a l
 #align list.perm_singleton List.perm_singleton
 
 @[simp]
 theorem singleton_perm {a : α} {l : List α} : [a] ~ l ↔ [a] = l :=
-  @replicate_perm α a 1 l
+  @replicate_perm α 1 a l
 #align list.singleton_perm List.singleton_perm
 
 theorem Perm.eq_singleton {a : α} {l : List α} (p : l ~ [a]) : l = [a] :=
feat: port Data.Multiset.Basic (#1491)

Co-authored-by: ChrisHughes24 <chrishughes24@gmail.com> Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Co-authored-by: Reid Barton <rwbarton@gmail.com> Co-authored-by: qawbecrdtey <qawbecrdtey@kaist.ac.kr> Co-authored-by: Chris Hughes <33847686+ChrisHughes24@users.noreply.github.com>

Diff
@@ -292,11 +292,11 @@ theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α
     exact fun a m => H₂ a (p₂.subset m)
 #align list.perm.pmap List.Perm.pmap
 
-theorem Perm.filter (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
+theorem Perm.filter (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
     filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter] ; apply s.filterMap _
 #align list.perm.filter List.Perm.filter
 
-theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
+theorem filter_append_perm (p : α → Bool) (l : List α) :
     filter p l ++ filter (fun x => ¬p x) l ~ l :=
   by
   induction' l with x l ih
@@ -476,7 +476,7 @@ theorem Subperm.subset {l₁ l₂ : List α} : l₁ <+~ l₂ → l₁ ⊆ l₂
   | ⟨_l, p, s⟩ => Subset.trans p.symm.subset s.subset
 #align list.subperm.subset List.Subperm.subset
 
-theorem Subperm.filter (p : α → Prop) [DecidablePred p] ⦃l l' : List α⦄ (h : l <+~ l') :
+theorem Subperm.filter (p : α → Bool) ⦃l l' : List α⦄ (h : l <+~ l') :
     filter p l <+~ filter p l' := by
   obtain ⟨xs, hp, h⟩ := h
   exact ⟨_, hp.filter p, h.filter p⟩
@@ -494,19 +494,18 @@ theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ →
     ⟨l, p.cons a⟩
 #align list.sublist.exists_perm_append List.Sublist.exists_perm_append
 
-theorem Perm.countp_eq (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
+theorem Perm.countp_eq (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
     countp p l₁ = countp p l₂ := by
   rw [countp_eq_length_filter, countp_eq_length_filter] ; exact (s.filter _).length_eq
 #align list.perm.countp_eq List.Perm.countp_eq
 
-theorem Subperm.countp_le (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} :
+theorem Subperm.countp_le (p : α → Bool) {l₁ l₂ : List α} :
     l₁ <+~ l₂ → countp p l₁ ≤ countp p l₂
   | ⟨_l, p', s⟩ => p'.countp_eq p ▸ s.countp_le p
 #align list.subperm.countp_le List.Subperm.countp_le
 
-theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred p] [DecidablePred p']
-    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countp p = l₂.countp p' :=
-  by
+theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Bool}
+    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countp p = l₂.countp p' := by
   rw [← s.countp_eq p']
   clear s
   induction' l₁ with y s hs
@@ -515,9 +514,8 @@ theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred
     simp only [countp_cons, hs hp.2, hp.1]
 #align list.perm.countp_congr List.Perm.countp_congr
 
-theorem countp_eq_countp_filter_add (l : List α) (p q : α → Prop) [DecidablePred p]
-    [DecidablePred q] : l.countp p = (l.filter q).countp p + (l.filter fun a => ¬q a).countp p :=
-  by
+theorem countp_eq_countp_filter_add (l : List α) (p q : α → Bool) :
+    l.countp p = (l.filter q).countp p + (l.filter fun a => ¬q a).countp p := by
   rw [← countp_append]
   exact Perm.countp_eq _ (filter_append_perm _ _).symm
 #align list.countp_eq_countp_filter_add List.countp_eq_countp_filter_add
@@ -861,7 +859,7 @@ theorem subset_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂
   subperm_cons_diff.subset
 #align list.subset_cons_diff List.subset_cons_diff
 
-theorem Perm.bag_inter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) :
+theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) :
     l₁.bagInter t ~ l₂.bagInter t :=
   by
   induction' h with x _ _ _ _ x y _ _ _ _ _ _ ih_1 ih_2 generalizing t; · simp
@@ -874,21 +872,21 @@ theorem Perm.bag_inter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l
     · simp [xt, yt, mt mem_of_mem_erase, Perm.cons]
     · simp [xt, yt]
   · exact (ih_1 _).trans (ih_2 _)
-#align list.perm.bag_inter_right List.Perm.bag_inter_right
+#align list.perm.bag_inter_right List.Perm.bagInter_right
 
-theorem Perm.bag_inter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) :
+theorem Perm.bagInter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) :
     l.bagInter t₁ = l.bagInter t₂ :=
   by
   induction' l with a l IH generalizing t₁ t₂ p; · simp
   by_cases a ∈ t₁
   · simp [h, p.subset h, IH (p.erase _)]
   · simp [h, mt p.mem_iff.2 h, IH p]
-#align list.perm.bag_inter_left List.Perm.bag_inter_left
+#align list.perm.bag_inter_left List.Perm.bagInter_left
 
-theorem Perm.bag_inter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) :
+theorem Perm.bagInter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) :
     l₁.bagInter t₁ ~ l₂.bagInter t₂ :=
-  ht.bag_inter_left l₂ ▸ hl.bag_inter_right _
-#align list.perm.bag_inter List.Perm.bag_inter
+  ht.bagInter_left l₂ ▸ hl.bagInter_right _
+#align list.perm.bag_inter List.Perm.bagInter
 
 theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} :
     a :: l₁ ~ l₂ ↔ a ∈ l₂ ∧ l₁ ~ l₂.erase a :=
feat: port Mathlib.Data.List.Perm (#1478)

Co-authored-by: Johan Commelin <johan@commelin.net> Co-authored-by: ChrisHughes24 <chrishughes24@gmail.com>

Diff
@@ -2,9 +2,16 @@
 Copyright (c) 2015 Microsoft Corporation. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
+
+! This file was ported from Lean 3 source module data.list.perm
+! leanprover-community/mathlib commit 7b78d1776212a91ecc94cf601f83bdcc46b04213
+! Please do not edit these lines, except to modify the commit id
+! if you have ported upstream changes.
 -/
-import Mathlib.Init.Set
-import Mathlib.Data.List.Pairwise
+import Mathlib.Data.List.Dedup
+import Mathlib.Data.List.Permutation
+import Mathlib.Data.List.Range
+import Mathlib.Data.Nat.Factorial.Basic
 
 /-!
 # List Permutations
@@ -17,147 +24,1504 @@ another.
 The notation `~` is used for permutation equivalence.
 -/
 
+
+open Nat
+
+universe uu vv
+
 namespace List
 
-/-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are Permutations
+variable {α : Type uu} {β : Type vv} {l₁ l₂ : List α}
+
+/-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations
   of each other. This is defined by induction using pairwise swaps. -/
-inductive Perm {α} : List α → List α → Prop
-| nil   : Perm [] []
-| cons  : ∀ (x : α) {l₁ l₂ : List α}, Perm l₁ l₂ → Perm (x::l₁) (x::l₂)
-| swap  : ∀ (x y : α) (l : List α), Perm (y::x::l) (x::y::l)
-| trans : ∀ {l₁ l₂ l₃ : List α}, Perm l₁ l₂ → Perm l₂ l₃ → Perm l₁ l₃
+inductive Perm : List α → List α → Prop
+  | nil : Perm [] []
+  | cons (x : α) {l₁ l₂ : List α} : Perm l₁ l₂ → Perm (x :: l₁) (x :: l₂)
+  | swap (x y : α) (l : List α) : Perm (y :: x :: l) (x :: y :: l)
+  | trans {l₁ l₂ l₃ : List α} : Perm l₁ l₂ → Perm l₂ l₃ → Perm l₁ l₃
+#align list.perm List.Perm
 
-open Perm
+open Perm (swap)
 
+/-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations
+  of each other. This is defined by induction using pairwise swaps. -/
 infixl:50 " ~ " => Perm
 
-protected theorem Perm.refl : ∀ (l : List α), l ~ l
-| []      => Perm.nil
-| (x::xs) => (Perm.refl xs).cons x
+@[simp, refl]
+protected theorem Perm.refl : ∀ l : List α, l ~ l
+  | [] => Perm.nil
+  | x :: xs => (Perm.refl xs).cons x
+#align list.perm.refl List.Perm.refl
 
-protected theorem Perm.symm {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₂ ~ l₁ := by
-induction p with
-| nil => exact Perm.nil
-| cons x _ ih => exact Perm.cons x ih
-| swap x y l => exact Perm.swap y x l
-| trans _ _ ih₁ ih₂ => exact Perm.trans ih₂ ih₁
+-- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it
+@[symm]
+protected theorem Perm.symm {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₂ ~ l₁ :=
+  p.rec
+    .nil
+    (fun x _ _ _ r₁ => .cons x r₁)
+    (fun x y l => .swap y x l)
+    (fun _ _ r₁ r₂ => .trans r₂ r₁)
+#align list.perm.symm List.Perm.symm
 
-theorem Perm_comm {l₁ l₂ : List α} : l₁ ~ l₂ ↔ l₂ ~ l₁ := ⟨Perm.symm, Perm.symm⟩
+theorem perm_comm {l₁ l₂ : List α} : l₁ ~ l₂ ↔ l₂ ~ l₁ :=
+  ⟨Perm.symm, Perm.symm⟩
+#align list.perm_comm List.perm_comm
 
-theorem Perm.swap' (x y : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : y::x::l₁ ~ x::y::l₂ :=
-  have h1 : y :: l₁ ~ y :: l₂ := Perm.cons y p
-  have h2 : x :: y :: l₁ ~ x :: y :: l₂ := Perm.cons x h1
-  have h3 : y :: x :: l₁ ~ x :: y :: l₁ := Perm.swap x y l₁
-  Perm.trans h3 h2
+theorem Perm.swap' (x y : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : y :: x :: l₁ ~ x :: y :: l₂ :=
+  (swap _ _ _).trans ((p.cons _).cons _)
+#align list.perm.swap' List.Perm.swap'
 
-theorem Perm.Equivalence : Equivalence (@Perm α) := ⟨Perm.refl, Perm.symm, Perm.trans⟩
+attribute [trans] Perm.trans
 
-instance (α : Type u) : Setoid (List α) := ⟨Perm, Perm.Equivalence⟩
+theorem Perm.eqv (α) : Equivalence (@Perm α) :=
+  ⟨Perm.refl, Perm.symm, Perm.trans⟩
+#align list.perm.eqv List.Perm.eqv
 
-theorem Perm.subset {α : Type u} {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ := by
-  induction p with
-  | nil => exact nil_subset _
-  | cons _ _ ih => exact cons_subset_cons _ ih
-  | swap x y l =>
-    intro a
-    rw [mem_cons]
-    exact fun
-    | Or.inl rfl => Mem.tail _ (Mem.head ..)
-    | Or.inr (Mem.head ..) => Mem.head ..
-    | Or.inr (Mem.tail _ a_mem_l) => Mem.tail _ (Mem.tail _ a_mem_l)
-  | trans _ _ ih₁ ih₂ => exact Subset.trans ih₁ ih₂
-
-theorem perm_middle {a : α} : ∀ {l₁ l₂ : List α}, l₁++a::l₂ ~ a::(l₁++l₂)
-| [], _ => Perm.refl _
-| b::l₁, l₂ =>
-  let h2 := @perm_middle α a l₁ l₂
-  (h2.cons _).trans (swap a b _)
-
-theorem perm_insertNth {x : α} : ∀ {l : List α} {n : Nat}, n ≤ l.length →
-  insertNth n x l ~ x :: l
-| [], 0, _ => Perm.refl _
-| [], _+1, h => False.elim (Nat.not_succ_le_zero _ h)
-| _::_, 0, _ => Perm.refl _
-| _::_, _+1, h =>
-  Perm.trans
-    (Perm.cons _ (perm_insertNth (Nat.le_of_succ_le_succ h)))
-    (Perm.swap _ _ _)
+--Porting note: new theorem
+theorem Perm.of_eq (h : l₁ = l₂) : l₁ ~ l₂ :=
+  h ▸ Perm.refl l₁
+
+instance isSetoid (α) : Setoid (List α) :=
+  Setoid.mk (@Perm α) (Perm.eqv α)
+#align list.is_setoid List.isSetoid
+
+-- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it
+theorem Perm.subset {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ := fun a =>
+  p.rec
+  (fun h => h)
+  (fun x l₁ l₂ _r hs h => by
+    cases h
+    . apply Mem.head
+    . apply Mem.tail
+      apply hs
+      assumption)
+  (fun x y l h => by
+    match h with
+    | .head _ => exact Mem.tail x (Mem.head l)
+    | .tail _ (.head _) => apply Mem.head
+    | .tail _ (.tail _ h) => exact Mem.tail x (Mem.tail y h))
+  (fun _ _ h₁ h₂ h => by
+    apply h₂
+    apply h₁
+    assumption)
+#align list.perm.subset List.Perm.subset
 
 theorem Perm.mem_iff {a : α} {l₁ l₂ : List α} (h : l₁ ~ l₂) : a ∈ l₁ ↔ a ∈ l₂ :=
-  Iff.intro (fun m ↦ h.subset m) fun m ↦ h.symm.subset m
+  Iff.intro (fun m => h.subset m) fun m => h.symm.subset m
+#align list.perm.mem_iff List.Perm.mem_iff
+
+theorem Perm.append_right {l₁ l₂ : List α} (t₁ : List α) (p : l₁ ~ l₂) : l₁ ++ t₁ ~ l₂ ++ t₁ :=
+  p.rec
+    (Perm.refl ([] ++ t₁))
+    (fun x _ _ _ r₁ => r₁.cons x)
+    (fun x y _ => swap x y _)
+    (fun _ _ r₁ r₂ => r₁.trans r₂)
+#align list.perm.append_right List.Perm.append_right
+
+theorem Perm.append_left {t₁ t₂ : List α} : ∀ l : List α, t₁ ~ t₂ → l ++ t₁ ~ l ++ t₂
+  | [], p => p
+  | x :: xs, p => (p.append_left xs).cons x
+#align list.perm.append_left List.Perm.append_left
+
+theorem Perm.append {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ++ t₁ ~ l₂ ++ t₂ :=
+  (p₁.append_right t₁).trans (p₂.append_left l₂)
+#align list.perm.append List.Perm.append
+
+theorem Perm.append_cons (a : α) {h₁ h₂ t₁ t₂ : List α} (p₁ : h₁ ~ h₂) (p₂ : t₁ ~ t₂) :
+    h₁ ++ a :: t₁ ~ h₂ ++ a :: t₂ :=
+  p₁.append (p₂.cons a)
+#align list.perm.append_cons List.Perm.append_cons
+
+@[simp]
+theorem perm_middle {a : α} : ∀ {l₁ l₂ : List α}, l₁ ++ a :: l₂ ~ a :: (l₁ ++ l₂)
+  | [], _ => Perm.refl _
+  | b :: l₁, l₂ => ((@perm_middle a l₁ l₂).cons _).trans (swap a b _)
+#align list.perm_middle List.perm_middle
+
+@[simp]
+theorem perm_append_singleton (a : α) (l : List α) : l ++ [a] ~ a :: l :=
+  perm_middle.trans <| by rw [append_nil]
+#align list.perm_append_singleton List.perm_append_singleton
+
+theorem perm_append_comm : ∀ {l₁ l₂ : List α}, l₁ ++ l₂ ~ l₂ ++ l₁
+  | [], l₂ => by simp
+  | a :: t, l₂ => (perm_append_comm.cons _).trans perm_middle.symm
+#align list.perm_append_comm List.perm_append_comm
+
+theorem concat_perm (l : List α) (a : α) : concat l a ~ a :: l := by simp
+#align list.concat_perm List.concat_perm
+
+theorem Perm.length_eq {l₁ l₂ : List α} (p : l₁ ~ l₂) : length l₁ = length l₂ :=
+  p.rec
+    rfl
+    (fun _x l₁ l₂ _p r => by simp [r])
+    (fun _x _y l => by simp)
+    (fun _p₁ _p₂ r₁ r₂ => Eq.trans r₁ r₂)
+#align list.perm.length_eq List.Perm.length_eq
+
+theorem Perm.eq_nil {l : List α} (p : l ~ []) : l = [] :=
+  eq_nil_of_length_eq_zero p.length_eq
+#align list.perm.eq_nil List.Perm.eq_nil
+
+theorem Perm.nil_eq {l : List α} (p : [] ~ l) : [] = l :=
+  p.symm.eq_nil.symm
+#align list.perm.nil_eq List.Perm.nil_eq
+
+@[simp]
+theorem perm_nil {l₁ : List α} : l₁ ~ [] ↔ l₁ = [] :=
+  ⟨fun p => p.eq_nil, fun e => e ▸ Perm.refl _⟩
+#align list.perm_nil List.perm_nil
+
+@[simp]
+theorem nil_perm {l₁ : List α} : [] ~ l₁ ↔ l₁ = [] :=
+  perm_comm.trans perm_nil
+#align list.nil_perm List.nil_perm
+
+theorem not_perm_nil_cons (x : α) (l : List α) : ¬[] ~ x :: l
+  | p => by injection p.symm.eq_nil
+#align list.not_perm_nil_cons List.not_perm_nil_cons
+
+@[simp]
+theorem reverse_perm : ∀ l : List α, reverse l ~ l
+  | [] => Perm.nil
+  | a :: l => by
+    rw [reverse_cons]
+    exact (perm_append_singleton _ _).trans ((reverse_perm l).cons a)
+#align list.reverse_perm List.reverse_perm
+
+theorem perm_cons_append_cons {l l₁ l₂ : List α} (a : α) (p : l ~ l₁ ++ l₂) :
+    a :: l ~ l₁ ++ a :: l₂ :=
+  (p.cons a).trans perm_middle.symm
+#align list.perm_cons_append_cons List.perm_cons_append_cons
+
+@[simp]
+theorem perm_replicate {a : α} {n : ℕ} {l : List α} :
+    l ~ List.replicate n a ↔ l = List.replicate n a :=
+  ⟨fun p => eq_replicate.2
+    ⟨p.length_eq.trans <| length_replicate _ _, fun _b m => eq_of_mem_replicate <| p.subset m⟩,
+    fun h => h ▸ Perm.refl _⟩
+
+set_option linter.deprecated false in
+@[deprecated perm_replicate]
+theorem perm_repeat {a : α} {n : ℕ} {l : List α} : l ~ List.repeat a n ↔ l = List.repeat a n :=
+  perm_replicate
+#align list.perm_repeat List.perm_repeat
+
+@[simp]
+theorem replicate_perm {a : α} {n : ℕ} {l : List α} :
+    List.replicate n a ~ l ↔ List.replicate n a = l :=
+  (perm_comm.trans perm_replicate).trans eq_comm
+
+set_option linter.deprecated false in
+@[deprecated replicate_perm]
+theorem repeat_perm {a : α} {n : ℕ} {l : List α} : List.repeat a n ~ l ↔ List.repeat a n = l :=
+  replicate_perm
+#align list.repeat_perm List.repeat_perm
+
+@[simp]
+theorem perm_singleton {a : α} {l : List α} : l ~ [a] ↔ l = [a] :=
+  @perm_replicate α a 1 l
+#align list.perm_singleton List.perm_singleton
+
+@[simp]
+theorem singleton_perm {a : α} {l : List α} : [a] ~ l ↔ [a] = l :=
+  @replicate_perm α a 1 l
+#align list.singleton_perm List.singleton_perm
+
+theorem Perm.eq_singleton {a : α} {l : List α} (p : l ~ [a]) : l = [a] :=
+  perm_singleton.1 p
+#align list.perm.eq_singleton List.Perm.eq_singleton
+
+theorem Perm.singleton_eq {a : α} {l : List α} (p : [a] ~ l) : [a] = l :=
+  p.symm.eq_singleton.symm
+#align list.perm.singleton_eq List.Perm.singleton_eq
+
+theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp
+#align list.singleton_perm_singleton List.singleton_perm_singleton
+
+theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : l ~ a :: l.erase a :=
+  let ⟨_l₁, _l₂, _, e₁, e₂⟩ := exists_erase_eq h
+  e₂.symm ▸ e₁.symm ▸ perm_middle
+#align list.perm_cons_erase List.perm_cons_erase
 
-/-- The way Lean 4 computes the motive with `elab_as_elim` has changed
-relative to the behaviour of `elab_as_eliminator` in Lean 3.
-See
-https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Potential.20elaboration.20bug.20with.20.60elabAsElim.60/near/299573172
-for an explanation of the change made here relative to mathlib3.
--/
 @[elab_as_elim]
-theorem perm_induction_on
-    {P : (l₁ : List α) → (l₂ : List α) → l₁ ~ l₂ → Prop} {l₁ l₂ : List α} (p : l₁ ~ l₂)
-    (nil : P [] [] .nil)
-    (cons : ∀ x l₁ l₂, (h : l₁ ~ l₂) → P l₁ l₂ h → P (x :: l₁) (x :: l₂) (.cons x h))
-    (swap : ∀ x y l₁ l₂, (h : l₁ ~ l₂) → P l₁ l₂ h →
-      P (y :: x :: l₁) (x :: y :: l₂) (.trans (.swap x y _) (.cons _ (.cons _ h))))
-    (trans : ∀ l₁ l₂ l₃, (h₁ : l₁ ~ l₂) → (h₂ : l₂ ~ l₃) → P l₁ l₂ h₁ → P l₂ l₃ h₂ →
-      P l₁ l₃ (.trans h₁ h₂)) : P l₁ l₂ p :=
-  have P_refl l : P l l (.refl l) :=
-    List.recOn l nil fun x xs ih ↦ cons x xs xs (Perm.refl xs) ih
-  Perm.recOn p nil cons (fun x y l ↦ swap x y l l (Perm.refl l) (P_refl l)) @trans
+theorem perm_induction_on {P : List α → List α → Prop} {l₁ l₂ : List α} (p : l₁ ~ l₂) (h₁ : P [] [])
+    (h₂ : ∀ x l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (x :: l₁) (x :: l₂))
+    (h₃ : ∀ x y l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (y :: x :: l₁) (x :: y :: l₂))
+    (h₄ : ∀ l₁ l₂ l₃, l₁ ~ l₂ → l₂ ~ l₃ → P l₁ l₂ → P l₂ l₃ → P l₁ l₃) : P l₁ l₂ :=
+  have P_refl : ∀ l, P l l := fun l => List.recOn l h₁ fun x xs ih => h₂ x xs xs (Perm.refl xs) ih
+  p.rec h₁ h₂ (fun x y l => h₃ x y l l (Perm.refl l) (P_refl l)) @h₄
+#align list.perm_induction_on List.perm_induction_onₓ
+
+-- Porting note: TODO figure out why invalid congr
+-- @[congr]
+theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~ l₂) :
+    filterMap f l₁ ~ filterMap f l₂ :=
+  by
+  induction p with
+  | nil => simp
+  | cons x _p IH =>
+    simp only [filterMap]
+    cases h : f x
+      <;> simp [h, filterMap, IH, Perm.cons]
+  | swap x y l₂ =>
+    simp only [filterMap]
+    cases hx : f x
+      <;> cases hy : f y
+        <;> simp [hx, hy, filterMap, swap]
+  | trans _p₁ _p₂ IH₁ IH₂ =>
+    exact IH₁.trans IH₂
+#align list.perm.filter_map List.Perm.filterMap
+
+-- Porting note: TODO figure out why invalid congr
+-- @[congr]
+theorem Perm.map (f : α → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : map f l₁ ~ map f l₂ :=
+  filterMap_eq_map f ▸ p.filterMap _
+#align list.perm.map List.Perm.map
+
+theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) {H₁ H₂} :
+    pmap f l₁ H₁ ~ pmap f l₂ H₂ :=
+  by
+  induction p with
+  | nil => simp
+  | cons x _p IH => simp [IH, Perm.cons]
+  | swap x y => simp [swap]
+  | trans _p₁ p₂ IH₁ IH₂ =>
+    refine' IH₁.trans IH₂
+    exact fun a m => H₂ a (p₂.subset m)
+#align list.perm.pmap List.Perm.pmap
+
+theorem Perm.filter (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
+    filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter] ; apply s.filterMap _
+#align list.perm.filter List.Perm.filter
+
+theorem filter_append_perm (p : α → Prop) [DecidablePred p] (l : List α) :
+    filter p l ++ filter (fun x => ¬p x) l ~ l :=
+  by
+  induction' l with x l ih
+  · rfl
+  · by_cases h : p x
+    · simp only [h, filter_cons_of_pos, filter_cons_of_neg, not_true, not_false_iff, cons_append]
+      exact ih.cons x
+    · simp only [h, filter_cons_of_neg, not_false_iff, filter_cons_of_pos]
+      refine' Perm.trans _ (ih.cons x)
+      exact perm_append_comm.trans (perm_append_comm.cons _)
+#align list.filter_append_perm List.filter_append_perm
+
+theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') :
+    ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' :=
+  by
+  induction p generalizing l₁ with
+  | nil =>
+    exact ⟨[], eq_nil_of_sublist_nil s ▸ Perm.refl _, nil_sublist _⟩
+  | cons x _ IH =>
+    cases' s with _ _ _ s l₁ _ _ s
+    · exact
+        let ⟨l₁', p', s'⟩ := IH s
+        ⟨l₁', p', s'.cons _⟩
+    · exact
+        let ⟨l₁', p', s'⟩ := IH s
+        ⟨x :: l₁', p'.cons x, s'.cons₂ _⟩
+  | swap x y _ =>
+    cases' s with _ _ _ s l₁ _ _ s <;> cases' s with _ _ _ s l₁ _ _ s
+    · exact ⟨l₁, Perm.refl _, (s.cons _).cons _⟩
+    · exact ⟨x :: l₁, Perm.refl _, (s.cons _).cons₂ _⟩
+    · exact ⟨y :: l₁, Perm.refl _, (s.cons₂ _).cons _⟩
+    · exact ⟨x :: y :: l₁, Perm.swap _ _ _, (s.cons₂ _).cons₂ _⟩
+  | trans _ _ IH₁ IH₂ =>
+    exact
+      let ⟨m₁, pm, sm⟩ := IH₁ s
+      let ⟨r₁, pr, sr⟩ := IH₂ sm
+      ⟨r₁, pr.trans pm, sr⟩
+#align list.exists_perm_sublist List.exists_perm_sublist
+
+theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂) : sizeOf l₁ = sizeOf l₂ :=
+  by
+  induction h with -- hd l₁ l₂ h₁₂ h_sz₁₂ a b l l₁ l₂ l₃ h₁₂ h₂₃ h_sz₁₂ h_sz₂₃
+  | nil => rfl
+  | cons _ _ h_sz₁₂ => simp [h_sz₁₂]
+  | swap => simp [add_left_comm]
+  | trans _ _ h_sz₁₂ h_sz₂₃ => simp [h_sz₁₂, h_sz₂₃]
+#align list.perm.sizeof_eq_sizeof List.Perm.sizeOf_eq_sizeOf
+
+section Rel
+
+open Relator
+
+variable {γ : Type _} {δ : Type _} {r : α → β → Prop} {p : γ → δ → Prop}
+
+-- mathport name: «expr ∘r »
+local infixr:80 " ∘r " => Relation.Comp
+
+theorem perm_comp_perm : (Perm ∘r Perm : List α → List α → Prop) = Perm :=
+  by
+  funext a c; apply propext
+  constructor
+  · exact fun ⟨b, hab, hba⟩ => Perm.trans hab hba
+  · exact fun h => ⟨a, Perm.refl a, h⟩
+#align list.perm_comp_perm List.perm_comp_perm
+
+theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) :
+    (Forall₂ r ∘r Perm) l v := by
+  induction hlu generalizing v
+  case nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩
+  case cons a l u _hlu ih =>
+    cases' huv with _ b _ v hab huv'
+    rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩
+    exact ⟨b :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩
+  case swap a₁ a₂ h₂₃ =>
+    cases' huv with _ b₁ _ l₂ h₁ hr₂₃
+    cases' hr₂₃ with _ b₂ _ l₂ h₂ h₁₂
+    exact ⟨b₂ :: b₁ :: l₂, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩
+  case
+    trans la₁ la₂ la₃ _ _ ih₁ ih₂ =>
+    rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩
+    rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩
+    exact ⟨lb₁, hab₁, Perm.trans h₁₂ h₂₃⟩
+#align list.perm_comp_forall₂ List.perm_comp_forall₂
+
+theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r :=
+  by
+  funext l₁ l₃; apply propext
+  constructor
+  · intro h
+    rcases h with ⟨l₂, h₁₂, h₂₃⟩
+    have : Forall₂ (flip r) l₂ l₁ := h₁₂.flip
+    rcases perm_comp_forall₂ h₂₃.symm this with ⟨l', h₁, h₂⟩
+    exact ⟨l', h₂.symm, h₁.flip⟩
+  · exact fun ⟨l₂, h₁₂, h₂₃⟩ => perm_comp_forall₂ h₁₂ h₂₃
+#align list.forall₂_comp_perm_eq_perm_comp_forall₂ List.forall₂_comp_perm_eq_perm_comp_forall₂
+
+theorem rel_perm_imp (hr : RightUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· → ·)) Perm Perm :=
+  fun a b h₁ c d h₂ h =>
+  have : (flip (Forall₂ r) ∘r Perm ∘r Forall₂ r) b d := ⟨a, h₁, c, h, h₂⟩
+  have : ((flip (Forall₂ r) ∘r Forall₂ r) ∘r Perm) b d := by
+    rwa [← forall₂_comp_perm_eq_perm_comp_forall₂, ← Relation.comp_assoc] at this
+  let ⟨b', ⟨c', hbc, hcb⟩, hbd⟩ := this
+  have : b' = b := right_unique_forall₂' hr hcb hbc
+  this ▸ hbd
+#align list.rel_perm_imp List.rel_perm_imp
+
+theorem rel_perm (hr : BiUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· ↔ ·)) Perm Perm :=
+  fun _a _b hab _c _d hcd =>
+  Iff.intro (rel_perm_imp hr.2 hab hcd) (rel_perm_imp hr.left.flip hab.flip hcd.flip)
+#align list.rel_perm List.rel_perm
+
+end Rel
+
+section Subperm
+
+
+/-- `Subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
+  a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
+  multiplicities of elements, and is used for the `≤` relation on multisets. -/
+def Subperm (l₁ l₂ : List α) : Prop :=
+  ∃ (l : _)(_ : l ~ l₁), l <+ l₂
+#align list.subperm List.Subperm
+
+/-- `Subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of
+  a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects
+  multiplicities of elements, and is used for the `≤` relation on multisets. -/
+infixl:50 " <+~ " => Subperm
+
+theorem nil_subperm {l : List α} : [] <+~ l :=
+  ⟨[], Perm.nil, by simp⟩
+#align list.nil_subperm List.nil_subperm
+
+theorem Perm.subperm_left {l l₁ l₂ : List α} (p : l₁ ~ l₂) : l <+~ l₁ ↔ l <+~ l₂ :=
+  suffices ∀ {l₁ l₂ : List α}, l₁ ~ l₂ → l <+~ l₁ → l <+~ l₂ from ⟨this p, this p.symm⟩
+  fun p ⟨_u, pu, su⟩ =>
+  let ⟨v, pv, sv⟩ := exists_perm_sublist su p
+  ⟨v, pv.trans pu, sv⟩
+#align list.perm.subperm_left List.Perm.subperm_left
+
+theorem Perm.subperm_right {l₁ l₂ l : List α} (p : l₁ ~ l₂) : l₁ <+~ l ↔ l₂ <+~ l :=
+  ⟨fun ⟨u, pu, su⟩ => ⟨u, pu.trans p, su⟩, fun ⟨u, pu, su⟩ => ⟨u, pu.trans p.symm, su⟩⟩
+#align list.perm.subperm_right List.Perm.subperm_right
+
+theorem Sublist.subperm {l₁ l₂ : List α} (s : l₁ <+ l₂) : l₁ <+~ l₂ :=
+  ⟨l₁, Perm.refl _, s⟩
+#align list.sublist.subperm List.Sublist.subperm
+
+theorem Perm.subperm {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ <+~ l₂ :=
+  ⟨l₂, p.symm, Sublist.refl _⟩
+#align list.perm.subperm List.Perm.subperm
+
+@[refl]
+theorem Subperm.refl (l : List α) : l <+~ l :=
+  (Perm.refl _).subperm
+#align list.subperm.refl List.Subperm.refl
+
+@[trans]
+theorem Subperm.trans {l₁ l₂ l₃ : List α} : l₁ <+~ l₂ → l₂ <+~ l₃ → l₁ <+~ l₃
+  | s, ⟨_l₂', p₂, s₂⟩ =>
+    let ⟨l₁', p₁, s₁⟩ := p₂.subperm_left.2 s
+    ⟨l₁', p₁, s₁.trans s₂⟩
+#align list.subperm.trans List.Subperm.trans
+
+theorem Subperm.length_le {l₁ l₂ : List α} : l₁ <+~ l₂ → length l₁ ≤ length l₂
+  | ⟨_l, p, s⟩ => p.length_eq ▸ s.length_le
+#align list.subperm.length_le List.Subperm.length_le
+
+theorem Subperm.perm_of_length_le {l₁ l₂ : List α} : l₁ <+~ l₂ → length l₂ ≤ length l₁ → l₁ ~ l₂
+  | ⟨_l, p, s⟩, h => (s.eq_of_length_le <| p.symm.length_eq ▸ h) ▸ p.symm
+#align list.subperm.perm_of_length_le List.Subperm.perm_of_length_le
+
+theorem Subperm.antisymm {l₁ l₂ : List α} (h₁ : l₁ <+~ l₂) (h₂ : l₂ <+~ l₁) : l₁ ~ l₂ :=
+  h₁.perm_of_length_le h₂.length_le
+#align list.subperm.antisymm List.Subperm.antisymm
+
+theorem Subperm.subset {l₁ l₂ : List α} : l₁ <+~ l₂ → l₁ ⊆ l₂
+  | ⟨_l, p, s⟩ => Subset.trans p.symm.subset s.subset
+#align list.subperm.subset List.Subperm.subset
+
+theorem Subperm.filter (p : α → Prop) [DecidablePred p] ⦃l l' : List α⦄ (h : l <+~ l') :
+    filter p l <+~ filter p l' := by
+  obtain ⟨xs, hp, h⟩ := h
+  exact ⟨_, hp.filter p, h.filter p⟩
+#align list.subperm.filter List.Subperm.filter
+
+end Subperm
+
+theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∃ l, l₂ ~ l₁ ++ l
+  | _, _, Sublist.slnil => ⟨nil, Perm.refl _⟩
+  | _, _, Sublist.cons a s =>
+    let ⟨l, p⟩ := Sublist.exists_perm_append s
+    ⟨a :: l, (p.cons a).trans perm_middle.symm⟩
+  | _, _, Sublist.cons₂ a s =>
+    let ⟨l, p⟩ := Sublist.exists_perm_append s
+    ⟨l, p.cons a⟩
+#align list.sublist.exists_perm_append List.Sublist.exists_perm_append
+
+theorem Perm.countp_eq (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} (s : l₁ ~ l₂) :
+    countp p l₁ = countp p l₂ := by
+  rw [countp_eq_length_filter, countp_eq_length_filter] ; exact (s.filter _).length_eq
+#align list.perm.countp_eq List.Perm.countp_eq
+
+theorem Subperm.countp_le (p : α → Prop) [DecidablePred p] {l₁ l₂ : List α} :
+    l₁ <+~ l₂ → countp p l₁ ≤ countp p l₂
+  | ⟨_l, p', s⟩ => p'.countp_eq p ▸ s.countp_le p
+#align list.subperm.countp_le List.Subperm.countp_le
+
+theorem Perm.countp_congr (s : l₁ ~ l₂) {p p' : α → Prop} [DecidablePred p] [DecidablePred p']
+    (hp : ∀ x ∈ l₁, p x = p' x) : l₁.countp p = l₂.countp p' :=
+  by
+  rw [← s.countp_eq p']
+  clear s
+  induction' l₁ with y s hs
+  · rfl
+  · simp only [mem_cons, forall_eq_or_imp] at hp
+    simp only [countp_cons, hs hp.2, hp.1]
+#align list.perm.countp_congr List.Perm.countp_congr
+
+theorem countp_eq_countp_filter_add (l : List α) (p q : α → Prop) [DecidablePred p]
+    [DecidablePred q] : l.countp p = (l.filter q).countp p + (l.filter fun a => ¬q a).countp p :=
+  by
+  rw [← countp_append]
+  exact Perm.countp_eq _ (filter_append_perm _ _).symm
+#align list.countp_eq_countp_filter_add List.countp_eq_countp_filter_add
+
+theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) :
+    count a l₁ = count a l₂ :=
+  p.countp_eq _
+#align list.perm.count_eq List.Perm.count_eq
+
+theorem Subperm.count_le [DecidableEq α] {l₁ l₂ : List α} (s : l₁ <+~ l₂) (a) :
+    count a l₁ ≤ count a l₂ :=
+  s.countp_le _
+#align list.subperm.count_le List.Subperm.count_le
+
+theorem Perm.foldl_eq' {f : β → α → β} {l₁ l₂ : List α} (p : l₁ ~ l₂) :
+    (∀ x ∈ l₁, ∀ y ∈ l₁, ∀ (z), f (f z x) y = f (f z y) x) → ∀ b, foldl f b l₁ = foldl f b l₂ :=
+  perm_induction_on p (fun _H b => rfl)
+    (fun x t₁ t₂ _p r H b => r (fun x hx y hy => H _ (.tail _ hx) _ (.tail _ hy)) _)
+    (fun x y t₁ t₂ _p r H b => by
+      simp only [foldl]
+      rw [H x (.tail _ <| .head _) y (.head _)]
+      exact r (fun x hx y hy => H _ (.tail _ <| .tail _ hx) _ (.tail _ <| .tail _ hy)) _)
+    fun t₁ t₂ t₃ p₁ _p₂ r₁ r₂ H b =>
+    Eq.trans (r₁ H b) (r₂ (fun x hx y hy => H _ (p₁.symm.subset hx) _ (p₁.symm.subset hy)) b)
+#align list.perm.foldl_eq' List.Perm.foldl_eq'
+
+theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : RightCommutative f) (p : l₁ ~ l₂) :
+    ∀ b, foldl f b l₁ = foldl f b l₂ :=
+  p.foldl_eq' fun x _hx y _hy z => rcomm z x y
+#align list.perm.foldl_eq List.Perm.foldl_eq
+
+theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
+    ∀ b, foldr f b l₁ = foldr f b l₂ :=
+  perm_induction_on p (fun b => rfl) (fun x t₁ t₂ _p r b => by simp ; rw [r b])
+    (fun x y t₁ t₂ _p r b => by simp ; rw [lcomm, r b]) fun t₁ t₂ t₃ _p₁ _p₂ r₁ r₂ a =>
+    Eq.trans (r₁ a) (r₂ a)
+#align list.perm.foldr_eq List.Perm.foldr_eq
+
+theorem Perm.rec_heq {β : List α → Sort _} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α}
+    (hl : Perm l l') (f_congr : ∀ {a l l' b b'}, Perm l l' → HEq b b' → HEq (f a l b) (f a l' b'))
+    (f_swap : ∀ {a a' l b}, HEq (f a (a' :: l) (f a' l b)) (f a' (a :: l) (f a l b))) :
+    HEq (@List.rec α β b f l) (@List.rec α β b f l') :=
+  by
+  induction hl
+  case nil => rfl
+  case cons a l l' h ih => exact f_congr h ih
+  case swap a a' l => exact f_swap
+  case trans l₁ l₂ l₃ _h₁ _h₂ ih₁ ih₂ => exact HEq.trans ih₁ ih₂
+#align list.perm.rec_heq List.Perm.rec_heq
+
+section
+
+variable {op : α → α → α} [IA : IsAssociative α op] [IC : IsCommutative α op]
+
+-- mathport name: op
+local notation a " * " b => op a b
+
+-- mathport name: foldl
+local notation l " <*> " a => foldl op a l
+
+theorem Perm.fold_op_eq {l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : (l₁ <*> a) = l₂ <*> a :=
+  h.foldl_eq (right_comm _ IC.comm IA.assoc) _
+#align list.perm.fold_op_eq List.Perm.fold_op_eq
+
+end
+
+section CommMonoid
+
+/-- If elements of a list commute with each other, then their product does not
+depend on the order of elements. -/
+@[to_additive
+      "If elements of a list additively commute with each other, then their sum does not
+      depend on the order of elements."]
+theorem Perm.prod_eq' [M : Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (hc : l₁.Pairwise Commute) :
+    l₁.prod = l₂.prod := by
+  refine h.foldl_eq' ?_ _
+  apply Pairwise.forall_of_forall
+  . intro x y h z
+    exact (h z).symm
+  . intros; rfl
+  . apply hc.imp
+    intro a b h z
+    rw [mul_assoc z, mul_assoc z, h]
+#align list.perm.prod_eq' List.Perm.prod_eq'
+-- Porting note: TODO do I need to do anything to handle the to_additive instance?
+
+variable [CommMonoid α]
+
+@[to_additive]
+theorem Perm.prod_eq {l₁ l₂ : List α} (h : Perm l₁ l₂) : prod l₁ = prod l₂ :=
+  h.fold_op_eq
+#align list.perm.prod_eq List.Perm.prod_eq
+
+@[to_additive]
+theorem prod_reverse (l : List α) : prod l.reverse = prod l :=
+  (reverse_perm l).prod_eq
+#align list.prod_reverse List.prod_reverse
+
+end CommMonoid
 
 theorem perm_inv_core {a : α} {l₁ l₂ r₁ r₂ : List α} :
-    l₁ ++ a :: r₁ ~ l₂ ++ a :: r₂ → l₁ ++ r₁ ~ l₂ ++ r₂ := by
+    l₁ ++ a :: r₁ ~ l₂ ++ a :: r₂ → l₁ ++ r₁ ~ l₂ ++ r₂ :=
+  by
   generalize e₁ : l₁ ++ a :: r₁ = s₁; generalize e₂ : l₂ ++ a :: r₂ = s₂
-  intro p; induction p using perm_induction_on generalizing l₁ l₂ r₁ r₂ with
-  | nil => apply (not_mem_nil a).elim; rw [← e₁]; simp
-  | cons x t₁ t₂ p w =>
-    rcases l₁ with _ | ⟨y, l₁⟩ <;> rcases l₂ with _ | ⟨z, l₂⟩ <;> injections <;> subst_vars
-    · exact p
-    · exact p.trans perm_middle
-    · exact perm_middle.symm.trans p
-    · exact (w rfl rfl).cons z
-  | swap x y t₁ t₂ p w =>
-    rcases l₁ with _ | ⟨y, _ | ⟨z, l₁⟩⟩ <;> rcases l₂ with _ | ⟨u, _ | ⟨v, l₂⟩⟩ <;>
-      injections <;> subst_vars
-    · exact p.cons y
-    · exact p.cons u
-    · exact (p.trans perm_middle).cons u
-    · exact p.cons y
-    · exact p.cons u
-    · exact ((p.trans perm_middle).cons v).trans (swap _ _ _)
-    · exact (perm_middle.symm.trans p).cons y
-    · exact (swap _ _ _).trans ((perm_middle.symm.trans p).cons u)
-    · exact (w rfl rfl).swap' _ _
-  | trans t₁ t₂ t₃ p₁ p₂ w₁ w₂ =>
-    subst t₁ t₃
-    let ⟨l₂, r₂, e₂⟩ := mem_split (p₁.subset (by simp) : a ∈ t₂)
-    subst t₂; exact (w₁ rfl rfl).trans (w₂ rfl rfl)
+  intro p; revert l₁ l₂ r₁ r₂ e₁ e₂; clear l₁ l₂ β
+  show ∀ _ _ _ _, _
+  refine
+      perm_induction_on p ?_ (fun x t₁ t₂ p IH => ?_) (fun x y t₁ t₂ p IH => ?_)
+        fun t₁ t₂ t₃ p₁ p₂ IH₁ IH₂ => ?_
+    <;> intro l₁ l₂ r₁ r₂ e₁ e₂
+  · apply (not_mem_nil a).elim
+    rw [← e₁]
+    simp
+  · cases' l₁ with y l₁ <;> cases' l₂ with z l₂ <;> dsimp at e₁ e₂ <;> injections <;> subst x
+    · substs t₁ t₂
+      exact p
+    · substs z t₁ t₂
+      exact p.trans perm_middle
+    · substs y t₁ t₂
+      exact perm_middle.symm.trans p
+    · substs z t₁ t₂
+      exact (IH _ _ _ _ rfl rfl).cons y
+  · rcases l₁ with (_ | ⟨y, _ | ⟨z, l₁⟩⟩) <;> rcases l₂ with (_ | ⟨u, _ | ⟨v, l₂⟩⟩) <;>
+          dsimp at e₁ e₂ <;> injections <;> substs x y
+    · substs r₁ r₂
+      exact p.cons a
+    · substs r₁ r₂
+      exact p.cons u
+    · substs r₁ v t₂
+      exact (p.trans perm_middle).cons u
+    · substs r₁ r₂
+      exact p.cons y
+    · substs r₁ r₂ y u
+      exact p.cons a
+    · substs r₁ u v t₂
+      exact ((p.trans perm_middle).cons y).trans (swap _ _ _)
+    · substs r₂ z t₁
+      exact (perm_middle.symm.trans p).cons y
+    · substs r₂ y z t₁
+      exact (swap _ _ _).trans ((perm_middle.symm.trans p).cons u)
+    · substs u v t₁ t₂
+      exact (IH _ _ _ _ rfl rfl).swap' _ _
+  · substs t₁ t₃
+    have : a ∈ t₂ := p₁.subset (by simp)
+    rcases mem_split this with ⟨l₂, r₂, e₂⟩
+    subst t₂
+    exact (IH₁ _ _ _ _ rfl rfl).trans (IH₂ _ _ _ _ rfl rfl)
+#align list.perm_inv_core List.perm_inv_core
 
 theorem Perm.cons_inv {a : α} {l₁ l₂ : List α} : a :: l₁ ~ a :: l₂ → l₁ ~ l₂ :=
   @perm_inv_core _ _ [] [] _ _
+#align list.perm.cons_inv List.Perm.cons_inv
 
-theorem Perm.length_eq {l₁ l₂ : List α} (p : l₁ ~ l₂) : length l₁ = length l₂ := by
-  induction p with
-  | nil => simp
-  | cons _ _ ih => simp [ih]
-  | swap _ _ l => simp
-  | trans _ _ ih₁ ih₂ => exact ih₁.trans ih₂
+@[simp]
+theorem perm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ ~ a :: l₂ ↔ l₁ ~ l₂ :=
+  ⟨Perm.cons_inv, Perm.cons a⟩
+#align list.perm_cons List.perm_cons
+
+theorem perm_append_left_iff {l₁ l₂ : List α} : ∀ l, l ++ l₁ ~ l ++ l₂ ↔ l₁ ~ l₂
+  | [] => Iff.rfl
+  | a :: l => (perm_cons a).trans (perm_append_left_iff l)
+#align list.perm_append_left_iff List.perm_append_left_iff
+
+theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l ↔ l₁ ~ l₂ :=
+  ⟨fun p => (perm_append_left_iff _).1 <| perm_append_comm.trans <| p.trans perm_append_comm,
+    Perm.append_right _⟩
+#align list.perm_append_right_iff List.perm_append_right_iff
+
+theorem perm_option_to_list {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList ↔ o₁ = o₂ :=
+  by
+  refine' ⟨fun p => _, fun e => e ▸ Perm.refl _⟩
+  cases' o₁ with a <;> cases' o₂ with b; · rfl
+  · cases p.length_eq
+  · cases p.length_eq
+  · exact Option.mem_toList.1 (p.symm.subset <| by simp)
+#align list.perm_option_to_list List.perm_option_to_list
+
+theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ ↔ l₁ <+~ l₂ :=
+  ⟨fun ⟨l, p, s⟩ => by
+    cases' s with _ _ _ s' u _ _ s'
+    · exact (p.subperm_left.2 <| (sublist_cons _ _).subperm).trans s'.subperm
+    · exact ⟨u, p.cons_inv, s'⟩, fun ⟨l, p, s⟩ => ⟨a :: l, p.cons a, s.cons₂ _⟩⟩
+#align list.subperm_cons List.subperm_cons
+
+alias subperm_cons ↔ subperm.of_cons subperm.cons
+
+--Porting note: commented out
+--attribute [protected] subperm.cons
+
+theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (h₁ : a ∉ l₁) (h₂ : a ∈ l₂)
+    (s : l₁ <+~ l₂) : a :: l₁ <+~ l₂ :=
+  by
+  rcases s with ⟨l, p, s⟩
+  induction s generalizing l₁
+  case slnil => cases h₂
+  case cons r₁ r₂ b s' ih =>
+    simp at h₂
+    cases' h₂ with e m
+    · subst b
+      exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩
+    · rcases ih d₁ h₁ m p with ⟨t, p', s'⟩
+      exact ⟨t, p', s'.cons _⟩
+  case cons₂ r₁ r₂ b _ ih =>
+    have bm : b ∈ l₁ := p.subset <| mem_cons_self _ _
+    have am : a ∈ r₂ := by
+      simp only [find?, mem_cons] at h₂
+      exact h₂.resolve_left fun e => h₁ <| e.symm ▸ bm
+    rcases mem_split bm with ⟨t₁, t₂, rfl⟩
+    have st : t₁ ++ t₂ <+ t₁ ++ b :: t₂ := by simp
+    rcases ih (d₁.sublist st) (mt (fun x => st.subset x) h₁) am
+        (Perm.cons_inv <| p.trans perm_middle) with
+      ⟨t, p', s'⟩
+    exact
+      ⟨b :: t, (p'.cons b).trans <| (swap _ _ _).trans (perm_middle.symm.cons a), s'.cons₂ _⟩
+#align list.cons_subperm_of_mem List.cons_subperm_of_mem
+
+theorem subperm_append_left {l₁ l₂ : List α} : ∀ l, l ++ l₁ <+~ l ++ l₂ ↔ l₁ <+~ l₂
+  | [] => Iff.rfl
+  | a :: l => (subperm_cons a).trans (subperm_append_left l)
+#align list.subperm_append_left List.subperm_append_left
+
+theorem subperm_append_right {l₁ l₂ : List α} (l) : l₁ ++ l <+~ l₂ ++ l ↔ l₁ <+~ l₂ :=
+  (perm_append_comm.subperm_left.trans perm_append_comm.subperm_right).trans (subperm_append_left l)
+#align list.subperm_append_right List.subperm_append_right
+
+theorem Subperm.exists_of_length_lt {l₁ l₂ : List α} :
+    l₁ <+~ l₂ → length l₁ < length l₂ → ∃ a, a :: l₁ <+~ l₂
+  | ⟨l, p, s⟩, h => by
+    suffices length l < length l₂ → ∃ a : α, a :: l <+~ l₂ from
+      (this <| p.symm.length_eq ▸ h).imp fun a => (p.cons a).subperm_right.1
+    clear h p l₁
+    induction' s with l₁ l₂ a s IH _ _ b _ IH <;> intro h
+    · cases h
+    · cases' lt_or_eq_of_le (Nat.le_of_lt_succ h : length l₁ ≤ length l₂) with h h
+      · exact (IH h).imp fun a s => s.trans (sublist_cons _ _).subperm
+      · exact ⟨a, s.eq_of_length h ▸ Subperm.refl _⟩
+    · exact (IH <| Nat.lt_of_succ_lt_succ h).imp fun a s =>
+          (swap _ _ _).subperm_right.1 <| (subperm_cons _).2 s
+
+#align list.subperm.exists_of_length_lt List.Subperm.exists_of_length_lt
+
+protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ :=
+  by
+  induction' d with a l₁' h d IH
+  · exact ⟨nil, Perm.nil, nil_sublist _⟩
+  · cases' forall_mem_cons.1 H with H₁ H₂
+    simp at h
+    exact cons_subperm_of_mem d h H₁ (IH H₂)
+#align list.nodup.subperm List.Nodup.subperm
+
+theorem perm_ext {l₁ l₂ : List α} (d₁ : Nodup l₁) (d₂ : Nodup l₂) :
+    l₁ ~ l₂ ↔ ∀ a, a ∈ l₁ ↔ a ∈ l₂ :=
+  ⟨fun p _ => p.mem_iff, fun H =>
+    (d₁.subperm fun a => (H a).1).antisymm <| d₂.subperm fun a => (H a).2⟩
+#align list.perm_ext List.perm_ext
+
+theorem Nodup.sublist_ext {l₁ l₂ l : List α} (d : Nodup l) (s₁ : l₁ <+ l) (s₂ : l₂ <+ l) :
+    l₁ ~ l₂ ↔ l₁ = l₂ :=
+  ⟨fun h => by
+    induction' s₂ with l₂ l a s₂ IH l₂ l a _ IH generalizing l₁
+    · exact h.eq_nil
+    · simp at d
+      cases' s₁ with _ _ _ s₁ l₁ _ _ s₁
+      · exact IH d.2 s₁ h
+      · apply d.1.elim
+        exact Subperm.subset ⟨_, h.symm, s₂⟩ (mem_cons_self _ _)
+    · simp at d
+      cases' s₁ with _ _ _ s₁ l₁ _ _ s₁
+      · apply d.1.elim
+        exact Subperm.subset ⟨_, h, s₁⟩ (mem_cons_self _ _)
+      · rw [IH d.2 s₁ h.cons_inv], fun h => by rw [h]⟩
+#align list.nodup.sublist_ext List.Nodup.sublist_ext
+
+section
+
+variable [DecidableEq α]
+
+-- attribute [congr]
+theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase a ~ l₂.erase a :=
+  if h₁ : a ∈ l₁ then
+    have h₂ : a ∈ l₂ := p.subset h₁
+    Perm.cons_inv <| (perm_cons_erase h₁).symm.trans <| p.trans (perm_cons_erase h₂)
+  else by
+    have h₂ : a ∉ l₂ := mt p.mem_iff.2 h₁
+    rw [erase_of_not_mem h₁, erase_of_not_mem h₂] ; exact p
+#align list.perm.erase List.Perm.erase
+
+theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a :=
+  by
+  by_cases h : a ∈ l
+  · exact (perm_cons_erase h).subperm
+  · rw [erase_of_not_mem h]
+    exact (sublist_cons _ _).subperm
+#align list.subperm_cons_erase List.subperm_cons_erase
+
+theorem erase_subperm (a : α) (l : List α) : l.erase a <+~ l :=
+  (erase_sublist _ _).subperm
+#align list.erase_subperm List.erase_subperm
+
+theorem Subperm.erase {l₁ l₂ : List α} (a : α) (h : l₁ <+~ l₂) : l₁.erase a <+~ l₂.erase a :=
+  let ⟨l, hp, hs⟩ := h
+  ⟨l.erase a, hp.erase _, hs.erase _⟩
+#align list.subperm.erase List.Subperm.erase
+
+theorem Perm.diff_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : l₁.diff t ~ l₂.diff t := by
+  induction t generalizing l₁ l₂ h <;> simp [*, Perm.erase]
+#align list.perm.diff_right List.Perm.diff_right
+
+theorem Perm.diff_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l.diff t₁ = l.diff t₂ := by
+  induction h generalizing l <;>
+    first |simp [*, Perm.erase, erase_comm]
+#align list.perm.diff_left List.Perm.diff_left
+
+theorem Perm.diff {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) : l₁.diff t₁ ~ l₂.diff t₂ :=
+  ht.diff_left l₂ ▸ hl.diff_right _
+#align list.perm.diff List.Perm.diff
+
+theorem Subperm.diff_right {l₁ l₂ : List α} (h : l₁ <+~ l₂) (t : List α) :
+    l₁.diff t <+~ l₂.diff t := by induction t generalizing l₁ l₂ h <;> simp [*, Subperm.erase]
+#align list.subperm.diff_right List.Subperm.diff_right
+
+theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) :
+    (a :: l).erase b <+~ a :: l.erase b :=
+  by
+  by_cases h : a = b
+  · subst b
+    rw [erase_cons_head]
+    apply subperm_cons_erase
+  · rw [erase_cons_tail _ h]
+#align list.erase_cons_subperm_cons_erase List.erase_cons_subperm_cons_erase
+
+theorem subperm_cons_diff {a : α} : ∀ {l₁ l₂ : List α}, (a :: l₁).diff l₂ <+~ a :: l₁.diff l₂
+  | l₁, [] => ⟨a :: l₁, by simp⟩
+  | l₁, b :: l₂ => by
+    simp only [diff_cons]
+    refine' ((erase_cons_subperm_cons_erase a b l₁).diff_right l₂).trans _
+    apply subperm_cons_diff
+#align list.subperm_cons_diff List.subperm_cons_diff
+
+theorem subset_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂ ⊆ a :: l₁.diff l₂ :=
+  subperm_cons_diff.subset
+#align list.subset_cons_diff List.subset_cons_diff
+
+theorem Perm.bag_inter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) :
+    l₁.bagInter t ~ l₂.bagInter t :=
+  by
+  induction' h with x _ _ _ _ x y _ _ _ _ _ _ ih_1 ih_2 generalizing t; · simp
+  · by_cases x ∈ t <;> simp [*, Perm.cons]
+  · by_cases x = y
+    · simp [h]
+    by_cases xt : x ∈ t <;> by_cases yt : y ∈ t
+    · simp [xt, yt, mem_erase_of_ne h, mem_erase_of_ne (Ne.symm h), erase_comm, swap]
+    · simp [xt, yt, mt mem_of_mem_erase, Perm.cons]
+    · simp [xt, yt, mt mem_of_mem_erase, Perm.cons]
+    · simp [xt, yt]
+  · exact (ih_1 _).trans (ih_2 _)
+#align list.perm.bag_inter_right List.Perm.bag_inter_right
+
+theorem Perm.bag_inter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) :
+    l.bagInter t₁ = l.bagInter t₂ :=
+  by
+  induction' l with a l IH generalizing t₁ t₂ p; · simp
+  by_cases a ∈ t₁
+  · simp [h, p.subset h, IH (p.erase _)]
+  · simp [h, mt p.mem_iff.2 h, IH p]
+#align list.perm.bag_inter_left List.Perm.bag_inter_left
+
+theorem Perm.bag_inter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) :
+    l₁.bagInter t₁ ~ l₂.bagInter t₂ :=
+  ht.bag_inter_left l₂ ▸ hl.bag_inter_right _
+#align list.perm.bag_inter List.Perm.bag_inter
+
+theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} :
+    a :: l₁ ~ l₂ ↔ a ∈ l₂ ∧ l₁ ~ l₂.erase a :=
+  ⟨fun h =>
+    have : a ∈ l₂ := h.subset (mem_cons_self a l₁)
+    ⟨this, (h.trans <| perm_cons_erase this).cons_inv⟩,
+    fun ⟨m, h⟩ => (h.cons a).trans (perm_cons_erase m).symm⟩
+#align list.cons_perm_iff_perm_erase List.cons_perm_iff_perm_erase
+
+theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l₁ = count a l₂ :=
+  ⟨Perm.count_eq, fun H => by
+    induction' l₁ with a l₁ IH generalizing l₂
+    · cases' l₂ with b l₂
+      · rfl
+      specialize H b
+      simp at H
+      contradiction
+    · have : a ∈ l₂ := count_pos.1 (by rw [← H] ; simp)
+      refine' ((IH fun b => _).cons a).trans (perm_cons_erase this).symm
+      specialize H b
+      rw [(perm_cons_erase this).count_eq] at H
+      by_cases b = a <;> simp [h] at H⊢ <;> assumption⟩
+#align list.perm_iff_count List.perm_iff_count
+
+theorem Subperm.cons_right {α : Type _} {l l' : List α} (x : α) (h : l <+~ l') : l <+~ x :: l' :=
+  h.trans (sublist_cons x l').subperm
+#align list.subperm.cons_right List.Subperm.cons_right
+
+/-- The list version of `add_tsub_cancel_of_le` for multisets. -/
+theorem subperm_append_diff_self_of_count_le {l₁ l₂ : List α}
+    (h : ∀ x ∈ l₁, count x l₁ ≤ count x l₂) : l₁ ++ l₂.diff l₁ ~ l₂ :=
+  by
+  induction' l₁ with hd tl IH generalizing l₂
+  · simp
+  · have : hd ∈ l₂ := by
+      rw [← count_pos]
+      exact lt_of_lt_of_le (count_pos.mpr (mem_cons_self _ _)) (h hd (mem_cons_self _ _))
+    replace := perm_cons_erase this
+    refine' Perm.trans _ this.symm
+    rw [cons_append, diff_cons, perm_cons]
+    refine' IH fun x hx => _
+    specialize h x (mem_cons_of_mem _ hx)
+    rw [perm_iff_count.mp this] at h
+    by_cases hx : x = hd
+    · subst hd
+      simpa [Nat.succ_le_succ_iff] using h
+    · simpa [hx] using h
+#align list.subperm_append_diff_self_of_count_le List.subperm_append_diff_self_of_count_le
+
+/-- The list version of `Multiset.le_iff_count`. -/
+theorem subperm_ext_iff {l₁ l₂ : List α} : l₁ <+~ l₂ ↔ ∀ x ∈ l₁, count x l₁ ≤ count x l₂ := by
+  refine' ⟨fun h x _ => Subperm.count_le h x, fun h => _⟩
+  suffices l₁ <+~ l₂.diff l₁ ++ l₁ by
+    refine' this.trans (Perm.subperm _)
+    exact perm_append_comm.trans (subperm_append_diff_self_of_count_le h)
+  exact (subperm_append_right l₁).mpr nil_subperm
+#align list.subperm_ext_iff List.subperm_ext_iff
+
+instance decidableSubperm : DecidableRel ((· <+~ ·) : List α → List α → Prop) := fun _ _ =>
+  decidable_of_iff _ List.subperm_ext_iff.symm
+#align list.decidable_subperm List.decidableSubperm
+
+@[simp]
+theorem subperm_singleton_iff {α} {l : List α} {a : α} : [a] <+~ l ↔ a ∈ l :=
+  ⟨fun ⟨s, hla, h⟩ => by rwa [perm_singleton.mp hla, singleton_sublist] at h, fun h =>
+    ⟨[a], Perm.refl _, singleton_sublist.mpr h⟩⟩
+#align list.subperm_singleton_iff List.subperm_singleton_iff
+
+theorem Subperm.cons_left {l₁ l₂ : List α} (h : l₁ <+~ l₂) (x : α) (hx : count x l₁ < count x l₂) :
+    x :: l₁ <+~ l₂ := by
+  rw [subperm_ext_iff] at h⊢
+  intro y hy
+  by_cases hy' : y = x
+  · subst x
+    simpa using Nat.succ_le_of_lt hx
+  · rw [count_cons_of_ne hy']
+    refine' h y _
+    simpa [hy'] using hy
+#align list.subperm.cons_left List.Subperm.cons_left
+
+instance decidablePerm : ∀ l₁ l₂ : List α, Decidable (l₁ ~ l₂)
+  | [], [] => isTrue <| Perm.refl _
+  | [], b :: l₂ => isFalse fun h => by have := h.nil_eq; contradiction
+  | a :: l₁, l₂ =>
+    haveI := decidablePerm l₁ (l₂.erase a)
+    decidable_of_iff' _ cons_perm_iff_perm_erase
+#align list.decidable_perm List.decidablePerm
+
+-- @[congr]
+theorem Perm.dedup {l₁ l₂ : List α} (p : l₁ ~ l₂) : dedup l₁ ~ dedup l₂ :=
+  perm_iff_count.2 fun a =>
+    if h : a ∈ l₁ then by simp [nodup_dedup, h, p.subset h] else by simp [h, mt p.mem_iff.2 h]
+#align list.perm.dedup List.Perm.dedup
+
+-- attribute [congr]
+theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.insert a ~ l₂.insert a :=
+  if h : a ∈ l₁ then by simpa [h, p.subset h] using p
+  else by simpa [h, mt p.mem_iff.2 h] using p.cons a
+#align list.perm.insert List.Perm.insert
+
+theorem perm_insert_swap (x y : α) (l : List α) :
+    List.insert x (List.insert y l) ~ List.insert y (List.insert x l) := by
+  by_cases xl : x ∈ l <;> by_cases yl : y ∈ l <;> simp [xl, yl]
+  by_cases xy : x = y; · simp [xy]
+  simp [List.insert, xl, yl, xy, Ne.symm xy]
+  constructor
+#align list.perm_insert_swap List.perm_insert_swap
+
+theorem perm_insertNth {α} (x : α) (l : List α) {n} (h : n ≤ l.length) :
+    insertNth n x l ~ x :: l := by
+  induction' l with _ _ l_ih generalizing n
+  · cases n
+    rfl
+    cases h
+  cases n
+  · simp [insertNth]
+  · simp only [insertNth, modifyNthTail]
+    refine' Perm.trans (Perm.cons _ (l_ih _)) _
+    · apply Nat.le_of_succ_le_succ h
+    · apply Perm.swap
+#align list.perm_insert_nth List.perm_insertNth
+
+theorem Perm.union_right {l₁ l₂ : List α} (t₁ : List α) (h : l₁ ~ l₂) : l₁.union t₁ ~ l₂.union t₁ :=
+  by
+  induction' h with a _ _ _ ih _ _ _ _ _ _ _ _ ih_1 ih_2 <;> try simp
+  · exact ih.insert a
+  · apply perm_insert_swap
+  · exact ih_1.trans ih_2
+#align list.perm.union_right List.Perm.union_right
+
+theorem Perm.union_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l.union t₁ ~ l.union t₂ := by
+  induction l <;> simp [*, Perm.insert]
+#align list.perm.union_left List.Perm.union_left
 
-theorem Perm.eq_nil {l : List α} (p : l ~ []) : l = [] := eq_nil_of_length_eq_zero p.length_eq
+-- @[congr]
+theorem Perm.union {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) :
+    l₁.union t₁ ~ l₂.union t₂ :=
+  (p₁.union_right t₁).trans (p₂.union_left l₂)
+#align list.perm.union List.Perm.union
 
-theorem Perm.nil_eq {l : List α} (p : [] ~ l) : [] = l := p.symm.eq_nil.symm
+theorem Perm.inter_right {l₁ l₂ : List α} (t₁ : List α) : l₁ ~ l₂ → l₁ ∩ t₁ ~ l₂ ∩ t₁ :=
+  Perm.filter _
+#align list.perm.inter_right List.Perm.inter_right
+
+theorem Perm.inter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) : l ∩ t₁ = l ∩ t₂ :=
+  filter_congr' fun a _ => by simpa using p.mem_iff
+#align list.perm.inter_left List.Perm.inter_left
+
+-- @[congr]
+theorem Perm.inter {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ∩ t₁ ~ l₂ ∩ t₂ :=
+  p₂.inter_left l₂ ▸ p₁.inter_right t₁
+#align list.perm.inter List.Perm.inter
+
+theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) :
+    l ∩ (t₁ ++ t₂) ~ l ∩ t₁ ++ l ∩ t₂ := by
+  induction l
+  case nil => simp
+  case cons x xs l_ih =>
+    by_cases h₁ : x ∈ t₁
+    · have h₂ : x ∉ t₂ := h h₁
+      simp [*]
+    by_cases h₂ : x ∈ t₂
+    · simp only [*, inter_cons_of_not_mem, false_or_iff, mem_append, inter_cons_of_mem,
+        not_false_iff]
+      refine' Perm.trans (Perm.cons _ l_ih) _
+      change [x] ++ xs ∩ t₁ ++ xs ∩ t₂ ~ xs ∩ t₁ ++ ([x] ++ xs ∩ t₂)
+      rw [← List.append_assoc]
+      solve_by_elim [Perm.append_right, perm_append_comm]
+    · simp [*]
+#align list.perm.inter_append List.Perm.inter_append
+
+end
 
 theorem Perm.pairwise_iff {R : α → α → Prop} (S : Symmetric R) :
-    ∀ {l₁ l₂ : List α}, l₁ ~ l₂ → (Pairwise R l₁ ↔ Pairwise R l₂) := by
-  suffices ∀ {l₁ l₂}, l₁ ~ l₂ → Pairwise R l₁ → Pairwise R l₂ from
-    fun l₁ l₂ p ↦ ⟨this p, this p.symm⟩
-  intros l₁ l₂ p d
-  induction d generalizing l₂ with
-  | nil => rw [← p.nil_eq]; constructor
-  | @cons a h d _ ih =>
-    obtain ⟨s₂, t₂, rfl⟩ := mem_split (p.subset (.head ..) : a ∈ l₂)
+    ∀ {l₁ l₂ : List α} (_p : l₁ ~ l₂), Pairwise R l₁ ↔ Pairwise R l₂ :=
+  suffices ∀ {l₁ l₂}, l₁ ~ l₂ → Pairwise R l₁ → Pairwise R l₂
+    from fun p => ⟨this p, this p.symm⟩
+  @fun l₁ l₂ p d => by
+  induction' d with a l₁ h _ IH generalizing l₂
+  · rw [← p.nil_eq]
+    constructor
+  · have : a ∈ l₂ := p.subset (mem_cons_self _ _)
+    rcases mem_split this with ⟨s₂, t₂, rfl⟩
     have p' := (p.trans perm_middle).cons_inv
-    exact (pairwise_middle S).2 (pairwise_cons.2 ⟨fun b m ↦ d _ (p'.symm.subset m), ih p'⟩)
+    refine' (pairwise_middle S).2 (pairwise_cons.2 ⟨fun b m => _, IH _ p'⟩)
+    exact h _ (p'.symm.subset m)
+#align list.perm.pairwise_iff List.Perm.pairwise_iff
+
+
+theorem Pairwise.perm {R : α → α → Prop} {l l' : List α} (hR : l.Pairwise R) (hl : l ~ l')
+    (hsymm : Symmetric R) : l'.Pairwise R :=
+  (hl.pairwise_iff hsymm).mp hR
+#align list.pairwise.perm List.Pairwise.perm
+
+theorem Perm.pairwise {R : α → α → Prop} {l l' : List α} (hl : l ~ l') (hR : l.Pairwise R)
+    (hsymm : Symmetric R) : l'.Pairwise R :=
+  hR.perm hl hsymm
+#align list.perm.pairwise List.Perm.pairwise
 
 theorem Perm.nodup_iff {l₁ l₂ : List α} : l₁ ~ l₂ → (Nodup l₁ ↔ Nodup l₂) :=
   Perm.pairwise_iff <| @Ne.symm α
+#align list.perm.nodup_iff List.Perm.nodup_iff
+
+theorem Perm.join {l₁ l₂ : List (List α)} (h : l₁ ~ l₂) : l₁.join ~ l₂.join :=
+  Perm.recOn h (Perm.refl _) (fun x xs₁ xs₂ _ ih => ih.append_left x)
+    (fun x₁ x₂ xs => by simpa only [join, append_assoc] using perm_append_comm.append_right _)
+    @fun xs₁ xs₂ xs₃ _ _ => Perm.trans
+#align list.perm.join List.Perm.join
+
+theorem Perm.bind_right {l₁ l₂ : List α} (f : α → List β) (p : l₁ ~ l₂) : l₁.bind f ~ l₂.bind f :=
+  (p.map _).join
+#align list.perm.bind_right List.Perm.bind_right
+
+theorem Perm.join_congr :
+    ∀ {l₁ l₂ : List (List α)} (_ : List.Forall₂ (· ~ ·) l₁ l₂), l₁.join ~ l₂.join
+  | _, _, Forall₂.nil => Perm.refl _
+  | _ :: _, _ :: _, Forall₂.cons h₁ h₂ => h₁.append (Perm.join_congr h₂)
+#align list.perm.join_congr List.Perm.join_congr
+
+theorem Perm.bind_left (l : List α) {f g : α → List β} (h : ∀ a ∈ l, f a ~ g a) :
+    l.bind f ~ l.bind g :=
+  Perm.join_congr <| by
+    rwa [List.forall₂_map_right_iff, List.forall₂_map_left_iff, List.forall₂_same]
+#align list.perm.bind_left List.Perm.bind_left
+
+theorem bind_append_perm (l : List α) (f g : α → List β) :
+    l.bind f ++ l.bind g ~ l.bind fun x => f x ++ g x :=
+  by
+  induction' l with a l IH <;> simp
+  refine' (Perm.trans _ (IH.append_left _)).append_left _
+  rw [← append_assoc, ← append_assoc]
+  exact perm_append_comm.append_right _
+#align list.bind_append_perm List.bind_append_perm
+
+theorem map_append_bind_perm (l : List α) (f : α → β) (g : α → List β) :
+    l.map f ++ l.bind g ~ l.bind fun x => f x :: g x := by
+  simpa [← map_eq_bind] using bind_append_perm l (fun x => [f x]) g
+#align list.map_append_bind_perm List.map_append_bind_perm
+
+theorem Perm.product_right {l₁ l₂ : List α} (t₁ : List β) (p : l₁ ~ l₂) :
+    product l₁ t₁ ~ product l₂ t₁ :=
+  p.bind_right _
+#align list.perm.product_right List.Perm.product_right
+
+theorem Perm.product_left (l : List α) {t₁ t₂ : List β} (p : t₁ ~ t₂) :
+    product l t₁ ~ product l t₂ :=
+  (Perm.bind_left _) fun _ _ => p.map _
+#align list.perm.product_left List.Perm.product_left
+
+-- @[congr]
+theorem Perm.product {l₁ l₂ : List α} {t₁ t₂ : List β} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) :
+    product l₁ t₁ ~ product l₂ t₂ :=
+  (p₁.product_right t₁).trans (p₂.product_left l₂)
+#align list.perm.product List.Perm.product
+
+theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α}
+    (H : Pairwise (fun a b => ∀ c ∈ f a, ∀ d ∈ f b, a = b ∧ c = d) l₁) (p : l₁ ~ l₂) :
+    lookmap f l₁ ~ lookmap f l₂ := by
+  induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ _ IH₁ IH₂; · simp
+  · cases h : f a
+    · simp [h]
+      exact IH (pairwise_cons.1 H).2
+    · simp [lookmap_cons_some _ _ h, p]
+  · cases' h₁ : f a with c <;> cases' h₂ : f b with d
+    · simp [h₁, h₂]
+      apply swap
+    · simp [h₁, lookmap_cons_some _ _ h₂]
+      apply swap
+    · simp [lookmap_cons_some _ _ h₁, h₂]
+      apply swap
+    · simp [lookmap_cons_some _ _ h₁, lookmap_cons_some _ _ h₂]
+      rcases(pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) _ h₂ _ h₁ with ⟨rfl, rfl⟩
+      exact Perm.refl _
+  · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H))
+    exact fun a b h c h₁ d h₂ => (h d h₂ c h₁).imp Eq.symm Eq.symm
+#align list.perm_lookmap List.perm_lookmap
+
+theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α}
+    (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ := by
+  induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ _ IH₁ IH₂; · simp
+  · by_cases h : f a
+    · simp [h, p]
+    · simp [h]
+      exact IH (pairwise_cons.1 H).2
+  · by_cases h₁ : f a <;> by_cases h₂ : f b <;> simp [h₁, h₂]
+    · cases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) h₂ h₁
+    · apply swap
+  · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H))
+    exact fun a b h h₁ h₂ => h h₂ h₁
+#align list.perm.erasep List.Perm.erasep
+
+theorem Perm.take_inter {α : Type _} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys)
+    (h' : ys.Nodup) : xs.take n ~ ys.inter (xs.take n) := by
+  simp only [List.inter]
+  exact Perm.trans (show xs.take n ~ xs.filter (. ∈ xs.take n) by
+      conv_lhs => rw [Nodup.take_eq_filter_mem ((Perm.nodup_iff h).2 h')])
+    (Perm.filter _ h)
+
+#align list.perm.take_inter List.Perm.take_inter
+
+theorem Perm.drop_inter {α} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys) (h' : ys.Nodup) :
+    xs.drop n ~ ys.inter (xs.drop n) :=
+  by
+  by_cases h'' : n ≤ xs.length
+  · let n' := xs.length - n
+    have h₀ : n = xs.length - n' := by
+      rwa [tsub_tsub_cancel_of_le]
+    have h₁ : n' ≤ xs.length := by apply tsub_le_self
+    have h₂ : xs.drop n = (xs.reverse.take n').reverse := by
+      rw [reverse_take _ h₁, h₀, reverse_reverse]
+    rw [h₂]
+    apply (reverse_perm _).trans
+    rw [inter_reverse]
+    apply Perm.take_inter _ _ h'
+    apply (reverse_perm _).trans; assumption
+  · have : drop n xs = [] := by
+      apply eq_nil_of_length_eq_zero
+      rw [length_drop, tsub_eq_zero_iff_le]
+      apply le_of_not_ge h''
+    simp [this, List.inter]
+#align list.perm.drop_inter List.Perm.drop_inter
+
+theorem Perm.dropSlice_inter {α} [DecidableEq α] {xs ys : List α} (n m : ℕ) (h : xs ~ ys)
+    (h' : ys.Nodup) : List.dropSlice n m xs ~ ys ∩ List.dropSlice n m xs := by
+  simp only [dropSlice_eq]
+  have : n ≤ n + m := Nat.le_add_right _ _
+  have h₂ := h.nodup_iff.2 h'
+  apply Perm.trans _ (Perm.inter_append _).symm
+  . exact Perm.append (Perm.take_inter _ h h') (Perm.drop_inter _ h h')
+  . exact disjoint_take_drop h₂ this
+#align list.perm.slice_inter List.Perm.dropSlice_inter
+
+-- enumerating permutations
+section Permutations
+
+theorem perm_of_mem_permutationsAux :
+    ∀ {ts is l : List α}, l ∈ permutationsAux ts is → l ~ ts ++ is := by
+  show ∀ (ts is l : List α), l ∈ permutationsAux ts is → l ~ ts ++ is
+  refine' permutationsAux.rec (by simp) _
+  introv IH1 IH2 m
+  rw [permutationsAux_cons, permutations, mem_foldr_permutationsAux2] at m
+  rcases m with (m | ⟨l₁, l₂, m, _, e⟩)
+  · exact (IH1 _ m).trans perm_middle
+  · subst e
+    have p : l₁ ++ l₂ ~ is := by
+      simp [permutations] at m
+      cases' m with e m
+      · simp [e]
+      exact is.append_nil ▸ IH2 _ m
+    exact ((perm_middle.trans (p.cons _)).append_right _).trans (perm_append_comm.cons _)
+#align list.perm_of_mem_permutations_aux List.perm_of_mem_permutationsAux
+
+theorem perm_of_mem_permutations {l₁ l₂ : List α} (h : l₁ ∈ permutations l₂) : l₁ ~ l₂ :=
+  (eq_or_mem_of_mem_cons h).elim (fun e => e ▸ Perm.refl _) fun m =>
+    append_nil l₂ ▸ perm_of_mem_permutationsAux m
+#align list.perm_of_mem_permutations List.perm_of_mem_permutations
+
+theorem length_permutationsAux :
+    ∀ ts is : List α, length (permutationsAux ts is) + is.length ! = (length ts + length is)! :=
+  by
+  refine' permutationsAux.rec (by simp) _
+  intro t ts is IH1 IH2
+  have IH2 : length (permutationsAux is nil) + 1 = is.length ! := by simpa using IH2
+  simp [Nat.factorial, Nat.add_succ, mul_comm] at IH1
+  rw [permutationsAux_cons,
+    length_foldr_permutationsAux2' _ _ _ _ _ fun l m => (perm_of_mem_permutations m).length_eq,
+    permutations, length, length, IH2, Nat.succ_add, Nat.factorial_succ, mul_comm (_ + 1),
+    ← Nat.succ_eq_add_one, ← IH1, add_comm (_ * _), add_assoc, Nat.mul_succ, mul_comm]
+#align list.length_permutations_aux List.length_permutationsAux
+
+theorem length_permutations (l : List α) : length (permutations l) = (length l)! :=
+  length_permutationsAux l []
+#align list.length_permutations List.length_permutations
+
+theorem mem_permutations_of_perm_lemma {is l : List α}
+    (H : l ~ [] ++ is → (∃ (ts' : _)(_ : ts' ~ []), l = ts' ++ is) ∨ l ∈ permutationsAux is []) :
+    l ~ is → l ∈ permutations is := by simpa [permutations, perm_nil] using H
+#align list.mem_permutations_of_perm_lemma List.mem_permutations_of_perm_lemma
+
+theorem mem_permutationsAux_of_perm :
+    ∀ {ts is l : List α},
+      l ~ is ++ ts → (∃ (is' : _)(_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is := by
+  show ∀ (ts is l : List α),
+      l ~ is ++ ts → (∃ (is' : _)(_ : is' ~ is), l = is' ++ ts) ∨ l ∈ permutationsAux ts is
+  refine' permutationsAux.rec (by simp) _
+  intro t ts is IH1 IH2 l p
+  rw [permutationsAux_cons, mem_foldr_permutationsAux2]
+  rcases IH1 _ (p.trans perm_middle) with (⟨is', p', e⟩ | m)
+  · clear p
+    subst e
+    rcases mem_split (p'.symm.subset (mem_cons_self _ _)) with ⟨l₁, l₂, e⟩
+    subst is'
+    have p := (perm_middle.symm.trans p').cons_inv
+    cases' l₂ with a l₂'
+    · exact Or.inl ⟨l₁, by simpa using p⟩
+    · exact Or.inr (Or.inr ⟨l₁, a :: l₂', mem_permutations_of_perm_lemma (IH2 _) p, by simp⟩)
+  · exact Or.inr (Or.inl m)
+#align list.mem_permutations_aux_of_perm List.mem_permutationsAux_of_perm
+
+@[simp]
+theorem mem_permutations {s t : List α} : s ∈ permutations t ↔ s ~ t :=
+  ⟨perm_of_mem_permutations, mem_permutations_of_perm_lemma mem_permutationsAux_of_perm⟩
+#align list.mem_permutations List.mem_permutations
+
+--Porting note: temporary theorem to solve diamond issue
+private theorem DecEq_eq {α : Type _} [DecidableEq α] :
+     instBEqList = @instBEq (List α) instDecidableEqList :=
+  congr_arg BEq.mk <| by
+    funext l₁ l₂
+    rw [Bool.eq_iff_eq_true_iff, @beq_iff_eq _ (instBEqList),
+      @beq_iff_eq _ (@instBEq (List α) instDecidableEqList)]
+
+theorem perm_permutations'Aux_comm (a b : α) (l : List α) :
+    (permutations'Aux a l).bind (permutations'Aux b) ~
+      (permutations'Aux b l).bind (permutations'Aux a) :=
+  by
+  induction' l with c l ih
+  · simp [swap]
+  simp [permutations'Aux]
+  apply Perm.swap'
+  have :
+    ∀ a b,
+      (map (cons c) (permutations'Aux a l)).bind (permutations'Aux b) ~
+        map (cons b ∘ cons c) (permutations'Aux a l) ++
+          map (cons c) ((permutations'Aux a l).bind (permutations'Aux b)) := by
+    intros a' b'
+    simp only [map_bind, permutations'Aux]
+    show List.bind (permutations'Aux _ l) (fun a => ([b' :: c :: a] ++
+      map (cons c) (permutations'Aux _ a))) ~ _
+    refine' (bind_append_perm _ (fun x => [b' :: c :: x]) _).symm.trans _
+    rw [← map_eq_bind, ← bind_map]
+    exact Perm.refl _
+  refine' (((this _ _).append_left _).trans _).trans ((this _ _).append_left _).symm
+  rw [← append_assoc, ← append_assoc]
+  exact perm_append_comm.append (ih.map _)
+#align list.perm_permutations'_aux_comm List.perm_permutations'Aux_comm
+
+theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t :=
+  by
+  induction' p with a s t _ IH a b l s t u _ _ IH₁ IH₂; · simp
+  · simp only [permutations']
+    exact IH.bind_right _
+  · dsimp [permutations']
+    rw [bind_assoc, bind_assoc]
+    apply Perm.bind_left
+    intro l' _
+    apply perm_permutations'Aux_comm
+  · exact IH₁.trans IH₂
+#align list.perm.permutations' List.Perm.permutations'
+
+theorem permutations_perm_permutations' (ts : List α) : ts.permutations ~ ts.permutations' := by
+  obtain ⟨n, h⟩ : ∃ n, length ts < n := ⟨_, Nat.lt_succ_self _⟩
+  induction' n with n IH generalizing ts; · cases h
+  refine' List.reverseRecOn ts (fun _ => _) (fun ts t _ h => _) h; · simp [permutations]
+  rw [← concat_eq_append, length_concat, Nat.succ_lt_succ_iff] at h
+  have IH₂ := (IH ts.reverse (by rwa [length_reverse])).trans (reverse_perm _).permutations'
+  simp only [permutations_append, foldr_permutationsAux2, permutationsAux_nil,
+    permutationsAux_cons, append_nil]
+  refine'
+    (perm_append_comm.trans ((IH₂.bind_right _).append ((IH _ h).map _))).trans
+      (Perm.trans _ perm_append_comm.permutations')
+  rw [map_eq_bind, singleton_append, permutations']
+  refine' (bind_append_perm _ _ _).trans _
+  refine' Perm.of_eq _
+  congr
+  funext _
+  rw [permutations'Aux_eq_permutationsAux2, permutationsAux2_append]
+#align list.permutations_perm_permutations' List.permutations_perm_permutations'
+
+@[simp]
+theorem mem_permutations' {s t : List α} : s ∈ permutations' t ↔ s ~ t :=
+  (permutations_perm_permutations' _).symm.mem_iff.trans mem_permutations
+#align list.mem_permutations' List.mem_permutations'
+
+theorem Perm.permutations {s t : List α} (h : s ~ t) : permutations s ~ permutations t :=
+  (permutations_perm_permutations' _).trans <|
+    h.permutations'.trans (permutations_perm_permutations' _).symm
+#align list.perm.permutations List.Perm.permutations
+
+@[simp]
+theorem perm_permutations_iff {s t : List α} : permutations s ~ permutations t ↔ s ~ t :=
+  ⟨fun h => mem_permutations.1 <| h.mem_iff.1 <| mem_permutations.2 (Perm.refl _),
+    Perm.permutations⟩
+#align list.perm_permutations_iff List.perm_permutations_iff
+
+@[simp]
+theorem perm_permutations'_iff {s t : List α} : permutations' s ~ permutations' t ↔ s ~ t :=
+  ⟨fun h => mem_permutations'.1 <| h.mem_iff.1 <| mem_permutations'.2 (Perm.refl _),
+    Perm.permutations'⟩
+#align list.perm_permutations'_iff List.perm_permutations'_iff
+
+set_option linter.deprecated false in
+theorem nthLe_permutations'Aux (s : List α) (x : α) (n : ℕ)
+    (hn : n < length (permutations'Aux x s)) :
+    (permutations'Aux x s).nthLe n hn = s.insertNth n x := by
+  induction' s with y s IH generalizing n
+  · simp only [length, zero_add, lt_one_iff] at hn
+    simp [hn]
+  · cases n
+    · simp [nthLe]
+    · simpa [nthLe] using IH _ _
+#align list.nth_le_permutations'_aux List.nthLe_permutations'Aux
+
+theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) :
+    count (x :: l) (permutations'Aux x l) = length (takeWhile ((· = ·) x) l) + 1 :=
+  by
+  induction' l with y l IH generalizing x
+  · simp [takeWhile, count]
+  · rw [permutations'Aux, DecEq_eq, count_cons_self]
+    by_cases hx : x = y
+    · subst hx
+      simpa [takeWhile, Nat.succ_inj', DecEq_eq] using IH _
+    · rw [takeWhile]
+      simp only [mem_map', cons.injEq, Ne.symm hx, false_and, and_false, exists_false,
+        not_false_iff, count_eq_zero_of_not_mem, zero_add, hx, decide_False, length_nil]
+#align list.count_permutations'_aux_self List.count_permutations'Aux_self
+
+@[simp]
+theorem length_permutations'Aux (s : List α) (x : α) :
+    length (permutations'Aux x s) = length s + 1 :=
+  by
+  induction' s with y s IH
+  · simp
+  · simpa using IH
+#align list.length_permutations'_aux List.length_permutations'Aux
+
+@[simp]
+theorem permutations'Aux_nthLe_zero (s : List α) (x : α)
+    (hn : 0 < length (permutations'Aux x s) := (by simp)) :
+    (permutations'Aux x s).nthLe 0 hn = x :: s :=
+  nthLe_permutations'Aux _ _ _ _
+#align list.permutations'_aux_nth_le_zero List.permutations'Aux_nthLe_zero
+
+theorem injective_permutations'Aux (x : α) : Function.Injective (permutations'Aux x) :=
+  by
+  intro s t h
+  apply insertNth_injective s.length x
+  have hl : s.length = t.length := by simpa using congr_arg length h
+  rw [← nthLe_permutations'Aux s x s.length (by simp), ←
+    nthLe_permutations'Aux t x s.length (by simp [hl])]
+  simp [h, hl]
+#align list.injective_permutations'_aux List.injective_permutations'Aux
+
+theorem nodup_permutations'Aux_of_not_mem (s : List α) (x : α) (hx : x ∉ s) :
+    Nodup (permutations'Aux x s) := by
+  induction' s with y s IH
+  · simp
+  · simp only [not_or, mem_cons] at hx
+    simp only [permutations'Aux, nodup_cons, mem_map', cons.injEq, exists_eq_right_right, not_and]
+    refine' ⟨fun _ => Ne.symm hx.left, _⟩
+    rw [nodup_map_iff]
+    · exact IH hx.right
+    · simp
+#align list.nodup_permutations'_aux_of_not_mem List.nodup_permutations'Aux_of_not_mem
+
+set_option linter.deprecated false in
+theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'Aux x s) ↔ x ∉ s :=
+  by
+  refine' ⟨fun h => _, nodup_permutations'Aux_of_not_mem _ _⟩
+  intro H
+  obtain ⟨k, hk, hk'⟩ := nthLe_of_mem H
+  rw [nodup_iff_nthLe_inj] at h
+  suffices k = k + 1 by simp at this
+  refine' h k (k + 1) _ _ _
+  · simpa [Nat.lt_succ_iff] using hk.le
+  · simpa using hk
+  rw [nthLe_permutations'Aux, nthLe_permutations'Aux]
+  have hl : length (insertNth k x s) = length (insertNth (k + 1) x s) := by
+    rw [length_insertNth _ _ hk.le, length_insertNth _ _ (Nat.succ_le_of_lt hk)]
+  refine' ext_nthLe hl fun n hn hn' => _
+  rcases lt_trichotomy n k with (H | rfl | H)
+  ·
+    rw [nthLe_insertNth_of_lt _ _ _ _ H (H.trans hk),
+      nthLe_insertNth_of_lt _ _ _ _ (H.trans (Nat.lt_succ_self _))]
+  ·
+    rw [nthLe_insertNth_self _ _ _ hk.le, nthLe_insertNth_of_lt _ _ _ _ (Nat.lt_succ_self _) hk,
+      hk']
+  · rcases(Nat.succ_le_of_lt H).eq_or_lt with (rfl | H')
+    · rw [nthLe_insertNth_self _ _ _ (Nat.succ_le_of_lt hk)]
+      convert hk' using 1
+      exact nthLe_insertNth_add_succ _ _ _ 0 _
+    · obtain ⟨m, rfl⟩ := Nat.exists_eq_add_of_lt H'
+      erw [length_insertNth _ _ hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn
+      rw [nthLe_insertNth_add_succ]
+      convert nthLe_insertNth_add_succ s x k m.succ (by simpa using hn) using 2
+      · simp [Nat.add_succ, Nat.succ_add]
+      · simp [add_left_comm, add_comm]
+      · simpa [Nat.succ_add] using hn
+#align list.nodup_permutations'_aux_iff List.nodup_permutations'Aux_iff
+
+set_option linter.deprecated false in
+theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations :=
+  by
+  rw [(permutations_perm_permutations' s).nodup_iff]
+  induction' hs with x l h h' IH
+  · simp
+  · rw [permutations']
+    rw [nodup_bind]
+    constructor
+    · intro ys hy
+      rw [mem_permutations'] at hy
+      rw [nodup_permutations'Aux_iff, hy.mem_iff]
+      exact fun H => h x H rfl
+    · refine' IH.pairwise_of_forall_ne fun as ha bs hb H => _
+      rw [disjoint_iff_ne]
+      rintro a ha' b hb' rfl
+      obtain ⟨⟨n, hn⟩, hn'⟩ := get_of_mem ha'
+      obtain ⟨⟨m, hm⟩, hm'⟩ := get_of_mem hb'
+      rw [mem_permutations'] at ha hb
+      have hl : as.length = bs.length := (ha.trans hb.symm).length_eq
+      simp only [Nat.lt_succ_iff, length_permutations'Aux] at hn hm
+      rw [← nthLe, nthLe_permutations'Aux] at hn' hm'
+      have hx :
+        nthLe (insertNth n x as) m (by rwa [length_insertNth _ _ hn, Nat.lt_succ_iff, hl]) = x :=
+        by simp [hn', ← hm', hm]
+      have hx' :
+        nthLe (insertNth m x bs) n (by rwa [length_insertNth _ _ hm, Nat.lt_succ_iff, ← hl]) =
+          x :=
+        by simp [hm', ← hn', hn]
+      rcases lt_trichotomy n m with (ht | ht | ht)
+      · suffices x ∈ bs by exact h x (hb.subset this) rfl
+        rw [← hx', nthLe_insertNth_of_lt _ _ _ _ ht (ht.trans_le hm)]
+        exact nthLe_mem _ _ _
+      · simp only [ht] at hm' hn'
+        rw [← hm'] at hn'
+        exact H (insertNth_injective _ _ hn')
+      · suffices x ∈ as by exact h x (ha.subset this) rfl
+        rw [← hx, nthLe_insertNth_of_lt _ _ _ _ ht (ht.trans_le hn)]
+        exact nthLe_mem _ _ _
+#align list.nodup_permutations List.nodup_permutations
+
+-- TODO: `nodup s.permutations ↔ nodup s`
+-- TODO: `count s s.permutations = (zip_with count s s.tails).prod`
+end Permutations
+
+end List

Dependencies 2 + 138

139 files ported (98.6%)
61065 lines ported (99.8%)
Show graph

The unported dependencies are