第3部分主要讲算法的具体实现,
如果对具体细节没有要求, 直接看1, 4就行, 直接用matlab内置的intlinprog函数或者python的cvxpy等第三方包
这里我个人更偏向于使用MATLAB求解
就是把一般的线性规划问题加点东西
约束决策变量为整数
举例: 比较下面两种
线 性 规 划 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} A\cdot 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 为整数\\ A\cdot 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) 有最优解, 但相对于原线性规划的最优值变差
引入松弛变量将不等式问题转化为等式问题
所有决策变量都是非负整数
除了决策变量是整数, 系数aij和常数bij也是整数 ( 这时引进的松弛变量和剩余变量也是整数 )
只有一部分决策变量是非负整数
决策变量只取0或1
一般整数规划 | 0-1整数规划 |
---|---|
分支定界法 | 匈牙利法 |
割平面法 | 隐枚举法 |
因为整数规划可行解是有限集 ( 画图画出来就是可行域里的网格 ) 可以使用穷举法, 即把每一个可行解都带入优化目标计算哪个最优, 但是穷举法浪费资源, 效率低, 因此不推荐使用 ,在这里也没有写出来
matlab内置的intlinprog()方法的实现细节
基本上重要的就是分支定界法, 别的方法就了解一下就行
不考虑整数限制, 先求出松弛问题 ( 不限制为整数的条件相等的线性规划问题 ) 的最优解
考虑特殊情况:
(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一样, 前面两个步骤对整数规划都是通用的
第三部, 如果解中含有非整数变量, 则对松弛问题增加一个线性约束来割平面, 使得非整数解恰好在被割掉的一块中, 并且不能割掉原问题的可行解, 一直重复直到都是整数
实际使用不多, 可以了解对比方法之间的区别
有一说一, 线性规划和整数规划部分, 还是MATLAB实现起来方便一些
python实现也有很多可以用的包, 但是都没有MATLAB打包的好, 效率也一般, 没有必要为了这个专门去学一个冷门的python包
建议亲这边使用MATLAB求解规划类的问题
内置函数
intlinprog()
可以解决混合整数规划, 可以指定哪些决策变量有整数约束
[x, fval] = intlinprog(c, intcon, A, b, Aeq, beq, lb, ub)
基本上和 linprog()
一样, intcon参数就是指定哪些变量有整数约束
参数命名都来自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^Tx\quad s.t. \left\{ \begin{aligned} x_{(intcon)} \; 是整数 \\ A\cdot 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, x2\ge0, 且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
intlinprog这个MATLAB函数是直接打包好给我们用的, 具体这个函数中发生了什么细节, 使用了什么算法, 可以参考下面的内容
如果编代码过程中出现了奇怪的错误, 可以从原理上提供一种解决错误的可能
算法概述
intlinprog
使用以下策略来求解混合整数线性规划。intlinprog
顺着执行下面的算法, 如果哪一步执行出了结果, 就不会再继续执行更下面的算法
可以使用的包plup, scipy(得自己实现整数规划算法的细节, 没有必要), 还有python的运筹学包, python-mip等等
对比了一下最好用的是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 且 为 整 数 min\quad z=40x_1+90x_2,\\ s.t. \left\{ \begin{aligned} 9x_1+7x_2 \le 56\\ 7x_1+20x_2\ge 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)