我正在尝试使用python在类型的非线性方程中找到三个未知数(x,y,z)的值:
g(x) * h(y) * k(z) = F
其中F是具有数百个值的向量。
我成功使用了scipy.optimize.minimize,其中F只有3个值,但是当F的大小大于3时失败。
如何使用F中的所有值找到(x,y,z)?到目前为止,唯一可用的方法是使用网格搜索,但效率非常低(参见#Find unknown 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)
答案 0 :(得分:0)
fun(x)
作为要最小化的函数。但是根据documentation最小化执行&#34;最小化一个或多个变量的标量函数。&#34;。这里的线索是标量。你需要返回一个标量。一种经典的方法是最小化平方偏差的总和:
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)
答案 1 :(得分:0)
正如@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查看另一个optimizers。同时给出明确的jacobians(作为leastsq()
的参数)可以提供帮助。