-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcolumnGen.py
More file actions
161 lines (135 loc) · 6.75 KB
/
columnGen.py
File metadata and controls
161 lines (135 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import gurobipy as gp
from gurobipy import GRB
from paramsVRP import ParamsVRP
from route import Route
from SPPRC import SPPRC
import numpy as np
class ColumnGeneration:
def __init__(self, user_param):
self.paramsVRP = user_param
self.routes = []
def compute_col_gen(self, initial_routes):
"""
执行列生成算法。
:param initial_routes: 初始路径列表
:return: 最优目标值
"""
#try:
# 初始化 Gurobi 模型
model = gp.Model("Column Generation")
model.setParam("OutputFlag", 0)
model.setParam("LogToConsole", 0)
# 添加初始路径
for route in initial_routes:
cost = sum(self.paramsVRP.dist[route.path[i]][route.path[i + 1]] for i in range(len(route.path) - 1))
route.set_cost(cost)
self.routes.append(route)
# 创建变量和目标函数
y = model.addVars(len(self.routes), vtype=GRB.CONTINUOUS, name="y", lb=0.0)
# 添加约束:每个客户必须被服务一次
constraints = model.addConstrs(
(gp.quicksum(y[i] for i, route in enumerate(self.routes) if client in route.path[1:-1]) >= 1
for client in range(1, self.paramsVRP.nbclients - 1)),
"ClientService"
)
model.update()
#print(constraints)
# 设置目标函数
model.setObjective(gp.quicksum(y[i] * self.routes[i].cost for i in range(len(self.routes))), GRB.MINIMIZE)
# 列生成主循环
iteration = 0
while True:
# 求解当前模型
model.optimize()
if model.status == GRB.OPTIMAL:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Objective = {model.objVal}")
elif model.status == GRB.INFEASIBLE:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Model is infeasible.")
elif model.status == GRB.UNBOUNDED:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Model is unbounded.")
else:
print(
f"[-----ColumnGeneration-----]Iteration {iteration}: Model not solved. Status = {model.status}")
objectiveFunc = model.getObjective()
'''
print(f"Model Objective Function: {objectiveFunc}")
constraints_ = model.getConstrs()
for i, constr in enumerate(constraints_):
print(f"Constraint {i}: {constr.ConstrName} with Linear Expression: {model.getRow(constr)} {constr.Sense} {constr.RHS}")
'''
#print(f"y = {y}")
# 获取对偶价格
pi = [constr.Pi for constr in constraints.values()]
#print(f"Iteration {iteration}: Objective = {model.objVal}, Pi = {pi}")
# 更新 SPPRC 的成本矩阵
for i in range(1, self.paramsVRP.nbclients - 1):
for j in range(self.paramsVRP.nbclients):
self.paramsVRP.cost[i][j] = self.paramsVRP.dist[i][j] - pi[i - 1]
if self.paramsVRP.cost[i][j] < 0:
#print(f"Negative cost found: {self.paramsVRP.cost[i][j]} at {i}, {j}")
pass
# 求解 SPPRC 获取新的列
sp = SPPRC(self.paramsVRP)
new_routes = []
sp.shortestPath(self.paramsVRP, new_routes, self.paramsVRP.nbclients - 2)
print(new_routes)
# 检查是否有新的负成本路径
if not new_routes:
print("[-]No new negative cost paths found.")
# 检查模型状态
if model.status == GRB.OPTIMAL:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Objective = {model.objVal}")
elif model.status == GRB.INFEASIBLE:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Model is infeasible.")
elif model.status == GRB.UNBOUNDED:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Model is unbounded.")
else:
print(
f"[-----ColumnGeneration-----]Iteration {iteration}: Model not solved. Status = {model.status}")
break
# 添加新的路径到模型
for new_route in new_routes:
cost = sum(self.paramsVRP.dist[new_route.path[i]][new_route.path[i + 1]] for i in range(len(new_route.path) - 1))
new_route.set_cost(cost)
self.routes.append(new_route)
# 获取模型中的所有变量
vars_to_remove = model.getVars()
for var in vars_to_remove:
model.remove(var)
constrs_to_remove = model.getConstrs()
for constr in constrs_to_remove:
model.remove(constr)
# 创建变量和目标函数
y = model.addVars(len(self.routes), vtype=GRB.CONTINUOUS, name="y", lb=0.0)
# 添加约束:每个客户必须被服务一次
constraints = model.addConstrs(
(gp.quicksum(y[i] for i, route in enumerate(self.routes) if client in route.path[1:-1]) >= 1
for client in range(1, self.paramsVRP.nbclients - 1)),
"ClientService"
)
model.setObjective(gp.quicksum(y[i] * self.routes[i].cost for i in range(len(self.routes))), GRB.MINIMIZE)
model.update()
iteration += 1
'''
# 检查模型状态
if model.status == GRB.OPTIMAL:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Objective = {model.objVal}")
elif model.status == GRB.INFEASIBLE:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Model is infeasible.")
elif model.status == GRB.UNBOUNDED:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Model is unbounded.")
else:
print(f"[-----ColumnGeneration-----]Iteration {iteration}: Model not solved. Status = {model.status}")
'''
# 输出最终结果
for i, route in enumerate(self.routes):
route.set_Q(y[i].x)
if route.Q > 0:
print(f"Route {i}: Cost = {route.cost}, Q = {route.Q}, Path = {route.path}")
return model.objVal, self.routes
'''
except gp.GurobiError as e:
print(f"Gurobi Error: {e}")
except Exception as e:
print(f"Error in compute_col_gen: {e}")
'''