dynare/dynare++/integ/cc/quasi_mcarlo.cweb

341 lines
8.3 KiB
Plaintext

@q $Id: quasi_mcarlo.cweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@ This is {\tt quasi\_mcarlo.cpp} file.
@c
#include "quasi_mcarlo.h"
#include <cmath>
@<|RadicalInverse| constructor code@>;
@<|RadicalInverse::eval| code@>;
@<|RadicalInverse::increase| code@>;
@<|RadicalInverse::print| code@>;
@<|HaltonSequence| static data@>;
@<|HaltonSequence| constructor code@>;
@<|HaltonSequence::operator=| code@>;
@<|HaltonSequence::increase| code@>;
@<|HaltonSequence::eval| code@>;
@<|HaltonSequence::print| code@>;
@<|qmcpit| empty constructor code@>;
@<|qmcpit| regular constructor code@>;
@<|qmcpit| copy constructor code@>;
@<|qmcpit| destructor@>;
@<|qmcpit::operator==| code@>;
@<|qmcpit::operator=| code@>;
@<|qmcpit::operator++| code@>;
@<|qmcpit::weight| code@>;
@<|qmcnpit| empty constructor code@>;
@<|qmcnpit| regular constructor code@>;
@<|qmcnpit| copy constructor code@>;
@<|qmcnpit| destructor@>;
@<|qmcnpit::operator=| code@>;
@<|qmcnpit::operator++| code@>;
@<|WarnockPerScheme::permute| code@>;
@<|ReversePerScheme::permute| code@>;
@ Here in the constructor, we have to calculate a maximum length of
|coeff| array for a given |base| and given maximum |maxn|. After
allocation, we calculate the coefficients.
@<|RadicalInverse| constructor code@>=
RadicalInverse::RadicalInverse(int n, int b, int mxn)
: num(n), base(b), maxn(mxn),
coeff((int)(floor(log((double)maxn)/log((double)b))+2), 0)
{
int nr = num;
j = -1;
do {
j++;
coeff[j] = nr % base;
nr = nr / base;
} while (nr > 0);
}
@ This evaluates the radical inverse. If there was no permutation, we have to calculate
$$
{c_0\over b}+{c_1\over b^2}+\ldots+{c_j\over b^{j+1}}
$$
which is evaluated as
$$
\left(\ldots\left(\left({c_j\over b}\cdot{1\over b}+{c_{j-1}\over b}\right)
\cdot{1\over b}+{c_{j-2}\over b}\right)
\ldots\right)\cdot{1\over b}+{c_0\over b}
$$
Now with permutation $\pi$, we have
$$
\left(\ldots\left(\left({\pi(c_j)\over b}\cdot{1\over b}+
{\pi(c_{j-1})\over b}\right)\cdot{1\over b}+
{\pi(c_{j-2})\over b}\right)
\ldots\right)\cdot{1\over b}+{\pi(c_0)\over b}
$$
@<|RadicalInverse::eval| code@>=
double RadicalInverse::eval(const PermutationScheme& p) const
{
double res = 0;
for (int i = j; i >= 0; i--) {
int cper = p.permute(i, base, coeff[i]);
res = (cper + res)/base;
}
return res;
}
@ We just add 1 to the lowest coefficient and check for overflow with respect to the base.
@<|RadicalInverse::increase| code@>=
void RadicalInverse::increase()
{
// todo: raise if |num+1 > maxn|
num++;
int i = 0;
coeff[i]++;
while (coeff[i] == base) {
coeff[i] = 0;
coeff[++i]++;
}
if (i > j)
j = i;
}
@ Debug print.
@<|RadicalInverse::print| code@>=
void RadicalInverse::print() const
{
printf("n=%d b=%d c=", num, base);
coeff.print();
}
@ Here we have the first 170 primes. This means that we are not able
to integrate dimensions greater than 170.
@<|HaltonSequence| static data@>=
int HaltonSequence::num_primes = 170;
int HaltonSequence::primes[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013
};
@ This takes first |dim| primes and constructs |dim| radical inverses
and calls |eval|.
@<|HaltonSequence| constructor code@>=
HaltonSequence::HaltonSequence(int n, int mxn, int dim, const PermutationScheme& p)
: num(n), maxn(mxn), per(p), pt(dim)
{
// todo: raise if |dim > num_primes|
// todo: raise if |n > mxn|
for (int i = 0; i < dim; i++)
ri.push_back(RadicalInverse(num, primes[i], maxn));
eval();
}
@
@<|HaltonSequence::operator=| code@>=
const HaltonSequence& HaltonSequence::operator=(const HaltonSequence& hs)
{
num = hs.num;
maxn = hs.maxn;
ri.clear();
for (unsigned int i = 0; i < hs.ri.size(); i++)
ri.push_back(RadicalInverse(hs.ri[i]));
pt = hs.pt;
return *this;
}
@ This calls |RadicalInverse::increase| for all radical inverses and
calls |eval|.
@<|HaltonSequence::increase| code@>=
void HaltonSequence::increase()
{
for (unsigned int i = 0; i < ri.size(); i++)
ri[i].increase();
num++;
if (num <= maxn)
eval();
}
@ This sets point |pt| to radical inverse evaluations in each dimension.
@<|HaltonSequence::eval| code@>=
void HaltonSequence::eval()
{
for (unsigned int i = 0; i < ri.size(); i++)
pt[i] = ri[i].eval(per);
}
@ Debug print.
@<|HaltonSequence::print| code@>=
void HaltonSequence::print() const
{
for (unsigned int i = 0; i < ri.size(); i++)
ri[i].print();
printf("point=[ ");
for (unsigned int i = 0; i < ri.size(); i++)
printf("%7.6f ", pt[i]);
printf("]\n");
}
@
@<|qmcpit| empty constructor code@>=
qmcpit::qmcpit()
: spec(NULL), halton(NULL), sig(NULL)@+ {}
@
@<|qmcpit| regular constructor code@>=
qmcpit::qmcpit(const QMCSpecification& s, int n)
: spec(&s), halton(new HaltonSequence(n, s.level(), s.dimen(), s.getPerScheme())),
sig(new ParameterSignal(s.dimen()))
{
}
@
@<|qmcpit| copy constructor code@>=
qmcpit::qmcpit(const qmcpit& qpit)
: spec(qpit.spec), halton(NULL), sig(NULL)
{
if (qpit.halton)
halton = new HaltonSequence(*(qpit.halton));
if (qpit.sig)
sig = new ParameterSignal(qpit.spec->dimen());
}
@
@<|qmcpit| destructor@>=
qmcpit::~qmcpit()
{
if (halton)
delete halton;
if (sig)
delete sig;
}
@
@<|qmcpit::operator==| code@>=
bool qmcpit::operator==(const qmcpit& qpit) const
{
return (spec == qpit.spec) &&
((halton == NULL && qpit.halton == NULL) ||
(halton != NULL && qpit.halton != NULL && halton->getNum() == qpit.halton->getNum()));
}
@
@<|qmcpit::operator=| code@>=
const qmcpit& qmcpit::operator=(const qmcpit& qpit)
{
spec = qpit.spec;
if (halton)
delete halton;
if (qpit.halton)
halton = new HaltonSequence(*(qpit.halton));
else
halton = NULL;
return *this;
}
@
@<|qmcpit::operator++| code@>=
qmcpit& qmcpit::operator++()
{
// todo: raise if |halton == null || qmcq == NULL|
halton->increase();
return *this;
}
@
@<|qmcpit::weight| code@>=
double qmcpit::weight() const
{
return 1.0/spec->level();
}
@
@<|qmcnpit| empty constructor code@>=
qmcnpit::qmcnpit()
: qmcpit(), pnt(NULL)@+ {}
@
@<|qmcnpit| regular constructor code@>=
qmcnpit::qmcnpit(const QMCSpecification& s, int n)
: qmcpit(s, n), pnt(new Vector(s.dimen()))
{
}
@
@<|qmcnpit| copy constructor code@>=
qmcnpit::qmcnpit(const qmcnpit& qpit)
: qmcpit(qpit), pnt(NULL)
{
if (qpit.pnt)
pnt = new Vector(*(qpit.pnt));
}
@
@<|qmcnpit| destructor@>=
qmcnpit::~qmcnpit()
{
if (pnt)
delete pnt;
}
@
@<|qmcnpit::operator=| code@>=
const qmcnpit& qmcnpit::operator=(const qmcnpit& qpit)
{
qmcpit::operator=(qpit);
if (pnt)
delete pnt;
if (qpit.pnt)
pnt = new Vector(*(qpit.pnt));
else
pnt = NULL;
return *this;
}
@ Here we inccrease a point in Halton sequence ant then store images
of the points in |NormalICDF| function.
@<|qmcnpit::operator++| code@>=
qmcnpit& qmcnpit::operator++()
{
qmcpit::operator++();
for (int i = 0; i < halton->point().length(); i++)
(*pnt)[i] = NormalICDF::get(halton->point()[i]);
return *this;
}
@ Clear from code.
@<|WarnockPerScheme::permute| code@>=
int WarnockPerScheme::permute(int i, int base, int c) const
{
return (c+i) % base;
}
@ Clear from code.
@<|ReversePerScheme::permute| code@>=
int ReversePerScheme::permute(int i, int base, int c) const
{
return (base-c) % base;
}
@ End of {\tt quasi\_mcarlo.cpp} file.