---
# System prepended metadata

title: TD 6

---

# Notes préliminaires
## Programmation orientée Objet
### Vocabulaire :
* **Classe** : Objet contenant la définition des méthodes et propriétés communs à un ensemble d’objets. “Moule à instance”.
* **Instance** : Objet avec un comportement d’état défini par une classe. “Résultat en sortie du moule”.
* **Variable d’instance** : Variable définie par une classe que chaque instance va copier pour son propre usage.
* **Méthode** : Une méthode définie dans une classe sera comprise par toutes les instances qui en proviennent.
Application à Python :
# Classe :
## Définition d'une classe
```
class Voiture:
    # Constructeur: méthode appelée à la création de l'objet
    def __init__(self, marque, modele, vmax, acceleration=20):
        # Déclaration des variables d'instance 
        # On utilise ici les arguments du constructeur
        self.marque = marque
        self.modele = modele
        self.vmax = vmax
        # Ou pas 
        self. vitesse = 0
        self.acceleration = 20

    # Méthode que chaque instance de la classe pourra utiliser
    def accelerer(self):
        self.vitesse = min(self.vmax, self.vitesse + self.acceleration)
```

# Instance et variables d’instance:

```
# Instanciation de deux voitures

c3 = Voiture("Citroen", "C3", 130)
p307 = Voiture("Peugeot", "307", 130, 30)

# Elles comprennent les memes methodes
c3.accelerer()
p307.accelerer()

# Ces deux instances ont les memes variables d'instance
c3.vitesse 
>>> 20
p307.vitesse
>>> 30

```
Explication de if __name__ == "__main__":
Cette expression se traduit en :
"""
Si le fichier donné est en train d’être exécuté, exécuter ce qui suit cette expression, sinon, si le fichier est importé, ne rien faire.

Elle permet de compartimenter proprement son code et ses classes en différents fichiers et de leur associer des variables/fonctions de test particulières.
"""
Exemples d’utilisation :

* Deux variables avec le même nom définies dans deux fichiers différents
*  Une fonction de test longue à exécuter (lecture de fichier par exemple)

# Exercice 1:

* Code donné : 
```
import visugraphe

# Insérer ici les définitions des classes Graphe et Noeud

if __name__ == "__main__":
    g = Graphe()
    nA = g.ajout_noeud("A")
    nB = g.ajout_noeud("B")
    nC = g.ajout_noeud("C")
    nD = g.ajout_noeud("D")
    nE = g.ajout_noeud("E")
    g.ajout_arete(nA, nB)
    g.ajout_arete(nA, nE)
    g.ajout_arete(nB, nC)
    g.ajout_arete(nB, nD)
    g.ajout_arete(nB, nE)
    g.ajout_arete(nC, nD)
    g.ajout_arete(nC, nE)
    g.ajout_arete(nD, nE)
    visugraphe.visu_graphe_simple(g)
```

### Classe Noeud :
```

class Noeud:
    def __init__(self, ...):
        ...
        

```   
* Solution : :
```
class Noeud:
    def __init__(self, nom):
        self.nom = nom
        self.couleur = 0
        self.voisins = []
```       

### Classe Graphe :
```
class Graphe:
    def __init__(self):
        ...
```
*  Solution : 
```
class Graphe:
    def __init__(self):
        self.noeuds = []

    def ajout_noeud(self, nom):
        """ nom est de type str
            renvoie le noeud créé
        """
        n = Noeud(nom)
        self.noeuds.append(n)
        return n

    def ajout_arete(self, n1, n2):
        if n2 not in n1.voisins:
            n1.voisins.append(n2)
            n2.voisins.append(n1)
```



# Exercice 2 : Implémentation de Welsh-Powell:
```
import visugraphe

class Graphe:
    def __init__(self):
        self.noeuds = []

    def ajout_noeud(self, nom):
        """ nom est de type str
            renvoie le noeud créé
        """
        n = Noeud(nom)
        self.noeuds.append(n)
        return n

    def ajout_arete(self, n1, n2):
        if n2 not in n1.voisins:
            n1.voisins.append(n2)
            n2.voisins.append(n1)

    def welsh_powell_1(self):
        li = []
        for n in self.noeuds:
            n.couleur = -1
            li.append((len(n.voisins), n.nom, n))
        li.sort()
        li.reverse()
        c = 0
        while len(li)!=0:
            for deg, nom, n in li:
                ok = True
                for v in n.voisins:
                    if v.couleur == c:
                        ok = False
                        break
                if ok:
                    n.couleur = c
            for i in range(len(li)-1, -1, -1):
                if li[i][2].couleur == c:
                    li.pop(i)
            c += 1

    def welsh_powell_2(self):
        li = []
        for n in self.noeuds:
            n.couleur = -1
            li.append((-len(n.voisins), n.nom, n))
        li.sort()
        c = 0
        nbcol = 0
        while nbcol<len(li):
            for deg, nom, n in li:
                ok = True
                if n.couleur == -1:
                    for v in n.voisins:
                        if v.couleur == c:
                            ok = False
                            break
                    if ok:
                        n.couleur = c
                        nbcol += 1
            c += 1
            
class Noeud:
    def __init__(self, nom):
        self.nom = nom
        self.couleur = 0
        self.voisins = []

if __name__ == "__main__":
    g = Graphe()
    nA = g.ajout_noeud("A")
    nB = g.ajout_noeud("B")
    nC = g.ajout_noeud("C")
    nD = g.ajout_noeud("D")
    nE = g.ajout_noeud("E")
    g.ajout_arete(nA, nB)
    g.ajout_arete(nA, nE)
    g.ajout_arete(nB, nC)
    g.ajout_arete(nB, nD)
    g.ajout_arete(nB, nE)
    g.ajout_arete(nC, nD)
    g.ajout_arete(nC, nE)
    g.ajout_arete(nD, nE)
    g.welsh_powell_1()
    # g.welsh_powell_2()
    visugraphe.visu_graphe_couleur(g)


```
# Exercice 3 : Graphes usuels et pathologiques : 
Utilisez une fonction clear avant de créer un nouveau graphe !
```
class Graphe:
    ...
    def clear(self):
        self.noeuds = []
```
-----------------
------------------

* **Clique (paramètre n) :**

Graphe à n noeuds, tous connectés par une arête.
![](https://hackmd.io/_uploads/SkU2nxVGp.png)


* **Biparti (paramètres n,p) :**

Graphe à n+p nœuds, chacun de n premiers nœuds étant relié à chacun des p derniers.

![](https://hackmd.io/_uploads/B1Bw6g4fT.png)

* **Cycle (paramètre n) :**

Graphe à n nœuds, chacun étant relié à son successeur et son prédécesseur.
![](https://hackmd.io/_uploads/H1cW0gEfT.png)

* **Pathos :**

Graphe à 8 nœuds, A, B, … H. Les noeuds A,C,D,E,G,H forment un cycle, auquel on ajoute les arêtes AB et EF.
![](https://hackmd.io/_uploads/r18iAgNMp.png)

* **Nombre chromatique et validation :**
1. Nombre chromatique (nombre de couleurs du graphe) 
2. Validation couleur (vérification que chaque noeud a bien une couleur différente de ses voisins) 

# solution : 

```
import visugraphe
import sys

class Graphe:
    def __init__(self):
        self.noeuds = []

    def clear(self):
        self.noeuds=[]

    def ajout_noeud(self, nom):
        """ nom est de type str
            renvoie le noeud créé
        """
        n = Noeud(nom)
        self.noeuds.append(n)
        return n

    def ajout_arete(self, n1, n2):
        if n2 not in n1.voisins:
            n1.voisins.append(n2)
            n2.voisins.append(n1)

    def clique(self, n):
        self.clear()
        for i in range(n):
            self.ajout_noeud(str(i))
        for i in range(n):
            for j in range(i):
                self.ajout_arete(self.noeuds[i], self.noeuds[j])
            
    def biparti(self, n, p):
        self.clear()
        for i in range(n):
            self.ajout_noeud("A"+str(i))
        for i in range(p):
            self.ajout_noeud("B"+str(i))
        for i in range(n):
            for j in range(p):
                self.ajout_arete(self.noeuds[i], self.noeuds[n+j])

    def cycle(self, n):
        self.clear()
        for i in range(n):
            self.ajout_noeud(str(i))
        for i in range(n-1):
            self.ajout_arete(self.noeuds[i], self.noeuds[i+1])
        self.ajout_arete(self.noeuds[0], self.noeuds[-1])

    def pathos(self):
        self.clear()
        nA = self.ajout_noeud("A")
        nB = self.ajout_noeud("B")
        nC = self.ajout_noeud("C")
        nD = self.ajout_noeud("D")
        nE = self.ajout_noeud("E")
        nF = self.ajout_noeud("F")
        nG = self.ajout_noeud("G")
        nH = self.ajout_noeud("H")
        for n, nn in zip([nA, nC, nD, nE, nG, nH], [nC, nD, nE, nG, nH, nA]):
            self.ajout_arete(n, nn)
        self.ajout_arete(nA, nB)
        self.ajout_arete(nE, nF)

    def validation_couleur(self):
        for n in self.noeuds:
            for v in n.voisins:
                if n.couleur == v.couleur:
                    return False
        return True
    
    def nombre_chromatique(self):
        s = set()
        for n in self.noeuds:
            s.add(n.couleur)
        return len(s)
        
    def welsh_powell_1(self):
        li = []
        for n in self.noeuds:
            n.couleur = -1
            li.append((len(n.voisins), n.nom, n))
        li.sort()
        li.reverse()
        c = 0
        while len(li)!=0:
            for deg, nom, n in li:
                ok = True
                for v in n.voisins:
                    if v.couleur == c:
                        ok = False
                        break
                if ok:
                    n.couleur = c
            for i in range(len(li)-1, -1, -1):
                if li[i][2].couleur == c:
                    li.pop(i)
            c += 1

    def welsh_powell_2(self):
        li = []
        for n in self.noeuds:
            n.couleur = -1
            li.append((-len(n.voisins), n.nom, n))
        li.sort()
        c = 0
        nbcol = 0
        while nbcol<len(li):
            for deg, nom, n in li:
                ok = True
                if n.couleur == -1:
                    for v in n.voisins:
                        if v.couleur == c:
                            ok = False
                            break
                    if ok:
                        n.couleur = c
                        nbcol += 1
            c += 1
            
class Noeud:
    def __init__(self, nom):
        self.nom = nom
        self.couleur = 0
        self.voisins = []

if __name__ == "__main__":
    g = Graphe()
    if sys.argv[1] == "clique":
        g.clique(int(sys.argv[2]))
    elif sys.argv[1] == "biparti":
        g.biparti(int(sys.argv[2]), int(sys.argv[3]))
    elif sys.argv[1] == "cycle":
        g.cycle(int(sys.argv[2]))
    elif sys.argv[1] == "pathos":
        g.pathos()
    g.welsh_powell_1()
    # g.welsh_powell_2()
    if sys.argv[1] == "pathos" and len(sys.argv)>2 and sys.argv[2]=="manuel":
        for i in [0,3,5,6]:
            g.noeuds[i].couleur = 0
        for i in [1, 2, 4, 7]:
            g.noeuds[i].couleur = 1
    if g.validation_couleur():
        print("Nombre chromatique estimé :", g.nombre_chromatique())
    else:
        print("Coloration incorrecte")
    visugraphe.visu_graphe_couleur(g)

```

# Exercice 4 : Lecture de graphe depuis un fichier: 

# Solution : 
```


import visugraphe
import sys

class Graphe:
    def __init__(self):
        self.noeuds = []

    def clear(self):
        self.noeuds=[]

    def ajout_noeud(self, nom, x=0, y=0):
        """ nom est de type str
            renvoie le noeud créé
        """
        n = Noeud(nom, x, y)
        self.noeuds.append(n)
        return n

    def ajout_arete(self, n1, n2):
        if n2 not in n1.voisins:
            n1.voisins.append(n2)
            n2.voisins.append(n1)

    def trouve_noeud(self, nom):
        for n in self.noeuds:
            if n.nom == nom:
                return n
        return None

    def lire_fichier(self, nom_de_fichier):
        f = open(nom_de_fichier)
        n = int(f.readline().strip())
        for i in range(n):
            lig = f.readline()
            nom, sx, sy = lig.split()
            self.ajout_noeud(nom, float(sx), float(sy))
        for i in range(n):
            lig = f.readline()
            tab = lig.split()
            n = self.trouve_noeud(tab[0])
            for nom in tab[1:]:
                v = self.trouve_noeud(nom)
                self.ajout_arete(n, v)
    
    def validation_couleur(self):
        for n in self.noeuds:
            for v in n.voisins:
                if n.couleur == v.couleur:
                    return False
        return True
    
    def nombre_chromatique(self):
        s = set()
        for n in self.noeuds:
            s.add(n.couleur)
        return len(s)
        
    def welsh_powell_1(self):
        li = []
        for n in self.noeuds:
            n.couleur = -1
            li.append((len(n.voisins), n.nom, n))
        li.sort()
        li.reverse()
        c = 0
        while len(li)!=0:
            for deg, nom, n in li:
                ok = True
                for v in n.voisins:
                    if v.couleur == c:
                        ok = False
                        break
                if ok:
                    n.couleur = c
            for i in range(len(li)-1, -1, -1):
                if li[i][2].couleur == c:
                    li.pop(i)
            c += 1

    def welsh_powell_2(self):
        li = []
        for n in self.noeuds:
            n.couleur = -1
            li.append((-len(n.voisins), n.nom, n))
        li.sort()
        c = 0
        nbcol = 0
        while nbcol<len(li):
            for deg, nom, n in li:
                ok = True
                if n.couleur == -1:
                    for v in n.voisins:
                        if v.couleur == c:
                            ok = False
                            break
                    if ok:
                        n.couleur = c
                        nbcol += 1
            c += 1
            
class Noeud:
    def __init__(self, nom, x=0, y=0):
        self.nom = nom
        self.couleur = 0
        self.x = x
        self.y = y
        self.voisins = []

if __name__ == "__main__":
    g = Graphe()
    g.lire_fichier(sys.argv[1])
    for n in g.noeuds:
        print(n.nom, n.x, n.y)
    g.welsh_powell_1()
    # g.welsh_powell_2()
    if g.validation_couleur():
        print("Nombre chromatique estimé :", g.nombre_chromatique())
    else:
        print("Coloration incorrecte")
    visugraphe.visu_graphe_coord(g)
```