Zulip Chat Archive
Stream: general
Topic: Filter keys of a Finmap?
Qiancheng Fu (May 27 2025 at 08:54):
Using Mathlib4, is there a good way to filter the entries of Finmap? I also want to prove that the result of the filtered map is equal to another maps under certain choice of predicate....
Basically something like the following:
M : Finmap fun (x : Nat) -> Nat
M.filter (fun x => 0 <= x) = M
I tried getting the underlying list of map M, performing the filter then turning it back into a finmap. However, I don't know how to prove anything after doing so......
Kenny Lau (May 27 2025 at 09:30):
@Qiancheng Fu I tried to make it but there's a sorry that I'm stuck on, but this should be what you need:
import Mathlib
set_option diagnostics true
def Finmap.filter {α : Type*} {β : α → Type*} (f : Finmap β)
(p : α → Prop) [DecidablePred p] : Finmap β where
entries := f.entries.filter (fun xy => p xy.1)
nodupKeys := sorry
theorem foo (M : Finmap fun (x : Nat) ↦ Nat) : M.filter (fun x => 0 ≤ x) = M := by
apply Finmap.ext
rw [Finmap.filter, Multiset.filter_eq_self]
· intros; exact Nat.zero_le _
Qiancheng Fu (May 27 2025 at 17:31):
Thanks! Unfortunately, the real thing that I want to be able to prove is a bit more complicated....
def Finmap.filter {α : Type*} {β : α → Type*} (f : Finmap β)
(p : Sigma β → Prop) [DecidablePred p] : Finmap β where
entries := f.entries.filter p
nodupKeys := sorry
def Finmap.lookup_filter {α : Type*} {β : α → Type*} [DecidableEq α]
(f : Finmap β) (p : Sigma β → Prop) [DecidablePred p] {l b} :
f.lookup l = some b -> p ⟨l, b⟩ -> (Finmap.filter f p).lookup l = b := by
sorry
Basically I want to say that if some entry exists that satisfies a predicate p, then this entry is still present after filtering using p.
The quotient around the underlying lists is frying my brain.....
Kenny Lau (May 27 2025 at 19:26):
@Qiancheng Fu there's no need to use underlying quotients (or underlying anything) if you have what we call an "API"
import Mathlib
def Finmap.filter {α : Type*} {β : α → Type*} (f : Finmap β)
(p : Sigma β → Prop) [DecidablePred p] : Finmap β where
entries := f.entries.filter p
nodupKeys := sorry
def Finmap.lookup_filter {α : Type*} {β : α → Type*} [DecidableEq α]
(f : Finmap β) (p : Sigma β → Prop) [DecidablePred p] {l : α} {b : β l}
(h1 : f.lookup l = some b) (h2 : p ⟨l, b⟩) : (Finmap.filter f p).lookup l = b :=
lookup_eq_some_iff.2 <| Multiset.mem_filter_of_mem (lookup_eq_some_iff.1 h1) h2
Kenny Lau (May 27 2025 at 19:27):
the philosophy here is that the "API" is the set of defining and characteristic properties where everything else can be derived from
Qiancheng Fu (May 27 2025 at 19:36):
Thank you so much! I'm gonna try to digest your answer. I find it quite hard to prove stuff when there's things that the api doesnt expose directly (i.e. filter).
Kenny Lau (May 27 2025 at 19:47):
@Qiancheng Fu this is the API of Multiset.filter: @loogle Multiset.filter
loogle (May 27 2025 at 19:47):
:search: Multiset.filter, Multiset.Nodup.filter, and 76 more
Robin Arnez (May 28 2025 at 12:27):
Just going to note that Std.ExtDHashMap is a good alternative that has filter:
example {α : Type*} {β : α → Type*} [DecidableEq α] [Hashable α]
(f : Std.ExtDHashMap α β) (p : (a : α) → β a → Bool) {l : α} {b : β l}
(h1 : f.get? l = some b) (h2 : p l b) : (f.filter p).get? l = some b := by
simp_all
Robin Arnez (May 28 2025 at 12:29):
Oh and
example (M : Std.ExtHashMap Nat Nat) : M.filter (fun x _ => 0 <= x) = M := by
ext; simp [Std.ExtHashMap.getElem?_filter]
Qiancheng Fu (May 28 2025 at 14:02):
@Robin Arnez That’s pretty slick. Exactly what I was looking for in a finite map data structure.
Last updated: Dec 20 2025 at 21:32 UTC