13 #ifndef EIGEN_HYBRIDNONLINEARSOLVER_H
14 #define EIGEN_HYBRIDNONLINEARSOLVER_H
18 namespace HybridNonLinearSolverSpace {
21 ImproperInputParameters = 0,
22 RelativeErrorTooSmall = 1,
23 TooManyFunctionEvaluation = 2,
25 NotMakingProgressJacobian = 4,
26 NotMakingProgressIterations = 5,
42 template<
typename FunctorType,
typename Scalar=
double>
46 typedef DenseIndex Index;
49 : functor(_functor) { nfev=njev=iter = 0; fnorm= 0.; useExternalScaling=
false;}
53 : factor(Scalar(100.))
55 , xtol(std::sqrt(NumTraits<Scalar>::epsilon()))
56 , nb_of_subdiagonals(-1)
57 , nb_of_superdiagonals(-1)
58 , epsfcn(Scalar(0.)) {}
62 Index nb_of_subdiagonals;
63 Index nb_of_superdiagonals;
66 typedef Matrix< Scalar, Dynamic, 1 > FVectorType;
67 typedef Matrix< Scalar, Dynamic, Dynamic > JacobianType;
69 typedef Matrix< Scalar, Dynamic, Dynamic > UpperTriangularType;
71 HybridNonLinearSolverSpace::Status hybrj1(
73 const Scalar tol = std::sqrt(NumTraits<Scalar>::epsilon())
76 HybridNonLinearSolverSpace::Status solveInit(FVectorType &x);
77 HybridNonLinearSolverSpace::Status solveOneStep(FVectorType &x);
78 HybridNonLinearSolverSpace::Status solve(FVectorType &x);
80 HybridNonLinearSolverSpace::Status hybrd1(
82 const Scalar tol = std::sqrt(NumTraits<Scalar>::epsilon())
85 HybridNonLinearSolverSpace::Status solveNumericalDiffInit(FVectorType &x);
86 HybridNonLinearSolverSpace::Status solveNumericalDiffOneStep(FVectorType &x);
87 HybridNonLinearSolverSpace::Status solveNumericalDiff(FVectorType &x);
89 void resetParameters(
void) { parameters = Parameters(); }
90 Parameters parameters;
91 FVectorType fvec, qtf, diag;
93 UpperTriangularType R;
98 bool useExternalScaling;
100 FunctorType &functor;
109 Scalar pnorm, xnorm, fnorm1;
110 Index nslow1, nslow2;
112 Scalar actred, prered;
113 FVectorType wa1, wa2, wa3, wa4;
120 template<
typename FunctorType,
typename Scalar>
121 HybridNonLinearSolverSpace::Status
130 if (n <= 0 || tol < 0.)
131 return HybridNonLinearSolverSpace::ImproperInputParameters;
134 parameters.maxfev = 100*(n+1);
135 parameters.xtol = tol;
136 diag.setConstant(n, 1.);
137 useExternalScaling =
true;
141 template<
typename FunctorType,
typename Scalar>
142 HybridNonLinearSolverSpace::Status
143 HybridNonLinearSolver<FunctorType,Scalar>::solveInit(FVectorType &x)
147 wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(n);
151 if (!useExternalScaling)
153 eigen_assert( (!useExternalScaling || diag.size()==n) ||
"When useExternalScaling is set, the caller must provide a valid 'diag'");
160 if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0. )
161 return HybridNonLinearSolverSpace::ImproperInputParameters;
162 if (useExternalScaling)
163 for (Index j = 0; j < n; ++j)
165 return HybridNonLinearSolverSpace::ImproperInputParameters;
170 if ( functor(x, fvec) < 0)
171 return HybridNonLinearSolverSpace::UserAsked;
172 fnorm = fvec.stableNorm();
181 return HybridNonLinearSolverSpace::Running;
184 template<
typename FunctorType,
typename Scalar>
185 HybridNonLinearSolverSpace::Status
186 HybridNonLinearSolver<FunctorType,Scalar>::solveOneStep(FVectorType &x)
190 eigen_assert(x.size()==n);
193 std::vector<JacobiRotation<Scalar> > v_givens(n), w_givens(n);
198 if ( functor.df(x, fjac) < 0)
199 return HybridNonLinearSolverSpace::UserAsked;
202 wa2 = fjac.colwise().blueNorm();
207 if (!useExternalScaling)
208 for (j = 0; j < n; ++j)
209 diag[j] = (wa2[j]==0.) ? 1. : wa2[j];
213 xnorm = diag.cwiseProduct(x).stableNorm();
214 delta = parameters.factor * xnorm;
216 delta = parameters.factor;
220 HouseholderQR<JacobianType> qrfac(fjac);
223 R = qrfac.matrixQR();
226 fjac = qrfac.householderQ();
229 qtf = fjac.transpose() * fvec;
232 if (!useExternalScaling)
233 diag = diag.cwiseMax(wa2);
237 internal::dogleg<Scalar>(R, diag, qtf, delta, wa1);
242 pnorm = diag.cwiseProduct(wa1).stableNorm();
246 delta = (std::min)(delta,pnorm);
249 if ( functor(wa2, wa4) < 0)
250 return HybridNonLinearSolverSpace::UserAsked;
252 fnorm1 = wa4.stableNorm();
257 actred = 1. - numext::abs2(fnorm1 / fnorm);
260 wa3 = R.template triangularView<Upper>()*wa1 + qtf;
261 temp = wa3.stableNorm();
264 prered = 1. - numext::abs2(temp / fnorm);
269 ratio = actred / prered;
272 if (ratio < Scalar(.1)) {
275 delta = Scalar(.5) * delta;
279 if (ratio >= Scalar(.5) || ncsuc > 1)
280 delta = (std::max)(delta, pnorm / Scalar(.5));
281 if (abs(ratio - 1.) <= Scalar(.1)) {
282 delta = pnorm / Scalar(.5);
287 if (ratio >= Scalar(1e-4)) {
290 wa2 = diag.cwiseProduct(x);
292 xnorm = wa2.stableNorm();
299 if (actred >= Scalar(.001))
303 if (actred >= Scalar(.1))
307 if (delta <= parameters.xtol * xnorm || fnorm == 0.)
308 return HybridNonLinearSolverSpace::RelativeErrorTooSmall;
311 if (nfev >= parameters.maxfev)
312 return HybridNonLinearSolverSpace::TooManyFunctionEvaluation;
313 if (Scalar(.1) * (std::max)(Scalar(.1) * delta, pnorm) <= NumTraits<Scalar>::epsilon() * xnorm)
314 return HybridNonLinearSolverSpace::TolTooSmall;
316 return HybridNonLinearSolverSpace::NotMakingProgressJacobian;
318 return HybridNonLinearSolverSpace::NotMakingProgressIterations;
326 wa1 = diag.cwiseProduct( diag.cwiseProduct(wa1)/pnorm );
327 wa2 = fjac.transpose() * wa4;
328 if (ratio >= Scalar(1e-4))
330 wa2 = (wa2-wa3)/pnorm;
333 internal::r1updt<Scalar>(R, wa1, v_givens, w_givens, wa2, wa3, &sing);
334 internal::r1mpyq<Scalar>(n, n, fjac.data(), v_givens, w_givens);
335 internal::r1mpyq<Scalar>(1, n, qtf.data(), v_givens, w_givens);
339 return HybridNonLinearSolverSpace::Running;
342 template<
typename FunctorType,
typename Scalar>
343 HybridNonLinearSolverSpace::Status
344 HybridNonLinearSolver<FunctorType,Scalar>::solve(FVectorType &x)
346 HybridNonLinearSolverSpace::Status status = solveInit(x);
347 if (status==HybridNonLinearSolverSpace::ImproperInputParameters)
349 while (status==HybridNonLinearSolverSpace::Running)
350 status = solveOneStep(x);
356 template<
typename FunctorType,
typename Scalar>
357 HybridNonLinearSolverSpace::Status
358 HybridNonLinearSolver<FunctorType,Scalar>::hybrd1(
366 if (n <= 0 || tol < 0.)
367 return HybridNonLinearSolverSpace::ImproperInputParameters;
370 parameters.maxfev = 200*(n+1);
371 parameters.xtol = tol;
373 diag.setConstant(n, 1.);
374 useExternalScaling =
true;
375 return solveNumericalDiff(x);
378 template<
typename FunctorType,
typename Scalar>
379 HybridNonLinearSolverSpace::Status
380 HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiffInit(FVectorType &x)
384 if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1;
385 if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1;
387 wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(n);
391 if (!useExternalScaling)
393 eigen_assert( (!useExternalScaling || diag.size()==n) ||
"When useExternalScaling is set, the caller must provide a valid 'diag'");
400 if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.nb_of_subdiagonals< 0 || parameters.nb_of_superdiagonals< 0 || parameters.factor <= 0. )
401 return HybridNonLinearSolverSpace::ImproperInputParameters;
402 if (useExternalScaling)
403 for (Index j = 0; j < n; ++j)
405 return HybridNonLinearSolverSpace::ImproperInputParameters;
410 if ( functor(x, fvec) < 0)
411 return HybridNonLinearSolverSpace::UserAsked;
412 fnorm = fvec.stableNorm();
421 return HybridNonLinearSolverSpace::Running;
424 template<
typename FunctorType,
typename Scalar>
425 HybridNonLinearSolverSpace::Status
426 HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiffOneStep(FVectorType &x)
434 std::vector<JacobiRotation<Scalar> > v_givens(n), w_givens(n);
437 if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1;
438 if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1;
441 if (internal::fdjac1(functor, x, fvec, fjac, parameters.nb_of_subdiagonals, parameters.nb_of_superdiagonals, parameters.epsfcn) <0)
442 return HybridNonLinearSolverSpace::UserAsked;
443 nfev += (std::min)(parameters.nb_of_subdiagonals+parameters.nb_of_superdiagonals+ 1, n);
445 wa2 = fjac.colwise().blueNorm();
450 if (!useExternalScaling)
451 for (j = 0; j < n; ++j)
452 diag[j] = (wa2[j]==0.) ? 1. : wa2[j];
456 xnorm = diag.cwiseProduct(x).stableNorm();
457 delta = parameters.factor * xnorm;
459 delta = parameters.factor;
463 HouseholderQR<JacobianType> qrfac(fjac);
466 R = qrfac.matrixQR();
469 fjac = qrfac.householderQ();
472 qtf = fjac.transpose() * fvec;
475 if (!useExternalScaling)
476 diag = diag.cwiseMax(wa2);
480 internal::dogleg<Scalar>(R, diag, qtf, delta, wa1);
485 pnorm = diag.cwiseProduct(wa1).stableNorm();
489 delta = (std::min)(delta,pnorm);
492 if ( functor(wa2, wa4) < 0)
493 return HybridNonLinearSolverSpace::UserAsked;
495 fnorm1 = wa4.stableNorm();
500 actred = 1. - numext::abs2(fnorm1 / fnorm);
503 wa3 = R.template triangularView<Upper>()*wa1 + qtf;
504 temp = wa3.stableNorm();
507 prered = 1. - numext::abs2(temp / fnorm);
512 ratio = actred / prered;
515 if (ratio < Scalar(.1)) {
518 delta = Scalar(.5) * delta;
522 if (ratio >= Scalar(.5) || ncsuc > 1)
523 delta = (std::max)(delta, pnorm / Scalar(.5));
524 if (abs(ratio - 1.) <= Scalar(.1)) {
525 delta = pnorm / Scalar(.5);
530 if (ratio >= Scalar(1e-4)) {
533 wa2 = diag.cwiseProduct(x);
535 xnorm = wa2.stableNorm();
542 if (actred >= Scalar(.001))
546 if (actred >= Scalar(.1))
550 if (delta <= parameters.xtol * xnorm || fnorm == 0.)
551 return HybridNonLinearSolverSpace::RelativeErrorTooSmall;
554 if (nfev >= parameters.maxfev)
555 return HybridNonLinearSolverSpace::TooManyFunctionEvaluation;
556 if (Scalar(.1) * (std::max)(Scalar(.1) * delta, pnorm) <= NumTraits<Scalar>::epsilon() * xnorm)
557 return HybridNonLinearSolverSpace::TolTooSmall;
559 return HybridNonLinearSolverSpace::NotMakingProgressJacobian;
561 return HybridNonLinearSolverSpace::NotMakingProgressIterations;
569 wa1 = diag.cwiseProduct( diag.cwiseProduct(wa1)/pnorm );
570 wa2 = fjac.transpose() * wa4;
571 if (ratio >= Scalar(1e-4))
573 wa2 = (wa2-wa3)/pnorm;
576 internal::r1updt<Scalar>(R, wa1, v_givens, w_givens, wa2, wa3, &sing);
577 internal::r1mpyq<Scalar>(n, n, fjac.data(), v_givens, w_givens);
578 internal::r1mpyq<Scalar>(1, n, qtf.data(), v_givens, w_givens);
582 return HybridNonLinearSolverSpace::Running;
585 template<
typename FunctorType,
typename Scalar>
586 HybridNonLinearSolverSpace::Status
587 HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiff(FVectorType &x)
589 HybridNonLinearSolverSpace::Status status = solveNumericalDiffInit(x);
590 if (status==HybridNonLinearSolverSpace::ImproperInputParameters)
592 while (status==HybridNonLinearSolverSpace::Running)
593 status = solveNumericalDiffOneStep(x);
599 #endif // EIGEN_HYBRIDNONLINEARSOLVER_H
Finds a zero of a system of n nonlinear functions in n variables by a modification of the Powell hybr...
Definition: HybridNonLinearSolver.h:43