Improve logging in Solver::Options::IsValid.

The error message now includes the value of the offending option.

Change-Id: Ic2493709f54f7efe59313d51d1ff9638191c8b38
diff --git a/internal/ceres/solver.cc b/internal/ceres/solver.cc
index 39efb23..8f19886 100644
--- a/internal/ceres/solver.cc
+++ b/internal/ceres/solver.cc
@@ -31,65 +31,51 @@
 
 #include "ceres/solver.h"
 
+#include <iostream>  // NOLINT
 #include <vector>
+#include "ceres/internal/port.h"
 #include "ceres/problem.h"
 #include "ceres/problem_impl.h"
 #include "ceres/program.h"
 #include "ceres/solver_impl.h"
 #include "ceres/stringprintf.h"
-#include "ceres/wall_time.h"
+#include "ceres/types.h"
 #include "ceres/version.h"
+#include "ceres/wall_time.h"
 
 namespace ceres {
 namespace {
 
-// TODO(sameeragarwal): These macros are not terribly informative when
-// things do crash. It would be nice to actually print the offending
-// value.
-
-#define OPTION_GT(x, y)                                                 \
-  if (options.x <= y) {                                                 \
-    *error = string("Invalid configuration. Violated constraint "       \
-                    "Solver::Options::" #x " > " #y);                   \
+#define OPTION_OP(x, y, OP)                                             \
+  if (!(options.x OP y)) {                                              \
+    std::stringstream ss;                                               \
+    ss << "Invalid configuration. ";                                    \
+    ss << string("Solver::Options::" #x " = ") << options.x << ". ";    \
+    ss << "Violated constraint: ";                                      \
+    ss << string("Solver::Options::" #x " " #OP " "#y);                 \
+    *error = ss.str();                                                  \
     return false;                                                       \
   }
 
-#define OPTION_GE(x, y)                                                 \
-  if (options.x < y) {                                                  \
-    *error = string("Invalid configuration. Violated constraint "       \
-                    "Solver::Options::" #x " >= " #y);                  \
+#define OPTION_OP_OPTION(x, y, OP)                                      \
+  if (!(options.x OP options.y)) {                                      \
+    std::stringstream ss;                                               \
+    ss << "Invalid configuration. ";                                    \
+    ss << string("Solver::Options::" #x " = ") << options.x << ". ";    \
+    ss << string("Solver::Options::" #y " = ") << options.y << ". ";    \
+    ss << "Violated constraint: ";                                      \
+    ss << string("Solver::Options::" #x );                              \
+    ss << string(#OP " Solver::Options::" #y ".");                      \
+    *error = ss.str();                                                  \
     return false;                                                       \
   }
 
-#define OPTION_LE(x, y)                                                 \
-  if (options.x > y) {                                                  \
-    *error = string("Invalid configuration. Violated constraint "       \
-                    "Solver::Options::" #x " <= " #y);                  \
-    return false;                                                       \
-  }
-
-#define OPTION_LT(x, y)                                                 \
-  if (options.x >= y) {                                                 \
-    *error = string("Invalid configuration. Violated constraint "       \
-                    "Solver::Options::" #x " < " #y);                   \
-    return false;                                                       \
-  }
-
-#define OPTION_LE_OPTION(x, y)                                          \
-  if (options.x > options.y) {                                          \
-    *error = string("Invalid configuration. Violated constraint "       \
-                    "Solver::Options::" #x " <= "                       \
-                    "Solver::Options::" #y);                            \
-    return false;                                                       \
-  }
-
-#define OPTION_LT_OPTION(x, y)                                          \
-  if (options.x >= options.y) {                                         \
-    *error = string("Invalid configuration. Violated constraint "       \
-                    "Solver::Options::" #x " < "                        \
-                    "Solver::Options::" #y);                            \
-    return false;                                                       \
-  }
+#define OPTION_GE(x, y) OPTION_OP(x, y, >=);
+#define OPTION_GT(x, y) OPTION_OP(x, y, >);
+#define OPTION_LE(x, y) OPTION_OP(x, y, <=);
+#define OPTION_LT(x, y) OPTION_OP(x, y, <);
+#define OPTION_LE_OPTION(x, y) OPTION_OP_OPTION(x ,y, <=)
+#define OPTION_LT_OPTION(x, y) OPTION_OP_OPTION(x ,y, <)
 
 bool CommonOptionsAreValid(const Solver::Options& options, string* error) {
   OPTION_GE(max_num_iterations, 0);
@@ -251,10 +237,12 @@
   if ((options.line_search_direction_type == ceres::BFGS ||
        options.line_search_direction_type == ceres::LBFGS) &&
       options.line_search_type != ceres::WOLFE) {
+
     *error =
-        string("Invalid configuration: require line_search_type == "
-               "ceres::WOLFE when using (L)BFGS to ensure that underlying "
-               "assumptions are guaranteed to be satisfied.");
+        string("Invalid configuration: Solver::Options::line_search_type = ")
+        + string(LineSearchTypeToString(options.line_search_type))
+        + string(". When using (L)BFGS, "
+                 "Solver::Options::line_search_type must be set to WOLFE.");
     return false;
   }
 
@@ -276,6 +264,8 @@
   return true;
 }
 
+#undef OPTION_OP
+#undef OPTION_OP_OPTION
 #undef OPTION_GT
 #undef OPTION_GE
 #undef OPTION_LE