-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpopulation.py
154 lines (108 loc) · 3.72 KB
/
population.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
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
from graph import Graph, Node, DistanceMatrix
from greedy import solve_greedy
from typing import List
import random
import copy
# Individual = Tour
class Tour:
def __init__(self, is_random=False, path=None):
assert Graph.num_nodes > 0
self.distance = 0
self.id_to_position = {}
if path and len(path) == Graph.num_nodes:
if type(path[0]) == int:
path = list(map(lambda id: Graph.get_node(id), path))
if is_random:
path = copy.deepcopy(Graph.nodes)
random.shuffle(path)
if path == None:
self.path = [None] * Graph.num_nodes
return
for i in range(Graph.num_nodes):
self.id_to_position[path[i].id] = i
prev_node = path[0]
for node in path[1:] + path[:1]:
self.distance += Graph.distance_matrix.get_distance(
node, prev_node)
prev_node = node
self.path = path
def __len__(self):
return Graph.num_nodes
def __repr__(self):
return str(self._path_to_id(self.path))
def add_node(self, index, node):
if index >= Graph.num_nodes:
index -= Graph.num_nodes
self.path[index] = node
self.id_to_position[node.id] = index
def get_node(self, index):
if index >= Graph.num_nodes:
index -= Graph.num_nodes
return self.path[index]
def contains_node(self, n2):
for n1 in self.path:
if n1 == None:
continue
if n1.id == n2.id:
return True
return False
def update_distance(self):
self.distance = 0
prev_node = self.path[0]
for node in self.path[1:] + self.path[:1]:
self.distance += Graph.distance_matrix.get_distance(
node, prev_node)
prev_node = node
def _path_to_id(self, path):
return list(map(lambda node: node.id if node != None else -1, path))
class Population:
def __init__(self, population_size: int = 0, tours=[]):
self.tours = []
if len(tours) == population_size:
self.tours = tours
else:
for _ in range(population_size):
# generate initial individuals
random_tour = Tour(is_random=True)
self.tours.append(random_tour)
assert len(self.tours) == population_size
def __len__(self):
return len(self.tours)
def __iter__(self):
self.index = -1
return self
def __next__(self):
if self.index + 1 >= len(self.tours):
raise StopIteration
else:
self.index += 1
return self.tours[self.index]
def append_tour(self, tour: Tour):
self.tours.append(tour)
def remove_tour(self, tour: Tour):
self.tours.remove(tour)
def get_tour(self, index: int):
if index < 0 or index >= len(self.tours):
return
return self.tours[index]
def get_fittest(self) -> Tour:
min_distance = float('inf')
best_tour = None
for tour in self.tours:
if tour.distance < min_distance:
min_distance = tour.distance
best_tour = tour
assert best_tour != None
return best_tour
def get_rank_probability(self, s) -> List[Tour]:
assert 1 <= s <= 2
# rank based selection probability
sorted_tour = sorted(enumerate(self.tours),
key=lambda t: t[1].distance)
mu = len(self)
P = [0] * mu
for i in range(mu):
index = sorted_tour[i][0]
P[index] = ((2 - s) / mu) \
+ (i * (s - 1) / sum(range(mu)))
return P