tomoto 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/ext/tomoto/ct.cpp +8 -4
  4. data/ext/tomoto/dmr.cpp +10 -4
  5. data/ext/tomoto/dt.cpp +13 -4
  6. data/ext/tomoto/extconf.rb +1 -1
  7. data/ext/tomoto/gdmr.cpp +14 -6
  8. data/ext/tomoto/hdp.cpp +9 -4
  9. data/ext/tomoto/hlda.cpp +9 -4
  10. data/ext/tomoto/hpa.cpp +9 -4
  11. data/ext/tomoto/lda.cpp +8 -4
  12. data/ext/tomoto/llda.cpp +8 -4
  13. data/ext/tomoto/mglda.cpp +11 -1
  14. data/ext/tomoto/pa.cpp +9 -4
  15. data/ext/tomoto/plda.cpp +8 -4
  16. data/ext/tomoto/slda.cpp +13 -5
  17. data/lib/tomoto/gdmr.rb +2 -2
  18. data/lib/tomoto/version.rb +1 -1
  19. data/vendor/EigenRand/EigenRand/Core.h +6 -1107
  20. data/vendor/EigenRand/EigenRand/Dists/Basic.h +490 -43
  21. data/vendor/EigenRand/EigenRand/Dists/Discrete.h +916 -285
  22. data/vendor/EigenRand/EigenRand/Dists/GammaPoisson.h +85 -36
  23. data/vendor/EigenRand/EigenRand/Dists/NormalExp.h +1038 -290
  24. data/vendor/EigenRand/EigenRand/EigenRand +2 -2
  25. data/vendor/EigenRand/EigenRand/Macro.h +4 -4
  26. data/vendor/EigenRand/EigenRand/MorePacketMath.h +54 -22
  27. data/vendor/EigenRand/EigenRand/MvDists/Multinomial.h +222 -0
  28. data/vendor/EigenRand/EigenRand/MvDists/MvNormal.h +492 -0
  29. data/vendor/EigenRand/EigenRand/PacketFilter.h +2 -2
  30. data/vendor/EigenRand/EigenRand/PacketRandomEngine.h +2 -2
  31. data/vendor/EigenRand/EigenRand/RandUtils.h +65 -11
  32. data/vendor/EigenRand/EigenRand/doc.h +142 -25
  33. data/vendor/EigenRand/LICENSE +1 -1
  34. data/vendor/EigenRand/README.md +109 -24
  35. data/vendor/tomotopy/README.kr.rst +27 -6
  36. data/vendor/tomotopy/README.rst +29 -8
  37. data/vendor/tomotopy/src/Labeling/FoRelevance.cpp +60 -12
  38. data/vendor/tomotopy/src/Labeling/FoRelevance.h +2 -2
  39. data/vendor/tomotopy/src/Labeling/Phraser.hpp +33 -21
  40. data/vendor/tomotopy/src/TopicModel/CT.h +8 -5
  41. data/vendor/tomotopy/src/TopicModel/CTModel.cpp +2 -6
  42. data/vendor/tomotopy/src/TopicModel/CTModel.hpp +29 -23
  43. data/vendor/tomotopy/src/TopicModel/DMR.h +33 -4
  44. data/vendor/tomotopy/src/TopicModel/DMRModel.cpp +2 -6
  45. data/vendor/tomotopy/src/TopicModel/DMRModel.hpp +231 -57
  46. data/vendor/tomotopy/src/TopicModel/DT.h +24 -5
  47. data/vendor/tomotopy/src/TopicModel/DTModel.cpp +2 -8
  48. data/vendor/tomotopy/src/TopicModel/DTModel.hpp +41 -28
  49. data/vendor/tomotopy/src/TopicModel/GDMR.h +31 -5
  50. data/vendor/tomotopy/src/TopicModel/GDMRModel.cpp +2 -7
  51. data/vendor/tomotopy/src/TopicModel/GDMRModel.hpp +211 -104
  52. data/vendor/tomotopy/src/TopicModel/HDP.h +11 -2
  53. data/vendor/tomotopy/src/TopicModel/HDPModel.cpp +2 -6
  54. data/vendor/tomotopy/src/TopicModel/HDPModel.hpp +52 -45
  55. data/vendor/tomotopy/src/TopicModel/HLDA.h +11 -2
  56. data/vendor/tomotopy/src/TopicModel/HLDAModel.cpp +2 -6
  57. data/vendor/tomotopy/src/TopicModel/HLDAModel.hpp +13 -16
  58. data/vendor/tomotopy/src/TopicModel/HPA.h +5 -2
  59. data/vendor/tomotopy/src/TopicModel/HPAModel.cpp +2 -6
  60. data/vendor/tomotopy/src/TopicModel/HPAModel.hpp +51 -21
  61. data/vendor/tomotopy/src/TopicModel/LDA.h +9 -2
  62. data/vendor/tomotopy/src/TopicModel/LDACVB0Model.hpp +8 -8
  63. data/vendor/tomotopy/src/TopicModel/LDAModel.cpp +2 -6
  64. data/vendor/tomotopy/src/TopicModel/LDAModel.hpp +70 -28
  65. data/vendor/tomotopy/src/TopicModel/LLDA.h +1 -2
  66. data/vendor/tomotopy/src/TopicModel/LLDAModel.cpp +2 -6
  67. data/vendor/tomotopy/src/TopicModel/LLDAModel.hpp +22 -12
  68. data/vendor/tomotopy/src/TopicModel/MGLDA.h +12 -3
  69. data/vendor/tomotopy/src/TopicModel/MGLDAModel.cpp +2 -10
  70. data/vendor/tomotopy/src/TopicModel/MGLDAModel.hpp +42 -19
  71. data/vendor/tomotopy/src/TopicModel/PA.h +9 -4
  72. data/vendor/tomotopy/src/TopicModel/PAModel.cpp +2 -6
  73. data/vendor/tomotopy/src/TopicModel/PAModel.hpp +48 -25
  74. data/vendor/tomotopy/src/TopicModel/PLDA.h +13 -2
  75. data/vendor/tomotopy/src/TopicModel/PLDAModel.cpp +2 -6
  76. data/vendor/tomotopy/src/TopicModel/PLDAModel.hpp +27 -19
  77. data/vendor/tomotopy/src/TopicModel/PT.h +12 -5
  78. data/vendor/tomotopy/src/TopicModel/PTModel.cpp +2 -3
  79. data/vendor/tomotopy/src/TopicModel/PTModel.hpp +29 -14
  80. data/vendor/tomotopy/src/TopicModel/SLDA.h +18 -6
  81. data/vendor/tomotopy/src/TopicModel/SLDAModel.cpp +2 -10
  82. data/vendor/tomotopy/src/TopicModel/SLDAModel.hpp +93 -43
  83. data/vendor/tomotopy/src/TopicModel/TopicModel.hpp +58 -23
  84. data/vendor/tomotopy/src/Utils/AliasMethod.hpp +6 -6
  85. data/vendor/tomotopy/src/Utils/Dictionary.h +11 -0
  86. data/vendor/tomotopy/src/Utils/SharedString.hpp +26 -1
  87. data/vendor/tomotopy/src/Utils/Trie.hpp +46 -21
  88. data/vendor/tomotopy/src/Utils/Utils.hpp +99 -14
  89. data/vendor/tomotopy/src/Utils/exception.h +1 -1
  90. data/vendor/tomotopy/src/Utils/math.h +5 -7
  91. data/vendor/tomotopy/src/Utils/serializer.hpp +329 -201
  92. data/vendor/tomotopy/src/Utils/text.hpp +8 -0
  93. data/vendor/tomotopy/src/Utils/tvector.hpp +49 -7
  94. metadata +9 -7
@@ -2,9 +2,9 @@
2
2
  * @file Discrete.h
3
3
  * @author bab2min (bab2min@gmail.com)
4
4
  * @brief
5
- * @version 0.2.0
6
- * @date 2020-06-22
7
- *
5
+ * @version 0.3.0
6
+ * @date 2020-10-07
7
+ *
8
8
  * @copyright Copyright (c) 2020
9
9
  *
10
10
  */
@@ -18,113 +18,8 @@
18
18
 
19
19
  namespace Eigen
20
20
  {
21
- namespace internal
21
+ namespace Rand
22
22
  {
23
- template<typename Scalar, typename Rng>
24
- struct scalar_uniform_int_op : public scalar_randbits_op<Scalar, Rng>
25
- {
26
- static_assert(std::is_same<Scalar, int32_t>::value, "uniformInt needs integral types.");
27
- using ur_base = scalar_randbits_op<Scalar, Rng>;
28
-
29
- Scalar pmin;
30
- size_t pdiff, bitsize, bitmask;
31
-
32
- scalar_uniform_int_op(const Rng& _rng, Scalar _min, Scalar _max)
33
- : ur_base{ _rng }, pmin{ _min }, pdiff{ (size_t)(_max - _min) }
34
- {
35
- if ((pdiff + 1) > pdiff)
36
- {
37
- bitsize = (size_t)std::ceil(std::log2(pdiff + 1));
38
- }
39
- else
40
- {
41
- bitsize = (size_t)std::ceil(std::log2(pdiff));
42
- }
43
- bitmask = (Scalar)(((size_t)-1) >> (sizeof(size_t) * 8 - bitsize));
44
- }
45
-
46
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() () const
47
- {
48
- auto rx = ur_base::operator()();
49
- if (pdiff == bitmask)
50
- {
51
- return (Scalar)(rx & bitmask) + pmin;
52
- }
53
- else
54
- {
55
- size_t bitcnt = bitsize;
56
- while (1)
57
- {
58
- Scalar cands = (Scalar)(rx & bitmask);
59
- if (cands <= pdiff) return cands;
60
- if (bitcnt + bitsize < 32)
61
- {
62
- rx >>= bitsize;
63
- bitcnt += bitsize;
64
- }
65
- else
66
- {
67
- rx = ur_base::operator()();
68
- bitcnt = bitsize;
69
- }
70
- }
71
- }
72
- }
73
-
74
- template<typename Packet>
75
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp() const
76
- {
77
- auto rx = ur_base::template packetOp<Packet>();
78
- auto pbitmask = pset1<Packet>(bitmask);
79
- if (pdiff == bitmask)
80
- {
81
- return padd(pand(rx, pbitmask), pset1<Packet>(pmin));
82
- }
83
- else
84
- {
85
- auto& cm = Rand::detail::CompressMask<sizeof(Packet)>::get_inst();
86
- thread_local Packet cache_rest;
87
- thread_local int cache_rest_cnt;
88
- thread_local const scalar_uniform_int_op* cache_ptr = nullptr;
89
- if (cache_ptr != this)
90
- {
91
- cache_ptr = this;
92
- cache_rest = pset1<Packet>(0);
93
- cache_rest_cnt = 0;
94
- }
95
-
96
- auto plen = pset1<Packet>(pdiff + 1);
97
- size_t bitcnt = bitsize;
98
- while (1)
99
- {
100
- // accept cands that only < plen
101
- auto cands = pand(rx, pbitmask);
102
- bool full = false;
103
- cache_rest_cnt = cm.compress_append(cands, pcmplt(cands, plen),
104
- cache_rest, cache_rest_cnt, full);
105
- if (full) return padd(cands, pset1<Packet>(pmin));
106
-
107
- if (bitcnt + bitsize < 32)
108
- {
109
- rx = psrl(rx, bitsize);
110
- bitcnt += bitsize;
111
- }
112
- else
113
- {
114
- rx = ur_base::template packetOp<Packet>();
115
- bitcnt = bitsize;
116
- }
117
- }
118
- }
119
- }
120
- };
121
-
122
- template<typename Scalar, typename Urng>
123
- struct functor_traits<scalar_uniform_int_op<Scalar, Urng> >
124
- {
125
- enum { Cost = HugeCost, PacketAccess = packet_traits<Scalar>::Vectorizable, IsRepeatable = false };
126
- };
127
-
128
23
  template<typename _Precision = uint32_t, typename _Size = uint32_t>
129
24
  class AliasMethod
130
25
  {
@@ -310,22 +205,156 @@ namespace Eigen
310
205
  return alias.get();
311
206
  }
312
207
  };
208
+
209
+ /**
210
+ * @brief Generator of integers with a given range `[min, max]`
211
+ *
212
+ * @tparam _Scalar any integral type
213
+ */
214
+ template<typename _Scalar>
215
+ class UniformIntGen : OptCacheStore, public GenBase<UniformIntGen<_Scalar>, _Scalar>
216
+ {
217
+ static_assert(std::is_same<_Scalar, int32_t>::value, "uniformInt needs integral types.");
218
+ int cache_rest_cnt = 0;
219
+ RandbitsGen<_Scalar> randbits;
220
+ _Scalar pmin;
221
+ size_t pdiff, bitsize, bitmask;
222
+
223
+ public:
224
+ using Scalar = _Scalar;
225
+
226
+ /**
227
+ * @brief Construct a new UniformInt Generator
228
+ *
229
+ * @param _min, _max the range of integers being generated
230
+ */
231
+ UniformIntGen(_Scalar _min = 0, _Scalar _max = 0)
232
+ : pmin{ _min }, pdiff{ (size_t)(_max - _min) }
233
+ {
234
+ if ((pdiff + 1) > pdiff)
235
+ {
236
+ bitsize = (size_t)std::ceil(std::log2(pdiff + 1));
237
+ }
238
+ else
239
+ {
240
+ bitsize = (size_t)std::ceil(std::log2(pdiff));
241
+ }
242
+ bitmask = (_Scalar)(((size_t)-1) >> (sizeof(size_t) * 8 - bitsize));
243
+ }
313
244
 
314
- template<typename Scalar, typename Rng, typename Precision = float>
315
- struct scalar_discrete_dist_op;
245
+ UniformIntGen(const UniformIntGen&) = default;
246
+ UniformIntGen(UniformIntGen&&) = default;
316
247
 
317
- template<typename Scalar, typename Rng>
318
- struct scalar_discrete_dist_op<Scalar, Rng, int32_t> : public scalar_randbits_op<Scalar, Rng>
319
- {
320
- static_assert(std::is_same<Scalar, int32_t>::value, "discreteDist needs integral types.");
321
- using ur_base = scalar_randbits_op<Scalar, Rng>;
248
+ UniformIntGen& operator=(const UniformIntGen&) = default;
249
+ UniformIntGen& operator=(UniformIntGen&&) = default;
322
250
 
251
+ template<typename Rng>
252
+ EIGEN_STRONG_INLINE const _Scalar operator() (Rng&& rng)
253
+ {
254
+ using namespace Eigen::internal;
255
+ auto rx = randbits(rng);
256
+ if (pdiff == bitmask)
257
+ {
258
+ return (_Scalar)(rx & bitmask) + pmin;
259
+ }
260
+ else
261
+ {
262
+ size_t bitcnt = bitsize;
263
+ while (1)
264
+ {
265
+ _Scalar cands = (_Scalar)(rx & bitmask);
266
+ if (cands <= pdiff) return cands;
267
+ if (bitcnt + bitsize < 32)
268
+ {
269
+ rx >>= bitsize;
270
+ bitcnt += bitsize;
271
+ }
272
+ else
273
+ {
274
+ rx = randbits(rng);
275
+ bitcnt = bitsize;
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ template<typename Packet, typename Rng>
282
+ EIGEN_STRONG_INLINE const Packet packetOp(Rng&& rng)
283
+ {
284
+ using namespace Eigen::internal;
285
+ auto rx = randbits.template packetOp<Packet>(rng);
286
+ auto pbitmask = pset1<Packet>(bitmask);
287
+ if (pdiff == bitmask)
288
+ {
289
+ return padd(pand(rx, pbitmask), pset1<Packet>(pmin));
290
+ }
291
+ else
292
+ {
293
+ auto& cm = Rand::detail::CompressMask<sizeof(Packet)>::get_inst();
294
+ auto plen = pset1<Packet>(pdiff + 1);
295
+ size_t bitcnt = bitsize;
296
+ while (1)
297
+ {
298
+ // accept cands that only < plen
299
+ auto cands = pand(rx, pbitmask);
300
+ bool full = false;
301
+ cache_rest_cnt = cm.compress_append(cands, pcmplt(cands, plen),
302
+ OptCacheStore::template get<Packet>(), cache_rest_cnt, full);
303
+ if (full) return padd(cands, pset1<Packet>(pmin));
304
+
305
+ if (bitcnt + bitsize < 32)
306
+ {
307
+ rx = psrl(rx, bitsize);
308
+ bitcnt += bitsize;
309
+ }
310
+ else
311
+ {
312
+ rx = randbits.template packetOp<Packet>(rng);
313
+ bitcnt = bitsize;
314
+ }
315
+ }
316
+ }
317
+ }
318
+ };
319
+
320
+ /**
321
+ * @brief Generator of integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`
322
+ *
323
+ * @tparam _Scalar any integral type
324
+ * @tparam Precision internal precision type
325
+ */
326
+ template<typename _Scalar, typename Precision = float>
327
+ class DiscreteGen;
328
+
329
+ /**
330
+ * @brief `DiscreteGen` with `int32_t` precision
331
+ *
332
+ * @tparam _Scalar any intergral type
333
+ */
334
+ template<typename _Scalar>
335
+ class DiscreteGen<_Scalar, int32_t> : public GenBase<DiscreteGen<_Scalar, int32_t>, _Scalar>
336
+ {
337
+ static_assert(std::is_same<_Scalar, int32_t>::value, "discreteDist needs integral types.");
338
+ #ifdef EIGEN_VECTORIZE_AVX2
339
+ OptCacheStore cache;
340
+ bool valid = false;
341
+ #endif
342
+ RandbitsGen<int32_t> randbits;
323
343
  std::vector<uint32_t> cdf;
324
- AliasMethod<int32_t, Scalar> alias_table;
344
+ AliasMethod<int32_t, _Scalar> alias_table;
325
345
 
346
+ public:
347
+ using Scalar = _Scalar;
348
+
349
+ /**
350
+ * @brief Construct a new Discrete Generator
351
+ *
352
+ * @tparam RealIter
353
+ * @param first, last the range of elements defining the numbers to use as weights.
354
+ * The type of the elements referred by it must be convertible to `double`.
355
+ */
326
356
  template<typename RealIter>
327
- scalar_discrete_dist_op(const Rng& _rng, RealIter first, RealIter last)
328
- : ur_base{ _rng }
357
+ DiscreteGen(RealIter first, RealIter last)
329
358
  {
330
359
  if (std::distance(first, last) < 16)
331
360
  {
@@ -345,20 +374,47 @@ namespace Eigen
345
374
  else
346
375
  {
347
376
  // use alias table
348
- alias_table = AliasMethod<int32_t, Scalar>{ first, last };
377
+ alias_table = AliasMethod<int32_t, _Scalar>{ first, last };
349
378
  }
350
379
  }
351
380
 
352
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() () const
381
+ /**
382
+ * @brief Construct a new Discrete Generator
383
+ *
384
+ * @tparam Real
385
+ * @param il an instance of initializer_list containing the numbers to use as weights.
386
+ * The type of the elements referred by it must be convertible to `double`.
387
+ */
388
+ template<typename Real,
389
+ typename std::enable_if<std::is_arithmetic<Real>::value, int>::type = 0>
390
+ DiscreteGen(const std::initializer_list<Real>& il)
391
+ : DiscreteGen(il.begin(), il.end())
392
+ {
393
+ }
394
+
395
+ DiscreteGen()
396
+ : DiscreteGen({ 1 })
353
397
  {
398
+ }
399
+
400
+ DiscreteGen(const DiscreteGen&) = default;
401
+ DiscreteGen(DiscreteGen&&) = default;
402
+
403
+ DiscreteGen& operator=(const DiscreteGen&) = default;
404
+ DiscreteGen& operator=(DiscreteGen&&) = default;
405
+
406
+ template<typename Rng>
407
+ EIGEN_STRONG_INLINE const _Scalar operator() (Rng&& rng)
408
+ {
409
+ using namespace Eigen::internal;
354
410
  if (!cdf.empty())
355
411
  {
356
- auto rx = ur_base::operator()() & 0x7FFFFFFF;
357
- return (Scalar)(std::lower_bound(cdf.begin(), cdf.end() - 1, rx) - cdf.begin());
412
+ auto rx = randbits(std::forward<Rng>(rng)) & 0x7FFFFFFF;
413
+ return (_Scalar)(std::lower_bound(cdf.begin(), cdf.end() - 1, rx) - cdf.begin());
358
414
  }
359
415
  else
360
416
  {
361
- auto rx = ur_base::operator()();
417
+ auto rx = randbits(std::forward<Rng>(rng));
362
418
  auto albit = rx & alias_table.get_bitmask();
363
419
  uint32_t alx = (uint32_t)(rx >> (sizeof(rx) * 8 - 31));
364
420
  if (alx < alias_table.get_prob()[albit]) return albit;
@@ -366,18 +422,16 @@ namespace Eigen
366
422
  }
367
423
  }
368
424
 
369
- template<typename Packet>
370
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp() const
425
+ template<typename Packet, typename Rng>
426
+ EIGEN_STRONG_INLINE const Packet packetOp(Rng&& rng)
371
427
  {
428
+ using namespace Eigen::internal;
372
429
  #ifdef EIGEN_VECTORIZE_AVX2
373
- thread_local Packet4i cache;
374
- thread_local const scalar_discrete_dist_op* cache_ptr = nullptr;
375
- if (cache_ptr == this)
430
+ if (valid)
376
431
  {
377
- cache_ptr = nullptr;
378
- return cache;
432
+ valid = false;
433
+ return cache.template get<Packet>();
379
434
  }
380
-
381
435
  using PacketType = Packet8i;
382
436
  #else
383
437
  using PacketType = Packet;
@@ -387,7 +441,7 @@ namespace Eigen
387
441
  if (!cdf.empty())
388
442
  {
389
443
  ret = pset1<PacketType>(cdf.size() - 1);
390
- auto rx = pand(ur_base::template packetOp<PacketType>(), pset1<PacketType>(0x7FFFFFFF));
444
+ auto rx = pand(randbits.template packetOp<PacketType>(std::forward<Rng>(rng)), pset1<PacketType>(0x7FFFFFFF));
391
445
  for (size_t i = 0; i < cdf.size() - 1; ++i)
392
446
  {
393
447
  ret = padd(ret, pcmplt(rx, pset1<PacketType>(cdf[i])));
@@ -395,15 +449,15 @@ namespace Eigen
395
449
  }
396
450
  else
397
451
  {
398
- auto rx = ur_base::template packetOp<PacketType>();
452
+ auto rx = randbits.template packetOp<PacketType>(std::forward<Rng>(rng));
399
453
  auto albit = pand(rx, pset1<PacketType>(alias_table.get_bitmask()));
400
454
  auto c = pcmplt(psrl(rx, 1), pgather(alias_table.get_prob(), albit));
401
455
  ret = pblendv(c, albit, pgather(alias_table.get_alias(), albit));
402
456
  }
403
457
 
404
458
  #ifdef EIGEN_VECTORIZE_AVX2
405
- cache = _mm256_extractf128_si256(ret, 1);
406
- cache_ptr = this;
459
+ valid = true;
460
+ cache.template get<Packet>() = _mm256_extractf128_si256(ret, 1);
407
461
  return _mm256_extractf128_si256(ret, 0);
408
462
  #else
409
463
  return ret;
@@ -411,18 +465,31 @@ namespace Eigen
411
465
  }
412
466
  };
413
467
 
414
- template<typename Scalar, typename Rng>
415
- struct scalar_discrete_dist_op<Scalar, Rng, float> : public scalar_uniform_real_op<float, Rng>
468
+ /**
469
+ * @brief `DiscreteGen` with `float` precision
470
+ *
471
+ * @tparam _Scalar any intergral type
472
+ */
473
+ template<typename _Scalar>
474
+ class DiscreteGen<_Scalar, float> : public GenBase<DiscreteGen<_Scalar, float>, _Scalar>
416
475
  {
417
- static_assert(std::is_same<Scalar, int32_t>::value, "discreteDist needs integral types.");
418
- using ur_base = scalar_uniform_real_op<float, Rng>;
419
-
476
+ static_assert(std::is_same<_Scalar, int32_t>::value, "discreteDist needs integral types.");
477
+ UniformRealGen<float> ur;
420
478
  std::vector<float> cdf;
421
- AliasMethod<float, Scalar> alias_table;
479
+ AliasMethod<float, _Scalar> alias_table;
422
480
 
481
+ public:
482
+ using Scalar = _Scalar;
483
+
484
+ /**
485
+ * @brief Construct a new Discrete Generator
486
+ *
487
+ * @tparam RealIter
488
+ * @param first, last the range of elements defining the numbers to use as weights.
489
+ * The type of the elements referred by it must be convertible to `double`.
490
+ */
423
491
  template<typename RealIter>
424
- scalar_discrete_dist_op(const Rng& _rng, RealIter first, RealIter last)
425
- : ur_base{ _rng }
492
+ DiscreteGen(RealIter first, RealIter last)
426
493
  {
427
494
  if (std::distance(first, last) < 16)
428
495
  {
@@ -442,35 +509,63 @@ namespace Eigen
442
509
  else
443
510
  {
444
511
  // use alias table
445
- alias_table = AliasMethod<float, Scalar>{ first, last };
512
+ alias_table = AliasMethod<float, _Scalar>{ first, last };
446
513
  }
447
514
  }
448
515
 
449
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() () const
516
+ /**
517
+ * @brief Construct a new Discrete Generator
518
+ *
519
+ * @tparam Real
520
+ * @param il an instance of initializer_list containing the numbers to use as weights.
521
+ * The type of the elements referred by it must be convertible to `double`.
522
+ */
523
+ template<typename Real,
524
+ typename std::enable_if<std::is_arithmetic<Real>::value, int>::type = 0>
525
+ DiscreteGen(const std::initializer_list<Real>& il)
526
+ : DiscreteGen(il.begin(), il.end())
527
+ {
528
+ }
529
+
530
+ DiscreteGen()
531
+ : DiscreteGen({ 1 })
532
+ {
533
+ }
534
+
535
+ DiscreteGen(const DiscreteGen&) = default;
536
+ DiscreteGen(DiscreteGen&&) = default;
537
+
538
+ DiscreteGen& operator=(const DiscreteGen&) = default;
539
+ DiscreteGen& operator=(DiscreteGen&&) = default;
540
+
541
+ template<typename Rng>
542
+ EIGEN_STRONG_INLINE const _Scalar operator() (Rng&& rng)
450
543
  {
544
+ using namespace Eigen::internal;
451
545
  if (!cdf.empty())
452
546
  {
453
- auto rx = ur_base::operator()();
454
- return (Scalar)(std::lower_bound(cdf.begin(), cdf.end() - 1, rx) - cdf.begin());
547
+ auto rx = ur(std::forward<Rng>(rng));
548
+ return (_Scalar)(std::lower_bound(cdf.begin(), cdf.end() - 1, rx) - cdf.begin());
455
549
  }
456
550
  else
457
551
  {
458
- auto albit = pfirst(this->rng()) & alias_table.get_bitmask();
459
- auto alx = ur_base::operator()();
552
+ auto albit = pfirst(rng()) & alias_table.get_bitmask();
553
+ auto alx = ur(rng);
460
554
  if (alx < alias_table.get_prob()[albit]) return albit;
461
555
  return alias_table.get_alias()[albit];
462
556
  }
463
557
  }
464
558
 
465
- template<typename Packet>
466
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp() const
559
+ template<typename Packet, typename Rng>
560
+ EIGEN_STRONG_INLINE const Packet packetOp(Rng&& rng)
467
561
  {
562
+ using namespace Eigen::internal;
468
563
  using PacketType = decltype(reinterpret_to_float(std::declval<Packet>()));
469
564
 
470
565
  if (!cdf.empty())
471
566
  {
472
567
  auto ret = pset1<Packet>(cdf.size());
473
- auto rx = ur_base::template packetOp<PacketType>();
568
+ auto rx = ur.template packetOp<PacketType>(std::forward<Rng>(rng));
474
569
  for (auto& p : cdf)
475
570
  {
476
571
  ret = padd(ret, reinterpret_to_int(pcmplt(rx, pset1<PacketType>(p))));
@@ -480,25 +575,38 @@ namespace Eigen
480
575
  else
481
576
  {
482
577
  using RUtils = RawbitsMaker<Packet, Rng>;
483
- auto albit = pand(RUtils{}.rawbits(this->rng), pset1<Packet>(alias_table.get_bitmask()));
484
- auto c = reinterpret_to_int(pcmplt(ur_base::template packetOp<PacketType>(), pgather(alias_table.get_prob(), albit)));
578
+ auto albit = pand(RUtils{}.rawbits(rng), pset1<Packet>(alias_table.get_bitmask()));
579
+ auto c = reinterpret_to_int(pcmplt(ur.template packetOp<PacketType>(rng), pgather(alias_table.get_prob(), albit)));
485
580
  return pblendv(c, albit, pgather(alias_table.get_alias(), albit));
486
581
  }
487
582
  }
488
583
  };
489
584
 
490
- template<typename Scalar, typename Rng>
491
- struct scalar_discrete_dist_op<Scalar, Rng, double> : public scalar_uniform_real_op<double, Rng>
585
+ /**
586
+ * @brief `DiscreteGen` with `double` precision
587
+ *
588
+ * @tparam _Scalar any intergral type
589
+ */
590
+ template<typename _Scalar>
591
+ class DiscreteGen<_Scalar, double> : public GenBase<DiscreteGen<_Scalar, double>, _Scalar>
492
592
  {
493
- static_assert(std::is_same<Scalar, int32_t>::value, "discreteDist needs integral types.");
494
- using ur_base = scalar_uniform_real_op<double, Rng>;
495
-
593
+ static_assert(std::is_same<_Scalar, int32_t>::value, "discreteDist needs integral types.");
594
+ UniformRealGen<double> ur;
496
595
  std::vector<double> cdf;
497
- AliasMethod<double, Scalar> alias_table;
596
+ AliasMethod<double, _Scalar> alias_table;
498
597
 
598
+ public:
599
+ using Scalar = _Scalar;
600
+
601
+ /**
602
+ * @brief Construct a new Discrete Generator
603
+ *
604
+ * @tparam RealIter
605
+ * @param first, last the range of elements defining the numbers to use as weights.
606
+ * The type of the elements referred by it must be convertible to `double`.
607
+ */
499
608
  template<typename RealIter>
500
- scalar_discrete_dist_op(const Rng& _rng, RealIter first, RealIter last)
501
- : ur_base{ _rng }
609
+ DiscreteGen(RealIter first, RealIter last)
502
610
  {
503
611
  if (std::distance(first, last) < 16)
504
612
  {
@@ -518,35 +626,63 @@ namespace Eigen
518
626
  else
519
627
  {
520
628
  // use alias table
521
- alias_table = AliasMethod<double, Scalar>{ first, last };
629
+ alias_table = AliasMethod<double, _Scalar>{ first, last };
522
630
  }
523
631
  }
524
632
 
525
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() () const
633
+ /**
634
+ * @brief Construct a new Discrete Generator
635
+ *
636
+ * @tparam Real
637
+ * @param il an instance of initializer_list containing the numbers to use as weights.
638
+ * The type of the elements referred by it must be convertible to `double`.
639
+ */
640
+ template<typename Real,
641
+ typename std::enable_if<std::is_arithmetic<Real>::value, int>::type = 0>
642
+ DiscreteGen(const std::initializer_list<Real>& il)
643
+ : DiscreteGen(il.begin(), il.end())
644
+ {
645
+ }
646
+
647
+ DiscreteGen()
648
+ : DiscreteGen({ 1 })
526
649
  {
650
+ }
651
+
652
+ DiscreteGen(const DiscreteGen&) = default;
653
+ DiscreteGen(DiscreteGen&&) = default;
654
+
655
+ DiscreteGen& operator=(const DiscreteGen&) = default;
656
+ DiscreteGen& operator=(DiscreteGen&&) = default;
657
+
658
+ template<typename Rng>
659
+ EIGEN_STRONG_INLINE const _Scalar operator() (Rng&& rng)
660
+ {
661
+ using namespace Eigen::internal;
527
662
  if (!cdf.empty())
528
663
  {
529
- auto rx = ur_base::operator()();
530
- return (Scalar)(std::lower_bound(cdf.begin(), cdf.end() - 1, rx) - cdf.begin());
664
+ auto rx = ur(std::forward<Rng>(rng));
665
+ return (_Scalar)(std::lower_bound(cdf.begin(), cdf.end() - 1, rx) - cdf.begin());
531
666
  }
532
667
  else
533
668
  {
534
- auto albit = pfirst(this->rng()) & alias_table.get_bitmask();
535
- auto alx = ur_base::operator()();
669
+ auto albit = pfirst(rng()) & alias_table.get_bitmask();
670
+ auto alx = ur(rng);
536
671
  if (alx < alias_table.get_prob()[albit]) return albit;
537
672
  return alias_table.get_alias()[albit];
538
673
  }
539
674
  }
540
675
 
541
- template<typename Packet>
542
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp() const
676
+ template<typename Packet, typename Rng>
677
+ EIGEN_STRONG_INLINE const Packet packetOp(Rng&& rng)
543
678
  {
679
+ using namespace Eigen::internal;
544
680
  using DPacket = decltype(reinterpret_to_double(std::declval<Packet>()));
545
681
  if (!cdf.empty())
546
682
  {
547
683
  auto ret = pset1<Packet>(cdf.size());
548
684
  #ifdef EIGEN_VECTORIZE_AVX
549
- auto rx = ur_base::template packetOp<Packet4d>();
685
+ auto rx = ur.template packetOp<Packet4d>(std::forward<Rng>(rng));
550
686
  for (auto& p : cdf)
551
687
  {
552
688
  auto c = reinterpret_to_int(pcmplt(rx, pset1<decltype(rx)>(p)));
@@ -554,8 +690,8 @@ namespace Eigen
554
690
  ret = padd(ret, r);
555
691
  }
556
692
  #else
557
- auto rx1 = ur_base::template packetOp<DPacket>(),
558
- rx2 = ur_base::template packetOp<DPacket>();
693
+ auto rx1 = ur.template packetOp<DPacket>(rng),
694
+ rx2 = ur.template packetOp<DPacket>(rng);
559
695
  for (auto& p : cdf)
560
696
  {
561
697
  auto pp = pset1<decltype(rx1)>(p);
@@ -568,64 +704,84 @@ namespace Eigen
568
704
  {
569
705
  #ifdef EIGEN_VECTORIZE_AVX
570
706
  using RUtils = RawbitsMaker<Packet, Rng>;
571
- auto albit = pand(RUtils{}.rawbits(this->rng), pset1<Packet>(alias_table.get_bitmask()));
572
- auto c = reinterpret_to_int(pcmplt(ur_base::template packetOp<Packet4d>(), pgather(alias_table.get_prob(), _mm256_castsi128_si256(albit))));
707
+ auto albit = pand(RUtils{}.rawbits(rng), pset1<Packet>(alias_table.get_bitmask()));
708
+ auto c = reinterpret_to_int(pcmplt(ur.template packetOp<Packet4d>(rng), pgather(alias_table.get_prob(), _mm256_castsi128_si256(albit))));
573
709
  return pblendv(combine_low32(c), albit, pgather(alias_table.get_alias(), albit));
574
710
  #else
575
711
  using RUtils = RawbitsMaker<Packet, Rng>;
576
- auto albit = pand(RUtils{}.rawbits(this->rng), pset1<Packet>(alias_table.get_bitmask()));
577
- auto c1 = reinterpret_to_int(pcmplt(ur_base::template packetOp<DPacket>(), pgather(alias_table.get_prob(), albit)));
578
- auto c2 = reinterpret_to_int(pcmplt(ur_base::template packetOp<DPacket>(), pgather(alias_table.get_prob(), albit, true)));
712
+ auto albit = pand(RUtils{}.rawbits(rng), pset1<Packet>(alias_table.get_bitmask()));
713
+ auto c1 = reinterpret_to_int(pcmplt(ur.template packetOp<DPacket>(rng), pgather(alias_table.get_prob(), albit)));
714
+ auto c2 = reinterpret_to_int(pcmplt(ur.template packetOp<DPacket>(rng), pgather(alias_table.get_prob(), albit, true)));
579
715
  return pblendv(combine_low32(c1, c2), albit, pgather(alias_table.get_alias(), albit));
580
716
  #endif
581
717
  }
582
718
  }
583
719
  };
584
720
 
585
- template<typename Scalar, typename Urng, typename Precision>
586
- struct functor_traits<scalar_discrete_dist_op<Scalar, Urng, Precision> >
587
- {
588
- enum { Cost = HugeCost, PacketAccess = packet_traits<Scalar>::Vectorizable, IsRepeatable = false };
589
- };
721
+ template<typename> class BinomialGen;
590
722
 
591
- template<typename Scalar, typename Rng>
592
- struct scalar_poisson_dist_op : public scalar_uniform_real_op<float, Rng>
723
+ /**
724
+ * @brief Generator of integers on a Poisson distribution
725
+ *
726
+ * @tparam _Scalar
727
+ */
728
+ template<typename _Scalar>
729
+ class PoissonGen : OptCacheStore, public GenBase<PoissonGen<_Scalar>, _Scalar>
593
730
  {
594
- static_assert(std::is_same<Scalar, int32_t>::value, "poisson needs integral types.");
595
- using ur_base = scalar_uniform_real_op<float, Rng>;
731
+ friend BinomialGen<_Scalar>;
732
+ static_assert(std::is_same<_Scalar, int32_t>::value, "poisson needs integral types.");
733
+ int cache_rest_cnt = 0;
734
+ UniformRealGen<float> ur;
596
735
 
736
+ protected:
597
737
  double mean, ne_mean, sqrt_tmean, log_mean, g1;
598
738
 
599
- scalar_poisson_dist_op(const Rng& _rng, double _mean)
600
- : ur_base{ _rng }, mean{ _mean }, ne_mean{ std::exp(-_mean) }
739
+ public:
740
+ using Scalar = _Scalar;
741
+
742
+ /**
743
+ * @brief Construct a new Poisson Generator
744
+ *
745
+ * @param _mean mean of the distribution
746
+ */
747
+ PoissonGen(double _mean = 1)
748
+ : mean{ _mean }, ne_mean{ std::exp(-_mean) }
601
749
  {
602
750
  sqrt_tmean = std::sqrt(2 * mean);
603
751
  log_mean = std::log(mean);
604
752
  g1 = mean * log_mean - std::lgamma(mean + 1);
605
753
  }
606
754
 
607
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() () const
755
+ PoissonGen(const PoissonGen&) = default;
756
+ PoissonGen(PoissonGen&&) = default;
757
+
758
+ PoissonGen& operator=(const PoissonGen&) = default;
759
+ PoissonGen& operator=(PoissonGen&&) = default;
760
+
761
+ template<typename Rng>
762
+ EIGEN_STRONG_INLINE const _Scalar operator() (Rng&& rng)
608
763
  {
764
+ using namespace Eigen::internal;
609
765
  if (mean < 12)
610
766
  {
611
- Scalar res = 0;
767
+ _Scalar res = 0;
612
768
  double val = 1;
613
769
  for (; ; ++res)
614
770
  {
615
- val *= ur_base::operator()();
771
+ val *= ur(rng);
616
772
  if (val <= ne_mean) break;
617
773
  }
618
774
  return res;
619
775
  }
620
776
  else
621
777
  {
622
- Scalar res;
778
+ _Scalar res;
623
779
  double yx;
624
- while(1)
780
+ while (1)
625
781
  {
626
- yx = std::tan(constant::pi * ur_base::operator()());
627
- res = (Scalar)(sqrt_tmean * yx + mean);
628
- if (res >= 0 && ur_base::operator()() <= 0.9 * (1.0 + yx * yx)
782
+ yx = std::tan(constant::pi * ur(rng));
783
+ res = (_Scalar)(sqrt_tmean * yx + mean);
784
+ if (res >= 0 && ur(rng) <= 0.9 * (1.0 + yx * yx)
629
785
  * std::exp(res * log_mean - std::lgamma(res + 1.0) - g1))
630
786
  {
631
787
  return res;
@@ -634,9 +790,10 @@ namespace Eigen
634
790
  }
635
791
  }
636
792
 
637
- template<typename Packet>
638
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp() const
793
+ template<typename Packet, typename Rng>
794
+ EIGEN_STRONG_INLINE const Packet packetOp(Rng&& rng)
639
795
  {
796
+ using namespace Eigen::internal;
640
797
  using PacketType = decltype(reinterpret_to_float(std::declval<Packet>()));
641
798
 
642
799
  if (mean < 12)
@@ -645,7 +802,7 @@ namespace Eigen
645
802
  PacketType val = pset1<PacketType>(1), pne_mean = pset1<PacketType>(ne_mean);
646
803
  while (1)
647
804
  {
648
- val = pmul(val, ur_base::template packetOp<PacketType>());
805
+ val = pmul(val, ur.template packetOp<PacketType>(rng));
649
806
  auto c = reinterpret_to_int(pcmplt(pne_mean, val));
650
807
  if (pmovemask(c) == 0) break;
651
808
  res = padd(res, pnegate(c));
@@ -655,16 +812,6 @@ namespace Eigen
655
812
  else
656
813
  {
657
814
  auto& cm = Rand::detail::CompressMask<sizeof(Packet)>::get_inst();
658
- thread_local PacketType cache_rest;
659
- thread_local int cache_rest_cnt;
660
- thread_local const scalar_poisson_dist_op* cache_ptr = nullptr;
661
- if (cache_ptr != this)
662
- {
663
- cache_ptr = this;
664
- cache_rest = pset1<PacketType>(0);
665
- cache_rest_cnt = 0;
666
- }
667
-
668
815
  const PacketType ppi = pset1<PacketType>(constant::pi),
669
816
  psqrt_tmean = pset1<PacketType>(sqrt_tmean),
670
817
  pmean = pset1<PacketType>(mean),
@@ -673,7 +820,7 @@ namespace Eigen
673
820
  while (1)
674
821
  {
675
822
  PacketType fres, yx, psin, pcos;
676
- psincos(pmul(ppi, ur_base::template packetOp<PacketType>()), psin, pcos);
823
+ psincos(pmul(ppi, ur.template packetOp<PacketType>(rng)), psin, pcos);
677
824
  yx = pdiv(psin, pcos);
678
825
  fres = ptruncate(padd(pmul(psqrt_tmean, yx), pmean));
679
826
 
@@ -681,68 +828,87 @@ namespace Eigen
681
828
  auto p2 = pexp(psub(psub(pmul(fres, plog_mean), plgamma(padd(fres, pset1<PacketType>(1)))), pg1));
682
829
 
683
830
  auto c1 = pcmple(pset1<PacketType>(0), fres);
684
- auto c2 = pcmple(ur_base::template packetOp<PacketType>(), pmul(p1, p2));
831
+ auto c2 = pcmple(ur.template packetOp<PacketType>(rng), pmul(p1, p2));
685
832
 
686
833
  auto cands = fres;
687
834
  bool full = false;
688
835
  cache_rest_cnt = cm.compress_append(cands, pand(c1, c2),
689
- cache_rest, cache_rest_cnt, full);
836
+ OptCacheStore::template get<PacketType>(), cache_rest_cnt, full);
690
837
  if (full) return pcast<PacketType, Packet>(cands);
691
838
  }
692
839
  }
693
840
  }
694
841
  };
695
842
 
696
- template<typename Scalar, typename Urng>
697
- struct functor_traits<scalar_poisson_dist_op<Scalar, Urng> >
843
+ /**
844
+ * @brief Generator of integers on a binomial distribution
845
+ *
846
+ * @tparam _Scalar
847
+ */
848
+ template<typename _Scalar>
849
+ class BinomialGen : public GenBase<BinomialGen<_Scalar>, _Scalar>
698
850
  {
699
- enum { Cost = HugeCost, PacketAccess = packet_traits<Scalar>::Vectorizable, IsRepeatable = false };
700
- };
851
+ static_assert(std::is_same<_Scalar, int32_t>::value, "binomial needs integral types.");
701
852
 
702
- template<typename Scalar, typename Rng>
703
- struct scalar_binomial_dist_op : public scalar_poisson_dist_op<Scalar, Rng>
704
- {
705
- static_assert(std::is_same<Scalar, int32_t>::value, "binomial needs integral types.");
706
- using ur_base = scalar_uniform_real_op<float, Rng>;
707
-
708
- Scalar trials;
853
+ PoissonGen<_Scalar> poisson;
854
+ _Scalar trials;
709
855
  double p, small_p, g1, sqrt_v, log_small_p, log_small_q;
710
856
 
711
- scalar_binomial_dist_op(const Rng& _rng, Scalar _trials = 1, double _p = 0.5)
712
- : scalar_poisson_dist_op<Scalar, Rng>{ _rng, _trials * std::min(_p, 1 - _p) },
857
+ public:
858
+ using Scalar = _Scalar;
859
+
860
+ /**
861
+ * @brief Construct a new Binomial Generator
862
+ *
863
+ * @param _trials the number of trials
864
+ * @param _p probability of a trial generating true
865
+ */
866
+ BinomialGen(_Scalar _trials = 1, double _p = 0.5)
867
+ : poisson{ _trials * std::min(_p, 1 - _p) },
713
868
  trials{ _trials }, p{ _p }, small_p{ std::min(p, 1 - p) }
714
-
869
+
715
870
  {
716
- g1 = std::lgamma(trials + 1);
717
- sqrt_v = std::sqrt(2 * this->mean * (1 - small_p));
718
- log_small_p = std::log(small_p);
719
- log_small_q = std::log(1 - small_p);
871
+ if (!(trials < 25 || poisson.mean < 1.0))
872
+ {
873
+ g1 = std::lgamma(trials + 1);
874
+ sqrt_v = std::sqrt(2 * poisson.mean * (1 - small_p));
875
+ log_small_p = std::log(small_p);
876
+ log_small_q = std::log(1 - small_p);
877
+ }
720
878
  }
721
879
 
722
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() () const
880
+ BinomialGen(const BinomialGen&) = default;
881
+ BinomialGen(BinomialGen&&) = default;
882
+
883
+ BinomialGen& operator=(const BinomialGen&) = default;
884
+ BinomialGen& operator=(BinomialGen&&) = default;
885
+
886
+ template<typename Rng>
887
+ EIGEN_STRONG_INLINE const _Scalar operator() (Rng&& rng)
723
888
  {
724
- Scalar res;
889
+ using namespace Eigen::internal;
890
+ _Scalar res;
725
891
  if (trials < 25)
726
892
  {
727
893
  res = 0;
728
894
  for (int i = 0; i < trials; ++i)
729
895
  {
730
- if (ur_base::operator()() < p) ++res;
896
+ if (poisson.ur(rng) < p) ++res;
731
897
  }
732
898
  return res;
733
899
  }
734
- else if (this->mean < 1.0)
900
+ else if (poisson.mean < 1.0)
735
901
  {
736
- res = scalar_poisson_dist_op<Scalar, Rng>::operator()();
902
+ res = poisson(rng);
737
903
  }
738
904
  else
739
905
  {
740
- while(1)
906
+ while (1)
741
907
  {
742
908
  double ys;
743
- ys = std::tan(constant::pi * ur_base::operator()());
744
- res = (Scalar)(sqrt_v * ys + this->mean);
745
- if (0 <= res && res <= trials && ur_base::operator()() <= 1.2 * sqrt_v
909
+ ys = std::tan(constant::pi * poisson.ur(rng));
910
+ res = (_Scalar)(sqrt_v * ys + poisson.mean);
911
+ if (0 <= res && res <= trials && poisson.ur(rng) <= 1.2 * sqrt_v
746
912
  * (1.0 + ys * ys)
747
913
  * std::exp(g1 - std::lgamma(res + 1)
748
914
  - std::lgamma(trials - res + 1.0)
@@ -757,9 +923,10 @@ namespace Eigen
757
923
  return p == small_p ? res : trials - res;
758
924
  }
759
925
 
760
- template<typename Packet>
761
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp() const
926
+ template<typename Packet, typename Rng>
927
+ EIGEN_STRONG_INLINE const Packet packetOp(Rng&& rng)
762
928
  {
929
+ using namespace Eigen::internal;
763
930
  using PacketType = decltype(reinterpret_to_float(std::declval<Packet>()));
764
931
  Packet res;
765
932
  if (trials < 25)
@@ -768,42 +935,32 @@ namespace Eigen
768
935
  res = pset1<Packet>(trials);
769
936
  for (int i = 0; i < trials; ++i)
770
937
  {
771
- auto c = reinterpret_to_int(pcmple(pp, ur_base::template packetOp<PacketType>()));
938
+ auto c = reinterpret_to_int(pcmple(pp, poisson.ur.template packetOp<PacketType>(rng)));
772
939
  res = padd(res, c);
773
940
  }
774
941
  return res;
775
942
  }
776
- else if (this->mean < 1.0)
943
+ else if (poisson.mean < 1.0)
777
944
  {
778
- res = scalar_poisson_dist_op<Scalar, Rng>::template packetOp<Packet>();
945
+ res = poisson.template packetOp<Packet>(rng);
779
946
  }
780
947
  else
781
948
  {
782
949
  auto& cm = Rand::detail::CompressMask<sizeof(Packet)>::get_inst();
783
- thread_local PacketType cache_rest;
784
- thread_local int cache_rest_cnt;
785
- thread_local const scalar_binomial_dist_op* cache_ptr = nullptr;
786
- if (cache_ptr != this)
787
- {
788
- cache_ptr = this;
789
- cache_rest = pset1<PacketType>(0);
790
- cache_rest_cnt = 0;
791
- }
792
-
793
950
  const PacketType ppi = pset1<PacketType>(constant::pi),
794
951
  ptrials = pset1<PacketType>(trials),
795
952
  psqrt_v = pset1<PacketType>(sqrt_v),
796
- pmean = pset1<PacketType>(this->mean),
953
+ pmean = pset1<PacketType>(poisson.mean),
797
954
  plog_small_p = pset1<PacketType>(log_small_p),
798
955
  plog_small_q = pset1<PacketType>(log_small_q),
799
956
  pg1 = pset1<PacketType>(g1);
800
957
  while (1)
801
958
  {
802
959
  PacketType fres, ys, psin, pcos;
803
- psincos(pmul(ppi, ur_base::template packetOp<PacketType>()), psin, pcos);
960
+ psincos(pmul(ppi, poisson.ur.template packetOp<PacketType>(rng)), psin, pcos);
804
961
  ys = pdiv(psin, pcos);
805
962
  fres = ptruncate(padd(pmul(psqrt_v, ys), pmean));
806
-
963
+
807
964
  auto p1 = pmul(pmul(pset1<PacketType>(1.2), psqrt_v), padd(pset1<PacketType>(1), pmul(ys, ys)));
808
965
  auto p2 = pexp(
809
966
  padd(padd(psub(
@@ -813,12 +970,12 @@ namespace Eigen
813
970
  );
814
971
 
815
972
  auto c1 = pand(pcmple(pset1<PacketType>(0), fres), pcmple(fres, ptrials));
816
- auto c2 = pcmple(ur_base::template packetOp<PacketType>(), pmul(p1, p2));
973
+ auto c2 = pcmple(poisson.ur.template packetOp<PacketType>(rng), pmul(p1, p2));
817
974
 
818
975
  auto cands = fres;
819
976
  bool full = false;
820
- cache_rest_cnt = cm.compress_append(cands, pand(c1, c2),
821
- cache_rest, cache_rest_cnt, full);
977
+ poisson.cache_rest_cnt = cm.compress_append(cands, pand(c1, c2),
978
+ poisson.template get<PacketType>(), poisson.cache_rest_cnt, full);
822
979
  if (full)
823
980
  {
824
981
  res = pcast<PacketType, Packet>(cands);
@@ -830,47 +987,521 @@ namespace Eigen
830
987
  }
831
988
  };
832
989
 
833
- template<typename Scalar, typename Urng>
834
- struct functor_traits<scalar_binomial_dist_op<Scalar, Urng> >
990
+ /**
991
+ * @brief Generator of integers on a geometric distribution
992
+ *
993
+ * @tparam _Scalar
994
+ */
995
+ template<typename _Scalar>
996
+ class GeometricGen : public GenBase<GeometricGen<_Scalar>, _Scalar>
835
997
  {
836
- enum { Cost = HugeCost, PacketAccess = packet_traits<Scalar>::Vectorizable, IsRepeatable = false };
837
- };
838
-
839
- template<typename Scalar, typename Rng>
840
- struct scalar_geometric_dist_op : public scalar_uniform_real_op<float, Rng>
841
- {
842
- static_assert(std::is_same<Scalar, int32_t>::value, "geomtric needs integral types.");
843
- using ur_base = scalar_uniform_real_op<float, Rng>;
844
-
998
+ static_assert(std::is_same<_Scalar, int32_t>::value, "geomtric needs integral types.");
999
+ UniformRealGen<float> ur;
845
1000
  double p, rlog_q;
846
1001
 
847
- scalar_geometric_dist_op(const Rng& _rng, double _p)
848
- : ur_base{ _rng }, p{ _p }, rlog_q{ 1 / std::log(1 - p) }
1002
+ public:
1003
+ using Scalar = _Scalar;
1004
+
1005
+ /**
1006
+ * @brief Construct a new Geometric Generator
1007
+ *
1008
+ * @param _p probability of a trial generating true
1009
+ */
1010
+ GeometricGen(double _p = 0.5)
1011
+ : p{ _p }, rlog_q{ 1 / std::log(1 - p) }
849
1012
  {
850
1013
  }
851
1014
 
852
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() () const
1015
+ GeometricGen(const GeometricGen&) = default;
1016
+ GeometricGen(GeometricGen&&) = default;
1017
+
1018
+ GeometricGen& operator=(const GeometricGen&) = default;
1019
+ GeometricGen& operator=(GeometricGen&&) = default;
1020
+
1021
+ template<typename Rng>
1022
+ EIGEN_STRONG_INLINE const _Scalar operator() (Rng&& rng)
853
1023
  {
854
- return (Scalar)(std::log(1 - ur_base::operator()()) * rlog_q);
1024
+ using namespace Eigen::internal;
1025
+ return (_Scalar)(std::log(1 - ur(std::forward<Rng>(rng))) * rlog_q);
855
1026
  }
856
1027
 
857
- template<typename Packet>
858
- EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp() const
1028
+ template<typename Packet, typename Rng>
1029
+ EIGEN_STRONG_INLINE const Packet packetOp(Rng&& rng)
859
1030
  {
1031
+ using namespace Eigen::internal;
860
1032
  using PacketType = decltype(reinterpret_to_float(std::declval<Packet>()));
861
1033
 
862
1034
  return pcast<PacketType, Packet>(ptruncate(pmul(plog(
863
- psub(pset1<PacketType>(1), ur_base::template packetOp<PacketType>())
1035
+ psub(pset1<PacketType>(1), ur.template packetOp<PacketType>(std::forward<Rng>(rng)))
864
1036
  ), pset1<PacketType>(rlog_q))));
865
1037
  }
866
1038
  };
867
1039
 
868
- template<typename Scalar, typename Urng>
869
- struct functor_traits<scalar_geometric_dist_op<Scalar, Urng> >
870
- {
871
- enum { Cost = HugeCost, PacketAccess = packet_traits<Scalar>::Vectorizable, IsRepeatable = false };
872
- };
873
1040
 
1041
+ template<typename Derived, typename Urng>
1042
+ using UniformIntType = CwiseNullaryOp<internal::scalar_rng_adaptor<UniformIntGen<typename Derived::Scalar>, typename Derived::Scalar, Urng, true>, const Derived>;
1043
+
1044
+ /**
1045
+ * @brief generates integers with a given range `[min, max]`
1046
+ *
1047
+ * @tparam Derived a type of Eigen::DenseBase
1048
+ * @tparam Urng
1049
+ * @param rows the number of rows being generated
1050
+ * @param cols the number of columns being generated
1051
+ * @param urng c++11-style random number generator
1052
+ * @param min, max the range of integers being generated
1053
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1054
+ *
1055
+ * @see Eigen::Rand::UniformIntGen
1056
+ */
1057
+ template<typename Derived, typename Urng>
1058
+ inline const UniformIntType<Derived, Urng>
1059
+ uniformInt(Index rows, Index cols, Urng&& urng, typename Derived::Scalar min, typename Derived::Scalar max)
1060
+ {
1061
+ return {
1062
+ rows, cols, { std::forward<Urng>(urng), UniformIntGen<typename Derived::Scalar>{ min, max } }
1063
+ };
1064
+ }
1065
+
1066
+ /**
1067
+ * @brief generates integers with a given range `[min, max]`
1068
+ *
1069
+ * @tparam Derived
1070
+ * @tparam Urng
1071
+ * @param o an instance of any type of Eigen::DenseBase
1072
+ * @param urng c++11-style random number generator
1073
+ * @param min, max the range of integers being generated
1074
+ * @return a random matrix expression of the same shape as `o`
1075
+ *
1076
+ * @see Eigen::Rand::UniformIntGen
1077
+ */
1078
+ template<typename Derived, typename Urng>
1079
+ inline const UniformIntType<Derived, Urng>
1080
+ uniformIntLike(Derived& o, Urng&& urng, typename Derived::Scalar min, typename Derived::Scalar max)
1081
+ {
1082
+ return {
1083
+ o.rows(), o.cols(), { std::forward<Urng>(urng), UniformIntGen<typename Derived::Scalar>{ min, max } }
1084
+ };
1085
+ }
1086
+
1087
+ template<typename Derived, typename Urng>
1088
+ using DiscreteFType = CwiseNullaryOp<internal::scalar_rng_adaptor<DiscreteGen<typename Derived::Scalar, float>, typename Derived::Scalar, Urng, true>, const Derived>;
1089
+
1090
+ /**
1091
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1092
+ * The data type used for calculation of probabilities is float(23bit precision).
1093
+ *
1094
+ * @tparam Derived
1095
+ * @tparam Urng
1096
+ * @param rows the number of rows being generated
1097
+ * @param cols the number of columns being generated
1098
+ * @param urng c++11-style random number generator
1099
+ * @param first, last the range of elements defining the numbers to use as weights. The type of the elements referred by `RealIter` must be convertible to `double`.
1100
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1101
+ *
1102
+ * @see Eigen::Rand::DiscreteGen
1103
+ */
1104
+ template<typename Derived, typename Urng, typename RealIter>
1105
+ inline const DiscreteFType<Derived, Urng>
1106
+ discreteF(Index rows, Index cols, Urng&& urng, RealIter first, RealIter last)
1107
+ {
1108
+ return {
1109
+ rows, cols, { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, float>{first, last} }
1110
+ };
1111
+ }
1112
+
1113
+ /**
1114
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1115
+ * The data type used for calculation of probabilities is float(23bit precision).
1116
+ *
1117
+ * @tparam Derived
1118
+ * @tparam Urng
1119
+ * @param o an instance of any type of Eigen::DenseBase
1120
+ * @param urng c++11-style random number generator
1121
+ * @param first, last the range of elements defining the numbers to use as weights. The type of the elements referred by `RealIter` must be convertible to `double`.
1122
+ * @return a random matrix expression of the same shape as `o`
1123
+ *
1124
+ * @see Eigen::Rand::DiscreteGen
1125
+ */
1126
+ template<typename Derived, typename Urng, typename RealIter>
1127
+ inline const DiscreteFType<Derived, Urng>
1128
+ discreteFLike(Derived& o, Urng&& urng, RealIter first, RealIter last)
1129
+ {
1130
+ return {
1131
+ o.rows(), o.cols(), { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, float>(first, last) }
1132
+ };
1133
+ }
1134
+
1135
+ /**
1136
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1137
+ * The data type used for calculation of probabilities is float(23bit precision).
1138
+ *
1139
+ * @tparam Derived
1140
+ * @tparam Urng
1141
+ * @param rows the number of rows being generated
1142
+ * @param cols the number of columns being generated
1143
+ * @param urng c++11-style random number generator
1144
+ * @param il an instance of `initializer_list` containing the numbers to use as weights. The type of the elements referred by it must be convertible to `double`.
1145
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1146
+ *
1147
+ * @see Eigen::Rand::DiscreteGen
1148
+ */
1149
+ template<typename Derived, typename Urng, typename Real>
1150
+ inline const DiscreteFType<Derived, Urng>
1151
+ discreteF(Index rows, Index cols, Urng&& urng, const std::initializer_list<Real>& il)
1152
+ {
1153
+ return {
1154
+ rows, cols, { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, float>{il.begin(), il.end()} }
1155
+ };
1156
+ }
1157
+
1158
+ /**
1159
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1160
+ * The data type used for calculation of probabilities is float(23bit precision).
1161
+ *
1162
+ * @tparam Derived
1163
+ * @tparam Urng
1164
+ * @param o an instance of any type of Eigen::DenseBase
1165
+ * @param urng c++11-style random number generator
1166
+ * @param il an instance of `initializer_list` containing the numbers to use as weights. The type of the elements referred by it must be convertible to `double`.
1167
+ * @return a random matrix expression of the same shape as `o`
1168
+ *
1169
+ * @see Eigen::Rand::DiscreteGen
1170
+ */
1171
+ template<typename Derived, typename Urng, typename Real>
1172
+ inline const DiscreteFType<Derived, Urng>
1173
+ discreteFLike(Derived& o, Urng&& urng, const std::initializer_list<Real>& il)
1174
+ {
1175
+ return {
1176
+ o.rows(), o.cols(), { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, float>(il.begin(), il.end()) }
1177
+ };
1178
+ }
1179
+
1180
+ template<typename Derived, typename Urng>
1181
+ using DiscreteDType = CwiseNullaryOp<internal::scalar_rng_adaptor<DiscreteGen<typename Derived::Scalar, double>, typename Derived::Scalar, Urng, true>, const Derived>;
1182
+
1183
+ /**
1184
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1185
+ * The data type used for calculation of probabilities is double(52bit precision).
1186
+ *
1187
+ * @tparam Derived
1188
+ * @tparam Urng
1189
+ * @param rows the number of rows being generated
1190
+ * @param cols the number of columns being generated
1191
+ * @param urng c++11-style random number generator
1192
+ * @param first, last the range of elements defining the numbers to use as weights. The type of the elements referred by `RealIter` must be convertible to `double`.
1193
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1194
+ *
1195
+ * @see Eigen::Rand::DiscreteGen
1196
+ */
1197
+ template<typename Derived, typename Urng, typename RealIter>
1198
+ inline const DiscreteDType<Derived, Urng>
1199
+ discreteD(Index rows, Index cols, Urng&& urng, RealIter first, RealIter last)
1200
+ {
1201
+ return {
1202
+ rows, cols, { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, double>{first, last} }
1203
+ };
1204
+ }
1205
+
1206
+ /**
1207
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1208
+ * The data type used for calculation of probabilities is double(52bit precision).
1209
+ *
1210
+ * @tparam Derived
1211
+ * @tparam Urng
1212
+ * @param o an instance of any type of Eigen::DenseBase
1213
+ * @param urng c++11-style random number generator
1214
+ * @param first, last the range of elements defining the numbers to use as weights. The type of the elements referred by `RealIter` must be convertible to `double`.
1215
+ * @return a random matrix expression of the same shape as `o`
1216
+ *
1217
+ * @see Eigen::Rand::DiscreteGen
1218
+ */
1219
+ template<typename Derived, typename Urng, typename RealIter>
1220
+ inline const DiscreteDType<Derived, Urng>
1221
+ discreteDLike(Derived& o, Urng&& urng, RealIter first, RealIter last)
1222
+ {
1223
+ return {
1224
+ o.rows(), o.cols(), { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, double>{first, last} }
1225
+ };
1226
+ }
1227
+
1228
+ /**
1229
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1230
+ * The data type used for calculation of probabilities is double(52bit precision).
1231
+ *
1232
+ * @tparam Derived
1233
+ * @tparam Urng
1234
+ * @param rows the number of rows being generated
1235
+ * @param cols the number of columns being generated
1236
+ * @param urng c++11-style random number generator
1237
+ * @param il an instance of `initializer_list` containing the numbers to use as weights. The type of the elements referred by it must be convertible to `double`.
1238
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1239
+ *
1240
+ * @see Eigen::Rand::DiscreteGen
1241
+ */
1242
+ template<typename Derived, typename Urng, typename Real>
1243
+ inline const DiscreteDType<Derived, Urng>
1244
+ discreteD(Index rows, Index cols, Urng&& urng, const std::initializer_list<Real>& il)
1245
+ {
1246
+ return {
1247
+ rows, cols, { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, double>{il.begin(), il.end()} }
1248
+ };
1249
+ }
1250
+
1251
+ /**
1252
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1253
+ * The data type used for calculation of probabilities is double(52bit precision).
1254
+ *
1255
+ * @tparam Derived
1256
+ * @tparam Urng
1257
+ * @param o an instance of any type of Eigen::DenseBase
1258
+ * @param urng c++11-style random number generator
1259
+ * @param il an instance of `initializer_list` containing the numbers to use as weights. The type of the elements referred by it must be convertible to `double`.
1260
+ * @return a random matrix expression of the same shape as `o`
1261
+ *
1262
+ * @see Eigen::Rand::DiscreteGen
1263
+ */
1264
+ template<typename Derived, typename Urng, typename Real>
1265
+ inline const DiscreteDType<Derived, Urng>
1266
+ discreteDLike(Derived& o, Urng&& urng, const std::initializer_list<Real>& il)
1267
+ {
1268
+ return {
1269
+ o.rows(), o.cols(), { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, double>{il.begin(), il.end()} }
1270
+ };
1271
+ }
1272
+
1273
+ template<typename Derived, typename Urng>
1274
+ using DiscreteType = CwiseNullaryOp<internal::scalar_rng_adaptor<DiscreteGen<typename Derived::Scalar, int32_t>, typename Derived::Scalar, Urng, true>, const Derived>;
1275
+
1276
+ /**
1277
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1278
+ * The data type used for calculation of probabilities is int32(32bit precision).
1279
+ *
1280
+ * @tparam Derived
1281
+ * @tparam Urng
1282
+ * @param rows the number of rows being generated
1283
+ * @param cols the number of columns being generated
1284
+ * @param urng c++11-style random number generator
1285
+ * @param first, last the range of elements defining the numbers to use as weights. The type of the elements referred by `RealIter` must be convertible to `double`.
1286
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1287
+ *
1288
+ * @see Eigen::Rand::DiscreteGen
1289
+ */
1290
+ template<typename Derived, typename Urng, typename RealIter>
1291
+ inline const DiscreteType<Derived, Urng>
1292
+ discrete(Index rows, Index cols, Urng&& urng, RealIter first, RealIter last)
1293
+ {
1294
+ return {
1295
+ rows, cols, { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, int32_t>{first, last} }
1296
+ };
1297
+ }
1298
+
1299
+ /**
1300
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1301
+ * The data type used for calculation of probabilities is int32(32bit precision).
1302
+ *
1303
+ * @tparam Derived
1304
+ * @tparam Urng
1305
+ * @param o an instance of any type of Eigen::DenseBase
1306
+ * @param urng c++11-style random number generator
1307
+ * @param first, last the range of elements defining the numbers to use as weights. The type of the elements referred by `RealIter` must be convertible to `double`.
1308
+ * @return a random matrix expression of the same shape as `o`
1309
+ *
1310
+ * @see Eigen::Rand::DiscreteGen
1311
+ */
1312
+ template<typename Derived, typename Urng, typename RealIter>
1313
+ inline const DiscreteType<Derived, Urng>
1314
+ discreteLike(Derived& o, Urng&& urng, RealIter first, RealIter last)
1315
+ {
1316
+ return {
1317
+ o.rows(), o.cols(), { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, int32_t>{first, last} }
1318
+ };
1319
+ }
1320
+
1321
+ /**
1322
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1323
+ * The data type used for calculation of probabilities is int32(32bit precision).
1324
+ *
1325
+ * @tparam Derived
1326
+ * @tparam Urng
1327
+ * @param rows the number of rows being generated
1328
+ * @param cols the number of columns being generated
1329
+ * @param urng c++11-style random number generator
1330
+ * @param il an instance of `initializer_list` containing the numbers to use as weights. The type of the elements referred by it must be convertible to `double`.
1331
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1332
+ *
1333
+ * @see Eigen::Rand::DiscreteGen
1334
+ */
1335
+ template<typename Derived, typename Urng, typename Real>
1336
+ inline const DiscreteType<Derived, Urng>
1337
+ discrete(Index rows, Index cols, Urng&& urng, const std::initializer_list<Real>& il)
1338
+ {
1339
+ return {
1340
+ rows, cols, { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, int32_t>{il.begin(), il.end()} }
1341
+ };
1342
+ }
1343
+
1344
+ /**
1345
+ * @brief generates random integers on the interval `[0, n)`, where the probability of each individual integer `i` is proportional to `w(i)`.
1346
+ * The data type used for calculation of probabilities is int32(32bit precision).
1347
+ *
1348
+ * @tparam Derived
1349
+ * @tparam Urng
1350
+ * @param o an instance of any type of Eigen::DenseBase
1351
+ * @param urng c++11-style random number generator
1352
+ * @param il an instance of `initializer_list` containing the numbers to use as weights. The type of the elements referred by it must be convertible to `double`.
1353
+ * @return a random matrix expression of the same shape as `o`
1354
+ *
1355
+ * @see Eigen::Rand::DiscreteGen
1356
+ */
1357
+ template<typename Derived, typename Urng, typename Real>
1358
+ inline const DiscreteType<Derived, Urng>
1359
+ discreteLike(Derived& o, Urng&& urng, const std::initializer_list<Real>& il)
1360
+ {
1361
+ return {
1362
+ o.rows(), o.cols(), { std::forward<Urng>(urng), DiscreteGen<typename Derived::Scalar, int32_t>{il.begin(), il.end()} }
1363
+ };
1364
+ }
1365
+
1366
+ template<typename Derived, typename Urng>
1367
+ using PoissonType = CwiseNullaryOp<internal::scalar_rng_adaptor<PoissonGen<typename Derived::Scalar>, typename Derived::Scalar, Urng, true>, const Derived>;
1368
+
1369
+ /**
1370
+ * @brief generates reals on the Poisson distribution.
1371
+ *
1372
+ * @tparam Derived
1373
+ * @tparam Urng
1374
+ * @param rows the number of rows being generated
1375
+ * @param cols the number of columns being generated
1376
+ * @param urng c++11-style random number generator
1377
+ * @param mean rate parameter
1378
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1379
+ *
1380
+ * @see Eigen::Rand::PoissonGen
1381
+ */
1382
+ template<typename Derived, typename Urng>
1383
+ inline const PoissonType<Derived, Urng>
1384
+ poisson(Index rows, Index cols, Urng&& urng, double mean = 1)
1385
+ {
1386
+ return {
1387
+ rows, cols, { std::forward<Urng>(urng), PoissonGen<typename Derived::Scalar>{mean} }
1388
+ };
1389
+ }
1390
+
1391
+ /**
1392
+ * @brief generates reals on the Poisson distribution.
1393
+ *
1394
+ * @tparam Derived
1395
+ * @tparam Urng
1396
+ * @param o an instance of any type of Eigen::DenseBase
1397
+ * @param urng c++11-style random number generator
1398
+ * @param mean rate parameter
1399
+ * @return a random matrix expression of the same shape as `o`
1400
+ *
1401
+ * @see Eigen::Rand::PoissonGen
1402
+ */
1403
+ template<typename Derived, typename Urng>
1404
+ inline const PoissonType<Derived, Urng>
1405
+ poissonLike(Derived& o, Urng&& urng, double mean = 1)
1406
+ {
1407
+ return {
1408
+ o.rows(), o.cols(), { std::forward<Urng>(urng), PoissonGen<typename Derived::Scalar>{mean} }
1409
+ };
1410
+ }
1411
+
1412
+ template<typename Derived, typename Urng>
1413
+ using BinomialType = CwiseNullaryOp<internal::scalar_rng_adaptor<BinomialGen<typename Derived::Scalar>, typename Derived::Scalar, Urng, true>, const Derived>;
1414
+
1415
+ /**
1416
+ * @brief generates reals on the binomial distribution.
1417
+ *
1418
+ * @tparam Derived
1419
+ * @tparam Urng
1420
+ * @param rows the number of rows being generated
1421
+ * @param cols the number of columns being generated
1422
+ * @param urng c++11-style random number generator
1423
+ * @param trials the number of trials
1424
+ * @param p probability of a trial generating true
1425
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1426
+ *
1427
+ * @see Eigen::Rand::BinomialGen
1428
+ */
1429
+ template<typename Derived, typename Urng>
1430
+ inline const BinomialType<Derived, Urng>
1431
+ binomial(Index rows, Index cols, Urng&& urng, typename Derived::Scalar trials = 1, double p = 0.5)
1432
+ {
1433
+ return {
1434
+ rows, cols, { std::forward<Urng>(urng), BinomialGen<typename Derived::Scalar>{trials, p} }
1435
+ };
1436
+ }
1437
+
1438
+ /**
1439
+ * @brief generates reals on the binomial distribution.
1440
+ *
1441
+ * @tparam Derived
1442
+ * @tparam Urng
1443
+ * @param o an instance of any type of Eigen::DenseBase
1444
+ * @param urng c++11-style random number generator
1445
+ * @param trials the number of trials
1446
+ * @param p probability of a trial generating true
1447
+ * @return a random matrix expression of the same shape as `o`
1448
+ *
1449
+ * @see Eigen::Rand::BinomialGen
1450
+ */
1451
+ template<typename Derived, typename Urng>
1452
+ inline const BinomialType<Derived, Urng>
1453
+ binomialLike(Derived& o, Urng&& urng, typename Derived::Scalar trials = 1, double p = 0.5)
1454
+ {
1455
+ return {
1456
+ o.rows(), o.cols(), { std::forward<Urng>(urng), BinomialGen<typename Derived::Scalar>{trials, p} }
1457
+ };
1458
+ }
1459
+
1460
+ template<typename Derived, typename Urng>
1461
+ using GeometricType = CwiseNullaryOp<internal::scalar_rng_adaptor<GeometricGen<typename Derived::Scalar>, typename Derived::Scalar, Urng, true>, const Derived>;
1462
+
1463
+ /**
1464
+ * @brief generates reals on the geometric distribution.
1465
+ *
1466
+ * @tparam Derived
1467
+ * @tparam Urng
1468
+ * @param rows the number of rows being generated
1469
+ * @param cols the number of columns being generated
1470
+ * @param urng c++11-style random number generator
1471
+ * @param p probability of a trial generating true
1472
+ * @return a random matrix expression with a shape (`rows`, `cols`)
1473
+ *
1474
+ * @see Eigen::Rand::GeometricGen
1475
+ */
1476
+ template<typename Derived, typename Urng>
1477
+ inline const GeometricType<Derived, Urng>
1478
+ geometric(Index rows, Index cols, Urng&& urng, double p = 0.5)
1479
+ {
1480
+ return {
1481
+ rows, cols, { std::forward<Urng>(urng), GeometricGen<typename Derived::Scalar>{p} }
1482
+ };
1483
+ }
1484
+
1485
+ /**
1486
+ * @brief generates reals on the geometric distribution.
1487
+ *
1488
+ * @tparam Derived
1489
+ * @tparam Urng
1490
+ * @param o an instance of any type of Eigen::DenseBase
1491
+ * @param urng c++11-style random number generator
1492
+ * @param p probability of a trial generating true
1493
+ * @return a random matrix expression of the same shape as `o`
1494
+ *
1495
+ * @see Eigen::Rand::GeometricGen
1496
+ */
1497
+ template<typename Derived, typename Urng>
1498
+ inline const GeometricType<Derived, Urng>
1499
+ geometricLike(Derived& o, Urng&& urng, double p = 0.5)
1500
+ {
1501
+ return {
1502
+ o.rows(), o.cols(), { std::forward<Urng>(urng), GeometricGen<typename Derived::Scalar>{p} }
1503
+ };
1504
+ }
874
1505
  }
875
1506
  }
876
1507