Module docstring
{"# List Permutations
This file develops theory about the List.Perm relation.
Notation
The notation ~ is used for permutation equivalence.
"}
{"# List Permutations
This file develops theory about the List.Perm relation.
The notation ~ is used for permutation equivalence.
"}
List.perm_rfl
theorem
: l ~ l
List.instIsSymmPerm
instance
: IsSymm (List α) Perm
instance : IsSymm (List α) Perm := ⟨fun _ _ ↦ .symm⟩
List.Perm.subset_congr_left
theorem
{l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₁ ⊆ l₃ ↔ l₂ ⊆ l₃
theorem Perm.subset_congr_left {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₁ ⊆ l₃l₁ ⊆ l₃ ↔ l₂ ⊆ l₃ :=
⟨h.symm.subset.trans, h.subset.trans⟩
List.Perm.subset_congr_right
theorem
{l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₃ ⊆ l₁ ↔ l₃ ⊆ l₂
theorem Perm.subset_congr_right {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₃ ⊆ l₁l₃ ⊆ l₁ ↔ l₃ ⊆ l₂ :=
⟨fun h' => h'.trans h.subset, fun h' => h'.trans h.symm.subset⟩
List.set_perm_cons_eraseIdx
theorem
{n : ℕ} (h : n < l.length) (a : α) : l.set n a ~ a :: l.eraseIdx n
theorem set_perm_cons_eraseIdx {n : ℕ} (h : n < l.length) (a : α) :
l.set n a ~ a :: l.eraseIdx n := by
rw [← insertIdx_eraseIdx h.ne]
apply perm_insertIdx
rw [length_eraseIdx_of_lt h]
exact Nat.le_sub_one_of_lt h
List.getElem_cons_eraseIdx_perm
theorem
{n : ℕ} (h : n < l.length) : l[n] :: l.eraseIdx n ~ l
theorem getElem_cons_eraseIdx_perm {n : ℕ} (h : n < l.length) :
l[n]l[n] :: l.eraseIdx nl[n] :: l.eraseIdx n ~ l := by
simpa [h] using (set_perm_cons_eraseIdx h l[n]).symm
List.perm_insertIdx_iff_of_le
theorem
{l₁ l₂ : List α} {m n : ℕ} (hm : m ≤ l₁.length) (hn : n ≤ l₂.length) (a : α) :
l₁.insertIdx m a ~ l₂.insertIdx n a ↔ l₁ ~ l₂
theorem perm_insertIdx_iff_of_le {l₁ l₂ : List α} {m n : ℕ} (hm : m ≤ l₁.length)
(hn : n ≤ l₂.length) (a : α) : l₁.insertIdx m a ~ l₂.insertIdx n al₁.insertIdx m a ~ l₂.insertIdx n a ↔ l₁ ~ l₂ := by
rw [rel_congr_left (perm_insertIdx _ _ hm), rel_congr_right (perm_insertIdx _ _ hn), perm_cons]
List.perm_insertIdx_iff
theorem
{l₁ l₂ : List α} {n : ℕ} {a : α} : l₁.insertIdx n a ~ l₂.insertIdx n a ↔ l₁ ~ l₂
@[simp]
theorem perm_insertIdx_iff {l₁ l₂ : List α} {n : ℕ} {a : α} :
l₁.insertIdx n a ~ l₂.insertIdx n al₁.insertIdx n a ~ l₂.insertIdx n a ↔ l₁ ~ l₂ := by
wlog hle : length l₁ ≤ length l₂ generalizing l₁ l₂
· rw [perm_comm, this (le_of_not_le hle), perm_comm]
cases Nat.lt_or_ge (length l₁) n with
| inl hn₁ =>
rw [insertIdx_of_length_lt hn₁]
cases Nat.lt_or_ge (length l₂) n with
| inl hn₂ => rw [insertIdx_of_length_lt hn₂]
| inr hn₂ =>
apply iff_of_false
· intro h
rw [h.length_eq] at hn₁
exact (hn₁.trans_le hn₂).not_le (length_le_length_insertIdx ..)
· exact fun h ↦ (hn₁.trans_le hn₂).not_le h.length_eq.ge
| inr hn₁ =>
exact perm_insertIdx_iff_of_le hn₁ (le_trans hn₁ hle) _
List.Perm.insertIdx
theorem
{l₁ l₂ : List α} (h : l₁ ~ l₂) (n : ℕ) (a : α) : l₁.insertIdx n a ~ l₂.insertIdx n a
@[gcongr]
protected theorem Perm.insertIdx {l₁ l₂ : List α} (h : l₁ ~ l₂) (n : ℕ) (a : α) :
l₁.insertIdx n a ~ l₂.insertIdx n a :=
perm_insertIdx_iff.mpr h
List.perm_eraseIdx_of_getElem?_eq
theorem
{l₁ l₂ : List α} {m n : ℕ} (h : l₁[m]? = l₂[n]?) : eraseIdx l₁ m ~ eraseIdx l₂ n ↔ l₁ ~ l₂
theorem perm_eraseIdx_of_getElem?_eq {l₁ l₂ : List α} {m n : ℕ} (h : l₁[m]? = l₂[n]?) :
eraseIdxeraseIdx l₁ m ~ eraseIdx l₂ neraseIdx l₁ m ~ eraseIdx l₂ n ↔ l₁ ~ l₂ := by
cases Nat.lt_or_ge m l₁.length with
| inl hm =>
rw [getElem?_eq_getElem hm, eq_comm, getElem?_eq_some_iff] at h
cases h with
| intro hn hnm =>
rw [← perm_cons l₁[m], rel_congr_left (getElem_cons_eraseIdx_perm ..), ← hnm,
rel_congr_right (getElem_cons_eraseIdx_perm ..)]
| inr hm =>
rw [getElem?_eq_none hm, eq_comm, getElem?_eq_none_iff] at h
rw [eraseIdx_of_length_le h, eraseIdx_of_length_le hm]
List.perm_comp_perm
theorem
: (Perm ∘r Perm : List α → List α → Prop) = Perm
theorem perm_comp_perm : (PermPerm ∘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⟩
List.perm_comp_forall₂
theorem
{l u v} (hlu : Perm l u) (huv : Forall₂ r u v) : (Forall₂ r ∘r Perm) l v
theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) :
(Forall₂Forall₂ r ∘r Perm) l v := by
induction hlu generalizing v with
| nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩
| cons u _hlu ih =>
obtain - | ⟨hab, huv'⟩ := huv
rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩
exact ⟨_ :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩
| swap a₁ a₂ h₂₃ =>
obtain - | ⟨h₁, hr₂₃⟩ := huv
obtain - | ⟨h₂, h₁₂⟩ := hr₂₃
exact ⟨_, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩
| trans _ _ ih₁ ih₂ =>
rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩
rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩
exact ⟨lb₁, hab₁, Perm.trans h₁₂ h₂₃⟩
List.forall₂_comp_perm_eq_perm_comp_forall₂
theorem
: Forall₂ r ∘r Perm = Perm ∘r Forall₂ r
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂Forall₂ r ∘r Perm = PermPerm ∘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₂₃
List.rel_perm_imp
theorem
(hr : RightUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· → ·)) Perm Perm
theorem rel_perm_imp (hr : RightUnique r) : (Forall₂Forall₂ r ⇒ Forall₂ r ⇒ (· → ·)) Perm Perm :=
fun a b h₁ c d h₂ h =>
have : (flipflip (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', ⟨_, hbc, hcb⟩, hbd⟩ := this
have : b' = b := right_unique_forall₂' hr hcb hbc
this ▸ hbd
List.rel_perm
theorem
(hr : BiUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· ↔ ·)) Perm Perm
theorem rel_perm (hr : BiUnique r) : (Forall₂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)
List.count_eq_count_filter_add
theorem
[DecidableEq α] (P : α → Prop) [DecidablePred P] (l : List α) (a : α) :
count a l = count a (l.filter P) + count a (l.filter (¬P ·))
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_not]
List.Perm.foldl_eq
theorem
{f : β → α → β} {l₁ l₂ : List α} [rcomm : RightCommutative f] (p : l₁ ~ l₂) : ∀ b, foldl f b l₁ = foldl f b l₂
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.right_comm z x y
List.Perm.foldr_eq
theorem
{f : α → β → β} {l₁ l₂ : List α} [lcomm : LeftCommutative f] (p : l₁ ~ l₂) : ∀ b, foldr f b l₁ = foldr f b l₂
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 with
| nil => rfl
| cons _ _ r => simp [r b]
| swap' _ _ _ r => simp only [foldr_cons]; rw [lcomm.left_comm, r b]
| trans _ _ r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b)
List.Perm.foldl_op_eq
theorem
{l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : (l₁ <*> a) = l₂ <*> a
List.Perm.foldr_op_eq
theorem
{l₁ l₂ : List α} {a : α} (h : l₁ ~ l₂) : l₁.foldr op a = l₂.foldr op a
List.perm_option_toList
theorem
{o₁ o₂ : Option α} : o₁.toList ~ o₂.toList ↔ o₁ = o₂
theorem perm_option_toList {o₁ o₂ : Option α} : o₁.toList ~ o₂.toListo₁.toList ~ o₂.toList ↔ o₁ = o₂ := by
refine ⟨fun p => ?_, fun e => e ▸ Perm.refl _⟩
rcases o₁ with - | a <;> rcases o₂ with - | b; · rfl
· cases p.length_eq
· cases p.length_eq
· exact Option.mem_toList.1 (p.symm.subset <| by simp)
List.perm_replicate_append_replicate
theorem
[DecidableEq α] {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]
theorem perm_replicate_append_replicate
[DecidableEq α] {l : List α} {a b : α} {m n : ℕ} (h : a ≠ b) :
l ~ replicate m a ++ replicate n bl ~ 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]l ⊆ [a, b] ↔ ∀ c, c ≠ b → c ≠ a → c ∉ l by
simp +contextual [count_replicate, h, this, count_eq_zero, Ne.symm]
trans ∀ c, c ∈ l → c = b ∨ c = a
· simp [subset_def, or_comm]
· exact forall_congr' fun _ => by rw [← and_imp, ← not_or, not_imp_not]
List.map_perm_map_iff
theorem
{l' : List α} {f : α → β} (hf : f.Injective) : map f l ~ map f l' ↔ l ~ l'
theorem map_perm_map_iff {l' : List α} {f : α → β} (hf : f.Injective) :
mapmap f l ~ map f l'map f l ~ map f l' ↔ l ~ l' := calc
map f l ~ map f l' ↔ Relation.Comp (· = map f ·) (· ~ ·) (map f l) l' := by rw [eq_map_comp_perm]
_ ↔ l ~ l' := by simp [Relation.Comp, map_inj_right hf]
List.Perm.flatMap_left
theorem
(l : List α) {f g : α → List β} (h : ∀ a ∈ l, f a ~ g a) : l.flatMap f ~ l.flatMap g
@[gcongr]
theorem Perm.flatMap_left (l : List α) {f g : α → List β} (h : ∀ a ∈ l, f a ~ g a) :
l.flatMap f ~ l.flatMap g :=
Perm.flatten_congr <| by
rwa [List.forall₂_map_right_iff, List.forall₂_map_left_iff, List.forall₂_same]
List.Perm.flatMap
theorem
{l₁ l₂ : List α} {f g : α → List β} (h : l₁ ~ l₂) (hfg : ∀ a ∈ l₁, f a ~ g a) : l₁.flatMap f ~ l₂.flatMap g
@[gcongr]
protected theorem Perm.flatMap {l₁ l₂ : List α} {f g : α → List β} (h : l₁ ~ l₂)
(hfg : ∀ a ∈ l₁, f a ~ g a) : l₁.flatMap f ~ l₂.flatMap g :=
.trans (.flatMap_left _ hfg) (h.flatMap_right _)
List.flatMap_append_perm
theorem
(l : List α) (f g : α → List β) : l.flatMap f ++ l.flatMap g ~ l.flatMap fun x => f x ++ g x
theorem flatMap_append_perm (l : List α) (f g : α → List β) :
l.flatMap f ++ l.flatMap g ~ l.flatMap fun x => f x ++ g x := by
induction l with | nil => simp | cons a l IH => ?_
simp only [flatMap_cons, append_assoc]
refine (Perm.trans ?_ (IH.append_left _)).append_left _
rw [← append_assoc, ← append_assoc]
exact perm_append_comm.append_right _
List.map_append_flatMap_perm
theorem
(l : List α) (f : α → β) (g : α → List β) : l.map f ++ l.flatMap g ~ l.flatMap fun x => f x :: g x
theorem map_append_flatMap_perm (l : List α) (f : α → β) (g : α → List β) :
l.map f ++ l.flatMap g ~ l.flatMap fun x => f x :: g x := by
simpa [← map_eq_flatMap] using flatMap_append_perm l (fun x => [f x]) g
List.Perm.product_right
theorem
{l₁ l₂ : List α} (t₁ : List β) (p : l₁ ~ l₂) : product l₁ t₁ ~ product l₂ t₁
@[gcongr]
theorem Perm.product_right {l₁ l₂ : List α} (t₁ : List β) (p : l₁ ~ l₂) :
productproduct l₁ t₁ ~ product l₂ t₁ :=
p.flatMap_right _
List.Perm.product_left
theorem
(l : List α) {t₁ t₂ : List β} (p : t₁ ~ t₂) : product l t₁ ~ product l t₂
@[gcongr]
theorem Perm.product_left (l : List α) {t₁ t₂ : List β} (p : t₁ ~ t₂) :
productproduct l t₁ ~ product l t₂ :=
(Perm.flatMap_left _) fun _ _ => p.map _
List.Perm.product
theorem
{l₁ l₂ : List α} {t₁ t₂ : List β} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : product l₁ t₁ ~ product l₂ t₂
@[gcongr]
theorem Perm.product {l₁ l₂ : List α} {t₁ t₂ : List β} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) :
productproduct l₁ t₁ ~ product l₂ t₂ :=
(p₁.product_right t₁).trans (p₂.product_left l₂)