> 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/autodiffmanifold.md).

# AutoDIffManifold

```cpp
class AutoDiffManifold
```

创建一个流形，同时通过自动微分来计算导数。要获得自动微分流形，必须定义一个带有模板化加减函数的 Functor：

```cpp
x_plus_delta = Plus(x, delta);
y_minus_x    = Minus(y, x);
```

其中，`x`、`y` 和 `x_plus_delta` 是局部空间上的向量（因此它们是 `kAmbientSize` 大小的向量），`delta`、`y_minus_x` 是切线空间中的向量（因此它们是 `kTangentSize` 大小向量）。Functor 的定义如下：

```cpp
struct Functor {
 template <typename T>
 bool Plus(const T* x, const T* delta, T* x_plus_delta) const;

 template <typename T>
 bool Minus(const T* y, const T* x, T* y_minus_x) const;
};
```

请注意，`Plus` 和 `Minus` 操作是以参数 `T` 为模板的。自动微分框架会用适当的 `Jet` 对象代替 `T`，以便在必要时计算导数。这与使用 `AutoDiffCostFunction` 时计算导数的机制相同。如果计算成功，`Plus` 和 `Minus` 应返回 true，否则返回 false，在这种情况下，计算结果将不会被使用。给定这个 Functor，相应的 `Manifold` 可以这样构造：

```cpp
AutoDiffManifold<Functor, kAmbientSize, kTangentSize> manifold;
```

{% hint style="warning" %}
The following is only used for illustration purposes. Ceres Solver ships with an optimized, production grade `QuaternionManifold` implementation.
{% endhint %}

作为一个具体的例子，我们来看看 [Quaternions](https://en.wikipedia.org/wiki/Quaternion) 要如何实现。四元数是嵌入到 $$\mathbb{R}^4$$ 的三维流形，即它们的局部维数为 4，切空间维数为 3。下面的函数定义了四元数流形上的 `Plus` 和 `Minus` 运算。它假定四元数在内存中的布局为 `[w,x,y,z]`，即实数或标量部分是第一坐标。

```cpp
struct QuaternionFunctor {
  template <typename T>
  bool Plus(const T* x, const T* delta, T* x_plus_delta) const {
    const T squared_norm_delta =
        delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];

    T q_delta[4];
    if (squared_norm_delta > T(0.0)) {
      T norm_delta = sqrt(squared_norm_delta);
      const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
      q_delta[0] = cos(norm_delta);
      q_delta[1] = sin_delta_by_delta * delta[0];
      q_delta[2] = sin_delta_by_delta * delta[1];
      q_delta[3] = sin_delta_by_delta * delta[2];
    } else {
      // We do not just use q_delta = [1,0,0,0] here because that is a
      // constant and when used for automatic differentiation will
      // lead to a zero derivative. Instead we take a first order
      // approximation and evaluate it at zero.
      q_delta[0] = T(1.0);
      q_delta[1] = delta[0];
      q_delta[2] = delta[1];
      q_delta[3] = delta[2];
    }

    QuaternionProduct(q_delta, x, x_plus_delta);
    return true;
  }

  template <typename T>
  bool Minus(const T* y, const T* x, T* y_minus_x) const {
    T minus_x[4] = {x[0], -x[1], -x[2], -x[3]};
    T ambient_y_minus_x[4];
    QuaternionProduct(y, minus_x, ambient_y_minus_x);
    T u_norm = sqrt(ambient_y_minus_x[1] * ambient_y_minus_x[1] +
                    ambient_y_minus_x[2] * ambient_y_minus_x[2] +
                    ambient_y_minus_x[3] * ambient_y_minus_x[3]);
    if (u_norm > 0.0) {
      T theta = atan2(u_norm, ambient_y_minus_x[0]);
      y_minus_x[0] = theta * ambient_y_minus_x[1] / u_norm;
      y_minus_x[1] = theta * ambient_y_minus_x[2] / u_norm;
      y_minus_x[2] = theta * ambient_y_minus_x[3] / u_norm;
    } else {
      We do not use [0,0,0] here because even though the value part is
      a constant, the derivative part is not.
      y_minus_x[0] = ambient_y_minus_x[1];
      y_minus_x[1] = ambient_y_minus_x[2];
      y_minus_x[2] = ambient_y_minus_x[3];
    }
    return true;
  }
};
```

根据这一结构，使用自动微分的四元数流形可以构造为

```cpp
Manifold* manifold = new AutoDiffManifold<QuaternionFunctor, 4, 3>;
```
