Honeycomb  0.1
Component-Model Framework
Vegas.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
5 
6 namespace honey
7 {
8 
10 
29 template<sdt Dim = 1, sdt DimRes = 1, class Real__ = Real, sdt BinCount = 100>
30 class Vegas
31 {
32 public:
33  typedef Real__ Real;
34 private:
35  typedef typename Numeral<Real>::Real_ Real_;
36  typedef typename Real_::DoubleType Double_;
37  typedef typename Double_::Real Double;
38  typedef Alge_<Real> Alge;
39  typedef Uniform_<Real> Uniform;
40 
41 public:
42  static const sdt dim = Dim;
43  static const sdt dimRes = DimRes;
45  typedef Vec<dim,Real> Vec;
46  typedef function<VecRes (const Vec&)> Func;
47 
49 
59  Vegas(const Func& func, RandomGen& gen, const Vec& lower, const Vec& upper, sdt sampleCount = 1000, Real warmUp = 0.1, sdt iterCount = 5, Real alpha = 1.5) :
60 
61  func(func), gen(gen), lower(lower), upper(upper), sampleCount(sampleCount), warmUp(Alge::max(warmUp,0)), iterCount(iterCount), alpha(alpha),
62  tgral(0), chi2a(0), sd(0), _progress(0), sampleTotal(0) {}
63 
64  ~Vegas() {}
65 
67 
71  const VecRes& integrate(Real progressDelta = 1);
72 
74  Real progress() const { return _progress; }
76  const VecRes& result() const { return tgral; }
78  const VecRes& chiSqr() const { return chi2a; }
80  const VecRes& stdDev() const { return sd; }
81 
82 private:
83  void init(sdt init, sdt sampleCount);
84  void rebin(Real rc, sdt nd, Real r[], Real xin[], Real xi[]);
85  void integrate_priv(sdt samplesMax);
86 
87  // Input
88  Func func;
89  RandomGen& gen;
90  Vec lower;
91  Vec upper;
92  sdt sampleCount;
93  Real warmUp;
94  sdt iterCount;
95  Real alpha;
96 
97  // Output
98  VecRes tgral;
99  VecRes chi2a;
100  VecRes sd;
101 
102  // Progress
103  Real _progress;
104  sdt sampleTotal;
105  sdt iterCur;
106  sdt npgCur;
107 
108  // Init 0 and 1
109  sdt ndo;
110  sdt ittot; // iter count across init > 1
111  sdt mds; // sampling mode
112 
113  // Init 2
114  sdt nd; // slices in grid (c.f. BinCount)
115  sdt ng;
116  sdt npg; // number of calls within bin
117  Real calls; // real total number of calls to fxn
118  Real dv2g;
119  Real dxg;
120  Real xnd;
121  Real xJac; // Jacobian of integration
122  Real dx[dim]; // width of integration region
123 
124  // Integrate locals
125  // accumulator for stuff at end of iteration...
126  struct iterAccu
127  {
128  Real Wgt; // weight
129  Real sWgt; // cumulative sum for weights
130  Real sChi; // cumulative sum for chi^2
131  Real sInt; // cumulative sum for integral
132  };
133  iterAccu Ai[dimRes]; // ...one for each integrand
134 
135  Real d[BinCount][dim];
136  Real di[BinCount][dim]; // delta i
137  Real r[BinCount];
138  Real xi[dim][BinCount];
139  Real xin[BinCount]; // aux. variable for rebinning
140 
141  sdt ia[dim];
142  sdt kg[dim];
143 
144  // accumulator over bins / hypercubes...
145  struct binAccu
146  {
147  Real ti; // sum for f over bins
148  Real tsi; // sum for variances over bins
149  };
150  binAccu Ab[dimRes]; // ...one for each integrand
151 
152  // accumulator over points x within bins...
153  struct pointAccu
154  {
155  Real f2; // f squared
156  Real fb; // sum for f within bi
157  Real f2b; // sum for f2 within bin
158  sdt npg; // number of calls within bin f != 0
159  };
160  pointAccu Ax[dimRes]; // ...one for each integrand
161 };
162 
163 template<sdt Dim, sdt DimRes, class Real, sdt BinCount>
164 const typename Vegas<Dim,DimRes,Real,BinCount>::VecRes&
166 {
167  sdt sampleWarmUp = warmUp*sampleCount;
168  if (_progress == 0)
169  {
170  //First run, init with warm up or main
171  if (sampleWarmUp > 0)
172  init(0, sampleWarmUp);
173  else
174  init(0, sampleCount);
175  }
176 
177  _progress = Alge::min(_progress + progressDelta, 1);
178  sdt sampleAcc = _progress*(sampleWarmUp+sampleCount) - sampleTotal;
179  sampleTotal += sampleAcc;
180 
181  if (sampleTotal - sampleAcc < sampleWarmUp)
182  {
183  //Warm up grid
184  integrate_priv(sampleTotal < sampleWarmUp ? sampleAcc : -1);
185  if (sampleTotal < sampleWarmUp)
186  return result();
187  //Done warm up, discard results and init main
188  sampleAcc = sampleTotal - sampleWarmUp;
189  init(1, sampleCount);
190  }
191 
192  //Piecewise sample count is not accurate, so -1 means run until completion
193  integrate_priv(_progress < 1 ? sampleAcc : -1);
194 
195  if (iterCur == iterCount)
196  //Calculation is complete
197  _progress = 1;
198 
199  return result();
200 }
201 
202 template<sdt Dim, sdt DimRes, class Real, sdt BinCount>
203 void Vegas<Dim,DimRes,Real,BinCount>::init(sdt init, sdt sampleCount)
204 {
205  iterCur = 0;
206  npgCur = -2;
207 
208  if (init <= 0) //entry for cold start
209  {
210  mds = 1; //1 == use stratified sampling
211  ndo = 1;
212  for (sdt j=0; j<dim; ++j) xi[j][0] = 1;
213  }
214 
215  if (init <= 1) //inherit the previous grid
216  {
217  for (sdt j=0; j<dimRes; ++j)
218  {
219  Ai[j].sInt = 0;
220  Ai[j].sWgt = 0;
221  Ai[j].sChi = 0;
222  }
223  ittot = 1;
224  }
225 
226  if (init <= 2) //inherit grid and results
227  {
228  nd = BinCount;
229  ng = 1;
230  if (mds)
231  {
232  ng = Alge::pow(Real(sampleCount)/2+0.25,1/Real(dim));
233  mds = 1;
234  if ((2*ng-BinCount) >= 0)
235  {
236  mds = -1;
237  npg = ng/BinCount+1;
238  nd = ng/npg;
239  ng = npg*nd;
240  }
241  }
242  if (ng <= 0)
243  {
244  //No samples
245  iterCur = iterCount;
246  return;
247  }
248  sdt k = 1;
249  for (sdt i=0; i<dim; ++i) k *= ng;
250  npg = sampleCount/k > 2 ? sampleCount/k : 2;
251  calls = npg * k;
252  dxg = 1/Real(ng);
253  dv2g = 1;
254  for (sdt i=0; i<dim; ++i) dv2g *= dxg;
255  dv2g = calls*calls*dv2g*dv2g/npg/npg/(npg-1.0);
256  xnd = nd;
257  dxg *= xnd;
258  xJac = 1/Real(calls);
259  for (sdt j=0; j<dim; ++j)
260  {
261  dx[j] = upper[j]-lower[j];
262  xJac *= dx[j];
263  }
264  if (nd != ndo)
265  {
266  for (sdt i=0; i<(nd>ndo?nd:ndo); ++i) r[i] = 1;
267  for (sdt j=0; j<dim; ++j) rebin(ndo/xnd,nd,r,xin,xi[j]);
268  ndo = nd;
269  }
270  }
271 }
272 
273 template<sdt Dim, sdt DimRes, class Real, sdt BinCount>
274 void Vegas<Dim,DimRes,Real,BinCount>::integrate_priv(sdt samplesMax)
275 {
276  sdt samples = 0;
277  samplesMax *= iterCount;
278 
279  for (; iterCur < iterCount; ++iterCur, ++ittot)
280  {
281  if (npgCur == -2)
282  {
283  //Init loop
284  npgCur = -1;
285  for (sdt j=0; j<dimRes; ++j) Ab[j].ti = Ab[j].tsi = 0;
286  for (sdt j=0; j<dim; ++j)
287  {
288  kg[j] = 1;
289  for (sdt i=0; i<nd; ++i) d[i][j] = di[i][j] = 0;
290  }
291  }
292  for (;;)
293  {
294  if (npgCur == -1)
295  {
296  //Init loop
297  npgCur = 0;
298  for (sdt j=0; j<dimRes; ++j)
299  {
300  Ax[j].fb = 0;
301  Ax[j].f2b = 0;
302  Ax[j].npg = 0;
303  }
304  }
305  for (sdt k=npgCur; k<npg; ++k, ++samples)
306  {
307  if (samplesMax >= 0 && samples >= samplesMax)
308  {
309  npgCur = k;
310  return;
311  }
312 
313  Real wgt = xJac;
314  Vec x;
315  for (sdt j=0; j<dim; ++j)
316  {
317  Real xrand = Uniform::nextStd(gen);
318  Real xn = (kg[j]-xrand)*dxg+1;
319  ia[j] = (xn<BinCount) ? xn : BinCount;
320  ia[j] = (ia[j]>1) ? ia[j] : 1;
321  Real xo, rc;
322  if (ia[j] > 1)
323  {
324  xo = xi[j][ia[j]-1]-xi[j][ia[j]-2];
325  rc = xi[j][ia[j]-2]+(xn-ia[j])*xo;
326  }
327  else
328  {
329  xo = xi[j][ia[j]-1];
330  rc = (xn-ia[j])*xo;
331  }
332  x[j] = lower[j]+rc*dx[j];
333  wgt *= xo*xnd;
334  }
335  VecRes f = func(const_cast<const Vec&>(x)); // call integrand at point x
336  for (sdt j=0; j<dimRes; ++j)
337  {
338  if (f[j] != 0) ++Ax[j].npg;
339  f[j] *= wgt;
340  Ax[j].f2 = f[j]*f[j];
341  Ax[j].fb += f[j];
342  Ax[j].f2b += Ax[j].f2;
343  }
344  for (sdt j=0; j<dim; ++j)
345  {
346  di[ia[j]-1][j] += f[0];
347  if (mds >= 0) d[ia[j]-1][j] += Ax[0].f2;
348  }
349  } // end of loop within hypercube
350  npgCur = -1;
351 
352  for (sdt j=0; j<dimRes; ++j)
353  {
354  Ax[j].f2b = Alge::sqrt(Ax[j].f2b*Ax[j].npg);
355  Ax[j].f2b = (Ax[j].f2b-Ax[j].fb)*(Ax[j].f2b+Ax[j].fb);
356  if (Ax[j].f2b <= 0) Ax[j].f2b = Real_::smallest;
357  Ab[j].ti += Ax[j].fb;
358  Ab[j].tsi += Ax[j].f2b;
359  }
360  if (mds < 0)
361  {
362  for (sdt j=0; j<dim; ++j) d[ia[j]-1][j] += Ax[0].f2b;
363  }
364  sdt k;
365  for (k=dim-1; k>=0; --k)
366  {
367  kg[k] %= ng;
368  if (++kg[k] != 1) break;
369  }
370  if (k < 0) break;
371  } // end of loop over hypercubes
372  npgCur = -2;
373 
374  for (sdt j=0; j<dimRes; ++j)
375  {
376  Ab[j].tsi *= dv2g;
377  Ai[j].Wgt = 1/Ab[j].tsi;
378  Ai[j].sInt += Ai[j].Wgt*Ab[j].ti;
379  Ai[j].sChi += Ai[j].Wgt*Ab[j].ti*Ab[j].ti;
380  Ai[j].sWgt += Ai[j].Wgt;
381  tgral[j] = Ai[j].sInt/Ai[j].sWgt;
382  chi2a[j] = (Ai[j].sChi-Ai[j].sInt*tgral[j])/(ittot-0.9999);
383  if (chi2a[j] < 0) chi2a[j] = 0;
384  sd[j] = Alge::sqrt(1/Ai[j].sWgt);
385  Ab[j].tsi = Alge::sqrt(Ab[j].tsi);
386  }
387 
388  Real dt[dim];
389  for (sdt j=0; j<dim; ++j)
390  {
391  Real xo = d[0][j];
392  Real xn = d[1][j];
393  d[0][j] = (xo+xn)/2;
394  dt[j] = d[0][j];
395  for (sdt i=1; i<nd-1; ++i)
396  {
397  Real rc = xo+xn;
398  xo = xn;
399  xn = d[i+1][j];
400  d[i][j] = (rc+xn)/3;
401  dt[j] += d[i][j];
402  }
403  d[nd-1][j] = (xo+xn)/2;
404  dt[j] += d[nd-1][j];
405  }
406  for (sdt j=0; j<dim; ++j)
407  {
408  Real rc = 0;
409  for (sdt i=0; i<nd; ++i)
410  {
411  if (d[i][j] < Real_::smallest) d[i][j] = Real_::smallest;
412  r[i] = Alge::pow((1.0-d[i][j]/dt[j])/
413  (Alge::log(dt[j])-Alge::log(d[i][j])),alpha);
414  rc += r[i];
415  }
416  rebin(rc/xnd,nd,r,xin,xi[j]);
417  }
418  }
419 }
420 
421 template<sdt Dim, sdt DimRes, class Real, sdt BinCount>
422 void Vegas<Dim, DimRes, Real, BinCount>::rebin(Real rc, sdt nd, Real r[], Real xin[], Real xi[])
423 {
424  sdt i;
425  sdt k = 0;
426  Real dr = 0;
427  Real xn = 0;
428  Real xo = 0;
429 
430  for (i=0; i<nd-1; i++)
431  {
432  while (rc > dr)
433  dr += r[k++];
434  if (k > 1) xo = xi[k-2];
435  xn = xi[k-1];
436  dr -= rc;
437  xin[i] = xn-(xn-xo)*dr/r[k-1];
438  }
439  for (i=0; i<nd-1; i++) xi[i] = xin[i];
440  xi[nd-1] = 1;
441 }
442 
443 }
444 
function< VecRes(const Vec &)> Func
Definition: Vegas.h:46
static Real pow(Real x, Real y)
x raised to exponent y
Definition: Alge.h:73
Algebra.
Definition: Alge.h:13
Random number generator interface.
Definition: Gen.h:11
static Real nextStd(RandomGen &gen)
Static function for standard distribution. Generate random real variate between 0 and 1 non-inclusive...
Definition: Uniform.h:29
~Vegas()
Definition: Vegas.h:64
ptrdiff_t sdt
Size difference type, shorthand for ptrdiff_t.
Definition: Core.h:92
Vec< dimRes, Real > VecRes
Definition: Vegas.h:44
static Real sqrt(Real x)
Square Root.
Definition: Alge.h:63
static std::common_type< Num, Num2 >::type min(Num a, Num2 b)
Get the minimum of two numbers.
Definition: Alge.h:89
Vegas(const Func &func, RandomGen &gen, const Vec &lower, const Vec &upper, sdt sampleCount=1000, Real warmUp=0.1, sdt iterCount=5, Real alpha=1.5)
Constructor, set up constants for all integration calls.
Definition: Vegas.h:59
const VecRes & stdDev() const
Estimate of standard deviation of integral result. Indicative of +- error range in result...
Definition: Vegas.h:80
Real progress() const
Current progress of calculation, from 0 (start) to 1 (complete).
Definition: Vegas.h:74
float Real
Real number type. See Real_ for real number operations and constants.
Definition: Real.h:21
Numeric type information, use numeral() to get instance safely from a static context.
Definition: Numeral.h:17
double Real
Definition: Real.h:14
Real__ Real
Definition: Vegas.h:33
const VecRes & result() const
Get current result of integration (same value returned by Integrate)
Definition: Vegas.h:76
const VecRes & integrate(Real progressDelta=1)
Perform integral calculation. The calculation can be split up over multiple calls.
Definition: Vegas.h:165
const VecRes & chiSqr() const
Get chi-square statistic for integral. A value that differs significantly from 1 (eg. diff > 0.5) indicates an unreliable result and more samples or iterations are required.
Definition: Vegas.h:78
static const sdt dimRes
Definition: Vegas.h:43
Vec< dim, Real > Vec
Definition: Vegas.h:45
static const sdt dim
Definition: Vegas.h:42
Generate a random variate between min and max non-inclusive with uniform (flat) distribution.
Definition: Dist.h:11
Monte Carlo (random-based) method to approximate the integral of a function over any number of dimens...
Definition: Vegas.h:30
Global Honeycomb namespace.
static Real log(Real x)
Natural logarithm. ie. ln(x)
Definition: Alge.h:80