mathematicskit.topology#
Simplicial complexes with signed boundary matrices, standard triangulations (spheres, torus, Klein bottle, Möbius strip, projective plane), barycentric subdivision and products; the Smith normal form, Betti numbers over \(\mathbb{Q}\) or \(\mathbb{Z}/p\), integer homology with torsion, and the Mayer-Vietoris sequence; the fundamental group; orientability, the classification of surfaces and Banchoff’s critical points; Sperner’s lemma, Brouwer fixed points, vector-field indices and Lefschetz numbers; Gauss’s linking number and Hopf’s turning number; and Vietoris-Rips and Čech complexes, persistent homology, the bottleneck distance and Mapper.
mathematicskit.topology: simplicial complexes, homology, the fundamental group, surfaces, fixed points, and persistent homology.
Simplicial complexes with signed boundary matrices; standard
triangulations of spheres, the torus, Klein bottle, Möbius strip and
projective plane, barycentric subdivision and products; the Smith normal
form, Betti numbers over Q (via numpy.linalg.matrix_rank) or Z/p,
integer homology with torsion, and the Mayer-Vietoris sequence; the
fundamental group as a presentation and its abelianization;
orientability, the classification of surfaces and Banchoff’s critical
points; Sperner’s lemma, Brouwer fixed points, vector-field indices and
Lefschetz numbers; Gauss’s linking number and Hopf’s turning number; and
Vietoris-Rips and Čech complexes, persistent homology, the bottleneck
distance and Mapper. Euler’s polyhedron formula lives in
mathematicskit.geometry.
- class mathematicskit.topology.CriticalPointsResult(index, minima, saddles, maxima)[source]#
Bases:
objectBanchoff’s critical points of a height function on the vertices of a complex.
The index of a vertex is the Euler characteristic of its lower star (the simplices whose highest vertex it is), \(1 - \chi(\text{lower link})\).
- class mathematicskit.topology.Filtration(simplices, values)[source]#
Bases:
objectA nested sequence of simplicial complexes, as simplices with the value at which each appears.
Every face enters no later than its cofaces, and simplices are kept sorted by (value, dimension), so any prefix of
simplicesis a simplicial complex.
- class mathematicskit.topology.FixedPointResult(point, triangle, n, residual)[source]#
Bases:
objectAn approximate fixed point from a fully labelled triangle of a Sperner labelling.
- class mathematicskit.topology.FundamentalGroupPresentation(generators, relations=<factory>)[source]#
Bases:
objectA presentation \(\langle g_1, \dots, g_n \mid r_1, \dots, r_m \rangle\) of \(\pi_1\).
Each relation is a word, a list of
(generator, exponent)letters with exponent \(\pm 1\).str()writes generators asa, b, c, ...and inverses as capitals.
- class mathematicskit.topology.HomologyResult(betti_numbers, torsion)[source]#
Bases:
objectInteger homology \(H_k \cong \mathbb{Z}^{\beta_k} \oplus \mathbb{Z}/t_1 \oplus \dots\) in each dimension.
- property euler_characteristic: int#
\(\sum_k (-1)^k \beta_k\), equal to the alternating simplex count.
- Type:
- class mathematicskit.topology.MapperResult(nodes, edges, node_values)[source]#
Bases:
objectThe Mapper graph of a point cloud: one node per cluster of each cover set, an edge where clusters share points.
- property graph: SimplicialComplex#
The Mapper graph as a 1-dimensional complex.
- Type:
- class mathematicskit.topology.MayerVietorisResult(betti_a, betti_b, betti_intersection, betti_union, rank_inclusion)[source]#
Bases:
objectThe Betti numbers in the Mayer-Vietoris sequence of \(X = A \cup B\) over \(\mathbb{Q}\).
Exactness at each term gives \(\beta_k(A \cup B) = \beta_k(A) + \beta_k(B) - \operatorname{rk} i_k + \beta_{k-1}(A \cap B) - \operatorname{rk} i_{k-1}\), where \(i_k: H_k(A \cap B) \to H_k(A) \oplus H_k(B)\) is induced by the inclusions.
- Parameters:
- class mathematicskit.topology.PersistenceDiagram(pairs)[source]#
Bases:
objectBirth-death pairs of a filtration’s homology classes, per dimension.
A class that never dies has death \(+\infty\).
- Parameters:
pairs (dict)
- betti_numbers(t)[source]#
The Betti numbers of the complex at filtration value
t: intervals with birth \(\le t <\) death.
- class mathematicskit.topology.SimplicialComplex(simplices=(), coordinates=None)[source]#
Bases:
objectA finite abstract simplicial complex on integer vertices.
Built from any collection of simplices (vertex lists); every face of every simplex is added, so
SimplicialComplex([[0, 1, 2]])is the filled triangle with its three edges and three vertices. Simplices are stored as sorted tuples, which fixes the orientation used byboundary_matrix():\[\partial_k [v_0, \dots, v_k] = \sum_{i=0}^{k} (-1)^i [v_0, \dots, \hat v_i, \dots, v_k].\]- Parameters:
Examples
>>> hollow_triangle = SimplicialComplex([[0, 1], [1, 2], [0, 2]]) >>> hollow_triangle.f_vector, hollow_triangle.euler_characteristic ((3, 3), 0) >>> hollow_triangle.boundary_matrix(1) array([[-1, -1, 0], [ 1, 0, -1], [ 0, 1, 1]])
- boundary_matrix(k)[source]#
The signed boundary matrix \(\partial_k: C_k \to C_{k-1}\), shape \((f_{k-1}, f_k)\).
Column
jholds the boundary of thej-thk-simplex. \(\partial_0\) is the zero map to the trivial group, with no rows. Consecutive boundary matrices multiply to zero, \(\partial_{k-1}\partial_k = 0\).
- property coordinates: ndarray | None#
Vertex positions, row
vfor vertexv(assignable from any array-like).- Type:
ndarray or None
- property euler_characteristic: int#
\(\chi = \sum_k (-1)^k f_k\), the alternating count of simplices.
- Type:
- property f_vector: tuple[int, ...]#
\((f_0, f_1, \dots)\), the number of simplices of each dimension.
- index(simplex)[source]#
Position of
simplexamong the simplices of its dimension (the row/column of the boundary matrices).
- induced_subcomplex(vertices)[source]#
The full subcomplex on
vertices: every simplex all of whose vertices are in the set.- Parameters:
vertices (iterable of int)
- Return type:
- Returns:
SimplicialComplex
- link(vertex)[source]#
The link of a vertex: the faces \(\tau\) with \(v \notin \tau\) and \(\tau \cup \{v\}\) in the complex.
- Parameters:
vertex (
int)- Return type:
- Returns:
SimplicialComplex
- property maximal_simplices: list[tuple[int, ...]]#
The simplices that are not a face of any other simplex.
- simplices(k=None)[source]#
The
k-simplices in lexicographic order, or all simplices by dimension ifkis omitted.
- class mathematicskit.topology.SmithNormalFormResult(D, U, V)[source]#
Bases:
objectThe Smith normal form \(D = UAV\) of an integer matrix.
\(U\) and \(V\) are unimodular (integer, determinant \(\pm 1\)) and \(D\) is diagonal with \(d_1 \mid d_2 \mid \dots \mid d_r\), all positive.
- class mathematicskit.topology.SurfaceClassification(name, orientable, euler_characteristic, boundary_components, genus)[source]#
Bases:
objectWhere a compact connected surface sits in the classification theorem.
- Parameters:
- class mathematicskit.topology.TriangleGrid(n, points, triangles)[source]#
Bases:
objectThe subdivision of the standard triangle into \(n^2\) small triangles.
Vertices are integer barycentric coordinates \((i, j, k)\) with \(i + j + k = n\).
- mathematicskit.topology.abelianization(presentation)[source]#
The abelianized group \(\pi_1^{ab} \cong H_1\), e.g.
"Z + Z/2".Abelianizing turns each relation into a row of exponent sums; the group is \(\mathbb{Z}^n\) modulo the row space, read off from the Smith normal form of that matrix (Hurewicz: it equals \(H_1\)).
- Parameters:
presentation (
FundamentalGroupPresentation)- Return type:
- Returns:
str
Examples
>>> from mathematicskit.topology.systems.complexes import klein_bottle >>> abelianization(fundamental_group(klein_bottle(3, 3))) 'Z + Z/2'
- mathematicskit.topology.barycentric_subdivision(K)[source]#
The barycentric subdivision \(\operatorname{sd} K\): one vertex per simplex, one simplex per chain of faces.
A \(k\)-simplex of \(\operatorname{sd} K\) is a chain \(\sigma_0 \subsetneq \sigma_1 \subsetneq \dots \subsetneq \sigma_k\). Vertex
iof the result is thei-th simplex ofK.simplices(), placed at its barycenter whenKhas coordinates. The space is unchanged, and so is its homology; that homology is a topological invariant was proved by refining any map to a simplicial one on a fine enough subdivision (Brouwer 1911, Alexander 1915).- Parameters:
- Return type:
- Returns:
SimplicialComplex
Examples
>>> barycentric_subdivision(simplex(2)).f_vector (7, 12, 6)
- mathematicskit.topology.betti_numbers(K, field=0)[source]#
The Betti numbers \(\beta_k = f_k - \operatorname{rk}\partial_k - \operatorname{rk}\partial_{k+1}\).
Enrico Betti’s connectivity numbers (1871), in Poincaré’s homological form. Over \(\mathbb{Q}\) (
field=0) they count the free part of integer homology; over \(\mathbb{Z}/p\) they also pick up \(p\)-torsion, so the Klein bottle has \(\beta_1 = 1\) over \(\mathbb{Q}\) but 2 over \(\mathbb{Z}/2\). See E. Betti, “Sopra gli spazi di un numero qualunque di dimensioni,” Annali di Matematica Pura ed Applicata 4 (1871), 140-158.- Parameters:
field (
int) – 0 for the rationals (vianumpy.linalg.matrix_rank()), or a primep.field=2never builds a dense matrix, and is the fast choice for large complexes such as Vietoris-Rips complexes.
- Return type:
- Returns:
tuple of int – \((\beta_0, \dots, \beta_{\dim K})\).
Examples
>>> from mathematicskit.topology.systems.complexes import sphere, torus >>> betti_numbers(sphere(2)), betti_numbers(torus()) ((1, 0, 1), (1, 2, 1))
- mathematicskit.topology.bottleneck_distance(diagram1, diagram2)[source]#
The bottleneck distance \(\inf_\gamma \sup_x \|x - \gamma(x)\|_\infty\) between two persistence diagrams.
Points may be matched to each other or to their nearest point on the diagonal, at distance \((d - b)/2\). Classes that never die must be matched among themselves (otherwise the distance is infinite). The stability theorem bounds it by the size of a perturbation: for sublevel-set filtrations of \(f\) and \(g\), \(d_B \le \|f - g\|_\infty\). See D. Cohen-Steiner, H. Edelsbrunner and J. Harer, “Stability of persistence diagrams,” Discrete & Computational Geometry 37 (2007), 103-120.
- Parameters:
- Return type:
- Returns:
float
Examples
>>> bottleneck_distance([[0, 4], [1, 2]], [[0, 3.5]]) 0.5
- mathematicskit.topology.boundary_components(K)[source]#
Number of boundary circles of a triangulated surface: components of the edges that lie in a single triangle.
- Parameters:
K (
SimplicialComplex) – A 2-dimensional pseudomanifold.- Return type:
- Returns:
int
Examples
>>> from mathematicskit.topology.systems.complexes import mobius_strip, simplex >>> boundary_components(simplex(2)), boundary_components(mobius_strip()) (1, 1)
- mathematicskit.topology.brouwer_fixed_point(f, n=64)[source]#
An approximate fixed point of a continuous self-map of the triangle, via Sperner’s lemma.
Each grid vertex \(x\) is labelled with the first coordinate the map does not increase, \(\min\{i : x_i > 0,\ f(x)_i \le x_i\}\). That is a Sperner labelling (a label exists because both \(x\) and \(f(x)\) sum to 1), so a fully labelled small triangle exists, and on it every coordinate is decreased somewhere. As \(n \to \infty\) such triangles shrink onto fixed points, which is Brouwer’s theorem: every continuous map of a disc to itself has a fixed point. See L. E. J. Brouwer, “Über Abbildung von Mannigfaltigkeiten,” Mathematische Annalen 71 (1911), 97-115.
- Parameters:
- Return type:
- Returns:
FixedPointResult – The centroid of the first fully labelled triangle.
Examples
>>> rotate = lambda x: np.roll(x, 1) >>> result = brouwer_fixed_point(rotate, n=30) >>> bool(np.allclose(result.point, 1 / 3, atol=2 / 30)) True
- mathematicskit.topology.cech_complex(points, radius, max_dim=2)[source]#
The Čech complex of planar points: every set whose discs of radius \(r\) share a common point.
Discs meet exactly when the smallest circle enclosing their centres has radius at most \(r\), which Welzl’s algorithm decides. The candidates are the Vietoris-Rips simplices at the same radius, since Čech \(\subseteq\) Rips; conversely Rips at \(r\) is inside Čech at \(2r/\sqrt3\) (Jung’s theorem). By the nerve theorem the Čech complex has the homotopy type of the union of the discs. See E. Čech, “Théorie générale de l’homologie dans un espace quelconque,” Fundamenta Mathematicae 19 (1932), 149-183; K. Borsuk, “On the imbedding of systems of compacta in simplicial complexes,” ibid. 35 (1948), 217-234.
- Parameters:
- Return type:
- Returns:
SimplicialComplex
Examples
>>> triangle = [[0, 0], [1, 0], [0.5, np.sqrt(3) / 2]] >>> cech_complex(triangle, 0.55).f_vector, vietoris_rips_complex(triangle, 0.55).f_vector ((3, 3), (3, 3, 1))
- mathematicskit.topology.circle(n=6)[source]#
The
n-gon: the circle \(S^1\) withnvertices on the unit circle.- Parameters:
n (
int) – Number of vertices, at least 3.- Return type:
- Returns:
SimplicialComplex
Examples
>>> circle(5).f_vector (5, 5)
- mathematicskit.topology.classify_surface(K)[source]#
Identify a triangulated compact connected surface by the classification theorem.
Every such surface is a sphere with \(g\) handles (orientable) or with \(g\) cross-caps (non-orientable), with some number \(b\) of open discs removed. The triple (orientability, \(\chi\), \(b\)) determines it, since capping the boundary gives a closed surface with \(\chi + b = 2 - 2g\) or \(2 - g\). See H. R. Brahana, “Systems of circuits on two-dimensional manifolds,” Annals of Mathematics 23(2) (1921), 144-168.
- Parameters:
K (
SimplicialComplex) – Connected, 2-dimensional, with every vertex link a circle (interior) or an arc (boundary).- Return type:
- Returns:
SurfaceClassification
Examples
>>> from mathematicskit.topology.systems.complexes import klein_bottle, projective_plane, torus >>> [classify_surface(K).name for K in (torus(), klein_bottle(), projective_plane())] ['torus', 'Klein bottle', 'projective plane']
- mathematicskit.topology.clique_simplices(adjacency, max_dim)[source]#
All cliques of a graph with at most
max_dim + 1vertices, as sorted vertex tuples.- Parameters:
- Return type:
- Returns:
list of tuple of int
Examples
>>> square_with_diagonal = np.array([[0, 1, 1, 1], [1, 0, 1, 0], [1, 1, 0, 1], [1, 0, 1, 0]], dtype=bool) >>> [s for s in clique_simplices(square_with_diagonal, 2) if len(s) == 3] [(0, 1, 2), (0, 2, 3)]
- mathematicskit.topology.critical_points(K, heights)[source]#
Banchoff’s critical points of a height function given on the vertices.
Each simplex is charged to its highest vertex, so the simplices are partitioned into lower stars, and the index of vertex \(v\) is \(\sum_{\sigma \in \text{lower star}(v)} (-1)^{\dim \sigma}\). On a surface a minimum has index \(+1\), a maximum \(+1\), a saddle \(-1\) (a monkey saddle \(-2\)), and a regular point 0; summing over all vertices gives Euler’s \(\chi\) – the polyhedral form of Morse’s relation between critical points and topology. Ties in height are broken by vertex label. See T. F. Banchoff, “Critical points and curvature for embedded polyhedra,” Journal of Differential Geometry 1 (1967), 245-256.
- Parameters:
heights (array_like) –
heights[v]is the height of vertexv.
- Return type:
- Returns:
CriticalPointsResult
Examples
>>> from mathematicskit.topology.systems.complexes import torus >>> T = torus(8, 6) >>> result = critical_points(T, T.coordinates[:, 0]) >>> len(result.minima), len(result.saddles), len(result.maxima), result.euler_characteristic (1, 2, 1, 0)
- mathematicskit.topology.fully_labeled_triangles(grid, labels)[source]#
Indices of the small triangles whose corners carry all three labels.
Sperner’s lemma: for a Sperner labelling their number is odd, hence at least one. Counting “doors” (edges labelled
{0, 1}) shows it: the bottom side has an odd number, and every small triangle has 0 or 2 doors unless it is fully labelled. See E. Sperner, “Neuer Beweis für die Invarianz der Dimensionszahl und des Gebietes,” Abhandlungen aus dem Mathematischen Seminar der Universität Hamburg 6 (1928), 265-272.- Parameters:
grid (
TriangleGrid)labels (array_like of int)
- Return type:
- Returns:
ndarray of int
Examples
>>> grid = triangle_grid(1) >>> fully_labeled_triangles(grid, [0, 1, 2]).tolist() [0]
- mathematicskit.topology.fundamental_group(K, base=None, simplify=True)[source]#
A presentation of \(\pi_1(K, v_0)\) from a spanning tree of the 1-skeleton.
Every edge outside a breadth-first spanning tree of the base point’s component is a generator (oriented from its lower to its higher vertex); every triangle \([a, b, c]\) gives the relation \([ab][bc][ac]^{-1} = 1\), with tree edges deleted. With
simplify, Tietze moves remove generators that a relation expresses in terms of the others. See H. Poincaré, “Analysis situs,” Journal de l’École Polytechnique (2) 1 (1895), 1-121, Sec. 12.- Parameters:
- Return type:
- Returns:
FundamentalGroupPresentation
Examples
>>> from mathematicskit.topology.systems.complexes import projective_plane, sphere, torus >>> str(fundamental_group(sphere(2))), str(fundamental_group(projective_plane())) ('1', '< a | aa >') >>> P = fundamental_group(torus(3, 3)) >>> len(P.generators), len(P.relations), len(P.relations[0]) (2, 1, 4)
- mathematicskit.topology.homology(K)[source]#
Integer homology \(H_k(K; \mathbb{Z}) \cong \mathbb{Z}^{\beta_k} \oplus \mathbb{Z}/t_1 \oplus \cdots\) by Smith normal form.
The rank of each boundary matrix gives the Betti numbers; the invariant factors of \(\partial_{k+1}\) that exceed 1 are the torsion coefficients of \(H_k\), which Poincaré introduced in 1900 after Heegaard showed that Betti numbers alone miss them. The alternating sum of the Betti numbers equals that of the simplex counts (the Euler-Poincaré formula).
- Parameters:
K (
SimplicialComplex) – Small enough for exact integer elimination (hundreds of simplices).- Return type:
- Returns:
HomologyResult
Examples
>>> from mathematicskit.topology.systems.complexes import klein_bottle, projective_plane >>> str(homology(projective_plane())) 'H_0 = Z, H_1 = Z/2, H_2 = 0' >>> homology(klein_bottle(3, 3)).group(1) 'Z + Z/2'
- mathematicskit.topology.is_orientable(K)[source]#
Whether a pure
n-dimensional pseudomanifold can be oriented coherently.Orientations are propagated across shared \((n-1)\)-faces by breadth-first search: a top simplex with orientation \(s\) induces \(s(-1)^i\) on its face opposite vertex
i, and two simplices sharing a face must induce opposite orientations on it. The surface is non-orientable exactly when some closed path of triangles returns with the orientation reversed, which is the one-sidedness that A. F. Möbius described in “Über die Bestimmung des Inhaltes eines Polyëders,” Berichte über die Verhandlungen der Königlich Sächsischen Gesellschaft der Wissenschaften 17 (1865), 31-68.- Parameters:
K (
SimplicialComplex) – Pure (every maximal simplex has the top dimension), with every codimension-1 face in at most two top simplices.- Return type:
- Returns:
bool
Examples
>>> from mathematicskit.topology.systems.complexes import mobius_strip, torus >>> is_orientable(torus()), is_orientable(mobius_strip()) (True, False)
- mathematicskit.topology.is_sperner_labeling(grid, labels)[source]#
Whether every vertex is labelled with a corner of its carrier face (a nonzero barycentric coordinate).
- Parameters:
grid (
TriangleGrid)labels (array_like of int) – A label in
{0, 1, 2}per grid vertex.
- Return type:
- Returns:
bool
Examples
>>> grid = triangle_grid(2) >>> is_sperner_labeling(grid, grid.points.argmax(axis=1)) True
- mathematicskit.topology.klein_bottle(n=6, m=4, R=2.0)[source]#
A triangulated Klein bottle, with the self-intersecting “figure-8” immersion in \(\mathbb{R}^3\) as coordinates.
The square’s sides are glued as a torus’s, except that one pair is glued with a flip, \((2\pi, v) \sim (0, -v)\).
- Parameters:
- Return type:
- Returns:
SimplicialComplex
Examples
>>> klein_bottle(3, 3).euler_characteristic 0
- mathematicskit.topology.lefschetz_number(K, vertex_map)[source]#
The Lefschetz number \(L(f) = \sum_k (-1)^k \operatorname{tr}(f_\#: C_k \to C_k)\) of a simplicial self-map.
By the Hopf trace formula the alternating trace on chains equals the alternating trace on homology, the Lefschetz number. A simplex that
fmaps onto itself contributes the sign of the permutation of its vertices, so \(L(f) \ne 0\) forces a fixed simplex, and by Brouwer’s barycentre argument a fixed point: the Lefschetz fixed-point theorem. The identity gives \(L = \chi(K)\). See S. Lefschetz, “Intersections and transformations of complexes and manifolds,” Transactions of the American Mathematical Society 28 (1926), 1-49; H. Hopf, “Über die algebraische Anzahl von Fixpunkten,” Mathematische Zeitschrift 29 (1929), 493-524.- Parameters:
vertex_map (dict or array_like) – The image of each vertex; every simplex must map onto a simplex of
K.
- Return type:
- Returns:
int
Examples
>>> from mathematicskit.topology.systems.complexes import circle >>> C = circle(6) >>> rotation = [(v + 1) % 6 for v in range(6)] >>> reflection = [(-v) % 6 for v in range(6)] >>> lefschetz_number(C, rotation), lefschetz_number(C, reflection) (0, 2)
- mathematicskit.topology.linking_number(curve1, curve2)[source]#
Gauss’s linking integral \(\frac{1}{4\pi}\oint\oint \frac{(r_1 - r_2)\cdot(dr_1 \times dr_2)}{|r_1 - r_2|^3}\) of two closed polygons.
Each pair of segments contributes the solid angle it subtends, computed exactly from the four unit normals of the tetrahedron the two segments span (K. Klenin and J. Langowski, “Computation of writhe in modeling of supercoiled DNA,” Biopolymers 54 (2000), 307-317), so the sum is an integer up to rounding error. The sign follows the curves’ orientations. See C. F. Gauss, “Zur mathematischen Theorie der electrodynamischen Wirkungen” (1833), in Werke V (Göttingen, 1867), 605.
- Parameters:
- Return type:
- Returns:
float – Close to an integer.
Examples
>>> t = np.linspace(0, 2 * np.pi, 60, endpoint=False) >>> ring = np.column_stack([np.cos(t), np.sin(t), 0 * t]) >>> hooked = np.column_stack([1 + np.cos(t), 0 * t, np.sin(t)]) >>> far = ring + [5, 0, 0] >>> round(linking_number(ring, hooked)), round(linking_number(ring, hooked[::-1])), round(linking_number(ring, far)) (-1, 1, 0)
- mathematicskit.topology.lower_star_filtration(K, vertex_values)[source]#
The sublevel-set filtration of a function on the vertices: each simplex enters at its highest vertex value.
The complex at value \(t\) is the full subcomplex on the vertices with \(f \le t\), the simplicial version of the sublevel sets \(f^{-1}(-\infty, t]\) of Morse theory.
- Parameters:
vertex_values (array_like) –
vertex_values[v]for each vertex labelv.
- Return type:
- Returns:
Filtration
Examples
>>> from mathematicskit.topology.systems.complexes import circle >>> lower_star_filtration(circle(3), [2.0, 0.0, 1.0]).values.tolist() [0.0, 1.0, 1.0, 2.0, 2.0, 2.0]
- mathematicskit.topology.mapper_graph(points, lens, eps, n_intervals=10, overlap=0.3)[source]#
The Mapper graph: cluster the points in each slice of a lens function, join clusters that share points.
The range of
lensis covered byn_intervalsintervals that overlap by the fractionoverlap; the points in each interval are split into clusters by single linkage at distanceeps; the nerve of the clusters is the graph. A discrete analogue of the Reeb graph that summarises the shape of high-dimensional data. See G. Singh, F. Mémoli and G. Carlsson, “Topological methods for the analysis of high dimensional data sets and 3D object recognition,” Eurographics Symposium on Point-Based Graphics (2007), 91-100.- Parameters:
- Return type:
- Returns:
MapperResult
Examples
>>> t = np.linspace(0, 2 * np.pi, 200, endpoint=False) >>> loop = np.column_stack([np.cos(t), np.sin(t)]) >>> result = mapper_graph(loop, loop[:, 0], eps=0.2, n_intervals=6) >>> len(result.nodes), len(result.edges) (10, 10)
- mathematicskit.topology.mayer_vietoris(A, B)[source]#
The ranks in the Mayer-Vietoris sequence of \(A \cup B\), over \(\mathbb{Q}\).
\[\cdots \to H_k(A \cap B) \xrightarrow{i_k} H_k(A) \oplus H_k(B) \to H_k(A \cup B) \xrightarrow{\delta} H_{k-1}(A \cap B) \to \cdots\]The rank of \(i_k\) is computed directly: the cycles of \(A \cap B\) (a basis from
scipy.linalg.null_space()) pushed into \(A\) and \(B\), counted modulo the boundaries there. Exactness then predicts the Betti numbers of the union from those of the pieces (MayerVietorisResult.predicted_union), which the result also computes directly. See W. Mayer, “Über abstrakte Topologie,” Monatshefte für Mathematik und Physik 36 (1929), 1-42; L. Vietoris, “Über die Homologiegruppen der Vereinigung zweier Komplexe,” ibid. 37 (1930), 159-162.- Parameters:
- Return type:
- Returns:
MayerVietorisResult
Examples
>>> from mathematicskit.topology.systems.complexes import circle >>> C = circle(6) >>> upper, lower = C.induced_subcomplex([0, 1, 2, 3]), C.induced_subcomplex([3, 4, 5, 0]) >>> result = mayer_vietoris(upper, lower) >>> result.betti_intersection, result.betti_union, result.predicted_union ((2,), (1, 1), (1, 1))
- mathematicskit.topology.mobius_strip(n=8, m=1, width=1.0)[source]#
A triangulated Möbius strip in \(\mathbb{R}^3\): a band whose ends are glued with a half twist.
- Parameters:
- Return type:
- Returns:
SimplicialComplex
Examples
>>> mobius_strip(5).f_vector (10, 20, 10)
- mathematicskit.topology.persistent_homology(filtration, max_dim=None, include_zero=False)[source]#
The persistence diagram of a filtration, by the standard column reduction over \(\mathbb{Z}/2\).
See H. Edelsbrunner, D. Letscher and A. Zomorodian, “Topological persistence and simplification,” Discrete & Computational Geometry 28 (2002), 511-533; A. Zomorodian and G. Carlsson, “Computing persistent homology,” ibid. 33 (2005), 249-274.
- Parameters:
filtration (
Filtration)max_dim (
int|None) – Highest homology dimension to report; by default the filtration’s top dimension.include_zero (
bool) – Keep pairs born and killed at the same value.
- Return type:
- Returns:
PersistenceDiagram
Examples
>>> from mathematicskit.topology.systems.point_clouds import vietoris_rips_filtration >>> square = [[0, 0], [1, 0], [1, 1], [0, 1]] >>> diagram = persistent_homology(vietoris_rips_filtration(square), max_dim=1) >>> diagram.diagram(0).tolist() [[0.0, 0.5], [0.0, 0.5], [0.0, 0.5], [0.0, inf]] >>> np.round(diagram.diagram(1), 4).tolist() [[0.5, 0.7071]]
- mathematicskit.topology.planar_betti_numbers(mask)[source]#
The Betti numbers \((\beta_0, \beta_1)\) of the region drawn in a 2D boolean image.
- Parameters:
mask (array_like of bool, shape (rows, cols)) – True on the region.
- Return type:
- Returns:
tuple of int – Components and holes.
Examples
>>> ring = np.ones((5, 5), dtype=bool) >>> ring[2, 2] = False >>> planar_betti_numbers(ring) (1, 1)
- mathematicskit.topology.projective_plane()[source]#
The 6-vertex real projective plane \(\mathbb{RP}^2\): the icosahedron with antipodal points identified.
It is the smallest triangulation of \(\mathbb{RP}^2\): 6 vertices, 15 edges and 10 triangles, so \(\chi = 1\). Vertex 0 is the centre of a disc whose boundary pentagon
1, ..., 5is glued to itself antipodally. It has no coordinates: \(\mathbb{RP}^2\) does not embed in \(\mathbb{R}^3\).- Return type:
- Returns:
SimplicialComplex
Examples
>>> projective_plane().f_vector (6, 15, 10)
- mathematicskit.topology.random_sperner_labeling(grid, seed=None)[source]#
A Sperner labelling chosen uniformly at random: each vertex gets a random corner of its carrier face.
- Parameters:
grid (
TriangleGrid)seed (int or numpy.random.Generator, optional)
- Return type:
- Returns:
ndarray of int
Examples
>>> grid = triangle_grid(5) >>> is_sperner_labeling(grid, random_sperner_labeling(grid, seed=0)) True
- mathematicskit.topology.rank_mod_p(A, p)[source]#
Rank of an integer matrix over the field GF(p), by Gaussian elimination.
Examples
>>> rank_mod_p([[2, 0], [0, 1]], 2), rank_mod_p([[2, 0], [0, 1]], 3) (1, 2)
- mathematicskit.topology.simplex(n)[source]#
The full
n-simplex: all \(2^{n+1} - 1\) faces of \(\{0, \dots, n\}\).It is contractible, so \(\chi = 1\).
- Parameters:
n (
int) – Dimension, at least 0.- Return type:
- Returns:
SimplicialComplex
Examples
>>> simplex(2).f_vector (3, 3, 1)
- mathematicskit.topology.simplicial_product(K, L)[source]#
A triangulation of \(|K| \times |L|\), by staircase paths through each product of simplices.
With the vertices of each complex ordered, the product \(\sigma \times \tau\) of a \(p\)-simplex and a \(q\)-simplex is cut into \(\binom{p+q}{p}\) simplices of dimension \(p + q\), one per monotone lattice path from \((\sigma_0, \tau_0)\) to \((\sigma_p, \tau_q)\); the ordering makes the pieces agree on shared faces. Vertex \((v, w)\) gets label
i * len(L.vertices) + j, wherevandware thei-th andj-th vertices ofKandL. See S. Eilenberg and J. A. Zilber, “Semi-simplicial complexes and singular homology,” Annals of Mathematics 51 (1950), 499-513.- Parameters:
- Return type:
- Returns:
SimplicialComplex – Coordinates are the concatenated coordinates of both factors, when both have them.
Examples
>>> simplicial_product(sphere(1), sphere(1)).f_vector (9, 27, 18)
- mathematicskit.topology.smith_normal_form(A)[source]#
The Smith normal form \(D = UAV\) of an integer matrix.
Repeatedly moves the smallest nonzero entry to the pivot, clears its row and column by integer row and column operations (the Euclidean algorithm in matrix form), and adds a row back whenever the pivot does not divide the rest, until \(D\) is diagonal with \(d_1 \mid d_2 \mid \cdots\). The invariant factors classify the finitely generated abelian group \(\mathbb{Z}^m / A\mathbb{Z}^n\). Arithmetic is in exact Python integers. See H. J. S. Smith, “On systems of linear indeterminate equations and congruences,” Philosophical Transactions of the Royal Society 151 (1861), 293-326.
- Parameters:
- Return type:
- Returns:
SmithNormalFormResult
Examples
>>> result = smith_normal_form([[2, 4, 4], [-6, 6, 12], [10, -4, -16]]) >>> result.invariant_factors [2, 6, 12] >>> bool(np.array_equal(result.U @ np.array([[2, 4, 4], [-6, 6, 12], [10, -4, -16]]) @ result.V, result.D)) True
- mathematicskit.topology.sphere(n, kind='simplex')[source]#
A triangulation of the
n-sphere \(S^n\).kind="simplex"gives the boundary of the \((n+1)\)-simplex (\(n + 2\) vertices, the fewest possible);kind="cross_polytope"gives the boundary of the cross-polytope (the octahedron for \(n = 2\)), with vertex \(2i\) at \(+e_i\) and \(2i+1\) at \(-e_i\), so that \(v \mapsto v \oplus 1\) is the antipodal map.- Parameters:
- Return type:
- Returns:
SimplicialComplex
Examples
>>> sphere(2).f_vector, sphere(2, kind="cross_polytope").f_vector ((4, 6, 4), (6, 12, 8))
- mathematicskit.topology.torus(n=6, m=4, R=2.0, r=1.0)[source]#
A triangulated torus \(T^2 = S^1 \times S^1\), embedded as a ring in \(\mathbb{R}^3\).
- Parameters:
- Return type:
- Returns:
SimplicialComplex
Examples
>>> torus(3, 3).f_vector (9, 27, 18)
- mathematicskit.topology.triangle_grid(n)[source]#
Subdivide the standard triangle into \(n^2\) congruent small triangles.
- Parameters:
n (
int) – Subdivisions per side, at least 1.- Return type:
- Returns:
TriangleGrid
Examples
>>> grid = triangle_grid(3) >>> grid.points.shape, grid.triangles.shape ((10, 3), (9, 3))
- mathematicskit.topology.turning_number(curve)[source]#
The turning number of a closed plane polygon: the total turning of its tangent divided by \(2\pi\).
Sums the signed exterior angle at each vertex. Hopf’s Umlaufsatz: every simple closed curve has turning number \(+1\) (counter-clockwise) or \(-1\) (clockwise); a figure eight has 0. By Whitney and Graustein (1937), two closed curves can be deformed into each other through immersed curves exactly when their turning numbers agree. See H. Hopf, “Über die Drehung der Tangenten und Sehnen ebener Kurven,” Compositio Mathematica 2 (1935), 50-62.
- Parameters:
curve (array_like, shape (n, 2)) – Vertices of a closed polygon with no zero-length edges and no reversal (exterior angle \(\pm\pi\)) at any vertex.
- Return type:
- Returns:
int
Examples
>>> t = np.linspace(0, 2 * np.pi, 200, endpoint=False) >>> turning_number(np.column_stack([np.cos(t), np.sin(t)])) 1 >>> turning_number(np.column_stack([np.sin(t), np.sin(2 * t)])) 0
- mathematicskit.topology.vector_field_index(field, center=(0.0, 0.0), radius=1.0, n_points=2000)[source]#
The index of a planar vector field around a circle: how many times the field turns as the circle is traversed.
The field’s direction is followed around \(n\) points of the circle and its total change of angle divided by \(2\pi\). The result is the sum of the indices of the zeros inside: \(+1\) for a source, sink or centre, \(-1\) for a saddle, \(k\) for \(z^k\). By the Poincaré-Hopf theorem the total index of a field pointing outward along the boundary of a region equals the region’s Euler characteristic, 1 for a disc. See H. Poincaré, “Sur les courbes définies par les équations différentielles (3e partie),” Journal de Mathématiques Pures et Appliquées (4) 1 (1885), 167-244; H. Hopf, “Vektorfelder in n-dimensionalen Mannigfaltigkeiten,” Mathematische Annalen 96 (1927), 225-249.
- Parameters:
- Return type:
- Returns:
int
Examples
>>> saddle = lambda x, y: (x, -y) >>> vector_field_index(saddle), vector_field_index(lambda x, y: (x * x - y * y, 2 * x * y)) (-1, 2)
- mathematicskit.topology.vietoris_rips_complex(points, radius, max_dim=2)[source]#
The Vietoris-Rips complex: every set of points with pairwise distances at most \(2r\).
It is the clique complex of the graph joining points closer than \(2r\). Vietoris introduced such complexes in 1927 to define homology for compact metric spaces, as a limit over ever finer scales; Rips used them for hyperbolic groups. See L. Vietoris, “Über den höheren Zusammenhang kompakter Räume und eine Klasse von zusammenhangstreuen Abbildungen,” Mathematische Annalen 97 (1927), 454-472.
- Parameters:
- Return type:
- Returns:
SimplicialComplex – With
pointsas coordinates.
Examples
>>> square = [[0, 0], [1, 0], [1, 1], [0, 1]] >>> vietoris_rips_complex(square, 0.5).f_vector, vietoris_rips_complex(square, 0.75).f_vector ((4, 4), (4, 6, 4))
- mathematicskit.topology.vietoris_rips_filtration(points, max_radius=inf, max_dim=2)[source]#
The Vietoris-Rips filtration: each simplex enters at half its diameter.
Homology of the filtration is reliable up to dimension
max_dim - 1;max_dim-dimensional classes cannot die, since no higher simplices are built.- Parameters:
- Return type:
- Returns:
Filtration
Examples
>>> F = vietoris_rips_filtration([[0, 0], [2, 0]]) >>> F.simplices, F.values.tolist() ([(0,), (1,), (0, 1)], [0.0, 0.0, 1.0])