繁体   English   中英

如何用Python解决三个未知数和数百种解决方案的非线性方程?

[英]How to solve nonlinear equation with Python with three unknowns and hundreds of solutions?

我正在尝试使用python在类型的非线性方程中找到三个未知数(x,y,z)的值:

g(x) * h(y) * k(z) = F

其中F是具有数百个值的向量。

我成功地使用了scipy.optimize.minimize,其中F仅具有3个值,但是当F的大小大于3时失败了。

如何使用F中的所有值找到(x,y,z)? 到目前为止,唯一可用的方法是使用网格搜索,但是效率很低(请参阅#查找未知的x [0],x [1],x [2])。 python中是否有一个函数可以用来查找x [0],x [1],x [2]而不是使用网格搜索?

这里的代码:

import numpy as np

#  Inputs:
thetas = np.array([25.4,65,37,54.9,26,21.3,24.1,35.7,46.1,61.1,57.2,41.9,20.5,24,55.6,56.9,42.2,39.9,30.8,59,28.8])
thetav = np.array([28.7,5.4,22.6,14.4,23.5,25,12.8,31.2,15.3,9,7.4,24.4,29.7,15.3,15.5,26.8,8.8,16.6,25.1,18.5,12])
azs =    np.array([130.3,158,150.2,164.8,152.4,143.5,144.2,151.8,167.4,169.7,162.2,161.4,138.2,147.8,172.9,168.6,158.3,159.8,151.7,160.8,144.5])
azv =    np.array([55.9,312.8,38.6,160.4,324.2,314.5,236.3,86.1,313.3,2.1,247.6,260.4,118.9,199.9,277,103.1,150.5,339.2,35.6,14.7,24.9])
F =   np.array([0.61745,0.43462,0.60387,0.56595,0.48926,0.55615,0.54351,0.64069,0.54228,0.51716,0.39157,0.51831,0.7053,0.62769,0.21159,0.29964,0.52126,0.53656,0.575,0.40306,0.60471])

relphi = np.abs(azs-azv)

thetas = np.deg2rad(thetas)
thetav = np.deg2rad(thetav)
relphi = np.deg2rad(relphi)


#  Compute the trigonometric functions:
coss = np.abs (np.cos(thetas))
cosv = np.cos(thetav)
sins = np.sqrt(1.0 - coss * coss)
sinv = np.sqrt(1.0 - cosv * cosv)
cosp = -np.cos(relphi)
tans = sins / coss
tanv = sinv / cosv
csmllg = coss * cosv + sins * sinv * cosp
bigg = np.sqrt(tans * tans + tanv * tanv - 2.0 * tans * tanv * cosp)


# Function to solve
def fun(x):
    return x[0] * ((coss * cosv) ** (x[1] - 1.0)) * ((coss + cosv) ** (x[1] - 1.0)) * (1.0 - x[2] * x[2]) / ((1.0 + x[2] * x[2] + 2.0 * x[2] * csmllg) ** (1.5) + 1e-12) * (1.0 + ((1 - x[0]) / (1.0 + bigg))) - F


# Find unknown x[0], x[1], x[2]

n_bins=51
rho0_min=0.0
rho0_max=2.0
rho0_index=np.linspace(rho0_min, rho0_max, n_bins,retstep=True)
k_min=0.0
k_max=2.0
k_index=np.linspace(k_min, k_max, n_bins,retstep=True)
bigtet_min=-1.0
bigtet_max=1.0
bigtet_index=np.linspace(bigtet_min, bigtet_max, n_bins,retstep=True)
results=np.zeros((4,n_bins**3))
minima=np.ones(4)
RMSE_th = 0.001
index_while=0
current_RMSE=1.0
while current_RMSE > RMSE_th:
    index_results=0
    for rho0 in rho0_index[0]:
        for k in k_index[0]:
            for bigtet in bigtet_index[0]:
                results[:,index_results] = [rho0, k, bigtet, np.sqrt(np.sum((surf-func([rho0,k,bigtet]))**2) / surf.size)]
                index_results=index_results+1
    minima = results[:,np.argmin(results[3,:])]

    if (index_while > 10) or ((current_RMSE-minima[3]) < RMSE_th/100.0):
        break
    else:
        current_RMSE=minima[3]
        index_while=index_while+1
        rho0_min=minima[0]-2*rho0_index[1]
        rho0_max=minima[0]+2*rho0_index[1]
        rho0_index=np.linspace(rho0_min, rho0_max, 11,retstep=True)
        k_min=minima[1]-2*k_index[1]
        k_max=minima[1]+2*k_index[1]
        k_index=np.linspace(k_min, k_max, 11,retstep=True)
        bigtet_min=minima[2]-2*bigtet_index[1]
        bigtet_max=minima[2]+2*bigtet_index[1]
        bigtet_index=np.linspace(bigtet_min, bigtet_max, 11,retstep=True)


rho0= minima[0]
k= minima[1]
bigtet= minima[2]
print (rho0,k,bigtet,minima[3])

return (rho0,k,bigtet)

啊哈,我明白了。 您正在使用scipy.optimize.minimize,它将获得函数fun(x)作为最小化函数。 但是根据文档, minimize执行“最小化一个或多个变量的标量函数”。 这里的线索是标量 您需要返回一个标量。 一种经典的方法是最小化平方偏差之和:

deviations = x[0] * ((coss * cosv) ** (x[1] - 1.0)) * ((coss + cosv) ** (x[1] - 1.0)) * (1.0 - x[2] * x[2]) / ((1.0 + x[2] * x[2] + 2.0 * x[2] * csmllg) ** (1.5) + 1e-12) * (1.0 + ((1 - x[0]) / (1.0 + bigg))) - F

我强烈建议您开始将该表达式切成小块,以便于理解。 然后,该函数的返回可能是:

return sum( deviations ** 2)

正如@Jblasco所建议的,您可以最小化平方和。 scipy.leastsq()专为解决此类问题而设计。 对于您的示例,代码将是:

import scipy.optimize as sopt

xx0 = np.array([0., 0., 0.])  # starting point
rslt = sopt.leastsq(fun, xx0, full_output=True)
print("The solution is {}".format(rslt[0]))

查看rslts的其他条目以获取有关解决方案质量的信息。 请记住,数字可能会给您带来麻烦,特别是在具有指数和数百个变量的情况下。 如果有问题,请从Scipy中检查其他优化器 还提供显式的jacobians(作为leastsq()参数)可以有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM