用数值方法求解非线性方程组

时间:2009-02-12 07:57:31

标签: java math mathematical-optimization numerical scientific-computing

我需要在Java程序中解决非线性最小化(N个未知数的最小残差平方)问题。解决这些问题的常用方法是Levenberg-Marquardt算法。我有几个问题

  • 是否有人对可用的不同LM实施有经验? LM的味道略有不同,我听说算法的确切实现对其数值稳定性有重要影响。我的功能非常好,所以这可能不是问题,但当然我想选择一个更好的选择。以下是我发现的一些替代方案:

  • 是否有任何常用的启发式方法来进行LM所需的初步猜测?

  • 在我的应用程序中,我需要对解决方案设置一些约束,但幸运的是它们很简单:我只是要求解决方案(为了成为物理解决方案)是非负的。略微负面的解决方案是数据中测量不准确的结果,显然应该为零。我正在考虑使用“常规”LM但是迭代以便如果一些未知数变为负数,我将其设置为零并从中解决其余部分。真正的数学家可能会嘲笑我,但你认为这可行吗?

感谢您的任何意见!

更新:这不是火箭科学,要解决的参数数量(N)最多为5,而数据集只有不足以使解决成为可能,所以我相信Java是相当的有效率足以解决这个问题。而且我相信聪明的应用数学家已经多次解决了这个问题,所以我只是在寻找一些现成的解决方案,而不是自己做饭。例如。如果它是纯Python,Scipy.optimize.minpack.leastsq可能会没问题。

5 个答案:

答案 0 :(得分:2)

您的初始猜测越接近解决方案,您收敛的速度就越快。

你说这是一个非线性问题。您可以进行线性化的最小二乘解。也许您可以使用该解决方案作为第一个猜测。一些非线性迭代会告诉你一些关于假设的好坏的信息。

另一个想法是尝试另一种优化算法。如果您可以在许多CPU上运行它们,遗传和蚁群算法可能是一个不错的选择。它们也不需要连续的导数,所以如果你有离散的,不连续的数据它们会很好。

答案 1 :(得分:2)

如果问题有限制,则不应使用无约束求解器。对于 实例如果知道你的一些变量必须是非负的,你应该知道 这对你的解算器。

如果您乐意使用Scipy,我会推荐scipy.optimize.fmin_l_bfgs_b 您可以使用L-BFGS-B在变量上放置简单边界。

请注意,L-BFGS-B采用一般的非线性目标函数,而不仅仅是 非线性最小二乘问题。

答案 2 :(得分:2)

我同意codehippo;我认为解决约束问题的最佳方法是使用专门设计来处理它们的算法。在这种情况下,L-BFGS-B算法应该是一个很好的解决方案。

但是,如果在你的情况下使用python的scipy.optimize.fmin_l_bfgs_b模块不是一个可行的选项(因为你使用的是Java),你可以尝试使用我编写的库:一个用于原始Fortran代码的Java包装器L-BFGS-B算法。您可以从http://www.mini.pw.edu.pl/~mkobos/programs/lbfgsb_wrapper下载它,看看它是否符合您的需求。

答案 3 :(得分:1)

FPL包非常可靠但有一些怪癖(数组访问从1开始),因为它对旧的fortran代码有非常直接的解释。如果您的函数表现良好,LM方法本身就非常可靠。强制非负约束的一种简单方法是直接使用参数的平方而不是参数。这可能会引入虚假解决方案,但对于简单模型,这些解决方案很容易被筛选出来。

可以使用“约束”LM方法的代码。在这里查看http://www.physics.wisc.edu/~craigm/idl/fitting.html获取mpfit。有一个python(遗憾地依赖于Numeric)和一个C版本。 LM方法大约有1500行代码,因此您可能倾向于将C移植到Java。实际上,“约束”LM方法与您设想的方法没有太大区别。在mpfit中,代码相对于变量的边界调整步长。我和mpfit也有很好的结果。

我对BFGS没有那么多经验,但是代码要复杂得多,而且我从未明白代码的许可。

祝你好运。

答案 4 :(得分:0)

我实际上并没有使用任何这些Java库,所以请稍等处理:基于后端,我可能会先查看JLAPACK。我相信LAPACK是Numpy的后端,它本质上是在Python中进行线性代数/数学操作的标准。至少,你肯定应该使用经过良好优化的C或Fortran库而不是纯Java,因为对于大型数据集,这些类型的任务可能会非常耗时。

为了创建初始猜测,它实际上取决于您尝试适合的功能类型(以及您拥有的数据类型)。基本上,只需寻找一些相对较快(可能是O(N)或更好)的计算,它将为您想要的参数提供近似值。 (我最近用Numpy中的高斯分布做了这个,我估计平均值只是average(values, weights = counts) - 也就是直方图中计数的加权平均值,这是数据集的真实均值。我正在寻找的峰值的确切中心,但它已经足够接近了,并且算法完成剩下的工作。)

至于保持正面的约束,你的方法似乎是合理的。由于您正在编写一个程序来完成工作,因此可能只需创建一个布尔标志,以便您轻松启用或禁用“强制 - 非负”行为,并将其运行两种方式进行比较。只有当你遇到很大的差异时(或者如果一个版本的算法花费的时间过长),可​​能需要担心。 (真正的数学家会从头开始分析最小二乘最小化;-P所以我认为你是那个可以嘲笑他们的人......开玩笑。也许吧。)