vSMC  v3.0.0
Scalable Monte Carlo
discrete_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/discrete_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_DISCRETE_DISTRIBUTION_HPP
33 #define VSMC_RNG_DISCRETE_DISTRIBUTION_HPP
34 
37 
38 #define VSMC_RUNTIME_ASSERT_RNG_DISCRETE_DISTRIBUTION_POSITIVE(flag) \
39  VSMC_RUNTIME_ASSERT( \
40  (flag), "**DiscreteDistribution** WEIGHTS ARE NOT NON-NEGATIVE")
41 
42 namespace vsmc
43 {
44 
47 template <typename IntType>
49 {
50  public:
51  using result_type = IntType;
53 
54  class param_type
55  {
56  public:
57  using result_type = IntType;
59 
61 
62  template <typename InputIter>
63  param_type(InputIter first, InputIter last) : probability_(first, last)
64  {
65  invariant();
66  }
67 
68  param_type(std::initializer_list<double> weights)
69  : probability_(weights.begin(), weights.end())
70  {
71  invariant();
72  }
73 
74  template <typename UnaryOperation>
75  param_type(std::size_t count, double xmin, double xmax,
76  UnaryOperation unary_op)
77  {
78  probability_.reserve(count);
79  double delta = (xmax - xmin) / static_cast<double>(count);
80  xmin += 0.5 * delta;
81  for (std::size_t i = 0; i != count; ++i)
82  probability_.push_back(
83  unary_op(xmin + static_cast<double>(i) * delta));
84  invariant();
85  }
86 
87  Vector<double> probability() const { return probability_; }
88 
89  friend bool operator==(
90  const param_type &param1, const param_type &param2)
91  {
92  return param1.probability_ == param2.probability_;
93  }
94 
95  friend bool operator!=(
96  const param_type &param1, const param_type &param2)
97  {
98  return !(param1 == param2);
99  }
100 
101  template <typename CharT, typename Traits>
102  friend std::basic_ostream<CharT, Traits> &operator<<(
103  std::basic_ostream<CharT, Traits> &os, const param_type &param)
104  {
105  if (!os)
106  return os;
107 
108  os << param.probability_;
109 
110  return os;
111  }
112 
113  template <typename CharT, typename Traits>
114  friend std::basic_istream<CharT, Traits> &operator>>(
115  std::basic_istream<CharT, Traits> &is, param_type &param)
116  {
117  if (!is)
118  return is;
119 
121  is >> std::ws >> probability;
122 
123  if (is) {
124  double sum = 0;
125  if (is_positive(probability, sum)) {
126  mul(probability.size(), 1 / sum, probability.data(),
127  probability.data());
128  param.probability_ = std::move(probability);
129  } else {
130  is.setstate(std::ios_base::failbit);
131  }
132  }
133 
134  return is;
135  }
136 
137  private:
138  Vector<double> probability_;
139 
140  friend distribution_type;
141 
142  void invariant()
143  {
144  if (probability_.size() == 0)
145  return;
146 
147  double sum = 0;
148 #ifndef NDEBUG
149  bool flag = is_positive(probability_, sum);
151 #else
152  is_positive(probability_, sum);
153 #endif
154  mul(probability_.size(), 1 / sum, probability_.data(),
155  probability_.data());
156  }
157 
158  void reset() {}
159 
160  static bool is_positive(const Vector<double> &probability, double &sum)
161  {
162  sum = 0;
163  bool flag = true;
164  for (std::size_t i = 0; i != probability.size(); ++i) {
165  sum += probability[i];
166  if (probability[i] < 0)
167  flag = false;
168  }
169 
170  return flag && sum > 0;
171  }
172  }; // class param_type
173 
175 
176  template <typename InputIter>
177  DiscreteDistribution(InputIter first, InputIter last) : param_(first, last)
178  {
179  }
180 
181  DiscreteDistribution(std::initializer_list<double> weights)
182  : param_(weights)
183  {
184  }
185 
186  template <typename UnaryOperation>
188  std::size_t count, double xmin, double xmax, UnaryOperation &&unary_op)
189  : param_type(count, xmin, xmax, std::forward<UnaryOperation>(unary_op))
190  {
191  }
192 
193  explicit DiscreteDistribution(const param_type &param) : param_(param) {}
194 
196  : param_(std::move(param))
197  {
198  }
199 
200  result_type min() const { return 0; }
201 
202  result_type max() const
203  {
204  return param_.size() == 0 ? 0 : param_.size() - 1;
205  }
206 
207  Vector<double> probability() const { return param_.probability_; }
208 
209  template <typename RNGType>
210  result_type operator()(RNGType &rng) const
211  {
212  return operator()(
213  rng, param_.probability_.begin(), param_.probability_.end(), true);
214  }
215 
234  template <typename RNGType, typename InputIter>
235  result_type operator()(RNGType &rng, InputIter first, InputIter last,
236  bool normalized = false) const
237  {
238  using value_type =
239  typename std::iterator_traits<InputIter>::value_type;
240 
242  value_type u = u01(rng);
243 
244  if (!normalized) {
245  value_type mulw =
246  1 / std::accumulate(first, last, static_cast<value_type>(0));
247  value_type accw = 0;
248  result_type index = 0;
249  while (first != last) {
250  accw += *first * mulw;
251  if (u <= accw)
252  return index;
253  ++first;
254  ++index;
255  }
256 
257  return index - 1;
258  }
259 
260  value_type accw = 0;
261  result_type index = 0;
262  while (first != last) {
263  accw += *first;
264  if (u <= accw)
265  return index;
266  ++first;
267  ++index;
268  }
269 
270  return index - 1;
271  }
272 
273  friend bool operator==(
274  const distribution_type &dist1, const distribution_type &dist2)
275  {
276  return dist1.param_ == dist2.param_;
277  }
278 
279  friend bool operator!=(
280  const distribution_type &dist1, const distribution_type &dist2)
281  {
282  return !(dist1 == dist2);
283  }
284 
285  template <typename CharT, typename Traits>
286  friend std::basic_ostream<CharT, Traits> &operator<<(
287  std::basic_ostream<CharT, Traits> &os, const distribution_type &dist)
288  {
289  os << dist.param_;
290 
291  return os;
292  }
293 
294  template <typename CharT, typename Traits>
295  friend std::basic_istream<CharT, Traits> &operator>>(
296  std::basic_istream<CharT, Traits> &is, distribution_type &dist)
297  {
298  is >> std::ws >> dist.param_;
299  if (is)
300  dist.reset();
301 
302  return is;
303  }
304 
305  private:
306  param_type param_;
307 }; // class DiscreteDistribution
308 
309 } // namespace vsmc
310 
311 #endif // VSMC_RNG_DISCRETE_DISTRIBUTION_HPP
std::vector< T, Alloc > Vector
std::vector with Allocator as default allocator
Definition: monitor.hpp:48
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:77
param_type(InputIter first, InputIter last)
friend bool operator==(const distribution_type &dist1, const distribution_type &dist2)
DiscreteDistribution(InputIter first, InputIter last)
STL namespace.
param_type(std::size_t count, double xmin, double xmax, UnaryOperation unary_op)
result_type operator()(RNGType &rng) const
RealType u01(UIntType u) noexcept
Convert uniform unsigned integers to floating points within [0, 1].
Definition: u01.hpp:213
param_type(std::initializer_list< double > weights)
DiscreteDistribution(param_type &&param)
friend bool operator!=(const distribution_type &dist1, const distribution_type &dist2)
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const param_type &param)
DiscreteDistribution(std::initializer_list< double > weights)
result_type operator()(RNGType &rng, InputIter first, InputIter last, bool normalized=false) const
Draw sample with external probabilities.
DiscreteDistribution< IntType > distribution_type
DiscreteDistribution(const param_type &param)
#define VSMC_RUNTIME_ASSERT_RNG_DISCRETE_DISTRIBUTION_POSITIVE(flag)
DiscreteDistribution(std::size_t count, double xmin, double xmax, UnaryOperation &&unary_op)
friend bool operator==(const param_type &param1, const param_type &param2)
Vector< double > probability() const
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, distribution_type &dist)
Draw a single sample given weights.
friend bool operator!=(const param_type &param1, const param_type &param2)
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const distribution_type &dist)
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, param_type &param)