45 ClassImp(TMVA::SimulatedAnnealing);
50 TMVA::SimulatedAnnealing::SimulatedAnnealing( IFitterTarget& target,
const std::vector<Interval*>& ranges )
51 : fKernelTemperature (kIncreasingAdaptive),
52 fFitterTarget ( target ),
53 fRandom ( new TRandom3(100) ),
56 fInitialTemperature ( 1000 ),
57 fMinTemperature ( 0 ),
59 fTemperatureScale ( 0.06 ),
60 fAdaptiveSpeed ( 1.0 ),
61 fTemperatureAdaptiveStep( 0.0 ),
62 fUseDefaultScale ( kFALSE ),
63 fUseDefaultTemperature ( kFALSE ),
64 fLogger( new MsgLogger(
"SimulatedAnnealing") ),
67 fKernelTemperature = kIncreasingAdaptive;
73 void TMVA::SimulatedAnnealing::SetOptions( Int_t maxCalls,
74 Double_t initialTemperature,
75 Double_t minTemperature,
77 TString kernelTemperatureS,
78 Double_t temperatureScale,
79 Double_t adaptiveSpeed,
80 Double_t temperatureAdaptiveStep,
81 Bool_t useDefaultScale,
82 Bool_t useDefaultTemperature)
85 fInitialTemperature = initialTemperature;
86 fMinTemperature = minTemperature;
89 if (kernelTemperatureS ==
"IncreasingAdaptive") {
90 fKernelTemperature = kIncreasingAdaptive;
91 Log() << kINFO <<
"Using increasing adaptive algorithm" << Endl;
93 else if (kernelTemperatureS ==
"DecreasingAdaptive") {
94 fKernelTemperature = kDecreasingAdaptive;
95 Log() << kINFO <<
"Using decreasing adaptive algorithm" << Endl;
97 else if (kernelTemperatureS ==
"Sqrt") {
98 fKernelTemperature = kSqrt;
99 Log() << kINFO <<
"Using \"Sqrt\" algorithm" << Endl;
101 else if (kernelTemperatureS ==
"Homo") {
102 fKernelTemperature = kHomo;
103 Log() << kINFO <<
"Using \"Homo\" algorithm" << Endl;
105 else if (kernelTemperatureS ==
"Log") {
106 fKernelTemperature = kLog;
107 Log() << kINFO <<
"Using \"Log\" algorithm" << Endl;
109 else if (kernelTemperatureS ==
"Sin") {
110 fKernelTemperature = kSin;
111 Log() << kINFO <<
"Using \"Sin\" algorithm" << Endl;
114 fTemperatureScale = temperatureScale;
115 fAdaptiveSpeed = adaptiveSpeed;
116 fTemperatureAdaptiveStep = temperatureAdaptiveStep;
118 fUseDefaultScale = useDefaultScale;
119 fUseDefaultTemperature = useDefaultTemperature;
125 TMVA::SimulatedAnnealing::~SimulatedAnnealing()
132 void TMVA::SimulatedAnnealing::FillWithRandomValues( std::vector<Double_t>& parameters )
134 for (UInt_t rIter = 0; rIter < parameters.size(); rIter++) {
135 parameters[rIter] = fRandom->Uniform(0.0,1.0)*(fRanges[rIter]->GetMax() - fRanges[rIter]->GetMin()) + fRanges[rIter]->GetMin();
142 void TMVA::SimulatedAnnealing::ReWriteParameters( std::vector<Double_t>& from, std::vector<Double_t>& to)
144 for (UInt_t rIter = 0; rIter < from.size(); rIter++) to[rIter] = from[rIter];
150 void TMVA::SimulatedAnnealing::GenerateNeighbour( std::vector<Double_t>& parameters, std::vector<Double_t>& oldParameters,
151 Double_t currentTemperature )
153 ReWriteParameters( parameters, oldParameters );
155 for (UInt_t rIter=0;rIter<parameters.size();rIter++) {
156 Double_t uni,distribution,sign;
158 uni = fRandom->Uniform(0.0,1.0);
159 sign = (uni - 0.5 >= 0.0) ? (1.0) : (-1.0);
160 distribution = currentTemperature * (TMath::Power(1.0 + 1.0/currentTemperature, TMath::Abs(2.0*uni - 1.0)) -1.0)*sign;
161 parameters[rIter] = oldParameters[rIter] + (fRanges[rIter]->GetMax()-fRanges[rIter]->GetMin())*0.1*distribution;
163 while (parameters[rIter] < fRanges[rIter]->GetMin() || parameters[rIter] > fRanges[rIter]->GetMax() );
169 std::vector<Double_t> TMVA::SimulatedAnnealing::GenerateNeighbour( std::vector<Double_t>& parameters, Double_t currentTemperature )
171 std::vector<Double_t> newParameters( fRanges.size() );
173 for (UInt_t rIter=0; rIter<parameters.size(); rIter++) {
174 Double_t uni,distribution,sign;
176 uni = fRandom->Uniform(0.0,1.0);
177 sign = (uni - 0.5 >= 0.0) ? (1.0) : (-1.0);
178 distribution = currentTemperature * (TMath::Power(1.0 + 1.0/currentTemperature, TMath::Abs(2.0*uni - 1.0)) -1.0)*sign;
179 newParameters[rIter] = parameters[rIter] + (fRanges[rIter]->GetMax()-fRanges[rIter]->GetMin())*0.1*distribution;
181 while (newParameters[rIter] < fRanges[rIter]->GetMin() || newParameters[rIter] > fRanges[rIter]->GetMax() );
184 return newParameters;
190 void TMVA::SimulatedAnnealing::GenerateNewTemperature( Double_t& currentTemperature, Int_t Iter )
192 if (fKernelTemperature == kSqrt) {
193 currentTemperature = fInitialTemperature/(Double_t)TMath::Sqrt(Iter+2) * fTemperatureScale;
195 else if (fKernelTemperature == kLog) {
196 currentTemperature = fInitialTemperature/(Double_t)TMath::Log(Iter+2) * fTemperatureScale;
198 else if (fKernelTemperature == kHomo) {
199 currentTemperature = fInitialTemperature/(Double_t)(Iter+2) * fTemperatureScale;
201 else if (fKernelTemperature == kSin) {
202 currentTemperature = (TMath::Sin( (Double_t)Iter / fTemperatureScale ) + 1.0 )/ (Double_t)(Iter+1.0) * fInitialTemperature + fEps;
204 else if (fKernelTemperature == kGeo) {
205 currentTemperature = currentTemperature*fTemperatureScale;
207 else if (fKernelTemperature == kIncreasingAdaptive) {
208 currentTemperature = fMinTemperature + fTemperatureScale*TMath::Log(1.0+fProgress*fAdaptiveSpeed);
210 else if (fKernelTemperature == kDecreasingAdaptive) {
211 currentTemperature = currentTemperature*fTemperatureScale;
213 else Log() << kFATAL <<
"No such kernel!" << Endl;
219 Bool_t TMVA::SimulatedAnnealing::ShouldGoIn( Double_t currentFit, Double_t localFit, Double_t currentTemperature )
221 if (currentTemperature < fEps)
return kFALSE;
222 Double_t lim = TMath::Exp( -TMath::Abs( currentFit - localFit ) / currentTemperature );
223 Double_t prob = fRandom->Uniform(0.0, 1.0);
224 return (prob < lim) ? kTRUE : kFALSE;
230 void TMVA::SimulatedAnnealing::SetDefaultScale()
232 if (fKernelTemperature == kSqrt) fTemperatureScale = 1.0;
233 else if (fKernelTemperature == kLog) fTemperatureScale = 1.0;
234 else if (fKernelTemperature == kHomo) fTemperatureScale = 1.0;
235 else if (fKernelTemperature == kSin) fTemperatureScale = 20.0;
236 else if (fKernelTemperature == kGeo) fTemperatureScale = 0.99997;
237 else if (fKernelTemperature == kDecreasingAdaptive) {
238 fTemperatureScale = 1.0;
239 while (TMath::Abs(TMath::Power(fTemperatureScale,fMaxCalls) * fInitialTemperature - fMinTemperature) >
240 TMath::Abs(TMath::Power(fTemperatureScale-0.000001,fMaxCalls) * fInitialTemperature - fMinTemperature)) {
241 fTemperatureScale -= 0.000001;
244 else if (fKernelTemperature == kIncreasingAdaptive) fTemperatureScale = 0.15*( 1.0 / (Double_t)(fRanges.size() ) );
245 else Log() << kFATAL <<
"No such kernel!" << Endl;
251 Double_t TMVA::SimulatedAnnealing::GenerateMaxTemperature( std::vector<Double_t>& parameters )
255 Double_t t, dT, cold, delta, deltaY, y, yNew, yBest, yOld;
256 std::vector<Double_t> x( fRanges.size() ), xNew( fRanges.size() ), xBest( fRanges.size() ), xOld( fRanges.size() );
259 dT = fTemperatureAdaptiveStep;
260 for (UInt_t rIter = 0; rIter < x.size(); rIter++)
261 x[rIter] = ( fRanges[rIter]->GetMax() + fRanges[rIter]->GetMin() ) / 2.0;
263 for (Int_t i=0; i<fMaxCalls/50; i++) {
264 if ((i>0) && (deltaY>0.0)) {
269 x = xOld = GenerateNeighbour(x,t);
270 y = yOld = fFitterTarget.EstimatorFunction( xOld );
272 for ( Int_t k=0; (k<30) && (equilibrium<=12); k++ ) {
273 xNew = GenerateNeighbour(x,t);
275 yNew = fFitterTarget.EstimatorFunction( xNew );
284 delta = TMath::Abs( deltaY );
285 if (y != 0.0) delta /= y;
286 else if (yNew != 0.0) delta /= y;
289 if (delta < 0.1) equilibrium++;
290 else equilibrium = 0;
296 yNew = fFitterTarget.EstimatorFunction( xNew );
297 deltaY = yNew - yOld;
298 if ( (deltaY < 0.0 )&&( yNew < yBest)) {
303 if ((stopper) && (deltaY >= (100.0 * cold)))
break;
312 Double_t TMVA::SimulatedAnnealing::Minimize( std::vector<Double_t>& parameters )
314 std::vector<Double_t> bestParameters(fRanges.size());
315 std::vector<Double_t> oldParameters (fRanges.size());
317 Double_t currentTemperature, bestFit, currentFit;
318 Int_t optimizeCalls, generalCalls, equals;
322 if (fUseDefaultTemperature) {
323 if (fKernelTemperature == kIncreasingAdaptive) {
324 fMinTemperature = currentTemperature = 1e-06;
325 FillWithRandomValues( parameters );
327 else fInitialTemperature = currentTemperature = GenerateMaxTemperature( parameters );
330 if (fKernelTemperature == kIncreasingAdaptive)
331 currentTemperature = fMinTemperature;
333 currentTemperature = fInitialTemperature;
334 FillWithRandomValues( parameters );
337 if (fUseDefaultScale) SetDefaultScale();
340 <<
"Temperatur scale = " << fTemperatureScale
341 <<
", current temperature = " << currentTemperature << Endl;
343 bestParameters = parameters;
344 bestFit = currentFit = fFitterTarget.EstimatorFunction( bestParameters );
346 optimizeCalls = fMaxCalls/100;
347 generalCalls = fMaxCalls - optimizeCalls;
350 Timer timer( fMaxCalls, fLogger->GetSource().c_str() );
352 for (Int_t sample = 0; sample < generalCalls; sample++) {
353 if (fIPyCurrentIter) *fIPyCurrentIter = sample;
354 if (fExitFromTraining && *fExitFromTraining)
break;
355 GenerateNeighbour( parameters, oldParameters, currentTemperature );
356 Double_t localFit = fFitterTarget.EstimatorFunction( parameters );
358 if (localFit < currentFit || TMath::Abs(currentFit-localFit) < fEps) {
359 if (TMath::Abs(currentFit-localFit) < fEps) {
369 currentFit = localFit;
371 if (currentFit < bestFit) {
372 ReWriteParameters( parameters, bestParameters );
373 bestFit = currentFit;
377 if (!ShouldGoIn(localFit, currentFit, currentTemperature))
378 ReWriteParameters( oldParameters, parameters );
380 currentFit = localFit;
386 GenerateNewTemperature( currentTemperature, sample );
388 if ((fMaxCalls<100) || sample%Int_t(fMaxCalls/100.0) == 0) timer.DrawProgressBar( sample );
392 Log() << kINFO <<
"Elapsed time: " << timer.GetElapsedTime()
397 Double_t startingTemperature = fMinTemperature*(fRanges.size())*2.0;
398 currentTemperature = startingTemperature;
401 for (Int_t sample=0;sample<optimizeCalls;sample++) {
402 GenerateNeighbour( parameters, oldParameters, currentTemperature );
403 Double_t localFit = fFitterTarget.EstimatorFunction( parameters );
405 if (localFit < currentFit) {
406 currentFit = localFit;
409 if (currentFit < bestFit) {
410 ReWriteParameters( parameters, bestParameters );
411 bestFit = currentFit;
414 else ReWriteParameters( oldParameters, parameters );
416 currentTemperature-=(startingTemperature - fEps)/optimizeCalls;
419 ReWriteParameters( bestParameters, parameters );