Python 使用 Gurobi 求解车辆路径问题 (CVRP) 优化代码示例
以下 Python 代码使用 Gurobi 库解决车辆路径问题 (CVRP),并提供了一些优化建议以提高内存效率:
from gurobipy import *
import numpy as np
def createDataSet(): # 创建数据集
rdn1 = np.random.RandomState(1)
points = []
i = 0
while True:
x = round(rdn1.uniform(0, 100), 1)
y = round(rdn1.uniform(0, 100), 1)
if 45 <= x <= 55 and 45 <= y <= 55:
continue
points.append((x, y))
i += 1
if i == 100:
break
rdn3 = np.random.RandomState(2)
demand = rdn3.randint(2, 11, 30) # 需求
return points, demand
vehicleNum = 50
clients, demand = createDataSet()
n_customers = len(clients)
vehicle_fixed_cost = 300 # 固定成本
vehicle_travel_cost = 1.5 # 行驶成本
vehicle_working_time_limit = 480 # 工作时间限制 min
vehicle_capacity_limit = 60 # 车辆容量限制
drive_speed = 0.75 # 车辆行驶速度 km/min
serive_speed = 2.5 # 实际单位货物服务速度 min
depot = [(50, 50)] # 0
positions = depot + clients
disMatrix = [[0] * (n_customers + 1) for _ in range(n_customers + 1)]
for i in range(n_customers + 1):
for j in range(i + 1, n_customers + 1):
d = round(((positions[i][0] - positions[j][0]) ** 2 + (positions[i][1] - positions[j][1]) ** 2) ** 0.5, 4)
disMatrix[i][j] = disMatrix[j][i] = d # 保留 4 位
BigM = 100000
model = Model('CVRP')
x = {}
y = {}
s = {}
# 定义决策变量
for i in range(n_customers + 1):
for k in range(vehicleNum):
name = 'y_' + str(i) + '_' + str(k)
if i != 0:
y[i, k] = model.addVar(lb=0, ub=1,
vtype=GRB.BINARY,
name=name)
for j in range(n_customers + 1):
if (i != j):
name = 'x_' + str(i) + '_' + str(j) + '_' + str(k)
x[i, j, k] = model.addVar(lb=0, ub=1,
vtype=GRB.BINARY,
name=name)
for i in range(n_customers + 1):
for k in range(vehicleNum):
name = 's_' + str(i) + '_' + str(k)
s[i, k] = model.addVar(lb=0, ub=vehicle_working_time_limit,
vtype=GRB.CONTINUOUS,
name=name) # 访问时间
# 定义目标函数
obj1 = LinExpr(0)
obj2 = LinExpr(0)
for i in range(n_customers + 1):
for k in range(vehicleNum):
for j in range(n_customers + 1):
if (i != j):
obj1.addTerms(vehicle_travel_cost * disMatrix[i][j], x[i, j, k]) # 第一项为系数
for k in range(vehicleNum):
for j in range(n_customers + 1):
if (j != 0):
obj2.addTerms(vehicle_fixed_cost, x[0, j, k])
model.setObjective(obj1 + obj2, GRB.MINIMIZE)
# 定义约束一 需求
model.addConstrs(quicksum(y[i, k] for k in range(vehicleNum)) == 1 for i in range(1, n_customers + 1))
# 定义约束二 流平衡
for k in range(vehicleNum):
for h in range(1, n_customers + 1):
expr1 = LinExpr(0)
expr2 = LinExpr(0)
for i in range(n_customers + 1):
if (h != i):
expr1.addTerms(1, x[i, h, k])
for j in range(n_customers + 1):
if (h != j):
expr2.addTerms(1, x[h, j, k])
model.addConstr(expr1 == expr2, name='flow_conservation_' + str(i))
expr1.clear()
expr2.clear()
# 定义约束三 车辆数量
# model.addConstr( quicksum( x[0,j,k] for j in range(1,n_customers+1)) == quicksum( x[j,0,k] for j in range(1,n_customers+1)) for k in range(vehicleNum) )
# model.addConstr( quicksum( x[0,j,k] for j in range(1,n_customers+1) ) <=1 for k in range(vehicleNum) )
for k in range(vehicleNum):
expr3 = LinExpr(0)
expr4 = LinExpr(0)
for j in range(1, n_customers + 1):
expr3.addTerms(1, x[0, j, k])
expr4.addTerms(1, x[j, 0, k])
model.addConstr(expr3 == expr4)
for k in range(vehicleNum):
expr5 = LinExpr(0)
for j in range(1, n_customers + 1):
expr5.addTerms(1, x[0, j, k])
model.addConstr(expr5 <= 1)
# 定义约束四 决策变量关联
for k in range(vehicleNum):
for j in range(1, n_customers + 1):
model.addConstrs(quicksum(x[i, j, k] for i in range(n_customers + 1) if i != j) == y[j, k])
for k in range(vehicleNum):
for i in range(1, n_customers + 1):
model.addConstrs(quicksum(x[i, j, k] for j in range(n_customers + 1) if i != j) == y[i, k])
## 容量约束
model.addConstrs(quicksum(demand[i] * y[i, k] for i in range(1, n_customers + 1)) <= vehicle_capacity_limit for k in range(vehicleNum))
# 时间约束
for k in range(vehicleNum):
for i in range(n_customers + 1):
for j in range(n_customers + 1):
if (i != j):
model.addConstr(s[i, k] + disMatrix[i][j] * drive_speed + demand[i] * serive_speed - s[j, k]
- BigM + BigM * x[i, j, k] <= 0)
model.addConstr(s[0, k] == 0 for k in range(vehicleNum))
# 返回时间约束
model.addConstr(quicksum((s[i, k] + demand[i] * serive_speed + disMatrix[i][0] * drive_speed) * x[i, 0, k] for i in range(1, n_customers + 1)) <= vehicle_working_time_limit for k in range(vehicleNum))
model.Params.TimeLimit = 600 # 设置求解时间上限
# 求解
model.optimize()
# 打印结果
print("
-----optimal value-----")
print(model.ObjVal)
for key in x.keys():
if (x[key].x > 0):
print(x[key].VarName + ' = ', x[key].x)
代码优化建议
- 内存泄漏问题:由于循环中不断创建变量,没有及时清除,可能导致内存泄漏。建议在每次循环结束时,手动清除相关变量的内存,例如使用
del语句删除不再需要的变量。 - 更高效的数据结构:可以使用 numpy 数组来存储模型中的参数和变量,以提高内存效率和代码可读性。
例如:
# 使用 numpy 数组存储距离矩阵
disMatrix = np.zeros((n_customers + 1, n_customers + 1))
for i in range(n_customers + 1):
for j in range(i + 1, n_customers + 1):
d = round(((positions[i][0] - positions[j][0]) ** 2 + (positions[i][1] - positions[j][1]) ** 2) ** 0.5, 4)
disMatrix[i][j] = disMatrix[j][i] = d
# 使用 numpy 数组存储决策变量
x = np.zeros((n_customers + 1, n_customers + 1, vehicleNum))
通过以上优化建议,可以提高代码的内存效率,避免出现 "out of memory" 错误。
注意:
- Gurobi 库需要单独安装。
- 代码中的参数可以根据实际情况进行调整。
- 以上优化建议仅供参考,具体实现需要根据实际情况进行调整。
原文地址: https://www.cveoy.top/t/topic/n5tS 著作权归作者所有。请勿转载和采集!