【问题标题】:Python: Finding multiple roots of nonlinear equationPython:找到非线性方程的多个根
【发布时间】:2012-10-14 19:41:14
【问题描述】:

假设如下函数:

f(x) = x * cos(x-4)

对于x = [-2.5, 2.5],此函数在f(0) = 0f(-0.71238898) = 0 处交叉0

这是通过以下代码确定的:

import math
from scipy.optimize import fsolve
def func(x):
    return x*math.cos(x-4)
x0 = fsolve(func, 0.0)
# returns [0.]
x0 = fsolve(func, -0.75)
# returns [-0.71238898]

使用fzero(或任何其他 Python 根查找器)在一次调用中找到两个根的正确方法是什么?是否有其他 scipy 函数可以执行此操作?

fzero reference

【问题讨论】:

  • 也许我的数学很模糊,但f(0) = 2 不在那里吗?
  • @mayhewr。看起来你的数学不是那么模糊。 ;)
  • @strimp099:f(x) 与 func(x) 完全不同。那你想解决哪一个?
  • 对不起,很草率。更新 f(x)
  • Scipy 邮件列表中的这一系列消息可能是相关的:mail.scipy.org/pipermail/scipy-user/2007-September/013870.html

标签: python optimization scipy


【解决方案1】:

我曾经为这个任务写过一个模块。它基于Numerical Methods in Engineering with Python by Jaan Kiusalaas一书中的第4.3章:

import math

def rootsearch(f,a,b,dx):
    x1 = a; f1 = f(a)
    x2 = a + dx; f2 = f(x2)
    while f1*f2 > 0.0:
        if x1 >= b:
            return None,None
        x1 = x2; f1 = f2
        x2 = x1 + dx; f2 = f(x2)
    return x1,x2

def bisect(f,x1,x2,switch=0,epsilon=1.0e-9):
    f1 = f(x1)
    if f1 == 0.0:
        return x1
    f2 = f(x2)
    if f2 == 0.0:
        return x2
    if f1*f2 > 0.0:
        print('Root is not bracketed')
        return None
    n = int(math.ceil(math.log(abs(x2 - x1)/epsilon)/math.log(2.0)))
    for i in range(n):
        x3 = 0.5*(x1 + x2); f3 = f(x3)
        if (switch == 1) and (abs(f3) >abs(f1)) and (abs(f3) > abs(f2)):
            return None
        if f3 == 0.0:
            return x3
        if f2*f3 < 0.0:
            x1 = x3
            f1 = f3
        else:
            x2 =x3
            f2 = f3
    return (x1 + x2)/2.0

def roots(f, a, b, eps=1e-6):
    print ('The roots on the interval [%f, %f] are:' % (a,b))
    while 1:
        x1,x2 = rootsearch(f,a,b,eps)
        if x1 != None:
            a = x2
            root = bisect(f,x1,x2,1)
            if root != None:
                pass
                print (round(root,-int(math.log(eps, 10))))
        else:
            print ('\nDone')
            break

f=lambda x:x*math.cos(x-4)
roots(f, -3, 3)

roots 在区间 [a, b] 中查找 f 的所有根。

【讨论】:

  • 感谢脚本。在 python 版本 2.x math.ceil 返回一个浮点数,所以你需要将 n 转换为 int(n)
  • @NicorLengert 感谢您的提及。我编辑了答案
  • @halex 你是我的英雄
【解决方案2】:

定义您的函数,使其可以将标量或 numpy 数组作为参数:

>>> import numpy as np
>>> f = lambda x : x * np.cos(x-4)

然后将参数向量传递给fsolve

>>> x = np.array([0.0, -0.75])
>>> fsolve(f,x)
array([ 0.        , -0.71238898])

【讨论】:

  • 如果我们愿意,在这种情况下你如何传递雅可比?只需将jac=jac 与分析雅可比传递给TypeError: Shape mismatch
【解决方案3】:

通常(即除非您的函数属于某个特定类)您无法找到所有全局解决方案 - 这些方法通常从给定起点进行局部优化。

但是,您可以将 math.cos() 与 numpy.cos() 切换,这将使您的函数矢量化,以便它可以一次求解多个值,例如fsolve(func, np.arange(-10,10,0.5)).

【讨论】:

猜你喜欢
  • 2022-08-04
  • 2014-03-17
  • 2017-07-11
  • 2017-04-22
  • 2016-02-10
  • 1970-01-01
  • 2016-06-09
  • 1970-01-01
  • 2021-06-08
相关资源
最近更新 更多