首页 > 解决方案 > Gekko,PWL 函数结果与预期不符

问题描述

z 的值是在我的原始代码中计算的,在这里我给了他们这些计算结果的值,它们model.Equation(z[i] == someCalculation)在我的原始代码中也看起来像。

from gekko import GEKKO
model = GEKKO(remote=False)

z = model.Array(model.Var,(3))
model.Equation(z[0] == 1e-5)
model.Equation(z[1] == 4)
model.Equation(z[2] == 5.99999)

z2 = model.Array(model.Var,(3))
for i in range(3):
    d = 1e-5
    x_data = [-1e5, 0, 0+d, 6]
    y_data = [0, 0, 1, 1]
    model.pwl(z[i], z2[i], x_data, y_data)
    
model.solve()
print(z)
print(z2)

我希望 z2 是[[0] [1] [1]],但我得到[[0.99035520756] [0.97749877939] [0.97771605357]], z 保持不变。可能有一种更简单的方法来做我想做的事情,但我也想了解为什么这种方法会产生这种结果。

编辑

添加一个类似的目标函数model.Obj(model.sum(z2))似乎可以使求解器也操纵这些变量,这至少可以说是不希望的。如果当前设置无法生成解决方案,我希望看到错误而不是“固定”变量的更改

标签: pythongekko

解决方案


我希望 z2 是[[1],[1],[1]]因为 PWL 输出从0和(输入)1之间上升。以下是一些更接近解决方案的事情:0+1e-5

  • 尝试使用APOPT求解器m.options.SOLVER=1IPOPT它是一个活动集求解器,而不是使用障碍法的默认求解器。活动集求解器倾向于返回更精确的解决方案,尤其是在定义解决方案时涉及障碍项的情况下。
  • 使用整数变量z2(使用APOPT求解器)。如果这是一个约束,这也将帮助您找到一个整数解决方案。
  • 使用更严格的解决方案公差,例如m.options.RTOL=1e-9. 默认容差为1e-6m.options.OTOL如果您需要更精确的目标函数,您可能还需要进行调整。

我将方程切换为model.Equation(z[0] == -1e-5)以显示[[0],[1],[1]]

from gekko import GEKKO
model = GEKKO(remote=False)

z = model.Array(model.Var,(3))
model.Equation(z[0] == -1e-5)
model.Equation(z[1] == 4)
model.Equation(z[2] == 5.99999)

z2 = model.Array(model.Var,(3)) #,integer=True)
for i in range(3):
    d = 1e-5
    x_data = [-1e5, 0, 0+d, 6]
    y_data = [0, 0, 1, 1]
    model.pwl(z[i], z2[i], x_data, y_data)

#model.options.RTOL = 1e-9
model.options.SOLVER = 1
model.solve()
print(z)
print(z2)

编辑

如您所见,PWL 函数使用松弛变量。包括另一个目标会干扰正确的 PWL 解决方案。处理该问题的方法是可能model.Obj(model.sum(z2))具有比 PWL 函数的梯度更小的梯度的相对目标。这是一个0.1*sum(z2)最小化和0.01*sum(z)最大化的例子。

from gekko import GEKKO
model = GEKKO(remote=False)

z = model.Array(model.Var,(3),value=1)

z2 = model.Array(model.Var,(3)) #,integer=True)
for i in range(3):
    d = 1e-5
    x_data = [-1e5, 0, 0+d, 6]
    y_data = [0, 0, 1, 1]
    model.pwl(z[i], z2[i], x_data, y_data)

# first most important objective is PWL (gradient = 1)

# second most important objective is to minimize z2 
model.Minimize(0.1*model.sum(z2))

# third most important objective is to maximize z
model.Maximize(0.01*model.sum(z))

model.options.SOLVER = 1
model.solve()
print(z)
print(z2)

这正确地给出了解决方案:

[[0.0] [0.0] [0.0]]
[[0.0] [0.0] [0.0]]

或者,您可以使用以下方法最大化0.1*sum(z2)和最小化0.01*sum(z)

from gekko import GEKKO
model = GEKKO(remote=False)

z = model.Array(model.Var,(3),value=1)

z2 = model.Array(model.Var,(3)) #,integer=True)
for i in range(3):
    d = 1e-5
    x_data = [-1e5, 0, 0+d, 6]
    y_data = [0, 0, 1, 1]
    model.pwl(z[i], z2[i], x_data, y_data)

# first most important objective is PWL (gradient = 1)

# second most important objective is to minimize z2 
model.Maximize(0.1*model.sum(z2))

# third most important objective is to maximize z
model.Minimize(0.01*model.sum(z))

model.options.SOLVER = 1
model.solve()
print(z)
print(z2)

给:

[[1e-05] [1e-05] [1e-05]]
[[1.0] [1.0] [1.0]]

我很欣赏警告信息的建议。但是,当语法正确但存在会导致不良解决方案的配置时,通常很难在模型中找到错误。希望您的出色问题将帮助其他人使用 PWL 功能。


推荐阅读