source: trunk/yat/random/random.cc @ 2802

Last change on this file since 2802 was 2802, checked in by Peter, 11 years ago

adding documentation and tests. Remove private member count_ (not needed). closes #568

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.1 KB
Line 
1// $Id: random.cc 2802 2012-07-29 10:13:39Z peter $
2
3/*
4  Copyright (C) 2005, 2006, 2007, 2008 Jari Häkkinen, Peter Johansson
5  Copyright (C) 2009, 2011, 2012 Peter Johansson
6
7  This file is part of the yat library, http://dev.thep.lu.se/yat
8
9  The yat library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 3 of the
12  License, or (at your option) any later version.
13
14  The yat library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with yat. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "random.h"
24#include "yat/statistics/Histogram.h"
25#include "yat/utility/Exception.h"
26
27#include <cassert>
28#include <cstring>
29#include <fstream>
30#include <sstream>
31
32namespace theplu {
33namespace yat {
34namespace random {
35
36  RNG* RNG::instance_=NULL;
37
38  RNG::RNG(void)
39    : rng_(gsl_rng_free)
40  {
41      // support rng/seed changes through environment vars
42    if (!gsl_rng_env_setup())
43      throw utility::GSL_error("RNG::RNG unknown generator");
44    seed_ = gsl_rng_default_seed;
45    // let's allocate already here, just to behave as yat 0.8
46    rng_alloc();
47  }
48
49
50  RNG::~RNG(void)
51  {
52  }
53
54
55  RNG* RNG::instance(void)
56  {
57    if (instance_==NULL)
58      instance_ = new RNG;
59    return instance_;
60  }
61
62
63  unsigned long RNG::max(void) const
64  {
65    return gsl_rng_max(rng());
66  }
67
68
69  unsigned long RNG::min(void) const
70  {
71    return gsl_rng_min(rng());
72  }
73
74
75  std::string RNG::name(void) const
76  {
77    return gsl_rng_name(rng());
78  }
79
80
81  const gsl_rng* RNG::rng(void) const
82  {
83    if (rng_.get()==NULL)
84      rng_alloc();
85    return rng_.get();
86  }
87
88
89  void RNG::rng_alloc(void) const
90  {
91    assert(rng_.get()==NULL);
92    gsl_rng* rng = gsl_rng_alloc(gsl_rng_default);
93    if (!rng)
94      throw utility::GSL_error("RNG failed to allocate memory");
95    gsl_rng_set(rng, seed_);
96    // bump seed to avoid subsequent gsl_rng to be identical
97    ++seed_;
98    // rng_ owns rng and takes care of deallocation
99    rng_.reset(rng);
100  }
101
102
103  void RNG::seed(unsigned long s) const
104  {
105    gsl_rng_set(rng(),s);
106    seed_ = s+1;
107  }
108
109
110  unsigned long RNG::seed_from_devurandom(void)
111  {
112    unsigned char ulongsize=sizeof(unsigned long);
113    char* buffer=new char[ulongsize];
114    std::ifstream is("/dev/urandom", std::ios::binary);
115    is.read(buffer,ulongsize);
116    is.close();
117    unsigned long s=0;
118    memcpy(&s, buffer, ulongsize);
119    delete[] buffer;
120    seed(s);
121    return s;
122  }
123
124
125  int RNG::set_state(const RNG_state& state)
126  {
127    if (rng_.get()==NULL)
128      rng_alloc();
129    return gsl_rng_memcpy(rng_.get(), state.rng());
130  }
131
132  // --------------------- RNG_state ----------------------------------
133
134  RNG_state::RNG_state(const RNG* rng)
135  {
136    clone(*rng->rng());
137  }
138
139
140  RNG_state::RNG_state(const RNG_state& state)
141  {
142    clone(*state.rng());
143  }
144
145
146  RNG_state::~RNG_state(void)
147  {
148    gsl_rng_free(rng_);
149    rng_=NULL;
150  }
151
152  const gsl_rng* RNG_state::rng(void) const
153  {
154    return rng_;
155  }
156
157
158  void RNG_state::clone(const gsl_rng& rng)
159  {
160    assert(rng_!=&rng);
161    if (!(rng_ = gsl_rng_clone(&rng)))
162      throw utility::GSL_error("RNG_state::RNG_state failed to allocate memory");
163  }
164
165  RNG_state& RNG_state::operator=(const RNG_state& rhs)
166  {
167    if (this != &rhs) {
168      gsl_rng_free(rng_);
169      clone(*rhs.rng());
170    }
171    return *this;
172  }
173
174  // --------------------- Discrete distribtuions ---------------------
175
176  Discrete::Discrete(void)
177    : rng_(RNG::instance())
178  {
179  }
180
181 
182  Discrete::~Discrete(void)
183  {
184  }
185
186
187  void Discrete::seed(unsigned long s) const
188  {
189    rng_->seed(s);
190  }
191
192
193  unsigned long Discrete::seed_from_devurandom(void) 
194  { 
195    return rng_->seed_from_devurandom(); 
196  }
197
198
199  DiscreteGeneral::DiscreteGeneral(const statistics::Histogram& hist)
200    : gen_(NULL)
201  {
202    p_.reserve(hist.nof_bins());
203    for (size_t i=0; i<hist.nof_bins(); i++) 
204      p_.push_back(hist[i]);
205    preproc();
206  }
207
208
209  DiscreteGeneral::DiscreteGeneral(const DiscreteGeneral& other)
210    : Discrete(other), gen_(NULL), p_(other.p_)
211  {
212    preproc();
213  }
214
215
216  DiscreteGeneral::~DiscreteGeneral(void)
217  {
218    free();
219  }
220
221
222  void DiscreteGeneral::free(void)
223  {
224    if (gen_)
225      gsl_ran_discrete_free( gen_ );
226    gen_ = NULL;
227  }
228
229
230  void DiscreteGeneral::preproc(void)
231  {
232    assert(!gen_);
233    assert(p_.size());
234    gen_ = gsl_ran_discrete_preproc( p_.size(), &p_.front() );
235    if (!gen_)
236      throw utility::GSL_error("DiscreteGeneral failed to setup generator.");
237  }
238
239
240  DiscreteGeneral& DiscreteGeneral::operator=(const DiscreteGeneral& rhs)
241  {
242    free();
243    p_ = rhs.p_;
244    preproc();
245    return *this;
246  }
247
248
249  unsigned long DiscreteGeneral::operator()(void) const
250  {
251    return gsl_ran_discrete(rng_->rng(), gen_);
252  }
253
254
255  DiscreteUniform::DiscreteUniform(unsigned long n)
256    : range_(n)
257  {
258    if (range_>rng_->max()) {
259      std::stringstream ss("DiscreteUniform::DiscreteUniform: ");
260      ss << n << " is too large for RNG " << rng_->name();
261      throw utility::GSL_error(ss.str());
262    }
263  }
264
265
266  unsigned long DiscreteUniform::operator()(void) const
267  {
268    return (range_ ?
269            gsl_rng_uniform_int(rng_->rng(), range_) : gsl_rng_get(rng_->rng()));
270  }
271
272
273  unsigned long DiscreteUniform::operator()(unsigned long n) const
274  {
275    // making sure that n is not larger than the range of the
276    // underlying RNG
277    if (n>rng_->max()) {
278      std::stringstream ss("DiscreteUniform::operator(unsigned long): ");
279      ss << n << " is too large for RNG " << rng_->name();
280      throw utility::GSL_error(ss.str());
281    }
282    return gsl_rng_uniform_int(rng_->rng(),n);
283  }
284
285
286  Poisson::Poisson(const double m)
287    : m_(m)
288  {
289  }
290
291  unsigned long Poisson::operator()(void) const
292  {
293    return gsl_ran_poisson(rng_->rng(), m_);
294  }
295
296
297  unsigned long Poisson::operator()(const double m) const
298  {
299    return gsl_ran_poisson(rng_->rng(), m);
300  }
301
302  // --------------------- Continuous distribtuions ---------------------
303
304  Continuous::Continuous(void)
305    : rng_(RNG::instance())
306  {
307  }
308
309
310  Continuous::~Continuous(void)
311  {
312  }
313
314
315  void Continuous::seed(unsigned long s) const
316  {
317    rng_->seed(s);
318  }
319
320
321  unsigned long Continuous::seed_from_devurandom(void)
322  {
323    return rng_->seed_from_devurandom();
324  }
325
326
327  ContinuousGeneral::ContinuousGeneral(const statistics::Histogram& hist)
328    : discrete_(DiscreteGeneral(hist)), hist_(hist)
329  {
330  }
331
332
333  double ContinuousGeneral::operator()(void) const
334  {
335    return hist_.observation_value(discrete_())+(u_()-0.5)*hist_.spacing();
336  }
337
338  double ContinuousUniform::operator()(void) const
339  {
340    return gsl_rng_uniform(rng_->rng());
341  }
342
343
344  Exponential::Exponential(const double m)
345    : m_(m)
346  {
347  }
348
349
350  double Exponential::operator()(void) const
351  {
352    return gsl_ran_exponential(rng_->rng(), m_);
353  }
354
355
356  double Exponential::operator()(const double m) const
357  {
358    return gsl_ran_exponential(rng_->rng(), m);
359  }
360
361
362  Gaussian::Gaussian(const double s, const double m)
363    : m_(m), s_(s)
364  {
365  }
366
367
368  double Gaussian::operator()(void) const
369  {
370    return gsl_ran_gaussian(rng_->rng(), s_)+m_;
371  }
372
373
374  double Gaussian::operator()(const double s) const
375  {
376    return gsl_ran_gaussian(rng_->rng(), s);
377  }
378
379
380  double Gaussian::operator()(const double s, const double m) const
381  {
382    return gsl_ran_gaussian(rng_->rng(), s)+m;
383  }
384
385}}} // of namespace random, yat, and theplu
Note: See TracBrowser for help on using the repository browser.