Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
MnUserTransformation.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
12#include "Minuit2/MnMatrix.h"
13
14#include <algorithm>
15#include <cstdio>
16#include <string>
17#include <sstream>
18
19namespace ROOT {
20
21namespace Minuit2 {
22
23class MnParStr {
24
25public:
26 MnParStr(const std::string &name) : fName(name) {}
27
28 bool operator()(const MinuitParameter &par) const
29 {
30 // return (strcmp(par.Name(), fName) == 0);
31 return par.GetName() == fName;
32 }
33
34private:
35 const std::string &fName;
36};
37
38MnUserTransformation::MnUserTransformation(std::span<const double> par, std::span<const double> err)
39{
40 // constructor from a vector of parameter values and a vector of errors (step sizes)
41 // class has as data member the transformation objects (all of the types),
42 // the std::vector of MinuitParameter objects and the vector with the index conversions from
43 // internal to external (fExtOfInt)
44
45 fParameters.reserve(par.size());
46 fExtOfInt.reserve(par.size());
47 fCache.reserve(par.size());
48
49 std::string parName;
50 for (unsigned int i = 0; i < par.size(); i++) {
51 std::ostringstream buf;
52 buf << "p" << i;
53 parName = buf.str();
54 Add(parName, par[i], err[i]);
55 }
56}
57
58//#ifdef MINUIT2_THREAD_SAFE
59// this if a thread-safe implementation needed if want to share transformation object between the threads
61{
62 // transform an internal Minuit vector of internal values in a std::vector of external values
63 // fixed parameters will have their fixed values
64 unsigned int n = pstates.size();
65 // need to initialize to the stored (initial values) parameter values for the fixed ones
66 std::vector<double> pcache(fCache);
67 for (unsigned int i = 0; i < n; i++) {
68 if (fParameters[fExtOfInt[i]].HasLimits()) {
69 pcache[fExtOfInt[i]] = Int2ext(i, pstates(i));
70 } else {
71 pcache[fExtOfInt[i]] = pstates(i);
72 }
73 }
74 return pcache;
75}
76
77// #else
78// const std::vector<double> & MnUserTransformation::operator()(const MnAlgebraicVector& pstates) const {
79// // transform an internal Minuit vector of internal values in a std::vector of external values
80// // std::vector<double> Cache(pstates.size() );
81// for(unsigned int i = 0; i < pstates.size(); i++) {
82// if(fParameters[fExtOfInt[i]].HasLimits()) {
83// fCache[fExtOfInt[i]] = Int2ext(i, pstates(i));
84// } else {
85// fCache[fExtOfInt[i]] = pstates(i);
86// }
87// }
88
89// return fCache;
90// }
91// #endif
92
93double MnUserTransformation::Int2ext(unsigned int i, double val) const
94{
95 // return external value from internal value for parameter i
96 if (fParameters[fExtOfInt[i]].HasLimits()) {
97 if (fParameters[fExtOfInt[i]].HasUpperLimit() && fParameters[fExtOfInt[i]].HasLowerLimit())
98 return fDoubleLimTrafo.Int2ext(val, fParameters[fExtOfInt[i]].UpperLimit(),
99 fParameters[fExtOfInt[i]].LowerLimit());
100 else if (fParameters[fExtOfInt[i]].HasUpperLimit() && !fParameters[fExtOfInt[i]].HasLowerLimit())
101 return fUpperLimTrafo.Int2ext(val, fParameters[fExtOfInt[i]].UpperLimit());
102 else
103 return fLowerLimTrafo.Int2ext(val, fParameters[fExtOfInt[i]].LowerLimit());
104 }
105
106 return val;
107}
108
109double MnUserTransformation::Int2extError(unsigned int i, double val, double err) const
110{
111 // return external error from internal error for parameter i
112
113 // err = sigma Value == std::sqrt(cov(i,i))
114 double dx = err;
115
116 if (fParameters[fExtOfInt[i]].HasLimits()) {
117 double ui = Int2ext(i, val);
118 double du1 = Int2ext(i, val + dx) - ui;
119 double du2 = Int2ext(i, val - dx) - ui;
120 if (fParameters[fExtOfInt[i]].HasUpperLimit() && fParameters[fExtOfInt[i]].HasLowerLimit()) {
121 // double al = fParameters[fExtOfInt[i]].Lower();
122 // double ba = fParameters[fExtOfInt[i]].Upper() - al;
123 // double du1 = al + 0.5*(sin(val + dx) + 1.)*ba - ui;
124 // double du2 = al + 0.5*(sin(val - dx) + 1.)*ba - ui;
125 // if(dx > 1.) du1 = ba;
126 if (dx > 1.)
127 du1 = fParameters[fExtOfInt[i]].UpperLimit() - fParameters[fExtOfInt[i]].LowerLimit();
128 dx = 0.5 * (std::fabs(du1) + std::fabs(du2));
129 } else {
130 dx = 0.5 * (std::fabs(du1) + std::fabs(du2));
131 }
132 }
133
134 return dx;
135}
136
139{
140 // return the external covariance matrix from the internal error matrix and the internal parameter value
141 // the vector of internal parameter is needed for the derivatives (Jacobian of the transformation)
142 // Vext(i,j) = Vint(i,j) * dPext(i)/dPint(i) * dPext(j)/dPint(j)
143 //
144 // Note: only the first derivative (Jacobian) of the int<->ext transformation enters here, even on the
145 // diagonal. Unlike the Hessian/G2 transformation (see AnalyticalGradientCalculator), there is no
146 // d^2Pext/dPint^2 * gradient term. The Hessian needs that extra non-tensorial term because it is
147 // evaluated at arbitrary, non-stationary points where the external gradient is nonzero. The covariance
148 // matrix, by contrast, is the inverse Hessian evaluated at the minimum, where the external gradient
149 // vanishes and that term is identically zero; the covariance then transforms as a genuine (2,0) tensor
150 // with the Jacobian alone. (Adding the term here would also break the exact round-trip between
151 // Int2extCovariance and Ext2intCovariance.)
152
154 for (unsigned int i = 0; i < vec.size(); i++) {
155 double dxdi = 1.;
156 if (fParameters[fExtOfInt[i]].HasLimits()) {
157 // dxdi = 0.5*std::fabs((fParameters[fExtOfInt[i]].Upper() -
158 // fParameters[fExtOfInt[i]].Lower())*cos(vec(i)));
159 dxdi = DInt2Ext(i, vec(i));
160 }
161 for (unsigned int j = i; j < vec.size(); j++) {
162 double dxdj = 1.;
163 if (fParameters[fExtOfInt[j]].HasLimits()) {
164 // dxdj = 0.5*std::fabs((fParameters[fExtOfInt[j]].Upper() -
165 // fParameters[fExtOfInt[j]].Lower())*cos(vec(j)));
166 dxdj = DInt2Ext(j, vec(j));
167 }
168 result(i, j) = dxdi * cov(i, j) * dxdj;
169 }
170 // double diag = Int2extError(i, vec(i), std::sqrt(cov(i,i)));
171 // result(i,i) = diag*diag;
172 }
173
174 return result;
175}
176
179{
180 // return the internal covariance matrix from the external error matrix and the internal parameter value
181 // the vector of internal parameter is needed for the derivatives (Jacobian of the transformation)
182 // Vint(i,j) = Vext(i,j) * dPint(i)/dPext(i) * dPint(j)/dPext(j)
183 //
184 // As in Int2extCovariance, only the Jacobian enters: no second-derivative (d^2Pint/dPext^2 * gradient)
185 // term is needed, since the covariance is the inverse Hessian at the minimum where the gradient is zero.
186
188 for (unsigned int i = 0; i < vec.size(); i++) {
189 double dxdi = 1.;
190 if (fParameters[fExtOfInt[i]].HasLimits()) {
191 dxdi = DExt2Int(i, vec(i));
192 }
193 for (unsigned int j = i; j < vec.size(); j++) {
194 double dxdj = 1.;
195 if (fParameters[fExtOfInt[j]].HasLimits()) {
196 dxdj = DExt2Int(j, vec(j));
197 }
198 result(i, j) = dxdi * cov(i, j) * dxdj;
199 }
200 }
201
202 return result;
203}
204
205double MnUserTransformation::Ext2int(unsigned int i, double val) const
206{
207 // return the internal value for parameter i with external value val
208
209 if (fParameters[i].HasLimits()) {
210 if (fParameters[i].HasUpperLimit() && fParameters[i].HasLowerLimit())
211 return fDoubleLimTrafo.Ext2int(val, fParameters[i].UpperLimit(), fParameters[i].LowerLimit(), Precision());
212 else if (fParameters[i].HasUpperLimit() && !fParameters[i].HasLowerLimit())
213 return fUpperLimTrafo.Ext2int(val, fParameters[i].UpperLimit(), Precision());
214 else
215 return fLowerLimTrafo.Ext2int(val, fParameters[i].LowerLimit(), Precision());
216 }
217
218 return val;
219}
220
221double MnUserTransformation::DInt2Ext(unsigned int i, double val) const
222{
223 // return the derivative of the int->ext transformation: dPext(i) / dPint(i)
224 // for the parameter i with value val
225
226 double dd = 1.;
227 if (fParameters[fExtOfInt[i]].HasLimits()) {
228 if (fParameters[fExtOfInt[i]].HasUpperLimit() && fParameters[fExtOfInt[i]].HasLowerLimit())
229 // dd = 0.5*std::fabs((fParameters[fExtOfInt[i]].Upper() -
230 // fParameters[fExtOfInt[i]].Lower())*cos(vec(i)));
231 dd = fDoubleLimTrafo.DInt2Ext(val, fParameters[fExtOfInt[i]].UpperLimit(),
232 fParameters[fExtOfInt[i]].LowerLimit());
233 else if (fParameters[fExtOfInt[i]].HasUpperLimit() && !fParameters[fExtOfInt[i]].HasLowerLimit())
234 dd = fUpperLimTrafo.DInt2Ext(val, fParameters[fExtOfInt[i]].UpperLimit());
235 else
236 dd = fLowerLimTrafo.DInt2Ext(val, fParameters[fExtOfInt[i]].LowerLimit());
237 }
238
239 return dd;
240}
241
242double MnUserTransformation::D2Int2Ext(unsigned int i, double val) const
243{
244 // return the second derivative of the int->ext transformation: d^2 Pext(i) / d Pint(i)^2
245 // for the parameter i with value val
246
247 double dd = 0.;
248 if (fParameters[fExtOfInt[i]].HasLimits()) {
249 if (fParameters[fExtOfInt[i]].HasUpperLimit() && fParameters[fExtOfInt[i]].HasLowerLimit())
250 dd = fDoubleLimTrafo.D2Int2Ext(val, fParameters[fExtOfInt[i]].UpperLimit(),
251 fParameters[fExtOfInt[i]].LowerLimit());
252 else if (fParameters[fExtOfInt[i]].HasUpperLimit() && !fParameters[fExtOfInt[i]].HasLowerLimit())
253 dd = fUpperLimTrafo.D2Int2Ext(val, fParameters[fExtOfInt[i]].UpperLimit());
254 else
255 dd = fLowerLimTrafo.D2Int2Ext(val, fParameters[fExtOfInt[i]].LowerLimit());
256 }
257
258 return dd;
259}
260
261double MnUserTransformation::DExt2Int(unsigned int i, double val) const
262{
263 // return the derivative of the ext->int transformation: dPint(i) / dPext(i)
264 // for the parameter i with value val
265
266 double dd = 1.;
267 if (fParameters[fExtOfInt[i]].HasLimits()) {
268 if (fParameters[fExtOfInt[i]].HasUpperLimit() && fParameters[fExtOfInt[i]].HasLowerLimit())
269 // dd = 0.5*std::fabs((fParameters[fExtOfInt[i]].Upper() -
270 // fParameters[fExtOfInt[i]].Lower())*cos(vec(i)));
271 dd = fDoubleLimTrafo.DExt2Int(val, fParameters[fExtOfInt[i]].UpperLimit(),
272 fParameters[fExtOfInt[i]].LowerLimit());
273 else if (fParameters[fExtOfInt[i]].HasUpperLimit() && !fParameters[fExtOfInt[i]].HasLowerLimit())
274 dd = fUpperLimTrafo.DExt2Int(val, fParameters[fExtOfInt[i]].UpperLimit());
275 else
276 dd = fLowerLimTrafo.DExt2Int(val, fParameters[fExtOfInt[i]].LowerLimit());
277 }
278
279 return dd;
280}
281
282unsigned int MnUserTransformation::IntOfExt(unsigned int ext) const
283{
284 // return internal index given external one ext
285 assert(ext < fParameters.size());
286 assert(!fParameters[ext].IsFixed());
287 assert(!fParameters[ext].IsConst());
288 auto iind = std::find(fExtOfInt.begin(), fExtOfInt.end(), ext);
289 assert(iind != fExtOfInt.end());
290
291 return (iind - fExtOfInt.begin());
292}
293
294std::vector<double> MnUserTransformation::Params() const
295{
296 // return std::vector of double with parameter values
297 unsigned int n = fParameters.size();
298 std::vector<double> result(n);
299 for (unsigned int i = 0; i < n; ++i)
300 result[i] = fParameters[i].Value();
301
302 return result;
303}
304
305std::vector<double> MnUserTransformation::Errors() const
306{
307 // return std::vector of double with parameter errors
308 std::vector<double> result;
309 result.reserve(fParameters.size());
310 for (auto const &ipar : Parameters()) {
311 result.push_back(ipar.Error());
312 }
313
314 return result;
315}
316
318{
319 // return the MinuitParameter object for index n (external)
320 assert(n < fParameters.size());
321 return fParameters[n];
322}
323
324// bool MnUserTransformation::Remove(const std::string & name) {
325// // remove parameter with name
326// // useful if want to re-define a parameter
327// // return false if parameter does not exist
328// auto itr = std::find_if(fParameters.begin(), fParameters.end(), MnParStr(name)
329// ); if (itr == fParameters.end() ) return false; int n = itr - fParameters.begin(); if (n < 0 || n >=
330// fParameters.size() ) return false; fParameters.erase(itr); fCache.erase( fExtOfInt.begin() + n);
331// auto iind = std::find(fExtOfInt.begin(), fExtOfInt.end(), n);
332// if (iind != fExtOfInt.end()) fExtOfInt.erase(iind);
333// }
334
335bool MnUserTransformation::Add(const std::string &name, double val, double err)
336{
337 // add a new unlimited parameter giving name, value and err (step size)
338 // return false if parameter already exists
339 if (std::find_if(fParameters.begin(), fParameters.end(), MnParStr(name)) != fParameters.end())
340 return false;
341 fExtOfInt.push_back(fParameters.size());
342 fCache.push_back(val);
343 fParameters.push_back(MinuitParameter(fParameters.size(), name, val, err));
344 return true;
345}
346
347bool MnUserTransformation::Add(const std::string &name, double val, double err, double low, double up)
348{
349 // add a new limited parameter giving name, value, err (step size) and lower/upper limits
350 // return false if parameter already exists
351 if (std::find_if(fParameters.begin(), fParameters.end(), MnParStr(name)) != fParameters.end())
352 return false;
353 fExtOfInt.push_back(fParameters.size());
354 fCache.push_back(val);
355 fParameters.push_back(MinuitParameter(fParameters.size(), name, val, err, low, up));
356 return true;
357}
358
359bool MnUserTransformation::Add(const std::string &name, double val)
360{
361 // add a new constant parameter giving name and value
362 // return false if parameter already exists
363 if (std::find_if(fParameters.begin(), fParameters.end(), MnParStr(name)) != fParameters.end())
364 return false;
365 fCache.push_back(val);
366 // constant parameter - do not add in list of internals (fExtOfInt)
367 fParameters.push_back(MinuitParameter(fParameters.size(), name, val));
368 return true;
369}
370
371void MnUserTransformation::Fix(unsigned int n)
372{
373 // fix parameter n (external index)
374 assert(n < fParameters.size());
375 auto iind = std::find(fExtOfInt.begin(), fExtOfInt.end(), n);
376 if (iind != fExtOfInt.end())
377 fExtOfInt.erase(iind, iind + 1);
378 fParameters[n].Fix();
379}
380
382{
383 // release parameter n (external index)
384 assert(n < fParameters.size());
385 auto iind = std::find(fExtOfInt.begin(), fExtOfInt.end(), n);
386 if (iind == fExtOfInt.end()) {
387 fExtOfInt.push_back(n);
388 std::sort(fExtOfInt.begin(), fExtOfInt.end());
389 }
390 fParameters[n].Release();
391}
392
393void MnUserTransformation::SetValue(unsigned int n, double val)
394{
395 // set value for parameter n (external index)
396 assert(n < fParameters.size());
397 fParameters[n].SetValue(val);
398 fCache[n] = val;
399}
400
401void MnUserTransformation::SetError(unsigned int n, double err)
402{
403 // set error for parameter n (external index)
404 assert(n < fParameters.size());
405 fParameters[n].SetError(err);
406}
407
408void MnUserTransformation::SetLimits(unsigned int n, double low, double up)
409{
410 // set limits (lower/upper) for parameter n (external index)
411 assert(n < fParameters.size());
412 assert(low != up);
413 fParameters[n].SetLimits(low, up);
414}
415
416void MnUserTransformation::SetUpperLimit(unsigned int n, double up)
417{
418 // set upper limit for parameter n (external index)
419 assert(n < fParameters.size());
420 fParameters[n].SetUpperLimit(up);
421}
422
423void MnUserTransformation::SetLowerLimit(unsigned int n, double lo)
424{
425 // set lower limit for parameter n (external index)
426 assert(n < fParameters.size());
427 fParameters[n].SetLowerLimit(lo);
428}
429
431{
432 // remove limits for parameter n (external index)
433 assert(n < fParameters.size());
434 fParameters[n].RemoveLimits();
435}
436
437void MnUserTransformation::SetName(unsigned int n, const std::string &name)
438{
439 // set name for parameter n (external index)
440 assert(n < fParameters.size());
441 fParameters[n].SetName(name);
442}
443
444double MnUserTransformation::Value(unsigned int n) const
445{
446 // get value for parameter n (external index)
447 assert(n < fParameters.size());
448 return fParameters[n].Value();
449}
450
451double MnUserTransformation::Error(unsigned int n) const
452{
453 // get error for parameter n (external index)
454 assert(n < fParameters.size());
455 return fParameters[n].Error();
456}
457
458// interface by parameter name
459
460void MnUserTransformation::Fix(const std::string &name)
461{
462 // fix parameter
463 Fix(Index(name));
464}
465
466void MnUserTransformation::Release(const std::string &name)
467{
468 // release parameter
470}
471
472void MnUserTransformation::SetValue(const std::string &name, double val)
473{
474 // set value for parameter
475 SetValue(Index(name), val);
476}
477
478void MnUserTransformation::SetError(const std::string &name, double err)
479{
480 // set error
481 SetError(Index(name), err);
482}
483
484void MnUserTransformation::SetLimits(const std::string &name, double low, double up)
485{
486 // set lower/upper limits
487 SetLimits(Index(name), low, up);
488}
489
490void MnUserTransformation::SetUpperLimit(const std::string &name, double up)
491{
492 // set upper limit
494}
495
496void MnUserTransformation::SetLowerLimit(const std::string &name, double lo)
497{
498 // set lower limit
500}
501
503{
504 // remove limits
506}
507
508double MnUserTransformation::Value(const std::string &name) const
509{
510 // get parameter value
511 return Value(Index(name));
512}
513
514double MnUserTransformation::Error(const std::string &name) const
515{
516 // get parameter error
517 return Error(Index(name));
518}
519
520unsigned int MnUserTransformation::Index(const std::string &name) const
521{
522 // get index (external) corresponding to name
523 auto ipar = std::find_if(fParameters.begin(), fParameters.end(), MnParStr(name));
524 assert(ipar != fParameters.end());
525 // return (ipar - fParameters.begin());
526 return (*ipar).Number();
527}
528
529int MnUserTransformation::FindIndex(const std::string &name) const
530{
531 // find index (external) corresponding to name - return -1 if not found
532 auto ipar = std::find_if(fParameters.begin(), fParameters.end(), MnParStr(name));
533 if (ipar == fParameters.end())
534 return -1;
535 return (*ipar).Number();
536}
537
538const std::string &MnUserTransformation::GetName(unsigned int n) const
539{
540 // get name corresponding to index (external)
541 assert(n < fParameters.size());
542 return fParameters[n].GetName();
543}
544
545const char *MnUserTransformation::Name(unsigned int n) const
546{
547 // get name corresponding to index (external)
548 return GetName(n).c_str();
549}
550
551} // namespace Minuit2
552
553} // namespace ROOT
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
char name[80]
Definition TGX11.cxx:148
Class describing a symmetric matrix of size n.
Definition MnMatrix.h:438
class for the individual Minuit Parameter with Name and number; contains the input numbers for the mi...
const std::string & GetName() const
MnParStr(const std::string &name)
bool operator()(const MinuitParameter &par) const
Class containing the covariance matrix data represented as a vector of size n*(n+1)/2 Used to hide in...
double Ext2int(unsigned int, double) const
MnUserCovariance Int2extCovariance(const MnAlgebraicVector &, const MnAlgebraicSymMatrix &) const
double DExt2Int(unsigned int, double) const
bool Add(const std::string &, double, double)
double DInt2Ext(unsigned int, double) const
void SetName(unsigned int, const std::string &)
std::vector< MinuitParameter > fParameters
std::vector< double > operator()(const MnAlgebraicVector &) const
const std::vector< MinuitParameter > & Parameters() const
unsigned int IntOfExt(unsigned int) const
double D2Int2Ext(unsigned int, double) const
MnUserCovariance Ext2intCovariance(const MnAlgebraicVector &, const MnAlgebraicSymMatrix &) const
const char * Name(unsigned int) const
std::vector< unsigned int > fExtOfInt
std::vector< double > Params() const
access to parameters and errors in column-wise representation
SqrtLowParameterTransformation fLowerLimTrafo
int FindIndex(const std::string &) const
double Int2ext(unsigned int, double) const
unsigned int Index(const std::string &) const
SinParameterTransformation fDoubleLimTrafo
const std::string & GetName(unsigned int) const
void SetLimits(unsigned int, double, double)
double Int2extError(unsigned int, double, double) const
const MnMachinePrecision & Precision() const
forwarded interface
SqrtUpParameterTransformation fUpperLimTrafo
const MinuitParameter & Parameter(unsigned int) const
long double DInt2Ext(long double Value, long double Upper, long double Lower) const
long double DExt2Int(long double Value, long double Upper, long double Lower) const
long double D2Int2Ext(long double Value, long double Upper, long double Lower) const
long double Int2ext(long double Value, long double Upper, long double Lower) const
long double Ext2int(long double Value, long double Upper, long double Lower, const MnMachinePrecision &) const
long double DExt2Int(long double Value, long double Lower) const
long double D2Int2Ext(long double Value, long double Lower) const
long double Ext2int(long double Value, long double Lower, const MnMachinePrecision &) const
long double DInt2Ext(long double Value, long double Lower) const
long double Int2ext(long double Value, long double Lower) const
long double D2Int2Ext(long double Value, long double Upper) const
long double DExt2Int(long double Value, long double Upper) const
long double Int2ext(long double Value, long double Upper) const
long double DInt2Ext(long double Value, long double Upper) const
long double Ext2int(long double Value, long double Upper, const MnMachinePrecision &) const
const Int_t n
Definition legend1.C:16