-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbenchmark_methods.py
More file actions
120 lines (102 loc) · 3.66 KB
/
Copy pathbenchmark_methods.py
File metadata and controls
120 lines (102 loc) · 3.66 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
from population import Population
import os
import time
import random
import numpy as np
import matplotlib.pyplot as plt
from typing import Dict, Any, List, Tuple
DURATION = 10
CITIES = 200
POPULATION_SIZE = CITIES * 5
TOURNAMENT_SIZE = POPULATION_SIZE // 10
MUTATION_RATE = 1
SEED = 80
METHODS = [
'pmx',
'cx',
'erx',
'ox',
'hx',
'hx extended',
]
def build_population(seed: int) -> Population:
# Seed for reproducibility of the initial population.
random.seed(seed)
np.random.seed(seed)
population = Population(POPULATION_SIZE, TOURNAMENT_SIZE, mutation_rate=MUTATION_RATE)
# Circle layout -> deterministic coordinates, no seeding needed.
population.generate_circle_cities(CITIES)
population.generate_individuals()
return population
def run_benchmark(method: str, duration: float, seed: int) -> Dict[str, Any]:
population = build_population(seed)
start = time.time()
iters = 0
best = max(population.individuals, key=lambda individual: individual.fitness)
# History of (elapsed seconds, fitness).
best_fitness_history: List[Tuple[float, float]] = []
# Sampling at a regular time step (for an x-axis in seconds).
SAMPLE_STEP = 0.1 # in seconds
next_sample = start
while time.time() - start < duration:
child1, child2 = population.crossover(method=method, mutation='2-opt alt')
# Update the best efficiently.
if child1.fitness > best.fitness:
best = child1
if child2.fitness > best.fitness:
best = child2
now = time.time()
if now >= next_sample:
best_fitness_history.append((now - start, best.fitness))
next_sample += SAMPLE_STEP
iters += 1
# Final best
final_best = max(population.individuals, key=lambda individual: individual.fitness)
if final_best.fitness > best.fitness:
best = final_best
return {
'method': method,
'iterations': iters,
'best_fitness': best.fitness,
'best_distance': best.total_distance,
'best_route': best.route,
'history': best_fitness_history,
}
def main():
print(f"Benchmark over {DURATION}s, cities={CITIES}, population_size={POPULATION_SIZE}, "
f"tournament_size={TOURNAMENT_SIZE}, mutation_rate={MUTATION_RATE}, seed={SEED}")
results = []
for method in METHODS:
print(f"\n--- Method: {method} ---")
res = run_benchmark(method, DURATION, SEED)
print(f"Iterations: {res['iterations']}")
print(f"Best distance: {res['best_distance']:.6f}")
print(f"Best fitness: {res['best_fitness']:.8f}")
results.append(res)
# Final summary sorted by best distance.
results_sorted = sorted(results, key=lambda r: r['best_distance'])
print("\n===== Summary (sorted by best distance) =====")
for r in results_sorted:
print(f"{r['method']:<3} | iters={r['iterations']:<6} | dist={r['best_distance']:.6f} | fit={r['best_fitness']:.8f}")
# Plot the fitness evolution over time.
plt.figure(figsize=(10, 6))
for r in results:
if r['history']:
xs, ys = zip(*r['history'])
plt.plot(xs, ys, label=r['method'])
plt.title('Fitness evolution over time (s)')
plt.xlabel('Time (seconds)')
plt.ylabel('Best fitness')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
try:
os.makedirs('outputs', exist_ok=True)
output_path = 'outputs/benchmark_fitness.png'
plt.savefig(output_path, dpi=150)
print(f"Figure saved: {output_path}")
except Exception as e:
print(f"Error saving figure: {e}")
plt.show()
if __name__ == '__main__':
main()