Zulip Chat Archive

Stream: general

Topic: finiteness


Scott Morrison (Apr 04 2018 at 06:10):

Do mathlib have something that behaves like:

class  Finite (α : Type u) :=
  (cardinality : nat)
  (bijection : trunc (equiv α (fin cardinality)))

Scott Morrison (Apr 04 2018 at 06:10):

Is this gross for some reason, and should be avoided?

Kenny Lau (Apr 04 2018 at 06:11):

It is in my category theory repo (the category “set”)

Kenny Lau (Apr 04 2018 at 06:11):

and it’s called fintype

Scott Morrison (Apr 04 2018 at 06:12):

It can't be called fintype, because mathlib already has a fintype which is slightly different (but equivalent, of course).

Scott Morrison (Apr 04 2018 at 06:12):

I guess I'm asking if there is a strong reason to (bite the bullet and learn how to use multisets and) use mathlib's fintype, or if it's okay to use something like this.

Kenny Lau (Apr 04 2018 at 06:15):

oops i meant the category is called set and uses fintype

Kenny Lau (Apr 04 2018 at 06:16):

but I guess I didn’t notice that you used trunc

Mario Carneiro (Apr 04 2018 at 06:27):

That's fintype. If you want to use such an interface to it, prove it and use it

Scott Morrison (Apr 04 2018 at 06:28):

Okay, I guess that's a good point. In the meantime I'm discovering fintype is pretty easy to use anyway.

Scott Morrison (Apr 04 2018 at 06:41):

What is the lemma that says fintype gives decidable_eq?

Mario Carneiro (Apr 04 2018 at 06:52):

I don't think it's true. So your formulation is a bit stronger, since it equips the set with a function to fin; in mathlib's fintype, this function is index_of, but it requires a separate proof of decidable_eq

Mario Carneiro (Apr 04 2018 at 06:53):

your Finite should be equivalent to the conjunction of fintype and decidable_eq

Scott Morrison (Apr 04 2018 at 06:53):

ah, okay.

Reid Barton (Aug 06 2020 at 18:29):

Is there any way we could get to a world in which

def finite {a : Type} (s : set a) : Prop := -- any definition of finiteness

structure finset (a : Type) :=
(s : set a)
(h : finite s)

class fintype (a : Type) : Prop :=
(h : finite (set.univ : set a))

Reid Barton (Aug 06 2020 at 18:51):

cons: all big_operators stuff becomes noncomputable
pros: API becomes comprehensible by humans, and no more instance diamonds for fintype

Sebastien Gouezel (Aug 06 2020 at 18:55):

(I also dream of a world where decidablewould disappear, but I know this won't happen)

Mario Carneiro (Aug 06 2020 at 18:58):

Up to proof irrelevance propositional equivalence, none of these definitions are different except you replaced fintype A with nonempty (fintype A). Maybe we should just have a class for that, replacing set.finite

Bhavik Mehta (Aug 06 2020 at 19:01):

actually do we lose anything by just changing fintype to the nonempty version of what it currently is? fintype.univ becomes noncomputable but it fixes the instance diamonds

Mario Carneiro (Aug 06 2020 at 19:01):

fintype.card also becomes noncomputable

Reid Barton (Aug 06 2020 at 19:04):

My bigger issue is that I find it really difficult to find what I'm looking for in data.finset/data.fintype/data.set.finite; it's possible this could be improved without any representation changes

Reid Barton (Aug 06 2020 at 19:06):

But a related issue is that there are three different ways to express the same ideas and they are connected by constructions that are not that simple

Reid Barton (Aug 06 2020 at 19:07):

It's my completely unsubstantiated opinion that if we proved a bunch of things for finite, say, we could systematically deduce the consequences for finset and fintype and end up with a more organized API

Reid Barton (Aug 06 2020 at 19:14):

Here is some pure fantasy: a universe level for only finite types

Jalex Stark (Aug 06 2020 at 19:21):

Type (1/2:\Q)

Kenny Lau (Aug 06 2020 at 23:53):

@Kevin Buzzard

Kevin Buzzard (Aug 07 2020 at 00:50):

We must make finiteness easier for mathematicians. Counting is all over Sylow's theorems and if people can't knock them off in Lean using what we have, then I think we don't have the right things. I recently had two distinct proofs that the trivial subgroup of a group was a fintype and it was annoying.

Kevin Buzzard (Aug 10 2020 at 11:17):

OK I have just spent some time trying to understand the issues here. I'm trying to prove Sylow's theorems with students. Sylow's theorems are theorems about finite groups with no mention of decidable equality or ever explicitly attempting to write down elements -- they apply to all finite groups. Hence it seems to me that computability is irrelevant, so fintype and finset are not the right classes. But set.finite isn't either, because it is unbundled finiteness. Reid is proposing a bundled version of finiteness which he also calls finset but how about for now we call it finset2.

structure finset2 (a : Type u) :=
(s : set a)
(h : finite s)

Is there an argument for developing an API for this? It is bundled noncomputable finiteness which seems to me to be the best for Lean and the best for Sylow. Have I understood things correctly? Are people just going to tell me to go ahead and try?

Kevin Buzzard (Aug 10 2020 at 11:36):

As for cardinality some non-cardinal options would be finset2.card, set.fincard : set X -> nat or fincard : Type u -> nat. These are all functions we don't have, right? @Patrick Massot you were complaining about fintype in another thread and it's got to the point where I just want to fix it. Sylow's theorems are about finite groups and I don't care whether they have decidable equality, I just want to be able to count subsets and not run into diamonds -- this is not an unreasonable request I don't think but perhaps the infrastructure is not yet there for this kind of thing.

Kevin Buzzard (Aug 11 2020 at 18:48):

More thoughts about finiteness and cardinality for sets and types.

Let's start with sets. Now set.finite exists in mathlib already; its definition is

def finite (s : set α) : Prop := nonempty (fintype s)

. It's not a class. Why is set.finite not a class? is_subgroup was a class. Could both set.finite and set.infinite be classes? This would be unbundled finiteness for sets (normal is unbundled Prop-valued normality for subgroups and we tried bundling it in the group theory game but it's quite inconvenient because you either reproduce a bunch of subgroup.* in normal.* or you put to_subgroup everywhere). The definition of bundled finiteness for sets I'm working with is

def finset2 (X : Type u) := {S : set X // finite S}

The idea would be to develop some API for set.finite and encourage mathematicians who don't #eval to either use set.finite or finset2 as their standard concept of finiteness for sets depending on whether they like bundled or unbundled -- and in particular to avoid finset completely because this is constructible finiteness.

For set cardinality the issue is that I don't know whether unbundled or bundled will be best, so I have had to introduce two nat-valued cardinalities -- firstly note that we have

noncomputable def equiv_finset (X : Type*) : finset2 X  (finset X) := ...

and so we can define

noncomputable def finset2.card (F : finset2 X) :  :=
((finset2.equiv_finset X).to_fun F).card

i.e. finset2.card is just finset.card but ported over the canonical bijection. This is cardinality for bundled finite sets. For unbundled finite sets there is the issue of trying to find the finite instance, and experience seems to show that this can be hard work, so I introduce

def sum [add_comm_monoid β] (s : set α) (f : α  β) : β :=
if h : finite s then h.to_finset.sum f else 37

and then define

def set.card (s : set α) :  :=
s.sum (λ x, 1)

These functions are really easy to apply because they don't check finiteness. Under finiteness conditions you can relate the card to finset2.card and this is your route back to finset.card if you want to port API.

Earlier on in my Lean career I was concerned about all this noncomputable stuff because I didn't really know how important computability was. The thing to understand about noncomputable cards is that you can still prove Sylow's theorems which are all about cards, you just can't #eval, and because I never #eval anyway I'm not bothered.


Now onto types. For unbundled finiteness for types I'm using

def is_finite (X : Type u) : Prop := nonempty (fintype X)

attribute [class] is_finite

and again the idea is to encourage non-#eval mathematicians to use is_finite instead of fintype, because using it is strictly easier, modulo the fact that of course a whole load of the fintype library needs to be ported over.

Bundling finite types seems like the sort of thing that the category theory library might want to do, but I'm not doing it right now.

For cardinality again I follow the principle that the fewer inputs your function has, the easier it is to use it, so I have gone for

def fincard (X : Type*) :  :=
if h : is_finite X then @fintype.card X (classical.choice h) else 0

and of course there's a route back to fintype.card in the is_finite setting, which enables noncomputational API (e.g. all theorems) to be ported.

All this work is piling up in the group-theory-game repo because we have got to the point where we want to prove Sylow's theorems. I think it might be sensible to start sending some of it to mathlib. Before I start, does anyone have any comments about the proposal, naming conventions, or anything else? I feel bad adding more definitions of finiteness but I think these are the things we need for reasoning. When I was refactoring subgroups I ran into an issue in the proof of Sylow's theorem where we are proving there are subgroups of order p^n for all n<=v_p(G); the n=0 case used bot and at some point I wanted to rewrite card_bot but unfortunately there are two proofs that the bot subgroup of a finite group is finite in mathlib -- one coming from the fact that it's the trivial group and one coming from the fact that a subset of a finite type is finite. This is just silly -- we don't need these subsingleton diamonds getting in the way when we are reasoning.

Mario Carneiro (Aug 11 2020 at 19:15):

What ever happened to definition irrelevance / API making? Instead of defining finset2, make an api that lets you treat a finset like a finset2

Chris Hughes (Aug 11 2020 at 19:19):

Agree with Mario here, nothing about finset forces you to be constructive.

Mario Carneiro (Aug 11 2020 at 19:20):

I think my definition of finsum is strictly more powerful than your sum too. If you are going to have no well definedness assumptions, you may as well have it give a reasonable result on the widest possible domain

Mario Carneiro (Aug 11 2020 at 19:22):

Oops, it appears this is a thread-spanning topic now. I'm referring to https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/universe.20hell.20in.20linear.20algebra/near/206415746

Kevin Buzzard (Aug 11 2020 at 19:27):

Yeah sorry, I had to choose whether to go with this thread or that one.

Kevin Buzzard (Aug 11 2020 at 19:39):

finsum is fine by me -- I was just using something Jeremy knocked up for MIL. I'm not sure I understand the finset2 thing though. I was 100% sure I used finset2 to make is_finite but I just removed the import and don't use it at all. So should I ditch finset2? I'm not sure I even need it now.

Kevin Buzzard (Aug 11 2020 at 19:40):

So is the point that we just don't define finset2 at all, prove that {S : set X // finite S} ≃ (finset X) and then for every lemma about finsets I prove some analogous lemma for set.finite?

Mario Carneiro (Aug 11 2020 at 19:43):

In what sense is that not already done in mathlib?

Mario Carneiro (Aug 11 2020 at 19:44):

set.finite has lots of lemmas generated exactly that way, and they are all very easy

Mario Carneiro (Aug 11 2020 at 19:44):

so you can add more if something is missing without too much trouble

Kevin Buzzard (Aug 11 2020 at 19:48):

I am confused about why we don't want finset2. What were the problems with is_subgroup which made us switch to subgroup? Were there actually no problems and we just decided that we wanted the cool dot notation?

Reid Barton (Aug 11 2020 at 19:49):

it was a class

Kevin Buzzard (Aug 11 2020 at 20:55):

So set.finite and set.infinite should not be classes? Here's the current definitions (mostly due to other people):

import data.finsupp

universe u

open_locale classical

attribute [class] set.finite set.infinite

noncomputable def finsum {ι α} [add_comm_monoid α] (f : ι  α) : α :=
if h :  f' : ι  α, f = f' then (classical.some h).sum (λ _ a, a) else 0

noncomputable def finsum_in {ι α} [add_comm_monoid α] (s : set ι) (f : ι  α) : α :=
finsum (λ i, if i  s then f i else 0)

localized "notation `∑` binders `, ` r:(scoped:67 f, finsum f) := r" in finsum
localized "notation `∑` binders ` in ` s `, ` r:(scoped:67 f, finsum_in s f) := r" in finsum

noncomputable def set.card {ι} (s : set ι) :=  x in s, 1

def is_finite (X : Type u) : Prop := nonempty (fintype X)

attribute [class] is_finite

noncomputable def fincard (X : Type u) :  :=
if h : is_finite X then @fintype.card X (classical.choice h) else 0

Mario Carneiro (Aug 11 2020 at 20:57):

I think set.card should be defined directly rather than by summing ones, but the definition will be equivalent regardless so it's not that important

Mario Carneiro (Aug 11 2020 at 20:57):

set.card s := fincard (\u s) for example

Mario Carneiro (Aug 11 2020 at 20:58):

also set.finite can be refactored on top of is_finite

Mario Carneiro (Aug 11 2020 at 20:59):

As for making is_finite a class, I think it will work okay, but it will be about as good as fintype for what it does

Mario Carneiro (Aug 11 2020 at 21:00):

In particular, AFAICT all the gripes about fintype are eliminated if it is excised from definitions such as fincard

Kevin Buzzard (Aug 11 2020 at 21:01):

wait -- are you telling me that the def of fincard should be rethought?

Mario Carneiro (Aug 11 2020 at 21:02):

no, I'm saying that it solves the bulk of the problems on its own

Mario Carneiro (Aug 11 2020 at 21:03):

As long as the fintype instance doesn't occur in the statement of theorems using finiteness, it should be fine to appear as a hypothesis

Mario Carneiro (Aug 11 2020 at 21:03):

so perhaps the is_finite class isn't so important

Kevin Buzzard (Aug 11 2020 at 21:04):

This is not just navel-gazing for its own sake -- I'm trying to use finiteness to prove results in group theory. The idea of decreeing that "we will only take sizes of sets" or "...of types" sounded appealing to me, but I've seen explicit examples today where you really have to move between sets and types.

Mario Carneiro (Aug 11 2020 at 21:04):

I'm still not convinced that you can't just use fintype (\u s) for talking about sets in a world of classes on types

Mario Carneiro (Aug 11 2020 at 21:05):

The main use of is_finite is not as a class but as a hypothesis, a proposition to be used however you use propositions

Kevin Buzzard (Aug 11 2020 at 21:05):

How are you proposing saying things like "if p is a partition of the finite type X then the sum of the sizes of the blocks of p equals the size of X"?

Mario Carneiro (Aug 11 2020 at 21:06):

theorem foo [fintype X] : ... fincard X

Kevin Buzzard (Aug 11 2020 at 21:07):

But you need to count all the subsets too

Kevin Buzzard (Aug 11 2020 at 21:07):

you have a set of subsets -- you don't really want to convert all of these to types, do you?

Mario Carneiro (Aug 11 2020 at 21:07):

finsum (\lam p, fincard p) = fincard X

Mario Carneiro (Aug 11 2020 at 21:07):

it's fine, let coercion do its magic

Kevin Buzzard (Aug 11 2020 at 21:09):

In practice I was using is_finite in the fincard proofs because most of them are case splits on whether something is finite or not. So it was very convenient to have is_finite as a class because i could just dump it into the inference system and then not worry about it. But I guess that given that I had it, I could just feed it into the theorems I need rather than doing the resetI dance

Kevin Buzzard (Aug 11 2020 at 21:11):

Amusing thing: when doing some set lemmas I realised I was constantly splitting on whether something was finite or infinite, and they were both classes, so I proved that every set was finite or infinite and then was doing cases; resetI. I then joked that I should just be doing casesI so I wrote it for a joke and then it turned out that it existed :P

Mario Carneiro (Aug 11 2020 at 21:12):

def partition (X : Type*) := {P : set (set X) //  x, ∃! p, p  P  x  p}

theorem partition_sum {X} [fintype X] (P : partition X) :
  finsum_in P.1 (λ p, fincard p) = fincard X := sorry

easy peasy

Mario Carneiro (Aug 11 2020 at 21:12):

(I won't prove it right now because fincard et al don't have an API yet)

Kevin Buzzard (Aug 11 2020 at 21:12):

that's a bad theorem, it uses the forbidden fintype

Mario Carneiro (Aug 11 2020 at 21:13):

No, the fintype does not appear in the statement of the theorem, so you can just get it from wherever you like

Mario Carneiro (Aug 11 2020 at 21:13):

you won't have unification problems as a result

Kevin Buzzard (Aug 11 2020 at 21:13):

Oh I see. But you should prove this for is_finite because it's more general

Mario Carneiro (Aug 11 2020 at 21:14):

it's (constructively, even) equivalent

Kevin Buzzard (Aug 11 2020 at 21:15):

then you should prove it for is_finite because fintype is deprecated?

Mario Carneiro (Aug 11 2020 at 21:15):

the idea with this proposal is that you use fintype for your typeclass needs and reserve is_finite as a regular hypothesis that you can pop open when you want to teach the typeclass system

Kevin Buzzard (Aug 11 2020 at 21:16):

I thought I never wanted to use fintype ever again?

Mario Carneiro (Aug 11 2020 at 21:16):

It already has all the "structural" instances you want

Mario Carneiro (Aug 11 2020 at 21:17):

the bad thing about fintype is that because it is a Type, you can get into unification issues like patrick mentioned at the start of the other thread

Mario Carneiro (Aug 11 2020 at 21:17):

but as long as you use fincard instead of fintype.card that problem goes away

Reid Barton (Aug 12 2020 at 18:52):

Kevin Buzzard said:

I then joked that I should just be doing casesI so I wrote it for a joke and then it turned out that it existed :P

on a related note, I just discovered fconstructor

Kevin Buzzard (Aug 13 2020 at 16:41):

Jason wanted to make an API for finsum (which was defined by Mario to be)

noncomputable def finsum {ι α} [add_comm_monoid α] (f : ι  α) : α :=
if h :  f' : ι  α, f = f' then (classical.some h).sum (λ _ a, a) else 0

and he realised that what he wanted was to prove that it equalled finset.sum. This would be easier if we used the following definition:

noncomputable def finsum2 {ι α} [add_comm_monoid α] (f : ι  α) : α :=
if h : (function.support f).finite then  x in h.to_finset, f x else 0

Are there disadvantages to finsum2 @Mario Carneiro ?

Mario Carneiro (Aug 13 2020 at 17:23):

which one has less imports?

Mario Carneiro (Aug 13 2020 at 17:23):

Either way you want to prove both definitions are the same

Kevin Buzzard (Aug 13 2020 at 17:24):

import data.finsupp data.support

noncomputable theory

open_locale classical big_operators

noncomputable def finsum {ι α} [add_comm_monoid α] (f : ι  α) : α :=
if h :  f' : ι  α, f = f' then (classical.some h).sum (λ _ a, a) else 0

noncomputable def finsum2 {ι α} [add_comm_monoid α] (f : ι  α) : α :=
if h : (function.support f).finite then  x in h.to_finset, f x else 0

theorem finsum_eq_finsum2 {ι α} [add_comm_monoid α] (f : ι  α) : finsum f = finsum2 f :=
begin
  unfold finsum,
  unfold finsum2,
  split_ifs with h1 h2 h3,
  { unfold finsupp.sum,
    congr',
    { ext x,
      rw finsupp.mem_support_iff,
      rw (classical.some_spec h1).symm,
      rw set.finite.mem_to_finset,
      refl },
    { exact (classical.some_spec h1).symm } },
  { exfalso,
    apply h2,
    clear h2,
    rcases h1 with h1, rfl,
    exact h1.finite_supp },
  { exfalso,
    apply h1,
    clear h1,
    let f' : ι  α :=
    { support := h3.to_finset,
      to_fun := f,
      mem_support_to_fun := begin
        intro i,
        simp only [function.mem_support, set.finite.mem_to_finset],
      end },
    use f',
    refl },
  { refl }
end .

Mario Carneiro (Aug 13 2020 at 17:26):

what is finiteness.is_finite?

Mario Carneiro (Aug 13 2020 at 17:30):

wow, I thought function.support would have an easy definition but the file that defines it has a ton of imports

Kenny Lau (Aug 13 2020 at 17:38):

I thought we stopped caring about the import hierarchy 37 days ago

Yury G. Kudryashov (Aug 13 2020 at 19:35):

This file has many imports because it was added after these imports

Yury G. Kudryashov (Aug 13 2020 at 19:36):

It's easy to remove all imports if you move lemmas to other files

Kevin Buzzard (Aug 13 2020 at 20:34):

Another insight from Chris at Xena this evening; how about this:

def finset.univ' (ι : Type*) : finset ι := if h : nonempty (fintype ι) then
  (classical.choice h).elems else 

def fincard' (X : Type u) :  := finset.card $ finset.univ' X

@Mario Carneiro you had suggested

def fincard (X : Type*) :  :=
if h : nonempty (fintype X) then @fintype.card X (classical.choice h) else 0

-- does this variant meet with your approval?

Mario Carneiro (Aug 13 2020 at 21:07):

ha, clever

Kenny Lau (Aug 13 2020 at 21:07):

@Kevin Buzzard @Mario Carneiro I would go as far as saying that the finset.univ in mathlib should be replaced with your new finset.univ' etc.

Mario Carneiro (Aug 13 2020 at 21:07):

that finset.univ' could be useful for many things

Kenny Lau (Aug 13 2020 at 21:07):

(etc. = the same for other definitions depending directly on fintype)

Kevin Buzzard (Aug 16 2020 at 14:33):

OK so @Jason KY. and I have been hacking away on this stuff, and we ran into something which presumably has been run into before. Recall we've been talking about these definitions (either will do for me but the finset one is easier to port with):

noncomputable def finsum {ι α} [add_comm_monoid α] (f : ι  α) : α :=
if h :  f' : ι  α, f = f' then (classical.some h).sum (λ _ a, a) else 0

noncomputable def finsum2 {ι α} [add_comm_monoid α] (f : ι  α) : α :=
if h : (function.support f).finite then  x in h.to_finset, f x else 0

Jason pointed out that we should probably do products too -- but then we run into the following issue: finsupp and support both want a zero. Is there an analogous construction in Lean which does either of these things but with a 1?

Kevin Buzzard (Aug 16 2020 at 14:38):

We can make one_support or whatever -- function.one_support f is the things which don't get mapped to one -- but then to_additive will turn this into zero_support. Presumably we can work around this? But do we want one_support at all?

Reid Barton (Aug 22 2020 at 17:18):

Kevin Buzzard said:

so I proved that every set was finite or infinite and then was doing cases; resetI. I then joked that I should just be doing casesI so I wrote it for a joke and then it turned out that it existed :P

I also just learned you can use it instead of unfreezing local instances.

Yury G. Kudryashov (Aug 22 2020 at 18:09):

We can define set.to_finset using the same trick, then finset.univ = univ.to_finset, fincard = finset.univ.card

Kevin Buzzard (Aug 22 2020 at 18:39):

There's a fincard branch of mathlib by the way.

Adam Topaz (Oct 06 2020 at 13:58):

Reid Barton said:

Is there any way we could get to a world in which

def finite {a : Type} (s : set a) : Prop := -- any definition of finiteness

structure finset (a : Type) :=
(s : set a)
(h : finite s)

class fintype (a : Type) : Prop :=
(h : finite (set.univ : set a))

I hereby sign this petition.

Patrick Massot (Oct 06 2020 at 14:03):

I sign any petition that could make finiteness manageable.

Johan Commelin (Oct 06 2020 at 14:10):

Reid Barton said:

It's my completely unsubstantiated opinion that if we proved a bunch of things for finite, say, we could systematically deduce the consequences for finset and fintype and end up with a more organized API

What would this systematic deduction look like? It should be possible to do that with current definitions, right?

I think the only design choice that is not trivial upto Prop-eq is whether fintype is Type or Prop valued.

Johan Commelin (Oct 06 2020 at 14:10):

Otoh, I do wish quite often that we had

def finite (s : set α) : Prop :=  t : finset α, s = t
-- instead of
def finite (s : set α) : Prop := nonempty (fintype s)

Johan Commelin (Oct 06 2020 at 14:11):

@Reid Barton If you want to start with set.finite instead of finset, I guess

def finite' {α : Type*} (s : set α) : Prop :=
 l : list α,  x, x  l  x  s

would be an obvious way to start.

Johan Commelin (Oct 06 2020 at 14:12):

But it's not yet clear to me how set.finite and finset would become much easier to handle than with what we have now. (Not saying the current setup is easy.)

Adam Topaz (Oct 06 2020 at 14:13):

Johan Commelin said:

Reid Barton If you want to start with set.finite instead of finset, I guess

def finite' {α : Type*} (s : set α) : Prop :=
 l : list α,  x, x  l  x  s

would be an obvious way to start.

You don't even need an if and only if, only that l surjects onto s.

Adam Topaz (Oct 06 2020 at 14:15):

def finite' {α : Type*} (s : set α) : Prop :=
 l : list α,  x, x  s  x  l

Adam Topaz (Oct 06 2020 at 14:17):

This makes it easier to prove that the intersection / union of two finite sets are finite.

Reid Barton (Oct 06 2020 at 14:25):

It really doesn't matter how you define finite. The right place to start would be constant finite : set \a -> Prop. At some point you'll have collected a bunch of proof obligations like finite_union, finite_fin, ... and then you can think about what definition would be best to prove them all.
A more important question might be whether finite or fintype should be the primitive one, with the other one defined in terms of it. But I think it doesn't matter too much.

Johan Commelin (Oct 06 2020 at 14:27):

Currently finset is the primitive one. Is that bad?

Adam Topaz (Oct 06 2020 at 14:29):

Oh? Why isn't set.finite defined as "there exists a finset such that..."?

Reid Barton (Oct 06 2020 at 14:29):

Johan Commelin said:

But it's not yet clear to me how set.finite and finset would become much easier to handle than with what we have now. (Not saying the current setup is easy.)

One advantage is everything just becomes more straightforward.

  • If you have (s : set T) (h : finite s), you don't need to go hunt down finite.to_finset. You can just write ⟨s, h⟩.
  • More importantly, when you extract the underlying set of this finset, it's now defeq to what you started with.
  • That means if we define all the has_mem, has_union etc. on finset using the corresponding set definition on the first component, then everything becomes defeq. You don't even really need to prove a theorem like (s t : finset α) : s ⊆ s ∪ t because you can just apply the set version. All lemmas about bounded quantification over set also apply to bounded quantification over finset, etc.

Reid Barton (Oct 06 2020 at 14:30):

(The other, more substantial advantage is that all the decidable_eq stuff disappears, but that comes with tradeoffs.)

Reid Barton (Oct 06 2020 at 14:33):

I think the current definition of finset probably comes from Coq or something but it doesn't fit the mathematician's idea of a finite set, which is first and foremost a set, that happens to be finite.

Reid Barton (Oct 06 2020 at 14:34):

Actually, we could probably achieve much of these "everything becomes more straightforward" advantages just by changing the definition of finsetto have an underlying set field, without simultaneously making things classical.

Johan Commelin (Oct 06 2020 at 14:39):

So it would have a set field and a multiset and a proof that they are "equal"?

Johan Commelin (Oct 06 2020 at 14:40):

But I guess that breaks the "everything is straightforward" part of the multiset-finset interface

Johan Commelin (Oct 06 2020 at 14:40):

Not saying that's a dealbreaker

Reid Barton (Oct 06 2020 at 14:42):

I guess if you wanted to do the constructive version of this then you would consider s : set together with a "finiteness structure" on s, which would be some kind of subsingleton (e.g. trunc (\Sigma n, s \~- fin n))

Reid Barton (Oct 06 2020 at 14:45):

But yeah, you could also do what you suggested.

Reid Barton (Oct 06 2020 at 14:46):

But I'd rather go completely classical. I'm just worried about what the story is going to be for computing, say, finset.sum over a singleton.

Reid Barton (Oct 06 2020 at 14:50):

As far as I can tell, effectively the only purpose of this decidable_eq stuff in finset/fintype is so that finset.sum+relatives will reduce on things like empty sets and singletons (is that it? I thought about finset.insert too but finset.sum_insert doesn't seem to be true by rfl actually).

Mario Carneiro (Oct 06 2020 at 15:28):

To my mind, the reason finset has a separate name is because it's not just the same as a finite set. If you want a finite set you can say that - a set that is finite

Reid Barton (Oct 06 2020 at 15:29):

But in that case we should port all the finset.sum, finset.min etc stuff to set + finite where it would be used

Mario Carneiro (Oct 06 2020 at 15:30):

Well yes, I thought we had made plans about that as well (c.f. finsum)

Mario Carneiro (Oct 06 2020 at 15:31):

In particular I think that in most cases you can leave off the finiteness assumptions in the definitions

Reid Barton (Oct 06 2020 at 15:32):

I still really hate this style.

Mario Carneiro (Oct 06 2020 at 15:32):

I don't think that partial functions does anyone any favors

Mario Carneiro (Oct 06 2020 at 15:33):

particularly when they get involved in stating structures and things, and you need to write proofs inline

Reid Barton (Oct 06 2020 at 15:37):

I don't understand how the proposed changes (change argument of sum from finset to set and pass finiteness assumptions to lemmas) won't make long calc manipulations of sums a lot messier.

Reid Barton (Oct 06 2020 at 15:38):

Particularly when the indexing set of the sum is changing through the calculation

Mario Carneiro (Oct 06 2020 at 15:42):

If each index set is "structurally" finite, then we can use a typeclass on set.finite to discharge it

Reid Barton (Oct 06 2020 at 15:42):

Oh boy you might have found something I hate even more :upside_down:

Mario Carneiro (Oct 06 2020 at 15:43):

importantly, we won't have to worry about carrying the original finiteness proof through all the manipulations and getting a mismatch when a new proof also applies

Mario Carneiro (Oct 06 2020 at 15:44):

Then again, in a case like this it seems like finset might be more your cup of tea. So why the use of sets?

Reid Barton (Oct 06 2020 at 15:46):

Well, for example, because I have a set R which is definable in an o-minimal structure and so I know either it's finite or contains an interval. If it's finite I want to take the smallest element (I also know it's nonempty), if it contains an interval I want to do something else.

Reid Barton (Oct 06 2020 at 15:48):

Currently I think what I do is: if it's finite then I use set.finite.to_finset to get a finset, then take the min of that, and then I need to do a bit of arguing to show how it relates to my original set.

Mario Carneiro (Oct 06 2020 at 15:48):

simp?

Reid Barton (Oct 06 2020 at 15:54):

I don't remember exactly what I had to do, but it was effort that served no apparent real purpose.

Reid Barton (Oct 06 2020 at 15:55):

In this case it was just a local let inside a proof, so simp wouldn't be too bad, but if it was an auxiliary top-level definition, then the "no partial functions" style is really annoying because the proof of finiteness now becomes a second top-level thing that you have to pass around as well

Mario Carneiro (Oct 06 2020 at 16:01):

I mean you could use {s // finite s} in some of these applications, but I don't know about giving this type the full mathlib treatment because it is isomorphic to finset and the API is the same

Reid Barton (Oct 06 2020 at 16:02):

Replacing finset with this is exactly what I want to do, and I don't agree that the API is the same.

Mario Carneiro (Oct 06 2020 at 16:03):

the functions are the same, the lemmas are the same

Mario Carneiro (Oct 06 2020 at 16:03):

don't come to me about defeq

Mario Carneiro (Oct 06 2020 at 16:04):

For <s, h> I'd rather see that as a lean limitation that we can't customize the function that this invokes

Reid Barton (Oct 06 2020 at 16:05):

Well this is very frustrating. All I can say is that I find finset consistently more difficult to deal with than the set equivalent. For a long time I thought it was just me, but finally I realized that it doesn't have to be this way.

Mario Carneiro (Oct 06 2020 at 16:10):

If you really want to do it, the API would have to be at least as large as finset.lean. Half baked APIs make me sad

Reid Barton (Oct 06 2020 at 16:11):

Of course, my intention was to replace finset entirely

Reid Barton (Oct 06 2020 at 16:11):

so that's why I'm more interested in the question: what will break?

Mario Carneiro (Oct 06 2020 at 16:11):

But I don't see that as an option, because finset has its place as a nodups multiset

Mario Carneiro (Oct 06 2020 at 16:12):

Perhaps that's a niche thing, but it's distinct

Mario Carneiro (Oct 06 2020 at 16:12):

we can change the name if it makes it easier

Mario Carneiro (Oct 06 2020 at 16:13):

As I said: the API is the same, so nothing should break, in particular if fintype remains based on the old finset

Mario Carneiro (Oct 06 2020 at 16:13):

fintype instances need to compute

Mario Carneiro (Oct 06 2020 at 16:14):

and they are occasionally defeq-forced, so replacing them with something noncomputable isn't going to fly

Reid Barton (Oct 06 2020 at 16:15):

Ideally fintype would become a proposition as well, and where something computational is really needed, we would use fin_enum. However I'm not sure how important this is.

Mario Carneiro (Oct 06 2020 at 16:16):

That seems reasonable; the fact that fintype instances lose the order is occasionally problematic

Mario Carneiro (Oct 06 2020 at 16:18):

so what would be the typeclass for finiteness of sets? would you reuse fintype (\u s) or would set.finite s be a class?

Reid Barton (Oct 06 2020 at 16:21):

I wasn't intending to change the status quo in terms of having finite as an unbundled predicate and finset as a bundled structure for set, and fintype as a class for types... it seems fairly reasonable to me

Reid Barton (Oct 06 2020 at 16:24):

in particular finiteness of sets is often non-structural, e.g., if s ⊆ t and t is finite then s is finite... I guess the same thing can happen with an injective map of types but maybe it's less important there?

Mario Carneiro (Oct 06 2020 at 16:25):

I mean would the type in instances be [fintype (\u s)] : fintype (\u (s \cap t)) or [set.finite s] : set.finite (s \cap t)

Johan Commelin (Oct 06 2020 at 16:25):

I think injective maps are important enough to please let set.finite not be a class.

Mario Carneiro (Oct 06 2020 at 16:26):

both would work I think, the second one requires set.finite to be a class which has occasional consequences for freezing which are sometimes undesirable for a proposition

Reid Barton (Oct 06 2020 at 16:26):

I see, I think the first one is okay. But now I also realize I think I haven't had so much experience with fintype directly.

Reid Barton (Oct 06 2020 at 16:28):

If you want fintype on \u of some set though then it makes sense to have structural instances for this that are parallel to finite.union, ... I guess.

Mario Carneiro (Oct 06 2020 at 16:29):

but now maybe we're losing the whole {s // finite s} thing this way

Reid Barton (Oct 06 2020 at 16:29):

I'm not sure what these instances would bottom out to though

Mario Carneiro (Oct 06 2020 at 16:30):

I would still prefer that finite s be defined as it is now, in terms of old finset

Reid Barton (Oct 06 2020 at 16:31):

Like why would you have any instance of fintype (\u s) in the first place (aside from if s : set t where fintype t)

Mario Carneiro (Oct 06 2020 at 16:31):

you might have finite s and haveI a fintype (\u s) instance

Mario Carneiro (Oct 06 2020 at 16:31):

maybe that's too much trouble?

Mario Carneiro (Oct 06 2020 at 16:34):

Working with finite sets in this way is probably always going to be a little brittle. It's easy to misplace the finiteness proofs

Mario Carneiro (Oct 06 2020 at 16:35):

I have always found it very easy to work with finset as currently defined because of its robust API, but that's only when dealing with them as finsets and not necessarily when interfacing with sets

Mario Carneiro (Oct 06 2020 at 16:37):

aagh I hate defeq

Reid Barton (Oct 06 2020 at 16:39):

I think finite would end up sort of like is_subgroup in that (besides maybe being used to implement finset) it ends up getting used mainly to mediate between the set world and the finset world

Reid Barton (Oct 06 2020 at 16:39):

like in the definable set example I gave before, where you have a set and then later you acquire the information that it's finite

Mario Carneiro (Oct 06 2020 at 16:42):

I mean you can do all that with the current API

Mario Carneiro (Oct 06 2020 at 16:42):

I'm sorry the function that does it has a name

Reid Barton (Oct 06 2020 at 16:43):

right, and you end up with 100-character long simp onlys instead of nothing

Mario Carneiro (Oct 06 2020 at 16:43):

nothing, he says

Reid Barton (Oct 06 2020 at 16:44):

I guess I don't understand the apparent opposition. Like is it a problem that (x, y).fst is defeq to x? Should we have only a propositional equality?

Reid Barton (Oct 06 2020 at 16:45):

Why would it be unreasonable to think "finite set" = subtype set.finite?

Mario Carneiro (Oct 06 2020 at 16:45):

I really hate this aspect of lean, that it makes one look so much worse than the other even though they are about the same complexity

Mario Carneiro (Oct 06 2020 at 16:46):

If defeq wasn't a thing then they would be the same, and you could set up the "refl"-equivalent tactic to work with whatever you say

Mario Carneiro (Oct 06 2020 at 16:46):

in lean that tool is simp but it does just a bit too much

Reid Barton (Oct 06 2020 at 16:47):

Right, I agree that this whole conversation is somehow an artifact of DTT

Mario Carneiro (Oct 06 2020 at 16:49):

Is there a way we can fix this with more notation?

Mario Carneiro (Oct 06 2020 at 16:50):

like make the constructor easier to call, and add a custom simp set to make the simp only more palatable

Mario Carneiro (Oct 06 2020 at 16:51):

I think if we start bending over backwards to make all the defeqs work out we will lose, because it is impossible to please everyone

Mario Carneiro (Oct 06 2020 at 16:52):

all equalities should be defeqs

Reid Barton (Oct 06 2020 at 16:56):

Already Johan's suggestion of adding "... and a set, such that it's equal to the multiset" would be an improvement. Then all the lemmas that say that union commutes with taking the underlying sets get baked into the definitions of those operations.

Reid Barton (Oct 06 2020 at 17:07):

But since (independently of this issue) it's also quite annoying to deal with finset.inter and so on having these decidable_eq instances which may or may not be coherent, and considering that in the end, it's unclear how much working constructively really buys us, it seems to me that doing things classically would be better anyways. And at that point just using subtype set.finite seems like a welcome simplification.

Kyle Miller (Oct 06 2020 at 17:55):

I wonder if this might be a good setup. It lets you reuse all the fintype machinery, so it might make fleshing out the interface easier.

import data.fintype.basic

structure new_finset (α : Type*) :=
(to_set : set α)
(finite : fintype to_set)

def set.to_new_finset {α : Type*} (s : set α) [fintype s] : new_finset α :=
new_finset.mk s (by apply_instance)

instance {α : Type*} : has_coe (new_finset α) (set α) :=
new_finset.to_set

@[simp]
lemma new_finset.coe {α : Type*} (s : new_finset α) : s.to_set = s := rfl

instance new_finset.fintype {α : Type*} (s : new_finset α) : fintype s :=
s.finite

Kyle Miller (Oct 06 2020 at 17:56):

The current finset would still exist somewhere but with a new name.

Kyle Miller (Oct 06 2020 at 18:00):

You also get a fairly nice new_finset.univ:

def new_finset.univ {α : Type*} [fintype α] : new_finset α :=
{ to_set := set.univ,
  finite := by apply_instance }

Adam Topaz (Oct 06 2020 at 18:02):

Wouldn't this get annoying because you would have to deal with the coercion from the set to the associated subtype?

Kyle Miller (Oct 06 2020 at 18:10):

If you want to go between set and finset you already have to use set.to_finset and finset's lift to set.

But something that would likely be a problem is that there are non-defeq fintype instances... so I retract this proposal. (Maybe it'd be ok with nonempty (fintype to_set).)

Kyle Miller (Sep 05 2021 at 21:21):

Reviving this thread, I'm wondering whether there's a reason the first definition was chosen over the second:

def set.finite (s : set α) : Prop := nonempty (fintype s)
-- versus
def set.finite (s : set α) : Prop :=  (t : finset α), s = t

Kyle Miller (Sep 05 2021 at 21:23):

Also, in case it changes the calculus of including a noncomputable finset, docs#set_like would be a way to implement one with a little less boilerplate (but still, it would be an undertaking to do it this way):

import tactic

universes u

structure finset' (α : Type u) :=
(s : set α)
(finite' :  (t : finset α), s = t)

namespace finset'
variables {α : Type u}

instance : set_like (finset' α) α :=
finset'.s, λ p q h, by { cases p, cases q, congr' }⟩

@[simp] lemma mem_coe {s : finset' α} {x : α} : x  s.s  x  (s : set α) := iff.rfl

@[ext] theorem ext {s t : finset' α} (h :  x, x  s  x  t) : s = t := set_like.ext h

/-- Copy of a `finset'` with a new `s` equal to the old one. Useful to fix definitional
equalities. See See Note [range copy pattern]. -/
protected def copy (s : finset' α) (t : set α) (hs : t = s) : finset' α :=
{ s := t,
  finite' := hs.symm  s.finite' }

lemma finite (s : finset' α) :  (t : finset α), (s : set α) = (t : set α) := s.finite'

noncomputable instance : has_coe (finset' α) (finset α) := λ s, s.finite.some

@[simp] lemma coe_set_finset (s : finset' α) : ((s : finset α) : set α) = s :=
s.finite.some_spec.symm

noncomputable instance (s : finset' α) : fintype s :=
(set.finite_mem_finset (s : finset α)).fintype

end finset'

Last updated: Dec 20 2023 at 11:08 UTC