0 引言
数学规划中最简单的一类问题是线性规划问题,它是整数规划及一些非线性规划问题的求解基础;
本篇就详细讲解下线性规划,问题建模的方法和技巧是最重要的部分会重点讲解,因为在解决实际问题时,把问题归结成一个线性规划数学模型是很重要的一步,但往往也是困难的一步,模型建立得是否恰当,直接影响到求解。
文末会用Python和OR-tools工具求解一个线性规划的例子,示范求解工具的使用。
1 定义
由前面一篇《数学建模workflow》已经介绍,优化问题一般包括三个要素:决策变量、目标函数、约束条件;
线性规划是目标函数和约束条件都为线性表达式的数学规划;
线性函数是什么样的呢?
一个函数是线性函数应当是这样的:
f
(
X
)
=
A
T
X
+
b
=
∑
i
=
0
n
a
i
x
i
+
b
f(X)=A^TX+b \\ =\sum_{i=0}^na_i x_i+b
f(X)=ATX+b=i=0∑naixi+b
其中A为列向量,X为自变量的列向量,b为常量值;
线性规划问题的标准型一般为:
(1)
m
i
n
z
=
∑
j
=
1
n
c
j
x
j
\tag{1} min \ \ z=\sum_{j=1}^{n}c_j x_j
min z=j=1∑ncjxj(1)
(2)
s
.
t
.
{
f
i
(
X
)
≤
0
,
i
=
1
,
2
,
.
.
.
,
m
i
h
k
(
X
)
=
0
,
k
=
1
,
2
,
.
.
.
o
k
l
b
≤
x
j
≤
u
b
,
j
=
1
,
2
,
.
.
.
,
n
\begin{alignedat}{2} \tag{2}s.t. \begin{cases} & f_i(X)&\leq 0,\ i&=1,2,...,m_i\\ &h_k(X)&= 0,\ k&=1,2,...o_k\\ lb\leq &x_j&\leq ub,\ j&=1,2,...,n \end{cases} \end{alignedat}
s.t.⎩⎪⎨⎪⎧lb≤fi(X)hk(X)xj≤0, i=0, k≤ub, j=1,2,...,mi=1,2,...ok=1,2,...,n(2)
其中,约束条件(2)构成的集合为可行域;如果我们假设可行域为R,R为有限区域且非空时存在有限最优解,R为无限区域时目标函数值无界,R为空集则目标函数无可行解。如果线性规划存在有限最优解,则最优目标函数值在其可行域R的边界上。
2 建模技巧
一些问题建立初步数学模型之后,目标函数和约束往往含有绝对值、最大值、最小值符号等,这种不是线性规划问题,但是通过一些变换技巧依然可以转化成线性规划问题;
2.1 含有绝对值符号的问题
例如规划问题:
min
∑
i
=
1
n
∣
x
i
∣
s.t.
A
X
≤
b
\begin{alignedat}{2} &\text{min} \sum_{i=1}^{n}|x_i| \\ &\text{s.t.} \ \ \ AX\leq b \end{alignedat}
mini=1∑n∣xi∣s.t. AX≤b
其中,
X
=
[
x
1
,
.
.
.
,
x
n
]
T
X=[x_1,...,x_n]^T
X=[x1,...,xn]T,
A
A
A和
b
b
b为相应维数的矩阵和向量。
要把上面的问题变换成线性规划问题,可以根据如下事实:
对任意的
x
i
x_i
xi,存在
u
i
,
v
i
>
0
u_i,v_i>0
ui,vi>0满足
∣
x
i
∣
=
u
i
+
v
i
x
i
=
u
i
−
v
i
\begin{alignedat}{2} |x_i|&=u_i+v_i \\ x_i&=u_i-v_i \end{alignedat}
∣xi∣xi=ui+vi=ui−vi
并且任意地,只要我们取
u
i
=
∣
x
i
∣
+
x
i
2
,
v
i
=
∣
x
i
∣
−
x
i
2
u_i=\frac{|x_i|+x_i}{2},v_i=\frac{|x_i|-x_i}{2}
ui=2∣xi∣+xi,vi=2∣xi∣−xi就能满足要求。
这样,就可以把问题的初始模型转化为如下线性规划模型:
min
∑
i
=
1
n
(
u
i
+
v
i
)
s.t.
{
A
(
u
−
v
)
≤
b
u
,
v
≥
0
\begin{alignedat}{2} &\text{min} \sum_{i=1}^{n}(u_i+v_i) \\ &\text{s.t.} \begin{cases} A(u-v)\leq b \\ u,v\geq 0 \end{cases} \end{alignedat}
mini=1∑n(ui+vi)s.t.{A(u−v)≤bu,v≥0
其中,
u
,
=
[
u
1
,
.
.
.
,
u
n
]
T
,
v
=
[
v
1
,
.
.
.
,
v
n
]
T
u,=[u_1,...,u_n]^T,v=[v_1,...,v_n]^T
u,=[u1,...,un]T,v=[v1,...,vn]T。
2.2 含有最值符号的问题
例如规划问题:
min
x
i
{
max
y
i
∣
a
i
x
i
−
b
i
y
i
∣
}
,
i
=
1
,
2
,
.
.
.
,
n
\text{min}_{x_i} \{\text{max}_{y_i}|a_ix_i-b_iy_i|\},\ \ i=1,2,...,n
minxi{maxyi∣aixi−biyi∣}, i=1,2,...,n
其中,决策变量
x
i
,
y
i
x_i,y_i
xi,yi取任意值,
a
i
,
b
i
a_i,b_i
ai,bi为已知常数。
显然,这个也不是线性规划问题。
对于这个问题,如果我们取
z
=
max
y
i
∣
a
i
x
i
−
b
i
y
i
∣
z=\text{max}_{y_i}|a_ix_i-b_iy_i|
z=maxyi∣aixi−biyi∣
此式等价于
a
i
x
i
−
b
i
y
i
≤
z
a_ix_i-b_iy_i\leq z
aixi−biyi≤z
可以标准化为
a
i
x
i
−
b
i
y
i
−
z
≤
0
a_ix_i-b_iy_i-z\leq 0
aixi−biyi−z≤0
则原规划问题转化为如下线性规划问题:
min
z
s.t.
a
i
x
i
−
b
i
y
i
−
z
≤
0
,
i
=
1
,
2
,
.
.
.
,
n
\begin{alignedat}{2} &\text{min} \ \ z \\ &\text{s.t.} \ \ \ a_ix_i-b_iy_i-z\leq 0,\ \ i=1,2,...,n \end{alignedat}
min zs.t. aixi−biyi−z≤0, i=1,2,...,n
3 求解方法
我们以一个完整的例子来说明求解过程。该例子的问题及建模过程已经在之前一篇文章《数学建模workflow》介绍过,这里不再重复建模过程细节,不熟悉的同学请先看那一篇文章。
问题如下:
某机床厂生产甲、乙两种机床,每台销售后的利润分别为4000 元与3000 元。
生产甲机床需用 A、B机器加工,加工时间分别为每台 2 小时和 1 小时;生产乙机床
需用 A、B、C三种机器加工,加工时间为每台各一小时。若每天可用于加工的机器时
数分别为A 机器10 小时、B 机器8 小时和C 机器7 小时,问该厂应生产甲、乙机床各
几台,才能使总利润最大?
建立的线性规划模型为:
m
a
x
z
=
4000
x
1
+
3000
x
2
s
.
t
.
2
x
1
+
x
2
≤
10
2
x
1
+
x
2
≤
10
x
1
+
x
2
≤
8
x
2
≤
7
x
1
≥
0
,
x
2
≥
0
max\ \ \ z=4000x_1+3000x_2 \\ s.t.\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ 2x_1 + x_2 \leq 10 \\ 2x_1 +x_2≤10 \\ x_1 + x_2 \leq 8 \\ x_2 \leq 7 \\ x_1 \geq 0,x_2 \geq 0
max z=4000x1+3000x2s.t. 2x1+x2≤102x1+x2≤10x1+x2≤8x2≤7x1≥0,x2≥0
我们用Python和OR-tools编程求解上述模型,完整的代码贴在下面,:
from ortools.linear_solver import pywraplp
def main():
# Select a solver according to the type of your problem.
solver = pywraplp.Solver(name='SolveSimpleSystem',problem_type=pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)
# Create the variables
x1 = solver.NumVar(0, solver.infinity(), name='x1')
x2 = solver.NumVar(0, 7, name='x2')
# create the constraints
constraint1 = solver.Constraint(-solver.infinity(),10)
constraint1.SetCoefficient(x1, 2)
constraint1.SetCoefficient(x2, 1)
constraint2 = solver.Constraint(-solver.infinity(), 8)
constraint2.SetCoefficient(x1, 1)
constraint2.SetCoefficient(x2, 1)
# Create the objective function
objective = solver.Objective()
objective.SetCoefficient(x1,4000)
objective.SetCoefficient(x2, 3000)
objective.SetMaximization()
# Call the solver.
solver.Solve()
print('Number of variables =', solver.NumVariables())
print('Number of constraints =', solver.NumConstraints())
# The value of each variable in the solution.
print('Solution:')
print('x1 = ', x1.solution_value())
print('x2 = ', x2.solution_value())
# The objective value of the solution.
opt_solution = 4 * x1.solution_value() + 3 * x2.solution_value()
print('Optimal objective value =', opt_solution)
if __name__ == '__main__':
main()
该代码是覆盖了线性规划中各种表达式的写法,非常具有代表性,仿照此例我们可以写出更复杂的模型的求解程序。程序中已经加了清晰的注释,相信大家不难看懂,就不解释了。
求解的最优方案:
4 参考资料
[1].https://developers.google.cn/optimization/introduction/python