Add Autodiff Codegen Tests

This patch adds end-to-end tests for the autodiff codegen system.
First, code is generated for various functors. This code is then
executed with different arguments and the result is compared
to traditional autodiff.

Change-Id: Icba9996ece26384a795d5b50480ec8194cab572f
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index 1611870..738b431 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -370,7 +370,8 @@
   add_library(test_util
               evaluator_test_utils.cc
               numeric_diff_test_utils.cc
-              test_util.cc)
+              test_util.cc
+              codegen/test_utils.cc)
   target_include_directories(test_util PUBLIC ${Ceres_SOURCE_DIR}/internal)
 
   if (MINIGLOG)
@@ -499,10 +500,6 @@
 
   add_subdirectory(generated_bundle_adjustment_tests)
 
-  if(CODE_GENERATION)
-    add_subdirectory(codegen)
-  endif()
-
 endif (BUILD_TESTING AND GFLAGS)
 
 macro(add_dependencies_to_benchmark BENCHMARK_TARGET)
@@ -528,3 +525,8 @@
   add_executable(schur_eliminator_benchmark schur_eliminator_benchmark.cc)
   add_dependencies_to_benchmark(schur_eliminator_benchmark)
 endif (BUILD_BENCHMARKS)
+
+if(CODE_GENERATION)
+  add_subdirectory(codegen)
+endif()
+
diff --git a/internal/ceres/codegen/CMakeLists.txt b/internal/ceres/codegen/CMakeLists.txt
index db21f9c..4bea21f 100644
--- a/internal/ceres/codegen/CMakeLists.txt
+++ b/internal/ceres/codegen/CMakeLists.txt
@@ -38,7 +38,8 @@
 #
 # The semantic tests, which check the correctness by executing the generated code
 # are still run on all platforms.
-if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+if (BUILD_TESTING AND GFLAGS)
+  if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
     set(CXX_FLAGS_OLD ${CMAKE_CXX_FLAGS})
     # From the man page:
     #   The C++ standard allows an implementation to omit creating a
@@ -49,10 +50,41 @@
     # gcc and different optimization levels. Without this flag, testing would
     # be very painfull and might break when a new compiler version is released.
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-elide-constructors")
-    ceres_test(expression)
-    ceres_test(expression_graph)
     ceres_test(expression_ref)
     ceres_test(code_generator)
     ceres_test(eliminate_nops)
     set(CMAKE_CXX_FLAGS ${CXX_FLAGS_OLD})
+  endif()
+
+  ceres_test(expression)
+  ceres_test(expression_graph)
+
+  macro (generate_test_functor FUNCTOR_NAME FUNCTOR_FILE)
+    ceres_generate_cost_function_implementation_for_functor(
+      NAME ${FUNCTOR_NAME}
+      INPUT_FILE ${FUNCTOR_FILE}
+      OUTPUT_DIRECTORY tests
+      NAMESPACE test
+      )
+  endmacro()
+
+  # Semantic tests should work on every platform
+  include(CeresCodeGeneration)
+
+
+  generate_test_functor(InputOutputAssignment autodiff_codegen_test.h)
+  generate_test_functor(CompileTimeConstants autodiff_codegen_test.h)
+  generate_test_functor(Assignments autodiff_codegen_test.h)
+  generate_test_functor(BinaryArithmetic autodiff_codegen_test.h)
+  generate_test_functor(UnaryArithmetic autodiff_codegen_test.h)
+  generate_test_functor(BinaryComparison autodiff_codegen_test.h)
+  generate_test_functor(LogicalOperators autodiff_codegen_test.h)
+  generate_test_functor(ScalarFunctions autodiff_codegen_test.h)
+  generate_test_functor(LogicalFunctions autodiff_codegen_test.h)
+  generate_test_functor(Branches autodiff_codegen_test.h)
+  ceres_test(autodiff_codegen)
+  target_link_libraries(autodiff_codegen_test PUBLIC
+    InputOutputAssignment CompileTimeConstants Assignments BinaryArithmetic
+    UnaryArithmetic BinaryComparison LogicalOperators ScalarFunctions
+    LogicalFunctions Branches)
 endif()
diff --git a/internal/ceres/codegen/autodiff_codegen_test.cc b/internal/ceres/codegen/autodiff_codegen_test.cc
new file mode 100644
index 0000000..c6c5cbc
--- /dev/null
+++ b/internal/ceres/codegen/autodiff_codegen_test.cc
@@ -0,0 +1,117 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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.
+//
+// Author: darius.rueckert@fau.de (Darius Rueckert)
+//
+// This file tests the Expression class. For each member function one test is
+// included here.
+//
+#include "autodiff_codegen_test.h"
+
+#include "ceres/autodiff_cost_function.h"
+#include "codegen/test_utils.h"
+#include "gtest/gtest.h"
+
+namespace ceres {
+namespace internal {
+
+class AutoDiffCodegenTest : public testing::TestWithParam<double> {
+ public:
+  template <typename CostFunctionType, int kNumResiduals, int... Ns>
+  void TestCostFunction() {
+    using CostFunctorType = CostFunctionToFunctor<CostFunctionType>;
+    CostFunctionType generated_cost_function;
+    CostFunctorType cost_functor;
+    auto* cost_function_ad =
+        new AutoDiffCostFunction<CostFunctorType, kNumResiduals, Ns...>(
+            &cost_functor);
+    auto value = GetParam();
+    CompareCostFunctions(&generated_cost_function,
+                         cost_function_ad,
+                         value,
+                         kRelativeErrorThreshold);
+  }
+  static constexpr double kRelativeErrorThreshold = 0;
+};
+
+TEST_P(AutoDiffCodegenTest, InputOutputAssignment) {
+  TestCostFunction<test::InputOutputAssignment, 7, 4, 2, 1>();
+}
+
+TEST_P(AutoDiffCodegenTest, CompileTimeConstants) {
+  TestCostFunction<test::CompileTimeConstants, 7, 1>();
+}
+
+TEST_P(AutoDiffCodegenTest, Assignments) {
+  TestCostFunction<test::Assignments, 8, 2>();
+}
+
+TEST_P(AutoDiffCodegenTest, BinaryArithmetic) {
+  TestCostFunction<test::BinaryArithmetic, 9, 2>();
+}
+
+TEST_P(AutoDiffCodegenTest, UnaryArithmetic) {
+  TestCostFunction<test::UnaryArithmetic, 3, 1>();
+}
+
+TEST_P(AutoDiffCodegenTest, BinaryComparison) {
+  TestCostFunction<test::BinaryComparison, 12, 2>();
+}
+
+TEST_P(AutoDiffCodegenTest, LogicalOperators) {
+  TestCostFunction<test::LogicalOperators, 8, 3>();
+}
+
+TEST_P(AutoDiffCodegenTest, ScalarFunctions) {
+  TestCostFunction<test::ScalarFunctions, 20, 22>();
+}
+
+TEST_P(AutoDiffCodegenTest, LogicalFunctions) {
+  TestCostFunction<test::LogicalFunctions, 4, 4>();
+}
+
+TEST_P(AutoDiffCodegenTest, Branches) {
+  TestCostFunction<test::Branches, 4, 3>();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    AutoDiffCodegenTest,
+    AutoDiffCodegenTest,
+    testing::Values(0,
+                    -1,
+                    1,
+                    0.5,
+                    -0.5,
+                    10,
+                    -10,
+                    1e20,
+                    1e-20,
+                    std::numeric_limits<double>::infinity(),
+                    std::numeric_limits<double>::quiet_NaN()));
+}  // namespace internal
+}  // namespace ceres
diff --git a/internal/ceres/codegen/autodiff_codegen_test.h b/internal/ceres/codegen/autodiff_codegen_test.h
new file mode 100644
index 0000000..f5a9f44
--- /dev/null
+++ b/internal/ceres/codegen/autodiff_codegen_test.h
@@ -0,0 +1,358 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2020 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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.
+//
+// Author: darius.rueckert@fau.de (Darius Rueckert)
+//
+// This file includes unit test functors for every supported expression type.
+// This is similar to expression_ref_test and codegeneration_test, but for the
+// complete pipeline including automatic differentation. For each of the structs
+// below, the Evaluate function is generated using GenerateCodeForFunctor. After
+// that this function is executed with random parameters. The result of the
+// residuals and jacobians is then compared to AutoDiff (without code
+// generation). Of course, the correctness of this module depends on the
+// correctness of autodiff.
+//
+#include <cmath>
+#include <limits>
+
+#include "ceres/codegen/codegen_cost_function.h"
+namespace test {
+
+struct InputOutputAssignment : public ceres::CodegenCostFunction<7, 4, 2, 1> {
+  template <typename T>
+  bool operator()(const T* x0, const T* x1, const T* x2, T* y) const {
+    y[0] = x0[0];
+    y[1] = x0[1];
+    y[2] = x0[2];
+    y[3] = x0[3];
+
+    y[4] = x1[0];
+    y[5] = x1[1];
+
+    y[6] = x2[0];
+    return true;
+  }
+#include "tests/inputoutputassignment.h"
+};
+
+struct CompileTimeConstants : public ceres::CodegenCostFunction<7, 1> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    y[0] = T(0);
+    y[1] = T(1);
+    y[2] = T(-1);
+    y[3] = T(1e-10);
+    y[4] = T(1e10);
+    y[5] = T(std::numeric_limits<double>::infinity());
+    y[6] = T(std::numeric_limits<double>::quiet_NaN());
+
+    return true;
+  }
+#include "tests/compiletimeconstants.h"
+};
+
+struct Assignments : public ceres::CodegenCostFunction<8, 2> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    T a = x0[0];
+    T b = x0[1];
+    y[0] = a;
+    y[1] = b;
+    y[2] = y[3] = a;
+
+    T c = a;
+    y[4] = c;
+
+    T d(b);
+    y[5] = d;
+
+    y[6] = std::move(c);
+
+    y[7] = std::move(T(T(std::move(T(a)))));
+    return true;
+  }
+#include "tests/assignments.h"
+};
+
+struct BinaryArithmetic : public ceres::CodegenCostFunction<9, 2> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    T a = x0[0];
+    T b = x0[1];
+    y[0] = a + b;
+    y[1] = a - b;
+    y[2] = a * b;
+    y[3] = a / b;
+
+    y[4] = a;
+    y[4] += b;
+    y[5] = a;
+    y[5] -= b;
+    y[6] = a;
+    y[6] *= b;
+    y[7] = a;
+    y[7] /= b;
+
+    y[8] = a + b * a / a - b + b / a;
+    return true;
+  }
+#include "tests/binaryarithmetic.h"
+};
+
+struct UnaryArithmetic : public ceres::CodegenCostFunction<3, 1> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    T a = x0[0];
+    y[0] = -a;
+    y[1] = +a;
+    y[2] = a;
+    return true;
+  }
+#include "tests/unaryarithmetic.h"
+};
+
+struct BinaryComparison : public ceres::CodegenCostFunction<12, 2> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    T a = x0[0];
+    T b = x0[1];
+
+    // For each operator we swap the inputs so both branches are evaluated once.
+    CERES_IF(a < b) { y[0] = T(0); }
+    CERES_ELSE { y[0] = T(1); }
+    CERES_ENDIF
+    CERES_IF(b < a) { y[1] = T(0); }
+    CERES_ELSE { y[1] = T(1); }
+    CERES_ENDIF
+
+    CERES_IF(a > b) { y[2] = T(0); }
+    CERES_ELSE { y[2] = T(1); }
+    CERES_ENDIF
+    CERES_IF(b > a) { y[3] = T(0); }
+    CERES_ELSE { y[3] = T(1); }
+    CERES_ENDIF
+
+    CERES_IF(a <= b) { y[4] = T(0); }
+    CERES_ELSE { y[4] = T(1); }
+    CERES_ENDIF
+    CERES_IF(b <= a) { y[5] = T(0); }
+    CERES_ELSE { y[5] = T(1); }
+    CERES_ENDIF
+
+    CERES_IF(a >= b) { y[6] = T(0); }
+    CERES_ELSE { y[6] = T(1); }
+    CERES_ENDIF
+    CERES_IF(b >= a) { y[7] = T(0); }
+    CERES_ELSE { y[7] = T(1); }
+    CERES_ENDIF
+
+    CERES_IF(a == b) { y[8] = T(0); }
+    CERES_ELSE { y[8] = T(1); }
+    CERES_ENDIF
+    CERES_IF(b == a) { y[9] = T(0); }
+    CERES_ELSE { y[9] = T(1); }
+    CERES_ENDIF
+
+    CERES_IF(a != b) { y[10] = T(0); }
+    CERES_ELSE { y[10] = T(1); }
+    CERES_ENDIF
+    CERES_IF(b != a) { y[11] = T(0); }
+    CERES_ELSE { y[11] = T(1); }
+    CERES_ENDIF
+
+    return true;
+  }
+#include "tests/binarycomparison.h"
+};
+
+struct LogicalOperators : public ceres::CodegenCostFunction<8, 3> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    T a = x0[0];
+    T b = x0[1];
+    T c = x0[2];
+    auto r1 = a < b;
+    auto r2 = a < c;
+
+    CERES_IF(r1) { y[0] = T(0); }
+    CERES_ELSE { y[0] = T(1); }
+    CERES_ENDIF
+    CERES_IF(r2) { y[1] = T(0); }
+    CERES_ELSE { y[1] = T(1); }
+    CERES_ENDIF
+    CERES_IF(!r1) { y[2] = T(0); }
+    CERES_ELSE { y[2] = T(1); }
+    CERES_ENDIF
+    CERES_IF(!r2) { y[3] = T(0); }
+    CERES_ELSE { y[3] = T(1); }
+    CERES_ENDIF
+
+    CERES_IF(r1 && r2) { y[4] = T(0); }
+    CERES_ELSE { y[4] = T(1); }
+    CERES_ENDIF
+    CERES_IF(!r1 && !r2) { y[5] = T(0); }
+    CERES_ELSE { y[5] = T(1); }
+    CERES_ENDIF
+
+    CERES_IF(r1 || r2) { y[6] = T(0); }
+    CERES_ELSE { y[6] = T(1); }
+    CERES_ENDIF
+    CERES_IF(!r1 || !r2) { y[7] = T(0); }
+    CERES_ELSE { y[7] = T(1); }
+    CERES_ENDIF
+
+    return true;
+  }
+#include "tests/logicaloperators.h"
+};
+
+struct ScalarFunctions : public ceres::CodegenCostFunction<20, 22> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    y[0] = abs(x0[0]);
+    y[1] = acos(x0[1]);
+    y[2] = asin(x0[2]);
+    y[3] = atan(x0[3]);
+    y[4] = cbrt(x0[4]);
+    y[5] = ceil(x0[5]);
+    y[6] = cos(x0[6]);
+    y[7] = cosh(x0[7]);
+    y[8] = exp(x0[8]);
+    y[9] = exp2(x0[9]);
+    y[10] = floor(x0[10]);
+    y[11] = log(x0[11]);
+    y[12] = log2(x0[12]);
+    y[13] = sin(x0[13]);
+    y[14] = sinh(x0[14]);
+    y[15] = sqrt(x0[15]);
+    y[16] = tan(x0[16]);
+    y[17] = tanh(x0[17]);
+    y[18] = atan2(x0[18], x0[19]);
+    y[19] = pow(x0[20], x0[21]);
+    return true;
+  }
+#include "tests/scalarfunctions.h"
+};
+
+struct LogicalFunctions : public ceres::CodegenCostFunction<4, 4> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    using std::isfinite;
+    using std::isinf;
+    using std::isnan;
+    using std::isnormal;
+    T a = x0[0];
+    auto r1 = isfinite(a);
+    auto r2 = isinf(a);
+    auto r3 = isnan(a);
+    auto r4 = isnormal(a);
+
+    CERES_IF(r1) { y[0] = T(0); }
+    CERES_ELSE { y[0] = T(1); }
+    CERES_ENDIF
+    CERES_IF(r2) { y[1] = T(0); }
+    CERES_ELSE { y[1] = T(1); }
+    CERES_ENDIF
+    CERES_IF(r3) { y[2] = T(0); }
+    CERES_ELSE { y[2] = T(1); }
+    CERES_ENDIF
+    CERES_IF(r4) { y[3] = T(0); }
+    CERES_ELSE { y[3] = T(1); }
+    CERES_ENDIF
+
+    return true;
+  }
+#include "tests/logicalfunctions.h"
+};
+
+struct Branches : public ceres::CodegenCostFunction<4, 3> {
+  template <typename T>
+  bool operator()(const T* x0, T* y) const {
+    T a = x0[0];
+    T b = x0[1];
+    T c = x0[2];
+    auto r1 = a < b;
+    auto r2 = a < c;
+    auto r3 = b < c;
+
+    // If without else
+    y[0] = T(0);
+    CERES_IF(r1) { y[0] += T(1); }
+    CERES_ENDIF
+
+    // If else
+    y[1] = T(0);
+    CERES_IF(r1) { y[1] += T(-1); }
+    CERES_ELSE { y[1] += T(1); }
+    CERES_ENDIF
+
+    // Nested if
+    y[2] = T(0);
+    CERES_IF(r1) {
+      y[2] += T(1);
+      CERES_IF(r2) {
+        y[2] += T(4);
+        CERES_IF(r2) { y[2] += T(8); }
+        CERES_ENDIF
+      }
+      CERES_ENDIF
+    }
+    CERES_ENDIF
+
+    // Nested if-else
+    y[3] = T(0);
+    CERES_IF(r1) {
+      y[3] += T(1);
+      CERES_IF(r2) {
+        y[3] += T(2);
+        CERES_IF(r3) { y[3] += T(4); }
+        CERES_ELSE { y[3] += T(8); }
+        CERES_ENDIF
+      }
+      CERES_ELSE {
+        y[3] += T(16);
+        CERES_IF(r3) { y[3] += T(32); }
+        CERES_ELSE { y[3] += T(64); }
+        CERES_ENDIF
+      }
+      CERES_ENDIF
+    }
+    CERES_ELSE {
+      y[3] += T(128);
+      CERES_IF(r2) { y[3] += T(256); }
+      CERES_ELSE { y[3] += T(512); }
+      CERES_ENDIF
+    }
+    CERES_ENDIF
+
+    return true;
+  }
+#include "tests/branches.h"
+};
+
+}  // namespace test
diff --git a/internal/ceres/codegen/test_utils.cc b/internal/ceres/codegen/test_utils.cc
new file mode 100644
index 0000000..c34e773
--- /dev/null
+++ b/internal/ceres/codegen/test_utils.cc
@@ -0,0 +1,87 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2020 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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.
+//
+// Author: darius.rueckert@fau.de (Darius Rueckert)
+
+#include "codegen/test_utils.h"
+
+namespace ceres {
+namespace internal {
+
+std::pair<std::vector<double>, std::vector<double> > EvaluateCostFunction(
+    CostFunction* cost_function, double value) {
+  auto num_residuals = cost_function->num_residuals();
+  auto parameter_block_sizes = cost_function->parameter_block_sizes();
+  auto num_parameter_blocks = parameter_block_sizes.size();
+
+  int total_num_parameters = 0;
+  for (auto block_size : parameter_block_sizes) {
+    total_num_parameters += block_size;
+  }
+
+  std::vector<double> params_array(total_num_parameters, value);
+  std::vector<double*> params(num_parameter_blocks);
+  std::vector<double> residuals(num_residuals, 0);
+  std::vector<double> jacobians_array(num_residuals * total_num_parameters, 0);
+  std::vector<double*> jacobians(num_parameter_blocks);
+
+  for (int i = 0, k = 0; i < num_parameter_blocks;
+       k += parameter_block_sizes[i], ++i) {
+    params[i] = &params_array[k];
+  }
+
+  for (int i = 0, k = 0; i < num_parameter_blocks;
+       k += parameter_block_sizes[i], ++i) {
+    jacobians[i] = &jacobians_array[k * num_residuals];
+  }
+
+  cost_function->Evaluate(params.data(), residuals.data(), jacobians.data());
+
+  return std::make_pair(residuals, jacobians_array);
+}
+
+void CompareCostFunctions(CostFunction* cost_function1,
+                          CostFunction* cost_function2,
+
+                          double value,
+                          double tol) {
+  auto residuals_and_jacobians_1 = EvaluateCostFunction(cost_function1, value);
+  auto residuals_and_jacobians_2 = EvaluateCostFunction(cost_function2, value);
+
+  ExpectArraysClose(residuals_and_jacobians_1.first.size(),
+                    residuals_and_jacobians_1.first.data(),
+                    residuals_and_jacobians_2.first.data(),
+                    tol);
+  ExpectArraysClose(residuals_and_jacobians_1.second.size(),
+                    residuals_and_jacobians_1.second.data(),
+                    residuals_and_jacobians_2.second.data(),
+                    tol);
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/internal/ceres/codegen/test_utils.h b/internal/ceres/codegen/test_utils.h
new file mode 100644
index 0000000..0a27927
--- /dev/null
+++ b/internal/ceres/codegen/test_utils.h
@@ -0,0 +1,83 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2020 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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.
+//
+// Author: darius.rueckert@fau.de (Darius Rueckert)
+
+#ifndef CERES_INTERNAL_CODEGEN_TEST_UTILS_H_
+#define CERES_INTERNAL_CODEGEN_TEST_UTILS_H_
+
+#include "ceres/internal/autodiff.h"
+#include "ceres/random.h"
+#include "ceres/sized_cost_function.h"
+#include "test_util.h"
+
+namespace ceres {
+namespace internal {
+
+// CodegenCostFunctions have both, an templated operator() and the Evaluate()
+// function. The operator() is used during code generation and Evaluate() is
+// used during execution.
+//
+// If we want to use the operator() during execution (with autodiff) this
+// wrapper class here has to be used. Autodiff doesn't support functors that
+// have an Evaluate() function.
+//
+// CostFunctionToFunctor hides the Evaluate() function, because it doesn't
+// derive from CostFunction. Autodiff sees it as a simple functor and will use
+// the operator() as expected.
+template <typename CostFunction>
+struct CostFunctionToFunctor {
+  template <typename... _Args>
+  CostFunctionToFunctor(_Args&&... __args)
+      : cost_function(std::forward<_Args>(__args)...) {}
+
+  template <typename... _Args>
+  bool operator()(_Args&&... __args) const {
+    return cost_function(std::forward<_Args>(__args)...);
+  }
+
+  CostFunction cost_function;
+};
+
+// Evaluate a cost function and return the residuals and jacobians.
+// All parameters are set to 'value'.
+std::pair<std::vector<double>, std::vector<double>> EvaluateCostFunction(
+    CostFunction* cost_function, double value);
+
+// Evaluates the two cost functions using the method above and then compares the
+// result. The comparison uses GTEST expect macros so this function should be
+// called from a test enviroment.
+void CompareCostFunctions(CostFunction* cost_function1,
+                          CostFunction* cost_function2,
+                          double value,
+                          double tol);
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif
diff --git a/internal/ceres/test_util.cc b/internal/ceres/test_util.cc
index 5156856..a131b79 100644
--- a/internal/ceres/test_util.cc
+++ b/internal/ceres/test_util.cc
@@ -34,6 +34,7 @@
 
 #include <algorithm>
 #include <cmath>
+
 #include "ceres/file.h"
 #include "ceres/stringprintf.h"
 #include "ceres/types.h"
@@ -54,6 +55,15 @@
 namespace internal {
 
 bool ExpectClose(double x, double y, double max_abs_relative_difference) {
+  if (std::isinf(x) && std::isinf(y)) {
+    EXPECT_EQ(std::signbit(x), std::signbit(y));
+    return true;
+  }
+
+  if (std::isnan(x) && std::isnan(y)) {
+    return true;
+  }
+
   double absolute_difference = fabs(x - y);
   double relative_difference = absolute_difference / std::max(fabs(x), fabs(y));
   if (x == 0 || y == 0) {
@@ -63,7 +73,10 @@
   }
   if (relative_difference > max_abs_relative_difference) {
     VLOG(1) << StringPrintf("x=%17g y=%17g abs=%17g rel=%17g",
-                            x, y, absolute_difference, relative_difference);
+                            x,
+                            y,
+                            absolute_difference,
+                            relative_difference);
   }
 
   EXPECT_NEAR(relative_difference, 0.0, max_abs_relative_difference);
@@ -108,36 +121,30 @@
   }
 }
 
-void ExpectArraysClose(int n,
-                       const double* p,
-                       const double* q,
-                       double tol) {
+void ExpectArraysClose(int n, const double* p, const double* q, double tol) {
   CHECK_GT(n, 0);
   CHECK(p);
   CHECK(q);
 
   for (int i = 0; i < n; ++i) {
-    EXPECT_TRUE(ExpectClose(p[i], q[i], tol))
-        << "p[" << i << "]" << p[i] << " "
-        << "q[" << i << "]" << q[i] << " "
-        << "tol: " << tol;
+    EXPECT_TRUE(ExpectClose(p[i], q[i], tol)) << "p[" << i << "]" << p[i] << " "
+                                              << "q[" << i << "]" << q[i] << " "
+                                              << "tol: " << tol;
   }
 }
 
 std::string TestFileAbsolutePath(const std::string& filename) {
-  return JoinPath(FLAGS_test_srcdir + CERES_TEST_SRCDIR_SUFFIX,
-                  filename);
+  return JoinPath(FLAGS_test_srcdir + CERES_TEST_SRCDIR_SUFFIX, filename);
 }
 
 std::string ToString(const Solver::Options& options) {
-  return StringPrintf(
-      "(%s, %s, %s, %s, %d)",
-      LinearSolverTypeToString(options.linear_solver_type),
-      SparseLinearAlgebraLibraryTypeToString(
-          options.sparse_linear_algebra_library_type),
-      options.linear_solver_ordering? "USER": "AUTOMATIC",
-      PreconditionerTypeToString(options.preconditioner_type),
-      options.num_threads);
+  return StringPrintf("(%s, %s, %s, %s, %d)",
+                      LinearSolverTypeToString(options.linear_solver_type),
+                      SparseLinearAlgebraLibraryTypeToString(
+                          options.sparse_linear_algebra_library_type),
+                      options.linear_solver_ordering ? "USER" : "AUTOMATIC",
+                      PreconditionerTypeToString(options.preconditioner_type),
+                      options.num_threads);
 }
 
 }  // namespace internal
diff --git a/internal/ceres/test_util.h b/internal/ceres/test_util.h
index b5f1393..ad98228 100644
--- a/internal/ceres/test_util.h
+++ b/internal/ceres/test_util.h
@@ -32,6 +32,7 @@
 #define CERES_INTERNAL_TEST_UTIL_H_
 
 #include <string>
+
 #include "ceres/internal/port.h"
 #include "ceres/problem.h"
 #include "ceres/solver.h"
@@ -44,6 +45,9 @@
 // Expects that x and y have a relative difference of no more than
 // max_abs_relative_difference. If either x or y is zero, then the relative
 // difference is interpreted as an absolute difference.
+//
+// If x and y have the same non-finite value (inf or nan) we treat them as being
+// close. In such a case no error is thrown and true is returned.
 bool ExpectClose(double x, double y, double max_abs_relative_difference);
 
 // Expects that for all i = 1,.., n - 1
@@ -113,11 +117,8 @@
     Solver::Summary summary;
     Solve(options, problem, &summary);
     CHECK_NE(summary.termination_type, ceres::FAILURE);
-    problem->Evaluate(Problem::EvaluateOptions(),
-                      nullptr,
-                      final_residuals,
-                      nullptr,
-                      nullptr);
+    problem->Evaluate(
+        Problem::EvaluateOptions(), nullptr, final_residuals, nullptr, nullptr);
   }
 
   std::vector<double> expected_final_residuals_;