1-- The geometric series: Σ X^k = 1/(1 - X) for |X| < 12-- 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.GeometricSeries8import ArchimedeanLimits910-- The partial sums (1 - X^n)/(1 - X), read as a quotient of sequences.11theorem geometricSeries.partial_sums (X : Real, n : Nat)12requires nonzero : (1:R) - X ≠013shows prefixSums(geometricTerms(X))[n] =14 divSequence(subSequence(constantSequence((1:R)), geometricTerms(X)),15 constantSequence((1:R) - X))[n]16proof17have sequence := geometricTerms.sequence at X18have ones := constantSequence.sequence at (1:R) with realOne.real19have denominatorReal := realSubValue.real at (1:R), X with20 realOne.real, assumption21have denominators := constantSequence.sequence at (1:R) - X with22 denominatorReal23have differences := subSequence.sequence with ones, sequence24have oneReal := RealSequence.value at constantSequence((1:R)), n with ones25have termReal := RealSequence.value at geometricTerms(X), n with sequence26have quotient := divSequence.value at27 subSequence(constantSequence((1:R)), geometricTerms(X)),28 constantSequence((1:R) - X), n with29 differences, denominators30have difference := subSequence.value at31 constantSequence((1:R)), geometricTerms(X), n with32 ones, sequence, oneReal, termReal33have one := constantSequence.value at (1:R), n with realOne.real, assumption34have denominator := constantSequence.value at (1:R) - X, n with35 denominatorReal, assumption36have term := geometricTerms.value at X, n with*37have value := prefixSums.value at geometricTerms(X), n with sequence38have formula := realPartialSum.geometric_quotient at X, n with nonzero39rw [value, formula, quotient, difference, one, denominator, term]40rfl4142-- Σ_{k=0}^{∞} X^k = 1/(1 - X) for |X| < 1.43theorem geometricSeries.sums_to (X : Real)44requires small : abs(X) < 145shows SumsTo(geometricTerms(X), (1:R) / ((1:R) - X))46proof47have sequence := geometricTerms.sequence at X48have prefixes := prefixSums.sequence with sequence49have absReal := abs.real at X50have upper := abs.upper at X51have belowOne : X < 1bylinarith52have denominatorPositive := realLess.iff_pos_sub.forward with belowOne53have denominatorReal := realSubValue.real at (1:R), X with54 realOne.real, assumption55have nonzero : (1:R) - X ≠056intro zero57rw zero at denominatorPositive58linarith59have ones := constantSequence.converges at (1:R) with realOne.real60have powers := geometricTerms.converges_zero with small61have numerators := ConvergesTo.sub with ones, powers62have denominators := constantSequence.converges at (1:R) - X with63 denominatorReal64have limit := ConvergesTo.div with numerators, denominators, nonzero65have zero := realSubValue.zero_right with realOne.real66rw zero at limit67have equal : ∀ n ∈ ℕ, prefixSums(geometricTerms(X))[n] =68 divSequence(subSequence(constantSequence((1:R)), geometricTerms(X)),69 constantSequence((1:R) - X))[n]70intros n naturalN71have typedN : Nat(n) byexact nat.omega.backward at n with naturalN72exact geometricSeries.partial_sums at X, n with nonzero73have converges := ConvergesTo.of_equal_terms with prefixes, limit, equal74exact SumsTo.of_converges with sequence, converges7576-- The classic instance: 1 + 1/2 + 1/4 + ⋯ = 2.77theorem geometricSeries.half_sums_to_two78shows SumsTo(geometricTerms(half((1:R))), (2:R))79proof80have halfReal := half.real with realOne.real81have halfPositive := half.positive with realZero.lt_one82have halfBelow := half.lt_self with realOne.real, realZero.lt_one83have halfNonnegative := realLess.implies_le with halfPositive84have absolute := abs.of_nonnegative with halfNonnegative85have small : abs(half((1:R))) < 1by rwa absolute86have sums := geometricSeries.sums_to with small87have doubled := half.add_self with realOne.real88have gapReal := realSubValue.real at (1:R), half((1:R)) with89 realOne.real, halfReal90have gapNonzero : (1:R) - half((1:R)) ≠091intro zero92linarith93have product : (2:R) * ((1:R) - half((1:R))) = (1:R)94have expand : (2:R) * ((1:R) - half((1:R))) =95 (2:R) - (half((1:R)) + half((1:R))) byring96rw [expand, doubled]97ring98have quotient := realDiv.of_mul_right with gapNonzero, product99rw← quotient at sums100exact sums101