When asked about the mathematics of LLMs, Terence Tao noted that "any
undergraduate Math major would have all the prerequisites." It's a funny quote,
like saying any Biologist has all the prerequisites to be a
sprinter. Still, the idea of the prerequisites of Deep Learning is
kind of interesting. What if you took seriously the idea that there was a
minimal formal curriculum between Peano and LeCun that you had to follow
(I'm picturing this being taught in a French university). For instance,
I see no reason you need anything at all from Linear Algebra.
So what are the prerequisites for speedrunning Deep Learning? The answer
is 1/2 of one freshman semester -- if you are already really smart.
This estimate comes from taking the textbook from a really hard math class,
Harvard Math 55, and removing all the parts that are not useful (who needs
integrals). I'm not sure what to make of this. On the one hand, it's pretty
nice that you can formally derive MNIST from first principles. On the other
hand, it is about 3,000 lines of Lean, which seems like a lot of machinery just
to get to "move towards the downwards direction". Would be quite curious if
someone can do this much faster.
Caveat: This blog is AI slop. The math is aligned to "Baby Rudin" --
Principles of Mathematical Analysis with pointers to the relevant theorems.
Hug your local mathematician, they are having a hard year.
Basic Topology
Metric Spaces
The blue segment is the direct route; amber goes via a third point. Dashed circles mark open neighborhoods.
Left: small neighborhoods stay inside the open disk. Right: the closed disk includes its boundary limit point, although its neighborhood extends outside.
abbrevPointSet(X:Type):=X→Prop-- Points less than r away from x; the boundary is excluded.defNeighborhood(M:Metric(R:=R)X)(x:X)(r:R):PointSetX:=funy=>M.distxy<r-- Every point has a small neighborhood entirely inside the set.defIsOpen(M:Metric(R:=R)X)(E:PointSetX):Prop:=∀x,Ex→∃r,0<r∧∀y,NeighborhoodMxry→Ey-- Every neighborhood of p contains a different point of E.defLimitPoint(M:Metric(R:=R)X)(E:PointSetX)(p:X):Prop:=∀r,0<r→∃q,Eq∧q≠p∧NeighborhoodMprq-- The set contains all of its limit points.defIsClosed(M:Metric(R:=R)X)(E:PointSetX):Prop:=∀p,LimitPointMEp→Ep-- Rudin Theorem 2.19: every neighborhood is open.theoremneighborhood_open(M:Metric(R:=R)X)(x:X)(r:R):IsOpenM(NeighborhoodMxr):=byintroyhyrefine⟨r-M.distxy,byexact(Scalar.lt_iff_sub_pos__).mphy,?_⟩introzhzhaveht:=M.trianglexyzdsimp[Neighborhood]at*grind[smaller]-- Rudin Theorem 2.23: a set is open iff its complement is closed.theoremopen_iff_complement_closed(M:Metric(R:=R)X)(E:PointSetX):IsOpenME↔IsClosedM(funp=>¬Ep):=byconstructor·introhopenphlimithpobtain⟨r,hr,hinside⟩:=hopenphpobtain⟨q,houtside,_,hq⟩:=hlimitrhrexacthoutside(hinsideqhq)·introhclosedphpapplyClassical.byContradictionintrohnohavehlimit:LimitPointM(funq=>¬Eq)p:=byintrorhrhavewitness:∃q,NeighborhoodMprq∧¬Eq:=byapplyClassical.byContradictionintrohnapplyhnorefine⟨r,hr,?_⟩introqhqexactClassical.byContradiction(funhe=>hn⟨q,hq,he⟩)obtain⟨q,hq,he⟩:=witnessexact⟨q,he,funhqp=>he(hqp▸hp),hq⟩exacthclosedphlimithp-- Rudin Theorem 2.24(c), two-set case of finite intersections of open-- sets.theoremopen_inter(M:Metric(R:=R)X)(EF:PointSetX)(hE:IsOpenME)(hF:IsOpenMF):IsOpenM(funx=>Ex∧Fx):=byintrox⟨hx,hy⟩obtain⟨r,hr,hEr⟩:=hExhxobtain⟨s,hs,hFs⟩:=hFxhyrefine⟨smallerrs,bygrind[smaller],?_⟩introyhexact⟨hEry(bydsimp[Neighborhood]at*;grind[smaller]),hFsy(bydsimp[Neighborhood]at*;grind[smaller])⟩-- Rudin Theorem 2.24(a): arbitrary unions of open sets are open.theoremopen_union(M:Metric(R:=R)X)(E:ι→PointSetX)(h:∀i,IsOpenM(Ei)):IsOpenM(funx=>∃i,Eix):=byintrox⟨i,hi⟩obtain⟨r,hr,hEr⟩:=hixhiexact⟨r,hr,funyhy=>⟨i,hEryhy⟩⟩
Closures
Closing the punctured disk fills its missing center and adds its outer boundary, shown in amber.
-- The points of E together with all of its limit points.defClosure(M:Metric(R:=R)X)(E:PointSetX):PointSetX:=funp=>Ep∨LimitPointMEp-- Rudin Definition 2.26 and the proof of Theorem 2.27(a): neighborhood-- characterization of closure; extracted helper.theoremclosure_neighborhood(M:Metric(R:=R)X)(E:PointSetX)(p:X):ClosureMEp↔∀r,0<r→∃q,Eq∧M.distpq<r:=byconstructor·introhprhrrcaseshpwithhp|hp·exact⟨p,hp,bysimpa[(M.zero_iffpp).mprrfl]usinghr⟩·obtain⟨q,hq,_,hd⟩:=hprhrexact⟨q,hq,hd⟩·introhby_caseshp:Ep·exactOr.inlhp·rightintrorhrobtain⟨q,hq,hd⟩:=hrhrexact⟨q,hq,funhe=>hp(he▸hq),hd⟩-- Rudin, corollary to Theorem 2.23, closed-to-open direction.theoremclosed_complement_open(M:Metric(R:=R)X)(E:PointSetX)(hE:IsClosedME):IsOpenM(funp=>¬Ep):=byintrophpapplyClassical.byContradictionintrohnoapplyhpapplyhEpintrorhrhavehex:∃q,NeighborhoodMprq∧Eq:=byapplyClassical.byContradictionintrohnapplyhnoexact⟨r,hr,funqhqhe=>hn⟨q,hq,he⟩⟩obtain⟨q,hq,he⟩:=hexexact⟨q,he,funhqp=>hp(hqp▸he),hq⟩-- Rudin Theorem 2.27(a): the closure is closed.theoremclosure_closed(M:Metric(R:=R)X)(E:PointSetX):IsClosedM(ClosureME):=byhavehopen:IsOpenM(funp=>¬ClosureMEp):=byintrophphavehn:¬∀r,0<r→∃q,Eq∧M.distpq<r:=funh=>hp((closure_neighborhoodMEp).mprh)obtain⟨r,hr⟩:=Classical.not_forall.mphnhavehrpos:0<r:=Classical.byContradiction(funh=>hr(funhpos=>False.elim(hhpos)))refine⟨r/2,bygrind,?_⟩introqhpqhqobtain⟨z,hz,hqz⟩:=(closure_neighborhoodMEq).mphq(r/2)(bygrind)haveht:=M.trianglepqzapplyhrintro_exact⟨z,hz,bydsimp[Neighborhood]athpq;grind(ematch:=0)⟩introphpapplyClassical.byContradictionintrohnobtain⟨r,hr,houtside⟩:=hopenphnobtain⟨q,hq,_,hd⟩:=hprhrexacthoutsideqhdhq-- Rudin Theorem 2.27(c): every closed superset contains the closure.theoremclosure_minimal(M:Metric(R:=R)X)(EF:PointSetX)(hF:IsClosedMF)(hEF:∀p,Ep→Fp):∀p,ClosureMEp→Fp:=byintrophprcaseshpwithhp|hp·exacthEFphp·applyhFpintrorhrobtain⟨q,hq,hne,hd⟩:=hprhrexact⟨q,hEFqhq,hne,hd⟩-- Consequence of Rudin Theorem 2.27(c): closure preserves inclusion;-- not a separately numbered theorem.theoremclosure_mono(M:Metric(R:=R)X)(EF:PointSetX)(hEF:∀p,Ep→Fp):∀p,ClosureMEp→ClosureMFp:=closure_minimalME(ClosureMF)(closure_closedMF)(funphp=>Or.inl(hEFphp))
Compact Sets
The dashed balls cover the solid disk. Removing redundant balls leaves a finite subcover on the right. Compactness requires this for every open cover.
-- Every open cover has a finite subcover drawn from that same cover.defIsCompact(M:Metric(R:=R)X)(K:PointSetX):Prop:=∀(I:Type)(U:I→PointSetX),(∀i,IsOpenM(Ui))→(∀x,Kx→∃i,Uix)→∃selected:ListI,∀x,Kx→∃i,i∈selected∧Uix-- Helper for Rudin Theorem 2.34: choose a common positive radius for-- finitely many neighborhoods.theoremfinite_positive_radius(rs:I→R)(selected:ListI)(positive:∀i,i∈selected→0<rsi):∃r,0<r∧∀i,i∈selected→r≤rsi:=byinductionselectedwith|nil=>exact⟨1,bygrind,bysimp⟩|consiselectedih=>obtain⟨r,hr,hsmall⟩:=ih(funjhj=>positivej(List.mem_cons_of_memihj))havehi:=positivei(bysimp)refine⟨smallerr(rsi),bygrind[smaller],?_⟩introjhjsimponly[List.mem_cons]athjrcaseshjwithhj|hj·substj;grind[smaller]·have:=hsmalljhj;grind[smaller]-- Rudin Theorem 2.34: compact subsets of metric spaces are closed.theoremcompact_closed(M:Metric(R:=R)X)(K:PointSetX)(compact:IsCompactMK):IsClosedMK:=byhavehopen:IsOpenM(funp=>¬Kp):=byintrophpletQ:={q:X//Kq}letradius(q:Q):=M.distpq.val/3havepositive:∀q,0<radiusq:=byintroqhavehne:p≠q.val:=funhe=>hp(he▸q.property)havehz:=M.zero_iffpq.valhavehn:=M.nonnegpq.valdsimp[radius]grind(ematch:=0)obtain⟨selected,cover⟩:=compactQ(funq=>NeighborhoodMq.val(radiusq))(funq=>neighborhood_openMq.val(radiusq))(funqhq=>⟨⟨q,hq⟩,bychangeM.distqq<radius⟨q,hq⟩simpa[(M.zero_iffqq).mprrfl]usingpositive⟨q,hq⟩⟩)obtain⟨r,hr,hsmall⟩:=finite_positive_radiusradiusselected(funq_=>positiveq)refine⟨r,hr,?_⟩introzhpzhzobtain⟨q,hq,hqz⟩:=coverzhzhaveh₁:=hsmallqhqhaveh₂:=M.trianglepzq.valrw[M.symmzq.val]ath₂haveh₃:=positiveqdsimp[Neighborhood,radius]at*grind(ematch:=0)introphpapplyClassical.byContradictionintrohnobtain⟨r,hr,houtside⟩:=hopenphnobtain⟨q,hq,_,hd⟩:=hprhrexacthoutsideqhdhq-- Rudin Theorem 2.35: a closed subset of a compact set is compact.theoremcompact_closed_subset(M:Metric(R:=R)X)(KF:PointSetX)(hK:IsCompactMK)(hF:IsClosedMF)(hFK:∀p,Fp→Kp):IsCompactMF:=byintroIUhopencoverletV:OptionI→PointSetX|none=>funp=>¬Fp|somei=>Uihavehv:∀i,IsOpenM(Vi):=byintroicasesiwith|none=>exactclosed_complement_openMFhF|somei=>exacthopenihavehc:∀p,Kp→∃i,Vip:=byintrop_by_caseshp:Fp·obtain⟨i,hi⟩:=coverphpexact⟨somei,hi⟩·exact⟨none,hp⟩obtain⟨selected,hs⟩:=hK(OptionI)Vhvhcrefine⟨selected.filterMapid,?_⟩introphpobtain⟨i,hi,hv⟩:=hsp(hFKphp)casesiwith|none=>exactFalse.elim(hvhp)|somei=>exact⟨i,List.mem_filterMap.mpr⟨somei,hi,rfl⟩,hv⟩-- Finite-index helper for the corollary to Rudin Theorem 2.36; no-- separate Rudin theorem.theoremlist_le_max(ns:ListNat):∀n,n∈ns→n≤ns.foldrmax0:=byinductionnswith|nil=>simp|consansih=>intronhnsimponly[List.mem_cons]athnsimponly[List.foldr]rcaseshnwithhn|hn·substn;omega·have:=ihnhn;omega-- Rudin, corollary to Theorem 2.36: a nested sequence of nonempty-- compact sets has nonempty intersection.theoremnested_compact_intersection(M:Metric(R:=R)X)(K:Nat→PointSetX)(compact:∀n,IsCompactM(Kn))(nonempty:∀n,∃p,Knp)(nested:∀mn,m≤n→∀p,Knp→Kmp):∃p,∀n,Knp:=byapplyClassical.byContradictionintrohnonehavecover:∀p,K0p→∃n,¬Knp:=byintrop_applyClassical.byContradictionintrohnapplyhnoneexact⟨p,funn=>Classical.byContradiction(funh=>hn⟨n,h⟩)⟩obtain⟨ns,hns⟩:=compact0Nat(funnp=>¬Knp)(funn=>closed_complement_openM(Kn)(compact_closedM(Kn)(compactn)))coverobtain⟨p,hp⟩:=nonempty(ns.foldrmax0)obtain⟨n,hn,hnot⟩:=hnsp(nested0_(byomega)php)exacthnot(nestedn_(list_le_maxnsnhn)php)
Nested Intervals
-- Rudin Theorem 2.38: nested nonempty closed intervals have nonempty-- intersection.theoremnested_intervals(ab:Nat→R)(nonempty:∀n,an≤bn)(nested:∀mn,m≤n→am≤an∧bn≤bm):∃x,∀n,an≤x∧x≤bn:=byhavecross:∀mn,an≤bm:=byintromnhaveh₁:=(nestedn(m+n)(byomega)).1haveh₂:=nonempty(m+n)haveh₃:=(nestedm(m+n)(byomega)).2grind(ematch:=0)obtain⟨x,upper,least⟩:=RealNumbers.leastUpperBound(funy=>∃n,an=y)⟨a0,0,rfl⟩⟨b0,funy⟨n,hn⟩=>hn▸cross0n⟩refine⟨x,?_⟩intromexact⟨upper(am)⟨m,rfl⟩,least(bm)(funy⟨n,hn⟩=>hn▸crossmn)⟩-- Rudin Theorem 1.20(a), Archimedean property with unit step.theoremexists_nat_gt(x:R):∃n:Nat,x<(n:R):=byapplyClassical.byContradictionintrohhavebound:∀n:Nat,(n:R)≤x:=byintron;have:¬x<(n:R):=funhn=>h⟨n,hn⟩;grindobtain⟨s,upper,least⟩:=RealNumbers.leastUpperBound(funy:R=>∃n:Nat,(n:R)=y)⟨0,0,bygrind⟩⟨x,funy⟨n,hn⟩=>hn▸boundn⟩havesmallerBound:∀y:R,(∃n:Nat,(n:R)=y)→y≤s-1:=byintroy⟨n,hn⟩havehu:=upper((n+1:Nat):R)⟨n+1,rfl⟩grindhave:=least(s-1)smallerBoundgrind
Compactness of an Interval
Nested squares shrink around a common point until they fit inside its amber neighborhood. This is the planar analogue of nested intervals.
-- Finitely many of the given sets cover the whole closed interval.defFiniteSubcover(U:I→PointSetR)(ab:R):Prop:=∃selected:ListI,∀x,a≤x→x≤b→∃i,i∈selected∧Uix-- Proof step in Rudin Theorem 2.40, real interval case: join finite-- subcovers of the two halves.theoremfiniteSubcover_join(U:I→PointSetR)(acb:R)(left:FiniteSubcoverUac)(right:FiniteSubcoverUcb):FiniteSubcoverUab:=byobtain⟨ls,hl⟩:=leftobtain⟨rs,hr⟩:=rightrefine⟨ls++rs,?_⟩introxhaxhxbby_caseshxc:x≤c·obtain⟨i,hi,hu⟩:=hlxhaxhxcexact⟨i,List.mem_append_left_hi,hu⟩·obtain⟨i,hi,hu⟩:=hrx(bygrind)hxbexact⟨i,List.mem_append_right_hi,hu⟩-- Proof step in Rudin Theorem 2.40, real interval case: one half still-- has no finite subcover.theoreminterval_bad_half(U:I→PointSetR)(ab:R)(hab:a≤b)(bad:¬FiniteSubcoverUab):∃q:R×R,a≤q.1∧q.2≤b∧q.2-q.1=(b-a)/2∧q.1≤q.2∧¬FiniteSubcoverUq.1q.2:=byby_caseshl:FiniteSubcoverUa((a+b)/2)·refine⟨((a+b)/2,b),bygrind,bygrind,bygrind,bygrind,?_⟩exactfunhr=>bad(finiteSubcover_joinUa((a+b)/2)bhlhr)·exact⟨(a,(a+b)/2),bygrind,bygrind,bygrind,bygrind,hl⟩-- Helper for the final step of Rudin Theorem 2.40, using the-- Archimedean property, Theorem 1.20(a).theorempowers_two_unbounded(B:R):∃n:Nat,B<(2:R)^n:=byhavelower:∀n:Nat,(n:R)+1≤(2:R)^n:=byintroninductionnwith|zero=>simponly[Lean.Grind.Semiring.pow_zero];grind|succnih=>havehn:(0:R)≤(n:R):=byhave:=Scalar.natCast_le_natCast(R:=R)|>.mpr(Nat.zero_len)grindrw[Lean.Grind.Semiring.pow_succ]grindobtain⟨n,hn⟩:=exists_nat_gtBexact⟨n,byhave:=lowern;grind⟩-- Arithmetic helper for Rudin Theorem 2.40; positivity of powers of two-- is not a separate theorem there.theorempowers_two_pos(n:Nat):0<(2:R)^n:=byinductionnwith|zero=>simponly[Lean.Grind.Semiring.pow_zero];grind|succnih=>rw[Lean.Grind.Semiring.pow_succ];exactScalar.mul_posih(bygrind)-- Rudin Theorem 2.40, k = 1: every closed bounded interval is compact-- (including an empty interval here).theoreminterval_compact(ab:R):IsCompactrealMetric(funx=>a≤x∧x≤b):=byintroIUhopencoversufficesh:FiniteSubcoverUabbyobtain⟨selected,hselected⟩:=hexact⟨selected,funxhx=>hselectedxhx.1hx.2⟩by_caseshab:a≤b·applyClassical.byContradictionintrobadletBad:={q:R×R//q.1≤q.2∧¬FiniteSubcoverUq.1q.2}letnext(q:Bad):Bad:=⟨Classical.choose(interval_bad_halfUq.val.1q.val.2q.property.1q.property.2),(Classical.choose_spec(interval_bad_halfUq.val.1q.val.2q.property.1q.property.2)).2.2.2⟩letintervals:Nat→Bad:=funn=>Nat.rec⟨(a,b),hab,bad⟩(fun_q=>nextq)nletlo(n:Nat):=(intervalsn).val.1lethi(n:Nat):=(intervalsn).val.2havestep(n:Nat):lon≤lo(n+1)∧hi(n+1)≤hin∧hi(n+1)-lo(n+1)=(hin-lon)/2:=byhaveh:=Classical.choose_spec(interval_bad_halfU(lon)(hin)(intervalsn).property.1(intervalsn).property.2)exact⟨h.1,h.2.1,h.2.2.1⟩havenest:∀mn,m≤n→lom≤lon∧hin≤him:=byintromnhmninductionnwith|zero=>have:m=0:=byomegasubstmexact⟨Std.le_refl_,Std.le_refl_⟩|succnih=>by_caseshe:m=n+1·substm;exact⟨Std.le_refl_,Std.le_refl_⟩haveh:=ih(byomega)havehstep:=stepnconstructor<;>grind(ematch:=0)havelength:∀n,(hin-lon)*(2:R)^n=b-a:=byintroninductionnwith|zero=>rw[Lean.Grind.Semiring.pow_zero]change(b-a)*1=b-agrind(ematch:=0)|succnih=>rw[(stepn).2.2,Lean.Grind.Semiring.pow_succ]grind(ematch:=0)obtain⟨x,hx⟩:=nested_intervalslohi(funn=>(intervalsn).property.1)nestobtain⟨i,hix⟩:=coverx(hx0)obtain⟨r,hr,hinside⟩:=hopenixhixobtain⟨n,hn⟩:=powers_two_unbounded((b-a)/r)havenarrow:hin-lon<r:=byhavepositive:=powers_two_pos(R:=R)napply(Scalar.mul_lt_mul_rightpositive).mpcalc(hin-lon)*(2:R)^n=b-a:=lengthn_<(2:R)^n*r:=(Scalar.div_lt_iffhr).mphn_=r*(2:R)^n:=bygrind(ematch:=0)apply(intervalsn).property.2refine⟨[i],?_⟩introyhayhybrefine⟨i,bysimp,?_⟩applyhinsideychangeabs(x-y)<rrw[abs_lt]havehxn:=hxnconstructor<;>grind(ematch:=0)·exact⟨[],funxhaxhxb=>False.elim(hab(bygrind))⟩-- Interval case of Rudin Theorem 2.34 combined with Theorem 2.40;-- proved directly here.theoreminterval_closed(ab:R):IsClosedrealMetric(funx=>a≤x∧x≤b):=byintrophpconstructor·applyClassical.byContradictionintrohobtain⟨q,hq,_,hd⟩:=hp(a-p)(bygrind)changeabs(p-q)<a-pathdhave:=(abs_lt__).mphdgrind(ematch:=0)·applyClassical.byContradictionintrohobtain⟨q,hq,_,hd⟩:=hp(p-b)(bygrind)changeabs(p-q)<p-bathdhave:=(abs_lt__).mphdgrind(ematch:=0)-- Consequence of Rudin Theorem 2.41, (a) implies (b), for k = 1; used-- explicitly in the proof of Theorem 3.11(c).theorembounded_closure_compact(E:PointSetR)(ab:R)(bounded:∀p,Ep→a≤p∧p≤b):IsCompactrealMetric(ClosurerealMetricE):=compact_closed_subsetrealMetric(funx=>a≤x∧x≤b)(ClosurerealMetricE)(interval_compactab)(closure_closedrealMetricE)(closure_minimalrealMetricE_(interval_closedab)bounded)
Numerical Sequences and Series
Convergent Sequences
The sequence eventually stays inside each smaller ball around the dark limit point.
-- Eventually every term is as close as desired to the fixed limit x.defConvergesTo(M:Metric(R:=R)X)(s:Nat→X)(x:X):Prop:=∀ε:R,0<ε→∃N:Nat,∀n,N≤n→M.dist(sn)x<ε-- Rudin Theorem 3.2(b): uniqueness of a sequence limit.theoremlimit_unique(M:Metric(R:=R)X)(s:Nat→X)(xy:X)(hx:ConvergesToMsx)(hy:ConvergesToMsy):x=y:=byapplyClassical.byContradictionintrohhavehd:0<M.distxy:=byhave:=M.nonnegxyhave:=M.zero_iffxygrind[smaller]obtain⟨N,hN⟩:=hx(M.distxy/2)(bygrind[smaller])obtain⟨K,hK⟩:=hy(M.distxy/2)(bygrind[smaller])havehn:=hN(maxNK)(byomega)havehk:=hK(maxNK)(byomega)haveht:=M.trianglex(s(maxNK))yrw[M.symmx(s(maxNK))]athtgrind[smaller]
The Arithmetic of Limits
-- Rudin Definition 3.1, constant-sequence example (e), generalized to-- any real constant.theoremseq_const(a:R):ConvergesTorealMetric(fun_=>a)a:=byintroεhεrefine⟨0,?_⟩intron_changeabs(a-a)<εsimpaonly[Scalar.sub_self,abs_zero]usinghε-- Rudin Theorem 3.3(a), real case: limit of a sum.theoremseq_add(st:Nat→R)(ab:R)(hs:ConvergesTorealMetricsa)(ht:ConvergesTorealMetrictb):ConvergesTorealMetric(funn=>sn+tn)(a+b):=byintroεhεobtain⟨N,hN⟩:=hs(ε/2)(bygrind)obtain⟨K,hK⟩:=ht(ε/2)(bygrind)refine⟨maxNK,?_⟩intronhnhaveh₁:=hNn(byomega)haveh₂:=hKn(byomega)changeabs(sn-a)<ε/2ath₁changeabs(tn-b)<ε/2ath₂havehh:=abs_triangle(sn-a)(tn-b)haveheq:(sn-a)+(tn-b)=sn+tn-(a+b):=bygrindrw[heq]athhchangeabs(sn+tn-(a+b))<εgrind-- Consequence of Rudin Theorem 1.33(e), real triangle inequality; an-- auxiliary estimate.theoremabs_bound_of_error(ab:R):absa≤abs(a-b)+absb:=byhaveht:=abs_triangle(a-b)bhaveheq:a-b+b=a:=bygrind[smaller]simpaonly[heq]usinght-- Rudin Theorem 3.3(c), real case: limit of a product.theoremseq_mul(st:Nat→R)(ab:R)(hs:ConvergesTorealMetricsa)(ht:ConvergesTorealMetrictb):ConvergesTorealMetric(funn=>sn*tn)(a*b):=byintroεhεletK:=absa+absb+1haveha:=abs_nonnegahavehb:=abs_nonnegbhavehK:0<K:=bydsimp[K];grindletη:=ε/(2*K)havehη:0<η:=bydsimp[η];rw[Scalar.div_def]exactScalar.mul_poshε(Scalar.inv_pos.mpr(bygrind))havehηK:2*η*K=ε:=bydsimp[η];grindobtain⟨N,hN⟩:=hsηhηobtain⟨M,hM⟩:=ht(smallerη1)(bygrind[smaller])refine⟨maxNM,?_⟩intronhnhaveh₁:=hNn(byomega)haveh₂:=hMn(byomega)changeabs(sn-a)<ηath₁changeabs(tn-b)<smallerη1ath₂havehtb:abs(tn)≤K:=byhave:=abs_bound_of_error(tn)bdsimp[K];grind[smaller]havehab:absa≤K:=bydsimp[K];grindhavep₁:=Scalar.mul_le_mul_of_nonneg_lefthtb(abs_nonneg(sn-a))havep₂:=Scalar.mul_lt_mul_of_pos_righth₁hKhavep₃:=Scalar.mul_le_mul_of_nonneg_righthab(abs_nonneg(tn-b))havep₄:=Scalar.mul_lt_mul_of_pos_left(showabs(tn-b)<ηfrombygrind[smaller])hKhavehh:=abs_triangle((sn-a)*tn)(a*(tn-b))rw[abs_mul,abs_mul]athhhaveheq:(sn-a)*tn+a*(tn-b)=sn*tn-a*b:=bygrindrw[heq]athhchangeabs(sn*tn-a*b)<εgrind-- Rudin Theorem 1.33(a), real case: a nonzero number has positive-- absolute value.theoremabs_pos(a:R)(ha:a≠0):0<absa:=byhave:=abs_nonnegahave:=abs_eq_zeroagrind[smaller]-- Consequence of Rudin Theorem 1.33(c), real case: absolute value of a-- quotient. Lean's total division also covers a zero denominator here.theoremabs_div(ab:R):abs(a/b)=absa/absb:=byby_caseshb:b=0·substbhaveheq:a*0=0:=bygrindsimponly[Scalar.div_def,Scalar.inv_zero,heq,abs_zero]grind·havehab:absb≠0:=byintroh;exacthb((abs_eq_zerob).mph)haveheq:a/b*b=a:=bygrind[smaller]haveh:=congrArgabsheqrw[abs_mul]athgrind[smaller]-- Rudin Theorem 3.3(d), real case; this version permits finitely many-- zero terms since convergence to a nonzero limit makes the tail-- nonzero.theoremseq_inv(s:Nat→R)(a:R)(ha:a≠0)(hs:ConvergesTorealMetricsa):ConvergesTorealMetric(funn=>1/sn)(1/a):=byintroεhεhavehp:=abs_posahahavehsq:=Scalar.mul_poshphphavehη:0<ε*(absa*absa)/2:=byhave:=Scalar.mul_poshεhsqgrindobtain⟨N,hN⟩:=hs(smaller(absa/2)(ε*(absa*absa)/2))(bygrind[smaller])refine⟨N,?_⟩intronhnhaveht:=hNnhnchangeabs(sn-a)<smaller(absa/2)(ε*(absa*absa)/2)aththavehab:abs(sn-a)=abs(a-sn):=byhaveheq:sn-a=-(a-sn):=bygrindrw[heq,abs_neg]havehlo:absa/2<abs(sn):=byhavehb:=abs_bound_of_errora(sn)rw[←hab]athbgrind[smaller]havehsp:0<abs(sn):=bygrindhavehsn:sn≠0:=byintrohz;rw[hz,abs_zero]athsp;grindhavehden:=Scalar.mul_poshsphphavehmul:=Scalar.mul_lt_mul_of_pos_righthlohphavehmulε:=Scalar.mul_lt_mul_of_pos_lefthmulhεhaveheq:1/sn-1/a=(a-sn)/(sn*a):=bygrindchangeabs(1/sn-1/a)<εrw[heq,abs_div,abs_mul,←hab]apply(Scalar.div_lt_iffhden).mprgrind[smaller]-- Consequence of Rudin Theorem 3.19 for convergent sequences, comparing-- with a constant upper bound.theoremseq_le(s:Nat→R)(aB:R)(hs:ConvergesTorealMetricsa)(hb:∀n,sn≤B):a≤B:=byapplyClassical.byContradictionintrohhavehp:0<a-B:=bygrindobtain⟨N,hN⟩:=hs(a-B)hphaveht:=hNN(byomega)changeabs(sN-a)<a-Baththave:=(abs_lt__).mphthave:=hbNgrind
Cauchy Sequences
Late terms cluster together. The amber distance between two terms is bounded by the two blue distances through the limit.
-- Any two sufficiently late terms are as close as desired.defIsCauchy(M:Metric(R:=R)X)(s:Nat→X):Prop:=∀ε:R,0<ε→∃N:Nat,∀mn,N≤m→N≤n→M.dist(sm)(sn)<ε
Diameter
Nested closed disks shrink to one point; their diameters tend to zero.
-- The least upper bound of all distances between points of E.defIsDiameter(M:Metric(R:=R)X)(E:PointSetX)(d:R):Prop:=(∀pq,Ep→Eq→M.distpq≤d)∧∀b,(∀pq,Ep→Eq→M.distpq≤b)→d≤b-- Rudin Definition 3.9 with the least-upper-bound property: existence-- of a finite diameter for a nonempty bounded set.theoremdiameter_exists(M:Metric(R:=R)X)(E:PointSetX)(nonempty:∃p,Ep)(bounded:∃b,∀pq,Ep→Eq→M.distpq≤b):∃d,IsDiameterMEd:=byobtain⟨p,hp⟩:=nonemptyobtain⟨b,hb⟩:=boundedobtain⟨d,upper,least⟩:=RealNumbers.leastUpperBound(funr=>∃pq,Ep∧Eq∧M.distpq=r)⟨M.distpp,p,p,hp,hp,rfl⟩⟨b,funr⟨p,q,hp,hq,he⟩=>he▸hbpqhphq⟩exact⟨d,(funpqhphq=>upper_⟨p,q,hp,hq,rfl⟩),funchc=>leastc(funr⟨p,q,hp,hq,he⟩=>he▸hcpqhphq)⟩-- Estimate in the proof of Rudin Theorem 3.10(a): a pairwise distance-- bound also holds on the closure.theoremclosure_distance_bound(M:Metric(R:=R)X)(E:PointSetX)(d:R)(bound:∀pq,Ep→Eq→M.distpq≤d):∀pq,ClosureMEp→ClosureMEq→M.distpq≤d:=byintropqhphqapplyClassical.byContradictionintrohletε:=(M.distpq-d)/3havehε:0<ε:=bydsimp[ε];grindobtain⟨p',hp',hpp'⟩:=(closure_neighborhoodMEp).mphpεhεobtain⟨q',hq',hqq'⟩:=(closure_neighborhoodMEq).mphqεhεhaveh₁:=M.trianglepp'qhaveh₂:=M.trianglep'q'qhaveh₃:=boundp'q'hp'hq'rw[M.symmq'q]ath₂dsimp[ε]at*grind(ematch:=0)-- Rudin Theorem 3.10(a): taking the closure preserves diameter,-- expressed through the IsDiameter predicate.theoremdiameter_closure(M:Metric(R:=R)X)(E:PointSetX)(d:R)(hd:IsDiameterMEd):IsDiameterM(ClosureME)d:=byrefine⟨closure_distance_boundMEdhd.1,?_⟩introbhbexacthd.2b(funpqhphq=>hbpq(Or.inlhp)(Or.inlhq))-- Rudin Theorem 3.10(b): nonempty nested compact sets with diameters-- tending to zero have a unique common point.theoremnested_compact_shrinking(M:Metric(R:=R)X)(K:Nat→PointSetX)(compact:∀n,IsCompactM(Kn))(nonempty:∀n,∃p,Knp)(nested:∀mn,m≤n→∀p,Knp→Kmp)(d:Nat→R)(diameters:∀n,IsDiameterM(Kn)(dn))(shrinking:ConvergesTorealMetricd0):∃p,(∀n,Knp)∧∀q,(∀n,Knq)→q=p:=byobtain⟨p,hp⟩:=nested_compact_intersectionMKcompactnonemptynestedrefine⟨p,hp,?_⟩introqhqapplyClassical.byContradictionintrohnehavehdist:0<M.distqp:=byhave:=M.nonnegqphave:=M.zero_iffqpgrind(ematch:=0)obtain⟨N,hN⟩:=shrinking(M.distqp)hdisthaveh₁:=hNN(byomega)changeabs(dN-0)<M.distqpath₁haveh₂:=(diametersN).1qp(hqN)(hpN)have:=(abs_lt__).mph₁grind(ematch:=0)-- Rudin Theorem 3.11(a): every convergent sequence is Cauchy.theoremconvergent_cauchy(M:Metric(R:=R)X)(s:Nat→X)(x:X)(h:ConvergesToMsx):IsCauchyMs:=byintroεhεobtain⟨N,hN⟩:=h(ε/2)(bygrind[smaller])refine⟨N,?_⟩intromnhmhnhaveh₁:=hNmhmhaveh₂:=hNnhnhaveht:=M.triangle(sm)x(sn)rw[M.symmx(sn)]athtgrind[smaller]
Cauchy Sequences in a Compact Set
defTail(s:Nat→X)(N:Nat):PointSetX:=funp=>∃n,N≤n∧sn=p-- Finite-maximum helper for the boundedness argument in Rudin Theorem-- 3.11(c); no separate theorem.theoremfinite_upper_bound(f:Nat→R)(N:Nat):∃B,∀n,n≤N→fn≤B:=byclassicalinductionNwith|zero=>refine⟨f0,?_⟩intronhnhave:n=0:=byomegasubstnexactStd.le_refl_|succNih=>obtain⟨B,hB⟩:=ihrefine⟨ifB≤f(N+1)thenf(N+1)elseB,?_⟩intronhnby_caseshe:n=N+1·substn;split<;>grind·have:=hBn(byomega)split<;>grind-- Boundedness step in the proof of Rudin Theorem 3.11(c), formulated-- for any metric space.theoremcauchy_bounded(M:Metric(R:=R)X)(s:Nat→X)(hs:IsCauchyMs):∃B,∀mn,M.dist(sm)(sn)≤B:=byclassicalobtain⟨N,hN⟩:=hs1(bygrind)obtain⟨B,hB⟩:=finite_upper_bound(funn=>M.dist(sn)(sN))NletC:=ifB≤1then1elseBhavebound:∀n,M.dist(sn)(sN)≤C:=byintronby_caseshn:n≤N·have:=hBnhndsimp[C];split<;>grind(ematch:=0)·have:=hNnN(byomega)(byomega)dsimp[C];split<;>grind(ematch:=0)refine⟨2*C,?_⟩intromnhaveh₁:=boundmhaveh₂:=boundnhaveht:=M.triangle(sm)(sN)(sn)rw[M.symm(sN)(sn)]athtgrind(ematch:=0)-- Rudin Theorem 3.11(b): a Cauchy sequence in a compact set converges-- to a point of that set.theoremcompact_cauchy_converges(M:Metric(R:=R)X)(K:PointSetX)(compact:IsCompactMK)(s:Nat→X)(inside:∀n,K(sn))(hs:IsCauchyMs):∃p,ConvergesToMsp:=byobtain⟨B,hB⟩:=cauchy_boundedMshshavehex:∀N,∃d,IsDiameterM(TailsN)d:=byintroNapplydiameter_existsM(TailsN)⟨sN,N,byomega,rfl⟩refine⟨B,?_⟩rintropq⟨m,_,rfl⟩⟨n,_,rfl⟩exacthBmnletd(N:Nat):=Classical.choose(hexN)havehd(N:Nat):=Classical.choose_spec(hexN)letF(N:Nat):=ClosureM(TailsN)havehF:∀N,IsClosedM(FN):=funN=>closure_closedM(TailsN)havehFK:∀Np,FNp→Kp:=funN=>closure_minimalM(TailsN)K(compact_closedMKcompact)(funp⟨n,_,hn⟩=>hn▸insiden)havehcompact:∀N,IsCompactM(FN):=funN=>compact_closed_subsetMK(FN)compact(hFN)(hFKN)havehnonempty:∀N,∃p,FNp:=funN=>⟨sN,Or.inl⟨N,byomega,rfl⟩⟩havehnested:∀mn,m≤n→∀p,Fnp→Fmp:=byintromnhmnapplyclosure_monoM(Tailsn)(Tailsm)rintrop⟨k,hk,he⟩exact⟨k,byomega,he⟩havehdiam:∀N,IsDiameterM(FN)(dN):=funN=>diameter_closureM(TailsN)(dN)(hdN)havehzero:ConvergesTorealMetricd0:=byintroεhεobtain⟨N,hN⟩:=hs(ε/2)(bygrind)refine⟨N,?_⟩intronhnhavehlo:=(hdn).1(sn)(sn)⟨n,byomega,rfl⟩⟨n,byomega,rfl⟩rw[(M.zero_iff(sn)(sn)).mprrfl]athlohavehhi:dn≤ε/2:=byapply(hdn).2rintropq⟨i,hi,rfl⟩⟨j,hj,rfl⟩exactScalar.le_of_lt(hNij(byomega)(byomega))changeabs(dn-0)<εrw[abs_lt]change0≤dnathlogrind(ematch:=0)obtain⟨p,hp,_⟩:=nested_compact_shrinkingMFhcompacthnonemptyhnesteddhdiamhzerorefine⟨p,?_⟩introεhεobtain⟨N,hN⟩:=hzeroεhεrefine⟨N,?_⟩intronhnhaveh₁:=(hdiamN).1(sn)p(Or.inl⟨n,hn,rfl⟩)(hpN)haveh₂:=hNN(byomega)changeabs(dN-0)<εath₂have:=(abs_lt__).mph₂grind(ematch:=0)
defIncreasing(s:Nat→R):Prop:=∀mn,m≤n→sm≤sn-- Rudin Theorem 3.14, bounded-to-convergent direction for increasing-- real sequences.theoremincreasing_bounded_converges(s:Nat→R)(hs:Increasings)(bounded:∃b,∀n,sn≤b):∃l,ConvergesTorealMetricsl:=byobtain⟨l,upper,least⟩:=RealNumbers.leastUpperBound(funx=>∃n,sn=x)⟨s0,0,rfl⟩(byobtain⟨b,hb⟩:=bounded;exact⟨b,funx⟨n,hn⟩=>hn▸hbn⟩)refine⟨l,?_⟩introεhεhavenear:∃N,l-ε<sN:=byapplyClassical.byContradictionintrohhavehb:∀x,(∃n,sn=x)→x≤l-ε:=byintrox⟨n,hn⟩have:¬l-ε<sn:=funht=>h⟨n,ht⟩grind[smaller]have:=least(l-ε)hbgrind[smaller]obtain⟨N,hN⟩:=nearrefine⟨N,?_⟩intronhnhaveh₁:=hsNnhnhaveh₂:=upper(sn)⟨n,rfl⟩changeabs(sn-l)<εrw[abs_lt]grind[smaller]
Series
The blocks are successive terms. Their cumulative lengths give the dots below, approaching the dashed limit.
defpartialSum(a:Nat→R):Nat→R|0=>0|n+1=>partialSuman+an-- Finite-sum identity underlying Rudin Theorem 3.47; this is not yet-- the infinite-series limit statement.theorempartialSum_scale(c:R)(a:Nat→R)(n:Nat):partialSum(funk=>c*ak)n=c*partialSuman:=byinductionnwith|zero=>simponly[partialSum];grind|succnih=>simponly[partialSum,ih];grind[smaller]-- The partial sums are Cauchy: far-out finite blocks have small sums.defCauchySeries(a:Nat→R):Prop:=IsCauchyrealMetric(partialSuma)-- Rudin Theorem 3.22: the Cauchy criterion for series, expressed as the-- Cauchy property of partial sums (Definition 3.21).theoremseries_cauchy_iff_converges(a:Nat→R):CauchySeriesa↔∃l,ConvergesTorealMetric(partialSuma)l:=byconstructor·exactreal_complete(partialSuma)·rintro⟨l,hl⟩exactconvergent_cauchy___hl-- Proof step for Rudin Theorem 3.24: partial sums of nonnegative terms-- are increasing.theorempartialSum_increasing(a:Nat→R)(ha:∀n,0≤an):Increasing(partialSuma):=byintromnhmninductionnwith|zero=>have:m=0:=byomegasubstm;grind|succnih=>by_caseshe:m=n+1·substm;grindhaveih:=ih(byomega)have:=hansimponly[partialSum]grind-- Rudin Theorem 3.24, bounded-partial-sums implies convergence-- direction.theoremnonnegative_series_converges(a:Nat→R)(ha:∀n,0≤an)(bounded:∃B,∀n,partialSuman≤B):∃l,ConvergesTorealMetric(partialSuma)l:=increasing_bounded_converges_(partialSum_increasingaha)bounded-- Finite-tail comparison used in Rudin Theorem 3.25(a); extracted-- helper.theorempartialSum_tail_le(ac:Nat→R)(N:Nat)(h:∀n,N≤n→an≤cn)(k:Nat):partialSuma(N+k)-partialSumaN≤partialSumc(N+k)-partialSumcN:=byinductionkwith|zero=>simponly[Nat.add_zero];grind|succkih=>have:=h(N+k)(byomega)simponly[partialSum]grind-- Finite triangle inequality used in Rudin Theorems 3.25(a) and 3.45;-- extracted helper.theorempartialSum_abs_tail(a:Nat→R)(nk:Nat):abs(partialSuma(n+k)-partialSuman)≤partialSum(funj=>abs(aj))(n+k)-partialSum(funj=>abs(aj))n:=byinductionkwith|zero=>simponly[Nat.add_zero,Scalar.sub_self,abs_zero];grind|succkih=>haveht:=abs_triangle(partialSuma(n+k)-partialSuman)(a(n+k))haveheq:partialSuma(n+k)-partialSuman+a(n+k)=partialSuma(n+k)+a(n+k)-partialSuman:=bygrindrw[heq]athtsimponly[partialSum]grind-- Rudin Theorem 3.25(a): convergence by comparison with an eventually-- dominating series.theoremseries_comparison(ac:Nat→R)(N₀:Nat)(h:∀n,N₀≤n→abs(an)≤cn)(hc:∃l,ConvergesTorealMetric(partialSumc)l):∃l,ConvergesTorealMetric(partialSuma)l:=byapply(series_cauchy_iff_convergesa).mphavehc:=(series_cauchy_iff_convergesc).mprhcintroεhεobtain⟨N,hN⟩:=hcεhεrefine⟨maxN₀N,?_⟩intromnhmhnhaveordered:∀mn,maxN₀N≤m→m≤n→abs(partialSuman-partialSumam)<ε:=byintromnhmhmnobtain⟨k,rfl⟩:=Nat.exists_eq_add_of_lehmnhaveh₁:=partialSum_abs_tailamkhaveh₂:=partialSum_tail_le(funj=>abs(aj))cm(funjhj=>hj(byomega))khaveh₃:=hN(m+k)m(byomega)(byomega)changeabs(partialSumc(m+k)-partialSumcm)<εath₃have:=(abs_lt__).mph₃grind(ematch:=0)changeabs(partialSumam-partialSuman)<εby_caseshmn:n≤m·exactorderednmhnhmn·haveht:=orderedmnhm(byomega)haveheq:partialSumam-partialSuman=-(partialSuman-partialSumam):=bygrindsimpaonly[heq,abs_neg]usinght-- Consequence of Rudin Theorem 1.33(c), real case, by induction on the-- exponent.theoremabs_pow(x:R)(n:Nat):abs(x^n)=(absx)^n:=byinductionnwith|zero=>simponly[Lean.Grind.Semiring.pow_zero];unfoldabs;grind|succnih=>simponly[Lean.Grind.Semiring.pow_succ,abs_mul,ih]-- Elementary ordered-arithmetic helper; no separate Rudin theorem is-- claimed.theorempow_nonneg(x:R)(hx:0≤x)(n:Nat):0≤x^n:=byinductionnwith|zero=>simponly[Lean.Grind.Semiring.pow_zero];grind|succnih=>simpaonly[Lean.Grind.Semiring.pow_succ]usingScalar.mul_nonnegihhx
Series of Nonnegative Terms
Nonnegative terms make the partial sums rise. Here they remain below the dashed upper bound and settle toward a limit.
-- Finite geometric-sum identity in the proof of Rudin Theorem 3.26,-- multiplied by 1 - q.theoremgeometric_sum_mul(q:R)(n:Nat):(1-q)*partialSum(funk=>q^k)n=1-q^n:=byinductionnwith|zero=>simponly[partialSum,Lean.Grind.Semiring.pow_zero];grind|succnih=>simponly[partialSum,Lean.Grind.Semiring.pow_succ]grind-- Partial-sum estimate from Rudin Theorem 3.26; this lemma does not-- assert the infinite sum's value.theoremgeometric_partial_bound(q:R)(hq:0≤q)(hqlt:q<1)(n:Nat):partialSum(funk=>q^k)n≤1/(1-q):=byhavehp:=pow_nonnegqhqnhavehi:=geometric_sum_mulqnapply(Lean.Grind.Field.IsOrdered.mul_le_mul_iff_of_pos_right(show0<1-qfrombygrind)).mpgrind
A fixed ratio below one gives a geometric bound on the tail.
-- Geometric-tail estimate in the proof of Rudin Theorem 3.34(a).theoremratio_geometric_bound(a:Nat→R)(N:Nat)(q:R)(hq:0≤q)(ratio:∀n,N≤n→a(n+1)≤q*an)(k:Nat):a(N+k)≤aN*q^k:=byinductionkwith|zero=>simponly[Nat.add_zero,Lean.Grind.Semiring.pow_zero];grind|succkih=>haveh₁:=ratio(N+k)(byomega)haveh₂:=Scalar.mul_le_mul_of_nonneg_leftihhqsimponly[Nat.add_succ,Lean.Grind.Semiring.pow_succ]grind-- Finite-sum indexing helper for Rudin Theorem 3.34(a); no separate-- numbered theorem.theorempartialSum_shift(a:Nat→R)(Nk:Nat):partialSuma(N+k)=partialSumaN+partialSum(funj=>a(N+j))k:=byinductionkwith|zero=>simponly[Nat.add_zero,partialSum];grind|succkih=>simponly[partialSum];grind-- Partial-sum bound extracted from the proof of Rudin Theorem 3.34(a),-- for nonnegative terms and a fixed eventual ratio bound.theoremseries_bounded_of_ratio(a:Nat→R)(ha:∀n,0≤an)(N:Nat)(q:R)(hq:0≤q)(hqlt:q<1)(ratio:∀n,N≤n→a(n+1)≤q*an):∃B,∀n,partialSuman≤B:=byrefine⟨partialSumaN+aN/(1-q),?_⟩intronhavehden:0<1-q:=bygrindhavehrem:0≤aN/(1-q):=byrw[Scalar.div_def]exactScalar.mul_nonneg(haN)(Scalar.le_of_lt(Scalar.inv_pos.mprhden))by_caseshn:N≤n·obtain⟨k,rfl⟩:=Nat.exists_eq_add_of_lehnhaveh₁:=partialSum_tail_le(funj=>a(N+j))(funj=>aN*q^j)0(funj_=>ratio_geometric_boundaNqhqratioj)ksimponly[Nat.zero_add,partialSum]ath₁rw[partialSum_scale]ath₁haveh₂:=Scalar.mul_le_mul_of_nonneg_left(geometric_partial_boundqhqhqltk)(haN)rw[partialSum_shift]grind·haveh₁:=partialSum_increasingahanN(byomega)grind-- Rudin Theorem 3.34(a), sufficient fixed-ratio form for nonnegative-- terms; the limsup formulation and divergence clause are not-- formalized here.theoremratio_test(a:Nat→R)(ha:∀n,0≤an)(N:Nat)(q:R)(hq:0≤q)(hqlt:q<1)(ratio:∀n,N≤n→a(n+1)≤q*an):∃l,ConvergesTorealMetric(partialSuma)l:=nonnegative_series_convergesaha(series_bounded_of_ratioahaNqhqhqltratio)-- Special case of the estimate for Rudin Theorem 3.34(a), with eventual-- ratio at most 1/2.theoremseries_bounded_of_half(a:Nat→R)(ha:∀n,0≤an)(N:Nat)(half:∀n,N≤n→2*a(n+1)≤an):∃B,∀n,partialSuman≤B:=byapplyseries_bounded_of_ratioahaN(1/2)(bygrind)(bygrind)intronhnhave:=halfnhngrind
Power Series
Adding more terms brings the amber partial sums toward the blue exponential curve.
A small punctured input neighborhood maps inside the requested output ball. The hollow input point is excluded.
-- Near p, but excluding p, the outputs approach q.defHasLimit(M:Metric(R:=R)X)(N:Metric(R:=R)Y)(E:PointSetX)(f:X→Y)(p:X)(q:Y):Prop:=∀ε,0<ε→∃δ,0<δ∧∀x,Ex→0<M.distxp→M.distxp<δ→N.dist(fx)q<ε-- Rudin Theorem 1.20(a), reciprocal form used in the proofs of Theorems-- 3.2(d) and 4.2.theoremreciprocal_nat_small(ε:R)(hε:0<ε):∃N:Nat,∀n,N≤n→1/((n+1:Nat):R)<ε:=byobtain⟨N,hN⟩:=exists_nat_gt(1/ε)refine⟨N,?_⟩intronhnhavehcast:=Scalar.natCast_le_natCast(R:=R)|>.mprhnhavehpos:(0:R)<((n+1:Nat):R):=Scalar.natCast_pos.mpr(byomega)apply(Scalar.div_lt_iffhpos).mprhaveh:=Scalar.mul_lt_mul_of_pos_righthNhεhavehc:=Scalar.mul_le_mul_of_nonneg_righthcast(Scalar.le_of_lthε)grind(ematch:=0)-- Rudin Theorem 4.2: sequential characterization of a function limit.-- Here HasLimit is the punctured epsilon-delta predicate even without a-- limit-point hypothesis.theoremlimit_iff_sequences(M:Metric(R:=R)X)(N:Metric(R:=R)Y)(E:PointSetX)(f:X→Y)(p:X)(q:Y):HasLimitMNEfpq↔∀s:Nat→X,(∀n,E(sn))→(∀n,sn≠p)→ConvergesToMsp→ConvergesToN(funn=>f(sn))q:=byconstructor·introhfshinhnehsεhεobtain⟨δ,hδ,hfδ⟩:=hfεhεobtain⟨K,hK⟩:=hsδhδrefine⟨K,?_⟩intronhnapplyhfδ(sn)(hinn)?_(hKnhn)have:=M.nonneg(sn)phave:=M.zero_iff(sn)phave:=hnengrind(ematch:=0)·introhseqapplyClassical.byContradictionintrohnotobtain⟨ε,hbad⟩:=Classical.not_forall.mphnothavehε:0<ε:=Classical.byContradiction(funh=>hbad(funhpos=>False.elim(hhpos)))havebad:∀δ,0<δ→∃x,Ex∧0<M.distxp∧M.distxp<δ∧¬N.dist(fx)q<ε:=byintroδhδapplyClassical.byContradictionintrohnapplyhbadintro_refine⟨δ,hδ,?_⟩introxhxhphdexactClassical.byContradiction(funh=>hn⟨x,hx,hp,hd,h⟩)haveradii:∀n:Nat,(0:R)<1/((n+1:Nat):R):=byintronhavehp:(0:R)<((n+1:Nat):R):=Scalar.natCast_pos.mpr(byomega)rw[Scalar.div_def]exactScalar.mul_pos(bygrind)(Scalar.inv_pos.mprhp)lets(n:Nat):=Classical.choose(bad(1/((n+1:Nat):R))(radiin))havespec(n:Nat):=Classical.choose_spec(bad(1/((n+1:Nat):R))(radiin))havehs:ConvergesToMsp:=byintroηhηobtain⟨K,hK⟩:=reciprocal_nat_smallηhηrefine⟨K,?_⟩intronhnhaveh₁:=(specn).2.2.1haveh₂:=hKnhnchangeM.dist(sn)p<ηgrind(ematch:=0)havehne:∀n,sn≠p:=byintronhehaveh:=(specn).2.1change0<M.dist(sn)pathrw[he,(M.zero_iffpp).mprrfl]athgrind(ematch:=0)obtain⟨K,hK⟩:=hseqs(funn=>(specn).1)hnehsεhεexact(specK).2.2.2(hKK(byomega))-- Rudin Theorem 3.2(d), with the proof's stronger choice of terms-- distinct from the limit point.theoremlimitPoint_sequence(M:Metric(R:=R)X)(E:PointSetX)(p:X)(hp:LimitPointMEp):∃s:Nat→X,(∀n,E(sn))∧(∀n,sn≠p)∧ConvergesToMsp:=byhaveradii:∀n:Nat,(0:R)<1/((n+1:Nat):R):=byintronrw[Scalar.div_def]exactScalar.mul_pos(bygrind)(Scalar.inv_pos.mpr(Scalar.natCast_pos.mpr(byomega)))lets(n:Nat):=Classical.choose(hp(1/((n+1:Nat):R))(radiin))havespec(n:Nat):=Classical.choose_spec(hp(1/((n+1:Nat):R))(radiin))refine⟨s,(funn=>(specn).1),(funn=>(specn).2.1),?_⟩introεhεobtain⟨N,hN⟩:=reciprocal_nat_smallεhεrefine⟨N,?_⟩intronhnhaveh₁:=(specn).2.2changeM.distp(sn)<1/((n+1:Nat):R)ath₁rw[M.symm]ath₁haveh₂:=hNnhngrind(ematch:=0)-- Rudin, corollary to Theorem 4.2: uniqueness of a function limit at a-- limit point of its domain.theoremfunction_limit_unique(M:Metric(R:=R)X)(N:Metric(R:=R)Y)(E:PointSetX)(f:X→Y)(p:X)(qr:Y)(hp:LimitPointMEp)(hq:HasLimitMNEfpq)(hr:HasLimitMNEfpr):q=r:=byobtain⟨s,hin,hne,hs⟩:=limitPoint_sequenceMEphpexactlimit_uniqueN(funn=>f(sn))qr((limit_iff_sequencesMNEfpq).mphqshinhnehs)((limit_iff_sequencesMNEfpr).mphrshinhnehs)
A continuous map carries a compact set to a compact image.
-- Rudin Theorem 4.14: the continuous image of a compact space is-- compact.theoremcontinuous_image_compact(M:Metric(R:=R)X)(N:Metric(R:=R)Y)(f:X→Y)(hf:∀p,ContinuousAtMN(fun_=>True)fp)(compact:IsCompactM(fun_=>True)):IsCompactN(funy=>∃x,fx=y):=byintroIUhopencoverobtain⟨selected,hselected⟩:=compactI(funix=>Ui(fx))(funi=>(continuous_iff_open_preimageMNf).mphf(Ui)(hopeni))(funx_=>cover(fx)⟨x,rfl⟩)refine⟨selected,?_⟩rintroy⟨x,rfl⟩exacthselectedxtrivial-- The outputs approach a as h approaches zero, including f(0) = a.defLimitAtZero(f:R→R)(a:R):Prop:=∀ε,0<ε→∃δ,0<δ∧∀h,absh<δ→abs(fh-a)<ε-- Representation helper for Rudin Definitions 4.1 and 4.5: LimitAtZero-- includes h = 0, so it also requires f(0) = a.theoremlimitAtZero_iff(f:R→R)(a:R):LimitAtZerofa↔HasLimitrealMetricrealMetric(fun_=>True)f0a∧f0=a:=byconstructor·introhfconstructor·introεhεobtain⟨δ,hδ,hfδ⟩:=hfεhεrefine⟨δ,hδ,?_⟩introh__hhchangeabs(h-0)<δathhhavehz:h-0=h:=bygrindrw[hz]athhexacthfδhhh·applyClassical.byContradictionintrohnhavehp:=abs_pos(f0-a)(bygrind)obtain⟨δ,hδ,hfδ⟩:=hf(abs(f0-a))hphave:=hfδ0(bysimpa[abs_zero]usinghδ)grind(ematch:=0)·rintro⟨hf,hzero⟩εhεobtain⟨δ,hδ,hfδ⟩:=hfεhεrefine⟨δ,hδ,?_⟩introhhhby_caseshz:h=0·substh;simpa[hzero,Scalar.sub_self,abs_zero]usinghε·applyhfδhtrivial·change0<abs(h-0)applyabs_posgrind·changeabs(h-0)<δhaveheq:h-0=h:=bygrindsimpaonly[heq]usinghh-- Constant-function case of Rudin Definition 4.5, expressed using-- LimitAtZero; no separate theorem.theoremlimit_const(a:R):LimitAtZero(fun_=>a)a:=(limitAtZero_iff__).mpr⟨hasLimit_constrealMetric(fun_=>True)0a,rfl⟩-- Identity-function case of Rudin Examples 4.11, expressed using-- LimitAtZero.theoremlimit_id:LimitAtZero(funh:R=>h)0:=byintroεhεrefine⟨ε,hε,?_⟩introhhhhaveheq:h-0=h:=bygrindsimpaonly[heq]usinghh-- Rudin Theorem 4.9, sum clause, expressed using LimitAtZero (which-- includes the value at zero).theoremlimit_add(fg:R→R)(ab:R)(hf:LimitAtZerofa)(hg:LimitAtZerogb):LimitAtZero(funh=>fh+gh)(a+b):=byobtain⟨hf,hf0⟩:=(limitAtZero_ifffa).mphfobtain⟨hg,hg0⟩:=(limitAtZero_iffgb).mphgexact(limitAtZero_iff__).mpr⟨hasLimit_addrealMetric(fun_=>True)fg0abhfhg,byrw[hf0,hg0]⟩-- Rudin Theorem 4.9, product clause, expressed using LimitAtZero (which-- includes the value at zero).theoremlimit_mul(fg:R→R)(ab:R)(hf:LimitAtZerofa)(hg:LimitAtZerogb):LimitAtZero(funh=>fh*gh)(a*b):=byobtain⟨hf,hf0⟩:=(limitAtZero_ifffa).mphfobtain⟨hg,hg0⟩:=(limitAtZero_iffgb).mphgexact(limitAtZero_iff__).mpr⟨hasLimit_mulrealMetric(fun_=>True)fg0abhfhg,byrw[hf0,hg0]⟩-- Consequence of Rudin Theorem 4.9, expressed using LimitAtZero.theoremlimit_sub(fg:R→R)(ab:R)(hf:LimitAtZerofa)(hg:LimitAtZerogb):LimitAtZero(funh=>fh-gh)(a-b):=byobtain⟨hf,hf0⟩:=(limitAtZero_ifffa).mphfobtain⟨hg,hg0⟩:=(limitAtZero_iffgb).mphgexact(limitAtZero_iff__).mpr⟨hasLimit_subrealMetric(fun_=>True)fg0abhfhg,byrw[hf0,hg0]⟩-- Rudin Theorem 4.9, quotient clause, expressed using LimitAtZero.theoremlimit_div(fg:R→R)(ab:R)(hb:b≠0)(hf:LimitAtZerofa)(hg:LimitAtZerogb):LimitAtZero(funh=>fh/gh)(a/b):=byobtain⟨hf,hf0⟩:=(limitAtZero_ifffa).mphfobtain⟨hg,hg0⟩:=(limitAtZero_iffgb).mphgexact(limitAtZero_iff__).mpr⟨hasLimit_divrealMetric(fun_=>True)fg0abhfhghb,byrw[hf0,hg0]⟩-- Rudin Theorem 4.7 specialized to continuity at zero, expressed using-- LimitAtZero.theoremlimit_comp(fg:R→R)(a:R)(hf:LimitAtZerofa)(hg:LimitAtZerog0):LimitAtZero(funh=>f(gh))a:=byintroεhεobtain⟨δ,hδ,hfδ⟩:=hfεhεobtain⟨ρ,hρ,hgρ⟩:=hgδhδrefine⟨ρ,hρ,funhhh=>hfδ(gh)?_⟩haveht:=hgρhhhhaveheq:gh-0=gh:=bygrindsimpaonly[heq]usinght
Differentiation
The Derivative of a Real Function
As the second point approaches the amber point, the pale secant lines approach the amber tangent.
-- The slope between nearby points approaches the fixed value d.defHasDerivative(f:R→R)(xd:R):Prop:=HasLimitrealMetricrealMetric(fun_=>True)(funt=>(ft-fx)/(t-x))xd-- Equivalent form of Rudin Definition 5.1; the first-order remainder is-- used in the proof of Theorem 5.5, (4)-(5).theoremderivative_iff_remainder(f:R→R)(xd:R):HasDerivativefxd↔∀ε:R,0<ε→∃δ:R,0<δ∧∀h:R,0<absh→absh<δ→abs(f(x+h)-fx-d*h)<ε*absh:=byconstructor·introhfεhεobtain⟨δ,hδ,hfδ⟩:=hfεhεrefine⟨δ,hδ,?_⟩introhhphhhaveheq:x+h-x=h:=bygrindhaveht:=hfδ(x+h)trivial(bychange0<abs(x+h-x);simpaonly[heq]usinghp)(bychangeabs(x+h-x)<δ;simpaonly[heq]usinghh)havehn:h≠0:=byintrohz;rw[hz,abs_zero]athp;grindchangeabs((f(x+h)-fx)/(x+h-x)-d)<εathtrw[heq]aththavehid:(f(x+h)-fx)/h-d=(f(x+h)-fx-d*h)/h:=bygrindrw[hid,abs_div]athtexact(Scalar.div_lt_iffhp).mpht·introhfεhεobtain⟨δ,hδ,hfδ⟩:=hfεhεrefine⟨δ,hδ,?_⟩introt_hphhchange0<abs(t-x)athpchangeabs(t-x)<δathhhaveht:=hfδ(t-x)hphhhaveheq:x+(t-x)=t:=bygrindrw[heq]aththavehn:t-x≠0:=byintrohz;rw[hz,abs_zero]athp;grindchangeabs((ft-fx)/(t-x)-d)<εhavehid:(ft-fx)/(t-x)-d=(ft-fx-d*(t-x))/(t-x):=bygrindrw[hid,abs_div]exact(Scalar.div_lt_iffhp).mprhtdefSecant(f:R→R)(xdh:R):R:=byclassicalexactifh=0thendelse(f(x+h)-fx)/h-- Algebraic helper for the increment factorization in Rudin Theorem-- 5.5, (4)-(5); the secant is filled in at zero.theoremsecant_increment(f:R→R)(xdh:R):f(x+h)-fx=h*Secantfxdh:=byunfoldSecantsplit<;>grind[smaller]-- Reparameterization of Rudin Definition 5.1 by t = x + h, with the-- secant value at h = 0 filled in by d.theoremderivative_iff_secant_limit(f:R→R)(xd:R):HasDerivativefxd↔LimitAtZero(Secantfxd)d:=byrw[derivative_iff_remainder]constructor·introhfεhεobtain⟨δ,hδ,hf'⟩:=hfεhεrefine⟨δ,hδ,?_⟩introhhhby_caseshz:h=0·substh;rw[Secant,if_posrfl,Scalar.sub_self,abs_zero];exacthε·havehp:0<absh:=byhave:=abs_nonnegh;have:=abs_eq_zeroh;grind[smaller]havehr:=hf'hhphhhaveheq:Secantfxdh-d=(f(x+h)-fx-d*h)/h:=byunfoldSecant;rw[if_neghz];grind[smaller]rw[heq,abs_div]exact(Scalar.div_lt_iffhp).mprhr·introhfεhεobtain⟨δ,hδ,hf'⟩:=hfεhεrefine⟨δ,hδ,?_⟩introhhphhhaveht:=Scalar.mul_lt_mul_of_pos_left(hf'hhh)hphaveheq:f(x+h)-fx-d*h=h*(Secantfxdh-d):=byhave:=secant_incrementfxdhgrind[smaller]rw[heq,abs_mul]grind[smaller]-- Helper derived from Rudin Definition 5.1: a convergent factorization-- of the increment gives the derivative.theoremderivative_of_slope(fs:R→R)(xd:R)(hs:LimitAtZerosd)(he:∀h,f(x+h)-fx=h*sh):HasDerivativefxd:=byapply(derivative_iff_remainderfxd).mprintroεhεobtain⟨δ,hδ,hs'⟩:=hsεhεrefine⟨δ,hδ,?_⟩introhhphhhaveheq:f(x+h)-fx-d*h=h*(sh-d):=byrw[heh];grind[smaller]rw[heq,abs_mul]have:=Scalar.mul_lt_mul_of_pos_left(hs'hhh)hpgrind[smaller]-- Local version of the increment-factorization helper for Rudin-- Definition 5.1; no separate theorem.theoremderivative_of_local_slope(fs:R→R)(xdρ:R)(hρ:0<ρ)(hs:LimitAtZerosd)(he:∀h,absh<ρ→f(x+h)-fx=h*sh):HasDerivativefxd:=byapply(derivative_iff_remainderfxd).mprintroεhεobtain⟨δ,hδ,hs'⟩:=hsεhεrefine⟨smallerδρ,bygrind[smaller],?_⟩introhhphhhavehhρ:absh<ρ:=bygrind[smaller]haveheq:f(x+h)-fx-d*h=h*(sh-d):=byrw[hehhhρ];grind[smaller]rw[heq,abs_mul]have:=Scalar.mul_lt_mul_of_pos_left(hs'h(bygrind[smaller]))hpgrind[smaller]-- Rudin Theorem 5.2: differentiability implies continuity; here for-- functions on the whole real line.theoremderivative_continuous(f:R→R)(xd:R)(hf:HasDerivativefxd):ContinuousAtrealMetricrealMetric(fun_=>True)fx:=byhavehs:=(derivative_iff_secant_limitfxd).mphfhavehv:=limit_add(fun_=>fx)(funh=>h*Secantfxdh)(fx)(0*d)(limit_const_)(limit_mul____limit_idhs)havehval:∀h,fx+h*Secantfxdh=f(x+h):=byintrohhave:=secant_incrementfxdhgrindhaveheq:fx+0*d=fx:=bygrindrw[heq]athvsimponly[hval]athvintroεhεobtain⟨δ,hδ,hvδ⟩:=hvεhεrefine⟨δ,hδ,?_⟩introt_htchangeabs(t-x)<δaththaveh:=hvδ(t-x)hthavehid:x+(t-x)=t:=bygrindchangeabs(ft-fx)<εsimpaonly[hid]usingh-- Reparameterization of Rudin Definition 4.5 by t = x + h; helper for-- Theorem 5.5.theoremcontinuous_increment_limit(f:R→R)(x:R)(hf:ContinuousAtrealMetricrealMetric(fun_=>True)fx):LimitAtZero(funh=>f(x+h))(fx):=byintroεhεobtain⟨δ,hδ,hfδ⟩:=hfεhεrefine⟨δ,hδ,?_⟩introhhhapplyhfδ(x+h)trivialchangeabs(x+h-x)<δhaveheq:x+h-x=h:=bygrindsimpaonly[heq]usinghh
The Arithmetic of Derivatives
The product changes by two thin strips; the corner is second-order.
A line keeps the same slope; the parabola and reciprocal curve have changing slopes.
-- Helper from Rudin Definition 5.1 for the constant and linear cases in-- Examples 5.4.theoremderivative_of_exact_increment(f:R→R)(xd:R)(hf:∀h,f(x+h)-fx=d*h):HasDerivativefxd:=byapply(derivative_iff_remainderfxd).mprintroεhεrefine⟨1,bygrind[smaller],?_⟩introhhp_rw[hfh]simpa[Scalar.sub_self,abs_zero]usingScalar.mul_poshεhp-- Rudin Examples 5.4: derivative of a constant.theoremderivative_const(cx:R):HasDerivative(fun_=>c)x0:=byapplyderivative_of_exact_incrementintroh;grind[smaller]-- Rudin Examples 5.4: derivative of the identity function.theoremderivative_id(x:R):HasDerivative(funt=>t)x1:=byapplyderivative_of_exact_incrementintroh;grind[smaller]-- Affine-polynomial case of Rudin Examples 5.4, using Theorem-- 5.3(a),(b).theoremderivative_affine(wbx:R):HasDerivative(funt=>w*t+b)xw:=byapplyderivative_of_exact_incrementintroh;grind[smaller]-- Rudin Examples 5.4, integer-power rule with exponent 2.theoremderivative_square(x:R):HasDerivative(funt=>t*t)x(2*x):=byhaveh:=derivative_mul(funt=>t)(funt=>t)x11(derivative_idx)(derivative_idx)haveheq:1*x+x*1=2*x:=bygrindsimpaonly[heq]usingh-- Rudin Examples 5.4, integer-power rule with exponent -1, away from-- zero.theoremderivative_reciprocal(x:R)(hx:x≠0):HasDerivative(funt=>1/t)x(-1/(x*x)):=byhaveh:=derivative_div(fun_=>1)(funt=>t)x01(derivative_const1x)(derivative_idx)hxhaveheq:0*x-1*1=-1:=bygrindsimpaonly[heq]usingh-- Rudin Theorem 5.3(c), with constant numerator 1.theoremderivative_inv(f:R→R)(xa:R)(hf:HasDerivativefxa)(hx:fx≠0):HasDerivative(funt=>1/ft)x(-a/(fx*fx)):=byhaveh:=derivative_div(fun_=>1)fx0a(derivative_const1x)hfhxhaveheq:0*fx-1*a=-a:=bygrindsimpaonly[heq]usingh
The Chain Rule
A small displacement is stretched at each stage. The two local scale factors multiply.