Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Toujours à la recherche de nouveaux exploits à accomplir, vous décidez de par

Commencez par trouver ce qui vous semble être le plus court chemin sans technique particulière. Notez votre réponse.

Directement Dijkstra

### 1.b Algorithme de Dijkstra

Sans l'implémenter pour le moment, trouvez le plus court chemin en utilisant manuellement l'algorithme de Dijkstra.
Expand All @@ -26,6 +28,8 @@ Notez chaque étape de votre raisonnement sur une feuille ou un document texte p

Comparez avec votre réponse précédente.

Bordeaux(0) -> Orléans(24) -> Paris(31) -> Strasbourg(57)

### 1.c Implémentation

Suivez précisément les étapes de mise en place :
Expand Down Expand Up @@ -138,8 +142,12 @@ Adaptez cette commande aux autres algorithmes pour la suite (et retirer le chemi

Combien de calculs de distance avez-vous effectué pour parvenir au résultat Bordeaux -> Strasbourg ?

13

Autrement dit, combien de fois avez vous mis à jour la distance pour un point du graphe ?

13

## Partie 2 : Amélioration avec l'algorithme A* (a-star)

Dijkstra garantit la meilleure solution possible. Mais vous avez sans doute remarqué qu'il s'aventure dans des recoins peu pertinents d'un point de vue "intelligent" (par exemple, tester Rouen dans un trajet Bordeaux -> Strasbourg...).
Expand Down Expand Up @@ -212,8 +220,12 @@ N'oubliez pas que vous pouvez, dans une méthode de `AStar`, appeler la méthode

Combien de calculs de distance ont été nécessaires pour calculer la solution du trajet Bordeaux -> Strasbourg ?

5

Que pensez-vous de la solution obtenue, comparée à l'algorithme de Dijsktra ?

Bien plus efficace

## Partie 3 : Variation avec SPFA (Shortest Path Faster Algorithm)

L'algorithme du plus court chemin pourrait en réalité s'appeler l'algorithme du chemin optimal, car on ne calcule pas toujours des distances.
Expand Down
22 changes: 22 additions & 0 deletions __main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from pathfinder.heuristics import heuristics
from pathfinder.city import City
from pathfinder.pathfinder import Pathfinder
from pathfinder.graphs import graph, spfa_graph
from pathfinder.spfa import SPFA
from pathfinder.types import Path
from pathfinder.astar import AStar

pathfinder: Pathfinder = Pathfinder(graph)
path: Path = pathfinder.get_shortest_path(City.BORDEAUX, City.STRASBOURG)
print(path)
print(pathfinder.get_counter())

astar = AStar(graph, heuristics)
second_path: Path = astar.get_shortest_path(City.BORDEAUX, City.STRASBOURG)
print(second_path)
print(astar.get_counter())

spfa = SPFA(spfa_graph)
third_path: Path = spfa.get_shortest_path(City.BORDEAUX, City.STRASBOURG)
print(third_path)
print(spfa.get_counter())
81 changes: 81 additions & 0 deletions pathfinder/astar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from pathfinder.city import City
from pathfinder.graphs import Graph
from pathfinder.pathfinder import Pathfinder
from pathfinder.types import Path


class AStar(Pathfinder):

def __init__(self, graph: Graph, heuristics: dict[City, float]):
"""We define also heuristics in this class"""
self.__heuristics: dict[City, float] = heuristics
super().__init__(graph)

def search_end(self, Town: City, total: float, end: City):
"""We search end and the distance she has from start"""

# We look all city near to the start until the end we define
while Town != end:
# We get the length to go at this city from the start
total = self.get_all_city()[Town]["Length"]

# We increment counter for each City we visit
self.set_counter(self.get_counter()+1)

# for each neighbors of the city
for neighbors in self.get_graph()[Town]:
# We begun by ask if we known this city
# and we add it for later if its isn't
if (neighbors not in self.get_all_city()):
self.set_all_city(self.add_city_to_do(
neighbors, self.get_length(Town, neighbors)+total,
Town), neighbors)

# little difference when we find end we stop the search
if (neighbors == end):
Town = neighbors
break

# if we already know this city we check if the length
# by this "town" is under the length we save
else:

# if it is under we remove the ancien length
# and replace by the new length
if (self.get_all_city()[neighbors]["Length"] >
self.get_graph()[Town][neighbors]+total
and neighbors in self.get_all_name()):
self.remove_city_to_do(
self.get_all_name().index(neighbors))
self.set_all_city(self.add_city_to_do(
neighbors, self.get_length(Town, neighbors)+total,
Town), neighbors)
# After Check all neighbor of a City we find the minimum length
# of all City not look
Town = self.remove_city_to_do(
self.get_index_minimum(self.get_all_number()))

# We increment counter for end City we visit
self.set_counter(self.get_counter()+1)
return Town

def get_length(self, town, neighbor):
"""We return the length between City in graph with heuristics"""
return super().get_length(town, neighbor)*self.get_heuristics(neighbor)

def reverse_path_from_end(self, town: City):
"""When we find end City we make all reverse way
for find shortest path"""
total: float = 0
steps: list[City] = []
# until we return to start we add City on "steps" and we add the length
while town is not None:
steps.insert(0, town)
if self.get_all_city()[town]["Previous_city"] is not None:
total += super().get_length(
town, self.get_all_city()[town]["Previous_city"])
town = self.get_all_city()[town]["Previous_city"]
return Path(total=total, steps=steps)

def get_heuristics(self, town: City):
return self.__heuristics[town]
16 changes: 16 additions & 0 deletions pathfinder/city.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from enum import Enum


class City(Enum):
BORDEAUX = "Bordeaux"
DIJON = "Dijon"
LILLE = "Lille"
LYON = "Lyon"
MARSEILLE = "Marseille"
NANTES = "Nantes"
ORLEANS = "Orléans"
PARIS = "Paris"
RENNES = "Rennes"
ROUEN = "Rouen"
STRASBOURG = "Strasbourg"
TOULOUSE = "Toulouse"
121 changes: 121 additions & 0 deletions pathfinder/graphs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from pathfinder.city import City

Graph = dict[City, dict[City, float]]

graph: Graph = {
City.BORDEAUX: {
City.NANTES: 19,
City.ORLEANS: 24,
City.LYON: 31,
City.TOULOUSE: 14
},
City.DIJON: {
City.STRASBOURG: 20,
City.PARIS: 16,
City.ORLEANS: 15,
City.LYON: 11
},
City.LILLE: {
City.ROUEN: 12,
City.PARIS: 13,
City.STRASBOURG: 29
},
City.LYON: {
City.BORDEAUX: 31,
City.DIJON: 11,
City.ORLEANS: 20,
City.MARSEILLE: 18,
City.TOULOUSE: 28
},
City.MARSEILLE: {
City.LYON: 18,
City.TOULOUSE: 22
},
City.NANTES: {
City.BORDEAUX: 19,
City.ORLEANS: 16,
City.RENNES: 6,
City.ROUEN: 19
},
City.ORLEANS: {
City.BORDEAUX: 24,
City.DIJON: 15,
City.LYON: 20,
City.NANTES: 16,
City.PARIS: 7,
City.ROUEN: 11
},
City.PARIS: {
City.DIJON: 16,
City.LILLE: 13,
City.ORLEANS: 7,
City.ROUEN: 7,
City.STRASBOURG: 26
},
City.RENNES: {
City.NANTES: 6,
City.ROUEN: 17,
},
City.ROUEN: {
City.LILLE: 12,
City.NANTES: 19,
City.ORLEANS: 11,
City.PARIS: 7,
City.RENNES: 17
},
City.STRASBOURG: {
City.DIJON: 20,
City.LILLE: 29,
City.PARIS: 26,
},
City.TOULOUSE: {
City.BORDEAUX: 14,
City.LYON: 28,
City.MARSEILLE: 22,
}
}

spfa_graph: Graph = {
City.BORDEAUX: {
City.NANTES: 50,
City.TOULOUSE: 50
},
City.DIJON: {
City.STRASBOURG: 30,
},
City.LILLE: {
},
City.LYON: {
City.DIJON: 20,
},
City.MARSEILLE: {
City.LYON: 30,
},
City.NANTES: {
City.ORLEANS: 10,
City.RENNES: 20,
},
City.ORLEANS: {
City.PARIS: 40,
City.STRASBOURG: 15
},
City.PARIS: {
City.LILLE: 50,
City.ORLEANS: -30,
City.STRASBOURG: -10,
},
City.RENNES: {
City.PARIS: 20,
City.ROUEN: 10,
},
City.ROUEN: {
City.PARIS: -50,
},
City.STRASBOURG: {
City.LILLE: 50,
},
City.TOULOUSE: {
City.LYON: -75,
City.MARSEILLE: 40,
}
}
17 changes: 17 additions & 0 deletions pathfinder/heuristics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from pathfinder.city import City


heuristics: dict[City, float] = {
City.BORDEAUX: 47,
City.DIJON: 15,
City.LILLE: 25,
City.LYON: 24,
City.MARSEILLE: 39,
City.NANTES: 44,
City.ORLEANS: 27,
City.PARIS: 25,
City.RENNES: 43,
City.ROUEN: 31,
City.STRASBOURG: 0,
City.TOULOUSE: 46,
}
Loading