1-- Maps between metric spaces and metric spaces built from others:2-- ε–δ continuity against continuity of the metric topologies, Lipschitz3-- maps, isometries, and uniform continuity, completeness, and the real4-- line, discrete, subspace, and product metrics as values5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Metric.Spaces11import Structure1213-- MetricContinuous(f, X, Y): f is an ε–δ continuous function between the14-- carriers; Lipschitz(f, X, Y, K), Isometry(f, X, Y), and15-- UniformlyContinuous(f, X, Y) likewise, and Complete(X) says every Cauchy16-- sequence converges. Each takes the spaces, so a hypothesis supplies both17-- distances. IsMetricContinuous(f, A, d, B, e) and the rest remain the forms18-- over separate pieces, bridged below.19predicate MetricContinuous (f X Y : Set) :=20 MetricSpace(X) ∧ MetricSpace(Y) ∧21 IsMetricContinuous(f, X.carrier, X.dist, Y.carrier, Y.dist)22predicate Lipschitz (f X Y : Set) (K : Real) :=23 MetricSpace(X) ∧ MetricSpace(Y) ∧24 IsLipschitz(f, X.carrier, X.dist, Y.carrier, Y.dist, K)25predicate Isometry (f X Y : Set) :=26 MetricSpace(X) ∧ MetricSpace(Y) ∧27 IsIsometry(f, X.carrier, X.dist, Y.carrier, Y.dist)28predicate UniformlyContinuous (f X Y : Set) :=29 MetricSpace(X) ∧ MetricSpace(Y) ∧30 IsUniformlyContinuous(f, X.carrier, X.dist, Y.carrier, Y.dist)31predicate Complete (X : Set) :=32 IsComplete(MetricSpace.carrier(X), MetricSpace.dist(X))3334-- A continuity, isometry, or Lipschitz hypothesis supplies convergence in35-- both of its spaces, so under it the binders (x : X) and (y : Y) are36-- carrier memberships and u ⇝ x is read in the space of its limit.37notationinfix50"⇝"=> Converges(metricTopology(X), _, _) viahypothesis MetricContinuous(f, X, Y) for X.carrier38notationinfix50"⇝"=> Converges(metricTopology(Y), _, _) viahypothesis MetricContinuous(f, X, Y) for Y.carrier39notationinfix50"⇝"=> Converges(metricTopology(X), _, _) viahypothesis Isometry(f, X, Y) for X.carrier40notationinfix50"⇝"=> Converges(metricTopology(Y), _, _) viahypothesis Isometry(f, X, Y) for Y.carrier41notationinfix50"⇝"=> Converges(metricTopology(X), _, _) viahypothesis Lipschitz(f, X, Y, K) for X.carrier42notationinfix50"⇝"=> Converges(metricTopology(Y), _, _) viahypothesis Lipschitz(f, X, Y, K) for Y.carrier43notation function "d(x, y)"=> X.dist(x, y) viahypothesis MetricContinuous(f, X, Y) for X.carrier44notation function "d(x, y)"=> Y.dist(x, y) viahypothesis MetricContinuous(f, X, Y) for Y.carrier45notation function "d(x, y)"=> X.dist(x, y) viahypothesis Isometry(f, X, Y) for X.carrier46notation function "d(x, y)"=> Y.dist(x, y) viahypothesis Isometry(f, X, Y) for Y.carrier47notation function "d(x, y)"=> X.dist(x, y) viahypothesis Lipschitz(f, X, Y, K) for X.carrier48notation function "d(x, y)"=> Y.dist(x, y) viahypothesis Lipschitz(f, X, Y, K) for Y.carrier4950instance MetricContinuous.parts (f X Y : Set)51requires continuous : MetricContinuous(f, X, Y)52shows IsMetricContinuous(f, X.carrier, X.dist, Y.carrier, Y.dist)53proof54obtain⟨metricX, metricY, engine⟩:= continuous55exact engine5657theorem MetricContinuous.of_projections (f X Y : Set)58requires metricX : MetricSpace(X)59requires metricY : MetricSpace(Y)60requires continuous :61 IsMetricContinuous(f, X.carrier, X.dist, Y.carrier, Y.dist)62shows MetricContinuous(f, X, Y)63proof64unfold MetricContinuous65exact⟨metricX, metricY, continuous⟩6667theorem MetricContinuous.source (f X Y : Set)68requires continuous : MetricContinuous(f, X, Y)69shows MetricSpace(X)70proof71obtain⟨metricX, rest⟩:= continuous72exact metricX7374theorem MetricContinuous.target (f X Y : Set)75requires continuous : MetricContinuous(f, X, Y)76shows MetricSpace(Y)77proof78obtain⟨metricX, metricY, rest⟩:= continuous79exact metricY8081theorem MetricContinuous.function_between (f X Y : Set)82requires continuous : MetricContinuous(f, X, Y)83shows f : X.carrier → Y.carrier84proof85have engine := MetricContinuous.parts with continuous86exact Continuity.IsMetricContinuous.function with engine8788-- ε–δ continuity is continuity of the metric topologies.89theorem MetricContinuous.iff_continuous (f X Y : Set)90requires metricX : MetricSpace(X)91requires metricY : MetricSpace(Y)92shows MetricContinuous(f, X, Y) ↔93 f : metricTopology(X) ⇒ metricTopology(Y)94proof95have partsX := MetricSpace.parts with metricX96have partsY := MetricSpace.parts with metricY97have spaceX := MetricSpace.topological_space with metricX98have spaceY := MetricSpace.topological_space with metricY99have criterion := IsMetricContinuous.iff_continuous_map at f, X.carrier, X.dist, Y.carrier, Y.dist with partsX, partsY100constructor101 . intro continuous102have engine := MetricContinuous.parts with continuous103have map := criterion.forward with engine104have shifted : ContinuousMap(f, TopologicalSpace.carrier(metricTopology(X)),105 TopologicalSpace.opens(metricTopology(X)),106 TopologicalSpace.carrier(metricTopology(Y)),107 TopologicalSpace.opens(metricTopology(Y)))108rw [metricTopology.carrier, metricTopology.opens]109rw [metricTopology.carrier, metricTopology.opens]110exact map111exact Continuous.of_projections with spaceX, spaceY, shifted112 . intro continuous113have map := Continuous.parts with continuous114rw [metricTopology.carrier, metricTopology.opens] at map115rw [metricTopology.carrier, metricTopology.opens] at map116have engine := criterion.backward with map117exact MetricContinuous.of_projections with metricX, metricY, engine118119theorem MetricContinuous.continuous (f X Y : Set)120requires continuous : MetricContinuous(f, X, Y)121shows f : metricTopology(X) ⇒ metricTopology(Y)122proof123have metricX := MetricContinuous.source with continuous124have metricY := MetricContinuous.target with continuous125have criterion := MetricContinuous.iff_continuous at f, X, Y with metricX, metricY126exact criterion.forward with continuous127128section ContinuityLaws129variable (f X Y : Set)130hypothesis continuous : MetricContinuous(f, X, Y)131132theorem MetricContinuous.apply_mem (x : X)133shows f(x) ∈ Y134proof135have function := MetricContinuous.function_between with continuous136have xIn : x ∈ X byassumption137exact FunctionBetween.apply_closed with function, xIn138139-- The ε–δ form at a point.140theorem MetricContinuous.control (x : X) (ε : Real)141requires positive : 0 < ε142shows∃ δ ∈ ℝ, 0 < δ ∧143∀ y ∈ X, (d(x, y) < δ → d(f(x), f(y)) < ε)144proof145have engine := MetricContinuous.parts with continuous146have xIn : x ∈ X byassumption147have pointwise := Continuity.IsMetricContinuous.at with engine, xIn148exact MetricContinuousAt.control with pointwise, positive149150-- A continuous map carries a convergent sequence to a convergent sequence.151theorem MetricContinuous.map_converges (u : Set) (x : X)152requires converges : u ⇝ x153shows compose(f, u, ℕ, X.carrier, Y.carrier) ⇝ f(x)154proof155have metricX := MetricContinuous.source with continuous156have metricY := MetricContinuous.target with continuous157have spaceX := MetricSpace.topological_space with metricX158have engine := MetricContinuous.parts with continuous159have function := MetricContinuous.function_between with continuous160have xIn : x ∈ X byassumption161have image := FunctionBetween.apply_closed with function, xIn162have sequence := Converges.sequence with spaceX, converges163rw metricTopology.carrier at sequence164have composite := compose.function with sequence, function165have bridge := Converges.iff_parts with metricX, sequence166have limit := bridge.forward with converges167have mapped := ConvergesIn.map_continuous with engine, limit168have bridgeY := Converges.iff_parts with metricY, composite169exact bridgeY.backward with mapped170171end ContinuityLaws172173theorem MetricContinuous.id (X : Set)174requires metric : MetricSpace(X)175shows MetricContinuous(identity(X.carrier), X, X)176proof177have parts := MetricSpace.parts with metric178have engine := identity.metric_continuous at X.carrier, X.dist179exact MetricContinuous.of_projections with*180181theorem MetricContinuous.comp (f g X Y Z : Set)182requires first : MetricContinuous(f, X, Y)183requires second : MetricContinuous(g, Y, Z)184shows MetricContinuous(compose(g, f, X.carrier, Y.carrier, Z.carrier), X, Z)185proof186have engineF := MetricContinuous.parts with first187have engineG := MetricContinuous.parts with second188have metricX := MetricContinuous.source with first189have metricZ := MetricContinuous.target with second190have engine := Continuity.IsMetricContinuous.compose with engineF, engineG191exact MetricContinuous.of_projections with*192193-- Lipschitz maps, isometries, and uniformly continuous maps are194-- continuous; an isometry preserves distances.195theorem Lipschitz.metric_continuous (f X Y : Set) (K : Real)196requires lipschitz : Lipschitz(f, X, Y, K)197shows MetricContinuous(f, X, Y)198proof199obtain⟨metricX, metricY, engine⟩:= lipschitz200have partsX := MetricSpace.parts with metricX201have partsY := MetricSpace.parts with metricY202have continuous := Continuity.IsLipschitz.continuous with partsX, partsY,203 engine204exact MetricContinuous.of_projections with*205206theorem Isometry.metric_continuous (f X Y : Set)207requires isometry : Isometry(f, X, Y)208shows MetricContinuous(f, X, Y)209proof210obtain⟨metricX, metricY, engine⟩:= isometry211have continuous := Continuity.IsIsometry.continuous with engine212exact MetricContinuous.of_projections with*213214theorem UniformlyContinuous.metric_continuous (f X Y : Set)215requires uniform : UniformlyContinuous(f, X, Y)216shows MetricContinuous(f, X, Y)217proof218obtain⟨metricX, metricY, engine⟩:= uniform219have continuous := Uniform.IsUniformlyContinuous.continuous with engine220exact MetricContinuous.of_projections with*221222section IsometryLaws223variable (f X Y : Set)224hypothesis isometry : Isometry(f, X, Y)225226theorem Isometry.dist (x y : X)227shows d(f(x), f(y)) = d(x, y)228proof229obtain⟨metricX, metricY, engine⟩:= isometry230have xIn : x ∈ X byassumption231have yIn : y ∈ X byassumption232exact IsIsometry.distance with engine, xIn, yIn233234end IsometryLaws235236section LipschitzLaws237variable (f X Y : Set) (K : Real)238hypothesis lipschitz : Lipschitz(f, X, Y, K)239240theorem Lipschitz.dist_le (x y : X)241shows d(f(x), f(y)) ≤ K * d(x, y)242proof243obtain⟨metricX, metricY, engine⟩:= lipschitz244have xIn : x ∈ X byassumption245have yIn : y ∈ X byassumption246exact IsLipschitz.bound with engine, xIn, yIn247248end LipschitzLaws249250-- Completeness.251instance Complete.parts (X : Set)252requires complete : Complete(X)253shows IsComplete(MetricSpace.carrier(X), MetricSpace.dist(X))254proof255unfold Complete at complete256exact complete257258theorem Complete.of_parts (X : Set)259requires complete : IsComplete(MetricSpace.carrier(X), MetricSpace.dist(X))260shows Complete(X)261proof262unfold Complete263exact complete264265theorem Complete.of_mk (A d : Set)266requires complete : IsComplete(A, d)267shows Complete(MetricSpace.mk(A, d))268proof269unfold Complete270 metric_projections271272theorem Complete.converges (X u : Set)273requires metric : MetricSpace(X)274requires complete : Complete(X)275requires cauchy : Cauchy(X, u)276shows∃ x ∈ X, u ⇝ x277proof278have pieces := Complete.parts with complete279have cauchyU := Cauchy.parts with cauchy280have limit := Sequences.IsComplete.limit with pieces, cauchyU281obtain⟨x, xIn, converges⟩:= limit282have sequence := SequenceIn.function with (IsCauchy.sequence with cauchyU)283have bridge := Converges.iff_parts at X, u, x with metric, sequence284witness x285exact⟨xIn, (bridge.backward with converges)⟩286287-- The real line with its usual distance, the discrete metric on a set, the288-- subspace metric on a subset, and the product of two metric spaces.289def realMetric : Set:= MetricSpace.mk(ℝ, realDistance)290def discreteMetric (A : Set) : Set:= MetricSpace.mk(A, discreteDistance(A))291def metricSubspace (X S : Set) : Set:=292 MetricSpace.mk(S, subspaceMetric(MetricSpace.dist(X), S))293def productMetric (X Y : Set) : Set:=294 MetricSpace.mk(MetricSpace.carrier(X) × MetricSpace.carrier(Y),295 productDistance(MetricSpace.carrier(X), MetricSpace.dist(X),296 MetricSpace.carrier(Y), MetricSpace.dist(Y)))297298theorem realMetric.carrier299shows MetricSpace.carrier(realMetric) = ℝ300proof301unfold realMetric302 metric_projections303304theorem realMetric.dist305shows MetricSpace.dist(realMetric) = realDistance306proof307unfold realMetric308 metric_projections309310instance realMetric.space311shows MetricSpace(realMetric)312proof313unfold realMetric314exact MetricSpace.of_parts with realDistance.metric315316instance realMetric.complete317shows Complete(realMetric)318proof319unfold realMetric320exact Complete.of_mk with realDistance.complete321322-- The metric topology of the line is the real line.323theorem realMetric.topology324shows metricTopology(realMetric) = realLine325proof326unfold metricTopology327rw [realMetric.carrier, realMetric.dist, realDistance.topology]328unfold realLine329rfl330331-- Convergence of a real sequence is convergence in the real metric.332theorem realMetric.converges_iff (u : Set) (L : Real)333requires metric : MetricSpace(realMetric)334requires sequence : u : ℕ → ℝ335shows ConvergesTo(u, L) ↔ u ⇝ L336proof337have realL : L ∈ MetricSpace.carrier(realMetric)338rw realMetric.carrier339typecheck340have sequenceIn : u : ℕ → MetricSpace.carrier(realMetric)341rw realMetric.carrier342exact sequence343have bridge := Converges.iff_parts with metric, sequenceIn344have engine := realDistance.converges_iff at u, L345rw [realMetric.carrier, realMetric.dist] at bridge346constructor347 . intro converges348exact bridge.backward with (engine.forward with converges)349 . intro converges350exact engine.backward with (bridge.forward with converges)351352instance discreteMetric.space (A : Set)353shows MetricSpace(discreteMetric(A))354proof355unfold discreteMetric356exact MetricSpace.of_parts with (discreteDistance.metric at A)357358instance discreteMetric.complete (A : Set)359shows Complete(discreteMetric(A))360proof361unfold discreteMetric362exact Complete.of_mk with (discreteDistance.complete at A)363364-- The discrete metric induces the discrete topology.365theorem discreteMetric.topology (A : Set)366shows metricTopology(discreteMetric(A)) = TopologicalSpace.mk(A, 𝒫(A))367proof368unfold metricTopology369unfold discreteMetric370 metric_projections371rw discreteDistance.topology372rfl373374instance metricSubspace.space (X S : Set)375requires metric : MetricSpace(X)376requires inside : S ⊆ X377shows MetricSpace(metricSubspace(X, S))378proof379have parts := MetricSpace.parts with metric380unfold metricSubspace381exact MetricSpace.of_parts with (subspaceMetric.metric with parts, inside)382383-- A closed subset of a complete space is complete.384theorem Complete.subspace (X S : Set)385requires metric : MetricSpace(X)386requires complete : Complete(X)387requires closed : Closed(metricTopology(X), S)388shows Complete(metricSubspace(X, S))389proof390have space := MetricSpace.topological_space with metric391have pieces := Complete.parts with complete392have closedS := Closed.parts with space, closed393rw [metricTopology.carrier, metricTopology.opens] at closedS394have metricClosed : MetricClosed(X.carrier, X.dist, S)395unfold MetricClosed396exact closedS397unfold metricSubspace398exact Complete.of_mk with (IsComplete.closed_subspace with pieces,399 metricClosed)400401instance productMetric.space (X Y : Set)402requires metricX : MetricSpace(X)403requires metricY : MetricSpace(Y)404shows MetricSpace(productMetric(X, Y))405proof406have partsX := MetricSpace.parts with metricX407have partsY := MetricSpace.parts with metricY408unfold productMetric409exact MetricSpace.of_parts with (productDistance.metric with partsX, partsY)410