It's also an Obj-C framework and so may not always match the needs of Swift code.
You might want to check out Pointfree's library: GitHub - pointfreeco/swift-gen: 🎱 Composable, transformable, controllable randomness. – I believe they have what you're looking for!
Good suggestions here, but shouldn't the ability to seed a standard PRNG to a given state (when it is desired) be built-in?
Last time I brought this up, with my own PRNG protocol, I had a State
associated type for that purpose. It was suggested to me that it would be better not to do that until we had the machinery to require that the state is trivially copyable. So, I removed that and left only the ability to initialize the PRNG from another RandomNumberGenerator
.
Having said that, a good first approximation would be a property that returns a [UInt8]
representing the current state, and an initializer that takes a [UInt8]
representing the desired state. With the obvious precondition that the state you initialize with must have come from the same kind of generator. (And each generator can document any intended methods to create such an array by hand).
Hope this is not deemed too old thread to resurrect to warrant a new thread.
A typical scenario in my case would be to have a reproducible sequence of random numbers, e.g. to ease debugging of some corner case.
While I could totally switch from:
Int.random(in: ......)
to the version of this function that takes RGN as a parameter:
Int.random(in: ......, using: &myRNG)
and do this when calling all similar API's that take RNG parameter (like "shuffle", or "randomElement") I can't do this in cases when I am using a third party code that doesn't allow me to customise what RNG they use.
I believe an option similar to "SWIFT_DETERMINISTIC_HASHING" is a good call: e.g. "SWIFT_DETERMINISTIC_RANDOMNESS". If present it could take a number as a starting "seed". Even fi it works in Xcode + debug only would be a good start.
Separate but related to that, as a more advanced debugging/diagnostic feature we may have a secondary similar setting that would override the RNG to use:
// normall usage:
Int.random(in: ....) // uses system RNG
Int.random(in: ...., using: &custom) // uses custom RNG
// when some special diagnostic option is switched on:
Int.random(in: ....) // uses some explicitly specified RNG
Int.random(in: ...., using: &custom) // ignores custom RNG and uses some explicitly specified RNG
For now I'm using this nasty hack as a workaround:
@_cdecl("swift_stdlib_random")
func swift_stdlib_random(_ buffer: UnsafeMutablePointer<UInt8>, _ count: Int) {
...
}
which works only under certain optimization settings (-O or -Osmall with whole module optimization switched off). The hack I don't feel good about even if that's for in-house use only.
In a multithreaded or concurrent environment, the order of random calls is not generally deterministic, so the random values observed are deterministic, so replacing the systemRNG with a seeded RNG does not get you reproducibility (unlike in the case of hashing, which is not effected by previous hashes). You have to make the RNG an explicit parameter to accomplish this task, and once you've done that you don't need to do anything else, you just substitute your deterministic RNG for the system one as that parameter.
Very good point. Even in a single threaded non concurrent environment I could make it non deterministic:
setRandomSeedSomehow(42)
let x = Int.random(in: .min ... .max) // this is deterministic
let stop = Date(timeIntervalSinceNow: 0.001)
while Date() < stop {
_ = Int.random(in: .min ... .max)
}
let y = Int.random(in: .min ... .max) // this is not deterministic
The option(s) I am looking for could be useful under "deterministic" conditions.