Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Init/Data/Array/Count.lean
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ theorem size_eq_countP_add_countP {xs : Array α} : xs.size = countP p xs + coun
rcases xs with ⟨xs⟩
simp [List.length_eq_countP_add_countP (p := p)]

@[grind =]
theorem countP_eq_size_filter {xs : Array α} : countP p xs = (filter p xs).size := by
rcases xs with ⟨xs⟩
simp [List.countP_eq_length_filter]

@[grind =]
grind_pattern countP_eq_size_filter => xs.countP p, xs.filter p

theorem countP_eq_size_filter' : countP p = size ∘ filter p := by
funext xs
apply countP_eq_size_filter
Expand Down
7 changes: 4 additions & 3 deletions src/Init/Data/List/Count.lean
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ section countP

variable {p q : α → Bool}

@[simp] theorem countP_nil : countP p [] = 0 := rfl
@[simp, grind =] theorem countP_nil : countP p [] = 0 := rfl

protected theorem countP_go_eq_add {l} : countP.go p l n = n + countP.go p l 0 := by
induction l generalizing n with
Expand All @@ -47,6 +47,7 @@ protected theorem countP_go_eq_add {l} : countP.go p l n = n + countP.go p l 0 :
@[simp] theorem countP_cons_of_neg {l} (pa : ¬p a) : countP p (a :: l) = countP p l := by
simp [countP, countP.go, pa]

@[grind =]
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]

Expand All @@ -66,7 +67,6 @@ theorem length_eq_countP_add_countP (p : α → Bool) {l : List α} : length l =
· rfl
· simp [h]

@[grind =] -- This to quite aggressive, as it introduces `filter` based reasoning whenever we see `countP`.
theorem countP_eq_length_filter {l : List α} : countP p l = (filter p l).length := by
induction l with
| nil => rfl
Expand All @@ -75,7 +75,8 @@ theorem countP_eq_length_filter {l : List α} : countP p l = (filter p l).length
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]

@[grind =]
grind_pattern countP_eq_length_filter => l.countP p, l.filter p

theorem countP_eq_length_filter' : countP p = length ∘ filter p := by
funext l
apply countP_eq_length_filter
Expand Down
3 changes: 2 additions & 1 deletion tests/lean/run/grind_11081.lean
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,6 @@ theorem countP_diff (hl : Subperm l₂ l₁) (p : α → Bool) :
List.Perm.subperm_left,
List.Sublist.subperm,
List.Subperm.perm_of_length_le,
List.Perm.countP_congr
List.Perm.countP_congr,
List.countP_eq_length_filter
]
20 changes: 9 additions & 11 deletions tests/lean/run/grind_list_count.lean
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ theorem countP_eq_length_filter' : countP p = length ∘ filter p := by
grind

theorem countP_le_length : countP p l ≤ l.length := by
grind
induction l with grind

theorem countP_append {l₁ l₂ : List α} : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by
grind
Expand All @@ -44,11 +44,11 @@ theorem countP_eq_zero {p} : countP p l = 0 ↔ ∀ a ∈ l, ¬p a := by
induction l with grind

theorem countP_eq_length {p} : countP p l = l.length ↔ ∀ a ∈ l, p a := by
induction l with grind
induction l with grind [countP_eq_length_filter]

theorem countP_replicate {p : α → Bool} {a : α} {n : Nat} :
countP p (replicate n a) = if p a then n else 0 := by
grind
induction n with grind

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
Expand All @@ -66,11 +66,9 @@ theorem countP_tail_le (l) : countP p l.tail ≤ countP p l := by grind

-- See `Init.Data.List.Nat.Count` for `le_countP_tail : countP p l - 1 ≤ countP p l.tail`.

-- TODO Should we have `@[grind]` for `filter_filter`?

theorem countP_filter {l : List α} :
countP p (filter q l) = countP (fun a => p a && q a) l := by
grind [List.filter_filter]
induction l with grind

theorem countP_true : (countP fun (_ : α) => true) = length := by
funext l
Expand All @@ -81,23 +79,23 @@ theorem countP_false : (countP fun (_ : α) => false) = Function.const _ 0 := by
induction l with grind

theorem countP_map {p : β → Bool} {f : α → β} {l} : countP p (map f l) = countP (p ∘ f) l := by
grind
induction l with grind

theorem length_filterMap_eq_countP {f : α → Option β} {l : List α} :
(filterMap f l).length = countP (fun a => (f a).isSome) l := by
induction l with grind -- TODO
induction l with grind

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
induction l with grind -- TODO
induction l with grind

theorem countP_flatten {l : List (List α)} :
countP p l.flatten = (l.map (countP p)).sum := by
grind
induction l with grind

theorem countP_flatMap {p : β → Bool} {l : List α} {f : α → List β} :
countP p (l.flatMap f) = sum (map (countP p ∘ f) l) := by
grind
induction l with grind

theorem countP_reverse {l : List α} : countP p l.reverse = countP p l := by
grind
Expand Down
Loading