Zulip Chat Archive
Stream: mathlib4
Topic: OfScientific
Heather Macbeth (Jan 20 2023 at 04:07):
I just encountered
failed to synthesize instance
OfScientific ℝ
while trying to refer to the real number 0.1. Do we want an OfScientific
instance for (say) any characteristic-zero field? Is norm_num
going to handle this? cc @Thomas Murrills @Mario Carneiro
Thomas Murrills (Jan 20 2023 at 04:22):
Hmm, I’m not really the one making design choices here, but I definitely think norm_num
should be able to recognize scientific notation—it seems it can’t do this even in e.g. the Rat
case.
I’ll open an issue/branch and see how far I get writing the extension right now.
Thomas Murrills (Jan 20 2023 at 04:24):
It also makes sense to me to have OfScientific
defined for all charzero division rings. Rat
has one already, and I don’t know if the general one should be defined in terms of casting Rat to the charzero field, or if this one should be abandoned in favor of a more general one, or what.
But imo it should exist! I wonder if it’s somewhere in mathlib3 already?
Thomas Murrills (Jan 20 2023 at 04:48):
Another semi-related question is whether norm_num
should handle floats. (Semi-related because scientific notation defaults to Float
unless you specify the type.) My guess is maybe, but I'd hope that's not needed soon? :sweat_smile:
Heather Macbeth (Jan 20 2023 at 16:06):
Thomas Murrills said:
scientific notation defaults to
Float
unless you specify the type
Is there a way to turn this off? We really don't want unsuspecting mathlib users to encounter Float
s after typing 0.1. If there's a default in mathlib it should be Rat.
Mario Carneiro (Jan 20 2023 at 17:49):
OfScientific
is basically a notation typeclass, which provides the interpretation of decimal numbers. I think it is relatively safe to have a blanket implementation for anything that would have a Rat.cast
instance.
Mario Carneiro (Jan 20 2023 at 17:50):
It is more or less unrelated to norm_num
, unless that instance leaves some ofScientific
term in the expression in which case norm_num
will want to unfold it to a fraction
Mario Carneiro (Jan 20 2023 at 17:51):
in lean 3, this instance was effectively unfolded at parse time, so if you write 0.2
you get exactly the same term as if you had written 1/5
instead
Mario Carneiro (Jan 20 2023 at 17:54):
Thomas Murrills said:
Another semi-related question is whether
norm_num
should handle floats. (Semi-related because scientific notation defaults toFloat
unless you specify the type.) My guess is maybe, but I'd hope that's not needed soon? :sweat_smile:
This is fundamentally impossible for lean 4 Float
as currently implemented, because everything is opaque.
Heather Macbeth said:
Thomas Murrills said:
scientific notation defaults to
Float
unless you specify the typeIs there a way to turn this off? We really don't want unsuspecting mathlib users to encounter
Float
s after typing 0.1. If there's a default in mathlib it should be Rat.
I have not tried having multiple @[default_instance]
instances at once, but I don't see any reason why it wouldn't work. If we provide another default instance for OfScientific pointing at Rat we can override this behavior.
Heather Macbeth (Jan 20 2023 at 17:56):
Is there going to be an issue having a [DivisionRing K] [CharZero K] instance for OfScientific
; will it conflict in the case K = Rat with the instance for Rat?
Heather Macbeth (Jan 20 2023 at 17:56):
(see discussion on mathlib4#1707)
Eric Wieser (Jan 20 2023 at 17:57):
It shouldn't do, we already solved this problem in Lean 3
Heather Macbeth (Jan 20 2023 at 17:57):
How?
Yaël Dillies (Jan 20 2023 at 17:59):
By making it be part of the definition of DivisionRing
Thomas Murrills (Jan 20 2023 at 18:01):
For whatever reason it doesn’t seem to conflict as-is—if I type #synth OfScientific Rat
after the DivisionRing
instance I still get the Rat
instance.
Not sure how Lean decides which instance to prefer or if changing the location of the instance might introduce some issues, but if it does, maybe we could tinker with the instance priorities?
Heather Macbeth (Jan 20 2023 at 18:01):
Yaël Dillies said:
By making it be part of the definition of
DivisionRing
What do you mean? Even nonzero characteristic division rings?
Yaël Dillies (Jan 20 2023 at 18:01):
This is what happens what rat_cast
, yes.
Heather Macbeth (Jan 20 2023 at 18:02):
We're talking about OfScientific
, not rat casting. (Of course they're related.)
Thomas Murrills (Jan 20 2023 at 18:05):
Mario Carneiro said:
It is more or less unrelated to
norm_num
, unless that instance leaves someofScientific
term in the expression in which casenorm_num
will want to unfold it to a fraction
Currently we are left with an ofScientific
in the expression and norm_num
fails when encountering it. Is there a shortcut we’d want to use for unfolding it here, or is the standard procedure for evaluating things warranted?
Eric Wieser (Jan 20 2023 at 18:06):
docs4#OfScientific for reference
Eric Wieser (Jan 20 2023 at 18:07):
Heather Macbeth said:
We're talking about
OfScientific
, not rat casting. (Of course they're related.)
The implementation for a division ring K
is presumably going to be ratCast (OfScientific ...)
. The implementation of ratCast
for Rat
is just id
.
Yaël Dillies (Jan 20 2023 at 18:07):
Well, rat_cast
is enough to define of_scientific
, so it should be included in at least all the structures where rat_cast
is.
Eric Wieser (Jan 20 2023 at 18:12):
As Yael alludes to, if we introduce some other division ring which has a more efficient implementation of ofScientific
that going through Rat
, then we're in trouble unless we make ofScientific
a field of docs4#DivisionRing
Heather Macbeth (Jan 20 2023 at 18:26):
This seems to fail in Lean 4:
import Mathlib.Data.Rat.Basic
example : (1:ℚ) / 10 = 0.1 := rfl -- fails
So I guess we really do need a norm_num
extension.
Eric Wieser (Jan 20 2023 at 18:28):
That's weird; I guess division doesn't reduce any more?
Mario Carneiro (Jan 20 2023 at 18:29):
Thomas Murrills said:
Mario Carneiro said:
It is more or less unrelated to
norm_num
, unless that instance leaves someofScientific
term in the expression in which casenorm_num
will want to unfold it to a fractionCurrently we are left with an
ofScientific
in the expression andnorm_num
fails when encountering it. Is there a shortcut we’d want to use for unfolding it here, or is the standard procedure for evaluating things warranted?
I was kind of hoping that lean would automatically unfold the instance like it does for coes, that would make things simpler. If there is a ofScientific
then we need to do the usual thing in norm_num: have a norm_num extension that matches on ofScientific
and unfolds it to a division or what have you. (If this comes up a few more times we might consider having a meta-norm_num tactic/macro which generates such extensions on demand, similar to the delaborator and formatter that you get for free using syntax
.)
Heather Macbeth (Jan 20 2023 at 18:30):
Note that Thomas already made a first stab at a norm_num
extension for OfScientific
: mathlib4#1707
Mario Carneiro (Jan 20 2023 at 18:30):
that last example does seem weird. What does it actually unfold to?
Mario Carneiro (Jan 20 2023 at 18:31):
oh fun:
#whnf (0.1 : ℚ)
-- Decidable.rec
-- (fun h =>
-- (fun hg => Rat.mk' (Int.div ↑1 ↑(Nat.gcd (Int.natAbs ↑1) (10 ^ 1))) (10 ^ 1 / Nat.gcd (Int.natAbs ↑1) (10 ^ 1))) h)
-- (fun h => (fun hg => Rat.mk' (↑1) (10 ^ 1)) h) (instDecidableEqNat (Nat.gcd (Int.natAbs ↑1) (10 ^ 1)) 1)
Mario Carneiro (Jan 20 2023 at 18:32):
it looks like it got stuck evaluating Nat.gcd
Eric Wieser (Jan 20 2023 at 18:34):
Does nat.gcd reduce in Lean 3?
Thomas Murrills (Jan 20 2023 at 18:34):
Heather Macbeth said:
Note that Thomas already made a first stab at a
norm_num
extension forOfScientific
: mathlib4#1707
I’ve only got it half done—I’m actually encountering some really weird monad errors in the main extension! I’ll bring them up later when I continue working on it.
Mario Carneiro (Jan 20 2023 at 18:34):
no it does not @Eric Wieser
Mario Carneiro (Jan 20 2023 at 18:36):
the difference in this case is that the reduction of 0.1
to 1/10
is done by meta code in lean 3, so the theorem 0.1 = 1/10
in lean 3 is a syntactic tautology
Thomas Murrills (Jan 21 2023 at 01:29):
(Moving from the GitHub discussion) Where is Rat.cast
? I can’t seem to find it—only Rat.castRec
, RatCast
, and Rat.castCoe
Gabriel Ebner (Jan 21 2023 at 01:30):
I think it's called RatCast.ratCast
.
Thomas Murrills (Jan 21 2023 at 01:32):
My understanding (via Mario’s comments) is that that’s not the lawful version, though, and Rat.cast is meant to be lawful somehow
Thomas Murrills (Jan 21 2023 at 01:44):
It seems to me like the laws for the rat cast are fields of DivisionRing
directly, though. Does Rat.cast
as a stand-alone typeclass actually exist yet?
Gabriel Ebner (Jan 21 2023 at 02:07):
Nat.cast
isn't lawful either.
Gabriel Ebner (Jan 21 2023 at 02:08):
The lawful version of Nat.cast
is the AddMonoidWithOne
type class. And the lawful version of Int.cast
is the AddGroupWithOne
type class.
Gabriel Ebner (Jan 21 2023 at 02:09):
Requiring a DivisionRing
instance to prove things about RatCast.ratCast
is the right (or at least consistent) thing to do here.
Kevin Buzzard (Jan 21 2023 at 10:44):
Hot take: AddMonoidWithOne
should be the to_additive
ised version of MonoidWithE
, with E=2.718....
Reid Barton (Jan 21 2023 at 10:52):
Do we have exponential periods yet?
Johan Commelin (Jan 21 2023 at 14:27):
Depending on which definition you want, they are either 5 lightyears away, or < 2 days of hacking.
Thomas Murrills (Jan 21 2023 at 20:51):
Gabriel Ebner said:
Requiring a
DivisionRing
instance to prove things aboutRatCast.ratCast
is the right (or at least consistent) thing to do here.
Makes sense! So, if we added it as a field to DivisionRing
would we also want a field that made ofScientific
lawful (i.e. said it was extensionally equal to the cast of Rat.ofScientific
)?
This would make it easy to prove things about it (e.g. in norm_num
), but I don’t know if any division rings somehow have completely different scientific notations.
Kevin Buzzard (Jan 21 2023 at 20:57):
The division rings which show up in my research are just full of things called d
and x
.
Thomas Murrills (Jan 21 2023 at 21:09):
It shouldn’t be much overhead (computationally or cognitively) in almost all cases, I think, as the default values should take care of it like they do for ratCast
: the default value of ofScientific
will be the cast of Rat.ofScientific
, and so the default proof that it’s lawful will be reflexivity, and you won’t even know it’s there. But if you need 0.1, you’ll have it. :)
Mario Carneiro (Jan 21 2023 at 21:15):
I still think we should not make this a field and should just have an OfScientific
instance for any division ring defined in terms of Rat.ofScientific
Mario Carneiro (Jan 21 2023 at 21:17):
There are lots of definitions that are not fields, and structure fields have a significant cost on the overall typeclass system, so I would really rather not have silly things like this being something everyone has to deal with when making fields
Heather Macbeth (Jan 21 2023 at 21:23):
Mario Carneiro said:
I still think we should not make this a field and should just have an
OfScientific
instance for any division ring defined in terms ofRat.ofScientific
Mario, there's a point about this suggestion which I don't understand -- won't it mean that Rat
gets two separate OfScientific
instances? Even though their data is the same, I would think that would cause problems.
Mario Carneiro (Jan 21 2023 at 21:23):
they should be defeq
Heather Macbeth (Jan 21 2023 at 21:23):
OK, maybe I hadn't appreciated that: it's ok to have multiple instances if they're defeq.
Mario Carneiro (Jan 21 2023 at 21:24):
because the RatCast Rat
instance should be the identity
Heather Macbeth (Jan 21 2023 at 21:24):
Do they need to be "quickly" defeq?
Mario Carneiro (Jan 21 2023 at 21:24):
they should be defeq at instance reducibility
Mario Carneiro (Jan 21 2023 at 21:24):
which I think is the case here
Thomas Murrills (Jan 21 2023 at 21:25):
Hmm…if someone wants to implement a new definition of ofScientific
for their division ring (which happens in one spot I think—something about Cauchy sequences), would that cause problems? Would we give the general one a lower priority or something?
Mario Carneiro (Jan 21 2023 at 21:25):
They should not do that
Thomas Murrills (Jan 21 2023 at 21:25):
They already do :grimacing:
Mario Carneiro (Jan 21 2023 at 21:25):
in lean 3 this was simply not a possibility and I think that was a good thing
Mario Carneiro (Jan 21 2023 at 21:25):
this is one more knob that people can use to write the same thing in multiple ways
Thomas Murrills (Jan 21 2023 at 21:26):
(Maybe we can get rid of the bespoke definition? I haven’t checked…)
Mario Carneiro (Jan 21 2023 at 21:27):
I'm sure the definition was written because the general one didn't exist yet
Heather Macbeth (Jan 21 2023 at 21:27):
I don't see that one? it's not listed at
https://leanprover-community.github.io/mathlib4_docs/Init/Data/OfScientific.html#OfScientific
Thomas Murrills (Jan 21 2023 at 21:29):
Wow, if I’m looking at the right thing, it’s disappeared since this thread started! That’s convenient!
Thomas Murrills (Jan 21 2023 at 21:41):
Oh, perhaps I’m mixing things up. I might have been thinking about things with custom RatCast
implementations. docs4#RatCast
Will that also make things potentially break though? When the instance of ofScientific
for all division rings searches for a way to cast rationals, will it find the custom cast, or the canonical cast? (Should we just force the canonical cast somehow in this instance?)
Mario Carneiro (Jan 21 2023 at 21:44):
It doesn't search for a way to cast rationals, the cast is baked into the definition and it is the canonical one
Thomas Murrills (Jan 21 2023 at 21:45):
Hmmm. So writing (3/4 : ℚ) : R
will use the canonical cast instead of whatever the division ring R
has defined?
Thomas Murrills (Jan 21 2023 at 21:46):
(Because that’s all this new instance we’re defining does atm)
Gabriel Ebner (Jan 21 2023 at 22:03):
I can only think of one case where the blanket instance is problematic: floating point numbers. There the (naive) rat cast version has less precision than the current implementation which directly produces the mantissa.
Gabriel Ebner (Jan 21 2023 at 22:05):
We could declare the blanket instance only for division rings, where the cast is unique.
Thomas Murrills (Jan 21 2023 at 22:08):
Is the cast definitionally unique for division rings or just propositionally unique? (Or is the latter enough for all purposes?) Does the ratCast
field of division rings ever come into play here?
Gabriel Ebner (Jan 21 2023 at 22:10):
Just proposition ally.
Gabriel Ebner (Jan 21 2023 at 22:11):
The ratCast field is used for coercions from rational numbers as the name implies.
Thomas Murrills (Jan 21 2023 at 22:13):
So when we write this instance for division rings for ofScientific
, I’m guessing we should use the value in that field instead of the (potentially not defeq) canonical cast to cast the value of Rat.ofScientific
, right? I’m just trying to figure out if that will ever cause any problems…
Gabriel Ebner (Jan 21 2023 at 22:16):
Oh yeah, I think we should define of scientific in terms of rat cast.
Mario Carneiro (Jan 21 2023 at 22:48):
Gabriel Ebner said:
I can only think of one case where the blanket instance is problematic: floating point numbers. There the (naive) rat cast version has less precision than the current implementation which directly produces the mantissa.
In that case we don't really care that it's the wrong instance since we aren't proving anything about those floats anyway
Mario Carneiro (Jan 21 2023 at 22:49):
It should be possible to implement that in such a way that there is no loss however, where the Rat -> Float
function builds the nearest float to the rational number according to the rounding mode
Eric Wieser (Jan 21 2023 at 23:32):
Floating point numbers aren't a division ring so I don't see a conflict here?
Eric Wieser (Jan 21 2023 at 23:35):
That is, DivisionRing.toOfScientific should be safe
Gabriel Ebner (Jan 22 2023 at 01:36):
Mario Carneiro said:
Gabriel Ebner said:
I can only think of one case where the blanket instance is problematic: floating point numbers. There the (naive) rat cast version has less precision than the current implementation which directly produces the mantissa.
In that case we don't really care that it's the wrong instance since we aren't proving anything about those floats anyway
On the contrary, we care much more for floating-point numbers than for division rings because the two operations are not equivalent. It's not just that we can't prove they're equal, we can actually observe that one of them is much worse! For division rings, it doesn't really matter whether we define scientific literals as ratCast ...
or intCast .. / natCast ...
or something else, because we provably get the same result every time. But for floating-point numbers e.g. going via intCast .. / natCast ..
would have unacceptable numerical precision.
Mario Carneiro (Jan 22 2023 at 01:41):
was intCast .. / natCast ..
ever on the table?
Mario Carneiro (Jan 22 2023 at 01:41):
that is a terrible implementation
Gabriel Ebner (Jan 22 2023 at 01:41):
Mario Carneiro said:
It should be possible to implement that in such a way that there is no loss however, where the
Rat -> Float
function builds the nearest float to the rational number according to the rounding mode
It is a good idea to define ratCast
that way (or at least close enough to that spec). Which still leaves the issue that 0.1
might be a different floating-point number depending on which instance is used. I'd like to avoid that potential nightmare.
Mario Carneiro (Jan 22 2023 at 01:42):
Like Eric said, there is no diamond here
Gabriel Ebner (Jan 22 2023 at 01:42):
?
Mario Carneiro (Jan 22 2023 at 01:42):
Float is not a division ring
Gabriel Ebner (Jan 22 2023 at 01:42):
Core has an OfScientific
instance for Float
.
Mario Carneiro (Jan 22 2023 at 01:43):
no one is suggesting an instance for [RatCast R] : OfScientific R
Gabriel Ebner (Jan 22 2023 at 01:43):
Oh yeah, my objections doesn't apply to the [DivisionrRing R] : OfScientific R
instance.
Mario Carneiro (Jan 22 2023 at 01:43):
I don't think Float
has a RatCast
instance either, for that matter
Mario Carneiro (Jan 22 2023 at 01:44):
although it probably should
Gabriel Ebner (Jan 22 2023 at 01:46):
Mario Carneiro said:
no one is suggesting an instance for
[RatCast R] : OfScientific R
I was going by Thomas's comment on the norm_num PR:
Though, @digama0, you suggested a blanket implementation for anything that has an instance of RatCast.
Mario Carneiro (Jan 22 2023 at 01:47):
yes, he misunderstood what I meant by "the instances required to get Rat.cast
"
Thomas Murrills (Jan 30 2023 at 06:35):
Ok, ofScientific
in norm_num
now works (mathlib4#1707) :)
Thomas Murrills (Jan 30 2023 at 06:36):
I relocated things best I could, and I’m sure there are cleanups or improvements to be made, but given the teaching deadline, I wanted to put it out for review asap!
Last updated: Dec 20 2023 at 11:08 UTC