个人而言,2019年觉得比较好用的python 库是sympy。SymPywww.sympy.org
这是一个符号运算库。
SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python.
里面包含大量的feature。对我个人而言,工作中,经常要对各种函数求导, 有些求导比较简单,但是有些函数本身比较复杂,导数不是难么显而易见的。 虽然在在写程序的时候可以用numerica jacobian,或者类似 ceres-solver 这种软件包提供的auto-diff 工具, 但是从效率上讲,还是有一个解析的导数形式会更高效一些(大多是情况下)。
SymPy不仅仅是好用的符号运算库,还自带一个 sympy.printing.cxxcode 也就是说,它可以很方便的把求得的解析形式转化成 C++的函数。 类似于matlab的code generator。 不得不说是C++ practicer福音。
下面是一个简单的例子, 算出jacobian的同时,给出c++的code:
Jacobian (pretty-printed):
[n₀⋅(gtf₀ ₁⋅l₂ - gtf₀ ₂⋅l₁) + n₁⋅(gtf₁ ₁⋅l₂ - gtf₁ ₂⋅l₁) + n₂⋅(gtf₂ ₁⋅l₂ - gtf₂ ₂⋅l₁) -n₀⋅(gtf₀ ₀⋅l₂ - gtf₀ ₂⋅l₀) - n₁⋅(gtf₁ ₀⋅l₂ - gtf₁ ₂⋅l₀) - n₂⋅(gtf₂ ₀⋅l₂ - gtf₂ ₂⋅l₀) n₀⋅(gtf₀ ₀⋅l₁ - gtf₀ ₁⋅l₀) +
n₁⋅(gtf₁ ₀⋅l₁ - gtf₁ ₁⋅l₀) + n₂⋅(gtf₂ ₀⋅l₁ - gtf₂ ₁⋅l₀) -gtf₀ ₀⋅n₀ - gtf₁ ₀⋅n₁ - gtf₂ ₀⋅n₂ -gtf₀ ₁⋅n₀ - gtf₁ ₁⋅n₁ - gtf₂ ₁⋅n₂ -gtf₀ ₂⋅n₀ - gtf₁ ₂⋅n₁ - gtf₂ ₂⋅n₂]
c++
void ComputeResidualAndJacobian(Scalar gtf_0_0, Scalar gtf_0_1, Scalar gtf_0_2, Scalar gtf_0_3, Scalar gtf_1_0, Scalar gtf_1_1, Scalar gtf_1_2, Scalar gtf_1_3, Scalar gtf_2_0, Scalar gtf_2_1, Scalar gtf_2_2, Scalar gtf_2_3, Scalar l_0, Scalar l_1, Scalar l_2, Scalar n_0, Scalar n_1, Scalar n_2, Scalar s_0, Scalar s_1, Scalar s_2, Scalar* residuals, Scalar* jacobian) {
*residuals = n_0*(gtf_0_0*l_0 + gtf_0_1*l_1 + gtf_0_2*l_2 + gtf_0_3 - s_0) + n_1*(gtf_1_0*l_0 + gtf_1_1*l_1 + gtf_1_2*l_2 + gtf_1_3 - s_1) + n_2*(gtf_2_0*l_0 + gtf_2_1*l_1 + gtf_2_2*l_2 + gtf_2_3 - s_2);
jacobian[0] = n_0*(gtf_0_1*l_2 - gtf_0_2*l_1) + n_1*(gtf_1_1*l_2 - gtf_1_2*l_1) + n_2*(gtf_2_1*l_2 - gtf_2_2*l_1);
jacobian[1] = -n_0*(gtf_0_0*l_2 - gtf_0_2*l_0) - n_1*(gtf_1_0*l_2 - gtf_1_2*l_0) - n_2*(gtf_2_0*l_2 - gtf_2_2*l_0);
jacobian[2] = n_0*(gtf_0_0*l_1 - gtf_0_1*l_0) + n_1*(gtf_1_0*l_1 - gtf_1_1*l_0) + n_2*(gtf_2_0*l_1 - gtf_2_1*l_0);
jacobian[3] = -gtf_0_0*n_0 - gtf_1_0*n_1 - gtf_2_0*n_2;
jacobian[4] = -gtf_0_1*n_0 - gtf_1_1*n_1 - gtf_2_1*n_2;
jacobian[5] = -gtf_0_2*n_0 - gtf_1_2*n_1 - gtf_2_2*n_2;
}