python求解线性规划问题和整数规划-建模初探

线性规划问题,在线性等式或者不等式的约束下,去求解一个线性目标函数的最大值最小值问题。

首先想到的是scipy中的优化包→optimize里面的 linprog。这个名字和MATLAB里面优化的名字是一样的。

对于简单的连续性线性极值问题,可以使用。

from scipy import optimize as op
help(op.linprog)

查看帮助,可以看到这个函数的用法

linprog(c, A_ub=None, b_ub=None, A_eq=None, b_eq=None, bounds=None,
		 method='interior-point', callback=None, options=None, x0=None)

最主要的就是 c,A_ub, b_ub, A_eq, b_eq,前五个参数。
这个函数求的是最小值,也就是求c(目标线性函数)最小,如果现实是求极大值,那么要加一个负号。
他所有的不等式约束都是默认"<=" , 所以要把所有的不等式都转成小于
A_ub,二维数组,所有不等式约束的系数组成
b_ub,一维数组,所有不等式约束的结果组成
A_eq,二维数组,就是约束中等式的系数组成
b_eq,一维数组,所以约束中等式的结果组成
bounds,边界,就是结果的取值边界,默认是(0,None),就是0到无穷大。可以写多个,比如有三个未知数:((0,3),(0,100),(0,None))。
method,方法,{‘interior-point’, ‘revised simplex’, ‘simplex’}三个值可选。

  1. interior-point:内部点,如果bounds为0~None,那么这个值永远取不到0,只会近似接近。
  2. revised simplex:改进的simplex方法。这个是最常用的。(第一种方法求出的都是近似的,很难把控我觉得)
  3. simplex:这是前版本遗留下来的方法,为了支持前版本的程序。
    其他参数不说了。这个够用。

例:
python求解线性规划问题和整数规划-建模初探_第1张图片
设变量x1为A1牛奶的产量,x2为A2的
目标函数就是利益最大:24 * x1+16 * x2 (也就是最小化: -24 * x1-16 * x2)
约束条件为:
x1<=100
4 * x1 + 2 * x2 <=480
x1 / 3 + x2 / 4<=50
x1,x2 >=0
由于里面有除号,所以计算机会近似,因为精度问题,得到的结果不理想。所以建模的时候不要有除号的出现。
我们重新定义,把产量前面加上系数:
设变量3 * x1为A1牛奶的产量,4 * x2为A2的
目标函数就是利益最大:24 * (3 * x1)+16 * (4 * x2) (也就是最小化: -72 * x1 -64 * x2)
约束条件为:
3 * x1<=100
4 * (3 * x1) + 2 * (4 * x2) <=480
x1 + x2 <=50
x1,x2 >=0
代码:(注意,如果式子中没有出现的未知数系数要写0,不能不写)

c = np.array([-72,-64])
A_ub = np.array([[3,0],[12,8],[1,1]])
b_ub = np.array([100,480,50])
op.linprog(c,A_ub,b_ub,method='revised simplex')

结果:

con: array([], dtype=float64)
     fun: -3360.0
 message: 'Optimization terminated successfully.'
     nit: 4
   slack: array([40.,  0.,  0.])
  status: 0
 success: True
       x: array([20., 30.])

A1产量60公斤,A2产量120公斤,最大利润3360

注意:要看status和success。不管成功与否,x都会给一个值。但是不一定能用。
只有 status: 0(表示算法状态状态码,0表示最优化名义上有解,是可行的), success: True(当算法成功完成时)
slack:松弛度,表示的是得到的结果集,带入原不等式,得到的差距有多少。这里可以看出第二个和第三个不等式的差距为0,说明时间和牛奶量都被充分利用了。

另外一个例子:
python求解线性规划问题和整数规划-建模初探_第2张图片
这是一个投资问题,学经济学的一般都会讲建模。
这里一共四个投资方案,每隔投资方法应该投多少,才能达到5年末总获利是最高的?
见下表,每个方案,投资的数,我用abcd表示

第一年 第二年 第三年 第四年 第五年
方案A a1 a2 a3 a4
方案B b
方案C c
方案D d1 d2 d3 d4 d5

那么就可以得出5年末的时候获利的金额是:
1.15 * a4 + 1.25 * b + 1.4 * c + 1.11 * d5
这就是目标函数,使他最大化。
因为第五年得到的,就是你前面投资产生的本利。第一年只跟a4有关系,以此类推

注意,方案A的获利在次年末。方案D的获利在每年初。所以第一年投的钱,第二年只能拿到d1产生的本利,再用这个钱去投资其他方案。以此类推,得到以下的约束条件:
a1 + d1 <=10
a2+c1+d2 = 1.11d1
a3+b1+d3 = 1.15a1+1.11d2
a4+d4 = 1.15a2+1.11d3
d5 = 1.15a3 + 1.11d4
这些式子化简转到一边。
代码如下:

c = np.array([0,0,0,-1.15,-1.25,-1.4,0,0,0,0,-1.11])
A_ub = np.array([[1,0,0,0,0,0,1,0,0,0,0],
				[0,0,0,0,1,0,0,0,0,0,0],
				[0,0,0,0,0,1,0,0,0,0,0]])
b_ub = np.array([10,4,3])
A_eq = np.array([
    [0,1,0,0,0,1,-1.11,1,0,0,0],
    [1.15,0,-1,0,-1,0,0,1.11,-1,0,0],
    [0,1.15,0,-1,0,0,0,0,1.11,-1,0],
    [0,0,1.15,0,0,0,0,0,0,1.11,-1]
])
b_eq = np.array([0,0,0,0])
op.linprog(c,A_ub,b_ub,A_eq,b_eq,method='revised simplex')

结果:

con: array([0.00000000e+00, 0.00000000e+00, 1.77635684e-15, 0.00000000e+00])
     fun: -16.85058155100001
 message: 'Optimization terminated successfully.'
     nit: 8
   slack: array([1.77635684e-15, 4.00000000e+00, 3.00000000e+00])
  status: 0
 success: True
       x: array([ 0.       ,  0.       ,  0.       ,  0.       ,  0.       ,
        0.       , 10.       , 11.1      , 12.321    , 13.67631  ,
       15.1807041])

整数规划:
例:
对于下面的式子

c = [3,4,1]
A = [[-1,-6,-2],[-2,0,0]]
b = [-5,-3]
Aeq = [[0,0,0]]
beq = [0]
res = op.linprog(c, A, b, Aeq, beq,method="revised simplex")

求解结果

con: array([0.])
     fun: 6.25
 message: 'Optimization terminated successfully.'
     nit: 0
   slack: array([0., 0.])
  status: 0
 success: True
       x: array([1.5 , 0.  , 1.75])

如果要求是整数,就无能为力。或者可以用lingo求解。这里不赘述。
在Python里有一个pulp的库,可以用来解整数问题
pulp在Python里本身不自带,要pip install pulp

import pulp as pp
# 定义一个问题,第一个参数就是一个名字,随便取,后面是一个int型,说明的是求最大或者最小
# pp.LpMinimize其实就是一个int,值为1
# pp.LpMaximize也是一个int,值为-1.
# 在参数后面也可以直接写1或者-1表示
# 其实默认的都是求最小值,在求最大值的时候两边都要乘以-1,转成最小值求解。
# 						所以最小值参数为1,最大值参数为-1
mylp = pp.LpProblem("lp1",pp.LpMinimize)

# 定义未知数,标记取值范围,cat为限制条件,Integer表示整数型,Continuous表示连续型
x1 = pp.LpVariable("x1",lowBound=0,cat="Integer")
x2 = pp.LpVariable("x2",lowBound=0,cat="Integer")
x3 = pp.LpVariable("x3",lowBound=0,cat="Integer")

# 在pulp中用+=符号,加约束和目标函数
# 只支持 = ,>= , <= 不支持> , <
mylp += 3*x1+4*x2+x3
mylp +=(x1+6*x2+2*x3 >=5)
mylp +=(2*x1 >=3)
打印mylp输出如下:

lp1:
MINIMIZE
3*x1 + 4*x2 + 1*x3 + 0
SUBJECT TO
_C1: x1 + 6 x2 + 2 x3 >= 5

_C2: 2 x1 >= 3

VARIABLES
0 <= x1 Integer
0 <= x2 Integer
0 <= x3 Integer
# 最后一定要调用这个函数。才能得到解
# 他返回一个int型,是一个status,表示的是pp.LpStatus里面对应的数字含义
# {0: 'Not Solved',
#   1: 'Optimal',最佳的
#  -1: 'Infeasible',
#  -2: 'Unbounded',
#  -3: 'Undefined'}

i = mylp.solve()
print(i) # 结果是1,返回1就说明成功计算了
# 得到这些值
[v.varValue for v in mylp.variables()]
输出:
[2.0, 0.0, 2.0]
mylp.objective
输出:3*x1 + 4*x2 + 1*x3 + 0

pp.value(mylp.objective)
最终的结果表达式的值,值为8.0

如果很复杂,还可以通过字典的形式,添加,这网上有很多教程,不赘述,有机会再写。

你可能感兴趣的:(数学,python,数据库,开发语言)