Skip to content

Commit 614d4dc

Browse files
committed
[Minuit2] Consistently use MnFcnCaller
1 parent 6e77e0b commit 614d4dc

14 files changed

+87
-122
lines changed

math/minuit2/inc/Minuit2/FumiliBuilder.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "Minuit2/MinimumBuilder.h"
1414
#include "Minuit2/VariableMetricEDMEstimator.h"
1515
#include "Minuit2/FumiliErrorUpdator.h"
16-
#include "Minuit2/MnFcn.h"
1716
#include "Minuit2/FunctionMinimum.h"
1817

1918
#include <vector>
@@ -22,6 +21,8 @@ namespace ROOT {
2221

2322
namespace Minuit2 {
2423

24+
class MnFcn;
25+
2526
/**
2627
2728
Builds the FunctionMinimum using the Fumili method.

math/minuit2/inc/Minuit2/MnFcn.h

+16-9
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ class MnFcn {
4040
{
4141
}
4242

43-
inline double operator()(const MnAlgebraicVector &v) const
44-
{
45-
return fTransform ? CallWithDoingTrafo(v) : CallWithoutDoingTrafo(v);
46-
}
47-
4843
unsigned int NumOfCalls() const { return fNumCall; }
4944

5045
double ErrorDef() const
@@ -61,19 +56,31 @@ class MnFcn {
6156

6257
// Access the parameter transformations.
6358
// For internal use in the Minuit2 implementation.
64-
const MnUserTransformation *transform() const { return fTransform; }
59+
const MnUserTransformation *Trafo() const { return fTransform; }
6560

6661
double CallWithTransformedParams(std::vector<double> const &vpar) const;
67-
68-
private:
6962
double CallWithoutDoingTrafo(const MnAlgebraicVector &) const;
70-
double CallWithDoingTrafo(const MnAlgebraicVector &) const;
7163

64+
private:
7265
const FCNBase &fFCN;
7366
mutable int fNumCall;
7467
const MnUserTransformation *fTransform = nullptr;
7568
};
7669

70+
// Helper class to call the MnFcn, caching the transformed parameters if necessary.
71+
class MnFcnCaller {
72+
public:
73+
MnFcnCaller(const MnFcn &mfcn);
74+
75+
double operator()(const MnAlgebraicVector &v);
76+
77+
private:
78+
MnFcn const &fMfcn;
79+
bool fDoInt2ext = false;
80+
std::vector<double> fLastInput;
81+
std::vector<double> fVpar;
82+
};
83+
7784
} // namespace Minuit2
7885

7986
} // namespace ROOT

math/minuit2/src/FumiliBuilder.cxx

+5-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "Minuit2/FumiliBuilder.h"
1111
#include "Minuit2/FumiliStandardMaximumLikelihoodFCN.h"
1212
#include "Minuit2/GradientCalculator.h"
13-
//#include "Minuit2/Numerical2PGradientCalculator.h"
1413
#include "Minuit2/MinimumState.h"
1514
#include "Minuit2/MinimumError.h"
1615
#include "Minuit2/FunctionGradient.h"
@@ -237,6 +236,8 @@ FunctionMinimum FumiliBuilder::Minimum(const MnFcn &fcn, const GradientCalculato
237236

238237
double lambda = (doLineSearch) ? 0.001 : 0;
239238

239+
MnFcnCaller fcnCaller{fcn};
240+
240241
do {
241242

242243
// const MinimumState& s0 = result.back();
@@ -269,7 +270,7 @@ FunctionMinimum FumiliBuilder::Minimum(const MnFcn &fcn, const GradientCalculato
269270
// take a full step
270271

271272
//evaluate function only if doing a line search
272-
double fval2 = (doLineSearch) ? fcn(s0.Vec() + step) : 0;
273+
double fval2 = (doLineSearch) ? fcnCaller(s0.Vec() + step) : 0;
273274
MinimumParameters p(s0.Vec() + step, fval2);
274275

275276
// check that taking the full step does not deteriorate minimum
@@ -324,7 +325,7 @@ FunctionMinimum FumiliBuilder::Minimum(const MnFcn &fcn, const GradientCalculato
324325

325326
// if the proposed point (newton step) is inside the trust region radius accept it
326327
if (norm <= delta) {
327-
p = MinimumParameters(s0.Vec() + step, fcn(s0.Vec() + step));
328+
p = MinimumParameters(s0.Vec() + step, fcnCaller(s0.Vec() + step));
328329
print.Debug("Accept full Newton step - it is inside TR ",delta);
329330
} else {
330331
//step = - (delta/norm) * step;
@@ -403,7 +404,7 @@ FunctionMinimum FumiliBuilder::Minimum(const MnFcn &fcn, const GradientCalculato
403404
}
404405
print.Debug("New accepted step is ",step);
405406

406-
p = MinimumParameters(s0.Vec() + step, fcn(s0.Vec() + step));
407+
p = MinimumParameters(s0.Vec() + step, fcnCaller(s0.Vec() + step));
407408
norm = delta;
408409
gdel = inner_product(step, s0.Gradient().Grad());
409410
}

math/minuit2/src/FumiliMinimizer.cxx

+3-6
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "Minuit2/MnUserParameters.h"
2222
#include "Minuit2/MnUserTransformation.h"
2323
#include "Minuit2/FumiliFCNBase.h"
24-
#include "Minuit2/FCNBase.h"
24+
#include "Minuit2/MnFcn.h"
2525
#include "Minuit2/MnStrategy.h"
2626
#include "Minuit2/MnPrint.h"
2727

@@ -63,11 +63,8 @@ FunctionMinimum FumiliMinimizer::Minimize(const FCNBase &fcn, const MnUserParame
6363
}
6464

6565
// compute initial values;
66-
const unsigned int n = st.VariableParameters();
67-
MnAlgebraicVector x(n);
68-
for (unsigned int i = 0; i < n; i++)
69-
x(i) = st.IntParameters()[i];
70-
double fcnmin = mfcn(x);
66+
MnAlgebraicVector x{st.IntParameters()};
67+
double fcnmin = MnFcnCaller{mfcn}(x);
7168
MinimumParameters pa(x, fcnmin);
7269
FunctionGradient grad = fgc(pa);
7370
FumiliErrorUpdator errUpdator;

math/minuit2/src/HessianGradientCalculator.cxx

+4-2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ HessianGradientCalculator::DeltaGradient(const MinimumParameters &par, const Fun
8484
unsigned int startElementIndex = mpiproc.StartElementIndex();
8585
unsigned int endElementIndex = mpiproc.EndElementIndex();
8686

87+
MnFcnCaller fcnCaller{fFcn};
88+
8789
for (unsigned int i = startElementIndex; i < endElementIndex; i++) {
8890
double xtf = x(i);
8991
double dmin = 4. * Precision().Eps2() * (xtf + Precision().Eps2());
@@ -100,9 +102,9 @@ HessianGradientCalculator::DeltaGradient(const MinimumParameters &par, const Fun
100102
double grdnew = 0.;
101103
for (unsigned int j = 0; j < Ncycle(); j++) {
102104
x(i) = xtf + d;
103-
double fs1 = Fcn()(x);
105+
double fs1 = fcnCaller(x);
104106
x(i) = xtf - d;
105-
double fs2 = Fcn()(x);
107+
double fs2 = fcnCaller(x);
106108
x(i) = xtf;
107109
// double sag = 0.5*(fs1+fs2-2.*fcnmin);
108110
// LM: should I calculate also here second derivatives ???

math/minuit2/src/MnFcn.cxx

+32-17
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,6 @@ double MnFcn::CallWithoutDoingTrafo(const MnAlgebraicVector &v) const
2121
return fFCN(std::vector<double>{v.Data(), v.Data() + v.size()});
2222
}
2323

24-
double MnFcn::CallWithDoingTrafo(const MnAlgebraicVector &v) const
25-
{
26-
// calling fTransform() like here was not thread safe because it was using a cached vector
27-
// return Fcn()( fTransform(v) );
28-
// make a new thread-safe implementation creating a vector each time
29-
// a bit slower few% in stressFit and 10% in Rosenbrock function but it is negligible in big fits
30-
31-
// get first initial values of parameter (in case some one is fixed)
32-
std::vector<double> vpar(fTransform->InitialParValues().begin(), fTransform->InitialParValues().end());
33-
34-
for (unsigned int i = 0; i < v.size(); i++) {
35-
vpar[fTransform->ExtOfInt(i)] = fTransform->Int2ext(i, v(i));
36-
}
37-
38-
return CallWithTransformedParams(vpar);
39-
}
40-
4124
// Calling the underlying function with the transformed parameters.
4225
// For internal use in the Minuit2 implementation.
4326
double MnFcn::CallWithTransformedParams(std::vector<double> const &vpar) const
@@ -48,6 +31,38 @@ double MnFcn::CallWithTransformedParams(std::vector<double> const &vpar) const
4831
return Fcn()(vpar);
4932
}
5033

34+
MnFcnCaller::MnFcnCaller(const MnFcn &mfcn) : fMfcn{mfcn}, fDoInt2ext{static_cast<bool>(mfcn.Trafo())}
35+
{
36+
if (!fDoInt2ext)
37+
return;
38+
39+
MnUserTransformation const &transform = *fMfcn.Trafo();
40+
41+
// get first initial values of parameter (in case some one is fixed)
42+
fVpar.assign(transform.InitialParValues().begin(), transform.InitialParValues().end());
43+
}
44+
45+
double MnFcnCaller::operator()(const MnAlgebraicVector &v)
46+
{
47+
if (!fDoInt2ext)
48+
return fMfcn.CallWithoutDoingTrafo(v);
49+
50+
MnUserTransformation const &transform = *fMfcn.Trafo();
51+
52+
bool firstCall = fLastInput.size() != v.size();
53+
54+
fLastInput.resize(v.size());
55+
56+
for (unsigned int i = 0; i < v.size(); i++) {
57+
if (firstCall || fLastInput[i] != v(i)) {
58+
fVpar[transform.ExtOfInt(i)] = transform.Int2ext(i, v(i));
59+
fLastInput[i] = v(i);
60+
}
61+
}
62+
63+
return fMfcn.CallWithTransformedParams(fVpar);
64+
}
65+
5166
} // namespace Minuit2
5267

5368
} // namespace ROOT

math/minuit2/src/MnFcnCaller.h

-55
This file was deleted.

math/minuit2/src/MnHesse.cxx

+4-6
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#include "Minuit2/MnPrint.h"
2323

2424
#include "./MPIProcess.h"
25-
#include "./MnFcnCaller.h"
25+
#include "Minuit2/MnFcn.h"
2626

2727
#include "Math/Util.h"
2828

@@ -49,11 +49,9 @@ MnHesse::operator()(const FCNBase &fcn, const MnUserParameterState &state, unsig
4949
// interface from MnUserParameterState
5050
// create a new Minimum state and use that interface
5151
unsigned int n = state.VariableParameters();
52-
MnFcn mfcn{fcn, state.Trafo(), state.NFcn()};
53-
MnAlgebraicVector x(n);
54-
for (unsigned int i = 0; i < n; i++)
55-
x(i) = state.IntParameters()[i];
56-
double amin = mfcn(x);
52+
MnFcn mfcn{fcn, state.Trafo(), static_cast<int>(state.NFcn())};
53+
MnAlgebraicVector x(state.IntParameters());
54+
double amin = MnFcnCaller{mfcn}(x);
5755
MinimumParameters par(x, amin);
5856
// check if we can use analytical gradient
5957
if (fcn.HasGradient()) {

math/minuit2/src/MnLineSearch.cxx

+5-3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ MnParabolaPoint MnLineSearch::operator()(const MnFcn &fcn, const MinimumParamete
6969
// start as in Fortran from 1 and count all the time we evaluate the function
7070
int niter = 1;
7171

72+
MnFcnCaller fcnCaller{fcn};
73+
7274
for (unsigned int i = 0; i < step.size(); i++) {
7375
if (step(i) == 0)
7476
continue;
@@ -83,7 +85,7 @@ MnParabolaPoint MnLineSearch::operator()(const MnFcn &fcn, const MinimumParamete
8385
slamin *= prec.Eps2();
8486

8587
double f0 = st.Fval();
86-
double f1 = fcn(st.Vec() + step);
88+
double f1 = fcnCaller(st.Vec() + step);
8789
niter++;
8890
double fvmin = st.Fval();
8991
double xvmin = 0.;
@@ -171,7 +173,7 @@ MnParabolaPoint MnLineSearch::operator()(const MnFcn &fcn, const MinimumParamete
171173
// MnAlgebraicVector tmp = step;
172174
// tmp *= slam;
173175
// f2 = fcn(st.Vec()+tmp);
174-
f2 = fcn(st.Vec() + slam * step);
176+
f2 = fcnCaller(st.Vec() + slam * step);
175177

176178
niter++; // do as in Minuit (count all func evalu)
177179

@@ -263,7 +265,7 @@ MnParabolaPoint MnLineSearch::operator()(const MnFcn &fcn, const MinimumParamete
263265
// take the step
264266
// MnAlgebraicVector tmp = step;
265267
// tmp *= slam;
266-
f3 = fcn(st.Vec() + slam * step);
268+
f3 = fcnCaller(st.Vec() + slam * step);
267269
print.Trace("f3", f3, "f3-p(2-0).Y()", f3 - p2.Y(), f3 - p1.Y(), f3 - p0.Y());
268270
// if latest point worse than all three previous, cut step
269271
if (f3 > p0.Y() && f3 > p1.Y() && f3 > p2.Y()) {

math/minuit2/src/MnSeedGenerator.cxx

+3-5
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ operator()(const MnFcn &fcn, const GradientCalculator &gc, const MnUserParameter
6969
// the line search.
7070
auto timingScope = std::make_unique<ROOT::Math::Util::TimingScope>([&print](std::string const &s) { print.Info(s); },
7171
"Evaluated function and gradient in");
72-
MinimumParameters pa(x, fcn(x));
72+
MinimumParameters pa(x, MnFcnCaller{fcn}(x));
7373
FunctionGradient dgrad = gc(pa);
7474
timingScope.reset();
7575

@@ -155,10 +155,8 @@ MnSeedGenerator::CallWithAnalyticalGradientCalculator(const MnFcn &fcn, const An
155155
const MnMachinePrecision &prec = st.Precision();
156156

157157
// initial starting values
158-
MnAlgebraicVector x(n);
159-
for (unsigned int i = 0; i < n; i++)
160-
x(i) = st.IntParameters()[i];
161-
double fcnmin = fcn(x);
158+
MnAlgebraicVector x(st.IntParameters());
159+
double fcnmin = MnFcnCaller{fcn}(x);
162160
MinimumParameters pa(x, fcnmin);
163161

164162
// compute function gradient

math/minuit2/src/Numerical2PGradientCalculator.cxx

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "Minuit2/MnPrint.h"
1919

2020
#include "./MPIProcess.h"
21-
#include "./MnFcnCaller.h"
2221

2322
#ifdef _OPENMP
2423
#include <omp.h>

math/minuit2/src/ParametricFunction.cxx

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ std::vector<double> ParametricFunction::GetGradient(std::vector<double> const &x
3636

3737
Numerical2PGradientCalculator gc(mfcn, st.Trafo(), strategy);
3838
MnAlgebraicVector xVec{x};
39-
FunctionGradient g = gc(MinimumParameters{xVec, mfcn(xVec)});
39+
FunctionGradient g = gc(MinimumParameters{xVec, MnFcnCaller{mfcn}(xVec)});
4040
const MnAlgebraicVector &grad = g.Vec();
4141
assert(grad.size() == x.size());
4242
// std::cout << "Param Function Gradient " << grad << std::endl;

0 commit comments

Comments
 (0)