Computational topology and topological data analysis library providing state-of-the-art algorithms for constructing simplicial complexes and computing persistent homology
—
Classes for constructing witness complexes, which provide memory-efficient approximations of complex topological structures using landmark points. Witness complexes are particularly useful for large datasets where full complex construction is computationally prohibitive.
Basic witness complex construction using abstract distance functions between landmarks and witnesses.
class WitnessComplex:
def __init__(self, landmarks, witnesses):
"""
Initialize witness complex constructor.
Parameters:
- landmarks: List of landmark point indices or points
- witnesses: List of witness point indices or points
"""
def create_simplex_tree(self, max_alpha_square: float, limit_dimension: int = float('inf')):
"""
Create simplex tree from the witness complex.
Parameters:
- max_alpha_square: Maximum alpha square value for filtration
- limit_dimension: Maximum dimension of simplices to include
Returns:
SimplexTree: Filtered witness complex as simplex tree
"""Strong witness complex variant that requires all faces of a simplex to be witnessed, providing more stable topological features.
class StrongWitnessComplex:
def __init__(self, landmarks, witnesses):
"""
Initialize strong witness complex constructor.
Parameters:
- landmarks: List of landmark point indices or points
- witnesses: List of witness point indices or points
"""
def create_simplex_tree(self, max_alpha_square: float, limit_dimension: int = float('inf')):
"""
Create simplex tree from the strong witness complex.
Parameters:
- max_alpha_square: Maximum alpha square value for filtration
- limit_dimension: Maximum dimension of simplices to include
Returns:
SimplexTree: Filtered strong witness complex as simplex tree
"""Witness complex optimized for point clouds embedded in Euclidean space, using efficient distance computations.
class EuclideanWitnessComplex:
def __init__(self, landmarks, witnesses):
"""
Initialize Euclidean witness complex constructor.
Parameters:
- landmarks: List of landmark points in Euclidean space
- witnesses: List of witness points in Euclidean space
"""
def create_simplex_tree(self, max_alpha_square: float, limit_dimension: int = float('inf')):
"""
Create simplex tree from the Euclidean witness complex.
Parameters:
- max_alpha_square: Maximum alpha square value for filtration
- limit_dimension: Maximum dimension of simplices to include
Returns:
SimplexTree: Filtered Euclidean witness complex as simplex tree
"""Combination of Euclidean optimization and strong witness conditions, providing the most stable witness complex construction.
class EuclideanStrongWitnessComplex:
def __init__(self, landmarks, witnesses):
"""
Initialize Euclidean strong witness complex constructor.
Parameters:
- landmarks: List of landmark points in Euclidean space
- witnesses: List of witness points in Euclidean space
"""
def create_simplex_tree(self, max_alpha_square: float, limit_dimension: int = float('inf')):
"""
Create simplex tree from the Euclidean strong witness complex.
Parameters:
- max_alpha_square: Maximum alpha square value for filtration
- limit_dimension: Maximum dimension of simplices to include
Returns:
SimplexTree: Filtered Euclidean strong witness complex as simplex tree
"""import gudhi
import numpy as np
# Generate large point cloud
all_points = np.random.random((1000, 3))
# Select landmarks using farthest point sampling
num_landmarks = 50
landmark_indices = gudhi.choose_n_farthest_points(all_points, num_landmarks)
landmarks = all_points[landmark_indices]
# Use all points as witnesses
witnesses = all_points
# Create Euclidean witness complex
witness_complex = gudhi.EuclideanWitnessComplex(landmarks, witnesses)
simplex_tree = witness_complex.create_simplex_tree(
max_alpha_square=0.1,
limit_dimension=2
)
# Compute persistence
persistence = simplex_tree.persistence()
print(f"Landmarks: {len(landmarks)}")
print(f"Witnesses: {len(witnesses)}")
print(f"Simplices: {simplex_tree.num_simplices()}")
print(f"Persistence pairs: {len(persistence)}")import gudhi
import numpy as np
# Generate point cloud
points = np.random.random((500, 2))
# Select landmarks
num_landmarks = 30
landmark_indices = gudhi.choose_n_farthest_points(points, num_landmarks)
landmarks = points[landmark_indices]
witnesses = points
# Create different witness complex variants
complexes = {
'Witness': gudhi.EuclideanWitnessComplex(landmarks, witnesses),
'Strong Witness': gudhi.EuclideanStrongWitnessComplex(landmarks, witnesses)
}
max_alpha = 0.05
results = {}
for name, complex_obj in complexes.items():
simplex_tree = complex_obj.create_simplex_tree(
max_alpha_square=max_alpha,
limit_dimension=1
)
persistence = simplex_tree.persistence()
results[name] = {
'simplices': simplex_tree.num_simplices(),
'persistence_pairs': len(persistence),
'betti_0': len([p for p in persistence if p[0] == 0]),
'betti_1': len([p for p in persistence if p[0] == 1])
}
for name, stats in results.items():
print(f"{name}:")
print(f" Simplices: {stats['simplices']}")
print(f" Persistence pairs: {stats['persistence_pairs']}")
print(f" Betti numbers: β₀={stats['betti_0']}, β₁={stats['betti_1']}")
print()import gudhi
import numpy as np
# Simulate very large dataset
np.random.seed(42)
large_dataset = np.random.random((10000, 5)) # 10k points in 5D
# Use witness complex for memory efficiency
num_landmarks = 100 # Much smaller than full dataset
# Select diverse landmarks
landmark_indices = gudhi.choose_n_farthest_points(large_dataset, num_landmarks)
landmarks = large_dataset[landmark_indices]
# Subsample witnesses for computational efficiency
num_witnesses = 2000
witness_indices = gudhi.pick_n_random_points(large_dataset, num_witnesses)
witnesses = large_dataset[witness_indices]
# Create witness complex
witness_complex = gudhi.EuclideanStrongWitnessComplex(landmarks, witnesses)
simplex_tree = witness_complex.create_simplex_tree(
max_alpha_square=0.2,
limit_dimension=2
)
# Analyze topology
persistence = simplex_tree.persistence()
# Extract significant features
significant_features = [
(dim, (birth, death)) for dim, (birth, death) in persistence
if death - birth > 0.01 # Minimum persistence threshold
]
print(f"Original dataset: {len(large_dataset)} points")
print(f"Landmarks: {len(landmarks)} points")
print(f"Witnesses: {len(witnesses)} points")
print(f"Significant topological features: {len(significant_features)}")
# Visualize persistence diagram
gudhi.plot_persistence_diagram(persistence)import gudhi
import numpy as np
from sklearn.cluster import KMeans
# Generate point cloud with clusters
np.random.seed(42)
cluster_centers = np.array([[0, 0], [3, 0], [1.5, 2.6]])
points = []
for center in cluster_centers:
cluster_points = np.random.normal(center, 0.3, (100, 2))
points.append(cluster_points)
all_points = np.vstack(points)
# Compare different landmark selection strategies
strategies = {
'Farthest Point': lambda pts, n: gudhi.choose_n_farthest_points(pts, n),
'Random': lambda pts, n: gudhi.pick_n_random_points(pts, n),
'K-means Centers': lambda pts, n: KMeans(n_clusters=n, random_state=42).fit(pts).cluster_centers_
}
num_landmarks = 15
results = {}
for strategy_name, strategy_func in strategies.items():
if strategy_name == 'K-means Centers':
landmarks = strategy_func(all_points, num_landmarks)
else:
landmark_indices = strategy_func(all_points, num_landmarks)
landmarks = all_points[landmark_indices]
# Create witness complex
witness_complex = gudhi.EuclideanWitnessComplex(landmarks, all_points)
simplex_tree = witness_complex.create_simplex_tree(
max_alpha_square=0.5,
limit_dimension=1
)
persistence = simplex_tree.persistence()
betti_1 = len([p for p in persistence if p[0] == 1 and p[1][1] != float('inf')])
results[strategy_name] = {
'simplices': simplex_tree.num_simplices(),
'holes_detected': betti_1
}
print("Landmark selection strategy comparison:")
for strategy, stats in results.items():
print(f"{strategy}: {stats['simplices']} simplices, {stats['holes_detected']} holes detected")Install with Tessl CLI
npx tessl i tessl/pypi-gudhi