Cours de Graph en python, Exercises of Physics

cours et exercice des Graphs en python

Typology: Exercises

2019/2020

Uploaded on 04/26/2023

lahcen-moumoun
lahcen-moumoun 🇲🇦

1 document

1 / 5

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
I.T.C. : Les graphes : graphes pondérés et recherche des distances
minimales.
Rappels sur la modélisation
On rappelle qu’un graphe pondéré (orienté par exemple) est représenté en python de 3 manières différentes :
1. Une liste contenant deux listes, une liste contenant les sommets du graphes, et une liste contenant les arcs (ou arrêtes) du
graphes, elle même représentées par une liste de taille 3 la troisième valeur représentant la pondération).
2. Un dictionnaire dont les clefs sont les sommets et les valeurs la liste des voisins du sommet avec la pondération du chemin
associé (donc une liste de liste). On parle de liste d’adjacence.
3. Une liste des sommets et une liste de liste représentant la matrice d’adjacence.
On peut écrire une fonction qui prend en entrée une liste de sommets et une liste d’arrêtes (une liste de liste donc) d’un graphe non
orienté et renvoie le dictionnaire associé à la liste d’adjacence.
def adja(S,A):
’’’ fonction qui prend en entrée une liste de sommets et une liste de listes (arrêtes du graphe) et renvoie un dictionnaire correspondant à la liste d’adjacence
(A : list, S : list)--> (dico : dict)’’’
dico={}
for sommet in S :
dico[sommet]=[]
for arrete in A:
s1,s2,pond=arrete[0],arrete[1],arrete[2]
dico[s1].append([s2,pond])
#dico[s2].append([s1,pond]) à rajouter si le graphe est non orienté)
return dico
On peut aussi écrire une fonction qui prend en entrée deux listes Set Atel que (S,A)représente un graphe non orienté et renvoie
la matrice d’adjacence associée. Et faire de même dans le cas le graphe est représenté par un dictionnaire (qui représente sa liste
d’adjacence).
def matriceadja(S,A) :
n=len(S)
mat=[[0 for _ in range(n) ] for _ in range(n) ]
trad={}
k=0
for sommet in S :
trad[sommet]=k
k=k+1
for arrete in A:
s1,s2=trad[arrete[0]],trad[arrete[1]]
mat[s1][s2]=arrete[2]
#mat[s2][s1]=arrete[2]
return mat
def matriceadja(D) :
key=D.keys()
n=len(key)
mat=[[0 for _ in range(n) ] for _ in range(n) ]
trad={}
k=0
for sommet in key :
1
pf3
pf4
pf5

Partial preview of the text

Download Cours de Graph en python and more Exercises Physics in PDF only on Docsity!

I.T.C. : Les graphes : graphes pondérés et recherche des distances

minimales.

Rappels sur la modélisation

On rappelle qu’un graphe pondéré (orienté par exemple) est représenté en python de 3 manières différentes :

  1. Une liste contenant deux listes, une liste contenant les sommets du graphes, et une liste contenant les arcs (ou arrêtes) du graphes, elle même représentées par une liste de taille 3 la troisième valeur représentant la pondération).
  2. Un dictionnaire dont les clefs sont les sommets et les valeurs la liste des voisins du sommet avec la pondération du chemin associé (donc une liste de liste). On parle de liste d’adjacence.
  3. Une liste des sommets et une liste de liste représentant la matrice d’adjacence.

On peut écrire une fonction qui prend en entrée une liste de sommets et une liste d’arrêtes (une liste de liste donc) d’un graphe non orienté et renvoie le dictionnaire associé à la liste d’adjacence.

def adja(S,A): ’’’ fonction qui prend en entrée une liste de sommets et une liste de listes (arrêtes du graphe) et r (A : list, S : list)--> (dico : dict)’’’ dico={} for sommet in S : dico[sommet]=[] for arrete in A: s1,s2,pond=arrete[0],arrete[1],arrete[2] dico[s1].append([s2,pond]) #dico[s2].append([s1,pond]) à rajouter si le graphe est non orienté) return dico

On peut aussi écrire une fonction qui prend en entrée deux listes S et A tel que (S, A) représente un graphe non orienté et renvoie la matrice d’adjacence associée. Et faire de même dans le cas où le graphe est représenté par un dictionnaire (qui représente sa liste d’adjacence).

def matriceadja(S,A) : n=len(S) mat=[[0 for _ in range(n) ] for _ in range(n) ] trad={} k= for sommet in S : trad[sommet]=k k=k+ for arrete in A: s1,s2=trad[arrete[0]],trad[arrete[1]] mat[s1][s2]=arrete[2] #mat[s2][s1]=arrete[2] return mat

def matriceadja(D) : key=D.keys() n=len(key) mat=[[0 for _ in range(n) ] for _ in range(n) ] trad={} k= for sommet in key :

trad[sommet]=k k=k+ for sommet in key: for voisin in D[sommet]: s1=trad[sommet] s2=trad[voisin[0]] mat[s1][s2]=voisin[1] #mat[s2][s1]=voisin[1] return mat

Rappels des parcours pour les graphes pondérés

On rappelle ici les algorithmes de parcours en profondeur et en largeur, dans le cas d’un graphe pondéré.

Parcours en profondeur

On utilise la structure de pile : from collections import deque def parcoursprof_it(graphe,sommet): visite=[] marque={} attente=deque() attente.append(sommet) while len(attente)>0: sommet=attente.pop() if sommet not in marque : visite.append(sommet) marque[sommet]= for vois in graphe[sommet]: if vois[0] not in marque: attente.append(vois[0]) return visite

Parcours en largeur

On utilise la structure de file : from collections import deque def parcourslargeur_it(graphe,sommet): visite=[] marque={} attente=deque() attente.append(sommet) while len(attente)>0: sommet=attente.popleft() if sommet not in marque : visite.append(sommet) marque[sommet]= for vois in graphe[sommet]: if vois[0] not in marque: attente.append(vois[0]) return visite

Algorithme de Dijkstra

on suppose dans cette partie que le graphe est connexe. L’objectif de cette partie est de construire un algorithme pour trouver le plus court chemin entre deux sommets dans un graphe pondéré orienté (ou non). Pour cela, on utilise un algorithme glouton qui repose sur le principe suivant : si dans un graphe pondéré,

d={k : float(’inf’) for k in G} d[s]= while len(d)>0: som=mini(d) for vois in G[som]: voisin,dist=vois[0],vois[1] if voisin not in D : d[voisin] = min(d[voisin] , d[som] + dist) D[som]=d[som] del d[som] return D

Analyse rapide : La terminaison est évidente, un variant de boucle étant tk la taille du dictionnaire d à l’étape k de la boucle while. La complexité est dans le pire des cas en O(n^2 ) où n est le nombre de sommet (n étapes dans la boucle while et moins de n étapes dans la boucle for). Remarque : il suffit de modifier la condition d’arrêt par while fin in d pour que l’algorithme s’arrête quand l’on sait la distance minimal de s à f in

A-star

Nous allons chercher un algorithme qui permet de trouver "un court chemin" entre deux sommets par une méthode heuristique. L’idée d’une méthode heuristique est de donner un algorithme qui renvoie une solution non optimale mais convenable et qui est obtenu en un temps raisonnable (ce qui est très utile dans les cas où aucun algorithme optimal n’est de complexité raisonnable). Nous avons déjà mis en oeuvre ce principe dans le cadre des algorithmes "gloutons". Pour cela, nous allons utiliser une fonction h, dont les données sont issues d’informations extérieures, qui prend en entrée un sommet s du graphe et renvoie un flottant (ou un entier) positif. Cette fonction "rajoutera" à chaque étape une pondération pour le choix du sommet prioritaire : l’idée étant d’éliminer des sommets qui semble (d’après les données extérieurs) inutile : on peut pour cela utiliser une "distance à vol d’oiseau" comme dans l’exemple ci-dessous, ou un nombre correspondant à une estimation du nombre de sommets à parcourir (comme dans l’exercice de fin), etc ....

def mini2(dico): ’’’ au moins une des valeurs du dico ne doit pas être inf ’’’ m=float(’inf’) for s in dico.keys() : d=dico[s][0]+dico[s][1] if d < m : m=d minimum=s return minimum

def astar(G,deb,fin,h): ’’’G est un graphe pondéré sous la forme d’un dictionnaire représentant sa liste d’adjacence, et s un D={} d={k : [float(’inf’),h(k)] for k in G} d[deb]=[0,h(deb)] while fin in d: print(d) som=mini2(d) for vois in G[som]: voisin,dist=vois[0],vois[1] if voisin not in D : d[voisin][0] = min(d[voisin][0] , d[som][0] + dist) D[som]=d[som] del d[som] return D[fin][0]

Réalisons l’exemple suivant : on considère la graphe donnée par sa liste d’adjacence :

G={}

G[’S’]=[[’A’,7],[’B’,2],[’C’,3]]

G[’A’]=[[’S’,7],[’B’,3],[’D’,4]]

G[’B’]=[[’S’,2],[’A’,3],[’D’,1],[’H’,1]]

G[’C’]=[[’S’,3],[’L’,2]]

G[’D’]=[[’A’,4],[’B’,4],[’F’,5]]

G[’E’]=[[’G’,2],[’K’,5]]

G[’F’]=[[’D’,5],[’H’,3]]

G[’G’]=[[’H’,2],[’E’,2]]

G[’H’]=[[’B’,1],[’F’,3],[’G’,2]]

G[’I’]=[[’J’,6],[’K’,4],[’L’,4]]

G[’J’]=[[’I’,6],[’K’,4],[’L’,4]]

G[’K’]=[[’I’,4],[’J’,4],[’E’,5]]

G[’L’]=[[’C’,2],[’I’,4],[’J’,4]]

def heur(s): val_heur={’A’:9,’B’:7,’C’:8,’D’:8,’E’:0,’F’:6,’G’:3,’H’:6,’I’:4 , ’J’:4 , ’K’:3 , ’L’:6 , ’S’:10} return val_heur[s]

print(dijkstra(G,’S’),astar(G,’S’,’E’,heur))

Exercices :

Exercice 1 : Avec un de vos voisins, donnez un graphe orienté pondéré de au moins 6 sommets et de au moins 10 arcs. Réaliser chacun de votre côté l’algorithme de Dijkstra et comparer vos résultats. Exercice 2 : En utilisant la fonction dijkstra, écrire une fonction qui prend en entrée un graphe non pondéré connexe et un sommet s et renvoie un dictionnaire dont les clefs sont les sommets k du graphe et les valeurs le nombre minimal d’arcs à parcourir pour aller de s à k. Exercice 3 : Pour le graphe qui suit, appliquer à la main l’algorithme de Dijkstra pour obtenir le chemin le plus court reliant les sommets R1 et R6. Faire de même avec l’algorithme A star en utilisant l’heuristique : la valeur associée à un sommet est 3 fois le nombre d’arrêtes nécessaires pour atteindre ce sommet (on suppose ce nombre connu et on le multiplie par trois car on suppose que la longueur moyenne d’une arrête est 3). Le graphe est donné par sa liste d’adjacence :

G={ ’R1’ : [[’R2’,2],[’R3’,2],[’R4’,3]], ’R2’ : [[’R1’,1],[’R4’,4],[’R7’,4]], ’R3’ : [[’R1’,2],[’R5’,5],[’R4’,2]], ’R4’ : [[’R1’,3],[’R2’,4],[’R3’,2],[’R6’,4],[’R7’,5]], ’R5’ : [[’R3’,5],[’R6’,4]], ’R6’ : [[’R4’,4],[’R4’,4],[’R7’,3]], ’R7’ : [[’R2’,4],[’R5’,5],[’R6’,3]], }