Skip to content

Draw NaN rather than hang when poisson() or negative_binomial() is sampled with an invalid parameter (#617) - #864

Merged
njtierney merged 6 commits into
mainfrom
i617-nan-hang
Oct 23, 2026
Merged

njtierney merged 6 commits into
mainfrom
i617-nan-hang

Conversation

@njtierney

Copy link
Copy Markdown
Collaborator

Closes #617.

  • TensorFlow's Poisson sampler on the CPU never returns for a NaN rate, and Ctrl-C doesn't stop it. TFP's GPU path masks NaN rates; its CPU path doesn't.
  • poisson() samples through it, and so does negative_binomial(), as a Poisson with a gamma-distributed rate. So calculate() and simulate() hung on a NaN or negative lambda (greta passes log(lambda)), and on a negative binomial whose rate is NaN.

What changes

  • A new internal tf_sample_where_valid() swaps each invalid parameter element for a safe placeholder before sampling, and gives NaN for those draws. When every element is valid, the draws are the same as on main, seed for seed.
  • poisson() masks a NaN log rate, which covers a NaN or negative lambda.
  • negative_binomial() masks a NaN or negative size, a TFP probs = 1 - prob outside [0, 1), and an infinite size with prob = 1. So prob = 0, or a prob so small that 1 - prob rounds to 1, draws NaN. An infinite size with prob below 1 still draws Inf, as on main.
  • Both distributions return list(log_prob, sample), like greta's other custom distributions. log_prob is TFP's, unchanged.

Not covered

  • greta.distributions' zero-inflated Poisson and negative binomial build their own TFP samplers, so they still hang. An issue there is drafted, not posted.
  • Every other TFP sampler greta uses was probed on the CPU with NaN, ±Inf, negative and huge parameters, and none hang. Some give a silently wrong draw, e.g. binomial() with a NaN size gives 0; that's a separate issue, also drafted.

Tests

  • tests/testthat/test_calculate.R: calculate() draws NaN for invalid poisson() and negative_binomial() elements, including negative_binomial(0, 0) and an infinite size with prob = 1, and ordinary draws for the valid elements beside them. On main the test hangs, and its session is killed at 600 s.
  • tests/testthat/helpers.R: in_fresh_greta() takes a timeout, so a test of a hang fails rather than hangs. The timeout also covers starting R and loading greta, hence 600 s.
  • The calculate, iid_samples and distributions tests pass. So does the whole suite locally, apart from two test_future.R errors: future workers load the installed greta, which predates %*% multiplies a data matrix once, not once per chain (#858) #859's unbatched_tf_name().

🤖 Generated with Claude Code

njtierney and others added 3 commits October 22, 2026 18:59
…mpled with an invalid parameter (#617)

- R/probability_distributions.R: tf_sample_where_valid() swaps invalid parameters for a placeholder before sampling and gives NaN for those draws; poisson() and negative_binomial() sample through it
- tests/testthat/helpers.R: in_fresh_greta() takes a timeout, so a test of a hang fails rather than hangs
- tests/testthat/test_calculate.R: calculate() draws NaN for an invalid poisson() and negative_binomial(), in a session killed after 120 seconds
- NEWS.md: bullet for #617

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aN rather than hanging and an infinite size still draws Inf (#617)

- R/probability_distributions.R: negative_binomial() checks TFP's probs = 1 - prob is in [0, 1) and masks an infinite size only with probs of 0, using TFP's constructor directly
- tests/testthat/test_calculate.R: the #617 test adds negative_binomial(0, 0), an infinite size, and valid elements a placeholder draw can't match, with a 600 s timeout that allows for a slow start

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…here_valid()

- tests/testthat/test_calculate.R: the comment says why the draws run in a killable session and why the timeout is long, without repeating the sampler's explanation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread R/probability_distributions.R Outdated
Comment thread R/probability_distributions.R
Comment thread R/probability_distributions.R Outdated
Comment thread NEWS.md Outdated
njtierney and others added 3 commits October 23, 2026 12:54
…l()'s mask

- R/probability_distributions.R: what tf_sample_where_valid() does and why in three lines; the negative binomial's invalid cases in two

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n lists on its own line

- R/probability_distributions.R: list(log_prob, sample) split over lines in both tf_distrib() methods

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@njtierney
njtierney marked this pull request as ready for review October 23, 2026 04:57
@njtierney
njtierney merged commit ea4e23f into main Oct 23, 2026
6 checks passed
@njtierney
njtierney deleted the i617-nan-hang branch October 23, 2026 04:58
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.

calculate() hangs with NaN parameters in sampling distribution in tf2 branch

1 participant