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.
OpenRAND is header only, so there is no need to install it. Simply copy the header files in include/
directory into your project and you're good to go!
You can also install OpenRAND using CMake. To integrate OpenRAND into your CMake project, add the following lines to your CMakeLists.txt file:
EDIT THIS STUFF FOR NEW URL
include(FetchContent)
FetchContent_Declare(
crng
GIT_REPOSITORY https://github.com/Shihab-Shahriar/rnd.git
GIT_TAG main
)
FetchContent_MakeAvailable(crng)
Here's a simple example of how to generate random numbers using OpenRAND:
#include <phillox.h>
int main() {
using RNG = Phillox; // Tyche
// Initialize RNG with seed and counter
RNG rng(1, 0);
// Draw random numbers of many types
int a = rng.rand<int>();
auto b = rng.rand<long long int>();
double c = rng.rand<double>();
float f = rng.rand<float>();
return 0;
}
The seed should correspond a work-unit or processing element of the program. For example, it could be the unique global id of a particle in a monte carlo simulation, or the pixel flat index in a ray tracing renderer. The counter should be incremented every time a new random number is drawn for a particular seed. This is helpful, for example, when a particle undergoes multiple kernel launches (with a new random stream required in each) in it's lifespan.
__global__ void apply_forces(Particle *particles, int counter, double sqrt_dt){
int i = blockIdx.x * blockDim.x + threadIdx.x;
...
// Apply random force
RNG local_rand_state(p.pid, counter);
//double2 r = curand_uniform2_double(&local_rand_state);
auto x = local_rand_state.rand<double>();
auto y = local_rand_state.rand<double>();
p.vx += (x * 2.0 - 1.0) * sqrt_dt;
p.vy += (y * 2.0 - 1.0) * sqrt_dt;
particles[i] = p;
}
int main(){
...
// Simulation loop
int iter = 0;
while (iter++ < STEPS) {
apply_forces<<<nblocks, nthreads>>>(particles, iter, sqrt_dt);
...
}
}
For more detailed information on how to use OpenRAND and its features, please refer to the documentation.
Briefly, OpenRAND contains a suite of counter-based random number generators, to
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.
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments We'd like to thank all the contributors who have helped make OpenRAND a powerful and reliable tool for reproducible scientific research.
Contact For inquiries or support, please contact us at [email protected].