1-- The discrete metric on any set: distinct points are at distance one, so2-- every subset is open, every subset is bounded, every map out of the3-- space is uniformly continuous, and the space is complete4-- 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.Discrete10import Line1112def discreteDistance (X : Set) : Set:=13 { q ∈ (X × X) × ℝ |∃ x ∈ X, ∃ y ∈ X,14 ((x = y ∧ q = ((x, y) ↦ (0:R))) ∨ (x ≠ y ∧ q = ((x, y) ↦ (1:R)))) }1516theorem discreteDistance.relates_self (X x : Set)17requires hx : x ∈ X18shows relates(discreteDistance(X), (x, x), (0:R))19proof20have zeroReal : (0:R) ∈ ℝ bytypecheck21have pair := product.pair at x, x, X, X with hx, hx22have entry := product.pair at (x, x), (0:R), X × X, ℝ with pair, zeroReal23unfold relates24apply discreteDistance.membership.backward25refine⟨entry, x, hx, x, hx, ?_⟩26left27constructor28 . rfl29 . rfl3031theorem discreteDistance.relates_distinct (X x y : Set)32requires hx : x ∈ X33requires hy : y ∈ X34requires distinct : x ≠ y35shows relates(discreteDistance(X), (x, y), (1:R))36proof37have oneReal : (1:R) ∈ ℝ bytypecheck38have pair := product.pair at x, y, X, X with hx, hy39have entry := product.pair at (x, y), (1:R), X × X, ℝ with pair, oneReal40unfold relates41apply discreteDistance.membership.backward42refine⟨entry, x, hx, y, hy, ?_⟩43right44constructor45 . exact distinct46 . rfl4748theorem discreteDistance.relation (X : Set)49shows RelationBetween(discreteDistance(X), X × X, ℝ)50proof51intros q hq52have parts := discreteDistance.membership.forward with hq53exact parts.left5455-- The value at a pair is determined by whether its coordinates coincide.56theorem discreteDistance.value_shape (X p v : Set)57requires edge : relates(discreteDistance(X), p, v)58shows59∃ x ∈ X, ∃ y ∈ X, p = (x, y) ∧ ((x = y ∧ v = (0:R)) ∨ (x ≠ y ∧ v = (1:R)))60proof61unfold relates at edge62obtain⟨bound, x, hx, y, hy, split⟩:=63 discreteDistance.membership.forward with edge64refine⟨x, hx, y, hy, ?_⟩65casessplitwith same | different66 . obtain⟨equal, shape⟩:= same67obtain⟨first, second⟩:= orderedPair.injective with shape68refine⟨first, ?_⟩69left70exact⟨equal, second⟩71 . obtain⟨unequal, shape⟩:= different72obtain⟨first, second⟩:= orderedPair.injective with shape73refine⟨first, ?_⟩74right75exact⟨unequal, second⟩7677theorem discreteDistance.functional (X : Set)78shows Functional(discreteDistance(X))79proof80intros p v first w second81obtain⟨x, hx, y, hy, shapeV, splitV⟩:=82 discreteDistance.value_shape with first83obtain⟨a, ha, b, hb, shapeW, splitW⟩:=84 discreteDistance.value_shape with second85rw shapeV at shapeW86obtain⟨xa, yb⟩:= orderedPair.injective with shapeW87rw [← xa, ← yb] at splitW88cases splitV with sameV | differentV89 . cases splitW with sameW | differentW90 . rw [sameV.right, sameW.right]91rfl92 . exfalso93exact differentW.left with sameV.left94 . cases splitW with sameW | differentW95 . exfalso96exact differentV.left with sameW.left97 . rw [differentV.right, differentW.right]98rfl99100theorem discreteDistance.total (X : Set)101shows∀ p ∈ X × X, ∃ v ∈ ℝ, relates(discreteDistance(X), p, v)102proof103intros p hp104obtain⟨bound, x, hx, y, hy, rfl⟩:= product.membership.forward with hp105havesplit : x = y ∨ x ≠ y bytauto106casessplitwith same | different107 . have zeroReal : (0:R) ∈ ℝ bytypecheck108refine⟨(0:R), zeroReal, ?_⟩109rw same110exact discreteDistance.relates_self with hy111 . have oneReal : (1:R) ∈ ℝ bytypecheck112refine⟨(1:R), oneReal, ?_⟩113exact discreteDistance.relates_distinct with hx, hy, different114115theorem discreteDistance.function (X : Set)116shows discreteDistance(X) : X × X → ℝ117proof118constructor119 . exact discreteDistance.relation at X120 . constructor121 . exact discreteDistance.functional at X122 . exact discreteDistance.total at X123124theorem discreteDistance.self (X x : Set)125requires hx : x ∈ X126shows discreteDistance(X)(x, x) = (0:R)127proof128have function := discreteDistance.function at X129have pair := product.pair at x, x, X, X with hx, hx130have edge := discreteDistance.relates_self with hx131unfold call2132exact FunctionBetween.apply_value with function, pair, edge133134theorem discreteDistance.distinct (X x y : Set)135requires hx : x ∈ X136requires hy : y ∈ X137requires distinct : x ≠ y138shows discreteDistance(X)(x, y) = (1:R)139proof140have function := discreteDistance.function at X141have pair := product.pair at x, y, X, X with hx, hy142have edge := discreteDistance.relates_distinct with hx, hy, distinct143unfold call2144exact FunctionBetween.apply_value with function, pair, edge145146theorem discreteDistance.le_one (X x y : Set)147requires hx : x ∈ X148requires hy : y ∈ X149shows discreteDistance(X)(x, y) ≤ (1:R)150proof151havesplit : x = y ∨ x ≠ y bytauto152casessplitwith same | different153 . rw same154haveself:= discreteDistance.self with hy155rwself156have one := realZero.lt_one157linarith158 . have value := discreteDistance.distinct with hx, hy, different159rw value160exact realLe.reflexive161162theorem discreteDistance.nonnegative (X x y : Set)163requires hx : x ∈ X164requires hy : y ∈ X165shows (0:R) ≤ discreteDistance(X)(x, y)166proof167havesplit : x = y ∨ x ≠ y bytauto168casessplitwith same | different169 . rw same170haveself:= discreteDistance.self with hy171rwself172exact realLe.reflexive173 . have value := discreteDistance.distinct with hx, hy, different174rw value175have one := realZero.lt_one176linarith177178theorem discreteDistance.real (X x y : Set)179requires hx : x ∈ X180requires hy : y ∈ X181showsReal(discreteDistance(X)(x, y))182proof183have function := discreteDistance.function at X184have pair := product.pair at x, y, X, X with hx, hy185unfoldReal186unfold call2187exact FunctionBetween.apply_closed with function, pair188189theorem discreteDistance.metric (X : Set)190shows IsMetric(X, discreteDistance(X))191proof192have one := realZero.lt_one193constructor194 . exact discreteDistance.function at X195 . constructor196 . intros x hx y hy197exact discreteDistance.nonnegative with hx, hy198 . constructor199 . intros x hx y hy200constructor201 . intro zero202by_contra203have value := discreteDistance.distinct with hx, hy, this204rw value at zero205linarith206 . intro same207rw same208exact discreteDistance.self with hy209 . constructor210 . intros x hx y hy211havesplit : x = y ∨ x ≠ y bytauto212casessplitwith same | different213 . rw same214rfl215 . have reversed : y ≠ x216intro equal217apply different218 symm at equal219exact equal220have valueXY := discreteDistance.distinct with hx, hy, different221have valueYX := discreteDistance.distinct with hy, hx, reversed222rw [valueXY, valueYX]223rfl224 . intros x hx y hy z hz225have nonnegativeXY := discreteDistance.nonnegative with hx, hy226have nonnegativeYZ := discreteDistance.nonnegative with hy, hz227have realXY := discreteDistance.real with hx, hy228have realYZ := discreteDistance.real with hy, hz229have realXZ := discreteDistance.real with hx, hz230have splitXZ : x = z ∨ x ≠ z bytauto231cases splitXZ with sameXZ | differentXZ232 . haveself : discreteDistance(X)(x, z) = (0:R)233rw sameXZ234exact discreteDistance.self with hz235rwself236linarith237 . have valueXZ := discreteDistance.distinct with hx, hz, differentXZ238rw valueXZ239have splitXY : x = y ∨ x ≠ y bytauto240cases splitXY with sameXY | differentXY241 . have differentYZ : y ≠ z242intro equal243apply differentXZ244rw sameXY245exact equal246have valueYZ := discreteDistance.distinct with hy, hz, differentYZ247rw valueYZ248linarith249 . have valueXY := discreteDistance.distinct with hx, hy, differentXY250rw valueXY251linarith252253-- Balls of radius at most one are singletons; larger balls are the space.254theorem discreteDistance.ball_small (X x : Set, r : Real)255requires hx : x ∈ X256requires positive : 0 < r257requires small : r ≤1258shows ball(X, discreteDistance(X), x, r) = {x}259proof260ext y261constructor262 . intro hy263have hyX := ball.point with hy264have near := ball.distance with hy265havesplit : x = y ∨ x ≠ y bytauto266casessplitwith same | different267 . rw← same268exact singleton.self at x269 . exfalso270have value := discreteDistance.distinct with hx, hyX, different271rw value at near272linarith273 . intro hy274have same := singleton.membership.forward with hy275rw same276apply ball.of_distance with hx277haveself:= discreteDistance.self with hx278rwself279exact positive280281theorem discreteDistance.ball_large (X x : Set, r : Real)282requires hx : x ∈ X283requires large : 1 < r284shows ball(X, discreteDistance(X), x, r) = X285proof286apply Subset.antisymmetric287 . exact ball.subset at X, discreteDistance(X), x, r288 . intros y hy289have bound := discreteDistance.le_one with hx, hy290have real := discreteDistance.real with hx, hy291apply ball.of_distance with hy292linarith293294theorem discreteDistance.open (X U : Set)295requires inside : U ⊆ X296shows MetricOpen(X, discreteDistance(X), U)297proof298constructor299 . exact inside300 . intros x hx301have hxX := inside with x, hx302have oneReal : (1:R) ∈ ℝ bytypecheck303have positive : (0:R) < 1bylinarith304have reflexive : (1:R) ≤1bylinarith305refine⟨(1:R), oneReal, positive, ?_⟩306have singleton := discreteDistance.ball_small at X, x, (1:R) with307 hxX, positive, reflexive308rw singleton309intros y hy310have same := singleton.membership.forward with hy311rw same312exact hx313314theorem discreteDistance.topology (X : Set)315shows metricTopology(X, discreteDistance(X)) =𝒫(X)316proof317apply Subset.antisymmetric318 . exact metricTopology.subset_powerset at X, discreteDistance(X)319 . intros U hU320have inside := powerset.membership_iff.forward with hU321exact metricTopology.of_open with (discreteDistance.open with inside)322323theorem discreteDistance.closed (X C : Set)324requires inside : C ⊆ X325shows MetricClosed(X, discreteDistance(X), C)326proof327apply MetricClosed.of_complement_open with inside328exact discreteDistance.open with (complement.subset at X, C)329330theorem discreteDistance.bounded (X S : Set)331requires inside : S ⊆ X332shows IsBounded(X, discreteDistance(X), S)333proof334apply IsBounded.of_bound at X, discreteDistance(X), S, (1:R) with inside335intros x hx y hy336exact discreteDistance.le_one with (inside with x, hx), (inside with y, hy)337338-- Every map out of a discrete space is uniformly continuous.339theorem discreteDistance.uniformly_continuous (f X Y e : Set)340requires metric : IsMetric(Y, e)341requires function : f : X → Y342shows IsUniformlyContinuous(f, X, discreteDistance(X), Y, e)343proof344apply IsUniformlyContinuous.of_control with function345intros ε hε positive346have oneReal : (1:R) ∈ ℝ bytypecheck347have one : (0:R) < 1bylinarith348refine⟨(1:R), oneReal, one, ?_⟩349intros x hx y hy near350havesplit : x = y ∨ x ≠ y bytauto351casessplitwith same | different352 . rw same353have image := FunctionBetween.apply_closed with function, hy354haveself:= IsMetric.self with metric, image355rwself356exact positive357 . exfalso358have value := discreteDistance.distinct with hx, hy, different359rw value at near360linarith361362theorem discreteDistance.continuous (f X Y e : Set)363requires metric : IsMetric(Y, e)364requires function : f : X → Y365shows IsMetricContinuous(f, X, discreteDistance(X), Y, e)366proof367have uniform := discreteDistance.uniformly_continuous with metric, function368exact IsUniformlyContinuous.continuous with uniform369370-- A Cauchy sequence in a discrete space is eventually constant.371theorem discreteDistance.cauchy_eventually_constant (X u : Set)372requires cauchy : IsCauchy(X, discreteDistance(X), u)373shows∃ N ∈ ℕ, ∀ n ∈ ℕ, (N ≤ n → u(n) = u(N))374proof375have sequence := IsCauchy.sequence with cauchy376have one : (0:R) < 1bylinarith377obtain⟨N, hN, close⟩:= IsCauchy.eventually with cauchy, one378have natN : Nat(N) byexact hN379refine⟨N, hN, ?_⟩380intros n hn le381have termN := SequenceIn.term_of_member with sequence, hN382have termn := SequenceIn.term_of_member with sequence, hn383have near := close with n, hn, N, hN, le, (LessEqual.reflexive at N)384by_contra385have value := discreteDistance.distinct with termn, termN, this386rw value at near387linarith388389theorem discreteDistance.complete (X : Set)390shows IsComplete(X, discreteDistance(X))391proof392have metric := discreteDistance.metric at X393apply IsComplete.of_limits with metric394intros u cauchy395have sequence := IsCauchy.sequence with cauchy396obtain⟨N, hN, constant⟩:=397 discreteDistance.cauchy_eventually_constant with cauchy398have termN := SequenceIn.term_of_member with sequence, hN399refine⟨u(N), termN, ?_⟩400apply ConvergesIn.of_eventually with sequence, termN401intros ε hε positive402refine⟨N, hN, ?_⟩403intros n hn le404have same := constant with n, hn, le405rw same406haveself:= discreteDistance.self with termN407rwself408exact positive409