Why reproducible random-number streams matter
A simulation can change even when its model equations and input data appear unchanged. Random draws may differ because the seed was not set, the generator changed, or the order and number of random-number calls changed. In a pharmacometric workflow, draws may be used for several distinct purposes: sampling parameter uncertainty, constructing a target covariate population, generating individual random effects, and adding residual error. Reproducing the final output requires control over all of those sources of randomness.
A seed is useful, but recording a single seed is not always enough. If one section of a script makes an extra random draw, later draws from a shared sequence can shift. Assigning and recording streams by stochastic component makes it easier to reproduce a run and to determine which component changed. It does not, by itself, establish that the draws are statistically independent or that results will be identical across different software implementations.
A workflow typically transforms generator outputs into the values it needs. For example, uniform draws may be transformed into normal random effects, or uniforms may select records from an empirical covariate dataset. The seed controls the underlying generator sequence; the transformation and its implementation also affect the resulting values.
From a seed to a reproducible run
Let \(S_0\) be the initialized generator state, let \(T\) be its state-update rule, and let \(G\) convert a state into a returned random value. In a simple generator, the process can be written as
If two runs start from the same \(S_0\) and apply the same \(T\), \(G\), and call sequence, their states and returned values match at every step. The argument is by induction: the initial states agree; if the states agree at step \(k\), applying the same update rule gives the same next state, and applying the same output rule gives the same next value. Consequently, the same sequence of transformations produces the same simulated quantities, subject to the same numerical implementation.
The call sequence is important. If a routine consumes additional generator outputs, all later values from that same sequence may change. A seed therefore specifies a starting point, not a promise that every downstream result remains unchanged after edits to the workflow.
Worked Example: A seed is not a component-level guarantee
Suppose a hypothetical generator produces the uniform sequence \(0.12, 0.81, 0.37, 0.64, 0.25, \ldots\) from a fixed seed. A script uses the first three values to select three covariate records and the next value to generate a random effect. The random effect therefore uses \(0.64\).
Now the covariate procedure is changed to select four records. It consumes the first four values, so the random-effect procedure receives \(0.25\) instead. The seed did not change, but the random effect did, because the shared stream was consumed differently.
If covariate sampling and random effects instead use separate, fixed streams, adding a covariate draw consumes only the covariate stream. The random-effect stream still begins at its assigned state. This protects the random-effect draws from that particular change in covariate draw count. The values shown are hypothetical; the example illustrates sequence consumption, not the output of a specified software generator.
Assigning streams to simulation components
For a simulation that samples uncertain parameters, covariates, random effects, and residual error, define those as distinct stochastic components. Assign each a reproducible stream or generator-supported substream, and document the mapping. A stream identifier can be more informative than a bare integer seed when the generator provides a formal stream-management facility.
Do not assume that four different integer seeds automatically produce independent streams. The quality and relationship of the sequences depend on the generator and the way streams are constructed. Use a generator's documented stream or substream mechanism when available, and follow its guidance for assigning streams. If the implementation offers only seed-based initialization, document that limitation rather than claiming independence from distinct seed values alone.
A practical seed record should connect each stochastic component to its stream and to the settings that determine how that stream is interpreted. At minimum, record:
- the component name and its assigned seed or stream identifier;
- the PRNG algorithm and implementation, including relevant software or package version;
- the number of draws requested and the transformations applied to them;
- the simulation code version and the inputs that affect draw generation.
For a rerun to match, also avoid hidden randomness: every stochastic operation must use the intended generator rather than an uncontrolled default. Record or fix relevant options for transformations and numerical routines when they can affect results. Exact reproduction across software versions or computing environments may require more than matching integer seeds.
Worked Example: Building a component seed ledger
Consider a hypothetical simulation with four stochastic components. The team uses one documented generator implementation and a supported stream-allocation procedure. The values in the ledger below are illustrative stream identifiers, not a recommendation that these integers are suitable for every generator.
| Component | Assigned stream identifier | Use |
|---|---|---|
| Parameter draws | 41021 | Draw parameter sets for each simulation replicate |
| Covariate sampling | 41022 | Sample or generate each virtual patient's covariates |
| Random effects | 41023 | Generate individual-level random effects |
| Residual error | 41024 | Generate observation-level residual error |
Suppose the run requests 500 parameter sets, 10,000 covariate records, 10,000 random-effect vectors, and 50,000 residual draws. The ledger should record those requested counts, along with any distributional transformations and their parameterization. These counts help detect a changed call pattern: if a rerun requests 10,001 random-effect vectors, the run is not the same computation even if the stream identifier is unchanged.
For instance, if the random effects are generated by transforming standard-normal draws through a specified covariance factor, record that transformation and the covariance factor used. A seed alone does not define which covariance model was applied. The stream ledger provides reproducible starting points; the model inputs and transformations define what is done with the draws.
Keeping draws aligned with their intended role
A stream assignment is most useful when it is stable: parameter draws always come from the parameter stream, covariate draws from the covariate stream, and so on. Avoid resetting one shared generator to the same seed at the start of multiple components. Doing so can make components reuse identical underlying sequences, which may induce unintended dependence. Separate component streams should be assigned using the generator's supported mechanism, not created by repeatedly restarting an identical sequence.
The component boundary should reflect the simulation design. If residual errors are generated separately for multiple endpoints, the workflow may need a documented allocation within the residual component so that a change to one endpoint does not unexpectedly shift another endpoint's draws. The choice of allocation depends on the intended design; it should be explicit and stable, not an accidental consequence of code execution order.
Worked Example: Reproducing one virtual patient's prediction
Suppose a hypothetical concentration model uses a parameter draw \(\theta=1.80\) mg/L, a patient's weight \(w=70\) kg, a random effect \(\eta=-0.100\), and residual error \(\epsilon=0.0800\) mg/L. For illustration, the simulated observation is defined as
The covariate stream supplies \(w=70\) kg, the parameter stream supplies \(\theta=1.80\) mg/L, the random-effects stream supplies \(\eta=-0.100\), and the residual stream supplies \(\epsilon=0.0800\) mg/L. Substitution gives
To reproduce this value, it is not sufficient to record only the final concentration or one global seed. The run record must identify the four stream assignments, the generator implementation, the transformations used to obtain each draw, and the model equation. This example describes one hypothetical realization; the numbers are not study results.
Diagnostics, alternatives, and limitations
When a rerun differs, first determine whether the underlying draws differ or whether the same draws were transformed differently. Compare saved component-level draws, if available, and inspect the generator settings, stream assignments, draw counts, and call order. If the component draws agree but predictions do not, investigate model inputs, transformations, and numerical settings. If only one component's draws differ, check whether its stream or generator changed; if several downstream components differ, a shared-stream call-count change is a plausible cause.
A useful reproducibility check is to run the same workflow twice from a clean initialization and compare selected draws and outputs. For exact comparisons, specify what must match: individual random draws, simulated records, or only a summary. A summary can match by coincidence even when underlying draws differ, so it is a weaker check than comparing component draws directly.
| Approach | Strength | Limitation |
|---|---|---|
| One global seed | Simple to set and can reproduce an unchanged script in a fixed environment | Changes in call order or draw counts can shift later components' draws |
| Separate component streams | Helps isolate changes and makes each source of randomness identifiable | Requires careful stream assignment and documentation; distinct seeds alone do not prove independence |
| Save and reuse realized draws | Can replay the exact sampled inputs without regenerating them | Requires storage and clear links between saved draws and the model inputs or run that used them |
Stream-based reproduction has limits. A generator may produce different results after a software update, or a transformation routine may change its algorithm. Different hardware or numerical libraries can also affect derived calculations even when the raw draws match. Therefore, record the generator implementation and relevant versions, and distinguish reproducibility of random draws from bit-for-bit reproducibility of all model outputs.
Common mistake
A related mistake is to treat different integer seeds as proof that streams are independent. Different seeds can initialize different states, but statistical independence is a property of the stream-construction method and generator, not something established merely by comparing seed values. Use documented stream allocation and describe exactly what is guaranteed.
Identify every step that consumes randomness, including parameter, covariate, random-effect, and residual draws.
Use the generator's documented method for separate streams or substreams; do not infer independence from distinct integers.
Store stream identifiers, generator implementation, versions, requested draw counts, and transformations alongside the relevant run inputs.
Reinitialize the streams and compare component-level draws and outputs to the reproducibility target you specified.
Check Your Understanding
Answer each question, then compare your reasoning with the solutions.
- Why can two runs with the same global seed produce different random-effect draws after the covariate sampler is changed to consume one additional draw?
- Does assigning different integer seeds to parameter and residual draws establish statistical independence? Explain.
- Name four items, beyond a single seed, that should be documented to support a reproducible rerun.
- In a rerun, component-level random draws match, but predicted concentrations differ. What should be checked next?
- What does a successful same-seed rerun establish, and what does it not establish about results from a different software version?
Solutions. (1) With a shared sequence, the extra covariate draw consumes a value that would otherwise have been used by the random-effect procedure, shifting its position in the sequence. (2) No. Independence depends on the generator and its documented stream-construction method; different seed values alone are not proof. (3) Suitable items include the PRNG algorithm and implementation version, stream identifiers, draw counts, transformations, simulation code version, and relevant inputs. (4) Check model inputs, equations, transformations, and numerical settings, because the discrepancy occurs after the component draws. (5) It supports reproducibility under the same generator, call sequence, transformations, and computational settings; it does not guarantee identical draws or outputs after a generator, software, or numerical implementation change.