Zulip Chat Archive
Stream: mathlib4
Topic: Fintype and Finite
Peter Nelson (Mar 28 2025 at 13:42):
@Oliver Nash mentioned in his review for #23399 that mathlib is moving to preferring Finite over Fintype in hypotheses, often accompanied by Nat.card over Fintype.card in statements. I'm a huge fan of this!
One annoyance, though, is that because the actual proof will often involve Fintype and sometimes Fintype.card for subtypes, proofs often open with the multi-line fluff have := Fintype.ofFinite a (for one or more types) as well as classical.
I think a one-line tactic that takes care of this invisibly would be nice. But also, one of the features I remember being touted with lean4 was loops in typeclass search. Could Fintype.ofFinite be an instance?
Kyle Miller (Mar 28 2025 at 13:47):
We definitely don't want Fintype.ofFinite to be a global instance, but inside of proofs you should be able to write have := Fintype.ofFinite rather than doing it per-type.
Peter Nelson (Mar 28 2025 at 13:54):
It looks like that doesn't always work; if you remove the V on line 227 of Acyclic.lean in the above PR, it breaks two lines after. (I unfortunately don't have the time to minimize this right now)
Yury G. Kudryashov (Mar 28 2025 at 14:39):
Kyle Miller said:
We definitely don't want
Fintype.ofFiniteto be a global instance, but inside of proofs you should be able to writehave := Fintype.ofFiniterather than doing it per-type.
I guess, you need at least one have per universe.
Eric Wieser (Mar 28 2025 at 15:35):
Yes, test-case:
import Mathlib
example {α β : Type*} [Finite α] [Finite β] : True := by
have := Fintype.ofFinite.{u_1}
have := Fintype.ofFinite.{u_2}
have : Fintype.card (α × β) = Fintype.card α * Fintype.card β := sorry
trivial
Peter Nelson (Mar 28 2025 at 15:41):
Here is a somewhat minimized example where the type is needed, with just one universe in play.
lemma bar (G : SimpleGraph V) [Fintype G.edgeSet] : G.edgeFinset.card = 5 := sorry
lemma foo {V : Type*} {G : SimpleGraph V} [Finite V] : Nat.card G.edgeSet = 5 := by
have := Fintype.ofFinite V
classical
simpa using bar G
-- succeeds
lemma foo' {V : Type*} {G : SimpleGraph V} [Finite V] : Nat.card G.edgeSet = 5 := by
have := Fintype.ofFinite
classical
simpa using bar G
/- Fails
type mismatch, term
bar G
after simplification has type
Fintype.card ↑G.edgeSet = 5 : Prop
but is expected to have type
Nat.card ↑G.edgeSet = 5 : Prop -/
Eric Wieser (Mar 28 2025 at 15:42):
@loogle Nat.card, Fintype.card
loogle (Mar 28 2025 at 15:42):
:search: Fintype.card_eq_nat_card, Nat.card_eq_fintype_card, and 13 more
Peter Nelson (Mar 28 2025 at 15:43):
I don't understand the point of this loogle.
Eric Wieser (Mar 28 2025 at 15:46):
Sorry, I wanted to check if there was a simp lemma to go from the first to the second
Eric Wieser (Mar 28 2025 at 15:46):
And indeed there is, so its strange that it isn't firing
Peter Nelson (Mar 28 2025 at 15:46):
Yes - and it fires just fine in the proof of foo.
Eric Wieser (Mar 28 2025 at 15:47):
have := Fintype.ofFinite.{u_1} suffices
Peter Nelson (Mar 28 2025 at 16:03):
Would streamlining this kind of thing with a tactic be reasonable? So the tactic invokes classical, then Fintype.ofFinite.{u} for every universe in the context?
Yury G. Kudryashov (Mar 28 2025 at 17:35):
What about universes like max u v + 1?
Kyle Miller (Mar 28 2025 at 17:36):
Maybe we could make a finite tactic instead that does what classical does, but locally adds the instance (with general universe parameter)
Shreyas Srinivas (Mar 28 2025 at 17:38):
what is the cardinality function for Finite?
Peter Nelson (Mar 28 2025 at 17:39):
Nat.card - it takes a junk value of zero for infinite types.
Shreyas Srinivas (Mar 28 2025 at 17:40):
Is there an encard?
Shreyas Srinivas (Mar 28 2025 at 17:40):
I am dealing with finite structures where maximum cardinality of some type being 0 is not very helpful
Peter Nelson (Mar 28 2025 at 17:41):
Yes, in the form of docs#ENat.card and docs#Set.encard
Shreyas Srinivas (Mar 28 2025 at 17:41):
Ah okay. That's very helpful. Thanks
Peter Nelson (Mar 28 2025 at 17:41):
I use it a lot! Also, the new enat_to_nat tactic is wonderful for calculations.
Peter Nelson (Mar 28 2025 at 17:43):
Kyle Miller said:
Maybe we could make a
finitetactic instead that does whatclassicaldoes, but locally adds the instance (with general universe parameter)
If this is technically feasible, that would be great for readability.
Shreyas Srinivas (Mar 28 2025 at 17:44):
For almost all discrete math problems, encard appears to be the natural cardinality function. (for example think graph distance algorithms that initially assign distance infinity to unexplored vertices).
Shreyas Srinivas (Mar 28 2025 at 17:44):
Moving between Finset and Set is much more painful.
Kyle Miller (Mar 28 2025 at 17:46):
If this is technically feasible
Yes, take a look at the definition of the classical tactic. There's very little code. You'd just have to replace the part that has Classical.propDecidable
Peter Nelson (Mar 28 2025 at 17:47):
My matroid repo uses ENat heavily, for exactly this reason.
ENat has a less full API than Nat, and in particular arguments that involve something resembling subtraction are very awkward, but this is made a lot better with enat_to_nat.
Last updated: May 02 2025 at 03:31 UTC