1#pragma once23#include "common.h"4#include "pattern.h"56#include <algorithm>7#include <cmath>8#include <cstdlib>9#include <iterator>10#include <limits>11#include <random>12#include <string>13#include <type_traits>14#include <utility>15#include <vector>1617namespace jngen {1819void assertRandomEngineConsistency();20void assertIntegerSizes();21void registerGen(int argc, char *argv[], int version = 1);2223class Random;2425class BaseTypedRandom {26public:27 BaseTypedRandom(Random& random) : random(random) {}2829protected:30 Random& random;31};3233template<typename T>34struct TypedRandom;3536uint64_t maskForBound(uint64_t bound);3738template<typename Result, typename Source>39Result uniformRandom(Result bound, Random& random, Source (Random::*method)()) {40 static_assert(sizeof(Result) <= sizeof(Source),41 "uniformRandom: Source type must be at least as large as Result type");42#ifdef JNGEN_FAST_RANDOM43 return (random.*method)() % bound;44#else45 Source mask = maskForBound(bound);46 while (true) {47 Source outcome = (random.*method)() & mask;48 if (outcome < static_cast<Source>(bound)) {49 return outcome;50 }51 }52#endif53}5455class Random {56public:57 Random() {58 assertRandomEngineConsistency();59 assertIntegerSizes();60 std::vector<uint32_t> seedSeq;61 // 4 random_device calls is enough for everyone62 std::random_device rd;63 for (size_t i = 0; i < 4; ++i) {64 seedSeq.push_back(rd());65 }66 seed(seedSeq);6768 }6970 void seed(uint32_t val);71 void seed(const std::vector<uint32_t>& seed);7273 uint32_t next();74 uint64_t next64();75 double nextf();7677 int next(int n);78 long long next(long long n);79 size_t next(size_t n);80 double next(double n);8182 int next(int l, int r);83 long long next(long long l, long long r);84 size_t next(size_t l, size_t r);85 double next(double l, double r);8687 int wnext(int n, int w);88 long long wnext(long long n, int w);89 size_t wnext(size_t n, int w);90 double wnext(double n, int w);9192 int wnext(int l, int r, int w);93 long long wnext(long long l, long long r, int w);94 size_t wnext(size_t l, size_t r, int w);95 double wnext(double l, double r, int w);9697 std::string next(const std::string& pattern);9899 template<typename ... Args>100 std::string next(const std::string& pattern, Args... args) {101 return next(format(pattern, args...));102 }103104 template<typename T, typename ... Args>105 T tnext(Args... args) {106 return TypedRandom<T>{*this}.next(args...);107 }108109 template<typename ... Args>110 std::pair<int, int> nextp(Args... args) {111 return tnext<std::pair<int, int>>(args...);112 }113114 template<typename Iterator>115 auto choice(Iterator begin, Iterator end)116 -> typename std::iterator_traits<Iterator>::value_type117 {118 auto length = std::distance(begin, end);119 ensure(length > 0, "Cannot select from a range of negative length");120 size_t index = tnext<size_t>(length);121 std::advance(begin, index);122 return *begin;123 }124125 template<typename Container>126 typename Container::value_type choice(const Container& container) {127 ensure(!container.empty(), "Cannot select from an empty container");128 return choice(container.begin(), container.end());129 }130131 template<typename T>132 T choice(const std::initializer_list<T>& ilist) {133 return choice(ilist.begin(), ilist.end());134 }135136 template<typename Numeric>137 size_t nextByDistribution(const std::vector<Numeric>& distribution) {138 ensure(!distribution.empty(), "Cannot sample by empty distribution");139 Numeric sum = std::accumulate(140 distribution.begin(), distribution.end(), Numeric(0));141 auto x = next(sum);142 for (size_t i = 0; i < distribution.size(); ++i) {143 if (x < distribution[i]) {144 return i;145 }146 x -= distribution[i];147 }148 return distribution.size() - 1;149 }150151 template<typename Numeric>152 size_t nextByDistribution(const std::initializer_list<Numeric>& ilist) {153 // TODO: looks suboptimal154 return nextByDistribution(std::vector<Numeric>(ilist));155 }156157private:158 template<typename T, typename ...Args>159 T smallWnext(int w, Args... args) {160 ENSURE(std::abs(w) <= WNEXT_LIMIT);161 T result = next(args...);162 while (w > 0) {163 result = std::max(result, next(args...));164 --w;165 }166 while (w < 0) {167 result = std::min(result, next(args...));168 ++w;169 }170 return result;171 }172173 double realWnext(int w) {174 if (w == 0) {175 return nextf();176 } else if (w > 0) {177 return std::pow(nextf(), 1.0 / (w + 1));178 } else {179 return 1.0 - std::pow(nextf(), 1.0 / (-w + 1));180 }181 }182183 std::mt19937 randomEngine_;184 constexpr static int WNEXT_LIMIT = 8;185};186187JNGEN_EXTERN Random rnd;188189template<>190struct TypedRandom<int> : public BaseTypedRandom {191 using BaseTypedRandom::BaseTypedRandom;192 int next(int n) { return random.next(n); }193 int next(int l, int r) { return random.next(l, r); }194};195196template<>197struct TypedRandom<double> : public BaseTypedRandom {198 using BaseTypedRandom::BaseTypedRandom;199 double next(double n) { return random.next(n); }200 double next(double l, double r) { return random.next(l, r); }201};202203template<>204struct TypedRandom<long double> : public BaseTypedRandom {205 using BaseTypedRandom::BaseTypedRandom;206 double next(double n) { return random.next(n); }207 double next(double l, double r) { return random.next(l, r); }208};209210template<>211struct TypedRandom<long long> : public BaseTypedRandom {212 using BaseTypedRandom::BaseTypedRandom;213 long long next(long long n) { return random.next(n); }214 long long next(long long l, long long r) { return random.next(l, r); }215};216217template<>218struct TypedRandom<size_t> : public BaseTypedRandom {219 using BaseTypedRandom::BaseTypedRandom;220 size_t next(size_t n) { return random.next(n); }221 size_t next(size_t l, size_t r) { return random.next(l, r); }222};223224template<>225struct TypedRandom<char> : public BaseTypedRandom {226 using BaseTypedRandom::BaseTypedRandom;227 char next(char n) { return random.next(n); }228 char next(char l, char r) { return random.next(l, r); }229};230231template<typename T>232struct TypedRandom : public BaseTypedRandom {233 using BaseTypedRandom::BaseTypedRandom;234 template<typename ... Args>235 T next(Args... args) { return random.next(args...); }236};237238struct RandomPairTraits {239 const bool ordered;240 const bool distinct;241};242243#ifdef JNGEN_DECLARE_ONLY244extern RandomPairTraits opair, dpair, odpair, dopair;245#else246RandomPairTraits opair{true, false};247RandomPairTraits dpair{false, true};248RandomPairTraits odpair{true, true};249RandomPairTraits dopair{true, true};250#endif251252template<>253struct TypedRandom<std::pair<int, int>> : public BaseTypedRandom {254 using BaseTypedRandom::BaseTypedRandom;255256 std::pair<int, int> next(int n) {257 return next(n, {false, false});258 }259 std::pair<int, int> next(int l, int r) {260 return next(l, r, {false, false});261 }262263 std::pair<int, int> next(int n, RandomPairTraits traits) {264 int first = rnd.next(n);265 int second;266 do {267 second = rnd.next(n);268 } while (traits.distinct && first == second);269 if (traits.ordered && first > second) {270 std::swap(first, second);271 }272 return {first, second};273 }274 std::pair<int, int> next(int l, int r, RandomPairTraits traits) {275 auto res = next(r-l+1, traits);276 res.first += l;277 res.second += l;278 return res;279 }280281private:282 std::pair<int, int> ordered(std::pair<int, int> pair) const {283 if (pair.first > pair.second) {284 std::swap(pair.first, pair.second);285 }286 return pair;287 }288};289290} // namespace jngen291292using jngen::Random;293294using jngen::rnd;295using jngen::opair;296using jngen::dpair;297using jngen::dopair;298using jngen::odpair;299300using jngen::registerGen;301302#ifndef JNGEN_DECLARE_ONLY303#define JNGEN_INCLUDE_RANDOM_INL_H304#include "impl/random_inl.h"305#undef JNGEN_INCLUDE_RANDOM_INL_H306#endif // JNGEN_DECLARE_ONLY