GEKKO优化出现方程约束超限及变量生成异常问题求助
问题原因分析与修正方案
问题1:总降价支出约束未生效
约束失效的根源是delta变量被错误地生成为数组,同时初始参数计算逻辑有误:
- 原本预期每个用户对应1个delta标量,但代码中用
np.sum(ml_bought[user]*delta_user[user])时,GEKKO会将标量Var与数组Param进行元素级乘法,自动把delta广播成和购买量数组同形状的数组。此时每个数组元素都能取到delta_max,总支出自然超出预算。 delta_basic的计算逻辑错误:sum(cons['user1'] +cons['user2']+cons['user3']+cons['user4'])是先元素级相加数组再求和,正确的总购买量应该是每个用户的购买量数组求和后再累加,这导致delta_min、delta_max的基准值计算偏差。
问题2:delta_user变成数组而非单个值
核心原因是使用了numpy的np.sum()处理GEKKO变量与数组的运算:
GEKKO的Var默认是标量,当与numpy数组Param进行元素级乘法时,会自动触发广播机制,将标量Var扩展为同形状的数组Var,违背了“每个用户对应1个delta值”的预期。
修正后的代码
import numpy as np from gekko import GEKKO cons = {'user1' :np.array([1,2,3,4]), 'user2' : np.array([5,6,7,8]), 'user3' : np.array([0.8,1,5,9]), 'user4' : np.array([16,8,7,1])} auto = { 'user1': 0.7, 'user2' : 0.6, 'user3' : 0.32, 'user4': 0.44 } m=GEKKO(remote=False) m.options.IMODE = 2 m.options.SOLVER = 1 m.options.CV_TYPE = 2 m.options.RTOL=1e-4 m.options.OTOL=1e-4 delta_user = {} # 每个用户对应单个降价幅度变量 ml_bought={} # 用户购买量数组 benefit_user = {} # 用户总降价支出 self_cons = {} # 自耗权重参数 fondos = m.Const(value =30) # 修正总购买量计算:累加每个用户的购买总量 total_quantity = sum(np.sum(v) for v in cons.values()) delta_basic = 30 / total_quantity delta_min = delta_basic * 0.75 delta_max = delta_basic * 1.25 for user in cons: # 每个用户仅创建1个标量降价变量 delta_user[user] = m.Var(lb=delta_min, ub=delta_max, value=delta_basic) self_cons[user] = m.Param(auto[user]) ml_bought[user] = m.Param(cons[user]) # 使用GEKKO原生sum函数,避免numpy广播生成数组 benefit_user[user] = m.Intermediate(m.sum(ml_bought[user] * delta_user[user])) # 总支出约束 m.Equation(m.sum([benefit_user[user] for user in cons]) <= fondos) # 目标函数:加权总收益最大化 m.Maximize(m.sum([benefit_user[user] * (self_cons[user]**2) for user in cons])) m.solve(disp=True) # 输出结果 print("各用户降价幅度:") for user in delta_user: print(f"{user}: {delta_user[user].value[0]}") total_expense = sum(benefit_user[user].value[0] for user in benefit_user) print(f"\n总降价支出:{total_expense}")
关键修正点
- 参数计算修正:用
sum(np.sum(v) for v in cons.values())正确计算总购买量,确保delta_basic等基准值准确。 - 避免数组广播:替换
np.sum()为GEKKO原生的m.sum(),保证每个delta_user[user]始终是标量变量。 - 结果提取:通过
.value[0]获取GEKKO标量Var的数值(Var的value属性为列表,单个值取索引0)。
内容的提问来源于stack exchange,提问作者lucassculp
相关产品推荐
相关产品推荐

