C++ mpi module for stochmagnet_main Package
normal_dist.hpp
1 // Copyright (c) 2000-2022, Heiko Bauke
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following
13 // disclaimer in the documentation and/or other materials provided
14 // with the distribution.
15 //
16 // * Neither the name of the copyright holder nor the names of its
17 // contributors may be used to endorse or promote products derived
18 // from this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 // OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 #if !(defined TRNG_NORMAL_DIST_HPP)
34 
35 #define TRNG_NORMAL_DIST_HPP
36 
37 #include <trng/cuda.hpp>
38 #include <trng/constants.hpp>
39 #include <trng/limits.hpp>
40 #include <trng/utility.hpp>
41 #include <trng/math.hpp>
42 #include <trng/special_functions.hpp>
43 #include <ostream>
44 #include <istream>
45 #include <iomanip>
46 #include <ciso646>
47 
48 namespace trng {
49 
50  // uniform random number generator class
51  template<typename float_t = double>
52  class normal_dist {
53  public:
54  using result_type = float_t;
55 
56  class param_type {
57  private:
58  result_type mu_{0}, sigma_{1};
59 
60  public:
61  TRNG_CUDA_ENABLE
62  result_type mu() const { return mu_; }
63  TRNG_CUDA_ENABLE
64  void mu(result_type mu_new) { mu_ = mu_new; }
65  TRNG_CUDA_ENABLE
66  result_type sigma() const { return sigma_; }
67  TRNG_CUDA_ENABLE
68  void sigma(result_type sigma_new) { sigma_ = sigma_new; }
69  TRNG_CUDA_ENABLE
70  param_type() = default;
71  TRNG_CUDA_ENABLE
72  explicit param_type(result_type mu, result_type sigma) : mu_{mu}, sigma_{sigma} {}
73 
74  friend class normal_dist;
75 
76  // EqualityComparable concept
77  friend TRNG_CUDA_ENABLE inline bool operator==(const param_type &P1,
78  const param_type &P2) {
79  return P1.mu_ == P2.mu_ and P1.sigma_ == P2.sigma_;
80  }
81 
82  friend TRNG_CUDA_ENABLE inline bool operator!=(const param_type &P1,
83  const param_type &P2) {
84  return not(P1 == P2);
85  }
86 
87  // -------------------------------------------------------------------
88 
89  // Streamable concept
90  template<typename char_t, typename traits_t>
91  friend std::basic_ostream<char_t, traits_t> &operator<<(
92  std::basic_ostream<char_t, traits_t> &out, const param_type &P) {
93  std::ios_base::fmtflags flags(out.flags());
94  out.flags(std::ios_base::dec | std::ios_base::fixed | std::ios_base::left);
95  out << '(' << std::setprecision(math::numeric_limits<float_t>::digits10 + 1) << P.mu()
96  << ' ' << P.sigma() << ')';
97  out.flags(flags);
98  return out;
99  }
100 
101  template<typename char_t, typename traits_t>
102  friend std::basic_istream<char_t, traits_t> &operator>>(
103  std::basic_istream<char_t, traits_t> &in, param_type &P) {
104  float_t mu, sigma;
105  std::ios_base::fmtflags flags(in.flags());
106  in.flags(std::ios_base::dec | std::ios_base::fixed | std::ios_base::left);
107  in >> utility::delim('(') >> mu >> utility::delim(' ') >> sigma >> utility::delim(')');
108  if (in)
109  P = param_type(mu, sigma);
110  in.flags(flags);
111  return in;
112  }
113  };
114 
115  private:
116  param_type P;
117 
118  public:
119  // constructor
120  TRNG_CUDA_ENABLE
121  explicit normal_dist(result_type mu, result_type sigma) : P{mu, sigma} {}
122  TRNG_CUDA_ENABLE
123  explicit normal_dist(const param_type &P) : P{P} {}
124  // reset internal state
125  TRNG_CUDA_ENABLE
126  void reset() {}
127  // random numbers
128  template<typename R>
129  TRNG_CUDA_ENABLE result_type operator()(R &r) {
130  return icdf(utility::uniformoo<result_type>(r));
131  }
132  template<typename R>
133  TRNG_CUDA_ENABLE result_type operator()(R &r, const param_type &P) {
134  normal_dist g(P);
135  return g(r);
136  }
137  // property methods
138  TRNG_CUDA_ENABLE
139  result_type min() const { return -math::numeric_limits<result_type>::infinity(); }
140  TRNG_CUDA_ENABLE
141  result_type max() const { return math::numeric_limits<result_type>::infinity(); }
142  TRNG_CUDA_ENABLE
143  const param_type &param() const { return P; }
144  TRNG_CUDA_ENABLE
145  void param(const param_type &P_new) { P = P_new; }
146  TRNG_CUDA_ENABLE
147  result_type mu() const { return P.mu(); }
148  TRNG_CUDA_ENABLE
149  void mu(result_type mu_new) { P.mu(mu_new); }
150  TRNG_CUDA_ENABLE
151  result_type sigma() const { return P.sigma(); }
152  TRNG_CUDA_ENABLE
153  void sigma(result_type sigma_new) { P.sigma(sigma_new); }
154  // probability density function
155  TRNG_CUDA_ENABLE
156  result_type pdf(result_type x) const {
157  const result_type t{x - P.mu()};
158  return math::constants<result_type>::one_over_sqrt_2pi / P.sigma() *
159  math::exp(t * t / (-2 * P.sigma() * P.sigma()));
160  }
161  // cumulative density function
162  TRNG_CUDA_ENABLE
163  result_type cdf(result_type x) const {
164  x -= P.mu();
165  x /= P.sigma();
166  return math::Phi(x);
167  }
168  // inverse cumulative density function
169  TRNG_CUDA_ENABLE
170  result_type icdf(result_type x) const { return math::inv_Phi(x) * P.sigma() + P.mu(); }
171  };
172 
173  // -------------------------------------------------------------------
174 
175  // EqualityComparable concept
176  template<typename float_t>
177  TRNG_CUDA_ENABLE inline bool operator==(const normal_dist<float_t> &g1,
178  const normal_dist<float_t> &g2) {
179  return g1.param() == g2.param();
180  }
181 
182  template<typename float_t>
183  TRNG_CUDA_ENABLE inline bool operator!=(const normal_dist<float_t> &g1,
184  const normal_dist<float_t> &g2) {
185  return g1.param() != g2.param();
186  }
187 
188  // Streamable concept
189  template<typename char_t, typename traits_t, typename float_t>
190  std::basic_ostream<char_t, traits_t> &operator<<(std::basic_ostream<char_t, traits_t> &out,
191  const normal_dist<float_t> &g) {
192  std::ios_base::fmtflags flags(out.flags());
193  out.flags(std::ios_base::dec | std::ios_base::fixed | std::ios_base::left);
194  out << "[normal " << g.param() << ']';
195  out.flags(flags);
196  return out;
197  }
198 
199  template<typename char_t, typename traits_t, typename float_t>
200  std::basic_istream<char_t, traits_t> &operator>>(std::basic_istream<char_t, traits_t> &in,
201  normal_dist<float_t> &g) {
202  typename normal_dist<float_t>::param_type p;
203  std::ios_base::fmtflags flags(in.flags());
204  in.flags(std::ios_base::dec | std::ios_base::fixed | std::ios_base::left);
205  in >> utility::ignore_spaces() >> utility::delim("[normal ") >> p >> utility::delim(']');
206  if (in)
207  g.param(p);
208  in.flags(flags);
209  return in;
210  }
211 
212 } // namespace trng
213 
214 #endif
Definition: normal_dist.hpp:56
Definition: normal_dist.hpp:52