Zulip Chat Archive
Stream: mathlib4
Topic: Making Reals computable (sometimes) using coercion
Cookie Guy (Jan 15 2026 at 02:02):
So I have been reading how Mathlib defines a Real and I found it quite wierd that it was completely uncomputable.. I looked into it and it makes sense, it is a quotient and those cant be computed and all. But I still find it wierd that a calculator cant approximate reals, it feels like a programming language should be able to approximate reals at the least. I figured it should be very handy and very easy in principle to make reals be able to be a function that takes in a precision and gives you are rational which is epsilon precise.
But then i found out that there are things like Specker's sequence.
Here's my solution
When you type let x : ℝ := 1 in lean, it is actually OfNat (1 : ℕ) to cast from natural to real. So my thought was that we remove this cast. We add a new type, called ApproximableReal or something. Every 'normal' number will be of this type. This is because an ApproximableReal is something like
structure ApproximableReal :=
approximator: ℚ → ℚ
convergence_proofs: ommited types
so very similar to our intuition on Cauchy Reals. It doesn't have decidable equality or any of the nice things that we get from normal Mathlib Reals, but it is computable. It is not intended to be used by itself, it automatically casts up to reals.
However, reals constructed in this fashion are nice because of something like Int.OfNat_nonneg, this has the ability to approximate as long as the real comes from an ApproximableReal.
ApproximableReals would have to be constructed differently i guess. Like for example Real.pi couldn't be an approximable real if it was written as IVT on 0 ∈ cos '' Icc (1 : ℝ) 2 like it is in lean right now, but it could if it was written using like infinite sum or integral of circle or whatever (could integrals become approximable too? or could only boxIntegrals).
By doing this, we preserve all of the nice properties present in current reals, but we can add that we can also compute most numbers.
I'd love to hear thoughts on why this is a good or bad idea?
Aaron Liu (Jan 15 2026 at 02:07):
what kinds of things do you expect to be easier to do with these approximate reals than with the docs#Real already in mathlib?
Cookie Guy (Jan 15 2026 at 02:09):
i want the ability to approximate reals. This would make, for example, bounding any approximable real, such as pi or e, trivial, but more in general, it allows us to use lean more easily for scientific calculation
Snir Broshi (Jan 15 2026 at 02:15):
pi is defined as 2 times the unique root of Real.cos in [1, 2], and e is defined as the sum of factorial reciprocals. How would bounding them be trivial? Wouldn't it just shift the problem to defining them as approximable reals?
Snir Broshi (Jan 15 2026 at 02:18):
btw Mathlib is missing Hurwitz's theorem, so if you're interested in approximating reals it seems fun to work on it
Cookie Guy (Jan 15 2026 at 02:25):
Snir Broshi said:
pi is defined as 2 times the unique root of
Real.cosin[1, 2], and e is defined as the sum of factorial reciprocals. How would bounding them be trivial? Wouldn't it just shift the problem to defining them as approximable reals?
i believe it should be far more natural.
lets say we define
a proof on the bound should come directly from the approximableReal arctan, which is defined as an infinite sum
alternatively, if we defined it as something more complicated like
then lean would use the proof that the limit converges as an epsilon delta as the first 'approximant', and i can imagine that this approximant is going to then use the approximant of arcsin internally, so some rather complicated stuff would be happening behind the hood, however it comes out directly from the construction of a ApproximableReal
the way we currently prove that 3.14 < π is through a rather involved proof using a recursive nested sqrt(2 + ...) and random rational numbers provided by mathematica which I honestly don't understand
In my opinion, restricting to approximable reals, while shifting the problem, makes the problem also a lot easier to solve, just a proof of convergence.
Aaron Liu (Jan 15 2026 at 02:33):
Cookie Guy said:
i want the ability to approximate reals. This would make, for example, bounding any approximable real, such as pi or e, trivial, but more in general, it allows us to use lean more easily for scientific calculation
trivial how? don't you now need to evaluate the approximation and bound its error?
Aaron Liu (Jan 15 2026 at 02:33):
or are you saying that should be a lot easier
Snir Broshi (Jan 15 2026 at 02:44):
Cookie Guy said:
i believe it should be far more natural.
...
a proof on the bound should come directly from the approximableReal arctan, which is defined as an infinite sum
...
then lean would use the proof that the limit converges as an epsilon delta as the first 'approximant', and i can imagine that this approximant is going to then use the approximant of arcsin internally, so some rather complicated stuff would be happening behind the hood, however it comes out directly from the construction of a ApproximableReal
...
In my opinion, restricting to approximable reals, while shifting the problem, makes the problem also a lot easier to solve, just a proof of convergence.
You're making bold claims without supplying any form of evidence (i.e. code) to support them. I don't see how that's any easier, but perhaps a code example would demonstrate it. Note that such an example needs to avoid importing the existing definition of pi, otherwise it might be using theorems which rely on the current definition of pi and so can't be used to change its definition.
Also, it seems like you're advocating for changing the definition of pi using inverse trig functions, which is a separate problem.
Cookie Guy (Jan 15 2026 at 02:47):
Aaron Liu said:
Cookie Guy said:
i want the ability to approximate reals. This would make, for example, bounding any approximable real, such as pi or e, trivial, but more in general, it allows us to use lean more easily for scientific calculation
trivial how? don't you now need to evaluate the approximation and bound its error?
I am imagining that ApproximableReal.approximant is a function that takes in a rational number epsilon and gives you a rational number which is closer than epsilon to the 'true value'. In my mind what will make it easier is that composition of functions comes automatically
now if i defined addition between two apporximableReal,
let a b: approximableReal, let ε be given
let a1 := a.approximant ε/2
let b1 := b.approximant ε/2
a + b
now by design, we will know that approximableReal has the property of being epsilon precise through some argument with ε = ε / 2 + ε / 2.
Using this , if we had appropriately defined pi and e, then lean would automatically know bounds on π + e
This idea could be extended to much more than just addition, such as sin : approximableReal → approximableReal would allow us to automatically argue about sin pi.
Snir Broshi (Jan 15 2026 at 02:49):
Can you please provide a concrete example of what you mean, using code? (#mwe)
Cookie Guy (Jan 15 2026 at 02:51):
yup, gimme a minute
Stepan Nesterov (Jan 15 2026 at 03:06):
It would certainly be convenient to have something like this work:
example : 23 < exp pi := by decide
but I assume that the reason it's not done with things like Approximable Reals is that it's probably very very hard and very slow
Aaron Liu (Jan 15 2026 at 03:07):
it's also not actually decidable
Stepan Nesterov (Jan 15 2026 at 03:09):
It's not decidable, but it is recursively enumerable
Stepan Nesterov (Jan 15 2026 at 03:09):
Like you can compute both sides to a certain precision and prove it
Cookie Guy (Jan 15 2026 at 03:39):
ok heres my rough draft of a mwe
it demonstrates how we could have reals with computable data that approximate
Aaron Liu (Jan 15 2026 at 03:57):
this is great for #eval! but
Aaron Liu (Jan 15 2026 at 03:57):
what about writing proofs with them
Aaron Liu (Jan 15 2026 at 03:57):
can you demonstrate how you can use these approximations to prove a bound
Junyan Xu (Jan 15 2026 at 09:24):
You might define
class Real.Approximation (r : ℝ) where
approx : ℕ → ℚ
is_approx : ∀ m, abs (approx m - r) ≤ (2 ^ m)⁻¹
and constructing instances of this class for specific real numbers, and on the other hand prove lemmas or write computable functions taking instances of this class as arguments, similarly to what I do for polynomials.
Jakub Nowak (Jan 15 2026 at 09:45):
Maybe we could change the definition of IsCauSeq from IsCauSeq abv f = ∀ ε > 0, ∃ (i : ℕ), ∀ j ≥ i, abv (f j - f i) < ε to something like
inductive IsCauSeq [Field α] [LinearOrder α] [IsStrictOrderedRing α] [Ring β] (abv : β → α) (f : ℕ → β) where
| existential (_ : ∀ ε > 0, ∃ (i : ℕ), ∀ j ≥ i, abv (f j - f i) < ε)
| computable (_ : ∀ ε > 0, { i : ℕ // ∀ j ≥ i, abv (f j - f i) < ε })
And then make Ring operations on CauSeq.Completion.Cauchy "try its best" to preserve computable when possible?
Jakub Nowak (Jan 15 2026 at 09:47):
I think instead of having this be part of the definition, having computable approximation as separate class as @Junyan Xu suggested would be cleaner. But that would require adding class instances for all definitions that output Real I think?
Jakub Nowak (Jan 15 2026 at 09:52):
Yet another idea is to have Real become a class, and have two different implementations of reals, one noncomputable and one computable.
Junyan Xu (Jan 15 2026 at 10:40):
As long as IsCauSeq is Prop it cannot carry any data for computability
It looks like your computable can carry data while existential cannot; why do you want both?
Jakub Nowak (Jan 15 2026 at 10:53):
Junyan Xu said:
As long as
IsCauSeqis Prop it cannot carry any data for computability
Ah yes, you're right, we would have to make a change in the definition of CauSeq instead of IsCauSeq.
Junyan Xu said:
It looks like your
computablecan carry data whileexistentialcannot; why do you want both?
computable one lets you extract approximations. But not all reals can be defined using computable so you still need to be able to create reals with existential constructor.
Jakub Nowak (Jan 15 2026 at 11:00):
In fact, maybe we could change definition of CauSeq to { f : ℕ → β // ∀ ε > 0, { i : ℕ // ∀ j ≥ i, abv (f j - f i) < ε } } and mark definitions of reals that require existential statement as noncomputable?
David Loeffler (Jan 15 2026 at 12:30):
Jakub Nowak said:
In fact, maybe we could change definition of CauSeq to
{ f : ℕ → β // ∀ ε > 0, { i : ℕ // ∀ j ≥ i, abv (f j - f i) < ε } }and mark definitions of reals that require existential statement asnoncomputable?
What does { f : ℕ → β // ∀ ε > 0, { i : ℕ // ∀ j ≥ i, abv (f j - f i) < ε } } mean here? I am familiar with the syntax { x : X // P x } if P : X → Prop, but I believe it isn't well-defined if P is Type-valued, as here.
Are you aiming at something like this, maybe?
structure CauSeqWithWitness where
f : ℕ → β
bound : ∀ ε > 0, ℕ
h_bound : ∀ ε > 0, ∀ i j ≥ bound ε, abs (f j - f i) < ε
And a CauchySeqWithWitness would count as being "computable" if both f and bound are computable functions?
Cookie Guy (Jan 15 2026 at 23:31):
Ok so i was doing some thinking today about this, and I realized there is a far better solution
Cookie Guy (Jan 15 2026 at 23:32):
Rather than changing the underlying type on reals, its far less intrusive to make a typeclass instance on the values, similar to how the measurability tactic does it
Cookie Guy (Jan 15 2026 at 23:35):
we can make a tag called calculability which shows how to calculate something, even if the underlying type was defined in an incalculable way
Cookie Guy (Jan 15 2026 at 23:37):
since it is now a typeclass over reals, it also allows us to make a much nicer definition of approximability
class Calculable (r : ℝ) where
/-- Given ε > 0, returns a rational approximation to r -/
approx : (ε : ℚ) → ε > 0 → ℚ
/-- The approximation is within ε of r -/
modulus : ∀ ε (ε_pos : ε > 0), |approx ε ε_pos - r| < ε
Cookie Guy (Jan 15 2026 at 23:40):
i have a working draft of it, though it does require two files to be created to allow aesop to work properly.
Cookie Guy (Jan 15 2026 at 23:42):
to make aesop work, we need to create a new file Called insert project.Calculable.Init in
with
import Aesop
import Mathlib.Init
/-!
# Calculable Rule Set
This module defines the `Calculable` Aesop rule set which is used by the
`approximation` tactic. Aesop rule sets only become visible once the file in which
they're declared is imported, so we must put this declaration into its own file.
-/
declare_aesop_rule_sets [Calculable]
Robin Arnez (Jan 15 2026 at 23:45):
There are actually already several projects for making real numbers more computable and automating proofs for interval arithmetic on real numbers, the most recent one being #general > LeanBound - interval arithmetic for Lean 4
Robin Arnez (Jan 15 2026 at 23:46):
Another one is #announce > Computable Reals for native_decide for example which works directly with native_decide (not quite decide but close)
Last updated: Feb 28 2026 at 14:05 UTC