Floating-Point Policy
| Status | Applies to | Owner |
|---|---|---|
| Active pre-release contract | Rust host arrays and JAX association kernels | Compute maintainers |
Floating-point width is selected by ownership boundary and numerical role. A single global dtype would either double host bandwidth or weaken Firth solver stability.
Contract
- Phenotypes, covariates, LOCO predictions, dosages, and genotype summary
buffers are stored as
f32on the Rust host. - JAX score-test arithmetic and public result statistics use
float32. - Null Firth, approximate Firth, fallback Newton-Raphson, likelihood,
information-matrix, and corrected-statistic calculations use JAX
float64. - Corrected Firth values are narrowed once when merged into float32 score results.
firth_dtypedoes not exist. Firth width is an algorithm invariant, not a user option.- Epsilon is derived from the active array dtype with
jnp.finfo(dtype).eps. A float64 epsilon must never be cast down and used as a float32 tolerance.
Configuration Values
Rust configuration thresholds are finite validated f64 newtypes:
- positive tolerances and variance floors are greater than zero;
- probabilities are in
(0, 1)and probability floors in(0, 0.5); - step-halving scales are in
(0, 1); - sparse carrier dosage thresholds are in
(0, 2].
The PyO3 boundary extracts the validated scalar with .get() and passes a
Python float into the typed JAX configuration. Kernels cast the scalar to the
array dtype at the point of use.
Review Checklist
- New host arrays remain
f32unless a measured host-side algorithm requires wider storage. - New Firth operands are explicitly converted to
jnp.float64before solver work begins. - New convergence constants derive from the operand dtype.
- No configuration or manifest field reintroduces
firth_dtype. - Narrowing output conversions occur once during materialization, not inside iterative kernels.