Five-minute quickstart¶
For the operator definition and proofs, read operator theory. For minimum-stretch selection and joint geometry, run the six-edge example.
Build one window, query its classes, then add a filtration stage.
Single scale¶
from homology_operator import (
ChainWindow, HomologyOperator, Matrix, ProjectionProblem, solve_projection,
)
window = ChainWindow(
k=0,
A=Matrix.zero(0, 2),
D=Matrix.from_rows(((1,), (1,))),
basis_previous=(),
basis_current=("v0", "v1"),
basis_next=("edge",),
weights=(10, 1),
)
solution = solve_projection(ProjectionProblem(window))
if solution.projection is None:
raise RuntimeError((solution.status, solution.diagnostics))
op = HomologyOperator(window, solution)
assert op.betti() == 1
assert op.same_class((1, 0), (0, 1))
assert op.class_distance((1, 0), (0, 1)) == 0
assert op.class_representative((0, 1)) == (1, 0)
assert op.selected_mass((0, 1)) == 10
query = op.readout("selected_mass", (0, 1))
assert query.state == "Computed" and query.exact
record = op.to_result()
The selected representative has mass 10; a homologous representative has mass 1.
selected_mass does not minimize class mass.
Finite filtration¶
from dataclasses import replace
from homology_operator import OperatorFamily
before = replace(window, D=Matrix.zero(2, 0), basis_next=())
windows = (before, window)
operators = tuple(
HomologyOperator(w, solve_projection(ProjectionProblem(w))) for w in windows
)
family = OperatorFamily((0, 1), windows, operators)
assert family.transport_rank(0, 1).value == 1
barcode = family.barcode()
assert barcode.state == "Computed"
assert family.track_mass((1, 1), 0, 1).value == 0
A dead class has a valid zero mass. Continue with single-scale queries and finite filtrations.