Module docstring
{"# Lemmas about List.countP and List.count.
","### countP ","### count "}
{"# Lemmas about List.countP and List.count.
","### countP ","### count "}
List.countP_nil
theorem
: countP p [] = 0
@[simp] theorem countP_nil : countP p [] = 0 := rfl
List.countP_go_eq_add
theorem
{l} : countP.go p l n = n + countP.go p l 0
protected theorem countP_go_eq_add {l} : countP.go p l n = n + countP.go p l 0 := by
induction l generalizing n with
| nil => rfl
| cons hd _ ih =>
unfold countP.go
rw [ih (n := n + 1), ih (n := n), ih (n := 1)]
if h : p hd then simp [h, Nat.add_assoc] else simp [h]
List.countP_cons_of_pos
theorem
{l} (pa : p a) : countP p (a :: l) = countP p l + 1
@[simp] theorem countP_cons_of_pos {l} (pa : p a) : countP p (a :: l) = countP p l + 1 := by
have : countP.go p (a :: l) 0 = countP.go p l 1 := show cond .. = _ by rw [pa]; rfl
unfold countP
rw [this, Nat.add_comm, List.countP_go_eq_add]
List.countP_cons_of_neg
theorem
{l} (pa : ¬p a) : countP p (a :: l) = countP p l
List.countP_cons
theorem
{a : α} {l : List α} : countP p (a :: l) = countP p l + if p a then 1 else 0
theorem countP_cons {a : α} {l : List α} : countP p (a :: l) = countP p l + if p a then 1 else 0 := by
by_cases h : p a <;> simp [h]
List.countP_singleton
theorem
{a : α} : countP p [a] = if p a then 1 else 0
@[simp] theorem countP_singleton {a : α} : countP p [a] = if p a then 1 else 0 := by
simp [countP_cons]
List.length_eq_countP_add_countP
theorem
(p : α → Bool) {l : List α} : length l = countP p l + countP (fun a => ¬p a) l
theorem length_eq_countP_add_countP (p : α → Bool) {l : List α} : length l = countP p l + countP (fun a => ¬p a) l := by
induction l with
| nil => rfl
| cons hd _ ih =>
if h : p hd then
rw [countP_cons_of_pos h, countP_cons_of_neg _, length, ih]
· rw [Nat.add_assoc, Nat.add_comm _ 1, Nat.add_assoc]
· simp [h]
else
rw [countP_cons_of_pos (p := fun a => ¬p a), countP_cons_of_neg h, length, ih]
· rfl
· simp [h]
List.countP_eq_length_filter
theorem
{l : List α} : countP p l = length (filter p l)
theorem countP_eq_length_filter {l : List α} : countP p l = length (filter p l) := by
induction l with
| nil => rfl
| cons x l ih =>
if h : p x
then rw [countP_cons_of_pos h, ih, filter_cons_of_pos h, length]
else rw [countP_cons_of_neg h, ih, filter_cons_of_neg h]
List.countP_eq_length_filter'
theorem
: countP p = length ∘ filter p
theorem countP_eq_length_filter' : countP p = lengthlength ∘ filter p := by
funext l
apply countP_eq_length_filter
List.countP_le_length
theorem
: countP p l ≤ l.length
theorem countP_le_length : countP p l ≤ l.length := by
simp only [countP_eq_length_filter]
apply length_filter_le
List.countP_append
theorem
{l₁ l₂ : List α} : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂
@[simp] theorem countP_append {l₁ l₂ : List α} : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by
simp only [countP_eq_length_filter, filter_append, length_append]
List.countP_pos_iff
theorem
{p} : 0 < countP p l ↔ ∃ a ∈ l, p a
@[simp] theorem countP_pos_iff {p} : 0 < countP p l ↔ ∃ a ∈ l, p a := by
simp only [countP_eq_length_filter, length_pos_iff_exists_mem, mem_filter, exists_prop]
List.countP_pos
abbrev
@[deprecated countP_pos_iff (since := "2024-09-09")] abbrev countP_pos := @countP_pos_iff
List.one_le_countP_iff
theorem
{p} : 1 ≤ countP p l ↔ ∃ a ∈ l, p a
@[simp] theorem one_le_countP_iff {p} : 1 ≤ countP p l ↔ ∃ a ∈ l, p a :=
countP_pos_iff
List.countP_eq_zero
theorem
{p} : countP p l = 0 ↔ ∀ a ∈ l, ¬p a
@[simp] theorem countP_eq_zero {p} : countPcountP p l = 0 ↔ ∀ a ∈ l, ¬p a := by
simp only [countP_eq_length_filter, length_eq_zero_iff, filter_eq_nil_iff]
List.countP_eq_length
theorem
{p} : countP p l = l.length ↔ ∀ a ∈ l, p a
@[simp] theorem countP_eq_length {p} : countPcountP p l = l.length ↔ ∀ a ∈ l, p a := by
rw [countP_eq_length_filter, length_filter_eq_length_iff]
List.countP_replicate
theorem
{p : α → Bool} {a : α} {n : Nat} : countP p (replicate n a) = if p a then n else 0
theorem countP_replicate {p : α → Bool} {a : α} {n : Nat} :
countP p (replicate n a) = if p a then n else 0 := by
simp only [countP_eq_length_filter, filter_replicate]
split <;> simp
List.boole_getElem_le_countP
theorem
{p : α → Bool} {l : List α} {i : Nat} (h : i < l.length) : (if p l[i] then 1 else 0) ≤ l.countP p
theorem boole_getElem_le_countP {p : α → Bool} {l : List α} {i : Nat} (h : i < l.length) :
(if p l[i] then 1 else 0) ≤ l.countP p := by
induction l generalizing i with
| nil => simp at h
| cons x l ih =>
cases i with
| zero => simp [countP_cons]
| succ i =>
simp only [length_cons, add_one_lt_add_one_iff] at h
simp only [getElem_cons_succ, countP_cons]
specialize ih h
exact le_add_right_of_le ih
List.Sublist.countP_le
theorem
(s : l₁ <+ l₂) : countP p l₁ ≤ countP p l₂
theorem Sublist.countP_le (s : l₁ <+ l₂) : countP p l₁ ≤ countP p l₂ := by
simp only [countP_eq_length_filter]
apply s.filter _ |>.length_le
List.IsPrefix.countP_le
theorem
(s : l₁ <+: l₂) : countP p l₁ ≤ countP p l₂
List.IsSuffix.countP_le
theorem
(s : l₁ <:+ l₂) : countP p l₁ ≤ countP p l₂
List.IsInfix.countP_le
theorem
(s : l₁ <:+: l₂) : countP p l₁ ≤ countP p l₂
theorem IsInfix.countP_le (s : l₁ <:+: l₂) : countP p l₁ ≤ countP p l₂ := s.sublist.countP_le
List.countP_tail_le
theorem
(l) : countP p l.tail ≤ countP p l
theorem countP_tail_le (l) : countP p l.tail ≤ countP p l :=
(tail_sublist l).countP_le
List.countP_filter
theorem
{l : List α} : countP p (filter q l) = countP (fun a => p a && q a) l
theorem countP_filter {l : List α} :
countP p (filter q l) = countP (fun a => p a && q a) l := by
simp only [countP_eq_length_filter, filter_filter]
List.countP_true
theorem
: (countP fun (_ : α) => true) = length
@[simp] theorem countP_true : (countP fun (_ : α) => true) = length := by
funext l
simp
List.countP_false
theorem
: (countP fun (_ : α) => false) = Function.const _ 0
@[simp] theorem countP_false : (countP fun (_ : α) => false) = Function.const _ 0 := by
funext l
simp
List.countP_map
theorem
{p : β → Bool} {f : α → β} : ∀ {l}, countP p (map f l) = countP (p ∘ f) l
@[simp] theorem countP_map {p : β → Bool} {f : α → β} :
∀ {l}, countP p (map f l) = countP (p ∘ f) l
| [] => rfl
| a :: l => by rw [map_cons, countP_cons, countP_cons, countP_map]; rfl
List.length_filterMap_eq_countP
theorem
{f : α → Option β} {l : List α} : (filterMap f l).length = countP (fun a => (f a).isSome) l
theorem length_filterMap_eq_countP {f : α → Option β} {l : List α} :
(filterMap f l).length = countP (fun a => (f a).isSome) l := by
induction l with
| nil => rfl
| cons x l ih =>
simp only [filterMap_cons, countP_cons]
split <;> simp [ih, *]
List.countP_filterMap
theorem
{p : β → Bool} {f : α → Option β} {l : List α} :
countP p (filterMap f l) = countP (fun a => ((f a).map p).getD false) l
theorem countP_filterMap {p : β → Bool} {f : α → Option β} {l : List α} :
countP p (filterMap f l) = countP (fun a => ((f a).map p).getD false) l := by
simp only [countP_eq_length_filter, filter_filterMap, ← filterMap_eq_filter]
simp only [length_filterMap_eq_countP]
congr
ext a
simp +contextual [Option.getD_eq_iff, Option.isSome_eq_isSome]
List.countP_flatten
theorem
{l : List (List α)} : countP p l.flatten = (l.map (countP p)).sum
@[simp] theorem countP_flatten {l : List (List α)} :
countP p l.flatten = (l.map (countP p)).sum := by
simp only [countP_eq_length_filter, filter_flatten]
simp [countP_eq_length_filter']
List.countP_join
abbrev
@[deprecated countP_flatten (since := "2024-10-14")] abbrev countP_join := @countP_flatten
List.countP_flatMap
theorem
{p : β → Bool} {l : List α} {f : α → List β} : countP p (l.flatMap f) = sum (map (countP p ∘ f) l)
theorem countP_flatMap {p : β → Bool} {l : List α} {f : α → List β} :
countP p (l.flatMap f) = sum (map (countPcountP p ∘ f) l) := by
rw [List.flatMap, countP_flatten, map_map]
List.countP_reverse
theorem
{l : List α} : countP p l.reverse = countP p l
@[simp] theorem countP_reverse {l : List α} : countP p l.reverse = countP p l := by
simp [countP_eq_length_filter, filter_reverse]
List.countP_mono_left
theorem
(h : ∀ x ∈ l, p x → q x) : countP p l ≤ countP q l
theorem countP_mono_left (h : ∀ x ∈ l, p x → q x) : countP p l ≤ countP q l := by
induction l with
| nil => apply Nat.le_refl
| cons a l ihl =>
rw [forall_mem_cons] at h
have ⟨ha, hl⟩ := h
simp [countP_cons]
cases h : p a
· simp only [Bool.false_eq_true, ↓reduceIte, Nat.add_zero]
apply Nat.le_trans ?_ (Nat.le_add_right _ _)
apply ihl hl
· simp only [↓reduceIte, ha h, succ_le_succ_iff]
apply ihl hl
List.countP_congr
theorem
(h : ∀ x ∈ l, p x ↔ q x) : countP p l = countP q l
theorem countP_congr (h : ∀ x ∈ l, p x ↔ q x) : countP p l = countP q l :=
Nat.le_antisymm
(countP_mono_left fun x hx => (h x hx).1)
(countP_mono_left fun x hx => (h x hx).2)
List.count_nil
theorem
{a : α} : count a [] = 0
List.count_cons
theorem
{a b : α} {l : List α} : count a (b :: l) = count a l + if b == a then 1 else 0
theorem count_cons {a b : α} {l : List α} :
count a (b :: l) = count a l + if b == a then 1 else 0 := by
simp [count, countP_cons]
List.count_eq_countP
theorem
{a : α} {l : List α} : count a l = countP (· == a) l
theorem count_eq_countP {a : α} {l : List α} : count a l = countP (· == a) l := rfl
List.count_eq_countP'
theorem
{a : α} : count a = countP (· == a)
theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
funext l
apply count_eq_countP
List.count_tail
theorem
: ∀ {l : List α} (h : l ≠ []) (a : α), l.tail.count a = l.count a - if l.head h == a then 1 else 0
theorem count_tail : ∀ {l : List α} (h : l ≠ []) (a : α),
l.tail.count a = l.count a - if l.head h == a then 1 else 0
| _ :: _, a, _ => by simp [count_cons]
List.count_le_length
theorem
{a : α} {l : List α} : count a l ≤ l.length
theorem count_le_length {a : α} {l : List α} : count a l ≤ l.length := countP_le_length
List.Sublist.count_le
theorem
(a : α) (h : l₁ <+ l₂) : count a l₁ ≤ count a l₂
theorem Sublist.count_le (a : α) (h : l₁ <+ l₂) : count a l₁ ≤ count a l₂ := h.countP_le
List.IsPrefix.count_le
theorem
(a : α) (h : l₁ <+: l₂) : count a l₁ ≤ count a l₂
List.IsSuffix.count_le
theorem
(a : α) (h : l₁ <:+ l₂) : count a l₁ ≤ count a l₂
List.IsInfix.count_le
theorem
(a : α) (h : l₁ <:+: l₂) : count a l₁ ≤ count a l₂
theorem IsInfix.count_le (a : α) (h : l₁ <:+: l₂) : count a l₁ ≤ count a l₂ := h.sublist.count_le a
List.count_tail_le
theorem
{a : α} {l : List α} : count a l.tail ≤ count a l
theorem count_tail_le {a : α} {l : List α} : count a l.tail ≤ count a l :=
(tail_sublist l).count_le a
List.count_le_count_cons
theorem
{a b : α} {l : List α} : count a l ≤ count a (b :: l)
theorem count_le_count_cons {a b : α} {l : List α} : count a l ≤ count a (b :: l) :=
(sublist_cons_self _ _).count_le a
List.count_singleton
theorem
{a b : α} : count a [b] = if b == a then 1 else 0
theorem count_singleton {a b : α} : count a [b] = if b == a then 1 else 0 := by
simp [count_cons]
List.count_append
theorem
{a : α} {l₁ l₂ : List α} : count a (l₁ ++ l₂) = count a l₁ + count a l₂
@[simp] theorem count_append {a : α} {l₁ l₂ : List α} : count a (l₁ ++ l₂) = count a l₁ + count a l₂ :=
countP_append
List.count_flatten
theorem
{a : α} {l : List (List α)} : count a l.flatten = (l.map (count a)).sum
theorem count_flatten {a : α} {l : List (List α)} : count a l.flatten = (l.map (count a)).sum := by
simp only [count_eq_countP, countP_flatten, count_eq_countP']
List.count_join
abbrev
@[deprecated count_flatten (since := "2024-10-14")] abbrev count_join := @count_flatten
List.count_reverse
theorem
{a : α} {l : List α} : count a l.reverse = count a l
@[simp] theorem count_reverse {a : α} {l : List α} : count a l.reverse = count a l := by
simp only [count_eq_countP, countP_eq_length_filter, filter_reverse, length_reverse]
List.boole_getElem_le_count
theorem
{a : α} {l : List α} {i : Nat} (h : i < l.length) : (if l[i] == a then 1 else 0) ≤ l.count a
theorem boole_getElem_le_count {a : α} {l : List α} {i : Nat} (h : i < l.length) :
(if l[i] == a then 1 else 0) ≤ l.count a := by
rw [count_eq_countP]
apply boole_getElem_le_countP (p := (· == a))
List.count_cons_self
theorem
{a : α} {l : List α} : count a (a :: l) = count a l + 1
@[simp] theorem count_cons_self {a : α} {l : List α} : count a (a :: l) = count a l + 1 := by
simp [count_cons]
List.count_cons_of_ne
theorem
(h : b ≠ a) {l : List α} : count a (b :: l) = count a l
@[simp] theorem count_cons_of_ne (h : b ≠ a) {l : List α} : count a (b :: l) = count a l := by
simp [count_cons, h]
List.count_singleton_self
theorem
{a : α} : count a [a] = 1
theorem count_singleton_self {a : α} : count a [a] = 1 := by simp
List.count_concat_self
theorem
{a : α} {l : List α} : count a (concat l a) = count a l + 1
theorem count_concat_self {a : α} {l : List α} : count a (concat l a) = count a l + 1 := by simp
List.count_pos_iff
theorem
{a : α} {l : List α} : 0 < count a l ↔ a ∈ l
@[simp]
theorem count_pos_iff {a : α} {l : List α} : 0 < count a l ↔ a ∈ l := by
simp only [count, countP_pos_iff, beq_iff_eq, exists_eq_right]
List.count_pos_iff_mem
abbrev
@[deprecated count_pos_iff (since := "2024-09-09")] abbrev count_pos_iff_mem := @count_pos_iff
List.one_le_count_iff
theorem
{a : α} {l : List α} : 1 ≤ count a l ↔ a ∈ l
@[simp] theorem one_le_count_iff {a : α} {l : List α} : 1 ≤ count a l ↔ a ∈ l :=
count_pos_iff
List.count_eq_zero_of_not_mem
theorem
{a : α} {l : List α} (h : a ∉ l) : count a l = 0
theorem count_eq_zero_of_not_mem {a : α} {l : List α} (h : a ∉ l) : count a l = 0 :=
Decidable.byContradiction fun h' => h <| count_pos_iff.1 (Nat.pos_of_ne_zero h')
List.not_mem_of_count_eq_zero
theorem
{a : α} {l : List α} (h : count a l = 0) : a ∉ l
theorem not_mem_of_count_eq_zero {a : α} {l : List α} (h : count a l = 0) : a ∉ l :=
fun h' => Nat.ne_of_lt (count_pos_iff.2 h') h.symm
List.count_eq_zero
theorem
{l : List α} : count a l = 0 ↔ a ∉ l
theorem count_eq_zero {l : List α} : countcount a l = 0 ↔ a ∉ l :=
⟨not_mem_of_count_eq_zero, count_eq_zero_of_not_mem⟩
List.count_eq_length
theorem
{l : List α} : count a l = l.length ↔ ∀ b ∈ l, a = b
theorem count_eq_length {l : List α} : countcount a l = l.length ↔ ∀ b ∈ l, a = b := by
rw [count, countP_eq_length]
refine ⟨fun h b hb => Eq.symm ?_, fun h b hb => ?_⟩
· simpa using h b hb
· rw [h b hb, beq_self_eq_true]
List.count_replicate_self
theorem
{a : α} {n : Nat} : count a (replicate n a) = n
@[simp] theorem count_replicate_self {a : α} {n : Nat} : count a (replicate n a) = n :=
(count_eq_length.2 <| fun _ h => (eq_of_mem_replicate h).symm).trans (length_replicate ..)
List.count_replicate
theorem
{a b : α} {n : Nat} : count a (replicate n b) = if b == a then n else 0
theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b == a then n else 0 := by
split <;> (rename_i h; simp only [beq_iff_eq] at h)
· exact ‹b = a› ▸ count_replicate_self ..
· exact count_eq_zero.2 <| mt eq_of_mem_replicate (Ne.symm h)
List.filter_beq
theorem
{l : List α} (a : α) : l.filter (· == a) = replicate (count a l) a
theorem filter_beq {l : List α} (a : α) : l.filter (· == a) = replicate (count a l) a := by
simp only [count, countP_eq_length_filter, eq_replicate_iff, mem_filter, beq_iff_eq]
exact ⟨trivial, fun _ h => h.2⟩
List.filter_eq
theorem
{α} [DecidableEq α] {l : List α} (a : α) : l.filter (· = a) = replicate (count a l) a
theorem filter_eq {α} [DecidableEq α] {l : List α} (a : α) : l.filter (· = a) = replicate (count a l) a :=
filter_beq a
List.le_count_iff_replicate_sublist
theorem
{l : List α} : n ≤ count a l ↔ replicate n a <+ l
theorem le_count_iff_replicate_sublist {l : List α} : n ≤ count a l ↔ replicate n a <+ l := by
refine ⟨fun h => ?_, fun h => ?_⟩
· exact ((replicate_sublist_replicate a).2 h).trans <| filter_beq a ▸ filter_sublist
· simpa only [count_replicate_self] using h.count_le a
List.replicate_count_eq_of_count_eq_length
theorem
{l : List α} (h : count a l = length l) : replicate (count a l) a = l
theorem replicate_count_eq_of_count_eq_length {l : List α} (h : count a l = length l) :
replicate (count a l) a = l :=
(le_count_iff_replicate_sublist.mp (Nat.le_refl _)).eq_of_length <| length_replicate.trans h
List.count_filter
theorem
{l : List α} (h : p a) : count a (filter p l) = count a l
@[simp] theorem count_filter {l : List α} (h : p a) : count a (filter p l) = count a l := by
rw [count, countP_filter]; congr; funext b
simp; rintro rfl; exact h
List.count_le_count_map
theorem
[DecidableEq β] {l : List α} {f : α → β} {x : α} : count x l ≤ count (f x) (map f l)
theorem count_le_count_map [DecidableEq β] {l : List α} {f : α → β} {x : α} :
count x l ≤ count (f x) (map f l) := by
rw [count, count, countP_map]
apply countP_mono_left; simp +contextual
List.count_filterMap
theorem
{α} [BEq β] {b : β} {f : α → Option β} {l : List α} : count b (filterMap f l) = countP (fun a => f a == some b) l
theorem count_filterMap {α} [BEq β] {b : β} {f : α → Option β} {l : List α} :
count b (filterMap f l) = countP (fun a => f a == some b) l := by
rw [count_eq_countP, countP_filterMap]
congr
ext a
obtain _ | b := f a
· simp
· simp
List.count_flatMap
theorem
{α} [BEq β] {l : List α} {f : α → List β} {x : β} : count x (l.flatMap f) = sum (map (count x ∘ f) l)
theorem count_flatMap {α} [BEq β] {l : List α} {f : α → List β} {x : β} :
count x (l.flatMap f) = sum (map (countcount x ∘ f) l) := countP_flatMap
List.count_erase
theorem
{a b : α} : ∀ {l : List α}, count a (l.erase b) = count a l - if b == a then 1 else 0
theorem count_erase {a b : α} :
∀ {l : List α}, count a (l.erase b) = count a l - if b == a then 1 else 0
| [] => by simp
| c :: l => by
rw [erase_cons]
if hc : c = b then
have hc_beq := beq_iff_eq.mpr hc
rw [if_pos hc_beq, hc, count_cons, Nat.add_sub_cancel]
else
have hc_beq := beq_false_of_ne hc
simp only [hc_beq, if_false, count_cons, count_cons, count_erase, reduceCtorEq]
if ha : b = a then
rw [ha, eq_comm] at hc
rw [if_pos (beq_iff_eq.2 ha), if_neg (by simpa using Ne.symm hc), Nat.add_zero, Nat.add_zero]
else
rw [if_neg (by simpa using ha), Nat.sub_zero, Nat.sub_zero]
List.count_erase_self
theorem
{a : α} {l : List α} : count a (List.erase l a) = count a l - 1
@[simp] theorem count_erase_self {a : α} {l : List α} :
count a (List.erase l a) = count a l - 1 := by rw [count_erase, if_pos (by simp)]
List.count_erase_of_ne
theorem
(ab : a ≠ b) {l : List α} : count a (l.erase b) = count a l
@[simp] theorem count_erase_of_ne (ab : a ≠ b) {l : List α} : count a (l.erase b) = count a l := by
rw [count_erase, if_neg (by simpa using ab.symm), Nat.sub_zero]