Quax
JAX + multiple dispatch + custom array-ish objects
For example, this can be mean overloading matrix multiplication to exploit sparsity or structure, or automatically rewriting a LoRA's matmul (W + AB)v into the more-efficient Wv + ABv.
Applications include:
- LoRA weight matrices
- symbolic zeros
- arrays with named dimensions
- structured (e.g. tridiagonal) matrices
- sparse arrays
- quantised arrays
- arrays with physical units attached
- etc! (See the built-in
quax.exampleslibrary for most of the above!)
This works via a custom JAX transform. Take an existing JAX program, wrap it in a quax.quaxify, and then pass in the custom array-ish objects. This means it will work even with existing programs, that were not written to accept such array-ish objects!
(Just like how jax.vmap takes a program, but reinterprets each operation as its batched version, so to will quax.quaxify take a program and reinterpret each operation according to what array-ish types are passed.)
Installation
pip install quax
Documentation
Available at https://nstarman.github.io/quax.
Example: LoRA
This example demonstrates everything you need to use the built-in quax.examples.lora library.
import equinox as eqx
import jax.random as jr
import quax
import quax.examples.lora as lora
#
# Start off with any JAX program: here, the forward pass through a linear layer.
#
key1, key2, key3 = jr.split(jr.PRNGKey(0), 3)
linear = eqx.nn.Linear(10, 12, key=key1)
vector = jr.normal(key2, (10,))
def run(model, x):
return model(x)
run(linear, vector) # can call this as normal
#
# Now let's Lora-ify it.
#
# Step 1: make the weight be a LoraArray.
lora_weight = lora.LoraArray(linear.weight, rank=2, key=key3)
lora_linear = eqx.tree_at(lambda l: l.weight, linear, lora_weight)
# Step 2: quaxify and call the original function. The transform will call the
# original function, whilst looking up any multiple dispatch rules registered.
# (In this case for doing matmuls against LoraArrays.)
quax.quaxify(run)(lora_linear, vector)
# Appendix: Quax includes a helper to automatically apply Step 1 to all
# `eqx.nn.Linear` layers in a model.
lora_linear = lora.loraify(linear, rank=2, key=key3)
Work in progress!
Right now, the following are not supported:
jax.custom_vjp
It should be fairly straightforward to add support for these; open an issue or pull request. (We've already got jax.custom_jvp, jax.lax.cond_p, jax.lax.while_p, and jax.lax.scan_p. :) )
See also: other libraries in the JAX ecosystem
Always useful
Equinox: neural networks and everything not already in core JAX!
jaxtyping: type annotations for shape/dtype of arrays.
Deep learning
Optax: first-order gradient (SGD, Adam, ...) optimisers.
Orbax: checkpointing (async/multi-host/multi-device).
Levanter: scalable+reliable training of foundation models (e.g. LLMs).
Scientific computing
Diffrax: numerical differential equation solvers.
Optimistix: root finding, minimisation, fixed points, and least squares.
Lineax: linear solvers.
BlackJAX: probabilistic+Bayesian sampling.
sympy2jax: SymPy<->JAX conversion; train symbolic expressions via gradient descent.
PySR: symbolic regression. (Non-JAX honourable mention!)
Built on Quax
Quaxed: a namespace of already-wrapped quaxify(jnp.foo) operations.
unxt: Unitful Quantities.
Awesome JAX
Awesome JAX: a longer list of other JAX projects.
Acknowledgements
Significantly inspired by https://github.com/davisyoshida/qax, https://github.com/stanford-crfm/levanter, and jax.experimental.sparse.
Metadata
Release files for quax 0.4.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| quax-0.4.5.tar.gz | 215.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| quax-0.4.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 277.0 kB
Release files / quax-0.4.5.tar.gz
| Download URL | quax-0.4.5.tar.gz |
|---|---|
| Size | 215.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6d075b52ce7e44785c7bac06c28f3608d05a52f1baf7b131b06af5a3848275f4
|
|
BLAKE2b-256 checksum How to use checksums |
04762f86afd710019c90b24c9a0a8634951bcb0c29ca1e343ff66df4b2c53162
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency logRelease files / quax-0.4.5-py3-none-any.whl
| Download URL | quax-0.4.5-py3-none-any.whl |
|---|---|
| Size | 61.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
45cb9a98c431ce5bf19286ece3672a737528a1a61ae0840410e9ac5e33600c8f
|
|
BLAKE2b-256 checksum How to use checksums |
8200db657d38107837a6bd7743bf842c1aefc77b2a205b66a3663094ebec23a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency log