-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfitness.py
More file actions
95 lines (82 loc) · 3.01 KB
/
fitness.py
File metadata and controls
95 lines (82 loc) · 3.01 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
def fitness_function(chromosome, distance_matrix, evrp_data,
battery_capacity=162, consumption_rate=1.0, charging_rate=1.0,
w1=0.6, w2=0.4, fitnes_only=True):
"""Compute fitness for a chromosome.
Parameters
- chromosome: list of genes with '|' separators between routes
- distance_matrix: distance matrix (0-indexed internally)
- evrp_data: EVRP data with stations, depot, demands, and capacity info
- fitnes_only: if True, only return fitness, otherwise return fitness, distance, charging time
Returns: lower is better
"""
total_distance = 0.0
total_charging_time = 0.0
invalid_penalty = 1e6
# Extract capacity constraint data
demands = evrp_data.get('demands', {})
vehicle_capacity = evrp_data.get('capacity', float('inf'))
stations = evrp_data['stations']
depot = evrp_data['depot']
# Helper to get distance
def get_dist(a, b):
# Adjust for 0-indexed distance_matrix (nodes are 1-indexed)
return distance_matrix[a-1][b-1]
# Parse chromosome into routes
routes = []
current = []
for gene in chromosome:
if gene == '|':
if current:
routes.append(current)
current = []
else:
current.append(gene)
if current:
routes.append(current)
# Evaluate each route
for route in routes:
battery = battery_capacity
# 1) CAPACITY CHECK: sum demands of all customers in this route
route_demand = 0
for node in route:
# Only count customer demands (skip depot and stations)
if node not in stations and node not in depot:
route_demand += demands.get(node, 0)
# If route demand exceeds vehicle capacity, add a penalty
if route_demand > vehicle_capacity:
print("Route demand exceeds vehicle capacity", route_demand, vehicle_capacity)
return invalid_penalty
# 2) ENERGY & DISTANCE SIMULATION
for i in range(len(route) - 1):
a, b = route[i], route[i+1]
dist = get_dist(a, b)
total_distance += dist
needed_energy = dist * consumption_rate
# BEFORE consuming energy, check if current node is a charging station
if a in stations:
# At charging station - calculate how much to charge
# Look ahead to find energy needed until next station/depot
energy_needed_ahead = 0.0
for j in range(i, len(route) - 1):
u, v = route[j], route[j+1]
energy_needed_ahead += get_dist(u, v) * consumption_rate
# Stop at next station or depot
if v in stations or v in depot:
break
# Charge only what we need (greedy charging)
required_energy = max(0.0, energy_needed_ahead - battery)
if required_energy > 0:
charge_time = required_energy / charging_rate if charging_rate > 0 else 0.0
total_charging_time += charge_time
battery = min(battery + required_energy, battery_capacity)
# Now consume energy for this segment
if battery + 1 < needed_energy - 1e-9: # small tolerance for floating point
return invalid_penalty
battery -= needed_energy
D = total_distance / 100.0
C = total_charging_time / 100.0
fitness = w1 * D + w2 * C
if(fitnes_only == False):
return fitness, D, C
else:
return fitness