EigenRand  0.3.0
Multinomial.h
Go to the documentation of this file.
1 
12 #ifndef EIGENRAND_MVDISTS_MULTINOMIAL_H
13 #define EIGENRAND_MVDISTS_MULTINOMIAL_H
14 
15 namespace Eigen
16 {
17  namespace Rand
18  {
25  template<typename _Scalar = int32_t, Index Dim = -1>
26  class MultinomialGen : public MvVecGenBase<MultinomialGen<_Scalar, Dim>, _Scalar, Dim>
27  {
28  static_assert(std::is_same<_Scalar, int32_t>::value, "`MultinomialGen` needs integral types.");
29  _Scalar trials;
30  Matrix<double, Dim, 1> probs;
31  DiscreteGen<_Scalar> discrete;
32  public:
40  template<typename WeightTy>
41  MultinomialGen(_Scalar _trials, const MatrixBase<WeightTy>& _weights)
42  : trials{ _trials }, probs{ _weights.template cast<double>() }, discrete(probs.data(), probs.data() + probs.size())
43  {
44  eigen_assert(_weights.cols() == 1);
45  for (Index i = 0; i < probs.size(); ++i)
46  {
47  eigen_assert(probs[i] >= 0);
48  }
49  probs /= probs.sum();
50  }
51 
52  MultinomialGen(const MultinomialGen&) = default;
53  MultinomialGen(MultinomialGen&&) = default;
54 
55  Index dims() const { return probs.rows(); }
56 
57  template<typename Urng>
58  inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
59  {
60  const Index dim = probs.size();
61  Matrix<_Scalar, Dim, -1> ret(dim, samples);
62  //if (trials < 2500)
63  {
64  for (Index j = 0; j < samples; ++j)
65  {
66  ret.col(j) = generate(urng);
67  }
68  }
69  /*else
70  {
71  ret.row(0) = binomial<Matrix<_Scalar, -1, 1>>(samples, 1, urng, trials, probs[0]).eval().transpose();
72  for (Index j = 0; j < samples; ++j)
73  {
74  double rest_p = 1 - probs[0];
75  _Scalar t = trials - ret(0, j);
76  for (Index i = 1; i < dim - 1; ++i)
77  {
78  ret(i, j) = binomial<Matrix<_Scalar, 1, 1>>(1, 1, urng, t, probs[i] / rest_p)(0);
79  t -= ret(i, j);
80  rest_p -= probs[i];
81  }
82  ret(dim - 1, j) = 0;
83  }
84  ret.row(dim - 1).setZero();
85  ret.row(dim - 1).array() = trials - ret.colwise().sum().array();
86  }*/
87  return ret;
88  }
89 
90  template<typename Urng>
91  inline Matrix<_Scalar, Dim, 1> generate(Urng&& urng)
92  {
93  const Index dim = probs.size();
94  Matrix<_Scalar, Dim, 1> ret(dim);
95  //if (trials < 2500)
96  {
97  ret.setZero();
98  auto d = discrete.template generate<Matrix<_Scalar, -1, 1>>(trials, 1, urng).eval();
99  for (Index i = 0; i < trials; ++i)
100  {
101  ret[d[i]] += 1;
102  }
103  }
104  /*else
105  {
106  double rest_p = 1;
107  _Scalar t = trials;
108  for (Index i = 0; i < dim - 1; ++i)
109  {
110  ret[i] = binomial<Matrix<_Scalar, 1, 1>>(1, 1, urng, t, probs[i] / rest_p)(0);
111  t -= ret[i];
112  rest_p -= probs[i];
113  }
114  ret[dim - 1] = 0;
115  ret[dim - 1] = trials - ret.sum();
116  }*/
117  return ret;
118  }
119  };
120 
131  template<typename IntTy, typename WeightTy>
132  inline auto makeMultinomialGen(IntTy trials, const MatrixBase<WeightTy>& probs)
134  {
136  }
137 
144  template<typename _Scalar, Index Dim = -1>
145  class DirichletGen : public MvVecGenBase<DirichletGen<_Scalar, Dim>, _Scalar, Dim>
146  {
147  Matrix<_Scalar, Dim, 1> alpha;
148  std::vector<GammaGen<_Scalar>> gammas;
149  public:
156  template<typename AlphaTy>
157  DirichletGen(const MatrixBase<AlphaTy>& _alpha)
158  : alpha{ _alpha }
159  {
160  eigen_assert(_alpha.cols() == 1);
161  for (Index i = 0; i < alpha.size(); ++i)
162  {
163  eigen_assert(alpha[i] > 0);
164  gammas.emplace_back(alpha[i]);
165  }
166  }
167 
168  DirichletGen(const DirichletGen&) = default;
169  DirichletGen(DirichletGen&&) = default;
170 
171  Index dims() const { return alpha.rows(); }
172 
173  template<typename Urng>
174  inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
175  {
176  const Index dim = alpha.size();
177  Matrix<_Scalar, Dim, -1> ret(dim, samples);
178  Matrix<_Scalar, -1, 1> tmp(samples);
179  for (Index i = 0; i < dim; ++i)
180  {
181  tmp = gammas[i].generateLike(tmp, urng);
182  ret.row(i) = tmp.transpose();
183  }
184  ret.array().rowwise() /= ret.array().colwise().sum();
185  return ret;
186  }
187 
188  template<typename Urng>
189  inline Matrix<_Scalar, Dim, 1> generate(Urng&& urng)
190  {
191  const Index dim = alpha.size();
192  Matrix<_Scalar, Dim, 1> ret(dim);
193  for (Index i = 0; i < dim; ++i)
194  {
195  ret[i] = gammas[i].template generate<Matrix<_Scalar, 1, 1>>(1, 1, urng)(0);
196  }
197  ret /= ret.sum();
198  return ret;
199  }
200  };
201 
210  template<typename AlphaTy>
211  inline auto makeDirichletGen(const MatrixBase<AlphaTy>& alpha)
212  -> DirichletGen<typename MatrixBase<AlphaTy>::Scalar, MatrixBase<AlphaTy>::RowsAtCompileTime>
213  {
214  return DirichletGen<typename MatrixBase<AlphaTy>::Scalar, MatrixBase<AlphaTy>::RowsAtCompileTime>{ alpha };
215  }
216  }
217 }
218 
219 #endif
Eigen::Rand::makeDirichletGen
auto makeDirichletGen(const MatrixBase< AlphaTy > &alpha) -> DirichletGen< typename MatrixBase< AlphaTy >::Scalar, MatrixBase< AlphaTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::DirichletGen
Definition: Multinomial.h:211
Eigen::Rand::DirichletGen
Generator of reals on a Dirichlet distribution.
Definition: Multinomial.h:146
Eigen::Rand::MvVecGenBase
Base class of all multivariate random vector generators.
Definition: Basic.h:84
Eigen::Rand::DirichletGen::DirichletGen
DirichletGen(const MatrixBase< AlphaTy > &_alpha)
Construct a new Dirichlet generator.
Definition: Multinomial.h:157
Eigen::Rand::MultinomialGen::MultinomialGen
MultinomialGen(_Scalar _trials, const MatrixBase< WeightTy > &_weights)
Construct a new multinomial generator.
Definition: Multinomial.h:41
Eigen::Rand::DiscreteGen
Generator of integers on the interval [0, n), where the probability of each individual integer i is p...
Definition: Discrete.h:324
Eigen::Rand::discrete
const DiscreteType< Derived, Urng > discrete(Index rows, Index cols, Urng &&urng, RealIter first, RealIter last)
generates random integers on the interval [0, n), where the probability of each individual integer i ...
Definition: Discrete.h:1238
Eigen::Rand::MultinomialGen
Generator of real vectors on a multinomial distribution.
Definition: Multinomial.h:27
Eigen::Rand::makeMultinomialGen
auto makeMultinomialGen(IntTy trials, const MatrixBase< WeightTy > &probs) -> MultinomialGen< IntTy, MatrixBase< WeightTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::MultinomialGen
Definition: Multinomial.h:132