Skip to main content
 首页 » 编程设计

python之将多元函数根的求根算法中的两个根之一括起来

2025年05月04日22lyhabc

对于(可能具有误导性的)标题和可能令人困惑的问题本身,我深表歉意,我在措辞问题上费了很大劲,尤其是将它压缩成一个句子作为标题。我想使用 python 找到具有两个变量 w 和 t 的函数 f(w, t, some_other_args) 的根。真正的函数结构真的又长又复杂,你可以在这篇文章的最后找到它。重要的是它包含以下行:

k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w)) 

这意味着 w 不能超过 1,因为那样会导致计算负数的平方根,这当然是不可能的。我有使用函数中的其他值计算 w 和 t 的近似值的算法,但它们非常不准确。

因此,我尝试使用 scipy.optimize.fsolve 计算根(在尝试了我可以在网上找到的所有求根算法之后,我发现这个算法最适合我的函数)使用这些近似值作为起点,看起来像这样:

solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args)) 

对于大多数值,这工作得很好。但是,如果 w 太接近 1,那么 fsolve 会尝试为 w 尝试一些大于 1 的值,这在反过来,引发 ValueError(因为计算负数的根在数学上是不可能的)。这是打印出 fsolve 使用的值的示例,其中 w 应该在 0.997 左右:

w_approx: 0.9960090844989311 
t_approx: 24.26777844720981 
Values: t:24.26777844720981, w:0.9960090844989311 
Values: t:24.26777844720981, w:0.9960090844989311 
Values: t:24.26777844720981, w:0.9960090844989311 
Values: t:24.267778808827888, w:0.9960090844989311 
Values: t:24.26777844720981, w:0.996009099340623 
Values: t:16.319554685876746, w:1.0096680915775516 
      solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args)) 
    File "C:\Users\...\venv\lib\site-packages\scipy\optimize\minpack.py", line 148, in fsolve 
      res = _root_hybr(func, x0, args, jac=fprime, **options) 
    File "C:\Users\...\venv\lib\site-packages\scipy\optimize\minpack.py", line 227, in _root_hybr 
      ml, mu, epsfcn, factor, diag) 
    File "C:\Users\...\algorithm.py", line 9, in f 
      k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w)) 
ValueError: math domain error 

那么,我如何告诉 optimize.fsolve w 不能大于 1?或者做这样的事情的替代算法是什么(我知道 brentq 等等,但所有这些都需要为 both 根提供一个间隔,我不知道想做。)?


测试代码(此处需要注意的重要事项:即使 func 理论上应该计算 R 和 T 给定 t 和 w,我必须反过来使用它。它有点笨拙,但我根本无法重写函数以使其接受 T, R 来计算 t, w - 对于我平庸的数学专业知识来说有点太多了 ;)) :

import math as m 
from scipy import optimize 
import numpy as np 
 
 
def func(t, w, r_1, r_2, r_3): 
 
    k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w)) 
 
    k23 = 2 * k / 3 
 
    z1 = 1 / (1 + k23) 
    z2 = 1 / (1 - k23) 
    z3 = 3 * ((1 / 5 + r_1 - r_2 - 1 / 5 * r_1 * r_2) / (z1 - r_2 * z2)) * m.exp(t * (k - 1)) 
    z4 = -(z2 - r_2 * z1) / (z1 - r_2 * z2) * m.exp(2 * k * t) 
    z5 = -(z1 - r_2 * z2) / (z2 - r_2 * z1) 
    z6 = 3 * (1 - r_2 / 5) / (z2 - r_2 * z1) 
 
    beta_t = r_3 / (z2 / z1 * m.exp(2 * k * t) + z5) * (z6 - 3 / (5 * z1) * m.exp(t * (k - 1))) 
    alpha_t = beta_t * z5 - r_3 * z6 
 
    beta_r = (z3 - r_1 / 5 / z2 * m.exp(-2 * t) * 3 - 3 / z2) / (z1 / z2 + z4) 
    alpha_r = -z1 / z2 * beta_r - 3 / z2 - 3 / 5 * r_1 / z2 * m.exp(-2 * t) 
 
    It_1 = 1 / 4 * w / (1 - 8 / 5 * w) * (alpha_t * z2 * m.exp(-k * t) + beta_t * z1 * m.exp(k * t) + 3 * r_3 * m.exp(-t)) 
 
    Ir_1 = (1 / 4 * w / (1 - 8 / 5 * w)) * (z1 * alpha_r + z2 * beta_r + 3 / 5 + 3 * r_1 * m.exp(-2 * t)) 
 
    T = It_1 + m.exp(-t) * r_3 
    R = Ir_1 + m.exp(-2 * t) * r_1 
 
    return [T, R] 
 
 
def calc_1(t, w, T, R, r_1, r_2, r_3): 
    t_begin = float(t[0]) 
    T_new, R_new = func(t_begin, w, r_1, r_2, r_3) 
    a = abs(-1 + T_new/T) 
    b = abs(-1 + R_new/R) 
    return np.array([a, b]) 
 
 
def calc_2(x, T, R, r_1, r_2, r_3): 
    t = x[0] 
    w = x[1] 
    T_new, R_new = func(t, w, r_1, r_2, r_3) 
    a = abs(T - T_new) 
    b = abs(R - R_new) 
    return np.array([a, b]) 
 
 
def approximate_w(R): 
    k = (1 - R) / (R + 2 / 3) 
    w_approx = (1 - ((2 / 3 * k) ** 2)) / (1 - ((1 / 3 * k) ** 2)) 
    return w_approx 
 
 
def approximate_t(w, T, R, r_1, r_2, r_3): 
    t = optimize.root(calc_1, x0=np.array([10, 0]), args=(w, T, R, r_1, r_2, r_3)) 
    return t.x[0] 
 
 
def solve(T, R, r_1, r_2, r_3): 
    w_x = approximate_w(R) 
    t_x = approximate_t(w_x, T, R, r_1, r_2, r_3) 
    sol = optimize.fsolve(calc_2, x0=np.array([t_x, w_x]), args=(T, R, r_1, r_2, r_3)) 
    return sol 
 
 
# Values for testing: 
T = 0.09986490557943692 
R = 0.8918728343037964 
r_1 = 0 
r_2 = 0 
r_3 = 1 
 
print(solve(T, R, r_1, r_2, r_3)) 

请您参考如下方法:

logistic呢?正在处理您想要约束的论点?我的意思是,在 f 中,你可以做

import numpy as np 
 
def f(free_w, ...): 
    w = 1/(1 + np.exp(-free_w)) # w will always lie between 0 and 1 
    ... 
    return zeros 

然后,您只需对 free_w 的解决方案值应用相同的逻辑转换即可获得 w*。见

solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args)) 
free_w   = solution[0] 
w        = 1/(1 + np.exp(-free_w))