MCKL
Monte Carlo Kernel Library
dirichlet_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/dirichlet_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_DIRICHLET_DISTRIBUTION_HPP
33 #define MCKL_RANDOM_DIRICHLET_DISTRIBUTION_HPP
34 
37 
38 namespace mckl {
39 
40 namespace internal {
41 
42 template <typename RealType>
44  std::size_t dim, RealType *alpha)
45 {
46  for (std::size_t i = 0; i != dim; ++i) {
47  if (alpha[i] <= 0) {
48  return false;
49  }
50  }
51  return true;
52 }
53 
54 template <typename RealType>
56  std::size_t n, std::size_t dim, RealType *r)
57 {
58  for (std::size_t i = 0; i != n; ++i, r += dim) {
59  RealType s = std::accumulate(r, r + dim, const_zero<RealType>());
60  mul<RealType>(dim, 1 / s, r, r);
61  }
62 }
63 
64 } // namespace internal
65 
66 template <typename RealType, typename RNGType>
67 inline void dirichlet_distribution(RNGType &rng, std::size_t n, RealType *r,
68  std::size_t dim, const RealType alpha)
69 {
70  if (n * dim == 0) {
71  return;
72  }
73 
74  gamma_distribution(rng, n * dim, r, alpha, const_one<RealType>());
76 }
77 
78 template <typename RealType, typename RNGType>
79 inline void dirichlet_distribution(RNGType &rng, std::size_t n, RealType *r,
80  std::size_t dim, const RealType *alpha)
81 {
82  if (n * dim == 0) {
83  return;
84  }
85 
86  Vector<RealType> s(n);
87  for (std::size_t i = 0; i != dim; ++i) {
88  gamma_distribution(rng, n, s.data(), alpha[i], const_one<RealType>());
89  RealType *t = r + i;
90  for (std::size_t j = 0; j != n; ++j, t += dim) {
91  *t = s[j];
92  }
93  }
95 }
96 
97 template <typename RealType>
99 {
101 
102  public:
103  using result_type = RealType;
105 
106  MCKL_PUSH_CLANG_WARNING("-Wpadded")
108  {
109  public:
110  using result_type = RealType;
112 
113  explicit param_type(std::size_t dim = 1)
114  : alpha_(dim, 1), is_scalar_(true)
115  {
117  this->dim(), this->alpha()),
118  "**DirichletDistribution** constructed with invalid "
119  "arguments");
120  }
121 
122  param_type(std::size_t dim, result_type alpha)
123  : alpha_(dim, alpha), is_scalar_(true)
124  {
126  this->dim(), this->alpha()),
127  "**DirichletDistribution** constructed with invalid "
128  "arguments");
129  }
130 
131  param_type(std::size_t dim, const result_type *alpha)
132  : alpha_(alpha, alpha + dim), is_scalar_(false)
133  {
135  this->dim(), this->alpha()),
136  "**DirichletDistribution** constructed with invalid "
137  "arguments");
138  }
139 
140  std::size_t dim() const { return alpha_.size(); }
141 
142  const result_type *alpha() const { return alpha_.data(); }
143 
144  friend bool operator==(
145  const param_type &param1, const param_type &param2)
146  {
147  if (param1.alpha_ != param2.alpha_) {
148  return false;
149  }
150  if (param1.is_scalar_ != param2.is_scalar_) {
151  return false;
152  }
153  return true;
154  }
155 
156  friend bool operator!=(
157  const param_type &param1, const param_type &param2)
158  {
159  return !(param1 == param2);
160  }
161 
162  template <typename CharT, typename Traits>
163  friend std::basic_ostream<CharT, Traits> &operator<<(
164  std::basic_ostream<CharT, Traits> &os, const param_type &param)
165  {
166  if (!os) {
167  return os;
168  }
169 
170  os << param.alpha_ << ' ';
171  os << param.is_scalar_;
172 
173  return os;
174  }
175 
176  template <typename CharT, typename Traits>
177  friend std::basic_istream<CharT, Traits> &operator>>(
178  std::basic_istream<CharT, Traits> &is, param_type &param)
179  {
180  if (!is) {
181  return is;
182  }
183 
184  param_type tmp;
185  is >> std::ws >> tmp.alpha_;
186  is >> std::ws >> tmp.is_scalar_;
187 
188  if (is) {
189  param = std::move(tmp);
190  } else {
191  is.setstate(std::ios_base::failbit);
192  }
193 
194  return is;
195  }
196 
197  private:
198  Vector<result_type> alpha_;
199  bool is_scalar_;
200 
201  friend distribution_type;
202  }; // class param_type
204 
206  DirichletDistribution(std::size_t dim = 1) : param_(dim) {}
207 
209  DirichletDistribution(std::size_t dim, result_type alpha)
210  : param_(dim, alpha)
211  {
212  reset();
213  }
214 
216  DirichletDistribution(std::size_t dim, const result_type *alpha)
217  : param_(dim, alpha)
218  {
219  reset();
220  }
221 
222  explicit DirichletDistribution(const param_type &param) : param_(param)
223  {
224  reset();
225  }
226 
228  : param_(std::move(param))
229  {
230  reset();
231  }
232 
233  template <typename OutputIter>
234  OutputIter min(OutputIter first) const
235  {
236  return std::fill_n(first, dim(), 0);
237  }
238 
239  template <typename OutputIter>
240  OutputIter max(OutputIter first) const
241  {
242  return std::fill_n(first, dim(), 1);
243  }
244 
245  void reset() {}
246 
247  std::size_t dim() const { return param_.dim(); }
248 
249  const result_type *alpha() const { return param_.alpha(); }
250 
251  const param_type &param() const { return param_; }
252 
253  void param(const param_type &param)
254  {
255  param_ = param;
256  reset();
257  }
258 
259  void param(param_type &&param)
260  {
261  param_ = std::move(param);
262  reset();
263  }
264 
265  template <typename RNGType>
266  void operator()(RNGType &rng, result_type *r)
267  {
268  operator()(rng, r, param_);
269  }
270 
271  template <typename RNGType>
272  void operator()(RNGType &rng, result_type *r, const param_type &param)
273  {
274  generate(rng, r, param);
275  }
276 
277  template <typename RNGType>
278  void operator()(RNGType &rng, std::size_t n, result_type *r)
279  {
280  operator()(rng, n, r, param_);
281  }
282 
283  template <typename RNGType>
285  RNGType &rng, std::size_t n, result_type *r, const param_type &param)
286  {
287  if (param.is_scalar_) {
288  dirichlet_distribution(rng, n, r, param.dim(), param.alpha()[0]);
289  } else {
290  dirichlet_distribution(rng, n, r, param.dim(), param.alpha());
291  }
292  }
293 
294  friend bool operator==(
295  const distribution_type &dist1, const distribution_type &dist2)
296  {
297  if (dist1.param_ != dist2.param_) {
298  return false;
299  }
300  return true;
301  }
302 
303  friend bool operator!=(
304  const distribution_type &dist1, const distribution_type &dist2)
305  {
306  return !(dist1 == dist2);
307  }
308 
309  template <typename CharT, typename Traits>
310  friend std::basic_ostream<CharT, Traits> &operator<<(
311  std::basic_ostream<CharT, Traits> &os, const distribution_type &dist)
312  {
313  if (!os) {
314  return os;
315  }
316 
317  os << dist.param_;
318 
319  return os;
320  }
321 
322  template <typename CharT, typename Traits>
323  friend std::basic_istream<CharT, Traits> &operator>>(
324  std::basic_istream<CharT, Traits> &is, distribution_type &dist)
325  {
326  if (!is) {
327  return is;
328  }
329 
330  param_type param;
331  is >> std::ws >> param;
332  if (is) {
333  dist.param_ = std::move(param);
334  }
335 
336  return is;
337  }
338 
339  private:
340  param_type param_;
341 
342  template <typename RNGType>
343  void generate(RNGType &rng, result_type *r, const param_type &param)
344  {
345  const std::size_t d = param.dim();
346  if (param.is_scalar_) {
347  GammaDistribution<result_type> gamma(param.alpha()[0]);
348  gamma(rng, d, r);
349  } else {
350  for (std::size_t i = 0; i != d; ++i) {
351  GammaDistribution<result_type> gamma(param.alpha()[i]);
352  r[i] = gamma(rng);
353  }
354  }
355  result_type s = std::accumulate(r, r + d, const_zero<result_type>());
356  mul<result_type>(d, 1 / s, r, r);
357  }
358 }; // class DirichletDistribution
359 
360 template <typename RealType, typename RNGType>
361 inline void rand(
362  RNGType &rng, DirichletDistribution<RealType> &distribution, RealType *r)
363 {
364  distribution(rng, r);
365 }
366 
367 template <typename RealType, typename RNGType>
368 inline void rand(RNGType &rng, DirichletDistribution<RealType> &distribution,
369  std::size_t n, RealType *r)
370 {
371  distribution(rng, n, r);
372 }
373 
374 } // namespace mckl
375 
376 #endif // MCKL_RANDOM_DIRICHLET_DISTRIBUTION_HPP
param_type(std::size_t dim, const result_type *alpha)
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const distribution_type &dist)
OutputIter max(OutputIter first) const
friend bool operator==(const distribution_type &dist1, const distribution_type &dist2)
#define MCKL_PUSH_CLANG_WARNING(warning)
Definition: compiler.h:63
std::vector< T, Alloc > Vector
std::vector with Allocator as the default allocator
Definition: memory.hpp:435
STL namespace.
void operator()(RNGType &rng, result_type *r)
void gamma_distribution(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
void param(const param_type &param)
void dirichlet_distribution(RNGType &rng, std::size_t n, RealType *r, std::size_t dim, const RealType alpha)
friend bool operator==(const param_type &param1, const param_type &param2)
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, distribution_type &dist)
friend bool operator!=(const param_type &param1, const param_type &param2)
void operator()(RNGType &rng, result_type *r, const param_type &param)
DirichletDistribution(const param_type &param)
void dirichlet_distribution_avg(std::size_t n, std::size_t dim, RealType *r)
OutputIter min(OutputIter first) const
DirichletDistribution(std::size_t dim, result_type alpha)
Construct a distribution with scalar shape.
Definition: mcmc.hpp:40
void rand(RNGType &rng, ArcsineDistribution< RealType > &distribution, std::size_t N, RealType *r)
void operator()(RNGType &rng, std::size_t n, result_type *r, const param_type &param)
#define MCKL_POP_CLANG_WARNING
Definition: compiler.h:66
DirichletDistribution(std::size_t dim, const result_type *alpha)
Construct a distribution with vector shapes.
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_ASSERT_REAL_TYPE(Name)
friend bool operator!=(const distribution_type &dist1, const distribution_type &dist2)
void operator()(RNGType &rng, std::size_t n, result_type *r)
param_type(std::size_t dim, result_type alpha)
const param_type & param() const
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, param_type &param)
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const param_type &param)
bool dirichlet_distribution_check_param(std::size_t dim, RealType *alpha)
void runtime_assert(bool cond, const char *msg, bool soft=false)
Definition: assert.hpp:65
const result_type * alpha() const
DirichletDistribution(std::size_t dim=1)
Construct a distribution with scalar shape.