Core pipeline
The main entry point is circle_bundles.Bundle.
- class circle_bundles.Bundle(X, *, U=None, cover=None, distance_matrix=False, pou=None, landmarks=None, total_metric=None, max_simp_dim=3, show_summary=False)[source]
Bases:
objectPrimary bundle analysis driver.
This class takes either
a minimal
Coverobject (holdingU, optionalpou, and optionallandmarks), ora raw membership matrix
U,
together with total-space data
X(either a point cloud or a distance matrix). It then:Builds the nerve simplices (edges/triangles/tetrahedra) directly from
U.Computes local trivializations and an O(2) cocycle on overlaps.
Computes characteristic-class representatives and edge-driven persistence.
Optionally computes global bundle-map coordinates and solver summaries.
- Parameters:
X (np.ndarray) – Either a point cloud of shape
(n_samples, D)(ifdistance_matrix=False), or a distance matrix of shape(n_samples, n_samples)(ifdistance_matrix=True).U (Optional[np.ndarray]) – Boolean membership matrix of shape
(n_sets, n_samples). EntryU[j, i]indicates whether sampleibelongs to chart/setj. Provide exactly one ofUorcover.cover (Optional['Cover']) – Optional
Coverobject holdingUand (optionally)pouandlandmarks. If provided, its fields are used as defaults. Provide exactly one ofUorcover.distance_matrix (bool) – If True, interpret
Xas a distance matrix. If False, interpretXas a point cloud.pou (Optional[np.ndarray]) – Optional partition of unity of shape
(n_sets, n_samples). Ifcoveris provided, this overridescover.poufor this Bundle (and does not mutate the cover).landmarks (Optional[np.ndarray]) – Optional landmark coordinates of shape
(n_sets, dB)used by visualization helpers. Ifcoveris provided, this overridescover.landmarksfor this Bundle.total_metric (Optional[object]) – Optional metric object passed through to local-trivialization computations. Only used when
distance_matrix=False.max_simp_dim (int) – Maximum simplex dimension to precompute from
U. Common values are 1, 2, or 3.show_summary (bool)
Notes
This object caches intermediate results. Any method that changes upstream state invalidates downstream caches (e.g., computing new local trivializations clears class/persistence caches).
- summary(modes=None)[source]
Display any summaries that are currently available and return them in a dict.
By default (
modes=None), this displays: -"nerve"(always available), -"local_triv"ifget_local_trivs()has been run, -"classes"ifget_classes()has been run, -"bundle_map"ifget_bundle_map()has been run.
- get_local_trivs(*, cc='pca2', min_patch_size=10, min_points_edge=5, pou=None, show_summary=False, verbose=True)[source]
Compute local trivializations, estimate an O(2) cocycle, and compute diagnostics.
This is the upstream computation needed by most later steps: transitions/cocycle estimation and bundle-quality diagnostics.
- Parameters:
cc (object) – Local coordinate constructor / charting method passed to
compute_local_triv()(e.g."pca2").min_patch_size (int) – Minimum number of samples required to compute a local trivialization on a chart.
min_points_edge (int) – Minimum overlap size
|U_j ∩ U_k|required to include an edge (j,k) in cocycle estimation.pou (ndarray | None) – Optional partition-of-unity override used for computing quality diagnostics. If omitted, uses
self.pouwhen available. This does not overwriteself.pou.show_summary (bool) – If True, display the local-trivialization summary after computing (auto rendering).
verbose (bool) – Verbosity forwarded to the local trivialization routine.
- Returns:
Container holding local trivializations, cocycle, and a quality report.
- Return type:
- Raises:
ValueError – If shapes are inconsistent (e.g. invalid
poushape).
Notes
Calling this method invalidates downstream caches (classes, global trivialization, bundle map).
- get_classes(*, edge_weights=None, prefer_edge_weight='rms', show_classes=False, show_persistence=False, show_rounding_distance=False)[source]
Compute characteristic-class representatives and their persistence.
This method computes discrete representatives of the characteristic classes associated to the estimated bundle cocycle (e.g. Euler class, orientation data), and studies their stability under a filtration of the nerve of the cover.
The filtration is induced by assigning weights to edges of the nerve, typically derived from local trivialization quality (e.g. RMS angular error). Persistent cohomology is then used to identify robust class representatives and to restrict the computation to a well-supported subcomplex.
- The result includes:
raw characteristic-class representatives on the full nerve,
persistent cocycle data with respect to the edge-weight filtration,
restricted class data computed on the induced persistent subcomplex,
a concise human-readable summary.
Local trivializations and an O(2)-valued cocycle must already be available; these are computed automatically by
get_local_trivs()if needed.- Parameters:
edge_weights (dict[(int, int), float], optional) – Explicit edge weights for the nerve filtration. Keys should be unordered vertex pairs
(i, j). If not provided, weights are inferred from bundle quality metrics (seeprefer_edge_weight).prefer_edge_weight ({"rms"}, default="rms") – Which quality-derived edge weight to use when
edge_weightsis not provided. Currently only RMS angular error is supported.show_classes (bool, default=False) – If True, display the computed characteristic-class representatives.
show_persistence (bool, default=False) – If True, display class persistence information
show_rounding_distance (bool, default=False) – If True, include rounding-distance diagnostic when displaying summaries.
- Returns:
- An object containing:
reps: characteristic-class representatives on the full nerve,persistence: persistence data for cocycles under the filtration,restricted: class data recomputed on the persistent subcomplex,summary_text: a concise textual summary suitable for logging or documentation output.
- Return type:
Notes
This method resets any cached global trivialization or bundle map, since class computation may change the effective subcomplex used for downstream constructions.
- get_global_trivialization(weight=None, *, pou=None)[source]
Compute a global circle-valued coordinate using the Singer construction.
This method produces a global fiber coordinate (an \(\mathbb{S}^1\)-valued coordinatization) by solving a Singer-type global alignment problem on a certified orientable 1-skeleton, and then blending local angles using a partition of unity.
The returned array
Fis a global coordinate representation in \(\mathbb{R}^2\) (e.g., cosine/sine embedding), suitable for downstream visualization or learning.- Parameters:
weight (float | None) – Optional edge-weight threshold used to further restrict the certified max-trivial subcomplex. If None, the maximal-trivial cutoff is used. If provided, it must be less than or equal to the maximal-trivial threshold; otherwise an error is raised.
pou (ndarray | None) – Optional partition-of-unity override of shape
(n_sets, n_samples).
- Returns:
Global fiber coordinate array of shape
(n_samples, 2)(degree-normalized).- Return type:
- Raises:
RuntimeError – If prerequisites have not been computed (see above), or if no partition of unity is available via
pouorself.pou.ValueError – If the maximal-trivial certified subcomplex is empty, if the chosen threshold yields no usable edges, if the cocycle is non-orientable on the selected subcomplex, or if
weightexceeds the maximal-trivial threshold.
- get_frame_dataset(*, pou=None, weight=None, packing='coloring2')[source]
Build the pre-projection frame dataset used by the bundle-map solver.
This method constructs the intermediate “frame” representation used by the bundle-map pipeline before any projection/reduction step.
- Parameters:
pou (ndarray | None) – Optional partition-of-unity override of shape
(n_sets, n_samples). If omitted, usesself.pou. The override does not overwriteself.pou.weight (float | None) – Optional edge-weight threshold used to restrict the cocycle-certified subcomplex. If None, the full cocycle-certified subcomplex is used. If provided, it must be <= the cocycle-certification threshold (the largest weight at which the class representatives still certify as cocycles).
packing (Literal['none', 'coloring', 'coloring2']) – Frame-packing strategy used when assembling the frame dataset (implementation-defined). Typical values include
"coloring2".
- Returns:
A frame dataset object produced by the internal v2 pipeline (implementation-defined type). The returned dataset corresponds to
stage="pre_projection".- Return type:
- Raises:
RuntimeError – If prerequisites have not been computed, or if no partition of unity is available.
ValueError – If the cocycle-certified subcomplex is empty, or if
weightexceeds the cocycle certification threshold, or if thresholding yields no edges.
- compare_trivs(*, ncols='auto', title_size=14, align=False, s=1.0, save_path=None, max_pairs=25, metric='mean', show=True, return_selected=False, min_points_edge=1, edges=None)[source]
Compare local circular coordinates on overlaps.
This method produces a static matplotlib diagnostic figure showing pairs of local fiber coordinates on chart overlaps, optionally aligning the second chart to the first by an O(2) fit.
Notes
If there are more than
max_pairsoverlaps, the visualizer selects a subset according tometric(typically WORST / MEDIAN / BEST).
- Parameters:
ncols (int | str) – Number of columns in the comparison grid, or
"auto"for an automatic layout.title_size (int) – Font size for subplot titles.
align (bool) – If True, align the second chart to the first on each overlap using an O(2) fit (useful when comparing angles up to a global reflection/rotation on overlaps).
s (float) – Marker size scaling for scatter plots.
save_path (str | None) – Optional path to save the figure (e.g.,
"compare_trivs.png").max_pairs (int) – Maximum number of overlap pairs to display.
metric (str) –
Overlap scoring metric used to rank/select pairs. Common values are:
"mean": mean circle-fit / angle disagreement on the overlap"rms": RMS circle-fit / angle disagreement on the overlap
show (bool) – If True, display the figure (matplotlib). If False, return the figure without display.
return_selected (bool) – If True, also return diagnostics about which overlaps were displayed.
min_points_edge (int) – Minimum overlap size required to include an edge when
edgesis not provided.edges (List[Tuple[int, int]] | None) – Optional explicit list of chart-index edges
[(j, k), ...]to consider. If provided, this overridesmin_points_edge.
- Returns:
If
return_selected=False(default), returns the matplotlib figure.If
return_selected=True, returns(fig, selected_edges, err_by_edge), where:selected_edgesis the list of overlaps actually displayederr_by_edgemaps each overlap edge to its diagnostic error value
- Return type:
matplotlib.figure.Figure or tuple
- Raises:
RuntimeError – If local trivializations have not been computed (call
get_local_trivs()first).
- show_nerve(*, landmarks=None, title=None, show_labels=True, show_axes=False, tri_opacity=0.25, tri_color='pink', cochains=None, weights=None, edge_cutoff=None, highlight_edges=None, highlight_color='red', prefer_local_weights='rms', use_slider=True, mark_cutoff=None, show_title_value=True)[source]
Visualize a single-cycle nerve in a canonical circle layout (matplotlib).
This visualization is designed for the common case where the 1-skeleton of the nerve is a single cycle graph. The vertices are arranged evenly on a circle, and edge annotations (weights, orientation data) are displayed directly on the plot.
- Parameters:
use_max_trivial – If True and persistence results are available, highlight edges belonging to the max-trivial subcomplex (when meaningful). If False, draw all edges uniformly.
weights (Dict[Tuple[int, int], float] | None) – Weight-label source selector:
"rms","witness", or"none".omega – Optional explicit edge-sign dict mapping
(i, j)to±1. If None, an attempt is made to pull a default from cached class representatives.phi – Optional explicit vertex-sign dict mapping vertex index to
±1.compute_phi – If True and
phiis not provided, attempt to compute a consistent gauge from the cached cocycle. Requires local trivializations/cocycle to have been computed.fail_if_not_cycle – If True (default), raise if the nerve graph is not a single cycle. If False, attempt to visualize “as-is” without canonical cycle reindexing.
title (str | None) – Optional plot title. Defaults to
"Nerve Visualization".save_path – Optional path to save the figure.
ax – Optional matplotlib Axes to draw into. If None, a new figure/axes are created.
figsize – Figure size (inches) used only when
ax is None.dpi – Optional DPI used only when
ax is None.r – Radius of the circle layout.
node_size – Node styling options.
node_facecolor – Node styling options.
node_edgecolor – Node styling options.
node_label_color – Node styling options.
removed_edge_color – Styling for edges not in the highlighted/kept set.
removed_edge_lw – Styling for edges not in the highlighted/kept set.
kept_edge_color – Styling for highlighted/kept edges.
kept_edge_lw – Styling for highlighted/kept edges.
omega_color – Text colors for omega/phi/weight annotations.
phi_color – Text colors for omega/phi/weight annotations.
weights_color – Text colors for omega/phi/weight annotations.
fontsize_node – Font sizes for node labels and annotations.
fontsize_omega – Font sizes for node labels and annotations.
fontsize_phi – Font sizes for node labels and annotations.
fontsize_weights – Font sizes for node labels and annotations.
omega_offset – Radial offsets used to place text annotations without overlapping edges.
weights_offset – Radial offsets used to place text annotations without overlapping edges.
phi_offset – Radial offsets used to place text annotations without overlapping edges.
landmarks (ndarray | None)
show_labels (bool)
show_axes (bool)
tri_opacity (float)
tri_color (str)
edge_cutoff (float | None)
highlight_color (str)
prefer_local_weights (Literal['rms', 'none'])
use_slider (bool)
mark_cutoff (float | None)
show_title_value (bool)
- Returns:
The matplotlib figure.
- Return type:
matplotlib.figure.Figure
- Raises:
RuntimeError – If the Bundle has no cached nerve edges.
ValueError – If
fail_if_not_cycle=Trueand the nerve graph is not a single cycle.RuntimeError – If
compute_phi=Truebut no cocycle is available (callget_local_trivs()first).
- show_circle_nerve(*, use_max_trivial=True, weights='rms', omega=None, phi=None, compute_phi=True, fail_if_not_cycle=True, title=None, save_path=None, ax=None, figsize=(5.0, 5.0), dpi=None, r=1.0, node_size=600, node_facecolor='lightblue', node_edgecolor='k', node_label_color='k', removed_edge_color='lightgray', removed_edge_lw=1.5, kept_edge_color='black', kept_edge_lw=4.0, omega_color='blue', phi_color='red', weights_color='black', fontsize_node=12, fontsize_omega=12, fontsize_phi=12, fontsize_weights=9, omega_offset=0.09, weights_offset=0.09, phi_offset=0.14)[source]
Visualize the nerve when it is a single cycle.
This helper draws the 1-skeleton of the cover nerve in a canonical circular layout and can optionally annotate it with:
kept edges from a persistence-derived “max trivial” subcomplex,
an edge cochain
omega(typically the orientation/monodromy data),a vertex cochain
phitaking values in{±1}(an orientation gauge),edge weights used for the filtration (e.g. RMS transition error).
The function is intended for the common situation where the nerve is a cycle graph (e.g. a good cover of a base circle), providing a compact diagnostic view of which edges are trusted and what twisting data is present.
- Parameters:
use_max_trivial (bool, default=True) – If True and persistence data is available (from
get_classes()), highlight the edges kept by the “max_trivial” persistent subcomplex. Kept edges are drawn with thicker styling.weights ({"rms", "witness", "none"}, default="rms") – Which edge weights to display on the cycle. If “none”, no edge weights are shown. Otherwise, weights are pulled from the latest available source (persistence edge weights when available, else quality-derived).
omega (dict[(int, int), int], optional) – Edge labels to display (e.g. values in
{0,1}or{±1}depending on convention). Keys should be unordered pairs(i, j). If not provided, the method attempts to usereps.omega_O1_usedfrom the most recently computed class representatives.phi (dict[int, int], optional) – Vertex labels (typically
±1) to display. If not provided andcompute_phi=True, an attempt is made to computephiby orienting the current cocycle along either the kept edges (if available) or all cycle edges.compute_phi (bool, default=True) – Whether to attempt automatic computation of
phiwhenphiis not provided. Requires that a cocycle has been computed viaget_local_trivs().fail_if_not_cycle (bool, default=True) – If True, raise a ValueError when the nerve is not a single cycle graph. If False, the method will still attempt a plot using the given edge set (without enforcing cycle ordering).
title (str, optional) – Title for the plot. Defaults to “Nerve Visualization”.
save_path (str, optional) – If provided, save the figure to this path.
ax (matplotlib Axes, optional) – Existing axes to draw into. If None, a new figure/axes are created.
figsize ((float, float), default=(5.0, 5.0)) – Matplotlib figure size in inches (used when
axis None).dpi (int, optional) – DPI for the created figure (used when
axis None).r (float, default=1.0) – Radius of the circular layout.
node_size (float) – Styling options for vertices and their labels.
node_facecolor (str) – Styling options for vertices and their labels.
node_edgecolor (str) – Styling options for vertices and their labels.
node_label_color (str) – Styling options for vertices and their labels.
removed_edge_color (str) – Styling for edges not in
kept_edges(whenuse_max_trivial=True).removed_edge_lw (float) – Styling for edges not in
kept_edges(whenuse_max_trivial=True).kept_edge_color (str) – Styling for kept edges.
kept_edge_lw (float) – Styling for kept edges.
omega_color (str) – Text colors for omega/phi/weight annotations.
phi_color (str) – Text colors for omega/phi/weight annotations.
weights_color (str) – Text colors for omega/phi/weight annotations.
fontsize_node (int) – Font sizes for node labels and annotations.
fontsize_omega (int) – Font sizes for node labels and annotations.
fontsize_phi (int) – Font sizes for node labels and annotations.
fontsize_weights (int) – Font sizes for node labels and annotations.
omega_offset (float) – Radial offsets for drawing omega/weights/phi text relative to the cycle.
weights_offset (float) – Radial offsets for drawing omega/weights/phi text relative to the cycle.
phi_offset (float) – Radial offsets for drawing omega/weights/phi text relative to the cycle.
- Returns:
The created figure (or the figure associated with
ax).- Return type:
matplotlib.figure.Figure
- Raises:
RuntimeError – If nerve edge data is missing (no stored nerve edges), or if
phiis requested to be computed but no cocycle is available.ValueError – If the nerve is not a single cycle graph and
fail_if_not_cycle=True.
Notes
When the nerve is a cycle, vertices and annotations are reindexed to follow the cyclic order for a clean, readable layout.
- get_simplices(dims=None, *, weight=None, vertices_as_tuples=False, canonicalize=True, prefer_edge_weight='rms')[source]
Return cached simplices of the nerve, optionally filtered by weight or persistence stage.
This method provides access to the simplices of the nerve of the cover (vertices, edges, triangles, and tetrahedra) that were computed and cached during bundle construction. The returned simplices can be restricted either by an explicit edge-weight threshold or by a named persistence stage derived from class computation.
- Parameters:
dims (int or iterable of int, optional) – Which simplex dimensions to return. For example:
0for vertices,1for edges,(1, 2)for edges and triangles. If None, simplices of all available dimensions are returned.weight (float or {"cocycle", "coboundary"}, optional) –
Restrict simplices using either:
a numeric edge-weight cutoff (float), keeping only simplices whose constituent edges have weight ≤
weight; ora named persistence stage (string), interpreted as:
"cocycle": the maximal stage where the class representatives are cocycles;"coboundary": alias for the former"max_trivial"persistence stage.
If None, no filtering is applied and the full cached nerve is returned.
vertices_as_tuples (bool, default=False) – If True, return vertices as singleton tuples
(i,)rather than integersi. This can be useful for uniform handling of simplices across dimensions.canonicalize (bool, default=True) – If True, return simplices in canonical sorted order with unique orientation conventions. If False, preserve the internal ordering as stored.
prefer_edge_weight (str, default="rms") – When
weightis given as a string stage name, specifies which edge-weight source to prefer if multiple are available (e.g. RMS angular error).
- Returns:
A dictionary (or nested structure) mapping each requested dimension to the corresponding list of simplices, with the exact structure depending on
dimsand formatting options.- Return type:
Any
Notes
Filtration convention. Vertices (0-simplices) are always assigned weight 0. Consequently, this method always returns the full vertex set
{0, …, n_sets−1}(or singleton tuples), regardless of the value ofweight. Only edges, triangles, and higher simplices are subject to filtering.