prrng 1.12.1
Loading...
Searching...
No Matches
prrng.h
Go to the documentation of this file.
1
20#ifndef PRRNG_H
21#define PRRNG_H
22
27#define PRRNG_PCG32_INITSTATE 0x853c49e6748fea9bULL
28
33#define PRRNG_PCG32_INITSEQ 0xda3e39cb94b95bdbULL
34
39#define PRRNG_PCG32_MULT 6364136223846793005ULL
40
41#include <array>
42#include <xtensor/xarray.hpp>
43#include <xtensor/xnoalias.hpp>
44#include <xtensor/xtensor.hpp>
45
46#ifndef PRRNG_USE_BOOST
55#define PRRNG_USE_BOOST 1
56#endif
57
58#if PRRNG_USE_BOOST
59#include <boost/math/special_functions/erf.hpp>
60#include <boost/math/special_functions/gamma.hpp>
61#include <xtensor/xvectorize.hpp>
62#endif
63
67#define PRRNG_QUOTE_HELPER(x) #x
68#define PRRNG_QUOTE(x) PRRNG_QUOTE_HELPER(x)
69
70#define PRRNG_ASSERT_IMPL(expr, file, line) \
71 if (!(expr)) { \
72 throw std::runtime_error( \
73 std::string(file) + ':' + std::to_string(line) + ": assertion failed (" #expr ") \n\t" \
74 ); \
75 }
76
77#define PRRNG_WARNING_IMPL(message, file, line, function) \
78 std::cout << std::string(file) + ":" + std::to_string(line) + " (" + std::string(function) + \
79 ")" + ": " message ") \n\t";
80
105#ifndef PRRNG_VERSION
106#define PRRNG_VERSION "@PROJECT_VERSION@"
107#endif
108
126#ifdef PRRNG_ENABLE_ASSERT
127#define PRRNG_ASSERT(expr) PRRNG_ASSERT_IMPL(expr, __FILE__, __LINE__)
128#else
129#define PRRNG_ASSERT(expr)
130#endif
131
149#ifdef PRRNG_ENABLE_DEBUG
150#define PRRNG_DEBUG(expr) PRRNG_ASSERT_IMPL(expr, __FILE__, __LINE__)
151#else
152#define PRRNG_DEBUG(expr)
153#endif
154
164#ifdef PRRNG_DISABLE_WARNING
165#define PRRNG_WARNING(message)
166#else
167#define PRRNG_WARNING(message) PRRNG_WARNING_IMPL(message, __FILE__, __LINE__, __FUNCTION__)
168#endif
169
179#ifdef PRRNG_ENABLE_WARNING_PYTHON
180#define PRRNG_WARNING_PYTHON(message) PRRNG_WARNING_IMPL(message, __FILE__, __LINE__, __FUNCTION__)
181#else
182#define PRRNG_WARNING_PYTHON(message)
183#endif
184
188namespace prrng {
189
204
225std::vector<double> default_parameters(
227 const std::vector<double>& parameters = std::vector<double>{}
228)
229{
230 std::vector<double> ret;
231 switch (distribution) {
233 ret = std::vector<double>{1, 0};
234 break;
236 ret = std::vector<double>{1, 0};
237 break;
239 ret = std::vector<double>{1, 0};
240 break;
242 ret = std::vector<double>{1, 0};
243 break;
245 ret = std::vector<double>{1, 1, 0};
246 break;
248 ret = std::vector<double>{1, 1, 0};
249 break;
251 ret = std::vector<double>{1, 1, 0};
252 break;
254 ret = std::vector<double>{1, 0, 0};
255 break;
257 std::vector<double>{};
258 break;
259 }
260
261 PRRNG_ASSERT(parameters.size() <= ret.size());
262 std::copy(parameters.begin(), parameters.end(), ret.begin());
263 return ret;
264}
265
266namespace detail {
267
274bool has_correct_parameters(enum distribution distribution, const std::vector<double>& parameters)
275{
276 switch (distribution) {
278 return parameters.size() == 2;
280 return parameters.size() == 2;
282 return parameters.size() == 2;
284 return parameters.size() == 2;
286 return parameters.size() == 3;
288 return parameters.size() == 3;
290 return parameters.size() == 3;
292 return parameters.size() == 3;
294 return true;
295 }
296
297 return true;
298}
299
306inline std::string unquote(const std::string& arg)
307{
308 std::string ret = arg;
309 ret.erase(std::remove(ret.begin(), ret.end(), '\"'), ret.end());
310 return ret;
311}
312
320inline std::string replace(std::string str, const std::string& from, const std::string& to)
321{
322 size_t start_pos = 0;
323 while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
324 str.replace(start_pos, from.length(), to);
325 start_pos += to.length();
326 }
327 return str;
328}
329
330template <class T>
331struct is_std_array : std::false_type {};
332
333template <class T, size_t N>
334struct is_std_array<std::array<T, N>> : std::true_type {};
335
339template <size_t N, class T, typename = void>
340struct check_fixed_rank {
341 constexpr static bool value = false;
342};
343
344template <size_t N, class T>
345struct check_fixed_rank<N, T, typename std::enable_if_t<xt::get_rank<T>::value != SIZE_MAX>> {
346 constexpr static bool value = (N == xt::get_rank<T>::value);
347};
348
349template <size_t N, class T>
350struct check_fixed_rank<N, T, typename std::enable_if_t<is_std_array<T>::value>> {
351 constexpr static bool value = (N == std::tuple_size<T>::value);
352};
353
357template <typename R, typename = void>
358struct get_value_type {
359 using type = typename R::value_type;
360};
361
362template <typename R>
363struct get_value_type<R, typename std::enable_if_t<std::is_arithmetic<R>::value>> {
364 using type = R;
365};
366
370template <typename R, size_t N>
371struct return_type_fixed {
372 using type = typename xt::xtensor<R, N>;
373};
374
378template <typename R, class S, typename = void>
379struct return_type {
380 using type = typename xt::xarray<R>;
381};
382
383template <typename R, class S>
384struct return_type<R, S, typename std::enable_if_t<is_std_array<S>::value>> {
385 using type = typename xt::xtensor<R, std::tuple_size<S>::value>;
386};
387
388template <typename R, class S>
389struct return_type<R, S, typename std::enable_if_t<xt::has_fixed_rank_t<S>::value>> {
390 using type = typename xt::xtensor<R, xt::get_rank<S>::value>;
391};
392
396template <typename R, class S, class T, typename = void>
397struct composite_return_type {
398 using type = typename xt::xarray<R>;
399};
400
401template <typename R, class S, class T>
402struct composite_return_type<
403 R,
404 S,
405 T,
406 typename std::enable_if_t<is_std_array<S>::value && is_std_array<T>::value>> {
407 constexpr static size_t N = std::tuple_size<S>::value + std::tuple_size<T>::value;
408 using type = typename xt::xtensor<R, N>;
409};
410
414template <typename R, typename = void>
415struct allocate_return {
416
417 using value_type = typename R::value_type;
418 R value;
419
420 template <class S>
421 allocate_return(const S& shape)
422 {
423#if (XTENSOR_PYTHON_VERSION_MINOR == 26 && XTENSOR_PYTHON_VERSION_PATCH <= 1) || \
424 (XTENSOR_PYTHON_VERSION_MINOR < 26)
425 if (shape.size() == 0) {
426 std::array<typename R::size_type, 1> shape_ = {1};
427 value.resize(shape_);
428 }
429 else {
430 value.resize(shape);
431 }
432#else
433 value.resize(shape);
434#endif
435 }
436
437 template <class I, std::size_t L>
438 allocate_return(const I (&shape)[L])
439 {
440 std::array<I, L> shape_;
441 std::copy(shape, shape + L, shape_.begin());
442 value.resize(shape_);
443 }
444
445 typename R::value_type* data()
446 {
447 return &value.front();
448 }
449
450 size_t size() const
451 {
452 return value.size();
453 }
454};
455
456template <typename R>
457struct allocate_return<R, typename std::enable_if_t<std::is_arithmetic<R>::value>> {
458
459 using value_type = R;
460 R value;
461
462 template <class S>
463 allocate_return(const S& shape)
464 {
465#ifdef PRRNG_ENABLE_ASSERT
466 PRRNG_ASSERT(shape.size() <= 1);
467 if (shape.size() == 1) {
468 PRRNG_ASSERT(shape[0] == 1);
469 }
470#else
471 (void)(shape);
472#endif
473 }
474
475 R* data()
476 {
477 return &value;
478 }
479
480 size_t size() const
481 {
482 return 1;
483 }
484};
485
493template <class S, class T, typename = void>
494struct concatenate {
495 static auto two(const S& s, const T& t)
496 {
497 std::vector<size_t> r;
498 r.insert(r.begin(), s.cbegin(), s.cend());
499 r.insert(r.end(), t.cbegin(), t.cend());
500 return r;
501 }
502};
503
504template <class S, class T>
505struct concatenate<
506 S,
507 T,
508 typename std::enable_if_t<is_std_array<S>::value && is_std_array<T>::value>> {
509 static auto two(const S& s, const T& t)
510 {
511 std::array<size_t, std::tuple_size<S>::value + std::tuple_size<T>::value> r;
512 std::copy(s.cbegin(), s.cend(), r.begin());
513 std::copy(t.cbegin(), t.cend(), r.begin() + std::tuple_size<S>::value);
514 return r;
515 }
516};
517
524template <class S>
525inline size_t size(const S& shape)
526{
527 using ST = typename S::value_type;
528 return std::accumulate(shape.cbegin(), shape.cend(), ST(1), std::multiplies<ST>());
529}
530
534template <class I, std::size_t L>
535std::array<I, L> to_array(const I (&shape)[L])
536{
537 std::array<I, L> r;
538 std::copy(&shape[0], &shape[0] + L, r.begin());
539 return r;
540}
541} // namespace detail
542
547inline std::string version()
548{
549 return detail::unquote(std::string(PRRNG_QUOTE(PRRNG_VERSION)));
550}
551
563inline std::vector<std::string> version_dependencies()
564{
565 std::vector<std::string> ret;
566
567 ret.push_back("prrng=" + version());
568
569 ret.push_back(
570 "xtensor=" + detail::unquote(std::string(PRRNG_QUOTE(XTENSOR_VERSION_MAJOR))) + "." +
571 detail::unquote(std::string(PRRNG_QUOTE(XTENSOR_VERSION_MINOR))) + "." +
572 detail::unquote(std::string(PRRNG_QUOTE(XTENSOR_VERSION_PATCH)))
573 );
574
575#ifdef XSIMD_VERSION_MAJOR
576 ret.push_back(
577 "xsimd=" + detail::unquote(std::string(PRRNG_QUOTE(XSIMD_VERSION_MAJOR))) + "." +
578 detail::unquote(std::string(PRRNG_QUOTE(XSIMD_VERSION_MINOR))) + "." +
579 detail::unquote(std::string(PRRNG_QUOTE(XSIMD_VERSION_PATCH)))
580 );
581#endif
582
583#ifdef XTL_VERSION_MAJOR
584 ret.push_back(
585 "xtl=" + detail::unquote(std::string(PRRNG_QUOTE(XTL_VERSION_MAJOR))) + "." +
586 detail::unquote(std::string(PRRNG_QUOTE(XTL_VERSION_MINOR))) + "." +
587 detail::unquote(std::string(PRRNG_QUOTE(XTL_VERSION_PATCH)))
588 );
589#endif
590
591#if defined(XTENSOR_PYTHON_VERSION_MAJOR)
592 ret.push_back(
593 "xtensor-python=" +
594 detail::unquote(std::string(PRRNG_QUOTE(XTENSOR_PYTHON_VERSION_MAJOR))) + "." +
595 detail::unquote(std::string(PRRNG_QUOTE(XTENSOR_PYTHON_VERSION_MINOR))) + "." +
596 detail::unquote(std::string(PRRNG_QUOTE(XTENSOR_PYTHON_VERSION_PATCH)))
597 );
598#endif
599
600#ifdef BOOST_VERSION
601 ret.push_back(
602 "boost=" + detail::unquote(std::to_string(BOOST_VERSION / 100000)) + "." +
603 detail::unquote(std::to_string((BOOST_VERSION / 100) % 1000)) + "." +
604 detail::unquote(std::to_string(BOOST_VERSION % 100))
605 );
606#endif
607
608 std::sort(ret.begin(), ret.end(), std::greater<std::string>());
609
610 return ret;
611}
612
617inline std::vector<std::string> version_compiler()
618{
619 std::vector<std::string> ret;
620
621#ifdef __DATE__
622 std::string date = detail::unquote(std::string(PRRNG_QUOTE(__DATE__)));
623 ret.push_back("date=" + detail::replace(detail::replace(date, " ", "-"), "--", "-"));
624#endif
625
626#ifdef __APPLE__
627 ret.push_back("platform=apple");
628#endif
629
630#ifdef __MINGW32__
631 ret.push_back("platform=mingw");
632#endif
633
634#ifdef __linux__
635 ret.push_back("platform=linux");
636#endif
637
638#ifdef _WIN32
639 ret.push_back("platform=windows");
640#else
641#ifdef WIN32
642 ret.push_back("platform=windows");
643#endif
644#endif
645
646#ifdef __clang_version__
647 ret.push_back(
648 "clang=" + detail::unquote(std::string(PRRNG_QUOTE(__clang_major__))) + "." +
649 detail::unquote(std::string(PRRNG_QUOTE(__clang_minor__))) + "." +
650 detail::unquote(std::string(PRRNG_QUOTE(__clang_patchlevel__)))
651 );
652#endif
653
654#ifdef __GNUC__
655 ret.push_back(
656 "gcc=" + detail::unquote(std::string(PRRNG_QUOTE(__GNUC__))) + "." +
657 detail::unquote(std::string(PRRNG_QUOTE(__GNUC_MINOR__))) + "." +
658 detail::unquote(std::string(PRRNG_QUOTE(__GNUC_PATCHLEVEL__)))
659 );
660#endif
661
662#ifdef _MSC_VER
663 ret.push_back("msvc=" + std::to_string(_MSC_VER));
664#endif
665
666 // c++ version
667
668#ifdef __cplusplus
669 ret.push_back("c++=" + detail::unquote(std::string(PRRNG_QUOTE(__cplusplus))));
670#endif
671
672 std::sort(ret.begin(), ret.end(), std::greater<std::string>());
673
674 return ret;
675}
676
677namespace iterator {
678
693template <class It, class T, class R = size_t>
694inline R lower_bound(const It first, const It last, const T& value, R guess = 0, R proximity = 10)
695{
696 if (proximity == 0) {
697 if (value <= *(first)) {
698 return 0;
699 }
700 return std::lower_bound(first, last, value) - first - 1;
701 }
702
703 if (*(first + guess) < value && value <= *(first + guess + 1)) {
704 return guess;
705 }
706
707 R l = guess > proximity ? guess - proximity : 0;
708 R r = std::min(guess + proximity, static_cast<R>(last - first - 1));
709
710 if (*(first + l) < value && *(first + r) >= value) {
711 return std::lower_bound(first + l, first + r, value) - first - 1;
712 }
713 else if (value <= *(first)) {
714 return 0;
715 }
716 else {
717 return std::lower_bound(first, last, value) - first - 1;
718 }
719}
720
721} // namespace iterator
722
723namespace inplace {
724
734template <class T, class V, class R>
735inline void
736lower_bound(const T& matrix, const V& value, R& index, typename R::value_type proximity = 10)
737{
738 PRRNG_ASSERT(value.dimension() == matrix.dimension() - 1);
739 PRRNG_ASSERT(value.dimension() == index.dimension());
740
741 auto nd = value.dimension();
742 auto stride = matrix.shape(nd);
743 auto n = value.size();
744
745#ifdef PRRNG_ENABLE_ASSERT
746 for (decltype(nd) i = 0; i < nd; ++i) {
747 PRRNG_ASSERT(matrix.shape(i) == value.shape(i));
748 PRRNG_ASSERT(matrix.shape(i) == index.shape(i));
749 }
750#endif
751
752 for (decltype(n) i = 0; i < n; ++i) {
753 index.flat(i) = iterator::lower_bound(
754 &matrix.flat(i * stride),
755 &matrix.flat(i * stride) + stride,
756 value.flat(i),
757 index.flat(i),
758 proximity
759 );
760 }
761}
762
770template <class V, class I>
771inline void cumsum_chunk(V& cumsum, const V& delta, const I& shift)
772{
773 PRRNG_ASSERT(cumsum.dimension() >= 1);
774 PRRNG_ASSERT(cumsum.dimension() == delta.dimension());
775
776 if (delta.size() == 0) {
777 return;
778 }
779
780 size_t dim = cumsum.dimension();
781 size_t n = cumsum.shape(dim - 1);
782 size_t ndelta = delta.shape(dim - 1);
783
784 for (size_t i = 0; i < shift.size(); ++i) {
785
786 if (shift.flat(i) == 0) {
787 continue;
788 }
789
790 auto* d = &delta.flat(i * ndelta);
791 auto* c = &cumsum.flat(i * n);
792
793 if (shift.flat(i) > 0) {
794 PRRNG_ASSERT(shift.flat(i) <= static_cast<typename I::value_type>(n));
795 PRRNG_ASSERT(static_cast<typename I::value_type>(ndelta) >= shift.flat(i));
796 size_t nadd = static_cast<size_t>(shift.flat(i));
797 size_t nkeep = n - nadd;
798 auto offset = *(c + n - 1);
799 std::copy(c + n - nkeep, c + n, c);
800 std::copy(d, d + nadd, c + nkeep);
801 *(c + nkeep) += offset;
802 std::partial_sum(c + nkeep, c + n, c + nkeep);
803 }
804 else {
805 PRRNG_ASSERT(-shift.flat(i) < static_cast<typename I::value_type>(n));
806 PRRNG_ASSERT(static_cast<typename I::value_type>(ndelta) > -shift.flat(i));
807 size_t nadd = static_cast<size_t>(-shift.flat(i));
808 size_t nkeep = n - nadd;
809 auto offset = *(c);
810 std::copy(c, c + nkeep, c + nadd);
811 std::copy(d, d + nadd + 1, c);
812 std::partial_sum(c, c + nadd + 1, c);
813 offset -= *(c + nadd);
814 std::transform(c, c + nadd + 1, c, [&](auto& v) { return v + offset; });
815 }
816 }
817}
818
819} // namespace inplace
820
836template <class T, class V, class R>
837inline R lower_bound(const T& matrix, const V& value, const R& index, size_t proximity = 10)
838{
839 R ret = index;
840 inplace::lower_bound(matrix, value, ret, proximity);
841 return ret;
842}
843
853template <class T, class V, class R>
854inline R lower_bound(const T& matrix, const V& value)
855{
856 R ret = xt::zeros<typename R::value_type>(value.shape());
857 inplace::lower_bound(matrix, value, ret, 0);
858 return ret;
859}
860
897template <class V, class I>
898inline V cumsum_chunk(const V& cumsum, const V& delta, const I& shift)
899{
900 V ret = cumsum;
901 inplace::cumsum_chunk(ret, delta, shift);
902 return ret;
903}
904
905namespace detail {
906
918template <class G, class D, class P>
919void chunk_align_at(
920 G& generator,
921 const D& get_chunk,
922 const P& param,
923 double* data,
924 ptrdiff_t size,
925 ptrdiff_t* start,
926 ptrdiff_t index
927)
928{
929 ptrdiff_t ichunk = index - *start;
930
931 if (ichunk > param.buffer && ichunk < size - param.buffer) {
932 return;
933 }
934
935 using R = decltype(get_chunk(size_t{}));
936 ptrdiff_t n = size;
937 ptrdiff_t offset = 0;
938 ichunk -= param.margin;
939
940 if (ichunk < 0 && ichunk > -size) {
941 n = -ichunk;
942 std::copy(data, data + size + ichunk, data + n);
943 }
944 else if (ichunk > 0 && ichunk < size) {
945 n = ichunk;
946 offset = size - ichunk;
947 std::copy(data + n, data + size, data);
948 }
949
950 *start = index - param.margin;
951 generator.jump_to(*start + offset);
952 R extra = get_chunk(static_cast<size_t>(n));
953 generator.drawn(n);
954 std::copy(extra.begin(), extra.end(), data + offset);
955}
956
961template <class G, class D, class S, class P>
962void cumsum_align_at(
963 G& generator,
964 const D& get_chunk,
965 const S& get_sum,
966 const P& param,
967 double* data,
968 ptrdiff_t size,
969 ptrdiff_t* start,
970 ptrdiff_t index
971)
972{
973 ptrdiff_t ichunk = index - *start;
974
975 if (ichunk > param.buffer && ichunk < size - param.buffer) {
976 return;
977 }
978
979 using R = decltype(get_chunk(size_t{}));
980 ichunk -= param.margin;
981
982 if (ichunk > 0 && ichunk < size) {
983 ptrdiff_t n = ichunk;
984 ptrdiff_t offset = size - ichunk;
985 double back = data[size - 1];
986 std::copy(data + n, data + size, data);
987
988 *start = index - param.margin;
989 generator.jump_to(*start + offset);
990 R extra = get_chunk(static_cast<size_t>(n));
991 generator.drawn(n);
992
993 extra.front() += back;
994 std::partial_sum(extra.begin(), extra.end(), extra.begin());
995 std::copy(extra.begin(), extra.end(), data + offset);
996 return;
997 }
998
999 if (ichunk < 0 && ichunk > -size) {
1000 ptrdiff_t n = -ichunk;
1001 double front = data[0];
1002 std::copy(data, data + size + ichunk, data + n);
1003
1004 *start = index - param.margin;
1005 generator.jump_to(*start);
1006 R extra = get_chunk(static_cast<size_t>(n + 1));
1007 generator.drawn(n + 1);
1008
1009 std::partial_sum(extra.begin(), extra.end(), extra.begin());
1010 extra -= extra.back() - front;
1011 std::copy(extra.begin(), extra.end(), data);
1012 return;
1013 }
1014
1015 if (ichunk < 0) {
1016 ptrdiff_t n = *start - (index - param.margin + size) + 1;
1017 *start = index - param.margin;
1018 generator.jump_to(*start);
1019 R extra = get_chunk(static_cast<size_t>(size));
1020 generator.drawn(size);
1021
1022 double front = data[0] - get_sum(n);
1023 generator.drawn(n);
1024
1025 std::partial_sum(extra.begin(), extra.end(), extra.begin());
1026 extra -= extra.back() - front;
1027 std::copy(extra.begin(), extra.end(), data);
1028 return;
1029 }
1030
1031 generator.jump_to(*start + size);
1032 ptrdiff_t n = index - param.margin - (*start + size);
1033 *start = index - param.margin;
1034 double back = get_sum(n) + data[size - 1];
1035 generator.drawn(n);
1036
1037 R extra = get_chunk(static_cast<size_t>(size));
1038 generator.drawn(size);
1039 extra.front() += back;
1040 std::partial_sum(extra.begin(), extra.end(), extra.begin());
1041 std::copy(extra.begin(), extra.end(), data);
1042}
1043
1054template <class G, class D>
1055void prev(
1056 G& generator,
1057 const D& get_chunk,
1058 ptrdiff_t margin,
1059 double* data,
1060 ptrdiff_t size,
1061 ptrdiff_t* start
1062)
1063{
1064 using R = decltype(get_chunk(size_t{}));
1065
1066 generator.jump_to(*start - size + margin);
1067
1068 double front = data[0];
1069 ptrdiff_t m = size - margin + 1;
1070 R extra = get_chunk(static_cast<size_t>(m));
1071 generator.drawn(m);
1072 std::partial_sum(extra.begin(), extra.end(), extra.begin());
1073 extra -= extra.back() - front;
1074
1075 std::copy(data, data + margin, data + size - margin);
1076 std::copy(extra.begin(), extra.end() - 1, data);
1077
1078 *start -= size - margin;
1079}
1080
1091template <class G, class D>
1092void next(
1093 G& generator,
1094 const D& get_chunk,
1095 ptrdiff_t margin,
1096 double* data,
1097 ptrdiff_t size,
1098 ptrdiff_t* start
1099)
1100{
1101 using R = decltype(get_chunk(size_t{}));
1102 PRRNG_ASSERT(margin < size);
1103
1104 generator.jump_to(*start + size);
1105
1106 double back = data[size - 1];
1107 ptrdiff_t n = size - margin;
1108 R extra = get_chunk(static_cast<size_t>(n));
1109 generator.drawn(n);
1110 extra.front() += back;
1111 std::partial_sum(extra.begin(), extra.end(), extra.begin());
1112 std::copy(data + size - margin, data + size, data);
1113 std::copy(extra.begin(), extra.end(), data + margin);
1114 *start += n;
1115}
1116
1131template <class G, class D, class S, class P>
1132void align(
1133 G& generator,
1134 const D& get_chunk,
1135 const S& get_sum,
1136 const P& param,
1137 double* data,
1138 ptrdiff_t size,
1139 ptrdiff_t* start,
1140 ptrdiff_t* i,
1141 double target,
1142 bool recursive = false
1143)
1144{
1145 using R = decltype(get_chunk(size_t{}));
1146
1147 if (target > data[size - 1]) {
1148 double delta = data[size - 1] - data[0];
1149 ptrdiff_t n = size;
1150 generator.jump_to(*start + size);
1151 double back = data[size - 1];
1152 double j = (target - data[size - 1]) / delta - (double)(param.margin) / (double)(n);
1153
1154 if (j > 1) {
1155 ptrdiff_t m = static_cast<ptrdiff_t>((j - 1) * static_cast<double>(n));
1156 back += get_sum(static_cast<size_t>(m));
1157 generator.drawn(m);
1158 *start += m + size;
1159 R extra = get_chunk(static_cast<size_t>(n));
1160 generator.drawn(n);
1161 extra.front() += back;
1162 std::partial_sum(extra.begin(), extra.end(), data);
1163 return align(generator, get_chunk, get_sum, param, data, size, start, i, target, true);
1164 }
1165
1166 next(generator, get_chunk, 1 + param.margin, data, size, start);
1167 return align(generator, get_chunk, get_sum, param, data, size, start, i, target, true);
1168 }
1169
1170 if (target < data[0]) {
1171 prev(generator, get_chunk, 0, data, size, start);
1172 return align(generator, get_chunk, get_sum, param, data, size, start, i, target, true);
1173 }
1174
1175 if (recursive || *i >= size) {
1176 *i = std::lower_bound(data, data + size, target) - data - 1;
1177 }
1178 else {
1179 *i = iterator::lower_bound(data, data + size, target, *i);
1180 }
1181
1182 if (*i == param.margin) {
1183 return;
1184 }
1185 if (!recursive && param.buffer > 0 && *i >= param.buffer && *i + param.buffer < size) {
1186 return;
1187 }
1188 if (*i < param.margin) {
1189 if (!param.strict && *i >= param.min_margin) {
1190 return;
1191 }
1192 prev(generator, get_chunk, 0, data, size, start);
1193 return align(generator, get_chunk, get_sum, param, data, size, start, i, target, true);
1194 }
1195
1196 generator.jump_to(*start + size);
1197 ptrdiff_t n = *i - param.margin;
1198 R extra = get_chunk(static_cast<size_t>(n));
1199 generator.drawn(n);
1200 *start += n;
1201 *i -= n;
1202 extra.front() += data[size - 1];
1203 std::partial_sum(extra.begin(), extra.end(), extra.begin());
1204 std::copy(data + n, data + size, data);
1205 std::copy(extra.begin(), extra.end(), data + size - n);
1206}
1207
1208} // namespace detail
1209
1218public:
1225 {
1226 m_scale = scale;
1227 }
1228
1235 template <class T>
1236 T pdf(const T& x)
1237 {
1238 double rate = 1.0 / m_scale;
1239 return rate * xt::exp(-rate * x);
1240 }
1241
1248 template <class T>
1249 T cdf(const T& x)
1250 {
1251 double rate = 1.0 / m_scale;
1252 return 1.0 - xt::exp(-rate * x);
1253 }
1254
1261 template <class T>
1262 T quantile(const T& p)
1263 {
1264 return -xt::log(1.0 - p) * m_scale;
1265 }
1266
1267private:
1268 double m_scale;
1269};
1270
1283public:
1290 {
1291 m_k = k;
1292 }
1293
1300 template <class T>
1301 T pdf(const T& x)
1302 {
1303 return m_k * xt::pow(x, m_k - 1.0);
1304 }
1305
1312 template <class T>
1313 T cdf(const T& x)
1314 {
1315 return xt::pow(x, m_k);
1316 }
1317
1324 template <class T>
1325 T quantile(const T& p)
1326 {
1327 return xt::pow(1.0 - p, 1.0 / m_k);
1328 }
1329
1330private:
1331 double m_k;
1332};
1333
1344public:
1351 gamma_distribution(double k = 1, double scale = 1)
1352 {
1353 m_shape = k;
1354 m_scale = scale;
1355 }
1356
1365 template <class T>
1366 T pdf(const T& x)
1367 {
1368 using value_type = typename T::value_type;
1369
1370#if PRRNG_USE_BOOST
1371 auto f = xt::vectorize(boost::math::gamma_p_derivative<value_type, value_type>);
1372 T ret = f(m_shape, x / m_scale);
1373 return xt::where(xt::equal(x, 0), 0.0, ret);
1374#else
1375 T ret = x;
1376 ret.fill(std::numeric_limits<value_type>::quiet_NaN());
1377 return ret;
1378#endif
1379 }
1380
1389 template <class T>
1390 T cdf(const T& x)
1391 {
1392 using value_type = typename T::value_type;
1393
1394#if PRRNG_USE_BOOST
1395 auto f = xt::vectorize(boost::math::gamma_p<value_type, value_type>);
1396 return f(m_shape, x / m_scale);
1397#else
1398 auto ret = x;
1399 ret.fill(std::numeric_limits<value_type>::quiet_NaN());
1400 return ret;
1401#endif
1402 }
1403
1412 template <class T>
1413 T quantile(const T& p)
1414 {
1415 using value_type = typename T::value_type;
1416
1417#if PRRNG_USE_BOOST
1418 auto f = xt::vectorize(boost::math::gamma_p_inv<value_type, value_type>);
1419 return m_scale * f(m_shape, p);
1420#else
1421 auto ret = p;
1422 ret.fill(std::numeric_limits<value_type>::quiet_NaN());
1423 return ret;
1424#endif
1425 }
1426
1427private:
1428 double m_shape;
1429 double m_scale;
1430};
1431
1445public:
1452 pareto_distribution(double k = 1, double scale = 1)
1453 {
1454 m_k = k;
1455 m_scale = scale;
1456 PRRNG_ASSERT(m_k > 0);
1457 PRRNG_ASSERT(m_scale > 0);
1458 }
1459
1466 template <class T>
1467 T pdf(const T& x)
1468 {
1469 return m_k * std::pow(m_scale, m_k) * xt::pow(x, -(m_k + 1.0));
1470 }
1471
1478 template <class T>
1479 T cdf(const T& x)
1480 {
1481 return 1.0 - std::pow(m_scale, m_k) * xt::pow(x, -m_k);
1482 }
1483
1490 template <class T>
1491 T quantile(const T& p)
1492 {
1493 return m_scale * xt::pow(1.0 - p, -1.0 / m_k);
1494 }
1495
1496private:
1497 double m_k;
1498 double m_scale;
1499};
1500
1510public:
1517 weibull_distribution(double k = 1, double scale = 1)
1518 {
1519 m_shape = k;
1520 m_scale = scale;
1521 }
1522
1529 template <class T>
1530 T pdf(const T& x)
1531 {
1532 T ret = xt::exp(-xt::pow(x / m_scale, m_shape));
1533 ret *= xt::pow(x / m_scale, m_shape - 1.0) * m_shape / m_scale;
1534
1535 if (xt::any(xt::equal(x, 0))) {
1536 if (m_shape == 1) {
1537 ret = xt::where(xt::equal(x, 0), 1.0 / m_scale, ret);
1538 }
1539 else if (m_shape > 1) {
1540 ret = xt::where(xt::equal(x, 0), 0.0, ret);
1541 }
1542 else {
1543 throw std::runtime_error("[prrng::weibull_distribution::pdf] Overflow error");
1544 }
1545 }
1546
1547 return ret;
1548 }
1549
1558 template <class T>
1559 T cdf(const T& x)
1560 {
1561 return -xt::expm1(-xt::pow(x / m_scale, m_shape));
1562 }
1563
1573 template <class T>
1574 T quantile(const T& p)
1575 {
1576 return m_scale * xt::pow(-xt::log1p(-p), 1.0 / m_shape);
1577 }
1578
1579private:
1580 double m_shape;
1581 double m_scale;
1582};
1583
1594public:
1601 normal_distribution(double mu = 0, double sigma = 1)
1602 {
1603 m_mu = mu;
1604 m_sigma = sigma;
1605 m_sigma_sqrt2 = m_sigma * std::sqrt(2.0);
1606 }
1607
1614 template <class T>
1615 T pdf(const T& x)
1616 {
1617 return xt::exp(-0.5 * xt::pow((x - m_mu) / m_sigma, 2.0)) /
1618 (m_sigma_sqrt2 * std::sqrt(xt::numeric_constants<double>::PI));
1619 }
1620
1633 template <class T>
1634 T cdf(const T& x)
1635 {
1636 return 0.5 * (1.0 + xt::erf((x - m_mu) / m_sigma_sqrt2));
1637 }
1638
1648 template <class T>
1649 T quantile(const T& p)
1650 {
1651 using value_type = typename detail::get_value_type<T>::type;
1652
1653#if PRRNG_USE_BOOST
1654 auto f = xt::vectorize(boost::math::erf_inv<value_type>);
1655 return m_mu + m_sigma_sqrt2 * f(2.0 * p - 1.0);
1656#else
1657 static_assert(xt::is_xexpression<T>::value, "T must be an xexpression");
1658 auto ret = p;
1659 ret.fill(std::numeric_limits<value_type>::quiet_NaN());
1660 return ret;
1661#endif
1662 }
1663
1664private:
1665 double m_mu;
1666 double m_sigma;
1667 double m_sigma_sqrt2;
1668};
1669
1689template <class Derived>
1691public:
1697 double cumsum_random(size_t n)
1698 {
1699 double ret = 0.0;
1700 for (size_t i = 0; i < n; ++i) {
1701 ret += static_cast<Derived*>(this)->next_double();
1702 }
1703 return ret;
1704 }
1705
1713 double cumsum_delta(size_t n, double scale = 1)
1714 {
1715 return static_cast<double>(n) * scale;
1716 }
1717
1725 double cumsum_exponential(size_t n, double scale = 1)
1726 {
1727 double ret = 0.0;
1728 for (size_t i = 0; i < n; ++i) {
1729 ret -= std::log(1.0 - static_cast<Derived*>(this)->next_double());
1730 }
1731 return scale * ret;
1732 }
1733
1741 double cumsum_power(size_t n, double k = 1)
1742 {
1743 double ret = 0.0;
1744 double exponent = 1.0 / k;
1745 for (size_t i = 0; i < n; ++i) {
1746 ret += std::pow(1.0 - static_cast<Derived*>(this)->next_double(), exponent);
1747 }
1748 return ret;
1749 }
1750
1759 double cumsum_gamma(size_t n, double k = 1, double scale = 1)
1760 {
1761#if PRRNG_USE_BOOST
1762 double ret = 0.0;
1763 for (size_t i = 0; i < n; ++i) {
1764 ret += boost::math::gamma_p_inv<double, double>(
1765 k, static_cast<Derived*>(this)->next_double()
1766 );
1767 }
1768 return scale * ret;
1769#else
1770 return std::numeric_limits<double>::quiet_NaN();
1771#endif
1772 }
1773
1782 double cumsum_pareto(size_t n, double k = 1, double scale = 1)
1783 {
1784 double ret = 0.0;
1785 double exponent = -1.0 / k;
1786 for (size_t i = 0; i < n; ++i) {
1787 ret += std::pow(1.0 - static_cast<Derived*>(this)->next_double(), exponent);
1788 }
1789 return scale * ret;
1790 }
1791
1800 double cumsum_weibull(size_t n, double k = 1, double scale = 1)
1801 {
1802 double ret = 0.0;
1803 double k_inv = 1.0 / k;
1804 for (size_t i = 0; i < n; ++i) {
1805 ret += std::pow(-std::log(1.0 - static_cast<Derived*>(this)->next_double()), k_inv);
1806 }
1807 return scale * ret;
1808 }
1809
1818 double cumsum_normal(size_t n, double mu = 0, double sigma = 1)
1819 {
1820#if PRRNG_USE_BOOST
1821 double ret = 0.0;
1822 for (size_t i = 0; i < n; ++i) {
1823 ret += boost::math::erf_inv<double>(
1824 2.0 * static_cast<Derived*>(this)->next_double() - 1.0
1825 );
1826 }
1827 return static_cast<double>(n) * mu + sigma * std::sqrt(2.0) * ret;
1828#else
1829 return std::numeric_limits<double>::quiet_NaN();
1830#endif
1831 }
1832
1843 template <typename Iterator>
1844 void shuffle(Iterator begin, Iterator end)
1845 {
1846 for (Iterator it = end - 1; it > begin; --it) {
1847 std::iter_swap(
1848 it, begin + static_cast<Derived*>(this)->next_uint32((uint32_t)(it - begin + 1))
1849 );
1850 }
1851 }
1852
1861 template <class P>
1862 auto decide(const P& p) -> typename detail::return_type<bool, P>::type
1863 {
1864 using R = typename detail::return_type<bool, P>::type;
1865 R ret = xt::empty<bool>(p.shape());
1866 this->decide(p, ret);
1867 return ret;
1868 }
1869
1873 template <class P, class R>
1874 R decide(const P& p)
1875 {
1876 using value_type = typename detail::get_value_type<R>::type;
1877 R ret = xt::empty<value_type>(p.shape());
1878 this->decide(p, ret);
1879 return ret;
1880 }
1881
1890 template <class P, class R>
1891 void decide(const P& p, R& ret)
1892 {
1893 PRRNG_ASSERT(xt::has_shape(p, ret.shape()));
1894 using value_type = typename detail::get_value_type<R>::type;
1895
1896 for (size_t i = 0; i < p.size(); ++i) {
1897 if (static_cast<Derived*>(this)->next_double() < p.flat(i)) {
1898 ret.flat(i) = static_cast<value_type>(true);
1899 }
1900 else {
1901 ret.flat(i) = static_cast<value_type>(false);
1902 }
1903 }
1904 }
1905
1915 template <class P, class T>
1916 auto decide_masked(const P& p, const T& mask) -> typename detail::return_type<bool, P>::type
1917 {
1918 using R = typename detail::return_type<bool, P>::type;
1919 R ret = xt::empty<bool>(p.shape());
1920 this->decide_masked(p, mask, ret);
1921 return ret;
1922 }
1923
1927 template <class P, class T, class R>
1928 R decide_masked(const P& p, const T& mask)
1929 {
1930 using value_type = typename detail::get_value_type<R>::type;
1931 R ret = xt::empty<value_type>(p.shape());
1932 this->decide_masked(p, mask, ret);
1933 return ret;
1934 }
1935
1945 template <class P, class T, class R>
1946 void decide_masked(const P& p, const T& mask, R& ret)
1947 {
1948 PRRNG_ASSERT(xt::has_shape(p, ret.shape()));
1949 using value_type = typename detail::get_value_type<R>::type;
1950
1951 for (size_t i = 0; i < p.size(); ++i) {
1952 if (mask.flat(i)) {
1953 ret.flat(i) = static_cast<value_type>(false);
1954 }
1955 else if (static_cast<Derived*>(this)->next_double() < p.flat(i)) {
1956 ret.flat(i) = static_cast<value_type>(true);
1957 }
1958 else {
1959 ret.flat(i) = static_cast<value_type>(false);
1960 }
1961 }
1962 }
1963
1969 double random()
1970 {
1971 return static_cast<Derived*>(this)->next_double();
1972 }
1973
1980 template <class S>
1981 auto random(const S& shape) -> typename detail::return_type<double, S>::type
1982 {
1983 using R = typename detail::return_type<double, S>::type;
1984 return this->random_impl<R>(shape);
1985 }
1986
1991 template <class R, class S>
1992 R random(const S& shape)
1993 {
1994 return this->random_impl<R>(shape);
1995 }
1996
2000 template <class I, std::size_t L>
2001 auto random(const I (&shape)[L]) -> typename detail::return_type_fixed<double, L>::type
2002 {
2003 using R = typename detail::return_type_fixed<double, L>::type;
2004 return this->random_impl<R>(shape);
2005 }
2006
2011 template <class R, class I, std::size_t L>
2012 R random(const I (&shape)[L])
2013 {
2014 return this->random_impl<R>(shape);
2015 }
2016
2023 template <typename T>
2024 T randint(T high)
2025 {
2026 PRRNG_ASSERT(high >= 0);
2027 PRRNG_ASSERT(static_cast<uint32_t>(high) < std::numeric_limits<uint32_t>::max());
2028
2029 uint32_t ret;
2030 this->draw_list_uint32(&ret, static_cast<uint32_t>(high), 1);
2031 return static_cast<T>(ret);
2032 }
2033
2041 template <class S, typename T>
2042 auto randint(const S& shape, T high) -> typename detail::return_type<T, S>::type
2043 {
2044 using R = typename detail::return_type<T, S>::type;
2045 return this->randint_impl<R>(shape, high);
2046 }
2047
2052 template <class R, class S, typename T>
2053 R randint(const S& shape, T high)
2054 {
2055 return this->randint_impl<R>(shape, high);
2056 }
2057
2061 template <class I, std::size_t L, typename T>
2062 auto randint(const I (&shape)[L], T high) -> typename detail::return_type_fixed<T, L>::type
2063 {
2064 using R = typename detail::return_type_fixed<T, L>::type;
2065 return this->randint_impl<R>(shape, high);
2066 }
2067
2072 template <class R, class I, std::size_t L, typename T>
2073 R randint(const I (&shape)[L], T high)
2074 {
2075 return this->randint_impl<R>(shape, high);
2076 }
2077
2086 template <class S, typename T, typename U>
2087 auto randint(const S& shape, T low, U high) -> typename detail::return_type<T, S>::type
2088 {
2089 using R = typename detail::return_type<T, S>::type;
2090 return this->randint_impl<R>(shape, low, high);
2091 }
2092
2097 template <class R, class S, typename T, typename U>
2098 R randint(const S& shape, T low, U high)
2099 {
2100 return this->randint_impl<R>(shape, low, high);
2101 }
2102
2106 template <class I, std::size_t L, typename T, typename U>
2107 auto randint(const I (&shape)[L], T low, U high) ->
2108 typename detail::return_type_fixed<T, L>::type
2109 {
2110 using R = typename detail::return_type_fixed<T, L>::type;
2111 return this->randint_impl<R>(shape, low, high);
2112 }
2113
2118 template <class R, class I, std::size_t L, typename T, typename U>
2119 R randint(const I (&shape)[L], T low, U high)
2120 {
2121 return this->randint_impl<R>(shape, low, high);
2122 }
2123
2130 double delta(double scale = 1)
2131 {
2132 return scale;
2133 }
2134
2144 template <class S>
2145 auto delta(const S& shape, double scale = 1) -> typename detail::return_type<double, S>::type
2146 {
2147 using R = typename detail::return_type<double, S>::type;
2148 return this->delta_impl<R>(shape, scale);
2149 }
2150
2155 template <class R, class S>
2156 R delta(const S& shape, double scale = 1)
2157 {
2158 return this->delta_impl<R>(shape, scale);
2159 }
2160
2164 template <class I, std::size_t L>
2165 auto delta(const I (&shape)[L], double scale = 1) ->
2166 typename detail::return_type_fixed<double, L>::type
2167 {
2168 using R = typename detail::return_type_fixed<double, L>::type;
2169 return this->delta_impl<R>(shape, scale);
2170 }
2171
2176 template <class R, class I, std::size_t L>
2177 R delta(const I (&shape)[L], double scale = 1)
2178 {
2179 return this->delta_impl<R>(shape, scale);
2180 }
2181
2188 double exponential(double scale = 1)
2189 {
2190 return -std::log(1.0 - static_cast<Derived*>(this)->next_double()) * scale;
2191 }
2192
2200 template <class S>
2201 auto exponential(const S& shape, double scale = 1) ->
2202 typename detail::return_type<double, S>::type
2203 {
2204 using R = typename detail::return_type<double, S>::type;
2205 return this->exponential_impl<R>(shape, scale);
2206 }
2207
2212 template <class R, class S>
2213 R exponential(const S& shape, double scale = 1)
2214 {
2215 return this->exponential_impl<R>(shape, scale);
2216 }
2217
2221 template <class I, std::size_t L>
2222 auto exponential(const I (&shape)[L], double scale = 1) ->
2223 typename detail::return_type_fixed<double, L>::type
2224 {
2225 using R = typename detail::return_type_fixed<double, L>::type;
2226 return this->exponential_impl<R>(shape, scale);
2227 }
2228
2233 template <class R, class I, std::size_t L>
2234 R exponential(const I (&shape)[L], double scale = 1)
2235 {
2236 return this->exponential_impl<R>(shape, scale);
2237 }
2238
2245 double power(double k = 1)
2246 {
2247 return std::pow(1.0 - static_cast<Derived*>(this)->next_double(), 1.0 / k);
2248 }
2249
2257 template <class S>
2258 auto power(const S& shape, double k = 1) -> typename detail::return_type<double, S>::type
2259 {
2260 using R = typename detail::return_type<double, S>::type;
2261 return this->power_impl<R>(shape, k);
2262 }
2263
2268 template <class R, class S>
2269 R power(const S& shape, double k = 1)
2270 {
2271 return this->power_impl<R>(shape, k);
2272 }
2273
2277 template <class I, std::size_t L>
2278 auto power(const I (&shape)[L], double k = 1) ->
2279 typename detail::return_type_fixed<double, L>::type
2280 {
2281 using R = typename detail::return_type_fixed<double, L>::type;
2282 return this->power_impl<R>(shape, k);
2283 }
2284
2289 template <class R, class I, std::size_t L>
2290 R power(const I (&shape)[L], double k = 1)
2291 {
2292 return this->power_impl<R>(shape, k);
2293 }
2294
2302 double gamma(double k = 1, double scale = 1)
2303 {
2304#if PRRNG_USE_BOOST
2305 return scale * boost::math::gamma_p_inv<double, double>(
2306 k, static_cast<Derived*>(this)->next_double()
2307 );
2308#else
2309 return std::numeric_limits<double>::quiet_NaN();
2310#endif
2311 }
2312
2322 template <class S>
2323 auto gamma(const S& shape, double k = 1, double scale = 1) ->
2324 typename detail::return_type<double, S>::type
2325 {
2326 using R = typename detail::return_type<double, S>::type;
2327 return this->gamma_impl<R>(shape, k, scale);
2328 }
2329
2334 template <class R, class S>
2335 R gamma(const S& shape, double k = 1, double scale = 1)
2336 {
2337 return this->gamma_impl<R>(shape, k, scale);
2338 }
2339
2343 template <class I, std::size_t L>
2344 auto gamma(const I (&shape)[L], double k = 1, double scale = 1) ->
2345 typename detail::return_type_fixed<double, L>::type
2346 {
2347 using R = typename detail::return_type_fixed<double, L>::type;
2348 return this->gamma_impl<R>(shape, k, scale);
2349 }
2350
2355 template <class R, class I, std::size_t L>
2356 R gamma(const I (&shape)[L], double k = 1, double scale = 1)
2357 {
2358 return this->gamma_impl<R>(shape, k, scale);
2359 }
2360
2368 double pareto(double k = 1, double scale = 1)
2369 {
2370 return scale * std::pow(1.0 - static_cast<Derived*>(this)->next_double(), -1.0 / k);
2371 }
2372
2381 template <class S>
2382 auto pareto(const S& shape, double k = 1, double scale = 1) ->
2383 typename detail::return_type<double, S>::type
2384 {
2385 using R = typename detail::return_type<double, S>::type;
2386 return this->pareto_impl<R>(shape, k, scale);
2387 }
2388
2393 template <class R, class S>
2394 R pareto(const S& shape, double k = 1, double scale = 1)
2395 {
2396 return this->pareto_impl<R>(shape, k, scale);
2397 }
2398
2402 template <class I, std::size_t L>
2403 auto pareto(const I (&shape)[L], double k = 1, double scale = 1) ->
2404 typename detail::return_type_fixed<double, L>::type
2405 {
2406 using R = typename detail::return_type_fixed<double, L>::type;
2407 return this->pareto_impl<R>(shape, k, scale);
2408 }
2409
2414 template <class R, class I, std::size_t L>
2415 R pareto(const I (&shape)[L], double k = 1, double scale = 1)
2416 {
2417 return this->pareto_impl<R>(shape, k, scale);
2418 }
2419
2427 double weibull(double k = 1, double scale = 1)
2428 {
2429 return scale *
2430 std::pow(-std::log(1.0 - static_cast<Derived*>(this)->next_double()), 1.0 / k);
2431 }
2432
2441 template <class S>
2442 auto weibull(const S& shape, double k = 1, double scale = 1) ->
2443 typename detail::return_type<double, S>::type
2444 {
2445 using R = typename detail::return_type<double, S>::type;
2446 return this->weibull_impl<R>(shape, k, scale);
2447 }
2448
2453 template <class R, class S>
2454 R weibull(const S& shape, double k = 1, double scale = 1)
2455 {
2456 return this->weibull_impl<R>(shape, k, scale);
2457 }
2458
2462 template <class I, std::size_t L>
2463 auto weibull(const I (&shape)[L], double k = 1, double scale = 1) ->
2464 typename detail::return_type_fixed<double, L>::type
2465 {
2466 using R = typename detail::return_type_fixed<double, L>::type;
2467 return this->weibull_impl<R>(shape, k, scale);
2468 }
2469
2474 template <class R, class I, std::size_t L>
2475 R weibull(const I (&shape)[L], double k = 1, double scale = 1)
2476 {
2477 return this->weibull_impl<R>(shape, k, scale);
2478 }
2479
2487 double normal(double mu = 0, double sigma = 1)
2488 {
2489#if PRRNG_USE_BOOST
2490 return mu + sigma * std::sqrt(2.0) *
2491 boost::math::erf_inv<double>(
2492 2.0 * static_cast<Derived*>(this)->next_positive_double() - 1.0
2493 );
2494#else
2495 return std::numeric_limits<double>::quiet_NaN();
2496#endif
2497 }
2498
2507 template <class S>
2508 auto normal(const S& shape, double mu = 0, double sigma = 1) ->
2509 typename detail::return_type<double, S>::type
2510 {
2511 using R = typename detail::return_type<double, S>::type;
2512 return this->normal_impl<R>(shape, mu, sigma);
2513 }
2514
2519 template <class R, class S>
2520 R normal(const S& shape, double mu = 0, double sigma = 1)
2521 {
2522 return this->normal_impl<R>(shape, mu, sigma);
2523 }
2524
2528 template <class I, std::size_t L>
2529 auto normal(const I (&shape)[L], double mu = 0, double sigma = 1) ->
2530 typename detail::return_type_fixed<double, L>::type
2531 {
2532 using R = typename detail::return_type_fixed<double, L>::type;
2533 return this->normal_impl<R>(shape, mu, sigma);
2534 }
2535
2540 template <class R, class I, std::size_t L>
2541 R normal(const I (&shape)[L], double mu = 0, double sigma = 1)
2542 {
2543 return this->normal_impl<R>(shape, mu, sigma);
2544 }
2545
2553 double draw(
2555 std::vector<double> parameters = std::vector<double>{},
2556 bool append_default = true
2557 )
2558 {
2559 if (append_default) {
2560 parameters = default_parameters(distribution, parameters);
2561 }
2562 else {
2563 PRRNG_ASSERT(detail::has_correct_parameters(distribution, parameters));
2564 }
2565
2566 switch (distribution) {
2568 return this->random() * parameters[0] + parameters[1];
2570 return this->delta(parameters[0]) + parameters[1];
2572 return this->exponential(parameters[0]) + parameters[1];
2574 return this->power(parameters[0]) + parameters[1];
2576 return this->pareto(parameters[0], parameters[1]) + parameters[2];
2578 return this->weibull(parameters[0], parameters[1]) + parameters[2];
2580 return this->gamma(parameters[0], parameters[1]) + parameters[2];
2582 return this->normal(parameters[0], parameters[1]) + parameters[2];
2584 throw std::runtime_error("Unknown distribution");
2585 }
2586
2587 throw std::runtime_error("Unknown distribution");
2588 }
2589
2598 template <class R, class S>
2600 const S& shape,
2602 std::vector<double> parameters = std::vector<double>{},
2603 bool append_default = true
2604 )
2605 {
2606 if (append_default) {
2607 parameters = default_parameters(distribution, parameters);
2608 }
2609 else {
2610 PRRNG_ASSERT(detail::has_correct_parameters(distribution, parameters));
2611 }
2612
2613 switch (distribution) {
2615 return this->random<R>(shape) * parameters[0] + parameters[1];
2617 return this->delta<R>(shape, parameters[0]) + parameters[1];
2619 return this->exponential<R>(shape, parameters[0]) + parameters[1];
2621 return this->power<R>(shape, parameters[0]) + parameters[1];
2623 return this->pareto<R>(shape, parameters[0], parameters[1]) + parameters[2];
2625 return this->weibull<R>(shape, parameters[0], parameters[1]) + parameters[2];
2627 return this->gamma<R>(shape, parameters[0], parameters[1]) + parameters[2];
2629 return this->normal<R>(shape, parameters[0], parameters[1]) + parameters[2];
2631 throw std::runtime_error("Unknown distribution");
2632 }
2633
2634 throw std::runtime_error("Unknown distribution");
2635 }
2636
2645 double cumsum(
2646 size_t n,
2648 std::vector<double> parameters = std::vector<double>{},
2649 bool append_default = true
2650 )
2651 {
2652 if (append_default) {
2653 parameters = default_parameters(distribution, parameters);
2654 }
2655 else {
2656 PRRNG_ASSERT(detail::has_correct_parameters(distribution, parameters));
2657 }
2658
2659 double m = static_cast<double>(n);
2660
2661 switch (distribution) {
2663 return this->cumsum_random(n) * parameters[0] + m * parameters[1];
2665 return this->cumsum_delta(n, parameters[0]) + m * parameters[1];
2667 return this->cumsum_exponential(n, parameters[0]) + m * parameters[1];
2669 return this->cumsum_power(n, parameters[0]) + m * parameters[1];
2671 return this->cumsum_pareto(n, parameters[0], parameters[1]) + m * parameters[2];
2673 return this->cumsum_weibull(n, parameters[0], parameters[1]) + m * parameters[2];
2675 return this->cumsum_gamma(n, parameters[0], parameters[1]) + m * parameters[2];
2677 return this->cumsum_normal(n, parameters[0], parameters[1]) + m * parameters[2];
2679 throw std::runtime_error("Unknown distribution");
2680 }
2681
2682 throw std::runtime_error("Unknown distribution");
2683 }
2684
2685private:
2686 void draw_list_double(double* data, size_t n)
2687 {
2688 for (size_t i = 0; i < n; ++i) {
2689 data[i] = static_cast<Derived*>(this)->next_double();
2690 }
2691 }
2692
2693 void draw_list_positive_double(double* data, size_t n)
2694 {
2695 for (size_t i = 0; i < n; ++i) {
2696 data[i] = static_cast<Derived*>(this)->next_positive_double();
2697 }
2698 }
2699
2700 void draw_list_uint32(uint32_t* data, uint32_t bound, size_t n)
2701 {
2702 for (size_t i = 0; i < n; ++i) {
2703 data[i] = static_cast<Derived*>(this)->next_uint32(bound);
2704 }
2705 }
2706
2707 template <class R, class S>
2708 R positive_random_impl(const S& shape)
2709 {
2710 static_assert(
2711 std::is_same<typename detail::allocate_return<R>::value_type, double>::value,
2712 "Return value_type must be double"
2713 );
2714
2715 detail::allocate_return<R> ret(shape);
2716 this->draw_list_positive_double(ret.data(), ret.size());
2717 return std::move(ret.value);
2718 }
2719
2720 template <class R, class S>
2721 R random_impl(const S& shape)
2722 {
2723 static_assert(
2724 std::is_same<typename detail::allocate_return<R>::value_type, double>::value,
2725 "Return value_type must be double"
2726 );
2727
2728 detail::allocate_return<R> ret(shape);
2729 this->draw_list_double(ret.data(), ret.size());
2730 return std::move(ret.value);
2731 }
2732
2733 template <class R, class S, typename T>
2734 R randint_impl(const S& shape, T high)
2735 {
2736 static_assert(
2737 std::numeric_limits<typename detail::allocate_return<R>::value_type>::max() >=
2738 std::numeric_limits<T>::max(),
2739 "Return value_type must must be able to accommodate the bound"
2740 );
2741
2742 PRRNG_ASSERT(high >= 0);
2743 PRRNG_ASSERT(static_cast<uint32_t>(high) < std::numeric_limits<uint32_t>::max());
2744
2745 detail::allocate_return<R> ret(shape);
2746 std::vector<uint32_t> tmp(ret.size());
2747 this->draw_list_uint32(&tmp.front(), static_cast<uint32_t>(high), ret.size());
2748 std::copy(tmp.begin(), tmp.end(), ret.data());
2749 return std::move(ret.value);
2750 }
2751
2752 template <class R, class S, typename T, typename U>
2753 R randint_impl(const S& shape, T low, U high)
2754 {
2755 static_assert(
2756 std::numeric_limits<typename detail::allocate_return<R>::value_type>::min() >=
2757 std::numeric_limits<T>::min(),
2758 "Return value_type must must be able to accommodate the bound"
2759 );
2760
2761 static_assert(
2762 std::numeric_limits<typename detail::allocate_return<R>::value_type>::max() >=
2763 std::numeric_limits<T>::max(),
2764 "Return value_type must must be able to accommodate the bound"
2765 );
2766
2767 static_assert(
2768 std::numeric_limits<typename detail::allocate_return<R>::value_type>::min() >=
2769 std::numeric_limits<U>::min(),
2770 "Return value_type must must be able to accommodate the bound"
2771 );
2772
2773 static_assert(
2774 std::numeric_limits<typename detail::allocate_return<R>::value_type>::max() >=
2775 std::numeric_limits<U>::max(),
2776 "Return value_type must must be able to accommodate the bound"
2777 );
2778
2779 PRRNG_ASSERT(high - low >= 0);
2780 PRRNG_ASSERT(static_cast<uint32_t>(high - low) < std::numeric_limits<uint32_t>::max());
2781
2782 detail::allocate_return<R> ret(shape);
2783 std::vector<uint32_t> tmp(ret.size());
2784 this->draw_list_uint32(&tmp.front(), static_cast<uint32_t>(high - low), ret.size());
2785 std::copy(tmp.begin(), tmp.end(), ret.data());
2786 return ret.value + low;
2787 }
2788
2789 template <class R, class S>
2790 R delta_impl(const S& shape, double scale)
2791 {
2792 detail::allocate_return<R> ret(shape);
2793 ret.value.fill(scale);
2794 return std::move(ret.value);
2795 }
2796
2797 template <class R, class S>
2798 R exponential_impl(const S& shape, double scale)
2799 {
2800 R r = this->random_impl<R>(shape);
2801 return exponential_distribution(scale).quantile(r);
2802 }
2803
2804 template <class R, class S>
2805 R power_impl(const S& shape, double k)
2806 {
2807 R r = this->random_impl<R>(shape);
2808 return power_distribution(k).quantile(r);
2809 }
2810
2811 template <class R, class S>
2812 R gamma_impl(const S& shape, double k, double scale)
2813 {
2814 R r = this->random_impl<R>(shape);
2815 return gamma_distribution(k, scale).quantile(r);
2816 }
2817
2818 template <class R, class S>
2819 R pareto_impl(const S& shape, double k, double scale)
2820 {
2821 R r = this->random_impl<R>(shape);
2822 return pareto_distribution(k, scale).quantile(r);
2823 }
2824
2825 template <class R, class S>
2826 R weibull_impl(const S& shape, double k, double scale)
2827 {
2828 R r = this->random_impl<R>(shape);
2829 return weibull_distribution(k, scale).quantile(r);
2830 }
2831
2832 template <class R, class S>
2833 R normal_impl(const S& shape, double mu, double sigma)
2834 {
2835 R r = this->positive_random_impl<R>(shape);
2836 return normal_distribution(mu, sigma).quantile(r);
2837 }
2838};
2839
2873class pcg32 : public GeneratorBase<pcg32> {
2874public:
2881 template <typename T = uint64_t, typename S = uint64_t>
2883 {
2884 static_assert(sizeof(uint64_t) >= sizeof(T), "Down-casting not allowed.");
2885 static_assert(sizeof(uint64_t) >= sizeof(S), "Down-casting not allowed.");
2886 this->seed(static_cast<uint64_t>(initstate), static_cast<uint64_t>(initseq));
2887 }
2888
2896 {
2899
2900 m_state = 0U;
2901 m_inc = (initseq << 1u) | 1u;
2902 (*this)();
2903 m_state += initstate;
2904 (*this)();
2905 }
2906
2915 uint32_t operator()()
2916 {
2917 uint64_t oldstate = m_state;
2918 m_state = oldstate * PRRNG_PCG32_MULT + m_inc;
2919 uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
2920 uint32_t rot = oldstate >> 59u;
2921 return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
2922 }
2923
2932 uint32_t next_uint32()
2933 {
2934 return (*this)();
2935 }
2936
2945 uint32_t next_uint32(uint32_t bound)
2946 {
2947 // To avoid bias, we need to make the range of the RNG a multiple of
2948 // bound, which we do by dropping output less than a threshold.
2949 // A naive scheme to calculate the threshold would be to do
2950 //
2951 // uint32_t threshold = 0x100000000ull % bound;
2952 //
2953 // but 64-bit div/mod is slower than 32-bit div/mod (especially on
2954 // 32-bit platforms). In essence, we do
2955 //
2956 // uint32_t threshold = (0x100000000ull-bound) % bound;
2957 //
2958 // because this version will calculate the same modulus, but the LHS
2959 // value is less than 2^32.
2960
2961 uint32_t threshold = (~bound + 1u) % bound;
2962
2963 // Uniformity guarantees that this loop will terminate. In practice, it
2964 // should usually terminate quickly; on average (assuming all bounds are
2965 // equally likely), 82.25% of the time, we can expect it to require just
2966 // one iteration. In the worst case, someone passes a bound of 2^31 + 1
2967 // (i.e., 2147483649), which invalidates almost 50% of the range. In
2968 // practice, bounds are typically small and only a tiny amount of the range
2969 // is eliminated.
2970 for (;;) {
2971 uint32_t r = next_uint32();
2972 if (r >= threshold) {
2973 return r % bound;
2974 }
2975 }
2976 }
2977
2986 {
2987 // Trick from MTGP: generate an uniformly distributed
2988 // single precision number in [1,2) and subtract 1.
2989 union {
2990 uint32_t u;
2991 float f;
2992 } x;
2993 x.u = (next_uint32() >> 9) | 0x3f800000u;
2994 return x.f - 1.0f;
2995 }
2996
3009 {
3010 union {
3011 uint64_t u;
3012 double d;
3013 } x;
3014
3015 x.u = ((uint64_t)next_uint32() << 20) | 0x3ff0000000000000ULL;
3016
3017 return x.d - 1.0;
3018 }
3019
3025 {
3026 union {
3027 uint64_t u;
3028 double d;
3029 } x;
3030
3031 x.u = ((uint64_t)next_uint32() << 20) | 0x3ff0000000000000ULL;
3032
3033 if (x.u == 0x3ff0000000000000ULL) {
3034 x.u += 1;
3035 }
3036
3037 return x.d - 1.0;
3038 }
3039
3046 uint64_t state() const
3047 {
3048 return m_state;
3049 }
3050
3057 template <typename R>
3059 {
3060 static_assert(
3061 std::numeric_limits<R>::max() >= std::numeric_limits<decltype(m_state)>::max(),
3062 "Down-casting not allowed."
3063 );
3064
3065 static_assert(
3066 std::numeric_limits<R>::min() <= std::numeric_limits<decltype(m_state)>::min(),
3067 "Down-casting not allowed."
3068 );
3069
3070 return static_cast<R>(m_state);
3071 }
3072
3078 uint64_t initstate() const
3079 {
3080 return m_initstate;
3081 }
3082
3089 template <typename R>
3090 R initstate() const
3091 {
3092 static_assert(
3093 std::numeric_limits<R>::max() >= std::numeric_limits<decltype(m_initstate)>::max(),
3094 "Down-casting not allowed."
3095 );
3096
3097 static_assert(
3098 std::numeric_limits<R>::min() <= std::numeric_limits<decltype(m_initstate)>::min(),
3099 "Down-casting not allowed."
3100 );
3101
3102 return static_cast<R>(m_initstate);
3103 }
3104
3110 uint64_t initseq() const
3111 {
3112 return m_initseq;
3113 }
3114
3121 template <typename R>
3122 R initseq() const
3123 {
3124 static_assert(
3125 std::numeric_limits<R>::max() >= std::numeric_limits<decltype(m_initseq)>::max(),
3126 "Down-casting not allowed."
3127 );
3128
3129 static_assert(
3130 std::numeric_limits<R>::min() <= std::numeric_limits<decltype(m_initseq)>::min(),
3131 "Down-casting not allowed."
3132 );
3133
3134 return static_cast<R>(m_initseq);
3135 }
3136
3143 template <typename T>
3145 {
3146 static_assert(sizeof(uint64_t) >= sizeof(T), "Down-casting not allowed.");
3147 m_state = static_cast<uint64_t>(state);
3148 }
3149
3153 int64_t operator-(const pcg32& other) const
3154 {
3155 PRRNG_DEBUG(m_inc == other.m_inc);
3156
3157 uint64_t cur_mult = PRRNG_PCG32_MULT;
3158 uint64_t cur_plus = m_inc;
3159 uint64_t cur_state = other.m_state;
3160 uint64_t the_bit = 1u;
3161 uint64_t distance = 0u;
3162
3163 while (m_state != cur_state) {
3164 if ((m_state & the_bit) != (cur_state & the_bit)) {
3165 cur_state = cur_state * cur_mult + cur_plus;
3166 distance |= the_bit;
3167 }
3168 PRRNG_DEBUG((m_state & the_bit) == (cur_state & the_bit));
3169 the_bit <<= 1;
3170 cur_plus = (cur_mult + 1ULL) * cur_plus;
3171 cur_mult *= cur_mult;
3172 }
3173
3174 return (int64_t)distance;
3175 }
3176
3188 template <typename R = int64_t>
3189 R distance(const pcg32& other) const
3190 {
3191 static_assert(sizeof(R) >= sizeof(int64_t), "Down-casting not allowed.");
3192 int64_t r = this->operator-(other);
3193
3194#ifdef PRRNG_ENABLE_DEBUG
3195 bool u = std::is_unsigned<R>::value;
3196 PRRNG_DEBUG((r < 0 && !u) || r >= 0);
3197#endif
3198
3199 return static_cast<R>(r);
3200 }
3201
3216 template <
3217 typename R = int64_t,
3218 typename T,
3219 std::enable_if_t<std::is_integral<T>::value, bool> = true>
3220 R distance(T other_state) const
3221 {
3222 static_assert(sizeof(R) >= sizeof(int64_t), "Down-casting not allowed.");
3223
3224 uint64_t cur_mult = PRRNG_PCG32_MULT;
3225 uint64_t cur_plus = m_inc;
3226 uint64_t cur_state = other_state;
3227 uint64_t the_bit = 1u;
3228 uint64_t distance = 0u;
3229
3230 while (m_state != cur_state) {
3231 if ((m_state & the_bit) != (cur_state & the_bit)) {
3232 cur_state = cur_state * cur_mult + cur_plus;
3233 distance |= the_bit;
3234 }
3235 PRRNG_DEBUG((m_state & the_bit) == (cur_state & the_bit));
3236 the_bit <<= 1;
3237 cur_plus = (cur_mult + 1ULL) * cur_plus;
3238 cur_mult *= cur_mult;
3239 }
3240
3241 int64_t r = (int64_t)distance;
3242
3243#ifdef PRRNG_ENABLE_DEBUG
3244 bool u = std::is_unsigned<R>::value;
3245 PRRNG_DEBUG((r < 0 && !u) || r >= 0);
3246#endif
3247
3248 return static_cast<R>(r);
3249 }
3250
3263 template <typename T>
3265 {
3266 static_assert(sizeof(int64_t) >= sizeof(T), "Down-casting not allowed.");
3267
3268 int64_t delta_ = static_cast<int64_t>(distance);
3269
3270 uint64_t cur_mult = PRRNG_PCG32_MULT;
3271 uint64_t cur_plus = m_inc;
3272 uint64_t acc_mult = 1u;
3273 uint64_t acc_plus = 0u;
3274
3275 // Even though delta is an unsigned integer, we can pass a signed
3276 // integer to go backwards, it just goes "the long way round".
3277 uint64_t delta = (uint64_t)delta_;
3278
3279 while (delta > 0) {
3280 if (delta & 1) {
3281 acc_mult *= cur_mult;
3282 acc_plus = acc_plus * cur_mult + cur_plus;
3283 }
3284 cur_plus = (cur_mult + 1) * cur_plus;
3285 cur_mult *= cur_mult;
3286 delta /= 2;
3287 }
3288 m_state = acc_mult * m_state + acc_plus;
3289 }
3290
3298 bool operator==(const pcg32& other) const
3299 {
3300 return m_state == other.m_state && m_inc == other.m_inc;
3301 }
3302
3310 bool operator!=(const pcg32& other) const
3311 {
3312 return m_state != other.m_state || m_inc != other.m_inc;
3313 }
3314
3315protected:
3316 uint64_t m_initstate;
3317 uint64_t m_initseq;
3318 uint64_t m_state;
3319 uint64_t m_inc;
3320};
3321
3329class pcg32_index : public pcg32 {
3330private:
3331 ptrdiff_t m_index;
3332 bool m_delta;
3333
3334public:
3340 template <typename T = uint64_t, typename S = uint64_t>
3344 bool delta = false
3345 )
3346 {
3347 static_assert(sizeof(uint64_t) >= sizeof(T), "Down-casting not allowed.");
3348 static_assert(sizeof(uint64_t) >= sizeof(S), "Down-casting not allowed.");
3349 this->seed(static_cast<uint64_t>(initstate), static_cast<uint64_t>(initseq));
3350 m_index = 0;
3351 m_delta = delta;
3352 }
3353
3363 uint64_t state_at(ptrdiff_t index)
3364 {
3365 if (m_delta) {
3366 return m_state;
3367 }
3368 uint64_t state = m_state;
3369 this->advance(index - m_index);
3370 uint64_t ret = m_state;
3371 this->restore(state);
3372 return ret;
3373 }
3374
3379 void jump_to(ptrdiff_t index)
3380 {
3381 if (m_delta) {
3382 return;
3383 }
3384 this->advance(index - m_index);
3385 m_index = index;
3386 }
3387
3392 void drawn(ptrdiff_t n)
3393 {
3394 if (m_delta) {
3395 return;
3396 }
3397 m_index += n;
3398 }
3399
3404 void set_delta(bool delta)
3405 {
3406 m_delta = delta;
3407 }
3408
3413 ptrdiff_t index() const
3414 {
3415 return m_index;
3416 }
3417
3422 void set_index(ptrdiff_t index)
3423 {
3424 m_index = index;
3425 }
3426};
3427
3450 ptrdiff_t buffer = 0,
3451 ptrdiff_t margin = 0,
3452 ptrdiff_t min_margin = 0,
3453 bool strict = false
3454 )
3455 {
3456 this->buffer = buffer;
3457 this->margin = margin;
3458 this->min_margin = min_margin;
3459 this->strict = strict;
3460 }
3461
3465 ptrdiff_t buffer = 0;
3466
3470 ptrdiff_t margin = 0;
3471
3475 ptrdiff_t min_margin = 0;
3476
3482 bool strict = false;
3483};
3484
3503template <class Data>
3505private:
3506 Data m_data;
3507 pcg32_index m_gen;
3508 std::function<Data(size_t)> m_draw;
3509 std::function<double(size_t)> m_sum;
3510 bool m_extendible;
3511 alignment m_align;
3512 distribution m_distro;
3513 std::array<double, 3> m_param;
3514 ptrdiff_t m_start;
3515 ptrdiff_t m_i;
3516
3520 void auto_functions()
3521 {
3522 m_extendible = true;
3523
3524 switch (m_distro) {
3525 case random:
3526 m_draw = [this](size_t n) -> Data {
3527 return m_gen.random<Data>(std::array<size_t, 1>{n}) * m_param[0] + m_param[1];
3528 };
3529 m_sum = [this](size_t n) -> double {
3530 return m_gen.cumsum_random(n) * m_param[0] + static_cast<double>(n) * m_param[1];
3531 };
3532 return;
3533 case delta:
3534 m_draw = [this](size_t n) -> Data {
3535 return m_gen.delta<Data>(std::array<size_t, 1>{n}, m_param[0]) + m_param[1];
3536 };
3537 m_sum = [this](size_t n) -> double {
3538 return m_gen.cumsum_delta(n, m_param[0]) + static_cast<double>(n) * m_param[1];
3539 };
3540 return;
3541 case exponential:
3542 m_draw = [this](size_t n) -> Data {
3543 return m_gen.exponential<Data>(std::array<size_t, 1>{n}, m_param[0]) + m_param[1];
3544 };
3545 m_sum = [this](size_t n) -> double {
3546 return m_gen.cumsum_exponential(n, m_param[0]) +
3547 static_cast<double>(n) * m_param[1];
3548 };
3549 return;
3550 case power:
3551 m_draw = [this](size_t n) -> Data {
3552 return m_gen.power<Data>(std::array<size_t, 1>{n}, m_param[0]) + m_param[1];
3553 };
3554 m_sum = [this](size_t n) -> double {
3555 return m_gen.cumsum_power(n, m_param[0]) + static_cast<double>(n) * m_param[1];
3556 };
3557 return;
3558 case gamma:
3559 m_draw = [this](size_t n) -> Data {
3560 return m_gen.gamma<Data>(std::array<size_t, 1>{n}, m_param[0], m_param[1]) +
3561 m_param[2];
3562 };
3563 m_sum = [this](size_t n) -> double {
3564 return m_gen.cumsum_gamma(n, m_param[0], m_param[1]) +
3565 static_cast<double>(n) * m_param[2];
3566 };
3567 return;
3568 case pareto:
3569 m_draw = [this](size_t n) -> Data {
3570 return m_gen.pareto<Data>(std::array<size_t, 1>{n}, m_param[0], m_param[1]) +
3571 m_param[2];
3572 };
3573 m_sum = [this](size_t n) -> double {
3574 return m_gen.cumsum_pareto(n, m_param[0], m_param[1]) +
3575 static_cast<double>(n) * m_param[2];
3576 };
3577 return;
3578 case weibull:
3579 m_draw = [this](size_t n) -> Data {
3580 return m_gen.weibull<Data>(std::array<size_t, 1>{n}, m_param[0], m_param[1]) +
3581 m_param[2];
3582 };
3583 m_sum = [this](size_t n) -> double {
3584 return m_gen.cumsum_weibull(n, m_param[0], m_param[1]) +
3585 static_cast<double>(n) * m_param[2];
3586 };
3587 return;
3588 case normal:
3589 m_draw = [this](size_t n) -> Data {
3590 return m_gen.normal<Data>(std::array<size_t, 1>{n}, m_param[0], m_param[1]) +
3591 m_param[2];
3592 };
3593 m_sum = [this](size_t n) -> double {
3594 return m_gen.cumsum_normal(n, m_param[0], m_param[1]) +
3595 static_cast<double>(n) * m_param[2];
3596 };
3597 return;
3598 case custom:
3599 m_extendible = false;
3600 return;
3601 }
3602 }
3603
3610 void copy_from(const pcg32_cumsum& other)
3611 {
3612 m_data = other.m_data;
3613 m_gen = other.m_gen;
3614 m_align = other.m_align;
3615 m_distro = other.m_distro;
3616 m_param = other.m_param;
3617 m_start = other.m_start;
3618 m_i = other.m_i;
3619 this->auto_functions();
3620 }
3621
3622public:
3647 template <class R, typename T = uint64_t, typename S = uint64_t>
3649 const R& shape,
3650 T initstate = PRRNG_PCG32_INITSTATE,
3651 S initseq = PRRNG_PCG32_INITSEQ,
3653 const std::vector<double>& parameters = std::vector<double>{},
3654 const alignment& align = alignment()
3655 )
3656 {
3657 m_data = xt::empty<typename Data::value_type>(shape);
3658 m_gen = pcg32_index(initstate, initseq, distribution == distribution::delta);
3659 m_start = m_gen.index();
3660 m_i = static_cast<ptrdiff_t>(m_data.size());
3661 m_align = align;
3662 m_distro = distribution;
3663 std::copy(parameters.begin(), parameters.end(), m_param.begin());
3664 this->auto_functions();
3665
3666 if (!m_extendible) {
3667 return;
3668 }
3669
3670 using E = decltype(m_draw(size_t{}));
3671 E extra = m_draw(m_data.size());
3672 m_gen.drawn(m_data.size());
3673 std::partial_sum(extra.begin(), extra.end(), m_data.begin());
3674 }
3675
3683 std::function<Data(size_t)> get_chunk,
3684 std::function<double(size_t)> get_cumsum,
3685 bool uses_generator = true
3686 )
3687 {
3688 m_extendible = true;
3689 m_draw = get_chunk;
3690 m_sum = get_cumsum;
3691 m_gen.set_delta(!uses_generator);
3692
3693 using E = decltype(m_draw(size_t{}));
3694 E extra = m_draw(m_data.size());
3695 m_gen.drawn(m_data.size());
3696 std::partial_sum(extra.begin(), extra.end(), m_data.begin());
3697 }
3698
3703 {
3704 this->copy_from(other);
3705 }
3706
3710 void operator=(const pcg32_cumsum& other)
3711 {
3712 this->copy_from(other);
3713 }
3714
3719 bool is_extendible() const
3720 {
3721 return m_extendible;
3722 }
3723
3728 const pcg32_index& generator() const
3729 {
3730 return m_gen;
3731 }
3732
3737 const auto& shape() const
3738 {
3739 return m_data.shape();
3740 }
3741
3746 auto size() const
3747 {
3748 return m_data.size();
3749 }
3750
3755 template <class T>
3756 pcg32_cumsum& operator+=(const T& value)
3757 {
3758 xt::noalias(m_data) += value;
3759 return *this;
3760 }
3761
3766 template <class T>
3767 pcg32_cumsum& operator-=(const T& value)
3768 {
3769 xt::noalias(m_data) -= value;
3770 return *this;
3771 }
3772
3777 const Data& data() const
3778 {
3779 return m_data;
3780 }
3781
3788 void set_data(const Data& data)
3789 {
3790 PRRNG_ASSERT(xt::has_shape(data, m_data.shape()));
3791 xt::noalias(m_data) = data;
3792 }
3793
3798 ptrdiff_t start() const
3799 {
3800 return m_start;
3801 }
3802
3807 void set_start(ptrdiff_t index)
3808 {
3809 m_start = index;
3810 }
3811
3826 ptrdiff_t index_at_align() const
3827 {
3828 return m_start + m_i;
3829 }
3830
3842 ptrdiff_t chunk_index_at_align() const
3843 {
3844 return m_i;
3845 }
3846
3854 double left_of_align() const
3855 {
3856 return m_data[m_i];
3857 }
3858
3866 double right_of_align() const
3867 {
3868 return m_data[m_i + 1];
3869 }
3870
3874 uint64_t state_at(ptrdiff_t index)
3875 {
3876 return m_gen.state_at(index);
3877 }
3878
3886 void restore(uint64_t state, double value, ptrdiff_t index)
3887 {
3888 m_gen.set_index(index);
3889 m_gen.restore(state);
3890 m_start = index;
3891
3892 using E = decltype(m_draw(size_t{}));
3893 E extra = m_draw(m_data.size());
3894 m_gen.drawn(m_data.size());
3895 extra.front() += value - extra.front();
3896 std::partial_sum(extra.begin(), extra.end(), m_data.begin());
3897 }
3898
3904 bool contains(double target) const
3905 {
3906 return target >= m_data.front() && target <= m_data.back();
3907 }
3908
3913 void prev(size_t margin = 0)
3914 {
3915 PRRNG_ASSERT(m_extendible);
3916 m_i = static_cast<ptrdiff_t>(m_data.size());
3917 detail::prev(m_gen, m_draw, margin, m_data.data(), m_data.size(), &m_start);
3918 }
3919
3924 void next(size_t margin = 0)
3925 {
3926 PRRNG_ASSERT(m_extendible);
3927 m_i = static_cast<ptrdiff_t>(m_data.size());
3928 detail::next(m_gen, m_draw, margin, m_data.data(), m_data.size(), &m_start);
3929 }
3930
3945 void align(double target)
3946 {
3947 if (!m_extendible) {
3948 PRRNG_ASSERT(this->contains(target));
3949 m_i = iterator::lower_bound(m_data.begin(), m_data.end(), target, m_i);
3950 return;
3951 }
3952
3953 detail::align(
3954 m_gen, m_draw, m_sum, m_align, m_data.data(), m_data.size(), &m_start, &m_i, target
3955 );
3956 }
3957};
3958
3966template <class Derived, class M>
3968public:
3969 using shape_type = M;
3970 using size_type = typename M::value_type;
3971
3978 {
3979 return m_size;
3980 }
3981
3987 const shape_type& strides() const
3988 {
3989 return m_strides;
3990 }
3991
3997 const shape_type& shape() const
3998 {
3999 return m_shape;
4000 }
4001
4008 template <class T>
4009 auto shape(T axis) const
4010 {
4011 return m_shape[axis];
4012 }
4013
4020 template <class T>
4021 auto flat_index(const T& index) const
4022 {
4023 PRRNG_DEBUG(this->inbounds(index));
4024 return std::inner_product(index.cbegin(), index.cend(), m_strides.cbegin(), 0);
4025 }
4026
4032 template <class T>
4033 bool inbounds(const T& index) const
4034 {
4035 if (index.size() != m_strides.size()) {
4036 return false;
4037 }
4038
4039 for (size_t i = 0; i < m_strides.size(); ++i) {
4040 if (index[i] >= m_shape[i]) {
4041 return false;
4042 }
4043 }
4044
4045 return true;
4046 }
4047
4054 template <class S>
4055 auto random(const S& ishape) -> typename detail::composite_return_type<double, M, S>::type
4056 {
4057 using R = typename detail::composite_return_type<double, M, S>::type;
4058 return this->random_impl<R>(ishape);
4059 }
4060
4065 template <class R, class S>
4066 R random(const S& ishape)
4067 {
4068 return this->random_impl<R>(ishape);
4069 }
4070
4074 template <class I, std::size_t L>
4075 auto random(const I (&ishape)[L]) ->
4076 typename detail::composite_return_type<double, M, std::array<size_t, L>>::type
4077 {
4078 using R = typename detail::composite_return_type<double, M, std::array<size_t, L>>::type;
4079 return this->random_impl<R>(detail::to_array(ishape));
4080 }
4081
4086 template <class R, class I, std::size_t L>
4087 R random(const I (&ishape)[L])
4088 {
4089 return this->random_impl<R>(detail::to_array(ishape));
4090 }
4091
4099 template <class S, typename T>
4100 auto randint(const S& ishape, T high) -> typename detail::composite_return_type<T, M, S>::type
4101 {
4102 using R = typename detail::composite_return_type<T, M, S>::type;
4103 return this->randint_impl<R>(ishape, high);
4104 }
4105
4110 template <class R, class S, typename T>
4111 R randint(const S& ishape, T high)
4112 {
4113 return this->randint_impl<R>(ishape, high);
4114 }
4115
4119 template <class I, std::size_t L, typename T>
4120 auto randint(const I (&ishape)[L], T high) ->
4121 typename detail::composite_return_type<T, M, std::array<size_t, L>>::type
4122 {
4123 using R = typename detail::composite_return_type<T, M, std::array<size_t, L>>::type;
4124 return this->randint_impl<R>(detail::to_array(ishape), high);
4125 }
4126
4131 template <class R, class I, std::size_t L, typename T>
4132 R randint(const I (&ishape)[L], T high)
4133 {
4134 return this->randint_impl<R>(detail::to_array(ishape), high);
4135 }
4136
4145 template <class S, typename T, typename U>
4146 auto randint(const S& ishape, T low, U high) ->
4147 typename detail::composite_return_type<T, M, S>::type
4148 {
4149 using R = typename detail::composite_return_type<T, M, S>::type;
4150 return this->randint_impl<R>(ishape, low, high);
4151 }
4152
4157 template <class R, class S, typename T, typename U>
4158 R randint(const S& ishape, T low, U high)
4159 {
4160 return this->randint_impl<R>(ishape, low, high);
4161 }
4162
4166 template <class I, std::size_t L, typename T, typename U>
4167 auto randint(const I (&ishape)[L], T low, U high) ->
4168 typename detail::composite_return_type<T, M, std::array<size_t, L>>::type
4169 {
4170 using R = typename detail::composite_return_type<T, M, std::array<size_t, L>>::type;
4171 return this->randint_impl<R>(detail::to_array(ishape), low, high);
4172 }
4173
4178 template <class R, class I, std::size_t L, typename T, typename U>
4179 R randint(const I (&ishape)[L], T low, U high)
4180 {
4181 return this->randint_impl<R>(detail::to_array(ishape), low, high);
4182 }
4183
4193 template <class S>
4194 auto delta(const S& ishape, double scale = 1) ->
4195 typename detail::composite_return_type<double, M, S>::type
4196 {
4197 using R = typename detail::composite_return_type<double, M, S>::type;
4198 return this->delta_impl<R>(ishape, scale);
4199 }
4200
4205 template <class R, class S>
4206 R delta(const S& ishape, double scale = 1)
4207 {
4208 return this->delta_impl<R>(ishape, scale);
4209 }
4210
4214 template <class I, std::size_t L>
4215 auto delta(const I (&ishape)[L], double scale = 1) ->
4216 typename detail::composite_return_type<double, M, std::array<size_t, L>>::type
4217 {
4218 using R = typename detail::composite_return_type<double, M, std::array<size_t, L>>::type;
4219 return this->delta_impl<R>(detail::to_array(ishape), scale);
4220 }
4221
4226 template <class R, class I, std::size_t L>
4227 R delta(const I (&ishape)[L], double scale = 1)
4228 {
4229 return this->delta_impl<R>(detail::to_array(ishape), scale);
4230 }
4231
4240 template <class S>
4241 auto exponential(const S& ishape, double scale = 1) ->
4242 typename detail::composite_return_type<double, M, S>::type
4243 {
4244 using R = typename detail::composite_return_type<double, M, S>::type;
4245 return this->exponential_impl<R>(ishape, scale);
4246 }
4247
4252 template <class R, class S>
4253 R exponential(const S& ishape, double scale = 1)
4254 {
4255 return this->exponential_impl<R>(ishape, scale);
4256 }
4257
4261 template <class I, std::size_t L>
4262 auto exponential(const I (&ishape)[L], double scale = 1) ->
4263 typename detail::composite_return_type<double, M, std::array<size_t, L>>::type
4264 {
4265 using R = typename detail::composite_return_type<double, M, std::array<size_t, L>>::type;
4266 return this->exponential_impl<R>(detail::to_array(ishape), scale);
4267 }
4268
4273 template <class R, class I, std::size_t L>
4274 R exponential(const I (&ishape)[L], double scale = 1)
4275 {
4276 return this->exponential_impl<R>(detail::to_array(ishape), scale);
4277 }
4278
4287 template <class S>
4288 auto power(const S& ishape, double k = 1) ->
4289 typename detail::composite_return_type<double, M, S>::type
4290 {
4291 using R = typename detail::composite_return_type<double, M, S>::type;
4292 return this->power_impl<R>(ishape, k);
4293 }
4294
4299 template <class R, class S>
4300 R power(const S& ishape, double k = 1)
4301 {
4302 return this->power_impl<R>(ishape, k);
4303 }
4304
4308 template <class I, std::size_t L>
4309 auto power(const I (&ishape)[L], double k = 1) ->
4310 typename detail::composite_return_type<double, M, std::array<size_t, L>>::type
4311 {
4312 using R = typename detail::composite_return_type<double, M, std::array<size_t, L>>::type;
4313 return this->power_impl<R>(detail::to_array(ishape), k);
4314 }
4315
4320 template <class R, class I, std::size_t L>
4321 R power(const I (&ishape)[L], double k = 1)
4322 {
4323 return this->power_impl<R>(detail::to_array(ishape), k);
4324 }
4325
4337 template <class S>
4338 auto gamma(const S& ishape, double k = 1, double scale = 1) ->
4339 typename detail::composite_return_type<double, M, S>::type
4340 {
4341 using R = typename detail::composite_return_type<double, M, S>::type;
4342 return this->gamma_impl<R>(ishape, k, scale);
4343 }
4344
4349 template <class R, class S>
4350 R gamma(const S& ishape, double k = 1, double scale = 1)
4351 {
4352 return this->gamma_impl<R>(ishape, k, scale);
4353 }
4354
4358 template <class I, std::size_t L>
4359 auto gamma(const I (&ishape)[L], double k = 1, double scale = 1) ->
4360 typename detail::composite_return_type<double, M, std::array<size_t, L>>::type
4361 {
4362 using R = typename detail::composite_return_type<double, M, std::array<size_t, L>>::type;
4363 return this->gamma_impl<R>(detail::to_array(ishape), k, scale);
4364 }
4365
4370 template <class R, class I, std::size_t L>
4371 R gamma(const I (&ishape)[L], double k = 1, double scale = 1)
4372 {
4373 return this->gamma_impl<R>(detail::to_array(ishape), k, scale);
4374 }
4375
4385 template <class S>
4386 auto pareto(const S& ishape, double k = 1, double scale = 1) ->
4387 typename detail::composite_return_type<double, M, S>::type
4388 {
4389 using R = typename detail::composite_return_type<double, M, S>::type;
4390 return this->pareto_impl<R>(ishape, k, scale);
4391 }
4392
4397 template <class R, class S>
4398 R pareto(const S& ishape, double k = 1, double scale = 1)
4399 {
4400 return this->pareto_impl<R>(ishape, k, scale);
4401 }
4402
4406 template <class I, std::size_t L>
4407 auto pareto(const I (&ishape)[L], double k = 1, double scale = 1) ->
4408 typename detail::composite_return_type<double, M, std::array<size_t, L>>::type
4409 {
4410 using R = typename detail::composite_return_type<double, M, std::array<size_t, L>>::type;
4411 return this->pareto_impl<R>(detail::to_array(ishape), k, scale);
4412 }
4413
4418 template <class R, class I, std::size_t L>
4419 R pareto(const I (&ishape)[L], double k = 1, double scale = 1)
4420 {
4421 return this->pareto_impl<R>(detail::to_array(ishape), k, scale);
4422 }
4423
4440 template <class S>
4441 auto weibull(const S& ishape, double k = 1, double scale = 1) ->
4442 typename detail::composite_return_type<double, M, S>::type
4443 {
4444 using R = typename detail::composite_return_type<double, M, S>::type;
4445 return this->weibull_impl<R>(ishape, k, scale);
4446 }
4447
4452 template <class R, class S>
4453 R weibull(const S& ishape, double k = 1, double scale = 1)
4454 {
4455 return this->weibull_impl<R>(ishape, k, scale);
4456 }
4457
4461 template <class I, std::size_t L>
4462 auto weibull(const I (&ishape)[L], double k = 1, double scale = 1) ->
4463 typename detail::composite_return_type<double, M, std::array<size_t, L>>::type
4464 {
4465 using R = typename detail::composite_return_type<double, M, std::array<size_t, L>>::type;
4466 return this->weibull_impl<R>(detail::to_array(ishape), k, scale);
4467 }
4468
4473 template <class R, class I, std::size_t L>
4474 R weibull(const I (&ishape)[L], double k = 1, double scale = 1)
4475 {
4476 return this->weibull_impl<R>(detail::to_array(ishape), k, scale);
4477 }
4478
4497 template <class S>
4498 auto normal(const S& ishape, double mu = 0, double sigma = 1) ->
4499 typename detail::composite_return_type<double, M, S>::type
4500 {
4501 using R = typename detail::composite_return_type<double, M, S>::type;
4502 return this->normal_impl<R>(ishape, mu, sigma);
4503 }
4504
4509 template <class R, class S>
4510 R normal(const S& ishape, double mu = 0, double sigma = 1)
4511 {
4512 return this->normal_impl<R>(ishape, mu, sigma);
4513 }
4514
4518 template <class I, std::size_t L>
4519 auto normal(const I (&ishape)[L], double mu = 0, double sigma = 1) ->
4520 typename detail::composite_return_type<double, M, std::array<size_t, L>>::type
4521 {
4522 using R = typename detail::composite_return_type<double, M, std::array<size_t, L>>::type;
4523 return this->normal_impl<R>(detail::to_array(ishape), mu, sigma);
4524 }
4525
4530 template <class R, class I, std::size_t L>
4531 R normal(const I (&ishape)[L], double mu = 0, double sigma = 1)
4532 {
4533 return this->normal_impl<R>(detail::to_array(ishape), mu, sigma);
4534 }
4535
4541 template <class T>
4542 auto cumsum_random(const T& n) -> typename detail::return_type<double, M>::type
4543 {
4544 using R = typename detail::return_type<double, M>::type;
4545 R ret = R::from_shape(m_shape);
4546 static_cast<Derived*>(this)->cumsum_random_impl(ret.data(), n.data());
4547 return ret;
4548 }
4549
4555 template <class R, class T>
4556 R cumsum_random(const T& n)
4557 {
4558 R ret = R::from_shape(m_shape);
4559 static_cast<Derived*>(this)->cumsum_random_impl(ret.data(), n.data());
4560 return ret;
4561 }
4562
4570 template <class T>
4571 auto cumsum_delta(const T& n, double scale = 1) -> typename detail::return_type<double, M>::type
4572 {
4573 using R = typename detail::return_type<double, M>::type;
4574 R ret = R::from_shape(m_shape);
4575 for (size_t i = 0; i < ret.size(); ++i) {
4576 ret.flat(i) = static_cast<double>(n.flat(i)) * scale;
4577 }
4578 return ret;
4579 }
4580
4588 template <class R, class T>
4589 R cumsum_delta(const T& n, double scale = 1)
4590 {
4591 R ret = R::from_shape(m_shape);
4592 for (size_t i = 0; i < ret.size(); ++i) {
4593 ret.flat(i) = static_cast<double>(n.flat(i)) * scale;
4594 }
4595 return ret;
4596 }
4597
4605 template <class T>
4606 auto cumsum_exponential(const T& n, double scale = 1) ->
4607 typename detail::return_type<double, M>::type
4608 {
4609 using R = typename detail::return_type<double, M>::type;
4610 R ret = R::from_shape(m_shape);
4611 static_cast<Derived*>(this)->cumsum_exponential_impl(ret.data(), n.data(), scale);
4612 return ret;
4613 }
4614
4622 template <class R, class T>
4623 R cumsum_exponential(const T& n, double scale = 1)
4624 {
4625 R ret = R::from_shape(m_shape);
4626 static_cast<Derived*>(this)->cumsum_exponential_impl(ret.data(), n.data(), scale);
4627 return ret;
4628 }
4629
4637 template <class T>
4638 auto cumsum_power(const T& n, double k = 1) -> typename detail::return_type<double, M>::type
4639 {
4640 using R = typename detail::return_type<double, M>::type;
4641 R ret = R::from_shape(m_shape);
4642 static_cast<Derived*>(this)->cumsum_power_impl(ret.data(), n.data(), k);
4643 return ret;
4644 }
4645
4653 template <class R, class T>
4654 R cumsum_power(const T& n, double k = 1)
4655 {
4656 R ret = R::from_shape(m_shape);
4657 static_cast<Derived*>(this)->cumsum_power_impl(ret.data(), n.data(), k);
4658 return ret;
4659 }
4660
4669 template <class T>
4670 auto cumsum_gamma(const T& n, double k = 1, double scale = 1) ->
4671 typename detail::return_type<double, M>::type
4672 {
4673 using R = typename detail::return_type<double, M>::type;
4674 R ret = R::from_shape(m_shape);
4675 static_cast<Derived*>(this)->cumsum_gamma_impl(ret.data(), n.data(), k, scale);
4676 return ret;
4677 }
4678
4687 template <class R, class T>
4688 R cumsum_gamma(const T& n, double k = 1, double scale = 1)
4689 {
4690 R ret = R::from_shape(m_shape);
4691 static_cast<Derived*>(this)->cumsum_gamma_impl(ret.data(), n.data(), k, scale);
4692 return ret;
4693 }
4694
4703 template <class T>
4704 auto cumsum_pareto(const T& n, double k = 1, double scale = 1) ->
4705 typename detail::return_type<double, M>::type
4706 {
4707 using R = typename detail::return_type<double, M>::type;
4708 R ret = R::from_shape(m_shape);
4709 static_cast<Derived*>(this)->cumsum_pareto_impl(ret.data(), n.data(), k, scale);
4710 return ret;
4711 }
4712
4721 template <class R, class T>
4722 R cumsum_pareto(const T& n, double k = 1, double scale = 1)
4723 {
4724 R ret = R::from_shape(m_shape);
4725 static_cast<Derived*>(this)->cumsum_pareto_impl(ret.data(), n.data(), k, scale);
4726 return ret;
4727 }
4728
4737 template <class T>
4738 auto cumsum_weibull(const T& n, double k = 1, double scale = 1) ->
4739 typename detail::return_type<double, M>::type
4740 {
4741 using R = typename detail::return_type<double, M>::type;
4742 R ret = R::from_shape(m_shape);
4743 static_cast<Derived*>(this)->cumsum_weibull_impl(ret.data(), n.data(), k, scale);
4744 return ret;
4745 }
4746
4755 template <class R, class T>
4756 R cumsum_weibull(const T& n, double k = 1, double scale = 1)
4757 {
4758 R ret = R::from_shape(m_shape);
4759 static_cast<Derived*>(this)->cumsum_weibull_impl(ret.data(), n.data(), k, scale);
4760 return ret;
4761 }
4762
4771 template <class T>
4772 auto cumsum_normal(const T& n, double mu = 0, double sigma = 1) ->
4773 typename detail::return_type<double, M>::type
4774 {
4775 using R = typename detail::return_type<double, M>::type;
4776 R ret = R::from_shape(m_shape);
4777 static_cast<Derived*>(this)->cumsum_normal_impl(ret.data(), n.data(), mu, sigma);
4778 return ret;
4779 }
4780
4789 template <class R, class T>
4790 R cumsum_normal(const T& n, double mu = 0, double sigma = 1)
4791 {
4792 R ret = R::from_shape(m_shape);
4793 static_cast<Derived*>(this)->cumsum_normal_impl(ret.data(), n.data(), mu, sigma);
4794 return ret;
4795 }
4796
4805 template <class P>
4806 auto decide(const P& p) -> typename detail::return_type<bool, P>::type
4807 {
4808 PRRNG_ASSERT(xt::has_shape(p, m_shape));
4809 using R = typename detail::return_type<bool, P>::type;
4810 R ret = R::from_shape(m_shape);
4811 static_cast<Derived*>(this)->decide_impl(p.data(), ret.data());
4812 return ret;
4813 }
4814
4818 template <class P, class R>
4819 R decide(const P& p)
4820 {
4821 PRRNG_ASSERT(xt::has_shape(p, m_shape));
4822 R ret = R::from_shape(m_shape);
4823 static_cast<Derived*>(this)->decide_impl(p.data(), ret.data());
4824 return ret;
4825 }
4826
4835 template <class P, class R>
4836 void decide(const P& p, R& ret)
4837 {
4838 static_assert(
4839 std::is_same<typename R::value_type, bool>::value, "Return value_type must be bool"
4840 );
4841
4842 PRRNG_ASSERT(xt::has_shape(p, m_shape));
4843 PRRNG_ASSERT(xt::has_shape(p, ret.shape()));
4844 static_cast<Derived*>(this)->decide_impl(p.data(), ret.data());
4845 }
4846
4856 template <class P, class T>
4857 auto decide_masked(const P& p, const T& mask) -> typename detail::return_type<bool, P>::type
4858 {
4859 PRRNG_ASSERT(xt::has_shape(p, m_shape));
4860 PRRNG_ASSERT(xt::has_shape(p, mask.shape()));
4861 using R = typename detail::return_type<bool, P>::type;
4862 R ret = R::from_shape(m_shape);
4863 static_cast<Derived*>(this)->decide_masked_impl(p.data(), mask.data(), ret.data());
4864 return ret;
4865 }
4866
4870 template <class P, class T, class R>
4871 R decide_masked(const P& p, const T& mask)
4872 {
4873 PRRNG_ASSERT(xt::has_shape(p, m_shape));
4874 PRRNG_ASSERT(xt::has_shape(p, mask.shape()));
4875 R ret = R::from_shape(m_shape);
4876 static_cast<Derived*>(this)->decide_masked_impl(p.data(), mask.data(), ret.data());
4877 return ret;
4878 }
4879
4889 template <class P, class T, class R>
4890 void decide_masked(const P& p, const T& mask, R& ret)
4891 {
4892 static_assert(
4893 std::is_same<typename R::value_type, bool>::value, "Return value_type must be bool"
4894 );
4895
4896 PRRNG_ASSERT(xt::has_shape(p, m_shape));
4897 PRRNG_ASSERT(xt::has_shape(p, mask.shape()));
4898 PRRNG_ASSERT(xt::has_shape(p, ret.shape()));
4899 static_cast<Derived*>(this)->decide_masked_impl(p.data(), mask.data(), ret.data());
4900 }
4901
4902private:
4903 template <class R, class S>
4904 R positive_random_impl(const S& ishape)
4905 {
4906 static_assert(
4907 std::is_same<typename R::value_type, double>::value, "Return value_type must be double"
4908 );
4909
4910 auto n = detail::size(ishape);
4911 R ret = R::from_shape(detail::concatenate<M, S>::two(m_shape, ishape));
4912 static_cast<Derived*>(this)->draw_list_positive_double(&ret.front(), n);
4913 return ret;
4914 }
4915
4916 template <class R, class S>
4917 R random_impl(const S& ishape)
4918 {
4919 static_assert(
4920 std::is_same<typename R::value_type, double>::value, "Return value_type must be double"
4921 );
4922
4923 auto n = detail::size(ishape);
4924 R ret = R::from_shape(detail::concatenate<M, S>::two(m_shape, ishape));
4925 static_cast<Derived*>(this)->draw_list_double(&ret.front(), n);
4926 return ret;
4927 }
4928
4929 template <class R, class S, typename T>
4930 R randint_impl(const S& ishape, T high)
4931 {
4932 static_assert(
4933 std::numeric_limits<typename R::value_type>::max() >= std::numeric_limits<T>::max(),
4934 "Return value_type must must be able to accommodate the bound"
4935 );
4936
4937 static_assert(
4938 std::numeric_limits<T>::max() <= std::numeric_limits<uint32_t>::max(), "Bound too large"
4939 );
4940
4941 auto n = detail::size(ishape);
4942 R ret = R::from_shape(detail::concatenate<M, S>::two(m_shape, ishape));
4943 std::vector<uint32_t> tmp(ret.size());
4944 static_cast<Derived*>(this)->draw_list_uint32(&tmp.front(), static_cast<uint32_t>(high), n);
4945 std::copy(tmp.begin(), tmp.end(), ret.begin());
4946 return ret;
4947 }
4948
4949 template <class R, class S, typename T, typename U>
4950 R randint_impl(const S& ishape, T low, U high)
4951 {
4952 static_assert(
4953 std::numeric_limits<typename R::value_type>::max() >= std::numeric_limits<T>::max(),
4954 "Return value_type must must be able to accommodate the bound"
4955 );
4956
4957 static_assert(
4958 std::numeric_limits<typename R::value_type>::min() >= std::numeric_limits<T>::min(),
4959 "Return value_type must must be able to accommodate the bound"
4960 );
4961
4962 static_assert(
4963 std::numeric_limits<typename R::value_type>::max() >= std::numeric_limits<U>::max(),
4964 "Return value_type must must be able to accommodate the bound"
4965 );
4966
4967 static_assert(
4968 std::numeric_limits<typename R::value_type>::min() >= std::numeric_limits<U>::min(),
4969 "Return value_type must must be able to accommodate the bound"
4970 );
4971
4972 static_assert(
4973 static_cast<uint32_t>(std::numeric_limits<T>::max()) <
4974 std::numeric_limits<uint32_t>::max(),
4975 "Bound too large"
4976 );
4977
4978 auto n = detail::size(ishape);
4979 R ret = R::from_shape(detail::concatenate<M, S>::two(m_shape, ishape));
4980 std::vector<uint32_t> tmp(ret.size());
4981 static_cast<Derived*>(this)->draw_list_uint32(
4982 &tmp.front(), static_cast<uint32_t>(high - low), n
4983 );
4984 std::copy(tmp.begin(), tmp.end(), ret.begin());
4985 return ret + low;
4986 }
4987
4988 template <class R, class S>
4989 R delta_impl(const S& ishape, double scale)
4990 {
4991 R ret = R::from_shape(detail::concatenate<M, S>::two(m_shape, ishape));
4992 ret.fill(scale);
4993 return ret;
4994 }
4995
4996 template <class R, class S>
4997 R exponential_impl(const S& ishape, double scale)
4998 {
4999 R r = this->random_impl<R>(ishape);
5000 return exponential_distribution(scale).quantile(r);
5001 }
5002
5003 template <class R, class S>
5004 R power_impl(const S& ishape, double k)
5005 {
5006 R r = this->random_impl<R>(ishape);
5007 return power_distribution(k).quantile(r);
5008 }
5009
5010 template <class R, class S>
5011 R gamma_impl(const S& ishape, double k, double scale)
5012 {
5013 R r = this->random_impl<R>(ishape);
5014 return gamma_distribution(k, scale).quantile(r);
5015 }
5016
5017 template <class R, class S>
5018 R pareto_impl(const S& ishape, double k, double scale)
5019 {
5020 R r = this->random_impl<R>(ishape);
5021 return pareto_distribution(k, scale).quantile(r);
5022 }
5023
5024 template <class R, class S>
5025 R weibull_impl(const S& ishape, double k, double scale)
5026 {
5027 R r = this->random_impl<R>(ishape);
5028 return weibull_distribution(k, scale).quantile(r);
5029 }
5030
5031 template <class R, class S>
5032 R normal_impl(const S& ishape, double mu, double sigma)
5033 {
5034 R r = this->positive_random_impl<R>(ishape);
5035 return normal_distribution(mu, sigma).quantile(r);
5036 }
5037
5038protected:
5042};
5043
5047template <class Generator, class Shape>
5048class pcg32_arrayBase : public GeneratorBase_array<pcg32_arrayBase<Generator, Shape>, Shape> {
5050
5051private:
5053
5054public:
5055 using size_type = typename Shape::value_type;
5056 using shape_type = Shape;
5057
5058protected:
5065 template <class T>
5066 void init(const T& initstate)
5067 {
5068 std::copy(initstate.shape().cbegin(), initstate.shape().cend(), m_shape.begin());
5069 std::copy(initstate.strides().cbegin(), initstate.strides().cend(), m_strides.begin());
5070 m_size = initstate.size();
5071 m_gen.reserve(m_size);
5072
5073 for (size_type i = 0; i < m_size; ++i) {
5074 m_gen.push_back(Generator(initstate.flat(i)));
5075 }
5076 }
5077
5085 template <class T, class U>
5086 void init(const T& initstate, const U& initseq)
5087 {
5088 PRRNG_ASSERT(xt::has_shape(initstate, initseq.shape()));
5089
5090 std::copy(initstate.shape().cbegin(), initstate.shape().cend(), m_shape.begin());
5091 std::copy(initstate.strides().cbegin(), initstate.strides().cend(), m_strides.begin());
5092 m_size = initstate.size();
5093 m_gen.reserve(m_size);
5094
5095 for (size_type i = 0; i < m_size; ++i) {
5096 m_gen.push_back(Generator(initstate.flat(i), initseq.flat(i)));
5097 }
5098 }
5099
5100public:
5101 pcg32_arrayBase() = default;
5102
5109 template <class... Args>
5110 Generator& operator()(Args... args)
5111 {
5112 return m_gen[this->get_item(0, 0, args...)];
5113 }
5114
5121 template <class... Args>
5122 const Generator& operator()(Args... args) const
5123 {
5124 return m_gen[this->get_item(0, 0, args...)];
5125 }
5126
5133 Generator& operator[](size_t i)
5134 {
5135 PRRNG_DEBUG(i < m_size);
5136 return m_gen[i];
5137 }
5138
5145 const Generator& operator[](size_t i) const
5146 {
5147 PRRNG_DEBUG(i < m_size);
5148 return m_gen[i];
5149 }
5150
5157 Generator& flat(size_t i)
5158 {
5159 PRRNG_DEBUG(i < m_size);
5160 return m_gen[i];
5161 }
5162
5169 const Generator& flat(size_t i) const
5170 {
5171 PRRNG_DEBUG(i < m_size);
5172 return m_gen[i];
5173 }
5174
5181 auto state() -> typename detail::return_type<uint64_t, Shape>::type
5182 {
5183 using R = typename detail::return_type<uint64_t, Shape>::type;
5184 return this->state<R>();
5185 }
5186
5193 template <class R>
5195 {
5196 using value_type = typename R::value_type;
5197 R ret = R::from_shape(m_shape);
5198
5199 for (size_type i = 0; i < m_size; ++i) {
5200 ret.flat(i) = m_gen[i].template state<value_type>();
5201 }
5202
5203 return ret;
5204 }
5205
5212 auto initstate() -> typename detail::return_type<uint64_t, Shape>::type
5213 {
5214 using R = typename detail::return_type<uint64_t, Shape>::type;
5215 return this->initstate<R>();
5216 }
5217
5223 template <class R>
5225 {
5226 using value_type = typename R::value_type;
5227 R ret = R::from_shape(m_shape);
5228
5229 for (size_type i = 0; i < m_size; ++i) {
5230 ret.flat(i) = m_gen[i].template initstate<value_type>();
5231 }
5232
5233 return ret;
5234 }
5235
5242 auto initseq() -> typename detail::return_type<uint64_t, Shape>::type
5243 {
5244 using R = typename detail::return_type<uint64_t, Shape>::type;
5245 return this->initseq<R>();
5246 }
5247
5254 template <class R>
5256 {
5257 using value_type = typename R::value_type;
5258 R ret = R::from_shape(m_shape);
5259
5260 for (size_type i = 0; i < m_size; ++i) {
5261 ret.flat(i) = m_gen[i].template initseq<value_type>();
5262 }
5263
5264 return ret;
5265 }
5266
5274 template <class T>
5275 auto distance(const T& arg) -> typename detail::return_type<int64_t, Shape>::type
5276 {
5277 using R = typename detail::return_type<int64_t, Shape>::type;
5278 return this->distance<R, T>(arg);
5279 }
5280
5289 template <class R, class T>
5290 R distance(const T& arg)
5291 {
5292 using value_type = typename R::value_type;
5293 R ret = R::from_shape(m_shape);
5294
5295 for (size_type i = 0; i < m_size; ++i) {
5296 ret.flat(i) = m_gen[i].template distance<value_type>(arg.flat(i));
5297 }
5298
5299 return ret;
5300 }
5301
5310 template <class T>
5311 void advance(const T& arg)
5312 {
5313 for (size_type i = 0; i < m_size; ++i) {
5314 m_gen[i].advance(arg.flat(i));
5315 }
5316 }
5317
5327 template <class T>
5328 void restore(const T& arg)
5329 {
5330 for (size_type i = 0; i < m_size; ++i) {
5331 m_gen[i].restore(arg.flat(i));
5332 }
5333 }
5334
5335protected:
5341 void decide_impl(const double* p, bool* ret)
5342 {
5343 for (size_type i = 0; i < m_size; ++i) {
5344 ret[i] = m_gen[i].next_double() < p[i];
5345 }
5346 }
5347
5354 void decide_masked_impl(const double* p, const bool* mask, bool* ret)
5355 {
5356 for (size_type i = 0; i < m_size; ++i) {
5357 if (mask[i]) {
5358 ret[i] = false;
5359 }
5360 else {
5361 ret[i] = m_gen[i].next_double() < p[i];
5362 }
5363 }
5364 }
5365
5371 void cumsum_random_impl(double* ret, const size_t* n)
5372 {
5373 for (size_type i = 0; i < m_size; ++i) {
5374 ret[i] = m_gen[i].cumsum_random(n[i]);
5375 }
5376 }
5377
5384 void cumsum_exponential_impl(double* ret, const size_t* n, double scale)
5385 {
5386 for (size_type i = 0; i < m_size; ++i) {
5387 ret[i] = m_gen[i].cumsum_exponential(n[i], scale);
5388 }
5389 }
5390
5397 void cumsum_power_impl(double* ret, const size_t* n, double k)
5398 {
5399 for (size_type i = 0; i < m_size; ++i) {
5400 ret[i] = m_gen[i].cumsum_power(n[i], k);
5401 }
5402 }
5403
5411 void cumsum_gamma_impl(double* ret, const size_t* n, double k, double scale)
5412 {
5413 for (size_type i = 0; i < m_size; ++i) {
5414 ret[i] = m_gen[i].cumsum_gamma(n[i], k, scale);
5415 }
5416 }
5417
5425 void cumsum_pareto_impl(double* ret, const size_t* n, double k, double scale)
5426 {
5427 for (size_type i = 0; i < m_size; ++i) {
5428 ret[i] = m_gen[i].cumsum_pareto(n[i], k, scale);
5429 }
5430 }
5431
5439 void cumsum_weibull_impl(double* ret, const size_t* n, double k, double scale)
5440 {
5441 for (size_type i = 0; i < m_size; ++i) {
5442 ret[i] = m_gen[i].cumsum_weibull(n[i], k, scale);
5443 }
5444 }
5445
5453 void cumsum_normal_impl(double* ret, const size_t* n, double mu, double sigma)
5454 {
5455 for (size_type i = 0; i < m_size; ++i) {
5456 ret[i] = m_gen[i].cumsum_normal(n[i], mu, sigma);
5457 }
5458 }
5459
5467 void draw_list_double(double* data, size_t n)
5468 {
5469 for (size_type i = 0; i < m_size; ++i) {
5470 for (size_t j = 0; j < n; ++j) {
5471 data[i * n + j] = m_gen[i].next_double();
5472 }
5473 }
5474 }
5475
5483 void draw_list_positive_double(double* data, size_t n)
5484 {
5485 for (size_type i = 0; i < m_size; ++i) {
5486 for (size_t j = 0; j < n; ++j) {
5487 data[i * n + j] = m_gen[i].next_positive_double();
5488 }
5489 }
5490 }
5491
5500 void draw_list_uint32(uint32_t* data, uint32_t bound, size_t n)
5501 {
5502 for (size_type i = 0; i < m_size; ++i) {
5503 for (size_t j = 0; j < n; ++j) {
5504 data[i * n + j] = m_gen[i].next_uint32(bound);
5505 }
5506 }
5507 }
5508
5509private:
5514 template <class T>
5515 size_t get_item(size_t sum, size_t d, T arg)
5516 {
5517 return sum + arg * m_strides[d];
5518 }
5519
5524 template <class T, class... Args>
5525 size_t get_item(size_t sum, size_t d, T arg, Args... args)
5526 {
5527 return get_item(sum + arg * m_strides[d], d + 1, args...);
5528 }
5529
5530protected:
5531 std::vector<Generator> m_gen;
5535};
5536
5558class pcg32_array : public pcg32_arrayBase<pcg32, std::vector<size_t>> {
5559private:
5561
5562public:
5563 using size_type = size_t;
5564 using shape_type = std::vector<size_t>;
5565
5566 pcg32_array() = default;
5567
5574 template <class T>
5576 {
5577 m_shape.resize(initstate.dimension());
5578 m_strides.resize(initstate.dimension());
5579 this->init(initstate);
5580 }
5581
5589 template <class T, class U>
5590 pcg32_array(const T& initstate, const U& initseq)
5591 {
5592 m_shape.resize(initstate.dimension());
5593 m_strides.resize(initstate.dimension());
5594 this->init(initstate, initseq);
5595 }
5596
5597protected:
5599 using GeneratorBase_array<derived_type, shape_type>::m_size;
5600 using GeneratorBase_array<derived_type, shape_type>::m_shape;
5601 using GeneratorBase_array<derived_type, shape_type>::m_strides;
5602};
5603
5607template <size_t N>
5608class pcg32_tensor : public pcg32_arrayBase<pcg32, std::array<size_t, N>> {
5609private:
5611
5612public:
5613 using size_type = size_t;
5614 using shape_type = std::array<size_t, N>;
5615
5616 pcg32_tensor() = default;
5617
5624 template <class T>
5626 {
5627 static_assert(detail::check_fixed_rank<N, T>::value, "Ranks to not match");
5628 this->init(initstate);
5629 }
5630
5638 template <class T, class U>
5639 pcg32_tensor(const T& initstate, const U& initseq)
5640 {
5641 static_assert(detail::check_fixed_rank<N, T>::value, "Ranks to not match");
5642 this->init(initstate, initseq);
5643 }
5644
5645protected:
5647 using GeneratorBase_array<derived_type, shape_type>::m_size;
5648 using GeneratorBase_array<derived_type, shape_type>::m_shape;
5649 using GeneratorBase_array<derived_type, shape_type>::m_strides;
5650};
5651
5655class pcg32_index_array : public pcg32_arrayBase<pcg32_index, std::vector<size_t>> {
5656private:
5658
5659public:
5660 pcg32_index_array() = default;
5661
5669 template <class T, class U>
5671 {
5672 m_shape.resize(initstate.dimension());
5673 m_strides.resize(initstate.dimension());
5674 this->init(initstate, initseq);
5675 }
5676
5677protected:
5678 using pcg32_arrayBase<pcg32_index, std::vector<size_t>>::m_gen;
5679 using GeneratorBase_array<derived_type, std::vector<size_t>>::m_size;
5680 using GeneratorBase_array<derived_type, std::vector<size_t>>::m_shape;
5681 using GeneratorBase_array<derived_type, std::vector<size_t>>::m_strides;
5682};
5683
5687template <size_t N>
5688class pcg32_index_tensor : public pcg32_arrayBase<pcg32_index, std::array<size_t, N>> {
5689private:
5691
5692public:
5693 pcg32_index_tensor() = default;
5694
5702 template <class T, class U>
5704 {
5705 static_assert(detail::check_fixed_rank<N, T>::value, "Ranks to not match");
5706 this->init(initstate, initseq);
5707 }
5708
5709protected:
5710 using pcg32_arrayBase<pcg32_index, std::array<size_t, N>>::m_gen;
5711 using GeneratorBase_array<derived_type, std::array<size_t, N>>::m_size;
5712 using GeneratorBase_array<derived_type, std::array<size_t, N>>::m_shape;
5713 using GeneratorBase_array<derived_type, std::array<size_t, N>>::m_strides;
5714};
5715
5716namespace detail {
5717
5718template <class T, typename = void>
5719struct auto_pcg32 {
5720 static auto get(const T& initseq)
5721 {
5722 return pcg32_array(initseq);
5723 }
5724
5725 template <class S>
5726 static auto get(const T& initseq, const S& initstate)
5727 {
5728 return pcg32_array(initseq, initstate);
5729 }
5730};
5731
5732template <class T>
5733struct auto_pcg32<T, typename std::enable_if_t<xt::has_fixed_rank_t<T>::value>> {
5734 static auto get(const T& initseq)
5735 {
5736 return pcg32_tensor<xt::get_rank<T>::value>(initseq);
5737 }
5738
5739 template <class S>
5740 static auto get(const T& initseq, const S& initstate)
5741 {
5742 return pcg32_tensor<xt::get_rank<T>::value>(initseq, initstate);
5743 }
5744};
5745
5746template <class T>
5747struct auto_pcg32<T, typename std::enable_if_t<std::is_integral<T>::value>> {
5748 static auto get(const T& initseq)
5749 {
5750 return pcg32(initseq);
5751 }
5752
5753 template <class S>
5754 static auto get(const T& initseq, const S& initstate)
5755 {
5756 return pcg32(initseq, initstate);
5757 }
5758};
5759
5760} // namespace detail
5761
5768template <class T>
5769inline auto auto_pcg32(const T& initstate)
5770{
5771 return detail::auto_pcg32<T>::get(initstate);
5772}
5773
5781template <class T, class S>
5782inline auto auto_pcg32(const T& initstate, const S& initseq)
5783{
5784 return detail::auto_pcg32<T>::get(initstate, initseq);
5785}
5786
5794template <class Generator, class Data, class Index, bool is_cumsum>
5796 static_assert(std::is_signed<typename Index::value_type>::value, "Index must be signed");
5797
5798public:
5799 using size_type = typename Data::size_type;
5800
5801protected:
5802 Generator m_gen;
5803 Data m_data;
5804
5810 std::vector<std::function<xt::xtensor<double, 1>(size_t)>> m_draw;
5811
5817 std::vector<std::function<double(size_t)>> m_sum;
5818
5823
5826 std::array<double, 3> m_param;
5827 Index m_start;
5828 Index m_i;
5829 size_t m_n;
5830
5831protected:
5841 template <class S, class T, class U>
5842 void init(
5843 const S& shape,
5844 const T& initstate,
5845 const U& initseq,
5847 const std::vector<double>& parameters,
5848 const alignment& align = alignment()
5849 )
5850 {
5851 PRRNG_ASSERT(xt::has_shape(initstate, initseq.shape()));
5852
5853 m_align = align;
5855 m_gen = Generator(initstate, initseq);
5856
5857 for (size_t i = 0; i < m_gen.size(); ++i) {
5858 m_gen[i].set_delta(distribution == distribution::delta);
5859 }
5860
5861 std::vector<size_t> data_shape;
5862 data_shape.resize(initstate.dimension() + shape.size());
5863 std::copy(initstate.shape().begin(), initstate.shape().end(), data_shape.begin());
5864 std::copy(shape.begin(), shape.end(), data_shape.begin() + initstate.dimension());
5865 m_data = xt::empty<typename Data::value_type>(data_shape);
5866 m_n = m_data.size() / initstate.size();
5867
5868 m_start = xt::zeros<typename Index::value_type>(m_gen.shape());
5869 m_i = m_n * xt::ones<typename Index::value_type>(m_gen.shape());
5870
5871 auto par = default_parameters(distribution, parameters);
5872 std::copy(par.begin(), par.end(), m_param.begin());
5873
5874 this->auto_functions();
5875
5876 using E = decltype(m_draw[size_t{}](size_t{}));
5877
5878 // if possible: draw the first chunk
5879 if (m_extendible) {
5880 for (size_t i = 0; i < m_gen.size(); ++i) {
5881 E extra = m_draw[i](m_n);
5882 m_gen[i].drawn(m_n);
5883 if constexpr (is_cumsum) {
5884 std::partial_sum(extra.begin(), extra.end(), &m_data.flat(i * m_n));
5885 }
5886 else {
5887 std::copy(extra.begin(), extra.end(), &m_data.flat(i * m_n));
5888 }
5889 }
5890 }
5891 }
5892
5897 {
5898 using R = decltype(m_draw[size_t{}](size_t{}));
5899 m_extendible = true;
5900
5902 m_draw.resize(m_gen.size());
5903 if constexpr (is_cumsum) {
5904 m_sum.resize(m_gen.size());
5905 }
5906 }
5907
5908 switch (m_distro) {
5909 case random:
5910 for (size_t i = 0; i < m_gen.size(); ++i) {
5911 m_draw[i] = [this, i](size_t n) -> R {
5912 return m_gen[i].template random<R>(std::array<size_t, 1>{n}) * m_param[0] +
5913 m_param[1];
5914 };
5915 if constexpr (is_cumsum) {
5916 m_sum[i] = [this, i](size_t n) -> double {
5917 return m_gen[i].cumsum_random(n) * m_param[0] +
5918 static_cast<double>(n) * m_param[1];
5919 };
5920 }
5921 }
5922 return;
5923 case delta:
5924 for (size_t i = 0; i < m_gen.size(); ++i) {
5925 m_draw[i] = [this, i](size_t n) -> R {
5926 return m_gen[i].template delta<R>(std::array<size_t, 1>{n}, m_param[0]) +
5927 m_param[1];
5928 };
5929 if constexpr (is_cumsum) {
5930 m_sum[i] = [this, i](size_t n) -> double {
5931 return m_gen[i].cumsum_delta(n, m_param[0]) +
5932 static_cast<double>(n) * m_param[1];
5933 };
5934 }
5935 }
5936 return;
5937 case exponential:
5938 for (size_t i = 0; i < m_gen.size(); ++i) {
5939 m_draw[i] = [this, i](size_t n) -> R {
5940 return m_gen[i].template exponential<R>(std::array<size_t, 1>{n}, m_param[0]) +
5941 m_param[1];
5942 };
5943 if constexpr (is_cumsum) {
5944 m_sum[i] = [this, i](size_t n) -> double {
5945 return m_gen[i].cumsum_exponential(n, m_param[0]) +
5946 static_cast<double>(n) * m_param[1];
5947 };
5948 }
5949 }
5950 return;
5951 case power:
5952 for (size_t i = 0; i < m_gen.size(); ++i) {
5953 m_draw[i] = [this, i](size_t n) -> R {
5954 return m_gen[i].template power<R>(std::array<size_t, 1>{n}, m_param[0]) +
5955 m_param[1];
5956 };
5957 if constexpr (is_cumsum) {
5958 m_sum[i] = [this, i](size_t n) -> double {
5959 return m_gen[i].cumsum_power(n, m_param[0]) +
5960 static_cast<double>(n) * m_param[1];
5961 };
5962 }
5963 }
5964 return;
5965 case gamma:
5966 for (size_t i = 0; i < m_gen.size(); ++i) {
5967 m_draw[i] = [this, i](size_t n) -> R {
5968 return m_gen[i].template gamma<R>(
5969 std::array<size_t, 1>{n}, m_param[0], m_param[1]
5970 ) +
5971 m_param[2];
5972 };
5973 if constexpr (is_cumsum) {
5974 m_sum[i] = [this, i](size_t n) -> double {
5975 return m_gen[i].cumsum_gamma(n, m_param[0], m_param[1]) +
5976 static_cast<double>(n) * m_param[2];
5977 };
5978 }
5979 }
5980 return;
5981 case pareto:
5982 for (size_t i = 0; i < m_gen.size(); ++i) {
5983 m_draw[i] = [this, i](size_t n) -> R {
5984 return m_gen[i].template pareto<R>(
5985 std::array<size_t, 1>{n}, m_param[0], m_param[1]
5986 ) +
5987 m_param[2];
5988 };
5989 if constexpr (is_cumsum) {
5990 m_sum[i] = [this, i](size_t n) -> double {
5991 return m_gen[i].cumsum_pareto(n, m_param[0], m_param[1]) +
5992 static_cast<double>(n) * m_param[2];
5993 };
5994 }
5995 }
5996 return;
5997 case weibull:
5998 for (size_t i = 0; i < m_gen.size(); ++i) {
5999 m_draw[i] = [this, i](size_t n) -> R {
6000 return m_gen[i].template weibull<R>(
6001 std::array<size_t, 1>{n}, m_param[0], m_param[1]
6002 ) +
6003 m_param[2];
6004 };
6005 if constexpr (is_cumsum) {
6006 m_sum[i] = [this, i](size_t n) -> double {
6007 return m_gen[i].cumsum_weibull(n, m_param[0], m_param[1]) +
6008 static_cast<double>(n) * m_param[2];
6009 };
6010 }
6011 }
6012 return;
6013 case normal:
6014 for (size_t i = 0; i < m_gen.size(); ++i) {
6015 m_draw[i] = [this, i](size_t n) -> R {
6016 return m_gen[i].template normal<R>(
6017 std::array<size_t, 1>{n}, m_param[0], m_param[1]
6018 ) +
6019 m_param[2];
6020 };
6021 if constexpr (is_cumsum) {
6022 m_sum[i] = [this, i](size_t n) -> double {
6023 return m_gen[i].cumsum_normal(n, m_param[0], m_param[1]) +
6024 static_cast<double>(n) * m_param[2];
6025 };
6026 }
6027 }
6028 return;
6029 case custom:
6030 m_extendible = false;
6031 return;
6032 }
6033 }
6034
6042 {
6043 m_gen = other.m_gen;
6044 m_data = other.m_data;
6045 m_align = other.m_align;
6046 m_distro = other.m_distro;
6047 m_param = other.m_param;
6048 m_start = other.m_start;
6049 m_i = other.m_i;
6050 m_n = other.m_n;
6051 this->auto_functions();
6052 }
6053
6054public:
6055 pcg32_arrayBase_chunkBase() = default;
6056
6061 {
6062 this->copy_from(other);
6063 }
6064
6069 {
6070 this->copy_from(other);
6071 }
6072
6077 template <class T>
6079 {
6080 xt::noalias(m_data) += values;
6081 return *this;
6082 }
6083
6088 template <class T>
6090 {
6091 xt::noalias(m_data) -= values;
6092 return *this;
6093 }
6094
6099 bool is_extendible() const
6100 {
6101 return m_extendible;
6102 }
6103
6109 {
6110 return static_cast<size_type>(m_n);
6111 }
6112
6117 const Generator& generators() const
6118 {
6119 return m_gen;
6120 }
6121
6125 const Data& data() const
6126 {
6127 return m_data;
6128 }
6129
6133 void set_data(const Data& data)
6134 {
6135 PRRNG_ASSERT(xt::has_shape(data, m_data.shape()));
6136 xt::noalias(m_data) = data;
6137 }
6138
6142 const Index& start() const
6143 {
6144 return m_start;
6145 }
6146
6150 void set_start(const Index& index)
6151 {
6152 PRRNG_ASSERT(xt::has_shape(index, m_gen.shape()));
6153 xt::noalias(m_start) = index;
6154 }
6155
6165 void align_at(const Index& index)
6166 {
6167 PRRNG_ASSERT(xt::has_shape(index, m_gen.shape()));
6168
6169 for (size_t i = 0; i < m_gen.size(); ++i) {
6170 if constexpr (!is_cumsum) {
6171 detail::chunk_align_at(
6172 m_gen[i],
6173 m_draw[i],
6174 m_align,
6175 &m_data.flat(i * m_n),
6176 m_n,
6177 &m_start.flat(i),
6178 index.flat(i)
6179 );
6180 }
6181 else {
6182 detail::cumsum_align_at(
6183 m_gen[i],
6184 m_draw[i],
6185 m_sum[i],
6186 m_align,
6187 &m_data.flat(i * m_n),
6188 m_n,
6189 &m_start.flat(i),
6190 index.flat(i)
6191 );
6192 }
6193 }
6194
6195 xt::noalias(m_i) = index - m_start;
6196 }
6197
6201 Index index_at_align() const
6202 {
6203 return m_start + m_i;
6204 }
6205
6209 const Index& chunk_index_at_align() const
6210 {
6211 return m_i;
6212 }
6213
6218 template <class R>
6219 void left_of_align(R& ret) const
6220 {
6221 PRRNG_ASSERT(xt::has_shape(ret, m_gen.shape()));
6222 using value_type = typename R::value_type;
6223
6224 for (size_t i = 0; i < m_gen.size(); ++i) {
6225 ret.flat(i) = static_cast<value_type>(m_data.flat(i * m_n + m_i.flat(i)));
6226 }
6227 }
6228
6233 template <class R>
6234 void right_of_align(R& ret) const
6235 {
6236 PRRNG_ASSERT(xt::has_shape(ret, m_gen.shape()));
6237 using value_type = typename R::value_type;
6238
6239 for (size_t i = 0; i < m_gen.size(); ++i) {
6240 ret.flat(i) = static_cast<value_type>(m_data.flat(i * m_n + m_i.flat(i) + 1));
6241 }
6242 }
6243
6247 template <class R>
6249 {
6250 R ret = R::from_shape(m_gen.shape());
6251 this->left_of_align(ret);
6252 return ret;
6253 }
6254
6258 template <class R>
6260 {
6261 R ret = R::from_shape(m_gen.shape());
6262 this->right_of_align(ret);
6263 return ret;
6264 }
6265
6269 template <class R, class T>
6270 R state_at(const T& index)
6271 {
6272 PRRNG_ASSERT(xt::has_shape(index, m_gen.shape()));
6273
6274 using value_type = typename R::value_type;
6275 R ret = R::from_shape(m_gen.shape());
6276
6277 for (size_t i = 0; i < m_gen.size(); ++i) {
6278 ret.flat(i) = static_cast<value_type>(m_gen[i].state_at(index.flat(i)));
6279 }
6280
6281 return ret;
6282 }
6283};
6284
6288template <class Generator, class Data, class Index>
6289class pcg32_arrayBase_chunk : public pcg32_arrayBase_chunkBase<Generator, Data, Index, false> {
6290protected:
6291 using pcg32_arrayBase_chunkBase<Generator, Data, Index, false>::m_data;
6292 using pcg32_arrayBase_chunkBase<Generator, Data, Index, false>::m_draw;
6293 using pcg32_arrayBase_chunkBase<Generator, Data, Index, false>::m_gen;
6294 using pcg32_arrayBase_chunkBase<Generator, Data, Index, false>::m_n;
6295 using pcg32_arrayBase_chunkBase<Generator, Data, Index, false>::m_i;
6296 using pcg32_arrayBase_chunkBase<Generator, Data, Index, false>::m_start;
6297 using pcg32_arrayBase_chunkBase<Generator, Data, Index, false>::m_align;
6298
6299public:
6300 using size_type = typename Data::size_type;
6301 using value_type = typename Data::value_type;
6302
6303 pcg32_arrayBase_chunk() = default;
6304
6311 template <class S, class T>
6312 void restore(const S& state, const T& index)
6313 {
6314 PRRNG_ASSERT(xt::has_shape(state, m_gen.shape()));
6315 PRRNG_ASSERT(xt::has_shape(index, m_gen.shape()));
6316 xt::noalias(m_start) = index;
6317
6318 for (size_t i = 0; i < m_gen.size(); ++i) {
6319 m_gen[i].set_index(index.flat(i));
6320 m_gen[i].restore(state.flat(i));
6321
6322 using E = decltype(m_draw[i](size_t{}));
6323 E extra = m_draw[i](m_n);
6324 m_gen[i].drawn(m_n);
6325 std::copy(extra.begin(), extra.end(), &m_data.flat(i * m_n));
6326 }
6327 }
6328};
6329
6342template <class Generator, class Data, class Index>
6343class pcg32_arrayBase_cumsum : public pcg32_arrayBase_chunkBase<Generator, Data, Index, true> {
6344protected:
6345 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_align;
6346 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_data;
6347 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_draw;
6348 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_extendible;
6349 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_gen;
6350 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_i;
6351 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_n;
6352 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_start;
6353 using pcg32_arrayBase_chunkBase<Generator, Data, Index, true>::m_sum;
6354
6355public:
6356 using size_type = typename Data::size_type;
6357
6358 pcg32_arrayBase_cumsum() = default;
6359
6360 // TODO: rename align_at_value ?
6364 template <class T>
6365 void align(const T& target)
6366 {
6367 PRRNG_ASSERT(xt::has_shape(target, m_gen.shape()));
6368
6369 if (!m_extendible) {
6370 PRRNG_ASSERT(this->contains(target));
6371 inplace::lower_bound(m_data, target, m_i);
6372 return;
6373 }
6374
6375 for (size_t i = 0; i < m_gen.size(); ++i) {
6376 detail::align(
6377 m_gen[i],
6378 m_draw[i],
6379 m_sum[i],
6380 m_align,
6381 &m_data.flat(i * m_n),
6382 m_n,
6383 &m_start.flat(i),
6384 &m_i.flat(i),
6385 target.flat(i)
6386 );
6387 }
6388 }
6389
6390 // todo: overload with array index
6391
6396 void align(size_t i, double target)
6397 {
6398 if (!m_extendible) {
6400 target >= m_data.flat(i * m_n) && target <= m_data.flat((i + 1) * m_n - 1)
6401 );
6402 m_i.flat(i) = iterator::lower_bound(
6403 &m_data.flat(i * m_n), &m_data.flat(i * m_n) + m_n, target, m_i.flat(i)
6404 );
6405 return;
6406 }
6407
6408 detail::align(
6409 m_gen[i],
6410 m_draw[i],
6411 m_sum[i],
6412 m_align,
6413 &m_data.flat(i * m_n),
6414 m_n,
6415 &m_start.flat(i),
6416 &m_i.flat(i),
6417 target
6418 );
6419 }
6420
6424 template <class S, class V, class T>
6425 void restore(const S& state, const V& value, const T& index)
6426 {
6427 PRRNG_ASSERT(xt::has_shape(state, m_gen.shape()));
6428 PRRNG_ASSERT(xt::has_shape(value, m_gen.shape()));
6429 PRRNG_ASSERT(xt::has_shape(index, m_gen.shape()));
6430 xt::noalias(m_start) = index;
6431
6432 for (size_t i = 0; i < m_gen.size(); ++i) {
6433 m_gen[i].set_index(index.flat(i));
6434 m_gen[i].restore(state.flat(i));
6435
6436 using E = decltype(m_draw[i](size_t{}));
6437 E extra = m_draw[i](m_n);
6438 m_gen[i].drawn(m_n);
6439 extra.front() += value.flat(i) - extra.front();
6440 std::partial_sum(extra.begin(), extra.end(), &m_data.flat(i * m_n));
6441 }
6442 }
6443
6447 template <class T>
6448 bool contains(const T& target) const
6449 {
6450 PRRNG_ASSERT(xt::has_shape(target, m_gen.shape()));
6451
6452 for (size_t i = 0; i < m_gen.size(); ++i) {
6453 if (target.flat(i) < m_data.flat(i * m_n) ||
6454 target.flat(i) > m_data.flat((i + 1) * m_n - 1)) {
6455 return false;
6456 }
6457 }
6458
6459 return true;
6460 }
6461};
6462
6467template <class Data, class Index>
6468class pcg32_array_chunk : public pcg32_arrayBase_chunk<pcg32_index_array, Data, Index> {
6469public:
6470 pcg32_array_chunk() = default;
6471
6475 template <class S, class T, class U>
6477 const S& shape,
6478 const T& initstate,
6479 const U& initseq,
6481 const std::vector<double>& parameters,
6482 const alignment& align = alignment()
6483 )
6484 {
6485 this->init(shape, initstate, initseq, distribution, parameters, align);
6486 }
6487};
6488
6493template <class Data, class Index, size_t N>
6494class pcg32_tensor_chunk : public pcg32_arrayBase_chunk<pcg32_index_tensor<N>, Data, Index> {
6495public:
6496 pcg32_tensor_chunk() = default;
6497
6501 template <class S, class T, class U>
6503 const S& shape,
6504 const T& initstate,
6505 const U& initseq,
6507 const std::vector<double>& parameters,
6508 const alignment& align = alignment()
6509 )
6510 {
6511 this->init(shape, initstate, initseq, distribution, parameters, align);
6512 }
6513};
6514
6527template <class Data, class Index>
6528class pcg32_array_cumsum : public pcg32_arrayBase_cumsum<pcg32_index_array, Data, Index> {
6529public:
6530 pcg32_array_cumsum() = default;
6531
6539 template <class S, class T, class U>
6541 const S& shape,
6542 const T& initstate,
6543 const U& initseq,
6545 const std::vector<double>& parameters,
6546 const alignment& align = alignment()
6547 )
6548 {
6549 this->init(shape, initstate, initseq, distribution, parameters, align);
6550 }
6551};
6552
6566template <class Data, class Index, size_t N>
6567class pcg32_tensor_cumsum : public pcg32_arrayBase_cumsum<pcg32_index_tensor<N>, Data, Index> {
6568public:
6569 pcg32_tensor_cumsum() = default;
6570
6574 template <class S, class T, class U>
6576 const S& shape,
6577 const T& initstate,
6578 const U& initseq,
6580 const std::vector<double>& parameters,
6581 const alignment& align = alignment()
6582 )
6583 {
6584 this->init(shape, initstate, initseq, distribution, parameters, align);
6585 }
6586};
6587
6588} // namespace prrng
6589
6590#endif
Base class of an array of pseudorandom number generators.
Definition prrng.h:3967
R cumsum_weibull(const T &n, double k=1, double scale=1)
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4756
R cumsum_exponential(const T &n, double scale=1)
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4623
auto normal(const S &ishape, double mu=0, double sigma=1) -> typename detail::composite_return_type< double, M, S >::type
Per generator, generate an nd-array of random numbers distributed according to a normal distribution.
Definition prrng.h:4498
auto random(const I(&ishape)[L]) -> typename detail::composite_return_type< double, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random numbers .
Definition prrng.h:4075
R randint(const I(&ishape)[L], T low, U high)
Per generator, generate an nd-array of random integers .
Definition prrng.h:4179
auto cumsum_pareto(const T &n, double k=1, double scale=1) -> typename detail::return_type< double, M >::type
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4704
auto decide_masked(const P &p, const T &mask) -> typename detail::return_type< bool, P >::type
Decide based on probability per generator.
Definition prrng.h:4857
R cumsum_normal(const T &n, double mu=0, double sigma=1)
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4790
auto weibull(const I(&ishape)[L], double k=1, double scale=1) -> typename detail::composite_return_type< double, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random numbers distributed according to a Weibull distribution...
Definition prrng.h:4462
R randint(const I(&ishape)[L], T high)
Per generator, generate an nd-array of random integers .
Definition prrng.h:4132
M shape_type
Type of the shape and strides lists.
Definition prrng.h:3969
R random(const S &ishape)
Per generator, generate an nd-array of random numbers .
Definition prrng.h:4066
auto randint(const I(&ishape)[L], T high) -> typename detail::composite_return_type< T, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random integers .
Definition prrng.h:4120
bool inbounds(const T &index) const
Check if an index is in bounds (and of the correct rank).
Definition prrng.h:4033
auto cumsum_power(const T &n, double k=1) -> typename detail::return_type< double, M >::type
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4638
R power(const S &ishape, double k=1)
Per generator, generate an nd-array of random numbers distributed according to an power distribution.
Definition prrng.h:4300
R pareto(const I(&ishape)[L], double k=1, double scale=1)
Per generator, generate an nd-array of random numbers distributed according to a Pareto distribution.
Definition prrng.h:4419
void decide_masked(const P &p, const T &mask, R &ret)
Decide based on probability per generator.
Definition prrng.h:4890
R decide(const P &p)
Decide based on probability per generator.
Definition prrng.h:4819
R exponential(const S &ishape, double scale=1)
Per generator, generate an nd-array of random numbers distributed according to an exponential distrib...
Definition prrng.h:4253
R cumsum_random(const T &n)
Per generator, return the result of the cumulative sum of n random numbers.
Definition prrng.h:4556
auto normal(const I(&ishape)[L], double mu=0, double sigma=1) -> typename detail::composite_return_type< double, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random numbers distributed according to a normal distribution.
Definition prrng.h:4519
auto cumsum_weibull(const T &n, double k=1, double scale=1) -> typename detail::return_type< double, M >::type
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4738
auto weibull(const S &ishape, double k=1, double scale=1) -> typename detail::composite_return_type< double, M, S >::type
Per generator, generate an nd-array of random numbers distributed according to a Weibull distribution...
Definition prrng.h:4441
R exponential(const I(&ishape)[L], double scale=1)
Per generator, generate an nd-array of random numbers distributed according to an exponential distrib...
Definition prrng.h:4274
R randint(const S &ishape, T high)
Per generator, generate an nd-array of random integers .
Definition prrng.h:4111
auto shape(T axis) const
Return the shape of the array of generators along a specific axis.
Definition prrng.h:4009
auto exponential(const S &ishape, double scale=1) -> typename detail::composite_return_type< double, M, S >::type
Per generator, generate an nd-array of random numbers distributed according to an exponential distrib...
Definition prrng.h:4241
R cumsum_delta(const T &n, double scale=1)
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4589
auto cumsum_normal(const T &n, double mu=0, double sigma=1) -> typename detail::return_type< double, M >::type
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4772
R random(const I(&ishape)[L])
Per generator, generate an nd-array of random numbers .
Definition prrng.h:4087
auto pareto(const S &ishape, double k=1, double scale=1) -> typename detail::composite_return_type< double, M, S >::type
Per generator, generate an nd-array of random numbers distributed according to a Pareto distribution.
Definition prrng.h:4386
auto delta(const I(&ishape)[L], double scale=1) -> typename detail::composite_return_type< double, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of numbers that are delta distribution.
Definition prrng.h:4215
auto randint(const S &ishape, T low, U high) -> typename detail::composite_return_type< T, M, S >::type
Per generator, generate an nd-array of random integers .
Definition prrng.h:4146
auto cumsum_exponential(const T &n, double scale=1) -> typename detail::return_type< double, M >::type
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4606
typename M::value_type size_type
Type of sizes.
Definition prrng.h:3970
R randint(const S &ishape, T low, U high)
Per generator, generate an nd-array of random integers .
Definition prrng.h:4158
R weibull(const S &ishape, double k=1, double scale=1)
Per generator, generate an nd-array of random numbers distributed according to a Weibull distribution...
Definition prrng.h:4453
R gamma(const I(&ishape)[L], double k=1, double scale=1)
Per generator, generate an nd-array of random numbers distributed according to a Gamma distribution.
Definition prrng.h:4371
const shape_type & strides() const
Return the strides of the array of generators.
Definition prrng.h:3987
R decide_masked(const P &p, const T &mask)
Decide based on probability per generator.
Definition prrng.h:4871
size_type size() const
Return the size of the array of generators.
Definition prrng.h:3977
shape_type m_strides
The strides of the array of generators.
Definition prrng.h:5041
auto randint(const S &ishape, T high) -> typename detail::composite_return_type< T, M, S >::type
Per generator, generate an nd-array of random integers .
Definition prrng.h:4100
R weibull(const I(&ishape)[L], double k=1, double scale=1)
Per generator, generate an nd-array of random numbers distributed according to a Weibull distribution...
Definition prrng.h:4474
auto power(const S &ishape, double k=1) -> typename detail::composite_return_type< double, M, S >::type
Per generator, generate an nd-array of random numbers distributed according to an power distribution.
Definition prrng.h:4288
const shape_type & shape() const
Return the shape of the array of generators.
Definition prrng.h:3997
R cumsum_power(const T &n, double k=1)
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4654
auto cumsum_random(const T &n) -> typename detail::return_type< double, M >::type
Per generator, return the result of the cumulative sum of n random numbers.
Definition prrng.h:4542
auto delta(const S &ishape, double scale=1) -> typename detail::composite_return_type< double, M, S >::type
Per generator, generate an nd-array of numbers that are delta distribution.
Definition prrng.h:4194
auto gamma(const I(&ishape)[L], double k=1, double scale=1) -> typename detail::composite_return_type< double, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random numbers distributed according to a Gamma distribution.
Definition prrng.h:4359
R gamma(const S &ishape, double k=1, double scale=1)
Per generator, generate an nd-array of random numbers distributed according to a Gamma distribution.
Definition prrng.h:4350
R delta(const S &ishape, double scale=1)
Per generator, generate an nd-array of numbers that are delta distribution.
Definition prrng.h:4206
auto flat_index(const T &index) const
Return a flat index based on an array index specified as a list.
Definition prrng.h:4021
R cumsum_pareto(const T &n, double k=1, double scale=1)
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4722
R cumsum_gamma(const T &n, double k=1, double scale=1)
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4688
R normal(const S &ishape, double mu=0, double sigma=1)
Per generator, generate an nd-array of random numbers distributed according to a normal distribution.
Definition prrng.h:4510
size_type m_size
See size().
Definition prrng.h:5039
R delta(const I(&ishape)[L], double scale=1)
Per generator, generate an nd-array of numbers that are delta distribution.
Definition prrng.h:4227
R normal(const I(&ishape)[L], double mu=0, double sigma=1)
Per generator, generate an nd-array of random numbers distributed according to a normal distribution.
Definition prrng.h:4531
auto exponential(const I(&ishape)[L], double scale=1) -> typename detail::composite_return_type< double, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random numbers distributed according to an exponential distrib...
Definition prrng.h:4262
auto random(const S &ishape) -> typename detail::composite_return_type< double, M, S >::type
Per generator, generate an nd-array of random numbers .
Definition prrng.h:4055
shape_type m_shape
See shape().
Definition prrng.h:5040
auto pareto(const I(&ishape)[L], double k=1, double scale=1) -> typename detail::composite_return_type< double, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random numbers distributed according to a Pareto distribution.
Definition prrng.h:4407
void decide(const P &p, R &ret)
Decide based on probability per generator.
Definition prrng.h:4836
auto decide(const P &p) -> typename detail::return_type< bool, P >::type
Decide based on probability per generator.
Definition prrng.h:4806
auto cumsum_delta(const T &n, double scale=1) -> typename detail::return_type< double, M >::type
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4571
auto power(const I(&ishape)[L], double k=1) -> typename detail::composite_return_type< double, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random numbers distributed according to an power distribution.
Definition prrng.h:4309
R power(const I(&ishape)[L], double k=1)
Per generator, generate an nd-array of random numbers distributed according to an power distribution.
Definition prrng.h:4321
auto cumsum_gamma(const T &n, double k=1, double scale=1) -> typename detail::return_type< double, M >::type
Per generator, return the result of the cumulative sum of n random numbers, distributed according to ...
Definition prrng.h:4670
auto gamma(const S &ishape, double k=1, double scale=1) -> typename detail::composite_return_type< double, M, S >::type
Per generator, generate an nd-array of random numbers distributed according to a Gamma distribution.
Definition prrng.h:4338
R pareto(const S &ishape, double k=1, double scale=1)
Per generator, generate an nd-array of random numbers distributed according to a Pareto distribution.
Definition prrng.h:4398
auto randint(const I(&ishape)[L], T low, U high) -> typename detail::composite_return_type< T, M, std::array< size_t, L > >::type
Per generator, generate an nd-array of random integers .
Definition prrng.h:4167
Base class of the pseudorandom number generators providing common methods.
Definition prrng.h:1690
R pareto(const S &shape, double k=1, double scale=1)
Generate an nd-array of random numbers distributed according to a Pareto distribution.
Definition prrng.h:2394
R randint(const S &shape, T high)
Generate an nd-array of random integers .
Definition prrng.h:2053
R random(const S &shape)
Generate an nd-array of random numbers .
Definition prrng.h:1992
R randint(const I(&shape)[L], T high)
Generate an nd-array of random integers .
Definition prrng.h:2073
void decide(const P &p, R &ret)
Decide based on probability per value.
Definition prrng.h:1891
double cumsum_power(size_t n, double k=1)
Result of the cumulative sum of n random numbers, distributed according to a power distribution,...
Definition prrng.h:1741
auto randint(const I(&shape)[L], T low, U high) -> typename detail::return_type_fixed< T, L >::type
Generate an nd-array of random integers .
Definition prrng.h:2107
auto pareto(const S &shape, double k=1, double scale=1) -> typename detail::return_type< double, S >::type
Generate an nd-array of random numbers distributed according to a Pareto distribution.
Definition prrng.h:2382
double exponential(double scale=1)
Return a random number distributed according to an exponential distribution.
Definition prrng.h:2188
R random(const I(&shape)[L])
Generate an nd-array of random numbers .
Definition prrng.h:2012
auto normal(const I(&shape)[L], double mu=0, double sigma=1) -> typename detail::return_type_fixed< double, L >::type
Generate an nd-array of random numbers distributed according to a normal distribution.
Definition prrng.h:2529
double normal(double mu=0, double sigma=1)
Return a random number distributed according to a normal distribution.
Definition prrng.h:2487
double pareto(double k=1, double scale=1)
Return a random number distributed according to a Pareto distribution.
Definition prrng.h:2368
double cumsum_exponential(size_t n, double scale=1)
Result of the cumulative sum of n random numbers, distributed according to an exponential distributio...
Definition prrng.h:1725
auto power(const I(&shape)[L], double k=1) -> typename detail::return_type_fixed< double, L >::type
Generate an nd-array of random numbers distributed according to an power distribution.
Definition prrng.h:2278
R gamma(const I(&shape)[L], double k=1, double scale=1)
Generate an nd-array of random numbers distributed according to a Gamma distribution.
Definition prrng.h:2356
auto delta(const S &shape, double scale=1) -> typename detail::return_type< double, S >::type
Generate an nd-array of numbers that are delta distribution.
Definition prrng.h:2145
R gamma(const S &shape, double k=1, double scale=1)
Generate an nd-array of random numbers distributed according to a Gamma distribution.
Definition prrng.h:2335
T randint(T high)
Generate a random integer .
Definition prrng.h:2024
auto exponential(const I(&shape)[L], double scale=1) -> typename detail::return_type_fixed< double, L >::type
Generate an nd-array of random numbers distributed according to an exponential distribution.
Definition prrng.h:2222
auto randint(const I(&shape)[L], T high) -> typename detail::return_type_fixed< T, L >::type
Generate an nd-array of random integers .
Definition prrng.h:2062
auto decide(const P &p) -> typename detail::return_type< bool, P >::type
Decide based on probability per value.
Definition prrng.h:1862
R delta(const I(&shape)[L], double scale=1)
Generate an nd-array of numbers that are delta distribution.
Definition prrng.h:2177
auto random(const S &shape) -> typename detail::return_type< double, S >::type
Generate an nd-array of random numbers .
Definition prrng.h:1981
R exponential(const I(&shape)[L], double scale=1)
Generate an nd-array of random numbers distributed according to an exponential distribution.
Definition prrng.h:2234
auto random(const I(&shape)[L]) -> typename detail::return_type_fixed< double, L >::type
Generate an nd-array of random numbers .
Definition prrng.h:2001
double cumsum(size_t n, enum prrng::distribution distribution, std::vector< double > parameters=std::vector< double >{}, bool append_default=true)
Get the cumulative sum of n random numbers according to some distribution.
Definition prrng.h:2645
R exponential(const S &shape, double scale=1)
Generate an nd-array of random numbers distributed according to an exponential distribution.
Definition prrng.h:2213
R draw(const S &shape, enum prrng::distribution distribution, std::vector< double > parameters=std::vector< double >{}, bool append_default=true)
Get an nd-array of random numbers according to some distribution.
Definition prrng.h:2599
auto gamma(const S &shape, double k=1, double scale=1) -> typename detail::return_type< double, S >::type
Generate an nd-array of random numbers distributed according to a Gamma distribution.
Definition prrng.h:2323
R delta(const S &shape, double scale=1)
Generate an nd-array of numbers that are delta distribution.
Definition prrng.h:2156
double cumsum_random(size_t n)
Result of the cumulative sum of n random numbers.
Definition prrng.h:1697
R power(const I(&shape)[L], double k=1)
Generate an nd-array of random numbers distributed according to an power distribution.
Definition prrng.h:2290
auto weibull(const I(&shape)[L], double k=1, double scale=1) -> typename detail::return_type_fixed< double, L >::type
Generate an nd-array of random numbers distributed according to a Weibull distribution.
Definition prrng.h:2463
R randint(const S &shape, T low, U high)
Generate an nd-array of random integers .
Definition prrng.h:2098
auto weibull(const S &shape, double k=1, double scale=1) -> typename detail::return_type< double, S >::type
Generate an nd-array of random numbers distributed according to a Weibull distribution.
Definition prrng.h:2442
auto normal(const S &shape, double mu=0, double sigma=1) -> typename detail::return_type< double, S >::type
Generate an nd-array of random numbers distributed according to a normal distribution.
Definition prrng.h:2508
double cumsum_pareto(size_t n, double k=1, double scale=1)
Result of the cumulative sum of n random numbers, distributed according to a Pareto distribution,...
Definition prrng.h:1782
R power(const S &shape, double k=1)
Generate an nd-array of random numbers distributed according to an power distribution.
Definition prrng.h:2269
R weibull(const I(&shape)[L], double k=1, double scale=1)
Generate an nd-array of random numbers distributed according to a Weibull distribution.
Definition prrng.h:2475
auto randint(const S &shape, T low, U high) -> typename detail::return_type< T, S >::type
Generate an nd-array of random integers .
Definition prrng.h:2087
double random()
Generate a random number .
Definition prrng.h:1969
R pareto(const I(&shape)[L], double k=1, double scale=1)
Generate an nd-array of random numbers distributed according to a Pareto distribution.
Definition prrng.h:2415
auto gamma(const I(&shape)[L], double k=1, double scale=1) -> typename detail::return_type_fixed< double, L >::type
Generate an nd-array of random numbers distributed according to a Gamma distribution.
Definition prrng.h:2344
R randint(const I(&shape)[L], T low, U high)
Generate an nd-array of random integers .
Definition prrng.h:2119
auto delta(const I(&shape)[L], double scale=1) -> typename detail::return_type_fixed< double, L >::type
Generate an nd-array of numbers that are delta distribution.
Definition prrng.h:2165
void shuffle(Iterator begin, Iterator end)
Draw uniformly distributed permutation and permute the given STL container.
Definition prrng.h:1844
double gamma(double k=1, double scale=1)
Return a random number distributed according to a Gamma distribution.
Definition prrng.h:2302
R weibull(const S &shape, double k=1, double scale=1)
Generate an nd-array of random numbers distributed according to a Weibull distribution.
Definition prrng.h:2454
R decide_masked(const P &p, const T &mask)
Decide based on probability per value.
Definition prrng.h:1928
R normal(const I(&shape)[L], double mu=0, double sigma=1)
Generate an nd-array of random numbers distributed according to a normal distribution.
Definition prrng.h:2541
auto pareto(const I(&shape)[L], double k=1, double scale=1) -> typename detail::return_type_fixed< double, L >::type
Generate an nd-array of random numbers distributed according to a Pareto distribution.
Definition prrng.h:2403
void decide_masked(const P &p, const T &mask, R &ret)
Decide based on probability per value.
Definition prrng.h:1946
double cumsum_delta(size_t n, double scale=1)
Result of the cumulative sum of n 'random' numbers, distributed according to a delta distribution,...
Definition prrng.h:1713
double weibull(double k=1, double scale=1)
Return a random number distributed according to a Weibull distribution.
Definition prrng.h:2427
auto randint(const S &shape, T high) -> typename detail::return_type< T, S >::type
Generate an nd-array of random integers .
Definition prrng.h:2042
double draw(enum prrng::distribution distribution, std::vector< double > parameters=std::vector< double >{}, bool append_default=true)
Get a random number according to some distribution.
Definition prrng.h:2553
R normal(const S &shape, double mu=0, double sigma=1)
Generate an nd-array of random numbers distributed according to a normal distribution.
Definition prrng.h:2520
auto power(const S &shape, double k=1) -> typename detail::return_type< double, S >::type
Generate an nd-array of random numbers distributed according to an power distribution.
Definition prrng.h:2258
double cumsum_normal(size_t n, double mu=0, double sigma=1)
Result of the cumulative sum of n random numbers, distributed according to a normal distribution,...
Definition prrng.h:1818
double cumsum_weibull(size_t n, double k=1, double scale=1)
Result of the cumulative sum of n random numbers, distributed according to a weibull distribution,...
Definition prrng.h:1800
double power(double k=1)
Return a random number distributed according to an power distribution.
Definition prrng.h:2245
auto decide_masked(const P &p, const T &mask) -> typename detail::return_type< bool, P >::type
Decide based on probability per value.
Definition prrng.h:1916
double cumsum_gamma(size_t n, double k=1, double scale=1)
Result of the cumulative sum of n random numbers, distributed according to a gamma distribution,...
Definition prrng.h:1759
R decide(const P &p)
Decide based on probability per value.
Definition prrng.h:1874
double delta(double scale=1)
Return a number distributed according to a delta distribution.
Definition prrng.h:2130
auto exponential(const S &shape, double scale=1) -> typename detail::return_type< double, S >::type
Generate an nd-array of random numbers distributed according to an exponential distribution.
Definition prrng.h:2201
Exponential distribution.
Definition prrng.h:1217
T quantile(const T &p)
Quantile (the inverse of the cumulative density function).
Definition prrng.h:1262
T pdf(const T &x)
Probability density function.
Definition prrng.h:1236
exponential_distribution(double scale=1)
Constructor.
Definition prrng.h:1224
T cdf(const T &x)
Cumulative density function.
Definition prrng.h:1249
Gamma distribution.
Definition prrng.h:1343
T cdf(const T &x)
Cumulative density function.
Definition prrng.h:1390
T quantile(const T &p)
Quantile (the inverse of the cumulative density function).
Definition prrng.h:1413
gamma_distribution(double k=1, double scale=1)
Constructor.
Definition prrng.h:1351
T pdf(const T &x)
Probability density function.
Definition prrng.h:1366
Normal distribution.
Definition prrng.h:1593
normal_distribution(double mu=0, double sigma=1)
Constructor.
Definition prrng.h:1601
T pdf(const T &x)
Probability density function.
Definition prrng.h:1615
T quantile(const T &p)
Quantile (the inverse of the cumulative density function).
Definition prrng.h:1649
T cdf(const T &x)
Cumulative density function.
Definition prrng.h:1634
Pareto distribution.
Definition prrng.h:1444
T cdf(const T &x)
Cumulative density function.
Definition prrng.h:1479
T quantile(const T &p)
Quantile (the inverse of the cumulative density function).
Definition prrng.h:1491
pareto_distribution(double k=1, double scale=1)
Constructor.
Definition prrng.h:1452
T pdf(const T &x)
Probability density function.
Definition prrng.h:1467
Array of generators of which a chunk of random numbers is kept in memory.
Definition prrng.h:5795
void auto_functions()
Set draw function.
Definition prrng.h:5896
pcg32_arrayBase_chunkBase & operator-=(const T &values)
Subtract values from each chunk.
Definition prrng.h:6089
std::array< double, 3 > m_param
Distribution parameters.
Definition prrng.h:5826
void align_at(const Index &index)
Get the index random number, which index specified per generator.
Definition prrng.h:6165
const Index & start() const
Global index of the first element in the chunk.
Definition prrng.h:6142
Index index_at_align() const
Global index of target (the last time prrng::pcg32_cumsum::align() was called).
Definition prrng.h:6201
const Index & chunk_index_at_align() const
Index of target relative to the beginning of the chunk (the last time prrng::pcg32_cumsum::align() wa...
Definition prrng.h:6209
void left_of_align(R &ret) const
Return the value of the cumsum left of the target (the last time prrng::pcg32_cumsum::align() was cal...
Definition prrng.h:6219
void operator=(const pcg32_arrayBase_chunkBase &other)
Copy constructor.
Definition prrng.h:6068
bool m_extendible
Signal if the drawing functions are specified, implying that the chunk can be changed.
Definition prrng.h:5822
size_t m_n
Size of the chunk.
Definition prrng.h:5829
pcg32_arrayBase_chunkBase(const pcg32_arrayBase_chunkBase &other)
Copy constructor.
Definition prrng.h:6060
void set_data(const Data &data)
Overwrite the current chunk of the cumsum of random numbers.
Definition prrng.h:6133
void right_of_align(R &ret) const
Return the value of the cumsum right of the target (the last time prrng::pcg32_cumsum::align() was ca...
Definition prrng.h:6234
std::vector< std::function< double(size_t)> > m_sum
Function to get the cumsum of n random numbers starting from the curent state of the generator (used ...
Definition prrng.h:5817
void init(const S &shape, const T &initstate, const U &initseq, enum distribution distribution, const std::vector< double > &parameters, const alignment &align=alignment())
Constructor.
Definition prrng.h:5842
pcg32_arrayBase_chunkBase & operator+=(const T &values)
Add values to each chunk.
Definition prrng.h:6078
void copy_from(const pcg32_arrayBase_chunkBase &other)
Copy constructor.
Definition prrng.h:6041
alignment m_align
alignment settings, see prrng::alignment().
Definition prrng.h:5824
Generator m_gen
Array of generators.
Definition prrng.h:5802
R right_of_align() const
Return the value of the cumsum right of the target (the last time prrng::pcg32_cumsum::align() was ca...
Definition prrng.h:6259
const Generator & generators() const
Reference to the underlying generators.
Definition prrng.h:6117
void set_start(const Index &index)
Set global index of the first element in the chunk.
Definition prrng.h:6150
const Data & data() const
The current chunk of the cumsum of random numbers.
Definition prrng.h:6125
Index m_start
Start index of the chunk.
Definition prrng.h:5827
R state_at(const T &index)
The current "state" of the generator.
Definition prrng.h:6270
std::vector< std::function< xt::xtensor< double, 1 >(size_t)> > m_draw
Function to draw the next chunk of n random numbers starting from the curent state of the generator.
Definition prrng.h:5810
Index m_i
Last known index of target in align.
Definition prrng.h:5828
typename Data::size_type size_type
Size type of the data container.
Definition prrng.h:5799
size_type chunk_size() const
Size of the chunk per generator.
Definition prrng.h:6108
R left_of_align() const
Return the value of the cumsum left of the target (the last time prrng::pcg32_cumsum::align() was cal...
Definition prrng.h:6248
bool is_extendible() const
true if the chunk is extendible.
Definition prrng.h:6099
distribution m_distro
Distribution name, see prrng::distribution().
Definition prrng.h:5825
Data m_data
Data container.
Definition prrng.h:5803
Array of generators of which a chunk of random numbers is kept in memory.
Definition prrng.h:6289
typename Data::value_type value_type
Value type of the data container.
Definition prrng.h:6301
void restore(const S &state, const T &index)
Restore the generator somewhere in the sequence.
Definition prrng.h:6312
typename Data::size_type size_type
Size type of the data container.
Definition prrng.h:6300
typename Data::size_type size_type
Size type of the data container.
Definition prrng.h:6356
void restore(const S &state, const V &value, const T &index)
Restore a specific state in the cumulative sum.
Definition prrng.h:6425
bool contains(const T &target) const
Check if the chunk contains a target.
Definition prrng.h:6448
void align(size_t i, double target)
Align the chunk to encompass a target value.
Definition prrng.h:6396
void align(const T &target)
Align the chunk to encompass a target value.
Definition prrng.h:6365
Base class, see pcg32_array for description.
Definition prrng.h:5048
Generator & flat(size_t i)
Return a reference to one generator, using a flat index.
Definition prrng.h:5157
Generator & operator()(Args... args)
Return a reference to one generator, using an array index.
Definition prrng.h:5110
void advance(const T &arg)
Advance generators.
Definition prrng.h:5311
auto initstate() -> typename detail::return_type< uint64_t, Shape >::type
Return the state initiator of all generators.
Definition prrng.h:5212
void draw_list_uint32(uint32_t *data, uint32_t bound, size_t n)
Draw n random numbers per array item, and write them to the correct position in data (assuming row-ma...
Definition prrng.h:5500
std::vector< Generator > m_gen
Underlying storage: one generator per array item.
Definition prrng.h:5531
R initstate()
Return the state initiator of all generators.
Definition prrng.h:5224
auto state() -> typename detail::return_type< uint64_t, Shape >::type
Return the state of all generators.
Definition prrng.h:5181
void cumsum_weibull_impl(double *ret, const size_t *n, double k, double scale)
Return the result of the cumulative sum of n random numbers.
Definition prrng.h:5439
auto distance(const T &arg) -> typename detail::return_type< int64_t, Shape >::type
Distance between two states.
Definition prrng.h:5275
void decide_masked_impl(const double *p, const bool *mask, bool *ret)
For each p take a decision.
Definition prrng.h:5354
void decide_impl(const double *p, bool *ret)
For each p take a decision.
Definition prrng.h:5341
R state()
Return the state of all generators.
Definition prrng.h:5194
auto initseq() -> typename detail::return_type< uint64_t, Shape >::type
Return the sequence initiator of all generators.
Definition prrng.h:5242
void draw_list_double(double *data, size_t n)
Draw n random numbers per array item, and write them to the correct position in data (assuming row-ma...
Definition prrng.h:5467
void cumsum_power_impl(double *ret, const size_t *n, double k)
Return the result of the cumulative sum of n random numbers.
Definition prrng.h:5397
void init(const T &initstate)
Constructor alias.
Definition prrng.h:5066
typename Shape::value_type size_type
Size type.
Definition prrng.h:5055
void cumsum_normal_impl(double *ret, const size_t *n, double mu, double sigma)
Return the result of the cumulative sum of n random numbers.
Definition prrng.h:5453
void cumsum_gamma_impl(double *ret, const size_t *n, double k, double scale)
Return the result of the cumulative sum of n random numbers.
Definition prrng.h:5411
Generator & operator[](size_t i)
Return a reference to one generator, using a flat index.
Definition prrng.h:5133
R initseq()
Return the sequence initiator of all generators.
Definition prrng.h:5255
void cumsum_pareto_impl(double *ret, const size_t *n, double k, double scale)
Return the result of the cumulative sum of n random numbers.
Definition prrng.h:5425
void restore(const T &arg)
Restore generators from a state.
Definition prrng.h:5328
const Generator & flat(size_t i) const
Return a constant reference to one generator, using a flat index.
Definition prrng.h:5169
Shape shape_type
Shape type.
Definition prrng.h:5056
void cumsum_random_impl(double *ret, const size_t *n)
Return the result of the cumulative sum of n random numbers.
Definition prrng.h:5371
const Generator & operator[](size_t i) const
Return a constant reference to one generator, using a flat index.
Definition prrng.h:5145
R distance(const T &arg)
Distance between two states.
Definition prrng.h:5290
const Generator & operator()(Args... args) const
Return a constant reference to one generator, using an array index.
Definition prrng.h:5122
void draw_list_positive_double(double *data, size_t n)
Draw n random numbers per array item, and write them to the correct position in data (assuming row-ma...
Definition prrng.h:5483
void init(const T &initstate, const U &initseq)
Constructor alias.
Definition prrng.h:5086
void cumsum_exponential_impl(double *ret, const size_t *n, double scale)
Return the result of the cumulative sum of n random numbers.
Definition prrng.h:5384
Array of generators of which a chunk of the random sequence is kept in memory.
Definition prrng.h:6468
pcg32_array_chunk(const S &shape, const T &initstate, const U &initseq, enum distribution distribution, const std::vector< double > &parameters, const alignment &align=alignment())
Definition prrng.h:6476
Array of generators of a random cumulative sum, see prrng::pcg32_cumsum().
Definition prrng.h:6528
pcg32_array_cumsum(const S &shape, const T &initstate, const U &initseq, enum distribution distribution, const std::vector< double > &parameters, const alignment &align=alignment())
Definition prrng.h:6540
Array of independent generators.
Definition prrng.h:5558
pcg32_array(const T &initstate, const U &initseq)
Constructor.
Definition prrng.h:5590
std::vector< size_t > shape_type
Shape type.
Definition prrng.h:5564
size_t size_type
Size type.
Definition prrng.h:5563
pcg32_array(const T &initstate)
Constructor.
Definition prrng.h:5575
Generator of a random cumulative sum of which a chunk is kept in memory.
Definition prrng.h:3504
double right_of_align() const
Return the value of the cumsum right of the target (the last time prrng::pcg32_cumsum::align() was ca...
Definition prrng.h:3866
const auto & shape() const
Shape of the chunk.
Definition prrng.h:3737
void restore(uint64_t state, double value, ptrdiff_t index)
Restore a specific state in the cumulative sum.
Definition prrng.h:3886
const Data & data() const
The current chunk of the cumsum of random numbers.
Definition prrng.h:3777
pcg32_cumsum(const R &shape, T initstate=0x853c49e6748fea9bULL, S initseq=0xda3e39cb94b95bdbULL, enum distribution distribution=distribution::custom, const std::vector< double > &parameters=std::vector< double >{}, const alignment &align=alignment())
Definition prrng.h:3648
pcg32_cumsum & operator-=(const T &value)
Subtract value(s) from the chunk.
Definition prrng.h:3767
pcg32_cumsum & operator+=(const T &value)
Add value(s) to the chunk.
Definition prrng.h:3756
ptrdiff_t chunk_index_at_align() const
Index of target relative to the beginning of the chunk (the last time prrng::pcg32_cumsum::align() wa...
Definition prrng.h:3842
const pcg32_index & generator() const
Pointer to the generator.
Definition prrng.h:3728
void operator=(const pcg32_cumsum &other)
Copy constructor.
Definition prrng.h:3710
void set_functions(std::function< Data(size_t)> get_chunk, std::function< double(size_t)> get_cumsum, bool uses_generator=true)
Use external functions to draw the random numbers.
Definition prrng.h:3682
void align(double target)
Align the chunk to encompass a target value.
Definition prrng.h:3945
ptrdiff_t start() const
Global index of the first element in the chunk.
Definition prrng.h:3798
bool contains(double target) const
Check if the chunk contains a target.
Definition prrng.h:3904
void set_data(const Data &data)
Overwrite the current chunk of the cumsum of random numbers.
Definition prrng.h:3788
void next(size_t margin=0)
Shift chunk right.
Definition prrng.h:3924
ptrdiff_t index_at_align() const
Global index of target (the last time prrng::pcg32_cumsum::align() was called).
Definition prrng.h:3826
auto size() const
Size of the chunk.
Definition prrng.h:3746
void set_start(ptrdiff_t index)
Set global index of the first element in the chunk.
Definition prrng.h:3807
double left_of_align() const
Return the value of the cumsum left of the target (the last time prrng::pcg32_cumsum::align() was cal...
Definition prrng.h:3854
bool is_extendible() const
true if the chunk is extendible.
Definition prrng.h:3719
pcg32_cumsum(const pcg32_cumsum &other)
Copy constructor.
Definition prrng.h:3702
uint64_t state_at(ptrdiff_t index)
The current "state" of the generator.
Definition prrng.h:3874
void prev(size_t margin=0)
Shift chunk left.
Definition prrng.h:3913
Array of prrng::pcg32_index().
Definition prrng.h:5655
pcg32_index_array(const T &initstate, const U &initseq)
Constructor.
Definition prrng.h:5670
Fixed rank version of pcg32_index_array.
Definition prrng.h:5688
pcg32_index_tensor(const T &initstate, const U &initseq)
Constructor.
Definition prrng.h:5703
Overload of prrng::pcg32() that keeps track of the current index of the generator in the sequence.
Definition prrng.h:3329
void jump_to(ptrdiff_t index)
Move to a certain index.
Definition prrng.h:3379
void set_delta(bool delta)
Signal if the generator is uniquely used to draw a delta distribution.
Definition prrng.h:3404
uint64_t state_at(ptrdiff_t index)
State at a specific index of the sequence.
Definition prrng.h:3363
void set_index(ptrdiff_t index)
Overwrite the generator index.
Definition prrng.h:3422
pcg32_index(T initstate=0x853c49e6748fea9bULL, S initseq=0xda3e39cb94b95bdbULL, bool delta=false)
Definition prrng.h:3341
ptrdiff_t index() const
Get the generator index.
Definition prrng.h:3413
void drawn(ptrdiff_t n)
Update the generator index with the number of items you have drawn.
Definition prrng.h:3392
Array of generators of which a chunk of the random sequence is kept in memory.
Definition prrng.h:6494
pcg32_tensor_chunk(const S &shape, const T &initstate, const U &initseq, enum distribution distribution, const std::vector< double > &parameters, const alignment &align=alignment())
Definition prrng.h:6502
Array of generators of a random cumulative sum, see prrng::pcg32_cumsum().
Definition prrng.h:6567
pcg32_tensor_cumsum(const S &shape, const T &initstate, const U &initseq, enum distribution distribution, const std::vector< double > &parameters, const alignment &align=alignment())
Definition prrng.h:6575
Fixed rank version of pcg32_array.
Definition prrng.h:5608
std::array< size_t, N > shape_type
Shape type.
Definition prrng.h:5614
pcg32_tensor(const T &initstate, const U &initseq)
Constructor.
Definition prrng.h:5639
pcg32_tensor(const T &initstate)
Constructor.
Definition prrng.h:5625
size_t size_type
Size type.
Definition prrng.h:5613
Random number generate using the pcg32 algorithm.
Definition prrng.h:2873
R distance(T other_state) const
The distance between two states.
Definition prrng.h:3220
bool operator==(const pcg32 &other) const
Equality operator.
Definition prrng.h:3298
uint32_t operator()()
Draw new random number (uniformly distributed, 0 <= r <= max(uint32_t)).
Definition prrng.h:2915
uint64_t m_initseq
Sequence initiator.
Definition prrng.h:3317
int64_t operator-(const pcg32 &other) const
The distance between two PCG32 pseudorandom number generators.
Definition prrng.h:3153
uint64_t initstate() const
The state initiator that was used upon construction.
Definition prrng.h:3078
double next_double()
Generate a double precision floating point value on the interval [0, 1).
Definition prrng.h:3008
R distance(const pcg32 &other) const
The distance between two PCG32 pseudorandom number generators.
Definition prrng.h:3189
uint32_t next_uint32()
Draw new random number (uniformly distributed, 0 <= r <= max(uint32_t)).
Definition prrng.h:2932
uint64_t state() const
The current "state" of the generator.
Definition prrng.h:3046
uint32_t next_uint32(uint32_t bound)
Draw new random number (uniformly distributed, 0 <= r <= bound).
Definition prrng.h:2945
void restore(T state)
Restore a given state in the sequence.
Definition prrng.h:3144
double next_positive_double()
Generate a double precision floating point value on the interval (0, 1).
Definition prrng.h:3024
R state()
The current "state" of the generator.
Definition prrng.h:3058
float next_float()
Generate a single precision floating point value on the interval [0, 1).
Definition prrng.h:2985
R initseq() const
The sequence initiator that was used upon construction.
Definition prrng.h:3122
bool operator!=(const pcg32 &other) const
Inequality operator.
Definition prrng.h:3310
void seed(uint64_t initstate=0x853c49e6748fea9bULL, uint64_t initseq=0xda3e39cb94b95bdbULL)
Seed the generator (constructor alias).
Definition prrng.h:2895
uint64_t m_initstate
State initiator.
Definition prrng.h:3316
uint64_t m_state
RNG state. All values are possible.
Definition prrng.h:3318
void advance(T distance)
Multi-step advance function (jump-ahead, jump-back).
Definition prrng.h:3264
R initstate() const
The state initiator that was used upon construction.
Definition prrng.h:3090
pcg32(T initstate=0x853c49e6748fea9bULL, S initseq=0xda3e39cb94b95bdbULL)
Constructor.
Definition prrng.h:2882
uint64_t initseq() const
The sequence initiator that was used upon construction.
Definition prrng.h:3110
uint64_t m_inc
Controls which RNG sequence (stream) is selected. Must always be odd.
Definition prrng.h:3319
Power distribution.
Definition prrng.h:1282
power_distribution(double k=1)
Constructor.
Definition prrng.h:1289
T cdf(const T &x)
Cumulative density function.
Definition prrng.h:1313
T quantile(const T &p)
Quantile (the inverse of the cumulative density function).
Definition prrng.h:1325
T pdf(const T &x)
Probability density function.
Definition prrng.h:1301
Weibull distribution.
Definition prrng.h:1509
T cdf(const T &x)
Cumulative density function.
Definition prrng.h:1559
weibull_distribution(double k=1, double scale=1)
Constructor.
Definition prrng.h:1517
T quantile(const T &p)
Quantile (the inverse of the cumulative density function).
Definition prrng.h:1574
T pdf(const T &x)
Probability density function.
Definition prrng.h:1530
Portable Reconstructible (Pseudo!) Random Number Generator.
Definition prrng.h:188
std::vector< std::string > version_compiler()
Information on the compiler, the platform, the C++ standard, and the compilation date.
Definition prrng.h:617
std::vector< double > default_parameters(enum distribution distribution, const std::vector< double > &parameters=std::vector< double >{})
Definition prrng.h:225
distribution
Distribution identifier.
Definition prrng.h:193
@ delta
delta
Definition prrng.h:195
@ gamma
gamma
Definition prrng.h:198
@ random
flat
Definition prrng.h:194
@ normal
normal
Definition prrng.h:201
@ exponential
exponential
Definition prrng.h:196
@ power
power
Definition prrng.h:197
@ custom
unknown
Definition prrng.h:202
@ pareto
pareto
Definition prrng.h:199
@ weibull
weibull
Definition prrng.h:200
std::string version()
Version string, e.g.
Definition prrng.h:547
std::vector< std::string > version_dependencies()
Versions of this library and of all of its dependencies.
Definition prrng.h:563
auto auto_pcg32(const T &initstate)
Return a pcg32, a pcg32_array, or a pcg32_tensor based on input.
Definition prrng.h:5769
R lower_bound(const T &matrix, const V &value, const R &index, size_t proximity=10)
Iterating on the last axis of an nd-array (e.g.
Definition prrng.h:837
V cumsum_chunk(const V &cumsum, const V &delta, const I &shift)
Update the chunk of a cumsum computed and stored in chunks.
Definition prrng.h:898
#define PRRNG_PCG32_MULT
Multiplicative factor for pcg32() (used internally, cannot be overwritten at run-time).
Definition prrng.h:39
#define PRRNG_PCG32_INITSTATE
Default initialisation state for pcg32() (used as constructor parameter that can be overwritten at ru...
Definition prrng.h:27
R lower_bound(const It first, const It last, const T &value, R guess=0, R proximity=10)
Return index of the first element in the range [first, last) such that element < value is false (i....
Definition prrng.h:694
#define PRRNG_VERSION
Library version.
Definition prrng.h:106
void cumsum_chunk(V &cumsum, const V &delta, const I &shift)
Update the chunk of a cumsum computed and stored in chunks.
Definition prrng.h:771
#define PRRNG_DEBUG(expr)
All debug assertions are implementation as:
Definition prrng.h:152
#define PRRNG_PCG32_INITSEQ
Default initialisation sequence for pcg32() (used as constructor parameter that can be overwritten at...
Definition prrng.h:33
#define PRRNG_ASSERT(expr)
All assertions are implementation as:
Definition prrng.h:129
Structure to assemble the alignment parameters.
Definition prrng.h:3433
bool strict
If true, margin is respected strictly: argmin(target > chunk) == margin.
Definition prrng.h:3482
ptrdiff_t margin
Index of the chunk to place the target.
Definition prrng.h:3470
ptrdiff_t min_margin
Minimal index to accept if strict = false.
Definition prrng.h:3475
ptrdiff_t buffer
If positive, only change the chunk if target is in chunk[:buffer] or chunk[-buffer:].
Definition prrng.h:3465
alignment(ptrdiff_t buffer=0, ptrdiff_t margin=0, ptrdiff_t min_margin=0, bool strict=false)
Definition prrng.h:3449