# 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ceres-solver-tutorial-cn.gitbook.io/ceres/modeling-non-linear-least-squares/main-class-interface/autodiffcostfunction.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
