circle_bundles.O2Cocycle

class circle_bundles.O2Cocycle(Omega, theta, det, err=None, ref_angle=0.0)[source]

Bases: object

An estimated O(2)-valued 1-cochain (typically a cocycle) on a cover nerve.

The primary field is Omega, a dictionary mapping directed edges to 2×2 matrices:

Omega[(j, k)] maps k-coordinates -> j-coordinates.

For convenience and downstream characteristic class computations, we also store determinant signs and rotation angles from a fixed-axis decomposition.

Parameters:
Omega

Dict mapping edges (j, k) to 2×2 matrices in O(2).

Type:

Dict[Tuple[int, int], numpy.ndarray]

theta

Dict mapping edges (j, k) to angles theta ∈ [0, 2π) such that Omega[(j,k)] = R(theta) * r(ref_angle) under this module’s convention.

Type:

Dict[Tuple[int, int], float]

det

Dict mapping edges (j, k) to det(Omega[(j,k)]) ∈ {+1, -1}.

Type:

Dict[Tuple[int, int], int]

err

Optional dict mapping edges (j, k) to an RMS angular error (radians) on overlaps.

Type:

Dict[Tuple[int, int], float] | None

ref_angle

Reflection axis angle (radians) used when decomposing det=-1 matrices.

Type:

float

Notes

  • By default, estimate_transitions() stores only canonical edges (j<k). Use complete_orientations() (or complete_edge_orientations()) if you want both directions (j,k) and (k,j).

  • The edge convention is important: Omega[(j,k)] is designed so that it takes vectors in chart k to vectors in chart j.

Examples

Typical usage is via a bundle construction pipeline, but you can also estimate transitions directly from local angles:

cocycle, report = estimate_transitions(U, f, min_points=10)
Omega_full = cocycle.complete_orientations().Omega
omega_Z2 = cocycle.omega_Z2()

See also

estimate_transitions

Fit O(2) transitions from overlap data.

complete_edge_orientations

Low-level helper to fill reversed edges by transposition.

__init__(Omega, theta, det, err=None, ref_angle=0.0)
Parameters:
Return type:

None

Methods

__init__(Omega, theta, det[, err, ref_angle])

complete_orientations()

Return an equivalent cocycle with both edge orientations filled in.

omega_O1()

Return the determinant-sign cochain as an O(1) (i.e. {±1}) valued 1-cochain.

omega_Z2()

Convert determinants to a Z₂-valued 1-cochain.

orient_if_possible(edges, *[, n_vertices, ...])

Attempt to gauge-transform the cocycle so that det=+1 on a chosen 1-skeleton.

restrict(edges)

Restrict this cocycle to a specified set of edges.

theta_normalized()

Return the rotation angles as an R/Z-valued cochain represented in [0, 1).

Attributes

err

ref_angle

Omega

theta

det

omega_Z2()[source]

Convert determinants to a Z₂-valued 1-cochain.

Returns:

Dict mapping edges to values in {0,1}, using the convention: det=+1 ↦ 0 and det=-1 ↦ 1.

Return type:

omega

omega_O1()[source]

Return the determinant-sign cochain as an O(1) (i.e. {±1}) valued 1-cochain.

Returns:

Dict mapping edges to ±1.

Return type:

omega

theta_normalized()[source]

Return the rotation angles as an R/Z-valued cochain represented in [0, 1).

The stored theta values are in radians in [0, 2π). This method converts to fractions of a full turn by dividing by 2π and reducing modulo 1.

Returns:

Dict mapping edges to floats in [0,1).

Return type:

theta01

restrict(edges)[source]

Restrict this cocycle to a specified set of edges.

Parameters:

edges (Iterable[Tuple[int, int]]) – Iterable of edges. Edges are canonicalized to (min, max) form.

Returns:

A new O2Cocycle containing only entries whose edges appear in edges.

Return type:

cocycle_restricted

Notes

Any edge not present in the underlying dicts is silently skipped.

complete_orientations()[source]

Return an equivalent cocycle with both edge orientations filled in.

For each undirected edge {j,k}, this ensures both directed entries are present:

Omega[(j,k)] maps k->j, Omega[(k,j)] = Omega[(j,k)]^T maps j->k.

Determinants, angles, and errors are also populated for the reversed edges in a way consistent with this module’s decomposition convention.

Return type:

O2Cocycle

orient_if_possible(edges, *, n_vertices=None, require_all_edges_present=True)[source]

Attempt to gauge-transform the cocycle so that det=+1 on a chosen 1-skeleton.

This is an “orientability test” for the determinant-sign cochain on the graph given by edges. We look for an assignment φ_j ∈ {+1, -1} to vertices such that for each undirected edge {j,k}:

φ_j * φ_k = det_{jk},

where det_{jk} is det(Omega_{jk}) on that edge.

If such a φ exists, we build a gauge g_j ∈ O(2) using the fixed reflection axis:

g_j = I if φ_j = +1 g_j = r(ref_angle) if φ_j = -1

and transform transitions by

Omega’_{jk} = g_j * Omega_{jk} * g_k^{-1},

which forces det(Omega’_{jk}) = +1 on all edges in the given 1-skeleton.

Parameters:
  • edges (Iterable[Tuple[int, int]]) – The set of edges defining the 1-skeleton on which to test/orient.

  • n_vertices (int | None) – Number of vertices in the graph. If None, inferred as 1 + max index seen in edges.

  • require_all_edges_present (bool) – If True, returns (False, self, phi) immediately if any requested edge is missing from this cocycle’s determinant dict. If False, missing edges are ignored.

Returns:

  • ok – True if the orientation assignment exists.

  • cocycle_oriented – If ok is True, the gauge-transformed cocycle; otherwise the original cocycle.

  • phi – An integer array of shape (n_vertices,) with entries in {+1,-1} giving φ.

Return type:

Tuple[bool, O2Cocycle, ndarray]

Notes

This is useful when you want to reduce an O(2)-bundle problem to an S¹-bundle problem on a subcomplex where the bundle is orientable.