37 #define dbg if(_nlOut) (*_nlOut)
38 #define xdbg if(_verbose >= 1 && _nlOut) (*_nlOut)
39 #define xxdbg if(_verbose >= 2 && _nlOut) (*_nlOut)
43 namespace algorithms {
50 _fTol(1.e-8), _gTol(1.e-8), _minStep(1.e-8), _maxIter(200),
51 _tau(1.e-3), _delta0(1.),
52 _nlOut(0), _verbose(0),
53 _hasDirectH(
false), _shouldUseCh(
true), _shouldUseSvd(
false)
57 const tmv::Vector<double>&
x,
const tmv::Vector<double>& f,
58 tmv::Matrix<double>& df)
const
60 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
65 tmv::Vector<double> x2 =
x;
66 tmv::Vector<double> f2(f.size());
67 tmv::Vector<double> f1(f.size());
68 for(
size_t j=0;j<x.size();++j) {
69 const double dx = sqrtEps * (x.norm() + 1.);
74 df.col(j) = (f2-f1)/(2.*dx);
80 const tmv::Vector<double>& x, tmv::Vector<double>& f,
81 std::ostream* os,
double relErr)
const
83 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
86 _pJ.reset(
new tmv::Matrix<double>(f.size(),x.size()));
87 tmv::Matrix<double>& J = *
_pJ;
89 tmv::Matrix<double> Jn(f.size(),x.size());
91 double err = MaxAbsElement(J-Jn) / Jn.norm();
92 if (!relErr) relErr = 10.*sqrtEps;
96 *os <<
"x = "<<x<<std::endl;
97 *os <<
"f = "<<f<<std::endl;
98 *os <<
"Direct J = "<<J<<std::endl;
99 *os <<
"Numeric J = "<<Jn<<std::endl;
101 *os <<
"MaxAbsElement(J-J_num) / J.norm() = "<<err<<std::endl;
102 *os <<
"cf. relerr = "<<relErr<<std::endl;
104 tmv::Matrix<double> diff = J-Jn;
105 *os <<
"J-J_num = "<<diff;
106 double maxel = diff.maxAbsElement();
107 *os <<
"Max element = "<<maxel<<std::endl;
108 for(
size_t i=0;i<diff.colsize();++i) {
109 for(
size_t j=0;j<diff.rowsize();++j) {
110 if (std::abs(diff(i,j)) > 0.9*maxel) {
111 *os<<
"J("<<i<<
','<<j<<
") = "<<J(i,j)<<
" ";
112 *os<<
"J_num("<<i<<
','<<j<<
") = "<<Jn(i,j)<<
" ";
113 *os<<
"diff = "<<J(i,j)-Jn(i,j)<<std::endl;
122 class NoDefinedH :
public std::runtime_error
126 std::runtime_error(
"calculateH is undefined in NLSolver")
130 void NLSolver::calculateH(
131 const tmv::Vector<double>& ,
const tmv::Vector<double>& ,
132 const tmv::Matrix<double>& , tmv::SymMatrix<double>& )
const
135 std::cerr<<
"H is undefined\n";
146 void NLSolver::calculateNumericH(
147 const tmv::Vector<double>& x,
148 const tmv::Vector<double>& f,
149 tmv::SymMatrix<double>& h)
const
153 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
154 const double dx = sqrt(sqrtEps) * (x.norm() + 1.);
155 double q0 = 0.5 * f.normSq();
157 tmv::Vector<double> x2 =
x;
158 tmv::Vector<double> f2(f.size());
159 for(
size_t i=0;i<x.size();++i) {
162 double q2a = 0.5*f2.normSq();
165 double q2b = 0.5*f2.normSq();
167 h(i,i) = (q2a + q2b - 2.*q0) / (dx*dx);
170 for(
size_t j=i+1;j<x.size();++j) {
174 q2a = 0.5*f2.normSq();
179 q2b = 0.5*f2.normSq();
184 double q2c = 0.5*f2.normSq();
189 double q2d = 0.5*f2.normSq();
191 h(i,j) = (q2a - q2b - q2c + q2d) / (4.*dx*dx);
199 #define CHECKF(normInfF) \
201 double checkfTemp = (normInfF); \
202 if (!(checkfTemp > _fTol)) { \
203 dbg<<"Found ||f|| ~= 0\n"; \
204 dbg<<"||f||_inf = "<<checkfTemp<<" < "<<_fTol<<std::endl; \
209 #define CHECKG(normInfG) \
211 double checkgTemp = (normInfG); \
212 if (!(checkgTemp > _gTol)) { \
213 dbg<<"Found local minimum of ||f||\n"; \
214 dbg<<"||g||_inf = "<<checkgTemp<<" < "<<_gTol<<std::endl; \
221 dbg<<"||f||_inf = "<<f.normInf()<<" !< "<<_fTol<<std::endl; \
222 dbg<<"||g||_inf = "<<g.normInf()<<" !< "<<_gTol<<std::endl; \
225 #define CHECKSTEP(normH) \
227 double checkStepTemp1 = (normH); \
228 double checkStepTemp2 = _minStep*(x.norm()+_minStep); \
229 if (!(checkStepTemp1 > checkStepTemp2)) { \
230 dbg<<"Step size became too small\n"; \
231 dbg<<"||h|| = "<<checkStepTemp1<<" < "<<checkStepTemp2<<std::endl; \
237 bool NLSolver::solveNewton(
238 tmv::Vector<double>& x, tmv::Vector<double>& f)
const
242 const double gamma1 = 0.1;
243 const double gamma2 = 0.5;
244 dbg<<
"Start Solve_Newton\n";
246 _pJ.reset(
new tmv::Matrix<double>(f.size(),x.size()));
247 tmv::Matrix<double>& J = *_pJ;
248 tmv::Vector<double> g(x.size());
249 tmv::Vector<double> h(x.size());
250 tmv::Vector<double> xNew(x.size());
251 tmv::Vector<double> fNew(f.size());
252 tmv::Vector<double> gNew(x.size());
254 xdbg<<
"x = "<<x<<std::endl;
255 this->calculateF(x,f);
256 xdbg<<
"f = "<<f<<std::endl;
258 double Q = 0.5*f.normSq();
259 xdbg<<
"Q = "<<Q<<std::endl;
260 this->calculateJ(x,f,J);
261 if (_shouldUseSvd) J.divideUsing(tmv::SV);
263 xdbg<<
"J = "<<J<<std::endl;
264 g = J.transpose() * f;
265 xdbg<<
"g = "<<g<<std::endl;
267 double alpha = Q/g.normSq();
268 bool shouldUseNewton =
true;
270 dbg<<
"iter |f|inf Q |g|inf alpha\n";
271 for(
int k=0;k<_maxIter;++k) {
272 shouldUseNewton =
true;
273 dbg<<k<<
" "<<f.normInf()<<
" "<<Q<<
" "<<g.normInf()<<
" "<<
277 xdbg<<
"h = "<<h<<std::endl;
278 double normH = h.norm();
286 double normG = g.norm();
287 double m2 = -normG*normG;
289 if ((k%5 == 0 && m >= 0.) || (k%5 != 0 && m/normH >= -0.01*normG)) {
291 shouldUseNewton =
false;
292 xdbg<<
"Newton is not a good descent direction - use steepest descent\n";
297 xdbg<<
"m = "<<m<<
", Steepest m = "<<m2<<std::endl;
298 xdbg<<
"m/h.norm() = "<<m/normH<<
", Steepest m/h.norm() = "<<-normG<<std::endl;
301 if (shouldUseNewton && alpha > 0.1) alpha = 1.0;
302 for(
int k2=0;k2<=_maxIter;++k2) {
303 if (k2 == _maxIter) {
304 dbg<<
"Maximum iterations exceeded in subloop of Newton method\n";
305 dbg<<
"This can happen when there is a singularity (or close to it)\n";
306 dbg<<
"along the gradient direction:\n";
308 dbg<<
"J Singular values = \n"<<J.svd().getS().diag()<<std::endl;
309 dbg<<
"V = \n"<<J.svd().getV()<<std::endl;
315 if (alpha < _minStep) {
316 dbg<<
"alpha became too small ("<<alpha<<
" < "<<_minStep<<
")\n";
320 xdbg<<
"xnew = "<<xNew<<std::endl;
321 this->calculateF(xNew,fNew);
322 xdbg<<
"fnew = "<<fNew<<std::endl;
323 double QNew = 0.5*fNew.normSq();
324 xdbg<<
"Qnew = "<<QNew<<std::endl;
328 if (QNew > Q + gamma1 * m * alpha) {
330 shouldUseNewton =
false;
331 xdbg<<
"Qnew not small enough: alpha => "<<alpha<<std::endl;
334 this->calculateJ(xNew,fNew,J);
336 xdbg<<
"Jnew = "<<J<<std::endl;
337 gNew = J.transpose() * fNew;
338 xdbg<<
"gnew = "<<gNew<<std::endl;
342 double mNew = h*gNew;
343 if (mNew < gamma2 * m) {
345 shouldUseNewton =
false;
346 xdbg<<
"New slope not shallow enough: alpha => "<<alpha<<std::endl;
347 xdbg<<
"(m = "<<m<<
", mnew = "<<mNew<<
")\n";
350 xdbg<<
"Good choice\n";
351 x = xNew; f = fNew; Q = QNew; g = gNew;
357 dbg<<
"Maximum iterations exceeded in Newton method\n";
362 bool NLSolver::solveLM(
363 tmv::Vector<double>& x, tmv::Vector<double>& f)
const
366 dbg<<
"Start Solve_LM\n";
368 _pJ.reset(
new tmv::Matrix<double>(f.size(),x.size()));
369 tmv::Matrix<double>& J = *_pJ;
370 tmv::Vector<double> h(x.size());
371 tmv::Vector<double> xNew(x.size());
372 tmv::Vector<double> fNew(f.size());
373 tmv::Vector<double> gNew(x.size());
375 xdbg<<
"x = "<<x<<std::endl;
376 this->calculateF(x,f);
377 xdbg<<
"f = "<<f<<std::endl;
379 double Q = 0.5*f.normSq();
380 xdbg<<
"Q = "<<Q<<std::endl;
381 this->calculateJ(x,f,J);
382 if (_shouldUseSvd) J.divideUsing(tmv::SV);
384 xdbg<<
"J = "<<J<<std::endl;
385 tmv::Vector<double> g = J.transpose() * f;
386 xdbg<<
"g = "<<g<<std::endl;
389 tmv::SymMatrix<double> A = J.transpose() * J;
390 xdbg<<
"JT J = "<<A<<std::endl;
391 if (_shouldUseSvd) A.divideUsing(tmv::SV);
392 else if (_shouldUseCh) A.divideUsing(tmv::CH);
393 else A.divideUsing(tmv::LU);
394 double mu = _tau * A.diag().normInf();
395 xdbg<<
"initial mu = "<<_tau<<
" * "<<A.diag().normInf()<<
" = "<<mu<<std::endl;
400 dbg<<
"iter |f|inf Q |g|inf mu\n";
401 for(
int k=0;k<_maxIter;++k) {
402 dbg<<k<<
" "<<f.normInf()<<
" "<<Q<<
" "<<g.normInf()<<
" "<<mu<<std::endl;
403 xdbg<<
"k = "<<k<<std::endl;
404 xdbg<<
"mu = "<<mu<<std::endl;
405 xdbg<<
"A = "<<A<<std::endl;
411 }
catch (tmv::NonPosDef) {
412 xdbg<<
"NonPosDef caught - switching division to LU method.\n";
414 A.divideUsing(tmv::LU);
418 xdbg<<
"h = "<<h<<std::endl;
422 xdbg<<
"xnew = "<<xNew<<std::endl;
423 this->calculateF(xNew,fNew);
424 xdbg<<
"fnew = "<<fNew<<std::endl;
425 double QNew = 0.5*fNew.normSq();
426 xdbg<<
"Qnew = "<<QNew<<std::endl;
433 this->calculateJ(x,f,J);
435 A = J.transpose() * J;
436 gNew = J.transpose() * f;
437 xdbg<<
"gnew = "<<gNew<<std::endl;
442 double rho = (Q-QNew) / (-0.5*h*g);
443 xdbg<<
"rho = "<<Q-QNew<<
" / "<<(-0.5*h*g)<<
" = "<<rho<<std::endl;
444 mu *= std::max(1./3.,1.-std::pow(2.*rho-1.,3)); nu = 2.;
445 xdbg<<
"mu *= "<<std::max(1./3.,1.-std::pow(2.*rho-1.,3))<<
" = "<<mu<<std::endl;
450 xdbg<<
"not improved\n";
451 A += mu*(nu-1.); mu *= nu; nu *= 2.;
453 xdbg<<
"mu *= (nu = "<<nu<<
") = "<<mu<<std::endl;
456 dbg<<
"Maximum iterations exceeded in LM method\n";
462 tmv::Vector<double>& x, tmv::Vector<double>& f)
const
465 dbg<<
"Start Solve_Dogleg\n";
466 _pJ.reset(
new tmv::Matrix<double>(f.size(),x.size()));
467 tmv::Matrix<double>& J = *_pJ;
468 tmv::Vector<double> h(x.size());
469 tmv::Vector<double> temp(x.size());
470 tmv::Vector<double> xNew(x.size());
471 tmv::Vector<double> fNew(f.size());
473 xdbg<<
"x = "<<x<<std::endl;
474 this->calculateF(x,f);
475 xdbg<<
"f = "<<f<<std::endl;
477 double Q = 0.5*f.normSq();
478 xdbg<<
"Q = "<<Q<<std::endl;
479 this->calculateJ(x,f,J);
480 if (_shouldUseSvd) J.divideUsing(tmv::SV);
482 xdbg<<
"J = "<<J<<std::endl;
483 xdbg<<
"J.svd = "<<J.svd().getS().diag()<<std::endl;
485 tmv::Vector<double> g = J.transpose() * f;
486 xdbg<<
"g = "<<g<<std::endl;
489 double delta = _delta0;
490 int maxnsing = std::min(f.size(),x.size());
491 int nsing = maxnsing;
493 dbg<<
"iter |f|inf Q |g|inf delta\n";
494 for(
int k=0;k<_maxIter;++k) {
495 dbg<<k<<
" "<<f.normInf()<<
" "<<Q<<
" "<<g.normInf()<<
" "<<delta<<std::endl;
496 xxdbg<<
"f = "<<f<<std::endl;
497 xxdbg<<
"g = "<<g<<std::endl;
498 xxdbg<<
"J = "<<J<<std::endl;
500 xxdbg<<
"J.svd = "<<J.svd().getS().diag()<<std::endl;
501 if (_shouldUseSvd && nsing == maxnsing && nsing > 1 &&
502 J.svd().isSingular()) {
503 xdbg<<
"Singular J, so try lowering number of singular values.\n";
504 nsing = J.svd().getKMax();
505 xdbg<<
"J Singular values = \n"<<J.svd().getS().diag()<<std::endl;
506 xdbg<<
"nsing -> "<<nsing<<std::endl;
509 xdbg<<
"h_newton = "<<h<<std::endl;
511 double normsqg = g.normSq();
512 double normH = h.norm();
513 double normH1 = normH;
516 if (normH <= delta) {
517 xdbg<<
"|h| < delta\n";
519 xdbg<<
"rhodenom = "<<rhoDenom<<std::endl;
521 xxdbg<<
"normsqg = "<<normsqg<<std::endl;
522 xxdbg<<
"(J*g) = "<<J*g<<std::endl;
523 xxdbg<<
"normsq = "<<(J*g).normSq()<<std::endl;
524 double alpha = normsqg / (J*g).normSq();
525 xdbg<<
"alpha = "<<alpha<<std::endl;
526 double normG = sqrt(normsqg);
527 xxdbg<<
"normG = "<<normG<<std::endl;
528 if (normG >= delta / alpha) {
529 xdbg<<
"|g| > delta/alpha\n";
530 h = -(delta / normG) * g;
531 xdbg<<
"h_gradient = "<<h<<std::endl;
532 rhoDenom = delta*(2.*alpha*normG-delta)/(2.*alpha);
533 xdbg<<
"rhodenom = "<<rhoDenom<<std::endl;
537 double a = temp.normSq();
538 double b = -alpha * g * temp;
539 double c = alpha*alpha*g.normSq()-delta*delta;
541 xdbg<<
"a,b,c = "<<a<<
" "<<b<<
" "<<c<<std::endl;
542 double beta = (b <= 0) ?
543 (-b + sqrt(b*b - a*c)) / a :
544 -c / (b + sqrt(b*b - a*c));
545 xdbg<<
"beta = "<<beta<<std::endl;
546 h = -alpha*g + beta*temp;
547 xdbg<<
"h_dogleg = "<<h<<std::endl;
548 xdbg<<
"h.norm() = "<<h.norm()<<
" delta = "<<delta<<std::endl;
550 0.5*alpha*std::pow((1.-beta)*normG,2) +
552 xdbg<<
"rhodenom = "<<rhoDenom<<std::endl;
560 xdbg<<
"xnew = "<<xNew<<std::endl;
561 this->calculateF(xNew,fNew);
562 xdbg<<
"fnew = "<<fNew<<std::endl;
563 double QNew = 0.5*fNew.normSq();
564 xdbg<<
"Qnew = "<<QNew<<std::endl;
566 bool deltaok =
false;
568 double rho = (Q-QNew) / rhoDenom;
569 xdbg<<
"rho = "<<Q-QNew<<
" / "<<rhoDenom<<
" = "<<rho<<std::endl;
570 x = xNew; f = fNew; Q = QNew;
572 this->calculateJ(x,f,J);
574 g = J.transpose() * f;
575 xdbg<<
"g = "<<g<<std::endl;
578 delta = std::max(delta,3.*normH);
585 double normsqh = normH1*normH1;
588 normsqg < 0.01 * normsqh && nsing > 1) {
590 dbg<<
"normsqg == "<<normsqg/normsqh<<
591 " * normsqh, so try lowering number of singular values.\n";
593 dbg<<
"nsing -> "<<nsing<<std::endl;
594 dbg<<
"J Singular values = \n"<<J.svd().getS().diag()<<std::endl;
598 double min_delta = _minStep * (x.norm()+_minStep);
599 if (delta < min_delta) {
600 dbg<<
"delta became too small ("<<
601 delta<<
" < "<<min_delta<<
")\n";
608 dbg<<
"Maximum iterations exceeded in Dogleg method\n";
614 tmv::Vector<double>& x, tmv::Vector<double>& f)
const
618 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
620 dbg<<
"Start Solve_Hybrid\n";
621 _pJ.reset(
new tmv::Matrix<double>(f.size(),x.size()));
622 tmv::Matrix<double>& J = *_pJ;
623 tmv::Vector<double> h(x.size());
624 tmv::Vector<double> xNew(x.size());
625 tmv::Vector<double> fNew(f.size());
626 tmv::Vector<double> gNew(x.size());
627 tmv::Matrix<double> JNew(f.size(),x.size());
628 tmv::Vector<double>
y(x.size());
629 tmv::Vector<double> v(x.size());
631 xdbg<<
"x = "<<x<<std::endl;
632 this->calculateF(x,f);
633 xdbg<<
"f = "<<f<<std::endl;
634 double normInfF = f.normInf();
636 double Q = 0.5*f.normSq();
637 xdbg<<
"Q = "<<Q<<std::endl;
638 this->calculateJ(x,f,J);
639 if (_shouldUseSvd) J.divideUsing(tmv::SV);
641 xdbg<<
"J = "<<J<<std::endl;
643 tmv::SymMatrix<double> A = J.transpose()*J;
644 xdbg<<
"A = "<<A<<std::endl;
645 if (_shouldUseSvd) A.divideUsing(tmv::SV);
646 else if (_shouldUseCh) A.divideUsing(tmv::CH);
647 else A.divideUsing(tmv::LU);
649 tmv::SymMatrix<double> H(x.size());
650 if (_shouldUseSvd) H.divideUsing(tmv::SV);
651 else if (_shouldUseCh) H.divideUsing(tmv::CH);
652 else H.divideUsing(tmv::LU);
654 bool shouldUseDirectH = _hasDirectH;
655 xdbg<<
"shouldUseDirectH = "<<shouldUseDirectH<<std::endl;
656 if (shouldUseDirectH) {
660 xdbg<<
"try calculateH\n";
661 this->calculateH(x,f,J,H);
663 }
catch(NoDefinedH) {
664 dbg<<
"No direct H calculation - calculate on the fly\n";
665 shouldUseDirectH =
false;
670 xdbg<<
"setToIdent\n";
673 xdbg<<
"After calculate H = "<<H<<std::endl;
675 tmv::Vector<double> g = J.transpose() * f;
676 xdbg<<
"g = "<<g<<std::endl;
677 double normInfG = g.normInf();
680 double mu = _tau * A.diag().normInf();
683 double delta = _delta0;
684 bool shouldUseQuasiNewton =
false;
687 dbg<<
"iter |f|inf Q |g|inf mu delta LM/QN\n";
688 for(
int k=0;k<_maxIter;++k) {
689 dbg<<k<<
" "<<normInfF<<
" "<<Q<<
" "<<normInfG<<
" "<< mu<<
" "<<
690 delta<<
" "<<(shouldUseQuasiNewton?
"QN":
"LM")<<std::endl;
691 xdbg<<
"k = "<<k<<std::endl;
692 xdbg<<
"mu = "<<mu<<std::endl;
693 xdbg<<
"delta = "<<delta<<std::endl;
694 xdbg<<
"A = "<<A<<std::endl;
695 xdbg<<
"H = "<<H<<std::endl;
696 xdbg<<
"method = "<<(shouldUseQuasiNewton ?
"quasinewton\n" :
"LM\n");
697 bool isBetter =
false;
698 bool shouldSwitchMethod =
false;
700 if (shouldUseQuasiNewton) {
706 }
catch (tmv::NonPosDef) {
707 xdbg<<
"NonPosDef caught - switching division to LU method for H\n";
708 H.divideUsing(tmv::LU);
718 }
catch (tmv::NonPosDef) {
719 xdbg<<
"NonPosDef caught - switching division to LU method for A\n";
720 A.divideUsing(tmv::LU);
726 xdbg<<
"h = "<<h<<std::endl;
727 double normH = h.norm();
729 if (shouldUseQuasiNewton && normH > delta) h *= delta/normH;
732 xdbg<<
"xnew = "<<xNew<<std::endl;
733 this->calculateF(xNew,fNew);
734 xdbg<<
"fnew = "<<fNew<<std::endl;
735 double QNew = 0.5*fNew.normSq();
736 xdbg<<
"Qnew = "<<QNew<<std::endl;
738 double normInfGNew = 0.;
739 bool isJNewSet =
false;
740 bool isGNewSet =
false;
741 if (!shouldUseDirectH || shouldUseQuasiNewton || QNew < Q) {
742 this->calculateJ(xNew,fNew,JNew);
743 xdbg<<
"Jnew = "<<JNew<<std::endl;
746 if (shouldUseQuasiNewton || QNew < Q) {
747 if (!isJNewSet)
dbg<<
"Error: JNew should be set!\n";
748 gNew = JNew.transpose() * fNew;
749 xdbg<<
"gnew = "<<gNew<<std::endl;
750 normInfGNew = gNew.normInf();
751 xdbg<<
"NormInf(gnew) = "<<NormInf(gNew)<<std::endl;
755 if (shouldUseQuasiNewton) {
756 xdbg<<
"quasinewton\n";
757 if (!isGNewSet)
dbg<<
"Error: gNew should be set!\n";
760 (QNew <= (1.+sqrtEps)*Q && normInfGNew < normInfG);
761 xdbg<<
"better = "<<isBetter<<std::endl;
762 shouldSwitchMethod = (normInfGNew >= normInfG);
763 xdbg<<
"switchmethod = "<<shouldSwitchMethod<<std::endl;
765 double rho = (Q-QNew) / (-h*g-0.5*(J*h).normSq());
767 delta = std::max(delta,3.*normH);
768 }
else if (rho < 0.25) {
770 double min_delta = _minStep * (x.norm()+_minStep);
771 if (delta < min_delta) {
772 dbg<<
"delta became too small ("<<
773 delta<<
" < "<<min_delta<<
")\n";
780 double min_delta = _minStep * (x.norm()+_minStep);
781 if (delta < min_delta) {
782 dbg<<
"delta became too small ("<<
783 delta<<
" < "<<min_delta<<
")\n";
796 double rho = (Q-QNew) / (-0.5*h*g);
797 mu *= std::max(1./3.,1.-std::pow(2.*rho-1.,3)); nu = 2.;
798 if (!isGNewSet)
dbg<<
"Error: gNew should be set!\n";
799 xdbg<<
"check1: "<<normInfGNew<<
" <? "<<0.02*QNew<<std::endl;
800 xdbg<<
"check2: "<<Q-QNew<<
" <? "<<0.02*QNew<<std::endl;
801 if (std::min(normInfGNew,Q-QNew) < 0.02 * QNew) {
803 if (count == 3) shouldSwitchMethod =
true;
808 if (!isJNewSet)
dbg<<
"Error: JNew should be set!\n";
809 A = JNew.transpose() * JNew;
813 A += mu*(nu-1.); mu *= nu; nu *= 2.;
816 shouldSwitchMethod = (nu >= 32.);
819 xdbg<<
"better = "<<isBetter<<std::endl;
820 xdbg<<
"switchmethod = "<<shouldSwitchMethod<<std::endl;
821 xdbg<<
"count = "<<count<<std::endl;
824 if (!shouldUseDirectH) {
825 if (!isJNewSet)
dbg<<
"Error: JNew should be set!\n";
826 y = JNew.transpose()*(JNew*h) + (JNew-J).transpose()*fNew;
828 xdbg<<
"hy = "<<hy<<std::endl;
831 xdbg<<
"v = "<<v<<std::endl;
832 xdbg<<
"y = "<<y<<std::endl;
833 xdbg<<
"hv = "<<h*v<<std::endl;
834 H -= (1./(h*v)) * (v^v);
835 xdbg<<
"H -> "<<H<<std::endl;
836 H += (1./hy) * (y^y);
838 xdbg<<
"H -> "<<H<<std::endl;
843 xdbg<<
"better"<<std::endl;
844 x = xNew; f = fNew; Q = QNew; normInfF = f.normInf();
845 if (isJNewSet) J = JNew;
846 else this->calculateJ(x,f,J);
847 if (isGNewSet) { g = gNew; normInfG = normInfGNew; }
848 else { g = J.transpose() * f; normInfG = g.normInf(); }
850 if (shouldUseDirectH && shouldUseQuasiNewton && !shouldSwitchMethod)
851 this->calculateH(x,f,J,H);
855 if (shouldSwitchMethod) {
856 if (shouldUseQuasiNewton) {
857 xdbg<<
"switch to LM\n";
858 A = J.transpose() * J;
862 shouldUseQuasiNewton =
false;
865 xdbg<<
"switch to quasinewton\n";
866 delta = std::max(1.5*_minStep*(x.norm()+_minStep),0.2*normH);
867 if (shouldUseDirectH) {
868 this->calculateH(x,f,J,H);
871 shouldUseQuasiNewton =
true;
875 dbg<<
"Maximum iterations exceeded in Hybrid method\n";
880 bool NLSolver::solveSecantLM(
881 tmv::Vector<double>& x, tmv::Vector<double>& f)
const
884 dbg<<
"Start Solve_SecantLM\n";
885 _pJ.reset(
new tmv::Matrix<double>(f.size(),x.size()));
886 tmv::Matrix<double>& J = *_pJ;
887 tmv::Vector<double> h(x.size());
888 tmv::Vector<double> xNew(x.size());
889 tmv::Vector<double> fNew(f.size());
890 tmv::Vector<double> gNew(x.size());
892 xdbg<<
"x = "<<x<<std::endl;
893 this->calculateF(x,f);
894 xdbg<<
"f = "<<f<<std::endl;
896 double Q = 0.5*f.normSq();
897 xdbg<<
"Q = "<<Q<<std::endl;
898 this->calculateJ(x,f,J);
899 if (_shouldUseSvd) J.divideUsing(tmv::SV);
900 xdbg<<
"J = "<<J<<std::endl;
901 tmv::SymMatrix<double> A = J.transpose() * J;
902 if (_shouldUseSvd) A.divideUsing(tmv::SV);
903 else if (_shouldUseCh) A.divideUsing(tmv::CH);
904 else A.divideUsing(tmv::LU);
905 tmv::Vector<double> g = J.transpose() * f;
906 xdbg<<
"g = "<<g<<std::endl;
909 double mu = _tau * A.diag().normInf();
913 dbg<<
"iter |f|inf Q |g|inf mu\n";
914 for(
int k=0,j=0;k<_maxIter;++k) {
915 dbg<<k<<
" "<<f.normInf()<<
" "<<Q<<
" "<<g.normInf()<<
" "<<
917 xdbg<<
"k = "<<k<<std::endl;
918 xdbg<<
"mu = "<<mu<<std::endl;
919 xdbg<<
"J = "<<J<<std::endl;
925 }
catch (tmv::NonPosDef) {
926 xdbg<<
"NonPosDef caught - switching division to LU method.\n";
927 A.divideUsing(tmv::LU);
931 xdbg<<
"h = "<<h<<std::endl;
932 double normH = h.norm();
935 xdbg<<
"j = "<<j<<std::endl;
936 if (h(j) < 0.8 * normH) {
938 double eta = _minStep * (x.norm() + 1.);
940 this->calculateF(xNew,fNew);
941 J.col(j) = (fNew-f)/eta;
942 xdbg<<
"J -> "<<J<<std::endl;
947 xdbg<<
"xnew = "<<xNew<<std::endl;
948 this->calculateF(xNew,fNew);
949 xdbg<<
"fnew = "<<fNew<<std::endl;
950 double QNew = 0.5*fNew.normSq();
951 xdbg<<
"Qnew = "<<QNew<<std::endl;
952 J += (1./h.normSq()) * ((fNew - f - J*h) ^ h);
953 xdbg<<
"J -> "<<J<<std::endl;
959 A = J.transpose() * J;
960 gNew = J.transpose() * f;
964 double rho = (Q-QNew) / (-0.5*h*g);
965 xdbg<<
"rho = "<<Q-QNew<<
" / "<<(-0.5*h*g)<<
" = "<<rho<<std::endl;
966 mu *= std::max(1./3.,1.-std::pow(2.*rho-1.,3)); nu = 2.;
967 xdbg<<
"mu = "<<mu<<std::endl;
971 A += mu*(nu-1.); mu *= nu; nu *= 2.;
974 dbg<<
"Maximum iterations exceeded in Secant LM method\n";
979 bool NLSolver::solveSecantDogleg(
980 tmv::Vector<double>& x, tmv::Vector<double>& f)
const
983 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
985 dbg<<
"Start Solve_SecantDogleg\n";
986 _pJ.reset(
new tmv::Matrix<double>(f.size(),x.size()));
987 tmv::Matrix<double>& J = *_pJ;
988 tmv::Vector<double> h(x.size());
989 tmv::Vector<double> temp(x.size());
990 tmv::Vector<double> xNew(x.size());
991 tmv::Vector<double> fNew(f.size());
992 tmv::Vector<double>
y(f.size());
993 tmv::Vector<double> djodjy(f.size());
995 xdbg<<
"x = "<<x<<std::endl;
996 this->calculateF(x,f);
997 xdbg<<
"f = "<<f<<std::endl;
999 double Q = 0.5*f.normSq();
1000 xdbg<<
"Q = "<<Q<<std::endl;
1001 this->calculateJ(x,f,J);
1002 if (_shouldUseSvd) J.divideUsing(tmv::SV);
1003 tmv::Matrix<double> D = J.inverse();
1005 tmv::Vector<double> g = J.transpose() * f;
1006 xdbg<<
"g = "<<g<<std::endl;
1008 double delta = _delta0;
1010 dbg<<
"iter |f|inf Q |g|inf delta\n";
1011 for(
int k=0,j=0;k<_maxIter;++k) {
1012 dbg<<k<<
" "<<f.normInf()<<
" "<<Q<<
" "<<g.normInf()<<
" "<<
1015 xdbg<<
"h = "<<h<<std::endl;
1017 double normsqg = g.normSq();
1018 double alpha = normsqg / (J*g).normSq();
1019 double normH = h.norm();
1022 if (normH <= delta) {
1023 xdbg<<
"|h| < delta \n";
1026 double normG = sqrt(normsqg);
1027 if (normG >= delta / alpha) {
1028 xdbg<<
"|g| > delta/alpha \n";
1029 h = -(delta / normG) * g;
1030 xdbg<<
"h = "<<h<<std::endl;
1031 rhoDenom = delta*(2.*alpha*normG-delta)/(2.*alpha);
1035 double a = temp.normSq();
1036 double b = -alpha * g * temp;
1037 double c = alpha*alpha*g.normSq()-delta*delta;
1039 double beta = (b <= 0) ?
1040 (-b + sqrt(b*b - a*c)) / a :
1041 -c / (b + sqrt(b*b - a*c));
1042 xdbg<<
"alpha = "<<alpha<<std::endl;
1043 xdbg<<
"beta = "<<beta<<std::endl;
1044 h = -alpha*g + beta*temp;
1045 xdbg<<
"h = "<<h<<std::endl;
1047 0.5*alpha*std::pow((1.-beta)*normG,2) +
1055 bool resetd =
false;
1056 if (h(j) < 0.8 * normH) {
1058 double eta = _minStep * (x.norm() + 1.);
1060 this->calculateF(xNew,fNew);
1063 double djy = D.row(j)*
y;
1064 if (djy < sqrtEps*eta) {
1067 djodjy = D.row(j)/djy;
1068 D -= ((D*
y) ^ djodjy);
1069 D.row(j) += eta*djodjy;
1072 j = (j+1)%J.ncols();
1075 this->calculateF(xNew,fNew);
1076 double QNew = 0.5*fNew.normSq();
1079 J += (1./h.normSq()) * ((fNew - f - J*h) ^ h);
1081 if (resetd || hDy < sqrtEps*h.norm()) {
1084 D += 1./(hDy) * ((h-D*y) ^ (h*D));
1088 double rho = (Q-QNew) / rhoDenom;
1089 xdbg<<
"rho = "<<Q-QNew<<
" / "<<rhoDenom<<
" = "<<rho<<std::endl;
1090 x = xNew; f = fNew; Q = QNew;
1092 g = J.transpose() * f;
1093 xdbg<<
"g = "<<g<<std::endl;
1096 delta = std::max(delta,3.*normH);
1097 }
else if (rho < 0.25) {
1099 double min_delta = _minStep * (x.norm()+_minStep);
1100 if (delta < min_delta) {
1101 dbg<<
"delta became too small ("<<
1102 delta<<
" < "<<min_delta<<
")\n";
1109 double min_delta = _minStep * (x.norm()+_minStep);
1110 if (delta < min_delta) {
1111 dbg<<
"delta became too small ("<<delta<<
" < "<<min_delta<<
")\n";
1117 dbg<<
"Maximum iterations exceeded in Secant Dogleg method\n";
1123 tmv::Vector<double>& x, tmv::Vector<double>& f)
const
1133 case HYBRID :
return solveHybrid(x,f);
1134 case DOGLEG :
return solveDogleg(x,f);
1135 case LM :
return solveLM(x,f);
1136 case NEWTON :
return solveNewton(x,f);
1137 case SECANT_LM :
return solveSecantLM(x,f);
1138 case SECANT_DOGLEG :
return solveSecantDogleg(x,f);
1139 default :
dbg<<
"Unknown method\n";
return false;
1146 catch (tmv::Singular& e) {
1147 dbg<<
"Singular matrix encountered in NLSolver::Solve\n";
1149 }
catch (tmv::Error& e) {
1150 dbg<<
"TMV error encountered in NLSolver::Solve\n";
1153 dbg<<
"Error encountered in NLSolver::Solve\n";
1162 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
1164 throw std::runtime_error(
1165 "J not set before calling getCovariance");
1167 tmv::Matrix<double>& J = *
_pJ;
1171 J.divideUsing(tmv::SV);
1172 J.svd().thresh(sqrtEps);
1174 J.makeInverseATA(cov);
1185 throw std::runtime_error(
1186 "J not set before calling getInverseCovariance");
1188 tmv::Matrix<double>& J = *
_pJ;
1189 invCov = J.transpose() * J;
1196 _fTol(1.e-8), _gTol(1.e-8), _minStep(1.e-8), _maxIter(200),
1197 _tau(1.e-3), _delta0(1.),
1198 _nlOut(0), _verbose(0)
1204 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
1212 const int n = x.size();
1213 for(
int j=0;j<n;++j) {
1214 const double dx = sqrtEps * (x.norm() + 1.);
1219 df.col(j) = (f2-f1)/(2.*dx);
1226 std::ostream* os,
double relErr)
const
1228 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
1234 DMatrix Jn(f.size(),x.size());
1237 if (!relErr) relErr = 10.*sqrtEps;
1241 *os <<
"x = "<<x<<std::endl;
1242 *os <<
"f = "<<f<<std::endl;
1243 *os <<
"Direct J = "<<J<<std::endl;
1244 *os <<
"Numeric J = "<<Jn<<std::endl;
1246 *os <<
"MaxAbsElement(J-J_num) / J.norm() = "<<err<<std::endl;
1247 *os <<
"cf. relerr = "<<relErr<<std::endl;
1248 if (err >= relErr) {
1250 *os <<
"J-J_num = "<<diff;
1251 double maxel = diff.TMV_maxAbsElement();
1252 *os <<
"Max element = "<<maxel<<std::endl;
1253 const int m = diff.TMV_colsize();
1254 const int n = diff.TMV_rowsize();
1255 for(
int i=0;i<
m;++i) {
1256 for(
int j=0;j<n;++j) {
1257 if (std::abs(diff(i,j)) > 0.9*maxel) {
1258 *os<<
"J("<<i<<
','<<j<<
") = "<<J(i,j)<<
" ";
1259 *os<<
"J_num("<<i<<
','<<j<<
") = "<<Jn(i,j)<<
" ";
1260 *os<<
"diff = "<<J(i,j)-Jn(i,j)<<std::endl;
1266 return err < relErr;
1269 #define CHECKF(normInfF) \
1271 double checkfTemp = (normInfF); \
1272 if (!(checkfTemp > _fTol)) { \
1273 dbg<<"Found ||f|| ~= 0\n"; \
1274 dbg<<"||f||_inf = "<<checkfTemp<<" < "<<_fTol<<std::endl; \
1279 #define CHECKG(normInfG) \
1281 double checkgTemp = (normInfG); \
1282 if (!(checkgTemp > _gTol)) { \
1283 dbg<<"Found local minimum of ||f||\n"; \
1284 dbg<<"||g||_inf = "<<checkgTemp<<" < "<<_gTol<<std::endl; \
1289 #define SHOWFAILFG \
1291 dbg<<"||f||_inf = "<<f.TMV_normInf()<<" !< "<<_fTol<<std::endl; \
1292 dbg<<"||g||_inf = "<<g.TMV_normInf()<<" !< "<<_gTol<<std::endl; \
1295 #define CHECKSTEP(normH) \
1297 double checkStepTemp1 = (normH); \
1298 double checkStepTemp2 = _minStep*(x.norm()+_minStep); \
1299 if (!(checkStepTemp1 > checkStepTemp2)) { \
1300 dbg<<"Step size became too small\n"; \
1301 dbg<<"||h|| = "<<checkStepTemp1<<" < "<<checkStepTemp2<<std::endl; \
1310 dbg<<
"Start Solve_Dogleg\n";
1311 _pJ.reset(
new DMatrix(f.size(),x.size()));
1318 xdbg<<
"x = "<<x.transpose()<<std::endl;
1319 this->calculateF(x,f);
1320 xdbg<<
"f = "<<f.transpose()<<std::endl;
1322 double Q = 0.5*f.TMV_normSq();
1323 xdbg<<
"Q = "<<Q<<std::endl;
1324 this->calculateJ(x,f,J);
1325 xdbg<<
"J = "<<J<<std::endl;
1327 DVector g = J.transpose() * f;
1328 xdbg<<
"g = "<<g.transpose()<<std::endl;
1331 double delta = _delta0;
1332 int maxnsing = std::min(f.size(),x.size());
1333 int nsing = maxnsing;
1335 dbg<<
"iter |f|inf Q |g|inf delta\n";
1336 for(
int k=0;k<_maxIter;++k) {
1337 dbg<<k<<
" "<<f.TMV_normInf()<<
" "<<Q<<
" "<<g.TMV_normInf()<<
" "<<delta<<std::endl;
1339 h = J.lu().solve(-f);
1340 xdbg<<
"h = "<<h.transpose()<<std::endl;
1342 double normsqg = g.TMV_normSq();
1343 double normH = h.norm();
1346 if (normH <= delta) {
1347 xdbg<<
"|h| < delta\n";
1349 xdbg<<
"rhodenom = "<<rhoDenom<<std::endl;
1352 double normG = sqrt(normsqg);
1353 if (normG >= delta / alpha) {
1354 xdbg<<
"|g| > delta/alpha\n";
1355 h = -(delta / normG) * g;
1356 xdbg<<
"h = "<<h.transpose()<<std::endl;
1357 rhoDenom = delta*(2.*alpha*normG-delta)/(2.*alpha);
1358 xdbg<<
"rhodenom = "<<rhoDenom<<std::endl;
1362 double a = temp.TMV_normSq();
1363 double b = -alpha * (g.transpose() * temp)(0,0);
1364 double c = alpha*alpha*g.TMV_normSq()-delta*delta;
1366 xdbg<<
"a,b,c = "<<a<<
" "<<b<<
" "<<c<<std::endl;
1367 double beta = (b <= 0) ?
1368 (-b + sqrt(b*b - a*c)) / a :
1369 -c / (b + sqrt(b*b - a*c));
1370 xdbg<<
"alpha = "<<alpha<<std::endl;
1371 xdbg<<
"beta = "<<beta<<std::endl;
1372 h = -alpha*g + beta*temp;
1373 xdbg<<
"h = "<<h.transpose()<<std::endl;
1374 xdbg<<
"h.norm() = "<<h.norm()<<
" delta = "<<delta<<std::endl;
1376 0.5*alpha*std::pow((1.-beta)*normG,2) +
1378 xdbg<<
"rhodenom = "<<rhoDenom<<std::endl;
1386 xdbg<<
"xnew = "<<xNew.transpose()<<std::endl;
1387 this->calculateF(xNew,fNew);
1388 xdbg<<
"fnew = "<<fNew.transpose()<<std::endl;
1389 double QNew = 0.5*fNew.TMV_normSq();
1390 xdbg<<
"Qnew = "<<QNew<<std::endl;
1392 bool deltaok =
false;
1394 double rho = (Q-QNew) / rhoDenom;
1395 xdbg<<
"rho = "<<Q-QNew<<
" / "<<rhoDenom<<
" = "<<rho<<std::endl;
1396 x = xNew; f = fNew; Q = QNew;
1398 this->calculateJ(x,f,J);
1399 g = J.transpose() * f;
1400 xdbg<<
"g = "<<g.transpose()<<std::endl;
1403 delta = std::max(delta,3.*normH);
1411 double min_delta = _minStep * (x.norm()+_minStep);
1412 if (delta < min_delta) {
1413 dbg<<
"delta became too small ("<<
1414 delta<<
" < "<<min_delta<<
")\n";
1421 dbg<<
"Maximum iterations exceeded in Dogleg method\n";
1430 const double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
1432 dbg<<
"Start Solve_Hybrid\n";
1433 _pJ.reset(
new DMatrix(f.size(),x.size()));
1439 DMatrix JNew(f.size(),x.size());
1443 xdbg<<
"x = "<<x.transpose()<<std::endl;
1444 this->calculateF(x,f);
1445 xdbg<<
"f = "<<f.transpose()<<std::endl;
1446 double normInfF = f.TMV_normInf();
1448 double Q = 0.5*f.TMV_normSq();
1449 xdbg<<
"Q = "<<Q<<std::endl;
1450 this->calculateJ(x,f,J);
1451 xdbg<<
"J = "<<J<<std::endl;
1454 xdbg<<
"A = "<<A<<std::endl;
1456 xdbg<<
"setToIdent\n";
1457 H.TMV_setToIdentity();
1458 xdbg<<
"After calculate H = "<<H<<std::endl;
1460 DVector g = J.transpose() * f;
1461 xdbg<<
"g = "<<g.transpose()<<std::endl;
1462 double normInfG = g.TMV_normInf();
1465 double mu = _tau * A.TMV_diag().TMV_normInf();
1466 A.EIGEN_diag() += mu;
1468 double delta = _delta0;
1469 bool shouldUseQuasiNewton =
false;
1472 dbg<<
"iter |f|inf Q |g|inf mu delta LM/QN\n";
1473 for(
int k=0;k<_maxIter;++k) {
1474 dbg<<k<<
" "<<normInfF<<
" "<<Q<<
" "<<normInfG<<
" "<< mu<<
" "<<
1475 delta<<
" "<<(shouldUseQuasiNewton?
"QN":
"LM")<<std::endl;
1476 xdbg<<
"k = "<<k<<std::endl;
1477 xdbg<<
"mu = "<<mu<<std::endl;
1478 xdbg<<
"delta = "<<delta<<std::endl;
1479 xdbg<<
"A = "<<A<<std::endl;
1480 xdbg<<
"H = "<<H<<std::endl;
1481 xdbg<<
"method = "<<(shouldUseQuasiNewton ?
"quasinewton\n" :
"LM\n");
1482 bool isBetter =
false;
1483 bool shouldSwitchMethod =
false;
1485 if (shouldUseQuasiNewton) {
1487 h = H.ldlt().solve(-g);
1490 h = A.ldlt().solve(-g);
1493 xdbg<<
"h = "<<h.transpose()<<std::endl;
1494 double normH = h.norm();
1496 if (shouldUseQuasiNewton && normH > delta) h *= delta/normH;
1499 xdbg<<
"xnew = "<<xNew.transpose()<<std::endl;
1500 this->calculateF(xNew,fNew);
1501 xdbg<<
"fnew = "<<fNew.transpose()<<std::endl;
1502 double QNew = 0.5*fNew.TMV_normSq();
1503 xdbg<<
"Qnew = "<<QNew<<std::endl;
1505 this->calculateJ(xNew,fNew,JNew);
1506 xdbg<<
"Jnew = "<<JNew<<std::endl;
1507 if (shouldUseQuasiNewton || QNew < Q) {
1508 gNew = JNew.transpose() * fNew;
1509 xdbg<<
"gnew = "<<gNew.transpose()<<std::endl;
1511 double normInfGNew = gNew.TMV_normInf();
1513 if (shouldUseQuasiNewton) {
1514 xdbg<<
"quasinewton\n";
1517 (QNew <= (1.+sqrtEps)*Q && normInfGNew < normInfG);
1518 xdbg<<
"better = "<<isBetter<<std::endl;
1519 shouldSwitchMethod = (normInfGNew >= normInfG);
1520 xdbg<<
"switchmethod = "<<shouldSwitchMethod<<std::endl;
1522 double rho = (Q-QNew) / (-(h.transpose()*g)(0,0)-0.5*(J*h).
TMV_normSq());
1524 delta = std::max(delta,3.*normH);
1525 }
else if (rho < 0.25) {
1527 double min_delta = _minStep * (x.norm()+_minStep);
1528 if (delta < min_delta) {
1529 dbg<<
"delta became too small ("<<
1530 delta<<
" < "<<min_delta<<
")\n";
1537 double min_delta = _minStep * (x.norm()+_minStep);
1538 if (delta < min_delta) {
1539 dbg<<
"delta became too small ("<<
1540 delta<<
" < "<<min_delta<<
")\n";
1553 double rho = (Q-QNew) / (-0.5*(h.transpose()*g)(0,0));
1554 mu *= std::max(1./3.,1.-std::pow(2.*rho-1.,3)); nu = 2.;
1555 xdbg<<
"check1: "<<normInfGNew<<
" <? "<<0.02*QNew<<std::endl;
1556 xdbg<<
"check2: "<<Q-QNew<<
" <? "<<0.02*QNew<<std::endl;
1557 if (std::min(normInfGNew,Q-QNew) < 0.02 * QNew) {
1559 if (count == 3) shouldSwitchMethod =
true;
1564 A = JNew.transpose() * JNew;
1565 A.EIGEN_diag() += mu;
1568 A.EIGEN_diag() += mu*(nu-1.); mu *= nu; nu *= 2.;
1571 shouldSwitchMethod = (nu >= 32.);
1573 xdbg<<
"better = "<<isBetter<<std::endl;
1574 xdbg<<
"switchmethod = "<<shouldSwitchMethod<<std::endl;
1575 xdbg<<
"count = "<<count<<std::endl;
1578 y = JNew.transpose()*(JNew*h) + (JNew-J).transpose()*fNew;
1579 double hy = (h.transpose()*
y)(0,0);
1580 xdbg<<
"hy = "<<hy<<std::endl;
1583 xdbg<<
"v = "<<v.transpose()<<std::endl;
1584 xdbg<<
"y = "<<
y.transpose()<<std::endl;
1585 double hv = (h.transpose()*v)(0,0);
1586 xdbg<<
"hv = "<<hv<<std::endl;
1587 H -= (1./hv) * (v * v.transpose());
1588 xdbg<<
"H -> "<<H<<std::endl;
1589 H += (1./hy) * (
y *
y.transpose());
1590 xdbg<<
"H -> "<<H<<std::endl;
1594 xdbg<<
"better"<<std::endl;
1595 x = xNew; f = fNew; Q = QNew; J = JNew; g = gNew;
1596 normInfF = f.TMV_normInf(); normInfG = normInfGNew;
1600 if (shouldSwitchMethod) {
1601 if (shouldUseQuasiNewton) {
1602 xdbg<<
"switch to LM\n";
1603 A = J.transpose() * J;
1605 A.EIGEN_diag() += mu;
1606 shouldUseQuasiNewton =
false;
1609 xdbg<<
"switch to quasinewton\n";
1610 delta = std::max(1.5*_minStep*(x.norm()+_minStep),0.2*normH);
1611 shouldUseQuasiNewton =
true;
1615 dbg<<
"Maximum iterations exceeded in Hybrid method\n";
1628 default :
dbg<<
"Unknown method\n";
return false;
1632 dbg<<
"Error encountered in NLSolver::Solve\n";
1640 const double eps = std::numeric_limits<double>::epsilon();
1642 throw std::runtime_error(
1643 "J not set before calling getCovariance");
1649 Eigen::JacobiSVD<DMatrix> SV_Solver_J(J, Eigen::ComputeThinU | Eigen::ComputeThinV);
1650 const DVector& svd_s = SV_Solver_J.singularValues();
1651 int kmax = svd_s.size();
1652 while(svd_s(kmax-1) < eps * svd_s(0)) --kmax;
1653 dbg<<
"In NLSolver::getCovariance:\n";
1654 dbg<<
"Using kmax = "<<kmax<<
" size = "<<svd_s.size()<<std::endl;
1659 const DMatrix& svd_v = SV_Solver_J.matrixV();
1660 DVector sm2 = svd_s.array().square().inverse().matrix();
1661 sm2.TMV_subVector(kmax, svd_s.size()).setZero();
1662 cov = svd_v * sm2.asDiagonal() * svd_v.transpose();
1664 Eigen::ColPivHouseholderQR<DMatrix> QR_Solver_J(J);
1670 QR_Solver_J.matrixQR().triangularView<Eigen::Upper>().transpose().solveInPlace(cov);
1671 QR_Solver_J.matrixQR().triangularView<Eigen::Upper>().solveInPlace(cov);
1678 throw std::runtime_error(
1679 "J not set before calling getInverseCovariance");
1682 invCov = J.transpose() * J;
virtual void getCovariance(DMatrix &cov) const
virtual void calculateF(const DVector &x, DVector &f) const =0
bool solveDogleg(DVector &x, DVector &f) const
virtual bool solve(DVector &x, DVector &f) const
bool solveHybrid(DVector &x, DVector &f) const
virtual void calculateJ(const DVector &x, const DVector &f, DMatrix &j) const
std::auto_ptr< DMatrix > _pJ
#define TMV_maxAbsElement()
virtual bool testJ(const DVector &, DVector &, std::ostream *os=0, double relerr=0.) const
virtual void getInverseCovariance(DMatrix &invcov) const
afw::table::Key< double > b