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,2014, 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 
35 #include <vsmc/internal/common.hpp>
36 #include <vsmc/math/cblas.hpp>
37 
38 #define VSMC_RUNTIME_ASSERT_RNG_DISCRETE_DISTRIBUTION_POSITIVE(param) \
39  VSMC_RUNTIME_ASSERT(is_positive(param), \
40  ("**DiscreteDistribution** WEIGHTS ARE NOT NON-NEGATIVE"));
41 
42 namespace vsmc {
43 
46 template <typename IntType = int>
48 {
49  public :
50 
51  typedef IntType result_type;
52  typedef std::vector<double> param_type;
53 
55 
56  template <typename InputIter>
57  DiscreteDistribution (InputIter first, InputIter last) :
58  param_(first, last)
59  {
61  normalize();
62  }
63 
64 #if VSMC_HAS_CXX11LIB_INITIALIZER_LIST
65  DiscreteDistribution (std::initializer_list<double> weights) :
66  param_(weights.begin(), weights.end())
67  {
69  normalize();
70  }
71 #endif
72 
73  template <typename UnaryOperation>
74  DiscreteDistribution (std::size_t count, double xmin, double xmax,
75  UnaryOperation unary_op)
76  {
77  param_.reserve(count);
78  double delta = (xmax - xmin) / static_cast<double>(count);
79  xmin += 0.5 * delta;
80  for (std::size_t i = 0; i != count; ++i)
81  param_.push_back(unary_op(xmin + static_cast<double>(i) * delta));
83  normalize();
84  }
85 
86  explicit DiscreteDistribution (const param_type &param)
87  {
89  param_ = param;
90  normalize();
91  }
92 
93 #if VSMC_HAS_CXX11_RVALUE_REFERENCES
94  explicit DiscreteDistribution (param_type &&param)
95  {
97  param_ = cxx11::move(param);
98  normalize();
99  }
100 #endif
101 
102  param_type param () const {return param_;}
103 
104  void param (const param_type &param)
105  {
107  param_ = param;
108  normalize();
109  }
110 
111 #if VSMC_HAS_CXX11_RVALUE_REFERENCES
112  void param (param_type &&param)
113  {
115  param_ = cxx11::move(param);
116  normalize();
117  }
118 #endif
119 
120  void reset () {}
121 
122  result_type min VSMC_MNE () const {return 0;}
123  result_type max VSMC_MNE () const
124  {return param_.size() == 0 ? 0 : param_.size() - 1;}
125 
126  std::vector<double> probability () const {return param_;}
127 
128  template <typename URNG>
129  result_type operator() (URNG &eng) const
130  {return operator()(eng, param_.begin(), param_.end(), true);}
131 
154  template <typename URNG, typename InputIter>
155  result_type operator() (URNG &eng, InputIter first, InputIter last,
156  bool normalized = false) const
157  {
158  typedef typename std::iterator_traits<InputIter>::value_type
159  value_type;
160 
161  cxx11::uniform_real_distribution<value_type> runif(0, 1);
162  value_type u = runif(eng);
163 
164  if (!normalized) {
165  value_type mulw = 1 / std::accumulate(first, last,
166  static_cast<value_type>(0));
167  value_type accw = 0;
168  result_type index = 0;
169  while (first != last) {
170  accw += *first * mulw;
171  if (u <= accw)
172  return index;
173  ++first;
174  ++index;
175  }
176 
177  return index - 1;
178  }
179 
180  value_type accw = 0;
181  result_type index = 0;
182  while (first != last) {
183  accw += *first;
184  if (u <= accw)
185  return index;
186  ++first;
187  ++index;
188  }
189 
190  return index - 1;
191  }
192 
193  friend inline bool operator== (
194  const DiscreteDistribution<IntType> &rdisc1,
195  const DiscreteDistribution<IntType> &rdisc2)
196  {return rdisc1.param_ == rdisc2.param_;}
197 
198  friend inline bool operator!= (
199  const DiscreteDistribution<IntType> &rdisc1,
200  const DiscreteDistribution<IntType> &rdisc2)
201  {return rdisc1.param_ != rdisc2.param_;}
202 
203  template <typename CharT, typename Traits>
204  friend inline std::basic_ostream<CharT, Traits> &operator<< (
205  std::basic_ostream<CharT, Traits> &os,
206  const DiscreteDistribution<IntType> &rdisc)
207  {
208  if (!os.good())
209  return os;
210 
211  os << rdisc.param_.size() << ' ';
212 
213  if (rdisc.param_.size() == 0)
214  return os;
215 
216  if (rdisc.param_.size() == 1) {
217  os << rdisc.param_[0];
218  return os;
219  }
220 
221  for (std::size_t i = 0; i != rdisc.param_.size() - 1; ++i)
222  os << rdisc.param_[i] << ' ';
223  os << rdisc.param_.back();
224 
225  return os;
226  }
227 
228  template <typename CharT, typename Traits>
229  friend inline std::basic_istream<CharT, Traits> &operator>> (
230  std::basic_istream<CharT, Traits> &is,
232  {
233  if (!is.good())
234  return is;
235 
236  std::size_t n;
237  is >> std::ws >> n;
238 
239  std::vector<double> param(n);
240  for (std::size_t i = 0; i != n; ++i)
241  is >> std::ws >> param[i];
242 
243  if (is.good()) {
244  if (rdisc.is_positive(param)) {
245  std::swap(rdisc.param_, param);
246  rdisc.normalize();
247  } else {
248  is.setstate(std::ios_base::failbit);
249  }
250  }
251 
252  return is;
253  }
254 
255  private :
256 
257  param_type param_;
258 
259  void normalize ()
260  {
261  if (param_.size() == 0)
262  return;
263 
264  double sumw = std::accumulate(param_.begin(), param_.end(), 0.0);
265  math::scal(param_.size(), 1 / sumw, &param_[0]);
266  }
267 
268  bool is_positive (const param_type &param)
269  {
270  for (std::size_t i = 0; i != param.size(); ++i)
271  if (param[i] < 0)
272  return false;
273 
274  if (param.size() == 0)
275  return true;
276 
277  if (std::accumulate(param.begin(), param.end(), 0.0) <= 0)
278  return false;
279 
280  return true;
281  }
282 }; // class DiscreteDistribution
283 
284 } // namespace vsmc
285 
286 #endif // VSMC_RNG_DISCRETE_DISTRIBUTION_HPP
Definition: adapter.hpp:37
DiscreteDistribution(InputIter first, InputIter last)
DiscreteDistribution(std::size_t count, double xmin, double xmax, UnaryOperation unary_op)
void param(const param_type &param)
#define VSMC_RUNTIME_ASSERT_RNG_DISCRETE_DISTRIBUTION_POSITIVE(param)
std::vector< double > probability() const
DiscreteDistribution(param_type &&param)
std::vector< double > param_type
#define VSMC_MNE
Avoid MSVC stupid behavior: MNE = Macro No Expansion.
Definition: defines.hpp:38
result_type operator()(URNG &eng) const
void scal(std::size_t n, T a, T *x)
Scale a vector.
Definition: cblas.hpp:80
remove_reference< T >::type && move(T &&t) noexcept
DiscreteDistribution(const param_type &param)
friend bool operator==(const DiscreteDistribution< IntType > &rdisc1, const DiscreteDistribution< IntType > &rdisc2)
void swap(Array< T, N > &ary1, Array< T, N > &ary2)
Array ADL of swap.
Definition: array.hpp:317
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, DiscreteDistribution< IntType > &rdisc)
Draw a single sample given weights.
void param(param_type &&param)
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const DiscreteDistribution< IntType > &rdisc)
friend bool operator!=(const DiscreteDistribution< IntType > &rdisc1, const DiscreteDistribution< IntType > &rdisc2)