diff --git a/array.h b/array.h index 2eec3ce..69bc377 100644 --- a/array.h +++ b/array.h @@ -58,11 +58,15 @@ class GenericArray : public ReprProxy>, public std::vector { template static GenericArray randomfUnique( size_t size, F func, const Args& ... args); + template + static GenericArray randomfAll(F func, const Args& ... args); template static GenericArray random(size_t size, const Args& ... args); template static GenericArray randomUnique(size_t size, const Args& ... args); + template + static GenericArray randomAll(const Args& ... args); static GenericArray id(size_t size, T start = T{}); @@ -184,6 +188,43 @@ GenericArray GenericArray::randomUnique( args...); } +template +template +GenericArray GenericArray::randomfAll( + F func, + const Args& ... args) +{ + typename detail::DictContainer::type set; + GenericArray result; + + int timeAfterLastHit = 0; + + while (true) { + T t = func(args...); + if (!set.count(t)) { + set.insert(t); + result.push_back(t); + timeAfterLastHit = 0; + } + + ++timeAfterLastHit; + + // Probability of finding not all elements is about e^{-20} ~= 1e-9 + if (timeAfterLastHit > (result.size() + 10) * 20) { + return result; + } + } +} + +template +template +GenericArray GenericArray::randomAll(const Args& ... args) +{ + return GenericArray::randomfAll( + [](Args... args) { return rnd.tnext(args...); }, + args...); +} + template GenericArray GenericArray::id(size_t size, T start) { constexpr bool enable = std::is_integral::value; diff --git a/jngen.h b/jngen.h index b9ff06a..7444847 100644 --- a/jngen.h +++ b/jngen.h @@ -830,30 +830,43 @@ struct TypedRandom : public BaseTypedRandom { T next(Args... args) { return random.next(args...); } }; -struct OrderedPairTag {} opair; +struct RandomPairTraits { + const bool ordered; + const bool distinct; +}; + +RandomPairTraits opair{true, false}; +RandomPairTraits dpair{false, true}; +RandomPairTraits odpair{true, true}; +RandomPairTraits dopair{true, true}; template<> struct TypedRandom> : public BaseTypedRandom { using BaseTypedRandom::BaseTypedRandom; std::pair next(int n) { - // can't write 'return {random.next(n), random.next(n)}' because order of - // evaluation of function arguments is unspecified. - int first = random.next(n); - int second = random.next(n); - return {first, second}; + return next(n, {false, false}); } std::pair next(int l, int r) { - int first = random.next(l, r); - int second = random.next(l, r); - return {first, second}; + return next(l, r, {false, false}); } - std::pair next(int n, OrderedPairTag) { - return ordered(next(n)); + std::pair next(int n, RandomPairTraits traits) { + int first = rnd.next(n); + int second; + do { + second = rnd.next(n); + } while (traits.distinct && first == second); + if (traits.ordered && first > second) { + std::swap(first, second); + } + return {first, second}; } - std::pair next(int l, int r, OrderedPairTag) { - return ordered(next(l, r)); + std::pair next(int l, int r, RandomPairTraits traits) { + auto res = next(r-l+1, traits); + res.first += l; + res.second += l; + return res; } private: @@ -871,6 +884,9 @@ using jngen::Random; using jngen::rnd; using jngen::opair; +using jngen::dpair; +using jngen::dopair; +using jngen::odpair; void registerGen(int argc, char *argv[], int version = 1) { (void)version; // unused, only for testlib.h compatibility @@ -1438,11 +1454,15 @@ class GenericArray : public ReprProxy>, public std::vector { template static GenericArray randomfUnique( size_t size, F func, const Args& ... args); + template + static GenericArray randomfAll(F func, const Args& ... args); template static GenericArray random(size_t size, const Args& ... args); template static GenericArray randomUnique(size_t size, const Args& ... args); + template + static GenericArray randomAll(const Args& ... args); static GenericArray id(size_t size, T start = T{}); @@ -1564,6 +1584,43 @@ GenericArray GenericArray::randomUnique( args...); } +template +template +GenericArray GenericArray::randomfAll( + F func, + const Args& ... args) +{ + typename detail::DictContainer::type set; + GenericArray result; + + int timeAfterLastHit = 0; + + while (true) { + T t = func(args...); + if (!set.count(t)) { + set.insert(t); + result.push_back(t); + timeAfterLastHit = 0; + } + + ++timeAfterLastHit; + + // Probability of finding not all elements is about e^{-20} ~= 1e-9 + if (timeAfterLastHit > (result.size() + 10) * 20) { + return result; + } + } +} + +template +template +GenericArray GenericArray::randomAll(const Args& ... args) +{ + return GenericArray::randomfAll( + [](Args... args) { return rnd.tnext(args...); }, + args...); +} + template GenericArray GenericArray::id(size_t size, T start) { constexpr bool enable = std::is_integral::value; @@ -2058,6 +2115,15 @@ class ArrayRandom { typedef decltype(func(args...)) T; return GenericArray::randomfUnique(size, func, args...); } + + template + static auto randomfAll( + F func, + Args... args) -> GenericArray + { + typedef decltype(func(args...)) T; + return GenericArray::randomfAll(size, func, args...); + } } rnda; } // namespace jngen diff --git a/random.h b/random.h index b2f72d8..6659172 100644 --- a/random.h +++ b/random.h @@ -246,30 +246,43 @@ struct TypedRandom : public BaseTypedRandom { T next(Args... args) { return random.next(args...); } }; -struct OrderedPairTag {} opair; +struct RandomPairTraits { + const bool ordered; + const bool distinct; +}; + +RandomPairTraits opair{true, false}; +RandomPairTraits dpair{false, true}; +RandomPairTraits odpair{true, true}; +RandomPairTraits dopair{true, true}; template<> struct TypedRandom> : public BaseTypedRandom { using BaseTypedRandom::BaseTypedRandom; std::pair next(int n) { - // can't write 'return {random.next(n), random.next(n)}' because order of - // evaluation of function arguments is unspecified. - int first = random.next(n); - int second = random.next(n); - return {first, second}; + return next(n, {false, false}); } std::pair next(int l, int r) { - int first = random.next(l, r); - int second = random.next(l, r); - return {first, second}; + return next(l, r, {false, false}); } - std::pair next(int n, OrderedPairTag) { - return ordered(next(n)); + std::pair next(int n, RandomPairTraits traits) { + int first = rnd.next(n); + int second; + do { + second = rnd.next(n); + } while (traits.distinct && first == second); + if (traits.ordered && first > second) { + std::swap(first, second); + } + return {first, second}; } - std::pair next(int l, int r, OrderedPairTag) { - return ordered(next(l, r)); + std::pair next(int l, int r, RandomPairTraits traits) { + auto res = next(r-l+1, traits); + res.first += l; + res.second += l; + return res; } private: @@ -287,6 +300,9 @@ using jngen::Random; using jngen::rnd; using jngen::opair; +using jngen::dpair; +using jngen::dopair; +using jngen::odpair; void registerGen(int argc, char *argv[], int version = 1) { (void)version; // unused, only for testlib.h compatibility diff --git a/rnda.h b/rnda.h index 6c042e6..02c3ebd 100644 --- a/rnda.h +++ b/rnda.h @@ -32,6 +32,15 @@ class ArrayRandom { typedef decltype(func(args...)) T; return GenericArray::randomfUnique(size, func, args...); } + + template + static auto randomfAll( + F func, + Args... args) -> GenericArray + { + typedef decltype(func(args...)) T; + return GenericArray::randomfAll(size, func, args...); + } } rnda; } // namespace jngen