Python bindings for the ext crate (Ext over the Steenrod algebra)
Project description
sseq_ext — Python bindings for ext
This crate exposes a minimal Python API over ext, the Rust library
for computing Ext over the Steenrod algebra.
The current scope mirrors a representative handful of the ext/examples/*.rs
example binaries; see examples/ for the corresponding Python translations:
| Rust example | Python translation |
|---|---|
ext/examples/algebra_dim.rs |
examples/algebra_dim.py |
ext/examples/resolve.rs |
examples/resolve.py |
ext/examples/resolve_through_stem.rs |
examples/resolve_through_stem.py |
ext/examples/num_gens.rs |
examples/num_gens.py |
ext/examples/resolution_size.rs |
examples/resolution_size.py |
ext/examples/differentials.rs |
examples/differentials.py |
ext/examples/filtration_one.rs |
examples/filtration_one.py |
ext/examples/chart.rs |
examples/chart.py |
ext/examples/secondary.rs |
examples/secondary.py |
ext/examples/massey.rs |
examples/massey.py |
Other examples (steenrod.rs, sq0.rs, mahowald_invariant.rs,
bruner.rs, define_module.rs, secondary_massey.rs, …) define their own
chain complexes inline or use APIs not yet bound. Adding them is a
straightforward extension of the existing scaffolding.
Install
This crate is built with maturin. It produces an
abi3 extension compatible with CPython >= 3.10. Using
uv:
cd python_ext
uv sync # creates a .venv with maturin and pytest, builds the extension
After that you can run the example translations:
uv run python examples/resolve.py S_2 30 15
uv run python examples/num_gens.py S_2 30 7
uv run python examples/chart.py S_2 30 7 --out chart.svg
uv run python examples/secondary.py S_2 30 7
uv run python examples/massey.py S_2 20 10 # interactive
To rebuild after editing the Rust sources:
uv run maturin develop --release
To run the tests:
uv run pytest
WebAssembly / Pyodide build
The crate can also be cross-compiled to a WebAssembly wheel that loads in
Pyodide (CPython in the browser). This produces a
wasm32-unknown-emscripten abi3 extension module.
Unlike the native build, the wasm build drops the concurrent (rayon/threads)
feature — default Pyodide has no threads — and the dev-only test-hooks
feature.
Requirements
- The emscripten SDK at the exact version the target Pyodide release was built with. Mismatched versions produce a wheel that fails to load.
pyodide-build(installed into the venv) and the matching Pyodide cross-build environment.
The versions are pinned in build-pyodide.sh:
| Pyodide | CPython | Emscripten |
|---|---|---|
314.0.0 |
3.14.2 | 5.0.3 |
Build
uv pip install pyodide-build # one-time, into the .venv
source .venv/bin/activate
./build-pyodide.sh
The script clones/activates a local emscripten SDK under .emsdk/
(gitignored), installs the Pyodide cross-build environment, and runs
pyodide build. The resulting wheel lands in dist/:
dist/sseq_ext-0.1.0-cp310-abi3-emscripten_5_0_3_wasm32.whl
To build manually, the key steps are:
source .emsdk/emsdk_env.sh
pyodide xbuildenv install 314.0.0
MATURIN_PEP517_ARGS="--no-default-features --features pyo3/extension-module" \
pyodide build
Loading in Pyodide
The wheel can be installed with micropip (e.g. serve it over HTTP):
import micropip
await micropip.install("https://.../sseq_ext-0.1.0-cp310-abi3-emscripten_5_0_3_wasm32.whl")
import sseq_ext
The test suite covers:
tests/test_examples.py— end-to-end smoke tests for each of the example scripts (with exact-output assertions where the computation is small and deterministic).tests/test_views.py— basic correctness of theFpVectorview system (slicing, owned/view/view-mut transitions, composition).tests/test_coordinates.py—Bidegree/BidegreeGenerator/BidegreeElementbehaviour.tests/test_api_fixes.py— negative indexing, getter consistency (prime/name), typed exceptions in place of panics, and coverage of theSubspaceand coordinate types.tests/test_view_safety.py— exhaustive safety tests:- Slice arithmetic & out-of-bounds handling (including out-of-range and
reversed
AugmentedMatrixsegment keys, and 3-segment matrices). - Read-only enforcement (writes through a
Viewraise). - Lifetime / GC (parent kept alive by view; cleaned up when both go).
- Mutation visibility between parent and view.
- Aliasing semantics for overlapping
ViewMuts. - Re-entrancy: a Rust-side test hook (gated behind the
test-hookscargo feature, on by default for dev builds) holdsborrow_muton aMatrixand tries to write through a view; the runtime borrow check fires withBufferError. These tests are skipped if the extension was built without the feature. - Random-op stress tests for owned vectors, matrix row views, and overlapping slices, cross-checked against a Python-side snapshot.
- Slice arithmetic & out-of-bounds handling (including out-of-range and
reversed
Release wheels can exclude the test-only hooks by building with
--no-default-features --features pyo3/extension-module.
Design notes
Scope
- The interactive
querycrate is not bound. Examples use Python idioms (sys.argv,argparse,input()) instead. - Built with the default
odd-primesfeature. The native build also enablesconcurrent(rayon threads) by default; it is exposed as asseq_extcargo feature so it can be dropped for the threadless WebAssembly/Pyodide build (--no-default-features). Thenassaufeature is not enabled, soQueryModuleResolutionisResolution<CCC>. - We only bind the concrete instantiations needed by
ext::utils::construct, i.e.Resolution<CCC>(for stable resolutions) and the matchingResolutionHomomorphism,ChainHomotopy,SecondaryResolution. Generic instantiations over other chain complexes are not exposed. - All long-lived Rust objects (resolutions, modules, homomorphisms) are
wrapped in
Arc<…>and exposed as opaque Python handles. Mutable resources (matrices, vectors) are wrapped in plainpyclassobjects with pyo3's borrow tracking.
FpVector views
FpVector is a tagged union of three internal modes:
Owned— wraps an actualfp::vector::FpVector.View— a read-only borrow into another object's storage.ViewMut— a mutable borrow.
The user-facing API uses .const / .mut accessors and standard Python
indexing:
| What you write | What you get |
|---|---|
v.const |
read-only view of the whole vector |
v.mut |
mutable view of the whole vector |
v.const[a:b], v.mut[a:b] |
read-only / mutable sub-view |
view[a:b] |
sub-view (mutability inherited) |
view[i] |
int entry (read; writes via view[i] = …) |
m.const[row], m.mut[row] |
row view of a Matrix |
am.const[row, seg] |
segment view of an AugmentedMatrix |
am.mut[row, (start_seg, end_seg)] |
range of segments |
am.segment_const[seg] |
matrix-like read-only view of one segment |
am.segment_mut[seg] |
matrix-like mutable view of one segment |
am.segment_mut[seg].add_identity() |
write identity into a (square) segment |
Slicing on a bare owned FpVector raises with a hint to use
.const / .mut. This avoids the ambiguity of whether v[a:b] should
yield a read-only or mutable view.
Views hold a reference-counted handle (Py<…>) to the parent so the parent
remains alive. Each operation on the view re-derives the underlying slice
transiently from the parent under a runtime borrow check (pyo3's
try_borrow / try_borrow_mut). If the parent is currently borrowed
elsewhere — e.g. you're in the middle of a method that takes &mut self
on the parent — the view operation raises BufferError.
This lets you write code like
hom.act(matrix.mut[idx, 0], v, gen)
which directly mirrors the Rust idiom
hom.act(matrix.row_mut(idx).slice_mut(start, end), v, gen)
without exposing raw FpSliceMut<'_> lifetimes to Python.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sseq_ext-0.1.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl.
File metadata
- Download URL: sseq_ext-0.1.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl
- Upload date:
- Size: 6.5 MB
- Tags: CPython 3.14, PyEmscripten 2026.0 wasm32
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95191aed7afeca0d5bc6c163e907feff57bd14de467ad11a726ea690fe6de6f4
|
|
| MD5 |
9513726edf4478e35d0d06e473b95b2b
|
|
| BLAKE2b-256 |
2634aafd1a214645b489bdcac82dbf10266a52fe02362d5ec5ab83fe6f39a308
|