mirror of
http://43.156.76.180:8026/YuuMJ/EukPhylo.git
synced 2025-12-28 04:20:25 +08:00
385 lines
8.2 KiB
C++
385 lines
8.2 KiB
C++
//#include <MainLib.h> //change
|
|
#include "RandomGenerator.h" //change
|
|
#include <algorithm>
|
|
#include <cassert> //change
|
|
|
|
#ifndef unix
|
|
#define CONSTANTS_VERY_LARGE_INT 4294967291
|
|
#define CONSTANTS_VERY_LARGE_INT_2 362436069
|
|
#define CONSTANTS_VERY_LARGE_INT_3 4294967295
|
|
#else
|
|
#define CONSTANTS_VERY_LARGE_INT 4294967291LL
|
|
#define CONSTANTS_VERY_LARGE_INT_2 362436069LL
|
|
#define CONSTANTS_VERY_LARGE_INT_3 4294967295LL
|
|
#endif
|
|
|
|
tRandomGenerator _RandomProbGenerator;
|
|
|
|
unsigned long
|
|
tMarsagliaGenerator::Next()
|
|
{
|
|
register unsigned long hold;
|
|
if (--i==0) i=43;
|
|
if (--j==0) j=43;
|
|
hold = word1[i]+carry;
|
|
if (word1[j] < hold)
|
|
{
|
|
word1[i] = CONSTANTS_VERY_LARGE_INT - (hold-word1[j]);
|
|
carry = 1;
|
|
}
|
|
else
|
|
{
|
|
word1[i] = word1[j]-hold;
|
|
carry=0;
|
|
}
|
|
weyl-=CONSTANTS_VERY_LARGE_INT_2;
|
|
return word1[i] - weyl;
|
|
}
|
|
|
|
tMarsagliaGenerator::tMarsagliaGenerator(unsigned query)
|
|
{
|
|
unsigned start=1; // default
|
|
|
|
if (query)
|
|
{
|
|
cout << "Enter random number seed, 0<seed<65000." << endl;
|
|
cin >> start;
|
|
}
|
|
|
|
srand(start);
|
|
|
|
for (j=1;j<=43;j++) // make initial numbers.
|
|
{
|
|
word1[j]=rand();
|
|
word1[j]=((word1[j] << 15 ) + rand());
|
|
word1[j]=((word1[j] << 2 ) + rand()%4);
|
|
if (word1[j]>CONSTANTS_VERY_LARGE_INT) word1[j] = CONSTANTS_VERY_LARGE_INT;
|
|
}
|
|
|
|
// initialize markers
|
|
i=44; j=23; carry=1; weyl=rand();
|
|
|
|
for (unsigned long a=1,garbage; a<100000; a++) // Warm-up
|
|
garbage = Next();
|
|
}
|
|
|
|
void
|
|
tMarsagliaGenerator::Initialize(unsigned start)
|
|
{
|
|
srand(start);
|
|
|
|
for (j=1;j<=43;j++) // make initial numbers.
|
|
{
|
|
word1[j]=rand();
|
|
word1[j]=((word1[j] << 15 ) + rand());
|
|
word1[j]=((word1[j] << 2 ) + rand()%4);
|
|
if (word1[j]>CONSTANTS_VERY_LARGE_INT) word1[j] = CONSTANTS_VERY_LARGE_INT;
|
|
}
|
|
|
|
i=44; j=23; carry=1; weyl=rand(); // initialize markers
|
|
|
|
for (unsigned long a=1,garbage; a<100000; a++) // Warm-up
|
|
garbage = Next();
|
|
}
|
|
|
|
double tMarsagliaGenerator::RandomDouble(double range)
|
|
{
|
|
return ((((double)Next())/CONSTANTS_VERY_LARGE_INT_3)*range);
|
|
}
|
|
|
|
|
|
|
|
double
|
|
tRandomGenerator::SampleUniform(void)
|
|
{
|
|
return RandomDouble(1.0);
|
|
}
|
|
|
|
|
|
|
|
double
|
|
tRandomGenerator::SampleNormal()
|
|
{
|
|
#ifdef notdef
|
|
// Ratio of uniforms, Ripley, Stochastic Simulation, p. 82
|
|
double U, V;
|
|
double X;
|
|
double Z;
|
|
double c = sqrt(2/exp(1));
|
|
do {
|
|
retry:
|
|
U = c*(SampleUniform()*2-1);
|
|
V = c*(SampleUniform()*2-1);
|
|
if( fabs(U) < EPS )
|
|
goto retry;
|
|
X = V/U;
|
|
Z = .25*X*X;
|
|
if( Z < 1 - U )
|
|
break;
|
|
} while( (Z > 0.259/U + 0.35 ) || Z > -log(U) );
|
|
return X;
|
|
#endif
|
|
|
|
// Box-Muller, Ripley p. 54
|
|
|
|
double theta = 2*3.1415926535897932384626433832795*SampleUniform(); //change
|
|
// double theta = 2*M_PI*SampleUniform(); //change
|
|
double R = sqrt(2*-log(SampleUniform()));
|
|
return R * cos(theta);
|
|
}
|
|
|
|
// Code adopted from David Heckerman
|
|
//-----------------------------------------------------------
|
|
// DblGammaGreaterThanOne(dblAlpha)
|
|
//
|
|
// routine to generate a gamma random variable with unit scale and
|
|
// alpha > 1
|
|
// reference: Ripley, Stochastic Simulation, p.90
|
|
// Chang and Feast, Appl.Stat. (28) p.290
|
|
//-----------------------------------------------------------
|
|
double tRandomGenerator::DblGammaGreaterThanOne(double dblAlpha)
|
|
{
|
|
double rgdbl[6];
|
|
|
|
rgdbl[1] = dblAlpha - 1.0;
|
|
rgdbl[2] = (dblAlpha - (1.0 / (6.0 * dblAlpha))) / rgdbl[1];
|
|
rgdbl[3] = 2.0 / rgdbl[1];
|
|
rgdbl[4] = rgdbl[3] + 2.0;
|
|
rgdbl[5] = 1.0 / sqrt(dblAlpha);
|
|
|
|
for (;;)
|
|
{
|
|
double dblRand1;
|
|
double dblRand2;
|
|
do
|
|
{
|
|
dblRand1 = SampleUniform();
|
|
dblRand2 = SampleUniform();
|
|
|
|
if (dblAlpha > 2.5)
|
|
dblRand1 = dblRand2 + rgdbl[5] * (1.0 - 1.86 * dblRand1);
|
|
|
|
} while (!(0.0 < dblRand1 && dblRand1 < 1.0));
|
|
|
|
double dblTemp = rgdbl[2] * dblRand2 / dblRand1;
|
|
|
|
if (rgdbl[3] * dblRand1 + dblTemp + 1.0 / dblTemp <= rgdbl[4] ||
|
|
rgdbl[3] * log(dblRand1) + dblTemp - log(dblTemp) < 1.0)
|
|
{
|
|
return dblTemp * rgdbl[1];
|
|
}
|
|
}
|
|
assert(false);
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
|
|
/* routine to generate a gamma random variable with unit scale and alpha
|
|
< 1
|
|
|
|
reference: Ripley, Stochastic Simulation, p.88 */
|
|
|
|
double
|
|
tRandomGenerator::DblGammaLessThanOne(double dblAlpha)
|
|
{
|
|
double dblTemp;
|
|
|
|
const double dblexp = exp(1.0);
|
|
|
|
for (;;)
|
|
{
|
|
double dblRand0 = SampleUniform();
|
|
double dblRand1 = SampleUniform();
|
|
if (dblRand0 <= (dblexp / (dblAlpha + dblexp)))
|
|
{
|
|
dblTemp = pow(((dblAlpha + dblexp) * dblRand0) /
|
|
dblexp, 1.0 / dblAlpha);
|
|
if (dblRand1 <= exp(-1.0 * dblTemp))
|
|
return dblTemp;
|
|
}
|
|
else
|
|
{
|
|
dblTemp = -1.0 * log((dblAlpha + dblexp) * (1.0 - dblRand0) /
|
|
(dblAlpha * dblexp));
|
|
if (dblRand1 <= pow(dblTemp,dblAlpha - 1.0))
|
|
return dblTemp;
|
|
}
|
|
}
|
|
assert(false);
|
|
return 0.0;
|
|
} /* DblGammaLessThanOne */
|
|
|
|
// Routine to generate a gamma random variable with unit scale (beta = 1)
|
|
double
|
|
tRandomGenerator::SampleGamma(double dblAlpha)
|
|
{
|
|
assert(dblAlpha > 0.0);
|
|
if( dblAlpha < 1.0 )
|
|
return DblGammaLessThanOne(dblAlpha);
|
|
else
|
|
if( dblAlpha > 1.0 )
|
|
return DblGammaGreaterThanOne(dblAlpha);
|
|
|
|
return -log(SampleUniform());
|
|
} /* gamma */
|
|
|
|
//-------------------------------------------------------------------------
|
|
// SampleDirichlet expects an RGALPHA such that the Dirichlet's parameters
|
|
// are a vector of alphas such that
|
|
// p(\theta) = c * \prod_i \theta_i^{\alpha_i - 1}
|
|
//-------------------------------------------------------------------------
|
|
|
|
void
|
|
tRandomGenerator::SampleDirichlet(const vector<double>& mean,
|
|
double precision,
|
|
vector<double>& rgprob)
|
|
{
|
|
assert(mean.size() == rgprob.size());
|
|
double dblSum = 0.0;
|
|
|
|
int i;
|
|
|
|
for( i = 0; i < mean.size(); i++ )
|
|
dblSum += (rgprob[i] = SampleGamma(mean[i] * precision));
|
|
|
|
for( i = 0; i < rgprob.size(); i++)
|
|
{
|
|
rgprob[i] = rgprob[i] / dblSum;
|
|
}
|
|
|
|
#ifdef LOG
|
|
cerr << "SampleDirichlet(";
|
|
for(int j = 0; j < mean.size(); j++ )
|
|
cerr << mean[j]*precision <<" ";
|
|
cerr << ") = [";
|
|
for(int j = 0; j < mean.size(); j++ )
|
|
cerr << rgprob[j] <<" ";
|
|
cerr <<"]\n";
|
|
#endif
|
|
}
|
|
|
|
void
|
|
tRandomGenerator::SampleDirichlet(int n,
|
|
double const * mean,
|
|
double precision,
|
|
double * rgprob)
|
|
{
|
|
double dblSum = 0.0;
|
|
int i;
|
|
|
|
for( i = 0; i < n; i++ )
|
|
dblSum += (rgprob[i] = SampleGamma(mean[i] * precision));
|
|
|
|
for( i = 0; i < n; i++)
|
|
{
|
|
rgprob[i] = rgprob[i] / dblSum;
|
|
}
|
|
|
|
#ifdef LOG
|
|
cerr << "SampleDirichlet(";
|
|
for(int j = 0; j < n; j++ )
|
|
cerr << mean[j]*precision <<" ";
|
|
cerr << ") = [";
|
|
for(int j = 0; j < n; j++ )
|
|
cerr << rgprob[j] <<" ";
|
|
cerr <<"]\n";
|
|
#endif
|
|
}
|
|
|
|
void
|
|
tRandomGenerator::SampleDirichlet(int n,
|
|
float const * mean,
|
|
double precision,
|
|
float * rgprob)
|
|
{
|
|
double dblSum = 0.0;
|
|
int i;
|
|
|
|
for( i = 0; i < n; i++ )
|
|
dblSum += (rgprob[i] = SampleGamma(mean[i] * precision));
|
|
|
|
for( i = 0; i < n; i++)
|
|
{
|
|
rgprob[i] = rgprob[i] / dblSum;
|
|
}
|
|
}
|
|
|
|
int
|
|
tRandomGenerator::SampleMultinomial( int n, double const* prob )
|
|
{
|
|
double p = SampleUniform();
|
|
int i = 0;
|
|
do{
|
|
p -= prob[i++];
|
|
} while( p > 0.0 && i < n );
|
|
|
|
#ifdef LOG
|
|
cerr << "SampleMulti(";
|
|
for(int j = 0; j < n; j++ )
|
|
cerr << prob[j] <<" ";
|
|
cerr << ") = " << i-1 << "\n";
|
|
#endif
|
|
|
|
return i-1;
|
|
}
|
|
|
|
int
|
|
tRandomGenerator::SampleLogMultinomial( int n, double* prob )
|
|
{
|
|
int i;
|
|
double s = 0.0;
|
|
double M = prob[0];
|
|
for( i = 1; i < n; i++ )
|
|
if( prob[i] > M )
|
|
M = prob[i];
|
|
|
|
for( i = 0; i < n; i++ )
|
|
{
|
|
prob[i] = exp(prob[i] - M);
|
|
s +=prob[i];
|
|
}
|
|
for( i = 0; i < n; i++ )
|
|
prob[i] /= s;
|
|
|
|
return SampleMultinomial(n , prob );
|
|
}
|
|
|
|
|
|
|
|
int
|
|
tRandomGenerator::sampleMulti( tMultinomial const & m ) {
|
|
int n;double const * p = NULL;
|
|
p = m.getParams(n);
|
|
return SampleMultinomial(n,p);
|
|
}
|
|
|
|
vector<int>
|
|
tRandomGenerator::sampleGroup(int size,int groupSize)
|
|
{
|
|
assert(groupSize<=size);
|
|
|
|
vector<int> group;
|
|
|
|
if (groupSize==size) {
|
|
for( int i=0; i<groupSize; i++ )
|
|
group.push_back(i);
|
|
return group;
|
|
}
|
|
|
|
vector<int> v;
|
|
for( int i=0; i<size; i++)
|
|
v.push_back(i);
|
|
|
|
for( int count = 0; count<groupSize; count++)
|
|
{
|
|
double val = SampleUniform();
|
|
int chosenPos = (int)( val*(size-count) );
|
|
group.push_back( v[chosenPos] );
|
|
v[chosenPos] = v[size-1-count];
|
|
}
|
|
sort(group.begin(),group.end());
|
|
|
|
return group;
|
|
}
|