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-2015, 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 #include <vsmc/math/cblas.hpp>
38 
39 #define VSMC_RUNTIME_ASSERT_RNG_DISCRETE_DISTRIBUTION_POSITIVE(flag) \
40  VSMC_RUNTIME_ASSERT( \
41  (flag), "**DiscreteDistribution** WEIGHTS ARE NOT NON-NEGATIVE")
42 
43 namespace vsmc
44 {
45 
48 template <typename IntType>
50 {
51  public:
52  using result_type = IntType;
54 
55  class param_type
56  {
57  public:
58  using result_type = IntType;
60 
62 
63  template <typename InputIter>
64  param_type(InputIter first, InputIter last)
65  : probability_(first, last)
66  {
67  invariant();
68  }
69 
70  param_type(std::initializer_list<double> weights)
71  : probability_(weights.begin(), weights.end())
72  {
73  invariant();
74  }
75 
76  template <typename UnaryOperation>
77  param_type(std::size_t count, double xmin, double xmax,
78  UnaryOperation unary_op)
79  {
80  probability_.reserve(count);
81  double delta = (xmax - xmin) / static_cast<double>(count);
82  xmin += 0.5 * delta;
83  for (std::size_t i = 0; i != count; ++i)
84  probability_.push_back(
85  unary_op(xmin + static_cast<double>(i) * delta));
86  invariant();
87  }
88 
89  Vector<double> probability() const { return probability_; }
90 
91  friend bool operator==(
92  const param_type &param1, const param_type &param2)
93  {
94  if (param1.probability_.size() != param2.probability_.size())
95  return false;
96 
97  for (std::size_t i = 0; i != param1.probability_.size(); ++i)
98  if (!internal::is_equal(
99  param1.probability_[i], param2.probability_[i]))
100  return false;
101 
102  return true;
103  }
104 
105  friend bool operator!=(
106  const param_type &param1, const param_type &param2)
107  {
108  return !(param1 == param2);
109  }
110 
111  template <typename CharT, typename Traits>
112  friend std::basic_ostream<CharT, Traits> &operator<<(
113  std::basic_ostream<CharT, Traits> &os, const param_type &param)
114  {
115  if (!os.good())
116  return os;
117 
118  os << param.probability_.size() << ' ';
119  for (std::size_t i = 0; i != param.probability_.size(); ++i)
120  os << param.probability_[i] << ' ';
121 
122  return os;
123  }
124 
125  template <typename CharT, typename Traits>
126  friend std::basic_istream<CharT, Traits> &operator>>(
127  std::basic_istream<CharT, Traits> &is, param_type &param)
128  {
129  if (!is.good())
130  return is;
131 
132  std::size_t n = 0;
133  is >> std::ws >> n;
134  if (!is.good())
135  return is;
136 
138  for (std::size_t i = 0; i != n; ++i)
139  is >> std::ws >> probability[i];
140 
141  if (is.good()) {
142  double sum = 0;
143  if (is_positive(probability, sum)) {
144  mul(probability.size(), 1 / sum, probability.data(),
145  probability.data());
146  param.probability_ = std::move(probability);
147  } else {
148  is.setstate(std::ios_base::failbit);
149  }
150  }
151 
152  return is;
153  }
154 
155  private:
156  Vector<double> probability_;
157 
158  friend distribution_type;
159 
160  void invariant()
161  {
162  if (probability_.size() == 0)
163  return;
164 
165  double sum = 0;
166 #ifndef NDEBUG
167  bool flag = is_positive(probability_, sum);
169 #else
170  is_positive(probability_, sum);
171 #endif
172  mul(probability_.size(), 1 / sum, probability_.data(),
173  probability_.data());
174  }
175 
176  void reset() {}
177 
178  static bool is_positive(const Vector<double> &probability, double &sum)
179  {
180  sum = 0;
181  bool flag = true;
182  for (std::size_t i = 0; i != probability.size(); ++i) {
183  sum += probability[i];
184  if (probability[i] < 0)
185  flag = false;
186  }
187 
188  return flag && sum > 0;
189  }
190  }; // class param_type
191 
193 
194  template <typename InputIter>
195  DiscreteDistribution(InputIter first, InputIter last)
196  : param_(first, last)
197  {
198  }
199 
200  DiscreteDistribution(std::initializer_list<double> weights)
201  : param_(weights)
202  {
203  }
204 
205  template <typename UnaryOperation>
207  std::size_t count, double xmin, double xmax, UnaryOperation &&unary_op)
208  : param_type(count, xmin, xmax, std::forward<UnaryOperation>(unary_op))
209  {
210  }
211 
212  explicit DiscreteDistribution(const param_type &param) : param_(param) {}
213 
215  : param_(std::move(param))
216  {
217  }
218 
219  result_type min VSMC_MNE() const { return 0; }
220 
222  {
223  return param_.size() == 0 ? 0 : param_.size() - 1;
224  }
225 
226  Vector<double> probability() const { return param_.probability_; }
227 
228  template <typename RNGType>
229  result_type operator()(RNGType &rng) const
230  {
231  return operator()(
232  rng, param_.probability_.begin(), param_.probability_.end(), true);
233  }
234 
253  template <typename RNGType, typename InputIter>
254  result_type operator()(RNGType &rng, InputIter first, InputIter last,
255  bool normalized = false) const
256  {
257  using value_type =
258  typename std::iterator_traits<InputIter>::value_type;
259 
261  value_type u = runif(rng);
262 
263  if (!normalized) {
264  value_type mulw =
265  1 / std::accumulate(first, last, static_cast<value_type>(0));
266  value_type accw = 0;
267  result_type index = 0;
268  while (first != last) {
269  accw += *first * mulw;
270  if (u <= accw)
271  return index;
272  ++first;
273  ++index;
274  }
275 
276  return index - 1;
277  }
278 
279  value_type accw = 0;
280  result_type index = 0;
281  while (first != last) {
282  accw += *first;
283  if (u <= accw)
284  return index;
285  ++first;
286  ++index;
287  }
288 
289  return index - 1;
290  }
291 
293 
294  private:
295  param_type param_;
296 }; // class DiscreteDistribution
297 
298 } // namespace vsmc
299 
300 #endif // VSMC_RNG_DISCRETE_DISTRIBUTION_HPP
Definition: monitor.hpp:49
Standard uniform distribution with open/closed variants.
Definition: common.hpp:512
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:112
param_type(InputIter first, InputIter last)
DiscreteDistribution(InputIter first, InputIter last)
typename std::conditional< std::is_scalar< T >::value, std::vector< T, AlignedAllocator< T >>, std::vector< T >>::type Vector
AlignedVector for scalar type and std::vector for others.
bool is_equal(const T &a, const T &b)
Definition: common.hpp:333
STL namespace.
param_type(std::size_t count, double xmin, double xmax, UnaryOperation unary_op)
#define VSMC_DEFINE_RNG_DISTRIBUTION_OPERATORS
Definition: common.hpp:286
result_type operator()(RNGType &rng) const
param_type(std::initializer_list< double > weights)
DiscreteDistribution(param_type &&param)
#define VSMC_MNE
Definition: defines.hpp:38
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
Draw a single sample given weights.
friend bool operator!=(const param_type &param1, const param_type &param2)
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, param_type &param)