Skip to content

Clamp fracDefining to 1.0 in perform_bootstrap to avoid numpy binomial "p > 1" crash - #321

Merged
mariaelf97 merged 1 commit into
andersen-lab:mainfrom
pditommaso:fix/bootstrap-fracdefining-clamp
Sep 4, 2026
Merged

mariaelf97 merged 1 commit into
andersen-lab:mainfrom
pditommaso:fix/bootstrap-fracdefining-clamp

Conversation

@pditommaso

@pditommaso pditommaso commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Hi, and thanks for maintaining Freyja! 🙏

Context. We run nf-core/viralrecon on a nightly basis across a few cloud backends, and noticed freyja boot occasionally failing on a small fraction of samples (~0.5–4% in our runs). Tracing it led to a floating-point edge case in perform_bootstrap; this PR proposes a small fix. More detail in #320.

What happens. fracDefining = fracDepths.sum() is mathematically the identity totalDepth / totalDepth = 1.0, but floating-point accumulation can land one ULP above 1.0 (e.g. 1.0000000000000002). Because that value is passed as the p argument to rng.binomial(totalDepth, fracDefining, numBootstraps), numpy rejects p > 1:

ValueError: p < 0, p > 1 or p is NaN

The change. Clamp fracDefining to its mathematical maximum of 1.0 before it's used as a probability:

fracDefining = min(fracDepths.sum(), 1.0)

When the value is already ≤ 1.0 nothing changes; when it rounds above 1.0, binomial now receives p = 1.0 and returns totalDepth (the intended result). fracDepths_adj = fracDepths / fracDefining is unaffected (division by 1.0).

Verification. rng.binomial(1684431, 1.0000000000000002, 10) raises the ValueError before the change and returns [1684431, …] after; a real SARS-CoV-2 sample that triggered the crash runs freyja boot to completion with the patch applied.

I didn't include a unit test since the trigger is a float-rounding artifact of specific (depth vector × barcode set) inputs that's tricky to reproduce portably — but I'd be glad to add one if you can suggest a stable way to force it, and of course happy to adjust the approach however you'd prefer.

Fixes #320.


Note: this PR was prepared with the help of an AI agent (Claude Code), and reviewed before submission.

…l "p > 1" crash

fracDefining = fracDepths.sum() is mathematically 1.0 but can float-round one ULP
above 1.0, which numpy.random.Generator.binomial rejects as p>1. Clamp to 1.0.

Fixes andersen-lab#320
@joshuailevy

Copy link
Copy Markdown
Collaborator

Hi @pditommaso, thanks for bringing this up and for providing a quick solve!

We hadn't observed this previously, but it makes sense that it'd crash like this if p>1. Your change should solve this issue nicely. We'll get this incorporated into main shortly!

Best,
Josh

@mariaelf97

Copy link
Copy Markdown
Collaborator

Thank you @pditommaso for this quick fix!
@joshuailevy I can re-lint and merge if you want.

@joshuailevy

Copy link
Copy Markdown
Collaborator

Sure! In transit atm, so if you have a moment free to de-lint that'd be awesome! thanks @mariaelf97

@mariaelf97
mariaelf97 merged commit 3050150 into andersen-lab:main Sep 4, 2026
1 of 2 checks passed
@pditommaso

Copy link
Copy Markdown
Contributor Author

Thanks both! much appreciated!

pditommaso added a commit to pditommaso/modules that referenced this pull request Sep 17, 2026
Bumps freyja from 2.0.3 to 2.0.4 across boot, demix, variants and update
(container + conda pins).

Freyja 2.0.4 fixes a floating-point rounding bug in perform_bootstrap
(andersen-lab/Freyja#321): fracDefining could round one ULP above 1.0 and
make numpy's binomial raise "p < 0, p > 1 or p is NaN", intermittently
crashing FREYJA_BOOT (nf-core/viralrecon#618). Verified present in the
container: sample_deconv.py now clamps `fracDefining = min(fracDepths.sum(), 1.0)`.

Snapshots are intentionally unchanged: freyja 2.0.4 still reports
"version 2.0.3" from `freyja --version` (upstream did not bump the version
string), so the captured version and `freyja variants` output are identical
to 2.0.3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

freyja boot: intermittent crash in perform_bootstrap when fracDefining rounds just above 1.0 (numpy binomial p > 1)

3 participants