Skip to content

[rand_pcg] Add internal state fetching and construction#108

Merged
dhardy merged 2 commits intorust-random:masterfrom
kaathewisegit:pcg-state
Apr 11, 2026
Merged

[rand_pcg] Add internal state fetching and construction#108
dhardy merged 2 commits intorust-random:masterfrom
kaathewisegit:pcg-state

Conversation

@kaathewisegit
Copy link
Copy Markdown
Contributor

This PR adds methods for retrieving inner state from a Lcg128Xsl64 instance and initializing it from that inner state.

I have a use case very similar to #64, where I want to manually serialize and deserialize an RNG object without going through serde. PCG is also not cryptographic, so retrieving its state shouldn't be problematic. from_state is almost the same as new, but new doesn't allow passing increment verbatim because it sets the lowest bit so that increment is odd (and it has to do that to match the original implementation).

This is only implemented for Pcg64. I can implement it for other variants if that's a problem

@dhardy
Copy link
Copy Markdown
Member

dhardy commented Apr 11, 2026

I don't have any problem exposing the state, but would prefer the following approach:

fn state(&self) -> u128
fn stream(&self) -> u128

This API is more flexible and can be used with new. The latter has to do self.increment >> 1 but I doubt that's a problem in practice.

If you agree to this API, please do the same for all rand_pcg RNGs, then prepare the release by bumping the version number in Cargo.toml and the CHANGELOG.

@kaathewisegit
Copy link
Copy Markdown
Contributor Author

The reason I need this functionality is for reproducible simulations. I have an MCMC with Pcg64 as the source of randomness, and I need to be able to dump it to a checkpoint file and restore an identical generator later. But if parameters go through new, they get changed in from_state_incr, meaning the two generators diverge.

This is already possible with serde, but I use a different serialization library. So I thought it'd be nice to have a way to do the same thing without serde here

@dhardy
Copy link
Copy Markdown
Member

dhardy commented Apr 11, 2026

Sorry, I was forgetting that fn new advances the state. I suggest adding the following together with the methods I mentioned above:

    /// Construct an instance using a pre-initialized `state`
    ///
    /// Unlike [`Self::new`], this method does not mutate `state`. It may
    /// therefore be used with [`Self::state`] to reconstruct an RNG.
    ///
    /// Note that the highest bit of the `stream` parameter is discarded
    /// to simplify upholding internal invariants.
    pub fn from_state(state: u128, stream: u128) -> Self {
        // The increment must be odd, hence we discard one bit:
        let increment = (stream << 1) | 1;
        Lcg128Xsl64 { state, increment }
    }

@kaathewisegit kaathewisegit changed the title [rand_pcg] Add to_state and from_state to Lcg128Xsl64 [rand_pcg] Add internal state fetching and construction Apr 11, 2026
@kaathewisegit
Copy link
Copy Markdown
Contributor Author

  • Added the state and stream methods and a from_state constructor for the 3 main generators (I used a macro defined in lib.rs for this to duplicate since they are identical, but I can undo that and split them back into the module files).
  • Added state method for Mcg128Xsl64. It's new doesn't do any processing, so there was no need for from_state.
  • Added tests to check that the restoration works correctly and that Mcg128Xsl64's state is always odd
  • Updated the changelog
  • Bumped the version to 0.10.2 (from 0.10.1)

Comment thread rand_pcg/CHANGELOG.md Outdated
Copy link
Copy Markdown
Member

@dhardy dhardy left a comment

Choose a reason for hiding this comment

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

LGTM; just needs the changelog title fixing for the release.

@dhardy dhardy merged commit cc285e9 into rust-random:master Apr 11, 2026
14 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.

2 participants