Zulip Chat Archive

Stream: Is there code for X?

Topic: fin (s.card) finset equiv


Wrenna Robson (Jun 30 2022 at 12:35):

Do we already have this? (Should be an MWE.)

namespace finset
open fintype
noncomputable def fin_equiv {α : Type*} (s : finset α) : fin (s.card)  s :=
equiv_of_card_eq ((card_coe s)  card_fin _)
end finset

To be clear, I know about fintype.fin_equiv. But I specifically want fin (s.card) and not fin (fintype.card s). What I want is an injective function from fin (s.card) to s, and this seems the best way to get it.

Wrenna Robson (Jun 30 2022 at 12:38):

Alternatively you could have:

namespace finset
open fintype
noncomputable def equiv_fin {α : Type*} (s : finset α) : s  fin (s.card) :=
equiv_of_card_eq (eq.trans (card_coe s) (card_fin _).symm)
end finset

Violeta Hernández (Jun 30 2022 at 12:50):

Would be nice to have MW imports too

Wrenna Robson (Jun 30 2022 at 12:50):

oh, bother.

Wrenna Robson (Jun 30 2022 at 12:50):

I've just closed my lean, I didn't think I was using any of my imports.

Violeta Hernández (Jun 30 2022 at 12:51):

Doesn't work without imports, so I have to figure out what to import

Violeta Hernández (Jun 30 2022 at 12:51):

Ah, import data.fintype.card does it

Wrenna Robson (Jun 30 2022 at 12:51):

Right, yes.

Violeta Hernández (Jun 30 2022 at 12:53):

This seems alright to me

Violeta Hernández (Jun 30 2022 at 12:53):

I was expecting fintype.card s and s.card to be def-eq, but it doesn't seem to be the case

Wrenna Robson (Jun 30 2022 at 12:54):

Yeah, that's the issue I was running into for why I wanted this for convenience.

Violeta Hernández (Jun 30 2022 at 12:56):

If it doesn't exist already, which it doesn't seem to, then it should totally be PR'd

Wrenna Robson (Jun 30 2022 at 12:56):

Cool - I'm meant to give a presentation in two hours which I haven't written yet so I'm just doing that first. If you feel like it you can PR it in the meantime ;)

Wrenna Robson (Jun 30 2022 at 14:23):

Do you think my fin_equiv or equiv_fin is better? Even though it's fin_equiv I want more, I feel like in a PR finset.equiv_fin to match fintype.equiv_fin would be better.

Wrenna Robson (Jun 30 2022 at 14:24):

You could also have a finset.equiv_of_card_eq, I guess.

Wrenna Robson (Jun 30 2022 at 14:30):

Why isn't fintype.card s and s.card defeq, I wonder.

Violeta Hernández (Jun 30 2022 at 14:30):

I prefer fin_equiv out of the general principle of having a simpler RHS

Wrenna Robson (Jun 30 2022 at 14:31):

Yes, that's how I feel.

Wrenna Robson (Jun 30 2022 at 14:31):

Maybe we should flip fintype.equiv_fin.

Violeta Hernández (Jun 30 2022 at 14:31):

docs#fintype.equiv_fin

Wrenna Robson (Jun 30 2022 at 14:31):

(Which is the corresponding theorem for fintypes.)

Violeta Hernández (Jun 30 2022 at 14:32):

I guess there is one exception to that principle of a simpler RHS: when your lemma is meant to expand an expression rather than simplify it

Violeta Hernández (Jun 30 2022 at 14:32):

I guess you can sort of argue that's happening here?

Wrenna Robson (Jun 30 2022 at 14:32):

Aye. I mean in my context what I want is embeddings from fin blah to the thing... because i'm sort of thinking of this as "labelling things with fin n".

Violeta Hernández (Jun 30 2022 at 14:33):

Surely there's few circumstances when you'll want to turn fin (fintype.card α) into α, but many where you'll want to do the opposite

Violeta Hernández (Jun 30 2022 at 14:33):

So yeah, on second thought, equiv_fin is the better one

Wrenna Robson (Jun 30 2022 at 14:33):

Like what this correspond to, basically, is: "Let s be a finite set of size n. Suppose x_0, x_1, ..., x_(n-1) are the elements of s. Then..."

Wrenna Robson (Jun 30 2022 at 14:34):

And that is implicitly taking fin (card s) to s.

Wrenna Robson (Jun 30 2022 at 14:35):

I mean possibly the answer is "even though it would just be an application of symmetry, have both".

Oliver Nash (Jun 30 2022 at 14:35):

Ages ago, I wanted something like this. I think this was the thread

https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Enumerating.20a.20finite.20subset

Violeta Hernández (Jun 30 2022 at 14:36):

I feel like there's little circumstances where you want names for both sides of an equiv

Wrenna Robson (Jun 30 2022 at 14:36):

Yes.

Violeta Hernández (Jun 30 2022 at 14:37):

Because, unless that equiv is incredibly well-behaved (something like a cast between type synonyms), you lose easy access to a lot of theorems about an equivalence and its inverse

Wrenna Robson (Jun 30 2022 at 14:37):

@Oliver Nash A similar situation to me. It is curious that we have finset.order_iso_of_fin but not the one that doesn't have a requirement for linear_order.

Wrenna Robson (Jun 30 2022 at 14:38):

list.nodup.nth_le_equiv has fin-first

Oliver Nash (Jun 30 2022 at 14:39):

Indeed. I’m afraid I’m on a phone on plane at the moment so I can’t say much but I do recall that I persuaded myself that I didn’t really want what I thought I wanted.

Wrenna Robson (Jun 30 2022 at 14:39):

Unfortunately I do want such an embedding, having tried my best to avoid it.

Violeta Hernández (Jun 30 2022 at 14:39):

Wrenna Robson said:

Oliver Nash A similar situation to me. It is curious that we have finset.order_iso_of_fin but not the one that doesn't have a requirement for linear_order.

I feel like most people's mental model of an ordered relation is a partial order, or sometimes just a linear order haha

Violeta Hernández (Jun 30 2022 at 14:40):

That would explain the odd missing generalizations you find now and then

Wrenna Robson (Jun 30 2022 at 14:40):

Well ideally you don't want an order at all.

Wrenna Robson (Jun 30 2022 at 14:40):

Like there is in some sense an order induced

Wrenna Robson (Jun 30 2022 at 14:41):

But it is arbitrary, or at least should be.

Wrenna Robson (Jun 30 2022 at 14:41):

Sometimes you want to choose it though

Kyle Miller (Jun 30 2022 at 15:09):

@Wrenna Robson A bit shorter:

noncomputable def equiv_fin {α : Type*} (s : finset α) : s  fin (s.card) :=
fintype.equiv_fin_of_card_eq (fintype.card_coe _)

Kyle Miller (Jun 30 2022 at 15:12):

Wrenna Robson said:

Why isn't fintype.card s and s.card defeq, I wonder.

That's a good question. I'm not sure if it can be made to be defeq -- to make a fintype instance you need a finset that enumerates all the elements of s coerced to a type, and currently it uses s.attach to do so:

example {α : Type*} (s : finset α) : fintype.card s = s.attach.card := rfl

Violeta Hernández (Jun 30 2022 at 15:20):

So really, this boils down to asking why finset.univ : finset s isn't def-eq to s

Yaël Dillies (Jun 30 2022 at 15:21):

That doesn't typecheck, right?

Violeta Hernández (Jun 30 2022 at 15:22):

Oh, yeah

Violeta Hernández (Jun 30 2022 at 15:22):

Well, there's the answer, isn't it?

Violeta Hernández (Jun 30 2022 at 15:24):

fintype.card s is defined as (finset.univ : finset s).card while s.card is just that

Violeta Hernández (Jun 30 2022 at 15:24):

Which makes sense I think

Kyle Miller (Jun 30 2022 at 15:26):

Still, I wonder if there's some trick where you can make fintype.card s reduce to s.card. The problem right now is that attach is a map operation over the underlying list, and that doesn't preserve the length definitionally.

Violeta Hernández (Jun 30 2022 at 15:27):

btw note s.attach is def-eq to (finset.univ : finset s)

Violeta Hernández (Jun 30 2022 at 15:28):

And finset.univ is def-eq to fintype.elems

Kyle Miller (Jun 30 2022 at 15:29):

Yes, finset.univ : finset s is defeq to s.attach because of docs#finset.fintype_coe_sort, which defines the fintype s instance.

Violeta Hernández (Jun 30 2022 at 15:30):

So really, I think the issue is that fintype.elems s isn't def-eq to s, which it can't reasonably be because they aren't of the same type

Violeta Hernández (Jun 30 2022 at 15:31):

It doesn't seem reasonable to define fintype.card s as anything other than (fintype.elems s).card

Kyle Miller (Jun 30 2022 at 15:32):

Sure, that's the proximal issue, but there still might be some trick so that (fintype.elems s).card reduces to s.card by using something other than s.attach. Neither of us can think of anything, but that doesn't mean that there isn't something that would work in place of s.attach.

Kyle Miller (Jun 30 2022 at 15:33):

It seems unlikely, but I'm not willing to say it's impossible here.

Kyle Miller (Jun 30 2022 at 15:41):

One solution would be to extend fintype to include a card field so you can get definitional control over it.

meta def tactic_rfl : tactic unit := `[exact rfl]

class fintype' (α : Type*) :=
(elems [] : finset α)
(complete :  x : α, x  elems)
(card :  := elems.card)
(card_eq : card = elems.card . tactic_rfl) -- just so the default case automatically goes through

Eric Wieser (Jun 30 2022 at 15:51):

If you want to go down that route, you could also have card be a member of finsets, multisets, or even lists

Kyle Miller (Jun 30 2022 at 15:56):

This seems it could easily lead to "fun." Imagine getting to use the finset.reset_card lemma to reset the internal card field to the card of its multiset, after spending some time wondering why you weren't able to rw with some other lemma.

Wrenna Robson (Jun 30 2022 at 16:25):

Kyle Miller said:

Wrenna Robson A bit shorter:

noncomputable def equiv_fin {α : Type*} (s : finset α) : s  fin (s.card) :=
fintype.equiv_fin_of_card_eq (fintype.card_coe _)

Very nice.

Wrenna Robson (Jun 30 2022 at 16:26):

Still not quite sure why all the lemmas like this for list e.g. list.nodup.nth_le_equiv have the fin on the left, but all these are on the right for fintype.

Wrenna Robson (Jun 30 2022 at 16:26):

Like you'd think they'd all be the same.

Wrenna Robson (Jun 30 2022 at 16:28):

Would you want a finset.trunc_equiv_fin as well? The computable version.

Wrenna Robson (Jun 30 2022 at 16:29):

Violeta Hernández said:

So really, I think the issue is that fintype.elems s isn't def-eq to s, which it can't reasonably be because they aren't of the same type

Oh, because one is a finset s and the other is finset \alph or whatever?

Kyle Miller (Jun 30 2022 at 16:39):

Wrenna Robson said:

Would you want a finset.trunc_equiv_fin as well? The computable version.

I'd say "no" unless you're using it. How much would having finset.equiv_fin simplify your work, by the way? I'm wondering if (equiv_fin_of_card_eq (card_coe _)).symm (assuming open fintype) is already short enough of a name for what you're doing.

Kyle Miller (Jun 30 2022 at 16:53):

(The trunc_equiv_fin definition is used extremely rarely in mathlib -- only 3 legitimate uses outside fintype/basic -- which is why I suggest not including finset.trunc_equiv_fin. I just made #15076 and #15077 to remove the uses that were in a computation-free and classical context so don't need to be computable.)

Wrenna Robson (Jun 30 2022 at 18:34):

Yeah, I wasn't sure why it existed. finset.equiv_fin wouldn't simplify things a lot but it would make like one line less unwieldy.

Kyle Miller (Jun 30 2022 at 20:01):

@Wrenna Robson I'm sort of ambivalent about finset.equiv_fin, but even though it's just a composition of two things, may as well add it since it makes it easier to find this particular equivalence.

I think new definitions usually need some sort of justification since there's a cognitive cost to adding definitions to mathlib, and these are some justifications that come to mind:

  • It's a common expression and will save on repetition.
  • It chooses a canonical way of stating something (a nexus for a concept).
  • There is theory surrounding it.

It's worth considering that not everything needs an explicit name, and sometimes the body of a definition might be about the same length as the name of the definition itself (so it can be its own name, so to speak).

However, for this equivalence, I suspect that anyone who uses it only really cares that the equivalence exists, and it's a more convenient writing it this way than having it be a lemma proving nonempty (s ≃ fin s.card).

Kyle Miller (Jun 30 2022 at 20:07):

By the way, here's one of the uses of trunc_equiv_fin: https://github.com/leanprover-community/mathlib/blob/eb852609e908d661c0e31c94fa3fff6d113b9d6e/src/group_theory/perm/sign.lean#L427

It's an auxiliary function for computing the sign of a permutation, and since it's computable you can #eval the sign function if you wanted to.

Wrenna Robson (Jun 30 2022 at 23:18):

I mean really I even only care that there's an embedding from fin n to s where s.card = n: it's literally just the "we can label the finset" concept.

Wrenna Robson (Jul 01 2022 at 06:54):

What file should this be in? Feels like I can't put it in the finset bit of data.fintype.basic because that is before the fintype version which it makes sense to use

Wrenna Robson (Jul 01 2022 at 07:25):

See #15080

Wrenna Robson (Jul 01 2022 at 07:26):

@Kyle Miller fyi


Last updated: Dec 20 2023 at 11:08 UTC