The output dtype depends on which backend ran, and therefore on the hardware:
metric backend dtype
---------------------------
pli metal float32
wpli metal float32
accorr metal float32
<all> numpy float64
<all> numba float64
<all> cuda float64
run_pairwise_kernel reads the result back as np.float32 (hypyp/sync/kernels/_metal_dispatch.py:163, and identically metal_accorr.py:193), and returns it unchanged. _cuda_dispatch.py is float64 throughout (documented at :40), as are the numpy and numba paths.
Consequences:
- The same script on an Apple Silicon machine and on a Linux/CUDA machine writes result files of different dtype, which is a reproducibility wart in saved derivatives.
- Downstream concatenation or stacking silently upcasts, so the precision loss is invisible.
BaseMetric.compute's docstring documents the return shape but says nothing about dtype, so there is no stated contract to rely on.
Note the float32 kernels themselves are accurate — measured max absolute deviation vs the float64 NumPy reference is 7.6e-09 (pli), 6.9e-08 (wpli), 5.2e-08 (accorr). The issue is only the inconsistent output contract.
Suggested fix: either cast the Metal result to float64 before returning (cheap, makes the contract uniform) or document the dtype per backend in BaseMetric.compute and sync/README.md. The first option is preferable — a backend switch should not change the dtype of a scientific result.
The output dtype depends on which backend ran, and therefore on the hardware:
run_pairwise_kernelreads the result back asnp.float32(hypyp/sync/kernels/_metal_dispatch.py:163, and identicallymetal_accorr.py:193), and returns it unchanged._cuda_dispatch.pyis float64 throughout (documented at:40), as are the numpy and numba paths.Consequences:
BaseMetric.compute's docstring documents the return shape but says nothing about dtype, so there is no stated contract to rely on.Note the float32 kernels themselves are accurate — measured max absolute deviation vs the float64 NumPy reference is 7.6e-09 (pli), 6.9e-08 (wpli), 5.2e-08 (accorr). The issue is only the inconsistent output contract.
Suggested fix: either cast the Metal result to float64 before returning (cheap, makes the contract uniform) or document the dtype per backend in
BaseMetric.computeandsync/README.md. The first option is preferable — a backend switch should not change the dtype of a scientific result.