|
|
import networkx as nx
|
|
|
import matplotlib.pyplot as plt
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
#! H=nx.Graph() #cr ́ee un graphe
|
|
|
#! H.add_edge(0,1) #ajoute une arˆete entre les sommets 0 et 1
|
|
|
#! H.add_edges_from([(3,0),(3,4)]) #ajoute les arˆetes d’une liste donn ́ee
|
|
|
#! H.add_node("toto") #ajoute un sommet nomm ́e "toto"
|
|
|
#! H.remove_node(s) #supprime le sommet s
|
|
|
#! H.nodes #sommets du graphe (attention, pour en faire
|
|
|
#! # une vraie liste Python, ́ecrire: list(H.nodes))
|
|
|
#! H.edges #arˆetes du graphe (attention, pour en faire
|
|
|
#! # une vraie liste Python, ́ecrire: list(H.edges))
|
|
|
#! H.edges(s) #les arˆetes qui touchent le sommet s
|
|
|
#! H.neighbors(s) #un it ́erateur sur les voisins du sommet s dans H
|
|
|
#! # pour obtenir une liste, ́ecrire: list(H.neighbors(s))
|
|
|
#! H.nodes[s]["attri"] #acc`ede `a l’attribut nomm ́e "attri" du sommet s
|
|
|
#! # (tant en lecture qu’en ́ecriture)
|
|
|
#! # exemple: H.nodes[s]["attri"]=2
|
|
|
#! # ou alors print(H.nodes[s]["attri"])
|
|
|
|
|
|
# Exercice 1
|
|
|
|
|
|
##################################
|
|
|
##Un graphe pour tester Dijkstra
|
|
|
###################################
|
|
|
print("Un graphe pour tester Dijkstra")
|
|
|
G=nx.Graph()
|
|
|
G.add_nodes_from(["A","B","C","D","E","F","G","H","I","J"],distance=None)
|
|
|
print(G.nodes())
|
|
|
G.add_edges_from([("A", "B", {"weight": 4}),("A", "C", {"weight": 2}),
|
|
|
("A", "E", {"weight": 1}),("B", "F", {"weight": 3}),
|
|
|
("C", "G", {"weight": 1}),("C", "H", {"weight": 2}),
|
|
|
("D", "H", {"weight": 1}),("E", "J", {"weight": 5}),
|
|
|
("F", "I", {"weight": 2}),("I", "J", {"weight": 5}),
|
|
|
("H", "J", {"weight": 6})])
|
|
|
print(G.edges())
|
|
|
#########################
|
|
|
print(G.edges[("A","B")]["weight"])
|
|
|
print(G.nodes["A"]["distance"])
|
|
|
#########################
|
|
|
|
|
|
#? 1.
|
|
|
# On rappelle ci-dessous l’algorithme de Dijkstra qui calcule les distances `a un sommet
|
|
|
# source donn ́e :
|
|
|
# Algorithme de Dijkstra pour le graphe G `a partir du sommet source s
|
|
|
# • L repr ́esentera la fronti`ere. Contient initialement seulement s.
|
|
|
# • La valeur de distance d est initialis ́ee `a d(s)=0 et `a d(v)=∞ pour
|
|
|
# chaque autre sommet v
|
|
|
# • Une liste T contient les sommets qui ont ́et ́e compl`etement trait ́es.
|
|
|
# Initialement T est vide.
|
|
|
# • Tant que L n’est pas vide :
|
|
|
# ⋆ choisir un sommet v dans L qui a une valeur de distance d(v)
|
|
|
# minimale
|
|
|
# ⋆ pour tout voisin w de v qui n’est pas dans T :
|
|
|
# - si d(v) plus le poids p de l’arˆete (v,w) est inf ́erieur `a
|
|
|
# d(w), on fixe d(w)=d(v)+p
|
|
|
# - ajouter w `a L
|
|
|
# ⋆ enlever v de L, ajouter v `a T
|
|
|
# Impl ́ementez l’algorithme en suivant les ́etapes suivantes :
|
|
|
# 1. ́Ecrire une fonction mise_a_jour_voisin(G,n,v) qui met `a jour la distance du som-
|
|
|
# met v `a la source (v est suppos ́e voisin de n dans le graphe G) `a partir de celle du
|
|
|
# sommet n (en supposant que la distance du sommet n `a la source est un nombre)
|
|
|
|
|
|
def mise_a_jour_voisin(G,n,v):
|
|
|
G.nodes[v]["distance"]=G.edges[(n,v)]["weight"]
|
|
|
|
|
|
print(mise_a_jour_voisin(G,"A","B"))
|
|
|
|
|
|
# 2.
|
|
|
# Ecrire une fonction choix_prochain_sommet(G,L), qui renvoie le sommet de la fronti`ere
|
|
|
# L qui sera choisi pour la prochaine it ́eration de l’algorithme de Dijkstra.
|
|
|
|
|
|
def choix_prochain_sommet(G,L):
|
|
|
return min(L,key=lambda x:G.nodes[x]["distance"])
|
|
|
|
|
|
print(choix_prochain_sommet(G,["A","B","C","D","E","F","G","H","I","J"]))
|
|
|
|
|
|
# 3.
|
|
|
# Ecrire une fonction Dijkstra(G,s) qui d ́etermine les distances entre le sommet s et
|
|
|
# tous les autres sommets dans le graphe valu ́e G.
|
|
|
|
|
|
def Dijkstra(G,s):
|
|
|
L=[s]
|
|
|
G.nodes[s]["distance"]=0
|
|
|
while L!=[]:
|
|
|
v=choix_prochain_sommet(G,L)
|
|
|
for w in G.neighbors(v):
|
|
|
if w not in L:
|
|
|
if G.nodes[v]["distance"]+G.edges[(v,w)]["weight"]<G.nodes[w]["distance"]:
|
|
|
G.nodes[w]["distance"]=G.nodes[v]["distance"]+G.edges[(v,w)]["weight"]
|
|
|
L.append(w)
|
|
|
L.remove(v)
|
|
|
|
|
|
print(Dijkstra(G,"A"))
|
|
|
|
|
|
# 4.Coder et tester l’algorithme de Floyd-Warshall, rappel ́e ci-dessous :
|
|
|
# Algorithme de Floyd-Warshall pour le graphe G
|
|
|
# • Les sommets sont ordonn ́es : s1 ... sn avec n le nombre de sommets
|
|
|
# • On initialise une matrice D de taille n×n, o`u D(i, j) devra contenir la
|
|
|
# distance entre le sommet si et le sommet sj . Pour toute arˆete entre si et
|
|
|
# sj de poids pij , on fixe D(i, j) = pij , et pour tout i on fixe D(i, i) = 0.
|
|
|
# Dans les autres cas, on fixe D(i, j) = ∞.
|
|
|
# • Pour k allant de 1 `a n :
|
|
|
# • Pour i allant de 1 `a n :
|
|
|
# • Pour j allant de 1 `a n :
|
|
|
# D(i, j) = min{D(i, j), D(i, k) + D(k, j)}
|
|
|
# • Renvoyer D
|
|
|
# Pourquoi n’est-t-il pas n ́ecessaire de copier la matrice D `a chaque ́etape ? V ́erifier que
|
|
|
# l’algorithme ne va pas ́ecraser des donn ́ees importantes en cours de route
|
|
|
|
|
|
def Floyd_Warshall(G):
|
|
|
n=len(G.nodes())
|
|
|
D=[[float("inf") for i in range(n)] for j in range(n)]
|
|
|
for i in range(n):
|
|
|
D[i][i]=0
|
|
|
for j in range(n):
|
|
|
if (i,j) in G.edges():
|
|
|
D[i][j]=G.edges[(i,j)]["weight"]
|
|
|
for k in range(n):
|
|
|
for i in range(n):
|
|
|
for j in range(n):
|
|
|
D[i][j]=min(D[i][j],D[i][k]+D[k][j])
|
|
|
return D
|
|
|
|
|
|
print(Floyd_Warshall(G))
|