Fix numba CauchyRV loc/scale - #2309
Merged
jessegrabowski merged 2 commits intoJul 30, 2026
Merged
Conversation
The numba dispatch computed `(loc + z) / scale` instead of `loc + scale * z`, giving the sampled variable location `loc/scale` and scale `1/scale`. `rng_fn_scipy` and the JAX dispatch are both correct, so only the numba backend was affected -- but it is the default linker. `logp` is untouched, so NUTS posteriors were fine; everything that draws was not, including `sample_prior_predictive` on a `HalfCauchy` prior. The existing `cauchy` case in `test_unaligned_RandomVariable` passed `scale=1.0`, where `(loc + z) / 1` is algebraically identical to `loc + 1 * z`, so both the location and scale errors vanished together. Bumping that to `scale=3.0` makes the Cramer-von Mises check fail on the old code (p = 1.7e-08) and pass on the new. Closes pymc-devs#2308
`test_unaligned_RandomVariable` is the only test that checks these samplers against their distribution, and it has three cases. `cauchy` and `gumbel` both used `scale=1.0`; `t` already passes `scale=np.pi`. `GumbelRV` has a hand-written core too (`loc - scale * np.log(-np.log(U))`) and is correct, but at `scale=1` a `(loc - z) / scale`-style slip would be invisible there for the same algebraic reason. Bumped to `scale=4.0`. Verified by injecting exactly that slip: the test fails at p=7.2e-08 with it and passes without. Audited the other hand-written numba cores (`t`, `halfnormal`, `pareto`, `invgamma`, `gumbel`, `wald`, plus the default-path RVs) against scipy with non-degenerate parameters -- all match, so `cauchy` was the only actual bug.
ricardoV94
approved these changes
Jul 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2308.
The numba dispatch computed
(loc + z) / scaleinstead ofloc + scale * z, so the sampled variable had locationloc/scaleand scale1/scale.rng_fn_scipyand the JAX dispatch were already correct, so only numba was affected — but it is the default linker.logpis untouched, so NUTS posteriors were fine; anything that draws was not, includingsample_prior_predictiveon aHalfCauchyprior (HalfCauchyRV.rv_opbuildsabs(cauchy(0, beta))).Tests
test_unaligned_RandomVariableis the only test checking these samplers against their distribution, and it has three cases. Two used a degenerate scale:cauchyscale=1.0scale=3.0gumbelscale=1.0scale=4.0tscale=np.piAt
scale=1,(loc ± z) / 1is algebraically identical toloc ± 1 * z, so both the location and scale errors vanish together and Cramér–von Mises passes.GumbelRVhas a hand-written core too (loc - scale * np.log(-np.log(U))) and is correct, but was equally undetectable. Verified by injecting the analogous slip: the new case fails at p=7.2e-08 with it, passes without.Audit
Checked every hand-written numba core (
t,halfnormal,pareto,invgamma,gumbel,wald) plus the default-path RVs against scipy with non-degenerate parameters. All match —cauchywas the only real bug.tests/link/numba/test_random.py: 84 passed, 2 xfailed.