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.