19
19
TOTAL_GENERATIONS = 100
20
20
21
21
22
- def readinp (filename ) :
22
+ def readinp (filename : str ) -> tsplib95 . models . Problem :
23
23
"""
24
24
Loads the Traveling Salesman Problem (TSP) from the provided file using
25
25
the tsplib95 package. This file should follow the .tsp format and contain
@@ -39,7 +39,7 @@ def readinp(filename):
39
39
return problem
40
40
41
41
42
- def fitness (mem , dist_mat ) :
42
+ def fitness (mem : list [ int ] , dist_mat : np . ndarray ) -> float :
43
43
"""
44
44
Calculates the fitness of a given solution (tour). The fitness is the
45
45
inverse of the total distance of the tour. A shorter distance results in
@@ -66,7 +66,9 @@ def fitness(mem, dist_mat):
66
66
return fitness
67
67
68
68
69
- def binary_tournament_selection (popln , dist_mat ):
69
+ def binary_tournament_selection (
70
+ popln : list [list [int ]], dist_mat : np .ndarray
71
+ ) -> tuple [list [int ], list [int ]]:
70
72
"""
71
73
Selects two parents from the population using binary tournament selection.
72
74
Two individuals are randomly chosen, and the one with higher fitness is
@@ -86,7 +88,7 @@ def binary_tournament_selection(popln, dist_mat):
86
88
>>> p1 in popln and p2 in popln
87
89
True
88
90
"""
89
- select = []
91
+ select : list [ list [ int ]] = []
90
92
while len (select ) != 2 :
91
93
i , j = random .sample (range (len (popln )), 2 ) # Randomly select two individuals
92
94
if fitness (popln [i ], dist_mat ) > fitness (popln [j ], dist_mat ):
@@ -96,7 +98,9 @@ def binary_tournament_selection(popln, dist_mat):
96
98
return select [0 ], select [1 ]
97
99
98
100
99
- def order_crossover (p1 , p2 , crossover_prob ):
101
+ def order_crossover (
102
+ p1 : list [int ], p2 : list [int ], crossover_prob : float
103
+ ) -> tuple [list [int ], list [int ]]:
100
104
"""
101
105
Applies order crossover (OX) between two parent solutions with a certain
102
106
probability. The OX method ensures that the relative order of the cities
@@ -122,8 +126,8 @@ def order_crossover(p1, p2, crossover_prob):
122
126
[3, 1, 2, 0]
123
127
"""
124
128
if random .random () < crossover_prob : # Perform crossover with given probability
125
- c1 = [- 1 ] * len (p1 )
126
- c2 = [- 1 ] * len (p2 )
129
+ c1 : list [ int ] = [- 1 ] * len (p1 )
130
+ c2 : list [ int ] = [- 1 ] * len (p2 )
127
131
start = random .randint (0 , len (p1 ) - 1 )
128
132
end = random .randint (start + 1 , len (p1 ))
129
133
c1 [start :end ] = p1 [start :end ] # Copy a segment from parent 1 to child 1
@@ -144,7 +148,7 @@ def order_crossover(p1, p2, crossover_prob):
144
148
return p1 , p2 # No crossover, return the parents unchanged
145
149
146
150
147
- def swap_mutation (child , mutation_prob , num_cities ) :
151
+ def swap_mutation (child : list [ int ] , mutation_prob : float , num_cities : int ) -> list [ int ] :
148
152
"""
149
153
Applies swap mutation to a child solution with a given probability.
150
154
Two random cities in the tour are swapped to introduce variability.
@@ -169,7 +173,7 @@ def swap_mutation(child, mutation_prob, num_cities):
169
173
return child
170
174
171
175
172
- def two_opt_local_search (child , dist_mat ) :
176
+ def two_opt_local_search (child : list [ int ] , dist_mat : np . ndarray ) -> list [ int ] :
173
177
"""
174
178
Applies the 2-opt local search algorithm to improve a solution (tour).
175
179
It repeatedly checks for pairs of edges in the tour and swaps them if
@@ -231,7 +235,7 @@ def two_opt_local_search(child, dist_mat):
231
235
# Generate initial population (first city is taken to be depot by default):
232
236
popln : list = []
233
237
while len (popln ) < TOTAL_POPULATION :
234
- sol_dist = 0
238
+ sol_dist = 0.0
235
239
individual = list (range (n_cities ))
236
240
subindiv = individual [1 :]
237
241
random .shuffle (subindiv )
0 commit comments