GEKKO资源优化问题:权重比值计算致目标值NaN的修复请求
资源优化问题GEKKO求解NaN问题修复
问题背景
现有资源优化问题:2名工人、4项任务,每项任务仅分配给一名工人,每名工人仅承接一项任务,目标是最大化总奖励。决策变量包括:
- 0-1分配矩阵:任务与工人的分配关系
- 权重数组:每项任务的相对权重
工人奖励计算逻辑为:任务权重 / 总权重 × 对应任务奖励,总奖励为两人奖励之和。
原始代码
import numpy as np from gekko import GEKKO rewards = np.array([[2,5,8,10],[1,5,7,11]]) m = GEKKO(remote=False) allocation = m.Array(m.Var,(2,4),lb=0,ub=1, integer=True) weights = m.Array(m.Var,4,lb=0,ub=1) def reward(allocation, weights, rewards): temp=np.copy(allocation) #sum_ = np.sum(weights) for i in range(allocation.shape[1]): temp[:, i] *= weights[i]#/sum_ total_rewards = np.sum(temp.flatten() * rewards.flatten()) return total_rewards for j in range(4): m.Equation(m.sum(allocation[:,j])<=1) m.Maximize(reward(allocation, weights, rewards)) m.options.SOLVER = 1 # change solver (1=APOPT,3=IPOPT) #m.open_folder() m.solve() print('allocation', allocation) print('weights', weights) print('Objective: ' + str(m.options.objfcnval))
问题现象
- 注释sum_时输出正常:
---------------------------------------------------------------- APMonitor, Version 1.0.1 APMonitor Optimization Suite ---------------------------------------------------------------- --------- APM Model Size ------------ Each time step contains Objects : 0 Constants : 0 Variables : 16 Intermediates: 0 Connections : 0 Equations : 5 Residuals : 5 Number of state variables: 16 Number of total equations: - 4 Number of slack variables: - 4 --------------------------------------- Degrees of freedom : 8 ---------------------------------------------- Steady State Optimization with APOPT Solver ---------------------------------------------- Iter: 1 I: 0 Tm: 0.00 NLPi: 4 Dpth: 0 Lvs: 3 Obj: -1.63E+01 Gap: NaN --Integer Solution: 0.00E+00 Lowest Leaf: -1.63E+01 Gap: 2.00E+00 Iter: 2 I: 0 Tm: 0.00 NLPi: 2 Dpth: 1 Lvs: 2 Obj: 0.00E+00 Gap: 2.00E+00 Iter: 3 I: 0 Tm: 0.00 NLPi: 3 Dpth: 1 Lvs: 4 Obj: -2.60E+01 Gap: 2.00E+00 --Integer Solution: -26.00E+00 Lowest Leaf: -2.60E+01 Gap: 0.00E+00 Iter: 4 I: 0 Tm: 0.00 NLPi: 1 Dpth: 2 Lvs: 4 Obj: -2.60E+01 Gap: 0.00E+00 Successful solution --------------------------------------------------- Solver : APOPT (v1.0) Solution time : 1.729999999224674E-002 sec Objective : -26.0000000000000 Successful solution --------------------------------------------------- allocation [[[1.0] [1.0] [1.0] [0.0]] [[0.0] [0.0] [0.0] [1.0]]] weights [[1.0] [1.0] [1.0] [1.0]] Objective: -26.0
注:此输出中工人1承接3项任务,违反“每名工人仅能承接一项任务”的约束,说明原始代码缺少该约束。
- 取消注释sum_时出现NaN:
---------------------------------------------------------------- APMonitor, Version 1.0.1 APMonitor Optimization Suite ---------------------------------------------------------------- --------- APM Model Size ------------ Each time step contains Objects : 0 Constants : 0 Variables : 16 Intermediates: 0 Connections : 0 Equations : 5 Residuals : 5 Number of state variables: 16 Number of total equations: - 4 Number of slack variables: - 4 --------------------------------------- Degrees of freedom : 8 ---------------------------------------------- Steady State Optimization with APOPT Solver ---------------------------------------------- Iter: 1 I: 0 Tm: 0.01 NLPi: 2 Dpth: 0 Lvs: 0 Obj: NaN Gap: 0.00E+00 Successful solution --------------------------------------------------- Solver : APOPT (v1.0) Solution time : 2.390000000013970E-002 sec Objective : NaN Successful solution --------------------------------------------------- allocation [[[0.0] [0.0] [0.0] [0.0]] [[0.0] [0.0] [0.0] [0.0]]] weights [[0.0] [0.0] [0.0] [0.0]] Objective: nan
问题分析与修复
核心问题
- 除以0风险:总权重
sum_可能为0,直接导致NaN。 - 符号变量处理错误:用
np.sum()处理GEKKO变量数组,numpy无法识别GEKKO的符号变量,应使用GEKKO内置的m.sum()。 - 约束缺失:原始代码仅限制每项任务最多分配给一名工人,未限制每名工人最多承接一项任务,导致分配结果不符合问题要求。
- numpy操作破坏符号结构:
np.copy()、flatten()等numpy操作会将GEKKO的符号变量转换为数值数组,导致优化器无法正确构建目标函数。
修复后的代码
import numpy as np from gekko import GEKKO rewards = np.array([[2,5,8,10],[1,5,7,11]]) m = GEKKO(remote=False) # 0-1分配矩阵 allocation = m.Array(m.Var,(2,4),lb=0,ub=1, integer=True) # 权重数组,设置下限避免全0 weights = m.Array(m.Var,4,lb=1e-6,ub=1) # 计算总权重,使用GEKKO的sum函数 total_weight = m.sum(weights) # 定义总奖励:用GEKKO的符号运算替代numpy操作 total_reward = 0 for worker in range(2): for task in range(4): # 任务权重/总权重 × 该任务对应奖励 × 是否分配 total_reward += (weights[task]/total_weight) * rewards[worker][task] * allocation[worker][task] # 约束1:每项任务最多分配给一名工人 for task in range(4): m.Equation(m.sum(allocation[:,task]) <= 1) # 约束2:每名工人最多承接一项任务 for worker in range(2): m.Equation(m.sum(allocation[worker,:]) <= 1) # 最大化总奖励 m.Maximize(total_reward) # 使用APOPT求解混合整数规划 m.options.SOLVER = 1 m.solve() # 打印结果 print("分配矩阵:") for row in allocation: print([x.value[0] for x in row]) print("\n权重数组:") print([w.value[0] for w in weights]) print(f"\n最大化总奖励: {m.options.objfcnval:.4f}")
修复说明
- 给
weights设置下限1e-6,避免总权重为0;同时用m.sum()计算总权重,确保符号运算正确。 - 用循环构建目标函数,避免numpy的数组操作,保证GEKKO能正确识别符号变量关系。
- 添加工人承接任务数的约束,确保每个工人最多接一项任务。
- 优化结果打印方式,更清晰展示数值。
内容的提问来源于stack exchange,提问作者Alok
相关产品推荐
相关产品推荐

