moving most used functions to specitic python files

This commit is contained in:
Louis 2023-06-17 18:09:21 +02:00
parent b21ecce51e
commit 0da622371f
9 changed files with 182 additions and 93 deletions

View File

@ -2,7 +2,7 @@ from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import random, time
from clustering import split_tour_across_clusters
from libs.clustering import split_tour_across_clusters
def generate_cities(nb, max_coords=1000):
return [random.sample(range(max_coords), 2) for _ in range(nb)]

View File

@ -2,7 +2,7 @@ from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import random, time, math
from clustering import split_tour_across_clusters
from libs.clustering import split_tour_across_clusters
random.seed(1)
@ -66,7 +66,7 @@ def simulated_annealing(cities, color='b', temperature=100000, cooling_rate=0.99
plt.ioff()
return best_solution
nb_ville = 100
nb_ville = 200
max_coords = 1000
nb_truck = 4
temperature = 10000

View File

@ -2,7 +2,7 @@ from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import random, time, math
from clustering import split_tour_across_clusters
from libs.clustering import split_tour_across_clusters
def generate_cities(nb, max_coords=1000):
return [random.sample(range(max_coords), 2) for _ in range(nb)]

View File

@ -2,9 +2,9 @@ from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import random, time, math
from clustering import split_tour_across_clusters
from libs.clustering import split_tour_across_clusters
random.seed(2)
random.seed(3)
def generate_cities(nb, max_coords=1000):
return [random.sample(range(max_coords), 2) for _ in range(nb)]
@ -60,9 +60,9 @@ class AntColony:
return [self.cities[i] for i in best_ant]
nb_ville = 50
max_coords = 10
nb_truck = 1
max_time = 1
max_coords = 1000
nb_truck = 2
max_time = 3
nb_ants = 10
max_time_per_cluster = max_time / nb_truck
@ -123,6 +123,13 @@ for i, cluster_indices in enumerate(clusters.values()):
print("Total distance for cluster", i, ": ", total_distance(best_route))
# calculate total distance for all clusters
full_total_distance = 0
for route, color in best_routes:
full_total_distance += total_distance(route)
print("Total distance for all clusters: ", full_total_distance)
for i, (route, color) in enumerate(best_routes):
x = [city[0] for city in route]
y = [city[1] for city in route]

View File

@ -1,81 +0,0 @@
from sklearn.cluster import KMeans
import numpy as np
def split_tour_across_clusters(cities, nb_truck):
if nb_truck == 1:
return {0: list(range(len(cities)))}
# clustering initial
kmeans = KMeans(n_clusters=nb_truck, random_state=0).fit(cities)
clusters = {i:[] for i in range(nb_truck)}
# assignation des indices des villes aux clusters
for i, label in enumerate(kmeans.labels_):
clusters[label].append(i)
max_iterations = len(cities)
iteration = 0
while True:
iteration += 1
if iteration > max_iterations:
print("Le nombre maximum d'itérations a été atteint. La boucle a été interrompue.")
break
# calcul des tailles de clusters
cluster_sizes = {i:len(clusters[i]) for i in range(nb_truck)}
# identification du cluster le plus grand et du plus petit
max_cluster = max(cluster_sizes, key=cluster_sizes.get)
min_cluster = min(cluster_sizes, key=cluster_sizes.get)
# s'il n'y a pas de grande disparité, on arrête la boucle
if cluster_sizes[max_cluster] - cluster_sizes[min_cluster] <= 1:
break
# calcul du centre de chaque cluster
cluster_centers = {i:np.mean([cities[index] for index in clusters[i]], axis=0) for i in range(nb_truck)}
# calcul des distances entre le centre du cluster le plus grand et les autres
distances = {i:np.linalg.norm(cluster_centers[max_cluster]-cluster_centers[i]) for i in range(nb_truck)}
del distances[max_cluster] # on supprime la distance vers lui-même
if nb_truck >= 3:
# on identifie les 2 clusters les plus proches
closest_clusters = sorted(distances, key=distances.get)[:2]
# parmi les deux clusters les plus proches, on choisit le plus petit
if cluster_sizes[closest_clusters[0]] <= cluster_sizes[closest_clusters[1]]:
target_cluster = closest_clusters[0]
else:
target_cluster = closest_clusters[1]
else:
closest_clusters = sorted(distances, key=distances.get)[:1]
target_cluster = closest_clusters[0]
# si le transfert va créer une plus grande disparité, on arrête la boucle
if cluster_sizes[target_cluster] >= cluster_sizes[max_cluster]:
break
# calcul des distances entre le centre du cluster cible et les villes du cluster le plus grand
distances_to_target = {index:np.linalg.norm(cluster_centers[target_cluster]-cities[index])
for index in clusters[max_cluster]}
# on identifie la ville la plus proche du centre du cluster cible
closest_city_index = min(distances_to_target, key=distances_to_target.get)
# on transfère la ville du cluster le plus grand au cluster cible
clusters[target_cluster].append(closest_city_index)
clusters[max_cluster].remove(closest_city_index)
# Ajout du point de départ et d'arrivée pour chaque cluster
depot_index = 0
for cluster in clusters.values():
if cluster[0] != depot_index:
cluster.insert(0, depot_index)
if cluster[-1] != depot_index:
cluster.append(depot_index)
return clusters

View File

@ -1,3 +1 @@
[[6734.0, 1453.0], [2233.0, 10.0], [5530.0, 1424.0], [401.0, 841.0], [3082.0, 1644.0], [7608.0, 4458.0], [7573.0, 3716.0], [7265.0, 1268.0], [6898.0, 1885.0], [1112.0, 2049.0], [5468.0, 2606.0], [5989.0, 2873.0], [4706.0, 2674.0], [4612.0, 2035.0], [6347.0, 2683.0], [6107.0, 669.0], [7611.0, 5184.0], [7462.0, 3590.0],
[7732.0, 4723.0], [5900.0, 3561.0], [4483.0, 3369.0], [6101.0, 1110.0], [5199.0, 2182.0], [1633.0, 2809.0], [4307.0, 2322.0], [675.0, 1006.0], [7555.0, 4819.0], [7541.0, 3981.0], [3177.0, 756.0], [7352.0, 4506.0], [7545.0, 2801.0], [3245.0, 3305.0], [6426.0, 3173.0], [4608.0, 1198.0], [23.0, 2216.0], [7248.0, 3779.0],
[7762.0, 4595.0], [7392.0, 2244.0], [3484.0, 2829.0], [6271.0, 2135.0], [4985.0, 140.0], [1916.0, 1569.0], [7280.0, 4899.0], [7509.0, 3239.0], [10.0, 2676.0], [6807.0, 2993.0], [5185.0, 3258.0], [3023.0, 1942.0]]
[['6734', '1453'], ['2233', '10'], ['5530', '1424'], ['401', '841'], ['3082', '1644'], ['7608', '4458'], ['7573', '3716'], ['7265', '1268'], ['6898', '1885'], ['1112', '2049'], ['5468', '2606'], ['5989', '2873'], ['4706', '2674'], ['4612', '2035'], ['6347', '2683'], ['6107', '669'], ['7611', '5184'], ['7462', '3590'], ['7732', '4723'], ['5900', '3561'], ['4483', '3369'], ['6101', '1110'], ['5199', '2182'], ['1633', '2809'], ['4307', '2322'], ['675', '1006'], ['7555', '4819'], ['7541', '3981'], ['3177', '756'], ['7352', '4506'], ['7545', '2801'], ['3245', '3305'], ['6426', '3173'], ['4608', '1198'], ['23', '2216'], ['7248', '3779'], ['7762', '4595'], ['7392', '2244'], ['3484', '2829'], ['6271', '2135'], ['4985', '140'], ['1916', '1569'], ['7280', '4899'], ['7509', '3239'], ['10', '2676'], ['6807', '2993'], ['5185', '3258'], ['3023', '1942']]

51
tests/libs/aco.py Normal file
View File

@ -0,0 +1,51 @@
import math, random, time, numpy as np
def distance(city1, city2):
return math.sqrt((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2) + 1e-10
def total_distance(cities):
return sum([distance(cities[i - 1], cities[i]) for i in range(len(cities))])
class AntColony:
def __init__(self, cities, n_ants, alpha=1, beta=2, evaporation=0.5, intensification=2, max_time=0.1):
self.cities = cities
self.n = len(cities)
self.n_ants = n_ants
self.alpha = alpha
self.beta = beta
self.evaporation = evaporation
self.intensification = intensification
self.max_time = max_time
self.pheromones = [[1 / self.n for _ in range(self.n)] for __ in range(self.n)]
def choose_next_city(self, ant):
unvisited_cities = [i for i in range(self.n) if i not in ant]
probabilities = [self.pheromones[ant[-1]][i] ** self.alpha * ((1 / distance(self.cities[ant[-1]], self.cities[i])) ** self.beta) for i in unvisited_cities]
total = sum(probabilities)
if total == 0:
probabilities = [1 / len(unvisited_cities) for _ in unvisited_cities]
else:
probabilities = [p / total for p in probabilities]
return np.random.choice(unvisited_cities, p=probabilities)
def update_pheromones(self, ant):
pheromones_delta = self.intensification / total_distance([self.cities[i] for i in ant])
for i in range(len(ant) - 1):
self.pheromones[ant[i]][ant[i+1]] += pheromones_delta
def run(self):
best_ant = []
best_distance = float('inf')
start_time = time.time()
while time.time() - start_time < self.max_time:
ants = [[random.randint(0, self.n - 1)] for _ in range(self.n_ants)]
for ant in ants:
for _ in range(self.n - 1):
ant.append(self.choose_next_city(ant))
ant_distance = total_distance([self.cities[i] for i in ant])
if ant_distance < best_distance:
best_distance = ant_distance
best_ant = ant.copy()
self.update_pheromones(ant)
self.pheromones = [[(1 - self.evaporation) * p for p in row] for row in self.pheromones]
return [self.cities[i] for i in best_ant]

81
tests/libs/clustering.py Normal file
View File

@ -0,0 +1,81 @@
from sklearn.cluster import KMeans
import numpy as np
def split_tour_across_clusters(cities, nb_truck):
if nb_truck == 1:
return {0: list(range(len(cities)))}
# clustering initial
kmeans = KMeans(n_clusters=nb_truck, random_state=0).fit(cities)
clusters = {i:[] for i in range(nb_truck)}
# assignation des indices des villes aux clusters
for i, label in enumerate(kmeans.labels_):
clusters[label].append(i)
max_iterations = len(cities)
iteration = 0
while True:
iteration += 1
if iteration > max_iterations:
print("Le nombre maximum d'itérations a été atteint. La boucle a été interrompue.")
break
# calcul des tailles de clusters
cluster_sizes = {i:len(clusters[i]) for i in range(nb_truck)}
# identification du cluster le plus grand et du plus petit
max_cluster = max(cluster_sizes, key=cluster_sizes.get)
min_cluster = min(cluster_sizes, key=cluster_sizes.get)
# s'il n'y a pas de grande disparité, on arrête la boucle
if cluster_sizes[max_cluster] - cluster_sizes[min_cluster] <= 1:
break
# calcul du centre de chaque cluster
cluster_centers = {i:np.mean([cities[index] for index in clusters[i]], axis=0) for i in range(nb_truck)}
# calcul des distances entre le centre du cluster le plus grand et les autres
distances = {i:np.linalg.norm(cluster_centers[max_cluster]-cluster_centers[i]) for i in range(nb_truck)}
del distances[max_cluster] # on supprime la distance vers lui-même
if nb_truck >= 3:
# on identifie les 2 clusters les plus proches
closest_clusters = sorted(distances, key=distances.get)[:2]
# parmi les deux clusters les plus proches, on choisit le plus petit
if cluster_sizes[closest_clusters[0]] <= cluster_sizes[closest_clusters[1]]:
target_cluster = closest_clusters[0]
else:
target_cluster = closest_clusters[1]
else:
closest_clusters = sorted(distances, key=distances.get)[:1]
target_cluster = closest_clusters[0]
# si le transfert va créer une plus grande disparité, on arrête la boucle
if cluster_sizes[target_cluster] >= cluster_sizes[max_cluster]:
break
# calcul des distances entre le centre du cluster cible et les villes du cluster le plus grand
distances_to_target = {index:np.linalg.norm(cluster_centers[target_cluster]-cities[index])
for index in clusters[max_cluster]}
# on identifie la ville la plus proche du centre du cluster cible
closest_city_index = min(distances_to_target, key=distances_to_target.get)
# on transfère la ville du cluster le plus grand au cluster cible
clusters[target_cluster].append(closest_city_index)
clusters[max_cluster].remove(closest_city_index)
# Ajout du point de départ et d'arrivée pour chaque cluster
depot_index = 0
for cluster in clusters.values():
if cluster[0] != depot_index:
cluster.insert(0, depot_index)
if cluster[-1] != depot_index:
cluster.append(depot_index)
return clusters

View File

@ -0,0 +1,33 @@
import math, random
def distance(city1, city2):
return math.sqrt((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2)
def total_distance(cities):
return sum([distance(cities[i - 1], cities[i]) for i in range(len(cities))])
def simulated_annealing(cities, temperature=10000, cooling_rate=0.9999, temperature_ok=0.001, cluster_index=0):
interration = 0
current_solution = cities.copy()
best_solution = cities.copy()
while temperature > temperature_ok:
new_solution = current_solution.copy()
# Swap two cities in the route
i = random.randint(0, len(new_solution) - 1)
j = random.randint(0, len(new_solution) - 1)
new_solution[i], new_solution[j] = new_solution[j], new_solution[i]
# Calculate the acceptance probability
current_energy = total_distance(current_solution)
new_energy = total_distance(new_solution)
delta = new_energy - current_energy
if delta < 0 or random.random() < math.exp(-delta / temperature):
current_solution = new_solution
if total_distance(current_solution) < total_distance(best_solution):
best_solution = current_solution
# Cool down
temperature *= cooling_rate
interration += 1
# Print every 1000 iterations
if interration % 1000 == 0:
print("Cluster", cluster_index, ": iteration", interration, "with current total distance", total_distance(current_solution))
return best_solution