1-- The embedding of the rationals in the reals preserves addition2-- Part of Cumulus, the Grace17 mathematics library.3-- Copyright (c) 2026 Grant Passmore.4-- Released under the Apache License 2.0. See LICENSE in the repository root.5-- Authors: Grant Passmore67module Grace.Cumulus.Real.RationalEmbedding8import Natural9import Rat.Density1011-- The cut of a sum is the sum of the cuts. A rational below p + q splits as12-- a + b with a below p and b below q, by density; the converse is monotonicity.13theorem rationalCut.add (p q : Rational)14shows rationalCut(p + q) = rationalCut(p) + rationalCut(q)15proof16have sumReal := rationalCut.real at p + q with*17have cutForm := realAddValue.cut at rationalCut(p), rationalCut(q) with*18have addReal := realAddValue.real at rationalCut(p), rationalCut(q) with*19rw cutForm20rw cutForm at addReal21applyReal.extensionality22 . exact sumReal23 . exact addReal24 . intros r rInQ25constructor26 . intro member27obtain⟨rMember, less⟩:= rationalCut.membership.forward with member28have commuted := rationalAddValue.commutative at p, q with*29rw commuted at less30have shifted := rationalLess.sub_left at r, q, p with*31obtain⟨a, aInQ, aAbove, aBelow⟩:= rationalLess.dense at r - q, p with*32have aMember : a ∈ rationalCut(p) := rationalCut.membership.backward with⟨aInQ, aBelow⟩33have moved := rationalLess.add_left_of_sub_left at r, q, a with*34have commutedA := rationalAddValue.commutative at q, a with*35rw commutedA at moved36have shiftedA := rationalLess.sub_left at r, a, q with*37obtain⟨b, bInQ, bAbove, bBelow⟩:= rationalLess.dense at r - a, q with*38have bMember : b ∈ rationalCut(q) := rationalCut.membership.backward with⟨bInQ, bBelow⟩39have below := rationalLess.add_left_of_sub_left at r, a, b with*40rw rationalAddValue.notation at below41exact realAddCut.membership_value.backward with⟨rInQ, a, aMember, b, bMember, below⟩42 . intro member43obtain⟨rMember, a, aMember, b, bMember, below⟩:= realAddCut.membership_value.forward with member44obtain⟨aInQ, aBelow⟩:= rationalCut.membership.forward with aMember45obtain⟨bInQ, bBelow⟩:= rationalCut.membership.forward with bMember46rw← rationalAddValue.notation at below47have first := rationalLess.add_right at a, p, b with*48have second := rationalLess.add_left at b, q, p with*49have chain := rationalLess.transitive at r, a + b, p + b with*50have whole := rationalLess.transitive at r, p + b, p + q with*51apply rationalCut.membership.backward52constructor53 . exact rInQ54 . exact whole5556theorem rationalCut.zero57shows rationalCut(rationalZero) = realZero58proof59simp6061theorem rationalCut.one62shows rationalCut(rationalOne) = realOne63proof64simp6566theorem rationalCut.neg (q : Rational)67shows rationalCut(-q) = -(rationalCut(q))68proof69have cancel := rationalAddValue.neg_right at q with*70have sum := rationalCut.add at q, -q with*71rw [cancel, rationalCut.zero] at sum72linarith7374theorem rationalCut.sub (p q : Rational)75shows rationalCut(p - q) = rationalCut(p) - rationalCut(q)76proof77have negation := rationalCut.neg at q with*78unfold rationalSubValue79have sum := rationalCut.add at p, -q with*80rw [sum, negation]81unfold realSubValue82rfl8384-- The rational n, built like realNat so the two embeddings line up.85def rationalNat (n : Nat) →Set86| zero => rationalZero87| succ(k) => rationalAddValue(rationalNat(k), rationalOne)8889theorem rationalNat.zero90shows rationalNat(0) = rationalZero91proof92simp9394theorem rationalNat.succ (n : Nat)95shows rationalNat(succ(n)) = (rationalNat(n):Q) + rationalOne96proof97rw [rationalNat, rationalAddValue.notation]98rfl99100theorem rationalNat.rational (n : Nat)101showsRational(rationalNat(n))102proof103induction n104| zero =>105rw rationalNat.zero106exact rationalZero.rational107| succ(k) using ih =>108rw rationalNat.succ109exact rationalAddValue.rational at rationalNat(k), rationalOne with*110111theorem realNat.successor (n : Nat)112shows realNat(succ(n)) = (realNat(n):R) +1113proof114rw realNat.succ115unfold realAddValue116unfold call2117rfl118119theorem rationalCut.natural (n : Nat)120shows rationalCut(rationalNat(n)) = realNat(n)121proof122induction n123| zero =>124rw [rationalNat.zero, realNat.zero]125exact rationalCut.zero126| succ(k) using ih =>127rw rationalNat.succ128have sum := rationalCut.add at rationalNat(k), rationalOne with*129rw [sum, ih, rationalCut.one, realNat.successor]130rfl131132theorem rationalNat.class (n : Nat)133shows rationalNat(n) = rationalClass(n, 0, 1)134proof135induction n136| zero =>137rw rationalNat.zero138unfold rationalZero139rfl140| succ(k) using ih =>141rw [rationalNat.succ, ih]142unfold rationalOne143have oneNonzero : 1≠0144intro bad145have positive : 0 < 1byarith146rw bad at positive147exact Less.irreflexive at0with*, positive148rw rationalAddValue.notation149have classes := rationalAddValue.classes at k, 0, 1, 1, 0, 1with*150rw classes151unfold rationalClassSum152have productNonzero : 1*1≠0153have unit := mul.right_unit at1with*154 rwa unit155have equivalent : 1* (1* k +1*1) + (1*1) *0= (1*1) * succ(k) +1* (1*0+1*0) byring156exact rationalClass.eq at1* k +1*1, 1*0+1*0, 1*1, succ(k), 0, 1with*157158-- Multiplying a rational by the natural m scales its cut by realNat(m).159theorem rationalCut.mul_natural (q : Rational) (m : Nat)160shows rationalCut(q * (rationalNat(m):Q)) = rationalCut(q) * realNat(m)161proof162induction m163| zero =>164rw rationalNat.zero165have zero := rationalMulValue.zero_right at q with*166rw [zero, rationalCut.zero, realNat.zero]167ring168| succ(k) using ih =>169rw rationalNat.succ170have distribute := rationalMulValue.distributive_left at q, rationalNat(k), rationalOne with*171rw distribute172have unit := rationalMulValue.one_right at q with*173rw unit174have sum := rationalCut.add at q * (rationalNat(k):Q), q with*175rw [sum, ih, realNat.successor]176ring177178-- A rational a/m, written as the class of ((a, b), m), scales to the difference179-- of two naturals: (a − b)/m times m is a − b.180theorem rationalClass.mul_denominator (a b m : Nat)181requires nonzero : m ≠0182shows (rationalClass(a, b, m):Q) * (rationalNat(m):Q) = (rationalNat(a):Q) - (rationalNat(b):Q)183proof184have oneNonzero : 1≠0185intro bad186have positive : 0 < 1byarith187rw bad at positive188exact Less.irreflexive with*, positive189have classA := rationalNat.class at a with*190have classB := rationalNat.class at b with*191have classM := rationalNat.class at m with*192rw [classA, classB, classM]193rw rationalMulValue.notation194have product := rationalMulValue.classes at a, b, m, m, 0, 1with*195rw product196unfold rationalClassMul197unfold rationalSubValue198rw rationalNegValue.notation199have negation := rationalNegValue.classes at b, 0, 1with*200rw negation201unfold rationalClassNeg202rw rationalAddValue.notation203have sum := rationalAddValue.classes at a, 0, 1, 0, b, 1with*204rw sum205unfold rationalClassSum206have mulNonzero : m *1≠0207have unit := mul.right_unit at m with*208 rwa unit209have productNonzero : 1*1≠0210have unit := mul.right_unit at1with*211 rwa unit212have equivalent : (1*1) * (a * m + b *0) + (m *1) * (1*0+1* b) = (m *1) * (1* a +1*0) + (1*1) * (a *0+ b * m)213ring214exact rationalClass.eq with*215216theorem rationalCut.scaled (a b m : Nat)217requires nonzero : m ≠0218shows (rationalCut(rationalClass(a, b, m)):R) * (realNat(m):R) = (realNat(a):R) - (realNat(b):R)219proof220have qRational := rationalClass.rational at a, b, m with*221have scaled := rationalCut.mul_natural at rationalClass(a, b, m), m with*222rw← scaled223have integer := rationalClass.mul_denominator at a, b, m with*224rw integer225have difference := rationalCut.sub at rationalNat(a), rationalNat(b) with*226rw [difference, rationalCut.natural, rationalCut.natural]227rfl228