有关 gurobi
的使用可以参考官方手册( Gurobi
安装路径 \win64\docs
下的 quickstart_windows.pdf
和 refman.pdf
)
# 一、一些使用技巧
# 1.1 gurobi 无穷大值
参考 refman.pdf
的 13.2
中的 FeasRelaxBigM
和 29.3
中的 Dealing with big-M constraints
# 1.2 gurobi 最大值
在模型中遇到如下所示求最小化数组中最大值的目标函数
可构造辅助变量,令改变量大于数组中的所有分量,最后对辅助变量进行最大 / 最小化
obj1 = m.addVar(vtype=GRB.CONTINUOUS, name='obj1') | |
m.addConstrs(obj1 >= tH[i] + Th * z.sum(axis=1).sum(axis=1)[i] for i in range(n_pod)) | |
m.setObjective(obj1, GRB.MINIMIZE) |
# 二、成功使用案例
from parameter import * | |
import gurobipy as gp | |
from gurobipy import GRB | |
import numpy as np | |
if __name__ == "__main__": | |
# Create optimization model | |
m = gp.Model('RMFS') | |
# Create variables | |
x = m.addMVar((n_pod, n_robot, n_pod), vtype=GRB.BINARY, name="x") # 货架 i 是机器人 r 第 k 个转运的任务(0,1 变量) | |
y = m.addMVar((n_pod, n_pod), vtype=GRB.BINARY, name="y") # 货架 i 是拣货人第 k 个处理的货架(0,1 变量) | |
z = m.addMVar((n_pod, n_order, n_commodity_type), vtype=GRB.INTEGER, name="z") # 货架 i 为订单 o 提供的商品 c 的数量(自然数) | |
tP = m.addVars(n_pod, vtype=GRB.CONTINUOUS, name="tP") # 货架 i 被机器人拿起的时间,-1 表示未搬运货架 | |
tD = m.addVars(n_pod, vtype=GRB.CONTINUOUS, name="tD") # 货架 i 被机器人放下的时间,-1 表示未搬运货架 | |
tH = m.addVars(n_pod, vtype=GRB.CONTINUOUS, name="tH") # 货架 i 被拣货人开始拣货的时间,-1 表示未搬运货架 | |
# Create auxiliary variable | |
obj1 = m.addVar(vtype=GRB.CONTINUOUS, name='obj1') | |
m.setParam(GRB.Param.FeasRelaxBigM, max(Td) * n_pod) | |
# Set objective | |
m.addConstrs(obj1 >= tH[i] + Th * z.sum(axis=1).sum(axis=1)[i] for i in range(n_pod)) | |
m.setObjective(obj1, GRB.MINIMIZE) | |
# Add constraint | |
# 1. 每个货架提供给所有订单的每种商品不超过其所包含的该商品的数量 | |
m.addConstrs(z.sum(axis=1)[i, j] <= np.array(A)[i, j] for i in range(n_pod) for j in range(n_commodity_type)) | |
# 2. 所有货架提供给某一订单的某种商品数等于该订单所需求的该种商品的数量 | |
m.addConstrs(z.sum(axis=0)[i, j] == np.array(B)[i, j] for i in range(n_order) for j in range(n_commodity_type)) | |
# 3. 每个货架最多被安排给一个转运机器人的一个顺序号 | |
m.addConstrs(x.sum(axis=1).sum(axis=1)[i] <= 1 for i in range(n_pod)) | |
# 4. 每个机器人的每个顺序号最多安排一个货架 | |
m.addConstrs(x.sum(axis=0)[i, j] <= 1 for i in range(n_robot) for j in range(n_pod)) | |
# 5. 若机器人的后序顺序号被安排了一个货架,则其前序顺序号一定被安排了一个货架 | |
m.addConstrs(x.sum(axis=0)[i, j] >= x.sum(axis=0)[i, j + 1] for j in range(n_pod - 1) for i in range(n_robot)) | |
# 6. 若某一货架为订单提供了商品,则必须为该货架安排一个转运机器人 | |
m.addConstrs(total_order * x.sum(axis=1).sum(axis=1)[i] >= z.sum(axis=1).sum(axis=1)[i] for i in range(n_pod)) | |
# 7. 某一货架被机器人放下的时间等于其被拿起的时间与转运时间之和 | |
m.addConstrs(tD[i] == tP[i] + np.array(Td)[i] for i in range(n_pod)) | |
# 8. 机器人拿起下一货架的时间不小于机器人放下上一货架和运行至下一货架的时间和 | |
m.addConstrs(tP[i2] >= tD[i1] + Tp[i2] + (x[i1, j, k] + x[i2, j, k + 1] - 2) * m.Params.FeasRelaxBigM for i1 in range(n_pod) for i2 in | |
range(n_pod) for j in range(n_robot) for k in range(n_pod - 1)) | |
# 9. 每个货架最多被安排给一个拣货顺序号 | |
m.addConstrs(y.sum(axis=0)[i] <= 1 for i in range(n_pod)) | |
# 10. 每个拣货顺序号最多安排一个货架 | |
m.addConstrs(y.sum(axis=1)[i] <= 1 for i in range(n_pod)) | |
# 11. 当前拣货顺序号被安排了一个货架,则其前序拣货顺序号一定被安排了一个货架 | |
m.addConstrs(y.sum(axis=0)[i] >= y.sum(axis=0)[i + 1] for i in range(n_pod - 1)) | |
# 12. 若货架被分配了一个转运机器人,则一定为其安排了拣货 | |
m.addConstrs(y.sum(axis=1)[i] == x.sum(axis=1).sum(axis=1)[i] for i in range(n_pod)) | |
# 13. 货架的拣货时间不早于其被机器人送到拣货站的时间 | |
m.addConstrs(tH[i] >= tD[i] for i in range(n_pod)) | |
# 14. 拣货人拣取下一货架的时间不小于拣货人开始拣取上一货架和拣取上一货架的时间和 | |
m.addConstrs(tH[i2] >= tH[i1] + Th * z.sum(axis=1).sum(axis=1)[i1] + (y[i1, j] + y[i2, j + 1] - 2) * m.Params.FeasRelaxBigM for j in | |
range(n_pod - 1) for i2 in range(n_pod) for i1 in range(n_pod)) | |
# 15. 机器人拿起的第一个货架等于机器人空载运行到该货架的时间 | |
m.addConstrs(tP[i] >= Tp[i] + (x[i, j, 0] - 1) * m.Params.FeasRelaxBigM for j in range(n_robot) for i in range(n_pod)) | |
# Optimize model | |
m.optimize() | |
for v in m.getVars(): | |
print('%s %g' % (v.VarName, v.X)) | |
print('Obj: %g' % m.ObjVal) |