Zulip Chat Archive
Stream: new members
Topic: Why Finset?
Jakub Nowak (Nov 14 2025 at 15:21):
In mathlib some theorems use Set, and some Finset. This sometimes leads to having to convert back-and-froth, or having to duplicate code for both Set and Finset. Wouldn't it be easier to use s : Set α with some s.Fin assumption (note that docs#Set.Finite is not the same as docs#Finset, because the latter also holds its elements as data)?
Kenny Lau (Nov 14 2025 at 15:29):
@Jakub Nowak do you have more context?
Shreyas Srinivas (Nov 14 2025 at 15:29):
There was Marcin's question from before, but it keeps happening all the time
Shreyas Srinivas (Nov 14 2025 at 15:29):
Finset is computable
Shreyas Srinivas (Nov 14 2025 at 15:30):
It requires its type to have an instance of DecidableEq
Shreyas Srinivas (Nov 14 2025 at 15:30):
Finite doesn't
Jakub Nowak (Nov 14 2025 at 15:35):
Yes, the point is docs#Set.Fin would also be computable. Smth like:
structure Set.Fin (s : Set α) where
finset : Finset α
eq : s = finset
Mirek Olšák (Nov 14 2025 at 15:36):
I agree that it is annoying when there are multiple ways to express the same idea, then one view supports well one part of reasoning, the other one another, etc. but I don't have a good solution.
Dexin Zhang (Nov 14 2025 at 15:36):
One thing I found that Finset has but Set.Finite does not is docs#Finset.strongInduction, which is indeed useful sometimes
Jakub Nowak (Nov 14 2025 at 15:38):
Kenny Lau said:
Jakub Nowak do you have more context?
I decided to ask because of that question: #new members > Hello & graph coloring exercises
But I agree with @Shreyas Srinivas, it's not the first time I had to deal with this.
Shreyas Srinivas (Nov 14 2025 at 15:38):
Fin is computable, but you can't say anything about computability of elements inside a Finite Set
Shreyas Srinivas (Nov 14 2025 at 15:39):
Note that I am not saying this justifies the Finset approach. I tend to use either Finite or Set.encard when required
Snir Broshi (Nov 14 2025 at 15:40):
Shreyas Srinivas said:
Finis computable, but you can't say anything about computability of elements inside aFinite Set
But what about the structure suggestion above?
Mirek Olšák (Nov 14 2025 at 15:41):
I would not blame computability here, most notably, Finset is like Set bundled together with its Finite, so we don't have to carry the assumption along. When using Finsets for example, we get automatically that intersections / unions / filters / images of finsets are still finite without doing any extra reasoning. Regarding computability, Fintype / Finite is the mysterious pair.
Jakub Nowak (Nov 14 2025 at 15:42):
Dexin Zhang said:
One thing I found that
Finsethas butSet.Finitedoes not is docs#Finset.strongInduction, which is indeed useful sometimes
We could have:
def Set.finStrongInduction {α : Type u_1} {p : (s : Set α) → s.Fin → Sort u_4} (H : (s : Set α) → s.Fin → ((t : Set α) → t ⊂ s → p t) → p s) (s : Set α) → (h : s.Fin) :
p s h
Though maybe, you also need t.Fin? Not sure t.Fin follows from s.Fin and t ⊂ s.
Eric Wieser (Nov 14 2025 at 16:04):
Jakub Nowak said:
Yes, the point is docs#Set.Fin would also be computable. Smth like:
structure Set.Fin (s : Set α) where finset : Finset α eq : s = finset
I think this becomes a question about bundled or unbundled data, rather than computability
Jakub Nowak (Nov 14 2025 at 16:07):
Eric Wieser said:
I think this becomes a question about bundled or unbundled data, rather than computability
Both Finset and Set.fin have bundled data. The point of the question is not about bundling data. It's about having "finite with bundled data" as a property of Set instead of separate type.
Eric Wieser (Nov 14 2025 at 16:12):
Set.Fin is (partially) unbundled because some of its data is in the type parameters
Jakub Nowak (Nov 14 2025 at 16:16):
Ah, yes, you're right. But I don't think that's the point of the question? Can you elaborate?
Jakub Nowak (Nov 14 2025 at 16:20):
My proposition is to:
- deprecate Finset
- for every instance where the are two definitions/theorems for both Set and Finset version, you would only keep Set version and add a separate theorems stating, the finiteness is preserved
- replace Finset arguments with two arguments
s : Set αands.Fin, possibly skipping some of thes.Finassumptions if they follow from other - replace Finset in return type with Set, and prove finiteness in a separate theorem
Kevin Buzzard (Nov 14 2025 at 16:27):
I'd vote for that but there will be strong opposition from people who want mathlib to be more constructivecomputable rather than less (sorry -- I don't know the difference)
Jakub Nowak (Nov 14 2025 at 16:33):
This wouldn't make mathlib less constructive, at least not directly. Though, it could be that after deprecation people will miss chances to add the finiteness theorems, when it's possible. We should hope for reviewers to also try and catch that.
Shreyas Srinivas (Nov 14 2025 at 16:35):
If you deprecate Finset you will not be able to define the Fin structure. Secondly the Fin name is already in use to bounded Nat
Andrew Yang (Nov 14 2025 at 16:35):
The right word might be less "computable" and not less "constructive"
e.g. you probably can't have this defeq example : ∑ i ∈ {1, 2, 3}, i = 6 := rfl without finsets.
Jakub Nowak (Nov 14 2025 at 16:37):
Shreyas Srinivas said:
If you deprecate Finset you will not be able to define the Fin structure.
We can just inline its fields.
Shreyas Srinivas said:
Secondly the Fin name is already in use to bounded Nat
I also agree that this name is bad, I'm not saying to use it, it's here just as an example.
Shreyas Srinivas (Nov 14 2025 at 16:40):
I think Finset is a useful structure to have in many cases. I just think we should be able to auto suggest typeclass instances that would make the Finset version of a lemma work with a Set version.
Shreyas Srinivas (Nov 14 2025 at 16:59):
Ideally there ought to be an open FiniteAll that works similar to open Classical but gives finite ness instances to everything that needs it.
Jakub Nowak (Nov 14 2025 at 17:24):
Andrew Yang said:
The right word might be less "computable" and not less "constructive"
e.g. you probably can't have this defeqexample : ∑ i ∈ {1, 2, 3}, i = 6 := rflwithout finsets.
It works with Set.Fin too:
code
Kenny Lau (Nov 14 2025 at 18:06):
I'm a bit wary of this approach of hiding by aesop under a notation
Kenny Lau (Nov 14 2025 at 18:07):
your suggestion is not very different from making Set.Finite a typeclass (with data)
Jakub Nowak (Nov 14 2025 at 18:07):
Kenny Lau said:
I'm a bit wary of this approach of hiding
by aesopunder a notation
I've used by aesop because it was easier. It would be better to implement separate tactic for this. Why do you think it's a problem?
Kenny Lau (Nov 14 2025 at 18:08):
ah right, the other thing is that once it contains data, then extensionality becomes a problem, this is also known as the "diamond"
Jakub Nowak (Nov 14 2025 at 18:09):
Kenny Lau said:
your suggestion is not very different from making
Set.Finitea typeclass (with data)
It's not, but we also have separate Finite and Fintype typeclasses. It's probably reasonable to have separate versions with and without data for set finiteness too.
Kenny Lau (Nov 14 2025 at 18:09):
Jakub Nowak said:
I've used
by aesopbecause it was easier. It would be better to implement separate tactic for this. Why do you think it's a problem?
if you use this notation in a statement, then you're using notation to hide away the fact that the statement uses an expensive tactic. This is not what notations are for.
Jakub Nowak (Nov 14 2025 at 18:10):
(deleted)
Jakub Nowak (Nov 14 2025 at 18:11):
Kenny Lau said:
if you use this notation in a statement, then you're using notation to hide away the fact that the statement uses an expensive tactic. This is not what notations are for.
I don't think it's an expensive tactic if it only proves that {a, b, c, ...} is a finite set by recursion over Insert.insert.
Jakub Nowak (Nov 14 2025 at 18:12):
It's basically the same work that the {a, b, c, ...} : Finset α notation does.
Jakub Nowak (Nov 14 2025 at 18:16):
The way I implemented it above, with aesop, it does way more. By we can write a separate tactic that's less expensive, and does only recursion on Insert.insert, nothing else. Just like {a, b, c, ...} : Finset α notation.
Kenny Lau (Nov 14 2025 at 18:19):
what do you think about using typeclass instead of aesop? and also please really consider the extensionality stuff, it's the same reason why we have Finset.sum_congr.
Shreyas Srinivas (Nov 14 2025 at 18:26):
You don’t need a new typeclass
Shreyas Srinivas (Nov 14 2025 at 18:26):
You just need to mixin Finite and DecidableEq
Kenny Lau (Nov 14 2025 at 18:33):
you won't get ∑ i ∈ {1, 2, 3}, i = 6 := rfl
Jakub Nowak (Nov 14 2025 at 18:34):
By typeclass you mean to use [Set.Fin s], right? One thing I don't like is that we would probably have to now have primed and non-primed version of theorems, one using [Set.Fin s] and one using {Set.Fin s}, e.g.:
def Set.Fin.subset (s₁ s₂ : Set α) [Set.Fin s₂] (sub : s₁ ⊆ s₂) : s₁.Fin := sorry
def Set.Fin.subset' (s₁ s₂ : Set α) {hs₂ : Set.Fin s₂} (sub : s₁ ⊆ s₂) : s₁.Fin := sorry
Unless we only use typeclass just to implement sum notation. But I don't understand why you think typeclass inference is better than custom tactic?
Shreyas Srinivas (Nov 14 2025 at 18:37):
Kenny Lau said:
you won't get
∑ i ∈ {1, 2, 3}, i = 6 := rfl
You’d have to redefine the notation to make is elaborate to a sum over Finvec. But I’d be surprised if that that was hard
Jakub Nowak (Nov 14 2025 at 18:42):
Kenny Lau said:
please really consider the extensionality stuff, it's the same reason why we have
Finset.sum_congr.
Unfortunately I don't exactly understand. But I also never had to use docs#Finset.sum_congr. Would something like this work?
theorem Set.Fin.sum_congr {ι : Type*} {M : Type*} {s₁ s₂ : Set ι} {hs₁ : s₁.Fin} {hs₂ : s₂.Fin} [AddCommMonoid M] {f g : ι → M} (h : s₁ = s₂) :
(∀ x ∈ s₂, f x = g x) → hs₁.sum f = hs₂.sum g
Kenny Lau (Nov 14 2025 at 18:43):
yes
Jakub Nowak (Nov 14 2025 at 18:44):
Although, not sure if that's provable, maybe we will also need (h' : (h ▸ hs₁) = hs₂) assumption.
Kenny Lau (Nov 14 2025 at 18:45):
Jakub Nowak said:
But I don't understand why you think typeclass inference is better than custom tactic?
I don't have a good answer to this question. Probably because typeclass is more predictable than tactics. A tactic could do any thing.
Kenny Lau (Nov 14 2025 at 18:45):
Jakub Nowak said:
Although, not sure if that's provable, maybe we will also need
(h' : (h ▸ hs₁) = hs₂)assumption.
I am 100% sure that it is true (and provable, obviously).
Kenny Lau (Nov 14 2025 at 18:46):
you should also prove that it's extensional, meaning Subsingleton (Set.Fin s) (which also implies your h')
Shreyas Srinivas (Nov 14 2025 at 18:50):
In fact we already have docs#Finvec.sum
Eric Wieser (Nov 14 2025 at 18:59):
That's really an implementation detail for a tactic that hasn't been written
Jakub Nowak (Nov 14 2025 at 19:33):
@Kenny Lau
I've tried proving Set.Fin.sum_congr, though, I encountered some problems, is this the instance of a problem you had in mind, that can often arise with using this approach?
import Mathlib
@[grind cases, grind ext]
structure Set.Fin (s : Set α) where
finset : Finset α
eq : s = finset
theorem Set.Fin.congr (s₁ s₂ : Set α) (h : s₁ = s₂) : s₁.Fin = s₂.Fin := by rw [h]
@[to_additive]
def Set.Fin.prod [CommMonoid M] {s : Set ι} (h : s.Fin) (f : ι → M) : M :=
Finset.prod h.finset f
instance Set.Fin.instSubsingleton (s : Set α) : Subsingleton (s.Fin) where
allEq a b := by
cases a
cases b
simp
simp_all
theorem Set.Fin.sum_congr {ι : Type*} {M : Type*} {s₁ s₂ : Set ι} {hs₁ : s₁.Fin} {hs₂ : s₂.Fin} [AddCommMonoid M] {f g : ι → M} (h : s₁ = s₂) :
(∀ x ∈ s₂, f x = g x) → hs₁.sum f = hs₂.sum g := by
intro h₂
have : hs₁ ≍ hs₂ := (Set.Fin.instSubsingleton s₁).helim (Set.Fin.congr s₁ s₂ h) hs₁ hs₂
sorry -- what now?
Robin Arnez (Nov 14 2025 at 19:53):
cases on an equality is your friend!
import Mathlib
class Set.Fin (s : Set α) where
finset : Finset α
eq : s = finset
@[to_additive]
def Set.Fin.prod [CommMonoid M] (s : Set ι) [h : s.Fin] (f : ι → M) : M :=
Finset.prod h.finset f
instance : Subsingleton (Set.Fin s) where
allEq a b := by
obtain ⟨s, hs⟩ := a
obtain ⟨s', hs'⟩ := b
rw [hs, Finset.coe_inj] at hs'
cases hs'
rfl
theorem Set.Fin.sum_congr {ι : Type*} {M : Type*} {s₁ s₂ : Set ι} {hs₁ : s₁.Fin} [s₂.Fin] [AddCommMonoid M] {f g : ι → M} (h : s₁ = s₂) :
(∀ x ∈ s₂, f x = g x) → Set.Fin.sum s₁ f = Set.Fin.sum s₂ g := by
cases h
cases Subsingleton.allEq hs₁ ‹_›
intro h
simp only [hs₁.eq, SetLike.mem_coe] at h
rw [sum, sum, Finset.sum_congr rfl h]
Last updated: Dec 20 2025 at 21:32 UTC