versatile-mcmc  0.1.7
random.hpp
Go to the documentation of this file.
1 
13 #ifndef VMCMC_RANDOM_H_
14 #define VMCMC_RANDOM_H_
15 
16 #include <vmcmc/logger.hpp>
17 
18 #include <random>
19 #include <type_traits>
20 #include <cmath>
21 #include <atomic>
22 #include <thread>
23 
24 #include <boost/numeric/ublas/vector.hpp>
25 #include <boost/numeric/ublas/matrix.hpp>
26 #include <boost/numeric/ublas/triangular.hpp>
27 
28 namespace vmcmc
29 {
30 
31 namespace ublas = boost::numeric::ublas;
32 
42 template <typename EngineT>
44 {
45 public:
46  typedef EngineT engine_type;
47  typedef typename engine_type::result_type result_type;
48 
54  static void Seed(result_type seed);
55 
60  static RandomPrototype& Instance();
61 
62 protected:
63  static std::atomic<result_type> sSeed;
64 
66  virtual ~RandomPrototype();
67 
68  RandomPrototype(const RandomPrototype& other) = delete;
69  RandomPrototype(RandomPrototype&& other) = delete;
70  void operator=(const RandomPrototype& other) = delete;
71  void operator=(RandomPrototype&& other) = delete;
72 
73 public:
78  engine_type& GetEngine() { return fEngine; }
79 
89  template <typename FloatT>
90  typename std::enable_if<std::is_floating_point<FloatT>::value, FloatT>::type
91  Uniform(FloatT min, FloatT max, bool minIncluded, bool maxIncluded);
92 
99  template <typename FloatT = double>
100  typename std::enable_if<std::is_floating_point<FloatT>::value, FloatT>::type
101  Uniform(FloatT min = 0.0, FloatT max = 1.0);
102 
109  template <typename IntegerT>
110  typename std::enable_if<std::is_integral<IntegerT>::value, IntegerT>::type
111  Uniform(IntegerT inclMin, IntegerT inclMax);
112 
118  template <typename FloatT = double>
119  bool Bool(FloatT probability = 0.5);
120 
127  template <typename FloatT = double>
128  FloatT Normal(FloatT mean = 0.0, FloatT sigma = 1.0);
129 
130  template <typename FloatT = double>
131  FloatT StudentT(FloatT n = 1.0, FloatT mean = 0.0, FloatT sigma = 1.0);
132 
138  template <typename FloatT>
139  inline FloatT Exponential(FloatT tau);
140 
146  template <typename IntegerT = uint32_t>
147  typename std::enable_if<std::is_integral<IntegerT>::value, IntegerT>::type
148  Poisson(double mean);
149 
155  template <typename FloatT>
156  typename std::enable_if<std::is_floating_point<FloatT>::value, FloatT>::type
157  Poisson(FloatT mean);
158 
163  template <typename ProbRangeT, typename IndexType = uint32_t>
164  IndexType Discrete(const ProbRangeT& probabilities);
165 
173  template <typename DistributionT>
174  typename DistributionT::result_type FromDistribution(DistributionT& dist = DistributionT());
175 
186  template <typename DistributionT, typename VectorT, typename MatrixT>
187  VectorT FromMultiVariateDistribution(DistributionT& dist, const VectorT& mean, const MatrixT& cholesky);
188 
196  template <typename DistributionT, typename VectorT>
197  VectorT FromMultiVariateDistribution(DistributionT& dist, const VectorT& mean, const VectorT& sigma);
198 
199 public:
200  static constexpr result_type min() { return engine_type::min(); }
201  static constexpr result_type max() { return engine_type::max(); }
202 
207  result_type operator()();
208 
209 private:
210  engine_type fEngine;
211 };
212 
213 template <typename EngineT>
214 void RandomPrototype<EngineT>::Seed(result_type seed)
215 {
216  sSeed = (seed == 0) ? std::random_device()() : seed;
217 }
218 
219 template <typename EngineT>
220 std::atomic<typename EngineT::result_type> RandomPrototype<EngineT>::sSeed( 0 );
221 
222 
223 
224 // TODO: Alright, Xcode as of version 7.3 does not support thread_local.
225 // At least, non-POD types are not supported.
226 // Possible workarounds: use mutexes or boost::thread_specific_ptr.
227 // For now I use a mutex lock, if thread_local is not supported by the compiler.
228 
229 #ifdef NO_TLS
230 
231 #include <mutex>
232 
233 template <typename EngineT>
235 {
236  static RandomPrototype sInstance;
237  return sInstance;
238 }
239 
240 template <typename EngineT>
241 inline auto RandomPrototype<EngineT>::operator()() -> result_type
242 {
243  static std::mutex sMtx;
244  std::lock_guard<std::mutex> lock(sMtx);
245 
246  return fEngine();
247 }
248 
249 #else
250 
251 template <typename EngineT>
253 {
254  static thread_local RandomPrototype sInstance;
255  return sInstance;
256 }
257 
258 template <typename EngineT>
259 inline auto RandomPrototype<EngineT>::operator()() -> result_type
260 {
261  return fEngine();
262 }
263 
264 #endif // NO_TLS
265 
266 
267 template <typename EngineT>
269  fEngine()
270 {
271  fEngine.seed( sSeed++ );
272 }
273 
274 template <typename EngineT>
276 { }
277 
278 template <typename EngineT>
279 template <typename FloatT>
280 typename std::enable_if<std::is_floating_point<FloatT>::value, FloatT>::type
281 inline RandomPrototype<EngineT>::Uniform(FloatT min, FloatT max, bool minIncluded, bool maxIncluded)
282 {
283  if (minIncluded) {
284  if (!maxIncluded) {
285  // pass
286  }
287  else {
288  max = std::nextafter(max, (max > min) ? std::numeric_limits<FloatT>::max() : -std::numeric_limits<FloatT>::max());
289  }
290  }
291  else {
292  if (!maxIncluded) {
293  min = std::nextafter(min, (max > min) ? std::numeric_limits<FloatT>::max() : -std::numeric_limits<FloatT>::max());
294  }
295  else {
296  std::swap(min, max);
297  }
298  }
299  return std::uniform_real_distribution<FloatT>(min, max)(*this);
300 }
301 
302 template <typename EngineT>
303 template <typename FloatT>
304 typename std::enable_if<std::is_floating_point<FloatT>::value, FloatT>::type
305 inline RandomPrototype<EngineT>::Uniform(FloatT min, FloatT max)
306 {
307  return std::uniform_real_distribution<FloatT>(min, max)(*this);
308 }
309 
310 template <typename EngineT>
311 template <typename IntegerT>
312 typename std::enable_if<std::is_integral<IntegerT>::value, IntegerT>::type
313 inline RandomPrototype<EngineT>::Uniform(IntegerT inclMin, IntegerT inclMax)
314 {
315  return std::uniform_int_distribution<IntegerT>(inclMin, inclMax)(*this);
316 }
317 
318 template <typename EngineT>
319 template <typename FloatT>
320 inline bool RandomPrototype<EngineT>::Bool(FloatT probability)
321 {
322  return std::uniform_real_distribution<FloatT>(0.0, 1.0)(*this) < probability;
323 }
324 
325 template <typename EngineT>
326 template <typename FloatT>
327 inline FloatT RandomPrototype<EngineT>::Normal(FloatT mean, FloatT sigma)
328 {
329  return std::normal_distribution<FloatT>(mean, sigma)(*this);
330 }
331 
332 template <typename EngineT>
333 template <typename DistributionT>
334 inline typename DistributionT::result_type RandomPrototype<EngineT>::FromDistribution(DistributionT& dist)
335 {
336  return dist(*this);
337 }
338 
339 template <typename EngineT>
340 template <typename DistributionT, typename VectorT, typename MatrixT>
341 inline VectorT RandomPrototype<EngineT>::FromMultiVariateDistribution(DistributionT& dist, const VectorT& mean, const MatrixT& cholesky)
342 {
343  LOG_DEFINE("vmcmc.random");
344  LOG_ASSERT( mean.size() == cholesky.size1() );
345 
346  VectorT noise( mean.size() );
347 
348  for (size_t i = 0; i < noise.size(); ++i)
349  noise[i] = dist(*this);
350 
351  return mean + ublas::prod(noise, cholesky);
352 }
353 
354 template <typename EngineT>
355 template <typename DistributionT, typename VectorT>
356 inline VectorT RandomPrototype<EngineT>::FromMultiVariateDistribution(DistributionT& dist, const VectorT& mean, const VectorT& sigma)
357 {
358  LOG_DEFINE("vmcmc.random");
359  LOG_ASSERT( mean.size() == sigma.size1() );
360 
361  VectorT noise( mean.size() );
362 
363  for (size_t i = 0; i < noise.size(); ++i)
364  noise[i] = dist(*this);
365 
366  return mean + ublas::element_prod(noise, sigma);
367 }
368 
369 
370 template <typename EngineT>
371 template <typename IntegerT>
372 typename std::enable_if<std::is_integral<IntegerT>::value, IntegerT>::type
374 {
375  return std::poisson_distribution<IntegerT>(mean)(*this);
376 }
377 
378 template <typename EngineT>
379 template <typename FloatT>
380 typename std::enable_if<std::is_floating_point<FloatT>::value, FloatT>::type
382 {
383  if (mean > std::numeric_limits<uint64_t>::max() / 2.0)
384  return Normal<FloatT>(mean, sqrt(mean));
385  else
386  return (FloatT) std::poisson_distribution<uint64_t>(mean)(*this);
387 }
388 
389 template <typename EngineT>
390 template <typename FloatT>
391 inline FloatT RandomPrototype<EngineT>::Exponential(FloatT tau)
392 {
393  return std::exponential_distribution<FloatT>(1.0/tau)(*this);
394 }
395 
396 template <typename EngineT>
397 template <typename ProbRangeT, typename IndexType>
398 inline IndexType RandomPrototype<EngineT>::Discrete(const ProbRangeT& probabilities)
399 {
400  return std::discrete_distribution<IndexType>(probabilities.begin(), probabilities.end())(*this);
401 }
402 
403 
408 
409 } /* namespace vmcmc */
410 
411 #endif /* VMCMC_RANDOM_H_ */
std::enable_if< std::is_floating_point< FloatT >::value, FloatT >::type Uniform(FloatT min, FloatT max, bool minIncluded, bool maxIncluded)
Get a random uniform number in the specified range.
Definition: random.hpp:281
Definition: algorithm.cpp:28
std::enable_if< std::is_integral< IntegerT >::value, IntegerT >::type Poisson(double mean)
Draw an integer value from a poisson distribution.
Definition: random.hpp:373
result_type operator()()
Invokes the underlying random number generator.
Definition: random.hpp:259
Class definitions and MACROs for logging purposes.
engine_type & GetEngine()
Get a reference to the underlying random number engine (mersenne twister).
Definition: random.hpp:78
bool Bool(FloatT probability=0.5)
Return a boolean.
Definition: random.hpp:320
A thread-safe interface for STL style pesudo random number generators (PRNG).
Definition: random.hpp:43
FloatT Normal(FloatT mean=0.0, FloatT sigma=1.0)
Draw from a gaussian / normal distribution.
Definition: random.hpp:327
VectorT FromMultiVariateDistribution(DistributionT &dist, const VectorT &mean, const MatrixT &cholesky)
Draw from a custom multivariate distribution.
Definition: random.hpp:341
Definition: blas.hpp:81
static RandomPrototype & Instance()
Get a reference to a static instance for the current thread.
Definition: random.hpp:252
FloatT Exponential(FloatT tau)
Draw from an exponential distribution according to exp(-t/tau).
Definition: random.hpp:391
IndexType Discrete(const ProbRangeT &probabilities)
Produces integers in the range [0, n) with the probability of producing each value is specified by th...
Definition: random.hpp:398
static void Seed(result_type seed)
Set the initial value for the global seed variable.
Definition: random.hpp:214
DistributionT::result_type FromDistribution(DistributionT &dist=DistributionT())
Draw from a custom distribution.
Definition: random.hpp:334