数学规划中最简单的一类问题是线性规划问题,它是整数规划及一些非线性规划问题的求解基础;
本篇就详细讲解下线性规划,问题建模的方法和技巧是最重要的部分会重点讲解,因为在解决实际问题时,把问题归结成一个线性规划数学模型是很重要的一步,但往往也是困难的一步,模型建立得是否恰当,直接影响到求解。
文末会用Python和OR-tools工具求解一个线性规划的例子,示范求解工具的使用。
由前面一篇《数学建模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的边界上。
一些问题建立初步数学模型之后,目标函数和约束往往含有绝对值、最大值、最小值符号等,这种不是线性规划问题,但是通过一些变换技巧依然可以转化成线性规划问题;
例如规划问题:
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。
例如规划问题:
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
我们以一个完整的例子来说明求解过程。该例子的问题及建模过程已经在之前一篇文章《数学建模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()
该代码是覆盖了线性规划中各种表达式的写法,非常具有代表性,仿照此例我们可以写出更复杂的模型的求解程序。程序中已经加了清晰的注释,相信大家不难看懂,就不解释了。
求解的最优方案:
[1].https://developers.google.cn/optimization/introduction/python