aboutsummaryrefslogtreecommitdiffhomepage
path: root/unsupported/Eigen/src/NonLinear/HybridNonLinearSolver.h
diff options
context:
space:
mode:
Diffstat (limited to 'unsupported/Eigen/src/NonLinear/HybridNonLinearSolver.h')
-rw-r--r--unsupported/Eigen/src/NonLinear/HybridNonLinearSolver.h358
1 files changed, 358 insertions, 0 deletions
diff --git a/unsupported/Eigen/src/NonLinear/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinear/HybridNonLinearSolver.h
index 0545cfe79..7836367ad 100644
--- a/unsupported/Eigen/src/NonLinear/HybridNonLinearSolver.h
+++ b/unsupported/Eigen/src/NonLinear/HybridNonLinearSolver.h
@@ -20,6 +20,23 @@ public:
const Scalar xtol = ei_sqrt(epsilon<Scalar>())
);
+ int solveNumericalDiff(
+ Matrix< Scalar, Dynamic, 1 > &x,
+ const Scalar tol = ei_sqrt(epsilon<Scalar>())
+ );
+ int solveNumericalDiff(
+ Matrix< Scalar, Dynamic, 1 > &x,
+ int &nfev,
+ Matrix< Scalar, Dynamic, 1 > &diag,
+ const int mode=1,
+ int nb_of_subdiagonals = -1,
+ int nb_of_superdiagonals = -1,
+ const int maxfev = 2000,
+ const Scalar factor = Scalar(100.),
+ const Scalar xtol = ei_sqrt(epsilon<Scalar>()),
+ const Scalar epsfcn = Scalar(0.)
+ );
+
Matrix< Scalar, Dynamic, 1 > fvec;
Matrix< Scalar, Dynamic, Dynamic > fjac;
Matrix< Scalar, Dynamic, 1 > R;
@@ -357,3 +374,344 @@ algo_end:
return info;
}
+
+
+template<typename FunctorType, typename Scalar>
+int HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiff(
+ Matrix< Scalar, Dynamic, 1 > &x,
+ const Scalar tol
+ )
+{
+ const int n = x.size();
+ int info, nfev=0;
+ Matrix< Scalar, Dynamic, 1> diag;
+
+ /* check the input parameters for errors. */
+ if (n <= 0 || tol < 0.) {
+ printf("HybridNonLinearSolver::solve() bad args : n,tol,...");
+ return 0;
+ }
+
+ diag.setConstant(n, 1.);
+ info = solveNumericalDiff(
+ x,
+ nfev,
+ diag,
+ 2,
+ -1, -1,
+ (n+1)*200,
+ 100.,
+ tol, Scalar(0.)
+ );
+ return (info==5)?4:info;
+}
+
+
+template<typename FunctorType, typename Scalar>
+int HybridNonLinearSolver<FunctorType,Scalar>::solveNumericalDiff(
+ Matrix< Scalar, Dynamic, 1 > &x,
+ int &nfev,
+ Matrix< Scalar, Dynamic, 1 > &diag,
+ const int mode,
+ int nb_of_subdiagonals,
+ int nb_of_superdiagonals,
+ const int maxfev,
+ const Scalar factor,
+ const Scalar xtol,
+ const Scalar epsfcn
+ )
+{
+ const int n = x.size();
+ Matrix< Scalar, Dynamic, 1 > wa1(n), wa2(n), wa3(n), wa4(n);
+
+
+ if (nb_of_subdiagonals<0) nb_of_subdiagonals = n-1;
+ if (nb_of_superdiagonals<0) nb_of_superdiagonals = n-1;
+ qtf.resize(n);
+ R.resize( (n*(n+1))/2);
+ fjac.resize(n, n);
+ fvec.resize(n);
+
+ /* Local variables */
+ int i, j, l, iwa[1];
+ Scalar sum;
+ int sing;
+ int iter;
+ Scalar temp;
+ int msum, iflag;
+ Scalar delta;
+ int jeval;
+ int ncsuc;
+ Scalar ratio;
+ Scalar fnorm;
+ Scalar pnorm, xnorm, fnorm1;
+ int nslow1, nslow2;
+ int ncfail;
+ Scalar actred, prered;
+ int info;
+
+ /* Function Body */
+
+ info = 0;
+ iflag = 0;
+ nfev = 0;
+
+ /* check the input parameters for errors. */
+
+ if (n <= 0 || xtol < 0. || maxfev <= 0 || nb_of_subdiagonals < 0 || nb_of_superdiagonals < 0 || factor <= 0. )
+ goto algo_end;
+ if (mode == 2)
+ for (j = 0; j < n; ++j)
+ if (diag[j] <= 0.) goto algo_end;
+
+ /* evaluate the function at the starting point */
+ /* and calculate its norm. */
+
+ iflag = functor.f(x, fvec);
+ nfev = 1;
+ if (iflag < 0)
+ goto algo_end;
+ fnorm = fvec.stableNorm();
+
+ /* determine the number of calls to fcn needed to compute */
+ /* the jacobian matrix. */
+
+ /* Computing MIN */
+ msum = std::min(nb_of_subdiagonals + nb_of_superdiagonals + 1, n);
+
+ /* initialize iteration counter and monitors. */
+
+ iter = 1;
+ ncsuc = 0;
+ ncfail = 0;
+ nslow1 = 0;
+ nslow2 = 0;
+
+ /* beginning of the outer loop. */
+
+ while (true) {
+ jeval = true;
+
+ /* calculate the jacobian matrix. */
+
+ iflag = ei_fdjac1(functor, x, fvec, fjac,
+ nb_of_subdiagonals, nb_of_superdiagonals, epsfcn);
+ nfev += msum;
+ if (iflag < 0)
+ break;
+
+ /* compute the qr factorization of the jacobian. */
+
+ ei_qrfac<Scalar>(n, n, fjac.data(), fjac.rows(), false, iwa, 1, wa1.data(), wa2.data());
+
+ /* on the first iteration and if mode is 1, scale according */
+ /* to the norms of the columns of the initial jacobian. */
+
+ if (iter == 1) {
+ if (mode != 2)
+ for (j = 0; j < n; ++j) {
+ diag[j] = wa2[j];
+ if (wa2[j] == 0.)
+ diag[j] = 1.;
+ }
+
+ /* on the first iteration, calculate the norm of the scaled x */
+ /* and initialize the step bound delta. */
+
+ wa3 = diag.cwise() * x;
+ xnorm = wa3.stableNorm();
+ delta = factor * xnorm;
+ if (delta == 0.)
+ delta = factor;
+ }
+
+ /* form (q transpose)*fvec and store in qtf. */
+
+ qtf = fvec;
+ for (j = 0; j < n; ++j)
+ if (fjac(j,j) != 0.) {
+ sum = 0.;
+ for (i = j; i < n; ++i)
+ sum += fjac(i,j) * qtf[i];
+ temp = -sum / fjac(j,j);
+ for (i = j; i < n; ++i)
+ qtf[i] += fjac(i,j) * temp;
+ }
+
+ /* copy the triangular factor of the qr factorization into r. */
+
+ sing = false;
+ for (j = 0; j < n; ++j) {
+ l = j;
+ if (j)
+ for (i = 0; i < j; ++i) {
+ R[l] = fjac(i,j);
+ l = l + n - i -1;
+ }
+ R[l] = wa1[j];
+ if (wa1[j] == 0.)
+ sing = true;
+ }
+
+ /* accumulate the orthogonal factor in fjac. */
+
+ ei_qform<Scalar>(n, n, fjac.data(), fjac.rows(), wa1.data());
+
+ /* rescale if necessary. */
+
+ /* Computing MAX */
+ if (mode != 2)
+ diag = diag.cwise().max(wa2);
+
+ /* beginning of the inner loop. */
+
+ while (true) {
+
+ /* determine the direction p. */
+
+ ei_dogleg<Scalar>(R, diag, qtf, delta, wa1);
+
+ /* store the direction p and x + p. calculate the norm of p. */
+
+ wa1 = -wa1;
+ wa2 = x + wa1;
+ wa3 = diag.cwise() * wa1;
+ pnorm = wa3.stableNorm();
+
+ /* on the first iteration, adjust the initial step bound. */
+
+ if (iter == 1)
+ delta = std::min(delta,pnorm);
+
+ /* evaluate the function at x + p and calculate its norm. */
+
+ iflag = functor.f(wa2, wa4);
+ ++nfev;
+ if (iflag < 0)
+ goto algo_end;
+ fnorm1 = wa4.stableNorm();
+
+ /* compute the scaled actual reduction. */
+
+ actred = -1.;
+ if (fnorm1 < fnorm) /* Computing 2nd power */
+ actred = 1. - ei_abs2(fnorm1 / fnorm);
+
+ /* compute the scaled predicted reduction. */
+
+ l = 0;
+ for (i = 0; i < n; ++i) {
+ sum = 0.;
+ for (j = i; j < n; ++j) {
+ sum += R[l] * wa1[j];
+ ++l;
+ }
+ wa3[i] = qtf[i] + sum;
+ }
+ temp = wa3.stableNorm();
+ prered = 0.;
+ if (temp < fnorm) /* Computing 2nd power */
+ prered = 1. - ei_abs2(temp / fnorm);
+
+ /* compute the ratio of the actual to the predicted */
+ /* reduction. */
+
+ ratio = 0.;
+ if (prered > 0.)
+ ratio = actred / prered;
+
+ /* update the step bound. */
+
+ if (ratio < Scalar(.1)) {
+ ncsuc = 0;
+ ++ncfail;
+ delta = Scalar(.5) * delta;
+ } else {
+ ncfail = 0;
+ ++ncsuc;
+ if (ratio >= Scalar(.5) || ncsuc > 1) /* Computing MAX */
+ delta = std::max(delta, pnorm / Scalar(.5));
+ if (ei_abs(ratio - 1.) <= Scalar(.1)) {
+ delta = pnorm / Scalar(.5);
+ }
+ }
+
+ /* test for successful iteration. */
+
+ if (ratio >= Scalar(1e-4)) {
+ /* successful iteration. update x, fvec, and their norms. */
+ x = wa2;
+ wa2 = diag.cwise() * x;
+ fvec = wa4;
+ xnorm = wa2.stableNorm();
+ fnorm = fnorm1;
+ ++iter;
+ }
+
+ /* determine the progress of the iteration. */
+
+ ++nslow1;
+ if (actred >= Scalar(.001))
+ nslow1 = 0;
+ if (jeval)
+ ++nslow2;
+ if (actred >= Scalar(.1))
+ nslow2 = 0;
+
+ /* test for convergence. */
+
+ if (delta <= xtol * xnorm || fnorm == 0.)
+ info = 1;
+ if (info != 0)
+ goto algo_end;
+
+ /* tests for termination and stringent tolerances. */
+
+ if (nfev >= maxfev)
+ info = 2;
+ /* Computing MAX */
+ if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= epsilon<Scalar>() * xnorm)
+ info = 3;
+ if (nslow2 == 5)
+ info = 4;
+ if (nslow1 == 10)
+ info = 5;
+ if (info != 0)
+ goto algo_end;
+
+ /* criterion for recalculating jacobian approximation */
+ /* by forward differences. */
+
+ if (ncfail == 2)
+ break;
+
+ /* calculate the rank one modification to the jacobian */
+ /* and update qtf if necessary. */
+
+ for (j = 0; j < n; ++j) {
+ sum = wa4.dot(fjac.col(j));
+ wa2[j] = (sum - wa3[j]) / pnorm;
+ wa1[j] = diag[j] * (diag[j] * wa1[j] / pnorm);
+ if (ratio >= Scalar(1e-4))
+ qtf[j] = sum;
+ }
+
+ /* compute the qr factorization of the updated jacobian. */
+
+ ei_r1updt<Scalar>(n, n, R.data(), R.size(), wa1.data(), wa2.data(), wa3.data(), &sing);
+ ei_r1mpyq<Scalar>(n, n, fjac.data(), fjac.rows(), wa2.data(), wa3.data());
+ ei_r1mpyq<Scalar>(1, n, qtf.data(), 1, wa2.data(), wa3.data());
+
+ /* end of the inner loop. */
+
+ jeval = false;
+ }
+ /* end of the outer loop. */
+ }
+algo_end:
+ /* termination, either normal or user imposed. */
+ if (iflag < 0)
+ info = iflag;
+ return info;
+}
+