vSMC
vSMC: Scalable Monte Carlo
normal_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/normal_distribution.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2016, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef VSMC_RNG_NORMAL_DISTRIBUTION_HPP
33 #define VSMC_RNG_NORMAL_DISTRIBUTION_HPP
34 
38 
39 namespace vsmc
40 {
41 
42 namespace internal
43 {
44 
45 template <typename RealType>
46 inline bool normal_distribution_check_param(RealType, RealType stddev)
47 {
48  return stddev > 0;
49 }
50 
51 } // namespace vsmc::internal
52 
55 template <typename RealType>
57 {
59  Normal, normal, mean, 0, stddev, 1)
60 
61  public:
62  using result_type = RealType;
64 
65  explicit NormalDistribution(result_type mean = 0, result_type stddev = 1)
66  : param_(mean, stddev), v_(0), saved_(false)
67  {
68  reset();
69  }
70 
71  explicit NormalDistribution(const param_type &param)
72  : param_(param), v_(0), saved_(false)
73  {
74  reset();
75  }
76 
77  result_type mean() const { return param_.mean(); }
78 
79  result_type stddev() const { return param_.stddev(); }
80 
81  result_type min() const
82  {
83  return std::numeric_limits<result_type>::lowest();
84  }
85 
86  result_type max() const { return std::numeric_limits<result_type>::max(); }
87 
88  void reset()
89  {
90  v_ = 0;
91  saved_ = false;
92  }
93 
94  const param_type &param() const { return param_; }
95 
96  void param(const param_type &param)
97  {
98  param_ = param;
99  reset();
100  }
101 
102  void pram(param_type &&param)
103  {
104  param_ = std::move(param);
105  reset();
106  }
107 
108  template <typename RNGType>
109  result_type operator()(RNGType &rng)
110  {
111  return operator()(rng, param_);
112  }
113 
114  template <typename RNGType>
115  result_type operator()(RNGType &rng, const param_type &param)
116  {
117  return generate(rng, param);
118  }
119 
120  template <typename RNGType>
121  void operator()(RNGType &rng, std::size_t n, result_type *r)
122  {
123  operator()(rng, n, r, param_);
124  }
125 
126  template <typename RNGType>
128  RNGType &rng, std::size_t n, result_type *r, const param_type &param)
129  {
130  if (n < 100) {
131  for (std::size_t i = 0; i != n; ++i)
132  r[i] = operator()(rng, param);
133  } else {
134  normal_distribution(rng, n, r, param);
135  }
136  }
137 
138  friend bool operator==(
139  const distribution_type &dist1, const distribution_type &dist2)
140  {
141  if (dist1.param_ != dist2.param_)
142  return false;
143  if (!internal::is_equal(dist1.v_, dist2.v_))
144  return false;
145  if (dist1.saved_ && !dist2.saved_)
146  return false;
147  if (!dist1.saved_ && dist2.saved_)
148  return false;
149  return true;
150  }
151 
152  friend bool operator!=(
153  const distribution_type &dist1, const distribution_type &dist2)
154  {
155  return !(dist1 == dist2);
156  }
157 
158  template <typename CharT, typename Traits>
159  friend std::basic_ostream<CharT, Traits> &operator<<(
160  std::basic_ostream<CharT, Traits> &os, const distribution_type &dist)
161  {
162  if (!os.good())
163  return os;
164 
165  os << dist.param_ << ' ';
166  os << dist.v_ << ' ';
167  os << dist.saved_;
168 
169  return os;
170  }
171 
172  template <typename CharT, typename Traits>
173  friend std::basic_istream<CharT, Traits> &operator>>(
174  std::basic_istream<CharT, Traits> &is, distribution_type &dist)
175  {
176  if (!is.good())
177  return is;
178 
179  param_type param;
180  result_type v;
181  bool saved;
182  is >> std::ws >> param;
183  is >> std::ws >> v;
184  is >> std::ws >> saved;
185  if (is.good()) {
186  dist.param_ = param;
187  dist.v_ = v;
188  dist.saved_ = saved;
189  }
190 
191  return is;
192  }
193 
194  private:
195  param_type param_;
196  result_type v_;
197  bool saved_;
198 
199  template <typename RNGType>
200  result_type generate(RNGType &rng, const param_type &param)
201  {
202  result_type z = 0;
203  if (saved_) {
204  z = v_;
205  saved_ = false;
206  } else {
208  result_type u1 = std::sqrt(-2 * std::log(u01(rng)));
209  result_type u2 = const_pi_2<result_type>() * u01(rng);
210  z = u1 * std::cos(u2);
211  v_ = u1 * std::sin(u2);
212  saved_ = true;
213  }
214 
215  return param.mean() + param.stddev() * z;
216  }
217 }; // class NormalDistribution
218 
219 namespace internal
220 {
221 
222 template <std::size_t K, typename RealType, typename RNGType>
224  RNGType &rng, std::size_t n, RealType *r, RealType mean, RealType stddev)
225 {
226  RealType s[K / 2];
227  const std::size_t nu = n / 2;
228  RealType *const u1 = r;
229  RealType *const u2 = r + nu;
230  u01_distribution(rng, n, r);
231  log(nu, u1, s);
232  mul(nu, static_cast<RealType>(-2), s, s);
233  sqrt(nu, s, s);
234  mul(nu, const_pi_2<RealType>(), u2, u2);
235  sincos(nu, u2, u1, u2);
236  mul(nu, stddev, s, s);
237  fma(nu, s, u1, mean, u1);
238  fma(nu, s, u2, mean, u2);
239 }
240 
241 } // namespace vsmc::internal
242 
245 template <typename RealType, typename RNGType>
247  RNGType &rng, std::size_t n, RealType *r, RealType mean, RealType stddev)
248 {
249  static_assert(std::is_floating_point<RealType>::value,
250  "**normal_distribution** USED WITH RealType OTHER THAN FLOATING POINT "
251  "TYPES");
252 
253  const std::size_t k = 1024;
254  const std::size_t m = n / k;
255  const std::size_t l = n % k;
256  for (std::size_t i = 0; i != m; ++i, r += k)
257  internal::normal_distribution_impl<k>(rng, k, r, mean, stddev);
258  internal::normal_distribution_impl<k>(rng, l, r, mean, stddev);
259  if (n % 2 != 0) {
261  RealType u = u01(rng);
262  RealType v = u01(rng);
263  r[l - 1] = mean +
264  stddev * std::sqrt(-2 * std::log(u)) *
265  std::cos(const_pi_2<RealType>() * v);
266  }
267 }
268 
269 VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Normal, normal, mean, stddev)
270 
271 } // namespace vsmc
272 
273 #endif // VSMC_RNG_NORMAL_DISTRIBUTION_HPP
NormalDistribution(const param_type &param)
Definition: monitor.hpp:49
void pram(param_type &&param)
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:112
const param_type & param() const
void sqrt(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:129
#define VSMC_DEFINE_RNG_DISTRIBUTION_PARAM_TYPE_2(Name, name, p1, v1, p2, v2)
Definition: common.hpp:157
bool is_equal(const T &a, const T &b)
Definition: common.hpp:90
void normal_distribution_impl(RNGType &rng, std::size_t n, RealType *r, RealType mean, RealType stddev)
void u01_distribution(RNGType &, std::size_t, RealType *)
Generate standard uniform random variates.
result_type operator()(RNGType &rng)
friend bool operator!=(const distribution_type &dist1, const distribution_type &dist2)
void normal_distribution(RNGType &, std::size_t, RealType *, RealType, RealType)
Generating Normal random variates.
Normal distribution.
Definition: common.hpp:582
void cos(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:152
void operator()(RNGType &rng, std::size_t n, result_type *r)
void operator()(RNGType &rng, std::size_t n, result_type *r, const param_type &param)
bool normal_distribution_check_param(RealType, RealType stddev)
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, distribution_type &dist)
void param(const param_type &param)
result_type stddev() const
void fma(std::size_t n, const T *a, const T *b, const T *c, T *y)
For , compute .
Definition: vmath.hpp:257
void sincos(std::size_t n, const float *a, float *y, float *z)
Definition: vmath.hpp:154
void sin(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:153
result_type operator()(RNGType &rng, const param_type &param)
Standard uniform distribution.
Definition: common.hpp:597
#define VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Name, name, p1, p2)
Definition: common.hpp:409
friend bool operator==(const distribution_type &dist1, const distribution_type &dist2)
void log(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:148
NormalDistribution< RealType > distribution_type
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const distribution_type &dist)