-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRoute.py
More file actions
206 lines (179 loc) · 6.99 KB
/
Copy pathRoute.py
File metadata and controls
206 lines (179 loc) · 6.99 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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import re
import sys
from models.Node import Node
from utils import DistanceCalculator
class Route:
def __init__(self):
self._index = -1 # Index of the route
self._nodes = [] # List of the nodes in the route
self._cost = 0.0 # Cost of the route
self._delivery_load = 0 # Delivery load
self._pickup_load = 0 # Pickup load
# Update: it's better to separate max capacities
# instead of resetting one variable because it will be useful when updating routes
self.max_linehaul_capacity = 0
self.max_backhaul_capacity = 0
def add_node(self, node):
"""
Adds the given node to the list of nodes
:param node: models.Node
:return: None
"""
assert isinstance(node, Node)
if len(self._nodes) > 0:
self.check_node(node)
self._nodes.append(node)
def check_node(self, node):
"""
According to the type of the last node,
updates the delivery/pickup load and updates the route's cost
:param node: models.Node
:return: None
"""
assert isinstance(node, Node)
if node.get_type == 'linehaul':
self._delivery_load += node.get_capacity
self.max_linehaul_capacity = self.max_linehaul_capacity - node.get_capacity
elif node.get_type == 'backhaul':
self._pickup_load += node.get_capacity
self.max_backhaul_capacity = self.max_backhaul_capacity - node.get_capacity
last_node = self._nodes[-1]
assert isinstance(last_node, Node)
self._cost += DistanceCalculator.euclidean_distance(last_node.get_coords(), node.get_coords())
self._cost = round(self._cost, 2)
def add_deposit_at_last(self):
"""
Adds the deposit node at the end of the route
:return:
"""
node = self._nodes[0]
self._nodes.append(node)
last_node = self._nodes[-1]
self._cost += DistanceCalculator.euclidean_distance(last_node.get_coords(), node.get_coords())
self._cost = round(self._cost, 2)
def add_node_at_position(self, node, position):
"""
Adds the given node at the given position and update the cost of the route
:param node:
:param position:
:return:
"""
is_valid = False
assert isinstance(position, int)
assert isinstance(node, Node)
last_node = self._nodes[position - 1]
assert isinstance(last_node, Node)
if node.get_type == 'linehaul':
if last_node.get_type == 'linehaul':
if node.get_capacity <= self.max_linehaul_capacity:
self._nodes.insert(position, node)
self._delivery_load += node.get_capacity
self.max_linehaul_capacity = self.max_linehaul_capacity - node.get_capacity
is_valid = True
else:
next_node = self._nodes[position + 1]
assert isinstance(next_node, Node)
if next_node.get_type == 'backhaul' or next_node.get_type == 'deposit':
if node.get_capacity <= self.max_backhaul_capacity:
self._nodes.insert(position, node)
self._pickup_load += node.get_capacity
self.max_backhaul_capacity = self.max_backhaul_capacity - node.get_capacity
is_valid = True
self.update_cost()
return is_valid
def delete_node_at_position(self, position):
"""
Deletes a node at the given position and updates the capacities
:param position:
:return:
"""
assert isinstance(position, int)
node = self._nodes[position]
assert isinstance(node, Node)
self._nodes.pop(position)
if node.get_type == 'linehaul':
self._delivery_load -= node.get_capacity
self.max_linehaul_capacity = self.max_linehaul_capacity + node.get_capacity
elif node.get_type == 'backhaul':
self._pickup_load -= node.get_capacity
self.max_backhaul_capacity = self.max_backhaul_capacity + node.get_capacity
self.update_cost()
return node
@property
def get_index(self):
return self._index
def set_index(self, index):
"""
Sets the index of this route
:type index: int
"""
assert isinstance(index, int)
self._index = index
@property
def get_nodes(self):
return self._nodes
@property
def get_cost(self):
return self._cost
@property
def get_delivery_load(self):
return self._delivery_load
def set_delivery_load(self, delivery_load):
self._delivery_load = delivery_load
@property
def get_pickup_load(self):
return self._pickup_load
def set_pickup_load(self, pickup_load):
self._pickup_load = pickup_load
def update_cost(self):
"""
Recalculates and updates the routes' cost
:return:
"""
cost = 0
for i in range(0, len(self._nodes) - 1):
last_node = self._nodes[i - 1]
assert isinstance(last_node, Node)
node = self._nodes[i]
assert isinstance(node, Node)
cost += DistanceCalculator.euclidean_distance(last_node.get_coords(), node.get_coords())
self._cost = round(cost, 2)
def is_route_valid(self):
seq = self.get_nodes_seq()
match = re.match(r'(L+B*){1}', seq)
if hasattr(match, 'groups'):
match_groups = match.groups()
if len(match_groups[0]) == len(seq):
return True and self.check_capacity()
return False
def check_capacity(self):
lcapacity = 0
bcapacity = 0
for n in self._nodes:
if n.get_type == 'linehaul':
lcapacity += n.get_capacity
elif n.get_type == 'backhaul':
bcapacity += n.get_capacity
if self._nodes[0].get_capacity < lcapacity or self._nodes[0].get_capacity < bcapacity:
return False
self.max_linehaul_capacity = self._nodes[0].get_capacity - lcapacity
self.max_backhaul_capacity = self._nodes[0].get_capacity - bcapacity
return True
def get_nodes_seq(self):
seq = ''
nodes = self.get_nodes
for i in range(1, len(nodes) - 1):
if bool(nodes[i].get_type == 'linehaul'):
seq += 'L'
else:
seq += 'B'
return seq
def __repr__(self):
return "\n{ " \
"\nindex: " + str(self.get_index) + ", " + \
"\nnodes: " + str(self.get_nodes) + ", " + \
"\nmax_linehaul_capacity: " + str(self.max_linehaul_capacity) + ", " + \
"\nmax_backhaul_capacity: " + str(self.max_backhaul_capacity) + ", " + \
"\ndelivery_load: " + str(self._delivery_load) + "," + \
"\npickup_load: " + str(self._pickup_load) + "," + \
"\ncost: " + str(self.get_cost) + "}"