1-- Square roots of nonnegative reals, from the least-upper-bound property.2-- 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.Sqrt8import Squares9import Order1011-- Section: Squares and order1213theorem realMulValue.square_le_of_le (A B : Real)14requires nonnegativeA : 0≤ A15requires le : A ≤ B16shows A * A ≤ B * B17proof18have nonnegativeB : 0≤ B19exact realLe.transitive with*20have first := realLe.mul_right_of_nonnegative with le, nonnegativeA21have second := realLe.mul_left_of_nonnegative with le, nonnegativeB22exact realLe.transitive with*2324theorem realMulValue.square_lt_of_lt (A B : Real)25requires nonnegativeA : 0≤ A26requires lt : A < B27shows A * A < B * B28proof29have positiveB : 0 < B30exact realLe.transitive_less with*31have le := realLess.implies_le at A, B with*32have first := realLe.mul_right_of_nonnegative with le, nonnegativeA33have second := realLess.mul_left_of_positive with lt, positiveB34exact realLe.transitive_less with*3536theorem realMulValue.le_of_square_le (A B : Real)37requires nonnegativeA : 0≤ A38requires nonnegativeB : 0≤ B39requires squares : A * A ≤ B * B40shows A ≤ B41proof42have notLess : ¬(B < A)43intro less44have strict := realMulValue.square_lt_of_lt with nonnegativeB, less45exact realLe.not_less with squares, strict46exact realLe.of_not_less with*4748theorem realMulValue.eq_of_square_eq (A B : Real)49requires nonnegativeA : 0≤ A50requires nonnegativeB : 0≤ B51requires squares : A * A = B * B52shows A = B53proof54have le : A * A ≤ B * B55rw squares56exact realLe.reflexive with*57have ge : B * B ≤ A * A58rw squares59exact realLe.reflexive with*60have ab := realMulValue.le_of_square_le at A, B with*61have ba := realMulValue.le_of_square_le at B, A with*62exact realLe.antisymmetric with*6364-- Section: Candidates below the square root6566-- The nonnegative reals whose square does not exceed X.67def sqrtCandidates (X : Real) : Set:=68 { T ∈ ℝ | (0:R) ≤ (T:R) ∧ (T:R) * (T:R) ≤ X }6970theorem sqrtCandidates.subset_reals (X : Real)71shows sqrtCandidates(X) ⊆ ℝ72proof73intros T member74obtain⟨inReals, _, _⟩:= sqrtCandidates.membership.forward with member75exact inReals7677theorem sqrtCandidates.zero (X : Real)78requires nonnegative : 0≤ X79shows realZero ∈ sqrtCandidates(X)80proof81have zeroIn : realZero ∈ ℝ bytypecheck82have zeroLe := realLe.reflexive with realZero.real83have square := realMulValue.zero_left with realZero.real84have squareLe : realZero * realZero ≤ X by rwa square85have conjunction : realZero ∈ ℝ ∧0≤ realZero ∧ realZero * realZero ≤ X byrefine⟨zeroIn, zeroLe, squareLe⟩86exact sqrtCandidates.membership.backward with conjunction8788theorem sqrtCandidates.nonempty (X : Real)89requires nonnegative : 0≤ X90shows Nonempty(sqrtCandidates(X))91proof92witness realZero93exact sqrtCandidates.zero with*9495-- Every candidate is at most X + 1: a larger T would satisfy T < T * T.96theorem sqrtCandidates.bounded (X : Real)97requires nonnegative : 0≤ X98shows RealUpperBound(sqrtCandidates(X), X +1)99proof100have boundReal : Real(X +1) bytypecheck101have subset := sqrtCandidates.subset_reals at X102unfold RealUpperBound103refine⟨boundReal, subset, _⟩104intros T member105obtain⟨inReals, nonnegativeT, squareLe⟩:= sqrtCandidates.membership.forward with member106have realT : Real(T) byexact inReals107have notLess : ¬(X +1 < T)108intro less109have one := realZero.lt_one110have oneLess : 1 < T bylinarith111have positiveT : 0 < T bylinarith112have grow : T *1 < T * T113exact realLess.mul_left_of_positive with*114have unit := realMulValue.one_right with realT115rw unit at grow116linarith117have le := realLe.of_not_less with*118exact realLe.subset with le119120-- Section: Existence121122-- The supremum of the candidates squares to X: if its square fell short, a123-- slightly larger candidate would exist; if it exceeded X, a slightly smaller124-- upper bound would.125theorem realSqrt.existence (X : Real)126requires nonnegative : 0≤ X127shows∃ T ∈ ℝ, (0:R) ≤ (T:R) ∧ (T:R) * (T:R) = X128proof129have inhabited := sqrtCandidates.nonempty with*130have bounded : ∃ B, RealUpperBound(sqrtCandidates(X), B) :=⟨X +1, sqrtCandidates.bounded at X with*⟩131obtain⟨U, least⟩:=Real.least_upper_bound_property with inhabited, bounded132have upper : RealUpperBound(sqrtCandidates(X), U)133rcases least with⟨bound, _⟩134exact bound135have minimal : ∀ B, RealUpperBound(sqrtCandidates(X), B) → U ⊆ B136rcases least with⟨_, minimal⟩137exact minimal138rcases upper with⟨realU, subsetReals, bounds⟩139have zeroMember := sqrtCandidates.zero with*140have zeroSubset := bounds with realZero, zeroMember141have nonnegativeU : 0≤ U byexact realLe.of_subset at realZero, U with realZero.real, realU, zeroSubset142have uIn : U ∈ ℝ bytypecheck143have compare : U * U = X ∨ U * U ≠ X bytauto144cases compare with equal | different145 . witness U146refine⟨uIn, nonnegativeU, equal⟩147 . have connected := realLess.connected_on148have order := connected with U * U, X, different149have one := realZero.lt_one150cases order with below | above151 . -- The square falls short: U + E is a larger candidate, for a small E.152exfalso153have positiveD : 0 < X - U * U bylinarith154have positiveW : 0 < U + U +1+ (X - U * U) bylinarith155have nonzeroW : U + U +1+ (X - U * U) ≠0156intro zeroW157rw zeroW at positiveW158linarith159have positiveE : 0 < (X - U * U) / (U + U +1+ (X - U * U))160have unfolded := realDiv.eq_mul_inv at X - U * U, U + U +1+ (X - U * U) with*161rw unfolded162have positiveInverse := realInvValue.positive at U + U +1+ (X - U * U) with*163exact realMulValue.positive with*164have cancel := realDiv.mul_right at X - U * U, U + U +1+ (X - U * U) with*165have eLessOne : (X - U * U) / (U + U +1+ (X - U * U)) < 1166have notLess : ¬(1≤ (X - U * U) / (U + U +1+ (X - U * U)))167intro oneLe168have nonnegativeW := realLess.implies_le at realZero, U + U +1+ (X - U * U) with*169have scaled := realLe.mul_right_of_nonnegative with oneLe, nonnegativeW170have oneLeft := realMulValue.one_left at U + U +1+ (X - U * U)171rw [oneLeft, cancel] at scaled172linarith173exact realLess.of_not_le with*174have eLeOne := realLess.implies_le at (X - U * U) / (U + U +1+ (X - U * U)), realOne with*175have nonnegativeE := realLess.implies_le at realZero, (X - U * U) / (U + U +1+ (X - U * U)) with*176have squareLeE : ((X - U * U) / (U + U +1+ (X - U * U))) * ((X - U * U) / (U + U +1+ (X - U * U))) ≤ (X - U * U) / (U + U +1+ (X - U * U))177have step := realLe.mul_left_of_nonnegative at (X - U * U) / (U + U +1+ (X - U * U)), realOne, (X - U * U) / (U + U +1+ (X - U * U)) with*178have unit := realMulValue.one_right at (X - U * U) / (U + U +1+ (X - U * U))179 rwa unit at step180have twoUOneLessW : U + U +1 < U + U +1+ (X - U * U) bylinarith181have scaledLess := realLess.mul_left_of_positive at U + U +1, U + U +1+ (X - U * U), (X - U * U) / (U + U +1+ (X - U * U)) with*182rw cancel at scaledLess183have expansion : (U + (X - U * U) / (U + U +1+ (X - U * U))) * (U + (X - U * U) / (U + U +1+ (X - U * U))) =184 U * U + ((U + U) * ((X - U * U) / (U + U +1+ (X - U * U))) + ((X - U * U) / (U + U +1+ (X - U * U))) * ((X - U * U) / (U + U +1+ (X - U * U))))185ring186have regroup : (U + U) * ((X - U * U) / (U + U +1+ (X - U * U))) + (X - U * U) / (U + U +1+ (X - U * U)) = ((X - U * U) / (U + U +1+ (X - U * U))) * (U + U +1)187ring188have squareLe : (U + (X - U * U) / (U + U +1+ (X - U * U))) * (U + (X - U * U) / (U + U +1+ (X - U * U))) ≤ X189linarith190have nonnegativeSum : 0≤ U + (X - U * U) / (U + U +1+ (X - U * U)) bylinarith191have sumIn : U + (X - U * U) / (U + U +1+ (X - U * U)) ∈ ℝ bytypecheck192have conjunction : U + (X - U * U) / (U + U +1+ (X - U * U)) ∈ ℝ ∧ (0:R) ≤ U + (X - U * U) / (U + U +1+ (X - U * U)) ∧ (U + (X - U * U) / (U + U +1+ (X - U * U))) * (U + (X - U * U) / (U + U +1+ (X - U * U))) ≤ X193refine⟨sumIn, nonnegativeSum, squareLe⟩194have sumMember := sqrtCandidates.membership.backward with conjunction195have sumSubset := bounds with U + (X - U * U) / (U + U +1+ (X - U * U)), sumMember196have sumLe := realLe.of_subset at U + (X - U * U) / (U + U +1+ (X - U * U)), U with*197linarith198 . -- The square exceeds X: U - E is a smaller upper bound, for a small E.199exfalso200have nonzeroU : U ≠0201intro uZero202rw uZero at above203have zeroSquare := realMulValue.zero_left with realZero.real204rw zeroSquare at above205linarith206have positiveU :=Real.positive_of_nonnegative_of_ne_zero with realU, nonnegativeU, nonzeroU207have positiveD : 0 < U * U - X bylinarith208have positiveTwoU : 0 < U + U bylinarith209have nonzeroTwoU : U + U ≠0210intro zeroTwoU211rw zeroTwoU at positiveTwoU212linarith213have positiveE : 0 < (U * U - X) / (U + U)214have unfolded := realDiv.eq_mul_inv at U * U - X, U + U with*215rw unfolded216have positiveInverse := realInvValue.positive at U + U with*217exact realMulValue.positive with*218have cancel := realDiv.mul_right at U * U - X, U + U with*219have eLessU : (U * U - X) / (U + U) < U220have notLe : ¬(U ≤ (U * U - X) / (U + U))221intro uLe222have nonnegativeTwoU := realLess.implies_le at realZero, U + U with*223have scaled := realLe.mul_right_of_nonnegative at U, (U * U - X) / (U + U), U + U with*224rw cancel at scaled225have doubled : U * (U + U) = U * U + U * U byring226have positiveSquare := realMulValue.square_positive with realU, nonzeroU227linarith228exact realLess.of_not_le with*229have positiveV : 0 < U - (U * U - X) / (U + U) bylinarith230have nonnegativeV := realLess.implies_le at realZero, U - (U * U - X) / (U + U) with*231have expansion : (U - (U * U - X) / (U + U)) * (U - (U * U - X) / (U + U)) =232 U * U - ((U * U - X) / (U + U)) * (U + U) + ((U * U - X) / (U + U)) * ((U * U - X) / (U + U))233ring234rw cancel at expansion235have nonnegativeSquare := realMulValue.square_nonnegative at (U * U - X) / (U + U)236have xLeSquare : X ≤ (U - (U * U - X) / (U + U)) * (U - (U * U - X) / (U + U)) bylinarith237have realV : Real(U - (U * U - X) / (U + U)) bytypecheck238have upperV : RealUpperBound(sqrtCandidates(X), U - (U * U - X) / (U + U))239unfold RealUpperBound240refine⟨realV, subsetReals, _⟩241intros T member242obtain⟨inReals, nonnegativeT, squareLe⟩:= sqrtCandidates.membership.forward with member243have squares : T * T ≤ (U - (U * U - X) / (U + U)) * (U - (U * U - X) / (U + U)) bylinarith244have le := realMulValue.le_of_square_le with*245exact realLe.subset with le246have uSubset := minimal with U - (U * U - X) / (U + U), upperV247have uLe := realLe.of_subset at U, U - (U * U - X) / (U + U) with*248linarith249250-- Section: The square root251252-- Nonnegative reals as a soft type, so that sqrt has a real result.253predicate NonnegativeReal (X : Set) :=Real(X) ∧ (0:R) ≤ (X:R)254255theorem NonnegativeReal.real (X : NonnegativeReal)256showsReal(X)257proof258have nonnegative : NonnegativeReal(X) byassumption259rcases nonnegative with⟨realX, _⟩260exact realX261262theorem NonnegativeReal.le (X : NonnegativeReal)263shows0≤ X264proof265have nonnegative : NonnegativeReal(X) byassumption266rcases nonnegative with⟨_, le⟩267exact le268269theorem NonnegativeReal.of_le (X : Real)270requires nonnegative : 0≤ X271shows NonnegativeReal(X)272proof273have realX : Real(X) bytypecheck274unfold NonnegativeReal275refine⟨realX, nonnegative⟩276277theorem realZero.nonnegative_real278shows NonnegativeReal(realZero)279proof280have le := realLe.reflexive with realZero.real281exact NonnegativeReal.of_le with realZero.real, le282283theorem realMulValue.square_nonnegative_real (T : Real)284shows NonnegativeReal(T * T)285proof286have le := realMulValue.square_nonnegative at T287exact NonnegativeReal.of_le with*288289theorem NonnegativeReal.mul (X Y : NonnegativeReal)290shows NonnegativeReal(X * Y)291proof292have leX := NonnegativeReal.le at X293have leY := NonnegativeReal.le at Y294have le := realMulValue.nonnegative at X, Y with*295exact NonnegativeReal.of_le with*296297theorem NonnegativeReal.add (X Y : NonnegativeReal)298shows NonnegativeReal(X + Y)299proof300have leX := NonnegativeReal.le at X301have leY := NonnegativeReal.le at Y302have step := realLe.add at realZero, X, realZero, Y with*303have zeroZero := realAddValue.zero_right with realZero.real304rw zeroZero at step305exact NonnegativeReal.of_le with*306307defunique realSqrt (X : Real) (T ∈ ℝ) := (0:R) ≤ (T:R) ∧ (T:R) * (T:R) = X308requires nonnegative : 0≤ X309proof310exact realSqrt.existence with*311uniqueness312intros T tMember first S sMember second313rcases first with⟨nonnegativeT, squareT⟩314rcases second with⟨nonnegativeS, squareS⟩315have squares : T * T = S * S316rw [squareT, squareS]317rfl318exact realMulValue.eq_of_square_eq with*319320def sqrt (X : NonnegativeReal) : Real:= realSqrt(X)321proof322have le := NonnegativeReal.le at X withassumption323have realX := NonnegativeReal.real at X withassumption324have selected := realSqrt.selected at X with realX, le325rcases selected with⟨member, _⟩326unfold sqrt327unfoldReal328exact member329330notationprefix90"√"=> sqrt forReal331332theorem sqrt.real (X : NonnegativeReal)333showsReal(√X)334proof335typecheck336337theorem sqrt.nonnegative (X : NonnegativeReal)338shows0≤√X339proof340have le := NonnegativeReal.le withassumption341have realX := NonnegativeReal.real withassumption342obtain⟨_, nonnegative, _⟩:= realSqrt.selected with le343unfold sqrt344exact nonnegative345346theorem sqrt.square (X : NonnegativeReal)347shows√X *√X = X348proof349have le := NonnegativeReal.le withassumption350obtain⟨_, _, square⟩:= realSqrt.selected with le351unfold sqrt352cc353354theorem sqrt.unique (X : NonnegativeReal) (T : Real)355requires nonnegative : 0≤ T356requires square : T * T = X357shows T =√X358proof359have rootNonnegative := sqrt.nonnegative at X360have rootSquare := sqrt.square at X361have squares : T * T =√X *√X362rw [square, rootSquare]363rfl364exact realMulValue.eq_of_square_eq with*365366theorem sqrt.of_square (T : Real)367requires nonnegative : 0≤ T368shows√(T * T) = T369proof370have squareNonnegative := realMulValue.square_nonnegative_real at T371have reflexiveSquare : T * T = T * T byrfl372have unique := sqrt.unique with squareNonnegative, nonnegative, reflexiveSquare373cc374375theorem sqrt.zero376shows√realZero = realZero377proof378have zeroNonnegative := realZero.nonnegative_real379have le := realLe.reflexive with realZero.real380have square := realMulValue.zero_left with realZero.real381have unique := sqrt.unique with*382cc383384theorem sqrt.mul (X Y : NonnegativeReal)385shows√(X * Y) =√X *√Y386proof387have productNonnegative := NonnegativeReal.mul at X, Y with*388have rootX := sqrt.nonnegative at X389have rootY := sqrt.nonnegative at Y390have squareX := sqrt.square at X391have squareY := sqrt.square at Y392have productRoots := realMulValue.nonnegative at√X, √Y with*393have identity : (√X *√Y) * (√X *√Y) = (√X *√X) * (√Y *√Y) byring394rw [squareX, squareY] at identity395have unique := sqrt.unique with*396cc397398theorem sqrt.le_of_le (X Y : Real)399requires nonnegativeX : NonnegativeReal(X)400requires nonnegativeY : NonnegativeReal(Y)401requires le : X ≤ Y402shows√X ≤√Y403proof404have rootX := sqrt.nonnegative with nonnegativeX405have rootY := sqrt.nonnegative with nonnegativeY406have squareX := sqrt.square with nonnegativeX407have squareY := sqrt.square with nonnegativeY408have squares : √X *√X ≤√Y *√Y by rwa [squareX, squareY]409exact realMulValue.le_of_square_le with*410411theorem sqrt.positive (X : NonnegativeReal)412requires nonzero : X ≠0413shows0 < √X414proof415have rootNonnegative := sqrt.nonnegative at X416have square := sqrt.square withassumption417have rootNonzero : √X ≠0418intro zero419apply nonzero420rw zero at square421have zeroSquare := realMulValue.zero_left with realZero.real422rw zeroSquare at square423cc424exactReal.positive_of_nonnegative_of_ne_zero with*425