-
Notifications
You must be signed in to change notification settings - Fork 1
/
core.py
103 lines (83 loc) · 3.53 KB
/
core.py
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
import numpy as np
from gurobipy import GRB, Model, quicksum
def solve_VRPTW(
coordinate: np.ndarray,
time_window: np.ndarray,
demand: np.ndarray,
service_duration: np.ndarray,
vehicle_quantity: int,
vehicle_capacity: float,
cost_per_distance: float,
time_per_distance: float,
big_m: float,
timelimit: float
):
"""
node quantity = customer quantity + 2 = n + 2
the starting depot is node 0 and the ending depot is node n + 1
time window for node 0 should be [0, 0] and for node n + 1 should be [0, max operating time]
return: is_feasible, objective value, arc matrix, arrival time matrix
"""
# define sets
node_quantity = coordinate.shape[0]
customer_quantity = node_quantity - 2
N = range(node_quantity)
C = range(1, customer_quantity + 1)
V = range(vehicle_quantity)
# calculate traveling distance and time from node to node
distance = np.zeros([node_quantity, node_quantity])
for i in N:
for j in N:
if i == j:
distance[i, j] = big_m
else:
distance[i, j] = np.hypot(coordinate[i, 0] - coordinate[j, 0], coordinate[i, 1] - coordinate[j, 1])
travel_time = np.zeros([node_quantity, node_quantity])
for i in N:
for j in N:
travel_time[i, j] = time_per_distance * np.hypot(coordinate[i, 0] - coordinate[j, 0], coordinate[i, 1] - coordinate[j, 1])
# writing mathematical formulation in code
model = Model("VRPTW")
x = model.addVars(node_quantity, node_quantity, vehicle_quantity, vtype=GRB.BINARY)
s = model.addVars(node_quantity, vehicle_quantity, vtype=GRB.CONTINUOUS)
model.modelSense = GRB.MINIMIZE
model.setObjective(quicksum(x[i, j, k] * distance[i, j] * cost_per_distance for i in N for j in N for k in V))
model.addConstrs(quicksum(x[i, j, k] for j in N for k in V) == 1 for i in C)
model.addConstrs(quicksum(x[0, j, k] for j in N) == 1 for k in V)
model.addConstrs(quicksum(x[i, customer_quantity + 1, k] for i in N) == 1 for k in V)
model.addConstrs(quicksum(x[i, h, k] for i in N) - quicksum(x[h, j, k] for j in N) == 0 for h in C for k in V)
model.addConstrs(quicksum(demand[i] * quicksum(x[i, j, k] for j in N) for i in C) <= vehicle_capacity for k in V)
model.addConstrs(s[i, k] >= time_window[i, 0] for i in N for k in V)
model.addConstrs(s[i, k] <= time_window[i, 1] for i in N for k in V)
model.addConstrs(s[i, k] + travel_time[i, j] + service_duration[i] - big_m * (1 - x[i, j, k]) <= s[j, k] for i in N for j in N for k in V)
# set timelimit and start solving
model.Params.Timelimit = timelimit
model.optimize()
# obtain the results
is_feasible = True
obj = 0
runtime = model.Runtime
mip_gap = GRB.INFINITY
result_arc = np.zeros([vehicle_quantity, node_quantity, node_quantity], dtype=int)
result_arrival_time = np.zeros([node_quantity, vehicle_quantity])
for k in V:
for i in N:
for j in N:
try:
result_arc[k, i, j] = round(x[i, j, k].X)
except:
is_feasible = False
break
for k in V:
for i in N:
try:
result_arrival_time[i, k] = s[i, k].X
except:
is_feasible = False
break
try:
obj = model.getObjective().getValue()
mip_gap = model.MIPGap
except:
is_feasible = False
return is_feasible, obj, result_arc, result_arrival_time, runtime, mip_gap