Metadata-Version: 2.4
Name: pytopology
Version: 1.10.0
Summary: Mathematical topology library: degree theory, embeddings, graphs, knots, surfaces, 3-manifolds, cosmology.
Author-email: Kadirhan Polat <kadirhanpolat@gmail.com>
License-Expression: MIT
Project-URL: Repository, https://github.com/kadirhanpolat/pytop
Project-URL: Bug Tracker, https://github.com/kadirhanpolat/pytop/issues
Keywords: topology,mathematics,knot-theory,manifolds,graph-topology,degree-theory,point-set-topology
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Education
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Provides-Extra: oracles
Requires-Dist: numpy>=1.26; extra == "oracles"
Requires-Dist: sympy>=1.12; extra == "oracles"
Requires-Dist: networkx>=3.0; extra == "oracles"
Requires-Dist: gudhi>=3.9; extra == "oracles"
Requires-Dist: python-flint>=0.6; extra == "oracles"
Provides-Extra: fast
Requires-Dist: python-flint>=0.6; extra == "fast"
Provides-Extra: gpu
Requires-Dist: cupy-cuda12x; extra == "gpu"
Dynamic: license-file

# pytop

[![CI](https://github.com/kadirhanpolat/pytop/actions/workflows/ci.yml/badge.svg)](https://github.com/kadirhanpolat/pytop/actions/workflows/ci.yml)
![Version](https://img.shields.io/badge/version-1.10.0-blue)
![PyPI](https://img.shields.io/pypi/v/pytopology)
![Coverage](https://img.shields.io/badge/coverage-85%25-brightgreen)
![Python](https://img.shields.io/badge/python-3.11--3.14-blue)

A mathematical topology library for Python, covering point-set topology, knot theory, graph topology, surface classification, 3-manifolds, higher categories, operads, spectral sequences, topological field theory, and more.

As of **v1.10.0** (live on PyPI — `pip install pytopology`, then `import pytop`), pytop ships **20 phases** with 12,278 tests passing (22 skipped: opt-in Ripser/SnapPy/Sage oracles) on a ruff-clean and mypy-clean `src/pytop`. **Phases 1–15**: computational core (Phases 1–7), advanced algebra (Phase 8), 19 computable-space representations (Phase 9), scale & algorithms (Phase 10), Lean 4 formal verification (Phase 11), Čech sheaf cohomology + persistent K-theory (Phase 12), homotopy theory (Phase 13), advanced knot homology (Phase 14), 4-manifold topology (Phase 15). **Phase 16** ✅ empirical validation & oracle ecosystem: benchmark suite, and **oracle parity now wired to GUDHI** — P16.2 cross-checks pytop's persistent Betti numbers against **GUDHI** (Betti-at-scale, matching on circle/sphere/multi-component fixtures), and **P16.3 cross-validates the full 10 000-complex statistical run against GUDHI at 100.0% parity** (0 outliers, avg 4.35 ms/complex). **Phase 17** ✅ **performance & scale**: **P17.1 ✅** profiling infrastructure (86 tests); **P17.2 ✅** algorithm optimization (method selection: 'twist'/'standard'/'cohomology'); **P17.3 ✅** scaling — **inductive Vietoris–Rips construction (~14–19× filtration-build speedup) + size-aware auto reduction routing now the default** (`method="auto"`: Twist for small complexes, de Silva dual cohomology for large Rips; up to ~12× faster end-to-end at n=350, byte-identical output). **Phase 18 ✅** documentation & pedagogy (16-chapter user guide — enriched across all four formats with intuition/counter-example boxes, proof sketches, verified examples and 46 figures; 225-module API ref; 36+ examples). **Phase 19** ✅ **API stability**: **P19.1 ✅** error messages (WHY-HOW-THEN); **P19.2 ✅** deprecation policy (`@deprecated` decorator + `DEPRECATIONS.md`, 18-month window); **P19.3 ✅** API consistency audit (`docs/API_DESIGN.md`). **Phase 20** ✅ **release maturity**: **P20.1 ✅** CI/CD hardening (Python 3.11–3.14 matrix); **P20.2 ✅** PyPI publishing (**live on PyPI** via GitHub Actions Trusted Publishing — `pip install pytopology`; ships `py.typed` for PEP 561 + a `python -m pytop` CLI); **P20.3 ✅** community onboarding (`CONTRIBUTING.md`, GitHub issue/PR templates; the 12 curated good-first-issues #35–#46 all resolved). Docstring doctests now run in CI.

## Installation

```bash
pip install pytopology      # then: import pytop
```

The distribution is published as **`pytopology`** (the bare `pytop` name is taken
on PyPI by an unrelated project); the import name is `pytop`. For a local
development checkout:

```bash
pip install -e .
```

**New here?** Start with the [Getting Started guide](docs/GETTING_STARTED.md) —
install to four working computations (homology, persistent homology, knot
invariants, graph planarity) in a few minutes.

Requires Python 3.11+.

## Quick Start

```python
import pytop

# Spaces and maps
from pytop import TopologicalSpace, continuous_map_profile

# Named spaces + catalog
from pytop import cantor_set, torus, n_sphere, catalog
s = cantor_set()
s.has_tag("totally_disconnected")   # True
catalog.get("Sorgenfrey line")       # SpaceRecord(...)
catalog.search(compact=True, metrizable=True)

# Compactness
from pytop import is_compact, CompactnessProfile

# Knot theory
from pytop import KnotProfile, reidemeister_move_profiles

# Surface classification
from pytop import SurfaceProfile, euler_characteristic_profile

# Degree theory
from pytop import get_retraction_degree_profiles, winding_number_profiles

# Experimental (unstable API)
from pytop.experimental import maturity_registry
```

### Computational core (new in v0.6.0)

```python
# Simplicial homology — Betti numbers and torsion, computed from a complex
from pytop import generated_subcomplex, betti_numbers, simplicial_homology
sphere = generated_subcomplex([{1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4}])
betti_numbers(sphere)                       # (1, 0, 1)  -> S^2

# Persistent homology / TDA — Vietoris–Rips barcodes from a point cloud
import math
from pytop import persistent_homology
from pytop.metric_spaces import FiniteMetricSpace
pts = [(math.cos(2*math.pi*k/12), math.sin(2*math.pi*k/12)) for k in range(12)]

# Default: Twist algorithm (Chen–Kerber 2011) with Clearing Lemma (~1.1× speedup)
pairs = persistent_homology(FiniteMetricSpace(carrier=tuple(pts), distance=math.dist), max_dimension=2)

# Or choose algorithm explicitly: method='twist' (default), 'standard', or 'cohomology'
pairs_cohomology = persistent_homology(
    FiniteMetricSpace(carrier=tuple(pts), distance=math.dist),
    max_dimension=2,
    method='cohomology'  # Incremental cocycle algorithm (often faster on Rips)

# Knot invariants — Jones / Alexander polynomials from a diagram
from pytop import KnotDiagram, jones_polynomial
trefoil = KnotDiagram([(1, 4, 2, 5), (3, 6, 4, 1), (5, 2, 6, 3)], signs=(-1, -1, -1))
jones_polynomial(trefoil)                   # -t^-4 + t^-3 + t^-1

# Surface classification from a polygon gluing word
from pytop import classify_surface_word
classify_surface_word("a b a^-1 b^-1").name   # "torus"

# Exact graph planarity / genus (rotation-system search)
from itertools import combinations
from pytop import is_planar
is_planar(list(combinations(range(5), 2)))  # False  -> K5 is non-planar

# Winding number / map degree
from pytop import winding_number
winding_number(pts)                          # 1

# pi-Base deductive inference (experimental, CC BY 4.0)
from pytop.experimental import deduce, find_counterexamples, property_uid
deduce({property_uid("Compact"): True, property_uid("Hausdorff"): True})  # ... Normal: True
find_counterexamples(has=["Compact"], lacks=["Hausdorff"])                # compact, non-Hausdorff spaces

# Research-grade computable-space protocol (experimental, Phase 1)
from pytop.experimental.spaces import (
    pi_base_space, ProductSpace, derive, SorgenfreyLineSpace, analyze_pi_base_space
)
cantor = pi_base_space("Cantor set")
derive(cantor, "compact").verdict.value           # True  (pi-Base certificate)
derive(ProductSpace([cantor, cantor]), "compact").verdict.value  # True  (Tychonoff)

sorgenfrey2 = ProductSpace([SorgenfreyLineSpace(), SorgenfreyLineSpace()])
derive(sorgenfrey2, "T3").verdict.value            # True  (regular is productive)
derive(sorgenfrey2, "lindelof").verdict.value      # None  (correctly undecided — the plane is not Lindelöf)

analyze_pi_base_space("Long line")                 # 16-property verdict dict
```

## Module Overview

| Domain | Key modules |
|--------|-------------|
| Foundations | `sets`, `relations`, `spaces`, `maps`, `predicates` |
| Metric spaces | `metric_spaces`, `metric_completeness`, `metrization_profiles` |
| Compactness | `compactness`, `compactness_variants`, `local_compactness` |
| Connectivity | `connectedness`, `paths`, `covering_spaces` |
| Separation axioms | `separation`, `countability` |
| Degree theory | `degree_theory`, `degree_theory_applications` |
| Knot theory | `knots`, `invariants` |
| Surfaces & manifolds | `surfaces`, `surface_classification`, `manifolds`, `three_manifolds` |
| Graph topology | `graph_topology` |
| **Computational homology** (v0.6.0+) | `homology`, `persistent_homology`, `homology_coefficients`, `mayer_vietoris`, `cellular_homology`, `cohomology` |
| **Optimized persistence** (v0.6.0+) | `persistent_homology_optimized` — Twist+Clearing (Chen–Kerber 2011), `ReductionStats` |
| **Persistent cohomology** (v0.9.7+) | `persistent_homology` — `persistence_pairs_cohomology` (de Silva dual; ~2–2.5× faster than standard) |
| **Cubical complexes** (v0.6.0+) | `cubical_homology` — `CubicalComplex`, SNF homology, `bitmap_to_cubical_filtration`, `persistent_homology_bitmap` |
| **Fundamental group / van Kampen** (v0.6.0+) | `van_kampen` — `GroupPresentation`, `van_kampen()`, `cw_complex_pi1()`, standard spaces |
| **Knot/link invariants** (v0.6.0+) | `knot_invariants` (Jones, Alexander, linking number/matrix), `seifert` (Seifert circles, genus bound, matrix, signature), `homfly` (HOMFLY-PT `P(a,z)` from braid closures), `multivariable_alexander` (`Δ_L(t₁,…,tₙ)` via Wirtinger + Fox) |
| **3-manifold homology** (v0.7.0+) | `dehn_surgery` — Dehn surgery → `H₁` (SNF cokernel of the framing/linking matrix), lens space homeomorphism/homotopy classification |
| **Khovanov homology** (v0.7.0+) | `khovanov` — bigraded `Kh^{i,j}` (free rank + torsion) categorifying the Jones polynomial |
| **Exact linear algebra** (v0.8.0+) | `exact_linalg` — Smith normal form, integer rank, Bareiss `integer_determinant`, `cokernel` → `AbelianGroup` |
| **TDA pipeline** (v1.0.3+) | `tda_pipeline` — `TDAPipeline` immutable builder; `.rips()/.cech()/.reduce()/.pairs()/.landscape()/.entropy()/.bottleneck()/.wasserstein()` |
| **Čech complex** (v1.0.1+) | `cech_complex` — `cech_filtration`, `persistent_homology_cech` (Welzl miniball) |
| **Persistence over Z/p** (v1.0.2+) | `persistent_homology_fp` — `persistence_pairs_fp(filtered, prime)` |
| **Standard triangulations** (v1.0.4+) | `simplicial_filtration` — `torus_filtration`, `klein_bottle_filtration`, `rp2_filtration` (7–8 vertex minimal triangulations) |
| **Simplicial maps** (v1.0.5+) | `simplicial_maps` — `SimplicialMap`, `chain_map_matrix`, `induced_map_on_homology`, `cone_complex`, `suspension_complex` |
| **Nerve complex** (v1.0.5+) | `nerve_complex` — `nerve_of_cover`, `good_cover_check`, `cech_nerve` (Welzl circumsphere) |
| **Spectral sequences** (v1.0.5+) | `spectral_sequences` — `SpectralPage`, `FilteredChainComplex`, `differential_d_r`, `converges_to` (E^∞ stability) |
| **Surgery theory** (v1.0.5+) | `surgery_theory` — `handle_attachment`, `trace_cobordism`, `trace_homology` |
| **Morse complex** (v1.0.5+) | `morse_complex` — `MorseChainComplex`, `morse_boundary_operator` (gradient V-path counting), `morse_homology` (cross-validated against simplicial H_*) |
| **Discrete Morse theory** (v0.9.8+) | `discrete_morse` — `MorsePair`, `MorseMatching`, `discrete_gradient_matching`, `check_morse_inequalities` |
| **Persistence distances** (v0.9.9+) | `persistence_distances` — `bottleneck_distance`, `wasserstein_distance`, `PersistenceLandscape`, `persistence_entropy` |
| **Mapper algorithm** (v1.0.0+) | `mapper` — Singh–Mémoli–Carlsson (2007): `IntervalCover`, `single_linkage_labels`, `MapperComplex` |
| **Degree / winding** (v0.6.0) | `winding_number` |
| **Surface classification** (v0.6.0) | `surface_word_classification` |
| **Graph planarity** (v0.6.0) | `graph_planarity` — O(V+E) left-right planarity test (Brandes 2009) |
| **Deductive inference** (v0.6.0) | `experimental.pi_base`, `experimental.pi_base_atlas` |
| **Convergence spaces** (v0.6.0) | `experimental.convergence_spaces` |
| **Computable spaces** (experimental) | `experimental.spaces` — protocol, 16 predicates, reasoning engine, pi-Base bridge, **19 representations** (Phase 9) |
| Cardinal functions | `cardinal_functions_framework`, `cardinal_numbers` |
| **Derived categories** (v1.0.9+) | `derived_categories` — `mapping_cone_complex`, `derived_functor_h` (Betti + torsion via SNF), `triangulated_structure_check` |
| **Topos / sheaf theory** (v1.0.9+) | `topos_theory` — `site_from_finite_topology`, `sheaf_on_site`, `sheafification_finite`, `topos_check` (Grothendieck topos) |
| **Operads** (v1.0.9+) | `operads` — `associahedron_complex` (Stasheff K_n, Catalan vertices), `operad_composition_check`, `bar_construction_sc` |
| **Higher categories** (v1.0.9+) | `higher_categories` — `nerve_of_category` N(C), `kan_fibration_check_sc`, `homotopy_type_finite_cat` (BC Betti numbers) |
| **Noncommutative K-theory** (v1.0.9+) | `noncommutative_topology` — `k0_group_matrix_algebra`, `spectral_dimension_finite` (log-log Weyl), `k1_group_matrix_algebra` |
| **Topological field theory** (v1.0.9+) | `topological_field_theory` — `cobordism_from_handles`, `tqft_dimension_2d`, `handle_signature_tft` (4-manifold handles) |
| **Sparse linear algebra** (v1.2.0+) | `sparse_linalg` — `sparse_smith_normal_form` (dict-based sparse SNF; auto-routed for large sparse matrices), `matrix_density` |
| **Parallel Khovanov** (v1.2.0+) | `khovanov` — `khovanov_homology(parallel=True)`; ThreadPoolExecutor over quantum gradings; GIL-limited on pure-Python, truly parallel with `[fast]` flint backend |
| **Witness complex** (v1.2.0+) | `witness_complex` — `landmark_sample` (maxmin/random), `witness_filtration` (strong-witness, de Silva & Carlsson 2004), `persistent_homology_witness` → `WitnessComplex` |
| **Streaming persistence** (v1.2.0+) | `streaming_persistence` — `StreamingPersistence`; incremental Z/2 column reduction; `add_simplex / current_pairs / current_betti / current_essential_pairs` |
| **GPU backend** (v1.2.0+, optional) | `_gpu_backend` — `gpu_twist_reduce`; cupy boolean-array column XOR; `[gpu]` extra in pyproject.toml; graceful CPU fallback |
| **Čech sheaf cohomology** (v1.4.0+) | `sheaf_cohomology` — `FiniteSheaf`, `constant_sheaf`, `skyscraper_sheaf`, `cech_cohomology` (Leray cover → alternating-sign coboundary → SNF), `sheaf_cohomology` (McCord minimal-neighborhood cover; H⁰ = ℤ^components) |
| **Persistent K-theory** (v1.4.0+) | `persistent_ktheory` — `KTheoryGroups` (rational AHSS: K⁰⊗ℚ = ⊕H_{2k}, K¹⊗ℚ = ⊕H_{2k+1}), `KBarcode` (Twist barcode partitioned by parity; χ_K = rank K⁰ − rank K¹), `k_theory_groups`, `k_barcode`, `k0/k1_simplicial`, `k_betti_numbers` |
| Higher algebra | `operads`, `spectral_sequences` |
| Higher categories | `higher_categories`, `topological_field_theory` |
| Cosmology | `cosmology_topology` |
| Named spaces | `named_spaces`, `space_catalog` |
| Experimental | `pytop.experimental` |

## Documentation

A comprehensive 16-chapter user guide (`docs/user_guide/`) covering point-set topology and
metric spaces in **four parallel formats**: Python scripts, Jupyter notebooks, Markdown, and
LaTeX (PDF). Every chapter is enriched with intuition + counter-example boxes, theorem
proof sketches, **verified** runnable pytop examples, exercises with worked solutions, and
**46 figures** — the four formats stay in sync via `docs/user_guide/tools/build_chapter_formats.py`.

| # | Chapter | Topics |
|---|---------|--------|
| 1–3 | Prerequisites | Quick start, propositional logic, set theory & functions |
| 4–13 | Point-set topology | Spaces, predicates, separation, compactness, connectedness, countability, continuous maps, subspace/product, quotient, initial/final topology |
| 14–16 | Metric spaces | Metric spaces, completeness & compactness, metric maps |

```bash
# Run any chapter as a script
py -3.14 docs/user_guide/python/ch04_topological_spaces.py

# Open a notebook
jupyter lab docs/user_guide/notebook/ch07_compactness.ipynb

# Compile the PDF (requires xelatex)
cd docs/user_guide/latex && xelatex main.tex

# Rebuild TikZ figures → PNG
py -3.14 docs/user_guide/tools/build_figures.py
```

Chapters 4 and 6 feature guided proofs, "Ne oldu?" walkthroughs, trace tables, TikZ figures,
and color-coded pedagogical boxes (sezgi / dikkat / nedenonemli / karşı-örnek).
Exercise solutions are in `docs/user_guide/{markdown,python,notebook}/solutions.*` and
`docs/user_guide/latex/appendix/solutions.tex`.

## What's New in v1.10.0

**The bridge family is complete**, and with it every open item on the roadmap.

pytop is pure Python with no runtime dependencies, and stays that way. Where an
established system does something pytop has no route to, the answer is to
interoperate rather than reimplement — Part IV of the roadmap argues for exactly
this. Three optional bridges now do it, sharing one transport and one safety
posture:

| Bridge | Supplies | Independent check on |
|---|---|---|
| `gap_bridge` | group order, structure description, SmallGroups id | SNF abelianization |
| `regina_bridge` | normal surfaces, census recognition | lens-space `H₁` |
| `snappy_bridge` | hyperbolic volume, census identification | Dehn-surgery `H₁` |

```python
from pytop.experimental import SnappySession, snappy_manifold_info

with SnappySession() as s:
    snappy_manifold_info("4_1", session=s).volume     # 2.029883...
```

Each reports itself unavailable rather than raising when Docker or its image is
absent, validates inputs before interpolating anything into generated code,
detects success by a sentinel rather than an exit code, and reaps the
in-container process on timeout — a client-side timeout kills only the
`docker exec` client, which left processes at 100% CPU until it was fixed.

Three stale roadmap entries were corrected in the process: the in-process SnapPy
bridge is no longer "deferred" (it shipped, as a container bridge), Regina-scale
normal surfaces are now reachable, and sheaf cohomology and persistent K-theory
were removed from "deferred (long-range)" — both shipped in v1.4.0.

## What's New in v1.9.0

**Phase 12 is complete (6/6).** Three milestones, and the two that were listed as
blocked or intractable turned out to be neither.

**P12.3 — Homeomorphism** (`pytop.experimental.homeomorphism`). The roadmap
listed "homeomorphism heuristics ... undecidable in general". There is a decidable
subclass worth having: for a **finite** space the topology and its specialization
preorder determine each other, so a bijection is a homeomorphism exactly when it
is a preorder isomorphism. `finite_homeomorphic` decides it and hands back the
bijection; its absence is a proof, not a failed search. Verified against
brute-force enumeration of every bijection on 100 space pairs.

For everything else, `homeomorphism_obstruction` certifies **non**-homeomorphism
from a differing invariant. There is deliberately no verdict meaning "probably
homeomorphic" — agreeing invariants prove nothing.

```python
from pytop.experimental import finite_homeomorphic
from pytop.experimental.spaces import FiniteSpace

s = FiniteSpace("sierpinski", (0, 1), [(), (0,), (0, 1)])
t = FiniteSpace("relabelled", ("a", "b"), [(), ("b",), ("a", "b")])
bool(finite_homeomorphic(s, t))        # True, with the bijection as witness
```

**P12.4 / P12.6 — GAP and Regina bridges.** Both optional; pytop stays
dependency-free and each reports itself unavailable rather than raising.

GAP (inside the SageMath image) names group presentations `van_kampen` leaves
unnamed and acts as an independent oracle for pytop's SNF abelianization. Regina
— whose image is **built** from Debian, since it publishes none and is not on
PyPI — is an independent source of lens-space homology and exposes normal-surface
enumeration, which pure-Python pytop deliberately does not attempt.

```python
from pytop.experimental import ReginaSession, regina_lens_homology

with ReginaSession() as s:
    regina_lens_homology(8, 3, session=s).torsion      # (8,)
```

Both bridges validate their inputs before interpolating anything, detect success
by a sentinel rather than an exit code, and reap the in-container process on
timeout — a client-side timeout kills only the `docker exec` client.

## What's New in v1.8.0

**Phase 12 advances to 4/6.** Two milestones, both shaped by adversarial design review.

**P12.5 — countably infinite complexes** (`pytop.experimental.infinite_complexes`).
Integral homology of ℝP^∞, ℂP^∞, S^∞ and BZ/p, exact by the structural theorem
(a cell of dimension `d` affects only `H_{d-1}` and `H_d`, so evaluating at index
`degree + 1` is a proof, not a truncation). `colimit_homology` handles
user-supplied towers: it verifies the chain-map law on *signed* cell maps, finds
a **non-empty** window of steps adding only high-dimensional cells, and returns a
`ConditionalHomology` that is falsy whenever anything was assumed. `rips_betti_scan`
reports Betti numbers of Rips complexes on metric balls and makes **no claim**
about any infinite complex.

Nothing here infers stabilisation from observation. There is no `patience` or
`budget` parameter and a test forbids reintroducing one: a direct limit is not
determined by its groups — `ℤ --×2--> ℤ --×2--> ⋯` has colimit `ℤ[1/2]` — and no
fixed number of consecutive isomorphisms is a proof either.

```python
from pytop.experimental import rp_infinity_homology, rips_betti_scan, z_lattice

rp_infinity_homology(3).torsion          # (2,)  -- H_3(RP^inf) = Z/2
scan = rips_betti_scan(z_lattice(2), (0, 0), eps=1.0,
                       radii=[1, 2, 3, 4, 5], max_degree=1)
[row[1] for row in scan.betti_z]         # [0, 4, 16, 32, 60] -- b_1 per radius, no colimit claim
```

**P12.4 — GAP bridge** (`pytop.experimental.gap_bridge`). Optional; pytop stays
dependency-free and `gap_available()` returns `False` rather than raising when
Docker or the image is absent. `van_kampen`'s classifier covers a fixed list and
leaves everything else unnamed; GAP supplies order, abelian invariants and the
SmallGroups id, and acts as an independent oracle for pytop's own SNF
abelianization.

```python
from pytop.experimental import GapSession, gap_group_info
from pytop.van_kampen import GroupPresentation

q8 = GroupPresentation(("a", "b"),
                       ((("a", 2), ("b", -2)),
                        (("a", 2), ("a", -1), ("b", -1), ("a", -1), ("b", -1))))
with GapSession() as s:
    gap_group_info(q8, session=s).small_group_id    # (8, 4) -- Q8
```

Generated GAP source is injection-safe by two independent measures: generators
are emitted positionally so no user-controlled name reaches GAP, **and** relator
exponents are validated, because `GroupPresentation` does not check them and
Python does not enforce the `int` annotation.

Regina is split out as **P12.6** with evidence: no public image under three
probed names, absent from the Sage image, no PyPI distribution.

## What's New in v1.7.0

**First PyPI publication (P20.2).** `pytopology 1.7.0` is **live on PyPI**:

```bash
pip install pytopology      # then: import pytop
```

The bare `pytop` name was already taken on PyPI by an unrelated abandoned project,
so the **distribution name is `pytopology`** while the **import name stays `pytop`**
(like `scikit-learn` → `import sklearn`). Publishing is fully automated via GitHub
Actions **Trusted Publishing** (OIDC, no stored API tokens): `.github/workflows/publish.yml`
builds the sdist + wheel, runs `twine check`, guards that the tag matches
`pyproject.toml`, and uploads to PyPI on every `v*` tag (a manual run targets
TestPyPI for a dry run). pytop has **zero runtime dependencies** — verified
end-to-end with a fresh-venv install from PyPI. The development status is now
`Production/Stable`. This release bundles the post-1.6.0 maturity work: P16.2 oracle
matrix, P16.3 GUDHI wiring, P17.3 auto reduction routing, the 51-prime knot table,
and the P19/P20 API-stability and onboarding items.

## What's New in v1.6.0

**P16.2 — Oracle parity, now wired to GUDHI.** The persistent-Betti cross-check
that was previously framework-only is now a real, passing comparison. Added
`tests/validation/betti_parity.py`: pytop and GUDHI build the *same* Vietoris–Rips
filtration and agree on the **Betti number at every scale** (bars alive at `s`,
`birth ≤ s < death`) for dimensions the truncated skeleton can represent
faithfully (`H_k` needs simplices up to dim `k+1`). Verified on circle, dense
circle, two disjoint circles (`H₀=H₁=2`), an icosahedral 2-sphere (`H₂=1`), and a
random cloud. This corrected two latent bugs in the old comparison (death-count
instead of Betti-at-scale; spurious `H₂` from a triangle-only complex).

**P16.3 — 10K statistical run now cross-validated against GUDHI.** The heavy
`test_10k_random_complexes_vs_oracles` previously recorded `num_with_gudhi: 0`
(pytop-only). It now compares pytop H₀/H₁ against GUDHI's `SimplexTree` on every
one of the 10 000 random Erdős–Rényi 1-skeleta: **parity 100.0%, 0 outliers**,
~45 s total. The fix was a real GUDHI gotcha — `compute_persistence()` defaults to
`persistence_dim_max=False`, silently skipping homology in the complex's *top*
dimension (H₁ for a 1-skeleton), so GUDHI reported H₁=0 on every cyclic graph;
calling `compute_persistence(persistence_dim_max=True)` then `betti_numbers()`
fixes it. An always-on `test_500_random_complexes_gudhi_parity` guard now asserts
100% pytop=GUDHI in the default suite. Ripser is not applicable to abstract
1-skeleta (point-cloud parity stays in `test_betti_parity.py`). Validation suite
79 → 107 passing.

**P17.3 — Inductive Vietoris–Rips construction (~14–19× faster builds).** Profiling
showed the *filtration build* — not the reduction — dominated the truncated-scale
regime (85–92% of wall-clock at n=100–200). `vietoris_rips_filtration` now uses
**inductive clique expansion** (Zomorodian 2010) over the neighborhood graph
instead of exhaustive `C(n, k+1)` subset enumeration. Build time scales with the
materialized complex, not `C(n, k+1)`: **n=500 went from 22.7 s → 1.65 s**, output
**byte-identical** to before (verified vs. a brute-force reference and the full
test suite). No API change. The Z/2 reduction is now the dominant cost for dense,
high-n complexes (the next, inherently sequential, target).

**P17.3 — Size-aware auto reduction routing (now the default, up to ~12× faster
end-to-end).** With the build phase fixed, the Z/2 reduction became the bottleneck.
The planned SciPy CSR path was dropped after profiling — the bigint-bitmask Twist
kernel already beats it (native integer XOR). The real win was routing to the de
Silva dual **cohomology** reduction, which does *hundreds* of cochain additions
where Twist does *millions* of column XORs on Rips (e.g. m=107k: 399 vs 1.8M). Twist
still wins on tiny complexes, so the new `persistence_pairs_auto` switches at
`AUTO_COHOMOLOGY_THRESHOLD = 1024` simplices, and `persistent_homology(method="auto")`
is now the **default**. Output is **byte-identical** to twist/cohomology/standard
on every input (universal cross-validation test; 12,000 tests pass + GUDHI parity
unchanged). End-to-end speedup **1.7× (n=150) → 3.3× (n=250) → 12.2× (n=350, 22.4 s
→ 1.8 s)**. New API: `persistence_pairs_auto`, `select_reduction_method`,
`AUTO_COHOMOLOGY_THRESHOLD`.

**P19.2 / P19.3 / P20.3 — API maturity & onboarding.** Reusable `@deprecated`
decorator (`pytop._deprecation`) emitting consistent WHY-HOW-THEN
`DeprecationWarning`s, plus `DEPRECATIONS.md` (18-month / next-major policy +
registry, with a **Candidates / soft-deprecations** section). API
naming/consistency audit in `docs/API_DESIGN.md` — finding #3 resolved by
soft-deprecating `persistent_homology_optimized` in favour of
`persistent_homology(method="auto")` (note only, no warning pre-1.7.0).
`CONTRIBUTING.md` + GitHub issue/PR templates, and `docs/GOOD_FIRST_ISSUES.md`
(12 curated, file-grounded starter tasks for the `good first issue` label).

**Maintenance — clean baseline.** Repo-wide lint/type debt cleared: `src/pytop`
is ruff-clean **and** mypy-clean (244 files) and the whole `src/`+`tests/` tree
passes ruff (was 236 ruff + 12 mypy errors; a latent `_gpu_backend` crash fixed
along the way). Version handling reconciled (`pyproject` ↔ `__version__` in sync);
backfilled the missing `v1.4.0`/`v1.5.0` release tags and tagged `v1.6.0`.

**Phase 16 — Empirical Validation & Oracle Ecosystem (P16.1–P16.3 complete)**

Cross-validates pytop against independent gold-standard external systems via unified oracle framework.

- **P16.1: Benchmark Suite (37 tests)** — Minimal triangulations (T², Klein, ℝP²), 51-prime knot table (unknot–17_1), large grid graphs (3×3–40×40), performance baselines.

- **P16.2: Oracle Parity Framework ✅ AUTONOMOUS** — Unified adapter system for external systems:
  - **`oracle_integrations.py`** — Abstract `OracleAdapter` with 4 concrete implementations:
    * `GudhiOracleAdapter`: persistent homology Rips/Čech Betti computation
    * `RipserOracleAdapter`: fast R-based persistent homology  
    * `SnapPyOracleAdapter`: Dehn surgery H₁, knot invariants (Docker opt-in `PYTOP_SNAPPY_ORACLE=1`)
    * `SageOracleAdapter`: K-theory rational groups, polynomial computation (Docker opt-in `PYTOP_SAGE_ORACLE=1`)
  - **`oracle_agreement_builder.py`** — Orchestration engine:
    * `OracleAgreementBuilder`: runs cross-oracle tests (polynomials, Betti, K-theory)
    * `AgreementMatrixReport`: aggregates results, exports JSON + Markdown with agreement rates
  - **`run_p16_2_oracle_agreement.py`** — Autonomous CLI runner:
    * `--fast` mode: sample validation (~0.5s)
    * `--full` mode: comprehensive cross-checks (~2–5min with all oracles)
    * Auto-detects available oracles, gracefully skips unavailable systems
    * JSON/Markdown reports with detailed agreement/disagreement breakdown
  - Extended knot table: 40 → **51 primes** (10-crossing 10_1–10_5 + a *verified* torus-knot tail — T(3,5)=10_124 and T(2,11..17)). The torus tail and 7 corrected low-crossing entries (4_1, 5_1, 5_2, 6_2, 6_3, 7_1, 8_19) carry pytop-recomputed invariants (Burau Alexander + braid-closure→PD Kauffman Jones), each triple-checksummed against the knot determinant (|Δ(−1)| = |V(−1)| = det, V(1)=1). The 8_x/9_x/10_x Jones (plus 6_1 and 7_2–7_7) are now **backfilled from the SageMath oracle** (Docker `sagemath/sagemath`), mirror-calibrated to the table convention and each verified `|V(−1)|=det` / `V(1)=1`; a universal `test_all_jones_satisfy_v1_equals_one` guard locks every entry. The corresponding **Alexander** polynomials were backfilled the same way (37 placeholders replaced with Sage's canonical Δ(1)=+1 values), locked by `test_all_alexander_satisfy_delta1_unit` (|Δ(1)|=1). The **genus** fields were then corrected to `span(Δ)/2` — the exact Seifert 3-genus for alternating/torus knots, i.e. every table entry (32 fixed, e.g. the 8_1 twist knot was listed genus 3, actually 1) — locked by `test_genus_matches_alexander_span` (2·genus = Alexander span). The knot table's Jones, Alexander, and genus columns are now fully oracle-verified.
  - **11 new tests**: oracle availability, adapter initialization, persistent Betti agreement (GUDHI/Ripser), polynomial reference validation
  - **Framework ready for**: PyPI publication, CI/CD integration, automated oracle matrix population

- **P16.3: Statistical Validation (10,000 complexes, ✅ GUDHI-cross-validated)** — Random Erdős–Rényi 1-skeleta (5–50 vertices):
  - `test_10k_random_complexes_vs_oracles`: pytop H₀/H₁ compared against GUDHI on all 10K inputs — **parity 100.0%, 0 outliers**, avg 4.35ms/complex, ~45s total (`statistical_validation_report.json`: `num_with_gudhi: 10000`)
  - `test_500_random_complexes_gudhi_parity`: always-on default-suite guard (asserts 100% pytop=GUDHI; skipped only if GUDHI missing)
  - GUDHI `SimplexTree` path uses `compute_persistence(persistence_dim_max=True)` so the top-dimension H₁ is computed, not skipped; Ripser is N/A for abstract complexes (point-cloud parity in `test_betti_parity.py`)
  - Outlier analysis and JSON report generation; ready for larger scales (50K+) and parallelization

**Phase 18 — Documentation & Pedagogy ✅ (P18.1–P18.3 complete)**

Complete user guide and API reference (16 chapters, 225 modules, 36+ examples).

## What's New in v1.2.0

**Phase 10 — Scale & Algorithm: 5 milestones, 65 new tests**

Extends practical input limits of existing engines and adds approximate / streaming TDA — without changing the pure-Python correctness core.

- **`sparse_linalg` (P10.1)** — Column-sparse Smith Normal Form via `_SparseMat` (dual row/col dicts).
  `sparse_smith_normal_form` accepts `list[list[int]]` or any `scipy.sparse` matrix.
  `homology._smith_normal_form` now **auto-routes** matrices with `min(m,n) ≥ 30` and density < 30 %
  through the sparse path — Khovanov and Rips boundary matrices hit this automatically.
  `matrix_density` helper exposes the sparsity fraction.

- **`khovanov_homology(parallel=True)` (P10.2)** — All per-quantum-grading SNF calls are submitted
  to a `ThreadPoolExecutor` and run in parallel.  With the pure-Python SNF backend the GIL limits
  true concurrency; with the optional `[fast]` flint backend (C code, GIL-free) the speedup is
  real.  Results are identical to the sequential path.

- **`witness_complex` (P10.3)** — Approximate persistence for large point clouds.
  `landmark_sample(points, k, method='maxmin')` — greedy farthest-point (maxmin) or uniform random.
  `witness_filtration(points, landmarks, max_dim)` — strong-witness filtration (de Silva & Carlsson
  2004): simplex σ enters at `ε(σ) = min_w max_{l∈σ} d(w,l)`.
  `persistent_homology_witness(points, k, max_dim)` — full pipeline returning a `WitnessComplex`
  (filtration + landmark indices + Twist-reduced pairs).

- **`streaming_persistence` (P10.4)** — Online Z/2 column reduction via `StreamingPersistence`.
  Simplices inserted one at a time with `add_simplex(simplex, birth)` (filtration order required).
  Bitmask-column representation (same as Twist+Clearing); `current_pairs()`, `current_betti()`,
  `current_essential_pairs()`.  Results match `persistence_pairs_twist` on the same filtration.

- **`_gpu_backend` (P10.5)** — Optional cupy-accelerated Twist+Clearing via `gpu_twist_reduce`.
  Columns stored as cupy boolean arrays; XOR is GPU-native.  Falls back silently to `_twist_reduce`
  when cupy is absent or the filtration is below `GPU_MIN_SIZE = 500`.
  Install with `pip install 'pytopology[gpu]'`.

```python
from pytop import sparse_smith_normal_form, matrix_density
from pytop import landmark_sample, witness_filtration, persistent_homology_witness
from pytop import StreamingPersistence
from pytop import GPU_AVAILABLE, gpu_twist_reduce

# Sparse SNF — same result as exact_linalg.smith_normal_form, faster on sparse inputs
boundary = [[1,-1,0,1],[0,1,-1,0],[-1,0,1,-1]]
print(matrix_density(boundary))          # 0.75 — dense, stays on dense path
print(sparse_smith_normal_form(boundary))  # [1, 1, 1]

# Witness complex — approximate H1 of a circle
import math, random
pts = [(math.cos(2*math.pi*i/50), math.sin(2*math.pi*i/50)) for i in range(50)]
wc = persistent_homology_witness(pts, k=12, max_dim=1, seed=0)
h1 = [p for p in wc.pairs if p.dimension == 1]
print(len(h1), "H1 bars")     # ≥ 1 (the circle loop)

# Streaming persistence — insert simplices one at a time
sp = StreamingPersistence()
for v in range(3): sp.add_simplex((v,), 0.0)
sp.add_simplex((0,1), 1.0); sp.add_simplex((0,2), 1.5); sp.add_simplex((1,2), 2.0)
print(sp.current_betti())      # {0: 1}  — one component
sp.add_simplex((0,1,2), 3.0)  # fill triangle
print(sp.current_pairs())      # includes the H1 bar [2.0, 3.0)

# Parallel Khovanov
from pytop import khovanov_homology, KnotDiagram
trefoil = KnotDiagram([(1,4,2,5),(3,6,4,1),(5,2,6,3)], signs=(1,1,1))
kh = khovanov_homology(trefoil, parallel=True)   # same groups, faster on large diagrams
```

**65 new tests; 11 467 total.**

---

## What's New in v1.5.0

**Phases 13–15 — Homotopy theory, advanced knot homology, and 4-manifold topology (15 new modules)**

Three full phases, each five modules, all pure-Python and dependency-free, ruff-clean and mypy-clean.

- **Phase 13 — Homotopy Theory:** `chain_homotopy` (∂h+h∂=f−g verification + ℚ-solver),
  `eilenberg_maclane` (H_*(K(G,n)) for cyclic/free/free-abelian/ℤ groups, asphericity),
  `massey_products` (triple products + formality), `hopf_invariant` (Hopf fibrations,
  Adams' theorem, π₃(S²)), `sullivan_models` (minimal models over ℚ; χ via the Hilbert
  series of ΛV → χ(T²)=0, χ(S^{2k})=2, χ(CP^n)=n+1).
- **Phase 14 — Advanced Knot Homology:** `khovanov_odd` (odd Khovanov homology),
  `grid_floer` (grid-diagram HFK̂ over 𝔽₂), `concordance` (τ, s, σ, Tristram–Levine,
  algebraic sliceness), `satellite_knots` (Morton's formula, exact torus-knot Alexander
  polynomial division, cables, Whitehead doubles), `virtual_knots` (Gauss codes, parity,
  odd writhe, arrow polynomial).
- **Phase 15 — 4-Manifold Topology:** `intersection_forms` (Sylvester congruence signature,
  E₈/hyperbolic, Donaldson), `kirby_calculus` (handle moves → intersection form),
  `casson_invariant` (Neumann–Wahl λ(Σ(a,b,c))=σ(Milnor fibre)/8), `milnor_fibers`
  (Brieskorn–Pham μ, signature, ADE), `rohlin_theorem` (spin + smooth ⇒ σ≡0 mod 16,
  Kirby–Siebenmann, Freedman realisation).

**140 new tests; 11 685 tests pass total.**

**Phase 12 — Research Frontier: Čech sheaf cohomology + persistent K-theory (P12.1–P12.2)**

Two new research-grade engines that push pytop into algebraic K-theory and sheaf theory territory.

- **`sheaf_cohomology` (P12.1)** — Čech cohomology of a sheaf on a finite topological space.
  `FiniteSheaf` (frozen dataclass: `open_sets`, integer-rank `sections`, integer-matrix `restrictions`);
  `constant_sheaf` and `skyscraper_sheaf` factory functions;
  `cech_cohomology(cover, sheaf, max_degree)` — full Čech cochain complex with alternating-sign
  coboundary δ^p, SNF → `AbelianGroup` per degree;
  `sheaf_cohomology(open_sets, universe, sheaf)` — uses the minimal-open-neighborhood Leray cover
  (McCord 1966) so H⁰ counts connected components correctly (e.g. H⁰=ℤ for Sierpiński,
  H⁰=ℤ² for discrete 2-point space).

- **`persistent_ktheory` (P12.2)** — Rational K-theory groups and persistent K-theory barcode.
  `KTheoryGroups` — AHSS collapse: K⁰⊗ℚ = ⊕H_{2k}, K¹⊗ℚ = ⊕H_{2k+1}; verified on
  point (1,0), S¹ (1,1), S² (2,0), torus T² (2,2).
  `KBarcode` — Twist-reduced persistence pairs partitioned by dimension parity;
  `k0_betti_at(ε)`, `k1_betti_at(ε)`, `euler_characteristic_at(ε)` (χ_K = rank K⁰ − rank K¹ = χ).

```python
from pytop import (
    FiniteSheaf, constant_sheaf, skyscraper_sheaf, cech_cohomology, sheaf_cohomology,
    KTheoryGroups, KBarcode, k_theory_groups, k_barcode, k_betti_numbers,
)
from pytop.homology import SimplicialComplex

# Sheaf cohomology: discrete 2-point space with constant sheaf ℤ
opens = [frozenset({0}), frozenset({1}), frozenset({0, 1})]
sheaf = constant_sheaf(opens)
result = sheaf_cohomology(opens, frozenset({0, 1}), sheaf)
print(result["cohomology"][0])  # AbelianGroup(free_rank=2, torsion=()) — two components

# Persistent K-theory of a circle
s1 = SimplicialComplex([(0,),(1,),(2,),(0,1),(1,2),(0,2)])
g = k_theory_groups(s1)
print(g.k0_rank, g.k1_rank)    # 1  1  — K⁰(S¹)=ℤ, K¹(S¹)=ℤ

from pytop.persistent_homology import vietoris_rips_filtration
import math
pts = [(math.cos(2*math.pi*i/8), math.sin(2*math.pi*i/8)) for i in range(8)]

class Cloud:
    carrier = pts
    def distance_between(self, a, b): return math.dist(a, b)

filt = vietoris_rips_filtration(Cloud(), max_dimension=2)
kb = k_barcode(filt)
print(kb.euler_characteristic_at(0.0))   # 8  (8 isolated points)
```

**78 new tests; 11 545 total.**

---

## What's New in v1.3.0

**Phase 11 — Lean 4 Formal Verification Expansion: 5 new proof files, 0 sorry**

Extends the `formal/` corpus from 6 to **11 Lean files**. The zero-sorry rule holds throughout.

- **`MayerVietoris.lean` (P11.1)** — Short exact sequences + snake lemma.
  `SES` structure (injective `i`, exact at `B`, surjective `p`); `ses_p_zero_of_im`
  (exactness → `p ∘ i = 0`); `delta_well_defined`; `snake_delta_exists`;
  `snake_delta_independent` (connecting class well-defined in A').

- **`VanKampen.lean` (P11.2)** — Group presentations + amalgamated free product.
  `Pres` structure; `TietzeEquiv` inductive relation with `tietze_elim` / `tietze_add_gen`;
  `AmalgamDatum` + `Pushout`; `pushout_universal`; `int_hom_determined_by_one`
  (ℤ is the free abelian group on one generator — uniqueness); `int_hom_exists` (existence).

- **`CohomologyRing.lean` (P11.3)** — Cup product over Bool (ℤ/2).
  Alexander–Whitney `cup` (`⌣`) operator; `cup_value_assoc` (`Bool.and_assoc`);
  `cup_comm_Z2`; `coboundary0`; `leibniz_0cochains` (Leibniz rule δ(f⌣g) = δf⌣g ⊕ f⌣δg,
  verified by 4-way Bool case analysis).

- **`PersistencePairing.lean` (P11.4)** — Persistence pairing perfection.
  `pairing_is_perfect` (= `reduce_is_reduced`); `pairs_have_distinct_births` (birth indices
  are `Nodup`). Key lemma chain: `isReduced_tail` → `filterMap_getLast_nodup_of_isReduced`
  (induction + `List.mem_iff_getElem` for positional index) → `zipWith_range_filterMap_snd_eq`
  → `map_fst_pairs_eq`.

- **`SpectralSequences.lean` (P11.5)** — Abstract spectral sequences.
  `ChainCx α` structure with differential `d : α →+ α` and `sq : ∀ x, d (d x) = 0`;
  `d_sq_zero`; `image_sub_kernel`; `SpectralSeq`; `StabilizesAt`; `Convergent`;
  `const_convergent`; `stabilizes_mono`; `same_diff_implies_same_stab`;
  `const_pages_convergent`.

**0 sorry across all 11 Lean files.**

---

## What's New in v1.1.0

**Phase 9 — `experimental.spaces` expansion: 6 new canonical representations (13 → 19)**

Six new infinite-space representations, all importable from `pytop.experimental.spaces`:

- **`OnePointCompactificationSpace` / `one_point_compactification(space)` (P9.1)** —
  Alexandroff one-point compactification αX = X ∪ {∞}.  For finite X the full topology is
  enumerated: opens(αX) = opens_X ∪ {U ∪ {∞} : U ∈ opens_X}.  Compact always; T2 iff base
  is locally compact Hausdorff; {∞} isolated when X is compact.

- **`StoneCechSpace` / `stone_cech_n()` (P9.2)** — Stone–Čech compactification βℕ.
  Compact T4, separable (ℕ embeds as a countable dense subspace), NOT first-countable (free
  ultrafilter points have no countable local base), NOT T6.
  Cardinals: weight = 𝔠, density = ℵ₀, character = 𝔠.

- **`HilbertCubeSpace` / `hilbert_cube()` (P9.3)** — Hilbert cube [0,1]^ω.
  Compact, connected, T6 (metrizable), second-countable, separable.  Points are finite
  rational tuples; separation via cylinder neighbourhoods.
  By Urysohn: every compact metrizable space embeds into [0,1]^ω.

- **`SolenoidSpace` / `dyadic_solenoid()` (P9.4)** — dyadic solenoid
  Σ = lim←{S¹ ←² S¹ ←² S¹ ←² …}.  Compact, connected, metrizable T6.
  NOT locally connected (local cross-sections are Cantor sets).
  `contains()` checks compatibility: 2·θₖ ≡ θₖ₋₁ (mod 1).

- **`UniformSpace` + `UniformProduct` + `UniformSubspace` (P9.5)** — uniform structure
  backed by a metric.  Methods: `entourage(ε)` (returns the ε-entourage as a callable
  relation), `is_cauchy(seq, ε)` (finite-sample Cauchy test), `uniform_neighbourhood(x, ε)`.
  `UniformProduct` uses sup-metric; `UniformSubspace` uses trace uniformity.
  Factories: `rational_uniform_space()`, `metric_uniform_space(name, d, member)`.

- **`ProfiniteSpace` / `p_adic_integers(p)` (P9.6)** — inverse limit of finite discrete
  groups.  `p_adic_integers(p)` builds ℤ_p = lim← ℤ/p ← ℤ/p² ← ℤ/p³ ← … via reduction
  mod pⁿ.  Compact, T6, totally disconnected, metrizable, second-countable.

```python
from pytop.experimental.spaces import (
    hilbert_cube, dyadic_solenoid, stone_cech_n, p_adic_integers,
    one_point_compactification, rational_uniform_space, UniformProduct,
    is_compact, is_connected, is_t6, is_first_countable, discrete_finite_space,
)
from fractions import Fraction

# Hilbert cube — compact T6, universal compact metrizable space
hc = hilbert_cube()
is_t6(hc).value        # True
is_compact(hc).value   # True

# Dyadic solenoid — compact, connected, NOT locally connected
sol = dyadic_solenoid()
sol.contains((Fraction(1,3), Fraction(2,3)))   # True (2·2/3 mod 1 = 1/3)
sol.certificate("locally_connected").value      # False

# Stone–Čech βℕ — separable but not first-countable
is_first_countable(stone_cech_n()).value   # False

# p-adic integers ℤ₅ — compatible sequences mod 5^k
z5 = p_adic_integers(5)
z5.contains((3, 8, 33))   # True  (8 mod 5 = 3, 33 mod 25 = 8)

# One-point compactification — finite → full topology enumerated
alpha = one_point_compactification(discrete_finite_space({0, 1}))
len(list(alpha.open_sets()))   # 8

# Uniform product with sup-metric
u = rational_uniform_space()
up = UniformProduct(u, u)
v = up.point_separation((Fraction(0), Fraction(0)), (Fraction(3,4), Fraction(1,4)))
v.witness["radius"]   # Fraction(3, 8)
```

**166 new tests; 11 402 total.**

---

## What's New in v1.0.9

**Phase 8 — Profile→Computational upgrade: 6 advanced algebra modules, 16 new functions**

Previously tag-based classifier modules promoted to genuine computational engines:

- **`derived_categories` (P8.1)** — `mapping_cone_complex` (block boundary matrix for C(f)_n = A_{n-1}⊕B_n);
  `derived_functor_h` (H_n from boundary matrices via Betti + torsion through SNF);
  `triangulated_structure_check` (g∘f=0 + cone Betti comparison).
- **`topos_theory` (P8.2)** — `site_from_finite_topology` (Grothendieck site from open-set lattice);
  `sheaf_on_site` (locality + gluing axioms); `sheafification_finite` (one-step F⁺ correction);
  `topos_check` (terminal object + fiber products + Ω → Grothendieck topos verdict).
- **`operads` (P8.3)** — `associahedron_complex(n)` (Stasheff K_n as SimplicialComplex; vertices = full
  binary trees with n leaves, edges = rotation pairs; K₃=interval, K₄=pentagon);
  `operad_composition_check` (µ(µ(a,b),c) = µ(a,µ(b,c)) for all basis triples);
  `bar_construction_sc` (bar complex skeletal model).
- **`higher_categories` (P8.4)** — `nerve_of_category` (N(C) up to dim 2; 2-simplex when composite
  a→c present for chain a→b→c); `kan_fibration_check_sc` (horn-filling condition);
  `homotopy_type_finite_cat` (BC = |N(C)| Betti numbers, is_contractible, is_connected).
- **`noncommutative_topology` (P8.5)** — `k0_group_matrix_algebra(n)` (K₀(Mₙ(ℚ)) ≅ ℤ, identity class = n,
  Morita invariance); `spectral_dimension_finite` (log-log regression on eigenvalue counting → d_s);
  `k1_group_matrix_algebra(n)` (K₁(Mₙ(ℚ)) ≅ ℚ*; torsion = ℤ/2).
- **`topological_field_theory` (P8.6)** — `cobordism_from_handles(n₀,n₁,n₂)` (χ, genus, connectivity);
  `tqft_dimension_2d(genus)` (Boolean TFT dim=1; A₂ TFT: 2/1/0 for g=0/1/≥2);
  `handle_signature_tft(n₀,…,n₄)` (4-manifold handles → Euler char, Betti, π₁ flag).

**171 new tests; 11 236 total.**

---

## What's New in v1.0.8

**Profile→Computational upgrade: 4 modules, 13 new functions**

Previously tag-based classifier modules promoted to genuine computational engines:

- **`shape_theory`** — `link_complex(simplices, vertex)` (lk(K,v) face-closed);
  `is_manifold_triangulation(simplices, n)` (every vertex link ≃ Sⁿ⁻¹ by homology);
  `has_trivial_shape_sc(simplices)` (contractibility via H_*);
  `shape_anr_check_sc(simplices)` (compact polyhedron ANR/FANR/movability + shape class).
- **`coarse_geometry`** — `growth_function_graph(adj, source, r)` (BFS ball sizes b(r));
  `geodesic_distance_graph(adj, u, v)` (shortest-path length or −1);
  `is_tree_graph(adj)` (connected + |E|=|V|−1, 0-Gromov-hyperbolic);
  `classify_graph_coarse_growth` (polynomial/exponential via log-log slope, degree estimate).
- **`locale_theory`** — `frame_from_finite_topology` (closure under ∩ and ∪, sorted frame);
  `pseudocomplement_in_frame` (b* = ∨{c : c∧b=∅});
  `well_inside_relation` (b << a iff b* ∨ a = top);
  `is_regular_frame` (every a = ∨{b : b << a});
  `is_spatial_finite_frame` (∅ and top present, opens separate points).
- **`dimension_theory`** — `covering_dimension_simplicial` (max simplex dim);
  `ind_finite_space` (longest strict chain in specialization poset; indiscrete spaces = 0).

**120 new tests; 11 065 total (pre-v1.0.9).**

---

## What's New in v1.0.7

**`experimental.spaces` extended representations (10 → 13):**

Three new canonical infinite-space representations expand the computable-space protocol:

- **`ProductMetricSpace`** — product of two metric spaces with the sup metric
  `d((x₁,y₁),(x₂,y₂)) = max(d_X(x₁,x₂), d_Y(y₁,y₂))`. Inherits all metric-space separation
  properties (T0–T6, first-countable, Tychonoff). Factory: `rational_plane()` builds ℚ².
- **`LexicographicSquareSpace`** — [0,1]² with the lexicographic order topology (the canonical
  example of a compact T5 space that is NOT metrizable). Certificates: compact, connected, T5,
  Lindelöf, first-countable; NOT second-countable, NOT separable (cellularity = 𝔠).
  `point_separation` splits at a rational midpoint in the first coordinate, or within the fiber
  for equal first coordinates. Factory: `lexicographic_square()`.
- **`CantorSpaceRepresentation`** — {0,1}^ω with the product topology. Points as finite binary
  tuples; `point_separation` returns the clopen cylinder at the first differing bit
  (undecidable when one tuple is a prefix of the other — honest!). Certificates: compact, T6,
  totally disconnected, second-countable, separable; weight = density = character = cellularity = ℵ₀.
  Brouwer's theorem: every compact metrizable zero-dimensional perfect space is homeomorphic to
  the Cantor space. Factory: `cantor_space()`.

```python
from pytop.experimental.spaces import (
    rational_plane, lexicographic_square, cantor_space,
    is_hausdorff, is_compact, is_connected, is_second_countable, is_separable,
    is_t5, is_t6,
)
from pytop.experimental.spaces.cardinal_invariants import cellularity, character
from pytop.experimental.spaces.core import CardinalValue

# ℚ² — product metric space
q2 = rational_plane()
is_hausdorff(q2).value                          # True  (metric space)
is_t6(q2).value                                 # True  (metrizable → perfectly normal)
q2.point_separation((0, 0), (1, 0)).witness[0][1]  # Fraction(1, 2)  (sup-ball radius)

# Lex square — compact T5 but NOT second-countable
lex = lexicographic_square()
is_compact(lex).value                           # True
is_connected(lex).value                         # True
is_t5(lex).value                                # True
is_second_countable(lex).value                  # False  (uncountable cellularity)
is_separable(lex).value                         # False
cellularity(lex)                                # CardinalValue(symbol='𝔠')
character(lex)                                  # CardinalValue(symbol='ℵ₀')

# Cantor space — compact, totally disconnected, perfect
cs = cantor_space()
is_compact(cs).value                            # True
is_connected(cs).value                          # False  (totally disconnected)
is_t6(cs).value                                 # True
is_second_countable(cs).value                   # True
character(cs)                                   # CardinalValue(symbol='ℵ₀')

# Separation: clopen cylinder at first differing bit
cs.point_separation((0, 1, 0), (0, 1, 1)).witness  # {'bit_position': 2, 'value': 0}

# Prefix → honest undecidable
from pytop.experimental.spaces.core import Decidability
cs.point_separation((0, 1), (0, 1, 0)).decidability  # Decidability.UNDECIDABLE
```

**10 945 tests passing when released** (+ 16 opt-in SageMath/SnapPy-oracle tests).

---

## What's New in v1.0.6

**Profile→Computational engine upgrades (6 modules) + critical `_snf_ext` bug fix:**

- **Covering spaces** (`covering_spaces.py`): `CoveringGraph`, `cyclic_voltage_cover` (voltage
  construction for cyclic covers), `fundamental_group_rank_graph` (first Betti number β₁ via Euler
  characteristic), `is_graph_covering_map` (sheet-count + uniform-degree check),
  `universal_covering_tree` (BFS spanning tree). 32 tests.
- **Fundamental group** (`fundamental_group.py`): `pi1_graph(edges)` — fundamental group of a
  1-complex via van Kampen + spanning-tree; k-cycle graph → free group Fₖ. 14 tests.
- **Three-manifolds** (`three_manifolds.py`): `mapping_torus_h1(monodromy)` — H₁ of the mapping
  torus via Wang sequence cokernel (SNF); `lens_space_pi1(p, q)` → ℤ/p. 21 tests.
- **Homotopy** (`homotopy.py`): `is_contractible_simplicial(simplices)` — contractibility via
  H_*(X;ℤ) ≅ H_*(pt;ℤ); `has_sphere_homology(simplices, n)` — sphere homology type test
  (H_*(X;ℤ) ≅ H_*(Sⁿ;ℤ)). Auto face-closure before boundary matrix. 26 tests.
- **Degree theory** (`degree_theory.py`): `map_degree_simplicial(sim_map, n)` — topological degree
  of f: Sⁿ → Sⁿ from the 1×1 matrix of `induced_map_on_homology` on H_n. 8 tests.
- **Manifolds** (`manifolds.py`): `euler_characteristic_simplicial(simplices)` — χ = Σ(−1)^k f_k
  computed combinatorially; correct for torus (χ=0), RP² (χ=1), disjoint unions (additive). 18 tests.
- **Critical bug fix** (`mayer_vietoris.py`): `_snf_ext` no longer hangs on matrices with negative
  entries. The `q -= 1` corrections assumed C-style truncation division; Python's `//` is floor
  division and already gives the correct quotient — the adjustment over-corrected, making the
  remainder exceed the pivot and triggering infinite swap cycles. Removed. All 150-iteration
  property tests now pass in < 0.5 s.

**10 864 tests passing when released** (+ 16 opt-in SageMath/SnapPy-oracle tests).

---

## What's New in v1.0.5 (Phase 7 complete)

**Phase 7 — Combinatorial topology & geometric structures (P7.2–P7.6):**

- **Simplicial maps** (`simplicial_maps.py`, P7.2): `SimplicialMap` dataclass with vertex-map
  validation, `chain_map_matrix` (integer matrix f#_k: C_k(K) → C_k(L) with correct signs),
  `induced_map_on_homology` (f_*: H_k(K;Z) → H_k(L;Z) via extended SNF), `cone_complex`
  (contractible CK = K * {apex}), `suspension_complex` (ΣK = K * S⁰; Σ(Sⁿ) ≃ Sⁿ⁺¹). 42 tests.
- **Nerve complex** (`nerve_complex.py`, P7.3): `nerve_of_cover` (nerve N(U) of a finite open
  cover), `good_cover_check` (verifies Nerve theorem preconditions — covers space, pairwise
  intersections, nonempty sets), `cech_nerve` (Čech complex at fixed radius via Welzl miniball
  least-squares circumsphere). 30 tests.
- **Spectral sequences (computational)** (`spectral_sequences.py`, P7.4): `SpectralPage`
  (bigraded Betti/torsion groups at page r), `FilteredChainComplex`, `filtered_chain_complex_from_simplices`,
  `differential_d_r` (E^r page differentials d^r: E^r_{p,q} → E^r_{p−r,q+r−1}),
  `converges_to` (iterates pages until E^{r+1} = E^r stability → E^∞). 25 new tests.
- **Surgery theory** (`surgery_theory.py`, P7.5): `handle_attachment` (K ∪ cone(Sᵏ⁻¹),
  homotopy-type of K with a k-cell attached), `trace_cobordism`, `trace_homology`
  (H_*(W;Z) via direct simplicial homology with Mayer–Vietoris interpretation). 24 tests.
- **Morse complex** (`morse_complex.py`, P7.6): `MorseChainComplex` (critical simplices +
  Morse boundary matrices from a discrete gradient matching), `morse_boundary_operator`
  (gradient V-path counting with Forman signs — DFS on the acyclic gradient graph),
  `morse_homology` (H_*(C^M;Z) via Smith normal form + automatic cross-validation against
  simplicial H_*(K;Z): **Morse homology theorem verified**). 32 tests.

**9 959 core tests passing when released (+ opt-in SageMath/SnapPy-oracle tests). All phases 1–7 complete.**

---

## What's New (post-v0.6.0, now on master — PR #15)

- **Phase 1/2 incremental improvements** (latest):
  - **Alexandroff factory functions**: `finite_circle()` (4-pt diamond, π₁=ℤ), `finite_sphere(n)`
    (2(n+1)-pt McCord model via iterated suspension, π₁=trivial for n≥2), `finite_wedge_circles(k)`
    (1+3k-pt model of S¹∨⋯∨S¹, π₁=F_k).
  - **AlexandroffSpace structural certificates**: `certificate("T0")` checks antisymmetry of the
    order relation (no open-set enumeration needed); `certificate("connected")` uses union-find on
    the strict-order graph. `cardinal_certificate("character")` = 1 (principal upset is the unique
    minimal neighbourhood); `cardinal_certificate("weight")` = |X| for T0 Alexandroff spaces.
  - **Urysohn witnesses for all infinite Tychonoff representations**:
    `SorgenfreyLineSpace` → Euclidean distance-ratio formula (valid because τ_std ⊊ τ_Sorgenfrey);
    `OrderTopologySpace` → order-metric formula (order topology on ℚ = metric topology).
  - **Stronger Tietze simplification**: `_cyclically_reduce` removes outer inverse-pair letters from
    relators; `_dedup_relators` eliminates duplicate relators up to cyclic conjugation + inversion.
    Applied after every Tietze II elimination.
  - **`predicates._decide` certificate-first**: structural certificates checked before finite-topology
    enumeration — allows subclasses to short-circuit without enumerating all open sets.
  - **`persistence_betti_numbers(pairs)`**: counts essential (death=∞) persistence pairs per dimension.
- **Research-grade computable-space protocol** (`experimental.spaces`) — Phase 1 complete (S1–S5):
  unified `Space` ABC with 16 witness-producing, decidability-honest predicates (T0–T6/Tychonoff,
  regular/normal, compact/connected, Lindelöf/separable, first/second-countable), **10 representations**
  (Finite, Cofinite, Order-ℚ, Metric, Sorgenfrey, Discrete-ℕ, Opaque, Alexandroff, Subbase,
  InverseLimit), finite+infinite construction closure (`ProductSpace`, `SubspaceSpace`, `SumSpace`,
  `QuotientSpace`), cardinal invariants (weight/density/character/cellularity), Urysohn witnesses,
  π₁ via McCord order complex, and a property-reasoning engine that derives and *explains* properties
  of constructed infinite spaces via preservation theorems + the pi-Base implication graph — no
  enumeration. `synthesize(has=…, lacks=…)` finds example spaces. Preservation table
  cross-validated against pi-Base meta-properties.
- **pi-Base atlas bridge** — `pi_base_space("Cantor set")` wraps any of 222 famous spaces as a
  protocol `Space`; feeds directly into the reasoning engine and construction wrappers.
- **Field-coefficient & relative homology** — `betti_numbers_over(K, "Q")` / `betti_numbers_over(K, p)`
  and `relative_homology(K, L)` / `relative_betti_numbers(K, L)`. Demonstrates coefficient
  dependence: RP² → H₁(;Q)=0 but H₁(;Z/2)=Z/2 (2-torsion visible over Z/2 only).
- **Mayer–Vietoris long exact sequence** — `mayer_vietoris(A, B)` computes the full LES for K = A ∪ B:
  extended Smith Normal Form yields explicit homology bases and cycle representatives;
  inclusion maps and the snake-lemma connecting homomorphism δ are returned as integer matrices;
  exactness verified at every position (S¹, S², interval). 30 new tests.
- **Cellular homology** — `cellular_homology(cw, k)` computes H_k(X; Z) from a CW complex specified
  by cell counts and integer boundary matrices. Convenience constructors cover the standard spaces:
  `cw_sphere(n)`, `cw_real_projective_space(n)`, `cw_complex_projective_space(n)`, `cw_torus()`,
  `cw_klein_bottle()`, `cw_lens_space(p)`, `cw_moore_space(n, k)`. `cw_from_simplicial(K)` bridges
  CW and simplicial homology for cross-validation. Chain-complex condition d∘d=0 verified on
  construction. 65 new tests.
- **Cohomology + cup product** — `simplicial_cohomology(K, k)` computes H^k(K; Z) via the cochain
  complex δ^k = (∂_{k+1})^T and extended Smith Normal Form. UCT (H^k torsion = H_{k-1} torsion)
  verified against homology. `simplicial_cohomology_ring(K)` returns a `CohomologyRing` with the
  Alexander-Whitney cup product on cohomology generators — torus H^1 ⊗ H^1 → H^2 pairing is
  non-degenerate and graded-commutative; RP² H^2 = Z/2 from UCT. 53 new tests.
- **Seifert–van Kampen theorem** — `van_kampen(π₁A, π₁B, π₁(A∩B), φ_A, φ_B)` computes π₁(A∪B) as
  the amalgamated free product via `GroupPresentation` + `GroupHomomorphism`. Tietze elimination
  reduces the raw presentation; abelianization (H₁ = π₁^ab) is computed via Smith Normal Form.
  `cw_complex_pi1(cw)` derives π₁ directly from a `CW1Complex` using a BFS spanning tree.
  Convenience constructors cover the standard spaces: `van_kampen_sphere()` → trivial,
  `van_kampen_torus()` → ⟨a,b | aba⁻¹b⁻¹⟩ ≅ ℤ², `van_kampen_klein_bottle()` → ⟨a,b | abab⁻¹⟩
  (H₁ = ℤ⊕ℤ/2), `van_kampen_real_projective_plane()` → ⟨a | a²⟩ ≅ ℤ/2,
  `van_kampen_wedge_circles(n)` → Fₙ. Group type identified automatically. 59 new tests.
- **Optimized persistence (Twist+Clearing)** — `persistent_homology_optimized` implements the
  Chen–Kerber 2011 Twist algorithm: columns processed dimension-top-down; the Clearing Lemma
  immediately skips every creator whose reduction is guaranteed to be zero. Returns identical
  results to the standard L→R sweep, typically with significantly fewer column additions.
  `persistence_pairs_twist_with_stats` exposes `ReductionStats` (n_cleared, clearing_ratio,
  n_column_additions). Shared `_twist_reduce` kernel reused by the cubical pipeline. 46 new tests.
- **Cubical complexes** — `cubical_homology` provides a complete cubical TDA stack:
  `CubicalComplex` (face-closure under ∂, ℤ boundary matrices, SNF-based homology — S¹: H₁=ℤ,
  D²: contractible, verified); `circle_cubical`, `disk_cubical`, `interval_complex` standard
  spaces; `CubicalFiltration` + `bitmap_to_cubical_filtration` (lower-star filtration from a
  2-D pixel array with f(face) ≤ f(coface) guaranteed); `persistence_pairs_cubical` +
  `persistent_homology_bitmap` via the shared Twist+Clearing kernel — 3×3 annular image
  correctly yields H₁ bar [0, 1). 74 new tests.
- **Phase 1/2 correctness fixes** (current):
  - **5 HIGH fixes**: `is_hausdorff` certificate bypass; `_close_under_unions` deduplication
    (constructions.py → imports from representations.py); `_provable_true_props` recursion guard
    (depth limit 100); `_product_pi1` bare `except Exception` removed; Mayer–Vietoris
    `_check_exact_at_middle` torsion-aware composition (`val % d == 0` for torsion generators).
  - **15 MEDIUM fixes**: `OrderTopologySpace` midpoint formula (`(lo+hi)/2`); `AlexandroffSpace`
    union-find refactored to `_order_graph_component_count()`; `SorgenfreyLineSpace` counterexample
    in certificate; `QuotientSpace.contains` raises `NotImplementedError`; `DiscreteCountableSpace`
    Urysohn support (discrete metric); `_bfs_urysohn` dead-code path fixed; `homology_coefficients`
    prime modulus validation; `relative_homology` double boundary matrix computation; `_induced_on_hk`
    zero-row shape for empty target; `mayer_vietoris` off-by-one boundary (max_dim+2→max_dim+1);
    `CohomologyRing.verify_graded_commutativity()` added; torus `group_type` corrected to
    `"free_abelian_rank_2"`; `cw_complex_pi1` disconnected 1-skeleton guard; cubical OOM warnings.
- **Performance optimizations** (current):
  - `_snf_ext(compute_transforms=False)` — skips all row/column transform matrix updates when only
    the diagonal D is needed; `_mat_rank` now uses this path (~80% inner-loop saving for rank queries).
  - `_twist_reduce` bigint bitmask — `list[set[int]]` → `list[int]` Python bigint column
    representation; pivot detection via `col.bit_length()-1` (C-level intrinsic); **~6.6× kernel
    speedup** applied to both `persistent_homology_optimized` and `cubical_homology`.
- **Phase 3 P3.1 — Knot/Link suite** (`feat/phase3-knot-suite`):
  - `seifert.py`: `seifert_circles`, `seifert_genus_bound`, `seifert_matrix`, `signature`
    (Sylvester LDLT, no numpy); unknot=0, trefoil=1, figure-8=1 verified.
  - `knot_invariants.py` extended: `LinkDiagram`, `linking_number`, `linking_matrix`;
    Hopf link linking number ±1 verified.
  - **HOMFLY-PT** (`homfly.py` + `Laurent2`): `homfly_polynomial(braid_word, n_strands)`
    computes the 2-variable invariant `P(a, z)` from a braid closure via skein recursion
    `a·P(L₊) − a⁻¹·P(L₋) = z·P(L₀)`. Termination is guaranteed by a descending-defect
    measure (under-first crossings → 0 ⇒ unlink). Verified against known values (unknot,
    unlinks, Hopf, trefoil −a⁻⁴+2a⁻²+a⁻²z², figure-8 a²−1+a⁻²−z²) and certified a genuine
    invariant via Markov-stabilisation (±) and conjugation invariance. `Laurent2.to_jones()`
    (a=t⁻¹) and `.to_alexander()` (a=1) reproduce pytop's existing Jones/Alexander exactly.
  - **Multivariable Alexander** (`multivariable_alexander.py`): `multivariable_alexander(link)`
    computes `Δ_L(t₁, …, tₙ)` from a `LinkDiagram` via a Wirtinger presentation (arcs +
    intrinsic orientation by component tracing) and Fox calculus over the n-variable Laurent
    ring, then the `(c−1)`-minor determinant `÷ (t_γ − 1)` for links. Verified: knots reproduce
    the braid Alexander (trefoil 1−t+t², figure-8 1−3t+t²); Hopf → 1; `(2,2k)` torus links →
    `Σ(t₁t₂)ⁱ` satisfying the Torres condition `Δ(t₁,1)=(t₁ᵏ−1)/(t₁−1)` and interchange
    symmetry; split links → 0.
- **Phase 3 P3.2 — 3-manifold basics** (`feat/phase3-knot-suite`, in progress):
  - **Dehn surgery → H₁** (`dehn_surgery.py`): `first_homology_of_surgery(coefficients,
    linking_numbers)` computes `H₁(M)` of rational/integral surgery on a framed link as the
    cokernel of `A_{ii}=pᵢ, A_{ij}=qᵢ·lk(Lᵢ,Lⱼ)` via Smith normal form;
    `first_homology_of_link_surgery(link, coefficients)` reads the linking numbers from a
    `LinkDiagram`. `lens_space_first_homology(p, q)` plus exact lens-space homeomorphism
    (`q'≡±q^±¹ mod p`) and homotopy-equivalence (`qq'≡±n² mod p`) classification. Verified:
    lens spaces ℤ/p, S¹×S² (0-surgery), T³ (0-surgery on Borromean rings), the Poincaré
    homology sphere (E₈ plumbing), and L(7,1)≃L(7,2) (homotopy-equivalent yet not homeomorphic).
- **Phase 3 P3.3 — Khovanov homology** (`feat/phase3-knot-suite`, in progress):
  - **Khovanov homology** (`khovanov.py`): `khovanov_homology(diagram)` builds the cube of
    resolutions from a PD code, the Frobenius algebra `V = ℤ⟨1,X⟩` (with `m`/`Δ` and the
    Khovanov sign), and reduces each quantum grading over ℤ by Smith normal form to give the
    bigraded `Kh^{i,j}` with **free ranks and torsion**. Verified: `d²=0`; the integral groups
    of the unknot, trefoil (ℤ/2 at (−2,−7)), figure-8 (ℤ/2 at (−1,−3),(2,3)) and Hopf link;
    and the graded Euler characteristic = unnormalised Jones (cross-checked against
    `jones_polynomial`).
- **Phase 4 P4.1 — property-based + cross-engine differential testing**
  (`tests/core/test_property_invariants.py`): seeded, reproducible checks of mathematical
  invariants and engine consistency over many random inputs — Euler–Poincaré, rational Betti =
  integral free rank, `b_i(ℤ/p) ≥ b_i(ℚ)`, HOMFLY-PT Markov(±)/conjugation invariance, HOMFLY-PT
  `a=1` = Burau Alexander (two independent engines), Dehn-surgery `|H₁| = |det|` (vs an independent
  Bareiss determinant), and lens-space homeomorphic ⇒ homotopy-equivalent.
- **Phase 4 P4.2 — exact integer linear algebra core** (`exact_linalg.py`): consolidates
  `smith_normal_form`, `integer_rank`, `integer_determinant` (fraction-free Bareiss), and
  `cokernel` → `AbelianGroup` behind one public, tested module. The Bareiss determinant and the
  Smith invariant factors cross-check each other (`det = ±∏ dᵢ` at full rank); `dehn_surgery`
  shares this core (DRY).
- **Phase 4 P4.3 — complexity discipline** (`docs/COMPLEXITY.md`): an honest reference of the
  asymptotic cost and *practical input limits* of every computational engine, plus `Complexity`
  notes on the heavy docstrings — stating plainly where exactness costs exponential time.
- **Phase 4 P4.4 — differential testing against independent oracles**
  (`tests/core/test_external_oracles.py`): pins `exact_linalg` against **sympy** (SNF/det/rank),
  `is_planar` against **networkx** (Boyer–Myrvold), and `signature` against **numpy** eigenvalues —
  truly independent implementations. Test-only (`pip install -e .[oracles]`); the runtime stays
  dependency-free and each block skips when its oracle is absent.
- **Phase 4 P4.5 / P4.6 — GUDHI & python-flint**: pytop's Vietoris–Rips persistence is validated
  against **GUDHI** (the gold-standard TDA library) and `exact_linalg` against **python-flint**; and
  with the optional `[fast]` extra, the integer Smith normal form — hence every homology / Khovanov /
  surgery engine built on it — is routed to **FLINT**, which is **~5–8× faster** even on pytop's
  *sparse* boundary/Khovanov matrices (identical results). The pure-Python core stays the default and
  the only hard requirement (`dependencies = []`).
- **Phase 4 P4.7 — SageMath oracle** (`tests/core/test_sage_oracle.py`, opt-in `PYTOP_SAGE_ORACLE=1`,
  Docker): one batched `sagemath/sagemath` run validates pytop's Alexander/Jones polynomials against
  Sage's independent algorithms and its van Kampen abelianisations against **GAP** (Klein ℤ⊕ℤ/2,
  torus ℤ², ℝP² ℤ/2, wedge ℤ³).
- **Phase 4 P4.8 — SnapPy oracle** (`tests/core/test_snappy_oracle.py`, opt-in
  `PYTOP_SNAPPY_ORACLE=1`, Docker): SnapPy is the gold-standard 3-manifold software and the one
  independent oracle for `dehn_surgery` — a batched run of a local `pytop-snappy` image validates
  `first_homology_of_surgery` against SnapPy's Dehn-filling homology (figure-8 knot surgeries → ℤ/p,
  Whitehead-link surgeries → ℤ/a ⊕ ℤ/b).
- **9 959 tests passing** across the core suite when released (+ 16 opt-in SageMath/SnapPy-oracle tests).

## What's New in v0.6.0

- **Constructive computational core** — invariants computed from raw input, not looked up:
  `homology` (integer boundary matrices → Smith normal form → Betti + torsion; S², T² = ℤ²,
  ℝP² = ℤ/2 verified), `persistent_homology` (Vietoris–Rips filtration → Z/2 reduction → barcodes),
  `knot_invariants` (Kauffman → Jones, reduced Burau → Alexander), `winding_number`,
  `surface_word_classification` (closed-surface type from a gluing word), and exact `graph_planarity`
  (rotation-system genus)
- **pi-Base deductive inference** (`pytop.experimental.pi_base` / `pi_base_atlas`) — a real
  property-inference engine over the pi-Base database (243 properties, 902 implication theorems,
  222 spaces, 2099 traits; CC BY 4.0, Clontz & Dabbs): `deduce` closes a trait set under the
  implication graph and detects contradictions, and `find_counterexamples(has=…, lacks=…)` searches
  the atlas. A cross-validation suite pins pytop's hand-encoded implications against the pi-Base graph
- **9 032 tests passing**; new modules at ≥ 90% coverage; dependency-free at runtime
- **`named_spaces` + `space_catalog`** — 104 canonical named topological spaces (Sierpiński space,
  Cantor set, Hilbert cube, Sorgenfrey line, p-adic numbers, lens spaces, solenoid, …) with a
  queryable `SpaceCatalog` registry; `from pytop import catalog` gives instant lookup by name or
  property
- **User guide enrichment pilot (ch04 + ch06)** — guided proofs, "Ne oldu?" example walkthroughs,
  trace tables, 8 TikZ figures (→ PNG), 4 pedagogical tcolorbox environments, exercise hints,
  and a complete solutions appendix across all 4 formats
- **Maarif pedagogy blocks — all 16 chapters × 3 formats** — every chapter now opens with
  5 pedagogical blockquotes (Neden/Keşif/Hata/Bkz./Öz-yansıtma) in Markdown, Python, and
  Jupyter Notebook formats; chapter-specific content guides motivation, common mistakes, and
  cross-references
- **User guide API hygiene** — ch10 raw `frozenset()`/`set()` patterns replaced with `make_set`/
  `empty_set`; ch03 extended with `compose_relations`, `equivalence_class`,
  `partition_from_equivalence`, and `total_order_from_list` examples across all 3 formats

## What's New in v0.5.33

- **`topological_field_theory`** — Atiyah-Segal axioms, cobordism hypothesis, Frobenius algebras, Chern-Simons, Donaldson, factorization algebras (196 tests)
- **`higher_categories`** — quasi-categories, Kan complexes, complete Segal spaces, stable ∞-categories, ∞-toposes (200 tests)
- **`spectral_sequences`** — Serre, Adams, AHSS, Leray-Hirsch, LHS, Grothendieck (170 tests)
- **`operads`** — Ass/Com/Lie/A∞/L∞/E_n, Koszul duality, bar-cobar (170 tests)
- **User guide** — 16-chapter guide in 4 formats, 73-page compiled PDF
- **8 914 tests passing**, 98.74% coverage

See [CHANGELOG.md](CHANGELOG.md) for full details.

## Formal Verification (`formal/`)

The `formal/` directory contains **Lean 4 + Mathlib v4.31** machine-checked proofs
for the core algorithms and topological foundations.  
Build: `cd formal && lake build`

### Verified paths

| File | Content | Sorry |
|------|---------|-------|
| `SNF/` | Smith Normal Form correctness — clearPass residues, pivot positivity, fuel-independence, divisibility chain, all 5 branch theorems | **0** |
| `Homology.lean` | Boundary operator ∂∘∂=0, Euler–Poincaré theorem via alternating-sum telescope | 0 |
| `EulerChar.lean` | Euler characteristic = alternating Betti sum | 0 |
| `PersHomology.lean` | Z/2 persistence reduction, `symmDiff_comm/self/assoc`, `reduce_is_reduced` (fuel-based `reduceColFuel` + `reduceInv_step` invariant), `pairs_have_distinct_deaths`, `pairs_birth_lt_death` | **0** |
| `PiBase.lean` | Pi-Base implication graph load & traversal | 0 |
| `SetTopology.lean` | Open-set axioms, closure/interior/boundary, Kuratowski, subspace & product topologies, homeomorphism, T₃/T₄ chain, `compact_union`, `compact_closed_subset`, Urysohn lemma | **0** |
| `MetricTopology.lean` | Metric space, open balls, ε-δ ↔ topological continuity, Cauchy sequences, completeness, `fixedPoint_unique`, Banach fixed-point theorem | **0** |
| `MayerVietoris.lean` _(Phase 11)_ | `SES` structure; `ses_p_zero_of_im`; `delta_well_defined`; `snake_delta_exists`; `snake_delta_independent` | **0** |
| `VanKampen.lean` _(Phase 11)_ | `Pres` + `TietzeEquiv`; `tietze_elim/add_gen`; `AmalgamDatum` + `Pushout`; `pushout_universal`; `int_hom_determined_by_one`; `int_hom_exists` | **0** |
| `CohomologyRing.lean` _(Phase 11)_ | Alexander–Whitney `cup` (`⌣`); `cup_value_assoc`; `cup_comm_Z2`; `coboundary0`; `leibniz_0cochains` | **0** |
| `PersistencePairing.lean` _(Phase 11)_ | `pairing_is_perfect`; `pairs_have_distinct_births`; lemma chain via `isReduced_tail` + `filterMap_getLast_nodup_of_isReduced` + `List.mem_iff_getElem` | **0** |
| `SpectralSequences.lean` _(Phase 11)_ | `ChainCx` (d²=0); `d_sq_zero`; `image_sub_kernel`; `SpectralSeq`; `const_convergent`; `stabilizes_mono`; `const_pages_convergent` | **0** |

### Key theorems (selected)

```lean
-- Smith Normal Form
theorem pytopSNF_positive      : ∀ i, 0 ≤ (pytopSNF M).diag i
theorem pytopSNF_fuel_independent : pytopSNF M = pytopSNF' M   -- fuel doesn't matter
theorem pytopSNF_divisibilityChain : isDivisibilityChain (pytopSNF M).diag

-- Set topology
theorem t4_implies_t3 (τ : Topology α) : isT4 τ → isT3 τ
theorem t3_implies_t2 (τ : Topology α) : isT3 τ → isT2 τ
theorem compact_union  (τ : Topology α) : isCompact τ K₁ → isCompact τ K₂ → isCompact τ (K₁ ∪ K₂)
theorem compact_closed_subset (τ : Topology α) : isCompact τ K → A ⊆ K → isClosed τ A → isCompact τ A

-- Metric topology
theorem openBall_isOpen   (M : MetricSpace α) : (metricTopology M).isOpen (openBall M x r)
theorem epsDelta_implies_topoCont : epsilonDeltaContinuous M N f x₀ → topological continuity at x₀
theorem topoCont_implies_epsDelta : topological continuity at x₀ → epsilonDeltaContinuous M N f x₀
theorem convergent_is_cauchy      : convergesTo M seq L → isCauchy M seq
theorem limit_unique              : convergesTo M seq L₁ → convergesTo M seq L₂ → L₁ = L₂
theorem fixedPoint_unique         : isContraction M f → f p = p → f q = q → p = q

-- Persistence homology (PersHomology.lean)
theorem symmDiff_assoc            : symmDiff (symmDiff a b) c = symmDiff a (symmDiff b c)
theorem reduce_is_reduced          : isReduced (reduce M)  -- fuel-based termination proof
theorem pairs_have_distinct_deaths : ((persistencePairs M).map Prod.snd).Nodup
theorem pairs_birth_lt_death       : (∀ jcol ∈ zipWith … (reduce M), ∀ x ∈ jcol.2, x < jcol.1)
                                     → ∀ p ∈ persistencePairs M, p.1 < p.2
```

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md).

## License

MIT — see [LICENSE](LICENSE).
