A simple solution for randomness copy problem

Ilya Yaroshenko via Digitalmars-d digitalmars-d at puremagic.com
Tue Nov 29 00:50:52 PST 2016


Hello,

The problem is that a structure for a random algorithm or a 
random variable may holds its own precomputed random state, which 
is not correct to copy.

 From [1] by Joseph Rushton Wakeling:
> Essentially the sampling algorithm carries out its own little 
> internal pseudo-random process which falls back to using the 
> RNG when necessary.
> I've had a lot of conversations with different people around 
> this issue, and I've tried out a bunch of different ideas, 
> including functor RNGs which would be wrapped with a range API 
> accessing them via pointer (a suggestion Dicebot among others 
> made to me).  In every case, I've run into difficulty when 
> moving from RNGs and distributions to random algorithms like 
> RandomCover and RandomSample.

The solution is to add a `hot` flag that indicates that 
precomputed random values can be used and reset this flag in copy 
constructor. It works without performance issues for the Vitter's 
algorithm and Normal sampling (of course if you don't copy the 
struct for each call).

Both Vitter's random sample algorithm and normal distribution 
needs this flag or analog anyway (at least in my implementations).

Below are 2 reduced code samples. The first one is for Vitter's 
strides for random sample and the second one is for Normal 
distribution.
The actual code for random sample (`sample`) can be found at [2], 
and for `NormalVairable` at 3.

[1] 
http://forum.dlang.org/post/gpsilefdillwtleuwohl@forum.dlang.org
[2] 
https://github.com/libmir/mir-random/blob/master/source/mir/random/algorithm.d
[3] 
https://github.com/libmir/mir-random/blob/master/source/mir/random/variable.d

----------- Vitter's Algorithm D ---------
struct VitterStrides
{
     private double vprime; // A future/pregenerated random value
     private bool hot; // A flag that indicates that vprime can be 
used

     this(this)
     {
         hot = false;
     }

     sizediff_t opCall(G)(ref G gen)
     {
         ...
     }
}

---------- Normal Distribution ----------
@RandomVariable struct NormalVariable(T)
     if (isFloatingPoint!T)
{
     private T y = 0;
     private bool hot;

     this(this)
     {
         hot = false;
     }

     ///
     T opCall(G)(ref G gen)
         if (isSaturatedRandomEngine!G)
     {
         T x = void;
         if (hot)
         {
             hot = false;
             x = y;
         }
         else
         {
             // compute independent x, y at once
         }
         ...
     }
}


More information about the Digitalmars-d mailing list