Python Interface¶
The Python interface provides thin bindings to the hypredrive C library. It accepts solver options as Python dictionaries, YAML strings, or YAML files; assembles sparse matrices from CSR data or SciPy CSR matrices; runs the solve lifecycle; and returns the local solution as a NumPy array.
The heavy lifting still happens in libHYPREDRV and HYPRE. The Python layer mainly handles input normalization, dtype checks, YAML conversion, and result extraction.
Prerequisites¶
Python 3.9 or newer.
NumPy.
Cython 3.0 or newer when building from source.
An MPI implementation with compiler wrappers available at build time.
mpi4pyfor distributed solves from Python.SciPy when passing
scipy.sparse.csr_matrixobjects directly.
Installation¶
There are three install modes:
GitHub Actions wheel artifacts for quick host-only installs with a compatible MPI runtime;
source installs against an installed or build-tree libHYPREDRV;
in-tree CMake builds for developers and CI.
Source builds keep Python packaging independent from ordinary C builds while still linking against libHYPREDRV.
Source install:
python -m pip install ./interfaces/python
When run from a full hypredrive checkout, this automatically builds and bundles the in-tree HYPREDRV/HYPRE libraries. When run from a standalone source distribution, CMake falls back to finding an installed MPI-enabled HYPREDRV/HYPRE stack. Binary MPI wheels are currently GitHub Actions artifacts, not PyPI or TestPyPI packages.
Against an installed hypredrive:
cmake --install build --prefix $HOME/opt/hypredrive
pip install ./interfaces/python \
--config-settings=cmake.define.HYPREDRV_PYTHON_BUNDLE_CORE=OFF \
--config-settings=cmake.define.CMAKE_PREFIX_PATH=$HOME/opt/hypredrive
Python source distributions are intended for downstream packagers and developer
environments where HYPREDRV and HYPRE are discoverable by CMake. They are not
self-contained PyPI-style source packages for systems without the C library stack.
Against an in-tree development build:
cmake -S . -B build -DBUILD_SHARED_LIBS=ON -DHYPREDRV_ENABLE_TESTING=OFF
cmake --build build --parallel
pip install -e ./interfaces/python \
--config-settings=cmake.define.HYPREDRV_DIR=$PWD/build
The top-level CMake build can also build the Python extension directly:
cmake -S . -B build -DHYPREDRV_ENABLE_PYTHON=ON
cmake --build build --target _core --parallel
This mode is intended for developer and CI builds. It requires Python, NumPy, and Cython
at configure/build time, so HYPREDRV_ENABLE_PYTHON is disabled by default.
Experimental wheel artifacts¶
The project CI can build experimental Python wheel artifacts for Linux and macOS.
These wheels bundle host-only libHYPREDRV and libHYPRE inside the Python
package, but they do not bundle MPI.
On pull requests, the wheel workflow runs only when the PR has the
Run Python Wheels label. It can also be started manually with
workflow_dispatch.
Download a wheel artifact from the GitHub Actions Python Wheels workflow
run first. GitHub stores artifacts as zip files, so unzip the artifact before
installing the wheel into a virtual environment on a machine with a compatible
MPI runtime:
python -m venv .venv
source .venv/bin/activate
unzip hypredrive-wheels-*.zip -d wheelhouse
python -m pip install wheelhouse/hypredrive-*.whl
Wheel artifacts are built by MPI flavor. Use an mpich wheel with an
MPICH-compatible runtime and an openmpi wheel with an OpenMPI-compatible
runtime.
Use a source install instead for custom HYPRE builds, GPU support, BIGINT/MIXEDINT, vendor MPI stacks, or downstream-packager control over shared libraries.
At runtime, the package records how it was built:
import hypredrive as hd
print(hd.BUILD_INFO)
Optional dependencies can be installed through package extras:
pip install ./interfaces/python[mpi]
pip install ./interfaces/python[scipy]
pip install -e ./interfaces/python[test]
mpi4py is optional for package import and serial solves, but it is the
supported MPI boundary for distributed Python use. HypreDrive accepts
mpi4py.MPI.Comm objects and forwards the underlying communicator to the C
library instead of exposing its own Python MPI wrapper.
Quick start¶
One-shot solve¶
import numpy as np
import scipy.sparse as sp
import hypredrive as hd
n = 64
diag_main = 2.0 * np.ones(n)
diag_off = -np.ones(n - 1)
A = sp.diags([diag_off, diag_main, diag_off], [-1, 0, 1], format="csr")
b = np.ones(n)
options = hd.configure(
solver="pcg",
preconditioner="amg",
pcg={"max_iter": 100, "relative_tol": 1.0e-8},
amg={"print_level": 0},
)
result = hd.solve(A, b, options=options)
print("solution norm:", result.solution_norm)
print("first entries:", result.x[:5])
Reusable driver¶
Use HypreDrive when one process needs to solve multiple related systems and reuse the
driver lifecycle.
import hypredrive as hd
with hd.HypreDrive(options="my_config.yaml") as drv:
for step in range(num_steps):
drv.set_matrix_from_csr(build_matrix(step))
drv.set_rhs(build_rhs(step))
drv.solve()
x = drv.get_solution()
Distributed solve with MPI¶
When using mpi4py, each rank provides its local CSR slab. Row bounds are global and
inclusive; column indices are global.
from mpi4py import MPI
import hypredrive as hd
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()
indptr, col_indices, data, rhs, row_start, row_end = build_local_slab(rank, size)
with hd.HypreDrive(options=opts, comm=comm) as drv:
drv.set_matrix_from_csr(
indptr,
col_indices,
data,
row_start=row_start,
row_end=row_end,
)
drv.set_rhs(rhs)
drv.solve()
x_local = drv.get_solution()
CSR input details¶
set_matrix_from_csr accepts either a SciPy CSR matrix or the raw
(indptr, col_indices, data) arrays. With raw arrays, row_start and
row_end are required and describe the inclusive global row range owned by the
rank. indptr has length nrows + 1 where
nrows = row_end - row_start + 1; col_indices contains global column
indices; and all input buffers may be released after the call returns because HYPRE
copies the data during IJ assembly.
Passing a SciPy sparse matrix with no explicit row range means single-rank/full-local
assembly. CSR inputs are used directly; other SciPy sparse formats are converted to
CSR first. Passing a SciPy sparse matrix with row_start and row_end means the
matrix is this rank’s local slab and must have
shape[0] == row_end - row_start + 1.
Empty local row ranges are not currently supported by the CSR/array API; every participating MPI rank must own at least one row.
Configuration input¶
Anywhere options is accepted, pass one of:
Input |
Behavior |
|---|---|
|
Converted to YAML in memory and parsed by hypredrive. |
|
Treated as a YAML document. |
|
File contents are loaded and parsed. |
|
Uses the Python binding’s minimal default YAML. |
The accepted YAML keys and solver/preconditioner options are the same as the CLI; see Input Structure (YAML).
Testing¶
After installing the package in editable mode with test dependencies:
pip install -e ./interfaces/python[test]
python -m pytest interfaces/python/tests/test_solve_serial.py -v
MPI tests must be launched under an MPI process manager:
mpirun -np 2 python -m pytest \
interfaces/python/tests/test_solve_mpi.py \
interfaces/python/tests/laplacian/test_example_mpi.py -v
Tests that require the native extension or mpi4py skip when those optional runtime
components are unavailable.
Current limitations¶
The Python interface currently targets real-valued solves.
Solution data is copied back to host NumPy arrays.
GPU/device execution is not exposed as a Python-native data path.
Result metadata is intentionally small; the one-shot API currently exposes the solution array and solution norm.
Distributed Python solves require
mpi4pyand useComm.py2f()plus the C-sideMPI_Comm_f2cbridge.Python examples live under
interfaces/python/examples.laplacian/laplacian.pyis the MPI-capable 3D example;laplacian/laplacian2d_seq.pyis the serial 2D example;darcy/darcy_mixed.pyis the mixed-form Darcy example.