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));