Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
AnalyticalGradientCalculator.cxx
Go to the documentation of this file.
1// @(#)root/minuit2:$Id$
2// Authors: M. Winkler, F. James, L. Moneta, A. Zsenei 2003-2005
3
4/**********************************************************************
5 * *
6 * Copyright (c) 2005 LCG ROOT Math team, CERN/PH-SFT *
7 * *
8 **********************************************************************/
9
11#include "Minuit2/FCNBase.h"
15#include "Minuit2/MnMatrix.h"
16#include "Minuit2/MnPrint.h"
17
18#include <cassert>
19
20namespace ROOT {
21namespace Minuit2 {
22
24{
25 // evaluate analytical gradient. take care of parameter transformations
26
27 std::vector<double> grad = fGradFunc.Gradient(fTransformation(par.Vec()));
28 assert(grad.size() == fTransformation.Parameters().size());
29
30 MnAlgebraicVector v(par.Vec().size());
31 for (unsigned int i = 0; i < par.Vec().size(); i++) {
32 unsigned int ext = fTransformation.ExtOfInt(i);
33 double dd = fTransformation.DInt2Ext(i, par.Vec()(i));
34 v(i) = dd * grad[ext];
35 }
36
37 MnPrint print("AnalyticalGradientCalculator");
38 print.Debug("User given gradient in Minuit2", v);
39
40 // in case we can compute Hessian do not waste re-computing G2 here
42 return FunctionGradient(v);
43
44 // compute G2 if possible
45 MnAlgebraicVector g2(par.Vec().size());
46 if (!this->G2(par, g2)) {
47 print.Error("Error computing G2");
48 return FunctionGradient(v);
49 }
50 return FunctionGradient(v,g2);
51}
52
54{
55 // needed from base class
56 return (*this)(par);
57}
58
59// G2 can be computed directly without Hessian or via the Hessian
61 return fGradFunc.HasG2() || fGradFunc.HasHessian();
62}
63
65 return fGradFunc.HasHessian();
66}
67
68
70{
71 // compute Hessian using external gradient
72 unsigned int n = par.Vec().size();
73 assert(hmat.size() == n *(n+1)/2);
74 // compute external Hessian and then transform
75 std::vector<double> extHessian = fGradFunc.Hessian(fTransformation(par.Vec()));
76 if (extHessian.empty()) {
77 MnPrint print("AnalyticalGradientCalculator::Hessian");
78 print.Info("FCN cannot compute Hessian matrix");
79 return false;
80 }
81 unsigned int next = sqrt(extHessian.size());
82 // we need now to transform the matrix from external to internal coordinates
83 for (unsigned int i = 0; i < n; i++) {
84 unsigned int iext = fTransformation.ExtOfInt(i);
85 double dxdi = fTransformation.DInt2Ext(i, par.Vec()(i));
86 for (unsigned int j = i; j < n; j++) {
87 double dxdj = fTransformation.DInt2Ext(j, par.Vec()(j));
88 unsigned int jext = fTransformation.ExtOfInt(j);
89 hmat(i, j) = dxdi * extHessian[iext*next+ jext] * dxdj;
90 }
91 }
92 return true;
93}
94
96{
97 // compute G2 using external calculator if available; otherwise fall back to Hessian diagonal
98 const unsigned int n = par.Vec().size(); // n is size of internal parameters
99 assert(g2.size() == n);
100
101 MnPrint print("AnalyticalGradientCalculator::G2");
102
103 // --- Preferred path: direct G2 from FCN ---
104 if (fGradFunc.HasG2()) {
105 std::vector<double> extG2 = fGradFunc.G2(fTransformation(par.Vec()));
106 if (extG2.empty()) {
107 print.Info("FCN cannot compute the 2nd derivatives vector (G2)");
108 return false;
109 }
110 assert(extG2.size() == fTransformation.Parameters().size());
111 for (unsigned int i = 0; i < n; i++) {
112 const unsigned int iext = fTransformation.ExtOfInt(i);
113 const double dxdi = fTransformation.DInt2Ext(i, par.Vec()(i));
114 g2(i) = dxdi * dxdi * extG2[iext];
115 }
116 return true;
117 }
118
119 // --- Fallback: use Hessian diagonal if FCN provides Hessian ---
120 if (!fGradFunc.HasHessian()) {
121 print.Info("FCN cannot compute the 2nd derivatives vector (G2) or the Hessian");
122 return false;
123 }
124
125 std::vector<double> extHessian = fGradFunc.Hessian(fTransformation(par.Vec()));
126 if (extHessian.empty()) {
127 print.Info("FCN cannot compute Hessian matrix (needed to derive G2)");
128 return false;
129 }
130
131 // FCNBase::Hessian is expected to return a flat nExt*nExt matrix (row-major).
132 const unsigned int nExt = static_cast<unsigned int>(std::lround(std::sqrt(static_cast<double>(extHessian.size()))));
133 if (nExt * nExt != extHessian.size()) {
134 print.Error("Unexpected Hessian size; cannot derive G2 from Hessian diagonal");
135 return false;
136 }
137 // Sanity check against transformation parameter count
138 assert(nExt == fTransformation.Parameters().size());
139
140 for (unsigned int i = 0; i < n; i++) {
141 const unsigned int iext = fTransformation.ExtOfInt(i);
142 const double diag = extHessian[iext * nExt + iext];
143 const double dxdi = fTransformation.DInt2Ext(i, par.Vec()(i));
144 g2(i) = dxdi * dxdi * diag;
145 }
146 return true;
147}
148
149} // namespace Minuit2
150
151} // namespace ROOT
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
bool G2(const MinimumParameters &, MnAlgebraicVector &) const override
compute second derivatives (diagonal of Hessian)
FunctionGradient operator()(const MinimumParameters &) const override
bool Hessian(const MinimumParameters &, MnAlgebraicSymMatrix &) const override
compute Hessian matrix
Class describing a symmetric matrix of size n.
Definition MnMatrix.h:438
const MnAlgebraicVector & Vec() const
void Debug(const Ts &... args)
Definition MnPrint.h:135
void Error(const Ts &... args)
Definition MnPrint.h:117
void Info(const Ts &... args)
Definition MnPrint.h:129
const Int_t n
Definition legend1.C:16