using System;
namespace Science.Mathematics.VectorCalculus
{
///
/// Adaptive multidimensional Monte Carlo integration.
///
public class IntegrationMultiD
{
private Function.ToLastType del;
public IntegrationMultiD()
{
}
public Function.ToLastType Function
{
set{del = value;}
}
public IntegrationMultiD(Function.ToLastType f)
{
del = f;
}
public IntegrationMultiD(Function.ToLastType f, double[] from, double[] to)
{
del = f;
this.from = from;
this.to = to;
}
public void Compute()
{
input = new double[2 * to.Length];
for (int i = 0; i < to.Length; i++)
{
input[i] = from[i];
input[to.Length + i] = to[i];
}
Vegas obj = new Vegas();
obj.Dummy = idum;
obj.vegas(input, input.Length / 2, del, 0, nc, 5, 0);
tgral = obj.BestEstimation;
sd = obj.StandardDeviation;
chi2a = obj.ChiSquare;
result = obj.Result;
}
private double[] input, from, to;
public double[] From
{
set { from = value;}
}
public double[] To
{
set { to = value;}
}
private ulong nc=100000;
public ulong NumberOfCall
{
set{nc=value;}
}
private ulong idum = 17;
public ulong Seed
{
set { idum = value; }
}
private double tgral, sd, chi2a;
private string result;
public double BestEstimation
{
get { return tgral; }
}
public double StandardDeviation
{
get { return sd; }
}
public double ChiSQUARE
{
get { return chi2a; }
}
public string Result
{
get { return result; }
}
public override string ToString()
{
string res = "";
res += this.BestEstimation.ToString() + " +/- " +
this.StandardDeviation.ToString();
res += "\r\n";
return res;
}
}
class Ran
{
ulong u, v, w;
public Ran(ulong j)
{
v = 4101842887655102017L;
w = 1;
u = j ^ v; int64();
v = u; int64();
w = v; int64();
}
public ulong int64()
{
u = u * 2862933555777941757L + 7046029254386353087L;
v ^= v >> 17; v ^= v << 31; v ^= v >> 8;
w = 4294957665U * (w & 0xffffffff) + (w >> 32);
ulong x = u ^ (u << 21); x ^= x >> 35; x ^= x << 4;
return (x + v) ^ w;
}
public double doub()
{
return 5.42101086242752217E-20 * int64();
}
public uint int32()
{
return (uint)int64();
}
ulong breg;
int bc;
public byte int8()
{
if ((bc--) != 0) return (byte)(breg >>= 8);
breg = int64();
bc = 7;
return (byte)breg;
}
}
class Vegas
{
public Vegas()
{
ia = new int[MXDIM];
kg = new int[MXDIM];
d = new double[NDMX,MXDIM];
di = new double[NDMX,MXDIM];
dt = new double[MXDIM];
dx = new double[MXDIM];
r = new double[NDMX];
x = new double[MXDIM];
xi= new double[MXDIM,NDMX];
xin= new double[NDMX];
}
private double ALPH = 1.5;
private int NDMX = 50;
private int MXDIM = 10;
private double TINY = 1.0e-30;
private int i,it,j,k,mds,nd,ndo,ng,npg;
private int[] ia, kg;
private double calls,dv2g,dxg,f,f2,f2b,fb,rc,ti,tsi,wgt,xjac,xn,xnd,xo;
private double[,] d, di, xi;
private double[] dt, dx, r, x, xin;
private double schi,si,swgt;
private ulong idum = 0;
public ulong Dummy
{
set{idum = value;}
}
private double tgral, sd, chi2a;
private string result;
public double BestEstimation
{
get{return tgral;}
}
public double StandardDeviation
{
get{return sd;}
}
public double ChiSquare
{
get{return chi2a;}
}
public string Result
{
get{return result;}
}
public void vegas(double[] regn, int ndim,
Function.ToLastType fxn, int init, ulong ncall,
int itmx, int nprn)
{
Ran obj = new Ran(idum);
if (init <= 0)
{
mds = ndo = 1;
for (j = 0; j < ndim; j++) xi[j, 0] = 1.0;
}
if (init <= 1) si = swgt = schi = 0.0;
if (init <= 2)
{
nd = NDMX;
ng = 1;
if (mds != 0)
{
ng = (int)Math.Pow(ncall / 2.0 + 0.25, 1.0 / ndim);
mds = 1;
if ((2 * ng - NDMX) >= 0)
{
mds = -1;
npg = ng / NDMX + 1;
nd = ng / npg;
ng = npg * nd;
}
}
for (k = 1, i = 0; i < ndim; i++) k *= ng;
npg = Math.Max((int)ncall / k, 2);
calls = npg * k;
dxg = 1.0 / ng;
for (dv2g = 1, i = 0; i < ndim; i++) dv2g *= dxg;
dv2g = Math.Pow(calls * dv2g, 2.0) / npg / npg / (npg - 1.0);
xnd = nd;
dxg *= xnd;
xjac = 1.0 / calls;
for (j = 0; j < ndim; j++)
{
dx[j] = regn[j + ndim] - regn[j];
xjac *= dx[j];
}
if (nd != ndo)
{
for (i = 0; i < nd; i++) r[i] = 1.0;
for (j = 0; j < ndim; j++) rebin(ndo / xnd, nd, r, xin, xi, j);
ndo = nd;
}
if (nprn >= 0)
{
result += "Input parameters for vegas:" + "ndim=" + Convert.ToString(ndim) + " ncall=" + Convert.ToString(calls) + "\r\n";
result += " it=" + Convert.ToString(it) + " itmx=" + Convert.ToString(itmx) + "\r\n";
result += " nprn=" + Convert.ToString(nprn) + " ALPH=" + Convert.ToString(ALPH) + "\r\n";
result += " mds=" + Convert.ToString(mds) + " nd=" + Convert.ToString(nd) + "\r\n";
for (j = 0; j < ndim; j++)
{
result += " xl[" + Convert.ToString(j) + "]=" + Convert.ToString(regn[j]) +
" xu[" + Convert.ToString(j) + "]=" + Convert.ToString(regn[j + ndim]) + "\r\n";
}
}
}
for (it = 1; it <= itmx; it++)
{
ti = tsi = 0.0;
for (j = 0; j < ndim; j++)
{
kg[j] = 1;
for (i = 0; i < nd; i++) d[i, j] = di[i, j] = 0.0;
}
for (; ; )
{
fb = f2b = 0.0;
for (k = 1; k <= npg; k++)
{
wgt = xjac;
for (j = 0; j < ndim; j++)
{
xn = (kg[j] - obj.doub()) * dxg + 1.0;
ia[j] = Math.Max(Math.Min((int)(xn), NDMX), 1);
if (ia[j] > 1)
{
xo = xi[j, ia[j] - 1] - xi[j, ia[j] - 2];
rc = xi[j, ia[j] - 2] + (xn - ia[j]) * xo;
}
else
{
xo = xi[j, ia[j] - 1];
rc = (xn - ia[j]) * xo;
}
x[j] = regn[j] + rc * dx[j];
wgt *= xo * xnd;
}
f = wgt * fxn(x); // f=wgt*fxn(x,wgt)
f2 = f * f;
fb += f;
f2b += f2;
for (j = 0; j < ndim; j++)
{
di[ia[j] - 1, j] += f;
if (mds >= 0) d[ia[j] - 1, j] += f2;
}
}
f2b = Math.Sqrt(f2b * npg);
f2b = (f2b - fb) * (f2b + fb);
if (f2b <= 0.0) f2b = TINY;
ti += fb;
tsi += f2b;
if (mds < 0)
{
for (j = 0; j < ndim; j++) d[ia[j] - 1, j] += f2b;
}
for (k = ndim; k >= 1; k--)
{
kg[k - 1] %= ng;
if (++kg[k - 1] != 1) break;
}
if (k < 1) break;
}
tsi *= dv2g;
wgt = 1.0 / tsi;
si += wgt * ti;
schi += wgt * ti * ti;
swgt += wgt;
tgral = si / swgt;
chi2a = (schi - si * tgral) / (it - 0.9999);
if (chi2a < 0.0) chi2a = 0.0;
sd = Math.Sqrt(1.0 / swgt);
tsi = Math.Sqrt(tsi);
if (nprn >= 0)
{
result += " iteration no. " + Convert.ToString(it) + ": integral =" + Convert.ToString(ti) +
" +/- " + Convert.ToString(tsi) + "\r\n";
result += " all iterations: integral=" + Convert.ToString(tgral) + "+/-" + Convert.ToString(sd) +
" chi**2/IT n = " + Convert.ToString(chi2a) + "\r\n";
if (nprn != 0)
{
for (j = 0; j < ndim; j++)
{
result += " DATA FOR axis " + Convert.ToString(j + 1) + "\r\n";
result += " X " + " delta i " + " X " + " delta i " +
" X " + " delta i " + "\r\n";
for (i = nprn / 2; i < nd; i += nprn + 2)
{
result += " " + Convert.ToString(xi[j, i]) + " " + Convert.ToString(di[i, j]) +
" " + Convert.ToString(xi[j, i + 1]) + " " + Convert.ToString(di[i + 1, j]) +
" " + Convert.ToString(xi[j, i + 2]) + " " + Convert.ToString(di[i + 2, j]) + "\r\n";
}
}
}
}
for (j = 0; j < ndim; j++)
{
xo = d[0, j];
xn = d[1, j];
d[0, j] = (xo + xn) / 2.0;
dt[j] = d[0, j];
for (i = 1; i < nd - 1; i++)
{
rc = xo + xn;
xo = xn;
xn = d[i + 1, j];
d[i, j] = (rc + xn) / 3.0;
dt[j] += d[i, j];
}
d[nd - 1, j] = (xo + xn) / 2.0;
dt[j] += d[nd - 1, j];
}
for (j = 0; j < ndim; j++)
{
rc = 0.0;
for (i = 0; i < nd; i++)
{
if (d[i, j] < TINY) d[i, j] = TINY;
r[i] = Math.Pow((1.0 - d[i, j] / dt[j]) /
(Math.Log(dt[j]) - Math.Log(d[i, j])), ALPH);
rc += r[i];
}
rebin(rc / xnd, nd, r, xin, xi, j);
}
}
}
private void rebin(double rc, int nd, double[] r, double[] xin, double[,] xi, int j)
{
int i, k = -1;
double dr = 0.0, xn = 0.0, xo = 0.0;
for (i = 0; i < nd - 1; i++)
{
while (rc > dr) dr += r[++k];
if (k > 0) xo = xi[j, k - 1];
xn = xi[j, k];
dr -= rc;
xin[i] = xn - (xn - xo) * dr / r[k];
}
for (i = 0; i < nd - 1; i++) xi[j, i] = xin[i];
xi[j, nd - 1] = 1.0;
}
}
}