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.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.

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 finite tactic instead that does what classical does, 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