Skip to content

Commit 788987a

Browse files
committed
some changes
1 parent f22a750 commit 788987a

File tree

6 files changed

+128
-50
lines changed

6 files changed

+128
-50
lines changed

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# TSP Problem with Genetic Algorithm
2+
## Data
3+
The input of this problem files with `tsp` format. I used the `tsplib95` library for weighted test cases (`bayg29`) and a self-written loader for test cases with coordinations.
4+
5+
## Algorithm
6+
At first, we generate our initial population with random routes(permutations).
7+
8+
The main process is a loop with several sections. At the end of every iteration in this loop, a new generation is born, preferably with better individuals.
9+
10+
Here is each section of this process:
11+
12+
### Selection
13+
The first thing we do with the previous generation is to select a subset of them as our parents. The primary consideration here is to make a balance between elites and vulgar to prevent overfitting or underfitting.
14+
15+
The algorithm used for this matter is tournament selection. For this, we choose a subset of the population by random, then we sort them based on their fitness and select a number of them as parents.
16+
17+
### Breeding
18+
With the parents being chosen, it is time for mating them with each other. Two individuals create a child with ordered recombination.
19+
20+
For choosing each pair, we shuffle parents and mate them by random. We repeat this shuffling until the number of our children has reached the population size.
21+
22+
### Mutation
23+
We have a parameter called the `mutation_rate`, which specifies the probability of mutation.
24+
25+
The mutations in this problem are done by swapping two cities(genes) in a permutation.
26+
27+
### Replacement
28+
The final step in the loop is to specify the next generation. We have considered a mix of children and parents because we want to keep the best parents for the next generation.
29+
We replace a fixed number of worst children with the best parents.
30+
31+
## Test
32+
### bayg29
33+
My best distances were between 1600 to 1800 and here is one of them:
34+
```
35+
Epoch 0 : Population total fitness: 0.021402390435083837 Best fitness: 0.000275178866263071 Least Distance: 3634
36+
Epoch 1 : Population total fitness: 0.022400741669908814 Best fitness: 0.00028694404591104734 Least Distance: 3485
37+
Epoch 2 : Population total fitness: 0.02321754970711249 Best fitness: 0.000299311583358276 Least Distance: 3341
38+
Epoch 3 : Population total fitness: 0.024596784139334586 Best fitness: 0.00030321406913280777 Least Distance: 3298
39+
Epoch 4 : Population total fitness: 0.025508500567304724 Best fitness: 0.00031655587211142766 Least Distance: 3159
40+
Epoch 5 : Population total fitness: 0.02567080676446863 Best fitness: 0.00031655587211142766 Least Distance: 3159
41+
Epoch 6 : Population total fitness: 0.026095669980930384 Best fitness: 0.00031826861871419476 Least Distance: 3142
42+
Epoch 7 : Population total fitness: 0.026213325051129905 Best fitness: 0.0003176620076238882 Least Distance: 3148
43+
...
44+
Epoch 92 : Population total fitness: 0.046347892289803405 Best fitness: 0.0005633802816901409 Least Distance: 1775
45+
Epoch 93 : Population total fitness: 0.04640791685328948 Best fitness: 0.0005633802816901409 Least Distance: 1775
46+
Epoch 94 : Population total fitness: 0.0463885029225474 Best fitness: 0.000572737686139748 Least Distance: 1746
47+
Epoch 95 : Population total fitness: 0.04655714750065836 Best fitness: 0.000572737686139748 Least Distance: 1746
48+
Epoch 96 : Population total fitness: 0.04607831403892826 Best fitness: 0.000572737686139748 Least Distance: 1746
49+
Epoch 97 : Population total fitness: 0.04588737374610269 Best fitness: 0.000572737686139748 Least Distance: 1746
50+
Epoch 98 : Population total fitness: 0.04635046560907124 Best fitness: 0.000572737686139748 Least Distance: 1746
51+
Epoch 99 : Population total fitness: 0.0466206756566057 Best fitness: 0.000572737686139748 Least Distance: 1746
52+
Best Answer:
53+
[13, 4, 20, 10, 2, 29, 3, 26, 6, 12, 9, 5, 21, 28, 1, 24, 8, 23, 27, 16, 7, 25, 19, 15, 18, 17, 14, 11, 22] 1746
54+
```
55+
56+
57+
## Considerations
58+
- Because we want to optimize our answers based on the total distance of the cycle, our fitness function is `1/total_distance` (so we try to maximize fitness).
59+

__pycache__/loader.cpython-38.pyc

1.28 KB
Binary file not shown.

__pycache__/utils.cpython-38.pyc

378 Bytes
Binary file not shown.

loader.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class Problem:
2+
def __init__(self, filepath):
3+
f = open(filepath, 'r')
4+
lines = f.readlines()
5+
self.coordinations = []
6+
start = False
7+
for line in lines:
8+
if start:
9+
line = line.strip().split()
10+
if len(line) < 3:
11+
break
12+
self.coordinations.append((float(line[1]), float(line[2])))
13+
continue
14+
15+
if 'DIMENSION' in line:
16+
line = line.split(':')
17+
self.dimension = int(line[1].strip())
18+
continue
19+
20+
if 'NODE_COORD_SECTION' in line:
21+
start = True
22+
self.calculate_weights()
23+
24+
def calculate_weights(self):
25+
self.weights = []
26+
for first_coordination in self.coordinations:
27+
weights = []
28+
for second_coordination in self.coordinations:
29+
weights.append((((first_coordination[0]-second_coordination[0])**2) +
30+
((first_coordination[1]-second_coordination[1])**2))**0.5)
31+
self.weights.append(weights)
32+
33+
def get_weight(self, start, end):
34+
return self.weights[start-1][end-1]

main.py

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,14 @@
1-
import tsplib95
2-
3-
from utils import initial_population
4-
from utils import generate_genration
5-
6-
7-
def TSP_GA(filename, n_generations, population_size, tournament_size, parents_size, mutation_rate, elite_size):
8-
problem = tsplib95.load('./problems/' + filename)
9-
10-
population = initial_population(problem, population_size)
11-
12-
for i in range(n_generations):
13-
population = generate_genration(
14-
i, population, tournament_size, parents_size, mutation_rate, elite_size)
15-
16-
print([x.distance for x in population])
17-
18-
print('Best Answer:')
19-
print(population[0].permutation, population[0].distance)
1+
from loader import Problem
2+
from utils import TSP_GA
203

214
def bayg29():
225
population_size = 100
236

247
tournament_size = 90
258

26-
parents_size = 40
9+
parents_size = 60
2710

28-
elite_size = 20
11+
elite_size = 30
2912

3013
mutation_rate = 0.01
3114

@@ -35,55 +18,42 @@ def bayg29():
3518
parents_size, mutation_rate, elite_size)
3619

3720

38-
def bayg29():
39-
population_size = 100
21+
def gr229():
22+
population_size = 200
4023

41-
tournament_size = 90
24+
tournament_size = 160
4225

43-
parents_size = 40
26+
parents_size = 90
4427

45-
elite_size = 20
28+
elite_size = 40
4629

4730
mutation_rate = 0.01
4831

49-
n_generations = 100
32+
n_generations = 10000
5033

51-
TSP_GA('bayg29.tsp', n_generations, population_size, tournament_size,
52-
parents_size, mutation_rate, elite_size)
53-
54-
55-
def gr229():
56-
population_size = 100
57-
58-
tournament_size = 90
59-
60-
parents_size = 70
61-
62-
elite_size = 30
63-
64-
mutation_rate = 0.05
65-
66-
n_generations = 100
34+
problem = Problem('./problems/gr229.tsp')
6735

6836
TSP_GA('gr229.tsp', n_generations, population_size, tournament_size,
69-
parents_size, mutation_rate, elite_size)
37+
parents_size, mutation_rate, elite_size, problem)
7038

7139

7240
def pr1002():
73-
population_size = 100
41+
population_size = 200
7442

75-
tournament_size = 90
43+
tournament_size = 140
7644

77-
parents_size = 50
45+
parents_size = 100
7846

79-
elite_size = 35
47+
elite_size = 80
8048

81-
mutation_rate = 0.05
49+
mutation_rate = 0.1
8250

8351
n_generations = 150
8452

53+
problem = Problem('./problems/pr1002.tsp')
54+
8555
TSP_GA('pr1002.tsp', n_generations, population_size, tournament_size,
86-
parents_size, mutation_rate, elite_size)
56+
parents_size, mutation_rate, elite_size, problem)
8757

8858
# bayg29()
8959

utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import random
2+
import tsplib95
23

34
from cycle import Cycle
45

@@ -110,3 +111,17 @@ def generate_genration(epoch, previous_population, tournament_size, parents_size
110111
eval_[0], "\tBest fitness:", eval_[1], "\tLeast Distance:", eval_[2])
111112

112113
return next_population
114+
115+
116+
def TSP_GA(filename, n_generations, population_size, tournament_size, parents_size, mutation_rate, elite_size, problem=None):
117+
if problem is None:
118+
problem = tsplib95.load('./problems/' + filename)
119+
120+
population = initial_population(problem, population_size)
121+
122+
for i in range(n_generations):
123+
population = generate_genration(
124+
i, population, tournament_size, parents_size, mutation_rate, elite_size)
125+
126+
print('Best Answer:')
127+
print(population[0].permutation, population[0].distance)

0 commit comments

Comments
 (0)