Improve the error handling in Conjugte Gradients.
Due to floating point and conditioning issues, a system
matrix which is guaranteed to be PSD in exact arithmetic
can appear indefinite to the ConjugateGradientsSolver.
Previously, x'Ax <= 0, the solver returned with numerical
failure. Which the trust region solver will treat as a failed
solve.
But, more general truncated Newton when they encounter indefiniteness
use the step computed till that point instead of declaring failure.
This changes does this and adds a bit more logging.
Change-Id: I0e0cc56ef7d856f1c54ac6d638327b8353039f70
diff --git a/internal/ceres/conjugate_gradients_solver.cc b/internal/ceres/conjugate_gradients_solver.cc
index d7aee31..43eeff4 100644
--- a/internal/ceres/conjugate_gradients_solver.cc
+++ b/internal/ceres/conjugate_gradients_solver.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2014 Google Inc. All rights reserved.
// http://code.google.com/p/ceres-solver/
//
// Redistribution and use in source and binary forms, with or without
@@ -149,8 +149,11 @@
A->RightMultiply(p.data(), q.data());
const double pq = p.dot(q);
if ((pq <= 0) || IsInfinite(pq)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = StringPrintf("Numerical failure. p'q = %e.", pq);
+ summary.termination_type = LINEAR_SOLVER_NO_CONVERGENCE;
+ summary.message = StringPrintf(
+ "Matrix is indefinite, no more progress can be made. "
+ "p'q = %e. |p| = %e, |q| = %e",
+ pq, p.norm(), q.norm());
break;
}
@@ -211,9 +214,11 @@
summary.num_iterations >= options_.min_num_iterations) {
summary.termination_type = LINEAR_SOLVER_SUCCESS;
summary.message =
- StringPrintf("Convergence: zeta = %e < %e",
+ StringPrintf("Iteration: %d Convergence: zeta = %e < %e. |r| = %e",
+ summary.num_iterations,
zeta,
- per_solve_options.q_tolerance);
+ per_solve_options.q_tolerance,
+ r.norm());
break;
}
Q0 = Q1;
@@ -224,7 +229,10 @@
summary.num_iterations >= options_.min_num_iterations) {
summary.termination_type = LINEAR_SOLVER_SUCCESS;
summary.message =
- StringPrintf("Convergence. |r| = %e <= %e.", norm_r, tol_r);
+ StringPrintf("Iteration: %d Convergence. |r| = %e <= %e.",
+ summary.num_iterations,
+ norm_r,
+ tol_r);
break;
}