SuiteSparse errors do not cause a fatal crash.
1. Move LinearSolverTerminationType to ceres::internal.
2. Add FATAL_ERROR as a new enum to LinearSolverTerminationType.
3. Pipe SuiteSparse errors via a LinearSolverTerminationType so
to distinguish between fatal and non-fatal errors.
4. Update levenberg marquardt and dogleg strategies to deal
with FATAL_ERROR.
5. Update trust_region_minimizer to terminate when FATAL_ERROR
is encountered.
6. Remove SuiteSparse::SolveCholesky as it screws up the error
handling.
7. Fix all clients calling SuiteSparse to handle the result of
SuiteSparse::Cholesky correctly.
8. Remove fatal failures in SuiteSparse when symbolic factorization
fails.
9. Fix all clients of SuiteSparse to deal with null symbolic factors.
This is a temporary fix to deal with some production problems. A more
extensive cleanup and testing regime will be put in place in a
subsequent CL.
Change-Id: I1f60d539799dd95db7ecc340911e261fa4824f92
diff --git a/internal/ceres/sparse_normal_cholesky_solver.cc b/internal/ceres/sparse_normal_cholesky_solver.cc
index f1a5237..697adc1 100644
--- a/internal/ceres/sparse_normal_cholesky_solver.cc
+++ b/internal/ceres/sparse_normal_cholesky_solver.cc
@@ -195,34 +195,50 @@
VectorRef(x, num_cols).setZero();
cholmod_sparse lhs = ss_.CreateSparseMatrixTransposeView(A);
- cholmod_dense* rhs = ss_.CreateDenseVector(Atb.data(), num_cols, num_cols);
+
event_logger.AddEvent("Setup");
if (factor_ == NULL) {
if (options_.use_postordering) {
- factor_ =
- CHECK_NOTNULL(ss_.BlockAnalyzeCholesky(&lhs,
- A->col_blocks(),
- A->row_blocks()));
+ factor_ = ss_.BlockAnalyzeCholesky(&lhs,
+ A->col_blocks(),
+ A->row_blocks());
} else {
- factor_ =
- CHECK_NOTNULL(ss_.AnalyzeCholeskyWithNaturalOrdering(&lhs));
+ factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(&lhs);
}
}
-
event_logger.AddEvent("Analysis");
- cholmod_dense* sol = ss_.SolveCholesky(&lhs, factor_, rhs);
+ if (factor_ == NULL) {
+ if (per_solve_options.D != NULL) {
+ A->DeleteRows(num_cols);
+ }
+
+ summary.termination_type = FATAL_ERROR;
+ return summary;
+ }
+
+ const LinearSolverTerminationType status = ss_.Cholesky(&lhs, factor_);
+ if (status != TOLERANCE) {
+ if (per_solve_options.D != NULL) {
+ A->DeleteRows(num_cols);
+ }
+
+ summary.termination_type = FATAL_ERROR;
+ return summary;
+ }
+
+ cholmod_dense* rhs = ss_.CreateDenseVector(Atb.data(), num_cols, num_cols);
+ cholmod_dense* sol = ss_.Solve(factor_, rhs);
event_logger.AddEvent("Solve");
ss_.Free(rhs);
- rhs = NULL;
-
if (per_solve_options.D != NULL) {
A->DeleteRows(num_cols);
}
summary.num_iterations = 1;
+
if (sol != NULL) {
memcpy(x, sol->x, num_cols * sizeof(*x));