| 1 | /* ======================================================================== *\
 | 
|---|
| 2 | !
 | 
|---|
| 3 | ! *
 | 
|---|
| 4 | ! * This file is part of MARS, the MAGIC Analysis and Reconstruction
 | 
|---|
| 5 | ! * Software. It is distributed to you in the hope that it can be a useful
 | 
|---|
| 6 | ! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
 | 
|---|
| 7 | ! * It is distributed WITHOUT ANY WARRANTY.
 | 
|---|
| 8 | ! *
 | 
|---|
| 9 | ! * Permission to use, copy, modify and distribute this software and its
 | 
|---|
| 10 | ! * documentation for any purpose is hereby granted without fee,
 | 
|---|
| 11 | ! * provided that the above copyright notice appear in all copies and
 | 
|---|
| 12 | ! * that both that copyright notice and this permission notice appear
 | 
|---|
| 13 | ! * in supporting documentation. It is provided "as is" without express
 | 
|---|
| 14 | ! * or implied warranty.
 | 
|---|
| 15 | ! *
 | 
|---|
| 16 | !
 | 
|---|
| 17 | !
 | 
|---|
| 18 | !   Author(s): Markus Gaug 10/2002  <mailto:markus@ifae.es>
 | 
|---|
| 19 | !
 | 
|---|
| 20 | !   Copyright: MAGIC Software Development, 2002
 | 
|---|
| 21 | !
 | 
|---|
| 22 | !
 | 
|---|
| 23 | \* ======================================================================== */
 | 
|---|
| 24 | 
 | 
|---|
| 25 | //////////////////////////////////////////////////////////////////////////////
 | 
|---|
| 26 | //                                                                          //
 | 
|---|
| 27 | //  MSimulatedAnnealing                                                     //
 | 
|---|
| 28 | //                                                                          //
 | 
|---|
| 29 | //  class to perform a Simulated Annealing minimization on an n-dimensional //
 | 
|---|
| 30 | //  simplex of a function 'FunctionToMinimize(TArrayF &)' in multi-         //
 | 
|---|
| 31 | //  dimensional parameter space.                                            //
 | 
|---|
| 32 | //  (The code is adapted from Numerical Recipies in C++, 2nd ed.,           //
 | 
|---|
| 33 | //  pp. 457-459)                                                            //
 | 
|---|
| 34 | //                                                                          //
 | 
|---|
| 35 | //  Classes can inherit from MSimulatedAnnealing                            //
 | 
|---|
| 36 | //  and use the function:                                                   //
 | 
|---|
| 37 | //                                                                          //
 | 
|---|
| 38 | //  RunSimulatedAnnealing();                                                //
 | 
|---|
| 39 | //                                                                          //
 | 
|---|
| 40 | //  They HAVE TO initialize the following input arguments                   //
 | 
|---|
| 41 | //  (with ndim being the parameter dimension (max. 20)):                    //
 | 
|---|
| 42 | //                                                                          //
 | 
|---|
| 43 | //  1) a TMatrix p(ndim+1,ndim)                                             //
 | 
|---|
| 44 | //     holding the start simplex                                            //
 | 
|---|
| 45 | //  2) a TArrayF y(ndim+1)                                                  //
 | 
|---|
| 46 | //     whose components must be pre-initialized to the values of            //
 | 
|---|
| 47 | //      FunctionToMinimize evaluated at the fNdim+1 vertices (rows) of p    //
 | 
|---|
| 48 | //  3) a TArrayF p0(ndim)                                                   //
 | 
|---|
| 49 | //     whose components contain the lower simplex borders                   //
 | 
|---|
| 50 | //  4) a TArrayF p1(ndim)                                                   //
 | 
|---|
| 51 | //     whose components contain the upper simplex borders                   //
 | 
|---|
| 52 | //    (The simplex will not get reflected out of these borders !!!)         //
 | 
|---|
| 53 | //                                                                          //
 | 
|---|
| 54 | //  These arrays have to be initialized with a call to:                     //
 | 
|---|
| 55 | //  Initialize(TMatrix \&, TArrayF \&, TArrayF \&, TArrayF \&)              //
 | 
|---|
| 56 | //                                                                          //
 | 
|---|
| 57 | //  5) a virtual function FunctionToMinimize(TArrayF &)                     //
 | 
|---|
| 58 | //     acting on a TArrayF(ndim) array of parameter values                  //
 | 
|---|
| 59 | //                                                                          //
 | 
|---|
| 60 | //  Additionally, a global start temperature can be chosen with:            //
 | 
|---|
| 61 | //                                                                          //
 | 
|---|
| 62 | //  SetStartTemperature(Float_t temp)                                       //
 | 
|---|
| 63 | //  (default is: 10)                                                        //
 | 
|---|
| 64 | //                                                                          //
 | 
|---|
| 65 | //  A total number of total moves (watch out for the CPU time!!!) with:     //
 | 
|---|
| 66 | //                                                                          //
 | 
|---|
| 67 | //  SetNumberOfMoves(Float_t totalMoves)                                    //
 | 
|---|
| 68 | //  (default is: 200)                                                       //
 | 
|---|
| 69 | //                                                                          //
 | 
|---|
| 70 | //  The temperature is reduced after evaluation step like:                  //
 | 
|---|
| 71 | //      CurrentTemperature = StartTemperature*(1-currentMove/totalMoves)    //
 | 
|---|
| 72 | //  where currentMove is the cumulative number of moves so far              //
 | 
|---|
| 73 | //                                                                          //
 | 
|---|
| 74 | //  WARNING: The start temperature and number of moves has to be optimized  //
 | 
|---|
| 75 | //           for each individual problem.                                   //
 | 
|---|
| 76 | //           It is not straightforward using the defaults!                  //
 | 
|---|
| 77 | //           In case, you omit this important step,                         //
 | 
|---|
| 78 | //           you will get local minima without even noticing it!!           //
 | 
|---|
| 79 | //                                                                          //
 | 
|---|
| 80 | //  You may define the following variables:                                 //
 | 
|---|
| 81 | //                                                                          //
 | 
|---|
| 82 | //  1) A global convergence criterium fTol                                  //
 | 
|---|
| 83 | //     which determines an early return for:                                //
 | 
|---|
| 84 | //                                                                          //
 | 
|---|
| 85 | //     max(FunctionToMinimize(p))-min(FunctionToMinimize(p))                //
 | 
|---|
| 86 | //     -----------------------------------------------------  \< fTol       //
 | 
|---|
| 87 | //     max(FunctionToMinimize(p))+min(FunctionToMinimize(p))                //
 | 
|---|
| 88 | //                                                                          //
 | 
|---|
| 89 | //     ModifyTolerance(Float_t)                                             //
 | 
|---|
| 90 | //                                                                          //
 | 
|---|
| 91 | //  2) A verbose level for prints to *fLog                                  //
 | 
|---|
| 92 | //                                                                          //
 | 
|---|
| 93 | //     SetVerbosityLevel(Verbosity_t)                                       //
 | 
|---|
| 94 | //                                                                          //
 | 
|---|
| 95 | //  3) A bit if you want to have stored                                     //
 | 
|---|
| 96 | //     the full simplex after every call to Amebsa:                         //
 | 
|---|
| 97 | //                                                                          //
 | 
|---|
| 98 | //     SetFullStorage()                                                     //
 | 
|---|
| 99 | //                                                                          //
 | 
|---|
| 100 | //  4) The random number generator                                          //
 | 
|---|
| 101 | //     e.g. if you want to test the stability of the output                 //
 | 
|---|
| 102 | //                                                                          //
 | 
|---|
| 103 | //     SetRandom(TRandom *rand)                                             //
 | 
|---|
| 104 | //                                                                          //
 | 
|---|
| 105 | //                                                                          //
 | 
|---|
| 106 | //  Output containers:                                                      //
 | 
|---|
| 107 | //                                                                          //
 | 
|---|
| 108 | //  MHSimulatedAnnealing                                                    //
 | 
|---|
| 109 | //                                                                          //
 | 
|---|
| 110 | //  Use:                                                                    //
 | 
|---|
| 111 | //    GetResult()->Draw(Option_t *o)                                        //
 | 
|---|
| 112 | //  or                                                                      //
 | 
|---|
| 113 | //    GetResult()->DrawClone(Option_t *o)                                   //
 | 
|---|
| 114 | //                                                                          //
 | 
|---|
| 115 | //  to retrieve the output histograms                                       //
 | 
|---|
| 116 | //                                                                          //
 | 
|---|
| 117 | //////////////////////////////////////////////////////////////////////////////
 | 
|---|
| 118 | #include "MSimulatedAnnealing.h"
 | 
|---|
| 119 | 
 | 
|---|
| 120 | #include <fstream>
 | 
|---|
| 121 | #include <iostream>
 | 
|---|
| 122 | 
 | 
|---|
| 123 | #include <TRandom.h>
 | 
|---|
| 124 | 
 | 
|---|
| 125 | #include "MLog.h"
 | 
|---|
| 126 | #include "MLogManip.h"
 | 
|---|
| 127 | 
 | 
|---|
| 128 | #include "MHSimulatedAnnealing.h"
 | 
|---|
| 129 | 
 | 
|---|
| 130 | const Float_t MSimulatedAnnealing::gsYtryStr = 10000000;  
 | 
|---|
| 131 | const Float_t MSimulatedAnnealing::gsYtryCon = 20000000;  
 | 
|---|
| 132 | const Int_t   MSimulatedAnnealing::gsMaxDim  = 20;
 | 
|---|
| 133 | const Int_t   MSimulatedAnnealing::gsMaxStep = 50;
 | 
|---|
| 134 | 
 | 
|---|
| 135 | ClassImp(MSimulatedAnnealing);
 | 
|---|
| 136 | 
 | 
|---|
| 137 | using namespace std;
 | 
|---|
| 138 | 
 | 
|---|
| 139 | // ---------------------------------------------------------------------------
 | 
|---|
| 140 | //
 | 
|---|
| 141 | //  Default Constructor
 | 
|---|
| 142 | //  Initializes random number generator and default variables
 | 
|---|
| 143 | //
 | 
|---|
| 144 | MSimulatedAnnealing::MSimulatedAnnealing()
 | 
|---|
| 145 |     : fResult(NULL), fTolerance(0.0001),
 | 
|---|
| 146 |       fNdim(0), fNumberOfMoves(200),
 | 
|---|
| 147 |       fStartTemperature(10), fFullStorage(kFALSE),
 | 
|---|
| 148 |       fInit(kFALSE), 
 | 
|---|
| 149 |       fP(gsMaxDim, gsMaxDim), fP0(gsMaxDim),
 | 
|---|
| 150 |       fP1(gsMaxDim), fY(gsMaxDim), fYb(gsMaxDim), fYconv(gsMaxDim),
 | 
|---|
| 151 |       fPb(gsMaxDim), fPconv(gsMaxDim),
 | 
|---|
| 152 |       fBorder(kEStrictBorder), fVerbose(kEDefault)
 | 
|---|
| 153 | {
 | 
|---|
| 154 | 
 | 
|---|
| 155 |     // random number generator
 | 
|---|
| 156 |     fRandom = gRandom;
 | 
|---|
| 157 | }
 | 
|---|
| 158 | 
 | 
|---|
| 159 | // --------------------------------------------------------------------------
 | 
|---|
| 160 | //
 | 
|---|
| 161 | //  Destructor. 
 | 
|---|
| 162 | //
 | 
|---|
| 163 | MSimulatedAnnealing::~MSimulatedAnnealing()
 | 
|---|
| 164 | {
 | 
|---|
| 165 |   if (fResult) 
 | 
|---|
| 166 |     delete fResult;
 | 
|---|
| 167 | }
 | 
|---|
| 168 | 
 | 
|---|
| 169 | // ---------------------------------------------------------------------------
 | 
|---|
| 170 | //
 | 
|---|
| 171 | //  Initialization needs the following four members:
 | 
|---|
| 172 | //
 | 
|---|
| 173 | //  1) a TMatrix p(ndim+1,ndim)
 | 
|---|
| 174 | //     holding the start simplex 
 | 
|---|
| 175 | //  2) a TVector y(ndim+1)
 | 
|---|
| 176 | //     whose components must be pre-initialized to the values of 
 | 
|---|
| 177 | //     FunctionToMinimize evaluated at the fNdim+1 vertices (rows) of fP
 | 
|---|
| 178 | //  3) a TVector p0(ndim)
 | 
|---|
| 179 | //     whose components contain the lower simplex borders 
 | 
|---|
| 180 | //  4) a TVector p1(ndim)
 | 
|---|
| 181 | //     whose components contain the upper simplex borders
 | 
|---|
| 182 | //    (The simplex will not get reflected out of these borders !!!)
 | 
|---|
| 183 | //
 | 
|---|
| 184 | //  It is possible to perform an initialization and 
 | 
|---|
| 185 | //  a subsequent RunMinimization several times. 
 | 
|---|
| 186 | //  Each time, a new class MHSimulatedAnnealing will get created
 | 
|---|
| 187 | //  (and destroyed). 
 | 
|---|
| 188 | //
 | 
|---|
| 189 | Bool_t MSimulatedAnnealing::Initialize(const TMatrix &p,  const TVector &y, 
 | 
|---|
| 190 |                                        const TVector &p0, const TVector &p1)
 | 
|---|
| 191 | {
 | 
|---|
| 192 | 
 | 
|---|
| 193 |     fNdim = p.GetNcols();
 | 
|---|
| 194 |     fMpts = p.GetNrows();
 | 
|---|
| 195 | 
 | 
|---|
| 196 |     //
 | 
|---|
| 197 |     // many necessary checks ...
 | 
|---|
| 198 |     //
 | 
|---|
| 199 |     if (fMpts > gsMaxDim) 
 | 
|---|
| 200 |     {
 | 
|---|
| 201 |        gLog << err << "Dimension of Matrix fP is too big ... aborting." << endl;
 | 
|---|
| 202 |         return kFALSE;
 | 
|---|
| 203 |     }
 | 
|---|
| 204 |     if (fNdim+1 != fMpts) 
 | 
|---|
| 205 |     {
 | 
|---|
| 206 |         gLog << err << "Matrix fP does not have the right dimensions ... aborting." << endl;
 | 
|---|
| 207 |         return kFALSE;
 | 
|---|
| 208 |     }
 | 
|---|
| 209 |     if (y.GetNrows() != fMpts) 
 | 
|---|
| 210 |     {
 | 
|---|
| 211 |         gLog << err << "Array fY has not the right dimension ... aborting." << endl;
 | 
|---|
| 212 |         return kFALSE;
 | 
|---|
| 213 |     }
 | 
|---|
| 214 |     if (p0.GetNrows() != fNdim) 
 | 
|---|
| 215 |     {
 | 
|---|
| 216 |         gLog << err << "Array fP0 has not the right dimension ... aborting." << endl;
 | 
|---|
| 217 |         return kFALSE;
 | 
|---|
| 218 |     }
 | 
|---|
| 219 |     if (p1.GetNrows() != fNdim) 
 | 
|---|
| 220 |     {
 | 
|---|
| 221 |         gLog << err << "Array fP1 has not the right dimension ... aborting." << endl;
 | 
|---|
| 222 |         return kFALSE;
 | 
|---|
| 223 |     }
 | 
|---|
| 224 | 
 | 
|---|
| 225 |     //
 | 
|---|
| 226 |     // In order to allow multiple use of the class
 | 
|---|
| 227 |     // without need to construct the class every time new
 | 
|---|
| 228 |     // delete the old fResult and create a new one in RunMinimization
 | 
|---|
| 229 |     //
 | 
|---|
| 230 |     if (fResult)
 | 
|---|
| 231 |        delete fResult;
 | 
|---|
| 232 | 
 | 
|---|
| 233 |     fY.ResizeTo(fMpts);
 | 
|---|
| 234 |     
 | 
|---|
| 235 |     fPsum.ResizeTo(fNdim);
 | 
|---|
| 236 |     fPconv.ResizeTo(fNdim);
 | 
|---|
| 237 |     
 | 
|---|
| 238 |     fP0.ResizeTo(fNdim);
 | 
|---|
| 239 |     fP1.ResizeTo(fNdim);
 | 
|---|
| 240 |     fPb.ResizeTo(fNdim);
 | 
|---|
| 241 |     
 | 
|---|
| 242 |     fP.ResizeTo(fMpts,fNdim);
 | 
|---|
| 243 | 
 | 
|---|
| 244 |     fY  = y;
 | 
|---|
| 245 |     fP  = p;
 | 
|---|
| 246 |     fP0 = p0;
 | 
|---|
| 247 |     fP1 = p1;
 | 
|---|
| 248 |     fPconv.Zero();
 | 
|---|
| 249 | 
 | 
|---|
| 250 |     fInit = kTRUE;
 | 
|---|
| 251 |     fYconv = 0.;
 | 
|---|
| 252 | 
 | 
|---|
| 253 |     return kTRUE;
 | 
|---|
| 254 | }
 | 
|---|
| 255 | 
 | 
|---|
| 256 | 
 | 
|---|
| 257 | // ---------------------------------------------------------------------------
 | 
|---|
| 258 | //
 | 
|---|
| 259 | //  RunMinimization:
 | 
|---|
| 260 | //
 | 
|---|
| 261 | //  Runs only eafter a call to Initialize(const TMatrix \&, const TVector \&,
 | 
|---|
| 262 | //                                        const TVector \&, const TVector \&)
 | 
|---|
| 263 | //  
 | 
|---|
| 264 | //  Temperature and number of moves should have been set
 | 
|---|
| 265 | //  (default: StartTemperature = 10, NumberOfMoves = 200
 | 
|---|
| 266 | //
 | 
|---|
| 267 | //  
 | 
|---|
| 268 | //  It is possible to perform an initialization and 
 | 
|---|
| 269 | //  a subsequent RunMinimization several times. 
 | 
|---|
| 270 | //  Each time, a new class MHSimulatedAnnealing will get created
 | 
|---|
| 271 | //  (and destroyed). 
 | 
|---|
| 272 | Bool_t MSimulatedAnnealing::RunMinimization()
 | 
|---|
| 273 | {
 | 
|---|
| 274 |     if (!fInit)
 | 
|---|
| 275 |     {
 | 
|---|
| 276 |         gLog << err << "No succesful initialization performed yet... aborting." << endl;
 | 
|---|
| 277 |         return kFALSE;
 | 
|---|
| 278 |     }
 | 
|---|
| 279 | 
 | 
|---|
| 280 |     Int_t    iter        = 0;
 | 
|---|
| 281 |     UShort_t iret        = 0;
 | 
|---|
| 282 |     UShort_t currentMove = 0;
 | 
|---|
| 283 |     Real_t   currentTemp = fStartTemperature;
 | 
|---|
| 284 | 
 | 
|---|
| 285 |     fResult = new MHSimulatedAnnealing(fNumberOfMoves,fNdim);
 | 
|---|
| 286 |     if (fFullStorage) 
 | 
|---|
| 287 |       fResult->InitFullSimplex();
 | 
|---|
| 288 | 
 | 
|---|
| 289 |     while(1)
 | 
|---|
| 290 |     {
 | 
|---|
| 291 |         if (iter > 0) 
 | 
|---|
| 292 |         {
 | 
|---|
| 293 |             gLog << "Convergence at move: " << currentMove ;
 | 
|---|
| 294 |             gLog << " and temperature: " << currentTemp << endl;
 | 
|---|
| 295 |             break;
 | 
|---|
| 296 |         }
 | 
|---|
| 297 |         
 | 
|---|
| 298 |         if (currentTemp > 0.) 
 | 
|---|
| 299 |         {
 | 
|---|
| 300 |           //
 | 
|---|
| 301 |           // Reduce the temperature 
 | 
|---|
| 302 |           //
 | 
|---|
| 303 |           // FIXME: Maybe it is necessary to also incorporate other 
 | 
|---|
| 304 |           //        ways to reduce the temperature (T0*(1-k/K)**alpha)
 | 
|---|
| 305 |           // 
 | 
|---|
| 306 |           currentTemp = fStartTemperature*(1.-(float)currentMove++/fNumberOfMoves);
 | 
|---|
| 307 |           iter = 1;
 | 
|---|
| 308 |         } 
 | 
|---|
| 309 |         else 
 | 
|---|
| 310 |         {
 | 
|---|
| 311 |             // Make sure that now, the program will return only on convergence !
 | 
|---|
| 312 |             // The program returns to here only after gsMaxStep moves
 | 
|---|
| 313 |             // If we have not reached convergence until then, we assume that an infinite 
 | 
|---|
| 314 |             // loop has occurred and quit.
 | 
|---|
| 315 |             if (iret != 0) 
 | 
|---|
| 316 |             {
 | 
|---|
| 317 |                 gLog << warn << "No Convergence at the end ! " << endl;
 | 
|---|
| 318 |                 fY.Zero();
 | 
|---|
| 319 | 
 | 
|---|
| 320 |                 break;
 | 
|---|
| 321 |             }
 | 
|---|
| 322 |             iter = 150;
 | 
|---|
| 323 |             iret++;
 | 
|---|
| 324 |             currentMove++;
 | 
|---|
| 325 |         }
 | 
|---|
| 326 |         
 | 
|---|
| 327 |         if (fVerbose==2) {
 | 
|---|
| 328 |             gLog << dbginf << " current..." << endl;
 | 
|---|
| 329 |             gLog << " - move:        " << currentMove << endl;
 | 
|---|
| 330 |             gLog << " - temperature: " << currentTemp << endl;
 | 
|---|
| 331 |             gLog << " - best function evaluation: " << fYb << endl;
 | 
|---|
| 332 |         }
 | 
|---|
| 333 | 
 | 
|---|
| 334 |         iter = Amebsa(iter, currentTemp);
 | 
|---|
| 335 | 
 | 
|---|
| 336 |         // Store the current best values in the histograms
 | 
|---|
| 337 |         fResult->StoreBestValueEver(fPb,fYb,currentMove);
 | 
|---|
| 338 | 
 | 
|---|
| 339 |         // Store the complete simplex if we have full storage
 | 
|---|
| 340 |         if (fFullStorage) 
 | 
|---|
| 341 |           fResult->StoreFullSimplex(fP,currentMove);
 | 
|---|
| 342 |     }
 | 
|---|
| 343 | 
 | 
|---|
| 344 |     //
 | 
|---|
| 345 |     // Now, the matrizes and vectors have all the same value, 
 | 
|---|
| 346 |     // Need to initialize again to allow a new Minimization
 | 
|---|
| 347 |     //
 | 
|---|
| 348 |     fInit = kFALSE;
 | 
|---|
| 349 | 
 | 
|---|
| 350 |     return kTRUE;
 | 
|---|
| 351 | }
 | 
|---|
| 352 | 
 | 
|---|
| 353 | // ---------------------------------------------------------------------------
 | 
|---|
| 354 | //
 | 
|---|
| 355 | //  Amebsa
 | 
|---|
| 356 | //
 | 
|---|
| 357 | //  This is the (adjusted) amebsa function from 
 | 
|---|
| 358 | //  Numerical Recipies (pp. 457-458)
 | 
|---|
| 359 | //             
 | 
|---|
| 360 | //  The routine makes iter function evaluations at an annealing
 | 
|---|
| 361 | //  temperature fCurrentTemp, then returns. If iter is returned 
 | 
|---|
| 362 | //  with a poisitive value, then early convergence has occurred. 
 | 
|---|
| 363 | //
 | 
|---|
| 364 | Int_t MSimulatedAnnealing::Amebsa(Int_t iter, const Real_t temp)
 | 
|---|
| 365 | {
 | 
|---|
| 366 |     GetPsum();
 | 
|---|
| 367 |   
 | 
|---|
| 368 |     while (1) 
 | 
|---|
| 369 |     {
 | 
|---|
| 370 |         UShort_t ihi = 0; // Simplex point with highest function evaluation
 | 
|---|
| 371 |         UShort_t ilo = 1; // Simplex point with lowest  function evaluation
 | 
|---|
| 372 | 
 | 
|---|
| 373 |         // Function eval. at ilo (with random fluctuations)
 | 
|---|
| 374 |         Real_t ylo = fY(0) + gRandom->Exp(temp); 
 | 
|---|
| 375 | 
 | 
|---|
| 376 |         // Function eval. at ihi (with random fluctuations)
 | 
|---|
| 377 |         Real_t yhi = fY(1) + gRandom->Exp(temp); 
 | 
|---|
| 378 | 
 | 
|---|
| 379 |         // The function evaluation at next highest point
 | 
|---|
| 380 |         Real_t ynhi = ylo; 
 | 
|---|
| 381 | 
 | 
|---|
| 382 |         if (ylo > yhi)
 | 
|---|
| 383 |         {
 | 
|---|
| 384 |             // Determine which point is the highest (worst),
 | 
|---|
| 385 |             // next-highest and lowest (best)
 | 
|---|
| 386 |             ynhi = yhi;
 | 
|---|
| 387 |             yhi  = ylo;
 | 
|---|
| 388 |             ylo  = ynhi;
 | 
|---|
| 389 |         }
 | 
|---|
| 390 |     
 | 
|---|
| 391 |         // By looping over the points in the simplex 
 | 
|---|
| 392 |         for (UShort_t i=2;i<fMpts;i++) 
 | 
|---|
| 393 |         {
 | 
|---|
| 394 |             const Real_t yt = fY(i) + gRandom->Exp(temp);
 | 
|---|
| 395 |       
 | 
|---|
| 396 |             if (yt <= ylo)
 | 
|---|
| 397 |             {
 | 
|---|
| 398 |                 ilo = i;
 | 
|---|
| 399 |                 ylo = yt;
 | 
|---|
| 400 |             }
 | 
|---|
| 401 | 
 | 
|---|
| 402 |             if (yt > yhi)
 | 
|---|
| 403 |             {
 | 
|---|
| 404 |                 ynhi = yhi;
 | 
|---|
| 405 |                 ihi  = i;
 | 
|---|
| 406 |                 yhi  = yt;
 | 
|---|
| 407 |             }
 | 
|---|
| 408 |             else 
 | 
|---|
| 409 |                 if (yt > ynhi) 
 | 
|---|
| 410 |                     ynhi = yt;
 | 
|---|
| 411 |         }
 | 
|---|
| 412 | 
 | 
|---|
| 413 |         // Now, fY(ilo) is smallest and fY(ihi) is at biggest value 
 | 
|---|
| 414 |         if (iter < 0)
 | 
|---|
| 415 |         {
 | 
|---|
| 416 |             // Enough looping with this temperature, go to decrease it
 | 
|---|
| 417 |             // First put best point and value in slot 0
 | 
|---|
| 418 |             
 | 
|---|
| 419 |             Real_t dum = fY(0);
 | 
|---|
| 420 |             fY(0)      = fY(ilo);
 | 
|---|
| 421 |             fY(ilo)    = dum;
 | 
|---|
| 422 | 
 | 
|---|
| 423 |             for (UShort_t n=0;n<fNdim;n++)
 | 
|---|
| 424 |             {
 | 
|---|
| 425 |                 dum       = fP(0,n);
 | 
|---|
| 426 |                 fP(0,n)   = fP(ilo,n);
 | 
|---|
| 427 |                 fP(ilo,n) = dum;
 | 
|---|
| 428 |             }
 | 
|---|
| 429 |           
 | 
|---|
| 430 |             break;
 | 
|---|
| 431 |         }
 | 
|---|
| 432 |         
 | 
|---|
| 433 |         // Compute the fractional range from highest to lowest and
 | 
|---|
| 434 |         // return if satisfactory
 | 
|---|
| 435 |         Real_t tol = fabs(yhi) + fabs(ylo);
 | 
|---|
| 436 |         if (tol != 0)
 | 
|---|
| 437 |             tol = 2.0*fabs(yhi-ylo)/tol;
 | 
|---|
| 438 |     
 | 
|---|
| 439 |         if (tol<fTolerance)
 | 
|---|
| 440 |         {
 | 
|---|
| 441 |             // Put best point and value in fPconv
 | 
|---|
| 442 |             fYconv = fY(ilo);
 | 
|---|
| 443 |             for (UShort_t n=0; n<fNdim; n++)
 | 
|---|
| 444 |                 fPconv(n) = fP(ilo, n);  
 | 
|---|
| 445 | 
 | 
|---|
| 446 |             break;
 | 
|---|
| 447 |         }
 | 
|---|
| 448 |         iter -= 2;
 | 
|---|
| 449 | 
 | 
|---|
| 450 |         // Begin new Iteration. First extrapolate by a factor of -1 through
 | 
|---|
| 451 |         // the face of the simplex across from the high point, i.e. reflect
 | 
|---|
| 452 |         // the simplex from the high point
 | 
|---|
| 453 |         Real_t ytry = Amotsa(-1.0, ihi, yhi,temp);
 | 
|---|
| 454 |     
 | 
|---|
| 455 |         if (ytry <= ylo)
 | 
|---|
| 456 |         {
 | 
|---|
| 457 |             // cout << " !!!!!!!!!!!!!! E X P A N D  !!!!!!!!!!!!!!" << endl;
 | 
|---|
| 458 |             // Gives a result better than the best point, so try an additional
 | 
|---|
| 459 |             // extrapolation by a factor of 2
 | 
|---|
| 460 |             ytry = Amotsa(2.0, ihi, yhi,temp);
 | 
|---|
| 461 |             continue;
 | 
|---|
| 462 |         }
 | 
|---|
| 463 | 
 | 
|---|
| 464 |         if (ytry < ynhi)
 | 
|---|
| 465 |         {
 | 
|---|
| 466 |             iter++;
 | 
|---|
| 467 |             continue;
 | 
|---|
| 468 |         }
 | 
|---|
| 469 | 
 | 
|---|
| 470 |         // cout << " !!!!!!!!!!!! R E F L E C T  !!!!!!!!!!!!!!!!!!!!" << endl;
 | 
|---|
| 471 |         // The reflected point is worse than the second-highest, so look for an
 | 
|---|
| 472 |         // intermediate lower point, for (a one-dimensional contraction */
 | 
|---|
| 473 |         const Real_t fYsave = yhi;
 | 
|---|
| 474 |         ytry = Amotsa(0.5, ihi, yhi,temp);
 | 
|---|
| 475 | 
 | 
|---|
| 476 |         if (ytry < fYsave)
 | 
|---|
| 477 |             continue;
 | 
|---|
| 478 | 
 | 
|---|
| 479 |         // cout << " !!!!!!!!!!!! R E F L E C T  !!!!!!!!!!!!!!!!!!!!" << endl;
 | 
|---|
| 480 |         // The reflected point is worse than the second-highest, so look for an
 | 
|---|
| 481 |         // intermediate lower point, for (a one-dimensional contraction */
 | 
|---|
| 482 |         const Real_t ysave = yhi;
 | 
|---|
| 483 |         ytry = Amotsa(0.5, ihi, yhi,temp);
 | 
|---|
| 484 |       
 | 
|---|
| 485 |         if (ytry < ysave)
 | 
|---|
| 486 |             continue;
 | 
|---|
| 487 | 
 | 
|---|
| 488 |         // cout << " !!!!!!!!!!!! C O N T R A C T  !!!!!!!!!!!!!!!!!!" << endl;
 | 
|---|
| 489 |         // Cannot seem to get rid of that point, better contract around the
 | 
|---|
| 490 |         // lowest (best) point
 | 
|---|
| 491 |         for (UShort_t i=0; i<fMpts; i++)
 | 
|---|
| 492 |         {
 | 
|---|
| 493 |             if (i != ilo)
 | 
|---|
| 494 |             {
 | 
|---|
| 495 |                 for (UShort_t j=0;j<fNdim;j++)
 | 
|---|
| 496 |                 {
 | 
|---|
| 497 |                     fPsum(j) = 0.5*(fP(i, j) + fP(ilo, j));
 | 
|---|
| 498 | 
 | 
|---|
| 499 |                     // Create new cutvalues
 | 
|---|
| 500 |                     fP(i, j) = fPsum(j);
 | 
|---|
| 501 |                 }
 | 
|---|
| 502 |                 fY(i) = FunctionToMinimize(fPsum);
 | 
|---|
| 503 |             }
 | 
|---|
| 504 |         }
 | 
|---|
| 505 | 
 | 
|---|
| 506 |         iter -= fNdim;
 | 
|---|
| 507 |         GetPsum();
 | 
|---|
| 508 |     }
 | 
|---|
| 509 |     return iter;
 | 
|---|
| 510 | }
 | 
|---|
| 511 | 
 | 
|---|
| 512 | void MSimulatedAnnealing::GetPsum()
 | 
|---|
| 513 | {
 | 
|---|
| 514 |     for (Int_t n=0; n<fNdim; n++)
 | 
|---|
| 515 |     {
 | 
|---|
| 516 |         Real_t sum=0.0;
 | 
|---|
| 517 |         for (Int_t m=0;m<fMpts;m++)
 | 
|---|
| 518 |             sum += fP(m,n);
 | 
|---|
| 519 | 
 | 
|---|
| 520 |         fPsum(n) = sum;
 | 
|---|
| 521 |     }
 | 
|---|
| 522 | }
 | 
|---|
| 523 | 
 | 
|---|
| 524 | 
 | 
|---|
| 525 | Real_t MSimulatedAnnealing::Amotsa(const Float_t fac, const UShort_t ihi, 
 | 
|---|
| 526 |                                    Real_t &yhi, const Real_t temp)
 | 
|---|
| 527 | {
 | 
|---|
| 528 |   
 | 
|---|
| 529 |     const Real_t fac1 = (1.-fac)/fNdim;
 | 
|---|
| 530 |     const Real_t fac2 = fac1 - fac;
 | 
|---|
| 531 | 
 | 
|---|
| 532 |     Int_t borderflag = 0;
 | 
|---|
| 533 |     TVector ptry(fNdim);
 | 
|---|
| 534 |     TVector cols(fMpts);
 | 
|---|
| 535 | 
 | 
|---|
| 536 |     for (Int_t j=0; j<fNdim; j++)
 | 
|---|
| 537 |     {
 | 
|---|
| 538 |         ptry(j) = fPsum(j)*fac1 - fP(ihi, j)*fac2;
 | 
|---|
| 539 | 
 | 
|---|
| 540 |         // Check that the simplex does not go to infinite values,
 | 
|---|
| 541 |         // in case of: reflect it
 | 
|---|
| 542 |         const Real_t newcut = ptry(j);
 | 
|---|
| 543 |   
 | 
|---|
| 544 |         if (fP1(j) > fP0(j))
 | 
|---|
| 545 |         {
 | 
|---|
| 546 |             if (newcut > fP1(j))
 | 
|---|
| 547 |             {
 | 
|---|
| 548 |                 ptry(j) = fP1(j);
 | 
|---|
| 549 |                 borderflag = 1;
 | 
|---|
| 550 |             }
 | 
|---|
| 551 |             else
 | 
|---|
| 552 |                 if (newcut < fP0(j))
 | 
|---|
| 553 |                 {
 | 
|---|
| 554 |                     ptry(j) = fP0(j);
 | 
|---|
| 555 |                     borderflag = 1;
 | 
|---|
| 556 |                 }
 | 
|---|
| 557 |         }
 | 
|---|
| 558 |     
 | 
|---|
| 559 |         else
 | 
|---|
| 560 |         {
 | 
|---|
| 561 |             if (newcut < fP1(j))
 | 
|---|
| 562 |             {
 | 
|---|
| 563 |                 ptry(j) = fP1(j);
 | 
|---|
| 564 |                 borderflag = 1;
 | 
|---|
| 565 |             }
 | 
|---|
| 566 |             else
 | 
|---|
| 567 |                 if (newcut > fP0(j))
 | 
|---|
| 568 |                 {
 | 
|---|
| 569 |                     ptry(j) = fP0(j);
 | 
|---|
| 570 |                     borderflag = 1;
 | 
|---|
| 571 |                 }
 | 
|---|
| 572 |         }
 | 
|---|
| 573 |     }
 | 
|---|
| 574 | 
 | 
|---|
| 575 |     Real_t faccompare = 0.5;
 | 
|---|
| 576 |     Real_t ytry = 0;
 | 
|---|
| 577 |   
 | 
|---|
| 578 |     switch (borderflag)
 | 
|---|
| 579 |     {
 | 
|---|
| 580 |     case kENoBorder:
 | 
|---|
| 581 |         ytry = FunctionToMinimize(fPsum);
 | 
|---|
| 582 |         break;
 | 
|---|
| 583 | 
 | 
|---|
| 584 |     case kEStrictBorder:
 | 
|---|
| 585 |         ytry = FunctionToMinimize(fPsum) + gsYtryStr;
 | 
|---|
| 586 |         break;
 | 
|---|
| 587 | 
 | 
|---|
| 588 |     case kEContractBorder:
 | 
|---|
| 589 |         ytry = fac == faccompare ? gsYtryCon : gsYtryStr;
 | 
|---|
| 590 |         break;
 | 
|---|
| 591 |     }
 | 
|---|
| 592 | 
 | 
|---|
| 593 |     if (ytry < fYb)
 | 
|---|
| 594 |     {
 | 
|---|
| 595 |         fPb = ptry;
 | 
|---|
| 596 |         fYb = ytry;
 | 
|---|
| 597 |     }
 | 
|---|
| 598 | 
 | 
|---|
| 599 |     const Real_t yflu = ytry + gRandom->Exp(temp);
 | 
|---|
| 600 | 
 | 
|---|
| 601 |     if (yflu >= yhi)
 | 
|---|
| 602 |         return yflu;
 | 
|---|
| 603 | 
 | 
|---|
| 604 |     fY(ihi) = ytry;
 | 
|---|
| 605 |     yhi     = yflu;
 | 
|---|
| 606 |     
 | 
|---|
| 607 |     for(Int_t j=0; j<fNdim; j++)
 | 
|---|
| 608 |     {
 | 
|---|
| 609 |         fPsum(j) += ptry(j)-fP(ihi, j);
 | 
|---|
| 610 |         fP(ihi, j) = ptry(j);
 | 
|---|
| 611 |     }
 | 
|---|
| 612 | 
 | 
|---|
| 613 |     return yflu;
 | 
|---|
| 614 | }
 | 
|---|
| 615 | 
 | 
|---|
| 616 | // ---------------------------------------------------------------------------
 | 
|---|
| 617 | //
 | 
|---|
| 618 | //  Dummy FunctionToMinimize
 | 
|---|
| 619 | //
 | 
|---|
| 620 | //  A class inheriting from MSimulatedAnnealing NEEDS to contain a similiar
 | 
|---|
| 621 | //  
 | 
|---|
| 622 | //  virtual Float_t FunctionToMinimize(const TVector \&)
 | 
|---|
| 623 | //  
 | 
|---|
| 624 | //  The TVector contains the n parameters (dimensions) of the function
 | 
|---|
| 625 | //
 | 
|---|
| 626 | Float_t MSimulatedAnnealing::FunctionToMinimize(const TVector &arr) 
 | 
|---|
| 627 | {
 | 
|---|
| 628 |   return 0.0;
 | 
|---|
| 629 | }
 | 
|---|