Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
MnPosDef.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
10#include "Minuit2/MnPosDef.h"
13#include "Minuit2/MnPrint.h"
14
15#include <algorithm>
16#include <cmath>
17#include <iostream>
18#include <limits>
19#include <vector>
20
21namespace ROOT {
22
23namespace Minuit2 {
24
25namespace {
26
27// Return true if the symmetric matrix p is certainly accepted by the eigenvalue test below, i.e. if its smallest
28// eigenvalue pmin satisfies pmin > epspdf * max(|pmax|, 1). This avoids the full O(n^3) eigen decomposition with
29// mneigen in the common case where the matrix is well inside the positive-definite region. A false return value
30// is not a verdict: the caller then falls back to the eigenvalue computation.
31//
32// The test is a Cholesky decomposition of p - shift * 1. Its success proves that all eigenvalues of p are larger
33// than shift. The Gershgorin bound gives max(|pmax|, 1) <= bound, so it suffices that shift >= epspdf * bound.
34// The shift also contains margins for the convergence tolerance of mneigen (relative precision 1e-6 on the
35// tridiagonal matrix, whose elements are bounded by the Gershgorin bound too) and for the rounding errors of the
36// Cholesky decomposition of a matrix with unit diagonal, so that a successful test always leads to the same
37// decision as the eigenvalues that mneigen would have computed.
38bool IsCertainlyPosDef(const MnAlgebraicSymMatrix &p, double epspdf)
39{
40 const unsigned int n = p.Nrow();
41
42 double bound = 1.;
43 for (unsigned int i = 0; i < n; i++) {
44 double rowSum = 0.;
45 for (unsigned int j = 0; j < n; j++)
46 rowSum += std::abs(p(i, j));
47 bound = std::max(bound, rowSum);
48 }
49 const double shift = (epspdf + 1.e-5 + (n + 1.) * n * std::numeric_limits<double>::epsilon()) * bound;
50
51 // Cholesky decomposition in the packed storage of the matrix: element (i, j) with j <= i is at i * (i + 1) / 2 + j.
52 std::vector<double> l(p.Data(), p.Data() + p.size());
53 for (unsigned int i = 0; i < n; i++) {
54 double *li = l.data() + i * (i + 1) / 2;
55 for (unsigned int j = 0; j <= i; j++) {
56 const double *lj = l.data() + j * (j + 1) / 2;
57 double sum = li[j];
58 if (i == j)
59 sum -= shift;
60 for (unsigned int k = 0; k < j; k++)
61 sum -= li[k] * lj[k];
62 if (i == j) {
63 if (!(sum > 0.))
64 return false;
65 li[i] = std::sqrt(sum);
66 } else {
67 li[j] = sum / lj[j];
68 }
69 }
70 }
71 return true;
72}
73
74} // namespace
75
77{
78 // interface from minimum state
79 MinimumError err = (*this)(st.Error(), prec);
80 return MinimumState(st.Parameters(), err, st.Gradient(), st.Edm(), st.NFcn());
81}
82
84{
85 MnPrint print("MnPosDef");
86
87 // make error matrix positive defined returning a new corrected minimum error state
88
89 MnAlgebraicSymMatrix err(e.InvHessian());
90 if (err.size() == 1 && err(0, 0) < prec.Eps()) {
91 err(0, 0) = 1.;
93 }
94 if (err.size() == 1 && err(0, 0) > prec.Eps()) {
95 return e;
96 }
97 // std::cout<<"MnPosDef init matrix= "<<err<<std::endl;
98
99 double epspdf = std::max(1.e-12, prec.Eps2()); // should this lower bound be configurable?
100 double dgmin = err(0, 0);
101
102 for (unsigned int i = 0; i < err.Nrow(); i++) {
103 if (err(i, i) <= 0 /* prec.Eps2() */)
104 print.Warn("non-positive diagonal element in covariance matrix[", i, "] =", err(i, i));
105
106 if (err(i, i) < dgmin)
107 dgmin = err(i, i);
108 }
109 double dg = 0.;
110 if (dgmin <= 0) {
111 // dg = 1. + epspdf - dgmin;
112 dg = 0.5 + epspdf - dgmin;
113 // dg = 0.5*(1. + epspdf - dgmin);
114
115 print.Warn("Added to diagonal of Error matrix a value", dg);
116
117 // std::cout << "Error matrix " << err << std::endl;
118 }
119
120 MnAlgebraicVector s(err.Nrow());
122 for (unsigned int i = 0; i < err.Nrow(); i++) {
123 err(i, i) += dg;
124 if (err(i, i) < 0.)
125 err(i, i) = 1.;
126 s(i) = 1. / std::sqrt(err(i, i));
127 for (unsigned int j = 0; j <= i; j++) {
128 p(i, j) = err(i, j) * s(i) * s(j);
129 }
130 }
131
132 // std::cout<<"MnPosDef p: "<<p<<std::endl;
133 if (IsCertainlyPosDef(p, epspdf))
134 return MinimumError(err, e.Dcovar());
135
137 double pmin = eval(0);
138 double pmax = eval(eval.size() - 1);
139 // std::cout<<"pmin= "<<pmin<<" pmax= "<<pmax<<std::endl;
140 pmax = std::max(std::fabs(pmax), 1.);
141 if (pmin > epspdf * pmax)
142 return MinimumError(err, e.Dcovar());
143
144 double pAdd = 0.001 * pmax - pmin;
145
146 for (unsigned int i = 0; i < err.Nrow(); i++)
147 err(i, i) *= (1. + pAdd);
148
149 print.Debug([&](std::ostream &os) {
150 os << "Eigenvalues:";
151 for (unsigned i = 0; i < err.Nrow(); ++i)
152 os << "\n " << eval(i);
153 });
154
155 // std::cout<<"MnPosDef final matrix: "<<err<<std::endl;
156
157 print.Warn("Matrix forced pos-def by adding to diagonal", pAdd);
158
160}
161
162} // namespace Minuit2
163
164} // namespace ROOT
#define e(i)
Definition RSha256.hxx:103
winID h TVirtualViewer3D TVirtualGLPainter p
Class describing a symmetric matrix of size n.
Definition MnMatrix.h:438
unsigned int Nrow() const
Definition MnMatrix.h:683
unsigned int size() const
Definition MnMatrix.h:681
unsigned int size() const
Definition MnMatrix.h:1032
MinimumError keeps the inv.
MinimumState keeps the information (position, Gradient, 2nd deriv, etc) after one minimization step (...
const MinimumError & Error() const
const MinimumParameters & Parameters() const
const FunctionGradient & Gradient() const
Sets the relative floating point (double) arithmetic precision.
double Eps() const
eps returns the smallest possible number so that 1.+eps > 1.
double Eps2() const
eps2 returns 2*sqrt(eps)
MinimumState operator()(const MinimumState &, const MnMachinePrecision &) const
Definition MnPosDef.cxx:76
void Debug(const Ts &... args)
Definition MnPrint.h:135
void Warn(const Ts &... args)
Definition MnPrint.h:123
const Int_t n
Definition legend1.C:16
LAVector eigenvalues(const LASymMatrix &)
Definition MnMatrix.cxx:606
LASymMatrix MnAlgebraicSymMatrix
Definition MnMatrixfwd.h:21
TLine l
Definition textangle.C:4
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2335