Skip to content

feat(std): add bounded random int to PCG32#1877

Merged
hsemenenko merged 4 commits into
Quantinuum:mainfrom
luffy-orf:feat/pcg32-bounded-rng
Jun 17, 2026
Merged

feat(std): add bounded random int to PCG32#1877
hsemenenko merged 4 commits into
Quantinuum:mainfrom
luffy-orf:feat/pcg32-bounded-rng

Conversation

@luffy-orf

Copy link
Copy Markdown
Contributor

Summary

  • Add PCG32.next_int_bounded(bound) using PCG's pcg32_boundedrand_r rejection sampling (uniform [0, bound) without modulo bias)
  • Extract _next_uint32() shared by next_int() and bounded draws
  • Harden PCG32: 64-bit state masking and safe rotate amounts (fixes hugr const-fold shift overflows in emulation)
    Fixes [Feature]: Add bounded random int to std.random #1874

Test plan

  • uv run pytest tests/integration/std/test_random.py
  • uv run pre-commit run --all-files
  • uv run pytest -n auto (1614 passed)

@luffy-orf luffy-orf requested a review from a team as a code owner June 16, 2026 13:21
@luffy-orf luffy-orf requested a review from hsemenenko June 16, 2026 13:21
@PabloAndresCQ PabloAndresCQ self-requested a review June 16, 2026 14:28

@PabloAndresCQ PabloAndresCQ left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This looks great. I've double checked against the reference implementation in C. I've also checked locally that the random_bound_int from the reference implementation and the Guppy implementation agree (and that they agree with the values in the test file).

I've made a couple of comments that are not from this PR, but from the original one that @luffy-orf also contributed with.

PS: I'm approving since, from the user perspective, this is sufficient. However, @hsemenenko, please have a look at the interface + my comments on tests, and mark as "Request changes" if you deem it necessary.

Comment thread tests/integration/std/test_random.py
Comment thread tests/integration/std/test_random.py
Comment thread tests/integration/std/test_random.py Outdated
@luffy-orf luffy-orf requested a review from PabloAndresCQ June 16, 2026 18:42

@hsemenenko hsemenenko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this, It looks great! I've added a few comments of things to change. None of the comments should require major changes but I think are useful additions.

Comment thread guppylang/src/guppylang/std/random.py Outdated
Comment thread guppylang/src/guppylang/std/random.py Outdated
Comment thread guppylang/src/guppylang/std/random.py Outdated
Comment thread guppylang/src/guppylang/std/random.py Outdated
Comment thread tests/integration/std/test_random.py
Comment thread tests/integration/std/test_random.py Outdated
Comment thread tests/integration/std/test_random.py Outdated
@luffy-orf

Copy link
Copy Markdown
Contributor Author

Thanks @hsemenenko all your review comments are addressed in the latest push:

_mask64 readability: two_to_32 now uses 1 << 32. For the 64-bit mask, (1 << 64) - 1 triggers a hugr const-fold shift overflow during emulation, so _mask64 combines two 32-bit masks instead (with an inline comment).
seeded_pcg32: seed parameter is now nat, since initseq is unsigned.
next_int_bounded: bound is now nat, panics on bound == 0, and test_pcg32_bounded_bound_zero_panics covers that path.
Tests: qsystem parity and motivating-example tests use .collated_shots(); the quantum interference test uses ClassicalReplay with four measurement patterns to exercise both branches.

Ready for another look when you have a moment

@luffy-orf luffy-orf requested a review from hsemenenko June 17, 2026 11:47

@hsemenenko hsemenenko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great, thank you. Apologies for not realising that 1<<64 would overflow, but great job coming up with a work around.

Just one minor change with the bound panic and I can approve.

Comment thread guppylang/src/guppylang/std/random.py Outdated
:py:meth:`guppylang.std.qsystem.random.RNG.random_int_bounded`.
"""
if bound == nat(0):
panic("PCG32.next_int_bounded: bound must be positive")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a discussion with @PabloAndresCQ, could this be changed to use exit rather than panic? The reason is that exit will only exit the current shot and then continue to the next shot, while panic will exit and not run any subsequent shots.

Suggested change
panic("PCG32.next_int_bounded: bound must be positive")
exit("PCG32.next_int_bounded: bound must be positive")

@luffy-orf

Copy link
Copy Markdown
Contributor Author

@hsemenenko Done - switched to exit for the zero-bound case and updated the test to verify shot 0 exits while shot 1 continues (test_pcg32_bounded_bound_zero_exits). Thanks for catching that distinction with @PabloAndresCQ!

@luffy-orf luffy-orf requested a review from hsemenenko June 17, 2026 14:55
@hsemenenko hsemenenko added this pull request to the merge queue Jun 17, 2026
Merged via the queue into Quantinuum:main with commit 01004a8 Jun 17, 2026
12 checks passed
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.

[Feature]: Add bounded random int to std.random

3 participants