MCKL
Monte Carlo Kernel Library
stable_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/stable_distribution.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, 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 MCKL_RANDOM_STABLE_DISTRIBUTION_HPP
33 #define MCKL_RANDOM_STABLE_DISTRIBUTION_HPP
34 
37 
38 namespace mckl {
39 
40 namespace internal {
41 
42 template <typename RealType>
44  RealType alpha, RealType beta, RealType, RealType b)
45 {
46  if (alpha <= 0) {
47  return false;
48  }
49  if (alpha > 2) {
50  return false;
51  }
52  if (beta < -1) {
53  return false;
54  }
55  if (beta > 1) {
56  return false;
57  }
58  if (b <= 0) {
59  return false;
60  }
61  return true;
62 }
63 
67 }; // enum StableDistributionAlgorithm
68 
69 MCKL_PUSH_CLANG_WARNING("-Wpadded")
70 template <typename RealType>
72 {
73  public:
75  RealType alpha = 1, RealType beta = 0, RealType = 0, RealType b = 1)
76  {
77  MCKL_PUSH_CLANG_WARNING("-Wfloat-equal")
78  MCKL_PUSH_INTEL_WARNING(1572) // floating-point comparison
79  algorithm_ = alpha == 1 ? StableDistributionAlgorithm1 :
83 
84  RealType zeta = -beta * std::tan(const_pi_by2<RealType>() * alpha);
85  xi_ = c_ = 0;
86  switch (algorithm_) {
88  xi_ = const_pi_by2<RealType>();
89  c_ = 1 / const_pi_by2<RealType>() * std::log(b);
90  break;
92  xi_ = 1 / alpha * std::atan(-zeta);
93  c_ = std::pow(1 + zeta * zeta, 1 / (2 * alpha));
94  break;
95  }
96  }
97 
98  RealType xi() const { return xi_; }
99  RealType c() const { return c_; }
100  StableDistributionAlgorithm algorithm() const { return algorithm_; }
101 
104  {
105  MCKL_PUSH_CLANG_WARNING("-Wfloat-equal")
106  MCKL_PUSH_INTEL_WARNING(1572) // floating-point comparison
107  if (c1.xi_ != c2.xi_) {
108  return false;
109  }
110  if (c1.c_ != c2.c_) {
111  return false;
112  }
113  if (c1.algorithm_ != c2.algorithm_) {
114  return false;
115  }
116  return true;
119  }
120 
121  private:
122  RealType xi_;
123  RealType c_;
124  StableDistributionAlgorithm algorithm_;
125 }; // class StableDistributionConstant
127 
128 template <std::size_t K, typename RealType, typename RNGType>
129 inline void stable_distribution_impl_1(RNGType &rng, std::size_t n,
130  RealType *r, RealType, RealType beta, RealType, RealType,
131  const StableDistributionConstant<RealType> &constant)
132 {
133  alignas(MCKL_ALIGNMENT) std::array<RealType, K * 3> s;
134  const RealType xi = constant.xi();
135  const RealType c = constant.c();
136  RealType *const u = s.data();
137  RealType *const w = s.data() + n;
138  RealType *const t = s.data() + n * 2;
139  u01_oo_distribution(rng, n, u);
140  muladd(n, u, const_pi<RealType>(), -const_pi_by2<RealType>(), u);
141  u01_oo_distribution(rng, n, w);
142  log(n, w, w);
143  mul(n, -const_one<RealType>(), w, w);
144  muladd(n, u, beta, const_pi_by2<RealType>(), t);
145  tan(n, u, r);
146  mul(n, t, r, r);
147  cos(n, u, u);
148  mul(n, w, u, u);
149  div(n, const_pi_by2<RealType>(), t, t);
150  mul(n, u, t, t);
151  muladd(n, t, -beta, r, r);
152  muladd(n, r, 1 / xi, c, r);
153 }
154 
155 template <std::size_t K, typename RealType, typename RNGType>
156 inline void stable_distribution_impl_a(RNGType &rng, std::size_t n,
157  RealType *r, RealType alpha, RealType, RealType, RealType,
158  const StableDistributionConstant<RealType> &constant)
159 {
160  alignas(MCKL_ALIGNMENT) std::array<RealType, K * 4> s;
161  const RealType xi = constant.xi();
162  const RealType c = constant.c();
163  RealType *const u = s.data();
164  RealType *const w = s.data() + n;
165  RealType *const p = s.data() + n * 2;
166  RealType *const t = s.data() + n * 3;
167  u01_oo_distribution(rng, n, u);
168  muladd(n, u, const_pi<RealType>(), -const_pi_by2<RealType>(), u);
169  u01_oo_distribution(rng, n, w);
170  log(n, w, w);
171  mul(n, -const_one<RealType>(), w, w);
172  muladd(n, u, alpha, alpha * xi, t);
173  sin(n, t, r);
174  cos(n, u, p);
175  pow(n, p, 1 / alpha, p);
176  div(n, r, p, r);
177  sub(n, u, t, u);
178  cos(n, u, u);
179  div(n, u, w, p);
180  pow(n, p, (1 - alpha) / alpha, p);
181  mul(n, p, r, r);
182  mul(n, c, r, r);
183 }
184 
185 template <std::size_t K, typename RealType, typename RNGType>
186 inline void stable_distribution_impl(RNGType &rng, std::size_t n, RealType *r,
187  RealType alpha, RealType beta, RealType a, RealType b)
188 {
189  const StableDistributionConstant<RealType> constant(alpha, beta, a, b);
190  switch (constant.algorithm()) {
192  stable_distribution_impl_1<K>(
193  rng, n, r, alpha, beta, a, b, constant);
194  break;
196  stable_distribution_impl_a<K>(
197  rng, n, r, alpha, beta, a, b, constant);
198  break;
199  }
200  muladd(n, r, b, a, r);
201 }
202 
203 } // namespace internal
204 
205 MCKL_DEFINE_RANDOM_DISTRIBUTION_BATCH_4(Stable, stable, RealType, RealType,
206  alpha, RealType, beta, RealType, a, RealType, b)
207 
208 template <typename RealType>
211 class StableDistribution
212 {
214  MCKL_DEFINE_RANDOM_DISTRIBUTION_4(Stable, stable, RealType, result_type,
215  alpha, 1, result_type, beta, 0, result_type, a, 0, result_type, b, 1)
216 
217  public:
218  result_type min() const
219  {
220  return std::numeric_limits<result_type>::lowest();
221  }
222 
223  result_type max() const { return std::numeric_limits<result_type>::max(); }
224 
225  void reset()
226  {
228  alpha(), beta(), a(), b());
229  }
230 
231  private:
233 
234  bool is_equal(const distribution_type &other) const
235  {
236  return constant_ == other.constant_;
237  }
238 
239  template <typename CharT, typename Traits>
240  void ostream(std::basic_ostream<CharT, Traits> &) const
241  {
242  }
243 
244  template <typename CharT, typename Traits>
245  void istream(std::basic_istream<CharT, Traits> &)
246  {
247  reset();
248  }
249 
250  template <typename RNGType>
251  result_type generate(RNGType &rng, const param_type &param)
252  {
253  if (param == param_) {
254  return generate(rng, param_, constant_);
255  }
256 
258  param.alpha(), param.beta(), param.a(), param.b());
259 
260  return generate(rng, param, constant);
261  }
262 
263  template <typename RNGType>
264  result_type generate(RNGType &rng, const param_type &param,
266  {
267  result_type r = 0;
268  switch (constant.algorithm()) {
270  r = generate_1(rng, param, constant);
271  break;
273  r = generate_a(rng, param, constant);
274  break;
275  }
276 
277  return param.a() + param.b() * r;
278  }
279 
280  template <typename RNGType>
281  result_type generate_1(RNGType &rng, const param_type &param,
283  {
285  result_type u =
286  u01(rng) * const_pi<result_type>() - const_pi_by2<result_type>();
287  result_type w = -std::log(u01(rng));
288  result_type t = const_pi_by2<result_type>() + param.beta() * u;
289  result_type r = t * std::tan(u);
290  t = (const_pi_by2<result_type>() / t) * (w * std::cos(u));
291  r -= param.beta() * t;
292 
293  return r / constant.xi() + constant.c();
294  }
295 
296  template <typename RNGType>
297  result_type generate_a(RNGType &rng, const param_type &param,
299  {
301  result_type u =
302  u01(rng) * const_pi<result_type>() - const_pi_by2<result_type>();
303  result_type w = -std::log(u01(rng));
304  result_type t = param.alpha() * (constant.xi() + u);
305  result_type r = std::sin(t);
306  result_type p = std::cos(u);
307  r /= std::pow(p, 1 / param.alpha());
308  p = std::cos(u - t) / w;
309  r *= std::pow(p, (1 - param.alpha()) / param.alpha());
310 
311  return r * constant.c();
312  }
313 }; // class StableDistribution
314 
316 
317 } // namespace mckl
318 
319 #endif // MCKL_RANDOM_STABLE_DISTRIBUTION_HPP
void pow(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:184
StableDistributionAlgorithm algorithm() const
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:124
void tan(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:238
#define MCKL_PUSH_CLANG_WARNING(warning)
Definition: compiler.h:63
friend bool operator==(const StableDistributionConstant< RealType > &c1, const StableDistributionConstant< RealType > &c2)
void sin(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:236
void log(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:226
void stable_distribution_impl(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta, RealType a, RealType b)
void u01_oo_distribution(RNGType &rng, std::size_t n, RealType *r)
T muladd(T a, T b, T c)
Definition: vmf.hpp:673
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_RAND(Name, T)
RealType u01(UIntType u)
Convert uniform unsigned integers to floating points within [0, 1].
Definition: u01.hpp:88
std::basic_ostream< CharT, Traits > & ostream(std::basic_ostream< CharT, Traits > &os, const std::array< T, N > &ary)
Definition: iostream.hpp:46
void stable_distribution_impl_a(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType, RealType, RealType, const StableDistributionConstant< RealType > &constant)
void sub(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:121
Standard uniform distribution on (0, 1)
#define MCKL_PUSH_INTEL_WARNING(wid)
Definition: compiler.h:88
StableDistributionConstant(RealType alpha=1, RealType beta=0, RealType=0, RealType b=1)
void stable_distribution_impl_1(RNGType &rng, std::size_t n, RealType *r, RealType, RealType beta, RealType, RealType, const StableDistributionConstant< RealType > &constant)
void cos(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:234
void atan(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:276
Definition: mcmc.hpp:40
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_4( Name, name, T, T1, p1, v1, T2, p2, v2, T3, p3, v3, T4, p4, v4)
#define MCKL_POP_CLANG_WARNING
Definition: compiler.h:66
#define MCKL_ALIGNMENT
The default alignment for scalar type.
Definition: config.h:187
bool is_equal(const float &v1, const float &v2)
Definition: is_equal.hpp:41
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_ASSERT_REAL_TYPE(Name)
std::basic_istream< CharT, Traits > & istream(std::basic_istream< CharT, Traits > &is, std::array< T, N > &ary)
Definition: iostream.hpp:66
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_BATCH_4( Name, name, T, T1, p1, T2, p2, T3, p3, T4, p4)
bool stable_distribution_check_param(RealType alpha, RealType beta, RealType, RealType b)
void div(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:175
#define MCKL_POP_INTEL_WARNING
Definition: compiler.h:89