在 python 中求解没有初始解的非线性方程(matlab 有效,python 无效)

Posted

技术标签:

【中文标题】在 python 中求解没有初始解的非线性方程(matlab 有效,python 无效)【英文标题】:Solve nonlinear equations without initial solution in python (matlab works, python does not) 【发布时间】:2021-11-05 11:10:23 【问题描述】:

目前我尝试计算以下形式的指数函数: f(x) = aexp(-bx)+c

对于上下文:这应该是二氧化碳排放量的减少函数。

条件如下:

f(x=0) = 700 Mt(德国当前的二氧化碳排放量) f(x=30) = 0 Mt(30 年内无二氧化碳排放) 积分 0->30 f(x) = 预算(剩余的二氧化碳预算 - 曲线下面积)

我可以使用 matlab (solve-function) 解决这个问题

但我想用 python 来做,但我尝试的所有求解器都失败了。当我使用 matlab 脚本的解决方案作为初始猜测时,一切正常。但我不想那样做。如果我不知道一个好的初始猜测,我想使用一个 python 求解器。

我应该使用哪一个?到目前为止,我从 scipy 和 gekko 尝试了 fsolve。

这是我的壁虎尝试的代码:

def solve(self, end_year, budget):
        self.end_year = end_year
        self.budget = budget
        d_year = self.end_year - self.start_year
        
        m = GEKKO()
        a,b,c = [m.Var(1) for i in range(3)]
        
        eq1 = a + c - self.co2_start
        eq2 = a*m.exp(-b*d_year) + c
        eq3 = a/b*(1-m.exp(-b*d_year))+c*d_year-self.budget
        
        m.Equation([eq1==0, eq2==0, eq3==0])
        m.solve(disp=False)
        self.a, self.b, self.c = a.value, b.value, c.value
´´´

【问题讨论】:

在我看来,分析(精确)解决方案应该是可能的。 a = -c 因为exp(0) = 1 不管b 的值如何,都可以从那里拿走。 @Thomas 实际上是 a+c = co2_start。我认为没有分析解决方案。 matlab 告诉我找不到解析解 嗯,好的,再想一想,由于积分,我不太确定是否存在解析解。但无论如何,您都可以通过消除其中一个未知数来简化求解器的工作。也许这允许你使用一个简单的初始猜测,比如将剩余的两个未知数设置为 0。 @Thomas 哦,太好了,谢谢,这确实有效!我设法消除了 a 和 c,最后只得到了 b 的方程式 【参考方案1】:

我没有认真考虑过这个问题的形式,但这里有一段使用scipy 的代码对我有用,不需要分析解决方案或简化:

from math import exp
import numpy as np
import scipy.integrate
import scipy.optimize
import matplotlib.pyplot as plt

co2_start = 700
co2_end = 0
year = 30
budget = 5000 # Not mentioned in the question

def func(x, a, b, c):
    return a * exp(-b * x) + c

def func_integral(x, a, b, c):
    # In this case it's easy to work out the integral analytically, but maybe
    # you want a more sophisticated `func` later.
    return scipy.integrate.quad(func, 0, x, (a, b, c))[0]

def err_func(x):
    try:
        a, b, c = x
        err_start = func(0, a, b, c) - co2_start
        err_end = func(year, a, b, c) - co2_end
        err_area = func_integral(year, a, b, c) - budget
        return [err_start**2, err_end**2, err_area**2]
    except OverflowError:
        return [np.inf, np.inf, np.inf]

solution = scipy.optimize.fsolve(err_func, [0, 1, 0])
print(solution)

a, b, c = solution
xs = np.arange(0, year)
ys = [func(x, a, b, c) for x in xs]
plt.plot(xs, ys)
plt.show()

我设置 a, b, c = 0, 1, 0 是因为我们知道 b 必须是正数,而 b = 0 区域对求解器来说是不愉快的。

它从quad 函数中吐出一个IntegrationWarning,但我希望这仅适用于远离实际解决方案的极端情况。

来自err_func,我在这里返回一个误差向量,其中包含每个条件的平方误差。这是一种常见的方法,但在这种情况下,它似乎也可以在没有平方的情况下工作。

另一个因素是处理OverflowError,因为求解器会尝试b 的值,其顺序为1e6,对于exp 函数来说太大了。我们通过返回无穷大来引导求解器远离该区域。

【讨论】:

以上是关于在 python 中求解没有初始解的非线性方程(matlab 有效,python 无效)的主要内容,如果未能解决你的问题,请参考以下文章

线性代数线性方程组的求解

[数值计算-6]:一元n次非线性方程求解-双点区间-二分迭代法&Python法代码示例

[数值计算-7]:一元n次非线性方程求解-单点盲探-牛顿迭代法&Python法代码示例

数学实验MATLAB 求解齐次线性方程组

[数值计算-8]:一元n次非线性方程求解-双点区间-弦截迭代法&Python法代码示例

求解模线性方程