-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmainscript.py
More file actions
144 lines (128 loc) · 5.25 KB
/
mainscript.py
File metadata and controls
144 lines (128 loc) · 5.25 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
import os
import csv
import random
from instance_parser import parse_instance
from heuristics import (
heuristic_population_initialization,
generate_giant_tour_and_split,
repair_route_battery_feasibility
)
from ga_operators import order_crossover_evrp, mutate_route
from validation import (
validate_solution,
validate_no_duplicates_route,
ensure_all_customers_present,
validate_and_finalize_routes
)
from local_search import apply_local_search, plot_routes, route_cost
from utils import make_routes_battery_feasible
from route_utils import sanitize_routes
from fitness import fitness_function
import matplotlib.pyplot as plt
# === CONFIG ===
INSTANCE_DIR = "instance_files"
RESULTS_FILE = "evaluation_results.csv"
TARGET_INSTANCES = ["C101-10.xml", "R102-10.xml", "RC102-10.xml"]
penalty_weights = {
'missing_customers': 1e6,
'battery_depletion': 1e4,
'unreachable_node': 1e5,
'unnecessary_recharges': 1000,
'low_battery': 5000,
'capacity_overload': 1e5,
'max_travel_time_exceeded': 1e5,
'invalid_route': 1e5,
'vehicle_count': 1e4,
}
def save_result_to_csv(instance_name, method, fitness, battery_feasible, route_count, vehicle_count, comment=""):
file_exists = os.path.isfile(RESULTS_FILE)
with open(RESULTS_FILE, mode='a', newline='') as file:
writer = csv.writer(file)
if not file_exists:
writer.writerow(["Instance", "Method", "Fitness", "Battery Feasible", "Route Count", "Vehicle Count", "Comments"])
writer.writerow([
instance_name,
method,
f"{fitness:.2f}",
"YES" if battery_feasible else "NO",
route_count,
vehicle_count,
comment
])
# === RUN FOR EACH INSTANCE ===
for filename in TARGET_INSTANCES:
print(f"\nProcessing: {filename}")
filepath = os.path.join(INSTANCE_DIR, filename)
# === PARSE INSTANCE ===
(nodes, charging_stations, depot, customers, cost_matrix, travel_time_matrix,
battery_capacity, num_vehicles_instance, vehicle_capacity, max_travel_time, requests) = parse_instance(filepath)
DEPOT = depot
E_max = battery_capacity
recharge_amount = E_max
num_generations = 30
population_size = 10
# === INITIAL POPULATION ===
print("\nInitializing GA Population...")
base_solution = generate_giant_tour_and_split(
DEPOT, list(customers), nodes, cost_matrix, travel_time_matrix,
requests, vehicle_capacity, max_travel_time, E_max
)
repaired_base = [repair_route_battery_feasibility(route, cost_matrix, E_max, recharge_amount,
charging_stations, DEPOT, nodes)
for route in base_solution]
population = [repaired_base]
additional_population = heuristic_population_initialization(
population_size - 1, nodes, cost_matrix, travel_time_matrix, DEPOT,
E_max, recharge_amount, charging_stations, vehicle_capacity,
max_travel_time, requests, num_vehicles_instance
)
population.extend(additional_population)
# === GA LOOP ===
for generation in range(num_generations):
print(f"\nGeneration {generation+1}...")
new_population = []
for i in range(population_size // 2):
parent1, parent2 = random.sample(population, 2)
child = order_crossover_evrp(parent1, parent2, cost_matrix, E_max, charging_stations, recharge_amount, DEPOT)
child = mutate_route(child)
repaired_child = make_routes_battery_feasible(child, cost_matrix, E_max, charging_stations, DEPOT)
repaired_child = sanitize_routes(repaired_child, DEPOT, charging_stations)
new_population.append(repaired_child)
population = sorted(new_population + population, key=lambda sol: fitness_function(
sol, cost_matrix, travel_time_matrix, E_max, charging_stations, recharge_amount, penalty_weights,
DEPOT, nodes, vehicle_capacity, max_travel_time, requests, customers
)[0])[:population_size]
# === BEST SOLUTION ===
best_solution = population[0]
final_fitness, battery_ok = fitness_function(
best_solution, cost_matrix, travel_time_matrix, E_max, charging_stations, recharge_amount,
penalty_weights, DEPOT, nodes, vehicle_capacity, max_travel_time, requests, customers
)
print(f"\nFinal Evaluation for {filename}:")
print(f" Total Routes: {len(best_solution)}")
print(f" Fitness Score: {final_fitness:.2f}")
print(f" Battery Feasible: {'YES' if battery_ok else 'NO'}")
for i, route in enumerate(best_solution):
print(f" Route {i+1}: {route} (Cost: {route_cost(route, cost_matrix)})")
instance_id = filename.replace(".xml", "")
plot_routes(
best_solution,
nodes=nodes,
depot=depot,
charging_stations=charging_stations,
cost_matrix=cost_matrix,
E_max=E_max,
save_plot=False,
method="GA",
instance_id=instance_id
)
plt.show(block=True)
save_result_to_csv(
instance_name=filename,
method="GA",
fitness=final_fitness,
battery_feasible=battery_ok,
route_count=len(best_solution),
vehicle_count=len(best_solution),
comment="GA result from mainscript.py"
)