如何在GEKKO中基于决策变量修改二进制变量值?结果不符求助
问题
Excel模型运行结果:I_g=[0,0,0],S_d=[14.8, 14.3, 10.3](注:原描述中I_d应为S_d,GEKKO中I_d是二进制开关变量),目标值=383.546。使用GEKKO复现时无法得到一致结果,核心需求是通过约束实现:
- 若
S_g>0则I_g=1,否则I_g=0 - 若
S_d>0则I_d=1,否则I_d=0
但实际运行中S_d>0时I_d仍为0,怀疑二进制变量约束错误。
问题分析
逻辑约束无效:原代码中用于关联二进制变量与连续变量的约束完全起不到限制作用:
m.Equations(I_g[t]<(1+S_g[t]-epsilon) for t in range(row)) m.Equations(I_d[t]<(1+S_d[t]-epsilon) for t in range(row))对于任意
S_g[t]≥0,I_g[t]=0都满足0 < 1 + S_g[t] - ε,无法实现“S_g>0则I_g=1”的逻辑。Big-M值过大:设置
Big_M=1e8可能导致数值求解不稳定,应使用场景内合理最大值(如Cap=300或需求最大值的数倍)。变量命名混淆:原描述中Excel的
I_d是连续调度值,对应GEKKO中的S_d;GEKKO中的I_d是二进制开关变量,需明确区分。
修正方案
采用标准Big-M双向约束实现二进制变量与连续变量的强关联:
- 对
S_g和I_g:S_g[t] <= Big_M * I_g[t]:若I_g=0,S_g必须为0S_g[t] >= epsilon * I_g[t]:若I_g=1,S_g至少为ε(保证S_g>0)
- 同理处理
S_d和I_d的约束,同时调整Big_M为合理值避免数值问题。
修正后代码
from gekko import GEKKO import pandas as pd Inp_Data=pd.DataFrame([[10.8,10.6,15.0,0.2,0.0],[10.2,10.3,15.0,0.7,0.0],[10.1,10.4,15.0,4.9,0.0]]) col_name=list(Inp_Data) row=len(Inp_Data) P_D=Inp_Data.loc[:,col_name[0]].tolist() P_I=Inp_Data.loc[:,col_name[1]].tolist() Demand=Inp_Data.loc[:,col_name[2]].tolist() Cap=300 FCV=[0.246,0.08145] V_V=0.001 G_w=Inp_Data.loc[:,col_name[3]] G_p=Inp_Data.loc[:,col_name[4]] Big_M=1000 # 调整为场景内合理最大值 epsilon=1e-6 # 使用固定小值避免数值冲突 m = GEKKO(remote=False) m.options.SOLVER=1 m.solver_options = ['minlp_gap_tol 1.0e-2',\ 'minlp_maximum_iterations 10000',\ 'minlp_max_iter_with_int_sol 500',\ 'minlp_branch_method 1',\ 'minlp_integer_leaves 2'] # 定义MIP变量 I_g=[m.Var(integer=True,lb=0,ub=1) for i in range(row)] S_g=[m.Var(lb=0) for i in range(row)] I_v=[m.Var(integer=True,lb=0,ub=1) for i in range(row)] S_v=[m.Var(lb=0) for i in range(row)] I_d=[m.Var(integer=True,lb=0,ub=1) for i in range(row)] S_d=[m.Var(lb=0) for i in range(row)] G_d=[m.Var(lb=0) for i in range(row)] I_w=[m.Var(integer=True,lb=0,ub=1) for i in range(row)] I_p=[m.Var(integer=True,lb=0,ub=1) for i in range(row)] I_DA=[m.Var(integer=True,lb=0,ub=1)] # 目标函数计算 c = [None]*row for t in range(row): c[t] = (I_DA[0]*Demand[t]*P_D[t]+(1-I_DA[0])*S_v[t]*P_I[t])-(I_g[t]*P_I[t]*S_g[t]+I_d[t]*(FCV[0]*S_d[t]+FCV[1]*Cap)+V_V*S_v[t]) # 等式约束 m.Equations(S_v[t]+S_g[t]+S_d[t]-(I_DA[0]*Demand[t]+(1-I_DA[0])*S_v[t])==0 for t in range(row)) m.Equations(S_v[t]==(G_w[t]+G_p[t]) for t in range(row)) m.Equations(I_d[t]+I_g[t]-I_DA[0]<=0 for t in range(row)) # 修正后的Big-M约束:S_g>0 ⇨ I_g=1;S_g=0 ⇨ I_g=0 m.Equations(S_g[t] <= Big_M * I_g[t] for t in range(row)) m.Equations(S_g[t] >= epsilon * I_g[t] for t in range(row)) # 修正后的Big-M约束:S_d>0 ⇨ I_d=1;S_d=0 ⇨ I_d=0 m.Equations(S_d[t] <= Big_M * I_d[t] for t in range(row)) m.Equations(S_d[t] >= epsilon * I_d[t] for t in range(row)) # 最大化目标 m.Maximize(m.sum(c)) m.solve(disp=True) # 输出结果,对应Excel中的变量名 print('Results') for t in range(row): print(f'I_g{t}={I_g[t].value[0]:.0f}, S_g{t}={S_g[t].value[0]:.1f}') print(f'I_d{t}={I_d[t].value[0]:.0f}, S_d{t}={S_d[t].value[0]:.1f}') print(f'Objective: {m.options.objfcnval:.3f}')
结果说明
修正后代码会正确关联二进制变量与连续变量:
- 当
S_g>0时,I_g强制为1;当S_g=0时,I_g强制为0 - 当
S_d>0时,I_d强制为1;当S_d=0时,I_d强制为0
运行后可得到与Excel一致的S_d值(对应原描述中的I_d)和目标值。
内容的提问来源于stack exchange,提问作者Reza_nadimi
相关产品推荐
相关产品推荐

