Repository navigation
Adopt the Python array API standard for backend dispatch and array typing #45
Copy link
Copy link
Open
Labels
refactorCodebase refactoringCodebase refactoring
Description
🤖 AI text below 🤖
Summary
Adopt the Python array API standard through array-api-compat. The array backend would then be inferred from the arrays themselves (array_namespace(x)) instead of being passed around as xp, and "an array of the current backend" would get an honest type, replacing today's loose use of numpy.typing.NDArray.
Current state
- The algorithms receive the array module as an
xpargument and callxp.asarray,xp.linalg.qr,xp.emptyand so on directly. This keeps the CPU (NumPy) and GPU (CuPy) paths in sync, butxphas to be threaded through every function. - Arrays of either backend are annotated as
numpy.typing.NDArray. For CuPy arrays that's incorrect. It goes unnoticed only because CuPy ships no type stubs, so the type checker seesAny. - Backend-specific features (CUDA streams and events, page-locked memory, CuPy's memory pool, the NCCL communicator planned for the multi-GPU work in feat(sweep): ✨ split the SRC sweep among the GPUs of a node #44) already live behind
src_method.utils._backend.
Proposal
- Namespace from the arrays. Use
array_api_compat.array_namespace(*arrays)in library code instead of anxpparameter, wherever the arrays are at hand. The publicdevice=argument stays; it only chooses where inputs are placed. - One array type. Introduce a single alias for arrays of the current backend, based on an array API typing protocol or a documented
Arrayalias, and use it everywhereNDArrayis used today. - Standard names where they exist. Move array creation,
linalg.qr/linalg.svd,conj, reshaping, transposition andasarrayto the standard API. - Keep what the standard doesn't cover behind
_backend.py: streams and events, pinned memory, the memory-pool cap and queries, and the host-side random draws, which stay on NumPy'sdefault_rngso a seed gives the same draws on every device. - Host transfers. Use
from_dlpackfor zero-copy exchange where it applies.to_numpystays as the single device-to-host transfer.
Benefits
- Fewer parameters, and backend dispatch that follows the data.
- Types that are correct for CuPy, and useful once a stricter type checker is in place (see Adopt ty as type checker #28).
- A route to further backends (PyTorch, JAX, Dask) at little extra cost, as far as
opt_einsumand the linear algebra allow.
Open questions and risks
opt_einsumalready dispatches on the operand types. Check that it accepts the arraysarray-api-compatwraps or returns, without an extra copy.truncated_qrdoes part of its work on the host (the SVD ofR). Keep that explicit.- Performance must not regress: the per-operation overhead of the compatibility layer should be negligible next to the contractions. Measure with
tests/test_stack.py::test_benchmark_src_stack_depth3andtests/test_package.py::test_benchmark_src_mpo_mpo. - Scheduling: land after the out-of-core (feat(sweep): ✨ out-of-core SRC sweep on one GPU #42) and multi-GPU (feat(sweep): ✨ split the SRC sweep among the GPUs of a node #44) work, so the refactor doesn't collide with them.
Acceptance
- No
xpparameters left in the algorithm modules, apart from the_backend.pyseam. - One array alias used consistently; no
numpy.typing.NDArrayon backend-generic arrays. uv run prek run --all-filesanduv run pytest, including the GPU tests on a GPU machine, pass; the benchmarks above within noise.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
refactorCodebase refactoringCodebase refactoring
Activity