> For the complete documentation index, see [llms.txt](https://ceres-solver-tutorial-cn.gitbook.io/ceres/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ceres-solver-tutorial-cn.gitbook.io/ceres/modeling-non-linear-least-squares/main-class-interface/autodiffcostfunction.md).

# AutoDiffCostFunction

```cpp
class AutoDiffCostFunction
```

定义一个 CostFunction 或者 SizeCostFunction 可能非常繁琐并且计算导数时很容易出错，因此 Ceres 提供了自动求导工具

```cpp
template <typename CostFunctor,
       int kNumResiduals,  // Number of residuals, or ceres::DYNAMIC.
       int... Ns>          // Size of each parameter block
class AutoDiffCostFunction : public
SizedCostFunction<kNumResiduals, Ns> {
 public:
  // Instantiate CostFunctor using the supplied arguments.
  template<class ...Args>
  explicit AutoDiffCostFunction(Args&& ...args);
  explicit AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor);
  explicit AutoDiffCostFunction(CostFunctor* functor, ownership = TAKE_OWNERSHIP);

  // Ignore the template parameter kNumResiduals and use
  // num_residuals instead.
  AutoDiffCostFunction(CostFunctor* functor,
                       int num_residuals,
                       ownership = TAKE_OWNERSHIP);
  AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor,
                       int num_residuals);
};
```

为了能够自动计算导数，用户在使用的时候需要自定义一个 class 并且重载 operator() 运算，且要使用模板参数 `T`。自动求导框架使用 Jet 对象来替换模板参数 `T`，以便于计算导数，但这些操作对用户来说都是隐藏的，因此用户只需要把这里的 `T` 当做一个 double 或者 float 类型的数据进行使用即可。括号运算符重载函数必须将残差的计算结果写入到最后一个非 const 参数中去，同时返回 true 预示着计算成功。

例如，考虑一个误差 $$e=k-x^{\top}y$$，其中 $$x,y$$ 都是两个维度的向量，$$k$$ 是一个常数，该误差的形式是最小二乘问题中的常见模式， $$x^{\top}y$$ 值可能是一系列测量结果的模型期望值，其中每次测量都有一个 $$k$$ 来构成代价函数实例，也就是说 $$x,y$$ 使我们的待优化变量，实际中我们会有多个 $$k$$ ，每个都会构成一个残差项。可以参考曲线拟合的思路。通过 Ceres 去实现上述建模的问题，我们首先要定义一个对象，并对括号运算符进行重载，计算残差。

```cpp
class MyScalarCostFunctor {
  MyScalarCostFunctor(double k): k_(k) {}

  template <typename T>
  bool operator()(const T* const x , const T* const y, T* e) const {
    e[0] = k_ - x[0] * y[0] - x[1] * y[1];
    return true;
  }

 private:
  double k_;
};
```

注意，在函数 operator() 的声明中，输入参数 $$x,y$$ 的位置在前面，通过一个 const \* 类型的模板参数传入，当然，如果有三个参数的情况下，第三个参数应该在 $$y$$ 的后面传入，输出永远是最后一个参数，是一个指向数组的指针，在上面的实现中，误差是一个标量，只有一个维度，因此只有 $$e\[0]$$被赋值。定义了该类之后，自动微分的代价函数可以被如下定义使用

```cpp
auto* cost_function
    = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(1.0);
                                                    ^  ^  ^
                                                    |  |  |
                        Dimension of residual ------+  |  |
                        Dimension of x ----------------+  |
                        Dimension of y -------------------+
```

在这个例子中，对应每一个 $$k$$ 都会有一个代价函数实例被创建。在上面的实例化中，`MyScalarCostFunction` 后面的模板参数 <1, 2, 2> 分别代表残差的维度，第一个参数的维度，第二个参数的维度。默认情况下，`AutoDiffCostFunction` 将获得传递给它的代价函数指针的所有权，即在删除 `AutoDiffCostFunction` 自身时代价函数也会被删除。不过，在某些情况下这可能并不可取，因此也可以在构造函数中指定 `DO_NOT_TAKE_OWNERSHIP` 作为第二个参数，同时传递一个不需要被 `AutoDiffCostFunction` 删除的成本函数指针。做法如下：

```cpp
MyScalarCostFunctor functor(1.0)
auto* cost_function
    = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
        &functor, DO_NOT_TAKE_OWNERSHIP);
```

在某些情况下，残差的维度我们甚至一开始是不确定的，需要在程序运行时才能够确定，`AutoDiffCostFunction` 也支持动态的残差维度。例如

```cpp
auto functor = std::make_unique<CostFunctorWithDynamicNumResiduals>(1.0);
auto* cost_function
    = new AutoDiffCostFunction<CostFunctorWithDynamicNumResiduals,
                                                    DYNAMIC, 2, 2>(
        std::move(functor),                            ^     ^  ^
        runtime_number_of_residuals); <----+           |     |  |
                                           |           |     |  |
                                           |           |     |  |
          Actual number of residuals ------+           |     |  |
          Indicate dynamic number of residuals --------+     |  |
          Dimension of x ------------------------------------+  |
          Dimension of y ---------------------------------------+
```

{% hint style="warning" %}
A common beginner’s error when first using `AutoDiffCostFunction` is to get the sizing wrong. In particular, there is a tendency to set the template parameters to (dimension of residual, number of parameters) instead of passing a dimension parameter for *every parameter block*. In the example above, that would be `<MyScalarCostFunction, 1, 2>`, which is missing the 2 as the last template argument.
{% endhint %}
