vSMC
vSMC: 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  if (param1.probability_.size() != param2.probability_.size())
93  return false;
94 
95  for (std::size_t i = 0; i != param1.probability_.size(); ++i)
96  if (!internal::is_equal(
97  param1.probability_[i], param2.probability_[i]))
98  return false;
99 
100  return true;
101  }
102 
103  friend bool operator!=(
104  const param_type &param1, const param_type &param2)
105  {
106  return !(param1 == param2);
107  }
108 
109  template <typename CharT, typename Traits>
110  friend std::basic_ostream<CharT, Traits> &operator<<(
111  std::basic_ostream<CharT, Traits> &os, const param_type &param)
112  {
113  if (!os.good())
114  return os;
115 
116  os << param.probability_.size() << ' ';
117  for (std::size_t i = 0; i != param.probability_.size(); ++i)
118  os << param.probability_[i] << ' ';
119 
120  return os;
121  }
122 
123  template <typename CharT, typename Traits>
124  friend std::basic_istream<CharT, Traits> &operator>>(
125  std::basic_istream<CharT, Traits> &is, param_type &param)
126  {
127  if (!is.good())
128  return is;
129 
130  std::size_t n = 0;
131  is >> std::ws >> n;
132  if (!is.good())
133  return is;
134 
136  for (std::size_t i = 0; i != n; ++i)
137  is >> std::ws >> probability[i];
138 
139  if (is.good()) {
140  double sum = 0;
141  if (is_positive(probability, sum)) {
142  mul(probability.size(), 1 / sum, probability.data(),
143  probability.data());
144  param.probability_ = std::move(probability);
145  } else {
146  is.setstate(std::ios_base::failbit);
147  }
148  }
149 
150  return is;
151  }
152 
153  private:
154  Vector<double> probability_;
155 
156  friend distribution_type;
157 
158  void invariant()
159  {
160  if (probability_.size() == 0)
161  return;
162 
163  double sum = 0;
164 #ifndef NDEBUG
165  bool flag = is_positive(probability_, sum);
167 #else
168  is_positive(probability_, sum);
169 #endif
170  mul(probability_.size(), 1 / sum, probability_.data(),
171  probability_.data());
172  }
173 
174  void reset() {}
175 
176  static bool is_positive(const Vector<double> &probability, double &sum)
177  {
178  sum = 0;
179  bool flag = true;
180  for (std::size_t i = 0; i != probability.size(); ++i) {
181  sum += probability[i];
182  if (probability[i] < 0)
183  flag = false;
184  }
185 
186  return flag && sum > 0;
187  }
188  }; // class param_type
189 
191 
192  template <typename InputIter>
193  DiscreteDistribution(InputIter first, InputIter last) : param_(first, last)
194  {
195  }
196 
197  DiscreteDistribution(std::initializer_list<double> weights)
198  : param_(weights)
199  {
200  }
201 
202  template <typename UnaryOperation>
204  std::size_t count, double xmin, double xmax, UnaryOperation &&unary_op)
205  : param_type(count, xmin, xmax, std::forward<UnaryOperation>(unary_op))
206  {
207  }
208 
209  explicit DiscreteDistribution(const param_type &param) : param_(param) {}
210 
212  : param_(std::move(param))
213  {
214  }
215 
216  result_type min() const { return 0; }
217 
218  result_type max() const
219  {
220  return param_.size() == 0 ? 0 : param_.size() - 1;
221  }
222 
223  Vector<double> probability() const { return param_.probability_; }
224 
225  template <typename RNGType>
226  result_type operator()(RNGType &rng) const
227  {
228  return operator()(
229  rng, param_.probability_.begin(), param_.probability_.end(), true);
230  }
231 
250  template <typename RNGType, typename InputIter>
251  result_type operator()(RNGType &rng, InputIter first, InputIter last,
252  bool normalized = false) const
253  {
254  using value_type =
255  typename std::iterator_traits<InputIter>::value_type;
256 
258  value_type u = u01(rng);
259 
260  if (!normalized) {
261  value_type mulw =
262  1 / std::accumulate(first, last, static_cast<value_type>(0));
263  value_type accw = 0;
264  result_type index = 0;
265  while (first != last) {
266  accw += *first * mulw;
267  if (u <= accw)
268  return index;
269  ++first;
270  ++index;
271  }
272 
273  return index - 1;
274  }
275 
276  value_type accw = 0;
277  result_type index = 0;
278  while (first != last) {
279  accw += *first;
280  if (u <= accw)
281  return index;
282  ++first;
283  ++index;
284  }
285 
286  return index - 1;
287  }
288 
289  friend bool operator==(
290  const distribution_type &dist1, const distribution_type &dist2)
291  {
292  return dist1.param_ == dist2.param_;
293  }
294 
295  friend bool operator!=(
296  const distribution_type &dist1, const distribution_type &dist2)
297  {
298  return !(dist1 == dist2);
299  }
300 
301  template <typename CharT, typename Traits>
302  friend std::basic_ostream<CharT, Traits> &operator<<(
303  std::basic_ostream<CharT, Traits> &os, const distribution_type &dist)
304  {
305  os << dist.param_;
306 
307  return os;
308  }
309 
310  template <typename CharT, typename Traits>
311  friend std::basic_istream<CharT, Traits> &operator>>(
312  std::basic_istream<CharT, Traits> &is, distribution_type &dist)
313  {
314  is >> std::ws >> dist.param_;
315  if (is.good())
316  dist.reset();
317 
318  return is;
319  }
320 
321  private:
322  param_type param_;
323 }; // class DiscreteDistribution
324 
325 } // namespace vsmc
326 
327 #endif // VSMC_RNG_DISCRETE_DISTRIBUTION_HPP
Definition: monitor.hpp:49
typename std::conditional< std::is_scalar< T >::value, AlignedVector< T >, std::vector< T >>::type Vector
AlignedVector for scalar type and std::vector for others.
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:112
param_type(InputIter first, InputIter last)
friend bool operator==(const distribution_type &dist1, const distribution_type &dist2)
DiscreteDistribution(InputIter first, InputIter last)
bool is_equal(const T &a, const T &b)
Definition: common.hpp:90
STL namespace.
param_type(std::size_t count, double xmin, double xmax, UnaryOperation unary_op)
result_type operator()(RNGType &rng) const
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)
Standard uniform distribution.
Definition: common.hpp:597
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)