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/suitesparse.cc b/internal/ceres/suitesparse.cc
index 9de32fd..ec93b1a 100644
--- a/internal/ceres/suitesparse.cc
+++ b/internal/ceres/suitesparse.cc
@@ -35,6 +35,7 @@
 #include "cholmod.h"
 #include "ceres/compressed_col_sparse_matrix_utils.h"
 #include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/linear_solver.h"
 #include "ceres/triplet_sparse_matrix.h"
 
 namespace ceres {
@@ -130,8 +131,11 @@
   cc_.supernodal = CHOLMOD_AUTO;
 
   cholmod_factor* factor = cholmod_analyze(A, &cc_);
-  CHECK_EQ(cc_.status, CHOLMOD_OK)
-      << "Cholmod symbolic analysis failed " << cc_.status;
+  if (cc_.status != CHOLMOD_OK) {
+    LOG(ERROR) << "cholmod_analyze failed. error code: " << cc_.status;
+    return NULL;
+  }
+
   CHECK_NOTNULL(factor);
 
   if (VLOG_IS_ON(2)) {
@@ -162,8 +166,11 @@
 
   cholmod_factor* factor  =
       cholmod_analyze_p(A, const_cast<int*>(&ordering[0]), NULL, 0, &cc_);
-  CHECK_EQ(cc_.status, CHOLMOD_OK)
-      << "Cholmod symbolic analysis failed " << cc_.status;
+  if (cc_.status != CHOLMOD_OK) {
+    LOG(ERROR) << "cholmod_analyze failed. error code: " << cc_.status;
+    return NULL;
+  }
+
   CHECK_NOTNULL(factor);
 
   if (VLOG_IS_ON(2)) {
@@ -180,8 +187,11 @@
   cc_.postorder = 0;
 
   cholmod_factor* factor  = cholmod_analyze(A, &cc_);
-  CHECK_EQ(cc_.status, CHOLMOD_OK)
-      << "Cholmod symbolic analysis failed " << cc_.status;
+  if (cc_.status != CHOLMOD_OK) {
+    LOG(ERROR) << "cholmod_analyze failed. error code: " << cc_.status;
+    return NULL;
+  }
+
   CHECK_NOTNULL(factor);
 
   if (VLOG_IS_ON(2)) {
@@ -233,7 +243,7 @@
   return true;
 }
 
-bool SuiteSparse::Cholesky(cholmod_sparse* A, cholmod_factor* L) {
+LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A, cholmod_factor* L) {
   CHECK_NOTNULL(A);
   CHECK_NOTNULL(L);
 
@@ -258,40 +268,37 @@
   switch (cc_.status) {
     case CHOLMOD_NOT_INSTALLED:
       LOG(WARNING) << "CHOLMOD failure: Method not installed.";
-      return false;
+      return FATAL_ERROR;
     case CHOLMOD_OUT_OF_MEMORY:
       LOG(WARNING) << "CHOLMOD failure: Out of memory.";
-      return false;
+      return FATAL_ERROR;
     case CHOLMOD_TOO_LARGE:
       LOG(WARNING) << "CHOLMOD failure: Integer overflow occured.";
-      return false;
+      return FATAL_ERROR;
     case CHOLMOD_INVALID:
       LOG(WARNING) << "CHOLMOD failure: Invalid input.";
-      return false;
+      return FATAL_ERROR;
     case CHOLMOD_NOT_POSDEF:
-      // TODO(sameeragarwal): These two warnings require more
-      // sophisticated handling going forward. For now we will be
-      // strict and treat them as failures.
       LOG(WARNING) << "CHOLMOD warning: Matrix not positive definite.";
-      return false;
+      return FAILURE;
     case CHOLMOD_DSMALL:
       LOG(WARNING) << "CHOLMOD warning: D for LDL' or diag(L) or "
                    << "LL' has tiny absolute value.";
-      return false;
+      return FAILURE;
     case CHOLMOD_OK:
       if (status != 0) {
-        return true;
+        return TOLERANCE;
       }
       LOG(WARNING) << "CHOLMOD failure: cholmod_factorize returned zero "
                    << "but cholmod_common::status is CHOLMOD_OK."
                    << "Please report this to ceres-solver@googlegroups.com.";
-      return false;
+      return FATAL_ERROR;
     default:
-      LOG(WARNING) << "Unknown cholmod return code. "
-                   << "Please report this to ceres-solver@googlegroups.com.";
-      return false;
+      LOG(WARNING) << "Unknown cholmod return code: " << cc_.status
+                   << ". Please report this to ceres-solver@googlegroups.com.";
+      return FATAL_ERROR;
   }
-  return false;
+  return FATAL_ERROR;
 }
 
 cholmod_dense* SuiteSparse::Solve(cholmod_factor* L,
@@ -304,20 +311,6 @@
   return cholmod_solve(CHOLMOD_A, L, b, &cc_);
 }
 
-cholmod_dense* SuiteSparse::SolveCholesky(cholmod_sparse* A,
-                                          cholmod_factor* L,
-                                          cholmod_dense* b) {
-  CHECK_NOTNULL(A);
-  CHECK_NOTNULL(L);
-  CHECK_NOTNULL(b);
-
-  if (Cholesky(A, L)) {
-    return Solve(L, b);
-  }
-
-  return NULL;
-}
-
 void SuiteSparse::ApproximateMinimumDegreeOrdering(cholmod_sparse* matrix,
                                                    int* ordering) {
   cholmod_amd(matrix, NULL, 0, ordering, &cc_);