【数学建模】线性规划各种问题的Python调包方法

匿名 (未验证) 提交于 2019-12-02 22:51:30

关键词:Python、调包、线性规划、指派问题、运输问题、pulp、混合整数线性规划(MILP)

注:此文章是线性规划的调包实现,具体步骤原理请搜索具体解法。

一、线性规划

该问题引用自《数学建模算法与应用-司守奎》第一章线性规划 3.线性规划
包的具体使用可参考scipy官网

scipy调包代码

import numpy as np  z = np.array([2, 3, 1])  a = np.array([[1, 4, 2], [3, 2, 0]])  b = np.array([8, 6])  x1_bound = x2_bound = x3_bound =(0, None)  from scipy import optimize  res = optimize.linprog(z, A_ub=-a, b_ub=-b,bounds=(x1_bound, x2_bound, x3_bound))  print(res)  #output: #     fun: 7.0 # message: 'Optimization terminated successfully.' #     nit: 2 #   slack: array([0., 0.]) #  status: 0 # success: True #       x: array([0.8, 1.8, 0. ]) 





这种情况,可以:
A_eq = [[1,2,4]] b_eq = [101] 

并在linprog中传入。

pulp调包代码

import pulp #目标函数的系数 z = [2, 3, 1] #约束 a = [[1, 4, 2], [3, 2, 0]] b = [8, 6] #确定最大化最小化问题,最大化只要把Min改成Max即可 m = pulp.LpProblem(sense=pulp.LpMinimize) #定义三个变量放到列表中 x = [pulp.LpVariable(f'x{i}', lowBound=0) for i in [1,2,3]] #定义目标函数,lpDot可以将两个列表的对应位相乘再加和 #相当于z[0]*x[0]+z[1]*x[0]+z[2]*x[2] m += pulp.lpDot(z, x)  #设置约束条件 for i in range(len(a)):     m += (pulp.lpDot(a[i], x) >= b[i]) #求解 m.solve() #输出结果 print(f'优化结果:{pulp.value(m.objective)}') print(f'参数取值:{[pulp.value(var) for var in x]}')  #output: #优化结果:7.0 #参数取值:[2.0, 0.0, 3.0] 


这种情况,可以:
A_eq = [1,2,4] b_eq = 101 m += (pulp.lpDot(A_eq, x) == b_eq) 

二、运输问题

个产地、

个销地,各产地的产量分别为

,各销地的 需求量分别为

。若该商品由

产地运到

销地的单位运价为

,问应该如何调 运才能使总运费最省?

,其取值为由

产地运往

销地的该商品数量,数学模型为 :


例题:

pulp调包代码

import pulp import numpy as np from pprint import pprint  def transportation_problem(costs, x_max, y_max):      row = len(costs)     col = len(costs[0])      prob = pulp.LpProblem('Transportation Problem', sense=pulp.LpMaximize)      var = [[pulp.LpVariable(f'x{i}{j}', lowBound=0, cat=pulp.LpInteger) for j in range(col)] for i in range(row)]      flatten = lambda x: [y for l in x for y in flatten(l)] if type(x) is list else [x]      prob += pulp.lpDot(flatten(var), costs.flatten())      for i in range(row):         prob += (pulp.lpSum(var[i]) <= x_max[i])      for j in range(col):         prob += (pulp.lpSum([var[i][j] for i in range(row)]) <= y_max[j])      prob.solve()      return {'objective':pulp.value(prob.objective), 'var': [[pulp.value(var[i][j]) for j in range(col)] for i in range(row)]} 

然后构造参数传递进去:

if __name__ == '__main__':     costs = np.array([[500, 550, 630, 1000, 800, 700],                        [800, 700, 600, 950, 900, 930],                        [1000, 960, 840, 650, 600, 700],                        [1200, 1040, 980, 860, 880, 780]])      max_plant = [76, 88, 96, 40]     max_cultivation = [42, 56, 44, 39, 60, 59]     res = transportation_problem(costs, max_plant, max_cultivation)      print(f'最大值为{res["objective"]}')     print('各变量的取值为:')     pprint(res['var'])  #output: #最大值为284230.0 #各变量的取值为: #[[0.0, 0.0, 6.0, 39.0, 31.0, 0.0], # [0.0, 0.0, 0.0, 0.0, 29.0, 59.0], # [2.0, 56.0, 38.0, 0.0, 0.0, 0.0], # [40.0, 0.0, 0.0, 0.0, 0.0, 0.0]] 

三、指派问题

该问题引用自《数学建模算法与应用-司守奎》第一章线性规划 3.指派问题
调包解决方法参考https://blog.csdn.net/your_answer/article/details/79160045
可参考官网https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.linear_sum_assignment.html

项工作,没人干且仅干一项工作,若分配第

人去干第

项工作,需花费

单位时间,问应如何分配工作才能使公认花费的总时间最少?
假设指派问题的系数矩阵为:

,若分配

工作,则取

,否则取

,上述指派问题的数学模型为

调用scipy解决

import numpy as np from scipy.optimize import linear_sum_assignment 

efficiency_matrix = np.array([     [12,7,9,7,9],     [8,9,6,6,6],     [7,17,12,14,12],     [15,14,6,6,10],     [4,10,7,10,6] ])  row_index, col_index=linear_sum_assignment(efficiency_matrix) print(row_index+1) print(col_index+1) print(efficiency_matrix[row_index,col_index])  #output: #[1 2 3 4 5] #[2 3 1 4 5] #[7 6 7 6 6] 

print(efficiency_matrix[row_index, col_index].sum()) #output: # 32 

调用pulp解决

def assignment_problem(efficiency_matrix):     row = len(efficiency_matrix)     col = len(efficiency_matrix[0])      flatten = lambda x: [y for l in x for y in flatten(l)] if type(x) is list else [x]      m = pulp.LpProblem('assignment', sense=pulp.LpMinimize)     var_x = [[pulp.LpVariable(f'x{i}{j}', cat=pulp.LpBinary) for j in range(col)] for i in range(row)]      m += pulp.lpDot(efficiency_matrix.flatten(), flatten(var_x))      for i in range(row):         m += (pulp.lpDot(var_x[i], [1]*col) == 1)      for j in range(col):         m += (pulp.lpDot([var_x[i][j] for i in range(row)], [1]*row) == 1)      m.solve()      print(m)      return {'objective':pulp.value(m.objective), 'var': [[pulp.value(var_x[i][j]) for j in range(col)] for i in range(row)]} 

efficiency_matrix = np.array([     [12, 7, 9, 7, 9],     [8, 9, 6, 6, 6],     [7, 17, 12, 14, 9],     [15, 14, 6, 6, 10],     [4, 10, 7, 10, 9] ])  res = assignment_problem(efficiency_matrix) print(f'最小值{res["objective"]}') print(res['var'])  #output #最小值32.0 #[[0.0, 1.0, 0.0, 0.0, 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, 1.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0]] 

四、pulp的使用方式

基本使用

prob = pulp.LpProblem('problem name', sense=pulp.LpMinimize) 

x0 = pulp.LpVariable('x0', lowBound=0, upBound=None, cat=pulp.LpInteger) x1 = pulp.LpVariable('x1', lowBound=0, upBound=None, cat=pulp.LpInteger) x2 = pulp.LpVariable('x2', lowBound=0, upBound=None, cat=pulp.LpInteger) 


如上述代码所示,pulp.LpInteger为离散变量,pulp.LpBinary为二值变量,同时也可以传入'Integer'字符串的方式指明变量类型。从上面几个问题的代码可以看出,我几乎没有单个定义变量,而是批量定义的。

prob += 2*x0-5*x1+4*x2 


prob += (x0+x1-6*x2 <= 120) 

prob.solve() 

print(pulp.value(prob.objective)) print(pulp.value(x0)) 

打印优化结果,并显示当优化达到结果时x0的取值。

思考程序本质










https://qiita.com/SaitoTsutomu/items/bfbf4c185ed7004b5721
https://www.bilibili.com/video/av18818604?from=search&seid=17463693264345909709



作者:crossous
链接:https://www.jianshu.com/p/9be417cbfebb
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!