OpenRAND is a C++ library designed to foster reproducible scientific research by providing a robust and replicable random number generation solution. It is a simple header only library that is performance portable, statistically robust, and easy to integrate into any HPC computing project.
Cross-Platform Support: OpenRAND is designed to work seamlessly across various platforms, including CPUs and GPUs. Its header-only library design allows it to be easily integrated into your project.
User-Friendly API: OpenRAND provides a user-friendly API, making it straightforward to generate random numbers in your applications.
Statistical Robustness: Built-in tests ensure that random number streams generated by OpenRAND are statistically robust, with no discernible patterns.
Performance: It is as fast and often faster than native libraries like libstdc++ or Nvidia's Curand, with minimal memory overhead. See the paper for details.
OpenRAND is header only, so there is no need to install it. You can simply copy the header files in include/
directory into your project and you're good to go!
You can also use CMake. To integrate OpenRAND into your CMake project, add the following lines to your CMakeLists.txt file:
include(FetchContent)
FetchContent_Declare(
crng
GIT_REPOSITORY https://github.com/msu-sparta/OpenRAND.git
GIT_TAG main
)
FetchContent_MakeAvailable(crng)
Alternatively, you can install OpenRAND by running make install
from a build directory, and linking to it using target_link_libraries(Executable PRIVATE OpenRAND::OpenRAND)
from an application.
You can optionally turn on tests, examples and benchmarks using OpenRAND_ENABLE_TESTS
, OpenRAND_ENABLE_EXAMPLES
and OpenRAND_ENABLE_BENCHMARKS
flags respectively. If you want to build the TestU01 statistical test suite, set CMake variable TESTU01_PATH
to locally installed TestU01 library location. For practrand, pipe the output of pract_rand*
executables (built by default when testing enabled) to Practrand's RNG_test
executable.
Here's a simple example of how to generate random numbers using OpenRAND:
#include <openrand/philox.h>
int main() {
using RNG = openrand::Philox; // Or, for example, Tyche
// Initialize RNG with seed and counter
RNG rng(1, 0);
// Draw uniform random numbers of many types
int a = rng.rand<int>(); // range [0,2^32)
auto b = rng.rand<long long int>(); // range [0,2^64)
double c = rng.rand<double>(); // range [0,1)
float f = rng.rand<float>(); // range [0,1)
// use std distribution functions with RNG
std::lognormal_distribution<double> dist(0.0, 1.0);
double x = dist(rng);
...
}
The seed should correspond to a work-unit of the program. For example, it could be the unique global id of a particle in a monte carlo simulation, or the (1D) pixel index in a ray tracing renderer. The counter should be incremented every time a new generator is needed for a particular seed. This is helpful, for example, when a particle undergoes multiple kernel launches in it's lifespan (with a new random stream required in each).
Below is a simplified monte carlo paticle simulation example that runs for 10000 time steps. Conveniently, we can simply use the iteration number as the counter
for all particles. For seed
, we assume each particle below has a unique global id atribute called pid
.
__global__ void apply_forces(Particle *particles, int counter){
int i = blockIdx.x * blockDim.x + threadIdx.x;
Particle p = particles[i];
...
// Apply random force
RNG local_rand_state(p.pid, counter);
p.vx += (local_rand_state.rand<double>() * 2.0 - 1.0);
...
}
int main(){
...
// Simulation loop
int iter = 0;
while (iter++ < 10000) {
apply_forces<<<nblocks, nthreads>>>(particles, iter);
...
}
}
For a quick intorduction to OpenRAND: please refer to this guide.
For more detailed information, refer to the doxygen doc here
Please refer to the paper published in (SoftwareX) journal for detailed performance figures, our design choices etc.
We welcome all sorts of contributions from the community- code, bug reports, documentation improvements, and any general feedback is always appreciated.
If you want to contribute code, please note that we follow Github Workflow for development. In short, fork this repo; create a new branch off of main
in your fork; make changes, commit, push your changes and then open a Pull Request.
If you'd like to make a major change or introduce a new feature, please open an issue first to discuss it with us.
If you use OpenRAND for your research, we would appreciate it if you cite our paper. Below is the BibTeX entry for our publication:
@article{KHAN2024101773,
title = {OpenRAND: A performance portable, reproducible random number generation library for parallel computations},
journal = {SoftwareX},
volume = {27},
pages = {101773},
year = {2024},
issn = {2352-7110},
doi = {https://doi.org/10.1016/j.softx.2024.101773},
url = {https://www.sciencedirect.com/science/article/pii/S2352711024001444},
author = {Shihab Shahriar Khan and Bryce Palmer and Christopher Edelmaier and Hasan Metin Aktulga}
}
This project is licensed under the MIT License - see the LICENSE file for details.