Zulip Chat Archive
Stream: std4
Topic: Equiv
James Gallicchio (Aug 14 2023 at 10:17):
Is Equiv
a reasonable Std addition? I'm working on incorporating SciLean's Enumtype
and having Equiv would make it a good deal cleaner. Seems highly useful in programming contexts.
Eric Wieser (Aug 14 2023 at 12:11):
Would docs#FunLike and docs#EquivLike move with it?
Eric Wieser (Aug 14 2023 at 12:11):
And docs#Function.Embedding ?
François G. Dorais (Aug 14 2023 at 15:22):
I think Equiv
would be good in Std. It's useful to transport structure and I also use it a lot to manipulate encodings (I guess that's what Enumtype
is about).
FunLike
and EquivLike
are interesting abstractions but I don't see the necessity to move these at the same time. I thinkFunction.Embedding
doesn't need to move at all and the main connection with Equiv
is noncomputable.
Eric Wieser (Aug 14 2023 at 15:27):
If we don't move FunLike
, then now std and mathlib have different ways to write function application, and simp lemmas are going to be a mess
Eric Wieser (Aug 14 2023 at 15:28):
François G. Dorais said:
I think
Function.Embedding
doesn't need to move at all and the main connection withEquiv
is noncomputable.
The main connection in my mind is docs#Equiv.toEmbedding, which is definitely computable...
François G. Dorais (Aug 14 2023 at 15:31):
I don't think it's necessary for Equiv
to have function application API in Std, that can stay in Mathlib. That's not the kind of thing that's useful for programming.
Scott Morrison (Aug 14 2023 at 15:33):
I think the problem here is that every e.toFun x
is "the wrong way to write it" according to Mathlib. Without moving FunLike
, you can't talk about e.toFun x
and still have these lemma ergonomic in Mathlib. Hopefully I'm wrong here....?
François G. Dorais (Aug 14 2023 at 15:48):
I think I understand the issue. It sounds like something that would need a surgical division.
Eric Wieser (Aug 14 2023 at 15:51):
Scott's summary is exactly the point I was trying to make
Eric Wieser (Aug 14 2023 at 15:57):
Two reasonable options in my mind are:
- Move
FunLike
too. This means you also needFunction.Injective
to move, which I can see being undesirable - Create a
PreFunlike
in Std which providePreFunLike.coe
(and no injectivity field), and then haveFunLike
in mathlib extend it. All the mathlib lemmas would still be aboutPreFunLike.coe
, so the issue Scott describes wouldn't occur (or call itFunLike
andFaithfulFunLike
)
Eric Wieser (Aug 14 2023 at 16:02):
In essence, the purpose of PreFunLike
is just to restore the Lean3 coeFn
behavior where all function coercions used the same head symbol...
François G. Dorais (Aug 14 2023 at 16:12):
After taking a look at Mathlib's Equiv
API and comparing with my own version, I see that they are wildly different and incompatible in many ways. I think it even makes sense to have two Equiv
types with a bridge to connect the two when necessary!
To see the incompatibility from the other point of view: for my main application of Equiv
, the forward function is actually implemented by an Array
and having a coercion to function would be very annoying! The important feature of Equiv
for me is composability, the forward and reverse functions are "implementation details".
Eric Wieser (Aug 14 2023 at 16:13):
It's probably also worth noting that Enumtype
already exists in some form in mathlib as docs#FinEnum
Eric Wieser (Aug 14 2023 at 16:14):
Perhaps we should refactor it there in mathlib first before attempting to move it to Std4
François G. Dorais (Aug 14 2023 at 16:51):
Maybe it's easier to approach the issue differently. It's not about moving Equiv
from Mathlib to Std, it's that both Mathlib and Std have some need for an Equiv
type. The two types may as well be the same for binary compatibility. However, there is no need for the two API to be the same. That is not sustainable. We can't think of Std as "the part of Mathlib that's not math".
I think it makes sense to proceed this way:
- Move the
Equiv
type (only) to Std. - Develop a
Std.Equiv
API, probably borrowing lots of code from Mathlib but with no aim for compatibility. In particular no≃
,↪
,↑
. - Reimplement some parts of the Mathlib
Equiv
API usingStd.Equiv
to avoid code duplication while maintaining Mathlib's API as-is.
That does mean that some things will have different names in Std and Mathlib but that's bound to happen anyway.
Eric Wieser (Aug 14 2023 at 16:53):
I don't see why we wouldn't make the API the same given we have the option to
Eric Wieser (Aug 14 2023 at 16:53):
If Std and mathlib disagree on how to write function application that's a pretty major disagreement. And if your Equiv
doesn't use function application then I'm not sure how it's used at all...
François G. Dorais (Aug 14 2023 at 16:55):
@Eric Wieser It's not a disagreement about how to write function application: there simply is no need for the coercion to function in Std, it's not a useful feature.
Eric Wieser (Aug 14 2023 at 16:56):
Well that's a disagreement about whether to write e.toFun x
or e x
François G. Dorais (Aug 14 2023 at 16:56):
The equivs are composed to construct more complex equivs without fussing about implementation details.
Eric Wieser (Aug 14 2023 at 16:57):
Are you saying toFun
is not part of the API at all?
François G. Dorais (Aug 14 2023 at 16:57):
It is, but it's an implementation detail.
François G. Dorais (Aug 14 2023 at 16:58):
For me, the equiv is a way not to worry about the functions.
Eric Wieser (Aug 14 2023 at 16:58):
What _is_ in the API then?
François G. Dorais (Aug 14 2023 at 16:59):
Groupoid laws.
François G. Dorais (Aug 14 2023 at 17:00):
And transport defs.
Eric Wieser (Aug 14 2023 at 17:01):
Do you envisage having APi that says List X
is equivalent to List Y
when X
is equivalent to Y
? If so, would Std contain the lemma about how that acts on nil
/ cons
?
François G. Dorais (Aug 14 2023 at 17:04):
I have that equivalence in my API, I never needed to know it preserves operations. That would be an isomorphism, not just an equivalence.
Eric Wieser (Aug 14 2023 at 17:11):
I think I'm missing the application here. If all you ever do with equivs is construct more equivs with them, what's the computational application that justifies them being data?
François G. Dorais (Aug 14 2023 at 17:24):
Here's an example where Equiv
comes in extremely handy. Some of my students are doing research on finite automata. The more efficient implementations of transitions and reachability algorithms use Boolean matrix multiplication. These matrix algorithms are implemented using arrays, but the machine states are typically more complex, with data about how the machine was constructed or the purpose of each state. To connect these two, I need an Equiv
from my machine's state type to Fin n
(say). How that Equiv
works is irrelevant. There's a transport function that uses that Equiv
so I can use matrix multiplication for calculation. The correctness proofs do have to fiddle with the forward and reverse functions but they only need to know that they are inverses of each other, so the Equiv
is really a black box.
James Gallicchio (Aug 14 2023 at 17:37):
hm, this spawned a lot of conversation...
I'm not opposed to refactoring FinEnum
; I think it was probably designed before any programming usage was intended. But if FinEnum
uses Equiv
, I'd still want to move Equiv
into Std.
We've discussed moving FunLike
before. But I am guessing we'd want to refactor out the injectivity field as Eric said.
Eric Wieser (Aug 14 2023 at 17:40):
I think a lot of my confusion would be resolved by seeing actual code written against the current docs#Equiv that demonstrates a practical situation where application is irrelevant. It sounds like @François G. Dorais's Equiv
would have a strict subset of the API it has in mathlib4, so that demo could be built without first extracting to Std4.
Eric Wieser (Aug 14 2023 at 17:41):
FinEnum
as it currently exists in mathlib is probably ok computationally for the typeclass, but all the instances are awful as they go back and forth via lists. A complete redesign along the lines of Enumtype
certainly seems like a reasonable choice.
James Gallicchio (Aug 14 2023 at 17:45):
Eric Wieser said:
seeing actual code written against the current docs#Equiv that demonstrates a practical situation where application is irrelevant.
It's never irrelevant -- but in my application, it didn't matter whether I wrote e x
or e.toFun x
because I wasn't proving anything and therefore didn't need any simp lemmas. But that's a bad excuse for not moving it to Std :-)
James Gallicchio (Aug 14 2023 at 17:50):
I'll start working on a refactor of FinEnum
.
François G. Dorais (Aug 14 2023 at 17:50):
That's right, it's not irrelevant but it's a black box and doesn't need special treatment. That said, I much prefer writing e.toFun x
than e x
since it's hard to see invisible things :-)
James Gallicchio (Aug 14 2023 at 17:52):
(you can see the equivalence e
, so it doesn't feel quite as invisible as coercions usually are...)
James Gallicchio (Aug 14 2023 at 17:57):
BTW, what's the reason for FunLike
to have the injectivity constraint? Is it acting as a safeguard against FunLike
instances that are antipatterns?
Eric Wieser (Aug 14 2023 at 18:03):
It's to allow ext
(and a handful of similar lemmas) to be generalized
Eric Wieser (Aug 14 2023 at 18:03):
So you can write FunLike.ext
and it works for Embedding
, Equiv
, AddHom
, etc
Eric Wieser (Aug 14 2023 at 18:05):
I think Std4 could probably justify dropping the injectivity bit if movingFunction.Injective
is undesirable (but maybe it's not?)
James Gallicchio (Aug 14 2023 at 18:08):
It seems useful in Std4, but I can imagine situations coming up where people want the notation without proving injectivity. Would it be reasonable to refactor in Mathlib the injectivity as another class? (LawfulFunLike
? FunLike.Inj
?)
Eric Wieser (Aug 14 2023 at 18:11):
I think the current name is best kept as the injective version
François G. Dorais (Aug 14 2023 at 18:30):
I think it's fine to have a plain ToFun
class in Std that can act as a grandparent to all of these. I can also get used to the coercion if that's what everybody wants.
James Gallicchio (Aug 14 2023 at 18:33):
To save on name bikeshedding, maybe we should just not prematurely refactor; once someone has a FunLike
that's not trivially injective we can come back to it :joy:
François G. Dorais (Aug 14 2023 at 18:39):
(I was using ToFun
as a description, not a suggestion. I'm actually surprised to see that it doesn't already exist somewhere.)
Eric Wieser (Aug 14 2023 at 18:42):
Well, the builtin is docs#CoeFun but that has elaboration magic that we don't want
François G. Dorais (Aug 14 2023 at 20:18):
@Eric Wieser I love that magic but I hate it sometimes. I often have to make silly aliases to make things work. How often do you run into this and how?
Eric Wieser (Aug 14 2023 at 20:19):
How often do I run into magic that we don't want with CoeFun
, you mean?
Eric Wieser (Aug 14 2023 at 20:20):
If we used the default CoeFun
then algebraMap R A r
would be (algebraMap R A).toAddMonoidHom.toAddHom.toFun r
or something, which is then syntactically different from (algebraMap R A).toMonoidHom.toMulHom.toFun r
, and now we have a whole tree of different paths to rewrite between when we don't care about any of them.
François G. Dorais (Aug 14 2023 at 20:21):
Things that don't hook right? Other things that can only be fixed by first rewriting into something with no magic...
(This is re the first part only.)
Eric Wieser (Aug 14 2023 at 20:23):
I'm afraid I'm not sure which message you're referring to (and I think there's a typo that's not helping)
François G. Dorais (Aug 14 2023 at 20:25):
Lag confusion... "the first part" was an answer to the sentence that ends with "you mean?"
Eric Wieser (Aug 14 2023 at 20:26):
I assume "hook" means "look" (as opposed to "hook right (arrow)" aka docs#Embedding)
François G. Dorais (Aug 14 2023 at 20:32):
No, it means hook as in fishing. It's an analogy with getting the right bait for the fish. Sorry for using that analogy, I thought it was common.
Mario Carneiro (Aug 14 2023 at 22:01):
I think it would be reasonable to move Equiv
to Std, along with a minimal FunLike
port including Function.Injective
. (injective, surjective, bijective were once part of lean 3 core, and most things in the lean 3 core library are candidates for std, even if they have since migrated out of the core library.) FinEnum
/ Enumtype
is a different matter and should probably not be discussed in this topic
Mario Carneiro (Aug 14 2023 at 22:03):
We had to do something similar when porting Int
/Rat
lemmas, we had to move NatCast
for consistency with mathlib even though it's just notation
Mario Carneiro (Aug 14 2023 at 22:04):
I think the main usage of Equiv
is as a "vocabulary type", we want everyone talking about equivs to use the same type to do so
Mario Carneiro (Aug 14 2023 at 22:04):
It's also not horrible computationally, although it's not something you want to use unless you have to
James Gallicchio (Aug 14 2023 at 22:09):
I'm hoping we can get Lean to inline enough stuff to find idempotent e \circ e.symm
applications and csimp them away, but that's a ways off :)
Mario Carneiro (Aug 14 2023 at 22:25):
that would be cool, but csimp definitely doesn't support it
James Gallicchio (Aug 14 2023 at 22:25):
ah, right, only constants. well. another thing to put on the pile of "useful if csimp supported non-constant rewrites"
Last updated: Dec 20 2023 at 11:08 UTC