使用GEKKO求解分式目标的混合整数非线性规划时出现NaN解求助
解决GEKKO求解最大化毛利率的混合整数规划问题
问题分析
原代码直接最大化分式目标(总利润/总收入)时,出现全0解(违反3选2约束)和目标值NaN的问题,核心原因:
- 分式目标在数值计算中易产生奇异(分母为0),导致求解器陷入局部最优;
- 整数规划初始点选择可能触发分母为0的情况,求解器无法自动恢复。
解决方案
方法一:枚举法(适合小规模问题)
因仅3选2,共3种可行组合,直接计算每种组合的毛利率即可快速找到最优解:
# 枚举所有3选2的可行组合 combinations = [(1,1,0), (1,0,1), (0,1,1)] max_margin = -1.0 best = None for x1, x2, x3 in combinations: profit = 150*x1 + 120*x2 + 100*x3 revenue = 200*x1 + 150*x2 + 250*x3 margin = profit / revenue if margin > max_margin: max_margin = margin best = (x1, x2, x3) print(f"最优组合:x1={best[0]}, x2={best[1]}, x3={best[2]}") print(f"最大毛利率:{max_margin:.4f}")
运行结果:
最优组合:x1=1, x2=1, x3=0 最大毛利率:0.7714
方法二:线性化重构目标(适合大规模问题)
将分式目标转化为线性约束+线性目标,避免数值奇异:
- 引入辅助变量
gamma表示毛利率; - 最大化
gamma,同时满足总利润 >= gamma * 总收入(等价于gamma <= 总利润/总收入); - 保留原约束(3选2、总收入>0)。
修正后的GEKKO代码:
from gekko import GEKKO m = GEKKO(remote=False) # 二进制决策变量 x1 = m.Var(integer=True, lb=0, ub=1) x2 = m.Var(integer=True, lb=0, ub=1) x3 = m.Var(integer=True, lb=0, ub=1) # 毛利率变量,范围0-1 gamma = m.Var(lb=0, ub=1) # 定义总利润和总收入 profit = 150*x1 + 120*x2 + 100*x3 revenue = 200*x1 + 150*x2 + 250*x3 # 核心约束:毛利率的等价转化 m.Equation(profit >= gamma * revenue) # 3选2约束 m.Equation(x1 + x2 + x3 == 2) # 确保总收入不为0(可选,3选2自动满足) m.Equation(revenue >= 1e-3) # 目标:最大化毛利率 m.Maximize(gamma) # 使用APOPT求解混合整数规划 m.options.SOLVER = 1 m.solve(disp=True) print(f"x1: {x1.value[0]}, x2: {x2.value[0]}, x3: {x3.value[0]}") print(f"最大毛利率: {gamma.value[0]:.4f}")
运行结果:
x1: 1.0, x2: 1.0, x3: 0.0 最大毛利率: 0.7714
关键说明
- 原代码失败的本质是分式目标的数值不稳定性,求解器遇到分母为0的奇异点后无法找到可行解;
- 线性化重构后的模型属于混合整数线性规划(MILP),APOPT求解器能高效处理这类问题,避免数值奇异;
- 若变量规模大(如几十上百个产品),优先使用线性化方法,枚举法仅适用于小规模场景。
内容的提问来源于stack exchange,提问作者soumyajt
相关产品推荐
相关产品推荐

