AutoDiff Code Generation - CMake Integration

This patch integrates the code generation module into the build
system. All depenendcies are tracked through CMake targets.
Modifying the cost functor will automatically trigger code
re-generation.

All this functionality is defined in the CMake function
ceres_generate_cost_function_implementation_for_functor
in CeresCodeGeneration.cmake. A hello world usage example
is included in examples/CMakeLists.txt.

Change-Id: I23b8b6698d1ea51cf3d788a47afcf39f8c5ce327
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f11e579..9bd1e90 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -771,6 +771,12 @@
               "${Ceres_SOURCE_DIR}/cmake/FindGlog.cmake"
         DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR})
 
+# Install codegen cmake scripts
+install(FILES "${Ceres_SOURCE_DIR}/cmake/codegen_include.h.in"
+              "${Ceres_SOURCE_DIR}/cmake/generate_code_for_functor.cc.in"
+              "${Ceres_SOURCE_DIR}/cmake/CeresCodeGeneration.cmake"
+        DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR})
+
 if (PROVIDE_UNINSTALL_TARGET)
   # Create an uninstall target to remove all installed files.
   configure_file("${Ceres_SOURCE_DIR}/cmake/uninstall.cmake.in"
diff --git a/cmake/CeresCodeGeneration.cmake b/cmake/CeresCodeGeneration.cmake
new file mode 100644
index 0000000..f3819ce
--- /dev/null
+++ b/cmake/CeresCodeGeneration.cmake
@@ -0,0 +1,153 @@
+# Ceres Solver - A fast non-linear least squares minimizer
+# Copyright 2019 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.
+#
+# Author: darius.rueckert@fau.de (Darius Rueckert)
+
+# The directory containing the following files
+#   - codegen_include.h.in
+#   - generate_code_from_functor.cc.in
+set(CODEGEN_CMAKE_SCRIPT_DIR "${CMAKE_CURRENT_LIST_DIR}")
+
+# Generates C-code implementation of Ceres' CostFunction::Evaluate() API from a
+# templated C++ cost functor derived from ceres::CodegenCostFunction using
+# autodiff. The resulting implementation replaces the direct instantiation of
+# autodiff in client code, typically resulting in improved performance.
+#
+# Parameters:
+#
+# NAME
+#     The name of the cost functor. The name must exactly match the C++ type
+#     name of the functor. This is also the name of the CMake output target.
+# NAMESPACE [optional]
+#     The C++ namespace of the cost functor type. For example, if the full
+#     type name is ceres::BundleAdjust, then NAME should be "BundleAdjust"
+#     and NAMESPACE should be "ceres".
+# INPUT_FILE
+#     The path to the header defining the cost functor <NAME>.
+# OUTPUT_DIRECTORY [default = "generated"]
+#     The relative output directory of the generated header file. This is the
+#     prefix that has to be added to the #include of the generated files, i.e:
+#     #include "<OUTPUT_DIRECTORY>/<GENERATED_FILE.h>"
+
+#
+# Example Usage:
+#   ceres_generate_cost_function_implementation_for_functor(
+#       NAME SquareFunctor
+#       INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/square_functor.h
+#       )
+#   add_executable(helloworld_codegen helloworld_codegen.cc )
+#   target_link_libraries(helloworld_codegen ceres SquareFunctor)
+function(ceres_generate_cost_function_implementation_for_functor)
+  # Define and parse arguments
+  set(OPTIONAL_ARGS)
+  set(ONE_VALUE_ARGS NAME INPUT_FILE OUTPUT_DIRECTORY NAMESPACE)
+  set(MULTI_VALUE_ARGS)
+  cmake_parse_arguments(
+    COST_FUNCTOR "${OPTIONAL_ARGS}" "${ONE_VALUE_ARGS}"
+    "${MULTI_VALUE_ARGS}" ${ARGN} )
+
+  # Default value of the output directory
+  set(OUTPUT_DIRECTORY "generated")
+  if(COST_FUNCTOR_OUTPUT_DIRECTORY)
+    set(OUTPUT_DIRECTORY "${COST_FUNCTOR_OUTPUT_DIRECTORY}")
+  endif()
+
+  set(CALLER_CODEGEN_BUILD_DIR "${PROJECT_BINARY_DIR}/codegen")
+  set(CALLER_CODEGEN_INCLUDE_DIR "${CALLER_CODEGEN_BUILD_DIR}/include/")
+
+  file(MAKE_DIRECTORY
+    "${CALLER_CODEGEN_BUILD_DIR}")
+  file(MAKE_DIRECTORY
+    "${CALLER_CODEGEN_INCLUDE_DIR}/${OUTPUT_DIRECTORY}")
+  file(MAKE_DIRECTORY
+    "${CALLER_CODEGEN_BUILD_DIR}/src")
+
+  # Convert the input file to an absolute path and check if it exists
+  get_filename_component(
+    COST_FUNCTOR_INPUT_FILE "${COST_FUNCTOR_INPUT_FILE}" REALPATH)
+  if(NOT EXISTS "${COST_FUNCTOR_INPUT_FILE}")
+    message(FATAL_ERROR
+      "Could not find codegen input file ${COST_FUNCTOR_INPUT_FILE}")
+  endif()
+
+
+  # The full C++ type name of the cost functor. This is used inside the
+  # generator to create an object of it.
+  set(FULL_CXX_FUNCTOR_TYPE_NAME "${COST_FUNCTOR_NAME}")
+  if(COST_FUNCTOR_NAMESPACE)
+    set(FULL_CXX_FUNCTOR_TYPE_NAME
+      "${COST_FUNCTOR_NAMESPACE}::${FULL_CXX_FUNCTOR_TYPE_NAME}")
+  endif()
+
+  # 1. Generate a wrapper include file which is included by the user.
+  #    This is required, because
+  #      - It must exist during compiliation of the code generator (otherwise
+  #        the #include will fail)
+  #      - We don't want to have the users add macros to their code
+  string(TOLOWER "${COST_FUNCTOR_NAME}" LOWER_CASE_FUNCTOR_NAME)
+  set(INCLUDE_FILE
+    "${CALLER_CODEGEN_INCLUDE_DIR}/${OUTPUT_DIRECTORY}/${LOWER_CASE_FUNCTOR_NAME}.h")
+  configure_file("${CODEGEN_CMAKE_SCRIPT_DIR}/codegen_include.inc.in" "${INCLUDE_FILE}")
+
+  # 2. Generate the source file for the code generator
+  set(GENERATOR_SOURCE
+    "${CALLER_CODEGEN_BUILD_DIR}/src/${LOWER_CASE_FUNCTOR_NAME}_code_generator.cc")
+  set(GENERATED_EVALUATION_IMPL_FILE
+    "${CALLER_CODEGEN_INCLUDE_DIR}/${OUTPUT_DIRECTORY}/${LOWER_CASE_FUNCTOR_NAME}_evaluate_impl.inc")
+  configure_file(
+    "${CODEGEN_CMAKE_SCRIPT_DIR}/generate_code_for_functor.cc.in" "${GENERATOR_SOURCE}")
+
+  # 3. Build the executable that generates the autodiff code
+  set(GENERATOR_TARGET ${COST_FUNCTOR_NAME}_generator)
+  add_executable(${GENERATOR_TARGET} "${GENERATOR_SOURCE}")
+  target_link_libraries(${GENERATOR_TARGET} ceres)
+  set_target_properties(${GENERATOR_TARGET} PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY "${CALLER_CODEGEN_BUILD_DIR}/bin")
+  target_compile_definitions(${GENERATOR_TARGET} PRIVATE -DCERES_CODEGEN)
+  target_include_directories(${GENERATOR_TARGET}
+    PRIVATE "${CALLER_CODEGEN_INCLUDE_DIR}")
+
+  # 4. Execute the program from (3.) using a custom command
+  add_custom_command(OUTPUT "${GENERATED_EVALUATION_IMPL_FILE}"
+    COMMAND ${GENERATOR_TARGET}
+    DEPENDS "${COST_FUNCTOR_INPUT_FILE}"
+    VERBATIM
+    )
+  set(GENERATE_TARGET ${COST_FUNCTOR_NAME}_generate)
+  add_custom_target(${GENERATE_TARGET} DEPENDS "${GENERATED_EVALUATION_IMPL_FILE}" VERBATIM)
+
+  # 5. Create an output target which can be used by the client. This is required,
+  #    because custom targets can't have include directories.
+  set(OUTPUT_TARGET ${COST_FUNCTOR_NAME})
+  add_library(${OUTPUT_TARGET} INTERFACE)
+  target_include_directories(
+    ${OUTPUT_TARGET} INTERFACE "${CALLER_CODEGEN_INCLUDE_DIR}")
+  target_sources(
+    ${OUTPUT_TARGET} INTERFACE "${INCLUDE_FILE}" "${GENERATED_EVALUATION_IMPL_FILE}")
+  add_dependencies(${OUTPUT_TARGET} ${GENERATE_TARGET})
+endfunction()
diff --git a/cmake/CeresConfig.cmake.in b/cmake/CeresConfig.cmake.in
index ced7daf..fd84dd2 100644
--- a/cmake/CeresConfig.cmake.in
+++ b/cmake/CeresConfig.cmake.in
@@ -166,6 +166,10 @@
 include(CMakeFindDependencyMacro)
 find_dependency(Threads)
 
+# Import code generation functions s/t they are available for use in client code
+# if find_package(Ceres) is successful.
+include(CeresCodeGeneration.cmake)
+
 # Eigen.
 # Flag set during configuration and build of Ceres.
 set(CERES_EIGEN_VERSION @EIGEN3_VERSION_STRING@)
diff --git a/cmake/codegen_include.inc.in b/cmake/codegen_include.inc.in
new file mode 100644
index 0000000..f52485b
--- /dev/null
+++ b/cmake/codegen_include.inc.in
@@ -0,0 +1,10 @@
+// This file is generated by Ceres autodiff code generation.
+// http://ceres-solver.org/
+
+#ifdef CERES_CODEGEN
+// Included by generator during generation of autodiff evaluation implementation,
+// by definition the generated implementation does not yet exist to be imported.
+#else
+// Included from client code, import generated implementation.
+#include "@OUTPUT_DIRECTORY@/@LOWER_CASE_FUNCTOR_NAME@_evaluate_impl.inc"
+#endif
diff --git a/cmake/generate_code_for_functor.cc.in b/cmake/generate_code_for_functor.cc.in
new file mode 100644
index 0000000..2ae2640
--- /dev/null
+++ b/cmake/generate_code_for_functor.cc.in
@@ -0,0 +1,27 @@
+// This file is generated by Ceres autodiff code generation."
+// http://ceres-solver.org/
+
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "ceres/codegen/generate_code_for_functor.h"
+#include "@COST_FUNCTOR_INPUT_FILE@"
+
+int main() {
+  const std::vector<std::string> lines =
+      ceres::GenerateCodeForFunctor<@FULL_CXX_FUNCTOR_TYPE_NAME@>(
+          ceres::AutoDiffCodeGenOptions());
+  const std::string output_file = "@GENERATED_EVALUATION_IMPL_FILE@";
+  std::ofstream stream(output_file);
+  if (!stream.is_open()) {
+    std::cerr << "Could not open file " << output_file << std::endl;
+    return EXIT_FAILURE;
+  }
+  for (auto line : lines) {
+    stream << line << std::endl;
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index e2f4df4..f185d19 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -73,8 +73,15 @@
 target_link_libraries(simple_bundle_adjuster ceres)
 
 if(CODE_GENERATION)
-  add_executable(autodiff_codegen autodiff_codegen.cc)
-  target_link_libraries(autodiff_codegen ceres)
+  include(CeresCodeGeneration)
+  ceres_generate_cost_function_implementation_for_functor(
+    NAME HelloWorldCostFunction
+    INPUT_FILE helloworld_cost_function.h
+    OUTPUT_DIRECTORY examples
+    NAMESPACE helloworld
+    )
+  add_executable(helloworld_codegen helloworld_codegen.cc )
+  target_link_libraries(helloworld_codegen ceres HelloWorldCostFunction)
 endif(CODE_GENERATION)
 
 if (GFLAGS)
diff --git a/examples/autodiff_codegen.cc b/examples/helloworld_codegen.cc
similarity index 69%
copy from examples/autodiff_codegen.cc
copy to examples/helloworld_codegen.cc
index 7813ac4..6aa0792 100644
--- a/examples/autodiff_codegen.cc
+++ b/examples/helloworld_codegen.cc
@@ -29,27 +29,37 @@
 // Author: darius.rueckert@fau.de (Darius Rueckert)
 //
 // A simple example showing how to generate code for a cost functor
-//
-// We recommend to use the CMake integration instead of using
-// GenerateCodeForFunctor directly.
-//
-#include "ceres/codegen/autodiff.h"
 
-struct SquareFunctor {
-  template <typename T>
-  bool operator()(const T* x, T* residual) const {
-    residual[0] = x[0] * x[0];
-    isfinite(x[0]);
-    return true;
-  }
-};
+#include "ceres/ceres.h"
+#include "glog/logging.h"
+#include "helloworld_cost_function.h"
+
+using ceres::CostFunction;
+using ceres::Problem;
+using ceres::Solve;
+using ceres::Solver;
 
 int main(int argc, char** argv) {
-  std::vector<std::string> code =
-      ceres::GenerateCodeForFunctor<SquareFunctor, 1, 1>(
-          ceres::AutoDiffCodeGenOptions());
-  for (auto str : code) {
-    std::cout << str << std::endl;
-  }
+  google::InitGoogleLogging(argv[0]);
+
+  // The variable to solve for with its initial value. It will be
+  // mutated in place by the solver.
+  double x = 0.5;
+  const double initial_x = x;
+
+  Problem problem;
+
+  const double kTargetValue = 10.0;
+  CostFunction* cost_function =
+      new helloworld::HelloWorldCostFunction(kTargetValue);
+  problem.AddResidualBlock(cost_function, NULL, &x);
+
+  Solver::Options options;
+  options.minimizer_progress_to_stdout = true;
+  Solver::Summary summary;
+  Solve(options, &problem, &summary);
+
+  std::cout << summary.BriefReport() << "\n";
+  std::cout << "x : " << initial_x << " -> " << x << "\n";
   return 0;
 }
diff --git a/examples/autodiff_codegen.cc b/examples/helloworld_cost_function.h
similarity index 72%
rename from examples/autodiff_codegen.cc
rename to examples/helloworld_cost_function.h
index 7813ac4..764d6c7 100644
--- a/examples/autodiff_codegen.cc
+++ b/examples/helloworld_cost_function.h
@@ -28,28 +28,29 @@
 //
 // Author: darius.rueckert@fau.de (Darius Rueckert)
 //
-// A simple example showing how to generate code for a cost functor
-//
-// We recommend to use the CMake integration instead of using
-// GenerateCodeForFunctor directly.
-//
-#include "ceres/codegen/autodiff.h"
+#include "ceres/codegen/codegen_cost_function.h"
 
-struct SquareFunctor {
+namespace helloworld {
+
+struct HelloWorldCostFunction : public ceres::CodegenCostFunction<1, 1> {
+  // We need a default constructor, because code is generated for the cost
+  // functor and not a specific instantiation of it.
+  HelloWorldCostFunction() = default;
+  explicit HelloWorldCostFunction(double target_value)
+      : target_value_(target_value) {}
+
   template <typename T>
   bool operator()(const T* x, T* residual) const {
-    residual[0] = x[0] * x[0];
-    isfinite(x[0]);
+    residual[0] = CERES_LOCAL_VARIABLE(T, target_value_) - x[0];
     return true;
   }
+
+// The include file name is automatically generated as
+// "<output_dir>/<lower_case_class_name>.h"
+#include "examples/helloworldcostfunction.h"
+
+ private:
+  double target_value_;
 };
 
-int main(int argc, char** argv) {
-  std::vector<std::string> code =
-      ceres::GenerateCodeForFunctor<SquareFunctor, 1, 1>(
-          ceres::AutoDiffCodeGenOptions());
-  for (auto str : code) {
-    std::cout << str << std::endl;
-  }
-  return 0;
-}
+}  // namespace helloworld
diff --git a/include/ceres/codegen/codegen_cost_function.h b/include/ceres/codegen/codegen_cost_function.h
new file mode 100644
index 0000000..57df088
--- /dev/null
+++ b/include/ceres/codegen/codegen_cost_function.h
@@ -0,0 +1,90 @@
+// 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)
+//
+#ifndef CERES_PUBLIC_CODEGEN_COST_FUNCTION_H_
+#define CERES_PUBLIC_CODEGEN_COST_FUNCTION_H_
+
+#include "ceres/codegen/macros.h"
+#include "ceres/sized_cost_function.h"
+
+namespace ceres {
+
+// This is the interface for automatically generating cost functor derivative
+// code. The template parameters are identical to those of SizedCostFunction<>.
+// The behaviour of this class changes between code generation and problem
+// solving.
+//
+// During code generation (when CERES_CODEGEN is defined), this class doesn't do
+// anything. The templated operator() from your derived cost functor is used.
+//
+// After code generation (when CERES_CODEGEN is not defined), this class is a
+// SizedCostFunction. The required Evaluate() function was generated and must be
+// included into your cost functor.
+//
+// Usage Example:
+//
+//   #include "ceres/codegen/cost_function.h"
+//
+//   struct HelloWorldCostFunction : public ceres::CodegenCostFunction<1, 1> {
+//     // A default constructor is required, because the code generator has to
+//     // create an object of the cost function.
+//     HelloWorldCostFunction() = default;
+//     template <typename T>
+//     bool operator()(const T* x, T* residual) const {
+//       residual[0] = x[0] * x[0];
+//       return true;
+//     }
+//   #include "examples/helloworldcostfunction.h"
+//   };
+
+template <int kNumResiduals_, int... Ns>
+class CodegenCostFunction
+#ifdef CERES_CODEGEN
+// During code generation we can't derive from SizedCostFunction.
+// The variadic evaluation with Jets would try to call the empty Evaluate()
+// instead of the templated functor.
+#else
+    : public SizedCostFunction<kNumResiduals_, Ns...>
+#endif
+{
+ public:
+  static constexpr int kNumResiduals = kNumResiduals_;
+  static_assert(kNumResiduals > 0,
+                "Cost functions must have at least one residual block.");
+  static_assert(kNumResiduals != DYNAMIC,
+                "Code generation for dynamic residuals is not yet supported.");
+  static_assert(internal::StaticParameterDims<Ns...>::kIsValid,
+                "Invalid parameter block dimension detected. Each parameter "
+                "block dimension must be bigger than zero.");
+  using ParameterDims = internal::StaticParameterDims<Ns...>;
+};
+
+}  // namespace ceres
+#endif  // CERES_PUBLIC_CODEGEN_COST_FUNCTION_H_
diff --git a/include/ceres/codegen/autodiff.h b/include/ceres/codegen/generate_code_for_functor.h
similarity index 88%
rename from include/ceres/codegen/autodiff.h
rename to include/ceres/codegen/generate_code_for_functor.h
index 0a2a65d..31ccdb2 100644
--- a/include/ceres/codegen/autodiff.h
+++ b/include/ceres/codegen/generate_code_for_functor.h
@@ -42,18 +42,17 @@
 struct AutoDiffCodeGenOptions {};
 
 // TODO(darius): Documentation
-template <typename CostFunctor, int kNumResiduals, int... Ns>
+template <typename DerivedCostFunctor>
 std::vector<std::string> GenerateCodeForFunctor(
     const AutoDiffCodeGenOptions& options) {
-  static_assert(kNumResiduals != DYNAMIC,
-                "A dynamic number of residuals is currently not supported.");
   // Define some types and shortcuts to make the code below more readable.
-  using ParameterDims = internal::StaticParameterDims<Ns...>;
+  using ParameterDims = typename DerivedCostFunctor::ParameterDims;
   using Parameters = typename ParameterDims::Parameters;
   // Instead of using scalar Jets, we use Jets of ExpressionRef which record
   // their own operations during evaluation.
   using ExpressionRef = internal::ExpressionRef;
   using ExprJet = Jet<ExpressionRef, ParameterDims::kNumParameters>;
+  constexpr int kNumResiduals = DerivedCostFunctor::kNumResiduals;
   constexpr int kNumParameters = ParameterDims::kNumParameters;
   constexpr int kNumParameterBlocks = ParameterDims::kNumParameterBlocks;
 
@@ -61,7 +60,11 @@
   // Code is generated for the CostFunctor and not an instantiation of it. This
   // is different to AutoDiffCostFunction, which computes the derivatives for
   // a specific object.
-  CostFunctor functor;
+  static_assert(std::is_default_constructible<DerivedCostFunctor>::value,
+                "Cost functors used in code generation must have a default "
+                "constructor. If you are using local variables, make sure to "
+                "wrap them into the CERES_LOCAL_VARIABLE macro.");
+  DerivedCostFunctor functor;
 
   // During recording phase all operations on ExpressionRefs are recorded to an
   // internal data structure, the ExpressionGraph. This ExpressionGraph is then
@@ -164,7 +167,7 @@
     internal::CodeGenerator::Options generator_options;
     generator_options.function_name =
         "void EvaluateResidual(double const* const* parameters, double* "
-        "residuals)";
+        "residuals) const";
     internal::CodeGenerator gen(residual_graph, generator_options);
     std::vector<std::string> code = gen.Generate();
     output.insert(output.end(), code.begin(), code.end());
@@ -179,7 +182,7 @@
     generator_options.function_name =
         "void EvaluateResidualAndJacobian(double const* const* parameters, "
         "double* "
-        "residuals, double** jacobians)";
+        "residuals, double** jacobians) const";
     internal::CodeGenerator gen(residual_and_jacobian_graph, generator_options);
     std::vector<std::string> code = gen.Generate();
     output.insert(output.end(), code.begin(), code.end());
@@ -193,8 +196,12 @@
   // in SizedCostFunctions.
   output.emplace_back("bool Evaluate(double const* const* parameters,");
   output.emplace_back("              double* residuals,");
-  output.emplace_back("              double** jacobians) {");
-  output.emplace_back("   if (jacobians) {");
+  output.emplace_back("              double** jacobians) const {");
+
+  output.emplace_back("   if (!jacobians) {");
+  output.emplace_back("     EvaluateResidual(parameters, residuals);");
+  output.emplace_back("     return true;");
+  output.emplace_back("   }");
 
   // Create a tmp array of all jacobians and use it for evaluation.
   // The generated code for a <2,3,1,2> cost functor is:
@@ -204,19 +211,19 @@
   //       jacobians_data + 6,
   //       jacobians_data + 8,
   //   };
-  output.emplace_back("     double jacobians_data[" +
+  output.emplace_back("   double jacobians_data[" +
                       std::to_string(kNumParameters * kNumResiduals) + "];");
-  output.emplace_back("     double* jacobians_ptrs[] = {");
+  output.emplace_back("   double* jacobians_ptrs[] = {");
   for (int i = 0, total_param_id = 0; i < kNumParameterBlocks;
        total_param_id += ParameterDims::GetDim(i), ++i) {
-    output.emplace_back("       jacobians_data + " +
+    output.emplace_back("     jacobians_data + " +
                         std::to_string(kNumResiduals * total_param_id) + ",");
   }
-  output.emplace_back("     };");
+  output.emplace_back("   };");
 
   // Evaluate into the tmp array.
   output.emplace_back(
-      "     EvaluateResidualAndJacobian(parameters, residuals, "
+      "   EvaluateResidualAndJacobian(parameters, residuals, "
       "jacobians_ptrs);");
 
   // Copy the computed jacobians into the output array. Add an if-statement to
@@ -238,18 +245,15 @@
   //      }
   //    }
   for (int i = 0; i < kNumParameterBlocks; ++i) {
-    output.emplace_back("     if (jacobians[" + std::to_string(i) + "]) {");
+    output.emplace_back("   if (jacobians[" + std::to_string(i) + "]) {");
     output.emplace_back(
-        "       for (int i = 0; i < " +
+        "     for (int i = 0; i < " +
         std::to_string(ParameterDims::GetDim(i) * kNumResiduals) + "; ++i) {");
-    output.emplace_back("         jacobians[" + std::to_string(i) +
+    output.emplace_back("       jacobians[" + std::to_string(i) +
                         "][i] = jacobians_ptrs[" + std::to_string(i) + "][i];");
-    output.emplace_back("       }");
     output.emplace_back("     }");
+    output.emplace_back("   }");
   }
-  output.emplace_back("     return true;");
-  output.emplace_back("   }");
-  output.emplace_back("   EvaluateResidual(parameters, residuals);");
   output.emplace_back("   return true;");
   output.emplace_back("}");