Import Geant4 10.4.0 source tree
This commit is contained in:
+1
-3
@@ -56,10 +56,9 @@ set(G4clhep_HEADERS
|
||||
include/CLHEP/Random/EngineFactory.h
|
||||
include/CLHEP/Random/engineIDulong.h
|
||||
include/CLHEP/Random/JamesRandom.h
|
||||
include/CLHEP/Random/mixmax.h
|
||||
include/CLHEP/Random/mixmax_skip_N8.icc
|
||||
include/CLHEP/Random/mixmax_skip_N17.icc
|
||||
include/CLHEP/Random/mixmax_skip_N256.icc
|
||||
include/CLHEP/Random/mixmax_skip_N240.icc
|
||||
include/CLHEP/Random/MixMaxRng.h
|
||||
include/CLHEP/Random/MTwistEngine.h
|
||||
include/CLHEP/Random/NonRandomEngine.h
|
||||
@@ -171,7 +170,6 @@ set(G4clhep_SOURCES
|
||||
src/LorentzVectorK.cc
|
||||
src/LorentzVectorL.cc
|
||||
src/LorentzVectorR.cc
|
||||
src/mixmax.cc
|
||||
src/MixMaxRng.cc
|
||||
src/MTwistEngine.cc
|
||||
src/NonRandomEngine.cc
|
||||
|
||||
Vendored
+16
@@ -17,6 +17,22 @@ committal in the CVS repository !
|
||||
* Reverse chronological order (last date on top), please *
|
||||
----------------------------------------------------------
|
||||
|
||||
15 November 2017 - G.Cosmo
|
||||
- MixMaxRng: fixed print_state() method to proper C++.
|
||||
|
||||
13 November 2017 - G.Cosmo
|
||||
- Fixed shadowing warning in MixMaxRng.
|
||||
|
||||
09 November 2017 - G.Cosmo
|
||||
- Updated MixMaxRng class to include latest C++ revision by K.Savvidy
|
||||
based in MixMax-2.0. Replaced skipping coefficients optional set for
|
||||
N=256 with N=240. Removed old C implementation files.
|
||||
- Set MixMax as the default random number generator in HepRandom.
|
||||
|
||||
09 October 2017 - G.Cosmo
|
||||
- Added missing DLL_API specification for static data member in Transform3D
|
||||
class.
|
||||
|
||||
10 May 2017 - G.Cosmo
|
||||
- Fixed shadowing compilation warnings on RotationA.cc.
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace HepGeom {
|
||||
public:
|
||||
/**
|
||||
* Global identity transformation. */
|
||||
static const Transform3D Identity;
|
||||
DLL_API static const Transform3D Identity;
|
||||
|
||||
// Helper class for implemention of C-style subscripting r[i][j]
|
||||
class Transform3D_row {
|
||||
|
||||
+107
-31
@@ -1,4 +1,4 @@
|
||||
// $Id:$
|
||||
//
|
||||
// -*- C++ -*-
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -7,53 +7,63 @@
|
||||
// class header file
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This file interfaces the PseudoRandom Number Generator
|
||||
// This file interfaces the MixMax PseudoRandom Number Generator
|
||||
// proposed by:
|
||||
// N.Z. Akopov, G.K.Saviddy & N.G. Ter-Arutyunian
|
||||
// "Matrix Generator of Pseudorandom Numbers",
|
||||
// J.Compt.Phy. 97, 573 (1991)
|
||||
// Preprint: EPI-867(18)-86, Yerevan June 1986.
|
||||
// G. Savvidy & N. Savvidy
|
||||
// "On the Monte Carlo Simulation of Physical Systems",
|
||||
// J.Comput.Phys. 97 (1991) 566
|
||||
|
||||
//
|
||||
// G.K.Savvidy and N.G.Ter-Arutyunian,
|
||||
// On the Monte Carlo simulation of physical systems,
|
||||
// J.Comput.Phys. 97, 566 (1991);
|
||||
// Preprint EPI-865-16-86, Yerevan, Jan. 1986
|
||||
// http://dx.doi.org/10.1016/0021-9991(91)90015-D
|
||||
//
|
||||
// K.Savvidy
|
||||
// "The MIXMAX random number generator"
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
//
|
||||
// K.Savvidy and G.Savvidy
|
||||
// "Spectrum and Entropy of C-systems. MIXMAX random number generator"
|
||||
// Chaos, Solitons & Fractals, Volume 91, (2016) pp. 33-38
|
||||
// http://dx.doi.org/10.1016/j.chaos.2016.05.003
|
||||
//
|
||||
// =======================================================================
|
||||
// Implementation by Konstantin Savvidy - 2004-2015
|
||||
// Release 0.99 and later: released under the LGPL license version 3.0
|
||||
// =======================================================================
|
||||
// CLHEP interface implemented by
|
||||
// J. Apostolakis, G. Cosmo & K. Savvidy - Created: 6th July 2015
|
||||
// CLHEP interface released under the LGPL license version 3.0
|
||||
// Implementation by Konstantin Savvidy - Copyright 2004-2017
|
||||
// =======================================================================
|
||||
|
||||
#ifndef MixMaxRng_h
|
||||
#define MixMaxRng_h 1
|
||||
|
||||
#include <array>
|
||||
#include "CLHEP/Random/RandomEngine.h"
|
||||
#include "CLHEP/Random/mixmax.h"
|
||||
|
||||
namespace CLHEP {
|
||||
|
||||
|
||||
/**
|
||||
* @author K. Savvidy
|
||||
* @ingroup random
|
||||
*/
|
||||
* @author K.Savvidy
|
||||
* @ingroup random
|
||||
*/
|
||||
|
||||
typedef unsigned long int myID_t;
|
||||
typedef unsigned long long int myuint_t;
|
||||
|
||||
class MixMaxRng: public HepRandomEngine {
|
||||
|
||||
static const int N = 17;
|
||||
|
||||
public:
|
||||
|
||||
MixMaxRng(std::istream& is);
|
||||
MixMaxRng();
|
||||
MixMaxRng(long seed);
|
||||
MixMaxRng(int rowIndex, int colIndex);
|
||||
virtual ~MixMaxRng();
|
||||
~MixMaxRng();
|
||||
// Constructor and destructor.
|
||||
|
||||
MixMaxRng(const MixMaxRng& rng);
|
||||
MixMaxRng& operator=(const MixMaxRng& rng);
|
||||
// Copy constructor and assignment operator.
|
||||
|
||||
double flat();
|
||||
double flat() { return (S.counter<=(N-1)) ? generate(S.counter):iterate(); }
|
||||
// Returns a pseudo random number between 0 and 1
|
||||
// (excluding the zero: in (0,1] )
|
||||
// smallest number which it will give is approximately 10^-19
|
||||
@@ -88,21 +98,87 @@ public:
|
||||
static std::string beginTag ( );
|
||||
virtual std::istream & getState ( std::istream & is );
|
||||
|
||||
std::string name() const;
|
||||
static std::string engineName() {return "MixMaxRng";}
|
||||
std::string name() const { return "MixMaxRng"; }
|
||||
static std::string engineName();
|
||||
|
||||
std::vector<unsigned long> put () const;
|
||||
bool get (const std::vector<unsigned long> & v);
|
||||
bool getState (const std::vector<unsigned long> & v);
|
||||
|
||||
static const unsigned int VECTOR_STATE_SIZE = 2*N+4; // 2N+4 for MIXMAX
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Pointer to the current status of the generator.
|
||||
rng_state_st* fRngState;
|
||||
};
|
||||
static constexpr long long int SPECIAL = ((N==17)? 0 : ((N==240)? 487013230256099140ULL:0) ); // etc...
|
||||
static constexpr long long int SPECIALMUL= ((N==17)? 36: ((N==240)? 51 :53) ); // etc...
|
||||
// Note the potential for confusion...
|
||||
static constexpr int BITS=61;
|
||||
static constexpr myuint_t M61=2305843009213693951ULL;
|
||||
static constexpr double INV_M61=0.43368086899420177360298E-18;
|
||||
static constexpr unsigned int VECTOR_STATE_SIZE = 2*N+4; // 2N+4 for MIXMAX
|
||||
|
||||
#define MIXMAX_MOD_MERSENNE(k) ((((k)) & M61) + (((k)) >> BITS) )
|
||||
|
||||
static constexpr int rng_get_N();
|
||||
static constexpr long long int rng_get_SPECIAL();
|
||||
static constexpr int rng_get_SPECIALMUL();
|
||||
void seed_uniquestream( myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID );
|
||||
void seed_spbox(myuint_t);
|
||||
void print_state() const;
|
||||
myuint_t precalc();
|
||||
myuint_t get_next() ;
|
||||
inline double get_next_float() { return get_next_float_packbits(); }
|
||||
// Returns a random double with all 52 bits random, in the range (0,1]
|
||||
|
||||
MixMaxRng Branch();
|
||||
void BranchInplace(int id);
|
||||
|
||||
MixMaxRng(myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID ); // Constructor with four 32-bit seeds
|
||||
inline void seed64(myuint_t seedval) { seed_uniquestream( 0, 0, (myID_t)(seedval>>32), (myID_t)seedval ); } // seed with one 64-bit seed
|
||||
|
||||
double generate(int i);
|
||||
double iterate();
|
||||
|
||||
double get_next_float_packbits();
|
||||
#if defined __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif
|
||||
inline double convert1double(myuint_t u)
|
||||
{
|
||||
const double one = 1;
|
||||
const myuint_t onemask = *(myuint_t*)&one;
|
||||
myuint_t tmp = (u>>9) | onemask; // bits between 52 and 62 dont affect the result!
|
||||
double d = *(double*)&tmp;
|
||||
return d-1.0;
|
||||
}
|
||||
#if defined __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
myuint_t MOD_MULSPEC(myuint_t k);
|
||||
myuint_t MULWU(myuint_t k);
|
||||
void seed_vielbein( unsigned int i); // seeds with the i-th unit vector, i = 0..N-1, for testing only
|
||||
myuint_t iterate_raw_vec(myuint_t* Y, myuint_t sumtotOld);
|
||||
myuint_t apply_bigskip(myuint_t* Vout, myuint_t* Vin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID );
|
||||
myuint_t modadd(myuint_t foo, myuint_t bar);
|
||||
#if defined(__x86_64__)
|
||||
myuint_t mod128(__uint128_t s);
|
||||
myuint_t fmodmulM61(myuint_t cum, myuint_t a, myuint_t b);
|
||||
#else // on all other platforms, including 32-bit linux, PPC and PPC64, ARM and all Windows
|
||||
myuint_t fmodmulM61(myuint_t cum, myuint_t s, myuint_t a);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
struct rng_state_st
|
||||
{
|
||||
std::array<myuint_t, N> V;
|
||||
myuint_t sumtot;
|
||||
int counter;
|
||||
};
|
||||
|
||||
typedef struct rng_state_st rng_state_t; // struct alias
|
||||
rng_state_t S;
|
||||
};
|
||||
|
||||
} // namespace CLHEP
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ public:
|
||||
HepRandom();
|
||||
HepRandom(long seed);
|
||||
// Contructors with and without a seed using the default engine
|
||||
// (JamesRandom).
|
||||
// (MixMax).
|
||||
|
||||
HepRandom(HepRandomEngine & algorithm);
|
||||
HepRandom(HepRandomEngine * algorithm);
|
||||
|
||||
@@ -1,259 +0,0 @@
|
||||
// $Id:$
|
||||
// -*- C++ -*-
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// MixMax Matrix PseudoRandom Number Generator
|
||||
// --- MixMax ---
|
||||
// class header file
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Created by Konstantin Savvidy on Sun Feb 22 2004.
|
||||
// The code is released under
|
||||
// GNU Lesser General Public License v3
|
||||
//
|
||||
// Generator described in
|
||||
// N.Z.Akopov, G.K.Savvidy and N.G.Ter-Arutyunian, Matrix Generator of Pseudorandom Numbers,
|
||||
// J.Comput.Phys. 97, 573 (1991);
|
||||
// Preprint EPI-867(18)-86, Yerevan Jun.1986;
|
||||
//
|
||||
// and
|
||||
//
|
||||
// K.Savvidy
|
||||
// The MIXMAX random number generator
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#ifndef CLHEP_MIXMAX_H_
|
||||
#define CLHEP_MIXMAX_H_ 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define USE_INLINE_ASM YES
|
||||
|
||||
namespace CLHEP {
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const int N = 17;
|
||||
/* The currently recommended N are 3150, 1260, 508, 256, 240, 88, 17, 8
|
||||
Since the algorithm is linear in N, the cost per number is
|
||||
almost independent of N.
|
||||
*/
|
||||
|
||||
#ifndef __LP64__
|
||||
typedef uint64_t myuint;
|
||||
//#warning but no problem, 'myuint' is 'uint64_t'
|
||||
#else
|
||||
typedef unsigned long long int myuint;
|
||||
//#warning but no problem, 'myuint' is 'unsigned long long int'
|
||||
#endif
|
||||
|
||||
struct rng_state_st
|
||||
{
|
||||
myuint V[N];
|
||||
myuint sumtot;
|
||||
int counter;
|
||||
FILE* fh;
|
||||
};
|
||||
|
||||
typedef struct rng_state_st rng_state_t; // C struct alias
|
||||
|
||||
int rng_get_N(void); // get the N programmatically, useful for checking the value for which the library was compiled
|
||||
|
||||
rng_state_t *rng_alloc(); /* allocate the state */
|
||||
int rng_free(rng_state_t* X); /* free memory occupied by the state */
|
||||
rng_state_t *rng_copy(myuint *Y); /* init from vector, takes the vector Y,
|
||||
returns pointer to the newly allocated and initialized state */
|
||||
void read_state(rng_state_t* X, const char filename[] );
|
||||
void print_state(rng_state_t* X);
|
||||
int iterate(rng_state_t* X);
|
||||
myuint iterate_raw_vec(myuint* Y, myuint sumtotOld);
|
||||
|
||||
|
||||
// FUNCTIONS FOR SEEDING
|
||||
|
||||
typedef uint32_t myID_t;
|
||||
|
||||
void seed_uniquestream(rng_state_t* X, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID);
|
||||
/*
|
||||
best choice: will make a state vector from which you can get at least 10^100 numbers
|
||||
guaranteed mathematically to be non-colliding with any other stream prepared from another set of 32bit IDs,
|
||||
so long as it is different by at least one bit in at least one of the four IDs
|
||||
-- useful if you are running a parallel simulation with many clusters, many CPUs each
|
||||
*/
|
||||
|
||||
void seed_spbox(rng_state_t* X, myuint seed); // non-linear method, makes certified unique vectors, probability for streams to collide is < 1/10^4600
|
||||
|
||||
void seed_vielbein(rng_state_t* X, unsigned int i); // seeds with the i-th unit vector, i = 0..N-1, for testing only
|
||||
|
||||
|
||||
|
||||
// FUNCTIONS FOR GETTING RANDOM NUMBERS
|
||||
|
||||
#ifdef __MIXMAX_C
|
||||
myuint get_next(rng_state_t* X); // returns 64-bit int, which is between 1 and 2^61-1 inclusive
|
||||
double get_next_float(rng_state_t* X); // returns double precision floating point number in (0,1]
|
||||
#endif //__MIXMAX_C
|
||||
|
||||
void fill_array(rng_state_t* X, unsigned int n, double *array); // fastest method: set n to a multiple of N (e.g. n=256)
|
||||
|
||||
void iterate_and_fill_array(rng_state_t* X, double *array); // fills the array with N numbers
|
||||
|
||||
myuint precalc(rng_state_t* X);
|
||||
/* needed if the state has been changed by something other than iterate, but no worries, seeding functions call this for you when necessary */
|
||||
myuint apply_bigskip(myuint* Vout, myuint* Vin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID );
|
||||
// applies a skip of some number of steps calculated from the four IDs
|
||||
void branch_inplace( rng_state_t* Xin, myID_t* ID ); // almost the same as apply_bigskip, but in-place and from a vector of IDs
|
||||
|
||||
|
||||
#define BITS 61
|
||||
|
||||
/* magic with Mersenne Numbers */
|
||||
|
||||
#define M61 2305843009213693951ULL
|
||||
|
||||
myuint modadd(myuint foo, myuint bar);
|
||||
myuint modmulM61(myuint s, myuint a);
|
||||
myuint fmodmulM61(myuint cum, myuint s, myuint a);
|
||||
|
||||
#define MERSBASE M61 //xSUFF(M61)
|
||||
#define MOD_PAYNE(k) ((((k)) & MERSBASE) + (((k)) >> BITS) ) // slightly faster than my old way, ok for addition
|
||||
#define MOD_REM(k) ((k) % MERSBASE ) // latest Intel CPU is supposed to do this in one CPU cycle, but on my machines it seems to be 20% slower than the best tricks
|
||||
#define MOD_MERSENNE(k) MOD_PAYNE(k)
|
||||
|
||||
#define INV_MERSBASE (0.43368086899420177360298E-18L)
|
||||
|
||||
|
||||
// the charpoly is irreducible for the combinations of N and SPECIAL and has maximal period for N=508, 256, half period for 1260, and 1/12 period for 3150
|
||||
|
||||
// #if (N==256)
|
||||
// #define SPECIALMUL 0
|
||||
// #define SPECIAL 487013230256099064ULL // s=487013230256099064, m=1 -- good old MIXMAX
|
||||
// #define MOD_MULSPEC(k) fmodmulM61( 0, SPECIAL , (k) );
|
||||
|
||||
// #elif (N==17)
|
||||
#define SPECIALMUL 36 // m=2^36+1
|
||||
/*
|
||||
#elif (N==8)
|
||||
#define SPECIALMUL 53 // m=2^53+1
|
||||
|
||||
#elif (N==40)
|
||||
#define SPECIALMUL 42 // m=2^42+1
|
||||
|
||||
#elif (N==96)
|
||||
#define SPECIALMUL 55 // m=2^55+1
|
||||
|
||||
#elif (N==64)
|
||||
#define SPECIALMUL 55 // m=2^55 (!!!) and m=2^37+2
|
||||
|
||||
#elif (N==120)
|
||||
#define SPECIALMUL 51 // m=2^51+1 and a SPECIAL=+1 (!!!)
|
||||
#define SPECIAL 1
|
||||
#define MOD_MULSPEC(k) (k);
|
||||
|
||||
#else
|
||||
#warning Not a verified N, you are on your own!
|
||||
#define SPECIALMUL 58
|
||||
|
||||
#endif // list of interesting N for modulus M61 ends here
|
||||
*/
|
||||
|
||||
#ifndef __MIXMAX_C // c++ can put code into header files, why cant we? (with the inline declaration, should be safe from duplicate-symbol error)
|
||||
|
||||
#define get_next(X) GET_BY_MACRO(X)
|
||||
#define get_next_float(X) get_next_float_BY_MACRO(X)
|
||||
|
||||
#endif // __MIXMAX_C
|
||||
|
||||
inline myuint GET_BY_MACRO(rng_state_t* X) {
|
||||
int i;
|
||||
i=X->counter;
|
||||
|
||||
if (i<=(N-1) ){
|
||||
X->counter++;
|
||||
return X->V[i];
|
||||
}else{
|
||||
X->sumtot = iterate_raw_vec(X->V, X->sumtot);
|
||||
X->counter=2;
|
||||
return X->V[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline double get_next_float_BY_MACRO(rng_state_t* X){
|
||||
int64_t Z=(int64_t)get_next(X);
|
||||
#if defined(__x86_64__) && defined(__SSE__) && defined(__AVX__) && defined(USE_INLINE_ASM)
|
||||
double F;
|
||||
__asm__ __volatile__( "pxor %0, %0;"
|
||||
//"cvtsi2sdq %1, %0;"
|
||||
:"=x"(F)
|
||||
//:"r"(Z)
|
||||
);
|
||||
F=Z;
|
||||
return F*INV_MERSBASE;
|
||||
#else
|
||||
return Z*INV_MERSBASE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ERROR CODES - exit() is called with these
|
||||
#define ARRAY_INDEX_OUT_OF_BOUNDS 0xFF01
|
||||
#define SEED_WAS_ZERO 0xFF02
|
||||
#define ERROR_READING_STATE_FILE 0xFF03
|
||||
#define ERROR_READING_STATE_COUNTER 0xFF04
|
||||
#define ERROR_READING_STATE_CHECKSUM 0xFF05
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
//#define HOOKUP_GSL 1
|
||||
|
||||
#ifdef HOOKUP_GSL // if you need to use mixmax through GSL, pass -DHOOKUP_GSL=1 to the compiler
|
||||
|
||||
#include <gsl/gsl_rng.h>
|
||||
unsigned long gsl_get_next(void *vstate);
|
||||
double gsl_get_next_float(void *vstate);
|
||||
void seed_for_gsl(void *vstate, unsigned long seed);
|
||||
|
||||
static const gsl_rng_type mixmax_type =
|
||||
{"MIXMAX", /* name */
|
||||
MERSBASE, /* RAND_MAX */
|
||||
1, /* RAND_MIN */
|
||||
sizeof (rng_state_t),
|
||||
&seed_for_gsl,
|
||||
&gsl_get_next,
|
||||
&gsl_get_next_float
|
||||
};
|
||||
|
||||
unsigned long gsl_get_next(void *vstate) {
|
||||
rng_state_t* X= (rng_state_t*)vstate;
|
||||
return (unsigned long)get_next(X);
|
||||
}
|
||||
|
||||
double gsl_get_next_float(void *vstate) {
|
||||
rng_state_t* X= (rng_state_t*)vstate;
|
||||
return ( (double)get_next(X)) * INV_MERSBASE;
|
||||
}
|
||||
|
||||
void seed_for_gsl(void *vstate, unsigned long seed){
|
||||
rng_state_t* X= (rng_state_t*)vstate;
|
||||
seed_spbox(X,(myuint)seed);
|
||||
}
|
||||
|
||||
const gsl_rng_type *gsl_rng_ran3 = &mixmax_type;
|
||||
|
||||
|
||||
#endif // HOOKUP_GSL
|
||||
|
||||
} // namespace CLHEP
|
||||
|
||||
#endif // closing CLHEP_MIXMAX_H_
|
||||
+15
-11
@@ -1,4 +1,4 @@
|
||||
// $Id:$
|
||||
//
|
||||
// -*- C++ -*-
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -6,19 +6,23 @@
|
||||
// --- MixMax ---
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// The code is being released under GNU Lesser General Public License v3
|
||||
// Generator described in:
|
||||
//
|
||||
// Generator described in
|
||||
// N.Z.Akopov, G.K.Savvidy and N.G.Ter-Arutyunian, Matrix Generator of Pseudorandom Numbers,
|
||||
// J.Comput.Phys. 97, 573 (1991);
|
||||
// Preprint EPI-867(18)-86, Yerevan Jun.1986;
|
||||
// G.K.Savvidy and N.G.Ter-Arutyunian,
|
||||
// On the Monte Carlo simulation of physical systems,
|
||||
// J.Comput.Phys. 97, 566 (1991);
|
||||
// Preprint EPI-865-16-86, Yerevan, Jan. 1986
|
||||
// http://dx.doi.org/10.1016/0021-9991(91)90015-D
|
||||
//
|
||||
// and
|
||||
// K.Savvidy
|
||||
// "The MIXMAX random number generator"
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
//
|
||||
// K.Savvidy
|
||||
// The MIXMAX random number generator
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
// K.Savvidy and G.Savvidy
|
||||
// "Spectrum and Entropy of C-systems. MIXMAX random number generator"
|
||||
// Chaos, Solitons & Fractals, Volume 91, (2016) pp. 33-38
|
||||
// http://dx.doi.org/10.1016/j.chaos.2016.05.003
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+15
-11
@@ -1,4 +1,4 @@
|
||||
// $Id:$
|
||||
//
|
||||
// -*- C++ -*-
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -6,19 +6,23 @@
|
||||
// --- MixMax ---
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// The code is being released under GNU Lesser General Public License v3
|
||||
// Generator described in:
|
||||
//
|
||||
// Generator described in
|
||||
// N.Z.Akopov, G.K.Savvidy and N.G.Ter-Arutyunian, Matrix Generator of Pseudorandom Numbers,
|
||||
// J.Comput.Phys. 97, 573 (1991);
|
||||
// Preprint EPI-867(18)-86, Yerevan Jun.1986;
|
||||
// G.K.Savvidy and N.G.Ter-Arutyunian,
|
||||
// On the Monte Carlo simulation of physical systems,
|
||||
// J.Comput.Phys. 97, 566 (1991);
|
||||
// Preprint EPI-865-16-86, Yerevan, Jan. 1986
|
||||
// http://dx.doi.org/10.1016/0021-9991(91)90015-D
|
||||
//
|
||||
// and
|
||||
// K.Savvidy
|
||||
// "The MIXMAX random number generator"
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
//
|
||||
// K.Savvidy
|
||||
// The MIXMAX random number generator
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
// K.Savvidy and G.Savvidy
|
||||
// "Spectrum and Entropy of C-systems. MIXMAX random number generator"
|
||||
// Chaos, Solitons & Fractals, Volume 91, (2016) pp. 33-38
|
||||
// http://dx.doi.org/10.1016/j.chaos.2016.05.003
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
+510
-72
@@ -1,4 +1,4 @@
|
||||
// $Id:$
|
||||
//
|
||||
// -*- C++ -*-
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -7,22 +7,27 @@
|
||||
// class implementation file
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This file interfaces the PseudoRandom Number Generator
|
||||
// proposed by N.Z. Akopov, G.K.Saviddy & N.G. Ter-Arutyunian
|
||||
// "Matrix Generator of Pseudorandom Numbers"
|
||||
// J. Compt. Phy. 97, 573 (1991)
|
||||
// Preprint: EPI-867(18)-86, Yerevan June 1986.
|
||||
// This file interfaces the MixMax PseudoRandom Number Generator
|
||||
// proposed by:
|
||||
//
|
||||
// Implementation by Konstantin Savvidy - 2004-2015
|
||||
// "The MIXMAX random number generator"
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
// G.K.Savvidy and N.G.Ter-Arutyunian,
|
||||
// On the Monte Carlo simulation of physical systems,
|
||||
// J.Comput.Phys. 97, 566 (1991);
|
||||
// Preprint EPI-865-16-86, Yerevan, Jan. 1986
|
||||
// http://dx.doi.org/10.1016/0021-9991(91)90015-D
|
||||
//
|
||||
// K.Savvidy
|
||||
// "The MIXMAX random number generator"
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
//
|
||||
// K.Savvidy and G.Savvidy
|
||||
// "Spectrum and Entropy of C-systems. MIXMAX random number generator"
|
||||
// Chaos, Solitons & Fractals, Volume 91, (2016) pp. 33-38
|
||||
// http://dx.doi.org/10.1016/j.chaos.2016.05.003
|
||||
//
|
||||
// Release 0.99 and later: released under the LGPL license version 3.0
|
||||
// =======================================================================
|
||||
// CLHEP interface implemented by
|
||||
// J. Apostolakis, G. Cosmo & K. Savvidy - Created: 6th July 2015
|
||||
// CLHEP interface released under the LGPL license version 3.0
|
||||
// Implementation by Konstantin Savvidy - Copyright 2004-2017
|
||||
// =======================================================================
|
||||
|
||||
#include "CLHEP/Random/Random.h"
|
||||
@@ -32,10 +37,6 @@
|
||||
|
||||
#include <string.h> // for strcmp
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "CLHEP/Random/mixmax.h"
|
||||
|
||||
const unsigned long MASK32=0xffffffff;
|
||||
|
||||
@@ -48,20 +49,17 @@ namespace {
|
||||
|
||||
static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
|
||||
|
||||
std::string MixMaxRng::name() const { return "MixMaxRng"; } // N=" + N
|
||||
|
||||
MixMaxRng::MixMaxRng()
|
||||
: HepRandomEngine()
|
||||
{
|
||||
int numEngines = ++numberOfEngines;
|
||||
fRngState= rng_alloc();
|
||||
setSeed(static_cast<long>(numEngines));
|
||||
}
|
||||
|
||||
MixMaxRng::MixMaxRng(long seed)
|
||||
: HepRandomEngine()
|
||||
{
|
||||
fRngState= rng_alloc();
|
||||
theSeed=seed;
|
||||
setSeed(seed);
|
||||
}
|
||||
|
||||
@@ -73,15 +71,14 @@ MixMaxRng::MixMaxRng(std::istream& is)
|
||||
|
||||
MixMaxRng::~MixMaxRng()
|
||||
{
|
||||
rng_free( fRngState );
|
||||
}
|
||||
|
||||
MixMaxRng::MixMaxRng(const MixMaxRng& rng)
|
||||
: HepRandomEngine(rng)
|
||||
{
|
||||
fRngState= rng_copy( rng.fRngState->V );
|
||||
fRngState->sumtot= rng.fRngState->sumtot;
|
||||
fRngState->counter= rng.fRngState->counter;
|
||||
S.V = rng.S.V;
|
||||
S.sumtot= rng.S.sumtot;
|
||||
S.counter= rng.S.counter;
|
||||
}
|
||||
|
||||
MixMaxRng& MixMaxRng::operator=(const MixMaxRng& rng)
|
||||
@@ -94,12 +91,9 @@ MixMaxRng& MixMaxRng::operator=(const MixMaxRng& rng)
|
||||
//
|
||||
HepRandomEngine::operator=(rng);
|
||||
|
||||
// Copy data
|
||||
//
|
||||
rng_free( fRngState );
|
||||
fRngState= rng_copy( rng.fRngState->V );
|
||||
fRngState->sumtot= rng.fRngState->sumtot;
|
||||
fRngState->counter= rng.fRngState->counter;
|
||||
S.V = rng.S.V;
|
||||
S.sumtot= rng.S.sumtot;
|
||||
S.counter= rng.S.counter;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -110,40 +104,127 @@ void MixMaxRng::saveStatus( const char filename[] ) const
|
||||
FILE *fh= fopen(filename, "w");
|
||||
if( fh )
|
||||
{
|
||||
fRngState->fh= fh;
|
||||
print_state(fRngState);
|
||||
int j;
|
||||
fprintf(fh, "mixmax state, file version 1.0\n" );
|
||||
fprintf(fh, "N=%u; V[N]={", rng_get_N() );
|
||||
for (j=0; (j< (rng_get_N()-1) ); j++) {
|
||||
fprintf(fh, "%llu, ", S.V[j] );
|
||||
}
|
||||
fprintf(fh, "%llu", S.V[rng_get_N()-1] );
|
||||
fprintf(fh, "}; " );
|
||||
fprintf(fh, "counter=%u; ", S.counter );
|
||||
fprintf(fh, "sumtot=%llu;\n", S.sumtot );
|
||||
fclose(fh);
|
||||
}
|
||||
fRngState->fh= 0;
|
||||
}
|
||||
|
||||
#define MIXMAX_ARRAY_INDEX_OUT_OF_BOUNDS 0xFF01
|
||||
#define MIXMAX_SEED_WAS_ZERO 0xFF02
|
||||
#define MIXMAX_ERROR_READING_STATE_FILE 0xFF03
|
||||
#define MIXMAX_ERROR_READING_STATE_COUNTER 0xFF04
|
||||
#define MIXMAX_ERROR_READING_STATE_CHECKSUM 0xFF05
|
||||
|
||||
void MixMaxRng::restoreStatus( const char filename[] )
|
||||
{
|
||||
read_state(fRngState, filename);
|
||||
// a function for reading the state from a file
|
||||
FILE* fin;
|
||||
if( ( fin = fopen(filename, "r") ) )
|
||||
{
|
||||
char l=0;
|
||||
while ( l != '{' ) { // 0x7B = "{"
|
||||
l=fgetc(fin); // proceed until hitting opening bracket
|
||||
}
|
||||
ungetc(' ', fin);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "mixmax -> read_state: error reading file %s\n", filename);
|
||||
exit(MIXMAX_ERROR_READING_STATE_FILE);
|
||||
}
|
||||
|
||||
myuint_t vecVal;
|
||||
//printf("mixmax -> read_state: starting to read state from file\n");
|
||||
if (!fscanf(fin, "%llu", &S.V[0]) )
|
||||
{
|
||||
fprintf(stderr, "mixmax -> read_state: error reading file %s\n", filename);
|
||||
exit(MIXMAX_ERROR_READING_STATE_FILE);
|
||||
}
|
||||
|
||||
int i;
|
||||
for( i = 1; i < rng_get_N(); i++)
|
||||
{
|
||||
if (!fscanf(fin, ", %llu", &vecVal) )
|
||||
{
|
||||
fprintf(stderr, "mixmax -> read_state: error reading vector component i=%d from file %s\n", i, filename);
|
||||
exit(MIXMAX_ERROR_READING_STATE_FILE);
|
||||
}
|
||||
if( vecVal <= MixMaxRng::M61 )
|
||||
{
|
||||
S.V[i] = vecVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "mixmax -> read_state: Invalid state vector value= %llu"
|
||||
" ( must be less than %llu ) "
|
||||
" obtained from reading file %s\n"
|
||||
, vecVal, MixMaxRng::M61, filename);
|
||||
}
|
||||
}
|
||||
|
||||
int counter;
|
||||
if (!fscanf( fin, "}; counter=%i; ", &counter))
|
||||
{
|
||||
fprintf(stderr, "mixmax -> read_state: error reading counter from file %s\n", filename);
|
||||
exit(MIXMAX_ERROR_READING_STATE_FILE);
|
||||
}
|
||||
if( counter <= rng_get_N() )
|
||||
{
|
||||
S.counter= counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "mixmax -> read_state: Invalid counter = %d"
|
||||
" Must be 0 <= counter < %u\n" , counter, rng_get_N());
|
||||
print_state();
|
||||
exit(MIXMAX_ERROR_READING_STATE_COUNTER);
|
||||
}
|
||||
precalc();
|
||||
myuint_t sumtot;
|
||||
if (!fscanf( fin, "sumtot=%llu\n", &sumtot))
|
||||
{
|
||||
fprintf(stderr, "mixmax -> read_state: error reading checksum from file %s\n", filename);
|
||||
exit(MIXMAX_ERROR_READING_STATE_FILE);
|
||||
}
|
||||
|
||||
if (S.sumtot != sumtot)
|
||||
{
|
||||
fprintf(stderr, "mixmax -> checksum error while reading state from file %s - corrupted?\n", filename);
|
||||
exit(MIXMAX_ERROR_READING_STATE_CHECKSUM);
|
||||
}
|
||||
fclose(fin);
|
||||
}
|
||||
|
||||
#undef MIXMAX_ARRAY_INDEX_OUT_OF_BOUNDS
|
||||
#undef MIXMAX_SEED_WAS_ZERO
|
||||
#undef MIXMAX_ERROR_READING_STATE_FILE
|
||||
#undef MIXMAX_ERROR_READING_STATE_COUNTER
|
||||
#undef MIXMAX_ERROR_READING_STATE_CHECKSUM
|
||||
|
||||
void MixMaxRng::showStatus() const
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << "------- MixMaxRng engine status -------" << std::endl;
|
||||
|
||||
std::cout << " Current state vector is:" << std::endl;
|
||||
fRngState->fh=stdout;
|
||||
print_state(fRngState);
|
||||
print_state();
|
||||
std::cout << "---------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
void MixMaxRng::setSeed(long longSeed, int /* extraSeed */)
|
||||
{
|
||||
unsigned long seed0;
|
||||
|
||||
//seed_uniquestream(0,0,0,longSeed);
|
||||
theSeed = longSeed;
|
||||
if( sizeof(long) > 4) // C standard says long is at least 32-bits
|
||||
seed0= static_cast<unsigned long>(longSeed) & MASK32 ;
|
||||
else
|
||||
seed0= longSeed;
|
||||
|
||||
seed_spbox(fRngState, seed0);
|
||||
seed_spbox(longSeed);
|
||||
}
|
||||
|
||||
// Preferred Seeding method
|
||||
@@ -174,24 +255,93 @@ void MixMaxRng::setSeeds(const long* Seeds, int seedNum)
|
||||
}
|
||||
theSeed = Seeds[0];
|
||||
theSeeds = Seeds;
|
||||
seed_uniquestream(fRngState, seed3, seed2, seed1, seed0);
|
||||
seed_uniquestream(seed3, seed2, seed1, seed0);
|
||||
}
|
||||
|
||||
double MixMaxRng::flat()
|
||||
std::string MixMaxRng::engineName()
|
||||
{
|
||||
return get_next_float(fRngState);
|
||||
return "MixMaxRng";
|
||||
}
|
||||
|
||||
constexpr int MixMaxRng::rng_get_N()
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
constexpr long long int MixMaxRng::rng_get_SPECIAL()
|
||||
{
|
||||
return SPECIAL;
|
||||
}
|
||||
|
||||
constexpr int MixMaxRng::rng_get_SPECIALMUL()
|
||||
{
|
||||
return SPECIALMUL;
|
||||
}
|
||||
|
||||
double MixMaxRng::generate(int i)
|
||||
{
|
||||
S.counter++;
|
||||
#if defined(__clang__) || defined(__llvm__)
|
||||
return INV_M61*static_cast<double>(S.V[i]);
|
||||
#elif defined(__GNUC__) && (__GNUC__ < 7) && (!defined(__ICC)) && defined(__x86_64__) && defined(__SSE2_MATH__)
|
||||
int64_t Z=S.V[i];
|
||||
double F=0.0;
|
||||
//#warning Using the inline assembler
|
||||
/* using SSE inline assemly to zero the xmm register, just before int64 -> double conversion,
|
||||
not necessary in GCC-5 or better, but huge penalty on earlier compilers
|
||||
*/
|
||||
__asm__ __volatile__( "pxor %0, %0;"
|
||||
"cvtsi2sdq %1, %0;"
|
||||
:"=x"(F)
|
||||
:"r"(Z)
|
||||
);
|
||||
return F*INV_M61;
|
||||
#else
|
||||
//#warning other method
|
||||
return convert1double(S.V[i]); //get_next_float_packbits();
|
||||
#endif
|
||||
}
|
||||
|
||||
double MixMaxRng::iterate()
|
||||
{
|
||||
myuint_t* Y=S.V.data();
|
||||
myuint_t tempP, tempV;
|
||||
Y[0] = ( tempV = S.sumtot);
|
||||
myuint_t sumtot = Y[0], ovflow = 0; // will keep a running sum of all new elements
|
||||
tempP = 0; // will keep a partial sum of all old elements
|
||||
myuint_t tempPO;
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[1] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[1] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[2] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[2] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[3] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[3] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[4] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[4] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[5] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[5] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[6] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[6] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[7] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[7] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[8] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[8] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[9] ); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[9] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[10]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[10] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[11]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[11] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[12]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[12] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[13]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[13] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[14]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[14] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[15]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[15] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
tempPO = MULWU(tempP); tempP = modadd(tempP, Y[16]); tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); Y[16] = tempV; sumtot += tempV; if (sumtot < tempV) {ovflow++;};
|
||||
S.sumtot = MIXMAX_MOD_MERSENNE(MIXMAX_MOD_MERSENNE(sumtot) + (ovflow <<3 ));
|
||||
|
||||
S.counter=2;
|
||||
return double(S.V[1])*INV_M61;
|
||||
}
|
||||
|
||||
void MixMaxRng::flatArray(const int size, double* vect )
|
||||
{
|
||||
// fill_array( fRngState, size, arrayDbl );
|
||||
// fill_array( S, size, arrayDbl );
|
||||
for (int i=0; i<size; ++i) { vect[i] = flat(); }
|
||||
}
|
||||
|
||||
MixMaxRng::operator unsigned int()
|
||||
{
|
||||
return static_cast<unsigned int>(get_next(fRngState));
|
||||
// get_next returns a 64-bit integer, of which the lower 61 bits
|
||||
return static_cast<unsigned int>(get_next());
|
||||
// clhep_get_next returns a 64-bit integer, of which the lower 61 bits
|
||||
// are random and upper 3 bits are zero
|
||||
}
|
||||
|
||||
@@ -202,12 +352,12 @@ std::ostream & MixMaxRng::put ( std::ostream& os ) const
|
||||
|
||||
int pr = os.precision(24);
|
||||
os << beginMarker << " ";
|
||||
os << theSeed << " ";
|
||||
os << theSeed << "\n";
|
||||
for (int i=0; i<rng_get_N(); ++i) {
|
||||
os << fRngState->V[i] << "\n";
|
||||
os << S.V[i] << "\n";
|
||||
}
|
||||
os << fRngState->counter << "\n";
|
||||
os << fRngState->sumtot << "\n";
|
||||
os << S.counter << "\n";
|
||||
os << S.sumtot << "\n";
|
||||
os << endMarker << "\n";
|
||||
os.precision(pr);
|
||||
return os;
|
||||
@@ -217,15 +367,16 @@ std::vector<unsigned long> MixMaxRng::put () const
|
||||
{
|
||||
std::vector<unsigned long> v;
|
||||
v.push_back (engineIDulong<MixMaxRng>());
|
||||
for (int i=0; i<rng_get_N(); ++i) {
|
||||
v.push_back(static_cast<unsigned long>(fRngState->V[i] & MASK32));
|
||||
for (int i=0; i<rng_get_N(); ++i)
|
||||
{
|
||||
v.push_back(static_cast<unsigned long>(S.V[i] & MASK32));
|
||||
// little-ended order on all platforms
|
||||
v.push_back(static_cast<unsigned long>(fRngState->V[i] >> 32 ));
|
||||
v.push_back(static_cast<unsigned long>(S.V[i] >> 32 ));
|
||||
// pack uint64 into a data structure which is 32-bit on some platforms
|
||||
}
|
||||
v.push_back(static_cast<unsigned long>(fRngState->counter));
|
||||
v.push_back(static_cast<unsigned long>(fRngState->sumtot & MASK32));
|
||||
v.push_back(static_cast<unsigned long>(fRngState->sumtot >> 32));
|
||||
v.push_back(static_cast<unsigned long>(S.counter));
|
||||
v.push_back(static_cast<unsigned long>(S.sumtot & MASK32));
|
||||
v.push_back(static_cast<unsigned long>(S.sumtot >> 32));
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -256,9 +407,9 @@ std::istream & MixMaxRng::getState ( std::istream& is )
|
||||
{
|
||||
char endMarker[MarkerLen];
|
||||
is >> theSeed;
|
||||
for (int i=0; i<rng_get_N(); ++i) is >> fRngState->V[i];
|
||||
is >> fRngState->counter;
|
||||
myuint checksum;
|
||||
for (int i=0; i<rng_get_N(); ++i) is >> S.V[i];
|
||||
is >> S.counter;
|
||||
myuint_t checksum;
|
||||
is >> checksum;
|
||||
is >> std::ws;
|
||||
is.width(MarkerLen);
|
||||
@@ -269,14 +420,14 @@ std::istream & MixMaxRng::getState ( std::istream& is )
|
||||
<< "\nInput stream is probably mispositioned now.\n";
|
||||
return is;
|
||||
}
|
||||
if ( fRngState->counter < 0 || fRngState->counter > rng_get_N() ) {
|
||||
if ( S.counter < 0 || S.counter > rng_get_N() ) {
|
||||
std::cerr << "\nMixMaxRng::getState(): "
|
||||
<< "vector read wrong value of counter from file!"
|
||||
<< "\nInput stream is probably mispositioned now.\n";
|
||||
return is;
|
||||
}
|
||||
precalc(fRngState);
|
||||
if ( checksum != fRngState->sumtot) {
|
||||
precalc();
|
||||
if ( checksum != S.sumtot) {
|
||||
std::cerr << "\nMixMaxRng::getState(): "
|
||||
<< "checksum disagrees with value stored in file!"
|
||||
<< "\nInput stream is probably mispositioned now.\n";
|
||||
@@ -303,13 +454,13 @@ bool MixMaxRng::getState (const std::vector<unsigned long> & v)
|
||||
return false;
|
||||
}
|
||||
for (int i=1; i<2*rng_get_N() ; i=i+2) {
|
||||
fRngState->V[i/2]= ( (v[i] & MASK32) | ( (myuint)(v[i+1]) << 32 ) );
|
||||
S.V[i/2]= ( (v[i] & MASK32) | ( (myuint_t)(v[i+1]) << 32 ) );
|
||||
// unpack from a data structure which is 32-bit on some platforms
|
||||
}
|
||||
fRngState->counter = v[2*rng_get_N()+1];
|
||||
precalc(fRngState);
|
||||
S.counter = v[2*rng_get_N()+1];
|
||||
precalc();
|
||||
if ( ( (v[2*rng_get_N()+2] & MASK32)
|
||||
| ( (myuint)(v[2*rng_get_N()+3]) << 32 ) ) != fRngState->sumtot) {
|
||||
| ( (myuint_t)(v[2*rng_get_N()+3]) << 32 ) ) != S.sumtot) {
|
||||
std::cerr << "\nMixMaxRng::getState(): vector has wrong checksum!"
|
||||
<< "\nInput vector is probably mispositioned now.\n";
|
||||
return false;
|
||||
@@ -317,4 +468,291 @@ bool MixMaxRng::getState (const std::vector<unsigned long> & v)
|
||||
return true;
|
||||
}
|
||||
|
||||
myuint_t MixMaxRng ::MOD_MULSPEC(myuint_t k)
|
||||
{
|
||||
switch (N)
|
||||
{
|
||||
case 17:
|
||||
return 0;
|
||||
break;
|
||||
case 8:
|
||||
return 0;
|
||||
break;
|
||||
case 240:
|
||||
return fmodmulM61( 0, SPECIAL , (k) );
|
||||
break;
|
||||
default:
|
||||
std::cerr << "MIXMAX ERROR: " << "Disallowed value of parameter N\n";
|
||||
std::terminate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
myuint_t MixMaxRng::MULWU (myuint_t k)
|
||||
{
|
||||
return (( (k)<<(SPECIALMUL) & M61) ^ ( (k) >> (BITS-SPECIALMUL)) );
|
||||
}
|
||||
|
||||
myuint_t MixMaxRng::iterate_raw_vec(myuint_t* Y, myuint_t sumtotOld)
|
||||
{
|
||||
// operates with a raw vector, uses known sum of elements of Y
|
||||
int i;
|
||||
|
||||
myuint_t tempP, tempV;
|
||||
Y[0] = ( tempV = sumtotOld);
|
||||
myuint_t sumtot = Y[0], ovflow = 0; // will keep a running sum of all new elements
|
||||
tempP = 0; // will keep a partial sum of all old elements
|
||||
for (i=1; (i<N); i++)
|
||||
{
|
||||
myuint_t tempPO = MULWU(tempP);
|
||||
tempP = modadd(tempP, Y[i]);
|
||||
tempV = MIXMAX_MOD_MERSENNE(tempV+tempP+tempPO); // new Y[i] = old Y[i] + old partial * m
|
||||
Y[i] = tempV;
|
||||
sumtot += tempV; if (sumtot < tempV) {ovflow++;}
|
||||
}
|
||||
return MIXMAX_MOD_MERSENNE(MIXMAX_MOD_MERSENNE(sumtot) + (ovflow <<3 ));
|
||||
}
|
||||
|
||||
myuint_t MixMaxRng::get_next()
|
||||
{
|
||||
int i;
|
||||
i=S.counter;
|
||||
|
||||
if ((i<=(N-1)) )
|
||||
{
|
||||
S.counter++;
|
||||
return S.V[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
S.sumtot = iterate_raw_vec(S.V.data(), S.sumtot);
|
||||
S.counter=2;
|
||||
return S.V[1];
|
||||
}
|
||||
}
|
||||
|
||||
myuint_t MixMaxRng::precalc()
|
||||
{
|
||||
int i;
|
||||
myuint_t temp;
|
||||
temp = 0;
|
||||
for (i=0; i < N; i++){
|
||||
temp = MIXMAX_MOD_MERSENNE(temp + S.V[i]);
|
||||
}
|
||||
S.sumtot = temp;
|
||||
return temp;
|
||||
}
|
||||
|
||||
double MixMaxRng::get_next_float_packbits()
|
||||
{
|
||||
myuint_t Z=get_next();
|
||||
return convert1double(Z);
|
||||
}
|
||||
|
||||
void MixMaxRng::seed_vielbein(unsigned int index)
|
||||
{
|
||||
int i;
|
||||
if (index<N)
|
||||
{
|
||||
for (i=0; i < N; i++){
|
||||
S.V[i] = 0;
|
||||
}
|
||||
S.V[index] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
S.counter = N; // set the counter to N if iteration should happen right away
|
||||
S.sumtot = 1;
|
||||
}
|
||||
|
||||
#define MIXMAX_SEED_WAS_ZERO 0xFF02
|
||||
|
||||
void MixMaxRng::seed_spbox(myuint_t seed)
|
||||
{
|
||||
// a 64-bit LCG from Knuth line 26, in combination with a bit swap is used to seed
|
||||
|
||||
const myuint_t MULT64=6364136223846793005ULL;
|
||||
int i;
|
||||
|
||||
myuint_t sumtot=0,ovflow=0;
|
||||
if (seed == 0)
|
||||
{
|
||||
fprintf(stderr, " try seeding with nonzero seed next time!\n");
|
||||
exit(MIXMAX_SEED_WAS_ZERO);
|
||||
}
|
||||
|
||||
myuint_t l = seed;
|
||||
|
||||
for (i=0; i < N; i++){
|
||||
l*=MULT64; l = (l << 32) ^ (l>>32);
|
||||
S.V[i] = l & M61;
|
||||
sumtot += S.V[(i)]; if (sumtot < S.V[(i)]) {ovflow++;}
|
||||
}
|
||||
S.counter = N; // set the counter to N if iteration should happen right away
|
||||
S.sumtot = MIXMAX_MOD_MERSENNE(MIXMAX_MOD_MERSENNE(sumtot) + (ovflow <<3 ));
|
||||
}
|
||||
|
||||
#undef MIXMAX_SEED_WAS_ZERO
|
||||
|
||||
void MixMaxRng::seed_uniquestream( myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID )
|
||||
{
|
||||
seed_vielbein(0);
|
||||
S.sumtot = apply_bigskip(S.V.data(), S.V.data(), clusterID, machineID, runID, streamID );
|
||||
S.counter = 1;
|
||||
}
|
||||
|
||||
myuint_t MixMaxRng::apply_bigskip( myuint_t* Vout, myuint_t* Vin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID )
|
||||
{
|
||||
/*
|
||||
makes a derived state vector, Vout, from the mother state vector Vin
|
||||
by skipping a large number of steps, determined by the given seeding ID's
|
||||
|
||||
it is mathematically guaranteed that the substreams derived in this way from the SAME (!!!) Vin will not collide provided
|
||||
1) at least one bit of ID is different
|
||||
2) less than 10^100 numbers are drawn from the stream
|
||||
(this is good enough : a single CPU will not exceed this in the lifetime of the universe, 10^19 sec,
|
||||
even if it had a clock cycle of Planch time, 10^44 Hz )
|
||||
|
||||
Caution: never apply this to a derived vector, just choose some mother vector Vin, for example the unit vector by seed_vielbein(X,0),
|
||||
and use it in all your runs, just change runID to get completely nonoverlapping streams of random numbers on a different day.
|
||||
|
||||
clusterID and machineID are provided for the benefit of large organizations who wish to ensure that a simulation
|
||||
which is running in parallel on a large number of clusters and machines will have non-colliding source of random numbers.
|
||||
|
||||
did i repeat it enough times? the non-collision guarantee is absolute, not probabilistic
|
||||
|
||||
*/
|
||||
|
||||
const myuint_t skipMat17[128][17] =
|
||||
#include "CLHEP/Random/mixmax_skip_N17.icc"
|
||||
;
|
||||
|
||||
const myuint_t* skipMat[128];
|
||||
for (int i=0; i<128; i++) { skipMat[i] = skipMat17[i];}
|
||||
|
||||
myID_t IDvec[4] = {streamID, runID, machineID, clusterID};
|
||||
int r,i,j, IDindex;
|
||||
myID_t id;
|
||||
myuint_t Y[N], cum[N];
|
||||
myuint_t coeff;
|
||||
myuint_t* rowPtr;
|
||||
myuint_t sumtot=0;
|
||||
|
||||
for (i=0; i<N; i++) { Y[i] = Vin[i]; sumtot = modadd( sumtot, Vin[i]); } ;
|
||||
for (IDindex=0; IDindex<4; IDindex++)
|
||||
{ // go from lower order to higher order ID
|
||||
id=IDvec[IDindex];
|
||||
//printf("now doing ID at level %d, with ID = %d\n", IDindex, id);
|
||||
r = 0;
|
||||
while (id)
|
||||
{
|
||||
if (id & 1)
|
||||
{
|
||||
rowPtr = (myuint_t*)skipMat[r + IDindex*8*sizeof(myID_t)];
|
||||
for (i=0; i<N; i++){ cum[i] = 0; }
|
||||
for (j=0; j<N; j++)
|
||||
{ // j is lag, enumerates terms of the poly
|
||||
// for zero lag Y is already given
|
||||
coeff = rowPtr[j]; // same coeff for all i
|
||||
for (i =0; i<N; i++){
|
||||
cum[i] = fmodmulM61( cum[i], coeff , Y[i] ) ;
|
||||
}
|
||||
sumtot = iterate_raw_vec(Y, sumtot);
|
||||
}
|
||||
sumtot=0;
|
||||
for (i=0; i<N; i++){ Y[i] = cum[i]; sumtot = modadd( sumtot, cum[i]); } ;
|
||||
}
|
||||
id = (id >> 1); r++; // bring up the r-th bit in the ID
|
||||
}
|
||||
}
|
||||
sumtot=0;
|
||||
for (i=0; i<N; i++){ Vout[i] = Y[i]; sumtot = modadd( sumtot, Y[i]); }
|
||||
// returns sumtot, and copy the vector over to Vout
|
||||
return (sumtot) ;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
myuint_t MixMaxRng::mod128(__uint128_t s)
|
||||
{
|
||||
myuint_t s1;
|
||||
s1 = ( ( ((myuint_t)s)&M61 ) + ( ((myuint_t)(s>>64)) * 8 ) + ( ((myuint_t)s) >>BITS) );
|
||||
return MIXMAX_MOD_MERSENNE(s1);
|
||||
}
|
||||
myuint_t MixMaxRng::fmodmulM61(myuint_t cum, myuint_t a, myuint_t b)
|
||||
{
|
||||
__uint128_t temp;
|
||||
temp = (__uint128_t)a*(__uint128_t)b + cum;
|
||||
return mod128(temp);
|
||||
}
|
||||
#else // on all other platforms, including 32-bit linux, PPC and PPC64, ARM and all Windows
|
||||
myuint_t MixMaxRng::fmodmulM61(myuint_t cum, myuint_t s, myuint_t a)
|
||||
{
|
||||
const myuint_t MASK32=0xFFFFFFFFULL;
|
||||
myuint_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;
|
||||
}
|
||||
#endif
|
||||
|
||||
myuint_t MixMaxRng::modadd(myuint_t foo, myuint_t bar)
|
||||
{
|
||||
#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) && (!defined(__ICC))
|
||||
//#warning Using assembler routine in modadd
|
||||
myuint_t out;
|
||||
/* Assembler trick suggested by Andrzej Görlich */
|
||||
__asm__ ("addq %2, %0; "
|
||||
"btrq $61, %0; "
|
||||
"adcq $0, %0; "
|
||||
:"=r"(out)
|
||||
:"0"(foo), "r"(bar)
|
||||
);
|
||||
return out;
|
||||
#else
|
||||
return MIXMAX_MOD_MERSENNE(foo+bar);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MixMaxRng::print_state() const
|
||||
{
|
||||
int j;
|
||||
std::cout << "mixmax state, file version 1.0\n";
|
||||
std::cout << "N=" << rng_get_N() << "; V[N]={";
|
||||
for (j=0; (j< (rng_get_N()-1) ); j++) {
|
||||
std::cout << S.V[j] << ", ";
|
||||
}
|
||||
std::cout << S.V[rng_get_N()-1];
|
||||
std::cout << "}; ";
|
||||
std::cout << "counter= " << S.counter;
|
||||
std::cout << "sumtot= " << S.sumtot << "\n";
|
||||
}
|
||||
|
||||
MixMaxRng MixMaxRng::Branch()
|
||||
{
|
||||
S.sumtot = iterate_raw_vec(S.V.data(), S.sumtot); S.counter = 1;
|
||||
MixMaxRng tmp=*this;
|
||||
tmp.BranchInplace(0); // daughter id
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void MixMaxRng::BranchInplace(int id)
|
||||
{
|
||||
// Dont forget to iterate the mother, when branching the daughter, or else will have collisions!
|
||||
// a 64-bit LCG from Knuth line 26, is used to mangle a vector component
|
||||
constexpr myuint_t MULT64=6364136223846793005ULL;
|
||||
myuint_t tmp=S.V[id];
|
||||
S.V[1] *= MULT64; S.V[id] &= M61;
|
||||
S.sumtot = MIXMAX_MOD_MERSENNE( S.sumtot + S.V[id] - tmp + M61);
|
||||
S.sumtot = iterate_raw_vec(S.V.data(), S.sumtot);// printf("iterating!\n");
|
||||
S.counter = 1;
|
||||
}
|
||||
|
||||
} // namespace CLHEP
|
||||
|
||||
Vendored
+2
-2
@@ -19,7 +19,7 @@
|
||||
// =======================================================================
|
||||
|
||||
#include <assert.h>
|
||||
#include "CLHEP/Random/JamesRandom.h"
|
||||
#include "CLHEP/Random/MixMaxRng.h"
|
||||
#include "CLHEP/Random/Random.h"
|
||||
#include "CLHEP/Random/StaticRandomStates.h"
|
||||
#include "CLHEP/Utility/memory.h"
|
||||
@@ -65,7 +65,7 @@ namespace CLHEP {
|
||||
private:
|
||||
|
||||
HepRandom theDefaultGenerator;
|
||||
HepJamesRandom theDefaultEngine;
|
||||
MixMaxRng theDefaultEngine;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Vendored
-452
@@ -1,452 +0,0 @@
|
||||
// $Id:$
|
||||
// -*- C++ -*-
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// MixMax Matrix PseudoRandom Number Generator
|
||||
// --- MixMax ---
|
||||
// class header file
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Created by Konstantin Savvidy on Sun Feb 22 2004.
|
||||
// As of version 0.99 and later, the code is being released under
|
||||
// GNU Lesser General Public License v3
|
||||
//
|
||||
// Generator described in
|
||||
// N.Z.Akopov, G.K.Savvidy and N.G.Ter-Arutyunian, Matrix Generator of Pseudorandom Numbers,
|
||||
// J.Comput.Phys. 97, 573 (1991);
|
||||
// Preprint EPI-867(18)-86, Yerevan Jun.1986;
|
||||
//
|
||||
// and
|
||||
//
|
||||
// K.Savvidy
|
||||
// The MIXMAX random number generator
|
||||
// Comp. Phys. Commun. (2015)
|
||||
// http://dx.doi.org/10.1016/j.cpc.2015.06.003
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define __MIXMAX_C // do NOT define it in your own program, just include mixmax.h
|
||||
|
||||
#include "CLHEP/Random/mixmax.h"
|
||||
|
||||
namespace CLHEP {
|
||||
|
||||
int iterate(rng_state_t* X){
|
||||
X->sumtot = iterate_raw_vec(X->V, X->sumtot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (SPECIALMUL!=0)
|
||||
inline uint64_t MULWU (uint64_t k){ return (( (k)<<(SPECIALMUL) & M61) | ( (k) >> (BITS-SPECIALMUL)) ) ;}
|
||||
#elif (SPECIALMUL==0)
|
||||
inline uint64_t MULWU (uint64_t){ return 0;}
|
||||
#else
|
||||
#error SPECIALMUL not undefined
|
||||
#endif
|
||||
|
||||
myuint iterate_raw_vec(myuint* Y, myuint sumtotOld){
|
||||
// operates with a raw vector, uses known sum of elements of Y
|
||||
int i;
|
||||
#ifdef SPECIAL
|
||||
myuint temp2 = Y[1];
|
||||
#endif
|
||||
myuint tempP, tempV;
|
||||
Y[0] = ( tempV = sumtotOld);
|
||||
myuint sumtot = Y[0], ovflow = 0; // will keep a running sum of all new elements (except Y[0])
|
||||
tempP = 0; // will keep a partial sum of all old elements (except Y[0])
|
||||
for (i=1; i<N; i++){
|
||||
#if (SPECIALMUL!=0)
|
||||
myuint tempPO = MULWU(tempP);
|
||||
tempP = modadd(tempP,Y[i]);
|
||||
tempV = MOD_MERSENNE(tempV + tempP + tempPO); // edge cases ?
|
||||
#else
|
||||
tempP = modadd(tempP , Y[i]);
|
||||
tempV = modadd(tempV , tempP);
|
||||
#endif
|
||||
Y[i] = tempV;
|
||||
sumtot += tempV; if (sumtot < tempV) {ovflow++;}
|
||||
}
|
||||
#ifdef SPECIAL
|
||||
temp2 = MOD_MULSPEC(temp2);
|
||||
Y[2] = modadd( Y[2] , temp2 );
|
||||
sumtot += temp2; if (sumtot < temp2) {ovflow++;}
|
||||
#endif
|
||||
return MOD_MERSENNE(MOD_MERSENNE(sumtot) + (ovflow <<3 ));
|
||||
}
|
||||
|
||||
myuint get_next(rng_state_t* X) {
|
||||
return GET_BY_MACRO(X);
|
||||
}
|
||||
|
||||
double get_next_float(rng_state_t* X){
|
||||
return get_next_float_BY_MACRO(X);
|
||||
}
|
||||
|
||||
void fill_array(rng_state_t* X, unsigned int n, double *array)
|
||||
{
|
||||
// Return an array of n random numbers uniformly distributed in (0,1]
|
||||
unsigned int i,j;
|
||||
const int M=N-1;
|
||||
for (i=0; i<(n/M); i++){
|
||||
iterate_and_fill_array(X, array+i*M);
|
||||
}
|
||||
unsigned int rem=(n % M);
|
||||
if (rem) {
|
||||
iterate(X);
|
||||
for (j=0; j< (rem); j++){
|
||||
array[M*i+j] = (int64_t)X->V[j] * (double)(INV_MERSBASE);
|
||||
}
|
||||
X->counter = j; // needed to continue with single fetches from the exact spot, but if you only use fill_array to get numbers then it is not necessary
|
||||
}else{
|
||||
X->counter = N;
|
||||
}
|
||||
}
|
||||
|
||||
void iterate_and_fill_array(rng_state_t* X, double *array){
|
||||
myuint* Y=X->V;
|
||||
int i;
|
||||
myuint tempP, tempV;
|
||||
#if (SPECIAL != 0)
|
||||
myuint temp2 = Y[1];
|
||||
#endif
|
||||
Y[0] = (tempV = modadd(Y[0] , X->sumtot));
|
||||
//array[0] = (double)tempV * (double)(INV_MERSBASE);
|
||||
myuint sumtot = 0, ovflow = 0; // will keep a running sum of all new elements (except Y[0])
|
||||
tempP = 0; // will keep a partial sum of all old elements (except Y[0])
|
||||
for (i=1; i<N; i++){
|
||||
tempP = modadd(tempP,Y[i]);
|
||||
Y[i] = ( tempV = modadd(tempV,tempP) );
|
||||
sumtot += tempV; if (sumtot < tempV) {ovflow++;}
|
||||
array[i-1] = (int64_t)tempV * (double)(INV_MERSBASE);
|
||||
}
|
||||
#if (SPECIAL != 0)
|
||||
temp2 = MOD_MULSPEC(temp2);
|
||||
Y[2] = modadd( Y[2] , temp2 );
|
||||
sumtot += temp2; if (sumtot < temp2) {ovflow++;}
|
||||
#endif
|
||||
X->sumtot = MOD_MERSENNE(MOD_MERSENNE(sumtot) + (ovflow <<3 ));
|
||||
}
|
||||
|
||||
myuint modadd(myuint foo, myuint bar){
|
||||
#if defined(__x86_64__) && defined(USE_INLINE_ASM)
|
||||
myuint out;
|
||||
/* Assembler trick suggested by Andrzej Görlich */
|
||||
__asm__ ("addq %2, %0; "
|
||||
"btrq $61, %0; "
|
||||
"adcq $0, %0; "
|
||||
:"=r"(out)
|
||||
:"0"(foo), "r"(bar)
|
||||
);
|
||||
return out;
|
||||
#else
|
||||
return MOD_MERSENNE(foo+bar);
|
||||
#endif
|
||||
}
|
||||
|
||||
rng_state_t* rng_alloc()
|
||||
{
|
||||
/* allocate the state */
|
||||
rng_state_t *p = (rng_state_t*)malloc(sizeof(rng_state_t));
|
||||
p->fh=NULL; // by default, set the output file handle to stdout
|
||||
return p;
|
||||
}
|
||||
|
||||
int rng_free(rng_state_t* X) /* free the memory occupied by the state */
|
||||
{
|
||||
free(X);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rng_state_t* rng_copy(myuint *Y)
|
||||
{
|
||||
/* copy the vector stored at Y, and return pointer to the newly allocated and initialized state.
|
||||
It is the user's responsibility to make sure that Y is properly allocated with rng_alloc,
|
||||
then pass Y->V or it can also be an array -- such as myuint Y[N+1] and Y[1]...Y[N] have been set to legal values [0 .. MERSBASE-1]
|
||||
Partial sums on this new state are recalculated, and counter set to zero, so that when get_next is called,
|
||||
it will output the initial vector before any new numbers are produced, call iterate(X) if you want to advance right away */
|
||||
rng_state_t* X = rng_alloc();
|
||||
myuint sumtot=0,ovflow=0;
|
||||
X->counter = 2;
|
||||
int i;
|
||||
for ( i=0; i < N; i++){
|
||||
X->V[i] = Y[i];
|
||||
sumtot += X->V[(i)]; if (sumtot < X->V[(i)]) {ovflow++;}
|
||||
|
||||
}
|
||||
X->sumtot = MOD_MERSENNE(MOD_MERSENNE(sumtot) + (ovflow <<3 ));
|
||||
return X;
|
||||
}
|
||||
|
||||
void seed_vielbein(rng_state_t* X, unsigned int index)
|
||||
{
|
||||
int i;
|
||||
if (index<N){
|
||||
for (i=0; i < N; i++){
|
||||
X->V[i] = 0;
|
||||
}
|
||||
X->V[index] = 1;
|
||||
}else{
|
||||
fprintf(stderr, "Out of bounds index, is not ( 0 <= index < N )\n"); exit(ARRAY_INDEX_OUT_OF_BOUNDS);
|
||||
}
|
||||
X->counter = N; // set the counter to N if iteration should happen right away
|
||||
//precalc(X);
|
||||
X->sumtot = 1; //(index ? 1:0);
|
||||
if (X->fh==NULL){X->fh=stdout;}
|
||||
}
|
||||
|
||||
void seed_spbox(rng_state_t* X, myuint seed)
|
||||
{ // a 64-bit LCG from Knuth line 26, in combination with a bit swap is used to seed
|
||||
const myuint MULT64=6364136223846793005ULL;
|
||||
int i;
|
||||
myuint sumtot=0,ovflow=0;
|
||||
if (seed == 0){
|
||||
fprintf(stderr, " try seeding with nonzero seed next time!\n");
|
||||
exit(SEED_WAS_ZERO);
|
||||
}
|
||||
|
||||
myuint l = seed;
|
||||
|
||||
//X->V[0] = l & MERSBASE;
|
||||
if (X->fh==NULL){X->fh=stdout;} // if the filehandle is not yet set, make it stdout
|
||||
for (i=0; i < N; i++){
|
||||
l*=MULT64; l = (l << 32) ^ (l>>32);
|
||||
X->V[i] = l & MERSBASE;
|
||||
sumtot += X->V[(i)]; if (sumtot < X->V[(i)]) {ovflow++;}
|
||||
}
|
||||
X->counter = N; // set the counter to N if iteration should happen right away
|
||||
X->sumtot = MOD_MERSENNE(MOD_MERSENNE(sumtot) + (ovflow <<3 ));
|
||||
}
|
||||
|
||||
myuint precalc(rng_state_t* X){
|
||||
int i;
|
||||
myuint temp;
|
||||
temp = 0;
|
||||
for (i=0; i < N; i++){
|
||||
temp = MOD_MERSENNE(temp + X->V[i]);
|
||||
}
|
||||
X->sumtot = temp;
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
int rng_get_N(void){return N;}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
inline myuint mod128(__uint128_t s){
|
||||
myuint s1;
|
||||
s1 = ( ( ((myuint)s)&MERSBASE ) + ( ((myuint)(s>>64)) * 8 ) + ( ((myuint)s) >>BITS) );
|
||||
return MOD_MERSENNE(s1);
|
||||
}
|
||||
|
||||
inline myuint fmodmulM61(myuint cum, myuint a, myuint b){
|
||||
__uint128_t temp;
|
||||
temp = (__uint128_t)a*(__uint128_t)b + cum;
|
||||
return mod128(temp);
|
||||
}
|
||||
|
||||
#else // on all other platforms, including 32-bit linux, PPC and PPC64 and all Windows
|
||||
#define MASK32 0xFFFFFFFFULL
|
||||
|
||||
inline myuint fmodmulM61(myuint cum, myuint s, myuint a)
|
||||
{
|
||||
myuint 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
void print_state(rng_state_t* X){
|
||||
int j;
|
||||
fprintf(X->fh, "mixmax state, file version 1.0\n" );
|
||||
fprintf(X->fh, "N=%u; V[N]={", rng_get_N() );
|
||||
for (j=0; (j< (rng_get_N()-1) ); j++) {
|
||||
fprintf(X->fh, "%llu, ", X->V[j] );
|
||||
}
|
||||
fprintf(X->fh, "%llu", X->V[rng_get_N()-1] );
|
||||
fprintf(X->fh, "}; " );
|
||||
fprintf(X->fh, "counter=%u; ", X->counter );
|
||||
fprintf(X->fh, "sumtot=%llu;\n", X->sumtot );
|
||||
}
|
||||
|
||||
void read_state(rng_state_t* X, const char filename[] ){
|
||||
// a function for reading the state from a file, after J. Apostolakis
|
||||
FILE* fin;
|
||||
if( ( fin = fopen(filename, "r") ) ){
|
||||
char l=0;
|
||||
while ( l != '{' ) { // 0x7B = "{"
|
||||
l=fgetc(fin); // proceed until hitting opening bracket
|
||||
}
|
||||
ungetc(' ', fin);
|
||||
}else{
|
||||
fprintf(stderr, "mixmax -> read_state: error reading file %s\n", filename);
|
||||
exit(ERROR_READING_STATE_FILE);
|
||||
}
|
||||
|
||||
myuint vecVal;
|
||||
//printf("mixmax -> read_state: starting to read state from file\n");
|
||||
if (!fscanf(fin, "%llu", &X->V[0]) ) {fprintf(stderr, "mixmax -> read_state: error reading file %s\n", filename); exit(ERROR_READING_STATE_FILE);}
|
||||
//printf("V[%d] = %llu\n",0, X->V[0]);
|
||||
int i;
|
||||
for( i = 1; i < rng_get_N(); i++){
|
||||
if (!fscanf(fin, ", %llu", &vecVal) ) {fprintf(stderr, "mixmax -> read_state: error reading vector component i=%d from file %s\n", i, filename); exit(ERROR_READING_STATE_FILE);}
|
||||
//printf("V[%d] = %llu\n",i, vecVal);
|
||||
if( vecVal <= MERSBASE ){
|
||||
X->V[i] = vecVal;
|
||||
}else{
|
||||
fprintf(stderr, "mixmax -> read_state: Invalid state vector value= %llu"
|
||||
" ( must be less than %llu ) "
|
||||
" obtained from reading file %s\n"
|
||||
, vecVal, MERSBASE, filename);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int counter;
|
||||
if (!fscanf( fin, "}; counter=%u; ", &counter)){fprintf(stderr, "mixmax -> read_state: error reading counter from file %s\n", filename); exit(ERROR_READING_STATE_FILE);}
|
||||
if( counter <= N ) {
|
||||
X->counter= counter;
|
||||
}else{
|
||||
fprintf(stderr, "mixmax -> read_state: Invalid counter = %d"
|
||||
" Must be 0 <= counter < %u\n" , counter, N);
|
||||
print_state(X);
|
||||
exit(ERROR_READING_STATE_COUNTER);
|
||||
}
|
||||
precalc(X);
|
||||
myuint sumtot;
|
||||
if (!fscanf( fin, "sumtot=%llu\n", &sumtot)){fprintf(stderr, "mixmax -> read_state: error reading checksum from file %s\n", filename); exit(ERROR_READING_STATE_FILE);}
|
||||
|
||||
if (X->sumtot != sumtot) {
|
||||
fprintf(stderr, "mixmax -> checksum error while reading state from file %s - corrupted?\n", filename);
|
||||
exit(ERROR_READING_STATE_CHECKSUM);
|
||||
}
|
||||
// else{fprintf(stderr, "mixmax -> read_state: checksum ok: %llu == %llu\n",X->sumtot, sumtot);}
|
||||
fclose(fin);
|
||||
}
|
||||
|
||||
|
||||
#define FUSEDMODMULVEC \
|
||||
{ for (i =0; i<N; i++){ \
|
||||
cum[i] = fmodmulM61( cum[i], coeff , Y[i] ) ; \
|
||||
} }
|
||||
|
||||
|
||||
#define SKIPISON 1
|
||||
|
||||
#if (BITS==61 && SKIPISON!=0)
|
||||
void seed_uniquestream( rng_state_t* Xin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID ){
|
||||
seed_vielbein(Xin,0);
|
||||
Xin->sumtot = apply_bigskip(Xin->V, Xin->V, clusterID, machineID, runID, streamID );
|
||||
if (Xin->fh==NULL){Xin->fh=stdout;} // if the filehandle is not yet set, make it stdout
|
||||
}
|
||||
|
||||
void branch_inplace( rng_state_t* Xin, myID_t* IDvec ){
|
||||
Xin->sumtot = apply_bigskip(Xin->V, Xin->V, IDvec[3], IDvec[2], IDvec[1], IDvec[0] );
|
||||
}
|
||||
|
||||
myuint apply_bigskip(myuint* Vout, myuint* Vin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID ){
|
||||
/*
|
||||
makes a derived state vector, Vout, from the mother state vector Vin
|
||||
by skipping a large number of steps, determined by the given seeding ID's
|
||||
|
||||
it is mathematically guaranteed that the substreams derived in this way from the SAME (!!!) Vin will not collide provided
|
||||
1) at least one bit of ID is different
|
||||
2) less than 10^100 numbers are drawn from the stream
|
||||
(this is good enough : a single CPU will not exceed this in the lifetime of the universe, 10^19 sec,
|
||||
even if it had a clock cycle of Planch time, 10^44 Hz )
|
||||
|
||||
Caution: never apply this to a derived vector, just choose some mother vector Vin, for example the unit vector by seed_vielbein(X,0),
|
||||
and use it in all your runs, just change runID to get completely nonoverlapping streams of random numbers on a different day.
|
||||
|
||||
clusterID and machineID are provided for the benefit of large organizations who wish to ensure that a simulation
|
||||
which is running in parallel on a large number of clusters and machines will have non-colliding source of random numbers.
|
||||
|
||||
did i repeat it enough times? the non-collision guarantee is absolute, not probabilistic
|
||||
|
||||
*/
|
||||
|
||||
|
||||
const myuint skipMat[128][N] =
|
||||
|
||||
//#if (N==8)
|
||||
//#include "CLHEP/Random/mixmax_skip_N8.icc"
|
||||
//#elif (N==17)
|
||||
#include "CLHEP/Random/mixmax_skip_N17.icc"
|
||||
//#elif (N==88)
|
||||
//#include "CLHEP/Random/mixmax_skip_N88.icc" // to make this file, delete all except some chosen 128 rows of the coefficients table
|
||||
//#elif (N==256)
|
||||
//#include "CLHEP/Random/mixmax_skip_N256.icc"
|
||||
//#elif (N==1000)
|
||||
//#include "CLHEP/Random/mixmax_skip_N1000.icc"
|
||||
//#elif (N==3150)
|
||||
//#include "CLHEP/Random/mixmax_skip_N3150.icc"
|
||||
//#endif
|
||||
;
|
||||
|
||||
myID_t IDvec[4] = {streamID, runID, machineID, clusterID};
|
||||
int r,i,j, IDindex;
|
||||
myID_t id;
|
||||
myuint Y[N], cum[N];
|
||||
myuint coeff;
|
||||
myuint* rowPtr;
|
||||
myuint sumtot=0;
|
||||
|
||||
|
||||
for (i=0; i<N; i++) { Y[i] = Vin[i]; sumtot = modadd( sumtot, Vin[i]); } ;
|
||||
for (IDindex=0; IDindex<4; IDindex++) { // go from lower order to higher order ID
|
||||
id=IDvec[IDindex];
|
||||
//printf("now doing ID at level %d, with ID = %d\n", IDindex, id);
|
||||
r = 0;
|
||||
while (id){
|
||||
if (id & 1) {
|
||||
rowPtr = (myuint*)skipMat[r + IDindex*8*sizeof(myID_t)];
|
||||
//printf("free coeff for row %d is %llu\n", r, rowPtr[0]);
|
||||
for (i=0; i<N; i++){ cum[i] = 0; }
|
||||
for (j=0; j<N; j++){ // j is lag, enumerates terms of the poly
|
||||
// for zero lag Y is already given
|
||||
coeff = rowPtr[j]; // same coeff for all i
|
||||
FUSEDMODMULVEC;
|
||||
sumtot = iterate_raw_vec(Y, sumtot);
|
||||
}
|
||||
sumtot=0;
|
||||
for (i=0; i<N; i++){ Y[i] = cum[i]; sumtot = modadd( sumtot, cum[i]); } ;
|
||||
}
|
||||
id = (id >> 1); r++; // bring up the r-th bit in the ID
|
||||
}
|
||||
}
|
||||
sumtot=0;
|
||||
for (i=0; i<N; i++){ Vout[i] = Y[i]; sumtot = modadd( sumtot, Y[i]); } ; // returns sumtot, and copy the vector over to Vout
|
||||
return (sumtot) ;
|
||||
}
|
||||
#else
|
||||
#warning For this N, we dont have the skipping coefficients yet, using alternative method to seed
|
||||
|
||||
void seed_uniquestream( rng_state_t* Xin, myID_t clusterID, myID_t machineID, myID_t runID, myID_t streamID ){
|
||||
Xin->V[0] = (myuint)clusterID;
|
||||
Xin->V[1] = (myuint)machineID;
|
||||
Xin->V[2] = (myuint)runID;
|
||||
Xin->V[3] = (myuint)streamID;
|
||||
Xin->V[4] = (myuint)clusterID << 5;
|
||||
Xin->V[5] = (myuint)machineID << 7;
|
||||
Xin->V[6] = (myuint)runID << 11;
|
||||
Xin->V[7] = (myuint)streamID << 13;
|
||||
precalc(Xin);
|
||||
Xin->sumtot = iterate_raw_vec(Xin->V, Xin->sumtot);
|
||||
Xin->sumtot = iterate_raw_vec(Xin->V, Xin->sumtot);
|
||||
}
|
||||
#endif // SKIPISON
|
||||
} // namespace CLHEP
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user