From 7b6d997110186543515051f1e164f415580320eb Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 19 Jun 2023 15:00:42 +0200 Subject: [PATCH] new deliverable --- Projet_algo.ipynb | 806 +--------------------------------------------- 1 file changed, 2 insertions(+), 804 deletions(-) diff --git a/Projet_algo.ipynb b/Projet_algo.ipynb index ad60941..b544ce5 100644 --- a/Projet_algo.ipynb +++ b/Projet_algo.ipynb @@ -264,7 +264,7 @@ "id": "7670fdf4-884c-4352-83fa-eed0c8b50074", "metadata": {}, "source": [ - "## Resolution algorithm " + "## Resolution algorithm (with coordinates)" ] }, { @@ -287,809 +287,7 @@ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import random, time, math\n", - "from tests.clustering import split_tour_across_clusters" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "c177ac22", - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "module 'networkx.linalg.graphmatrix' has no attribute 'to_numpy_matrix'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[17], line 41\u001b[0m\n\u001b[0;32m 38\u001b[0m \u001b[39mreturn\u001b[39;00m adjacency_matrix\n\u001b[0;32m 40\u001b[0m \u001b[39m# Générer la matrice d'adjacence pondérée\u001b[39;00m\n\u001b[1;32m---> 41\u001b[0m weighted_adjacency_matrix \u001b[39m=\u001b[39m generate_weighted_adjacency_matrix(graph)\n\u001b[0;32m 43\u001b[0m \u001b[39m# Afficher la matrice d'adjacence pondérée\u001b[39;00m\n\u001b[0;32m 44\u001b[0m \u001b[39mprint\u001b[39m(weighted_adjacency_matrix)\n", - "Cell \u001b[1;32mIn[17], line 36\u001b[0m, in \u001b[0;36mgenerate_weighted_adjacency_matrix\u001b[1;34m(graph)\u001b[0m\n\u001b[0;32m 34\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mgenerate_weighted_adjacency_matrix\u001b[39m(graph):\n\u001b[0;32m 35\u001b[0m \u001b[39m# Créer une matrice d'adjacence pondérée à partir du graphe\u001b[39;00m\n\u001b[1;32m---> 36\u001b[0m adjacency_matrix \u001b[39m=\u001b[39m graphmatrix\u001b[39m.\u001b[39;49mto_numpy_matrix(graph, weight\u001b[39m=\u001b[39m\u001b[39m'\u001b[39m\u001b[39mdistance\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[0;32m 38\u001b[0m \u001b[39mreturn\u001b[39;00m adjacency_matrix\n", - "\u001b[1;31mAttributeError\u001b[0m: module 'networkx.linalg.graphmatrix' has no attribute 'to_numpy_matrix'" - ] - } - ], - "source": [ - "\n", - "import random\n", - "import numpy as np\n", - "import networkx as nx\n", - "import matplotlib.pyplot as plt\n", - "import time as time\n", - "\n", - "from networkx.linalg import graphmatrix\n", - "\n", - "def generate_graph(num_nodes):\n", - " G = nx.Graph()\n", - " G.add_nodes_from(range(num_nodes + 1))\n", - " \n", - " for node in G.nodes():\n", - " connected_nodes = sorted(set(G.nodes()) - {node})\n", - " if len(connected_nodes) < 2:\n", - " continue\n", - " distance1 = random.randint(1, 10)\n", - " distance2 = random.randint(1, 10)\n", - " random_nodes = random.sample(connected_nodes, 2)\n", - " G.add_edges_from([(node, random_nodes[0], {'distance': distance1}),\n", - " (node, random_nodes[1], {'distance': distance2})])\n", - "\n", - " while not nx.is_connected(G):\n", - " node1, node2 = random.sample(G.nodes(), 2)\n", - " if not G.has_edge(node1, node2):\n", - " distance = random.randint(1, 10)\n", - " G.add_edge(node1, node2, distance=distance)\n", - "\n", - " return G\n", - "\n", - "graph = generate_graph(12)\n", - "A = nx.adjacency_matrix(graph)\n", - "\n", - "def generate_weighted_adjacency_matrix(graph):\n", - " # Créer une matrice d'adjacence pondérée à partir du graphe\n", - " adjacency_matrix = graphmatrix.to_numpy_matrix(graph, weight='distance')\n", - "\n", - " return adjacency_matrix\n", - "\n", - "# Générer la matrice d'adjacence pondérée\n", - "weighted_adjacency_matrix = generate_weighted_adjacency_matrix(graph)\n", - "\n", - "# Afficher la matrice d'adjacence pondérée\n", - "print(weighted_adjacency_matrix)\n", - "\n", - "\n", - "def generate_distance_matrix(graph):\n", - " num_nodes = graph.number_of_nodes()\n", - " distance_array = np.full((num_nodes, num_nodes), float('inf')) # Initialiser avec l'infini\n", - " for edge in graph.edges(data=True):\n", - " i, j, data = edge\n", - " distance_array[i][j] = data['distance']\n", - " distance_array[j][i] = data['distance'] # Pour un graphe non orienté\n", - " np.fill_diagonal(distance_array, 0) # Remplir la diagonale avec des zéros\n", - " return distance_array\n", - "\n", - "# Générer la matrice de distances\n", - "distance_matrix = generate_distance_matrix(graph)\n", - "\n", - "\n", - "# Afficher la matrice de distances\n", - "print(distance_matrix)\n", - "\n", - "\n", - "\n", - "# Dessiner le graphe\n", - "nx.draw(graph, with_labels=True)\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "9aac4453", - "metadata": {}, - "source": [ - "# On applique l'algorithme des fourmis (ACO) sur notre graphe\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "23e32e2a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Meilleure solution : [[6, 5, 4, 8, 1, 11, 0], [9, 3, 7, 12, 10, 2, 0]]\n", - "Distance totale : 81.0\n" - ] - } - ], - "source": [ - "import concurrent.futures\n", - "num_trucks = 2 # Nombre de camions disponibles\n", - "\n", - "\n", - "# Fonction d'évaluation de la qualité d'une solution (ici, la distance totale)\n", - "def evaluate_solution(solution, distances):\n", - " total_distance = 0\n", - " num_nodes = len(solution)\n", - "\n", - " for i in range(num_nodes - 1):\n", - " current_node = solution[i]\n", - " next_node = solution[i + 1]\n", - " total_distance += distances[current_node][next_node]\n", - "\n", - "\n", - " # Ajouter la distance de retour au dépôt\n", - " total_distance += distances[solution[-1]][solution[0]]\n", - "\n", - " return total_distance\n", - "\n", - " \n", - "def ant_colony_optimization(distances, num_ants, num_iterations, evaporation_rate, alpha, beta, num_trucks):\n", - " num_nodes = len(distances)\n", - " \n", - " pheromone = np.ones((num_nodes, num_nodes)) # Matrice de phéromones initiale\n", - " best_solution = None\n", - " best_distance = float('inf')\n", - "\n", - " start_time = time.time()\n", - "\n", - " for iteration in range(num_iterations):\n", - " # Construction de solutions par les fourmis\n", - " solutions = []\n", - "\n", - " for ant in range(num_ants):\n", - " visited = set()\n", - " current_node = random.randint(0, num_nodes - 1)\n", - " visited.add(current_node)\n", - " solution = [current_node]\n", - "\n", - " while len(visited) < num_nodes:\n", - " next_node = None\n", - " probabilities = []\n", - "\n", - " # Calcul des probabilités de choisir chaque prochain nœud\n", - " for node in range(num_nodes):\n", - " if node not in visited and (node !=0 or len(visited) == num_nodes - 1):\n", - " pheromone_value = pheromone[current_node][node]\n", - " distance_value = distances[current_node][node]\n", - " probability = (pheromone_value ** alpha) * ((1 / distance_value) ** beta)\n", - " probabilities.append((node, probability))\n", - "\n", - " total_probability = sum(prob for _, prob in probabilities)\n", - " probabilities = [(node, prob / total_probability) for node, prob in probabilities]\n", - "\n", - " \n", - " roulette_wheel = random.random()\n", - " probability_sum = 0\n", - "\n", - "\n", - " for node, probability in probabilities:\n", - " \n", - " probability_sum += probability\n", - " if probability_sum >= roulette_wheel:\n", - " next_node = node\n", - " break\n", - "\n", - " visited.add(next_node)\n", - " solution.append(next_node)\n", - " current_node = next_node\n", - "\n", - " # Ajouter le retour au dépôt central à la fin du trajet\n", - " solution.append(0)\n", - "\n", - " solutions.append(solution)\n", - "\n", - " # Évaluation des solutions et mise à jour de la meilleure solution\n", - " for solution in solutions:\n", - " distance = evaluate_solution(solution, distances)\n", - " if distance < best_distance:\n", - " best_solution = solution\n", - " best_distance = distance\n", - "\n", - " # Mise à jour des phéromones\n", - " pheromone *= evaporation_rate # Évaporation des phéromones existantes\n", - "\n", - " for solution in solutions:\n", - " delta_pheromone = 1 / evaluate_solution(solution, distances)\n", - " for i in range(num_nodes - 1):\n", - " node1 = solution[i]\n", - " node2 = solution[i + 1]\n", - " pheromone[node1][node2] += delta_pheromone\n", - " pheromone[node2][node1] += delta_pheromone\n", - "\n", - " # Séparer la meilleure solution en trajets pour chaque camion\n", - " truck_solutions = []\n", - " num_nodes_per_truck = num_nodes // num_trucks\n", - "\n", - " for i in range(num_trucks):\n", - " start_index = i * num_nodes_per_truck\n", - " end_index = start_index + num_nodes_per_truck\n", - " truck_solution = best_solution[start_index:end_index]\n", - " truck_solutions.append(truck_solution + [0])\n", - " \n", - "\n", - " return truck_solutions, best_distance\n", - "\n", - "\n", - "def trucks_thread(i, num_nodes_per_truck, best_solution, truck_solutions):\n", - " start_index = i * num_nodes_per_truck\n", - " end_index = start_index + num_nodes_per_truck\n", - " truck_solution = best_solution[start_index:end_index]\n", - " truck_solutions.append(truck_solution)\n", - " return truck_solutions\n", - "\n", - "\n", - "num_ants = 10\n", - "num_iterations = 100\n", - "evaporation_rate = 0.5\n", - "alpha = 1\n", - "beta = 1\n", - "\n", - "best_truck_solutions, best_distance = ant_colony_optimization(distance_matrix, num_ants, num_iterations, evaporation_rate, alpha, beta, num_trucks)\n", - "\n", - "\n", - "print(\"Meilleure solution :\", best_truck_solutions)\n", - "print(\"Distance totale :\", best_distance)\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "6928bbbd", - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "module 'networkx' has no attribute 'from_numpy_matrix'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[11], line 114\u001b[0m\n\u001b[0;32m 111\u001b[0m \u001b[39m# Pour chaque solution de camion, nous devons trouver le chemin le plus court du dépôt au premier nœud du chemin\u001b[39;00m\n\u001b[0;32m 112\u001b[0m \u001b[39mfor\u001b[39;00m i, truck_solution \u001b[39min\u001b[39;00m \u001b[39menumerate\u001b[39m(best_truck_solutions):\n\u001b[0;32m 113\u001b[0m \u001b[39m# Créer un graphe à partir de la matrice de distance\u001b[39;00m\n\u001b[1;32m--> 114\u001b[0m G \u001b[39m=\u001b[39m nx\u001b[39m.\u001b[39;49mfrom_numpy_matrix(distance_matrix)\n\u001b[0;32m 116\u001b[0m \u001b[39m# Utiliser l'algorithme de Dijkstra pour trouver le chemin le plus court du dépôt (nœud 0) au premier nœud du chemin du camion\u001b[39;00m\n\u001b[0;32m 117\u001b[0m shortest_path \u001b[39m=\u001b[39m nx\u001b[39m.\u001b[39mdijkstra_path(G, \u001b[39m0\u001b[39m, truck_solution[\u001b[39m1\u001b[39m])\n", - "\u001b[1;31mAttributeError\u001b[0m: module 'networkx' has no attribute 'from_numpy_matrix'" - ] - } - ], - "source": [ - "num_trucks = 2 # Nombre de camions disponibles\n", - "\n", - "def evaluate_solution(solution, distances):\n", - " total_distance = 0\n", - " num_nodes = len(solution)\n", - "\n", - " # Calculer la distance entre chaque paire consécutive de nœuds dans la solution\n", - " for i in range(num_nodes - 1):\n", - " current_node = solution[i]\n", - " next_node = solution[i + 1]\n", - " total_distance += distances[current_node][next_node]\n", - "\n", - " # Ajouter la distance de retour au dépôt\n", - " total_distance += distances[solution[-1]][solution[0]]\n", - "\n", - " return total_distance\n", - "\n", - "def ant_colony_optimization(distances, num_ants, num_iterations, evaporation_rate, alpha, beta, num_trucks):\n", - " num_nodes = len(distances)\n", - " \n", - " pheromone = np.ones((num_nodes, num_nodes)) # Matrice de phéromones initiale\n", - " best_solution = None\n", - " best_distance = float('inf')\n", - "\n", - " for iteration in range(num_iterations):\n", - " # Construction de solutions par les fourmis\n", - " solutions = []\n", - "\n", - " for ant in range(num_ants):\n", - " visited = set()\n", - " current_node = 0 # Initialiser current_node à 0\n", - " visited.add(current_node)\n", - " solution = [current_node]\n", - "\n", - " while len(visited) < num_nodes:\n", - " next_node = None\n", - " probabilities = []\n", - "\n", - " # Calcul des probabilités de choisir chaque prochain nœud\n", - " for node in range(num_nodes):\n", - " if node not in visited and node < len(pheromone) and current_node < len(pheromone):\n", - " pheromone_value = pheromone[current_node][node]\n", - " distance_value = distances[current_node][node]\n", - " probability = (pheromone_value ** alpha) * ((1 / distance_value) ** beta)\n", - " probabilities.append((node, probability))\n", - "\n", - " total_probability = sum(prob for _, prob in probabilities)\n", - " probabilities = [(node, prob / total_probability) for node, prob in probabilities]\n", - "\n", - " roulette_wheel = random.random()\n", - " probability_sum = 0\n", - "\n", - " for node, probability in probabilities:\n", - " probability_sum += probability\n", - " if probability_sum >= roulette_wheel:\n", - " next_node = node\n", - " break\n", - "\n", - " visited.add(next_node)\n", - " solution.append(next_node)\n", - " current_node = next_node\n", - "\n", - " # Ajouter le retour au dépôt central à la fin du trajet\n", - " solution.append(0)\n", - "\n", - " solutions.append(solution)\n", - "\n", - " # Évaluation des solutions et mise à jour de la meilleure solution\n", - " for solution in solutions:\n", - " distance = evaluate_solution(solution, distances)\n", - " if distance < best_distance:\n", - " best_solution = solution\n", - " best_distance = distance\n", - "\n", - " # Mise à jour des phéromones\n", - " pheromone *= evaporation_rate # Évaporation des phéromones existantes\n", - "\n", - " for solution in solutions:\n", - " delta_pheromone = 1 / evaluate_solution(solution, distances)\n", - " for i in range(num_nodes - 1):\n", - " node1 = solution[i]\n", - " node2 = solution[i + 1]\n", - " pheromone[node1][node2] += delta_pheromone\n", - " pheromone[node2][node1] += delta_pheromone\n", - "\n", - " # Séparer la meilleure solution en trajets pour chaque camion\n", - " truck_solutions = []\n", - " num_nodes_per_truck = num_nodes // num_trucks\n", - "\n", - " for i in range(num_trucks):\n", - " start_index = i * num_nodes_per_truck\n", - " end_index = start_index + num_nodes_per_truck\n", - " truck_solution = best_solution[start_index:end_index]\n", - " truck_solutions.append(truck_solution + [0])\n", - " \n", - "\n", - " return truck_solutions, best_distance\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "num_ants = 10\n", - "num_iterations = 100\n", - "evaporation_rate = 0.5\n", - "alpha = 1\n", - "beta = 1\n", - "\n", - "best_truck_solutions,best_distance = ant_colony_optimization(distance_matrix, num_ants, num_iterations, evaporation_rate, alpha, beta, num_trucks)\n", - "\n", - "# Pour chaque solution de camion, nous devons trouver le chemin le plus court du dépôt au premier nœud du chemin\n", - "for i, truck_solution in enumerate(best_truck_solutions):\n", - " # Créer un graphe à partir de la matrice de distance\n", - " G = nx.from_numpy_matrix(distance_matrix)\n", - " \n", - " # Utiliser l'algorithme de Dijkstra pour trouver le chemin le plus court du dépôt (nœud 0) au premier nœud du chemin du camion\n", - " shortest_path = nx.dijkstra_path(G, 0, truck_solution[1])\n", - " \n", - " # Remplacer le premier nœud du chemin du camion par le chemin le plus court trouvé\n", - " best_truck_solutions[i] = [0] + shortest_path + truck_solution[2:]\n", - "\n", - "# Calculer la distance totale pour chaque solution de camion\n", - "total_distances = [evaluate_solution(truck_solution, distance_matrix) for truck_solution in best_truck_solutions]\n", - "\n", - "# Afficher les solutions et les distances totales pour chaque camion\n", - "for i, (truck_solution, total_distance) in enumerate(zip(best_truck_solutions, total_distances)):\n", - " print(f\"Camion {i+1} :\")\n", - " print(\"Solution :\", truck_solution)\n", - " print(\"Distance totale :\", total_distance)\n", - " print()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "421c05e1", - "metadata": {}, - "source": [] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "a6ffa6c9", - "metadata": {}, - "source": [ - "\n", - "def ant_colony_optimization(distances, num_ants, num_iterations, evaporation_rate, alpha, beta, num_trucks):\n", - " num_nodes = len(distances)\n", - " \n", - " pheromone = np.ones((num_nodes, num_nodes)) # Matrice de phéromones initiale\n", - " best_solution = None\n", - " best_distance = float('inf')\n", - "\n", - " for iteration in range(num_iterations):\n", - " # Construction de solutions par les fourmis\n", - " solutions = []\n", - "\n", - " for ant in range(num_ants):\n", - " visited = set()\n", - " current_node = 0 # Tous les camions partent du dépôt\n", - " visited.add(current_node)\n", - " solution = [current_node]\n", - "\n", - " while len(visited) < num_nodes:\n", - " next_node = None\n", - " probabilities = []\n", - "\n", - " # Calcul des probabilités de choisir chaque prochain nœud\n", - " for node in range(num_nodes):\n", - " if node not in visited:\n", - " pheromone_value = pheromone[current_node][node]\n", - " distance_value = distances[current_node][node]\n", - " probability = (pheromone_value ** alpha) * ((1 / distance_value) ** beta)\n", - " probabilities.append((node, probability))\n", - "\n", - " total_probability = sum(prob for _, prob in probabilities)\n", - " probabilities = [(node, prob / total_probability) for node, prob in probabilities]\n", - "\n", - " roulette_wheel = random.random()\n", - " probability_sum = 0\n", - "\n", - " for node, probability in probabilities:\n", - " probability_sum += probability\n", - " if probability_sum >= roulette_wheel:\n", - " next_node = node\n", - " break\n", - "\n", - " visited.add(next_node)\n", - " solution.append(next_node)\n", - " current_node = next_node\n", - "\n", - " # Ajouter le retour au dépôt central à la fin du trajet\n", - " solution.append(0)\n", - "\n", - " solutions.append(solution)\n", - "\n", - " # Évaluation des solutions et mise à jour de la meilleure solution\n", - " for solution in solutions:\n", - " distance = evaluate_solution(solution, distances)\n", - " if distance < best_distance:\n", - " best_solution = solution\n", - " best_distance = distance\n", - "\n", - " # Mise à jour des phéromones\n", - " pheromone *= evaporation_rate # Évaporation des phéromones existantes\n", - "\n", - " for solution in solutions:\n", - " delta_pheromone = 1 / evaluate_solution(solution, distances)\n", - " for i in range(num_nodes - 1):\n", - " node1 = solution[i]\n", - " node2 = solution[i + 1]\n", - " pheromone[node1][node2] += delta_pheromone\n", - " pheromone[node2][node1] += delta_pheromone\n", - "\n", - " # Séparer la meilleure solution en trajets pour chaque camion\n", - " truck_solutions = []\n", - " num_nodes_per_truck = num_nodes // num_trucks\n", - "\n", - " for i in range(num_trucks):\n", - " start_index = i * num_nodes_per_truck\n", - " end_index = start_index + num_nodes_per_truck\n", - " truck_solution = best_solution[start_index:end_index]\n", - " truck_solutions.append(truck_solution + [0])\n", - " \n", - "\n", - " return truck_solutions, best_distance\n", - "\n", - "num_ants = 10\n", - "num_iterations = 100\n", - "evaporation_rate = 0.5\n", - "alpha = 1\n", - "beta = 1\n", - "\n", - "best_truck_solutions,best_distance = ant_colony_optimization(distance_matrix, num_ants, num_iterations, evaporation_rate, alpha, beta, num_trucks)\n", - "\n", - "# Pour chaque solution de camion, nous devons trouver le chemin le plus court du dépôt au premier nœud du chemin\n", - "for i, truck_solution in enumerate(best_truck_solutions):\n", - " # Créer un graphe à partir de la matrice de distance\n", - " G = nx.from_numpy_matrix(distance_matrix)\n", - " \n", - " # Utiliser l'algorithme de Dijkstra pour trouver le chemin le plus court du dépôt (nœud 0) au premier nœud du chemin du camion\n", - " shortest_path = nx.dijkstra_path(G, 0, truck_solution[1])\n", - " \n", - " # Remplacer le premier nœud du chemin du camion par le chemin le plus court trouvé\n", - " best_truck_solutions[i] = [0] + shortest_path + truck_solution[2:]\n", - "\n", - "# Calculer la distance totale pour chaque solution de camion\n", - "total_distances = [evaluate_solution(truck_solution, distance_matrix) for truck_solution in best_truck_solutions]\n", - "\n", - "# Afficher les solutions et les distances totales pour chaque camion\n", - "for i, (truck_solution, total_distance) in enumerate(zip(best_truck_solutions, total_distances)):\n", - " print(f\"Camion {i+1} :\")\n", - " print(\"Solution :\", truck_solution)\n", - " print(\"Distance totale :\", total_distance)\n", - " print()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "29df0137", - "metadata": {}, - "source": [ - "# En rajoutant la contrainte de Time Window pour une instance de VRPTW\n", - "\n", - "Dans un premier temps on va attribuer des fenêtres de temps pour chaque clients (ville dans notre graphe)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "8266e414-d350-4101-8f15-9cc05ee02934", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "20\n", - "Client 0 : (0, inf)\n", - "Client 1 : (44, 94)\n", - "Client 2 : (99, 111)\n", - "Client 3 : (80, 125)\n", - "Client 4 : (85, 96)\n", - "Client 5 : (71, 85)\n", - "Client 6 : (34, 69)\n", - "Client 7 : (20, 30)\n", - "Client 8 : (46, 56)\n", - "Client 9 : (90, 109)\n", - "Client 10 : (74, 116)\n", - "Client 11 : (95, 112)\n", - "Client 12 : (93, 131)\n", - "Client 13 : (46, 82)\n", - "Client 14 : (86, 124)\n", - "Client 15 : (87, 129)\n", - "Client 16 : (13, 23)\n", - "Client 17 : (0, 28)\n", - "Client 18 : (77, 108)\n", - "Client 19 : (76, 105)\n", - "Client 20 : (78, 94)\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n", - "[(0, 19), (0, 16), (0, 5), (0, 10), (1, 18), (1, 8), (1, 11), (2, 18), (2, 6), (2, 3), (2, 9), (2, 10), (2, 14), (2, 17), (3, 7), (3, 8), (3, 16), (4, 15), (4, 5), (4, 13), (5, 8), (5, 7), (6, 16), (6, 19), (7, 15), (7, 19), (8, 13), (9, 20), (10, 15), (11, 14), (11, 18), (12, 15), (12, 17), (12, 16), (13, 19), (13, 17), (13, 20), (14, 20), (14, 15), (15, 18), (15, 20)]\n" - ] - } - ], - "source": [ - "\n", - "def assign_time_windows(graph):\n", - " # Créer un dictionnaire pour stocker les fenêtres de temps des clients\n", - " time_windows = {}\n", - "\n", - " # Définir la fenêtre de temps pour le dépôt central (nœud 0)\n", - " time_windows[0] = (0, float('inf'))\n", - "\n", - " # Assigner une fenêtre de temps à chaque client\n", - " for node in graph.nodes():\n", - " if node !=0 and node != graph.number_of_nodes() :\n", - " # Générer une fenêtre de temps aléatoire pour chaque client\n", - " start_time = random.randint(0, 100)\n", - " end_time = start_time + random.randint(10, 50)\n", - " time_windows[node] = (start_time, end_time)\n", - " \n", - "\n", - " return time_windows\n", - "\n", - "# Attribuer les fenêtres de temps aux clients\n", - "time_windows = assign_time_windows(graph)\n", - "\n", - "print(max(graph.nodes()))\n", - "# Afficher les fenêtres de temps assignées\n", - "for node, window in time_windows.items():\n", - " print(\"Client\", node, \":\", window)\n", - " \n", - "#paramètres ACO\n", - "\n", - "print(graph.nodes())\n", - "print(graph.edges())\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "747541f5", - "metadata": {}, - "source": [ - "# On va ensuite réadapter l'algorithme pour prendre en compte les time Windows " - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "901e6b93", - "metadata": {}, - "outputs": [], - "source": [ - "import concurrent.futures\n", - "import random\n", - "import numpy as np\n", - "import time\n", - "import heapq\n", - "\n", - "\n", - "# Fonction d'évaluation de la qualité d'une solution (ici, la distance totale)\n", - "def evaluate_solution(solution, distances, time_windows, dijkstra_distances):\n", - " total_distance = 0\n", - " total_delay = 0\n", - " arrival_time = 0\n", - " num_nodes = len(solution)\n", - " waiting_times = []\n", - "\n", - " total_distance += dijkstra_distances[solution[1]]\n", - "\n", - " for i in range(num_nodes - 1):\n", - " current_node = solution[i]\n", - " next_node = solution[i + 1]\n", - " total_distance += distances[current_node][next_node]\n", - " arrival_time += distances[current_node][next_node]\n", - "\n", - " if arrival_time < time_windows[next_node][0]:\n", - " waiting_time = time_windows[next_node][0] - arrival_time\n", - " waiting_times.append((next_node, waiting_time))\n", - " arrival_time = time_windows[next_node][0]\n", - " elif arrival_time > time_windows[next_node][1]:\n", - " total_delay += arrival_time - time_windows[next_node][1]\n", - "\n", - " # Ajouter la distance de retour au dépôt\n", - " total_distance += distances[solution[-1]][solution[0]]\n", - "\n", - " return total_distance, total_delay, waiting_times\n", - "\n", - " \n", - "# Fonction pour l'algorithme de Dijkstra\n", - "def calculate_dijkstra(start_node, distances):\n", - " num_nodes = len(distances)\n", - " shortest_distances = [float('inf')] * num_nodes\n", - " shortest_distances[start_node] = 0\n", - " shortest_paths = [[] for _ in range(num_nodes)]\n", - " shortest_paths[start_node] = [start_node]\n", - " priority_queue = [(0, start_node)]\n", - " while priority_queue:\n", - " current_distance, current_node = heapq.heappop(priority_queue)\n", - " if current_distance == shortest_distances[current_node]:\n", - " for neighbor, distance in enumerate(distances[current_node]):\n", - " new_distance = current_distance + distance\n", - " if new_distance < shortest_distances[neighbor]:\n", - " shortest_distances[neighbor] = new_distance\n", - " shortest_paths[neighbor] = shortest_paths[current_node] + [neighbor]\n", - " heapq.heappush(priority_queue, (new_distance, neighbor))\n", - " return shortest_distances, shortest_paths\n", - "\n", - "\n", - "dijkstra_distances, dijkstra_paths = calculate_dijkstra(0, distance_matrix)\n", - "\n", - "\n", - "def ant_colony_optimization(distances, num_ants, num_iterations, evaporation_rate, alpha, beta, num_trucks):\n", - " num_nodes = len(distances)\n", - " pheromone = np.ones((num_nodes, num_nodes)) \n", - " best_solution = None\n", - " best_distance = float('inf')\n", - " best_delay = float('inf')\n", - " best_score = float('inf') \n", - " best_waiting_times = None\n", - "\n", - " for iteration in range(num_iterations):\n", - " solutions = []\n", - " for ant in range(num_ants):\n", - " visited = set()\n", - " current_node = random.randint(0, num_nodes - 1)\n", - " visited.add(current_node)\n", - " solution = [current_node]\n", - " while len(visited) < num_nodes:\n", - " next_node = None\n", - " probabilities = []\n", - " arrival_time = 0\n", - " for node in range(num_nodes):\n", - " if node not in visited and (node !=0 or len(visited) == num_nodes - 1):\n", - " pheromone_value = pheromone[current_node][node]\n", - " distance_value = distances[current_node][node]\n", - " wait_time = max(0, time_windows[node][0]- (arrival_time + distance_value))\n", - " probability = (pheromone_value ** alpha) * ((1 / (distance_value + wait_time)) ** beta)\n", - " probabilities.append((node, probability))\n", - " total_probability = sum(prob for _, prob in probabilities)\n", - " probabilities = [(node, prob / total_probability) for node, prob in probabilities]\n", - " roulette_wheel = random.random()\n", - " probability_sum = 0\n", - " for node, probability in probabilities:\n", - " probability_sum += probability\n", - " if probability_sum >= roulette_wheel:\n", - " next_node = node\n", - " break\n", - " visited.add(next_node)\n", - " solution.append(next_node)\n", - " current_node = next_node\n", - " solution.append(0)\n", - " solutions.append(solution)\n", - "\n", - " for solution in solutions:\n", - " distance, delay, waiting_times = evaluate_solution(solution, distances, time_windows, dijkstra_distances)\n", - " score = distance + delay\n", - " if score < best_score:\n", - " best_solution = solution\n", - " best_distance = distance\n", - " best_delay = delay\n", - " best_waiting_times = waiting_times\n", - " pheromone *= evaporation_rate\n", - " for solution in solutions:\n", - " delta_pheromone = 1 / (evaluate_solution(solution, distances, time_windows, dijkstra_distances)[0] + 0.01)\n", - " for i in range(num_nodes - 1):\n", - " node1 = solution[i]\n", - " node2 = solution[i + 1]\n", - " pheromone[node1][node2] += delta_pheromone\n", - " pheromone[node2][node1] += delta_pheromone\n", - " truck_solutions = []\n", - " num_nodes_per_truck = num_nodes // num_trucks\n", - " for i in range(num_trucks):\n", - " start_index = i * num_nodes_per_truck\n", - " end_index = start_index + num_nodes_per_truck\n", - " truck_solution = best_solution[start_index:end_index]\n", - " \n", - " # Ajoutez le chemin le plus court entre le nœud 0 et le premier nœud du chemin\n", - " dijkstra_path_to_first_node = dijkstra_paths[truck_solution[0]]\n", - " truck_solution = dijkstra_path_to_first_node + truck_solution\n", - " \n", - " # Ajoutez le chemin le plus court entre le dernier nœud du chemin et le dépôt (nœud 0)\n", - " dijkstra_path_to_depot = dijkstra_paths[truck_solution[-1]]\n", - " truck_solution = truck_solution + dijkstra_path_to_depot\n", - "\n", - " truck_solutions.append(truck_solution)\n", - " return truck_solutions, best_distance, best_waiting_times\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "f24a5980", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Meilleures solutions :\n", - "Camion 1 : [0, 9, 9, 8, 17, 7, 1, 13, 14, 0, 14]\n", - "Camion 2 : [0, 12, 12, 18, 4, 5, 20, 19, 15, 0, 15]\n", - "Camion 3 : [0, 10, 10, 3, 2, 16, 6, 11, 0, 0]\n", - "Distance totale : 48.0\n" - ] - } - ], - "source": [ - "num_thread = 1\n", - "num_ants = 10\n", - "num_iterations = 100\n", - "evaporation_rate = 0.5\n", - "alpha = 1\n", - "beta = 1\n", - "\n", - "num_trucks = 3 # Nombre de camions disponibles\n", - "\n", - "\n", - "\n", - "with concurrent.futures.ThreadPoolExecutor(max_workers=num_thread) as executor:\n", - " futures = [executor.submit(ant_colony_optimization, distance_matrix, num_ants, num_iterations, evaporation_rate, alpha, beta, num_trucks) for _ in range(num_thread)]\n", - "\n", - " for future in concurrent.futures.as_completed(futures):\n", - " best_truck_solutions, best_distance, best_waiting_times = future.result()\n", - " print(\"Meilleures solutions :\")\n", - " for i, truck_solution in enumerate(best_truck_solutions):\n", - " print(f\"Camion {i+1} : {truck_solution}\")\n", - " print(\"Distance totale :\", best_distance)" + "from tests.libs.clustering import split_tour_across_clusters" ] } ],