Minuit2: Minimum parameter postprocessing

Hey,

I’ve been using Minuit2 to minimize a function. However, something strange seems to happen after the minimizer has converged already.

----------> Iteration 5 FVAL = 1.51459120364 Edm = 1.18106858216e-07 Nfcn = 56 Error matrix change = 0.180018 Parameters : p0 = 2.38513 p1 = 0.174605 ----------> Iteration 6 FVAL = 1.51459120364 Edm = 1.20813613993e-07 Nfcn = 66 Error matrix change = 0 Parameters : p0 = 2.38513 p1 = 0.174605 Minuit2Minimizer : Valid minimum - status = 0 FVAL = 1.51459120364307576 Edm = 1.2081361399259303e-07 Nfcn = 66 par0 = 3.63942e-05 +/- 0.127334 (limited) par1 = 0.174605 +/- 0.00273269 (limited)

So, the parameter 0 that is output in the end differs significantly from its value during the last iteration. I tried to find out what happens in between but couldn’t find any hint to what might go wrong.
The result (and whether or not the output coincides with the parameter value after the last iteration) seems to depend on what I chose as initial guess. However, I don’t see why 1.3 and 2.0 respectively should produce that different results in the above example.

Could someone hint me to what’s going on in between?

Best,

Ben

Hi,

The values should be the same. Which version are you using it ? It could be that in the old version the internal parameter value was printed, so since you have bounds this could explain the difference.
Otherwise I would need your program to understand this issue

Best Regards

Lorenzo

Hi,

thanks for the input!

I reran the fits without constraining its parameters and found the same behavior. (As for the different fit value, I seem to have used a different dataset in preparing the first post.)

----------> Iteration 10 FVAL = 0.856419063148 Edm = 5.72075520085e-07 Nfcn = 77 Error matrix change = 0.28739 Parameters : p0 = 1.20871 p1 = 0.140929 ----------> Iteration 11 FVAL = 0.856419063148 Edm = 5.99546924562e-07 Nfcn = 87 Error matrix change = 0 Parameters : p0 = 1.20871 p1 = 0.140929 Minuit2Minimizer : Valid minimum - status = 0 FVAL = 0.856419063148204818 Edm = 5.99546924562318814e-07 Nfcn = 87 par0 = 79213.7 +/- 0.0624281 par1 = 0.140929 +/- 0.0025865

I’m running ROOT 5.34/14 (v5-34-14), so not exactly an old version.

As for the code, there shouldn’t be anything special there,

Minuit2Minimizer mnmr(kMigrad); mnmr.SetFunction(fun); mnmr.SetMaxFunctionCalls(1000000); mnmr.SetMaxIterations(100000); mnmr.SetTolerance(0.001); mnmr.SetPrintLevel(3);

Then I’m assigning the single parameters either with or without lower bounds imposed, e.g. via

inside a loop over the parameters indexed by n. Next thing is to call

which is what produces the output in the beginning of the post. The fun-object passed to SetFunction is a customized class implementing the respective ROOT interface,

class MetricBase : public ROOT::Minuit2::FCNGradientBase, public ROOT::Math::IBaseFunctionMultiDim

which I think should work correctly, since the minimization proceeds successfully during the iterations.
Is it something in the way I set up and call the minimizer?

Thanks very much!
Ben

Hi,

while trying to get things to work I stumbled upon reproducible segfaults in the Minuit2 code. I’m not sure whether these two things are related.

When instantiating Minuit2MInimizer with kCombined instead of kMigrad, from time to time the minimizer will fail in using Migrad, try to fall back to Simplex first,

Info in <Minuit2>: VariableMetricBuilder: no improvement in line search Info in <Minuit2>: VariableMetricBuilder: iterations finish without convergence. Info in <Minuit2>: VariableMetricBuilder : edm = 4.40902e+07 Info in <Minuit2>: requested : edmval = 2e-06 Info in <Minuit2>: VariableMetricBuilder: FunctionMinimum is invalid after second try Info in <Minuit2>: CombinedMinimumBuilder: migrad method fails, will try with simplex method first.

and segfault afterwards,

#5 0x00007f47564d319b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) () from /usr/lib/libstdc++.so.6 #6 0x00007f475831ef3b in ROOT::Minuit2::MnSeedGenerator::operator()(ROOT::Minuit2::MnFcn const&, ROOT::Minuit2::GradientCalculator const&, ROOT::Minuit2::MnUserParameterState const&, ROOT::Minuit2::MnStrategy const&) const () from /home/.../root/lib/libMinuit2.so #7 0x00007f47582d25a2 in ROOT::Minuit2::CombinedMinimumBuilder::Minimum(ROOT::Minuit2::MnFcn const&, ROOT::Minuit2::GradientCalculator const&, ROOT::Minuit2::MinimumSeed const&, ROOT::Minuit2::MnStrategy const&, unsigned int, double) const () from /home/.../root/lib/libMinuit2.so #8 0x00007f4758331205 in ROOT::Minuit2::ModularFunctionMinimizer::Minimize(ROOT::Minuit2::MnFcn const&, ROOT::Minuit2::GradientCalculator const&, ROOT::Minuit2::MinimumSeed const&, ROOT::Minuit2::MnStrategy const&, unsigned int, double) const () from /home/.../root/lib/libMinuit2.so #9 0x00007f475832f5cc in ROOT::Minuit2::ModularFunctionMinimizer::Minimize(ROOT::Minuit2::FCNBase const&, ROOT::Minuit2::MnUserParameterState const&, ROOT::Minuit2::MnStrategy const&, unsigned int, double) const () from /home/.../root/lib/libMinuit2.so #10 0x00007f47582ee41d in ROOT::Minuit2::Minuit2Minimizer::Minimize() () from /home/.../root/lib/libMinuit2.so

In MnSeedGenerator::() there is a function call to the user-supplied function. However, nothing special happens here except that the user-function is computed for one parameter-set.
Funny enough, both kMigrad and kSimplex work fine (with the same initial guesses and everything) and it’s just in using kCombined that the minimizer segfaults when switching from one to the other. I do not at all understand where there would be some string operation involved anyway.

Any ideas?

Best,

Ben

Hi,

so I’m avoiding kCombined and using kMigrad now which, as said before, circumvents the segfaults. However, the original problem still persists.

While trying to localize where the parameters actually acquire their nonsensical value, I included - just to get started - some parameter output in Minuit2Minimizer.cxx, line 406, after all the necessary work for the minimization has been finished and it’s just output that’s left to be done.
My code now reads

[code] std::cout << "\t int2ext p0: " << fMinimum->UserState().Int2ext(0, fMinimum->States().back().Vec()(0)) << std::endl;
std::cout << "\t p0: " << fMinimum->States().back().Vec()(0) << std::endl;
std::cout << "\t FCN value: " << fMinimum->States().back().Fval() << std::endl;

fState = fMinimum->UserState();
bool ok = ExamineMinimum(*fMinimum);
[/code]

which should be exactly the same thing as what happens in ExamineMinimum.
If the fit is not limited, I indeed recover the correct value of p0,

[code] int2ext p0: 0.602549
p0: 0.602549
FCN value: 0.839383
Number of iterations 8

[…]

----------> Iteration 7
FVAL = 0.839382619981 Edm = 9.99641890615e-10 Nfcn = 63
Error matrix change = 0
Parameters : p0 = 0.602549 p1 = 0.140805
[/code]

and since the fit was not limited, the transformation doesn’t do anything.
Now, if I impose p0 > 0.0, I’m not even able to grab the parameter value after the last iteration correctly,

[code] int2ext p0: 52009.4
p0: 1.25226
FCN value: 0.839383
Number of iterations 8

[…]

----------> Iteration 7
FVAL = 0.839382621804 Edm = 2.82273972718e-09 Nfcn = 58
Error matrix change = 0
Parameters : p0 = 0.602548 p1 = 0.140805
[/code]

although my output line should be precisely what produces the original Minuit output immediately after my code.

Where am I being stupid here?

Ben

Hi,

If I have understood you well , you have 2 problems:

  • using the combined minimizer you have a segfault. I would probably need your code to debug. Is it possible that you attach or send directly to me ?

  • you see different parameter values printed by Minuit. This does not happen when there are no limits (i.e. internal and external parameters are the same). Again I would need also the code here to understand it better

Best Regards

Lorenzo

Hi,

the segfault doesn’t worry me too much since using Minuit with just kMigrad converges, so I’m using this method now.

However, the problem outlined in post #1 persist, namely that something happens to the parameter value between the final iteration and its being printed. This happens irrespectively of whether I perform a limited or unlimited minimization.
As far as I can tell, Hesse() is supposed to change the parameter values only if it happens to stumble across a smaller function value in the course of its calculations. This is definitely not the case here (the function value with the parameter given in the final state is order of magnitudes larger).

Now, I was trying to localize in exactly what part of the code the final iteration step’s parameter values are changed to the nonsensical value that’s output by PrintResults(). Therefore I injected some code outputting the parameter state of the various objects available after the minimization has finished.
And it is here already that I came across a serious puzzle: I think the first code snippet from the last post (which I inserted into l. 405) should print the very same value as the code in ExamineMinimum() (l. 431). However, the output is different. In between, nothing related to my code wrapping around the minimizer is called.

Do I misunderstand something in believing that my code snippet should indeed print the very same thing as is printed immediately afterwards?

For the general problem however, I’m still struggling to produce a minimal working example, which I haven’t succeeded in so far because it’s all part of a fairly big codebase.

Best,
Ben

Hi,

it would be nice however to understand it, so if there is a bug it could be fixed. However I need to reproduce it.

For the second problem, if I have understood well you have a different printout between

std::cout << "\t int2ext p0: " << fMinimum->UserState().Int2ext(0, fMinimum->States().back().Vec()(0)) << std::endl;

inserted before bool ok = ExamineMinimum(*fMinimum);

and the code printed in ExamineMinimum.

This is not possible. Nothing happenes between. If it is happen, something is wrong or corrupted somewhere…
I need the code to reproduce then

Lorenzo

I finally managed to put that standalone version together.
However, while at it we found the issue in the code which was a memory overflow caused by not specializing the Clone()-function correctly in the derived function classes. Hence presumably everything from the segfault to strange values should be cured.

Apologies for wasting your time.
Thanks very much!
Ben