/*  Copyright (C) 2015  Povilas Kanapickas <povilas@radix.lt>

    This file is part of cppreference-doc

    This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
    Unported License. To view a copy of this license, visit
    http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
    Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.

    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.3 or
    any later version published by the Free Software Foundation; with no
    Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
*/

#ifndef CPPREFERENCE_RANDOM_H
#define CPPREFERENCE_RANDOM_H

#if CPPREFERENCE_STDVER >= 2011
#include <initializer_list>

namespace std {

template <
    class UIntType,
    UIntType a,
    UIntType c,
    UIntType m
    > class linear_congruential_engine {
public:
    typedef UIntType result_type;
    static constexpr UIntType multiplier;
    static constexpr UIntType increment;
    static constexpr UIntType modulus;
    static constexpr UIntType default_seed;

    explicit linear_congruential_engine(result_type value = default_seed);

    template<class Sseq >
    explicit linear_congruential_engine(Sseq& s);

    linear_congruential_engine(const linear_congruential_engine&);

    void seed(result_type value = default_seed);

    template<class Sseq >
    void seed(Sseq& seq);

    result_type operator()();

    void discard(unsigned long long z);

    static constexpr result_type min();
    static constexpr result_type max();
};

template<class UIntType, UIntType a, UIntType c, UIntType m >
bool operator==(const linear_congruential_engine<UIntType, a, c, m>& lhs,
                const linear_congruential_engine<UIntType, a, c, m>& rhs);

template<class UIntType, UIntType a, UIntType c, UIntType m >
bool operator==(const linear_congruential_engine<UIntType, a, c, m>& lhs,
                const linear_congruential_engine<UIntType, a, c, m>& rhs);

template<class CharT, class Traits, class ResultType,
         class UIntType, UIntType a, UIntType c, UIntType m >
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& ost,
           const linear_congruential_engine<UIntType, a, c, m>& e);

template<class CharT, class Traits, class ResultType,
         class UIntType, UIntType a, UIntType c, UIntType m >
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& ist,
           linear_congruential_engine<UIntType, a, c, m>& e);

typedef std::linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
typedef std::linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647> minstd_rand;

template <
    class UIntType,
    size_t w, size_t n, size_t m, size_t r,
    UIntType a, size_t u, UIntType d, size_t s,
    UIntType b, size_t t,
    UIntType c, size_t l, UIntType f
    > class mersenne_twister_engine {
public:
    typedef UIntType result_type;
    static constexpr size_t word_size;
    static constexpr size_t state_size;
    static constexpr size_t shift_size;
    static constexpr size_t mask_bits;
    static constexpr UIntType xor_mask;
    static constexpr size_t tampering_u;
    static constexpr UIntType tampering_d;
    static constexpr size_t tampering_s;
    static constexpr UIntType tampering_b;
    static constexpr size_t tampering_t;
    static constexpr UIntType tampering_c;
    static constexpr size_t tampering_l;
    static constexpr UIntType initialization_multiplier;

    explicit mersenne_twister_engine(result_type value = default_seed);

    template<class Sseq >
    explicit mersenne_twister_engine(Sseq& s);

    mersenne_twister_engine(const mersenne_twister_engine&);

    void seed(result_type value = default_seed);

    template<class Sseq >
    void seed(Sseq& seq);

    result_type operator()();

    void discard(unsigned long long z);

    static constexpr result_type min();
    static constexpr result_type max();
};

template<class UIntType,
         size_t w, size_t n, size_t m, size_t r,
         UIntType a, size_t u, UIntType d, size_t s,
         UIntType b, size_t t,
         UIntType c, size_t l, UIntType f >
bool operator==(const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& lhs,
                const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& rhs);

template<class UIntType,
         size_t w, size_t n, size_t m, size_t r,
         UIntType a, size_t u, UIntType d, size_t s,
         UIntType b, size_t t,
         UIntType c, size_t l, UIntType f >
bool operator==(const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& lhs,
                const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& rhs);

template<class CharT, class Traits, class ResultType,

         class UIntType,
         size_t w, size_t n, size_t m, size_t r,
         UIntType a, size_t u, UIntType d, size_t s,
         UIntType b, size_t t,
         UIntType c, size_t l, UIntType f >
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& ost,
           const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& e);

template<class CharT, class Traits, class ResultType,

         class UIntType,
         size_t w, size_t n, size_t m, size_t r,
         UIntType a, size_t u, UIntType d, size_t s,
         UIntType b, size_t t,
         UIntType c, size_t l, UIntType f >
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& ist,
           mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& e);

typedef std::mersenne_twister_engine<std::uint_fast32_t, 32, 624, 397, 31,
        0x9908b0df, 11,
        0xffffffff, 7,
        0x9d2c5680, 15,
        0xefc60000, 18, 1812433253> mt19937;

typedef std::mersenne_twister_engine<std::uint_fast64_t, 64, 312, 156, 31,
        0xb5026f5aa96619e9, 29,
        0x5555555555555555, 17,
        0x71d67fffeda60000, 37,
        0xfff7eee000000000, 43, 6364136223846793005> mt19937_64;

template <
    class UIntType,
    size_t w, size_t s, size_t r
    > class subtract_with_carry_engine {
public:
    typedef UIntType result_type;
    static constexpr size_t word_size;
    static constexpr size_t short_lag;
    static constexpr size_t long_lag;
    static constexpr UIntType default_seed;

    explicit subtract_with_carry_engine(result_type value = default_seed);

    template<class Sseq >
    explicit subtract_with_carry_engine(Sseq& s);

    subtract_with_carry_engine(const subtract_with_carry_engine&);

    void seed(result_type value = default_seed);

    template<class Sseq >
    void seed(Sseq& seq);

    result_type operator()();

    void discard(unsigned long long z);

    static constexpr result_type min();
    static constexpr result_type max();
};

template<class UIntType, size_t w, size_t s, size_t r >
bool operator==(const subtract_with_carry_engine<UIntType, w, s, r>& lhs,
                const subtract_with_carry_engine<UIntType, w, s, r>& rhs);

template<class UIntType, size_t w, size_t s, size_t r >
bool operator==(const subtract_with_carry_engine<UIntType, w, s, r>& lhs,
                const subtract_with_carry_engine<UIntType, w, s, r>& rhs);

template<class CharT, class Traits, class ResultType,
         class UIntType, size_t w, size_t s, size_t r >
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& ost,
           const subtract_with_carry_engine<UIntType, w, s, r>& e);

template<class CharT, class Traits, class ResultType,
         class UIntType, size_t w, size_t s, size_t r >
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& ist,
           subtract_with_carry_engine<UIntType, w, s, r>& e);

typedef std::subtract_with_carry_engine<std::uint_fast32_t, 24, 10, 24> ranlux24_base;
typedef std::subtract_with_carry_engine<std::uint_fast64_t, 48, 5, 12> ranlex48_base;

template <
    class Engine,
    size_t P, size_t R
    > class discard_block_engine {
public:
    typedef typename Engine::result_type result_type;
    static constexpr size_t block_size;
    static constexpr size_t used_size;

    discard_block_engine();

    explicit discard_block_engine(result_type s);

    template<class Sseq >
    explicit discard_block_engine(Sseq& seq);
    explicit discard_block_engine(const Engine& e);
    explicit discard_block_engine(Engine&& e);

    const Engine& base() const;

    void seed();
    void seed(result_type value);

    template<class Sseq >
    void seed(Sseq& seq);

    result_type operator()();

    void discard(unsigned long long z);

    static constexpr result_type min();
    static constexpr result_type max();
};

template<class Engine, size_t p, size_t r >
bool operator==(const discard_block_engine<Engine, p, r>& lhs,
                const discard_block_engine<Engine, p, r>& rhs);

template<class Engine, size_t p, size_t r >
bool operator!=(const discard_block_engine<Engine, p, r>& lhs,
                const discard_block_engine<Engine, p, r>& rhs);

template<class CharT, class Traits, class ResultType,
         class Engine, size_t p, size_t r >
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& ost,
           const discard_block_engine<Engine, p, r>& e);

template<class CharT, class Traits, class ResultType,
         class Engine, size_t p, size_t r >
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& ist,
           discard_block_engine<Engine, p, r>& e);

typedef std::discard_block_engine<std::ranlux24_base, 223, 23> randex24;
typedef std::discard_block_engine<std::ranlux48_base, 389, 11> randex48;

template <
    class Engine,
    std::size_t W,
    class UIntType
    > class independent_bits_engine {
public:
    typedef typename Engine::result_type result_type;

    independent_bits_engine();

    explicit independent_bits_engine(result_type s);

    template<class Sseq >
    explicit independent_bits_engine(Sseq& seq);
    explicit independent_bits_engine(const Engine& e);
    explicit independent_bits_engine(Engine&& e);

    const Engine& base() const;

    void seed();
    void seed(result_type value);

    template<class Sseq >
    void seed(Sseq& seq);

    result_type operator()();

    void discard(unsigned long long z);

    static constexpr result_type min();
    static constexpr result_type max();
};

template <
    class Engine,
    std::size_t K
    > class shuffle_order_engine {
public:
    typedef typename Engine::result_type result_type;
    static constexpr size_t table_size;

    shuffle_order_engine();

    explicit shuffle_order_engine(result_type s);

    template<class Sseq >
    explicit shuffle_order_engine(Sseq& seq);
    explicit shuffle_order_engine(const Engine& e);
    explicit shuffle_order_engine(Engine&& e);

    const Engine& base() const;

    void seed();
    void seed(result_type value);

    template<class Sseq >
    void seed(Sseq& seq);

    result_type operator()();

    void discard(unsigned long long z);

    static constexpr result_type min();
    static constexpr result_type max();
};

typedef std::shuffle_order_engine<std::minstd_rand0, 256> knuth_b;

class seed_seq {
public:
    typedef std::uint_least32_t result_type;

    seed_seq();
    seed_seq(const seed_seq&) = delete;

    template<class InputIt >
    seed_seq(InputIt begin, InputIt end);

    template<class T >
    seed_seq(std::initializer_list<T> il);

    template<class RandomIt >
    void generate(RandomIt begin, RandomIt end);

    std::size_t size() const;

    template<class OutputIt >
    void param(OutputIt dest) const;
};

template<class IntType = int >
class uniform_int_distribution {
public:
    typedef IntType result_type;
    typedef void* param_type; // TODO

    explicit uniform_int_distribution(IntType a = 0,
                                      IntType b = std::numeric_limits<IntType>::max());
    explicit uniform_int_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type a() const;
    result_type b() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;

    result_type max() const;
};

template<class ResultType >
bool operator==(const uniform_int_distribution<ResultType>& lhs,
                const uniform_int_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const uniform_int_distribution<ResultType>& lhs,
                const uniform_int_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const uniform_int_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        uniform_int_distribution<ResultType>& d);

template<class RealType = double >
class uniform_real_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit uniform_real_distribution(RealType a = 0.0, RealType b = 1.0);
    explicit uniform_real_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type a() const;
    result_type b() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;

    result_type max() const;
};

template<class ResultType >
bool operator==(const uniform_real_distribution<ResultType>& lhs,
                const uniform_real_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const uniform_real_distribution<ResultType>& lhs,
                const uniform_real_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const uniform_real_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        uniform_real_distribution<ResultType>& d);

template<class RealType, size_t bits, class Generator >
RealType generate_canonical(Generator& g);

class bernoulli_distribution {
public:
    typedef bool result_type;
    typedef void* param_type; // TODO

    explicit bernoulli_distribution(double p = 0.5);
    explicit bernoulli_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    double p() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

bool operator==(const bernoulli_distribution& lhs,
                const bernoulli_distribution& rhs);

bool operator!=(const bernoulli_distribution& lhs,
                const bernoulli_distribution& rhs);

template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const bernoulli_distribution& d);

template<class CharT, class Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        bernoulli_distribution& d);

template<class IntType = int >
class binomial_distribution {
public:
    typedef IntType result_type;
    typedef void* param_type; // TODO

    explicit binomial_distribution(IntType t = 1, double p = 0.5);
    explicit binomial_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    double p() const;
    IntType t() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;

};

template<class ResultType >
bool operator==(const binomial_distribution<ResultType>& lhs,
                const binomial_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const binomial_distribution<ResultType>& lhs,
                const binomial_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const binomial_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        binomial_distribution<ResultType>& d);

template<class IntType = int >
class negative_binomial_distribution {
public:
    typedef IntType result_type;
    typedef void* param_type; // TODO

    explicit negative_binomial_distribution(IntType k = 1, double p = 0.5);
    explicit negative_binomial_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    double p() const;
    IntType k() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;

};

template<class ResultType >
bool operator==(const negative_binomial_distribution<ResultType>& lhs,
                const negative_binomial_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const negative_binomial_distribution<ResultType>& lhs,
                const negative_binomial_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const negative_binomial_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        negative_binomial_distribution<ResultType>& d);

template<class IntType = int >
class geometric_distribution {
public:
    typedef IntType result_type;
    typedef void* param_type; // TODO

    explicit geometric_distribution(double p = 0.5);
    explicit geometric_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    double p() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;

};

template<class ResultType >
bool operator==(const geometric_distribution<ResultType>& lhs,
                const geometric_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const geometric_distribution<ResultType>& lhs,
                const geometric_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const geometric_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        geometric_distribution<ResultType>& d);

template<class IntType = int >
class poisson_distribution {
public:
    typedef IntType result_type;
    typedef void* param_type; // TODO

    explicit poisson_distribution(double mean = 1.0);
    explicit poisson_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    double mean() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;

};

template<class ResultType >
bool operator==(const poisson_distribution<ResultType>& lhs,
                const poisson_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const poisson_distribution<ResultType>& lhs,
                const poisson_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const poisson_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        poisson_distribution<ResultType>& d);

template<class RealType = double >
class exponential_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit exponential_distribution(RealType lambda = 1.0);
    explicit exponential_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type lambda() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const exponential_distribution<ResultType>& lhs,
                const exponential_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const exponential_distribution<ResultType>& lhs,
                const exponential_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const exponential_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        exponential_distribution<ResultType>& d);

template<class RealType = double >
class gamma_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit gamma_distribution(RealType alpha = 1.0, RealType beta = 1.0);
    explicit gamma_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type alpha() const;
    result_type beta() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const gamma_distribution<ResultType>& lhs,
                const gamma_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const gamma_distribution<ResultType>& lhs,
                const gamma_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const gamma_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        gamma_distribution<ResultType>& d);

template<class RealType = double >
class weibull_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit weibull_distribution(RealType a = 1.0, RealType b = 1.0);
    explicit weibull_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type a() const;
    result_type b() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const weibull_distribution<ResultType>& lhs,
                const weibull_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const weibull_distribution<ResultType>& lhs,
                const weibull_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const weibull_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        weibull_distribution<ResultType>& d);

template<class RealType = double >
class extreme_value_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit extreme_value_distribution(RealType a = 0.0, RealType b = 1.0);
    explicit extreme_value_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type a() const;
    result_type b() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const extreme_value_distribution<ResultType>& lhs,
                const extreme_value_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const extreme_value_distribution<ResultType>& lhs,
                const extreme_value_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const extreme_value_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        extreme_value_distribution<ResultType>& d);

template<class RealType = double >
class normal_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit normal_distribution(RealType mean = 0.0, RealType stddev = 1.0);
    explicit normal_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type mean() const;
    result_type stddev() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const normal_distribution<ResultType>& lhs,
                const normal_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const normal_distribution<ResultType>& lhs,
                const normal_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const normal_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        normal_distribution<ResultType>& d);

template<class RealType = double >
class lognormal_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit lognormal_distribution(RealType m = 0.0, RealType s = 1.0);
    explicit lognormal_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type m() const;
    result_type s() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const lognormal_distribution<ResultType>& lhs,
                const lognormal_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const lognormal_distribution<ResultType>& lhs,
                const lognormal_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const lognormal_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        lognormal_distribution<ResultType>& d);

template<class RealType = double >
class chi_squared_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit chi_squared_distribution(RealType n = 1.0);
    explicit chi_squared_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type n() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const chi_squared_distribution<ResultType>& lhs,
                const chi_squared_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const chi_squared_distribution<ResultType>& lhs,
                const chi_squared_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const chi_squared_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        chi_squared_distribution<ResultType>& d);

template<class RealType = double >
class cauchy_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit cauchy_distribution(RealType a = 0.0, RealType b = 1.0);
    explicit cauchy_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type a() const;
    result_type b() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const cauchy_distribution<ResultType>& lhs,
                const cauchy_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const cauchy_distribution<ResultType>& lhs,
                const cauchy_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const cauchy_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        cauchy_distribution<ResultType>& d);

template<class RealType = double >
class fisher_f_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit fisher_f_distribution(RealType m = 1.0, RealType n = 1.0);
    explicit fisher_f_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type m() const;
    result_type n() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const fisher_f_distribution<ResultType>& lhs,
                const fisher_f_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const fisher_f_distribution<ResultType>& lhs,
                const fisher_f_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const fisher_f_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        fisher_f_distribution<ResultType>& d);

template<class RealType = double >
class student_t_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    explicit student_t_distribution(RealType n = 1.0);
    explicit student_t_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    result_type n() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const student_t_distribution<ResultType>& lhs,
                const student_t_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const student_t_distribution<ResultType>& lhs,
                const student_t_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const student_t_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        student_t_distribution<ResultType>& d);

template<class IntType = int >
class discrete_distribution {
public:
    typedef IntType result_type;
    typedef void* param_type; // TODO

    discrete_distribution();

    template<class InputIt >
    discrete_distribution(InputIt first, InputIt last);

    discrete_distribution(std::initializer_list<double> weights);

    template<class UnaryOperation >
    discrete_distribution(std::size_t count, double xmin, double xmax,
                          UnaryOperation unary_op);

    explicit discrete_distribution(const param_type& params);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    std::vector<double> probabilities() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;

};

template<class ResultType >
bool operator==(const discrete_distribution<ResultType>& lhs,
                const discrete_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const discrete_distribution<ResultType>& lhs,
                const discrete_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const discrete_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        discrete_distribution<ResultType>& d);

template<class RealType = double >
class piecewise_constant_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    piecewise_constant_distribution();

    template<class InputIt1, class InputIt2 >
    piecewise_constant_distribution(InputIt1 first_i, InputIt1 last_i,
                                    InputIt2 first_w);

    template<class UnaryOperation >
    piecewise_constant_distribution(std::initializer_list<RealType> bl,
                                    UnaryOperation fw);

    template<class UnaryOperation >
    piecewise_constant_distribution(std::size_t nw,
                                    RealType xmin, RealType xmax,
                                    UnaryOperation fw);

    explicit piecewise_constant_distribution(const param_type& parm);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    std::vector<RealType> intervals() const;
    std::vector<RealType> densities() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const piecewise_constant_distribution<ResultType>& lhs,
                const piecewise_constant_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const piecewise_constant_distribution<ResultType>& lhs,
                const piecewise_constant_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const piecewise_constant_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        piecewise_constant_distribution<ResultType>& d);

template<class RealType = double >
class piecewise_linear_distribution {
public:
    typedef RealType result_type;
    typedef void* param_type; // TODO

    piecewise_linear_distribution();

    template<class InputIt1, class InputIt2 >
    piecewise_linear_distribution(InputIt1 first_i, InputIt1 last_i,
                                  InputIt2 first_w);

    template<class UnaryOperation >
    piecewise_linear_distribution(std::initializer_list<RealType> ilist,
                                  UnaryOperation fw);

    template<class UnaryOperation >
    piecewise_linear_distribution(std::size_t nw,
                                  RealType xmin, RealType xmax,
                                  UnaryOperation fw);

    explicit piecewise_linear_distribution(const param_type& parm);

    void reset();

    template<class Generator >
    result_type operator()(Generator& g);

    template<class Generator >
    result_type operator()(Generator& g, const param_type& params);

    std::vector<RealType> intervals() const;
    std::vector<RealType> densities() const;

    param_type param() const;
    void param(const param_type& params);

    result_type min() const;
    result_type max() const;
};

template<class ResultType >
bool operator==(const piecewise_linear_distribution<ResultType>& lhs,
                const piecewise_linear_distribution<ResultType>& rhs);

template<class ResultType >
bool operator!=(const piecewise_linear_distribution<ResultType>& lhs,
                const piecewise_linear_distribution<ResultType>& rhs);

template<class CharT, class Traits, class ResultType >
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& ost,
        const piecewise_linear_distribution<ResultType>& d);

template<class CharT, class Traits, class ResultType >
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& ist,
        piecewise_linear_distribution<ResultType>& d);


class random_device {
public:
    typedef unsigned int result_type;

    // actually the default value is impl-defined
    explicit random_device(const std::string& token = "");

    random_device(const random_device&) = delete;
    random_device& operator=(const random_device&) = delete;

    result_type operator()();
    double entropy() const;
    static constexpr result_type min();
    static constexpr result_type max();
};
} // namespace std

#endif // CPPREFERENCE_STDVER >= 2011

#endif // CPPREFERENCE_RANDOM_H
