Code and documentation for computing the discrete modulus of families of objects on graphs. It serves as a reference implementation of the theory, and includes a companion book that introduces the theory and walks through the code.
Currently the code includes a Python library (discrete_modulus, located in
python/) and a specialized C++ library (cpp/)
implementing an exact-arithmetic algorithm for computing spanning tree modulus.
julia/ is a placeholder for a future Julia code. Each is an
independent implementation of the same underlying theory, they aren't intended to interoperate (yet).
lean/ is a Lean 4 project, still early-stage, that will independently
verify certificates of optimality produced from the C++ solver's output, built
on top of lean-modulus.
python/: thediscrete_modulusPython package (python/src/discrete_modulus/: basic algorithm, family operators, NetworkX-based families, demo graphs), managed withuv(python/pyproject.toml+python/uv.lock). Requires Python >= 3.11.python/tests/: thepytestsuite.python/docs/: a standalonemkdocssite that generates the Python API reference from docstrings viamkdocstrings.
book/: the.qmdpages that make up the companion book, built with Quarto.cpp/: thediscrete_modulusC++ library (header-only,cpp/include/discrete_modulus/: exact spanning tree modulus via Cunningham's algorithm), built with CMake and Boost.Graph. Narrower in scope thanpython/so far; seecpp/README.md.cpp/test/: the Catch2 test suite.cpp/docs/: Doxygen config for the API reference.
julia/: not implemented yet; see itsREADME.mdfor intended scope.lean/: a Lean 4 project (DiscreteModulusCert, managed with Lake) that kernel-checks certificates of spanning-tree-modulus optimality without trusting the C++ solver's arithmetic. Depends onlean-modulus(pinned to a specific commit) for its graph/matroid infrastructure. Seedocs/certification/for how this fits together with the C++ solver and the Python certificate builder.docs/certification/: what a certificate is, how the solver/builder/verifier pipeline produces and checks one, and exactly what is (and isn't) trusted, with a worked example..github/workflows/: CI, linting, tests (Python, C++, and Lean), and the book/docs build+deploy (see CI below)..devcontainer/: a devcontainer with Python,uv, the Quarto CLI, and the C++ toolchain (CMake, Boost, Doxygen) preinstalled (see Development environment below).
The package is managed with uv:
cd python
uv syncThis creates a .venv with the library and its runtime dependencies
(numpy, scipy, cvxpy, networkx). There are three more dependency groups for
other tasks, addable individually or together:
cd python
uv sync --group dev --group book --group docsor uv sync --all-groups for everything at once.
-
dev:ruff,mypy,pytest, for linting, type-checking, and testing:cd python uv sync --group dev uv run ruff check src/ tests/ uv run mypy src/ tests/ uv run pytest --cov --cov-report=term-missing -
book: Jupyter, matplotlib,pycddlib, needed to execute the book's code cells.pycddlibbuilds a C extension againstcddlib's headers (Ubuntu/Debian:apt install libcdd-dev): already present in the devcontainer image. See "Building the book" below. -
docs:mkdocs+mkdocstrings, needed to build the Python API reference. See "Building the Python API reference" below.
The .qmd pages in book/ import the library the same way, via
import discrete_modulus, in executable code cells.
The book is built with Quarto: install the Quarto CLI separately (it's not a Python package): see the get-started guide.
Quarto's Python code cells run via Jupyter, against the uv-managed
environment. book/_environment already points Quarto at it
(QUARTO_PYTHON=../python/.venv/bin/python):
cd python
uv sync --group book
cd ../book
quarto renderor, for live-reloading while editing:
cd python
uv sync --group book
cd ../book
quarto previewcd python
uv sync --group docs
cd docs
uv run mkdocs buildor, for live-reloading while editing:
cd python
uv sync --group docs
cd docs
uv run mkdocs servemkdocstrings renders the reference pages directly from docstrings at
build time, driven by the ::: module.path directives in
python/docs/pages/reference/*.md.
The cpp/ library is built with CMake (>= 3.20) and
requires Boost (>= 1.74, the graph component).
On Ubuntu/Debian: apt install cmake libboost-graph-dev (already present
in the devcontainer image).
cmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Release
cmake --build cpp/build
ctest --test-dir cpp/build --output-on-failureWarning
-DCMAKE_BUILD_TYPE=Release is critical. This is a CPU-bound algorithm, and
an unoptimized build is dramatically slower.
See cpp/README.md for more, including running the
spt_mod CLI.
Kept out of the main devcontainer: Mathlib's binary cache alone is several
GB, only needed by contributors actually working on lean/. Run its setup
script once, which installs elan if
needed, then fetches dependencies and Mathlib's cache before building:
lean/setup.shSubsequent builds:
cd lean
lake buildRequires Doxygen (and, optionally, Graphviz for diagrams):
cd cpp/docs
doxygen Doxyfilegenerates cpp/docs/_site/html/.
The included devcontainer (.devcontainer/) has Python, uv, the Quarto
CLI, libcdd-dev, and the C++ toolchain (CMake, Boost, Doxygen, Graphviz)
preinstalled, and runs uv sync --all-groups on create: opening the repo
in it (VS Code's Dev Containers extension, or a Codespace) is enough to
lint, test, and build the book, the Python API docs, and the C++ library
immediately. The Lean toolchain is deliberately left out (see "Building the
Lean verifier" above): run lean/setup.sh once if you need it.
lint.yml:ruff check,ruff format --check,mypy, on changes underpython/.test.yml:pytestacross a Python version matrix, on changes underpython/.cpp-test.yml: configures, builds, and runs the Catch2 test suite forcpp/, on changes undercpp/.lean-test.yml: installselan, fetches Mathlib's cache, and runslake buildforlean/, on changes underlean/.book.yml: builds the book, the Python API reference, and the C++ API reference as independent jobs, then assembles them into one site (book at the root, API references underreference/python/andreference/cpp/) and publishes it to thegh-pagesbranch, on push tomain. Structured so that adding a Julia docs build later only means adding one more build job and one more assembly step.
BSD 3-Clause. See LICENSE for details.
Nathan Albin and Pietro Poggi-Corradini