00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "Minuit2/MnPosDef.h"
00011 #include "Minuit2/MinimumState.h"
00012 #include "Minuit2/MnMachinePrecision.h"
00013
00014 #if defined(DEBUG) || defined(WARNINGMSG)
00015 #include "Minuit2/MnPrint.h"
00016 #endif
00017
00018 #include <algorithm>
00019
00020
00021 namespace ROOT {
00022
00023 namespace Minuit2 {
00024
00025
00026 LAVector eigenvalues(const LASymMatrix&);
00027
00028
00029 MinimumState MnPosDef::operator()(const MinimumState& st, const MnMachinePrecision& prec) const {
00030
00031 MinimumError err = (*this)(st.Error(), prec);
00032 return MinimumState(st.Parameters(), err, st.Gradient(), st.Edm(), st.NFcn());
00033 }
00034
00035 MinimumError MnPosDef::operator()(const MinimumError& e, const MnMachinePrecision& prec) const {
00036
00037
00038 MnAlgebraicSymMatrix err(e.InvHessian());
00039 if(err.size() == 1 && err(0,0) < prec.Eps()) {
00040 err(0,0) = 1.;
00041 return MinimumError(err, MinimumError::MnMadePosDef());
00042 }
00043 if(err.size() == 1 && err(0,0) > prec.Eps()) {
00044 return e;
00045 }
00046
00047
00048 double epspdf = std::max(1.e-6, prec.Eps2());
00049 double dgmin = err(0,0);
00050
00051 for(unsigned int i = 0; i < err.Nrow(); i++) {
00052 #ifdef WARNINGMSG
00053 if(err(i,i) <= 0 )
00054 MN_INFO_VAL2("negative or zero diagonal element in covariance matrix",i);
00055 #endif
00056 if(err(i,i) < dgmin) dgmin = err(i,i);
00057 }
00058 double dg = 0.;
00059 if(dgmin <= 0) {
00060
00061 dg = 0.5 + epspdf - dgmin;
00062
00063 #ifdef WARNINGMSG
00064 MN_INFO_VAL2("added to diagonal of Error matrix a value",dg);
00065 #endif
00066
00067 }
00068
00069 MnAlgebraicVector s(err.Nrow());
00070 MnAlgebraicSymMatrix p(err.Nrow());
00071 for(unsigned int i = 0; i < err.Nrow(); i++) {
00072 err(i,i) += dg;
00073 if(err(i,i) < 0.) err(i,i) = 1.;
00074 s(i) = 1./sqrt(err(i,i));
00075 for(unsigned int j = 0; j <= i; j++) {
00076 p(i,j) = err(i,j)*s(i)*s(j);
00077 }
00078 }
00079
00080
00081 MnAlgebraicVector eval = eigenvalues(p);
00082 double pmin = eval(0);
00083 double pmax = eval(eval.size() - 1);
00084
00085 pmax = std::max(fabs(pmax), 1.);
00086 if(pmin > epspdf*pmax) return MinimumError(err, e.Dcovar());
00087
00088 double padd = 0.001*pmax - pmin;
00089 #ifdef DEBUG
00090 std::cout<<"eigenvalues: "<<std::endl;
00091 #endif
00092 for(unsigned int i = 0; i < err.Nrow(); i++) {
00093 err(i,i) *= (1. + padd);
00094 #ifdef DEBUG
00095 std::cout<<eval(i)<<std::endl;
00096 #endif
00097 }
00098
00099 #ifdef WARNINGMSG
00100 MN_INFO_VAL2("matrix forced pos-def by adding to diagonal",padd);
00101 #endif
00102 return MinimumError(err, MinimumError::MnMadePosDef());
00103 }
00104
00105 }
00106
00107 }