12/01/18
This commit is contained in:
parent
3c48f975b2
commit
92ae9237d3
5 changed files with 197 additions and 24 deletions
BIN
compte_rendu/images/3_7.png
Normal file
BIN
compte_rendu/images/3_7.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
BIN
compte_rendu/images/3_8_astar.png
Normal file
BIN
compte_rendu/images/3_8_astar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
compte_rendu/images/3_8_dijkstra.png
Normal file
BIN
compte_rendu/images/3_8_dijkstra.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
127
graphe.py
127
graphe.py
|
@ -1,4 +1,7 @@
|
|||
import sys
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
import triangulation
|
||||
import tas
|
||||
|
||||
|
@ -18,7 +21,8 @@ class Graphe:
|
|||
self.nom = nom
|
||||
self.sommets = []
|
||||
self.aretes = []
|
||||
self.cout = Graphe.Cout.TEMPS
|
||||
self.cout = None, Graphe.Cout.TEMPS
|
||||
self.arrivee = None
|
||||
|
||||
def renomme(self, nom):
|
||||
"""Renome le graphe
|
||||
|
@ -35,7 +39,7 @@ class Graphe:
|
|||
|
||||
:return: Le sommet créé.
|
||||
"""
|
||||
s = Sommet((x, y), len(self.sommets))
|
||||
s = Sommet((x, y), len(self.sommets), graphe=self)
|
||||
self.sommets.append(s)
|
||||
return s
|
||||
|
||||
|
@ -77,7 +81,10 @@ class Graphe:
|
|||
for s in self.sommets:
|
||||
dest.changeCouleur(s.couleur)
|
||||
dest.tracePoint((s.x(), s.y()))
|
||||
dest.traceTexte((s.x(), s.y()), 'v' + str(s.num))
|
||||
if hasattr(s, 'nom'):
|
||||
dest.traceTexte((s.x(), s.y()), s.nom)
|
||||
else:
|
||||
dest.traceTexte((s.x(), s.y()), 'v' + str(s.num))
|
||||
|
||||
for a in self.aretes:
|
||||
dest.changeCouleur(a.couleur)
|
||||
|
@ -166,7 +173,7 @@ class Graphe:
|
|||
sommets.actualise(voisin.cle)
|
||||
voisin.precedent = arete
|
||||
|
||||
def dijkstraPartiel(self, depart, arrivee):
|
||||
def dijkstraPartiel(self, depart=None, arrivee=None):
|
||||
"""Calcule les plus courts chemins depuis le sommet `depart` vers
|
||||
`arrivee` (attention, effets de bord).
|
||||
|
||||
|
@ -177,20 +184,63 @@ class Graphe:
|
|||
s.precedent = None
|
||||
sommets = tas.Tas(lambda x: -x.cumul)
|
||||
depart = depart or self.sommets[0]
|
||||
arrivee = arrivee or self.sommets[-1]
|
||||
depart.cumul = 0
|
||||
depart.cle = sommets.ajoute(depart)
|
||||
while not sommets.empty():
|
||||
n_visite = 0
|
||||
quit = False
|
||||
while not (sommets.empty() or quit):
|
||||
s = sommets.pop()
|
||||
for arete in s.aretes:
|
||||
voisin = arete.voisin(s)
|
||||
inf = voisin.cumul is None
|
||||
if inf or s.cumul + arete.cout < voisin.cumul:
|
||||
voisin.cumul = s.cumul + arete.cout
|
||||
voisin.precedent = arete
|
||||
if inf: # cumul infini
|
||||
n_visite += 1
|
||||
voisin.couleur = (0.5, 0.9, 0.1)
|
||||
if voisin == arrivee:
|
||||
quit = True
|
||||
voisin.cle = sommets.ajoute(voisin)
|
||||
else:
|
||||
sommets.actualise(voisin.cle)
|
||||
return self.cheminOptimal(arrivee), n_visite
|
||||
|
||||
def astar(self, depart=None, arrivee=None):
|
||||
"""Calcule les plus courts chemins depuis le sommet `depart` vers
|
||||
`arrivee` (attention, effets de bord).
|
||||
|
||||
:param depart: Sommet de départ.
|
||||
"""
|
||||
for s in self.sommets:
|
||||
s.cumul = None
|
||||
s.precedent = None
|
||||
self.arrivee = arrivee or self.sommets[-1]
|
||||
arrivee = self.arrivee
|
||||
sommets = tas.Tas(lambda x: -(x.cumul + x.minCumulRestant))
|
||||
depart = depart or self.sommets[0]
|
||||
depart.cumul = 0
|
||||
depart.cle = sommets.ajoute(depart)
|
||||
n_visite = 0
|
||||
quit = False
|
||||
while not (sommets.empty() or quit):
|
||||
s = sommets.pop()
|
||||
for arete in s.aretes:
|
||||
voisin = arete.voisin(s)
|
||||
inf = voisin.cumul is None
|
||||
if inf or s.cumul + arete.cout < voisin.cumul:
|
||||
voisin.cumul = s.cumul + arete.cout
|
||||
voisin.precedent = arete
|
||||
if inf: # cumul infini
|
||||
n_visite += 1
|
||||
voisin.couleur = (0.5, 0.9, 0.1)
|
||||
if voisin == arrivee:
|
||||
quit = True
|
||||
voisin.cle = sommets.ajoute(voisin)
|
||||
else:
|
||||
sommets.actualise(voisin.cle)
|
||||
return self.cheminOptimal(arrivee), n_visite
|
||||
|
||||
def traceArbreDesChemins(self):
|
||||
"""Change la couleur des chemins optimaux en violet-rose
|
||||
|
@ -198,9 +248,9 @@ class Graphe:
|
|||
"""
|
||||
for s in self.sommets:
|
||||
if s.precedent:
|
||||
s.precedent.couleur = (252/255, 17/255, 189/255)
|
||||
s.precedent.couleur = (252 / 255, 17 / 255, 189 / 255)
|
||||
if not s.cumul: # sommet de départ
|
||||
s.couleur = (10/255, 98/255, 252/255)
|
||||
s.couleur = (10 / 255, 98 / 255, 252 / 255)
|
||||
|
||||
def fixeCarburantCommeCout(self):
|
||||
"""Fixe le carburant pour cout lors du calcul de plus court chemin."""
|
||||
|
@ -235,11 +285,60 @@ class Graphe:
|
|||
for a in chemin:
|
||||
a.couleur = c
|
||||
|
||||
def matriceCout(self, tournee):
|
||||
"""Calcule la matrice de cout d'une tournée.
|
||||
|
||||
:param tournee:La liste des étapes avec en première position le départ.
|
||||
"""
|
||||
n = len(tournee)
|
||||
matrice = np.zeros((n, n))
|
||||
for x, sx in enumerate(tournee):
|
||||
self.dijkstra(sx)
|
||||
for y, sy in enumerate(tournee):
|
||||
matrice[x, y] = matrice[y, x] = sy.cumul
|
||||
return matrice
|
||||
|
||||
def voyageurDeCommerceNaif(self, tournee):
|
||||
meilleurItineraire = []
|
||||
minCout = sys.float_info.max
|
||||
matrice = self.matriceCout(tournee)
|
||||
cout = 0
|
||||
visite = [False]*len(tournee)
|
||||
visite[0] = True
|
||||
itineraire = [0]
|
||||
def backtrack():
|
||||
nonlocal meilleurItineraire, minCout, matrice, cout, visite, itineraire
|
||||
if cout < minCout:
|
||||
if len(itineraire)==len(tournee):
|
||||
if cout + matrice[0, itineraire[-1]] < minCout:
|
||||
minCout = cout + matrice[0, itineraire[-1]]
|
||||
meilleurItineraire = [tournee[x] for x in itineraire]
|
||||
else:
|
||||
for i,sommet_visite in enumerate(visite):
|
||||
if not sommet_visite:
|
||||
visite[i] = True
|
||||
indicePrec = itineraire[-1]
|
||||
itineraire.append(i)
|
||||
cout += matrice[i, indicePrec]
|
||||
backtrack()
|
||||
visite[i] = False
|
||||
cout -= matrice[i, indicePrec]
|
||||
itineraire.pop()
|
||||
backtrack()
|
||||
return minCout, meilleurItineraire
|
||||
|
||||
def traceItineraire(self, itineraire):
|
||||
for i,x in enumerate(itineraire):
|
||||
x.nom = "s" + str(i)
|
||||
suivant = itineraire[(i+1)%len(itineraire)]
|
||||
c,_ = self.astar(x, suivant)
|
||||
self.colorieChemin(c, (0.8, 0.1, 0.8))
|
||||
|
||||
|
||||
class Sommet:
|
||||
"""Implémente un sommet de graphe."""
|
||||
|
||||
def __init__(self, pos, num, couleur=(0., 0., 0.)):
|
||||
def __init__(self, pos, num, couleur=(0., 0., 0.), graphe=None):
|
||||
"""Initialise un sommet.
|
||||
|
||||
:param pos: couple donnant la position du point.
|
||||
|
@ -252,6 +351,18 @@ class Sommet:
|
|||
self.aretes = set()
|
||||
self.cumul = None
|
||||
self.precedent = None
|
||||
self.graphe = graphe
|
||||
|
||||
@property
|
||||
def minCumulRestant(self):
|
||||
x, y = self.graphe.arrivee.pos
|
||||
d = ((self.pos[0] - x)**2 + (self.pos[1] - y)**2)**(1 / 2)
|
||||
if self.graphe.cout is Graphe.Cout.TEMPS:
|
||||
return d / 90 # On minore le temps en divisant par la vitesse max
|
||||
elif self.graphe.cout is Graphe.Cout.CARBURANT:
|
||||
return d
|
||||
else:
|
||||
return 0
|
||||
|
||||
def __str__(self):
|
||||
return "v{} (x = {} km y = {} km)".format(
|
||||
|
|
94
test.py
94
test.py
|
@ -269,6 +269,84 @@ def testQuestion3_6():
|
|||
pl.show()
|
||||
|
||||
|
||||
def testQuestion3_7():
|
||||
"""Trace le plus court chemin avec dijkstra."""
|
||||
g = graphe.pointsAleatoires(30, 30)
|
||||
g.fixeTempsCommeCout()
|
||||
|
||||
graphe.reseauRapide(g)
|
||||
g.dijkstraPartiel(g.sommets[0], g.sommets[-1])
|
||||
g.traceArbreDesChemins()
|
||||
g.renomme("Dijkstra partiel")
|
||||
graphique.affiche(g, (0, 0), 10.)
|
||||
|
||||
|
||||
def testQuestion3_8():
|
||||
"""Trace le plus court chemin avec dijkstra."""
|
||||
g = graphe.pointsAleatoires(30, 30)
|
||||
g.fixeCarburantCommeCout()
|
||||
|
||||
graphe.reseauRapide(g)
|
||||
g.astar(g.sommets[0], g.sommets[-1])
|
||||
g.traceArbreDesChemins()
|
||||
g.renomme("A*")
|
||||
graphique.affiche(g, (0, 0), 10., blocage=False)
|
||||
g.dijkstraPartiel(g.sommets[0], g.sommets[-1])
|
||||
g.traceArbreDesChemins()
|
||||
g.renomme("Dijkstra partiel")
|
||||
graphique.affiche(g, (0, 0), 10.)
|
||||
|
||||
|
||||
def testQuestion3_9():
|
||||
"""Compare Dijkstra avec et sans tas et A*."""
|
||||
prepare = lambda p : graphe.reseauRapide(graphe.pointsAleatoires(p, 10))
|
||||
valeurs_n = list(map(lambda x: int(x), np.logspace(1, 3, 50)))
|
||||
temps1 = chronometre(graphe.Graphe.dijkstra, prepare, valeurs_n)
|
||||
temps2 = chronometre(graphe.Graphe.dijkstraPartiel, prepare, valeurs_n)
|
||||
temps3 = chronometre(graphe.Graphe.astar, prepare, valeurs_n)
|
||||
pl.close('all')
|
||||
pl.title("Comparaison du temps d'exécution de `dijkstra`, `dijkstraPartiel` et `astar`.")
|
||||
pl.plot(valeurs_n, temps1, label='Dijkstra')
|
||||
pl.plot(valeurs_n, temps2, label='Dijkstra partiel avec tas')
|
||||
pl.plot(valeurs_n, temps3, label='A*')
|
||||
pl.legend(loc='best')
|
||||
pl.xlabel("n")
|
||||
pl.ylabel("temps")
|
||||
pl.show()
|
||||
pl.title("Comparaison du temps d'exécution de `dijkstra`, `dijkstraPartiel` et `astar`.")
|
||||
pl.loglog(valeurs_n, temps1, label='Dijkstra')
|
||||
pl.loglog(valeurs_n, temps2, label='Dijkstra partiel avec tas')
|
||||
pl.loglog(valeurs_n, temps3, label='A*')
|
||||
pl.legend(loc='best')
|
||||
pl.xlabel("n")
|
||||
pl.ylabel("temps")
|
||||
pl.show()
|
||||
|
||||
|
||||
def testQuestion4_1():
|
||||
"""Trace le plus court chemin avec dijkstra."""
|
||||
g = graphe.pointsAleatoires(30, 30)
|
||||
|
||||
graphe.reseauRapide(g)
|
||||
g.renomme("graphe")
|
||||
print("Points 0,1 et 2")
|
||||
tournee = [g.sommets[i] for i in (0, 1, 2)]
|
||||
print(g.matriceCout(tournee))
|
||||
graphique.affiche(g, (0, 0), 10.)
|
||||
|
||||
|
||||
def testQuestion4_2():
|
||||
g = graphe.pointsAleatoires(30, 30)
|
||||
|
||||
graphe.reseauRapide(g)
|
||||
g.renomme("graphe")
|
||||
print("Points 0,1,2 et 7")
|
||||
tournee = [g.sommets[i] for i in (0, 1, 2, 7)]
|
||||
cout,iti = g.voyageurDeCommerceNaif(tournee)
|
||||
g.traceItineraire(iti)
|
||||
graphique.affiche(g, (0, 0), 10.)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
n = sys.argv[1]
|
||||
if n in ('--help', '-h'):
|
||||
|
@ -276,19 +354,3 @@ if __name__ == '__main__':
|
|||
else:
|
||||
print('Question ', n)
|
||||
locals()['testQuestion'+n]()
|
||||
# testQuestion1_2()
|
||||
# testQuestion1_3()
|
||||
# testQuestion1_4()
|
||||
# testQuestion2_2()
|
||||
# testQuestion2_4()
|
||||
# testQuestion2_5()
|
||||
# testQuestion2_6()
|
||||
# testQuestion2_7()
|
||||
# testQuestion2_8()
|
||||
# testQuestion2_9()
|
||||
# testQuestion3_1()
|
||||
# testQuestion3_2()
|
||||
# testQuestion3_3()
|
||||
# testQuestion3_4()
|
||||
# testQuestion3_5()
|
||||
# testQuestion3_6()
|
||||
|
|
Loading…
Reference in a new issue