Repository navigation
Conversation
Replace the per-walker Python loop with one array comparison. A single `rand(n)` call returns the same numbers as `n` calls to `rand()`, so chains, log-probabilities, acceptance and RNG state are bit-identical. Adds a test comparing against the original loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016SNW8QBXAe3BuS2s3soERw
This branch has not been deployed
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.
Summary
This PR vectorizes the accept/reject step in
RedBlueMove.propose. The sampler's output is bit-identical, and it is 1.1–2.6× faster, most noticeably for large ensembles andvectorize=True.RedBlueMoveis the base class forStretchMove(the default),WalkMove,DEMove,DESnookerMoveandKDEMove, so all of them get faster.The change
It is a single block in
src/emcee/moves/red_blue.py: 7 lines replaced by 4. No other library code changes, and no API, behavior or dependency changes.Why the output is bit-identical
RandomState.rand(n)returns exactly the same numbers, in the same order, asnsuccessive calls torand(), and leaves the generator in the same state afterwards.state.log_prob[S1]lists walkers in the same ascending order as the oldall_inds[S1]loop, andfactorsandnew_log_probsare already in that order.(f + nlp) - log_prob, in the same order and at the same precision.-inflog-probabilities give the samenan → rejectresult as before.False, so assigningaccepted[S1]gives the same result as the old "set toTrueif accepted" loop.Testing
StretchMove,WalkMove,DEMove,DESnookerMove,KDEMove, and a weighted mix of moves.vectorize=True, an odd number of walkers,nsplits=3,randomize_split=False, a likelihood that returns-inf, blobs, and alongdoublebackend.longdoublelog-prob array matches in every value; its only byte differences are in the unused padding bytes of x86's 80-bit long double, which come fromnp.empty.test_vectorized_accept_matches_loopintests/unit/test_stretch.py. It runs the newproposealongside a copy of the original loop for 50 steps and asserts identical acceptance flags, coordinates, log-probabilities and RNG state. It covers 32 and 33 walkers,nsplits2 and 3, and-inflog-probabilities.test_tqdm_modes, which needsipywidgetsand is unrelated to this change.blackandisort(the versions pinned in.pre-commit-config.yaml) andpyflakesare clean on the changed files.Performance
Iterations per second with a trivial Gaussian log-prob, so the numbers mostly reflect emcee's own overhead. Best of 3 runs, with the old and new versions run alternately. Python 3.13, NumPy 2.5, x86_64.
vectorize=Truevectorize=Truevectorize=Truevectorize=TrueThe speedup grows with the number of walkers because the removed loop ran Python code once per walker per step. With an expensive likelihood the absolute saving per walker per step stays the same, but it becomes a smaller share of total runtime.
Generated by Claude Code