0

I'm working on an algorithm (procedural racetrack generator) whose outcome, in the general case, is solely based on the RNG outputs. But in some specific scenarios, I need to provide to user the ability to bypass some generation steps (e.g. terrain conformation) without affecting the rest of the generation process.

Let me make a simple practical example:

## Procedural racetrack ##
                                                         *
           | Track shape generation | Terrain generation | Surfaces generation | Assets picking |
RNG stream | 1 2 3                  | 4 5 6 7            | 8 9                 | 0              |
## User-overridden racetrack ##
                                                         *
           | Track shape generation | Terrain generation | Surfaces generation | Assets picking |
RNG stream | 1 2 3                  | provided by user   | 4 5                 | 6              |

As you can see, in the User-overridden racetrack case, the fact that the Terrain generation step is bypassed (and so no RNG output is consumed) alters all the subsequent generation steps. The number of RNG outputs required for every generation step in not constant among different racetracks generation (and it isn't even predeterminable in advance).

What I'm looking for is some sort of RNG synchronization operation (probably not the most corrected term to use...) to put in between the Terrain generation step and the Surfaces generation step to have the same RNG stream from the * onwards, regardless if the terrain is provided by user or not. I thought about something like:

uint64_t seed = // initialized with racetrack ID
pcg32 rng(seed);

// Do Track shape generation step
// Do Terrain generation generation step

seed = seed + k; // where k is some constant
rng.seed(seed);

// Do Surfaces generation step
// Do Assets picking step

But I don't know if seed = seed + k; is a valid reseeding approach (or there's something better) and if some value is better than others for k.

Reference to the question originally submitted in the Issues section of PCG repository : https://github.com/imneme/pcg-cpp/issues/72

TaaTT4
  • 87
  • 1
  • 5
  • Related: https://stackoverflow.com/questions/64965398/when-and-why-are-random-number-generators-not-sampled-for-certain-functions-and/64967064#64967064 Your issue is not specific to PCG, though; it's not a problem with PCG as opposed to another pseudorandom number generator. – Peter O. May 10 '21 at 11:13
  • Indeed I would have the same issue using another RNG (e.g. mt19937). I'm using PCG because my seeds (which correspond to racetrack IDs) are `uint32_t` numbers and, for what I've understood, PCG is the RNG which produces best results if seeded with 32 bits of data. – TaaTT4 May 10 '21 at 14:49

1 Answers1

1

This comes down to assigning a separate PRNG for each of your four (or more) stages of generation (in your example, track shape generation, terrain generation, surface generation, and asset picking), and assigning a seed to each one of them. (In your case, one way this can work is to form a hash of the racetrack ID, an ID for each generation stage, and a fixed bitstring, and use that hash as the seed for each PRNG.)

In general, however, your choice of seed may matter, in practice if not in theory.

For example, there are many PRNGs for which a given seeding strategy will produce correlated pseudorandom number sequences. For example, in most versions of PCG, two sequences generated from seeds that differ only in their high bits will be highly correlated ("Subsequences from the same generator").

To reduce the risk of correlated pseudorandom numbers, you can use PRNG algorithms, such as SFC and other so-called "counter-based" PRNGs (Salmon et al., "Parallel Random Numbers: As Easy as 1, 2, 3", 2011), that support independent "streams" of pseudorandom numbers by giving each seed its own independent sequence of pseudorandom numbers. (Note, however, that PCG has a flawed notion of "streams".) There are other strategies as well, and I explain more about this in "Seeding Multiple Processes".

See also:

Peter O.
  • 32,158
  • 14
  • 82
  • 96
  • Thank you! There's a lot of information to go deeper into this topic. I wasn't aware of "counter-based" RNGs which seem to be the most useful class of RNG in my scenario. – TaaTT4 May 14 '21 at 13:47