30 MnCross MnFunctionCross::operator()(
const std::vector<unsigned int>& par,
const std::vector<double>& pmid,
31 const std::vector<double>& pdir,
double tlr,
unsigned int maxcalls)
const {
39 unsigned int npar = par.size();
40 unsigned int nfcn = 0;
41 const MnMachinePrecision& prec = fState.Precision();
43 double mgr_tlr = 0.5 * tlr;
48 double up = fFCN.Up();
52 unsigned int maxitr = 15;
54 double aminsv = fFval;
55 double aim = aminsv + up;
59 std::vector<double> alsb(3, 0.), flsb(3, 0.);
61 int printLevel = MnPrint::Level();
65 std::cout<<
"MnFunctionCross for parameter "<<par.front()<<
"fmin = " << aminsv
66 <<
" contur value aim = (fmin + up) = " << aim << std::endl;
73 for(
unsigned int i = 0; i < par.size(); i++) {
74 unsigned int kex = par[i];
75 if(fState.Parameter(kex).HasLimits()) {
76 double zmid = pmid[i];
77 double zdir = pdir[i];
78 if(fabs(zdir) < fState.Precision().Eps())
continue;
80 if(zdir > 0. && fState.Parameter(kex).HasUpperLimit()) {
81 double zlim = fState.Parameter(kex).UpperLimit();
82 aulim = std::min(aulim, (zlim-zmid)/zdir);
84 else if(zdir < 0. && fState.Parameter(kex).HasLowerLimit()) {
85 double zlim = fState.Parameter(kex).LowerLimit();
86 aulim = std::min(aulim, (zlim-zmid)/zdir);
92 std::cout<<
"Largest allowed aulim "<< aulim << std::endl;
95 if(aulim < aopt+tla) limset =
true;
98 MnMigrad migrad(fFCN, fState, MnStrategy(std::max(0,
int(fStrategy.Strategy()-1))));
100 for(
unsigned int i = 0; i < npar; i++) {
102 std::cout <<
"MnFunctionCross: Set value for " << par[i] <<
" to " << pmid[i] << std::endl;
104 migrad.SetValue(par[i], pmid[i]);
106 if (printLevel > 1) {
107 std::cout <<
"MnFunctionCross: parameter " << i <<
" set to " << pmid[i] << std::endl;
112 FunctionMinimum min0 = migrad(maxcalls, mgr_tlr);
116 std::cout <<
"MnFunctionCross: after Migrad on n-1 minimum is " << min0 << std::endl;
119 if(min0.HasReachedCallLimit())
120 return MnCross(min0.UserState(), nfcn, MnCross::CrossFcnLimit());
121 if(!min0.IsValid())
return MnCross(fState, nfcn);
122 if(limset ==
true && min0.Fval() < aim)
123 return MnCross(min0.UserState(), nfcn, MnCross::CrossParLimit());
127 flsb[0] = min0.Fval();
128 flsb[0] = std::max(flsb[0], aminsv + 0.1*up);
129 aopt = sqrt(up/(flsb[0]-aminsv)) - 1.;
130 if(fabs(flsb[0] - aim) < tlf)
return MnCross(aopt, min0.UserState(), nfcn);
132 if(aopt > 1.) aopt = 1.;
133 if(aopt < -0.5) aopt = -0.5;
140 std::cout <<
"MnFunctionCross: flsb[0] = " << flsb[0] <<
" aopt = " << aopt << std::endl;
143 for(
unsigned int i = 0; i < npar; i++) {
145 std::cout <<
"MnFunctionCross: Set new value for " << par[i] <<
" from " << pmid[i] <<
" to " << pmid[i] + (aopt)*pdir[i] <<
" aopt = " << aopt << std::endl;
147 migrad.SetValue(par[i], pmid[i] + (aopt)*pdir[i]);
149 if (printLevel > 1) {
150 std::cout <<
"MnFunctionCross: parameter " << i <<
" set to " << pmid[i] + (aopt)*pdir[i] << std::endl;
155 FunctionMinimum min1 = migrad(maxcalls, mgr_tlr);
159 std::cout <<
"MnFunctionCross: after Migrad on n-1 minimum is " << min1 << std::endl;
162 if(min1.HasReachedCallLimit())
163 return MnCross(min1.UserState(), nfcn, MnCross::CrossFcnLimit());
164 if(!min1.IsValid())
return MnCross(fState, nfcn);
165 if(limset ==
true && min1.Fval() < aim)
166 return MnCross(min1.UserState(), nfcn, MnCross::CrossParLimit());
170 flsb[1] = min1.Fval();
171 double dfda = (flsb[1] - flsb[0])/(alsb[1] - alsb[0]);
174 std::cout <<
"aopt = " << aopt <<
" min1Val = " << flsb[1] <<
" dfda = " << dfda << std::endl;
182 std::cout <<
"MnFunctionCross: dfda < 0 - iterate from " << ipt <<
" to max of " << maxitr << std::endl;
186 unsigned int maxlk = maxitr - ipt;
187 for(
unsigned int it = 0; it < maxlk; it++) {
191 aopt = alsb[0] + 0.2*(it+1);
197 for(
unsigned int i = 0; i < npar; i++) {
199 std::cout <<
"MnFunctionCross: Set new value for " << par[i] <<
" to " << pmid[i] + (aopt)*pdir[i] <<
" aopt = " << aopt << std::endl;
201 migrad.SetValue(par[i], pmid[i] + (aopt)*pdir[i]);
202 if (printLevel > 1) {
203 std::cout <<
"MnFunctionCross: parameter " << i <<
" set to " << pmid[i] + (aopt)*pdir[i] << std::endl;
207 min1 = migrad(maxcalls, mgr_tlr);
211 std::cout <<
"MnFunctionCross: after Migrad on n-1 minimum is " << min1 << std::endl;
212 std::cout <<
"nfcn = " << nfcn << std::endl;
215 if(min1.HasReachedCallLimit())
216 return MnCross(min1.UserState(), nfcn, MnCross::CrossFcnLimit());
217 if(!min1.IsValid())
return MnCross(fState, nfcn);
218 if(limset ==
true && min1.Fval() < aim)
219 return MnCross(min1.UserState(), nfcn, MnCross::CrossParLimit());
222 flsb[1] = min1.Fval();
223 dfda = (flsb[1] - flsb[0])/(alsb[1] - alsb[0]);
227 std::cout <<
"aopt = " << aopt <<
" min1Val = " << flsb[1] <<
" dfda = " << dfda << std::endl;
232 if(ipt > maxitr)
return MnCross(fState, nfcn);
239 aopt = alsb[1] + (aim-flsb[1])/dfda;
242 std::cout <<
"MnFunctionCross: dfda > 0 : aopt = " << aopt << std::endl;
245 double fdist = std::min(fabs(aim - flsb[0]), fabs(aim - flsb[1]));
246 double adist = std::min(fabs(aopt - alsb[0]), fabs(aopt - alsb[1]));
248 if(fabs(aopt) > 1.) tla = tlr*fabs(aopt);
249 if(adist < tla && fdist < tlf)
return MnCross(aopt, min1.UserState(), nfcn);
250 if(ipt > maxitr)
return MnCross(fState, nfcn);
251 double bmin = std::min(alsb[0], alsb[1]) - 1.;
252 if(aopt < bmin) aopt = bmin;
253 double bmax = std::max(alsb[0], alsb[1]) + 1.;
254 if(aopt > bmax) aopt = bmax;
262 for(
unsigned int i = 0; i < npar; i++) {
264 std::cout <<
"MnFunctionCross: Set new value for " << par[i] <<
" from " << pmid[i] <<
" to " << pmid[i] + (aopt)*pdir[i] <<
" aopt = " << aopt << std::endl;
266 migrad.SetValue(par[i], pmid[i] + (aopt)*pdir[i]);
267 if (printLevel > 1) {
268 std::cout <<
"MnFunctionCross: parameter " << i <<
" set to " << pmid[i] + (aopt)*pdir[i] << std::endl;
272 FunctionMinimum min2 = migrad(maxcalls, mgr_tlr);
276 std::cout <<
"MnFunctionCross: after Migrad on n-1 minimum is " << min2 << std::endl;
277 std::cout <<
"nfcn = " << nfcn << std::endl;
280 if(min2.HasReachedCallLimit())
281 return MnCross(min2.UserState(), nfcn, MnCross::CrossFcnLimit());
282 if(!min2.IsValid())
return MnCross(fState, nfcn);
283 if(limset ==
true && min2.Fval() < aim)
284 return MnCross(min2.UserState(), nfcn, MnCross::CrossParLimit());
288 flsb[2] = min2.Fval();
292 double ecarmn = fabs(flsb[2] - aim);
294 unsigned int ibest = 2;
295 unsigned int iworst = 0;
296 unsigned int noless = 0;
298 for(
unsigned int i = 0; i < 3; i++) {
299 double ecart = fabs(flsb[i] - aim);
308 if(flsb[i] < aim) noless++;
312 std::cout <<
"MnFunctionCross: have three points : nless < aim = " << noless <<
" ibest = " << ibest <<
" iworst = " << iworst << std::endl;
318 if(noless == 1 || noless == 2)
goto L500;
320 if(noless == 0 && ibest != 2)
return MnCross(fState, nfcn);
323 if(noless == 3 && ibest != 2) {
327 std::cout <<
"MnFunctionCross: all three points below - look again fir positive slope " << std::endl;
334 flsb[iworst] = flsb[2];
335 alsb[iworst] = alsb[2];
336 dfda = (flsb[1] - flsb[0])/(alsb[1] - alsb[0]);
338 std::cout <<
"MnFunctionCross: new straight line using point 1-2 - dfda = " << dfda << std::endl;
346 MnParabola parbol = MnParabolaFactory()(MnParabolaPoint(alsb[0], flsb[0]), MnParabolaPoint(alsb[1], flsb[1]), MnParabolaPoint(alsb[2], flsb[2]));
352 std::cout <<
"MnFunctionCross: parabola fit: iteration " << ipt << std::endl;
355 double coeff1 = parbol.C();
356 double coeff2 = parbol.B();
357 double coeff3 = parbol.A();
358 double determ = coeff2*coeff2 - 4.*coeff3*(coeff1 - aim);
361 std::cout <<
"MnFunctionCross: parabola fit: a = " << coeff3 <<
" b = "
362 << coeff2 <<
" c = " << coeff1 <<
" determ = " << determ << std::endl;
365 if(determ < prec.Eps())
return MnCross(fState, nfcn);
366 double rt = sqrt(determ);
367 double x1 = (-coeff2 + rt)/(2.*coeff3);
368 double x2 = (-coeff2 - rt)/(2.*coeff3);
369 double s1 = coeff2 + 2.*x1*coeff3;
370 double s2 = coeff2 + 2.*x2*coeff3;
373 std::cout <<
"MnFunctionCross: parabola fit: x1 = " << x1 <<
" x2 = "
374 << x2 <<
" s1 = " << s1 <<
" s2 = " << s2 << std::endl;
378 if(s1*s2 > 0.) MN_INFO_MSG(
"MnFunctionCross problem 1");
388 std::cout <<
"MnFunctionCross: parabola fit: aopt = " << aopt <<
" slope = "
389 << slope << std::endl;
394 if(fabs(aopt) > 1.) tla = tlr*fabs(aopt);
397 std::cout <<
"MnFunctionCross: Delta(aopt) = " << fabs(aopt - alsb[ibest]) <<
" tla = "
398 << tla <<
"Delta(F) = " << fabs(flsb[ibest] - aim) <<
" tlf = " << tlf << std::endl;
402 if(fabs(aopt - alsb[ibest]) < tla && fabs(flsb[ibest] - aim) < tlf)
403 return MnCross(aopt, min2.UserState(), nfcn);
410 unsigned int ileft = 3;
411 unsigned int iright = 3;
412 unsigned int iout = 3;
415 ecarmn = fabs(aim-flsb[0]);
416 for(
unsigned int i = 0; i < 3; i++) {
417 double ecart = fabs(flsb[i] - aim);
422 if(ecart > ecarmx) ecarmx = ecart;
424 if(iright == 3) iright = i;
425 else if(flsb[i] > flsb[iright]) iout = i;
430 }
else if(ileft == 3) ileft = i;
431 else if(flsb[i] < flsb[ileft]) iout = i;
439 std::cout <<
"MnFunctionCross: ileft = " << ileft <<
" iright = "
440 << iright <<
" iout = " << iout <<
" ibest = " << ibest << std::endl;
445 if(ecarmx > 10.*fabs(flsb[iout] - aim))
446 aopt = 0.5*(aopt + 0.5*(alsb[iright] + alsb[ileft]));
449 double smalla = 0.1*tla;
450 if(slope*smalla > tlf) smalla = tlf/slope;
451 double aleft = alsb[ileft] + smalla;
452 double aright = alsb[iright] - smalla;
455 if(aopt < aleft) aopt = aleft;
456 if(aopt > aright) aopt = aright;
457 if(aleft > aright) aopt = 0.5*(aleft + aright);
467 for(
unsigned int i = 0; i < npar; i++) {
469 std::cout <<
"MnFunctionCross: Set new value for " << par[i] <<
" from " << pmid[i] <<
" to " << pmid[i] + (aopt)*pdir[i] <<
" aopt = " << aopt << std::endl;
471 migrad.SetValue(par[i], pmid[i] + (aopt)*pdir[i]);
472 if (printLevel > 1) {
473 std::cout <<
"MnFunctionCross: parameter " << i <<
" set to " << pmid[i] + (aopt)*pdir[i] << std::endl;
476 min2 = migrad(maxcalls, mgr_tlr);
479 std::cout <<
"MnFunctionCross: after Migrad on n-1 minimum is " << min2 << std::endl;
480 std::cout <<
"nfcn = " << nfcn << std::endl;
483 if(min2.HasReachedCallLimit())
484 return MnCross(min2.UserState(), nfcn, MnCross::CrossFcnLimit());
485 if(!min2.IsValid())
return MnCross(fState, nfcn);
486 if(limset ==
true && min2.Fval() < aim)
487 return MnCross(min2.UserState(), nfcn, MnCross::CrossParLimit());
492 flsb[iout] = min2.Fval();
494 }
while(ipt < maxitr);
498 return MnCross(fState, nfcn);