scipy.optimize.root 中计算雅可比行列式的默认选项

Default options in computing the Jacobian in scipy.optimize.root

scipy.optimize.rootmethod = lm 的文档中,以下是 options 关键字的默认值。

options={'col_deriv': 0, 'diag': None, 'factor': 100, 'gtol': 0.0, 'eps': 0.0, 'func': None, 'maxiter': 0, 'xtol': 1.49012e-08, 'ftol': 1.49012e-08}

col_deriv 的描述中,他们说

col_deriv : bool, optional non-zero to specify that the Jacobian function computes derivatives down the columns (faster, because there is no transpose operation)

如果我理解它说的声明,例如,如果我写 col_deriv = Truejacobian 将按列计算,因此速度更快。

问题:如果更快,为什么col_deriv的非零值不是默认值?。

我是不是漏掉了什么?

也许来自 scipy.optimize.leastsq 的文档可以提供帮助,因为它同时记录了 Dfun (Jacobian) 和 col_deriv。从 Dfun 我们得到:

Dfun : callable, optional

A function or method to compute the Jacobian of func with derivatives across the rows. If this is None, the Jacobian will be estimated.

col_deriv 我们得到:

col_deriv : bool, optional

non-zero to specify that the Jacobian function computes derivatives down the columns (faster, because there is no transpose operation).

我的解读如下:

  1. 默认情况下,scipy 期望计算雅可比矩阵的函数 return 一个遵循“正常”定义的矩阵(例如,参见 https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant ).

  2. 但是,scipy 本身会调用其他函数,可能是用 Fortran see, e.g., minpack 编写的,这些函数期望将导数(关于坐标)放在列中。

因此,如果计算雅可比矩阵的函数可以 return 一个沿列而不是行放置导数的矩阵,那么 scipy 在传递之前不需要转置雅可比矩阵到 minpack 函数从而节省计算时间。

默认值对应于编写雅可比矩阵的数学约定,如 Wikipedia 等处所述:矩阵的第一行由函数第一个分量的偏导数等组成. 这在多变量微积分中效果更好,因为可以将右边的矩阵乘以变量的列向量以获得函数的线性逼近。

例如让

fun = lambda x: [x[0]**3-x[1], 2*x[0]+x[1]-12]

雅可比行列式的传统写法是

jac = lambda x: [[3*x[0]**2, -1], [2, 1]]

其中 [3*x[0]**2, -1] 来自对 funx[0]**3-x[1] 的第一个组件的微分。

方法 root(fun, [0, 0], jac=jac) 在 12 次迭代中收敛。或者我们可以用转置的方式写雅可比矩阵,

jact = lambda x: [[3*x[0]**2, 2], [-1, 1]]

并使用

root(fun, [0, 0], jac=jact, options={"col_deriv": 1})

效果相同。对我来说,收益是否值得并不明显,但也许它适用于非常大的系统。

如果 "col_deriv": 1 是默认值,将会有不满意的用户以他们习惯的方式实现 Jacobian 并发现性能很差(在上面的示例中使用了错误版本的 Jacobian more比根搜索的步骤数加倍)。