Skip to content

Quaxify only some argumentsยค

By default quax.quaxify takes every Value you pass and handles it. Sometimes you want one to travel through untouched โ€” most often so it reaches a nested quax.quaxify that knows what to do with it, rather than being resolved by the outer one.

Pass a filter_spec. It partitions (fn, args, kwargs), so the spec has that shape: one entry for the function, one tuple for the positional arguments, one dict for the keyword arguments.

import jax.numpy as jnp
import quax
from quax.examples.unitful import Unitful, meters, seconds


def inner(s):
    return s * 2.0


def outer(m, s):
    # `s` arrives here untouched, so the nested quaxify is what handles it
    return m * 3.0, quax.quaxify(inner)(s)


filter_spec = (False, (True, False), {})  # (fn, args, kwargs)

m_out, s_out = quax.quaxify(outer, filter_spec=filter_spec)(
    Unitful(jnp.ones(2), meters), Unitful(jnp.ones(2), seconds)
)
print(m_out.array, m_out.units)  # [3. 3.] {m: 1}
print(s_out.array, s_out.units)  # [2. 2.] {s: 1}

False at a position means "leave this alone"; True means "quaxify it".

Reach for this when two libraries' types would otherwise meet in one dispatch, and you would be forced to write a rule for the combination. Splitting the quaxifies keeps each type's rules owned by the project that defines them.