Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:38:17

0001 // -*- C++ -*-
0002 //
0003 // ACDCGen.icc is a part of ThePEG - Toolkit for HEP Event Generation
0004 // Copyright (C) 1999-2019 Leif Lonnblad
0005 //
0006 // ThePEG is licenced under version 3 of the GPL, see COPYING for details.
0007 // Please respect the MCnet academic guidelines, see GUIDELINES for details.
0008 //
0009 
0010 namespace ACDCGenerator {
0011 
0012 template <typename Rnd, typename FncPtr>
0013 inline ACDCGen<Rnd,FncPtr>::ACDCGen(Rnd * r)
0014   : theRnd(r), theNAcc(0), theN(0), theNI(1, 0),
0015     theSumW(1, 0.0), theSumW2(1, 0.0),
0016     theEps(100*std::numeric_limits<double>::epsilon()), theMargin(1.1),
0017     theNTry(100), theMaxTry(10000), useCheapRandom(false), theFunctions(1),
0018     theDimensions(1, 0), thePrimaryCells(1), theSumMaxInts(1, 0.0), theLast(0),
0019     theLastCell(0), theLastF(0.0) {
0020   maxsize = 0;
0021 }
0022 
0023 template <typename Rnd, typename FncPtr>
0024 inline ACDCGen<Rnd,FncPtr>::ACDCGen()
0025   : theRnd(0), theNAcc(0), theN(0), theNI(1, 0),
0026     theSumW(1, 0.0), theSumW2(1, 0.0),
0027     theEps(100*std::numeric_limits<double>::epsilon()), theMargin(1.1),
0028     theNTry(100), theMaxTry(10000), useCheapRandom(false), theFunctions(1),
0029     theDimensions(1, 0), thePrimaryCells(1), theSumMaxInts(1, 0.0), theLast(0),
0030     theLastCell(0), theLastF(0.0) {
0031   maxsize = 0;
0032 }
0033 
0034 template <typename Rnd, typename FncPtr>
0035 inline ACDCGen<Rnd,FncPtr>::~ACDCGen() {
0036   clear();
0037 }
0038 
0039 template <typename Rnd, typename FncPtr>
0040 inline void ACDCGen<Rnd,FncPtr>::setRnd(Rnd * r) {
0041   theRnd = r;
0042 }
0043 
0044 template <typename Rnd, typename FncPtr>
0045 inline void ACDCGen<Rnd,FncPtr>::clear() {
0046   theNAcc = 0;
0047   theN = 0;
0048   theNI = vector<long>(1, 0);
0049   theSumW = DVector(1, 0.0);
0050   theSumW2 = DVector(1, 0.0);
0051   theFunctions = FncVector(1);
0052   theDimensions = DimVector(1, 0);
0053   for ( int i = 0, N = thePrimaryCells.size(); i < N; ++i )
0054     delete thePrimaryCells[i];
0055   thePrimaryCells = CellVector(1);
0056   theSumMaxInts = DVector(1, 0.0);
0057   theLast = 0;
0058   theLastCell = 0;
0059   theLastPoint.clear();
0060   theLastF = 0.0;
0061   levels.clear();
0062 }
0063 
0064 template <typename Rnd, typename FncPtr>
0065 inline bool ACDCGen<Rnd,FncPtr>::
0066 addFunction(DimType dim, FncPtrType fnc, double maxrat) {
0067   if ( maxrat < 0.0 ) maxrat = 1.0/nTry();
0068   typedef multimap<double,DVector> PointMap;
0069   theLast = theFunctions.size();
0070   theFunctions.push_back(fnc);
0071   theNI.push_back(0);
0072   theSumW.push_back(0.0);
0073   theSumW2.push_back(0.0);
0074   theDimensions.push_back(dim);
0075 
0076   // Generate nTry() points with non-zero function value
0077   DVector x(dim);
0078   PointMap pmap;
0079   long itry = 0;
0080   while ( pmap.size() < nTry() ) {
0081     if ( ++itry > maxTry() ) {
0082       thePrimaryCells.push_back(new ACDCGenCell(0.0));
0083       theSumMaxInts.push_back(theSumMaxInts.back() + cells().back()->doMaxInt());
0084       return false;
0085     }
0086     rnd(dim, x);
0087     double val = FncTraits::value(fnc, x);
0088     if ( val > 0.0 ) {
0089       pmap.insert(make_pair(val, x));
0090       itry = 0;
0091     }
0092   }
0093 
0094   // Create the root cell and set its overestimated function value to
0095   // the smallest non-zero value found
0096   double minf = pmap.begin()->first;
0097   double maxf = (--pmap.end())->first;
0098   minf = max(minf, maxrat*maxf);
0099   //  thePrimaryCells.push_back(new ACDCGenCell(pmap.begin()->first));
0100   thePrimaryCells.push_back(new ACDCGenCell(minf));
0101   theLastF = pmap.begin()->first;
0102   pmap.erase(pmap.begin());
0103   theSumMaxInts.push_back(theSumMaxInts.back() + cells().back()->doMaxInt());
0104 
0105   // Start the divide-and-conquer procedure using the point with the
0106   // highest function value found.
0107   theLastF = (--pmap.end())->first;
0108   theLastPoint =  (--pmap.end())->second;
0109   pmap.erase(--pmap.end());
0110   DVector up(dim, 1.0);
0111   DVector lo(dim, 0.0);
0112   theLastCell = cells().back()->getCell(lo, lastPoint(), up);
0113   if ( lastF() > lastCell()->g() ) {
0114     compensate(lo, up);
0115     levels.clear();
0116   }
0117 
0118   // For each other generated point check that it's below the
0119   // overestimated value of the corresponding cell. If not start the
0120   // divide-and-conquer using that point.
0121   while ( !pmap.empty() ) {
0122     theLastPoint = pmap.begin()->second;
0123     theLastF = pmap.begin()->first;
0124     pmap.erase(pmap.begin());
0125     DVector up(dim, 1.0);
0126     DVector lo(dim, 0.0);
0127     theLastCell = cells().back()->getCell(lo, lastPoint(), up);
0128     if ( lastF() > lastCell()->g() ) {
0129       compensate(lo, up);
0130       levels.clear();
0131     }
0132   }
0133   //  cells().back()->smooth(1.0/nTry());
0134   return true;
0135 }
0136 
0137 template <typename Rnd, typename FncPtr>
0138 inline void ACDCGen<Rnd,FncPtr>::chooseCell(DVector & lo, DVector & up) {
0139   if ( compensating() ) {
0140     // If we are compensating, we must choose the cell to be compensated.
0141     up = levels.back().up;
0142     lo = levels.back().lo;
0143     theLastCell = levels.back().cell;
0144     theLast = levels.back().index;
0145   } else {
0146     // Otherwise, first choose the function to be used and choose the
0147     // corresponding root cell.
0148     theLast = upper_bound(sumMaxInts().begin(), sumMaxInts().end(),
0149               rnd()*sumMaxInts().back())
0150       - sumMaxInts().begin();
0151     if(theLast>=sumMaxInts().size()) {
0152       throw ThePEG::Exception() << "Selected a function outside the allowed range"
0153                 << " in ACDCGen::chooseCell(). This is usually due"
0154                 << " to a floating point error (nan or inf) in the"
0155                 << " calculation of the weight"
0156                 << ThePEG::Exception::abortnow;
0157     }
0158     up = DVector(lastDimension(), 1.0);
0159     lo = DVector(lastDimension(), 0.0);
0160     theLastCell = lastPrimary();
0161   }
0162 
0163   // Now select randomly a sub-cell of the chosen cell
0164   if ( cheapRandom() ) {
0165     theLastCell = lastCell()->generate(lo, up, theRnd);
0166   } else {
0167     DVector rndv(lastDimension());
0168     rnd(lastDimension(), rndv);
0169     theLastCell = lastCell()->generate(lo, up, rndv);
0170   }
0171 }
0172 
0173 template <typename Rnd, typename FncPtr>
0174 inline typename ACDCGen<Rnd,FncPtr>::FncPtrType
0175 ACDCGen<Rnd,FncPtr>::generate() {
0176   long itry = 0;
0177   while ( true ) {
0178     if ( ++itry > maxTry() ) return FncPtrType();
0179     ++theN;
0180 
0181     // First choose a function and a cell to generate in.
0182     DVector up;
0183     DVector lo;
0184     chooseCell(lo, up);
0185 
0186     // Now choose a point in that cell according to a flat distribution.
0187     DimType D = lastDimension();
0188     theLastPoint.resize(D);
0189     for ( DimType d = 0; d < D; ++d ) theLastPoint[d] = rnd(lo[d], up[d]);
0190 
0191     // Calculate the function value in this point
0192     theLastF = FncTraits::value(lastFunction(), theLastPoint);
0193     if ( theLastF <= 0.0 ) continue;
0194 
0195     // If we are compensating we require the function value to be
0196     // above the previous overestimate of the function.
0197     if ( compensating() && lastF() < levels.back().g ) theLastF = 0.0;
0198 
0199     double w = lastF()/lastCell()->g();
0200     if ( w > 1.0 ) {
0201       // If the value was above the overestimate then we must start
0202       // the compensation procedure and the curren point is disregarded.
0203       --theN;
0204       compensate(lo, up);
0205       continue;
0206     }
0207 
0208     // Accept the point according to the ratio of the true and
0209     // overestimated function value.
0210     theSumW[last()] += w;
0211     theSumW2[last()] += w*w;
0212     ++theNI[last()];
0213     if ( w > rnd() ) {
0214       ++theNAcc;
0215       return lastFunction();
0216     }
0217   }
0218 }
0219 
0220 template <typename Rnd, typename FncPtr>
0221 inline void ACDCGen<Rnd,FncPtr>::reject() {
0222   theSumW[last()] -= 1.0;
0223   theSumW2[last()] -= 1.0;
0224   --theNAcc;
0225 }
0226 
0227 template <typename Rnd, typename FncPtr>
0228 inline bool ACDCGen<Rnd,FncPtr>::compensating() {
0229   while ( levels.size() && levels.back().lastN < N() ) levels.pop_back();
0230   // Leave all levels which has reached there 'expiry date'.
0231 
0232   return !levels.empty();
0233 }
0234 
0235 template <typename Rnd, typename FncPtr>
0236 inline long ACDCGen<Rnd,FncPtr>::compleft() const {
0237   if ( levels.empty() ) return 0;
0238   long left = 1;
0239   for ( int i = 0, Ni = levels.size(); i < Ni; ++i )
0240     left = max(left, levels[i].lastN - N());
0241 
0242   return left;
0243 }
0244 
0245 template <typename Rnd, typename FncPtr>
0246 inline void ACDCGen<Rnd,FncPtr>::
0247 compensate(const DVector & lo, const DVector & up) {
0248   //Save the previous overestimated integral and create a new
0249   //compensation level.
0250   double i0 = maxInt();
0251   Level level;
0252   level.g = lastCell()->g();
0253 
0254   // Start the divide-and-conquer algorithm slicing up the selected
0255   // cell and specify it as the cell to compensate.
0256   Slicer slicer(lastDimension(), *this, lo, up);
0257   level.cell = slicer.first;
0258   level.index = last();
0259   level.up = slicer.firstup;
0260   level.lo = slicer.firstlo;
0261 
0262   // Now calculate the the new overestimated total integral and
0263   // calculate the number of attempted points needed to compensate.
0264   double rat = (doMaxInt())/i0;
0265   level.lastN = long(N()*rat);
0266 
0267   // If we are already compensating increase also the previous
0268   // compensation levels.
0269   for ( size_type i = 0; i < levels.size(); ++i )
0270     levels[i].lastN = long(levels[i].lastN*rat);
0271   levels.insert(levels.end(), level);
0272   maxsize = std::max(maxsize, levels.size());
0273 }
0274 
0275 template <typename Rnd, typename FncPtr>
0276 inline void ACDCGen<Rnd,FncPtr>::eps(double newEps) {
0277   theEps = newEps;
0278 }
0279 
0280 template <typename Rnd, typename FncPtr>
0281 inline void ACDCGen<Rnd,FncPtr>::margin(double newMargin) {
0282   theMargin = newMargin;
0283 }
0284 
0285 template <typename Rnd, typename FncPtr>
0286 inline long ACDCGen<Rnd,FncPtr>::N() const {
0287   return theN;
0288 }
0289 
0290 template <typename Rnd, typename FncPtr>
0291 inline long ACDCGen<Rnd,FncPtr>::n() const {
0292   return theNAcc;
0293 }
0294 
0295 template <typename Rnd, typename FncPtr>
0296 inline typename ACDCGen<Rnd,FncPtr>::size_type
0297 ACDCGen<Rnd,FncPtr>::nTry() const {
0298   return theNTry;
0299 }
0300 
0301 template <typename Rnd, typename FncPtr>
0302 inline void ACDCGen<Rnd,FncPtr>::nTry(size_type newNTry) {
0303   theNTry = newNTry;
0304 }
0305 
0306 template <typename Rnd, typename FncPtr>
0307 inline long ACDCGen<Rnd,FncPtr>::maxTry() const {
0308   return theMaxTry;
0309 }
0310 
0311 template <typename Rnd, typename FncPtr>
0312 inline void ACDCGen<Rnd,FncPtr>::maxTry(long newMaxTry) {
0313   theMaxTry = newMaxTry;
0314 }
0315 
0316 template <typename Rnd, typename FncPtr>
0317 inline bool ACDCGen<Rnd,FncPtr>::cheapRandom() const {
0318   return useCheapRandom;
0319 }
0320 
0321 template <typename Rnd, typename FncPtr>
0322 inline void ACDCGen<Rnd,FncPtr>::cheapRandom(bool b) {
0323   useCheapRandom = b;
0324 }
0325 
0326 template <typename Rnd, typename FncPtr>
0327 inline double ACDCGen<Rnd,FncPtr>::maxInt() const {
0328   return theSumMaxInts.back();
0329 }
0330 
0331 template <typename Rnd, typename FncPtr>
0332 inline double ACDCGen<Rnd,FncPtr>::doMaxInt() {
0333   for ( size_type i = 1, imax = functions().size(); i < imax; ++i )
0334     theSumMaxInts[i] = sumMaxInts()[i - 1] + cells()[i]->doMaxInt();
0335   return maxInt();
0336 }
0337 
0338 template <typename Rnd, typename FncPtr>
0339 inline int ACDCGen<Rnd,FncPtr>::nBins() const {
0340   int sum = 0;
0341   for ( size_type i = 1; i < functions().size(); ++i )
0342     sum += cell(i)->nBins();
0343   return sum;
0344 }
0345 
0346 template <typename Rnd, typename FncPtr>
0347 inline int ACDCGen<Rnd,FncPtr>::depth() const {
0348   int mx = 0;
0349   for ( size_type i = 1; i < functions().size(); ++i )
0350     mx = max(mx, cell(i)->depth());
0351   return mx;
0352 }
0353 
0354 template <typename Rnd, typename FncPtr>
0355 inline double ACDCGen<Rnd,FncPtr>::efficiency() const {
0356   return N() > 0? double(n())/double(N()): 0.0;
0357 }
0358 
0359 template <typename Rnd, typename FncPtr>
0360 inline double ACDCGen<Rnd,FncPtr>::integral(FncPtrType f) const {
0361   if ( N() <= 0 ) return maxInt();
0362   double sumw = 0.0;
0363   for ( size_type i = 1; i < functions().size(); ++i )
0364     if ( functions()[i] == f || !f ) sumw += theSumW[i];
0365   return maxInt()*sumw/N();
0366 }
0367 
0368 template <typename Rnd, typename FncPtr>
0369 inline double ACDCGen<Rnd,FncPtr>::integralErr(FncPtrType f) const {
0370   if ( N() <= 0 ) return maxInt();
0371   double sumw2 = 0.0;
0372   double sumw = 0.0;
0373   for ( size_type i = 1; i < functions().size(); ++i )
0374     if ( functions()[i] == f || !f ) {
0375       sumw2 += theSumW2[i];
0376       sumw += theSumW[i];
0377     }
0378   if ( f ) return maxInt()*sqrt(sumw2)/N();
0379   return maxInt()*sqrt(max(0.,sumw2 - sumw*sumw/N()))/N();
0380 }
0381 
0382 template <typename Rnd, typename FncPtr>
0383 inline double ACDCGen<Rnd,FncPtr>::eps() const {
0384   return theEps;
0385 }
0386 
0387 template <typename Rnd, typename FncPtr>
0388 inline double ACDCGen<Rnd,FncPtr>::margin() const {
0389   return theMargin;
0390 }
0391 
0392 template <typename Rnd, typename FncPtr>
0393 inline double ACDCGen<Rnd,FncPtr>::rnd() const {
0394   return RndTraits::rnd(theRnd);
0395 }
0396 
0397 template <typename Rnd, typename FncPtr>
0398 inline double ACDCGen<Rnd,FncPtr>::rnd(double lo, double up) const {
0399   return RndTraits::rnd(theRnd, lo, up);
0400 }
0401 
0402 template <typename Rnd, typename FncPtr>
0403 inline void ACDCGen<Rnd,FncPtr>::
0404 rnd(const DVector & lo, const DVector & up, DVector & r) const {
0405   RndTraits::rnd(theRnd, lo.begin(), lo.end(), up.begin(), r.begin());
0406 }
0407 
0408 template <typename Rnd, typename FncPtr>
0409 inline void ACDCGen<Rnd,FncPtr>::
0410 rnd(DimType D, DVector & r) const {
0411   RndTraits::rnd(theRnd, D, r.begin());
0412 }
0413 
0414 template <typename Rnd, typename FncPtr>
0415 inline long ACDCGen<Rnd,FncPtr>::rndInt(long x) const {
0416   return RndTraits::rndInt(theRnd, x);
0417 }
0418 
0419 template <typename Rnd, typename FncPtr>
0420 inline const typename ACDCGen<Rnd,FncPtr>::FncVector &
0421 ACDCGen<Rnd,FncPtr>::functions() const {
0422   return theFunctions;
0423 }
0424 
0425 template <typename Rnd, typename FncPtr>
0426 inline typename ACDCGen<Rnd,FncPtr>::FncPtrType
0427 ACDCGen<Rnd,FncPtr>::function(size_type i) const {
0428   return functions()[i];
0429 }
0430 
0431 template <typename Rnd, typename FncPtr>
0432 inline typename ACDCGen<Rnd,FncPtr>::FncPtrType
0433 ACDCGen<Rnd,FncPtr>::lastFunction() const {
0434   return function(last());
0435 }
0436 
0437 template <typename Rnd, typename FncPtr>
0438 inline const typename ACDCGen<Rnd,FncPtr>::DimVector &
0439 ACDCGen<Rnd,FncPtr>::dimensions() const {
0440   return theDimensions;
0441 }
0442 
0443 template <typename Rnd, typename FncPtr>
0444 inline DimType ACDCGen<Rnd,FncPtr>::dimension(size_type i) const {
0445   return dimensions()[i];
0446 }
0447 
0448 template <typename Rnd, typename FncPtr>
0449 inline DimType ACDCGen<Rnd,FncPtr>::lastDimension() const {
0450   return dimension(last());
0451 }
0452 
0453 template <typename Rnd, typename FncPtr>
0454 inline const typename ACDCGen<Rnd,FncPtr>::CellVector &
0455 ACDCGen<Rnd,FncPtr>::cells() const {
0456   return thePrimaryCells;
0457 }
0458 
0459 template <typename Rnd, typename FncPtr>
0460 inline ACDCGenCell * ACDCGen<Rnd,FncPtr>::cell(size_type i) const {
0461   return cells()[i];
0462 }
0463 
0464 template <typename Rnd, typename FncPtr>
0465 inline ACDCGenCell * ACDCGen<Rnd,FncPtr>::lastPrimary() const {
0466   return cell(last());
0467 }
0468 
0469 template <typename Rnd, typename FncPtr>
0470 inline const DVector & ACDCGen<Rnd,FncPtr>::sumMaxInts() const {
0471   return theSumMaxInts;
0472 }
0473 
0474 template <typename Rnd, typename FncPtr>
0475 inline typename ACDCGen<Rnd,FncPtr>::size_type
0476 ACDCGen<Rnd,FncPtr>::last() const {
0477   return theLast;
0478 }
0479 
0480 template <typename Rnd, typename FncPtr>
0481 inline typename ACDCGen<Rnd,FncPtr>::size_type
0482 ACDCGen<Rnd,FncPtr>::size() const {
0483   return cells().size() - 1;
0484 }
0485 
0486 template <typename Rnd, typename FncPtr>
0487 inline ACDCGenCell * ACDCGen<Rnd,FncPtr>::lastCell() const {
0488   return theLastCell;
0489 }
0490 
0491 template <typename Rnd, typename FncPtr>
0492 inline const DVector & ACDCGen<Rnd,FncPtr>::lastPoint() const {
0493   return theLastPoint;
0494 }
0495 
0496 template <typename Rnd, typename FncPtr>
0497 inline double ACDCGen<Rnd,FncPtr>::lastF() const {
0498   return theLastF;
0499 }
0500 
0501 template <typename Rnd, typename FncPtr>
0502 typename ACDCGen<Rnd,FncPtr>::size_type ACDCGen<Rnd,FncPtr>::maxsize = 0;
0503 
0504 template <typename Rnd, typename FncPtr>
0505 vector<ACDCGenCellInfo> ACDCGen<Rnd,FncPtr>::extractCellInfo() const {
0506   vector<ACDCGenCellInfo> ret;
0507   for ( size_type i = 1; i < cells().size(); ++i ) {
0508     DVector lo(dimension(i), 0.0);
0509     DVector up(dimension(i), 1.0);
0510     cell(i)->extract(lo, up, ret);
0511   }
0512   return ret;
0513 }
0514 
0515 template <typename Rnd, typename FncPtr>
0516 ACDCGen<Rnd,FncPtr>::Slicer::
0517 Slicer(DimType Din, ACDCGen & gen, const DVector & loin, const DVector & upin)
0518   : D(Din), lo(loin), up(upin), xcl(loin), xcu(upin), xhl(loin), xhu(upin),
0519     fhl(Din, 0.0), fhu(Din, 0.0), xsel(gen.lastPoint()), fsel(gen.lastF()),
0520     current(gen.lastCell()), first(gen.lastCell()),
0521     firstlo(loin), firstup(upin),f(gen.lastFunction()),
0522     epsilon(gen.eps()), margin(gen.margin()), minf(0.0), wholecomp(false) {
0523   divideandconquer();
0524 }
0525 
0526 template <typename Rnd, typename FncPtr>
0527 ACDCGen<Rnd,FncPtr>::Slicer::~Slicer() {
0528   // Added for debugging purposes.
0529 }
0530 
0531 template <typename Rnd, typename FncPtr>
0532 void ACDCGen<Rnd,FncPtr>::Slicer::divideandconquer() {
0533   // If the current function value was just a little above the
0534   // overestimate, just increase the overestimate of this cell and
0535   // we're done.
0536   if ( fsel < current->g()*margin ) {
0537     current->g(current->g()*margin);
0538     return;
0539   }
0540 
0541   // First initialize and slice up the current cell and save the
0542   // resulting for the compensation procedure.
0543   init();
0544   slice();
0545   if ( !wholecomp ) {
0546     first = current;
0547     firstlo = lo;
0548     firstup = up;
0549   }
0550 
0551   // Find the largest function value in the current cell and as long
0552   // as it is above the current overestimate, increase the
0553   // overestimate and repeat the slicing.
0554   while ( shiftmaxmin() > current->g() ) {
0555     current->g(minf*margin);
0556     if ( current->g() > fsel ) return;
0557     init();
0558     slice();
0559   }   
0560 }
0561 
0562 template <typename Rnd, typename FncPtr>
0563 double ACDCGen<Rnd,FncPtr>::Slicer::shiftmaxmin() {
0564   // Find the largest diagonal
0565   DVector test = xsel;
0566   double scale = 0.0;
0567   for ( DimType d = 0; d < D; ++d )
0568     if ( fhl[d] > fsel || fhu[d] > fsel ) scale += 1.0;
0569   scale = sqrt(scale);
0570   for ( DimType d = 0; d < D; ++d ) {
0571     if ( fhl[d] > fsel && fhl[d] > fhu[d] )
0572       test[d] = test[d] + (xhl[d] - test[d])/scale;
0573     if ( fhu[d] > fsel && fhu[d] > fhl[d] )
0574       test[d] = test[d] + (xhu[d] - test[d])/scale;
0575   }
0576 
0577   // Find the largest value above overestimate
0578   DimType dsel = -1;
0579   double x = 0;
0580   minf = fsel;
0581   for ( DimType d = 0; d < D; ++d ) {
0582 
0583     // Find the point with the function minimum value above the
0584     // current overestimate.
0585     minf = std::min(minf, fhl[d]);
0586     minf = std::min(minf, fhu[d]);
0587 
0588     // Find points with the maximum function value and shift the
0589     // current point to it.
0590     if ( fhu[d] > fsel ) {
0591       fsel = fhu[d];
0592       dsel = d;
0593       x = xhu[d];
0594     }
0595     if ( fhl[d] > fsel ) {
0596       fsel = fhl[d];
0597       dsel = d;
0598       x = xhl[d];
0599     }
0600   }
0601 
0602   // Check also the largest diagonal
0603   //  double ftest = (*f)(test);
0604 //   if ( ftest > fsel ) {
0605 //     xsel = test;
0606 //     fsel = ftest;
0607 //     dsel = -1;
0608 //   }
0609 
0610   if ( dsel >= 0 ) xsel[dsel] = x;
0611   minf = std::max(minf, current->g());
0612   return fsel;
0613 }
0614 
0615 template <typename Rnd, typename FncPtr>
0616 void ACDCGen<Rnd,FncPtr>::Slicer::dohalf(DimType d) {
0617   xcl[d] = lo[d];
0618 
0619   // Find the point closest below the current point in the given
0620   // dimension with a function value below the current overestimate,
0621   // also find the one furthest away from the current point with a
0622   // function value above the current overestimate. Use a crude
0623   // iterative mid-point selection.
0624   while ( true ) {
0625     xhl[d] = (xsel[d] + xcl[d])*0.5;
0626 
0627     std::swap(xsel[d], xhl[d]);
0628     fhl[d] = FncTraits::value(f, xsel);
0629     std::swap(xsel[d], xhl[d]);
0630 
0631     if ( fhl[d] > current->g() ) break;
0632     if ( xsel[d] - xcl[d] < epsilon ) break;
0633 
0634     xcl[d] = xhl[d];
0635   }
0636 
0637   // Check if the current slicing is worth doing...
0638   double cut = ( up[d] - xcl[d] )/( up[d] - lo[d] );
0639   if ( cut < 1.0 - current->g()/fsel && cut > 0.0 )
0640     rateslice.insert(std::make_pair(cut, -1-d));
0641 
0642   // Find the point closest above the current point in the given
0643   // dimension with a function value below the current overestimate,
0644   // also find the one furthest away from the current point with a
0645   // function value above the current overestimate. Use a crude
0646   // iterative mid-point selection.
0647   xcu[d] = up[d];
0648   while ( true ) {
0649     xhu[d] = (xsel[d] + xcu[d])*0.5;
0650 
0651     std::swap(xsel[d], xhu[d]);
0652     fhu[d] = FncTraits::value(f, xsel);
0653     std::swap(xsel[d], xhu[d]);
0654 
0655     if ( fhu[d] > current->g() ) break;
0656     if ( xcu[d] - xsel[d] < epsilon ) break;
0657 
0658     xcu[d] = xhu[d];
0659   }
0660 
0661   // Check if the current slicing is worth doing...
0662   cut = ( xcu[d] - lo[d] )/( up[d] - lo[d] );
0663   if ( cut < 1.0 - current->g()/fsel && cut > 0.0 )
0664     rateslice.insert(std::make_pair(cut, 1+d));
0665 
0666 }
0667 
0668 template <typename Rnd, typename FncPtr>
0669 void ACDCGen<Rnd,FncPtr>::Slicer::init() {
0670   for ( DimType d = 0; d < D; ++d ) dohalf(d);
0671 }
0672 
0673 template <typename Rnd, typename FncPtr>
0674 void ACDCGen<Rnd,FncPtr>::Slicer::slice() {
0675   while ( !rateslice.empty() ) {
0676     // Perform the slicing which reduces the volume of the cell the
0677     // most first.
0678     DimType d = rateslice.begin()->second;
0679     rateslice.erase(rateslice.begin());
0680     if ( d > 0 ) {
0681       // Slice from above.
0682       d = d - 1;
0683       current->splitme(lo[d], xcu[d], up[d], d);
0684       checkdiag(current->upper(), d, xcu[d], up[d]);
0685       current = current->lower();
0686       up[d] = xcu[d];
0687     } else {
0688       // Slice from below..
0689       d = -d - 1;
0690       current->splitme(lo[d], xcl[d], up[d], d);
0691       checkdiag(current->lower(), d, lo[d], xcl[d]);
0692       current = current->upper();
0693       lo[d] = xcl[d];
0694     }
0695     dohalf(d);
0696   }
0697 }
0698 
0699 template <typename Rnd, typename FncPtr>
0700 void ACDCGen<Rnd,FncPtr>::Slicer::
0701 checkdiag(ACDCGenCell * cell, DimType dc, double lod, double upd) {
0702   return;
0703   // Look at the midpoint in the dc direction in which a cell has been
0704   // chopped off.
0705   if ( upd - lod <= epsilon ) return;
0706   DVector newlo = lo;
0707   DVector newup = up;
0708   newlo[dc] = lod;
0709   newup[dc] = upd;
0710   DVector newsel = xsel;
0711   newsel[dc] = 0.5*(lod + upd);
0712   double newfsel = FncTraits::value(f, newsel);
0713   double newfh = newfsel;
0714   DVector newxsel = newsel;
0715   vector<int> dir(D, 0);
0716 
0717   // For each other direction look at the mid point between the point
0718   // chosen above and the borders of the cell. Save the point which
0719   // gives the highest function value.
0720   for ( DimType d = 0; d < D; ++d ) {
0721     if ( d == dc ) continue;
0722     double xdum = 0.5*(newlo[d] + newsel[d]);
0723     swap(xdum, newsel[d]);
0724     double fh1 = FncTraits::value(f, newsel);
0725     if ( fh1 > newfsel ) {
0726       newfsel = fh1;
0727       newxsel = newsel;
0728     }
0729     if ( fh1 > newfh ) dir[d] = -1;
0730     swap(xdum, newsel[d]);
0731     xdum = 0.5*(newsel[d] + newup[d]);
0732     swap(xdum, newsel[d]);
0733     double fh2 = FncTraits::value(f, newsel);
0734     if ( fh2 > newfsel ) {
0735       newfsel = fh2;
0736       newxsel = newsel;
0737     }
0738     if ( fh2 > newfh && fh2 > fh1 ) dir[d] = 1;
0739     swap(xdum, newsel[d]);
0740   }
0741 
0742   // Now check along the diagonal where we found the highest values.
0743   for ( DimType d = 0; d < D; ++d ) {
0744     if ( dir[d] == 0 ) continue;
0745     if ( dir[d] > 0 ) newsel[d] = 0.5*(newsel[d] + newup[d]);
0746     else newsel[d] = 0.5*(newlo[d] + newsel[d]);
0747   }
0748   newfh = FncTraits::value(f, newsel);
0749   if ( newfh > newfsel ) {
0750     newfsel = newfh;
0751     newxsel = newsel;
0752   }
0753 
0754   if ( newfsel < cell->g() ) return;
0755 
0756   // If this the highest value is above the overestimate, also this
0757   // cell needs to be divided up and conquered.
0758   wholecomp = true;
0759   Slicer dummy(D, *this, cell, newlo, newxsel, newup, newfsel);
0760 }
0761 
0762 template <typename Rnd, typename FncPtr>
0763 ACDCGen<Rnd,FncPtr>::Slicer::
0764 Slicer(DimType Din, const Slicer & s, ACDCGenCell * cellin,
0765        const DVector & loin, const DVector & xselin, const DVector & upin,
0766        double fselin)
0767   : D(Din), lo(loin), up(upin), xcl(loin), xcu(upin), xhl(loin), xhu(upin),
0768     fhl(Din, 0.0), fhu(Din, 0.0), xsel(xselin), fsel(fselin),
0769     current(cellin), first(cellin),
0770     firstlo(loin), firstup(upin),f(s.f),
0771     epsilon(s.epsilon), margin(s.margin), minf(0.0), wholecomp(false) {
0772   divideandconquer();
0773 }
0774 
0775 template <typename Rnd, typename FncPtr>
0776 template <typename POStream>
0777 void ACDCGen<Rnd,FncPtr>::output(POStream & os) const {
0778   os << theNAcc << theN << theEps << theMargin << theNTry << theMaxTry
0779      << useCheapRandom << theLast << theLastPoint << theLastF
0780      << theFunctions.size() << levels.size();
0781   for ( int i = 1, N = theFunctions.size(); i < N; ++i )
0782     os << theFunctions[i] << theDimensions [i] << theSumMaxInts[i]
0783        << *thePrimaryCells[i] << theNI[i] << theSumW[i] << theSumW2[i];
0784   if ( theLast > 0 ) // first entry in thePrimaryCells always points at 0x0
0785     os << thePrimaryCells[theLast]->getIndex(theLastCell);
0786   else
0787     os << -1l;
0788   for ( int i = 0, N = levels.size(); i < N; ++i )
0789     os << levels[i].lastN << levels[i].g << levels[i].index
0790        << levels[i].up << levels[i].lo
0791        << thePrimaryCells[levels[i].index]->getIndex(levels[i].cell);
0792 }
0793 
0794 template <typename Rnd, typename FncPtr>
0795 template <typename PIStream>
0796 void ACDCGen<Rnd,FncPtr>::input(PIStream & is) {
0797   clear();
0798   long fsize = 0;
0799   long lsize = 0;
0800   is >> theNAcc >> theN >> theEps >> theMargin >> theNTry >> theMaxTry
0801      >> useCheapRandom >> theLast >> theLastPoint >> theLastF >> fsize >> lsize;
0802   while ( --fsize ) {
0803     theFunctions.push_back(FncPtrType());
0804     theDimensions.push_back(DimType());
0805     theSumMaxInts.push_back(0.0);
0806     theNI.push_back(0);
0807     theSumW.push_back(0.0);
0808     theSumW2.push_back(0.0);
0809     thePrimaryCells.push_back(new ACDCGenCell(0.0));
0810     is >> theFunctions.back() >> theDimensions.back() >> theSumMaxInts.back()
0811        >> *thePrimaryCells.back() >> theNI.back()
0812        >> theSumW.back() >> theSumW2.back();
0813   }
0814   long index = -1;
0815   is >> index;
0816   if ( index == -1 )
0817     theLastCell = 0x0;
0818   else
0819     theLastCell = thePrimaryCells[theLast]->getCell(index);
0820   while ( lsize-- ) {
0821     levels.push_back(Level());
0822     is >> levels.back().lastN >> levels.back().g >> levels.back().index
0823        >> levels.back().up >> levels.back().lo >> index;
0824     levels.back().cell = thePrimaryCells[levels.back().index]->getCell(index);
0825   }
0826 }
0827 
0828 }