# Analytic Derivatives

在某些情况下，使用自动微分可能是低效的。例如，当导数的闭式解很容易得到时，相对于依赖自动微分代码使用的链式规则求导来说，前者更高效一点。当然也不是说不能用自动求导，具体问题往往需要具体分析，那种更快更高效其实需要在实际中做测试，选择适合自己的即可。

在这种情况下，可以提供自己的残差和雅可比计算代码。为此，我们需要定义一个 `CostFunction` 或 `SizedCostFunction` 的子类（如果在编译时知道参数和残差的大小）。例如，这里的 `SimpleCostFunction` 实现了 $$f(x)=10-x$$。

```cpp
class QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> {
 public:
  virtual ~QuadraticCostFunction() {}
  virtual bool Evaluate(double const* const* parameters,
                        double* residuals,
                        double** jacobians) const {
    const double x = parameters[0][0];
    residuals[0] = 10 - x;

    // Compute the Jacobian if asked for.
    if (jacobians != nullptr && jacobians[0] != nullptr) {
      jacobians[0][0] = -1;
    }
    return true;
  }
};
```

`SimpleCostFunction::Evaluate` 的第一个参数 `parameters` 为 input，是一个二维数组，存放优化变量的当前值，`residuals` 是一个输出数组，存放残差， `jacobians` 是一个二维数组用于存放残差相对于参数的雅可比矩阵。 `jacobians` 数组是非必须的， `Evaluate` 会检查它是否为空，如果不为空，则用残差函数的导数值填充它。在本例中，由于残差函数是线性的，因此雅各比是常数 。

从上面的代码片段可以看出，实现 `CostFunction` 对象有点繁琐。Ceres 建议使用 `AutoDiffCostFunction` 或 `NumericDiffCostFunction` 来构建残差块，除非您能够自行管理 jacobian 的计算。

## Footnotes

* [examples/helloworld\_analytic\_diff.cc](https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/helloworld_analytic_diff.cc).
