This PR adds grind annotations for `List.Perm`; involves a revision of grind annotations for `List.countP/count` as well.
259 lines
9.2 KiB
Text
259 lines
9.2 KiB
Text
/-
|
||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Kim Morrison
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
import all Init.Data.Array.Count
|
||
import all Init.Data.Vector.Basic
|
||
import Init.Data.Vector.Lemmas
|
||
|
||
/-!
|
||
# Lemmas about `Vector.countP` and `Vector.count`.
|
||
-/
|
||
|
||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||
|
||
namespace Vector
|
||
|
||
open Nat
|
||
|
||
/-! ### countP -/
|
||
section countP
|
||
|
||
variable {p q : α → Bool}
|
||
|
||
@[simp] theorem countP_empty : countP p #v[] = 0 := rfl
|
||
|
||
@[simp] theorem countP_push_of_pos {xs : Vector α n} (pa : p a) : countP p (xs.push a) = countP p xs + 1 := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp_all
|
||
|
||
@[simp] theorem countP_push_of_neg {xs : Vector α n} (pa : ¬p a) : countP p (xs.push a) = countP p xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp_all
|
||
|
||
theorem countP_push {a : α} {xs : Vector α n} : countP p (xs.push a) = countP p xs + if p a then 1 else 0 := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.countP_push]
|
||
|
||
@[grind =]
|
||
theorem countP_singleton {a : α} : countP p #v[a] = if p a then 1 else 0 := by
|
||
simp
|
||
|
||
theorem size_eq_countP_add_countP {xs : Vector α n} : n = countP p xs + countP (fun a => ¬p a) xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.size_eq_countP_add_countP (p := p)]
|
||
|
||
theorem countP_le_size {xs : Vector α n} : countP p xs ≤ n := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.countP_le_size (p := p)]
|
||
|
||
@[simp, grind =] theorem countP_append {xs : Vector α n} {ys : Vector α m} : countP p (xs ++ ys) = countP p xs + countP p ys := by
|
||
cases xs
|
||
cases ys
|
||
simp
|
||
|
||
@[simp] theorem countP_pos_iff {p} : 0 < countP p xs ↔ ∃ a ∈ xs, p a := by
|
||
cases xs
|
||
simp
|
||
|
||
@[simp] theorem one_le_countP_iff {p} : 1 ≤ countP p xs ↔ ∃ a ∈ xs, p a :=
|
||
countP_pos_iff
|
||
|
||
@[simp] theorem countP_eq_zero {p} : countP p xs = 0 ↔ ∀ a ∈ xs, ¬p a := by
|
||
cases xs
|
||
simp
|
||
|
||
@[simp] theorem countP_eq_size {p} {xs : Vector α n} : countP p xs = n ↔ ∀ a ∈ xs, p a := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp
|
||
|
||
@[simp] theorem countP_cast (p : α → Bool) (xs : Vector α n) : countP p (xs.cast h) = countP p xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp
|
||
|
||
theorem countP_replicate {a : α} {n : Nat} : countP p (replicate n a) = if p a then n else 0 := by
|
||
simp only [replicate_eq_mk_replicate, countP_cast, countP_mk]
|
||
simp [Array.countP_replicate]
|
||
|
||
@[deprecated countP_replicate (since := "2025-03-18")]
|
||
abbrev countP_mkVector := @countP_replicate
|
||
|
||
theorem boole_getElem_le_countP {p : α → Bool} {xs : Vector α n} (h : i < n) :
|
||
(if p xs[i] then 1 else 0) ≤ xs.countP p := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.boole_getElem_le_countP]
|
||
|
||
theorem countP_set {p : α → Bool} {xs : Vector α n} {a : α} (h : i < n) :
|
||
(xs.set i a).countP p = xs.countP p - (if p xs[i] then 1 else 0) + (if p a then 1 else 0) := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.countP_set, h]
|
||
|
||
@[simp] theorem countP_true : (countP fun (_ : α) => true) = (fun (_ : Vector α n) => n) := by
|
||
funext xs
|
||
rw [countP]
|
||
simp only [Array.countP_true, xs.2]
|
||
|
||
@[simp] theorem countP_false : (countP fun (_ : α) => false) = (fun (_ : Vector α n) => 0) := by
|
||
funext xs
|
||
simp
|
||
|
||
@[simp] theorem countP_map {p : β → Bool} {f : α → β} {xs : Vector α n} :
|
||
countP p (map f xs) = countP (p ∘ f) xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp
|
||
|
||
@[simp] theorem countP_flatten {xss : Vector (Vector α m) n} :
|
||
countP p xss.flatten = (xss.map (countP p)).sum := by
|
||
rcases xss with ⟨xss, rfl⟩
|
||
simp [Function.comp_def]
|
||
|
||
theorem countP_flatMap {p : β → Bool} {xs : Vector α n} {f : α → Vector β m} :
|
||
countP p (xs.flatMap f) = (map (countP p ∘ f) xs).sum := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.countP_flatMap, Function.comp_def]
|
||
|
||
@[simp, grind =] theorem countP_reverse {xs : Vector α n} : countP p xs.reverse = countP p xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp
|
||
|
||
theorem countP_mono_left (h : ∀ x ∈ xs, p x → q x) : countP p xs ≤ countP q xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simpa using Array.countP_mono_left (by simpa using h)
|
||
|
||
theorem countP_congr (h : ∀ x ∈ xs, p x ↔ q x) : countP p xs = countP q xs :=
|
||
Nat.le_antisymm
|
||
(countP_mono_left fun x hx => (h x hx).1)
|
||
(countP_mono_left fun x hx => (h x hx).2)
|
||
|
||
end countP
|
||
|
||
/-! ### count -/
|
||
section count
|
||
|
||
variable [BEq α]
|
||
|
||
@[simp, grind =] theorem count_empty {a : α} : count a #v[] = 0 := rfl
|
||
|
||
theorem count_push {a b : α} {xs : Vector α n} :
|
||
count a (xs.push b) = count a xs + if b == a then 1 else 0 := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_push]
|
||
|
||
theorem count_eq_countP {a : α} {xs : Vector α n} : count a xs = countP (· == a) xs := rfl
|
||
|
||
theorem count_eq_countP' {a : α} : count (n := n) a = countP (· == a) := by
|
||
funext xs
|
||
apply count_eq_countP
|
||
|
||
theorem count_le_size {a : α} {xs : Vector α n} : count a xs ≤ n := countP_le_size
|
||
|
||
grind_pattern count_le_size => count a xs
|
||
|
||
theorem count_le_count_push {a b : α} {xs : Vector α n} : count a xs ≤ count a (xs.push b) := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_push]
|
||
|
||
@[simp, grind =] theorem count_singleton {a b : α} : count a #v[b] = if b == a then 1 else 0 := by
|
||
simp [count_eq_countP]
|
||
|
||
@[simp, grind =] theorem count_append {a : α} {xs : Vector α n} {ys : Vector α m} :
|
||
count a (xs ++ ys) = count a xs + count a ys :=
|
||
countP_append ..
|
||
|
||
@[simp, grind =] theorem count_flatten {a : α} {xss : Vector (Vector α m) n} :
|
||
count a xss.flatten = (xss.map (count a)).sum := by
|
||
rcases xss with ⟨xss, rfl⟩
|
||
simp [Array.count_flatten, Function.comp_def]
|
||
|
||
@[simp, grind =] theorem count_reverse {a : α} {xs : Vector α n} : count a xs.reverse = count a xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp
|
||
|
||
theorem boole_getElem_le_count {a : α} {xs : Vector α n} (h : i < n) :
|
||
(if xs[i] == a then 1 else 0) ≤ xs.count a := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.boole_getElem_le_count, h]
|
||
|
||
theorem count_set {a b : α} {xs : Vector α n} (h : i < n) :
|
||
(xs.set i a).count b = xs.count b - (if xs[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_set, h]
|
||
|
||
@[simp] theorem count_cast {xs : Vector α n} : (xs.cast h).count a = xs.count a := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp
|
||
|
||
variable [LawfulBEq α]
|
||
|
||
@[simp] theorem count_push_self {a : α} {xs : Vector α n} : count a (xs.push a) = count a xs + 1 := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_push_self]
|
||
|
||
@[simp] theorem count_push_of_ne {xs : Vector α n} (h : b ≠ a) : count a (xs.push b) = count a xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_push_of_ne, h]
|
||
|
||
theorem count_singleton_self {a : α} : count a #v[a] = 1 := by simp
|
||
|
||
@[simp]
|
||
theorem count_pos_iff {a : α} {xs : Vector α n} : 0 < count a xs ↔ a ∈ xs := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_pos_iff, beq_iff_eq, exists_eq_right]
|
||
|
||
@[simp] theorem one_le_count_iff {a : α} {xs : Vector α n} : 1 ≤ count a xs ↔ a ∈ xs :=
|
||
count_pos_iff
|
||
|
||
theorem count_eq_zero_of_not_mem {a : α} {xs : Vector α n} (h : a ∉ xs) : count a xs = 0 :=
|
||
Decidable.byContradiction fun h' => h <| count_pos_iff.1 (Nat.pos_of_ne_zero h')
|
||
|
||
theorem not_mem_of_count_eq_zero {a : α} {xs : Vector α n} (h : count a xs = 0) : a ∉ xs :=
|
||
fun h' => Nat.ne_of_lt (count_pos_iff.2 h') h.symm
|
||
|
||
theorem count_eq_zero {xs : Vector α n} : count a xs = 0 ↔ a ∉ xs :=
|
||
⟨not_mem_of_count_eq_zero, count_eq_zero_of_not_mem⟩
|
||
|
||
theorem count_eq_size {xs : Vector α n} : count a xs = n ↔ ∀ b ∈ xs, a = b := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_eq_size]
|
||
|
||
@[simp] theorem count_replicate_self {a : α} {n : Nat} : count a (replicate n a) = n := by
|
||
simp only [replicate_eq_mk_replicate, count_cast, count_mk]
|
||
simp
|
||
|
||
@[deprecated count_replicate_self (since := "2025-03-18")]
|
||
abbrev count_mkVector_self := @count_replicate_self
|
||
|
||
theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b == a then n else 0 := by
|
||
simp only [replicate_eq_mk_replicate, count_cast, count_mk]
|
||
simp [Array.count_replicate]
|
||
|
||
@[deprecated count_replicate (since := "2025-03-18")]
|
||
abbrev count_mkVector := @count_replicate
|
||
|
||
theorem count_le_count_map [BEq β] [LawfulBEq β] {xs : Vector α n} {f : α → β} {x : α} :
|
||
count x xs ≤ count (f x) (map f xs) := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_le_count_map]
|
||
|
||
theorem count_flatMap {α} [BEq β] {xs : Vector α n} {f : α → Vector β m} {x : β} :
|
||
count x (xs.flatMap f) = (map (count x ∘ f) xs).sum := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.count_flatMap, Function.comp_def]
|
||
|
||
theorem countP_replace {a b : α} {xs : Vector α n} {p : α → Bool} :
|
||
(xs.replace a b).countP p =
|
||
if xs.contains a then xs.countP p + (if p b then 1 else 0) - (if p a then 1 else 0) else xs.countP p := by
|
||
rcases xs with ⟨xs, rfl⟩
|
||
simp [Array.countP_replace]
|
||
|
||
theorem count_replace {a b c : α} {xs : Vector α n} :
|
||
(xs.replace a b).count c =
|
||
if xs.contains a then xs.count c + (if b == c then 1 else 0) - (if a == c then 1 else 0) else xs.count c := by
|
||
simp [count_eq_countP, countP_replace]
|
||
|
||
end count
|