Zulip Chat Archive

Stream: general

Topic: with_top, enat, and with_zero


Aaron Anderson (Mar 02 2021 at 22:58):

I find myself wishing that enat and with_top, and with_zero and with_bot, had definition equality.
Instead, in each case, one is an option and the other is a roption.

Aaron Anderson (Mar 02 2021 at 23:01):

I might find myself motivated to try making one of these changes, say, to make enat an abbreviation for with_top nat. Is there a good reason not to do that? I'm not terribly well-versed in the philosophy of decidability here, but I think it doesn't matter much for enat at least. After all, there is already an equiv there.

Kevin Buzzard (Mar 02 2021 at 23:06):

I find it frustrating that some of these things are definitionally equal because it can lead to leaks where r : with_zero G suddenly magically becomes r : option G and then stuff can break. I also had this vague idea that in Lean 4 we were going to be encouraged to make new structures for all of these? Or am I talking nonsense?

Aaron Anderson (Mar 02 2021 at 23:09):

Well, I've already found one answer to my question, which is that somehow roptions get around the decidability of ∃ n, P n in the definition of enat.find.

Aaron Anderson (Mar 02 2021 at 23:10):

Kevin Buzzard said:

I find it frustrating that some of these things are definitionally equal because it can lead to leaks where r : with_zero G suddenly magically becomes r : option G and then stuff can break. I also had this vague idea that in Lean 4 we were going to be encouraged to make new structures for all of these? Or am I talking nonsense?

Perhaps with with_zero and with_bot I'm overreaching with definitional hubris (not that they feel like they should be implemented differently)

Aaron Anderson (Mar 02 2021 at 23:11):

but the fact that there are times we want with_top nat and times we want enat is really disturbing...

Kevin Buzzard (Mar 02 2021 at 23:12):

I don't think I ever want enat...

Kevin Buzzard (Mar 02 2021 at 23:12):

Isn't it just some constructivist nonsense?

Aaron Anderson (Mar 02 2021 at 23:13):

I'm pretty sure the reason is literally so that you can define enat.find P whenever P is decidable, without needing ∃ n, P n to be decidable.

Eric Wieser (Mar 02 2021 at 23:21):

Aaron Anderson said:

but the fact that there are times we want with_top nat and times we want enat is really disturbing...

What's the killer feature of with_top, if the killer feature of enat is avoiding decidability for docs#enat.find?

Eric Wieser (Mar 02 2021 at 23:21):

Is the problem just that one has less API than the other?

Aaron Anderson (Mar 02 2021 at 23:28):

The problem to me is that I’d like to use the APIs interchangeably (also, I’d like to be able to define additive valuations using with_top, but maybe that’s not critical)

Aaron Anderson (Mar 02 2021 at 23:38):

I would then just say to change with_top and with_bot to roptions, but maybe soon I will find out a reason that that’s a bad idea

Kevin Buzzard (Mar 02 2021 at 23:38):

The killer feature of with_top is that option is so easy to use, you just do proofs by cases or with the equation compiler

Aaron Anderson (Mar 02 2021 at 23:39):

However, with_zero seems to have worked fine as a roption...

Eric Wieser (Mar 02 2021 at 23:55):

I don't think the earlier statement about docs#enat.find was correct, it has exactly the same decidable assumptions as docs#nat.find

Aaron Anderson (Mar 03 2021 at 00:21):

That’s correct, but I can’t seem to replicate it with with_top nat

Aaron Anderson (Mar 03 2021 at 00:22):

At least, not computably

Johan Commelin (Mar 03 2021 at 05:53):

The killer feature of with_top is probably that you can use the equation compiler to split between nat and infty.

Gabriel Ebner (Mar 03 2021 at 09:29):

In my eyes, the biggest API problem with enat (and also related to not being able to use the equation compiler) is that it encourages the use of roption.get. That function is pretty unergonomic since you always need to provide a proof that the enat is finite as a second argument.
The roption definition of enat is a tradeoff: enat.find becomes computable, but other operations such as become noncomputable. I don't think this tradeoff is worth it, and I believe that def enat := with_top nat would be the better choice.

Yaël Dillies (Aug 04 2021 at 09:20):

If everybody agrees, I'll prepare a PR for that to change.

Eric Wieser (Aug 04 2021 at 09:33):

Aaron Anderson said:

However, with_zero seems to have worked fine as a roption...

Not sure what you mean by that, src#with_zero is an option, and has been for at least two years.

Kevin Buzzard (Aug 04 2021 at 09:44):

Yes it's enat which is the roption, and this fact basically renders it unusable for me (I don't know the API and don't see any reason why it shouldn't just be an option but no doubt others do!).

Yaël Dillies (Aug 04 2021 at 10:02):

Yeah sorry I meant that I will change the def of enat to with_top ℕ. And Aaron probably tried to make with_zero a roption.

Eric Wieser (Aug 04 2021 at 10:03):

Is it worth keeping enat around as renat?

Eric Wieser (Aug 04 2021 at 10:03):

Otherwise, is anything else using roption?

Yaël Dillies (Aug 04 2021 at 10:04):

Yeah, all of Mario's computability stuff.

Yaël Dillies (Aug 04 2021 at 10:04):

What's weird is to define concrete types with it. That's option's job.

Eric Wieser (Aug 04 2021 at 10:05):

I think it would probably be good to get @Mario Carneiro to sign off on removal as opposed to renaming

Eric Wieser (Aug 04 2021 at 10:05):

Certainly enat via roption is annoying to mathematicians, but perhaps it's still useful and just needs to be more hidden.

Yaël Dillies (Aug 04 2021 at 10:06):

From the above discussion, the argument in favor of roption is mostly to have enat.find computable.

Kevin Buzzard (Aug 04 2021 at 10:47):

I think that this would be a rather painful refactor and it's not clear to me what we're gaining.

There are tons of places in mathlib where the constructivists have done something and I would have done something different. For example finset is constructive, finsupp and dfinsupp are constructive, enat is constructive etc; I find all of these things hard to work with for various reasons. But just because we now have set.finite and finsum and nat.card doesn't mean that I'm pressing for the removal of finset -- indeed people like Bhavik swear by it for the kind of mathematics they're doing.

Gabriel Ebner (Aug 04 2021 at 10:56):

I think that this would be a rather painful refactor and it's not clear to me what we're gaining.

A big one that was already mentioned in this thread is support for the equation compiler. We can also reuse all lemmas about with_top. The refactor should be relatively quick (there's only 268 lines mentioning the word enat in mathlib and half of them in data/nat/enat.lean).

Gabriel Ebner (Aug 04 2021 at 11:02):

I think a big argument for a constructive finset is that you can actually compute with it. You can prove equalities between finsets using dec_trivial, you can print them in the VM, etc.

It is much harder to compute with (the roption version of) enat. Almost no property of enats is decidable: equality is not decidable, order is not decidable. So no dec_trivial. Printing an enat to a string is of course not computable either.

Mario Carneiro (Aug 04 2021 at 11:57):

I still think roption is the more mathematically natural choice given its topology, but I understand the arguments in favor of option, and the equation compiler in particular is something that API lemmas can't paper over. And the duplication with with_top nat is undesirable. So there is probably no point in me blocking this on purist grounds when it isn't actually helping anyone.

To the extent that the option / roption distinction has been hidden behind an API, it should not be that bad to refactor, although some care (a typeclass?) will be needed to ensure that multiplicity on int comes out computable (which is useful for dec_trivial).

Gabriel Ebner (Aug 04 2021 at 12:15):

(deleted)


Last updated: Dec 20 2023 at 11:08 UTC