13 #ifndef EIGEN_HYBRIDNONLINEARSOLVER_H
14 #define EIGEN_HYBRIDNONLINEARSOLVER_H
16 #include "./InternalHeaderCheck.h"
20 namespace HybridNonLinearSolverSpace {
23 ImproperInputParameters = 0,
24 RelativeErrorTooSmall = 1,
25 TooManyFunctionEvaluation = 2,
27 NotMakingProgressJacobian = 4,
28 NotMakingProgressIterations = 5,
44 template<
typename FunctorType,
typename Scalar=
double>
48 typedef DenseIndex Index;
51 : functor(_functor) { nfev=njev=iter = 0; fnorm= 0.; useExternalScaling=
false;}
55 : factor(Scalar(100.))
58 , nb_of_subdiagonals(-1)
59 , nb_of_superdiagonals(-1)
60 , epsfcn(Scalar(0.)) {}
64 Index nb_of_subdiagonals;
65 Index nb_of_superdiagonals;
73 HybridNonLinearSolverSpace::Status hybrj1(
78 HybridNonLinearSolverSpace::Status solveInit(
FVectorType &x);
79 HybridNonLinearSolverSpace::Status solveOneStep(
FVectorType &x);
80 HybridNonLinearSolverSpace::Status solve(
FVectorType &x);
82 HybridNonLinearSolverSpace::Status hybrd1(
87 HybridNonLinearSolverSpace::Status solveNumericalDiffInit(
FVectorType &x);
88 HybridNonLinearSolverSpace::Status solveNumericalDiffOneStep(
FVectorType &x);
89 HybridNonLinearSolverSpace::Status solveNumericalDiff(
FVectorType &x);
91 void resetParameters(
void) { parameters = Parameters(); }
92 Parameters parameters;
100 bool useExternalScaling;
102 FunctorType &functor;
111 Scalar pnorm, xnorm, fnorm1;
112 Index nslow1, nslow2;
114 Scalar actred, prered;
122 template<
typename FunctorType,
typename Scalar>
123 HybridNonLinearSolverSpace::Status
132 if (n <= 0 || tol < 0.)
133 return HybridNonLinearSolverSpace::ImproperInputParameters;
136 parameters.maxfev = 100*(n+1);
137 parameters.xtol = tol;
138 diag.setConstant(n, 1.);
139 useExternalScaling =
true;
143 template<
typename FunctorType,
typename Scalar>
144 HybridNonLinearSolverSpace::Status
145 HybridNonLinearSolver<FunctorType,Scalar>::solveInit(FVectorType &x)
149 wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(n);
153 if (!useExternalScaling)
155 eigen_assert( (!useExternalScaling || diag.size()==n) &&
"When useExternalScaling is set, the caller must provide a valid 'diag'");
162 if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0. )
163 return HybridNonLinearSolverSpace::ImproperInputParameters;
164 if (useExternalScaling)
165 for (
Index j = 0; j < n; ++j)
167 return HybridNonLinearSolverSpace::ImproperInputParameters;
172 if ( functor(x, fvec) < 0)
173 return HybridNonLinearSolverSpace::UserAsked;
174 fnorm = fvec.stableNorm();
183 return HybridNonLinearSolverSpace::Running;
186 template<
typename FunctorType,
typename Scalar>
187 HybridNonLinearSolverSpace::Status
188 HybridNonLinearSolver<FunctorType,Scalar>::solveOneStep(FVectorType &x)
192 eigen_assert(x.size()==n);
195 std::vector<JacobiRotation<Scalar> > v_givens(n), w_givens(n);
200 if ( functor.df(x, fjac) < 0)
201 return HybridNonLinearSolverSpace::UserAsked;
204 wa2 = fjac.colwise().blueNorm();
209 if (!useExternalScaling)
210 for (j = 0; j < n; ++j)
211 diag[j] = (wa2[j]==0.) ? 1. : wa2[j];
215 xnorm = diag.cwiseProduct(x).stableNorm();
216 delta = parameters.factor * xnorm;
218 delta = parameters.factor;
222 HouseholderQR<JacobianType> qrfac(fjac);
225 R = qrfac.matrixQR();
228 fjac = qrfac.householderQ();
231 qtf = fjac.transpose() * fvec;
234 if (!useExternalScaling)
235 diag = diag.cwiseMax(wa2);
239 internal::dogleg<Scalar>(R, diag, qtf, delta, wa1);
244 pnorm = diag.cwiseProduct(wa1).stableNorm();
248 delta = (std::min)(delta,pnorm);
251 if ( functor(wa2, wa4) < 0)
252 return HybridNonLinearSolverSpace::UserAsked;
254 fnorm1 = wa4.stableNorm();
259 actred = 1. - numext::abs2(fnorm1 / fnorm);
262 wa3 = R.template triangularView<Upper>()*wa1 + qtf;
263 temp = wa3.stableNorm();
266 prered = 1. - numext::abs2(temp / fnorm);
271 ratio = actred / prered;
274 if (ratio < Scalar(.1)) {
277 delta = Scalar(.5) * delta;
281 if (ratio >= Scalar(.5) || ncsuc > 1)
282 delta = (std::max)(delta, pnorm / Scalar(.5));
283 if (
abs(ratio - 1.) <= Scalar(.1)) {
284 delta = pnorm / Scalar(.5);
289 if (ratio >= Scalar(1e-4)) {
292 wa2 = diag.cwiseProduct(x);
294 xnorm = wa2.stableNorm();
301 if (actred >= Scalar(.001))
305 if (actred >= Scalar(.1))
309 if (delta <= parameters.xtol * xnorm || fnorm == 0.)
310 return HybridNonLinearSolverSpace::RelativeErrorTooSmall;
313 if (nfev >= parameters.maxfev)
314 return HybridNonLinearSolverSpace::TooManyFunctionEvaluation;
315 if (Scalar(.1) * (std::max)(Scalar(.1) * delta, pnorm) <= NumTraits<Scalar>::epsilon() * xnorm)
316 return HybridNonLinearSolverSpace::TolTooSmall;
318 return HybridNonLinearSolverSpace::NotMakingProgressJacobian;
320 return HybridNonLinearSolverSpace::NotMakingProgressIterations;
328 wa1 = diag.cwiseProduct( diag.cwiseProduct(wa1)/pnorm );
329 wa2 = fjac.transpose() * wa4;
330 if (ratio >= Scalar(1e-4))
332 wa2 = (wa2-wa3)/pnorm;
335 internal::r1updt<Scalar>(R, wa1, v_givens, w_givens, wa2, wa3, &sing);
336 internal::r1mpyq<Scalar>(n, n, fjac.data(), v_givens, w_givens);
337 internal::r1mpyq<Scalar>(1, n, qtf.data(), v_givens, w_givens);
341 return HybridNonLinearSolverSpace::Running;
344 template<
typename FunctorType,
typename Scalar>
345 HybridNonLinearSolverSpace::Status
346 HybridNonLinearSolver<FunctorType,Scalar>::solve(FVectorType &x)
348 HybridNonLinearSolverSpace::Status status = solveInit(x);
349 if (status==HybridNonLinearSolverSpace::ImproperInputParameters)
351 while (status==HybridNonLinearSolverSpace::Running)
352 status = solveOneStep(x);
358 template<
typename FunctorType,
typename Scalar>
359 HybridNonLinearSolverSpace::Status
360 HybridNonLinearSolver<FunctorType,Scalar>::hybrd1(
368 if (n <= 0 || tol < 0.)
369 return HybridNonLinearSolverSpace::ImproperInputParameters;
372 parameters.maxfev = 200*(n+1);
373 parameters.xtol = tol;
375 diag.setConstant(n, 1.);
376 useExternalScaling =
true;
377 return solveNumericalDiff(x);
380 template<
typename FunctorType,
typename Scalar>
381 HybridNonLinearSolverSpace::Status
382 HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiffInit(FVectorType &x)
386 if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1;
387 if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1;
389 wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(n);
393 if (!useExternalScaling)
395 eigen_assert( (!useExternalScaling || diag.size()==n) &&
"When useExternalScaling is set, the caller must provide a valid 'diag'");
402 if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.nb_of_subdiagonals< 0 || parameters.nb_of_superdiagonals< 0 || parameters.factor <= 0. )
403 return HybridNonLinearSolverSpace::ImproperInputParameters;
404 if (useExternalScaling)
405 for (
Index j = 0; j < n; ++j)
407 return HybridNonLinearSolverSpace::ImproperInputParameters;
412 if ( functor(x, fvec) < 0)
413 return HybridNonLinearSolverSpace::UserAsked;
414 fnorm = fvec.stableNorm();
423 return HybridNonLinearSolverSpace::Running;
426 template<
typename FunctorType,
typename Scalar>
427 HybridNonLinearSolverSpace::Status
428 HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiffOneStep(FVectorType &x)
436 std::vector<JacobiRotation<Scalar> > v_givens(n), w_givens(n);
439 if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1;
440 if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1;
443 if (internal::fdjac1(functor, x, fvec, fjac, parameters.nb_of_subdiagonals, parameters.nb_of_superdiagonals, parameters.epsfcn) <0)
444 return HybridNonLinearSolverSpace::UserAsked;
445 nfev += (std::min)(parameters.nb_of_subdiagonals+parameters.nb_of_superdiagonals+ 1, n);
447 wa2 = fjac.colwise().blueNorm();
452 if (!useExternalScaling)
453 for (j = 0; j < n; ++j)
454 diag[j] = (wa2[j]==0.) ? 1. : wa2[j];
458 xnorm = diag.cwiseProduct(x).stableNorm();
459 delta = parameters.factor * xnorm;
461 delta = parameters.factor;
465 HouseholderQR<JacobianType> qrfac(fjac);
468 R = qrfac.matrixQR();
471 fjac = qrfac.householderQ();
474 qtf = fjac.transpose() * fvec;
477 if (!useExternalScaling)
478 diag = diag.cwiseMax(wa2);
482 internal::dogleg<Scalar>(R, diag, qtf, delta, wa1);
487 pnorm = diag.cwiseProduct(wa1).stableNorm();
491 delta = (std::min)(delta,pnorm);
494 if ( functor(wa2, wa4) < 0)
495 return HybridNonLinearSolverSpace::UserAsked;
497 fnorm1 = wa4.stableNorm();
502 actred = 1. - numext::abs2(fnorm1 / fnorm);
505 wa3 = R.template triangularView<Upper>()*wa1 + qtf;
506 temp = wa3.stableNorm();
509 prered = 1. - numext::abs2(temp / fnorm);
514 ratio = actred / prered;
517 if (ratio < Scalar(.1)) {
520 delta = Scalar(.5) * delta;
524 if (ratio >= Scalar(.5) || ncsuc > 1)
525 delta = (std::max)(delta, pnorm / Scalar(.5));
526 if (
abs(ratio - 1.) <= Scalar(.1)) {
527 delta = pnorm / Scalar(.5);
532 if (ratio >= Scalar(1e-4)) {
535 wa2 = diag.cwiseProduct(x);
537 xnorm = wa2.stableNorm();
544 if (actred >= Scalar(.001))
548 if (actred >= Scalar(.1))
552 if (delta <= parameters.xtol * xnorm || fnorm == 0.)
553 return HybridNonLinearSolverSpace::RelativeErrorTooSmall;
556 if (nfev >= parameters.maxfev)
557 return HybridNonLinearSolverSpace::TooManyFunctionEvaluation;
558 if (Scalar(.1) * (std::max)(Scalar(.1) * delta, pnorm) <= NumTraits<Scalar>::epsilon() * xnorm)
559 return HybridNonLinearSolverSpace::TolTooSmall;
561 return HybridNonLinearSolverSpace::NotMakingProgressJacobian;
563 return HybridNonLinearSolverSpace::NotMakingProgressIterations;
571 wa1 = diag.cwiseProduct( diag.cwiseProduct(wa1)/pnorm );
572 wa2 = fjac.transpose() * wa4;
573 if (ratio >= Scalar(1e-4))
575 wa2 = (wa2-wa3)/pnorm;
578 internal::r1updt<Scalar>(R, wa1, v_givens, w_givens, wa2, wa3, &sing);
579 internal::r1mpyq<Scalar>(n, n, fjac.data(), v_givens, w_givens);
580 internal::r1mpyq<Scalar>(1, n, qtf.data(), v_givens, w_givens);
584 return HybridNonLinearSolverSpace::Running;
587 template<
typename FunctorType,
typename Scalar>
588 HybridNonLinearSolverSpace::Status
589 HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiff(FVectorType &x)
591 HybridNonLinearSolverSpace::Status status = solveNumericalDiffInit(x);
592 if (status==HybridNonLinearSolverSpace::ImproperInputParameters)
594 while (status==HybridNonLinearSolverSpace::Running)
595 status = solveNumericalDiffOneStep(x);
Finds a zero of a system of n nonlinear functions in n variables by a modification of the Powell hybr...
Definition: HybridNonLinearSolver.h:46
Namespace containing all symbols from the Eigen library.
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)