使用列表解析生成的函数作为约束时,scipy.minimize失败

jfewjypa  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(131)

我正在使用Python库函数scipy.minimize来求解一系列带有约束的线性方程,最大化多边形内内接圆的半径。请看这里,了解内接于多边形内的圆是什么:
x1c 0d1x的数据
优化的约束如下:具有坐标(x[1],x[2)的圆中点与多边形的每一条线之间的距离必须大于半径-否则圆半径将到达多边形外部并且圆将不再内接。
这些约束通过以下lambda函数来表示,多边形(在我们的示例中为三角形)的每一边都有一个函数:

# all of these functions have to remain non-negative
constraint1 = lambda x: distance_to_line((x[1],x[2]),polygon_points[0],polygon_points[1]) - x[0]
constraint2 = lambda x: distance_to_line((x[1],x[2]),polygon_points[1],polygon_points[2]) - x[0]
constraint3 = lambda x: distance_to_line((x[1],x[2]),polygon_points[2],polygon_points[3]) - x[0]

字符串
这里的变量是圆半径的x[0]和圆中点坐标的x[1],x[2]。

variables = [0, 0, 0]


目标函数与x[0]相反,x[0]是圆半径:

def objective (x):
    return -(x[0])


将这些分量输入到minimize函数中会给出正确的结果,程序的工作方式如下,result.x[0]会打印出正确的半径:

constraints = [{'type': 'ineq', 'fun': constraint1},{'type': 'ineq', 'fun': constraint2},{'type': 'ineq', 'fun': constraint3}]

result = minimize(objective, variables, constraints=constraints)

print("Maximum radius: " + str(result.x[0]))


到目前为止一切顺利但这就是问题所在。正如您可能已经注意到的,通过列表解析生成约束函数是有意义的,因此可以处理潜在的无限数量的多边形线。

all_constraints = [lambda x: distance_to_line((x[1],x[2]),polygon_points[i],polygon_points[i+1]) -x[0] for i in range (0,3)]

但是scipy.minimize不再工作,如果我给它提供这三个列表解析生成的lambda函数,而不是手动编写的函数:

constraints = []
for function in all_constraints :
    constraints.append({'type': 'ineq', 'fun': function})


相反,我在result.message中得到了各种错误消息,如“LSQ子问题中的奇异矩阵E”或“不等式约束不兼容”。
这让我很困惑,因为列表解析生成的函数和开始时手动编写的函数在内容和结果上应该是完全等价的。
all_constraints真的等同于上面三个手工编写的函数吗?还是我在某个地方犯了错误?

7qhs6swi

7qhs6swi1#

你遇到了一个问题,这里描述得很好:https://stackoverflow.com/a/34021333/22174676
TL;DR是:lambda函数在被调用时将引用变量I,而不是在定义lambda时使用i的值。因此,当您运行约束时,它将对所有约束使用i的最后一个值,这将导致所有约束都相同,并且系统不可解。
要根据i变量部分定义每个函数,请考虑定义一个依赖于x和i的一般约束函数,并使用partial(来自functools)创建所有约束,如下所示:

from functools import partial
def const(x, i):
    return distance_to_line((x[1],x[2]),polygon_points[i],polygon_points[i+1])-x[0]

all_constraints = [partial(const, i=i) for i in range(3)]

字符串

相关问题