MinimumError MnPosDef::operator()(const MinimumError& e, const MnMachinePrecision& prec) const { MnAlgebraicSymMatrix err(e.invHessian()); if(err.size() == 1 && err(0,0) < prec.eps()) { err(0,0) = 1.; return MinimumError(err, MinimumError::MnMadePosDef()); } if(err.size() == 1 && err(0,0) > prec.eps()) { return e; } // std::cout<<"MnPosDef init matrix= "<<err<<std::endl; double epspdf = std::max(1.e-6, prec.eps2()); double dgmin = err(0,0); for(unsigned int i = 0; i < err.nrow(); i++) { if(err(i,i) < prec.eps2()) //std::cout<<"negative or zero diagonal element "<<i<<" in covariance matrix"<<std::endl; if(err(i,i) < dgmin) dgmin = err(i,i); } double dg = 0.; if(dgmin < prec.eps2()) { //dg = 1. + epspdf - dgmin; dg = 0.5 + epspdf - dgmin; // dg = 0.5*(1. + epspdf - dgmin); //std::cout<<"added "<<dg<<" to diagonal of error matrix"<<std::endl; //std::cout << "Error matrix " << err << std::endl; } MnAlgebraicVector s(err.nrow()); MnAlgebraicSymMatrix p(err.nrow()); for(unsigned int i = 0; i < err.nrow(); i++) { err(i,i) += dg; if(err(i,i) < 0.) err(i,i) = 1.; s(i) = 1./sqrt(err(i,i)); for(unsigned int j = 0; j <= i; j++) { p(i,j) = err(i,j)*s(i)*s(j); } } //std::cout<<"MnPosDef p: "<<p<<std::endl; MnAlgebraicVector eval = eigenvalues(p); double pmin = eval(0); double pmax = eval(eval.size() - 1); //std::cout<<"pmin= "<<pmin<<" pmax= "<<pmax<<std::endl; pmax = std::max(fabs(pmax), 1.); if(pmin > epspdf*pmax) return MinimumError(err, e.dcovar()); double padd = 0.001*pmax - pmin; //std::cout<<"eigenvalues: "<<std::endl; for(unsigned int i = 0; i < err.nrow(); i++) { err(i,i) *= (1. + padd); //std::cout<<eval(i)<<std::endl; } // std::cout<<"MnPosDef final matrix: "<<err<<std::endl; // std::cout<<"matrix forced pos-def by adding "<<padd<<" to diagonal"<<std::endl; // std::cout<<"eigenvalues: "<<eval<<std::endl; return MinimumError(err, MinimumError::MnMadePosDef()); }
struct QuantizedValue *FindMatch(uint8 const *sample, int ndims, uint8 *weights, struct QuantizedValue *q) { InitHeap(&TheQueue); struct QuantizedValue *bestmatch=0; double besterror=1.0e63; PUSHNODE(q); for(;;) { struct QuantizedValue *test=(struct QuantizedValue *) RemoveHeapItem(&TheQueue); if (! test) break; // heap empty // printf("got pop node =%p minerror=%f\n",test,test->MinError); if (test->MinError>besterror) break; if (test->Children[0]) { // it's a parent node. put the children on the queue struct QuantizedValue *c1=test->Children[0]; struct QuantizedValue *c2=test->Children[1]; c1->MinError=MinimumError(c1,sample,ndims,weights); if (c1->MinError < besterror) HeapInsert(&TheQueue,&(c1->MinError)); c2->MinError=MinimumError(c2,sample,ndims,weights); if (c2->MinError < besterror) HeapInsert(&TheQueue,&(c2->MinError)); } else { // it's a leaf node. This must be a new minimum or the MinError // test would have failed. if (test->MinError < besterror) { bestmatch=test; besterror=test->MinError; } } } if (bestmatch) { SquaredError+=besterror; bestmatch->NQuant++; for(int i=0;i<ndims;i++) bestmatch->Sums[i]+=sample[i]; } return bestmatch; }
MnUserParameterState MnHesse::operator()(const FCNBase& fcn, const MnUserParameterState& state, unsigned int maxcalls) const { unsigned int n = state.variableParameters(); MnUserFcn mfcn(fcn, state.trafo()); MnAlgebraicVector x(n); for(unsigned int i = 0; i < n; i++) x(i) = state.intParameters()[i]; double amin = mfcn(x); Numerical2PGradientCalculator gc(mfcn, state.trafo(), theStrategy); MinimumParameters par(x, amin); FunctionGradient gra = gc(par); MinimumState tmp = (*this)(mfcn, MinimumState(par, MinimumError(MnAlgebraicSymMatrix(n), 1.), gra, state.edm(), state.nfcn()), state.trafo(), maxcalls); return MnUserParameterState(tmp, fcn.up(), state.trafo()); }
MinimumState MnHesse::operator()(const MnFcn& mfcn, const MinimumState& st, const MnUserTransformation& trafo, unsigned int maxcalls) const { const MnMachinePrecision& prec = trafo.precision(); // make sure starting at the right place double amin = mfcn(st.vec()); double aimsag = sqrt(prec.eps2())*(fabs(amin)+mfcn.up()); // diagonal elements first unsigned int n = st.parameters().vec().size(); if(maxcalls == 0) maxcalls = 200 + 100*n + 5*n*n; MnAlgebraicSymMatrix vhmat(n); MnAlgebraicVector g2 = st.gradient().g2(); MnAlgebraicVector gst = st.gradient().gstep(); MnAlgebraicVector grd = st.gradient().grad(); MnAlgebraicVector dirin = st.gradient().gstep(); MnAlgebraicVector yy(n); if(st.gradient().isAnalytical()) { InitialGradientCalculator igc(mfcn, trafo, theStrategy); FunctionGradient tmp = igc(st.parameters()); gst = tmp.gstep(); dirin = tmp.gstep(); g2 = tmp.g2(); } MnAlgebraicVector x = st.parameters().vec(); for(unsigned int i = 0; i < n; i++) { double xtf = x(i); double dmin = 8.*prec.eps2()*(fabs(xtf) + prec.eps2()); double d = fabs(gst(i)); if(d < dmin) d = dmin; for(unsigned int icyc = 0; icyc < ncycles(); icyc++) { double sag = 0.; double fs1 = 0.; double fs2 = 0.; for(unsigned int multpy = 0; multpy < 5; multpy++) { x(i) = xtf + d; fs1 = mfcn(x); x(i) = xtf - d; fs2 = mfcn(x); x(i) = xtf; sag = 0.5*(fs1+fs2-2.*amin); if(sag > prec.eps2()) goto L30; // break; if(trafo.parameter(i).hasLimits()) { if(d > 0.5) goto L26; d *= 10.; if(d > 0.5) d = 0.51; continue; } d *= 10.; } L26: std::cout<<"MnHesse: 2nd derivative zero for parameter "<<i<<std::endl; std::cout<<"MnHesse fails and will return diagonal matrix "<<std::endl; for(unsigned int j = 0; j < n; j++) { double tmp = g2(j) < prec.eps2() ? 1. : 1./g2(j); vhmat(j,j) = tmp < prec.eps2() ? 1. : tmp; } return MinimumState(st.parameters(), MinimumError(vhmat, MinimumError::MnHesseFailed()), st.gradient(), st.edm(), mfcn.numOfCalls()); L30: double g2bfor = g2(i); g2(i) = 2.*sag/(d*d); grd(i) = (fs1-fs2)/(2.*d); gst(i) = d; dirin(i) = d; yy(i) = fs1; double dlast = d; d = sqrt(2.*aimsag/fabs(g2(i))); if(trafo.parameter(i).hasLimits()) d = std::min(0.5, d); if(d < dmin) d = dmin; // see if converged if(fabs((d-dlast)/d) < tolerstp()) break; if(fabs((g2(i)-g2bfor)/g2(i)) < tolerg2()) break; d = std::min(d, 10.*dlast); d = std::max(d, 0.1*dlast); } vhmat(i,i) = g2(i); if(mfcn.numOfCalls() > maxcalls) { //std::cout<<"maxcalls " << maxcalls << " " << mfcn.numOfCalls() << " " << st.nfcn() << std::endl; std::cout<<"MnHesse: maximum number of allowed function calls exhausted."<<std::endl; std::cout<<"MnHesse fails and will return diagonal matrix "<<std::endl; for(unsigned int j = 0; j < n; j++) { double tmp = g2(j) < prec.eps2() ? 1. : 1./g2(j); vhmat(j,j) = tmp < prec.eps2() ? 1. : tmp; } return MinimumState(st.parameters(), MinimumError(vhmat, MinimumError::MnHesseFailed()), st.gradient(), st.edm(), mfcn.numOfCalls()); } } if(theStrategy.strategy() > 0) { // refine first derivative HessianGradientCalculator hgc(mfcn, trafo, theStrategy); FunctionGradient gr = hgc(st.parameters(), FunctionGradient(grd, g2, gst)); grd = gr.grad(); } //off-diagonal elements for(unsigned int i = 0; i < n; i++) { x(i) += dirin(i); for(unsigned int j = i+1; j < n; j++) { x(j) += dirin(j); double fs1 = mfcn(x); double elem = (fs1 + amin - yy(i) - yy(j))/(dirin(i)*dirin(j)); vhmat(i,j) = elem; x(j) -= dirin(j); } x(i) -= dirin(i); } //verify if matrix pos-def (still 2nd derivative) MinimumError tmp = MnPosDef()(MinimumError(vhmat,1.), prec); vhmat = tmp.invHessian(); int ifail = invert(vhmat); if(ifail != 0) { std::cout<<"MnHesse: matrix inversion fails!"<<std::endl; std::cout<<"MnHesse fails and will return diagonal matrix."<<std::endl; MnAlgebraicSymMatrix tmpsym(vhmat.nrow()); for(unsigned int j = 0; j < n; j++) { double tmp = g2(j) < prec.eps2() ? 1. : 1./g2(j); tmpsym(j,j) = tmp < prec.eps2() ? 1. : tmp; } return MinimumState(st.parameters(), MinimumError(tmpsym, MinimumError::MnHesseFailed()), st.gradient(), st.edm(), mfcn.numOfCalls()); } FunctionGradient gr(grd, g2, gst); // needed this ? (if posdef and inversion ok continue. it is like this in the Fortran version // if(tmp.isMadePosDef()) { // std::cout<<"MnHesse: matrix is invalid!"<<std::endl; // std::cout<<"MnHesse: matrix is not pos. def.!"<<std::endl; // std::cout<<"MnHesse: matrix was forced pos. def."<<std::endl; // return MinimumState(st.parameters(), MinimumError(vhmat, MinimumError::MnMadePosDef()), gr, st.edm(), mfcn.numOfCalls()); // } //calculate edm MinimumError err(vhmat, 0.); VariableMetricEDMEstimator estim; double edm = estim.estimate(gr, err); return MinimumState(st.parameters(), err, gr, edm, mfcn.numOfCalls()); }