问题描述
假设某产品的生产线由5道工序,3个工作站,3个工人组成。工序之间的优先关系如图1所示。
图1 工序优先关系图
不同员工加工各个工序的时间各不相同,分别如表1,2,3所示。求解最佳的工序分配方案与人员指派方案,使得目标函数取得最小值。
表1 员工1在各工作站加工各工序所用时间
1 | 2 | 3 | |
1 | 14.87 | 21.29 | 18.89 |
2 | 19.78 | 11.58 | 13.36 |
3 | 22.89 | 15.35 | 22.70 |
4 | 19.35 | 15.31 | 10.49 |
5 | 21.93 | 16.29 | 12.76 |
表2 员工2在各工作站加工各工序所用时间
1 | 2 | 3 | |
1 | 13.82 | 20.77 | 20.75 |
2 | 18.98 | 11.18 | 11.63 |
3 | 20.64 | 15.29 | 21.91 |
4 | 17.29 | 14.62 | 10.66 |
5 | 21.84 | 16.03 | 10.87 |
表3 员工3在各工作站加工各工序所用时间
1 | 2 | 3 | |
1 | 15.79 | 22.90 | 19.60 |
2 | 18.48 | 12.45 | 11.35 |
3 | 22.16 | 17.51 | 22.58 |
4 | 19.16 | 14.61 | 12.25 |
5 | 20.34 | 17.80 | 10.17 |
符号说明
数学建模
思路1:用变量A代表工人与工位之间的指派关系,用变量X代表工序与工位之间的分配关系。问题可描述为:
其中c为系数矩阵,A、X都是决策变量所组成的矩阵,并且其取值都是0或1。
不知道其属于哪种规划问题,首先考虑采用benders分解方法求解,但是benders分解所适用的形式是类似于这种形式的问题。
其次用固定一个变量,求解另一个变量,再固定另一个,反过来求解这一个变量并不断循环的思路进行优化。(但是结果可能有问题)。
思路2:用一个变量,既能表示工序与工位的分配关系,又能表示工人与工位的指派关系。问题的模型可以简化为一个线性规划问题。
约束为:
优化求解
思路一:
# 通过固定一个变量,求解另一个变量的思想进行优化。轮流对A和X进行优化
import gurobipy as gp
from gurobipy import GRB
import numpy as np
import math
import pandas as pd
import matplotlib.pyplot as plt
Index_works=10
Stations=10
Works=10
a=np.ones((Index_works,Stations))
e=np.random.rand(Index_works,Stations)#随机生成的系数
# e=np.array([[0.36732504, 0.59868139, 0.52340548, 0.89953054],
# [0.58727324, 0.44467678, 0.50980262, 0.56266788],
# [0.3325161, 0.12459947, 0.99864395, 0.9913541 ],
# [0.80171981, 0.37986221, 0.89358609, 0.66410582],])
# 固定a求解x的一阶段问题
def FSP(a):
m1 = gp.Model("first-stage")
X_is = m1.addMVar((Index_works,Stations),vtype=GRB.BINARY,name='X')
obj = a@X_is@e
m1.setObjective(obj.sum(), GRB.MINIMIZE)
for index_work in range(Index_works):
m1.addConstr(X_is[index_work,:].sum()==1,name="row"+str(index_work))
for station in range(Stations):
m1.addConstr(X_is[:,station].sum()==1,name="col"+str(station))
m1.addConstr(X_is[1,1]==0,name="col"+str(station))
m1.addConstr(X_is[0,0]==1,name="col"+str(station))
m1.update()
m1.setParam('OutputFlag',0)
m1.Params.InfUnbdInfo = 1
m1.optimize()
if m1.Status == 5: # model is unbounded
print('wujie')
if m1.Status == 2: # model is optimal
obj = m1.objVal
x_list = [X_is.X[i,j] for i in range(Index_works) for j in range(Stations)]
x_array = np.array(x_list, dtype = int)
return m1.Status,obj,x_array.reshape(Index_works,Stations)
# 固定x,求解a的二阶段问题
def SSP(x):
m2 = gp.Model("second-stage")
A_sw = m2.addMVar((Stations,Works),vtype=GRB.BINARY,name='A')
obj2 = A_sw@x@e
m2.setObjective(obj2.sum(), GRB.MINIMIZE)
for work in range(Works):
m2.addConstr(A_sw[work,:].sum()==1,name="row"+str(work))
for station in range(Stations):
m2.addConstr(A_sw[:,station].sum()==1,name="col"+str(station))
m2.addConstr(A_sw[1,1]==1,name="col"+str(station))
m2.addConstr(A_sw[0,0]==1,name="col"+str(station))
m2.update()
m2.setParam('OutputFlag',0)
m2.Params.InfUnbdInfo = 1
m2.optimize()
if m2.Status == 5: # model is unbounded
print('wujie')
if m2.Status == 2: # model is optimal
obj = m2.objVal
A_list = [A_sw.X[i,j] for i in range(Stations) for j in range(Works)]
A_array = np.array(A_list, dtype = int)
return m2.Status,obj,A_array.reshape(Stations,Works)
data=[]
for i in range(10):
a1=FSP(a)[2]
b1=FSP(a)[1]
a2=SSP(a1)[2]
b2=SSP(a1)[1]
a=a2
# print(b1,b2)
data.append(b1)
plt.plot(data)
plt.show()
思路二求解结果:
import gurobipy as gp
from gurobipy import GRB
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import networkx as nx
G=nx.DiGraph() #创建什么都没有的空图
Index_works=5
Stations=3
Workers=3
A=np.array([[0,1,1,0,0],[0,0,0,1,0],[0,0,0,0,1],[0,0,0,0,1],[0,0,0,0,0]])#优先关系
relation = np.argwhere(A==1)+1
num_relation = np.size(relation,0)#优先关系有几组
# start=[relation[i][0] for i in range(num_relation)]#边的起点列表
# to=[relation[i][1] for i in range(num_relation)]#边的终点列表
# for j in range(len(start)):
# G.add_edge(start[j], to[j])
# # pos = [(i+1,i) for i in range(num_relation)]
# nx.draw(G,with_labels=True)
# plt.show()
T=np.array([[[14.87,21.29,18.89],
[19.78,11.58,13.36],
[22.89,15.35,22.70],
[19.35,15.31,10.49],
[21.93,16.29,12.76]],
[[13.82,20.77,20.75],
[18.98,11.18,11.63],
[20.64,15.29,21.91],
[17.29,14.62,10.66],
[21.84,16.03,10.87]],
[[15.79,22.90,19.60],
[18.48,12.45,11.35],
[22.16,17.51,22.58],
[19.16,14.61,12.25],
[20.34,17.80,10.17]]])#时间矩阵
m = gp.Model()
X_isw = m.addMVar((Workers,Index_works,Stations),vtype=GRB.BINARY,name='X')
res = np.multiply(T, X_isw)
obj1 = res.sum().sum()
m.setObjective(obj1,GRB.MINIMIZE)
#约束1:保证每个工作只有一个工作站来做
for index_work in range(Index_works):
m.addConstr(X_isw[:,index_work,:].sum()>=1,name='cons1_%d'%(index_work))
# 一个工人指派给一个工作站==>每个表只有一列大于0==>每张表的和大于1同时小于等于Index_works-Workers+1
for worker in range(Workers):
m.addConstr(X_isw[worker,:,:].sum()<=Index_works-Workers+1,name='cons2_%d'%(worker))
m.addConstr(X_isw[worker,:,:].sum()>=1,name='cons3_%d'%(worker))
#每个工作站都要有工作
for station in range(Stations):
m.addConstr(X_isw[:,:,station].sum()>=1,name='cons4_%d'%(station))
# 约束2:保障工序间的优先关系
# for worker in range(Workers):
# for i in range(num_relation):
# for station in range(Stations):
# a=(station+1)*X_isw[worker,relation[i][0]-1,station]
# b=(station+1)*X_isw[worker,relation[i][1]-1,station]
# m.addConstr(a<=b,name='cons5_%d_%d_%d'%(worker,i,station))
# 约束3:保障每个工作站都不超过生产节拍
for station in range(Stations):
m.addConstr(res[:,:,station].sum()<=300,name='cons2_%d'%(station))
m.update()
m.setParam('OutputFlag',0)
m.Params.InfUnbdInfo = 1
m.optimize()
m.write('model1.lp')
if m.Status == 5: # model is unbounded
print('无界解')
if m.Status == 2: # model is optimal
print('求得该问题最优解为:')
obj = m.objVal
print(obj)
x_list = [X_isw.X[i,j,k] for i in range(Stations) for j in range(Index_works)for k in range(Workers)]
x_array = np.array(x_list, dtype = int)
result = x_array.reshape(Workers,Index_works,Stations)
ans = []
index = ['工序'+str(i+1) for i in range(Index_works)]
columns = ['工位'+str(i+1) for i in range(Stations)]
for worker in range(Workers):
ans.append(pd.DataFrame(result[worker],index=index,columns=columns))
print('工人'+str(worker+1)+'分配情况:')
print(ans[worker])
elif m.Status == 3:
print('无解')
else:
print('出现其他情况')
输出结果为:其输出结果所代表的含义为工人1在工位3上加工工序1,2。
求得该问题最优解为:
3801.35
工人1分配情况:
工位1 工位2 工位3
工序1 0 0 1
工序2 0 0 1
工序3 0 0 0
工序4 0 0 0
工序5 0 0 0
工人2分配情况:
工位1 工位2 工位3
工序1 0 0 0
工序2 0 0 0
工序3 0 0 0
工序4 0 1 0
工序5 0 0 0
工人3分配情况:
工位1 工位2 工位3
工序1 0 0 0
工序2 0 0 0
工序3 1 0 0
工序4 0 0 0
工序5 1 0 0