如何在 Gekko 中使用 if2/3

Arr*_*val 5 gekko

我正在优化的问题是在输电网络中建设发电厂。为此,我在每辆公交车上放置发电厂,并让优化告诉我应该建造哪些发电厂以最大限度地降低运行成本。

为了对植物的放置进行建模,我尝试使用一组二进制变量,如果植物完全被使用,则标记为 1,否则标记为 0。然后在最小化的目标函数中,我将此数组乘以一个常数:USEW

我进行了多次尝试但没有任何效果。似乎有效的方法是直接在 Obj 中使用if2函数。 Gekko功能。然而我得到了非常奇怪的结果。我的代码有点长,所以我只会发布相关的行,希望这个想法很清楚,如果不是,请告诉我,我会发布整个内容。

bus=node=24
t=24
Sbase=100.
Gen = 12
VOLL = 10000.
VOLW = 50.
USEW = 100.
Pw = m.Array(m.Var,(bus,t), lb=0., ub=0., value=0.)
for b in range(bus):
    m.Minimize( np.sum(VOLL*lsh[b,:] + VOLW*Pc[b,:])*Sbase \
               + m.if2(-1.*Sbase*m.sum(Pw[b,:]),1,0)*USEW )
Run Code Online (Sandbox Code Playgroud)

问题出在if2零件上。如果我移除它,我会得到预期的结果,但随后会失去放置哪种植物的决定。我也尝试过,if3但也没有成功。从我看来,优化器似乎正在尝试最小化,Pw[b,:]因为结果仅包含零。以某种方式绕过该if2部分并进入内部sum

根据文档,这部分:m.if2(-1.*Sbase*m.sum(Pw[b,:]),1,0)应该返回0或,1但似乎没有这样做。我乘以-1因为Pw总是正数,我想检测何时Pw>0

我需要有关如何为此目的正确使用条件函数的帮助。谢谢

EDIT1 考虑以下情况:

from gekko import GEKKO
m = GEKKO(remote=False)
Sbase=100.
Pw = array([[[0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0],
    [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0],
    [0.0], [0.0], [0.0], [0.0], [0.0], [0.0]],
   [[10.0], [10.0], [10.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0],
    [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0],
    [0.0], [0.0], [0.0], [0.0], [0.0], [0.0]]], dtype=object)

# for np.sum(Pw[0,:])=0.0
print('sum of Pw[0,:]=', np.sum(Pw[0,:]))
print(m.if3(-1.*Sbase*np.sum(Pw[0,:]),1,0).value)
print(m.if3(-1.*Sbase*np.sum(Pw[0,:]),0,1).value)
# for np.sum(Pw[1,:])=30.0
print('sum of Pw[1,:]=', np.sum(Pw[1,:]))
print(m.if3(-1.*Sbase*np.sum(Pw[1,:]),1,0).value)
print(m.if3(-1.*Sbase*np.sum(Pw[1,:]),0,1).value)
Run Code Online (Sandbox Code Playgroud)

结果总是一样的:0x1如果我交换and x2or 条件 >=0 或 <0并不重要:

0.0
sum of Pw[0,:]= 0.0
0 #result 1
0 #result 2
sum of Pw[1,:]= 30.0
0 #result 3
0 #result 4
Run Code Online (Sandbox Code Playgroud)

Joh*_*ren 2

您可以尝试的一件事是使用 1e-3(或使用的某个最小值)的切换点而不是零。当开关点为零且条件为1e-10时,输出将为 ,1因为它大于开关点。这是必需的,因为 Gekko 使用基于梯度的优化器,其解容差为1e-6(默认),因此该容差内的解是可以接受的。

文档中的几个示例也可能有所帮助。您可能还想查看sign2/sign3函数和max2/max3函数,它们也可能为您提供所需的结果。

if2文档

IF 条件与互补约束开关变量。IF 语句的传统方法不是连续可微的,可能导致基于梯度的优化器无法收敛。该if2方法使用二进制切换变量来确定是y=x1(when condition<0) 还是y=x2(when condition>=0):

if3文档

IF 以二进制开关变量为条件。IF 语句的传统方法不是连续可微的,可能导致基于梯度的优化器无法收敛。该if3方法使用二进制切换变量来确定是y=x1(when condition<0) 还是y=x2(when condition>=0)。

用法

y = m.if3(condition,x1,x2)

输入:

  • condition:GEKKO 变量、参数或表达式
  • x1and x2:GEKKO 变量、参数或表达式

输出:

  • y = x1什么时候condition<0
  • y = x2什么时候condition>=0
from gekko import GEKKO
m = GEKKO(remote=False)
p = m.Param()
y = m.if3(p-4,p**2,p+1)

# solve with condition<0
p.value = 3
m.solve(disp=False)
print(y.value)

# solve with condition>=0
p.value = 5
m.solve(disp=False)
print(y.value)
Run Code Online (Sandbox Code Playgroud)

还有关于基于梯度的优化器的逻辑条件以及类型之间的差异的附加信息2 (MPCC)3 (binary)

对 EDIT1 的回应

由于 Gekko 始终使用 的切换条件0,因此我们可以使用 修改切换条件condition<swc并将其重新拟合为 gekko 形式condition-swc<0。从我回复的示例中,我们可以将开关条件移动swc=0.1

swc = 0.1
y = m.if3(p-4-swc,p**2,p+1)
Run Code Online (Sandbox Code Playgroud)

在你的情况下,你可以使用swc=1e-3或 更高一点的东西来避免在开关条件下的解决方案。虽然if3通常需要更长的时间来解决,但我通常会得到比 更好的结果if2,特别是如果存在干扰if2MPCC 的竞争目标。

  • 您好,感谢您的回复。你的答案的第一段包含了几个我无法分开的概念。如何将开关点设置为1e-3?正如我所看到的,开关点对于 if2/3 到 0 都是硬编码的:条件&lt;0 和条件&gt;=0。然后你说“当开关点为零时...”,但在上一句中它被设置为 1e-3。我知道我的困惑很愚蠢,但请耐心等待。 (2认同)