我试图找到Python中以下方程组的最优解:
(x-x1)^2 + (y-y1)^2 - r1^2 = 0
(x-x2)^2 + (y-y2)^2 - r2^2 = 0
(x-x3)^2 + (y-y3)^2 - r3^2 = 0
给定值(x,y)和半径(r):
x1, y1, r1 = (0, 0, 0.88)
x2, y2, r2 = (2, 0, 1)
x3, y3, r3 = (0, 2, 0.75)
找到点(x,y)的最优解的最佳方法是什么?
使用上面的例子,它将是:
〜(1,1)
答案 0 :(得分:14)
如果我理解你的问题,我认为这就是你之后的事情:
from scipy.optimize import minimize
import numpy as np
def f(coord,x,y,r):
return np.sum( ((coord[0] - x)**2) + ((coord[1] - y)**2) - (r**2) )
x = np.array([0, 2, 0])
y = np.array([0, 0, 2])
r = np.array([.88, 1, .75])
# initial (bad) guess at (x,y) values
initial_guess = np.array([100,100])
res = minimize(f,initial_guess,args = [x,y,r])
哪个收益率:
>>> print res.x
[ 0.66666666 0.66666666]
您也可以尝试使用最小二乘法,该方法需要一个返回向量的目标函数。它希望最小化该向量的平方和。使用最小二乘法,您的目标函数将如下所示:
def f2(coord,args):
x,y,r = args
# notice that we're returning a vector of dimension 3
return ((coord[0]-x)**2) + ((coord[1] - y)**2) - (r**2)
你最小化它是这样的:
from scipy.optimize import leastsq
res = leastsq(f2,initial_guess,args = [x,y,r])
哪个收益率:
>>> print res[0]
>>> [ 0.77961518 0.85811473]
这基本上与使用minimize
并将原始目标函数重写为:
def f(coord,x,y,r):
vec = ((coord[0]-x)**2) + ((coord[1] - y)**2) - (r**2)
# return the sum of the squares of the vector
return np.sum(vec**2)
这会产生:
>>> print res.x
>>> [ 0.77958326 0.8580965 ]
请注意args
与leastsq
的处理方式略有不同,并且两个函数返回的数据结构也不同。有关详细信息,请参阅scipy.optimize.minimize
和scipy.optimize.leastsq
的文档。
有关更多优化选项,请参阅scipy.optimize
文档。
答案 1 :(得分:4)
我注意到已接受的解决方案中的代码不再起作用了......我想可能scipy.optimize
已经更改了它的界面,因为答案已经发布了。我错了。无论如何,我的建议是使用scipy.optimize
中的算法,并且接受的答案确实证明了(或者一次,如果界面发生了变化)。
我在这里添加了一个额外的答案,纯粹是为了建议一个在核心使用scipy.optimize
算法的替代软件包,但对于约束优化更加健壮。包裹是mystic
。其中一项重大改进是mystic
提供了受约束的全局优化。
首先,这是您的示例,与scipy.optimize.minimize
方式完全相同,但使用全局优化器。
from mystic import reduced
@reduced(lambda x,y: abs(x)+abs(y)) #choice changes answer
def objective(x, a, b, c):
x,y = x
eqns = (\
(x - a[0])**2 + (y - b[0])**2 - c[0]**2,
(x - a[1])**2 + (y - b[1])**2 - c[1]**2,
(x - a[2])**2 + (y - b[2])**2 - c[2]**2)
return eqns
bounds = [(None,None),(None,None)] #unnecessary
a = (0,2,0)
b = (0,0,2)
c = (.88,1,.75)
args = a,b,c
from mystic.solvers import diffev2
from mystic.monitors import VerboseMonitor
mon = VerboseMonitor(10)
result = diffev2(objective, args=args, x0=bounds, bounds=bounds, npop=40, \
ftol=1e-8, disp=False, full_output=True, itermon=mon)
print result[0]
print result[1]
结果如下:
Generation 0 has Chi-Squared: 38868.949133
Generation 10 has Chi-Squared: 2777.470642
Generation 20 has Chi-Squared: 12.808055
Generation 30 has Chi-Squared: 3.764840
Generation 40 has Chi-Squared: 2.996441
Generation 50 has Chi-Squared: 2.996441
Generation 60 has Chi-Squared: 2.996440
Generation 70 has Chi-Squared: 2.996433
Generation 80 has Chi-Squared: 2.996433
Generation 90 has Chi-Squared: 2.996433
STOP("VTRChangeOverGeneration with {'gtol': 1e-06, 'target': 0.0, 'generations': 30, 'ftol': 1e-08}")
[ 0.66667151 0.66666422]
2.99643333334
如上所述,lambda
中reduced
的选择会影响优化程序找到的点,因为方程式没有实际的解决方案。
mystic
还提供将符号方程转换为函数的功能,其中结果函数可用作目标或惩罚函数。这是同样的问题,但使用方程作为惩罚而不是目标。
def objective(x):
return 0.0
equations = """
(x0 - 0)**2 + (x1 - 0)**2 - .88**2 == 0
(x0 - 2)**2 + (x1 - 0)**2 - 1**2 == 0
(x0 - 0)**2 + (x1 - 2)**2 - .75**2 == 0
"""
bounds = [(None,None),(None,None)] #unnecessary
from mystic.symbolic import generate_penalty, generate_conditions
from mystic.solvers import diffev2
pf = generate_penalty(generate_conditions(equations), k=1e12)
result = diffev2(objective, x0=bounds, bounds=bounds, penalty=pf, \
npop=40, gtol=50, disp=False, full_output=True)
print result[0]
print result[1]
结果:
[ 0.77958328 0.8580965 ]
3.6473132399e+12
结果与以前不同,因为应用的惩罚与我们之前在reduced
中应用的惩罚不同。在mystic
中,您可以选择要应用的惩罚。
有人指出方程没有解决方案。从上面的结果可以看出,结果严重受到惩罚,因此很好地表明没有解决方案。但是,mystic
还有另一种方法,你可以在没有解决方案的情况下看到它。而不是应用更传统的penalty
,这会对违反约束的解决方案进行处罚...... mystic
提供constraint
,这本质上是一个内核转换,它会删除所有可能的解决方案不符合常数。
def objective(x):
return 0.0
equations = """
(x0 - 0)**2 + (x1 - 0)**2 - .88**2 == 0
(x0 - 2)**2 + (x1 - 0)**2 - 1**2 == 0
(x0 - 0)**2 + (x1 - 2)**2 - .75**2 == 0
"""
bounds = [(None,None),(None,None)] #unnecessary
from mystic.symbolic import generate_constraint, generate_solvers, simplify
from mystic.symbolic import generate_penalty, generate_conditions
from mystic.solvers import diffev2
cf = generate_constraint(generate_solvers(simplify(equations)))
result = diffev2(objective, x0=bounds, bounds=bounds, \
constraints=cf, \
npop=40, gtol=50, disp=False, full_output=True)
print result[0]
print result[1]
结果:
[ nan 657.17740835]
0.0
nan
基本上表明没有有效的解决方案。
仅供参考,我是作者,所以我有一些偏见。但是,mystic
几乎与scipy.optimize
一样长,已经成熟,并且在这段时间内具有更稳定的界面。关键是,如果你需要一个更加灵活和强大的约束非线性优化器,我建议mystic
。
答案 2 :(得分:1)
这些方程可以看作描述2D空间中三个圆周上的所有点。解决方案将是圆圈截取的点。
圆的半径之和小于它们中心之间的距离,因此圆圈不重叠。我在下面绘制了圆圈:
没有一点可以满足这个方程组。
答案 3 :(得分:0)
我通过以下方式制作了一个示例脚本。请注意,最后一行将找到最佳解决方案(a,b):
import numpy as np
import scipy as scp
import sympy as smp
from scipy.optimize import minimize
a,b = smp.symbols('a b')
x_ar, y_ar = np.random.random(3), np.random.random(3)
x = np.array(smp.symbols('x0:%d'%np.shape(x_ar)[0]))
y = np.array(smp.symbols('y0:%d'%np.shape(x_ar)[0]))
func = np.sum(a**2+b**2-x*(a+b)+2*y)
print func
my_func = smp.lambdify((x,y), func)
print 1.0/3*my_func(x_ar,y_ar)
ab = smp.lambdify((a,b),my_func(x_ar,x_ar))
print ab(1,2)
def ab_v(x):
return ab(*tuple(x))
print ab_v((1,2))
minimize(ab_v,(0.1,0.1))
输出结果为:
3*a**2 + 3*b**2 - x0*(a + b) - x1*(a + b) - x2*(a + b) + 2*y0 + 2*y1 + 2*y2
1.0*a**2 - 0.739792011558683*a + 1.0*b**2 - 0.739792011558683*b +0.67394435712335
12.7806239653
12.7806239653
Out[33]:
status: 0
success: True
njev: 3
nfev: 12
hess_inv: array([[1, 0],
[0, 1]])
fun: 3.6178137388030356
x: array([ 0.36989601, 0.36989601])
message: 'Optimization terminated successfully.'
jac: array([ 5.96046448e-08, 5.96046448e-08])