msu-sparta / OpenRAND

Reproducible random number generation for parallel computations
https://msu-sparta.github.io/OpenRAND/
MIT License
26 stars 2 forks source link

Ability to use with C++'s exsiting pseudo random generation framework #14

Closed define-private-public closed 9 months ago

define-private-public commented 10 months ago

Hi. This is a very nice project here. I have an open source RayTracing project. It can act as a way of benchmarking certain C++ features and libraries.

For example, I swapped out the standard Mersenne Twister engine (std::mt19937) with PCG32 and saw both better performance and nicer random.

I wanted to try out OpenRAND to see if it might be more performant than PCG32. But when I tried to plug it in I noticed that its API differs from C++'s built in interface. Including things like std::seed_seq or the random number distrubtors.

Having OpenRAND work with C++'s existing framework would be very beneficial IMO.

Shihab-Shahriar commented 10 months ago

Hi, thanks for your interest in OpenRAND.

Can you please tell me what particular compatibility you're looking for? I'll be happy to add anything that's reasonably possible. Regarding you particular examples:

  1. OpenRAND generators does support standard cpp random number distributors. Here's a code snippet:

    
    // Initialize RNG with seed and counter
    RNG rng(1, 0);
    
    // use std distribution functions with RNG
    std::lognormal_distribution<double> dist(0.0, 1.0);
    double x = dist(rng);
  2. My understanding is that seed_seq serves two purposes: inititiazling a single generator that has huge state- not relevant for OpenRAND since it uses only 96 bits, a 64-bit seed and 32-bit counter. The other, perhaps more common use is it provides a set of good initial seeds for multiple generators so they don't produce dependent/correlated streams (e.g. for multithreaded applications). A key feature of OpenRAND is that it doesn't need to have a set of seeds with special properties to produce independent streams, any set of seeds will produce good quality data so long the seeds are unique. You can just use RNG rng(omp_get_thread_num(), 0) to initialize local rng in a thread for example.

By the way your project looks nice. I forked the GPU accelerated version of that same code with a previous iteration of OpenRAND: it's here

define-private-public commented 10 months ago

https://github.com/define-private-public/PSRayTracing/blob/master/render_library/RandomGenerator.h#L178

In my code, I was trying to see if I could plug in openrand::Phillox there. And well, it didn't compile (which was kinda expected). I was hoping to make minimal changes to my RandomGenerator object to try out OpenRand. std::mt19937 and pcg32 can work interchangeably.


My project is meant to operate a bit differently from the original "Ray Tracing in One Weekend" code. It has a similar architecture and outputs (and being CPU bound only). But it's goal was to see how far one could push standard vanilla C++ (or not requiring hefty 3rd party libraries); mostly by rewriting code. If OpenRAND is more performant than PCG32 I'd love to swap it out at the RNG for the project.

Shihab-Shahriar commented 9 months ago

I was looking at PCG32 code, here is a minimal implementation from the author:

typedef struct { uint64_t state;  uint64_t inc; } pcg32_random_t;

uint32_t pcg32_random_r(pcg32_random_t* rng)
{
    uint64_t oldstate = rng->state;
    // Advance internal state
    rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
    // Calculate output function (XSH RR), uses old state for max ILP
    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
    uint32_t rot = oldstate >> 59u;
    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}

No loops (or rounds); there is a 64 bit multiply, but other than that it's mostly extremely efficient bit operations. In terms of speed, I do not believe it's possible for any OpenRAND generator to beat this.

I had considered including the PCG to OpenRAND. But at the author herself notes, it can not consistently produce statistically independent streams for any set of unique seeds. That's a very valuable property to have, it allows users to seamlessly use application variables to instantiate generators without going through a seperate seed generation step.

define-private-public commented 9 months ago

So in a nutshell, you don't think that OpenRAND could beat PCG32 in performance? That's mainly what I'm looking for.

Thank you for your investigation on this. I really appreciate it in try to squeeze more throughput of out my project.