Build, test and document¶
Run from the repository root with CPython 3.12.x and a C++20 compiler. Install the local test tools before using Make:
python3.12 -m venv .venv
.venv/bin/python -m pip install --cache-dir .cache/pip -r requirements/test.lock
make test
make test PRESET=cpu-openmp
make gtest PRESET=cpu-asan
make lint
make typecheck
make test-native
make demo
make test runs GoogleTest and pytest through CTest. make gtest and
make pytest select their respective layers. The sanitizer preset runs
native address and undefined-behavior checks. Python tests live under
tests/python/; examples live under examples/. make lint checks Python lint
and formatting plus C++ formatting. Build directories are isolated by preset
under build/. JOBS controls build parallelism; PYTHON, BUILD_DIR
and CMAKE_ARGS allow local toolchain overrides.
make typecheck checks representative public CPU and CUDA calls with the
pinned mypy development tool. It copies the staged package into an isolated
consumer directory, verifies that importing the CUDA façade does not load the
optional extension, and checks return types and rejected API usage. No GPU or
Torch/CuPy installation is needed. The checks live under tests/typing/;
the benchmark package is outside their scope.
make test-native builds the selected preset with Python and internal tests
disabled in build/<preset>-native. It installs the development component,
moves the installation prefix, and configures an independent C++ consumer
outside the checkout. The consumer checks dense/CSR CG and PCG, reusable
workspaces, true residuals and basic operation counts. Native, OpenMP and BLAS
CI configurations run these checks. Consumer compile settings are checked for
leaked library-only macros, OpenMP flags and CUDA SDK include directories.
Small syntax-only probes verify the installed SolveInfo discard diagnostic
and accepted explicit-discard/status-use forms. Only these probe commands use
-Werror; project and imported-target warning settings remain unchanged.
CUDA CI also compiles/links the optional consumer and reports device-dependent
skips; the GPU job uses
NATIVE_ARGS=--require-cuda. NATIVE_BUILD_DIR overrides its build path.
See Installation for direct CMake commands and imported targets.
No command above upgrades system packages, installs with pip --user, or
changes shell configuration. CMake downloads pinned GoogleTest into its local
build dependency directory. The optional BLAS dependency also belongs in the
project’s local dependency directory.
Optional dense BLAS¶
The BLAS kernel replaces dense matrix-vector products. Vector updates and
reductions retain the selected fused/separate CPU policy. dense_kernel is
independent of algorithm, fused and Jacobi preconditioning. The first
implementation accepts only num_threads=1; native OpenMP remains available
for multiple threads. CSR operators require dense_kernel="native".
Build the optional mode explicitly:
make test PRESET=cpu-blas
make docs PRESET=cpu-blas
make doctest PRESET=cpu-blas
The Linux native build needs GNU or LLVM nm and objcopy in the
existing toolchain. CMake downloads pinned OpenBLAS 0.3.30 and builds a private
sequential LP64 double-precision BLAS provider under build/_deps. It needs
no Fortran compiler or LAPACK build. Initial dependency downloads require
network access. Wheel builds statically include the provider and use private
symbol names, so installed wheels do not depend on that source/build directory.
On x86-64, a BLAS-enabled binary or wheel requires a CPU supporting SSE3 and SSSE3 (the CORE2 kernel baseline). The provider dispatches between CORE2 and Haswell kernels on supported CPUs. This requirement applies to the entire BLAS-enabled extension, including import; selecting the native kernel does not remove it. Other Linux architectures use the provider’s native build target and require a compatible CPU when relocating the wheel. These wheels are local platform builds; no manylinux portability is claimed.
Inspect cgpy.blas_enabled() and cgpy.build_info() in the process that
will run the solve. See Python API for the runtime contract.
>>> A = np.array([[4.0, 1.0], [1.0, 3.0]])
>>> b = np.array([1.0, 2.0])
>>> result = cgpy.solve(A, b, dense_kernel="blas", num_threads=1)
>>> result.converged
True
>>> np.testing.assert_allclose(result.x, [1 / 11, 7 / 11])
A native-only build rejects the unavailable choice explicitly:
>>> try:
... cgpy.solve(np.eye(2), np.ones(2), dense_kernel="blas")
... except ValueError:
... rejected = True
... else:
... rejected = False
>>> rejected
True
Wheel and source distributions¶
make wheel
make sdist
make dist
.venv/bin/python -m pip wheel --cache-dir .cache/pip --wheel-dir build/sdist-wheel dist/cgpy-*.tar.gz
make test-dist DIST_BLAS=OFF DIST_DIR=dist/native
make test-dist DIST_BLAS=ON DIST_DIR=dist/blas
make wheel builds a wheel with isolated backend dependencies, make
sdist builds a source distribution, and make dist builds both through
the source-distribution path. The pip command builds an sdist with isolation.
make test-dist additionally installs that wheel into a separate temporary
environment outside the source tree and checks dense/CSR APIs, native
imports and public types against that installed environment. Both native
stubs and the py.typed marker must survive the sdist-to-wheel path. The
type checker runs in the development environment; it is not a runtime
dependency of the installed wheel.
Native and BLAS wheels have the same package version and wheel tag;
use separate output directories to retain both artifacts. Runtime-only
CPU installs need NumPy; Python 3.12 is required for every package mode.
CUDA builds use PRESET=cuda-release and DIST_CUDA=ON explicitly, with
their own compatible local toolkit and runtime dependencies. See CUDA
for complete commands and architecture/host-compiler overrides. CPU wheels
retain CG_ENABLE_CUDA=OFF. Distribution checks require CUDA sources in the
sdist, inspect installed ELF dependencies/RPATH, and execute GPU smoke solves
when a usable device exists; GPUless installation checks report that skip.
Sphinx documentation¶
.venv/bin/python -m pip install --cache-dir .cache/pip -r requirements/docs.lock
make docs
make doctest
The HTML entry point is build/docs/html/index.html. The doctest builder
executes native dense, CSR and prepared-solver examples; a BLAS build also
executes the BLAS example above. Availability-specific groups use explicit
runtime skip conditions; native-only builds test unavailable-mode rejection.
Both builders treat warnings as
errors. Autodoc imports the selected real extension through the same
PYTHONPATH as the other Make targets, and Napoleon renders NumPy-style
docstrings. No imports are mocked. Once dependencies and the extension are
available, Sphinx requires no network access: the configuration uses no remote
theme assets or intersphinx inventories.
GitHub Pages publishes the HTML built from main at
the documentation site.
The Documentation workflow builds the real CPU extension, checks Sphinx
warnings and executes doctests on every pull request. After a merge to
main, it uploads the HTML and deploys it to the github-pages
environment. The repository’s Pages source is GitHub Actions; generated HTML
stays out of Git. BLAS and CUDA documentation examples are additionally
checked in their respective solver CI jobs.
Python version and dependency policy¶
Python support is intentionally limited to CPython 3.12.x. CI varies the
execution/build configuration rather than testing unrelated interpreter
versions. Use a current 3.12 patch release. Native-only builds use
CG_BUILD_PYTHON=OFF and have no Python requirement.
The requirement files are explicit pinned pip inputs, maintained by review; there is no automatic lock generator. See dependency maintenance for clean-environment installation and update checks.