Equivalence of reals

Analysis I, Chapter 5 epilogue: Isomorphism with the Mathlib real numbers

In this (technical) epilogue, we show that the "Chapter 5" real numbers Chapter5.Real : TypeChapter5.Real are isomorphic in various standard senses to the standard real numbers : Type. This we do by matching both structures with Dedekind cuts of the (Mathlib) rational numbers : Type.

From this point onwards, Chapter5.Real : TypeChapter5.Real will be deprecated, and we will use the standard real numbers : Type instead. In particular, one should use the full Mathlib API for : Type for all subsequent chapters, in lieu of the Chapter5.Real : TypeChapter5.Real API.

Filling the sorries here requires both the Chapter5.Real API and the Mathlib API for the standard natural numbers : Type. As such, they are excellent exercises to prepare you for the aforementioned transition.

Tips from past users

Users of the companion who have completed the exercises in this section are welcome to send their tips for future users in this section as PRs.

  • (Add tip here)

namespace Chapter5@[ext] structure DedekindCut where E : Set nonempty : E.Nonempty bounded : BddAbove E lower: IsLowerSet E nomax : q E, r E, r > qtheorem isLowerSet_iff (E: Set ) : IsLowerSet E q r, r < q q E r E := isLowerSet_iff_forall_ltabbrev Real.toSet_Rat (x:Real) : Set := { q | (q:Real) < x }lemma declaration uses 'sorry'Real.toSet_Rat_nonempty (x:Real) : x.toSet_Rat.Nonempty := x:Realx.toSet_Rat.Nonempty All goals completed! 🐙lemma declaration uses 'sorry'Real.toSet_Rat_bounded (x:Real) : BddAbove x.toSet_Rat := x:RealBddAbove x.toSet_Rat All goals completed! 🐙lemma declaration uses 'sorry'Real.toSet_Rat_lower (x:Real) : IsLowerSet x.toSet_Rat := x:RealIsLowerSet x.toSet_Rat All goals completed! 🐙lemma declaration uses 'sorry'Real.toSet_Rat_nomax {x:Real} : q x.toSet_Rat, r x.toSet_Rat, r > q := x:Real q x.toSet_Rat, r x.toSet_Rat, r > q All goals completed! 🐙abbrev Real.toCut (x:Real) : DedekindCut := { E := x.toSet_Rat nonempty := x.toSet_Rat_nonempty bounded := x.toSet_Rat_bounded lower := x.toSet_Rat_lower nomax := x.toSet_Rat_nomax }abbrev DedekindCut.toSet_Real (c: DedekindCut) : Set Real := (fun (q:) (q:Real)) '' c.Elemma declaration uses 'sorry'DedekindCut.toSet_Real_nonempty (c: DedekindCut) : c.toSet_Real.Nonempty := c:DedekindCutc.toSet_Real.Nonempty All goals completed! 🐙lemma declaration uses 'sorry'DedekindCut.toSet_Real_bounded (c: DedekindCut) : BddAbove c.toSet_Real := c:DedekindCutBddAbove c.toSet_Real All goals completed! 🐙noncomputable abbrev DedekindCut.toReal (c: DedekindCut) : Real := sSup c.toSet_Reallemma DedekindCut.toReal_isLUB (c: DedekindCut) : IsLUB c.toSet_Real c.toReal := ExtendedReal.sSup_of_bounded c.toSet_Real_nonempty c.toSet_Real_boundednoncomputable abbrev declaration uses 'sorry'declaration uses 'sorry'Real.equivCut : Real DedekindCut where toFun := toCut invFun := DedekindCut.toReal left_inv x := x:Realx.toCut.toReal = x All goals completed! 🐙 right_inv c := c:DedekindCutc.toReal.toCut = c All goals completed! 🐙end Chapter5

Now to develop analogous results for the Mathlib reals.

abbrev Real.toSet_Rat (x:) : Set := { q | (q:) < x }
lemma declaration uses 'sorry'Real.toSet_Rat_nonempty (x:) : x.toSet_Rat.Nonempty := x:x.toSet_Rat.Nonempty All goals completed! 🐙lemma declaration uses 'sorry'Real.toSet_Rat_bounded (x:) : BddAbove x.toSet_Rat := x:BddAbove x.toSet_Rat All goals completed! 🐙lemma declaration uses 'sorry'Real.toSet_Rat_lower (x:) : IsLowerSet x.toSet_Rat := x:IsLowerSet x.toSet_Rat All goals completed! 🐙lemma declaration uses 'sorry'Real.toSet_Rat_nomax (x:) : q x.toSet_Rat, r x.toSet_Rat, r > q := x: q x.toSet_Rat, r x.toSet_Rat, r > q All goals completed! 🐙abbrev Real.toCut (x:) : Chapter5.DedekindCut := { E := x.toSet_Rat nonempty := x.toSet_Rat_nonempty bounded := x.toSet_Rat_bounded lower := x.toSet_Rat_lower nomax := x.toSet_Rat_nomax }namespace Chapter5abbrev DedekindCut.toSet_R (c: DedekindCut) : Set := (fun (q:) (q:)) '' c.Elemma declaration uses 'sorry'DedekindCut.toSet_R_nonempty (c: DedekindCut) : c.toSet_R.Nonempty := c:DedekindCutc.toSet_R.Nonempty All goals completed! 🐙lemma declaration uses 'sorry'DedekindCut.toSet_R_bounded (c: DedekindCut) : BddAbove c.toSet_R := c:DedekindCutBddAbove c.toSet_R All goals completed! 🐙noncomputable abbrev DedekindCut.toR (c: DedekindCut) : := sSup c.toSet_Rlemma DedekindCut.toR_isLUB (c: DedekindCut) : IsLUB c.toSet_R c.toR := isLUB_csSup c.toSet_R_nonempty c.toSet_R_boundedend Chapter5noncomputable abbrev declaration uses 'sorry'declaration uses 'sorry'Real.equivCut : Chapter5.DedekindCut where toFun := _root_.Real.toCut invFun := Chapter5.DedekindCut.toR left_inv x := x:x.toCut.toR = x All goals completed! 🐙 right_inv c := c:Chapter5.DedekindCutc.toR.toCut = c All goals completed! 🐙namespace Chapter5

The isomorphism between the Chapter 5 reals and the Mathlib reals.

noncomputable abbrev Real.equivR : Real := Real.equivCut.trans _root_.Real.equivCut.symm
lemma Real.equivR_iff (x : Real) (y : ) : y = Real.equivR x y.toCut = x.toCut := x:Realy:y = equivR x y.toCut = x.toCut x:Realy:_root_.Real.equivCut y = equivCut x y.toCut = x.toCut All goals completed! 🐙-- In order to use this definition, we need some machinery ----- -- We start by showing it works for ratCasts theorem declaration uses 'sorry'Real.equivR_ratCast {q: } : equivR q = (q: ) := q:equivR q = q All goals completed! 🐙lemma Real.equivR_nat {n: } : equivR n = (n: ) := equivR_ratCastlemma Real.equivR_int {n: } : equivR n = (n: ) := equivR_ratCast---- -- We then want to set up a way to convert from the Real `LIM` to the ℝ `Real.mk` -- To do this we need a few things: -- Convertion between the notions of Cauchy Sequences theorem declaration uses 'sorry'Sequence.IsCauchy.to_IsCauSeq {a: } (ha: IsCauchy a) : IsCauSeq _root_.abs a := a: ha:(↑a).IsCauchyIsCauSeq _root_.abs a All goals completed! 🐙-- Convertion of an `IsCauchy` to a `CauSeq` abbrev Sequence.IsCauchy.CauSeq {a: } : (ha: IsCauchy a) CauSeq _root_.abs := (a, ·.to_IsCauSeq)-- We then set up the conversion from Sequence.Equiv to CauSeq.LimZero because -- it is the equivalence relation example {a b: CauSeq abs} : a b CauSeq.LimZero (a - b) := a:CauSeq absb:CauSeq absa b (a - b).LimZero All goals completed! 🐙theorem declaration uses 'sorry'Sequence.Equiv.LimZero {a b: } (ha: IsCauchy a) (hb: IsCauchy b) (h:Equiv a b) : CauSeq.LimZero (ha.CauSeq - hb.CauSeq) := a: b: ha:(↑a).IsCauchyhb:(↑b).IsCauchyh:Equiv a b(ha.CauSeq - hb.CauSeq).LimZero All goals completed! 🐙-- We can now use it to convert between different functions in Real.mk theorem Real.mk_eq_mk {a b: } (ha : Sequence.IsCauchy a) (hb : Sequence.IsCauchy b) (hab: Sequence.Equiv a b) : Real.mk ha.CauSeq = Real.mk hb.CauSeq := Real.mk_eq.mpr (hab.LimZero ha hb)-- Both directions of the equivalence theorem declaration uses 'sorry'Sequence.Equiv_iff_LimZero {a b: } (ha: IsCauchy a) (hb: IsCauchy b) : Equiv a b CauSeq.LimZero (ha.CauSeq - hb.CauSeq) := a: b: ha:(↑a).IsCauchyhb:(↑b).IsCauchyEquiv a b (ha.CauSeq - hb.CauSeq).LimZero a: b: ha:(↑a).IsCauchyhb:(↑b).IsCauchy(ha.CauSeq - hb.CauSeq).LimZero Equiv a b All goals completed! 🐙---- -- We create some cauchy sequences with useful properties -- We show that for any sequence, it will eventually be arbitrarily close to its LIM open Real in theorem declaration uses 'sorry'Sequence.difference_approaches_zero {a: } (ha: Sequence.IsCauchy a) : ε > 0, N, n N, |LIM a - a n| (ε: ) := a: ha:(↑a).IsCauchy ε > 0, N, n N, |LIM a - (a n)| ε All goals completed! 🐙-- There exists a Cauchy sequence entirely above the LIM theorem declaration uses 'sorry'Real.exists_equiv_above {a: } (ha: Sequence.IsCauchy a) : (b: ), Sequence.IsCauchy b Sequence.Equiv a b n, LIM a b n := a: ha:(↑a).IsCauchy b, (↑b).IsCauchy Sequence.Equiv a b (n : ), LIM a (b n) All goals completed! 🐙-- There exists a Cauchy sequence entirely below the LIM theorem declaration uses 'sorry'Real.exists_equiv_below {a: } (ha: Sequence.IsCauchy a) : (b: ), Sequence.IsCauchy b Sequence.Equiv a b n, b n LIM a := a: ha:(↑a).IsCauchy b, (↑b).IsCauchy Sequence.Equiv a b (n : ), (b n) LIM a All goals completed! 🐙
Real.mk_le {f g : CauSeq  abs} : Real.mk f  Real.mk g  f  g
Real.mk_le_of_forall_le {f : CauSeq  abs} {x : } (h :  i,  j  i, (f j)  x) : Real.mk f  x
Real.mk_const {x : } : Real.mk (CauSeq.const abs x) = x
-- Transform a `Real` to an `ℝ` by going through Cauchy Sequences -- we can use the conversion of Real.mk_eq to use different sequences to show different parts theorem declaration uses 'sorry'Real.equivR_eq' {a: } (ha: Sequence.IsCauchy a) : (LIM a).equivR = Real.mk ha.CauSeq := a: ha:(↑a).IsCauchyequivR (LIM a) = Real.mk ha.CauSeq a: ha:(↑a).IsCauchyhq: q, q = LIM aequivR (LIM a) = Real.mk ha.CauSeqa: ha:(↑a).IsCauchyhq:¬ q, q = LIM aequivR (LIM a) = Real.mk ha.CauSeq a: ha:(↑a).IsCauchyhq: q, q = LIM aequivR (LIM a) = Real.mk ha.CauSeq All goals completed! 🐙 a: ha:(↑a).IsCauchyhq:¬ q, q = LIM asSup (Rat.cast '' (LIM a).toSet_Rat) = Real.mk ha.CauSeq a: ha:(↑a).IsCauchyhq:¬ q, q = LIM aReal.mk ha.CauSeq upperBounds (Rat.cast '' (LIM a).toSet_Rat)a: ha:(↑a).IsCauchyhq:¬ q, q = LIM aReal.mk ha.CauSeq lowerBounds (upperBounds (Rat.cast '' (LIM a).toSet_Rat)) a: ha:(↑a).IsCauchyhq:¬ q, q = LIM aReal.mk ha.CauSeq upperBounds (Rat.cast '' (LIM a).toSet_Rat) -- show that `Real.mk ha.CauSeq` is an upper bound a: ha:(↑a).IsCauchyhq:¬ q, q = LIM aa✝:hy:a✝ Rat.cast '' (LIM a).toSet_Rata✝ Real.mk ha.CauSeq a: ha:(↑a).IsCauchyhq:¬ q, q = LIM aa✝:hy✝:a✝ Rat.cast '' (LIM a).toSet_Raty:hy:y (LIM a).toSet_Rath:y = a✝a✝ Real.mk ha.CauSeq a: ha:(↑a).IsCauchyhq:¬ q, q = LIM aa✝:hy✝:a✝ Rat.cast '' (LIM a).toSet_Raty:hy:y (LIM a).toSet_Rath:y = a✝Real.mk (CauSeq.const _root_.abs y) Real.mk ha.CauSeq All goals completed! 🐙 -- show that for any other upper bound, `Real.mk ha.CauSeq` is smaller a: ha:(↑a).IsCauchyhq:¬ q, q = LIM aM:hM:M upperBounds (Rat.cast '' (LIM a).toSet_Rat)Real.mk ha.CauSeq M All goals completed! 🐙lemma Real.equivR_eq (x: Real) : (a : ) (ha: Sequence.IsCauchy a), x = LIM a x.equivR = Real.mk ha.CauSeq := x:Real a, (ha : (↑a).IsCauchy), x = LIM a equivR x = Real.mk ha.CauSeq a: ha:(↑a).IsCauchy a_1, (ha : (↑a_1).IsCauchy), LIM a = LIM a_1 equivR (LIM a) = Real.mk ha.CauSeq All goals completed! 🐙

The isomorphism preserves order and ring operations

noncomputable abbrev declaration uses 'sorry'declaration uses 'sorry'declaration uses 'sorry'Real.equivR_ordered_ring : Real ≃+*o where toEquiv := equivR map_add' := (x y : Real), equivR.toFun (x + y) = equivR.toFun x + equivR.toFun y All goals completed! 🐙 map_mul' := (x y : Real), equivR.toFun (x * y) = equivR.toFun x * equivR.toFun y All goals completed! 🐙 map_le_map_iff' := {a b : Real}, equivR.toFun a equivR.toFun b a b All goals completed! 🐙
-- helpers for converting properties between Real and ℝ lemma Real.equivR_map_mul {x y : Real} : equivR (x * y) = equivR x * equivR y := equivR_ordered_ring.map_mul _ _lemma Real.equivR_map_inv {x: Real} : equivR (x⁻¹) = (equivR x)⁻¹ := map_inv₀ equivR_ordered_ring _theorem declaration uses 'sorry'Real.equivR_map_pos {x: Real} : 0 < x 0 < equivR x := x:Real0 < x 0 < equivR x All goals completed! 🐙theorem declaration uses 'sorry'Real.equivR_map_nonneg {x: Real} : 0 x 0 equivR x := x:Real0 x 0 equivR x All goals completed! 🐙-- Showing equivalence of the different pows theorem declaration uses 'sorry'Real.pow_of_equivR (x:Real) (n:) : equivR (x^n) = (equivR x)^n := x:Realn:equivR (x ^ n) = equivR x ^ n All goals completed! 🐙theorem declaration uses 'sorry'Real.zpow_of_equivR (x:Real) (n:) : equivR (x^n) = (equivR x)^n := x:Realn:equivR (x ^ n) = equivR x ^ n All goals completed! 🐙theorem declaration uses 'sorry'Real.ratPow_of_equivR (x:Real) (q:) : equivR (x^q) = (equivR x)^(q:) := x:Realq:equivR (x ^ q) = equivR x ^ q All goals completed! 🐙end Chapter5