Topological Spaces & Continuity
Key Points
- •A topological space abstracts the idea of “closeness” using open sets instead of distances, allowing geometry without measuring lengths.
- •Continuity in topology means preimages of open sets are open, which generalizes the familiar epsilon–delta definition from calculus.
- •Homeomorphisms are structure-preserving bijections; if two spaces are homeomorphic, they are the same from a topological point of view.
- •On finite sets, we can algorithmically verify topology axioms, continuity, and homeomorphism using set operations.
- •Open sets must include the empty set and the whole space and be closed under arbitrary unions and finite intersections.
- •Bases generate topologies efficiently: every open set is a union of basis elements.
- •For metric spaces, open balls produce a standard topology that matches our geometric intuition.
- •C++ can model finite topologies with bitmasks, enabling fast checks of axioms and continuity with clear time and space complexity.
Prerequisites
- →Set theory basics — Open sets, unions, intersections, and power sets are the language of topology.
- →Functions and mappings — Continuity and homeomorphisms are properties of functions between sets.
- →Logic and proofs — Understanding axioms, implications, and equivalences is essential for topology.
- →Metric spaces (optional) — Provide intuition via open balls and relate to familiar Euclidean ideas.
- →Bit operations in C++ — Efficient finite-set representations use bitmasks and bitwise logic.
Detailed Explanation
Tap terms for definitions01Overview
A topological space is a mathematical structure designed to capture the notion of “nearness” without relying on exact distances. Instead of numbers measuring how far apart points are, topology uses collections of subsets called open sets. These open sets indicate which points are considered close in a very flexible way. This abstraction unifies and generalizes ideas from calculus, geometry, and analysis. For example, in Euclidean space, the usual open intervals or open balls play the role of open sets. But topology allows much stranger (yet rigorous) notions of openness, enabling powerful results that apply to many contexts at once. Continuity in this setting is defined by how functions interact with open sets: a function is continuous if taking the preimage of any open set gives an open set. This captures the intuitive idea of “no sudden jumps” without epsilon–delta calculations. Two spaces that are essentially the same topologically are linked by a homeomorphism, a bijective continuous map whose inverse is also continuous. Homeomorphisms preserve all topological properties, so they provide a robust notion of equivalence between spaces. Although topological spaces can be infinite and very complex, many educational and computational experiments can be done on finite spaces. In this resource, we build C++ tools to represent finite topologies, verify the axioms, check continuity and homeomorphism, and compute interior and closure—all using efficient bitwise operations and clear complexity analysis.
02Intuition & Analogies
Imagine a city drawn as dots (intersections) and shaded regions (neighborhoods). You can describe which parts of the city feel like a single neighborhood by listing all shaded regions that locals agree are “open areas.” If a spot is in an open area, you can wiggle a little and still remain in the same area—no sharp borders pin you down. The complete list of these allowable open regions defines your city’s sense of “nearby,” even if you never measure actual distances. Now think about a weather app that maps each city location to a temperature. The app is continuous if warm zones on the thermometer correspond to open regions back in the city map; that is, if the preimage of a warm temperature range (an open set in the thermometer scale) is itself an open region in the city. There are no sudden spikes: moving a tiny bit in the city doesn’t fling you across a sharp temperature boundary. Two cities can be redrawn—perhaps one is stretched like rubber—so that their neighborhoods match up perfectly. If there’s a way to pair every point of one city with exactly one point of the other so that open regions map to open regions in both directions, the cities are topologically the same. This pairing is a homeomorphism, and it means all “rubber-sheet” properties—like connectivity or the number of holes—are preserved. In topology, what matters is how things are glued together, not the exact metric distances. Computers can mimic this intuition on small, finite “cities” by representing regions as bitmasks and checking these neighborhood rules mechanically.
03Formal Definition
04When to Use
- Abstracting continuity and convergence: When distance is unnecessary or unavailable (e.g., function spaces, quotient constructions), topology provides the right framework.
- Comparing shapes up to deformation: When you care about holes, connectedness, or separation but not rigid lengths or angles, homeomorphisms capture the right equivalence.
- Building new spaces from old: Product, subspace, and quotient topologies assemble complex objects from simpler pieces in a principled way.
- Generalizing analysis: Many theorems in calculus extend to topological spaces (compactness ensures limit points; continuity is preimage-open), enabling powerful, domain-agnostic results.
- Computing on finite models: In discrete mathematics, digital image analysis, finite-state systems, and graph-based neighborhoods, finite topologies can model adjacency or reachability and can be checked algorithmically.
- Educational tooling: For small sets, programmatic verification of topology axioms, continuity checks, and homeomorphism tests help build intuition by experimentation. Use these ideas whenever the shape of information (how pieces fit and vary) matters more than precise numeric measurement, or when constructing robust notions of continuity in non-metric contexts.
⚠️Common Mistakes
- Confusing metric continuity with topological continuity: Epsilon–delta is not required; continuity is entirely about preimages of open sets being open. Always check preimages, not images.
- Forgetting arbitrary unions: A topology must be closed under unions of any subfamily, not just pairwise or triple unions. On finite collections, pairwise closure implies finite closure, but you still conceptually require arbitrary unions.
- Ignoring the empty set or whole space: Both must be open; omitting either violates the axioms immediately.
- Checking images instead of preimages: For continuity, verifying that images of open sets are open is not sufficient in general. The correct criterion is preimage-openness.
- Confusing homeomorphism with bijection: A bijection need not be a homeomorphism; both the function and its inverse must be continuous. Verify continuity in both directions.
- Overlooking basis conditions: Not every collection of subsets generates a topology. Ensure basis axioms hold before taking unions to form the topology.
- Computational blowups: Enumerating all unions of basis elements or all subsets can be exponential. On finite sets, prefer bitwise operations and incremental closure checks, and stay mindful of sizes.
Key Formulas
Topology Axioms
Explanation: A topology is a collection of subsets including the empty set and the whole space, closed under arbitrary unions and finite intersections. This succinctly encodes the rules open sets must obey.
Topological Continuity
Explanation: Continuity is defined by preimages of opens being open. It generalizes the epsilon–delta definition without using distances.
Homeomorphism Criterion
Explanation: A homeomorphism is a structure-preserving bijection between topological spaces. It captures when two spaces are topologically identical.
Topology Generated by a Basis
Explanation: Given a basis, the topology consists of all unions of basis elements. Basis axioms ensure these unions satisfy the topology rules.
Open Ball
Explanation: In a metric space, open balls are the fundamental open neighborhoods. All opens can be formed as unions of such balls.
Interior as Union of Opens
Explanation: The interior of A is the largest open set contained in A. It is the union of all opens lying inside A.
Closure as Intersection of Closeds
Explanation: The closure of A is the smallest closed set containing A. It is the intersection of all closed supersets of A.
Closure–Interior Duality
Explanation: Closure and interior are complements of each other when swapping A with its complement. This is often the easiest way to compute one from the other.
Subspace Openness
Explanation: Openness in a subspace is inherited by intersecting opens of the ambient space with the subset. This defines the subspace topology.
Product Topology
Explanation: The product topology on X×Y is generated by rectangles U×V where U and V are open. It is the standard way to topologize Cartesian products.
Complexity Analysis
Code Examples
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 using Mask = unsigned long long; // supports up to 64 elements 5 6 // Build a bitmask from a list of elements (0-based indices) 7 Mask set_to_mask(const vector<int>& elems) { 8 Mask m = 0ULL; 9 for (int x : elems) { 10 if (x < 0 || x >= 64) throw runtime_error("element out of range for 64-bit mask"); 11 m |= (1ULL << x); 12 } 13 return m; 14 } 15 16 string to_bits(Mask m, int n){ 17 string s; s.reserve(n); 18 for(int i=n-1;i>=0;--i) s.push_back((m>>i & 1ULL)?'1':'0'); 19 return s; 20 } 21 22 // Check if a family of subsets (tau) is a topology on X={0,...,n-1} 23 bool is_topology(int n, const vector<Mask>& tau, string& reason){ 24 if (n <= 0 || n > 64) { reason = "n must be in [1,64]"; return false; } 25 Mask FULL = (n==64? ~0ULL : ((1ULL<<n)-1ULL)); 26 27 // Deduplicate and validate subsets are within universe 28 unordered_set<Mask> T; T.reserve(tau.size()*2+1); 29 for (Mask m : tau){ 30 if ((m & ~FULL) != 0ULL) { reason = "some set contains elements outside X"; return false; } 31 T.insert(m); 32 } 33 34 // Axiom 1: empty and whole space are open 35 if (!T.count(0ULL)) { reason = "missing empty set"; return false; } 36 if (!T.count(FULL)) { reason = "missing whole space"; return false; } 37 38 // Axiom 2 (arbitrary unions): It suffices to check closure under binary union for finite families. 39 vector<Mask> vec(T.begin(), T.end()); 40 for (size_t i=0;i<vec.size();++i){ 41 for (size_t j=0;j<vec.size();++j){ 42 Mask u = vec[i] | vec[j]; 43 if (!T.count(u)) { 44 reason = string("not closed under unions; example: ") + to_bits(vec[i],n) + " U " + to_bits(vec[j],n); 45 return false; 46 } 47 } 48 } 49 50 // Axiom 3 (finite intersections): check closure under binary intersection 51 for (size_t i=0;i<vec.size();++i){ 52 for (size_t j=0;j<vec.size();++j){ 53 Mask inter = vec[i] & vec[j]; 54 if (!T.count(inter)) { 55 reason = string("not closed under intersections; example: ") + to_bits(vec[i],n) + " ∩ " + to_bits(vec[j],n); 56 return false; 57 } 58 } 59 } 60 61 reason = "OK"; 62 return true; 63 } 64 65 int main(){ 66 // Example 1: Discrete topology on X={0,1,2} 67 int n = 3; 68 vector<Mask> tau_discrete; 69 for (int m=0; m < (1<<n); ++m) tau_discrete.push_back(static_cast<Mask>(m)); 70 71 string reason; 72 cout << "Discrete topology valid? " << boolalpha << is_topology(n, tau_discrete, reason) << ", reason: " << reason << "\n"; 73 74 // Example 2: An invalid family (missing union closure) 75 vector<Mask> tau_bad; // {∅, X, {0}, {1}} but missing {0,1} 76 Mask FULL = (1ULL<<n)-1ULL; 77 tau_bad = {0ULL, FULL, set_to_mask({0}), set_to_mask({1})}; 78 cout << "Bad family valid? " << boolalpha << is_topology(n, tau_bad, reason) << ", reason: " << reason << "\n"; 79 80 // Example 3: Indiscrete topology {∅, X} 81 vector<Mask> tau_indiscrete = {0ULL, FULL}; 82 cout << "Indiscrete topology valid? " << boolalpha << is_topology(n, tau_indiscrete, reason) << ", reason: " << reason << "\n"; 83 84 return 0; 85 } 86
Represents subsets of a finite set as 64-bit masks and checks the topology axioms. On finite families, binary union closure implies arbitrary unions, and binary intersection closure implies finite intersections. The examples validate the discrete and indiscrete topologies and reject a faulty collection that is not closed under unions.
1 #include <bits/stdc++.h> 2 using namespace std; 3 using Mask = unsigned long long; 4 5 Mask full_mask(int n){ return (n==64? ~0ULL : ((1ULL<<n)-1ULL)); } 6 7 bool is_topology(int n, const vector<Mask>& tau){ 8 Mask FULL = full_mask(n); 9 unordered_set<Mask> T(tau.begin(), tau.end()); 10 if (!T.count(0ULL) || !T.count(FULL)) return false; 11 vector<Mask> v(T.begin(), T.end()); 12 for (auto a: v) for (auto b: v) if (!T.count(a|b)) return false; 13 for (auto a: v) for (auto b: v) if (!T.count(a&b)) return false; 14 return true; 15 } 16 17 // continuity: preimage of every open set is open 18 bool is_continuous(int nX, const vector<Mask>& tauX, 19 int nY, const vector<Mask>& tauY, 20 const vector<int>& f){ 21 if ((int)f.size()!=nX) return false; 22 unordered_set<Mask> TX(tauX.begin(), tauX.end()); 23 for (Mask V : tauY){ 24 Mask pre = 0ULL; 25 for (int x=0; x<nX; ++x){ 26 int y = f[x]; 27 if (y<0 || y>=nY) return false; // invalid map 28 if ((V>>y) & 1ULL) pre |= (1ULL<<x); 29 } 30 if (!TX.count(pre)) return false; 31 } 32 return true; 33 } 34 35 bool is_bijection(const vector<int>& f, int n){ 36 if ((int)f.size()!=n) return false; 37 vector<int> seen(n,0); 38 for (int x=0;x<n;++x){ 39 int y=f[x]; 40 if (y<0||y>=n) return false; 41 if (seen[y]) return false; 42 seen[y]=1; 43 } 44 return true; 45 } 46 47 vector<int> inverse_bijection(const vector<int>& f){ 48 int n=f.size(); 49 vector<int> inv(n); 50 for(int x=0;x<n;++x) inv[f[x]]=x; 51 return inv; 52 } 53 54 int main(){ 55 // X={0,1,2} with indiscrete topology {∅,X} 56 int nX=3; vector<Mask> tauX = {0ULL, (1ULL<<nX)-1ULL}; 57 // Y={0,1,2} with discrete topology (all subsets open) 58 int nY=3; vector<Mask> tauY; for(int m=0;m<(1<<nY);++m) tauY.push_back((Mask)m); 59 60 // Any function f:X->Y is continuous when X is indiscrete 61 vector<int> f = {2,0,1}; 62 cout << boolalpha << "Is f continuous (indiscrete domain -> discrete codomain)? " 63 << is_continuous(nX,tauX,nY,tauY,f) << "\n"; 64 65 // Now both X and Y discrete: every bijection is a homeomorphism 66 vector<Mask> tauXd = tauY; // discrete 67 vector<Mask> tauYd = tauY; // discrete 68 vector<int> g = {1,2,0}; // a bijection on {0,1,2} 69 70 bool bij = is_bijection(g, nX); 71 bool cont = is_continuous(nX,tauXd,nY,tauYd,g); 72 vector<int> ginv = inverse_bijection(g); 73 bool cont_inv = is_continuous(nY,tauYd,nX,tauXd,ginv); 74 75 cout << "Is g a homeomorphism between discrete spaces? " 76 << (bij && cont && cont_inv) << "\n"; 77 78 // Example where bijection is NOT a homeomorphism 79 // Domain discrete, codomain indiscrete: inverse cannot be continuous unless constant. 80 bool bij2 = is_bijection(g, nX); 81 bool cont2 = is_continuous(nX,tauXd,nY,tauX,g); // to indiscrete codomain 82 vector<int> ginv2 = inverse_bijection(g); 83 bool cont_inv2 = is_continuous(nY,tauX,nX,tauXd,ginv2); // inverse continuity fails 84 85 cout << "Bijection from discrete to indiscrete is homeomorphism? " 86 << (bij2 && cont2 && cont_inv2) << "\n"; 87 88 return 0; 89 } 90
Implements continuity by checking that preimages of open sets in the codomain are open in the domain. A bijection is a homeomorphism only if both directions are continuous. The examples show: (1) any map from an indiscrete domain is continuous, and (2) bijections between discrete spaces are homeomorphisms, while a bijection to an indiscrete space fails to be a homeomorphism.
1 #include <bits/stdc++.h> 2 using namespace std; using Mask = unsigned long long; 3 4 Mask full_mask(int n){ return (n==64? ~0ULL : ((1ULL<<n)-1ULL)); } 5 6 Mask interior(Mask A, const vector<Mask>& tau){ 7 Mask in = 0ULL; 8 for (Mask U : tau){ 9 if ((U & ~A) == 0ULL) // U subset of A 10 in |= U; 11 } 12 return in; 13 } 14 15 Mask closure(Mask A, const vector<Mask>& tau, int n){ 16 Mask X = full_mask(n); 17 Mask comp = X ^ A; 18 Mask int_comp = interior(comp, tau); 19 return X ^ int_comp; // cl(A) = X \ int(X\A) 20 } 21 22 string bits(Mask m, int n){ string s; for(int i=n-1;i>=0;--i) s.push_back((m>>i & 1ULL)?'1':'0'); return s; } 23 24 int main(){ 25 // Space: X={0,1,2} 26 int n=3; Mask X = (1ULL<<n)-1ULL; 27 // Topology: tau = {∅, X, {0}, {0,1}} (valid topology) 28 vector<Mask> tau = {0ULL, X, 1ULL<<0, (1ULL<<0)|(1ULL<<1)}; 29 30 // Set A = {1,2} 31 Mask A = (1ULL<<1)|(1ULL<<2); 32 33 Mask inA = interior(A, tau); 34 Mask clA = closure(A, tau, n); 35 36 cout << "A: " << bits(A,n) << "\n"; 37 cout << "int(A): " << bits(inA,n) << "\n"; 38 cout << "cl(A): " << bits(clA,n) << "\n"; 39 40 return 0; 41 } 42
Computes interior as the union of all open sets contained in A and closure via the duality cl(A) = X \ int(X\A). Using bitmasks makes subset checks and unions constant time per open set. The demonstration uses a small nontrivial topology and a subset A to illustrate both operations.