最优化问题是运筹学与数学需要解决的主要问题之一,它既是运筹学的分支之一也是数学的分支之一,那么它在运筹学中与在数学中有什么区别呢?
在数学中,我们主要关注问题的数学模型以及解决问题的方法;而在运筹学中,我们不仅仅要关注模型本身,还需要关注如何从社会经济现象中总结事物的一般规律,并将这种规律总结成具体的数学模型,从现象到模型,是优化在运筹学与数学中的主要区别之一。
最优化问题的目的是在一定的约束条件下,找到问题的最优解,并找出取得最优解的一般条件。现实中很多问题,我们都能通过数学模型求解出其最优解,然而当问题规模逐渐增大时,原来的解法可能耗费的时间会呈指数形式增长,当规模增大到一定的程度,问题便变得不可计算了,这时我们称这种问题为NP问题,即在问题的规模没有限制的情况下,我们找不到一个确定的解法能在多项式时间内算出这个问题的最优解,我们只能在多项式时间内找出它的“满意解”,并且告诉你这个解好不好。
使用python解决最优化问题时,一些问题只需要不到100行代码就可以解决,但是很多解法往往需要几百行甚至几千行的代码才能解决,有时间写这些代码,还不如找个别人写好的方法直接拿来用,只要知道它参数传递的格式,就能直接用别人的工具解决自己的问题。
MIP(Mixed-Integer Linear Programming)软件包就是这样一个解最优化问题的工具,它的主页在Python-MIP,类似的工具还有pyscipopt包、docplex包、Ortool包等等,这些都可以很好的解决优化问题,可能它们最大的区别就是底层的求解器不同而已。MIP用的是CBC求解器,还可以集成gurobi求解器,pyscipopt用的是scip求解器…
利用MIP解决最优化问题所需的代码量可能是自己写代码的十分之一甚至百分之一,以一个简单的指派问题为例:
自己写代码解的话参考我的上一篇博客整数规划–指派问题,大致需要个170行左右(这里我使用的解法是指派问题的一般解法,如果要用单纯形法 + 分支定界法来解,可能代码量更多),而使用软件包就简单了:
from mip import Model, xsum, BINARY
model = Model()
c = [[12,7,9,7,9],[8,9,6,6,6],[7,17,12,14,9],[15,14,6,6,10],[4,10,7,10,9]] #效率矩阵
x = [[model.add_var(var_type=BINARY) for i in range(len(c))] for j in range(len(c))] #决策变量
model.objective = xsum(x[i][j] * c[i][j] for i in range(len(c)) for j in range(len(c))) #目标函数
for i in range(len(c)): #每行只能有一个1
model += xsum(x[i][j] for j in range(len(c))) == 1
for j in range(len(c)): #每列只能有一个1
model += xsum(x[i][j] for i in range(len(c))) == 1
model.verbose = 0
model.optimize() #执行模型
print("最优解为:",model.objective_value)
print("最终解矩阵为:")
for xi in x:
xList = []
for xij in xi:
xList.append(xij.x)
print(xList)
不算结果输出的代码,大致只需要9行,一行初始化模型求解器,一行定义效率矩阵,一行定义决策变量,一行定义目标函数,再加上4行的约束(MIP重载了运算符,使用+号就能直接添加约束)与一行的调用问题求解函数。
机器使用了可以忽略的时间就得到了最优解。
这就是求解工具的强大之处,直接使用已有的工具能够节省很多写代码的时间,但是有一说一,解决问题的数学模型还是需要自己弄出来的,不然连工具都不知道咋用。