-
-
Notifications
You must be signed in to change notification settings - Fork 21.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to restore RandomNumberGenerator
state
#44089
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thanks for the fix and the test suite.
@timothyqiu @avencherus Could either of you confirm that this addresses your use case? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested - Seems worked fine
Yeah it works fine as far as I could tell. Storing the seed and state value and setting the seed and state back to these values allows the generation to carry on where it left off.
Results in:
|
Restoring the That said, there's a reason why #35764 proposed to have |
I'm not sure exactly what the criteria is for the setter/getter to be represented with properties. Would be curious if there is a guideline to this. |
IIUC, "seed" is a term to describe what initialized the random sequence. But it's previously used as a mixture of both RNG initializer and RNG state. Separating into Adding a separate |
I'd just like to restate one idiosyncrasy of this class as-is. If you want to make an exact copy of an RNG, you have to copy over the right properties in the right order:
Although the above example uses two separate RNG objects, the same steps must be followed when saving or loading the RNG state elsewhere, such as to/from a save file. Not everyone will care about restoring both the seed and the state of an RNG, but those that do will need to keep in mind that setting the One possible solution, which is similar how the full-featured C++ PCG headers do it, is to make |
Info: Unity's If we want to play safe and prevent extra I think this should be discussed at GIP first to reach consensus, but I hope the changes themselves in this PR are unambiguous, but yeah I agree that it may be easy to do a mistake with such API, but then we're talking about adding extra layer of complexity to the class (which Godot's development philosophy might not tolerate). 😛 I think most people will still use just the |
- added `state` as a property to restore internal state of RNG; - `get_seed()` returns last seed used to initialize the state rather than the current state. Co-authored-by: MidZik <[email protected]>
I have updated the documentation to mention that setting the seed has a side effect of changing the state, with code snippets suggesting the correct order of initialization. |
avencherus
MidZik
There are cases where setting properties have certain "side effects" as well already in Godot, most prominently seen in
So I'm just saying that perhaps it's not that catastrophic, and that's just one of the things which can be properly documented instead of over-engineering the solution. I'm perfectly fine with current API myself. |
I wrote a proposal to discuss this: godotengine/godot-proposals#1950. |
It's been a few years since I last messed around with prng, and I'm lacking time to review Godot's implementation. Though I have this vague memory that the seed and state in some methods are one and the same thing. The seed would just conceptually be the starting point (what you're seeding the function with), and the math would just modify the value in a deterministic way. If it's the same case with Godot's implementation, then maybe it's conceptually easier for most to split things apart to express these ideas with their own language and intents. Otherwise it requires some specialized knowledge here to have these expectations. Wish I knew more here, as it'd probably be clearer to give some pseudo code instead. At any rate, hope this doesn't get wound up in a debate about best practices or API purity. I'll use whatever you come up with. I'm only looking forward to a reliable way via GDScript to restore the sequences of the RNG class without having to deviate from the core code of the 3.2 branch. |
I wouldn't fixate on the exact implementation, the interface could be agnostic. I think it's totally possible that some other RNG implementation has better distinction between initial state/seeding/current state mechanism.
Yes, I'd just merge this PR sooner than later because it does fix an existing bug with The test suite is hopefully correct so if anyone would like to remove the |
Yep sounds good to me. Any concern on the impact this may have on compatibility for |
Thanks! |
Well I think technically it does break compatibility, but then users rely on the buggy behavior in 3.2 in that case... I'd say it's unlikely that a regular user would want to retrieve the seed, most of the time it's the other way. That said, I'm not sure whether this bug fix is that critical to be cherry-picked, but I wouldn't mind if this could be cherry-picked personally, I've never had to use it like that. I usually store the seed somewhere else instead (upon initialization of RNG class). And I think it would be easy to fix this in projects as long as |
I think it's more of a compatibility concern for 3.1. This wouldn't close #44031 until it has been cherry-picked. The unintended usage of seed to restore state isn't working anymore in 3.2. I haven't been doing the kind of testing that would expose this in a while, so I didn't noticed my RNG was broken until timothyqiu posted the issue. At present 3.1 and master have ways to restore RNG state, but 3.2 does not. |
Well the compatibility breakage from 3.1 to 3.2 was known and intentional, as it was fixing issues with the 3.1 RNG implementation. Then #44031 was not intentional, but my question is whether fixing it will break compatibility between 3.2-3.2.3 and 3.2.4, e.g. for users who do manage to use the 3.2-3.2.3 RNG in a reproducible way, and expect this to stay compatible. |
Sorry, I don't think I understand. Is there a way to reproduce the RNG state in 3.2? Or do you mean some situation where the RNG is created again with a seed and they rely on the same results from there? In the first case, I don't know, the only work around I can think of to that is to store the number of times you use an RNG and when making a new one use it that many times to get it to return to the desired state.
In the other case, works the same as far as I can tell.
Or something else? |
I say cherry-picking this to 3.2 has little chance/impact of breaking existing ways of having reproducible results with RNG, in contrast with potentially breaking changes such as That said, I think you'd still be able to do the workarounds even with a bug fix in this PR, including the above snippets. |
The cherry-picked version should only add the
The above workaround function lets a user get a random float from an RNG, and also puts the RNG into a state where you can save the seed and get reproducible results. At the expense of drastically reducing the RNG quality. |
@MidZik Do you have some usage code to go with that? I couldn't figure out how to restore state with that function. |
@avencherus You just save and restore the
The important detail is that after calling |
So I'm still not sure about what should be done exactly to fix the issue in |
As MidZik said, I think just exposing the |
Sounds good. I'd welcome a tested PR that does this :) |
Closes #44031 (CC @timothyqiu, @Chaosus).
Note that I haven't done the revert here as in #44037.
Based on #35764 (only the changes pertaining to RNG class are retained).
state
as a property to restore internal state of RNG;get_seed()
returns last seed used to initialize the state rather than the current state now.Added a test suite with a snippet from #44031, with test cases for restoring the sequence from resetting the state and the seed.
Resetting the seed is enough to achieve reproducible sequence of random numbers, but the state can be restored directly if you want to reproduce the same numbers at different times (given the same seed), at least that's how I understand the problem, just see the test cases for concrete usage examples.
The
state
property should only be set to values returned by the same property, else the RNG quality will likely suffer.Additionally,
randomize()
could also return the new seed, but sinceget_seed()
is functional now, this might not be necessary.Compatibility breakage is minimal, and the only breaking change is that
get_seed()
will correctly return the seed, and not the previous state.