Skip to content

Fix NUTS under NumPy >= 2.4 and relax the numpy cap to <2.5 - #773

Open
Radiationsafety wants to merge 1 commit into
CUQI-DTU:mainfrom
Radiationsafety:numpy-2.4-fixes
Open

Radiationsafety wants to merge 1 commit into
CUQI-DTU:mainfrom
Radiationsafety:numpy-2.4-fixes

Conversation

@Radiationsafety

Copy link
Copy Markdown

Summary

NumPy 2.4 turns int() conversion of 1-element (shape-(1,)) arrays into a TypeError (previously only a DeprecationWarning). The NUTS slice and U-turn indicators in cuqi/sampler/_hmc.py hit exactly this pattern whenever the target logpdf returns shape-(1,) arrays (e.g. GMRF posteriors built from JointDistribution):

TypeError: only 0-dimensional arrays can be converted to Python scalars
  File "cuqi/sampler/_hmc.py", line 375, in _BuildTree
    n_prime = int(log_u <= Ham_prime)

Changes

  1. cuqi/sampler/_hmc.py — wrap the three affected conversions with np.squeeze(), which maps both true scalars and shape-(1,) arrays to 0-d before int():

    • slice acceptance check: n_prime = int(np.squeeze(log_u <= Ham_prime))
    • U-turn check inside the recursive _BuildTree
    • U-turn check in the (iterative) stop criterion

    Semantics are unchanged on all older NumPy versions (np.squeeze of a scalar is a 0-d array; int() on 0-d arrays is legal in every NumPy 2.x).

  2. requirements.txt — relax the upper bound numpy<=2.2.0 -> numpy<2.5 so NumPy 2.3/2.4 environments can resolve CUQIpy. No other runtime dependency (jax is not pulled in by the core requirements) pins numpy below 2.3.

Validation

Differential test through the bssunfold BSS-unfolding integration (solve_cuqi_bayesian, custom cuqi.model.Model forward A @ exp(theta) with analytic gradient, GMRF/OU priors, likelihood, Posterior + PCN/NUTS/HybridGibbs):

sampler chain config max rel. diff vs upstream 1.5.1 @ numpy 2.2.0
PCN 600 samples + 400 burn-in, seed 42 0.0 (bit-identical)
NUTS 80 samples + 60 burn-in, gmrf_order=2, seed 42 0.0 (bit-identical)
HybridGibbs (hierarchical, Gamma hyperprior) 120 samples + 80 burn-in, seed 42 0.0 (bit-identical)

i.e. with this patch, identical seeded chains under numpy 2.4.1 reproduce the upstream-CUQIpy-on-numpy 2.2.0 results bit-for-bit; without the patch NUTS raises the TypeError above.

Happy to split the cap relaxation into a separate PR if the maintainers prefer to review/verify the version bump independently of the bug fix.

NumPy 2.4 turns int() conversion of 1-element arrays into a TypeError
(previously only a DeprecationWarning).  The NUTS slice and U-turn
indicators in cuqi/sampler/_hmc.py hit exactly this pattern whenever the
target logpdf returns shape-(1,) arrays (e.g. GMRF posteriors with
array-valued logpdfs):

  TypeError: only 0-dimensional arrays can be converted to Python scalars
    _hmc.py, line 375 in _BuildTree: n_prime = int(log_u <= Ham_prime)

- Wrap the three affected conversions (slice acceptance, U-turn check in
  the recursive _BuildTree and in the stop criterion) with np.squeeze(),
  which maps both true scalars and shape-(1,) arrays to 0-d before int().
  Semantics are unchanged on older NumPy versions.

- requirements.txt: relax the upper bound 'numpy<=2.2.0' -> 'numpy<2.5'
  so that NumPy 2.3/2.4 environments can resolve CUQIpy.

Validation (bssunfold BSS-unfolding integration, seeded chains): with
this patch, PCN / NUTS / hierarchical-Gibbs posterior spectra computed
under numpy 2.4.1 are bit-for-bit identical to upstream CUQIpy 1.5.1
under numpy 2.2.0 (max relative difference 0.0); without the patch NUTS
raises the TypeError above.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant