简体   繁体   English

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

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

I am trying to use python to find the values of three unknowns (x,y,z) in a nonlinear equation of the type: 我正在尝试使用python在类型的非线性方程中找到三个未知数(x,y,z)的值:

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

where F is a vector with hundreds of values. 其中F是具有数百个值的向量。

I successfully used scipy.optimize.minimize where F only had 3 values, but that failed when the size of F was greater than 3. 我成功地使用了scipy.optimize.minimize,其中F仅具有3个值,但是当F的大小大于3时失败了。

How can I find (x,y,z) using all values in F? 如何使用F中的所有值找到(x,y,z)? So far, the only usable approach is to use a grid search, but this quite inefficient (see # Find unknown x[0], x[1], x[2]). 到目前为止,唯一可用的方法是使用网格搜索,但是效率很低(请参阅#查找未知的x [0],x [1],x [2])。 Is there a function in python that I can use to find x[0], x[1], x[2] instead of using the grid search? python中是否有一个函数可以用来查找x [0],x [1],x [2]而不是使用网格搜索?

Here the code: 这里的代码:

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)

Aha, I see. 啊哈,我明白了。 You are using scipy.optimize.minimize, which gets the function fun(x) as the function to minimize. 您正在使用scipy.optimize.minimize,它将获得函数fun(x)作为最小化函数。 But according to the documentation minimize performs "Minimization of scalar function of one or more variables.". 但是根据文档, minimize执行“最小化一个或多个变量的标量函数”。 The clue here being scalar . 这里的线索是标量 You need to return a scalar. 您需要返回一个标量。 A classic method would be to minimize the sum of the square deviations: 一种经典的方法是最小化平方偏差之和:

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

I strongly suggest you start chopping that expression to pieces, so that it's easier to understand. 我强烈建议您开始将该表达式切成小块,以便于理解。 Then, the return of the function could be: 然后,该函数的返回可能是:

return sum( deviations ** 2)

As @Jblasco suggested, you can minimize the sum of squares. 正如@Jblasco所建议的,您可以最小化平方和。 scipy.leastsq() is designed for such problems. scipy.leastsq()专为解决此类问题而设计。 For your example, the code would be: 对于您的示例,代码将是:

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]))

Look at the other entries of rslts for getting information on the quality of the solution. 查看rslts的其他条目以获取有关解决方案质量的信息。 Keep in mind that the numerics can play tricks on you, especially when having exponents and hundreds of variables. 请记住,数字可能会给您带来麻烦,特别是在具有指数和数百个变量的情况下。 If you have problems, check out the other optimizers from Scipy. 如果有问题,请从Scipy中检查其他优化器 Also giving explicit jacobians (as parameter of leastsq() ) can help. 还提供显式的jacobians(作为leastsq()参数)可以有所帮助。

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

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