第3部分主要讲算法的具体实现,
如果对具体细节没有要求, 直接看1, 4就行, 直接用matlab内置的intlinprog函数或者python的cvxpy等第三方包
这里我个人更偏向于使用MATLAB求解
- 整数规划
- 1. 从线性规划到整数规划
- 1.1 整数规划是什么
- 将线性规划决策变量解限制为整数可能会出现的情况
- 2. 整数规划分类
- 2.1 纯整数规划
- 2.2 全整数规划
- 2.3 混合整数规划
- 2.4 0-1整数规划
- 3. 整数规划求解方法
- 3.1 对于不同种类整数规划问题的求解方法
- 3.2 求解方法介绍
- 3.2.1 分支定界法
- 3.2.1.1 文字介绍
- 3.2.1.2 流程图
- 3.2.2 割平面法
- 3.2.2.1文字介绍
- 4. 实现代码
- 4.1Matlab内置函数
- 4.1.1 函数原型
- 4.1.2 数学原型
- 4.1.3 实现代码举例
- 求解
- 代码
- 附上答案
- 4.1.4 进阶内容: intlinprog函数具体使用了什么算法
- 4.2 python实现
- 4.2.1 这里使用cvxpy包举例:
- 题目
- 求解代码
1. 从线性规划到整数规划 1.1 整数规划是什么
就是把一般的线性规划问题加点东西
约束决策变量为整数
举例: 比较下面两种
线
性
规
划
x
=
(
x
i
)
n
a
r
g
m
i
n
∑
i
=
1
n
c
i
x
i
s
.
t
.
{
A
⋅
x
≤
b
A
e
q
⋅
x
=
b
e
q
l
b
≤
x
≤
u
b
线性规划\ x = (x_i)_n\ argmin; sum^n_{i=1}c_ix_i quad s.t. left{ begin{aligned} Acdot x le b \ Aeq cdot x = beq \ lb le x le ub end{aligned} right .\\
线性规划x=(xi)nargmini=1∑ncixis.t.⎩⎪⎨⎪⎧A⋅x≤bAeq⋅x=beqlb≤x≤ub
整 数 规 划 x = ( x i ) n a r g m i n ∑ i = 1 n c i x i s . t . { x 1 , x 3 为 整 数 A ⋅ x ≤ b A e q ⋅ x = b e q l b ≤ x ≤ u b 这 个 例 子 相 对 于 线 性 规 划 约 束 了 两 个 决 策 变 量 x 1 , x 3 为 整 数 有 整 数 约 束 的 规 划 就 是 整 数 规 划 这 个 例 子 就 是 一 个 整 数 规 划 整数规划\ x = (x_i)_n\ argmin; sum^n_{i=1}c_ix_i quad s.t. left{ begin{aligned} x_1, x_3 为整数\ Acdot x le b \ Aeq cdot x = beq \ lb le x le ub end{aligned} right .\\ 这个例子相对于线性规划约束了两个决策变量x_1, x_3为整数\有整数约束的规划就是整数规划\这个例子就是一个整数规划 整数规划x=(xi)nargmini=1∑ncixis.t.⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧x1,x3为整数A⋅x≤bAeq⋅x=beqlb≤x≤ub这个例子相对于线性规划约束了两个决策变量x1,x3为整数有整数约束的规划就是整数规划这个例子就是一个整数规划
将线性规划决策变量解限制为整数可能会出现的情况整数规划求解不是将线性规划解简单取整得到的
(1) 原线性规划最优解就是整数, 那么可以直接转化为整数规划问题, 最优解和线性规划问题最优解一致
(2) 无可行解 (无最优解)
(3) 有最优解, 但相对于原线性规划的最优值变差
引入松弛变量将不等式问题转化为等式问题
所有决策变量都是非负整数
2.2 全整数规划除了决策变量是整数, 系数aij和常数bij也是整数 ( 这时引进的松弛变量和剩余变量也是整数 )
2.3 混合整数规划只有一部分决策变量是非负整数
2.4 0-1整数规划决策变量只取0或1
| 一般整数规划 | 0-1整数规划 |
|---|---|
| 分支定界法 | 匈牙利法 |
| 割平面法 | 隐枚举法 |
因为整数规划可行解是有限集 ( 画图画出来就是可行域里的网格 ) 可以使用穷举法, 即把每一个可行解都带入优化目标计算哪个最优, 但是穷举法浪费资源, 效率低, 因此不推荐使用 ,在这里也没有写出来
3.2 求解方法介绍
matlab内置的intlinprog()方法的实现细节
- 使用[线性规划预处理]缩减问题的规模。
- 使用[线性规划]求解初始松弛(非整数)问题。
- 执行[混合整数规划预处理]以收紧混合整数问题的 LP 松弛。
- 尝试[切割生成]以进一步收紧混合整数问题的 LP 松弛。
- 尝试使用[启发式方法]求得整数可行解。
- 使用[分支定界]算法系统地搜索最优解。此算法通过限制整数变量的可能值范围来求解 LP 松弛问题。它尝试在最优目标函数值上生成一系列更新边界。
基本上重要的就是分支定界法, 别的方法就了解一下就行
3.2.1 分支定界法 3.2.1.1 文字介绍-
不考虑整数限制, 先求出松弛问题 ( 不限制为整数的条件相等的线性规划问题 ) 的最优解
-
考虑特殊情况:
(1) 松弛问题无解, 则整数规划无解
(2) 松弛问题解为整数( 见1.1 ), 则整数规划解就是松弛规划的解
- *若以上都不满足
则对不是整数的决策变量增加新的约束
向上取整或者向下取整做两个分支, 直到所有的解都是整数, 在所有的整数可行解中取最优解输出
x
i
⟶
x
i
≥
⌈
x
i
⌉
或
x
i
⟶
x
i
≤
⌊
x
i
⌋
x_i quad longrightarrow quad x_i geq lceil x_i rceil \ 或\ x_i quad longrightarrow quad x_i leq lfloor x_i rfloor
xi⟶xi≥⌈xi⌉或xi⟶xi≤⌊xi⌋
3.2.1.2 流程图
其中递归的部分
3.2.2 割平面法 3.2.2.1文字介绍
前面两步跟3.2.1.2一样, 前面两个步骤对整数规划都是通用的
第三部, 如果解中含有非整数变量, 则对松弛问题增加一个线性约束来割平面, 使得非整数解恰好在被割掉的一块中, 并且不能割掉原问题的可行解, 一直重复直到都是整数
实际使用不多, 可以了解对比方法之间的区别
有一说一, 线性规划和整数规划部分, 还是MATLAB实现起来方便一些
python实现也有很多可以用的包, 但是都没有MATLAB打包的好, 效率也一般, 没有必要为了这个专门去学一个冷门的python包
建议亲这边使用MATLAB求解规划类的问题
4.1.1 函数原型内置函数 intlinprog()
可以解决混合整数规划, 可以指定哪些决策变量有整数约束
[x, fval] = intlinprog(c, intcon, A, b, Aeq, beq, lb, ub)
基本上和 linprog() 一样, intcon参数就是指定哪些变量有整数约束
4.1.2 数学原型参数命名都来自4.1.1的函数原型
a
r
g
m
i
n
c
T
x
s
.
t
.
{
x
(
i
n
t
c
o
n
)
是
整
数
A
⋅
x
≤
b
A
e
q
⋅
x
=
b
e
q
l
b
≤
x
≤
u
b
argmin; c^Txquad s.t. left{ begin{aligned} x_{(intcon)} ; 是整数 \ Acdot x le b \ Aeq cdot x = beq \ lb le x le ub end{aligned} right .
argmincTxs.t.⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧x(intcon)是整数A⋅x≤bAeq⋅x=beqlb≤x≤ub
a r g m a x z = 5 x 1 + 8 x 2 s . t . { x 1 + x 2 ≤ 6 5 x 1 + 9 x 2 ≤ 45 x 1 , x 2 ≥ 0 , 且 x 1 , x 2 为 整 数 argmax enspace z=5x_1 + 8x_2 qquad\ s.t. left{ begin{aligned} x_1 + x_2 le 6 \ 5x_1 + 9x_2 le 45\ x1, x2ge0, 且x_1, x_2为整数 end{aligned} right . argmaxz=5x1+8x2s.t.⎩⎪⎨⎪⎧x1+x2≤65x1+9x2≤45x1,x2≥0,且x1,x2为整数
代码c = [-5; -8];
% 无论线性规划还是整数规划, 在matlab中默认都是求最小值,
% 题目要求最大值, 所以加个负号
A = [1, 1;
5, 9];
b = [6; 45];
lb = zeros(2, 1);
intcon = [1, 2];
% 着重看上面这个, 这里指定了x1, x2为整数
% 所以根据4.1.2数学原型中写到的intcon的意义, intcon = [1, 2]
[x, fval] = intlinprog(c, intcon, A, b, [], [], lb, []);
x
-fval % 因为之前为了求最大值加了负号, 所以这里再把答案负回来
附上答案
x 1 = 0 x 2 = 5 f v a l = 40 x_1 = 0 qquad x_2=5 qquad fval = 40 x1=0x2=5fval=40
4.1.4 进阶内容: intlinprog函数具体使用了什么算法intlinprog这个MATLAB函数是直接打包好给我们用的, 具体这个函数中发生了什么细节, 使用了什么算法, 可以参考下面的内容
如果编代码过程中出现了奇怪的错误, 可以从原理上提供一种解决错误的可能
算法概述
intlinprog 使用以下策略来求解混合整数线性规划。intlinprog 顺着执行下面的算法, 如果哪一步执行出了结果, 就不会再继续执行更下面的算法
- 使用线性规划预处理缩减问题的规模。
- 使用线性规划求解初始松弛(非整数)问题。
- 执行混合整数规划预处理以收紧混合整数问题的 LP 松弛。
- 尝试切割生成以进一步收紧混合整数问题的 LP 松弛。
- 尝试使用启发式方法求得整数可行解。
- 使用分支定界算法系统地搜索最优解。此算法通过限制整数变量的可能值范围来求解 LP 松弛问题。它尝试在最优目标函数值上生成一系列更新边界。
可以使用的包plup, scipy(得自己实现整数规划算法的细节, 没有必要), 还有python的运筹学包, python-mip等等
对比了一下最好用的是cvxpy包
4.2.1 这里使用cvxpy包举例: 题目
m i n z = 40 x 1 + 90 x 2 , s . t . { 9 x 1 + 7 x 2 ≤ 56 7 x 1 + 20 x 2 ≥ 70 x 1 , x 2 ≥ 0 且 为 整 数 minquad z=40x_1+90x_2,\ s.t. left{ begin{aligned} 9x_1+7x_2 le 56\ 7x_1+20x_2ge 70\ x_1, x_2 ge0 且为整数 end{aligned} right . minz=40x1+90x2,s.t.⎩⎪⎨⎪⎧9x1+7x2≤567x1+20x2≥70x1,x2≥0且为整数
求解代码import cvxpy as cp
import numpy as np
# 不懂见数学原型中的定义, 什么价值向量资源向量什么的
c = np.array([40, 90])
a = np.array([[9, 7],
[-7, -20]])
b = np.array([56, -70])
######
x = cp.Variable(2, interger=True) # 用cvxpy来定义两个整数决策变量, 也就是约束x为整数
obj = cp.Minimize(c*x) # 目标函数
cons = [a * x <= b, x >= 0] # 约束条件
prob = cp.Problem(obj, cons) # 构建问题模型
prob.solve(solver='GLPK_MI', verbose=True) # 求解
print("最优值", prob.value)
print("最优解", x.value)



