1-- Interior, closure, boundary, limit points, and dense sets: the laws that2-- connect them, including the duality between interior and closure under3-- complements4-- 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.Topology.ClosureLaws10import Space1112-- Interior1314theorem interiorIn.whole (X T : Set)15requires topology : IsTopology(X, T)16shows interiorIn(T, X) = X17proof18exact interiorIn.of_open with (IsTopology.whole with topology)1920theorem interiorIn.empty (X T : Set)21requires topology : IsTopology(X, T)22shows interiorIn(T, ∅) =∅23proof24exact interiorIn.of_open with (IsTopology.empty with topology)2526theorem interiorIn.subset_whole (X T A : Set)27requires topology : IsTopology(X, T)28shows interiorIn(T, A) ⊆ X29proof30have isOpen := interiorIn.open at X, T, A with topology31exact IsTopology.subset with topology, isOpen3233theorem interiorIn.membership (T A x : Set)34shows x ∈ interiorIn(T, A) ↔∃ U ∈ T, x ∈ U ∧ U ⊆ A35proof36constructor37 . intro hx38unfold interiorIn at hx39obtain⟨U, hU, hxU⟩:= union.membership.forward with hx40have parts := openSubsets.membership.forward with hU41exact⟨U, parts.left, hxU, parts.right⟩42 . intro h43obtain⟨U, hU, hxU, inside⟩:= h44have below := interiorIn.greatest with hU, inside45exact below with x, hxU4647theorem interiorIn.subset_closure (X T A : Set)48requires topology : IsTopology(X, T)49requires hA : A ⊆ X50shows interiorIn(T, A) ⊆ closure(X, T, A)51proof52have below := interiorIn.subset at T, A53have contains := Space.closure.contains with topology, hA54exact Subset.transitive with below, contains5556theorem interiorIn.union2_subset (X T A B : Set)57requires topology : IsTopology(X, T)58shows interiorIn(T, A) ∪ interiorIn(T, B) ⊆ interiorIn(T, A ∪ B)59proof60apply union2.subset61 . exact interiorIn.monotone with topology, (union2.subset_left at A, B)62 . exact interiorIn.monotone with topology, (union2.subset_right at A, B)6364-- Closure6566theorem closure.empty (X T : Set)67requires topology : IsTopology(X, T)68shows closure(X, T, ∅) =∅69proof70exact closure.of_closed with topology, (IsClosed.empty with topology)7172theorem closure.whole (X T : Set)73requires topology : IsTopology(X, T)74shows closure(X, T, X) = X75proof76exact closure.of_closed with topology, (IsClosed.whole with topology)7778theorem closure.intersection2_subset (X T A B : Set)79requires topology : IsTopology(X, T)80requires hA : A ⊆ X81requires hB : B ⊆ X82shows closure(X, T, A ∩ B) ⊆ closure(X, T, A) ∩ closure(X, T, B)83proof84apply intersection.greatest85 . exact closure.monotone with topology, hA, (intersection.subset_left at A, B)86 . exact closure.monotone with topology, hB, (intersection.subset_right at A, B)8788-- Duality: the closure of a complement is the complement of the interiorIn.89theorem closure.complement (X T A : Set)90requires topology : IsTopology(X, T)91requires hA : A ⊆ X92shows closure(X, T, complement(X, A)) = complement(X, interiorIn(T, A))93proof94have openInterior := interiorIn.open at X, T, A with topology95have complementSubset := complement.subset at X, A96apply Subset.antisymmetric97 . have closed := Open.complement_closed with topology, openInterior98have inside := complement.antitone at X, interiorIn(T, A), A with (interiorIn.subset at T, A)99exact closure.least with closed, inside100 . have closedClosure := closure.closed with topology, complementSubset101have openPart := IsClosed.complement_open with closedClosure102have contains := Space.closure.contains with topology, complementSubset103have below := complement.antitone at X, complement(X, A), closure(X, T, complement(X, A)) with contains104have double := complement.complement with hA105rw double at below106have inside := interiorIn.greatest with openPart, below107have flipped := complement.antitone at X, complement(X, closure(X, T, complement(X, A))), interiorIn(T, A) with inside108have closureInside := closure.subset with topology, complementSubset109have doubleClosure := complement.complement with closureInside110 rwa doubleClosure at flipped111112theorem interiorIn.complement (X T A : Set)113requires topology : IsTopology(X, T)114requires hA : A ⊆ X115shows interiorIn(T, complement(X, A)) = complement(X, closure(X, T, A))116proof117have complementSubset := complement.subset at X, A118have duality := closure.complement with topology, complementSubset119have double := complement.complement with hA120rw double at duality121have interiorInside := interiorIn.subset_whole at X, T, complement(X, A) with topology122have doubleInterior := complement.complement with interiorInside123rw [duality, doubleInterior]124rfl125126-- Boundary: the closure with the interior removed.127128def boundary (X T A : Set) : Set:= closure(X, T, A) ∖ interiorIn(T, A)129130theorem boundary.membership (X T A x : Set)131shows x ∈ boundary(X, T, A) ↔ x ∈ closure(X, T, A) ∧¬x ∈ interiorIn(T, A)132proof133simp [boundary, difference.membership]134135theorem boundary.subset_closure (X T A : Set)136shows boundary(X, T, A) ⊆ closure(X, T, A)137proof138unfold boundary139exact difference.subset_left140141theorem boundary.subset_whole (X T A : Set)142requires topology : IsTopology(X, T)143requires hA : A ⊆ X144shows boundary(X, T, A) ⊆ X145proof146have below := boundary.subset_closure at X, T, A147have inside := closure.subset with topology, hA148exact Subset.transitive with below, inside149150theorem boundary.closed (X T A : Set)151requires topology : IsTopology(X, T)152requires hA : A ⊆ X153shows IsClosed(X, T, boundary(X, T, A))154proof155have closedClosure := closure.closed with topology, hA156have openInterior := interiorIn.open at X, T, A with topology157have closedComplement := Open.complement_closed with topology, openInterior158have closureInside := closure.subset with topology, hA159have same : boundary(X, T, A) = closure(X, T, A) ∩ complement(X, interiorIn(T, A))160ext x161constructor162 . intro hx163have parts := boundary.membership.forward with hx164have hxX := closureInside with x, parts.left165apply intersection.membership.backward166exact⟨parts.left, (complement.membership.backward with⟨hxX, parts.right⟩)⟩167 . intro hx168have parts := intersection.membership.forward with hx169have away := complement.membership.forward with parts.right170exact boundary.membership.backward with⟨parts.left, away.right⟩171rw same172exact IsClosed.intersection2 with topology, closedClosure, closedComplement173174theorem boundary.complement (X T A : Set)175requires topology : IsTopology(X, T)176requires hA : A ⊆ X177shows boundary(X, T, complement(X, A)) = boundary(X, T, A)178proof179have closureInside := closure.subset with topology, hA180have closureSwap := closure.complement with topology, hA181have interiorSwap := interiorIn.complement with topology, hA182unfold boundary183rw [closureSwap, interiorSwap]184ext x185constructor186 . intro hx187have parts := difference.membership.forward with hx188have inComplement := complement.membership.forward with parts.left189apply difference.membership.backward190constructor191 . by_contra outside192apply parts.right193exact complement.membership.backward with⟨inComplement.left, outside⟩194 . exact inComplement.right195 . intro hx196have parts := difference.membership.forward with hx197have hxX := closureInside with x, parts.left198apply difference.membership.backward199constructor200 . exact complement.membership.backward with⟨hxX, parts.right⟩201 . intro away202have awayParts := complement.membership.forward with away203exact awayParts.right with parts.left204205theorem IsClosed.iff_boundary_subset (X T A : Set)206requires topology : IsTopology(X, T)207requires hA : A ⊆ X208shows IsClosed(X, T, A) ↔ boundary(X, T, A) ⊆ A209proof210constructor211 . intro closed212have same := closure.of_closed with topology, closed213have below := boundary.subset_closure at X, T, A214 rwa same at below215 . intro inside216apply IsClosed.iff_closure.backward with topology, hA217have interiorBelow := interiorIn.subset at T, A218apply Subset.antisymmetric219 . intros x hx220havesplit : x ∈ interiorIn(T, A) ∨¬x ∈ interiorIn(T, A) bytauto221casessplitwith inner | outer222 . exact interiorBelow with x, inner223 . have onBoundary := boundary.membership.backward at X, T, A, x with⟨hx, outer⟩224exact inside with x, onBoundary225 . exact Space.closure.contains with topology, hA226227theorem Open.iff_boundary_disjoint (X T U : Set)228requires topology : IsTopology(X, T)229requires hU : U ⊆ X230shows U ∈ T ↔ Disjoint(U, boundary(X, T, U))231proof232constructor233 . intro isOpen234have same := interiorIn.of_open with isOpen235apply Disjoint.iff.backward236intros x hx onBoundary237have parts := boundary.membership.forward with onBoundary238apply parts.right239 rwa same240 . intro disjoint241have separated := Disjoint.iff.forward with disjoint242have contains := Space.closure.contains with topology, hU243apply Open.iff_interior.backward with topology244apply Subset.antisymmetric245 . exact interiorIn.subset at T, U246 . intros x hx247have inClosure := contains with x, hx248by_contra outer249apply separated with x, hx250exact boundary.membership.backward with⟨inClosure, outer⟩251252theorem closure.union_boundary (X T A : Set)253requires topology : IsTopology(X, T)254requires hA : A ⊆ X255shows closure(X, T, A) = A ∪ boundary(X, T, A)256proof257have contains := Space.closure.contains with topology, hA258have interiorBelow := interiorIn.subset at T, A259apply Subset.antisymmetric260 . intros x hx261apply union2.membership.backward262havesplit : x ∈ interiorIn(T, A) ∨¬x ∈ interiorIn(T, A) bytauto263casessplitwith inner | outer264 . left265exact interiorBelow with x, inner266 . right267exact boundary.membership.backward with⟨hx, outer⟩268 . apply union2.subset269 . exact contains270 . exact boundary.subset_closure at X, T, A271272theorem interiorIn.difference_boundary (X T A : Set)273requires topology : IsTopology(X, T)274requires hA : A ⊆ X275shows interiorIn(T, A) = A ∖ boundary(X, T, A)276proof277have contains := Space.closure.contains with topology, hA278have interiorBelow := interiorIn.subset at T, A279ext x280constructor281 . intro hx282apply difference.membership.backward283constructor284 . exact interiorBelow with x, hx285 . intro onBoundary286have parts := boundary.membership.forward with onBoundary287exact parts.right with hx288 . intro hx289have parts := difference.membership.forward with hx290have inClosure := contains with x, parts.left291by_contra outer292apply parts.right293exact boundary.membership.backward with⟨inClosure, outer⟩294295theorem boundary.whole (X T : Set)296requires topology : IsTopology(X, T)297shows boundary(X, T, X) =∅298proof299have closureWhole := closure.whole with topology300have interiorWhole := interiorIn.whole with topology301simp [boundary]302exact difference.self at X303304theorem boundary.empty (X T : Set)305requires topology : IsTopology(X, T)306shows boundary(X, T, ∅) =∅307proof308have closureEmpty := closure.empty with topology309have interiorEmpty := interiorIn.empty with topology310simp [boundary]311exact difference.self at∅312313-- A set that is both open and closed has no boundary.314theorem boundary.empty_of_clopen (X T U : Set)315requires topology : IsTopology(X, T)316requires isOpen : U ∈ T317requires closed : IsClosed(X, T, U)318shows boundary(X, T, U) =∅319proof320have closureSame := closure.of_closed with topology, closed321have interiorSame := interiorIn.of_open with isOpen322simp [boundary]323exact difference.self at U324325theorem boundary.boundary_subset (X T A : Set)326requires topology : IsTopology(X, T)327requires hA : A ⊆ X328shows boundary(X, T, boundary(X, T, A)) ⊆ boundary(X, T, A)329proof330have closed := boundary.closed with topology, hA331have same := closure.of_closed with topology, closed332have below := boundary.subset_closure at X, T, boundary(X, T, A)333 rwa same at below334335-- Limit points: every open set around x meets A away from x.336337def limitPoints (X T A : Set) : Set:=338 { x ∈ X |∀ U ∈ T, x ∈ U → Nonempty(U ∩ (A ∖ {x})) }339340theorem limitPoints.subset (X T A : Set)341shows limitPoints(X, T, A) ⊆ X342proof343intros x hx344have parts := limitPoints.membership.forward with hx345exact parts.left346347theorem limitPoints.subset_closure (X T A : Set)348requires topology : IsTopology(X, T)349requires hA : A ⊆ X350shows limitPoints(X, T, A) ⊆ closure(X, T, A)351proof352intros x hx353have parts := limitPoints.membership.forward with hx354apply closure.membership.backward with topology, hA355refine⟨parts.left, ?_⟩356intros U hU hxU357obtain⟨a, ha⟩:= parts.right with U, hU, hxU358have inner := intersection.membership.forward with ha359have away := difference.singleton_membership.forward with inner.right360witness a361exact intersection.membership.backward with⟨inner.left, away.left⟩362363theorem closure.union_limitPoints (X T A : Set)364requires topology : IsTopology(X, T)365requires hA : A ⊆ X366shows closure(X, T, A) = A ∪ limitPoints(X, T, A)367proof368apply Subset.antisymmetric369 . intros x hx370have parts := closure.membership.forward with topology, hA, hx371apply union2.membership.backward372havesplit : x ∈ A ∨¬x ∈ A bytauto373casessplitwith inA | outside374 . left375exact inA376 . right377apply limitPoints.membership.backward378refine⟨parts.left, ?_⟩379intros U hU hxU380obtain⟨a, ha⟩:= parts.right with U, hU, hxU381have inner := intersection.membership.forward with ha382have distinct : a ≠ x383intro same384apply outside385rw← same386exact inner.right387witness a388apply intersection.membership.backward389refine⟨inner.left, ?_⟩390exact difference.singleton_membership.backward with⟨inner.right, distinct⟩391 . apply union2.subset392 . exact Space.closure.contains with topology, hA393 . exact limitPoints.subset_closure with topology, hA394395theorem IsClosed.iff_limitPoints_subset (X T A : Set)396requires topology : IsTopology(X, T)397requires hA : A ⊆ X398shows IsClosed(X, T, A) ↔ limitPoints(X, T, A) ⊆ A399proof400constructor401 . intro closed402have same := closure.of_closed with topology, closed403have below := limitPoints.subset_closure with topology, hA404 rwa same at below405 . intro inside406apply IsClosed.iff_closure.backward with topology, hA407havesplit:= closure.union_limitPoints with topology, hA408rwsplit409apply Subset.antisymmetric410 . exact union2.subset with (Subset.reflexive at A), inside411 . exact union2.subset_left at A, limitPoints(X, T, A)412413theorem limitPoints.monotone (X T A B : Set)414requires hAB : A ⊆ B415shows limitPoints(X, T, A) ⊆ limitPoints(X, T, B)416proof417intros x hx418have parts := limitPoints.membership.forward with hx419apply limitPoints.membership.backward420refine⟨parts.left, ?_⟩421intros U hU hxU422obtain⟨a, ha⟩:= parts.right with U, hU, hxU423have inner := intersection.membership.forward with ha424have away := difference.singleton_membership.forward with inner.right425witness a426apply intersection.membership.backward427refine⟨inner.left, ?_⟩428exact difference.singleton_membership.backward with⟨(hAB with a, away.left), away.right⟩429430-- Isolated points: some open set around x meets A only in x.431432predicate IsolatedPoint (X T A x : Set) :=433 x ∈ A ∧∃ U ∈ T, x ∈ U ∧ U ∩ A = {x}434435theorem IsolatedPoint.not_limit (X T A x : Set)436requires isolated : IsolatedPoint(X, T, A, x)437shows¬x ∈ limitPoints(X, T, A)438proof439obtain⟨hxA, U, hU, hxU, trace⟩:= isolated440intro limit441have parts := limitPoints.membership.forward with limit442obtain⟨a, ha⟩:= parts.right with U, hU, hxU443have inner := intersection.membership.forward with ha444have away := difference.singleton_membership.forward with inner.right445have inTrace : a ∈ U ∩ A := intersection.membership.backward with⟨inner.left, away.left⟩446rw trace at inTrace447have same := singleton.membership.forward with inTrace448exact away.right with same449450theorem IsolatedPoint.of_not_limit (X T A x : Set)451requires topology : IsTopology(X, T)452requires hA : A ⊆ X453requires hxA : x ∈ A454requires notLimit : ¬x ∈ limitPoints(X, T, A)455shows IsolatedPoint(X, T, A, x)456proof457have hxX := hA with x, hxA458refine⟨hxA, ?_⟩459by_contra none460apply notLimit461apply limitPoints.membership.backward462refine⟨hxX, ?_⟩463intros U hU hxU464by_contra empty465apply none466refine⟨U, hU, hxU, ?_⟩467ext y468constructor469 . intro hy470have parts := intersection.membership.forward with hy471apply singleton.membership.backward472by_contra distinct473apply empty474witness y475apply intersection.membership.backward476refine⟨parts.left, ?_⟩477exact difference.singleton_membership.backward with⟨parts.right, distinct⟩478 . intro hy479have same := singleton.membership.forward with hy480rw same481exact intersection.membership.backward with⟨hxU, hxA⟩482483theorem IsolatedPoint.iff (X T A x : Set)484requires topology : IsTopology(X, T)485requires hA : A ⊆ X486requires hxA : x ∈ A487shows IsolatedPoint(X, T, A, x) ↔¬x ∈ limitPoints(X, T, A)488proof489constructor490 . intro isolated491exact IsolatedPoint.not_limit with isolated492 . intro notLimit493exact IsolatedPoint.of_not_limit with topology, hA, hxA, notLimit494495-- Dense sets496497theorem IsDense.whole (X T : Set)498requires topology : IsTopology(X, T)499shows IsDense(X, T, X)500proof501exact closure.whole with topology502503theorem IsDense.iff_meets_open (X T A : Set)504requires topology : IsTopology(X, T)505requires hA : A ⊆ X506shows IsDense(X, T, A) ↔∀ U ∈ T, Nonempty(U) → Nonempty(U ∩ A)507proof508constructor509 . intros dense U hU inhabited510have equal : closure(X, T, A) = X := dense511obtain⟨x, hx⟩:= inhabited512have inside := IsTopology.subset with topology, hU513have hxX := inside with x, hx514have inClosure : x ∈ closure(X, T, A)515rw equal516exact hxX517have parts := closure.membership.forward with topology, hA, inClosure518exact parts.right with U, hU, hx519 . intro meets520have inside := closure.subset with topology, hA521have equal : closure(X, T, A) = X522apply Subset.antisymmetric523 . exact inside524 . intros x hx525apply closure.membership.backward with topology, hA526refine⟨hx, ?_⟩527intros U hU hxU528have inhabited : Nonempty(U) :=⟨x, hxU⟩529exact meets with U, hU, inhabited530exact equal531532theorem IsDense.of_subset (X T A B : Set)533requires topology : IsTopology(X, T)534requires hB : B ⊆ X535requires hAB : A ⊆ B536requires dense : IsDense(X, T, A)537shows IsDense(X, T, B)538proof539have equal : closure(X, T, A) = X := dense540have below := closure.monotone with topology, hB, hAB541have inside := closure.subset with topology, hB542rw equal at below543exact Subset.antisymmetric with inside, below544545theorem IsDense.meets (X T A U : Set)546requires topology : IsTopology(X, T)547requires hA : A ⊆ X548requires dense : IsDense(X, T, A)549requires hU : U ∈ T550requires inhabited : Nonempty(U)551shows Nonempty(U ∩ A)552proof553have meets := IsDense.iff_meets_open.forward with topology, hA, dense554exact meets with U, hU, inhabited555556theorem IsDense.interior_complement (X T A : Set)557requires topology : IsTopology(X, T)558requires hA : A ⊆ X559shows IsDense(X, T, A) ↔ interiorIn(T, complement(X, A)) =∅560proof561have swap := interiorIn.complement with topology, hA562have inside := closure.subset with topology, hA563rw swap564constructor565 . intro dense566have equal : closure(X, T, A) = X := dense567rw equal568exact complement.self at X569 . intro empty570unfold complement at empty571have below := difference.eq_empty_iff.forward with empty572exact Subset.antisymmetric with inside, below573