8 #include <gsl/gsl_rng.h>
9 #include <gsl/gsl_randist.h>
11 #include <boost/thread/mutex.hpp>
12 #include <boost/thread/thread.hpp>
18 #include <boost/random.hpp>
33 #define NUKLEI_RANDOM_SYNC_NONE
37 static inline int nuklei_thread_num()
39 return omp_get_thread_num();
41 static inline int nuklei_max_threads()
53 static inline int nuklei_thread_num()
57 static inline int nuklei_max_threads()
66 static std::vector<boost::mt19937>* bRandGens;
68 static std::vector<gsl_rng*>* gRandGens;
69 static std::vector<boost::shared_ptr<boost::mutex> >* mutexes;
80 const char * envValPara = getenv(
"NUKLEI_PARALLELIZATION");
81 if (envValPara != NULL)
83 std::string para(envValPara);
84 if (para ==
"single" || para ==
"openmp")
88 else if (para ==
"pthread")
90 #if defined(NUKLEI_RANDOM_SYNC_OMP) || defined(NUKLEI_RANDOM_SYNC_NONE) || !defined(NUKLEI_RANDOM_SYNC_MUTEX)
91 std::cout <<
"NUKLEI_PARALLELIZATION is set to pthread. "
92 "You should manually undefine all NUKLEI_RANDOM_SYNC_* in Random.cpp, "
93 "and define NUKLEI_RANDOM_SYNC_MUTEX instead. Note that multithreading "
94 "will be slower than with OpenMP. "
95 "See http://renaud-detry.net/nuklei/group__faq.html" << std::endl;
101 std::cout <<
"Unknown value '" << para <<
"' for NUKLEI_PARALLELIZATION"
102 " env variable." << std::endl;
107 const char * envVal = getenv(
"NUKLEI_RANDOM_SEED");
110 const char * log = getenv(
"NUKLEI_LOG_LEVEL");
111 if (log != NULL && numify<unsigned>(log) >= Log::INFO)
112 std::cout <<
"export " <<
"NUKLEI_RANDOM_SEED" <<
"="
113 << numify<int>(envVal)
115 double seed_d = numify<double>(envVal);
117 seed = numify<unsigned>(envVal);
119 seed = time(NULL)*getpid();
122 bRandGens =
new std::vector<boost::mt19937>(nuklei_max_threads());
123 gRandGens =
new std::vector<gsl_rng*>(nuklei_max_threads(), NULL);
124 for (
int i = 0; i < nuklei_max_threads(); i++)
125 gRandGens->at(i) = gsl_rng_alloc(gsl_rng_mt19937);
127 mutexes =
new std::vector<boost::shared_ptr<boost::mutex> >();
128 for (
int i = 0; i < nuklei_max_threads(); i++)
129 mutexes->push_back(boost::shared_ptr<boost::mutex>(
new boost::mutex()));
137 if (getenv(
"NUKLEI_RANDOM_SEED") != NULL)
146 for (
int i = 0; i < bRandGens->size(); ++i)
148 bRandGens->at(i).seed(s+i);
150 for (
int i = 0; i < gRandGens->size(); ++i)
152 gsl_rng_set(gRandGens->at(i), s+i+1);
162 #if defined(NUKLEI_RANDOM_SYNC_OMP)
163 # pragma omp critical(nuklei_randomRng)
164 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX)
165 boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
166 #elif defined(NUKLEI_RANDOM_SYNC_NONE)
168 # error Undefined random sync method
170 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN
172 boost::uniform_01<>
dist;
173 boost::variate_generator<boost::mt19937&, boost::uniform_01<> >
174 die(bRandGens->at(nuklei_thread_num()),
dist);
178 r = gsl_rng_uniform(gRandGens->at(nuklei_thread_num()));
188 NUKLEI_FAST_ASSERT(a < b);
208 #if defined(NUKLEI_RANDOM_SYNC_OMP)
209 # pragma omp critical(nuklei_randomRng)
210 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX)
211 boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
212 #elif defined(NUKLEI_RANDOM_SYNC_NONE)
214 # error Undefined random sync method
216 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN
218 boost::uniform_int<unsigned long>
dist(0, n-1);
219 boost::variate_generator<boost::mt19937&, boost::uniform_int<unsigned long> >
220 die(bRandGens->at(nuklei_thread_num()),
dist);
224 r = gsl_rng_uniform_int(gRandGens->at(nuklei_thread_num()), n);
232 #if defined(NUKLEI_RANDOM_SYNC_OMP)
233 # pragma omp critical(nuklei_randomRng)
234 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX)
235 boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
236 #elif defined(NUKLEI_RANDOM_SYNC_NONE)
238 # error Undefined random sync method
241 boost::triangle_distribution<>
dist(-b/2, 0, b/2);
242 boost::variate_generator<boost::mt19937&, boost::triangle_distribution<> >
243 die(bRandGens->at(nuklei_thread_num()),
dist);
256 #if defined(NUKLEI_RANDOM_SYNC_OMP)
257 # pragma omp critical(nuklei_randomRng)
258 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX)
259 boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
260 #elif defined(NUKLEI_RANDOM_SYNC_NONE)
262 # error Undefined random sync method
264 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN
266 boost::normal_distribution<>
dist(0, sigma);
267 boost::variate_generator<boost::mt19937&, boost::normal_distribution<> >
268 die(bRandGens->at(nuklei_thread_num()),
dist);
272 r = gsl_ran_gaussian(gRandGens->at(nuklei_thread_num()), sigma);
280 #if defined(NUKLEI_RANDOM_SYNC_OMP)
281 # pragma omp critical(nuklei_randomRng)
282 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX)
283 boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
284 #elif defined(NUKLEI_RANDOM_SYNC_NONE)
286 # error Undefined random sync method
288 r = gsl_ran_beta(gRandGens->at(nuklei_thread_num()), a, b);
295 #if defined(NUKLEI_RANDOM_SYNC_OMP)
296 # pragma omp critical(nuklei_randomRng)
297 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX)
298 boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
299 #elif defined(NUKLEI_RANDOM_SYNC_NONE)
301 # error Undefined random sync method
303 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN
306 typedef boost::uniform_on_sphere<double, std::vector<double> > dist_t;
308 boost::variate_generator<boost::mt19937&, dist_t >
309 die(bRandGens->at(nuklei_thread_num()),
dist);
310 std::vector<double> r = die();
315 gsl_ran_dir_2d(gRandGens->at(nuklei_thread_num()), &dir.X(), &dir.Y());
323 #if defined(NUKLEI_RANDOM_SYNC_OMP)
324 # pragma omp critical(nuklei_randomRng)
325 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX)
326 boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
327 #elif defined(NUKLEI_RANDOM_SYNC_NONE)
329 # error Undefined random sync method
331 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN
333 typedef boost::uniform_on_sphere<double, std::vector<double> > dist_t;
335 boost::variate_generator<boost::mt19937&, dist_t >
336 die(bRandGens->at(nuklei_thread_num()),
dist);
337 std::vector<double> r = die();
342 gsl_ran_dir_3d(gRandGens->at(nuklei_thread_num()), &dir.X(), &dir.Y(), &dir.Z());
355 #if defined(NUKLEI_RANDOM_QUATERNION_MARSAGLIA_1972)
356 coord_t x1, y1, s1, x2, y2, s2;
371 coord_t root = std::sqrt( (1-s1)/s2 );
377 #elif defined(NUKLEI_RANDOM_QUATERNION_GAUSSIAN_PROJ)
385 #else // Fastest method (although MARSAGLIA is comparable)
392 Quaternion u(std::cos(t2) * s2,
401 void Random::printRandomState()
403 NUKLEI_INFO(
"Random state: " <<