Skip to main content

Differentiable eigenvalue decomposition with JAX (CPU/GPU)

Project description

Differentiable Generalized Eigenvalue Decomposition

Tests

Eigh Logo

Standalone implementation of differentiable eigenvalue decomposition with CPU (LAPACK) and GPU (cuSOLVER) backends. Extracted from pyscfad.

CPU and GPU wheels on PyPI for Linux and macOS (Apple Silicon), Python 3.10–3.13, JAX 0.5–0.10+. See Installation and Compatibility.

New

  • Core code rewritten to be able to run on older cluster with JAX 0.4.XX for instance (most likely on GPU clusters).
  • Builds for CUDA but I recommend just building from source, fast and easy with this package (it will work for your specific JAX version).

Features

  • Generalized Problems: A @ V = B @ V @ diag(W), etc.
  • JAX Integrated: Full support for jit, vmap, grad, and jvp.
  • High Performance: Optimized LAPACK (CPU) and cuSOLVER (GPU) kernels.
  • Precision: float32/64 and complex64/128.
  • Degeneracy Handling: Configurable deg_thresh for stable gradients.

Installation & Quick Start

CPU

pip install eigh

Prebuilt CPU-only wheels — Linux (x86_64) and macOS (Apple Silicon), Python 3.10–3.13, JAX 0.5+.

GPU - Build from source (Recommended)

Make sure first that you have JAX installed that runs fine on your GPU.

Build from source for a jaxlib / CUDA / glibc combination the wheels don't cover. The main case is an environment pinned to e.g., jaxlib 0.4.29 (the prebuilt wheels require jaxlib ≥ 0.5 — the FFI binary ABI changed at 0.5, so a 0.5 wheel can't run on 0.4.x and vice-versa). The source builds against whatever jaxlib is in your env (0.4.29 or 0.5–0.10+), CPU or GPU:

git clone https://github.com/Brogis1/eigh && cd eigh
pip install "scikit-build-core>=0.8" "nanobind>=1.0.0" cmake ninja
pip install . --no-build-isolation --no-deps
  • --no-build-isolation compiles against the jaxlib already in your env.
  • --no-deps keeps your pinned jax/jaxlib (essential on 0.4.29 — otherwise pip would upgrade it to ≥0.5).
  • For GPU, have nvcc on PATH (module load cuda/12.x); look for CUDA support enabled in the build log (CUDA not foundnvcc not on PATH). Plain jaxlib (no CUDA) yields a CPU-only build.

Full details and the why — FFI ABI, pinned-jaxlib clusters, nvcc paths, GPU verification — are in docs/TECHNICAL_NOTES.md.

GPU (CUDA 12, Linux x86_64)

You can try this and may get lucky if it happens that JAX and other libraries match. I strongly recommend to build from source (see GPU - Build from source). Pick the package matching your cluster's CUDA version:

pip install eigh-cuda120   # CUDA 12.0+ (works through 12.8+); the safe default
pip install eigh-cuda128   # CUDA 12.8+ (newer toolchain / glibc 2.34)

Both bundle the cuSOLVER kernel + NVIDIA CUDA runtime libs; import eigh auto-detects the GPU. They are separate packages from this same repo — import eigh is identical. See Compatibility.

Usage Example

import jax
import jax.numpy as jnp
# Gen. eigensolver from PySCFAD
from eigh import eigh, eigh_gen

jax.config.update("jax_enable_x64", True)
# Eigenvalue problem
A = jnp.array([[2., 1.], [1., 2.]])
B = jnp.array([[1., 1], [0.5, 1.]])
w1, v1 = eigh(A)
w2, v2 = eigh_gen(A, B)

# With gradients
grad1 = jax.grad(lambda A: eigh(A)[0].sum())(A)
grad2 = jax.grad(lambda A: eigh_gen(A, B)[0].sum())(A)
print("Eigenvalues:", w1, w2)
print("Eigenvectors:", v1, v2)
print("Gradients computed:", grad1.shape, grad2.shape)

Benchmarks

Forward/backward scaling vs. matrix size, and gradient stability as eigenvalues approach degeneracy — for the JAX eigensolvers in src/jax/. See benchmarks/suite/ for the scripts.

Forward-pass scaling Backward-pass (gradient) scaling

API Reference

  • eigh(a, b=None, *, lower=True, eigvals_only=False, type=1, deg_thresh=1e-9) Scipy-compatible interface. type supports 1: A@v=B@v@λ, 2: A@B@v=v@λ, 3: B@A@v=v@λ.
  • eigh_gen(a, b, *, lower=True, itype=1, deg_thresh=1e-9) Lower-level generalized solver.

Degenerate Eigenvalues & Gradients

Individual eigenvalue gradients are ill-defined for degenerate (repeated) eigenvalues. However, symmetric functions (like sum, var, trace) have stable gradients. The deg_thresh parameter (default 1e-9) masks divisions by near-zero gaps to maintain stability.

JAX Eigensolvers

A collection of differentiable generalized eigensolvers with different strategies for handling degenerate eigenvalues in reverse-mode gradients. Useful for training pipelines where degeneracies are common.

If you just want a working solver, use stable_eigh_pyscfad / stable_eigh_gen_pyscfad from generalized_eigensolver_pyscfad.py. They wrap the fast LAPACK/cuSOLVER kernels with a Lorentzian-broadened custom VJP, so gradients stay stable when eigenvalues are (nearly) degenerate.

On Windows, or if you cannot build the C++ kernels, use stable_generalized_eigh from generalized_eigensolver_stable.py instead — same gradient treatment, pure JAX.

The remaining solvers below are kept for benchmarking and for reproducing prior work; they are not recommended as defaults.

Recommended

Solver File Strategy
stable_eigh_pyscfad / stable_eigh_gen_pyscfad generalized_eigensolver_pyscfad.py LAPACK/cuSOLVER kernels + Lorentzian-broadened VJP [2]
stable_eigh / stable_generalized_eigh (pure-JAX) generalized_eigensolver_stable.py Pure-JAX Cholesky + Lorentzian-broadened VJP [2]

Alternative stable solvers

Solver File Strategy Gradient notes
subspace_eigh generalized_eigensolver.py Custom VJP: Lorentzian broadening F/(F²+ε²) [2] Stable
subspace_generalized_eigh generalized_eigensolver.py Symmetry-breaking perturbation + subspace_eigh [2,4] Stable
degen_eigh generalized_eigensolver.py Custom VJP: mask degenerate F_ij by threshold [1,3] Stable only for symmetric-subspace losses
safe_generalized_eigh generalized_eigensolver.py Cholesky + degen_eigh Inherits degen_eigh caveat

Baselines (not gradient-safe at degeneracies)

Solver File Strategy
standard_eig generalized_eigensolver.py scipy.linalg.eigh — non-differentiable reference
jax_eig generalized_eigensolver.py Plain Cholesky + jnp.linalg.eigh, default VJP
generalized_eigh generalized_eigensolver.py Symmetrized Cholesky with SPD shift, default VJP

Compatibility

  • Python: 3.10–3.13. JAX: 0.5 → 0.10+ for the prebuilt wheels; jax 0.4.29 via source build (its FFI ABI differs from 0.5+, so it needs its own build — see Build from source).
  • CPU wheels: Linux x86_64 (manylinux_2_28, bundled OpenBLAS) and macOS arm64.
  • GPU wheels: Linux x86_64, CUDA 12 — eigh-cuda120 (CUDA 12.0+, glibc 2.17) and eigh-cuda128 (CUDA 12.8+, glibc 2.34).
  • Windows: no compiled wheel — use the pure-JAX solvers in src/jax/, or build from source.

Full detail — the FFI binary-ABI rules, why GPU ships as separate packages, the abi3 wheel matrix, HPC/cluster notes, and how to build on a pinned old jaxlib — is in docs/TECHNICAL_NOTES.md.

References

Development & Testing

  • Requirements: CMake 3.18+, C++17, JAX, NumPy, LAPACK/CUDA.
  • Tests:
    pytest tests/test_eigh.py     # Core functionality
    pytest tests/test_eigh_gen.py # Generalized itypes
    pytest tests/test_eigh_jit.py # JIT & vmap
    
  • GPU Setup:
    source setup_gpu_env_clean.sh
    ./run_gpu.sh python example_simple.py
    

License & Citation

Apache License 2.0. If used in research, please cite:

@software{sokolov2026eigh,
  author={Sokolov, Igor},
  title={Eigh: Differentiable eigenvalue decomposition with jax (cpu/gpu)},
  url={https://github.com/Brogis1/eigh},
  year={2026}
}

@software{pyscfad,
  author = {Zhang, Xing},
  title = {PySCFad: Automatic Differentiation for PySCF},
  url = {https://github.com/fishjojo/pyscfad},
  year = {2021-2025}
}

@article{10.1063/5.0118200,
    author = {Zhang, Xing and Chan, Garnet Kin-Lic},
    title = {Differentiable quantum chemistry with PySCF for molecules and materials at the mean-field level and beyond},
    journal = {The Journal of Chemical Physics},
    volume = {157},
    number = {20},
    pages = {204801},
    year = {2022},
    month = {11},
    issn = {0021-9606},
    doi = {10.1063/5.0118200},
    url = {https://doi.org/10.1063/5.0118200},
}

@article{sokolov2026xc,
  title = {Quantum-enhanced neural exchange-correlation functionals},
  author = {Sokolov, Igor O. and Both, Gert-Jan and Bochevarov, Art D. and Dub, Pavel A. and Levine, Daniel S. and Brown, Christopher T. and Acheche, Shaheen and Barkoutsos, Panagiotis Kl. and Elfving, Vincent E.},
  journal = {Phys. Rev. A},
  volume = {113},
  issue = {1},
  pages = {012427},
  numpages = {24},
  year = {2026},
  month = {Jan},
  publisher = {American Physical Society},
  doi = {10.1103/m51l-fys2},
  url = {https://link.aps.org/doi/10.1103/m51l-fys2}
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

eigh-0.4.0.tar.gz (1.3 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

eigh-0.4.0-cp312-abi3-manylinux_2_28_x86_64.whl (12.0 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.28+ x86-64

eigh-0.4.0-cp312-abi3-macosx_11_0_arm64.whl (59.2 kB view details)

Uploaded CPython 3.12+macOS 11.0+ ARM64

eigh-0.4.0-cp311-cp311-manylinux_2_28_x86_64.whl (12.0 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64

eigh-0.4.0-cp311-cp311-macosx_11_0_arm64.whl (60.9 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

eigh-0.4.0-cp310-cp310-manylinux_2_28_x86_64.whl (12.0 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64

eigh-0.4.0-cp310-cp310-macosx_11_0_arm64.whl (60.9 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

File details

Details for the file eigh-0.4.0.tar.gz.

File metadata

  • Download URL: eigh-0.4.0.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for eigh-0.4.0.tar.gz
Algorithm Hash digest
SHA256 66439cb25b0aa8a81daf350e10f1d602a82c48bb5fdb55c25ed97176b46ab6eb
MD5 2b71fd549882d699c350a19ffc7c74d6
BLAKE2b-256 16f6cd0daf39844439c3b8e3fcdbef2917246a0c225e1e95935f016dd81ee5ea

See more details on using hashes here.

File details

Details for the file eigh-0.4.0-cp312-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for eigh-0.4.0-cp312-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8434c1a8b5e2482e2df3f74f9f719f87ecbfa056dbd2c591d1269fd9d3c8e1c2
MD5 448a5f6da1c88549ef47c7b94755fc83
BLAKE2b-256 05d7478002e851fc45c28d09b7f159ec5afb5484b5c486509920517b05d84cc3

See more details on using hashes here.

File details

Details for the file eigh-0.4.0-cp312-abi3-macosx_11_0_arm64.whl.

File metadata

  • Download URL: eigh-0.4.0-cp312-abi3-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 59.2 kB
  • Tags: CPython 3.12+, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for eigh-0.4.0-cp312-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0b9962e63a824c05e9b7732c6ec2cad74be16cb137a6646a12b093e0b4f8fa7b
MD5 0f9cbded3036e0bbd50b46a8fbb1d2bd
BLAKE2b-256 b253f228001344536e7a6d9737b8fd92abe4469bfdc1f834a920817666ffb5f2

See more details on using hashes here.

File details

Details for the file eigh-0.4.0-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for eigh-0.4.0-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6f2210574f839a8e5001216d1bd3a89d9286eb1deb3840a63af13ebd2ace4838
MD5 eee9629003c1583bd85cf7b5d8872b23
BLAKE2b-256 67ba4d1b47b9bc3c88a03aa925e13ff68c6c42221fc6a9e49b3d1110b91e5c24

See more details on using hashes here.

File details

Details for the file eigh-0.4.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for eigh-0.4.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 89a43e5fd42147cd169f3005a3562b29ac8603f326d67982a3f4c737ecf8a154
MD5 fe757a73755fdc0b732c52f2f4e160ca
BLAKE2b-256 1f3fd879afb2d0bd4f7dd56de8d2c3fbb3f8c5dcb32e75e35d759b7ad74f480e

See more details on using hashes here.

File details

Details for the file eigh-0.4.0-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for eigh-0.4.0-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e672555c58327bb18111d9032e3d91f5ab0bbc78130067dcaddc5e3313094436
MD5 251e87516e3315351fb79a0f99dc9908
BLAKE2b-256 92811356da98f3c7933e566be63d9745f0bcd8b03f32268a2f7a373a46efc989

See more details on using hashes here.

File details

Details for the file eigh-0.4.0-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for eigh-0.4.0-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 951c0f645a122a01e7c0972556b5b440abe5e6691ad04e16c614ef6b47963204
MD5 de9cb533e878bad101ddc186478209e9
BLAKE2b-256 f01892c81f9b0f6b8a267409018bf831f42409400e6acbf2a041a71803843ff5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page