Skip to content

Compiler backend qualification

op_system selects its numerical namespace from the input arrays. Optional runtime extras install JAX, Torch or the explicit CuPy CUDA 12 wheel family; installing the compiler alone requires neither. Root compiler qualification is a separate required CI matrix from the provider's tests and the baseline compiler test suite.

The required jobs explicitly install NumPy, JAX, or CPU Torch and execute the matching tests through scripts/qualify_backend.py. The runner fails if the backend is missing, if no tests run, or if a selected test is skipped. Ordinary optional-backend skips in the baseline suite therefore cannot substitute for these jobs.

Qualified capabilities

The CI jobs run on Python 3.12 with the dependencies resolved for that run; their logs record backend and Python versions. Baseline package tests separately cover supported Python 3.11–3.13. Qualification covers float32 and float64 values, with JAX x64 enabled explicitly for double-precision checks. State and floating parameters use the same dtype; mixed-precision combinations remain unqualified.

Capability NumPy JAX CPU Torch
Flat and structured/PyTree RHS parity, shapes, dtypes, namespace Qualified Qualified Qualified
Independent-group block RHS Qualified, eager loop Qualified, eager loop and native vmap Qualified, eager loop and torch.func.vmap
Coupled-group flat/structured RHS Qualified Qualified Qualified
Treating coupled groups as independent blocks Rejected Rejected Rejected
Native JIT and batched parameter evaluation No AD/JIT contract Qualified with jit/vmap Torch compiler integration unqualified
Directional derivatives against independent finite differences No AD contract Qualified Autograd qualified in float64
CUDA/CuPy and other GPU execution Unqualified here Unqualified here Unqualified here

Named latent observables have a separate initial operation boundary: arithmetic/exp, broadcasting, declared-node/counter selection and explicit reductions. Their required tests check independent nonuniform-grid values, JAX float64 JIT/vmap and state/parameter/time derivatives, and Torch float64/float32 autograd. Static measure/coordinate metadata is outside that derivative contract. Broader RHS qualification does not automatically qualify additional observable operations or devices.

The separate CuPy device contract provides an optional install path and a required actual-device command. Its CPU skips are not GPU evidence. GPU execution is outside the qualified CPU matrix. The matrix describes the tested workload and paths, not every combination of compiler operators, backend versions, devices, or automatic differentiation transforms.

Native state actions additionally qualify explicit JAX/Torch RHS and scalar/array observable JVP/VJP products, JAX JIT/vmap, Torch vmap and nonlinear outer state/parameter gradients. A required older-JAX lane runs the complete selected suite on JAX/jaxlib 0.4.36, NumPy 2.0.0 and array-api-compat 1.12.0. This is a named compatibility point alongside current resolution, not qualification of every JAX version. Minimum Torch 2.6 executes the same native action checks. Required lanes reject optional skips.

Independent equations and structural checks

benchmarks/hierarchical_model.py defines a synthetic closed three-compartment relaxation network. State and a local rate vary by group, while a global gain, stage recovery rates, and a stage transport matrix are shared. Aliases, stage reductions, and an apply_along transport expression exercise axis reordering and broadcasting. The reference uses explicit cell loops, not generated code or expressions copied from the compiler IR.

The coupled variant uses other groups' state through a group reduction. It matches the same independently written equations, and an attempted factorize_axes: [group] fails. Native block mapping is tested only for the independent variant, slicing local parameters while sharing global ones.

Transport is part of this fixture's equations. Operator descriptors intended for a downstream integration engine are a separate interface; compilation does not automatically apply every metadata operator to an RHS.

JAX checks JIT, batch evaluation, and shared/local parameter directional derivatives against finite differences of the independent reference. Torch checks autograd through state and shared/local parameters, with a reference finite-difference check. A closed RHS has conserved totals, so a squared-RHS objective is used to avoid an identically zero gradient from summing all flows.

Local commands

From a clean checkout with uv and just installed:

just qualify-numpy
just qualify-jax
just qualify-torch
# Or run all three required core qualifications:
just qualify

The Torch target installs CPU wheels explicitly. These commands change the selected extras in the local environment; use separate worktrees/environments when retaining multiple dependency selections matters. They run the same qualification runner as CI. Normal quality, documentation, baseline tests, provider checks, and wheel validation remain required alongside qualification.

Scientific validity, agreement across untested parameter regimes, and solution accuracy of a downstream ODE/PDE integrator require separate evidence.

Literal RHS values, including zero and aliased constants, inherit the qualified floating state's precision during assembly. Flat, structured, and available block evaluation preserve dtype and namespace. Explicitly typed array-valued parameters retain their own precision; this rule does not coerce deliberately mixed-precision input arrays into the state dtype. Constant forcing has a zero state Jacobian under the tested JAX and Torch functional AD transforms.

Continuous-axis reduction weights use the floating state's dtype and device, including nested categorical sums and multi-axis trapezoidal integration. Analytic bilinear integrals on nonuniform grids qualify values, precision, namespace on all three CPU namespaces, JAX JIT, and JAX/Torch derivatives. Explicitly typed input arrays still follow native promotion; mixed-precision inputs remain unqualified.

Required compiler qualification also checks conditional scalar reaction balance artifacts against independent source-flux equations on NumPy, JAX and CPU Torch in float32/float64. The producer emits static exact integer weights and metadata; these tests qualify agreement with the represented native RHS, without claiming runtime integration accuracy, general stoichiometric inference or spatial and operator conservation. See reaction balances.

Minimum Torch qualification runs the complete required native suite, including shaped shared/local parameter gradients, coordinate transforms and vectorized scalar-time gradients in float32/64. Already-native tensors use torch.as_tensor when conversion is needed, preserving their graph edges on Torch 2.6 with the minimum compatibility namespace. NumPy/JAX/CuPy conversion rules are unchanged. This remains eager/autograd qualification; strict Torch compiler capture is a separate version-scoped contract.

Scalar callable and strict compiler boundary

Scalar RHS aliases, shared subexpressions, equations and latent observables use validated cached expression functions. Runtime calls bind fresh environment values as explicit arguments. Constructors evaluate a generated lambda once; these numerical calls no longer invoke Python eval. Code objects remain available for inspection. The vectorized path reuses the same helper. Reaction callbacks retain their separate existing restricted code-object evaluation.

A regression guard disables runtime eval after constructing a public synthetic model, then changes parameters and checks independent RHS/observable values. Torch tests check values and first derivatives in float32/64. Strict single-FX-graph capture is qualified on Torch 2.14.1; Torch 2.6 retains its eager/AD contract. Older strict compilation encounters upstream namespace-helper limitations and is not covered by this new capture qualification. FX capture here uses an inspection backend; native solver-loop acceleration requires separate engine evidence.

The paired scalar receipt records 12 fresh CPU workers: three each for one, two, eight and 32 scalar states, using the same normalized model and arrays for the baseline/candidate factories. Fifteen alternating pairs of 1000 calls per worker check independent values before timing. Candidate/baseline process-median latency ratios are 1.012, 1.029, 1.044 and 1.051 respectively. This is a small eager scalar-RHS cost for the reusable compiler boundary, not an eager speedup claim. The record preserves raw samples, source snapshots/hashes, construction times and reproduction code. These paired workers do not measure observation latency, complete integration or training.