#ifndef BOOST_RANDOM_MIXMAX_HPP
#define BOOST_RANDOM_MIXMAX_HPP
#include <array>
#include <sstream>
#include <cstdint>
#include <boost/random/detail/seed.hpp>
#include <boost/random/detail/seed_impl.hpp>
namespace boost {
namespace random {
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> class mixmax_engine{
public:
typedef std::uint64_t result_type ;
BOOST_STATIC_CONSTANT(std::uint64_t,mixmax_min=0);
BOOST_STATIC_CONSTANT(std::uint64_t,mixmax_max=((1ULL<<61)-1));
BOOST_STATIC_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION() {return mixmax_min;}
BOOST_STATIC_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION() {return mixmax_max;}
static const bool has_fixed_range = false;
BOOST_STATIC_CONSTANT(int,N=Ndim); explicit mixmax_engine(); explicit mixmax_engine(std::uint64_t); explicit mixmax_engine(uint32_t clusterID, uint32_t machineID, uint32_t runID, uint32_t streamID ); void seed(std::uint64_t seedval=default_seed){seed_uniquestream( &S, 0, 0, (uint32_t)(seedval>>32), (uint32_t)seedval );}
private: struct rng_state_st{
std::array<std::uint64_t, Ndim> V;
std::uint64_t sumtot;
int counter;
};
typedef struct rng_state_st rng_state_t; rng_state_t S;
public: template<class It> mixmax_engine(It& first, It last) { seed(first,last); }
BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(mixmax_engine, SeedSeq, seq){ seed(seq); }
template<class It>
void seed(It& first, It last){
uint32_t v[4];
detail::fill_array_int<32>(first, last, v);
seed_uniquestream( &S, v[0], v[1], v[2], v[3]);
}
BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(mixmax_engine, SeeqSeq, seq){
uint32_t v[4];
detail::seed_array_int<32>(seq, v);
seed_uniquestream( &S, v[0], v[1], v[2], v[3]);
}
std::uint64_t operator()(){
if (S.counter<=(Ndim-1) ){
return S.V[S.counter++];
}else{
S.sumtot = iterate_raw_vec(S.V.data(), S.sumtot);
S.counter=2;
return S.V[1];
}
}
template<class Iter>
void generate(Iter first, Iter last) { detail::generate_from_int(*this, first, last); }
void discard(std::uint64_t nsteps) { for(std::uint64_t j = 0; j < nsteps; ++j) (*this)(); }
template<class CharT, class Traits>
friend std::basic_ostream<CharT,Traits>&
operator<< (std::basic_ostream<CharT,Traits>& ost, const mixmax_engine& me){
ost << Ndim << " " << me.S.counter << " " << me.S.sumtot << " ";
for (int j=0; (j< (Ndim) ); j++) {
ost << (std::uint64_t)me.S.V[j] << " ";
}
ost << "\n";
ost.flush();
return ost;
}
template<class CharT, class Traits>
friend std::basic_istream<CharT,Traits>&
operator>> (std::basic_istream<CharT,Traits> &in, mixmax_engine& me){
std::array<std::uint64_t, Ndim> vec;
std::uint64_t sum=0, savedsum=0, counter=0;
in >> counter >> std::ws;
BOOST_ASSERT(counter==Ndim);
in >> counter >> std::ws;
in >> savedsum >> std::ws;
for(int j=0;j<Ndim;j++) {
in >> std::ws >> vec[j] ;
sum=me.MOD_MERSENNE(sum+vec[j]);
}
if (sum == savedsum && counter>0 && counter<Ndim){
me.S.V=vec; me.S.counter = counter; me.S.sumtot=savedsum;
}else{
in.setstate(std::ios::failbit);
}
return in;
}
friend bool operator==(const mixmax_engine & x,
const mixmax_engine & y){return x.S.counter==y.S.counter && x.S.sumtot==y.S.sumtot && x.S.V==y.S.V ;}
friend bool operator!=(const mixmax_engine & x,
const mixmax_engine & y){return !operator==(x,y);}
private:
BOOST_STATIC_CONSTANT(int, BITS=61);
BOOST_STATIC_CONSTANT(std::uint64_t, M61=2305843009213693951ULL);
BOOST_STATIC_CONSTANT(std::uint64_t, default_seed=1);
inline std::uint64_t MOD_MERSENNE(std::uint64_t k) {return ((((k)) & M61) + (((k)) >> BITS) );}
inline std::uint64_t MULWU(std::uint64_t k);
inline void seed_vielbein(rng_state_t* X, unsigned int i); inline void seed_uniquestream( rng_state_t* Xin, uint32_t clusterID, uint32_t machineID, uint32_t runID, uint32_t streamID );
inline std::uint64_t iterate_raw_vec(std::uint64_t* Y, std::uint64_t sumtotOld);
inline std::uint64_t apply_bigskip(std::uint64_t* Vout, std::uint64_t* Vin, uint32_t clusterID, uint32_t machineID, uint32_t runID, uint32_t streamID );
inline std::uint64_t modadd(std::uint64_t foo, std::uint64_t bar);
inline std::uint64_t fmodmulM61(std::uint64_t cum, std::uint64_t s, std::uint64_t a);
};
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::mixmax_engine()
{
seed_uniquestream( &S, 0, 0, 0, default_seed);
}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::mixmax_engine(std::uint64_t seedval){
seed_uniquestream( &S, 0, 0, (uint32_t)(seedval>>32), (uint32_t)seedval );
}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::mixmax_engine(uint32_t clusterID, uint32_t machineID, uint32_t runID, uint32_t streamID){
seed_uniquestream( &S, clusterID, machineID, runID, streamID );
}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> uint64_t mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::MULWU (uint64_t k){ return (( (k)<<(SPECIALMUL) & M61) ^ ( (k) >> (BITS-SPECIALMUL)) ) ;}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> std::uint64_t mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::iterate_raw_vec(std::uint64_t* Y, std::uint64_t sumtotOld){
std::uint64_t tempP=0, tempV=sumtotOld;
Y[0] = tempV;
std::uint64_t sumtot = Y[0], ovflow = 0; for (int i=1; i<Ndim; i++){
std::uint64_t tempPO = MULWU(tempP);
tempV = (tempV+tempPO);
tempP = modadd(tempP, Y[i]);
tempV = modadd(tempV, tempP); Y[i] = tempV;
sumtot += tempV; if (sumtot < tempV) {ovflow++;}
}
return MOD_MERSENNE(MOD_MERSENNE(sumtot) + (ovflow <<3 ));
}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> void mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::seed_vielbein(rng_state_t* X, unsigned int index){
for (int i=0; i < Ndim; i++){
X->V[i] = 0;
}
if (index<Ndim) { X->V[index] = 1; }else{ X->V[0]=1; }
X->counter = Ndim; X->sumtot = 1;
}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> void mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::seed_uniquestream( rng_state_t* Xin, uint32_t clusterID, uint32_t machineID, uint32_t runID, uint32_t streamID ){
seed_vielbein(Xin,0);
Xin->sumtot = apply_bigskip(Xin->V.data(), Xin->V.data(), clusterID, machineID, runID, streamID );
Xin->counter = 1;
}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> std::uint64_t mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::apply_bigskip( std::uint64_t* Vout, std::uint64_t* Vin, uint32_t clusterID, uint32_t machineID, uint32_t runID, uint32_t streamID ){
const std::uint64_t skipMat17[128][17] =
#include "boost/random/detail/mixmax_skip_N17.ipp"
;
const std::uint64_t* skipMat[128];
BOOST_ASSERT(Ndim==17);
for (int i=0; i<128; i++) { skipMat[i] = skipMat17[i];}
uint32_t IDvec[4] = {streamID, runID, machineID, clusterID};
std::uint64_t Y[Ndim], cum[Ndim];
std::uint64_t sumtot=0;
for (int i=0; i<Ndim; i++) { Y[i] = Vin[i]; sumtot = modadd( sumtot, Vin[i]); } ;
for (int IDindex=0; IDindex<4; IDindex++) { uint32_t id=IDvec[IDindex];
int r = 0;
while (id){
if (id & 1) {
std::uint64_t* rowPtr = (std::uint64_t*)skipMat[r + IDindex*8*sizeof(uint32_t)];
for (int i=0; i<Ndim; i++){ cum[i] = 0; }
for (int j=0; j<Ndim; j++){ std::uint64_t coeff = rowPtr[j]; for (int i =0; i<Ndim; i++){
cum[i] = fmodmulM61( cum[i], coeff , Y[i] ) ;
}
sumtot = iterate_raw_vec(Y, sumtot);
}
sumtot=0;
for (int i=0; i<Ndim; i++){ Y[i] = cum[i]; sumtot = modadd( sumtot, cum[i]); } ;
}
id = (id >> 1); r++; }
}
sumtot=0;
for (int i=0; i<Ndim; i++){ Vout[i] = Y[i]; sumtot = modadd( sumtot, Y[i]); } ; return (sumtot) ;
}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> inline std::uint64_t mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::fmodmulM61(std::uint64_t cum, std::uint64_t s, std::uint64_t a){
const std::uint64_t MASK32=0xFFFFFFFFULL;
std::uint64_t o,ph,pl,ah,al;
o=(s)*a;
ph = ((s)>>32);
pl = (s) & MASK32;
ah = a>>32;
al = a & MASK32;
o = (o & M61) + ((ph*ah)<<3) + ((ah*pl+al*ph + ((al*pl)>>32))>>29) ;
o += cum;
o = (o & M61) + ((o>>61));
return o;
}
template <int Ndim, unsigned int SPECIALMUL, std::int64_t SPECIAL> std::uint64_t mixmax_engine <Ndim, SPECIALMUL, SPECIAL> ::modadd(std::uint64_t foo, std::uint64_t bar){
return MOD_MERSENNE(foo+bar);
}
typedef mixmax_engine<17,36,0> mixmax;
}}
#endif