EigenRand  0.5.0
 
Loading...
Searching...
No Matches
Multinomial.h
Go to the documentation of this file.
1
12#ifndef EIGENRAND_MVDISTS_MULTINOMIAL_H
13#define EIGENRAND_MVDISTS_MULTINOMIAL_H
14
15namespace 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;
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 MultinomialGen& operator=(const MultinomialGen&) = default;
56 MultinomialGen& operator=(MultinomialGen&&) = default;
57
58 Index dims() const { return probs.rows(); }
59
60 template<typename Urng>
61 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
62 {
63 const Index dim = probs.size();
64 Matrix<_Scalar, Dim, -1> ret(dim, samples);
65 if (trials < std::max(30 * (dim - 1), (Index)100))
66 {
67 for (Index s = 0; s < samples; ++s)
68 {
69 ret.col(s) = generate(urng);
70 }
71 }
72 else
73 {
74 Array<_Scalar, 1, -1> r_trials{ samples }, t{ samples };
75 Map<const Array<float, -1, 1>> fr_trials{ reinterpret_cast<float*>(r_trials.data()), samples };
76 Map<Array<float, -1, 1>> ft{ reinterpret_cast<float*>(t.data()), samples };
77 r_trials.setConstant(trials);
78 ft = impl::binomial(urng, fr_trials, probs[0]);
79 r_trials -= t;
80 ret.row(0) = t.matrix();
81 double rest_p = 1 - probs[0];
82 for (Index i = 1; i < dim - 1; ++i)
83 {
84 ft = impl::binomial(urng, fr_trials, probs[i] / rest_p);
85 r_trials -= t;
86 ret.row(i) = t.matrix();
87 rest_p -= probs[i];
88 }
89
90 ret.row(dim - 1) = r_trials;
91 }
92 return ret;
93 }
94
95 template<typename Urng>
96 inline Matrix<_Scalar, Dim, 1> generate(Urng&& urng)
97 {
98 const Index dim = probs.size();
99 Matrix<_Scalar, Dim, 1> ret(dim);
100 //if (trials < std::max(30 * (dim - 1), (Index)100))
101 {
102 ret.setZero();
103 auto d = discrete.template generate<Matrix<_Scalar, 16, 1>>(16, 1, urng);
104 Matrix<_Scalar, 16, 1> buf;
105 Index i;
106 for (i = 0; i < (trials & ~15); i += 16)
107 {
108 buf = d;
109 for (Index j = 0; j < 16; ++j)
110 {
111 ret[buf[j]] += 1;
112 }
113 }
114 buf.middleRows(0, trials - i) = d.middleRows(0, trials - i);
115 for (Index j = 0; j < trials - i; ++j)
116 {
117 ret[buf[j]] += 1;
118 }
119 }
120 /*else
121 {
122 double rest_p = 1;
123 _Scalar t = trials;
124 for (Index i = 0; i < dim - 1; ++i)
125 {
126 ret[i] = binomial<Array<_Scalar, 1, 1>>(1, 1, urng, t, probs[i] / rest_p)(0);
127 t -= ret[i];
128 rest_p -= probs[i];
129 }
130 ret[dim - 1] = trials - ret.head(dim - 1).sum();
131 }*/
132 return ret;
133 }
134 };
135
146 template<typename IntTy, typename WeightTy>
147 inline auto makeMultinomialGen(IntTy trials, const MatrixBase<WeightTy>& probs)
149 {
151 }
152
159 template<typename _Scalar, Index Dim = -1>
160 class DirichletGen : public MvVecGenBase<DirichletGen<_Scalar, Dim>, _Scalar, Dim>
161 {
162 static_assert(std::is_floating_point<_Scalar>::value, "`DirichletGen` needs floating point types.");
163
164 Matrix<_Scalar, Dim, 1> alpha;
165 std::vector<GammaGen<_Scalar>> gammas;
166 public:
173 template<typename AlphaTy>
174 DirichletGen(const MatrixBase<AlphaTy>& _alpha)
175 : alpha{ _alpha }
176 {
177 eigen_assert(_alpha.cols() == 1);
178 for (Index i = 0; i < alpha.size(); ++i)
179 {
180 eigen_assert(alpha[i] > 0);
181 gammas.emplace_back(alpha[i]);
182 }
183 }
184
185 DirichletGen(const DirichletGen&) = default;
186 DirichletGen(DirichletGen&&) = default;
187
188 Index dims() const { return alpha.rows(); }
189
190 template<typename Urng>
191 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
192 {
193 const Index dim = alpha.size();
194 Matrix<_Scalar, Dim, -1> ret(dim, samples);
195 Matrix<_Scalar, -1, 1> tmp(samples);
196 for (Index i = 0; i < dim; ++i)
197 {
198 tmp = gammas[i].generateLike(tmp, urng);
199 ret.row(i) = tmp.transpose();
200 }
201 ret.array().rowwise() /= ret.array().colwise().sum();
202 return ret;
203 }
204
205 template<typename Urng>
206 inline Matrix<_Scalar, Dim, 1> generate(Urng&& urng)
207 {
208 const Index dim = alpha.size();
209 Matrix<_Scalar, Dim, 1> ret(dim);
210 for (Index i = 0; i < dim; ++i)
211 {
212 ret[i] = gammas[i].template generate<Matrix<_Scalar, 1, 1>>(1, 1, urng)(0);
213 }
214 ret /= ret.sum();
215 return ret;
216 }
217 };
218
227 template<typename AlphaTy>
228 inline auto makeDirichletGen(const MatrixBase<AlphaTy>& alpha)
229 -> DirichletGen<typename MatrixBase<AlphaTy>::Scalar, MatrixBase<AlphaTy>::RowsAtCompileTime>
230 {
231 return DirichletGen<typename MatrixBase<AlphaTy>::Scalar, MatrixBase<AlphaTy>::RowsAtCompileTime>{ alpha };
232 }
233 }
234}
235
236#endif
Generator of reals on a Dirichlet distribution.
Definition: Multinomial.h:161
DirichletGen(const MatrixBase< AlphaTy > &_alpha)
Construct a new Dirichlet generator.
Definition: Multinomial.h:174
Generator of integers on the interval [0, n), where the probability of each individual integer i is p...
Definition: Discrete.h:329
Generator of real vectors on a multinomial distribution.
Definition: Multinomial.h:27
MultinomialGen(_Scalar _trials, const MatrixBase< WeightTy > &_weights)
Construct a new multinomial generator.
Definition: Multinomial.h:41
Base class of all multivariate random vector generators.
Definition: Basic.h:160
auto makeMultinomialGen(IntTy trials, const MatrixBase< WeightTy > &probs) -> MultinomialGen< IntTy, MatrixBase< WeightTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::MultinomialGen
Definition: Multinomial.h:147
auto makeDirichletGen(const MatrixBase< AlphaTy > &alpha) -> DirichletGen< typename MatrixBase< AlphaTy >::Scalar, MatrixBase< AlphaTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::DirichletGen
Definition: Multinomial.h:228
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:1580