Better error checking and reporting for linear solvers.

A lot of error checking cruft has accumulated over the years
in the various linear solvers. This change makes the error reporting
more robust and consistent across the various solvers.

Preconditioners are not covered by this change and will be the
subject of a future change.

Change-Id: Ibeb2572a1e67758953dde8d12e3abc6d1df9052d
diff --git a/internal/ceres/lapack.cc b/internal/ceres/lapack.cc
index e93e05f..0061433 100644
--- a/internal/ceres/lapack.cc
+++ b/internal/ceres/lapack.cc
@@ -29,6 +29,9 @@
 // Author: sameeragarwal@google.com (Sameer Agarwal)
 
 #include "ceres/lapack.h"
+
+#include "ceres/internal/port.h"
+#include "ceres/linear_solver.h"
 #include "glog/logging.h"
 
 // C interface to the LAPACK Cholesky factorization and triangular solve.
@@ -63,12 +66,14 @@
 namespace ceres {
 namespace internal {
 
-int LAPACK::SolveInPlaceUsingCholesky(int num_rows,
-                                      const double* in_lhs,
-                                      double* rhs_and_solution) {
+LinearSolverTerminationType LAPACK::SolveInPlaceUsingCholesky(
+    int num_rows,
+    const double* in_lhs,
+    double* rhs_and_solution,
+    string* status) {
 #ifdef CERES_NO_LAPACK
   LOG(FATAL) << "Ceres was built without a BLAS library.";
-  return -1;
+  return FATAL_ERROR;
 #else
   char uplo = 'L';
   int n = num_rows;
@@ -77,17 +82,33 @@
   double* lhs = const_cast<double*>(in_lhs);
 
   dpotrf_(&uplo, &n, lhs, &n, &info);
-  if (info != 0) {
-    LOG(INFO) << "Cholesky factorization (dpotrf) failed: " << info;
-    return info;
+  if (info < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+               << "Please report it."
+               << "LAPACK::dpotrf fatal error."
+               << "Argument: " << -info << " is invalid.";
+    return FATAL_ERROR;
+  }
+
+  if (info > 0) {
+    *status =
+        StringPrintf(
+            "LAPACK::dpotrf numerical failure. "
+             "The leading minor of order %d  is not positive definite.", info);
+    return FAILURE;
   }
 
   dpotrs_(&uplo, &n, &nrhs, lhs, &n, rhs_and_solution, &n, &info);
-  if (info != 0) {
-    LOG(INFO) << "Triangular solve (dpotrs) failed: " << info;
+  if (info < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+               << "Please report it."
+               << "LAPACK::dpotrs fatal error."
+               << "Argument: " << -info << " is invalid.";
+    return FATAL_ERROR;
   }
 
-  return info;
+  *status = "Success";
+  return TOLERANCE;
 #endif
 };
 
@@ -113,20 +134,27 @@
          &lwork,
          &info);
 
-  CHECK_EQ(info, 0);
+  if (info < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+               << "Please report it."
+               << "LAPACK::dgels fatal error."
+               << "Argument: " << info << " is invalid.";
+  }
   return static_cast<int>(work);
 #endif
 }
 
-int LAPACK::SolveUsingQR(int num_rows,
-                         int num_cols,
-                         const double* in_lhs,
-                         int work_size,
-                         double* work,
-                         double* rhs_and_solution) {
+LinearSolverTerminationType LAPACK::SolveInPlaceUsingQR(
+    int num_rows,
+    int num_cols,
+    const double* in_lhs,
+    int work_size,
+    double* work,
+    double* rhs_and_solution,
+    string* status) {
 #ifdef CERES_NO_LAPACK
   LOG(FATAL) << "Ceres was built without a LAPACK library.";
-  return -1;
+  return FATAL_ERROR;
 #else
   char trans = 'N';
   int m = num_rows;
@@ -149,7 +177,15 @@
          &work_size,
          &info);
 
-  return info;
+  if (info < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+               << "Please report it."
+               << "LAPACK::dgels fatal error."
+               << "Argument: " << -info << " is invalid.";
+  }
+
+  *status = "Success.";
+  return TOLERANCE;
 #endif
 }