Interval-Cauchy real sequences #
A ComputableℝSeq carries a sequence of rational intervals (ℚInterval) that
converge to a single real number, with proofs that the lower and upper rational
bounds are valid and Cauchy-equivalent. This file develops the basic interval
arithmetic on ℚInterval and the algebraic operations (addition, negation,
multiplication, inversion) on ComputableℝSeq, culminating in a commutative
semiring structure.
The interval sequence is an arbitrary function ℕ → ℚInterval, with no recursiveness
requirement, so membership in this type is not computability in the computable-analysis
sense. Addition, negation, and multiplication are executable interval arithmetic, while
sign (and hence inversion and division, which need a nonzero witness) is defined
classically and is noncomputable.
Notation ℚInterval for a nonempty rational interval.
Equations
- QInterval.termℚInterval = Lean.ParserDescr.node `QInterval.termℚInterval 1024 (Lean.ParserDescr.symbol "ℚInterval")
Instances For
A real lies in a ℚInterval when it is between the lower and upper bounds.
Equations
Instances For
Multiplication on intervals of ℚ. TODO: Should generalize to any LinearOrderedField...
Equations
- One or more equations did not get rendered due to their size.
Instances For
Multiplication of intervals by a ℚ. TODO: Should generalize to any LinearOrderedField
Equations
Instances For
Interval multiplication on ℚInterval.
Equations
Instances For
Multiplication of a ℚInterval by a rational scalar.
Equations
- QInterval.instHMulQIntervalQ = { hMul := QInterval.mulQ }
Instances For
Division of a ℚInterval by a rational scalar.
Equations
- QInterval.instHDivQIntervalQ = { hDiv := fun (x : NonemptyInterval ℚ) (y : ℚ) => x * y⁻¹ }
Instances For
The constant interval at a rational number.
Equations
- QInterval.instRatCastQInterval = { ratCast := fun (q : ℚ) => NonemptyInterval.pure q }
Instances For
The constant interval at a numeric literal.
Equations
- QInterval.instOfNatQInterval = { ofNat := NonemptyInterval.pure ↑n }
Instances For
Structure for sequences that converge to some real number from above and below. lub is a
function that gives upper and lower bounds, bundled so it can reuse computation; it is an
arbitrary function ℕ → ℚInterval, with no recursiveness requirement. hcl and hcu
assert that the two bounds are Cauchy sequences, hlub asserts that they're valid
lower and upper bounds, and heq' asserts that they converge to a common value. Use
ComputableℝSeq.mk to construct with regards to a reference real value.
The defs lb, ub are the actual CauSeq's , val is the associated real number,
and hlb, hub, and heq relate lb ub and val to each other.
- mk' :: (
- lub : ℕ → NonemptyInterval ℚ
The bundled lower and upper rational bounds at each step
n. - )
Instances For
The lower-bound Cauchy sequence of a ComputableℝSeq.
Instances For
The upper-bound Cauchy sequence of a ComputableℝSeq.
Instances For
Get the real value determined by the sequence. (Irreducibly) given here as the limit of the lower bound sequence.
Instances For
Make a computable sequence for x from a separate lower and upper bound CauSeq.
Equations
- ComputableℝSeq.mk x lub hcl hcu hlb hub heq = { lub := lub, hcl := hcl, hcu := hcu, hlub := ⋯, heq' := heq }
Instances For
All rational numbers q have a computable sequence: the constant sequence q.
Equations
- ComputableℝSeq.ofRat q = ComputableℝSeq.mk (↑q) (fun (x : ℕ) => NonemptyInterval.pure q) ⋯ ⋯ ⋯ ⋯ ⋯
Instances For
Equations
- ComputableℝSeq.natCast = { natCast := fun (n : ℕ) => ComputableℝSeq.ofRat ↑n }
Equations
- ComputableℝSeq.intCast = { intCast := fun (z : ℤ) => ComputableℝSeq.ofRat ↑z }
Equations
- ComputableℝSeq.ratCast = { ratCast := fun (q : ℚ) => ComputableℝSeq.ofRat q }
Addition of computable real sequences.
Instances For
Negation of a computable real sequence.
Instances For
Subtraction of computable real sequences.
Instances For
"Bundled" multiplication to give lower and upper bounds. This bundling avoids the need to call lb and ub separately for each half (which, in a large product, leads to an exponential slowdown). This could be further optimized to use only two ℚ multiplications instead of four, when the sign is apparent.
Equations
- x.mul' y n = QInterval.mulPair (x.lub n) (y.lub n)
Instances For
The lower bounds from mul' are precisely the same sequence as mulLb.
The upper bounds from mul' are precisely the same sequence as mulUb.
The lower bounds from mul' form a Cauchy sequence.
The upper bounds from mul' form a Cauchy sequence.
Multiplication of computable real sequences.
Instances For
Equations
- ComputableℝSeq.instComputableZero = { zero := ↑0 }
Equations
- ComputableℝSeq.instComputableOne = { one := ↑1 }
Equations
- ComputableℝSeq.instAdd = { add := ComputableℝSeq.add }
Equations
- ComputableℝSeq.instNeg = { neg := ComputableℝSeq.neg }
Equations
- ComputableℝSeq.instSub = { sub := ComputableℝSeq.sub }
Equations
- ComputableℝSeq.instMul = { mul := ComputableℝSeq.mul }
Equations
- ComputableℝSeq.instInh = { default := 0 }
The sign of x, defined classically as the sign of its real value, so this definition is
noncomputable and carries no algorithmic content. (Searching the interval sequence for a
sign witness terminates exactly when x ≠ 0 or some interval is the point 0, so a fuel-free
executable version cannot be total.) This ends up providing the DecidableEq and
DecidableLT instances on Computableℝ, which are likewise classical.
Equations
- x.sign = SignType.sign x.val
Instances For
If x is nonzero, there is eventually a point in the Cauchy sequences where either the lower or upper bound prove this. This theorem states that this point exists.
Equations
- One or more equations did not get rendered due to their size.
Instances For
With the proof that x≠0, we can also eventually get a sign witness: a number n such that either 0 < x and 0 < lb n; or that x < 0 and ub n < 0. Marking it as irreducible because in theory all of the info needed is in the return Subtype.
Equations
- x.signWitness hnz = ComputableℝSeq.definition.signWitness_aux✝ x 0 hnz
Instances For
With the proof that x≠0, we get a total comparison function.
Equations
- ComputableℝSeq.isPos hnz = decide (0 < ↑x.lb ↑(x.signWitness hnz))
Instances For
Given computable sequences for a nonzero x, drop the leading terms of both sequences (lb and ub) until both are nonzero. This gives a new sequence that we can "safely" invert.
Equations
- x.dropTilSigned hnz = ComputableℝSeq.mk x.val (fun (n : ℕ) => x.lub (↑(x.signWitness hnz) + n)) ⋯ ⋯ ⋯ ⋯ ⋯
Instances For
The sequence of lower bounds of 1/x. Only functions "correctly" to give lower bounds if we
assume that hx is already hx.dropTilSigned (as proven in lbInv_correct) -- but those
assumptions aren't need for proving that it's Cauchy.
Equations
Instances For
When applied to a dropTilSigned, lbInv is a correct lower bound on x⁻¹.
When applied to a dropTilSigned, ubInv is a correct upper bound on x⁻¹.
When applied to a dropTilSigned, lbInv is converges to x⁻¹.
When applied to a dropTilSigned, ubInv is converges to x⁻¹.
TODO: version without hnz hypothesis.
An inverse is defined only on reals that we can prove are nonzero. If we can prove they are
nonzero, then we can prove that at some point we learn the sign, and so can start giving actual
upper and lower bounds. There is a separate inv that uses sign to construct the proof of
nonzeroness by searching along the sequence (but isn't guaranteed to terminate).
Equations
- x.safeInv hnz = ComputableℝSeq.mk x.val⁻¹ (fun (n : ℕ) => { fst := ↑((x.dropTilSigned hnz).lbInv ⋯) n, snd := ↑((x.dropTilSigned hnz).ubInv ⋯) n, fst_le_snd := ⋯ }) ⋯ ⋯ ⋯ ⋯ ⋯
Instances For
Subtype of sequences with nonzero values. These admit a (terminating) inverse function.
Equations
- ComputableℝSeq.nzSeq = { x : ComputableℝSeq // x.val ≠ 0 }
Instances For
The inverse on the subtype of sequences with nonzero value.
Equations
- ComputableℝSeq.invNz x = ⟨(↑x).safeInv ⋯, ⋯⟩
Instances For
Equations
Inverse of a computable real. Will terminate if the argument is nonzero, or if it is zero and
the upper and lower bounds become exactly zero at some point. See ComputableℝSeq.sign. If you
want to only call this in a way guaranteed to terminate, use ComputableℝSeq.safeInv.
Equations
- x.inv = match h : x.sign with | SignType.pos => x.safeInv ⋯ | SignType.neg => x.safeInv ⋯ | SignType.zero => 0
Instances For
Equations
- ComputableℝSeq.instInv = { inv := ComputableℝSeq.inv }
Equations
- ComputableℝSeq.instDiv = { div := fun (x y : ComputableℝSeq) => x * y⁻¹ }
The inverse is equal to the safeInv. This is an actual equality of sequences, not just
equivalence.
Computable sequences have most of the properties of a field, including negation, subtraction, multiplication, division, IntCast all working as one would expect, with commutativity/associativity, involutive negation, and distributive properties ... except for a few crucial facts that a - a ≠ 0, a * a⁻¹ ≠ 1, and (a⁻¹)⁻¹ ≠ a. This typeclass collects all these facts together.
TODO could include mul_inv_rev, inv_eq_of_mul, intCast_ofNat, intCast_negSucc.
- add : G → G → G
- zero : G
- mul : G → G → G
- one : G
- inv : G → G
- div : G → G → G
- neg : G → G
- sub : G → G → G
- zsmul_succ' (n : ℕ) (a : G) : ComputableℝSeq.CompSeqClass.zsmul (↑n.succ) a = ComputableℝSeq.CompSeqClass.zsmul (↑n) a + a
- zsmul_neg' (n : ℕ) (a : G) : ComputableℝSeq.CompSeqClass.zsmul (Int.negSucc n) a = -ComputableℝSeq.CompSeqClass.zsmul (↑n.succ) a
Instances
Equations
- One or more equations did not get rendered due to their size.
The equivalence relation on ComputableℝSeq's given by converging to the same real value.
Equations
- ComputableℝSeq.equiv = { r := fun (f g : ComputableℝSeq) => f.val = g.val, iseqv := ComputableℝSeq.equiv._proof_1 }