背景
在我们的工作和生活中,有非常多带有约束的问题需要解决。例如,
- 在预算有限的情况下,如何买到区位、学区、楼龄、户型都比较满意的房子?
- 分布在北京各个地区的几个哥们要聚餐,选择哪个餐厅才能让大家通行距离比较接近,餐厅口味也不错?
- 公司有一个由10辆车组成的车队,从仓库出发为100家企业配送物资,每家企业都有不同的收货时间窗口,物资体积、重量也各不相同,同时,车辆有其最大载容、载重及最大行驶距离。如何做车辆与企业匹配和路径规划,能够满足要求的同时最小化成本?
解决这类问题有比较常用的套路,即使不了解运筹优化底层原理,也能够快速解决问题,简称“三段式”:
- 定义问题
- 建模问题
- 利用成熟的求解器求解问题
在求解器中,可以分为商业求解器和开源求解器。财大气粗的传统行业以购买商业求解器为主,通常解决的问题规模大、计算性能好;互联网公司以开源求解器为主,稍逊色,好处是免费,一般场景下也够用了。当然,如果问题比较特殊(e.g.时效要求较高),需要自行编码完成求解过程。
我们接下来要介绍的ortools是google开源的一种运筹优化工具。之所以称为“工具”,是因为ortools不仅自研了cpsat求解器,也提供了对开源求解器(e.g.SCIP)、商业求解器(Gurobi、CPLEX)的支持。
需要补充一点,不同的求解器/工具有其擅长之处。就算是开源工具,不同工具也各自优劣。例如,ortools提供了线性规划、整数规划、约束规划以及后续VRP问题、网络流问题等场景化应用,但ortools API十分匮乏,相关资料较少;jsprit则聚焦在VRP问题,项目整体具有比较好的设计理念,非常适合公司层面的项目开发,缺点也比较明显,它只支持VRP问题。
本系列主要以ortools官方指南为蓝本,从实际应用的角度出发,解读ortools工具,并提供使用案例及代码解读。
核心模块
核心模块大体可以分为两部分,前面3个模块是基础功能:
- 线性规划(Linear Optimization)
- 整数规划(Integer Optimization)
- 约束规划(Constraint Optimization)
后面5个模块偏重场景应用:
- 分配(Assignment)
- 路径规划(Routing)
- 装箱(Bin Packing)
- 网络流(Network Flows)
- 调度(Scheduling)
基础功能
线性规划
线性规划问题指,目标函数和约束条件都为线性的优化问题。
例如,
$$ \begin{equation} \begin{array}{r} \operatorname{maximize} x_{1}+2 x_{2} \\ \text { subject to } x_{1}+x_{2} \leq 3 \\ x_{2} \leq 2 \\ x_{1} \geq 0 \\ x_{2} \geq 0 \end{array} \end{equation} $$
几何含义:在可行域内(4条实线包围的蓝色区域)移动目标函数(虚线),使得目标函数最大化。
整数规划
整数规划一般指约束变量含有整数的优化问题。
例如,常见的背包问题
设有一个背包,其最大承重为 b ,考虑 n 件物品,其中第 j 件重量为 \( a_j \) ,其价值为 \(c_j\)。问如何选取物品装入背包中,使得背包内物品的总价值最大?
设决策变量 \(x_j\)取值0或1,表示是否选择该物品。则背包问题可以表示为下列整数规划:
$$ \begin{array}{c} \max _{x} \sum_{j=1}^{n} c_{j} x_{j} \\ \text { s.t. } \quad \sum_{j=1}^{n} a_{j} x_{j} \leq b \\ x \in\{0,1\}^{n} \end{array} $$
这类问题,决策变量通常是离散的。
整数规划大体可以分为以下几类。
- 线性整数规划(Integer Linear Programming):目标函数为线性,约束为线性,决策变量只含有整数变量的整数规划问题。线性整数规划问题目前是整数规划问题中研究最多,也是算法相对比较成熟一点的领域。
- 0-1线性规划(Binary Linear Programming):目标函数为线性,约束为线性,决策变量只含有0-1变量的整数规划问题。线性整数规划都可以转化为0-1线性规划问题。
- 混合整数线性规划(Mixed-integer Linear Programming):目标函数为线性,约束为线性,决策变量既含有整数变量也含有连续变量的整数规划问题。
- 非线性整数规划(Nonlinear Integer Programming):目标函数和约束中至少有一个是非线性的,决策变量只含有整数变量的整数规划问题。非线性整数规划的难度要比线性整数规划问题难很多。
- 0-1非线性规划(Nonlinear Binary Programming):目标函数和约束中至少有一个是非线性的,决策变量只含有0-1变量的整数规划问题。
- Mixed-integer Nonlinear Programming (0-1非线性混合整数规划):目标函数和约束中至少有一个是非线性的,决策变量既含有整数变量也含有连续变量的整数规划问题。
- Polynomial Binary Programming (0-1多项式规划):目标函数和约束中都是多项式函数,决策变量只含有0-1变量的整数规划问题。
在工作中,为了快速解决,通常会利用trick将各类问题简化为前3类整数规划问题。
约束规划
约束规划指求解满足各项约束的可行解的问题。与线性规划、整数规划不同,约束规划更加关注可行解,没有明确的优化目标。当然,约束规划也可以求解最优化问题,未来会详细解读。
例如,后续章节中出现的员工排班问题,就是非常典型的约束规划问题。
应用模块
分配
分配问题即供需双方的匹配问题。特别的,最近几年O2O公司崛起,滴滴司机订单分配、外卖配送员订单分配等问题层出不穷,除了传统最优化的目标,时效性、高并发等性能要求更加被关注。
路径规划
路径规划是比较常见的运筹优化问题,滴滴、美团、京东、顺丰等几乎所有涉及物流的公司都会与路径规划有千丝万缕的联系。在ortools中,VRP模块提供了几乎全部的常用变种,例如,TSP、VRP、VRPTW、CVRP等。在前公司就曾经利用ortools的路径规划模块解决车辆调度与路径规划问题。
装箱
装箱问题在工业界应用场景不多,但是一个非常难的算法问题。后续会对比背包问题与装箱问题的异同。如果有机会,会尝试分享物流行业里面装箱问题的应用。
网络流
网络流问题,本质是将网络关系的先验知识利用起来的过程,通常,解决同样的问题,网络流算法比传统整数规划或线性规划算法效率更高。
调度
调度问题由来已久,不管是经典的车间调度问题、传统的护士排班问题,还是外卖员排班、便利蜂员工排班、配送员排班,都可以归类到调度的范畴。差异仅仅在于不同场景下,商业诉求不同,约束也就不同。
结语
本文简单介绍ortools各模块的内容,在后续文章中将详细介绍如何使用ortools各模块。
参考
1.https://developers.google.cn/...
2.图片参考自 https://zhuanlan.zhihu.com/p/...
3.部分理论描述参考自 https://zhuanlan.zhihu.com/p/...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。