1-- Infinite series as limits of partial sums2-- 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.Analysis.Series8import FiniteSum9import ExtremeValue1011-- Section: Series12-- A series sums to S when its sequence of partial sums converges to S.13predicate SumsTo (u : Set) (S : Real) :=14 RealSequence(u) ∧ ConvergesTo(prefixSums(u), S)1516predicate Summable (u : Set) :=∃ S ∈ ℝ, SumsTo(u, S)1718theorem SumsTo.sequence (u : Set) (S : Real)19requires sums : SumsTo(u, S)20shows RealSequence(u)21proof22simp [SumsTo]2324theorem SumsTo.converges (u : Set) (S : Real)25requires sums : SumsTo(u, S)26shows ConvergesTo(prefixSums(u), S)27proof28simp [SumsTo]2930theorem SumsTo.of_converges (u : Set) (S : Real)31requires sequence : RealSequence(u)32requires converges : ConvergesTo(prefixSums(u), S)33shows SumsTo(u, S)34proof35constructor36 . exact sequence37 . exact converges3839theorem SumsTo.unique (u : Set) (S T : Real)40requires sumsS : SumsTo(u, S)41requires sumsT : SumsTo(u, T)42shows S = T43proof44have convergesS := SumsTo.converges with sumsS45have convergesT := SumsTo.converges with sumsT46exact ConvergesTo.unique with convergesS, convergesT4748theorem SumsTo.summable (u : Set) (S : Real)49requires sums : SumsTo(u, S)50shows Summable(u)51proof52have realS : S ∈ ℝ bysimp [Real]53witness S54constructor55 . exact realS56 . exact sums5758-- Section: PartialSumAlgebra59-- The partial sums of a termwise sum are the sums of the partial sums.60theorem prefixSums.add (u v : Set, n : Nat)61requires sequenceU : RealSequence(u)62requires sequenceV : RealSequence(v)63shows prefixSums(addSequence(u, v))[n] =64 addSequence(prefixSums(u), prefixSums(v))[n]65proof66have added := addSequence.sequence with sequenceU, sequenceV67have prefixesU := prefixSums.sequence with sequenceU68have prefixesV := prefixSums.sequence with sequenceV69have sumU := RealSequence.value at prefixSums(u), n with prefixesU70have sumV := RealSequence.value at prefixSums(v), n with prefixesV71have valueAdded := prefixSums.value at addSequence(u, v), n with added72have valueU := prefixSums.value at u, n with sequenceU73have valueV := prefixSums.value at v, n with sequenceV74have combined := addSequence.value at prefixSums(u), prefixSums(v), n with75 prefixesU, prefixesV, sumU, sumV76have linear := realPartialSum.add at u, v, n with sequenceU, sequenceV77rw [valueAdded, combined, valueU, valueV, linear]78rfl7980theorem prefixSums.neg (u : Set, n : Nat)81requires sequence : RealSequence(u)82shows prefixSums(negSequence(u))[n] = negSequence(prefixSums(u))[n]83proof84have negated := negSequence.sequence with sequence85have prefixes := prefixSums.sequence with sequence86have sumReal := RealSequence.value at prefixSums(u), n with prefixes87have valueNegated := prefixSums.value at negSequence(u), n with negated88have valueU := prefixSums.value at u, n with sequence89have combined := negSequence.value at prefixSums(u), n with prefixes, sumReal90have linear := realPartialSum.neg at u, n with sequence91rw [valueNegated, combined, valueU, linear]92rfl9394theorem prefixSums.scale (u : Set, n : Nat, C : Real)95requires sequence : RealSequence(u)96shows prefixSums(mulSequence(constantSequence(C), u))[n] =97 mulSequence(constantSequence(C), prefixSums(u))[n]98proof99have constants := constantSequence.sequence at C100have scaled := mulSequence.sequence with constants, sequence101have prefixes := prefixSums.sequence with sequence102have constantReal := RealSequence.value at constantSequence(C), n with103 constants104have sumReal := RealSequence.value at prefixSums(u), n with prefixes105have valueScaled := prefixSums.value at106 mulSequence(constantSequence(C), u), n with scaled107have valueU := prefixSums.value at u, n with sequence108have combined := mulSequence.value at109 constantSequence(C), prefixSums(u), n with110 constants, prefixes, constantReal, sumReal111have constant := constantSequence.value at C, n with*112have linear := realPartialSum.scale at u, n, C with sequence113rw [valueScaled, combined, valueU, linear, constant]114rfl115116-- Section: SeriesAlgebra117theorem SumsTo.add (u v : Set) (S T : Real)118requires sumsU : SumsTo(u, S)119requires sumsV : SumsTo(v, T)120shows SumsTo(addSequence(u, v), S + T)121proof122have sequenceU := SumsTo.sequence with sumsU123have sequenceV := SumsTo.sequence with sumsV124have convergesU := SumsTo.converges with sumsU125have convergesV := SumsTo.converges with sumsV126have added := addSequence.sequence with sequenceU, sequenceV127have prefixes := prefixSums.sequence with added128have limit := ConvergesTo.add with convergesU, convergesV129have equal : ∀ n ∈ ℕ, prefixSums(addSequence(u, v))[n] =130 addSequence(prefixSums(u), prefixSums(v))[n]131intros n naturalN132have typedN : Nat(n) byexact nat.omega.backward at n with naturalN133exact prefixSums.add with sequenceU, sequenceV134have converges := ConvergesTo.of_equal_terms with prefixes, limit, equal135exact SumsTo.of_converges with added, converges136137theorem SumsTo.neg (u : Set) (S : Real)138requires sums : SumsTo(u, S)139shows SumsTo(negSequence(u), -S)140proof141have sequence := SumsTo.sequence with sums142have converges := SumsTo.converges with sums143have negated := negSequence.sequence with sequence144have prefixes := prefixSums.sequence with negated145have limit := ConvergesTo.neg with converges146have equal : ∀ n ∈ ℕ, prefixSums(negSequence(u))[n] =147 negSequence(prefixSums(u))[n]148intros n naturalN149have typedN : Nat(n) byexact nat.omega.backward at n with naturalN150exact prefixSums.neg with sequence151have convergesNegated := ConvergesTo.of_equal_terms with152 prefixes, limit, equal153exact SumsTo.of_converges with negated, convergesNegated154155theorem SumsTo.sub (u v : Set) (S T : Real)156requires sumsU : SumsTo(u, S)157requires sumsV : SumsTo(v, T)158shows SumsTo(subSequence(u, v), S - T)159proof160have negated := SumsTo.neg with sumsV161have added := SumsTo.add with sumsU, negated162unfold subSequence163unfold realSubValue164exact added165166theorem SumsTo.scale (u : Set) (S C : Real)167requires sums : SumsTo(u, S)168shows SumsTo(mulSequence(constantSequence(C), u), C * S)169proof170have sequence := SumsTo.sequence with sums171have converges := SumsTo.converges with sums172have constants := constantSequence.sequence at C173have scaled := mulSequence.sequence with constants, sequence174have prefixes := prefixSums.sequence with scaled175have constantConverges := constantSequence.converges at C176have limit := ConvergesTo.mul with constantConverges, converges177have equal : ∀ n ∈ ℕ,178 prefixSums(mulSequence(constantSequence(C), u))[n] =179 mulSequence(constantSequence(C), prefixSums(u))[n]180intros n naturalN181have typedN : Nat(n) byexact nat.omega.backward at n with naturalN182exact prefixSums.scale with sequence183have convergesScaled := ConvergesTo.of_equal_terms with184 prefixes, limit, equal185exact SumsTo.of_converges with scaled, convergesScaled186187-- Section: FiniteSeries188-- Beyond the index N the partial sums of a vanishing sequence stay fixed.189theorem realPartialSum.eventually_zero (u : Set, N m : Nat)190requires sequence : RealSequence(u)191requires vanishing : ∀ n ∈ ℕ, N ≤ n → u[n] = (0:R)192shows realPartialSum(u, add(N, m)) = ∑ i < N, u(i)193proof194induction m195| zero =>196rw add.right_unit197rfl198| succ(k) using ih =>199have index : Nat(add(N, k)) bytypecheck200have indexNatural := nat.omega.forward with index201have after : N≤ add(N, k) byexact LessEqual.add_right at N, k202have term := vanishing with add(N, k), indexNatural, after203have termReal := RealSequence.value at u, add(N, k) with sequence204have prefixReal := realPartialSum.real at u, N with sequence205rw [add.succ_right, realPartialSum.succ, ih]206linarith207208theorem SumsTo.of_eventually_zero (u : Set, N : Nat)209requires sequence : RealSequence(u)210requires vanishing : ∀ n ∈ ℕ, N ≤ n → u[n] = (0:R)211shows SumsTo(u, ∑ i < N, u(i))212proof213have prefixes := prefixSums.sequence with sequence214have sumReal := realPartialSum.real at u, N with sequence215have naturalN := nat.omega.forward at N withassumption216apply SumsTo.of_converges with sequence217constructor218 . exact prefixes219 . intros E realE positive220witness N221constructor222 . exact naturalN223 . intros n naturalIndex after224have typedN : Nat(n) byexact nat.omega.backward at n with naturalIndex225obtain⟨m, typedM, split⟩:= after226have value := prefixSums.value at u, n with sequence227have fixed := realPartialSum.eventually_zero at u, N, m with228 sequence, vanishing229rwsplitat fixed230rw [value, fixed]231exact openBall.center with positive232233theorem SumsTo.zero234shows SumsTo(constantSequence((0:R)), (0:R))235proof236have sequence := constantSequence.sequence at (0:R)237have vanishing : ∀ n ∈ ℕ, 0≤ n → constantSequence(0)[n] = (0:R)238intros n naturalN after239have typedN : Nat(n) byexact nat.omega.backward at n with naturalN240exact constantSequence.value at (0:R), n with*241have sums := SumsTo.of_eventually_zero at constantSequence(0), 0with242 sequence, vanishing243 rwa realPartialSum.zero at sums244245-- Section: Comparison246theorem SumsTo.le_of_le_terms (u v : Set) (S T : Real)247requires sumsU : SumsTo(u, S)248requires sumsV : SumsTo(v, T)249requiresordered : PointwiseLE(u, v)250shows S ≤ T251proof252have sequenceU := SumsTo.sequence with sumsU253have sequenceV := SumsTo.sequence with sumsV254have convergesU := SumsTo.converges with sumsU255have convergesV := SumsTo.converges with sumsV256have bounded : ∀ k ∈ ℕ, (u[k]:R) ≤ (v[k]:R)257intros k naturalK258have view :=orderedwith k, naturalK259exact realLe.characterization.backward with view260have prefixOrdered : PointwiseLE(prefixSums(u), prefixSums(v))261intros n naturalN262have typedN : Nat(n) byexact nat.omega.backward at n with naturalN263have valueU := prefixSums.value at u, n with sequenceU264have valueV := prefixSums.value at v, n with sequenceV265have comparison := realPartialSum.monotone at u, v, n with266 sequenceU, sequenceV, bounded267rw [valueU, valueV]268exact realLe.characterization.forward with comparison269exact ConvergesTo.le_of_le_terms with convergesU, convergesV, prefixOrdered270271theorem SumsTo.nonnegative (u : Set) (S : Real)272requires sums : SumsTo(u, S)273requires nonnegative : NonnegativeTerms(u)274shows0≤ S275proof276have sequence := SumsTo.sequence with sums277haveordered : PointwiseLE(constantSequence(0), u)278intros n naturalN279have typedN : Nat(n) byexact nat.omega.backward at n with naturalN280have value := constantSequence.value at (0:R), n with*281rw value282exact nonnegative with n, naturalN283exact SumsTo.le_of_le_terms with SumsTo.zero, sums, ordered284285-- Section: Summability286theorem Summable.add (u v : Set)287requires summableU : Summable(u)288requires summableV : Summable(v)289shows Summable(addSequence(u, v))290proof291obtain⟨S, realS, sumsU⟩:= summableU292obtain⟨T, realT, sumsV⟩:= summableV293have typedS : Real(S) byexact realS294have typedT : Real(T) byexact realT295have sums := SumsTo.add with sumsU, sumsV296exact SumsTo.summable with sums297298theorem Summable.neg (u : Set)299requires summable : Summable(u)300shows Summable(negSequence(u))301proof302obtain⟨S, realS, sums⟩:= summable303have typedS : Real(S) byexact realS304have negated := SumsTo.neg with sums305exact SumsTo.summable with negated306307theorem Summable.sub (u v : Set)308requires summableU : Summable(u)309requires summableV : Summable(v)310shows Summable(subSequence(u, v))311proof312obtain⟨S, realS, sumsU⟩:= summableU313obtain⟨T, realT, sumsV⟩:= summableV314have typedS : Real(S) byexact realS315have typedT : Real(T) byexact realT316have sums := SumsTo.sub with sumsU, sumsV317exact SumsTo.summable with sums318319theorem Summable.scale (u : Set) (C : Real)320requires summable : Summable(u)321shows Summable(mulSequence(constantSequence(C), u))322proof323obtain⟨S, realS, sums⟩:= summable324have typedS : Real(S) byexact realS325have scaled := SumsTo.scale at u, S, C with sums326exact SumsTo.summable with scaled327328-- Section: Tails329-- Dropping the first k terms of a convergent sequence keeps its limit.330theorem ConvergesTo.shifted (u : Set) (L : Real, k : Nat)331requires converges : ConvergesTo(u, L)332shows ConvergesTo(shiftedRealSequence(u, k), L)333proof334have sequence := ConvergesTo.sequence with converges335have shifted := shiftedRealSequence.sequence at u, k with sequence336constructor337 . exact shifted338 . intros E realE positive339obtain⟨N, naturalN, close⟩:= ConvergesTo.eventually with340 converges, positive341witness N342constructor343 . exact naturalN344 . intros n naturalIndex after345have typedN : Nat(n) byexact nat.omega.backward at n with naturalIndex346have typedBound : Nat(N) byexact nat.omega.backward at N with naturalN347have index : Nat(add(k, n)) bytypecheck348have indexNatural := nat.omega.forward with index349have below : N≤ add(k, n) byarith350have value := shiftedRealSequence.value at u, k, n with sequence351rw value352exact close with add(k, n), indexNatural, below353354-- The terms of a convergent series tend to zero: each term is the355-- difference of two consecutive partial sums.356theorem SumsTo.terms_converge_zero (u : Set) (S : Real)357requires sums : SumsTo(u, S)358shows ConvergesTo(u, (0:R))359proof360have sequence := SumsTo.sequence with sums361have converges := SumsTo.converges with sums362have prefixes := prefixSums.sequence with sequence363have shifted := ConvergesTo.shifted at prefixSums(u), S, 1with converges364have limit := ConvergesTo.sub with shifted, converges365have zero := realSubValue.self at S366rw zero at limit367have shiftedSequence := shiftedRealSequence.sequence at368 prefixSums(u), 1with prefixes369have equal : ∀ n ∈ ℕ, u[n] =370 subSequence(shiftedRealSequence(prefixSums(u), 1), prefixSums(u))[n]371intros n naturalN372have typedN : Nat(n) byexact nat.omega.backward at n with naturalN373have shiftedReal := RealSequence.value at374 shiftedRealSequence(prefixSums(u), 1), n with shiftedSequence375have prefixReal := RealSequence.value at prefixSums(u), n with prefixes376have difference := subSequence.value at377 shiftedRealSequence(prefixSums(u), 1), prefixSums(u), n with378 shiftedSequence, prefixes, shiftedReal, prefixReal379have shiftedValue := shiftedRealSequence.value at380 prefixSums(u), 1, n with prefixes381have swap := add.commutative at n, 1382have successor := add.right_one at n383have next := prefixSums.value at u, succ(n) with sequence384have current := prefixSums.value at u, n with sequence385have term := RealSequence.value at u, n with sequence386have sumReal := realPartialSum.real at u, n with sequence387rw [difference, shiftedValue, swap, successor, next, current,388 realPartialSum.succ]389ring390exact ConvergesTo.of_equal_terms with sequence, limit, equal391