This is a package for Lean4 to enable computations with real numbers. As a theorem prover, Lean happily will talk about all real numbers, including ones that cannot be computed. But most real numbers of interest can be computed. This is a package to help automatically determine certain statements about those real numbers. As a concrete example, statements like
example : Real.sqrt (1 + (1/4 : ℚ)) > Real.sqrt (2 + Real.sqrt (3 : ℕ)) / (Real.sqrt 7 - 1/2) := by
native_decide
can now be proved by native_decide
.
Background
Colloquially, a real number is often called "computable" if there is an algorithm that produces successive lower- and upper-bounds which converge to that number (although precise definitions by experts may vary), and a computable function is one that maps computable numbers to computable numbers. These sequences are all rational numbers, so that we can represent them exactly. This gives it the flavor of Interval arithmetic, but with the additional guarantee that our intervals need to converge.
For example, real addition is computable, since we can simply add the respective lower and upper bound sequences for the two summands. But computing the sign of a real is, strictly speaking, not computable: the lower bounds -1 / 2^n
and upper bounds 1 / 2^n
converge to zero, but at any finite iteration we can't rule out that they're converging to a positive or negative value. For this reason, our implementation is a partial function: when the sign is needed, it will continue evaluating all the sequence until it determines the sign; this may not terminate.
Implementation details
A ComputableℝSeq
carries the functions for lower and upper bounds, together with proofs of their validity: they are equivalent Cauchy sequences, and the lower bound (resp. upper) stays below (resp. above) the completion of the Cauchy sequence. Addition, negation, multiplication, and continuous functions can be computed on these sequences without issue.
When the sign function is needed, ComputableℝSeq.sign
gives a partial def
for computing this. Evaluating ComputableℝSeq.sign
on 4 * (1/4 : ℚ) - 1
will immediately give 0
, since the lower and upper bounds will both evaluate to zero; but Real.sqrt 2 - Real.sqrt 2
will never terminate. Computing the inverse of a ComputableℝSeq
then calls sign
appropriately. This also lets us create a Decidable (x ≤ y)
instance where x
and y
are ComputableℝSeq
.
To make this painlessly usable with native_decide
, a typeclass IsComputable (x : ℝ)
is available. This looks at the expression and tries to structurally synthesize a ComputableℝSeq
equal to the expression. This means that Real.sqrt (2 + Real.sqrt 3)
is synthesized from a series of IsComputable
instances for addition and square roots; but a local assumption like x = 3
cannot be used. Then, given a pair of IsComputable
instances on x : ℝ
and y : ℝ
, we have Decidable (x ≤ y)
.
The partial aspect means that, in general, native_decide will be able to prove any true inequality or nonequality, but is only able to provide equalities if they're structurally rational expressions.
example : Real.sqrt 2 > 4 / 3 := by --true inequality, good
native_decide
example : Real.sqrt 2 ≤ 1 + Real.sqrt 5 := by --true inequality, good
native_decide
example : Real.sqrt 2 ≠ 4 / 3 := by --true nonequality, good
native_decide
example : Real.sqrt 2 > 1 + Real.sqrt 5 := by --false inequality, gives an error that it evaluates to false
native_decide
example : 2 + 5 = 14 / 2 := by --true equality, works because only rational numbers are involved
native_decide
example : Real.sqrt 2 = Real.sqrt 2 := by --hangs, never terminate
native_decide
example : Real.sqrt 2 - Real.sqrt 2 = 0:= by --hangs
native_decide
What's supported
- Addition, negation, subtraction
- Multiplication, natural number powers
- Inverses, division, integer powers
- Casts from naturals, rationals, and
ofNat
literals Real.sqrt
TODO List
Roughly in order:
OfScientific.ofScientific
so that literals like1.2
can be handled correctly- Adding support for
Real.pi
using repeated square-roots formula - Adding support for
Real.exp
using repeated halving- This immediately gives support for
Real.sinh
,Real.cosh
,Real.tanh
- This immediately gives support for
- Adding support for
Real.log
- will require similarly "sign handling" to inverses, due to the discontinuity at zero.- This gets us
Real.arsinh
... not that it's in particularly high demand.
- This gets us
- Adding support for
Real.cos
- This gets us
Real.sin
,Real.tan
, and most importantly, real powers_ ^ _
. These rely on cosine because of their behavior with negative powers.
- This gets us
- Supporting complex numbers, as a pair of computable sequences for real and imaginary parts.
- Then using
Real.exp
andReal.sin
/Real.cos
, we getComplex.exp
; then we get trig functions on the complex numbers for free too.
- Then using
- Adding
Real.arctan
.- This gets us
Real.arcsin
andReal.arccos
, but also importantlyComplex.log
. Then fromComplex.log
we get all the trig functions' inverses on the complex numbers.
- This gets us