例如,当处理大型雅可比矩阵时,如何处理数字代码中的复杂性?


10

我正在求解一个耦合方程组的非线性系统,并且已经计算出离散系统的雅可比行列式。结果是非常复杂,下面是(仅!)的第一一个的3列3×9矩阵,

偏雅可比矩阵

(之所以会出现复杂性,部分原因是数值方案需要指数拟合才能保持稳定性。)

关于使用Jacobian实现数字代码,我有一个普遍的问题。

我可以继续在代码中实现此矩阵。但是我的直觉告诉我,由于纯粹的复杂性和不可避免的引入错误,期望几天(也许几周!)乏味的调试。似乎不可避免地如何应对这样的复杂性?您是否使用从符号包中自动生成代码(然后手动调整代码)?

首先,我计划用有限差分近似调试解析雅可比行列式,我是否应该注意任何陷阱?您如何处理代码中的类似问题?

更新资料

我正在用Python进行编码,并使用sympy生成了Jacobian。也许我可以使用代码生成功能?


您使用什么计算机代数系统生成雅可比表达式?如果使用的是Maple,则可能需要查看codegen其中的包,因为它可以为每个或所有表达式自动生成紧凑而有效的C或Fortran代码。
2013年

这里有很多有用的答案,选择一个没有意义。我应该将其设为“社区Wiki”帖子吗?
boyfarrell

Answers:


6

一个词:模块化

您的Jacobian中有很多重复的表达式可以写成它们自己的函数。您没有理由多次编写相同的操作,这将使调试更加容易。如果只写一次,则错误只有一个地方(理论上)。

模块化代码也将使测试更加容易。您可以为Jacobian的每个组成部分编写测试,而不是尝试测试整个矩阵。例如,如果您以模块化方式编写函数am(),则可以轻松为其编写健全性测试,检查是否正确区分了它等等。

另一个建议是查看用于组装Jacobian的自动差异库。无法保证它们没有错误,但是与编写自己的错误/调试相比,调试/更少的错误可能更少。以下是您可能要看的一些内容:

  • 萨卡多(Sandia Labs)
  • ADIC(阿贡)

抱歉,刚刚看到您正在使用python。ScientificPython支持AD。


好建议。中间表达式通常不需要具有自己的功能-只需将它们存储在中间变量中即可。
David Ketcheson

5

让我在这里以一个故事为开头谨慎说几句话。很久以前,刚开始时我和一个伙伴一起工作。他有一个目标很杂乱的优化问题要解决。他的解决方案是生成分析导数以进行优化。

我看到的问题是这些衍生物很讨厌。它们是使用Macsyma生成的,并转换为fortran代码,每个都有数十条连续语句。实际上,Fortran编译器对此感到不安,因为它超出了连续语句的最大数量。尽管我们找到了一个可以解决该问题的标志,但还有其他问题。

  • 在长表达式中,正如CA系统通常生成的那样,存在大量减法抵消的风险。计算很多大数,却发现它们全部互相抵消而产生一个小数。

  • 实际上,与使用有限差分的数字生成的导数相比,分析生成的导数实际上通常更昂贵。n个变量的梯度所花费的成本可能是评估目标函数的成本的n倍以上。(您可能能够节省一些时间,因为许多术语可以在各种派生词中重复使用,但这也将迫使您进行仔细的手工编码,而不是使用计算机生成的表达式。而且任何时候编写令人讨厌的数学代码表达式,则出错的可能性并不小。请确保验证这些导数的准确性。)

我的故事的重点是这些CA生成的表达式都有其自身的问题。有趣的是,我的同事实际上为这个问题的复杂性感到骄傲,他显然解决了一个非常困难的问题,因为代数是如此讨厌。我不认为他认为的是,代数是否实际上在计算正确的东西,执行得是否准确以及执行得是否有效。

如果我当时是这个项目的资深人士,我会读给他看一下暴动。他的骄傲让他使用了可能不必要复杂的解决方案,甚至没有检查基于有限差分的梯度是否足够。我敢打赌,我们可能花了一个星期的时间来运行此优化程序。至少,我会建议他仔细测试所产生的渐变。准确吗?与有限差分导数相比,精度如何?实际上,今天周围有一些工具也会在其导数预测中返回误差的估计值。对于我在MATLAB中编写的自适应微分代码(派生),这确实是正确的。

测试代码。验证派生词。

但是在执行任何此操作之前,请考虑是否可以选择其他更好的优化方案。例如,如果您正在进行指数拟合,则很有可能使用分区的非线性最小二乘法(有时称为可分离的最小二乘。我认为这是Seber和Wild在他们的书中使用的术语。)就是将参数集分为本征线性和本征非线性。使用仅对非线性参数有效的优化。假定那些参数是“已知的”,则可以使用简单的线性最小二乘法来估计固有线性参数。该方案将减少优化中的参数空间。由于您无需查找线性参数的起始值,因此它使问题更加可靠。它减小了搜索空间的维数,因此使问题运行得更快。我再次提供一个用于此目的的工具,但仅限于MATLAB中。

如果您确实使用分析导数,则对它们进行编码以重用术语。这可以节省大量时间,并且实际上可以减少错误,从而节省您自己的时间。但是,然后检查那些数字!


5

有几种策略可以考虑:

  1. 使用CAS查找符号形式的导数,然后导出代码以计算导数。

  2. 使用自动微分(AD)工具生成代码,该代码计算从代码派生的值,以计算功能。

  3. 使用有限差分近似来近似雅可比行列式。

自动微分可以产生更有效的代码来计算整个雅可比行列,然后使用符号计算为矩阵中的每个条目产生一个公式。有限差分是仔细检查导数的好方法。



1

除了BrianBorcher的出色建议之外,实值函数的另一种可行方法是使用复步导数逼近(请参阅本文(付费专区)和本文)。在某些情况下,这种方法以将函数中变量的值从实数更改为复数的代价,可以得出更准确的数值导数。第二篇文章列出了复杂阶跃函数逼近可能会失效的一些情况。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.