Add an optional dependency on the Google Benchmark library.

Also add a small benchmark for automatic differentiation.

Change-Id: I01c985495a973bc2a2fdc6c33fa1eb5ab788d7ef
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f6062d6..f12d5ed 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,6 +37,8 @@
   cmake_policy(SET CMP0042 NEW)
 endif()
 
+include(CMakeDependentOption)
+
 project(Ceres C CXX)
 
 # NOTE: The 'generic' CMake variables CMAKE_[SOURCE/BINARY]_DIR should not be
@@ -131,6 +133,7 @@
 option(BUILD_TESTING "Enable tests" ON)
 option(BUILD_DOCUMENTATION "Build User's Guide (html)" OFF)
 option(BUILD_EXAMPLES "Build examples" ON)
+cmake_dependent_option(BUILD_BENCHMARKS "Build Ceres benchmarking suite" ON "CXX11" OFF)
 option(BUILD_SHARED_LIBS "Build Ceres as a shared library." OFF)
 if (MSVC)
   option(MSVC_USE_STATIC_CRT
@@ -518,11 +521,22 @@
   endif()
 endif(CXX11)
 
+if (BUILD_BENCHMARKS)
+  find_package(benchmark QUIET)
+  if (benchmark_FOUND)
+     message("-- Found Google benchmark library. Building Ceres benchmarks.")
+  else()
+     message("-- Failed to find Google benchmark library, disabling build of benchmarks.")
+     update_cache_variable(BUILD_BENCHMARKS OFF)
+  endif()
+endif()
+
 include_directories(
   include
   internal
   internal/ceres
   ${GLOG_INCLUDE_DIRS})
+
 # Eigen SparseQR generates various compiler warnings related to unused and
 # uninitialised local variables.  To avoid having to individually suppress these
 # warnings around the #include statments for Eigen headers across all GCC/Clang
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index c68edab..b7c99ac 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -371,3 +371,8 @@
   ceres_test(bundle_adjustment)
 
 endif (BUILD_TESTING AND GFLAGS)
+
+if (BUILD_BENCHMARKS)
+  add_executable(autodiff_cost_function_benchmark autodiff_cost_function_benchmark.cc)
+  target_link_libraries(autodiff_cost_function_benchmark ceres benchmark::benchmark)
+endif (BUILD_BENCHMARKS)
diff --git a/internal/ceres/autodiff_cost_function_benchmark.cc b/internal/ceres/autodiff_cost_function_benchmark.cc
new file mode 100644
index 0000000..9436354
--- /dev/null
+++ b/internal/ceres/autodiff_cost_function_benchmark.cc
@@ -0,0 +1,116 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <memory>
+
+#include "benchmark/benchmark.h"
+#include "ceres/ceres.h"
+#include "ceres/jet.h"
+
+namespace ceres {
+
+// From the NIST problem collection.
+struct Rat43CostFunctor {
+  Rat43CostFunctor(const double x, const double y) : x_(x), y_(y) {}
+
+  template <typename T>
+  bool operator()(const T* parameters, T* residuals) const {
+    const T& b1 = parameters[0];
+    const T& b2 = parameters[1];
+    const T& b3 = parameters[2];
+    const T& b4 = parameters[3];
+    residuals[0] = b1 * pow(1.0 + exp(b2 - b3 * x_), -1.0 / b4) - y_;
+    return true;
+  }
+
+ private:
+  const double x_;
+  const double y_;
+};
+
+// Simple implementation of autodiff using Jets directly instead of
+// going through the machineary of AutoDiffCostFunction, which does
+// the same thing, but much more generically.
+class Rat43Automatic : public ceres::SizedCostFunction<1, 4> {
+ public:
+  Rat43Automatic(const Rat43CostFunctor* functor) : functor_(functor) {}
+  virtual ~Rat43Automatic() {}
+  virtual bool Evaluate(double const* const* parameters,
+                        double* residuals,
+                        double** jacobians) const {
+    if (!jacobians) {
+      return (*functor_)(parameters[0], residuals);
+    }
+
+    typedef ceres::Jet<double, 4> JetT;
+    JetT jets[4];
+    for (int i = 0; i < 4; ++i) {
+      jets[i].a = parameters[0][i];
+      jets[i].v.setZero();
+      jets[i].v[i] = 1.0;
+    }
+
+    JetT result;
+    (*functor_)(jets, &result);
+
+    residuals[0] = result.a;
+    for (int i = 0; i < 4; ++i) {
+      jacobians[0][i] = result.v[i];
+    }
+    return true;
+  }
+
+ private:
+  std::unique_ptr<const Rat43CostFunctor> functor_;
+};
+
+static void BM_Rat43AutoDiff(benchmark::State& state) {
+  double parameter_block1[] = {1., 2., 3., 4.};
+  double* parameters[] = {parameter_block1};
+
+  double jacobian1[] = {0.0, 0.0, 0.0, 0.0};
+  double residuals;
+  double* jacobians[] = {jacobian1};
+  const double x = 0.2;
+  const double y = 0.3;
+  std::unique_ptr<ceres::CostFunction> cost_function(
+      new ceres::AutoDiffCostFunction<Rat43CostFunctor, 1, 4>(
+          new Rat43CostFunctor(x, y)));
+
+  while (state.KeepRunning()) {
+    cost_function->Evaluate(
+        parameters, &residuals, state.range(0) ? jacobians : nullptr);
+  }
+}
+BENCHMARK(BM_Rat43AutoDiff)->Arg(0)->Arg(1);
+
+}  // namespace ceres
+
+BENCHMARK_MAIN();