在构建线性规划(LP)或者混合整数规划(MIP)的过程中,经常会遇到求解器报infeasible 错误。 这里记录下如何用gurobi快速分析问题, 找到存在矛盾的约束条件。
1 利用gurobi的computeIIS生成ilp文件
computeIIS的全面解释应该是翻阅Gurobi的官方文档, 这里截取一部分。
个人的理解是computeIIS会从原始的不可行的模型中找到存在冲突(矛盾的)约束和变量(边界), 需要注意的是模型中可能存在多个冲突点, gurobi可以帮助我们找到其中的一部分冲突点或者全部(不保证),另外这个命令返回的约束和条件也不是最少的那个冲突点。这个限制不影响我们对具体问题的分析。
这个命令的好处是当我们的模型文件比较大, 比如约束条件成百上千, 甚至更多的时候,该命令生成的ilp文件会帮助我们缩小问题的分析范围。
当原始模型文件中存在多个冲突的时候,一个可行的做法是:
- step 1: 检测到模型存在不可行,进入step2, 否则 正常求解问题
- step 2: 利用computeIIS分析 找到存在的矛盾的约束
- step 3: 解决存在的问题
这三个是一个循环的过程, 直到求解器可以正常求解模型。下面给出调用computeIIS的python代码。
import gurobipy as gp
# 读取原始的lp问题(infeasible)
model = gp.read('model_file.lp')
# 设置参数(不是必须得)
model.setParam('TimeLimit', 1000)
# 求解
model.optimize()
# 如果求解过程中报infeasible问题 退出, 则执行computeIIS, 并把结果保存到后缀为ilp的文件中
model.computeIIS()
model.write("model_file.ilp")
2 松弛变量法
松弛变量法顾名思义就是在原来的模型约束条件中增加松弛变量。原来的模型因为存在相互冲突的约束条件导致模型不可行, 那么通过在这些存在冲突的约束条件中增加松弛变量而使得模型变得可行。 这时候可能会有疑问,松弛变量的取值范围如何, 我们定义松弛变量的时候都定义成非负数, 增加松弛变量相当于对原始的模型做一定程度的矫正,我们希望这个矫正越小越好。所以顺理成章的衍生出一个LP或者MIP问题,这个问题的目标是对增加的松弛变量的和求最小,约束是原始模型的约束松弛化。 看看下面gurobi给出的例子, 会有更深的理解。
import gurobipy as gp
# 读取原来的不可行模型
feasmodel = gp.read("model_file.lp")
# clear objective
feasmodel.setObjective(0.0)
# add slack variables
# 对原来的约束松弛化
for c in feasmodel.getConstrs():
sense = c.Sense
if sense != '>':
feasmodel.addVar(obj=1.0, name="ArtN_" + c.ConstrName,
column=gp.Column([-1], [c]))
if sense != '<':
feasmodel.addVar(obj=1.0, name="ArtP_" + c.ConstrName,
column=gp.Column([1], [c]))
# optimize modified model
feasmodel.setParam('MIPGap', 0.05)
feasmodel.optimize()
feasmodel.write('feasopt.lp')
feasmodel.write('feasopt.sol')
上述代码生成的feasopt.lp文件是我们对原问题的约束松弛化,目标是所增加的松弛变量的和。feasopt.sol 中是目标取得最优时变量的取值。
一个sol文件的示例(仅仅是示例, 不要和你自己的实际问题对应):
......
......
ArtN_l_t_c_A7_1 0
ArtN_l_t_c_A7_2 0
ArtN_l_t_c_A7_3 0
ArtN_l_t_c_A7_4 0
ArtN_l_t_c_A7_6 0
ArtN_l_t_c_A8_1 5.0999999999985448e+00
ArtN_l_t_c_A8_2 0
ArtN_l_t_c_A8_3 5.0999999999985448e+00
ArtN_l_t_c_A8_4 5.0999999999985448e+00
ArtN_l_t_c_A8_6 8.7
ArtN_l_t_c_AL_0 0
ArtN_l_t_c_AL_1 0
ArtN_l_t_c_AL_2 0
ArtN_l_t_c_AL_3 0
ArtN_l_t_c_AL_4 0
ArtN_l_t_c_AL_6 0
ArtN_l_t_c_AM_1 1037.5
ArtN_l_t_c_AM_2 4122.25
ArtN_l_t_c_AM_3 231
ArtN_l_t_c_AM_4 7.25
ArtN_l_t_c_AM_6 3450
现在可以找到sol文件中松弛变量(以ArtN_或者ArtP_开头), 关注取值不是0的变量, 结合feasopt.lp 来看, 到底是哪些约束存在冲突。
这里分享一下个人的体会, 松弛变量法是在全部约束中增加松弛,存在一些缺点, 一定程度是增加了问题的分析规划, 并且不够精准。我平时是结合computeIIS和松弛变量法来分析问题的, 通过computeIIS 获得ilp文件, 如果ilp问题得出只是个位数或者十几个约束冲突, 凭着对问题的理解, 自然就分析出矛盾所在了, 如果冲突约束特别多, 那么只是有针对性的在ilp中给出指示的约束中增加松弛, 而不是松弛原始模型的全部约束, 这样可以更快的聚焦问题。