1-- Continuity between metric spaces: the ε–δ definition, its equivalence2-- with topological continuity for the metric topologies, composition,3-- Lipschitz maps, and isometries4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.Metric.Continuity10import Closed1112predicate MetricContinuousAt (f X d Y e x : Set) :=13 FunctionBetween(f, X, Y) ∧ x ∈ X ∧14 (∀ ε ∈ ℝ, 0 < ε →∃ δ ∈ ℝ, 0 < δ ∧15∀ y ∈ X, (d(x, y) < δ → e(f(x), f(y)) < ε))1617predicate IsMetricContinuous (f X d Y e : Set) :=18 FunctionBetween(f, X, Y) ∧ (∀ x ∈ X, MetricContinuousAt(f, X, d, Y, e, x))1920theorem MetricContinuousAt.function (f X d Y e x : Set)21requires continuous : MetricContinuousAt(f, X, d, Y, e, x)22shows f : X → Y23proof24exact continuous.left2526theorem MetricContinuousAt.point (f X d Y e x : Set)27requires continuous : MetricContinuousAt(f, X, d, Y, e, x)28shows x ∈ X29proof30obtain⟨function, hx, control⟩:= continuous31exact hx3233theorem MetricContinuousAt.control (f X d Y e x : Set, ε : Real)34requires continuous : MetricContinuousAt(f, X, d, Y, e, x)35requires positive : 0 < ε36shows∃ δ ∈ ℝ, 0 < δ ∧∀ y ∈ X, (d(x, y) < δ → e(f(x), f(y)) < ε)37proof38obtain⟨function, hx, control⟩:= continuous39have realE : ε ∈ ℝ bytypecheck40exact control with ε, realE, positive4142theorem MetricContinuousAt.of_control (f X d Y e x : Set)43requires function : f : X → Y44requires hx : x ∈ X45requires control : ∀ ε ∈ ℝ, 0 < ε →∃ δ ∈ ℝ, 0 < δ ∧46∀ y ∈ X, (d(x, y) < δ → e(f(x), f(y)) < ε)47shows MetricContinuousAt(f, X, d, Y, e, x)48proof49exact⟨function, hx, control⟩5051-- Continuity at a point in terms of balls: a small ball around x is mapped52-- into any given ball around f(x).53theorem MetricContinuousAt.ball (f X d Y e x : Set, ε : Real)54requires continuous : MetricContinuousAt(f, X, d, Y, e, x)55requires positive : 0 < ε56shows∃ δ ∈ ℝ, 0 < δ ∧57 ball(X, d, x, δ) ⊆ functionPreimage(f, X, ball(Y, e, f(x), ε))58proof59have function := MetricContinuousAt.function with continuous60obtain⟨δ, hδ, positiveD, maps⟩:=61 MetricContinuousAt.control with continuous, positive62refine⟨δ, hδ, positiveD, ?_⟩63intros y hy64have hyX := ball.point with hy65have near := ball.distance with hy66have value := FunctionBetween.apply_closed with function, hyX67have close := maps with y, hyX, near68apply functionPreimage.membership.backward69exact⟨hyX, (ball.of_distance with value, close)⟩7071theorem MetricContinuousAt.of_ball (f X d Y e x : Set)72requires function : f : X → Y73requires hx : x ∈ X74requires maps : ∀ ε ∈ ℝ, 0 < ε →∃ δ ∈ ℝ, 0 < δ ∧75 ball(X, d, x, δ) ⊆ functionPreimage(f, X, ball(Y, e, f(x), ε))76shows MetricContinuousAt(f, X, d, Y, e, x)77proof78apply MetricContinuousAt.of_control with function, hx79intros ε hε positive80obtain⟨δ, hδ, positiveD, inside⟩:= maps with ε, hε, positive81refine⟨δ, hδ, positiveD, ?_⟩82intros y hy near83have member := inside with y, (ball.of_distance with hy, near)84have parts := functionPreimage.membership.forward with member85exact ball.distance with parts.right8687theorem IsMetricContinuous.function (f X d Y e : Set)88requires continuous : IsMetricContinuous(f, X, d, Y, e)89shows f : X → Y90proof91exact continuous.left9293theorem IsMetricContinuous.at (f X d Y e x : Set)94requires continuous : IsMetricContinuous(f, X, d, Y, e)95requires hx : x ∈ X96shows MetricContinuousAt(f, X, d, Y, e, x)97proof98exact continuous.right with x, hx99100theorem IsMetricContinuous.of_pointwise (f X d Y e : Set)101requires function : f : X → Y102requires pointwise : ∀ x ∈ X, MetricContinuousAt(f, X, d, Y, e, x)103shows IsMetricContinuous(f, X, d, Y, e)104proof105exact⟨function, pointwise⟩106107theorem identity.metric_continuous_at (X d x : Set)108requires hx : x ∈ X109shows MetricContinuousAt(identity(X), X, d, X, d, x)110proof111have function := identity.function at X112apply MetricContinuousAt.of_control with function, hx113intros ε hε positive114refine⟨ε, hε, positive, ?_⟩115intros y hy near116have fixedX := identity.apply with hx117have fixedY := identity.apply with hy118 rwa [fixedX, fixedY]119120theorem identity.metric_continuous (X d : Set)121shows IsMetricContinuous(identity(X), X, d, X, d)122proof123apply IsMetricContinuous.of_pointwise with (identity.function at X)124intros x hx125exact identity.metric_continuous_at with hx126127theorem constantFunction.metric_continuous_at (X d Y e x c : Set)128requires metric : IsMetric(Y, e)129requires hx : x ∈ X130requires hc : c ∈ Y131shows MetricContinuousAt(constantFunction(X, Y, c), X, d, Y, e, x)132proof133have function := constantFunction.function at X, Y, c with hc134apply MetricContinuousAt.of_control with function, hx135intros ε hε positive136refine⟨ε, hε, positive, ?_⟩137intros y hy near138have valueX := constantFunction.apply with hx, hc139have valueY := constantFunction.apply with hy, hc140rw [valueX, valueY]141haveself:= IsMetric.self with metric, hc142rwself143exact positive144145theorem constantFunction.metric_continuous (X d Y e c : Set)146requires metric : IsMetric(Y, e)147requires hc : c ∈ Y148shows IsMetricContinuous(constantFunction(X, Y, c), X, d, Y, e)149proof150have function := constantFunction.function at X, Y, c with hc151apply IsMetricContinuous.of_pointwise with function152intros x hx153exact constantFunction.metric_continuous_at with metric, hx, hc154155theorem MetricContinuousAt.compose (g f X d Y e Z k x : Set)156requires first : MetricContinuousAt(f, X, d, Y, e, x)157requires second : MetricContinuousAt(g, Y, e, Z, k, f(x))158shows MetricContinuousAt(compose(g, f, X, Y, Z), X, d, Z, k, x)159proof160have fFunction := MetricContinuousAt.function with first161have gFunction := MetricContinuousAt.function with second162have hx := MetricContinuousAt.point with first163have composite := compose.function with fFunction, gFunction164apply MetricContinuousAt.of_control with composite, hx165intros ε hε positive166obtain⟨η, hη, positiveH, mapsG⟩:=167 MetricContinuousAt.control with second, positive168obtain⟨δ, hδ, positiveD, mapsF⟩:=169 MetricContinuousAt.control with first, positiveH170refine⟨δ, hδ, positiveD, ?_⟩171intros y hy near172have valueX := compose.apply with fFunction, gFunction, hx173have valueY := compose.apply with fFunction, gFunction, hy174rw [valueX, valueY]175have middle := mapsF with y, hy, near176have imageY := FunctionBetween.apply_closed with fFunction, hy177exact mapsG with f(y), imageY, middle178179theorem IsMetricContinuous.compose (g f X d Y e Z k : Set)180requires first : IsMetricContinuous(f, X, d, Y, e)181requires second : IsMetricContinuous(g, Y, e, Z, k)182shows IsMetricContinuous(compose(g, f, X, Y, Z), X, d, Z, k)183proof184have fFunction := IsMetricContinuous.function with first185have gFunction := IsMetricContinuous.function with second186apply IsMetricContinuous.of_pointwise with (compose.function with187 fFunction, gFunction)188intros x hx189have image := FunctionBetween.apply_closed with fFunction, hx190have atX := IsMetricContinuous.at with first, hx191have atImage := IsMetricContinuous.at with second, image192exact MetricContinuousAt.compose with atX, atImage193194-- ε–δ continuity is continuity for the metric topologies.195theorem IsMetricContinuous.continuous_map (f X d Y e : Set)196requires metricD : IsMetric(X, d)197requires metricE : IsMetric(Y, e)198requires continuous : IsMetricContinuous(f, X, d, Y, e)199shows ContinuousMap(f, X, metricTopology(X, d), Y, metricTopology(Y, e))200proof201have function := IsMetricContinuous.function with continuous202constructor203 . exact function204 . intros V hV205apply metricTopology.of_open206constructor207 . exact functionPreimage.subset at f, X, V208 . intros x hx209have parts := functionPreimage.membership.forward with hx210obtain⟨ε, hε, positive, ballInside⟩:=211 metricTopology.ball_inside with hV, parts.right212have atX := IsMetricContinuous.at with continuous, parts.left213obtain⟨δ, hδ, positiveD, maps⟩:=214 MetricContinuousAt.ball with atX, positive215refine⟨δ, hδ, positiveD, ?_⟩216intros y hy217have preimage := functionPreimage.membership.forward with (maps with218 y, hy)219apply functionPreimage.membership.backward220exact⟨preimage.left, (ballInside with f(y), preimage.right)⟩221222theorem ContinuousMap.metric_continuous (f X d Y e : Set)223requires metricD : IsMetric(X, d)224requires metricE : IsMetric(Y, e)225requires continuous :226 ContinuousMap(f, X, metricTopology(X, d), Y, metricTopology(Y, e))227shows IsMetricContinuous(f, X, d, Y, e)228proof229have function := ContinuousMap.function with continuous230apply IsMetricContinuous.of_pointwise with function231intros x hx232apply MetricContinuousAt.of_ball with function, hx233intros ε hε positive234have image := FunctionBetween.apply_closed with function, hx235have openBall := ball.member_topology at Y, e, f(x), ε with metricE, image236have preimageOpen := ContinuousMap.preimage with continuous, openBall237have center := ball.center with metricE, image, positive238have inPreimage : x ∈ functionPreimage(f, X, ball(Y, e, f(x), ε)) :=239 functionPreimage.membership.backward with⟨hx, center⟩240exact metricTopology.ball_inside with preimageOpen, inPreimage241242theorem IsMetricContinuous.iff_continuous_map (f X d Y e : Set)243requires metricD : IsMetric(X, d)244requires metricE : IsMetric(Y, e)245shows IsMetricContinuous(f, X, d, Y, e) ↔246 ContinuousMap(f, X, metricTopology(X, d), Y, metricTopology(Y, e))247proof248constructor249 . intro continuous250exact IsMetricContinuous.continuous_map with metricD, metricE, continuous251 . intro continuous252exact ContinuousMap.metric_continuous with metricD, metricE, continuous253254-- Lipschitz maps255256predicate IsLipschitz (f X d Y e : Set) (K : Real) :=257 FunctionBetween(f, X, Y) ∧0≤ K ∧258 (∀ x ∈ X, ∀ y ∈ X, e(f(x), f(y)) ≤ realMul(K, d(x, y)))259260theorem IsLipschitz.function (f X d Y e : Set) (K : Real)261requires lipschitz : IsLipschitz(f, X, d, Y, e, K)262shows f : X → Y263proof264exact lipschitz.left265266theorem IsLipschitz.nonnegative (f X d Y e : Set) (K : Real)267requires lipschitz : IsLipschitz(f, X, d, Y, e, K)268shows0≤ K269proof270obtain⟨function, nonnegative, bound⟩:= lipschitz271exact nonnegative272273theorem IsLipschitz.bound (f X d Y e x y : Set) (K : Real)274requires lipschitz : IsLipschitz(f, X, d, Y, e, K)275requires hx : x ∈ X276requires hy : y ∈ X277shows e(f(x), f(y)) ≤ realMul(K, d(x, y))278proof279obtain⟨function, nonnegative, bound⟩:= lipschitz280exact bound with x, hx, y, hy281282-- The modulus ε / (K + 1) works for every Lipschitz constant K ≥ 0.283theorem Lipschitz.modulus (K ε : Real)284requires nonnegative : 0≤ K285requires positive : 0 < ε286shows0 < ε / (K +1) ∧ K * (ε / (K +1)) < ε287proof288have successorPositive : (0:R) < K +1bylinarith289have nonzero : K +1≠0290intro zero291rw zero at successorPositive292exact realLess.not_self with successorPositive293have quotientReal := realDiv.real at ε, K +1with*294have cancel := realDiv.mul_left at ε, K +1with*{2}, nonzero295have inversePositive := realInvValue.positive with successorPositive296have inverseReal := realInvValue.real at K +1297have asProduct := realDiv.eq_mul_inv at ε, K +1with*298have quotientPositive : 0 < ε / (K +1)299rw asProduct300exact realMulValue.positive with positive, inversePositive301constructor302 . exact quotientPositive303 . have expand : K * (ε / (K +1)) = ε - ε / (K +1) by304linear_combination cancel305rw expand306linarith307308theorem IsLipschitz.continuous_at (f X d Y e x : Set) (K : Real)309requires metricD : IsMetric(X, d)310requires metricE : IsMetric(Y, e)311requires lipschitz : IsLipschitz(f, X, d, Y, e, K)312requires hx : x ∈ X313shows MetricContinuousAt(f, X, d, Y, e, x)314proof315have function := IsLipschitz.function with lipschitz316have imageX := FunctionBetween.apply_closed with function, hx317have nonnegative := IsLipschitz.nonnegative with lipschitz318apply MetricContinuousAt.of_control with function, hx319intros ε hε positive320obtain⟨positiveD, small⟩:= Lipschitz.modulus with nonnegative, positive321have quotientReal : ε / (K +1) ∈ ℝ bytypecheck322refine⟨ε / (K +1), quotientReal, positiveD, ?_⟩323intros y hy near324have bound := IsLipschitz.bound with lipschitz, hx, hy325have imageY := FunctionBetween.apply_closed with function, hy326have dxy := IsMetric.real with metricD, hx, hy327have exy := IsMetric.real with metricE, imageX, imageY328have le := realLess.implies_le with near329have scaled := realLe.mul_left_of_nonnegative with le, nonnegative330linarith331332theorem IsLipschitz.continuous (f X d Y e : Set) (K : Real)333requires metricD : IsMetric(X, d)334requires metricE : IsMetric(Y, e)335requires lipschitz : IsLipschitz(f, X, d, Y, e, K)336shows IsMetricContinuous(f, X, d, Y, e)337proof338apply IsMetricContinuous.of_pointwise with (IsLipschitz.function with lipschitz)339intros x hx340exact IsLipschitz.continuous_at with metricD, metricE, lipschitz, hx341342theorem IsLipschitz.identity (X d : Set)343requires metric : IsMetric(X, d)344shows IsLipschitz(identity(X), X, d, X, d, (1:R))345proof346have one : (0:R) ≤1bylinarith347unfold IsLipschitz348constructor349 . exact identity.function at X350 . constructor351 . exact one352 . intros x hx y hy353have fixedX := identity.apply with hx354have fixedY := identity.apply with hy355have dxy := IsMetric.real with metric, hx, hy356have unit := realMulValue.one_left at d(x, y)357rw [fixedX, fixedY, unit]358exact realLe.reflexive359360theorem IsLipschitz.constant (X d Y e c : Set)361requires metricD : IsMetric(X, d)362requires metricE : IsMetric(Y, e)363requires hc : c ∈ Y364shows IsLipschitz(constantFunction(X, Y, c), X, d, Y, e, (0:R))365proof366have zero : (0:R) ≤0bylinarith367unfold IsLipschitz368constructor369 . exact constantFunction.function at X, Y, c with hc370 . constructor371 . exact zero372 . intros x hx y hy373have valueX := constantFunction.apply with hx, hc374have valueY := constantFunction.apply with hy, hc375have dxy := IsMetric.real with metricD, hx, hy376haveself:= IsMetric.self with metricE, hc377have annihilate := realMulValue.zero_left at d(x, y)378rw [valueX, valueY, self, annihilate]379exact realLe.reflexive380381theorem IsLipschitz.compose (g f X d Y e Z k : Set) (K L : Real)382requires metricD : IsMetric(X, d)383requires metricE : IsMetric(Y, e)384requires metricK : IsMetric(Z, k)385requires first : IsLipschitz(f, X, d, Y, e, K)386requires second : IsLipschitz(g, Y, e, Z, k, L)387shows IsLipschitz(compose(g, f, X, Y, Z), X, d, Z, k, L * K)388proof389have fFunction := IsLipschitz.function with first390have gFunction := IsLipschitz.function with second391have nonnegativeK := IsLipschitz.nonnegative with first392have nonnegativeL := IsLipschitz.nonnegative with second393have product := realMulValue.nonnegative with nonnegativeL, nonnegativeK394unfold IsLipschitz395constructor396 . exact compose.function with fFunction, gFunction397 . constructor398 . exact product399 . intros x hx y hy400have valueX := compose.apply with fFunction, gFunction, hx401have valueY := compose.apply with fFunction, gFunction, hy402rw [valueX, valueY]403have imageX := FunctionBetween.apply_closed with fFunction, hx404have imageY := FunctionBetween.apply_closed with fFunction, hy405have inner := IsLipschitz.bound with first, hx, hy406have outer := IsLipschitz.bound with second, imageX, imageY407have dxy := IsMetric.real with metricD, hx, hy408have exy := IsMetric.real with metricE, imageX, imageY409have outerX := FunctionBetween.apply_closed with gFunction, imageX410have outerY := FunctionBetween.apply_closed with gFunction, imageY411have kxy := IsMetric.real with metricK, outerX, outerY412have scaled := realLe.mul_left_of_nonnegative with inner, nonnegativeL413have regroup : L * (K * d(x, y)) = (L * K) * d(x, y) byring414rw regroup at scaled415linarith416417-- Isometries418419predicate IsIsometry (f X d Y e : Set) :=420 FunctionBetween(f, X, Y) ∧ (∀ x ∈ X, ∀ y ∈ X, e(f(x), f(y)) = d(x, y))421422theorem IsIsometry.function (f X d Y e : Set)423requires isometry : IsIsometry(f, X, d, Y, e)424shows f : X → Y425proof426exact isometry.left427428theorem IsIsometry.distance (f X d Y e x y : Set)429requires isometry : IsIsometry(f, X, d, Y, e)430requires hx : x ∈ X431requires hy : y ∈ X432shows e(f(x), f(y)) = d(x, y)433proof434exact isometry.right with x, hx, y, hy435436theorem IsIsometry.lipschitz (f X d Y e : Set)437requires metric : IsMetric(X, d)438requires isometry : IsIsometry(f, X, d, Y, e)439shows IsLipschitz(f, X, d, Y, e, (1:R))440proof441have one : (0:R) ≤1bylinarith442unfold IsLipschitz443constructor444 . exact IsIsometry.function with isometry445 . constructor446 . exact one447 . intros x hx y hy448have preserved := IsIsometry.distance with isometry, hx, hy449have dxy := IsMetric.real with metric, hx, hy450have unit := realMulValue.one_left at d(x, y)451rw [preserved, unit]452exact realLe.reflexive453454theorem IsIsometry.continuous_at (f X d Y e x : Set)455requires isometry : IsIsometry(f, X, d, Y, e)456requires hx : x ∈ X457shows MetricContinuousAt(f, X, d, Y, e, x)458proof459have function := IsIsometry.function with isometry460apply MetricContinuousAt.of_control with function, hx461intros ε hε positive462refine⟨ε, hε, positive, ?_⟩463intros y hy near464have preserved := IsIsometry.distance with isometry, hx, hy465 rwa preserved466467theorem IsIsometry.continuous (f X d Y e : Set)468requires isometry : IsIsometry(f, X, d, Y, e)469shows IsMetricContinuous(f, X, d, Y, e)470proof471apply IsMetricContinuous.of_pointwise with (IsIsometry.function with isometry)472intros x hx473exact IsIsometry.continuous_at with isometry, hx474475theorem IsIsometry.injective (f X d Y e : Set)476requires metricD : IsMetric(X, d)477requires metricE : IsMetric(Y, e)478requires isometry : IsIsometry(f, X, d, Y, e)479shows InjectiveBetween(f, X, Y)480proof481have function := IsIsometry.function with isometry482constructor483 . exact function484 . intros x hx y hy z hz first second485have valueX := FunctionBetween.apply_value with function, hx, first486have valueY := FunctionBetween.apply_value with function, hy, second487have preserved := IsIsometry.distance with isometry, hx, hy488haveself:= IsMetric.self with metricE, hz489have zero : d(x, y) = (0:R)490rw← preserved491rw [valueX, valueY]492exactself493exact IsMetric.eq_of_zero with metricD, hx, hy, zero494495theorem IsIsometry.compose (g f X d Y e Z k : Set)496requires first : IsIsometry(f, X, d, Y, e)497requires second : IsIsometry(g, Y, e, Z, k)498shows IsIsometry(compose(g, f, X, Y, Z), X, d, Z, k)499proof500have fFunction := IsIsometry.function with first501have gFunction := IsIsometry.function with second502refine⟨(compose.function with fFunction, gFunction), ?_⟩503intros x hx y hy504have valueX := compose.apply with fFunction, gFunction, hx505have valueY := compose.apply with fFunction, gFunction, hy506rw [valueX, valueY]507have imageX := FunctionBetween.apply_closed with fFunction, hx508have imageY := FunctionBetween.apply_closed with fFunction, hy509have inner := IsIsometry.distance with first, hx, hy510have outer := IsIsometry.distance with second, imageX, imageY511rw outer512exact inner513514theorem identity.isometry (X d : Set)515shows IsIsometry(identity(X), X, d, X, d)516proof517refine⟨(identity.function at X), ?_⟩518intros x hx y hy519have fixedX := identity.apply with hx520have fixedY := identity.apply with hy521rw [fixedX, fixedY]522rfl523524-- An isometry maps a ball onto the ball of the image inside the image.525theorem IsIsometry.ball_image (f X d Y e x y : Set, r : Real)526requires isometry : IsIsometry(f, X, d, Y, e)527requires hx : x ∈ X528requires hy : y ∈ X529shows y ∈ ball(X, d, x, r) ↔ f(y) ∈ ball(Y, e, f(x), r)530proof531have function := IsIsometry.function with isometry532have preserved := IsIsometry.distance with isometry, hx, hy533have image := FunctionBetween.apply_closed with function, hy534constructor535 . intro member536have near := ball.distance with member537apply ball.of_distance with image538 rwa preserved539 . intro member540have near := ball.distance with member541apply ball.of_distance with hy542 rwa preserved at near543