Poly
Poly
Poly
e
https://moodle1.u-bordeaux.fr/course/view.php
2020–2021
qu
ati
orm
inf
Table des matières 3
2 Manipulation d’images 23
2.1 Mise en jambes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.2 Tracés de segments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.3 Manipulation de couleurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.4 Exercices de révisions et compléments . . . . . . . . . . . . . . . . . . . . . . . . 28
3 Boucle conditionnelle 35
3.1 Échauffement : fonctions mystères . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2 Recherche à l’aide d’une boucle conditionnelle . . . . . . . . . . . . . . . . . . . . 36
3.3 Exercices de révisions et compléments . . . . . . . . . . . . . . . . . . . . . . . . 37
5 Chaînes et connexité 52
5.1 Échauffement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.2 Algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.3 Exercices et notions complémentaires . . . . . . . . . . . . . . . . . . . . . . . . . 56
B Palettes 79
C Aide-mémoire 80
C.1 Environnement de TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
C.2 Rappel de la syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
C.3 Utilisation de la bibliothèque de graphes . . . . . . . . . . . . . . . . . . . . . . . 85
C.4 Utilisation de la bibliothèque d’images . . . . . . . . . . . . . . . . . . . . . . . . 87
3
C.5 Comprendre les messages d’erreur . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4
Introduction et utilisation du fascicule
L’ensemble des resources électroniques (e.g, pdf du polycopié, annales d’examens) est sur
le site web https://moodle1.u-bordeaux.fr/course/view.php
Contenu du fascicule
Ce fascicule contient différents chapitres correspondant aux différents objets et propriétés
d’images et de graphes que nous allons étudier pendant le semestre.
Un grand nombre d’exercices sont proposés, parmi ceux-ci seuls les exercices placés dans les
sections intitulées Exercices de révisions et compléments sont facultatifs : ils serviront à bien se
préparer aux examens voire à occuper les étudiants les plus rapides.
À la suite des chapitres constituant le cours on trouvera deux énoncés de devoir surveillés.
On trouvera ensuite un aide-mémoire de la syntaxe de python et des fonctions de nos biblio-
thèques d’images et de graphes, et, à la fin du fascicule, une description des messages d’erreur
et comment les traiter.
Un support plus fourni mais plus ancien est disponible sur Internet sous forme d’un livre :
http://dept-info.labri.fr/ENSEIGNEMENT/INITINFO/initinfo/supports/book/index.html
(Initiation à l’Informatique, par Irène Durand et Robert Strandh)
Typographie
L’informatique étant une science faisant le lien entre théorie et programmation, dans ce
fascicule, on utilise les conventions de typographie suivantes pour bien distinguer les deux :
5
• les énoncés théoriques sont écrits en italique. Il ne s’agit donc pas de code python, mais
d’énoncés mathématiques décrivant les objets de manière abstraite, permettant ainsi
d’écrire des preuves, par exemple.
• les énoncés python sont écrits en style machine à écrire (police à chasse fixe), il ne
s’agit donc pas d’énoncés mathématiques, mais de code python, interprétés par la machine.
Il est important de bien distinguer les deux, car ils ne s’écrivent pas de la même façon et n’ont
pas exactement les mêmes détails de signification – Par exemple i=i+1 est (presque) toujours
faux en mathématiques, mais i=i+1 est très utilisé en python ! Certains exercices incluent par
exemple un énoncé mathématique qu’il s’agira de reformuler en python.
Mise en page
Pour les retrouver facilement dans le fascicule, les introductions de notions sont surlignées
et les fonctions prédéfinies sont encadrées :
On trouve à gauche ce que l’on appelle le prototype de la fonction, c’est-à-dire son nom et
la liste des paramètres que l’on doit lui fournir. La partie droite décrit son comportement.
Seule la liste des fonctions des bibliothèques d’images et de graphes est fournie lors des
épreuves. Toutes les notions surlignées doivent être apprises.
Les codes modèles illustrant des constructions courantes en programmation sont mis en
valeur à l’aide d’une double ligne verticale :
# d é finition de la fonction f
def f ( x ):
a = x +1
return a * a + x + 1
6
Chapitre 1. Premiers pas en python
On observe que dans chaque colonne de ce tableau, une seule case est en gras ; elle corres-
pond à la variable affectée à l’étape correspondante (l’étape 1 correspond à l’exécution de la
première instruction, etc . . . ), les autres variables ne sont pas affectées. On notera également
que l’affectation de la variable x à l’étape 4 n’a pas d’effet sur les variables y et z. La valeur
finale d’une variable est la valeur dans la dernière colonne. La valeur finale de x est donc 3661,
celle de y est 3600 et celle de z est 61.
Pour améliorer la lecture et faciliter l’écriture de ce style de tableau, il est intéressant d’écrire
uniquement les valeurs des variables affectées, étape par étape. La valeur finale d’une variable
est maintenant la valeur la plus à droite sur sa ligne, il s’agit toujours de la valeur calculée lors
la dernière affectation de la variable.
étape 1 étape 2 étape 3 étape 4 étape 5
x 60 3661
y — 3600
z — — 61 3662
−−−−→
temps
Dans le tableau ci-dessus une seule valeur apparaît par colonne car dans le programme
correspondant, comme dans tous ceux de ce chapitre, une affectation ne concerne qu’une seule
variable à la fois. Dans les exercices qui suivent, nous vous recommandons fermement d’utiliser
un tel tableau pour montrer l’évolution des valeurs des variables. On veillera à ne faire apparaître
qu’une seule affectation par colonne pour bien mettre en valeur la chronologie des affectations.
7
Exercice 1.1.1 Que contiennent les variables x, y, z après les instructions suivantes ?
x = 6 étape 1 étape 2 étape 3 étape 4
y = x + 3 x
x = 3 y
z = 2 * y - 7 z
Exercice 1.1.3 Que contiennent les variables x, y, z après les instructions suivantes ?
x = 6 étape 1 étape 2 étape 3 étape 4
y = 7 x
z = x y
z = z + y z
x 1
Exercice 1.1.5 Parmi les codes suivants, quels sont les programmes python qui s’exécutent sans
causer d’erreur ? Indiquer les erreurs dans les codes erronés.
x = 1 y = 2 y = 2
x = y + 1 x = 1 x = 1
y = 2 x = y +- 2 x = y + 3
x = 1 y = 2 y = 2
y = 0 x = 1 x = 1
x + y = 1 x = y +/ - 1 y = x -+ 1
Exercice 1.1.6 Écrire une suite d’instructions permettant d’échanger le contenu de deux va-
riables a et b.
Divisions entières
En termes simples, la division entière est une division arrondie « par défaut », c’est-à-dire
que l’on ne conserve pas les chiffres après la virgule dans le résultat (le quotient) : 17/5 = 3, 4
mais on ne conserve que 3. Il y a alors un reste : 17 − 5 ∗ 3 = 2
Plus formellement, le quotient entier q de deux entiers a et b positifs, et le reste r de la
division sont définis par :
a = bq + r avec 0 ≤ r < b
Par exemple le quotient et le reste de la division de 17 par 5 sont 3 et 2 car 17 = 5 × 3 + 2.
En python le quotient entier de a par b est noté a//b, et le reste a%b (aussi appelé modulo).
Exercice 1.1.7 Taper les instructions suivantes et prenez le temps d’expliquer précisément l’évo-
lution des variables pendant l’exécution pas à pas de ces instructions. Les parties à droite des
dièses # ne sont que des commentaires pour vous, l’ordinateur ne les interprètera pas même si
vous les tapez.
8
x = 11 * 34
x = 13.4 - 6
y = 13 / 4 # division avec virgule
y = 13 // 4 # division entiere , notez la difference
z = 13 % 2 # pourquoi cela vaut - il 1 ?
x = 14 % 10 # quel sens donner au reste d ' une divison par 10 ?
y = 14 // 10
i = x + y
x
y
z
i
1.2 Fonctions
La plupart des fonctions servent à calculer un résultat, comme en mathématiques, et à le
retourner (on dit aussi renvoyer). La syntaxe python pour la définition d’une fonction est la
suivante :
def nom_fonction ( liste , de , parametres ):
corps de la fonction
La définition d’une fonction, effectuée en général une seule fois, permet de définir les para-
mètres de la fonction et le corps de la fonction. Remarquez les deux points à la fin de la première
ligne. Les instructions qui constituent le corps de la fonction doivent être indentées par rapport
au mot clef def, c’est-à-dire décalées, pour indiquer à python qu’elles font partie de la définition
de la fonction.
L’instruction return termine l’exécution de la fonction, elle peut être suivie d’une expression
pour indiquer la valeur renvoyée par la fonction.
Dans l’exemple ci-dessous, la fonction f a un seul paramètre, nommé x, et le corps de la
fonction f est constitué de deux instructions.
Exemple de définition et d’appels de fonction :
# d é finition de la fonction f
def f ( x ):
a = x +1
return a * a + x + 1
Une fonction doit être appelée pour être exécutée et peut être appelée autant de fois que
l’on veut. Un appel de fonction fournit les arguments de cet appel et il y a autant d’arguments
qu’il y a de paramètres dans la définition de la fonction.
Comme pour l’instruction d’affectation, l’appel d’une fonction se fait en plusieurs étapes bien
distinctes : les valeurs des arguments passés à la fonction sont d’abord calculées. La fonction
est alors appelée avec le résultat de ces calculs. Le corps de la fonction est alors exécuté, les
paramètres contenant alors les résultats des calculs des arguments. La fonction se termine au
9
premier return exécuté qui désigne la valeur à retourner. L’exécution revient alors à l’endroit
où l’on a effectué l’appel à la fonction, et c’est la valeur retournée par la fonction qui y est
utilisée.
# definition de la fonction g contenant du code mort
def g ( x ):
a = x +1
return a * a + x + 1
# code mort - erreur de programmation a eviter
b = a + 1
La définition de fonction ci-dessus contient du code mort : les instructions qui suivent une
instruction return ne sont jamais exécutées, c’est une erreur de programmation.
Exercice 1.2.1 Taper les instructions suivantes qui appellent la fonction f en lui passant diffé-
rents arguments et prenez le temps d’expliquer en détail les résultats obtenus.
def f ( x ):
a = x +1
return a * a + x + 1
y = f (2)
t = 4
y = f(t) # on passe la valeur d ' une variable
y = f (1) + f (2) # on effectue deux appels
x = 0
z = x +1
y = f(z)
y = f ( x +1) # on passe directement la valeur d ' une expression
z = f (x - t )
t = f(t) # on peut meme passer la variable qui servira a
# stocker le resultat
x = f ( f (1)) # on peut combiner deux appels , le resultat de
# l ' un est passe en parametre a l ' autre
Exercice 1.2.2 Parmi les codes suivants, quels sont les programmes python qui ne comportent
pas d’erreur ? Rayer les codes erronés.
Exercice 1.2.3
1. Soient x et y deux variables contenant chacune un nombre. Écrire l’expression python qui
stocke dans une variable m le calcul de la moyenne des deux nombres x et y.
2. Écrire une fonction moyenne(a,b) qui retourne la moyenne des deux nombres a et b.
Testez-la avec les arguments 42 et 23.
10
3. Écrire une fonction moyennePonderee(a, coef_a, b, coef_b) qui retourne la moyennne
pondérée par le coefficient coef_a pour la note a et par le coefficient coef_b pour la note
b. Testez-la en appelant moyennePonderee(5,2,12,3).
4. Utilisez votre fonction moyennePonderee(a, coef_a, b, coef_b) pour écrire une autre
version de la fonction moyenne(a,b) (question 2.). Testez-la.
Compléments de programmation
Une erreur classique de programmation consiste à utiliser une variable qui n’est pas définie.
C’est le cas de la variable a dans le code ci-dessous. Cette erreur est signalée par un message et
provoque l’arrêt de l’exécution du programme.
11
1.3 Conditionnelles
Expressions booléennes
Une expression booléenne est une expression qui n’a que deux valeurs possibles, True (vrai)
ou False (faux) ; les tests x == y (égalité), x != y (inégalité), x < y, x <= y, x >= y, etc. sont des
expressions booléennes. On peut combiner des expressions booléennes avec les opérateurs and,
or et not.
Exercice 1.3.1 Taper les instructions suivantes et prenez le temps d’expliquer précisément l’évo-
lution des variables pendant l’exécution pas à pas de ces instructions.
i = 9
j = 0
b = i < j # b ne contient donc pas un entier , mais True ou False
b = i != 9
b = i == 9
bi = i % 2 == 0 or i % 3 == 0
bj = j % 2 == 0 or j % 3 == 0
b = bi and bj
c = not b
Exercice 1.3.2 Parmi les expressions suivantes, quelles sont celles qui valent True si et seule-
ment si 1 les trois variables a, b et c ont des valeurs toutes différentes ? Rayer les expressions
incorrectes.
• a != b or b != c • a != b or b != c or a != c
Exercice 1.3.3 Écrire une expression qui vaut True si x appartient à [0, 5[ et False dans le cas
contraire.
Écrire une expression qui vaut True si x n’appartient pas à [0, 5[ et False dans le cas
contraire. Proposez-en deux formes différentes : l’une avec une négation, et l’autre sans.
Exercice 1.3.4 Parmi les expressions suivantes, quelles sont celles qui valent True si l’entier n
est pair et False dans le cas contraire ? Rayer les mauvaises réponses.
• n == 0 % 2 • 1 != 2 % n • n // 2 == 0
• n % 2 != 1 • 0 != n % 2 • n % 2 == 0
Exercice 1.3.5 Écrire une fonction pair(n) qui teste si son paramètre n est pair ; la valeur
renvoyée doit être booléenne, c’est-à-dire égale à True ou False. Testez-la.
1. si et seulement si signifie que l’un est vrai si l’autre est vrai, et que l’un est faux si l’autre est faux.
12
Exécution conditionnelle
La syntaxe if ... else ... permet de tester des conditions pour exécuter ou non certaines
instructions.
if condition_1 :
code a executer si conditon_1 est vraie
elif condition_2 :
code a executer si condition_2 est vraie
et condition_1 est fausse
else :
code a executer si aucune condition est vraie
La partie else est optionnelle et la partie elif peut apparaître autant de fois que nécessaire.
Les exemples suivant détaillent l’utilisation de cette structure :
def prixCinema ( age ):
def prixCinema ( age ):
if age < 18:
prix = 10
prix = 6.70
if age < 18:
else :
prix = 6.70
prix = 10
return prix
return prix
Ne pas oublier les deux points à la fin des lignes if, else. Les instructions à exécuter dans
chacun des cas doivent être indentées et rigoureusement alignées verticalement (ici il y a quatre
blancs au début de chaque instruction indentée) — en fait l’utilisateur est aidé dans cette tâche
par le logiciel de programmation, qui insère les blancs à sa place. La partie else n’est pas
obligatoire : son absence indique simplement qu’il n’y a rien à faire dans ce cas.
La syntaxe if ... else ... peut être imbriquée, par exemple cela permet de distinguer
trois cas : age ≤ 14, 14 < age < 18 et age ≥ 18. :
def prixCinema ( age ):
if age <= 14:
prix = 5
else :
if age < 18:
prix = 6.70
else :
prix = 10
return prix
On peut utiliser la syntaxe if ... elif ... else ... pour l’écrire de manière plus simple.
On peut répéter la partie elif autant de fois que voulu. Sur cet exemple :
Cette fonction peut être écrite encore plus simplement en éliminant la variable locale prix
grâce à l’instruction return :
13
def prixCinema ( age ):
if age <= 14:
return 5
elif age < 18:
return 6.70
else :
return 10
Supposons que l’on exécute prixCinema(17). La condition (age <= 14) du premier test
n’étant pas satisfaite, le deuxième test (if age < 18) est alors évalué. Comme la condition
(age < 18) est vraie, l’instruction return 6.70 est exécutée et a pour effet de terminer l’éva-
luation de la fonction. Dans ce cas, l’instruction return 10 n’est pas executée.
Exercice 1.3.6 Donner les valeurs des variables x et y après exécution de l’exemple suivant
pour x valant 1, puis pour x valant 8.
if x % 2 == 0:
y = x // 2
else :
y = x + 1
x = x + 1
if x % 2 == 0: if x % 2 == 0: if x % 2 == 0:
y = x // 2 y = x // 2 y = x // 2
y = x + 1 else : else :
x = x + 1 y = x + 1 y = x + 1
x = x + 1 x = x + 1
Exercice 1.3.8 Écrire une fonction max2(x,y) qui calcule et retourne la plus grande valeur
parmi deux nombres x et y. Attention : bien nommer cette fonction max2, et non max, car la
fonction max est prédéfinie en python.
14
La boucle for permet de parcourir les éléments d’une liste ; en voici la syntaxe :
for variable in liste :
corps de la boucle
Remarquez bien les deux points à la fin de la ligne et le fait que les instructions appartenant
au corps de la boucle doivent être indentées (décalées) par rapport au mot clef for. L’évaluation
par python d’une boucle for correspond à l’algorithme suivant :
Exercice 1.4.1 Dans l’environnement Python Tutor, entrer l’instruction suivante et analyser ce
qui est affiché :
for i in [2 , 8 , 5]:
print (i , i * i )
u = [2 , 8 , 5]
for i in u :
print (i , i * i )
La variable i est-elle définie après exécution de ces instructions ? Si oui, quelle est sa valeur ?
L [1,3,13]
i -
s 0
L’instruction return termine l’exécution de la fonction qui la contient. Que calcule la fonc-
tion somme si par malheur on indente trop la dernière ligne, comme ci-dessous ?
def sommeListe ( L ):
s = 0
for i in L :
s = s + i
return s # gros bug !
15
Exercice 1.4.3 Écrire les fonctions suivantes prenant en paramètre une liste de nombres L, et
testez ces fonctions :
• une fonction maximumListe(L) qui calcule et retourne le maximum de ces nombres (sup-
posés positifs).
• une fonction nbPairsListe(L) qui compte et retourne combien de ces nombres sont pairs.
Exercice 1.4.4 On considère les fonctions existePairListe(L), qui renvoie True si au moins
un des nombres de la liste est pair et False sinon, et tousPairsListe(L) qui renvoie True si
tous les nombres de la liste sont pairs, et False sinon.
Écrire ces deux fonctions en faisant en sorte qu’elles retournent leur résultat dès que celui-ci
est déterminé. Testez ces fonctions.
Une comparaison sur le nombre de tests réalisés par les fonctions existePairListe(L) et
existePairListeInefficace(L) est présentée en Section 1.6.
2. L’écart-type d’une liste de nombres L permet d’estimer dans quelle mesure les éléments
de L s’éloignent de la moyenne des éléments de L. Par exemple l’écart-type de la liste
[8, 8, 8, 12, 12, 12] est de 2 (puisque tous les éléments sont à distance 2 de la
moyenne 10).
On peut le calculer en utilisant la somme des carrés des éléments de L et la somme des
éléments de L (en notant n le nombre d’éléments de L obtenu avec la fonction len) :
√∑
2 (∑ )2
i Li i Li
EcartT ype(L) = −
n n
Pour calculer une racine carrée, il faut ajouter from math import sqrt au début du
fichier pour avoir accès à la fonction sqrt . En appelant les fonctions sommeListe et
sommeCarresListe écrites précédemment, écrivez une fonction ecartTypeListe(L) qui
calcule l’écart-type de la liste L.
16
1.5 Utilisation de range dans des boucles for
La fonction range(debut, fin, pas) permet de définir une suite arithmétique finie d’entiers
de raison pas commençant par l’entier debut et bornée par fin (qui ne fait pas partie de la
suite). Les syntaxes possibles de range sont :
range ( debut , fin , pas )
range ( debut , fin ) # pas vaut 1 par defaut
range ( fin ) # debut vaut 0 par defaut
L’argument pas est donc optionnel, et vaut 1 par défaut. L’argument debut est également
optionnel, et vaut 0 par défaut. La suite se termine juste avant d’atteindre fin.
Exercice 1.5.1 Entrer les instructions suivantes et analyser les réponses de python :
for j in range (10):
print (j , j * j )
Exercice 1.5.2 Dans l’environnement Python Tutor, tester chacun des groupes d’instructions
suivantes et analyser les résultats comme précédemment :
for a in [ " a " ," b " ," c " ]:
for i in [1 ,2 ,3]:
print (a , i )
u = [2 ,6 ,1 ,10 ,6]
v = [2 ,5 ,6 ,4]
for x in u :
for y in v :
print (x , y , x + y , x == y )
17
• a = b and b = c • a = b and b = c and a = c
• not (a != b or b != c) • not (a != b or b != c or a != c)
Exécution conditionnelle
Exercice 1.6.2 Écrire une fonction max3(x,y,z) qui calcule et retourne le maximum de trois
nombres x, y, z. Donner plusieurs versions de cette fonction dont une utilise la fonction max2
de l’exercice 1.3.8
Exercice 1.6.3 Écrire une fonction uneMinuteEnPlus qui calcule et retourne l’heure une minute
après celle passée en paramètre, sous la forme d’un duplet de deux entiers correspondant à une
heure et une minute valides. Exemples :
Exercice 1.6.4 Le service de reprographie propose les photocopies avec le tarif suivant : les 10
premières coûtent 20 centimes l’unité, les 20 suivantes coûtent 15 centimes l’unité et au-delà de
30 le coût est de 10 centimes. Écrire une fonction coutPhotocopies(n) qui calcule et retourne
le prix à payer pour n photocopies.
n! = 1 × 2 × · · · × n
Écrire une fonction factorielle(n) qui utilise cette définition pour calculer et retourner
n!. Tester votre fonction en affichant les factorielles des nombres de 0 à 100.
Exercice 1.6.6 (extrait DS 2015-16) Rappel : On dit que i est un diviseur de n si le reste
de la division de n par i est égal à 0.
2. Un nombre est dit premier s’il n’a que 2 diviseurs : 1 et lui-même. Calculez à la main sur
papier la liste des nombres premiers inférieurs à 15.
3. Écrire une fonction estPremier(n) qui retourne True si n est premier, False sinon (on
profitera du fait que seuls les nombres strictement inférieurs à n peuvent être diviseurs de
n).
4. Écrire une fonction nbPremiers(n) qui retourne le nombre de nombres premiers stricte-
ment plus petits que n.
18
Analyse de données
Nous vous fournissons un module bibcsv.py qui permet d’ouvrir des fichiers CSV contenant
juste une liste de nombres. Ce module est disponible en téléchargement sur le site https:
//moodle1.u-bordeaux.fr/course/view.php. Utiliser un clic droit et "enregistrer sous" pour
l’enregistrer à côté de vos autres fichiers python. Pour utiliser un module, il faut commencer
par l’importer, et toute session de travail utilisant ce module doit commencer par la phrase
magique :
from bibcsv import *
Exercice 1.6.7 Récupérer le fichier notes.csv depuis le site du cours, l’enregistrer de la même
façon, et utiliser ouvrirCSV pour récupérer la liste des nombres stockée dans le fichier CSV :
maliste = ouvrirCSV ( " notes . csv " )
2. Vous pouvez créer votre propre fichier .csv avec LibreOffice. Dans une feuille de cal-
cul, mettez les nombres à la suite dans la première colonne uniquement (ou bien en les
copiant/collant depuis un document existant). Utilisez "Fichier", "Enregistrer sous", sai-
sissez un nom de fichier en utilisant l’extension .csv et validez, confirmez que c’est bien
le format CSV que vous désirez utiliser, et utilisez les options par défaut. Vous pouvez
alors charger le fichier dans python à l’aide d’ouvrirCSV et effectuer les mêmes analyses.
19
Pour aller plus loin : notion de complexité en moyenne
On se propose d’approfondir l’exercice 1.4.4 pour lequel vous aviez déjà programmé les
fonctions existePairListe(L) et tousPairsListe(L). Le but de cet exercice est de les réécrire
de façon optimisé, c’est-à-dire en faisant en sorte qu’elles retournent leur résultat dès que celui-ci
est déterminé, sans nécessairement tester tous les éléments de la liste.
Exercice 1.6.8 Comparer le nombre de tests réalisés par les fonctions existePairListe(L)
et existePairListeInefficace(L) pour les cas où une liste de 100 éléments est passée en
paramètre et que cette liste :
Pour déterminer si une liste contient ou pas un nombre pair, nous avons implémenté deux
algorithmes, l’un naïf (exercice 1.6.8) l’autre optimisé (exercice 1.4.4) puis nous avons comparé
leurs performances dans les meilleurs et pires cas. Mais en pratique, est-on généralement plus
proche du meilleur cas ? du pire cas ? ou bien entre les deux ? En fait, pour comparer les
performances de ces deux algorithmes, il est intéressant de comparer le nombre moyen de tests
utilisés par chaque algorithme pour traiter un ensemble pertinent de listes.
Pour définir mathématiquement cette notion d’ensemble pertinent, il est d’usage en infor-
matique de considérer des ensembles regroupant toutes les entrées ayant la même taille. Ici, la
taille de l’entrée de nos deux algorithmes correspond à la longueur de la liste passée en para-
mètre. Ainsi la question que nous allons résoudre pour chaque algorithme est : « combien de
tests nécessite en moyenne cet algorithme pour traiter une liste de n entiers ? ».
Pour l’algorithme naïf (noté Anaïf ), qui parcourt systématiquement toute la liste listen de n
éléments, le coût de traitement de toute liste de n entiers est de n tests. On a donc :
• il y a 2n listes dans Ln ;
• une liste sur deux de Ln commence par un nombre pair et donc 2n−1 listes nécessitent un
seul test pour être traitées par l’algorithme optimisé ;
• une liste sur quatre de Ln a son premier nombre pair en deuxième position et donc 2n−2
listes nécessitent deux tests ;
• de façon plus générale, il y a 2n−i listes de Ln ayant son premier nombre pair en i-ième
position et demandant i tests ;
20
Au total il faut 1.2n−1 + 2.2n−2 + 3.2n−3 + · · · + n.2n−n + n tests, le nombre moyen de tests
est donc de ∑i=n n−i
+ n i=n∑ i
i=1 i.2 n 1
= + n = 2 − n−1
2n i=1
2i 2 2
Sous l’hypothèse d’équiprobabilité des nombres pairs et impairs, on a donc :
1
Complexité_Moyenne (Aoptimisé (listen )) = 2 − <2
2n−1
Exercice 1.6.9 Calculer le nombre moyen de tests réalisés par l’algorithme optimisé dans le cas
de listes ne contenant qu’un seul nombre pair placé aléatoirement dans la liste.
21
Chapitre 2. Manipulation d’images
Une image, en informatique, est un simple tableau à deux dimensions de points colorés
(appelés pixels, picture elements).
Les coordonnées (x, y) d’un pixel expriment sa position au sein de l’image : x est son abscisse,
en partant de la gauche de l’image, et y est son ordonnée, en partant du haut de l’image (à
l’inverse de l’ordonnée mathématique, donc). Elles partent toutes deux de 0. Le schéma ci-
dessous montre un exemple d’image en gris sur fond blanc, de 7 pixels de largeur et 4 pixels de
hauteur, les abscisses vont donc de 0 à 6 et les ordonnées vont de 0 à 3.
La couleur RGB (r, g, b) d’un pixel est la quantité de rouge (r pour red), vert (g pour green)
et de bleu (b pour blue) composant la couleur affichée à l’écran. Le mélange se fait comme
trois lampes colorées rouge, vert et bleue, et les trois valeurs r, g, b expriment les intensités
lumineuses de chacune de ces trois lampes, exprimées entre 0 et 255. Par exemple, (0, 0, 0)
correspond à trois lampes éteintes, et produit donc du noir. (255, 255, 255) correspond à trois
lampes allumées au maximum, et produit donc du blanc. (255, 0, 0) correspond à seulement une
lampe rouge allumée au maximum, et produit donc du rouge. (255, 255, 0) correspond à une
lampe rouge et une lampe verte allumées au maximum, et produit donc du jaune, et ainsi de
suite. Cela correspond très précisément à ce qui se passe sur vos écrans ! Si vous prenez une
loupe, vous verrez que l’écran est composé de petits points (appelés sous-pixels) verts, rouges
et bleus, allumés plus ou moins fortement pour former les couleurs.
Dans ce chapitre, nous étudierons deux grands types d’opérations disponibles typiquement
dans les logiciels de manipulation d’image : nous produirons parfois des images de zéro (synthèse
d’images), d’autres fois nous transformerons des images existantes (traitement d’images, ou
filtres).
23
2.1 Mise en jambes
python permet bien sûr de manipuler des images, à l’aide de la python Imaging Library
(PIL), qui est préinstallée sur vos machines. Nous vous fournissons un module bibimages.py
qui permet d’utiliser plus simplement la bibliothèque PIL. Ce module est disponible en téléchar-
gement sur le site https://moodle1.u-bordeaux.fr/course/view.php. Utiliser un clic droit
et "enregistrer sous" pour l’enregistrer à côté de vos autres fichiers python. Ce module comporte
aussi une poignée de fonctions qui permettent de manipuler les images. Pour utiliser un module
il faut commencer par l’importer, et toute session de travail sur les images doit commencer par
la phrase magique :
from bibimages import *
Voici un résumé des fonctions que nous utiliserons dans ce chapitre :
24
Vous pourrez bien sûr, pour tous les exercices, utiliser d’autres images venant d’Internet
ou d’ailleurs (pour autant que les licences sous lesquelles lesdites images sont placées vous le
permettent !).
Note :
Une chaîne de caractères est une suite de valeurs numériques élémentaires, dont chacune
représente un caractère. En python, on définit une chaîne de caractères comme un ensemble de ca-
ractères placés entre deux caractères “guillemets” ou “apostrophe” : "Bonjour", 'tout le monde'.
De nombreuses fonctions permettent de manipuler des chaînes de caractères : la fonction print
permet d’afficher une chaîne de caractères, l’opérateur “+” permet de concaténer deux chaînes
pour en former une nouvelle, etc.
Ici, "teapot.png" est une chaîne de caractères contenant le nom du fichier à ouvrir. python ne
cherche pas à comprendre ce qu’il y a entre les guillemets. Si par contre on oublie les guillemets,
python va chercher une variable appelée teapot, ce qui n’est pas du tout ce que l’on veut.
Exercice 2.2.3 Écrire une fonction ligneHorizontale(img,c,y) qui dessine, dans une image
img donnée, une ligne horizontale de couleur c à la distance y du haut de l’image.
Que se produit-il si l’on appelle la fonction ligneHorizontale(img,c,y) avec une valeur
de y qui dépasse la hauteur de l’image img ?
Améliorer le code de votre fonction afin de tester d’abord si la valeur de y est valide. Si ce
n’est pas le cas, votre fonction devra ne rien dessiner.
Donner une nouvelle version de la fonction ligneHorizontaleAuMilieu2(img,c) qui des-
sine une ligne horizontale de couleur c au milieu de l’image img en ne faisant qu’appeler la
fonction ligneHorizontale(img,c,y).
25
Note : profitez de la fonction range(debut,fin,pas), qui est toute prête à vous fournir la
liste exacte des ordonnées concernées.
Par exemple, grilleHorizontale(monImage,(255,255,0),10) dessinerait dans monImage
des lignes jaunes avec pour ordonnées 0, 10, 20, 30, etc.
Exercice 2.2.5 Écrire une fonction rectangleCreux(img,x1,x2,y1,y2,c) qui dessine les côtés
d’un rectangle de couleur c, les coins du rectangles étant les pixels de coordonnées (x1, y1),
(x2, y1), (x1, y2), (x2, y2). Il s’agit bien sûr de dessiner quatre lignes formant les côtés du
rectangle. Testez-la plusieurs fois avec des coordonnées différentes et des couleurs différentes,
sur une image noire et sur la photo de théière.
Que se passe-t-il si l’un des paramètres dépasse de la taille de l’image ? Est-il facile de
corriger le problème ?
Exercice 2.2.6 Qu’effectue la fonction suivante ? N’hésitez pas à la copier depuis le PDF dis-
ponible sur le site du cours et à la coller dans Python Tutor.
def remplir ( img , c ):
l = largeurImage ( img )
h = hauteurImage ( img )
for x in range ( l ):
for y in range ( h ):
colorierPixel ( img , x , y , c )
Décrire précisément ce qu’effectue chaque ligne, testez-la. Est-ce que les pixels sont coloriés
ligne par ligne ou colonne par colonne ? Si le premier pixel colorié est celui de coordonnées (0, 0),
quelles sont les coordonnées du pixel colorié en deuxième, (0, 1) ou (1, 0) ?
Mêmes questions pour la version suivante :
def remplirBis ( img , c ):
l = largeurImage ( img )
h = hauteurImage ( img )
for y in range ( h ):
for x in range ( l ):
colorierPixel ( img , x , y , c )
Définir une fonction remplir2(img,c) produisant le même résultat, en utilisant la fonction
ligneHorizontale.
Serait-il possible possible d’obtenir le même effet avec la fonction grilleHorizontale ?
Exercice 2.2.7 En vous inspirant très largement de la fonction remplir, écrivez une fonction
rectanglePlein(img,x1,x2,y1,y2,c) qui dessine un rectangle plein de couleur c dont les
coins sont les pixels de coordonnées (x1, y1), (x2, y1), (x1, y2), (x2, y2).
Exercice 2.2.8 On veut colorier toute une image img en gris. On a commencé par taper ceci :
# code a completer
c = (127 ,127 ,127)
l = largeurImage ( img )
h = hauteurImage ( img )
et il s’agit maintenant de parcourir toute l’image pour la colorier. Parmi les codes suivants,
lesquels sont corrects ? Rayer les codes erronés.
26
for x in range ( h ): for x in range (1 ,l ,1):
for y in range ( l ): for y in range (1 ,h ,1):
colorierPixel ( img , x , y , c ) colorierPixel ( img , x , y , c )
Exercice 2.2.9 Écrire une fonction remplirDegradeGris(img) qui remplit l’image img avec
un dégradé de gris depuis du noir en haut à du blanc en bas : tous les pixels de la ligne tout en
haut de l’image doivent être noirs, et tous les pixels de la ligne tout en bas de l’image doivent
être blancs, et les pixels des lignes intermédiaires, d’un niveau de gris intermédiaire, en dégradé.
Que suffit-il de changer pour que le dégradé soit de la gauche vers la droite ?
Que suffit-il de changer pour que le dégradé soit du bas vers le haut ?
Exercice 2.2.10 Écrire une fonction remplirRougeVertJaune(img) qui remplit l’image img
avec un dégradé de couleurs : le coin en haut à gauche doit être noir, le coin en bas à gauche
doit être vert, le coin en haut à droite doit être rouge, et le coin en bas à droite doit être jaune
(le jaune est le mélange à part égale de rouge et de vert).
De la même façon, écrivez remplirRougeBleuViolet(img) et remplirVertBleuCyan(img)
Il est très courant d’appliquer un filtre sur une image, c’est-à-dire un calcul sur chacun des
pixels de l’image. L’instruction
(r ,g , b ) = couleurPixel ( img , 10 , 10)
récupère les valeurs r, g et b de la couleur du pixel de coordonnées (10, 10). Par exemple, pour
ne conserver que la composante rouge du pixel (10, 10), on peut utiliser :
colorierPixel ( img , 10 , 10 , (r ,0 ,0))
Exercice 2.3.1 Écrire une fonction filtreRouge(img) qui, pour chaque pixel de l’image, ne
conserve que la composante rouge. Testez-la sur la photo de théière. Faites de même pour le
vert et le bleu et affichez les trois résultats ainsi que l’image d’origine côte à côte. Remarquez
notamment que pour le bleu il n’y a pas d’ombre en bas à droite. En effet, la source lumineuse
en haut à gauche ne contient pas de bleu.
Exercice 2.3.2 Écrire une fonction modifierLuminosite(img,facteur) qui pour chaque pixel
multiplie par f acteur les valeurs des trois composantes r, g, et b. Remarquez que la fonction
colorierPixel n’apprécie pas que l’on donne des valeurs non entières. Utilisez donc la fonction
int(f) qui convertit une valeur avec virgule f en valeur entière.
Testez les facteurs 1.2, 2, 0.8, 0.5 sur la photo de théière (n’oubliez pas de recharger la
photo à chaque fois pour éviter de cumuler les effets).
27
Exercice 2.3.3 On dispose d’une photographie d’un personnage prise sur un fond vert (sur la
photocopie le vert apparaît en gris clair, l’image est disponible sur le site du cours). On souhaite
incruster ce personnage sur un autre fond comme dans l’exemple suivant.
1. Écrire et tester une fonction copieCoinImage(avantPlan, fond) qui copie l’image avantPlan
dans l’image fond. On place l’image en avant plan en haut à gauche de l’image de fond
(on fait correspondre leurs coins supérieurs gauches). On suppose également que l’image
de fond est assez grande pour contenir toute l’image à copier.
2. Écrire et tester une fonction copieImage(avantPlan , fond, dx, dy) qui copie l’image
avantPlan dans l’image fond en faisant correspondre le pixel (0,0) de l’image d’avant
plan avec le pixel (dx,dy) de l’image de fond.
3. On suppose que le fond vert, qui ne doit pas apparaître dans l’image résultat, est composé
uniquement de pixels de couleur (0,255,0). Écrire et tester une fonction incrusterImage(avantPlan,
fond, x, y) qui incruste sans copier les pixels verts l’image avantPlan dans l’image fond
tout en faisant le pixel (0,0) de l’image d’avant plan avec le pixel (x,y) de l’image de
fond.
28
Exercice 2.4.3 (extrait DS 2015-16) On souhaite masquer la moitié d’une image à l’aide
d’une couleur. Voici un exemple :
Exercice 2.4.4 Écrire une fonction diagonale(img) qui dessine en blanc la ligne diagonale
entre le coin en haut à gauche et le coin en bas à droite de l’image. Tester avec différentes tailles
d’image, et corriger l’erreur que vous avez commise.
Exercice 2.4.5 On souhaite ajouter des lignes verticales noires à une image.
Écrire une fonction emprisonner(img, nbBarreaux, epaisseur) qui ajoute nbBarreaux
lignes verticales d’epaisseur pixels et réparties de façon homogène dans l’image.
Exercice 2.4.6 En vous souvenant du schéma du cercle trigonométrique pour écrire l’équation
paramétrique de la courbe du cercle, écrire une fonction cercle(img,x,y,r) qui dessine un
cercle de rayon r dont le centre a pour coordonnées (x, y).
Note : Les outils trigonométriques (cos, sin, pi, ...) sont disponibles en tapant :
from math import *
Exercice 2.4.7 On souhaite masquer une image en diagonale à 45 degré à l’aide d’une couleur.
Voici un exemple :
2. Est-ce que votre fonction est correcte pour une image qui serait plus haute que large ?
Sinon, corrigez.
29
Exercice 2.4.8 Écrire une fonction remplirDegradeDiagonaleBleu(img) qui remplit l’image
img avec un dégradé de bleu en diagonale : le coin en haut à gauche doit être noir, le coin en
bas à droite doit être bleu.
Écrire une fonction remplirDegradeDiagonaleBleuInverse(img) qui remplit l’image img
avec un dégradé de bleu en diagonale dans l’autre sens : le coin en haut à gauche doit être bleu,
le coin en bas à droite doit être noir.
En combinant les formules utilisées pour remplirRougeVertJaune et pour remplirDegrade-
DiagonaleBleu, écrire une fonction remplirCouleurs(img) qui remplit l’image img avec un
dégradé entre les différentes couleurs : le coin en haut à gauche doit être bleu, le coin en bas
à gauche doit être vert, le coin en haut à droite doit être rouge, et le coin en bas à droite doit
être jaune.
Manipulation de couleurs
Exercice 2.4.9 Écrire une fonction emprisonnerJoliment(img, nbBarreaux, epaisseur) qui
améliore le rendu de l’exercice 2.4.5 en faisant apparaître un dégradé de gris sur chaque barreau.
Pour calculer la couleur d’un pixel d’un barreau, on pourra utiliser une formule telle que
Exercice 2.4.10 Écrire une fonction monochrome(img) qui pour chaque pixel, calcule la moyenne
lum = r+g+b
3 des composantes r, g, b, et peint le pixel de la couleur (lum, lum, lum).
En observant bien, les éléments verts semblent cependant plus foncés que sur la photo
d’origine. L’œil humain est effectivement peu sensible au bleu et beaucoup plus au vert. Une
conversion plus ressemblante est donc d’utiliser plutôt l = 0.3 ∗ r + 0.59 ∗ g + 0.11 ∗ b. Essayez,
et constatez que les éléments verts ont une luminosité plus fidèle à la version couleur.
Exercice 2.4.11 Écrire une fonction noirEtBlanc(img) qui convertit une image monochrome,
telle que produite par la fonction monochrome de l’exercice 2.4.10, en une image noir et blanc :
chaque pixel peut valoir (0,0,0) ou (255,255,255) selon que la luminosité est plus petite ou plus
grande que 127.
Cette conversion ne permet néanmoins pas de représenter les variations douces de luminosité.
L’exercice 2.4.12 présente une méthode plus avancée résolvant cette limitation.
Exercice 2.4.12 Comme vous l’avez constaté dans l’exercice 2.4.11, la qualité des images pro-
duites par la fonction noirEtBlanc laisse à désirer. L’algorithme proposé par Floyd et Stein-
berg, permet de limiter la perte d’information due à la quantification des pixels en blanc ou noir.
Écrire une fonction floydSteinberg(img) qui convertit une image monochrome en noir et blanc
à l’aide de l’algorithme de Floyd et Steinberg (cf. page Wikipedia : http://fr.wikipedia.org/
wiki/Algorithme_de_Floyd-Steinberg).
Exercice 2.4.13 L’effet de postérisation est obtenu en diminuant le nombre de couleurs d’une
image. Une manière simple de l’obtenir est d’arrondir les composantes r, g, b des pixels de
l’image à des multiples d’un entier, par exemple des multiples de 64. Écrivez donc une fonction
posteriser(img,n) qui arrondit les composantes des pixels de l’image à un multiple de n.
Essayez sur une photo avec n = 64, 128, 150, 200.
Exercice 2.4.14 Une manière simple de rendre une image floue est d’utiliser l’opération moyenne.
Écrire une fonction flou(img) qui pour chaque pixel n’étant pas sur les bords, le peint de la
30
couleur moyenne des pixels voisins 1 . Comparer le résultat à l’original. Pourquoi faut-il plutôt
passer une deuxième image en paramètre à la fonction, et ne pas toucher à la première image ?
Exercice 2.4.15 On cherche à réaliser la fusion de deux images supposées de même taille,
comme dans l’exemple suivant.
Manipulations géométriques
Exercice 2.4.16 (extrait DS 2014-15) Un reporter a pris plusieurs photographies d’un pay-
sage. Elles sont de même hauteur mais montrent des points de vue décalés. Il souhaite mainte-
nant les mettre côte à côte pour obtenir une image panoramique de ce paysage (sans se soucier
des problèmes de perspective).
1. Écrire une fonction assembler(imgGauche, imgDroite, imgPano) qui place dans imgPano
l’image correspondant à l’assemblage horizontal des images imgGauche et imgDroite.
Quelle doit être la largeur de l’image imgPano passée en paramètre ?
Exercice 2.4.17 (extrait DST 2015-16) L’objectif de cet exercice est d’écrire le code de deux
fonctions Python permettant d’effectuer la transformation miroir (symétrie axiale) d’une image.
Voici un exemple :
1. Écrire une fonction miroirVertical(img1, img2) qui place dans img2 l’image corres-
pondant au miroir vertical de img1 (img1 et img2 sont supposées de même taille).
1. Pour un résultat réellement correct, il faudrait en fait pour chaque composante prendre la racine carrée de
la moyenne des carrés des pixels voisins, voir https://www.youtube.com/watch?v=LKnqECcg6Gw
31
2. Écrire une fonction miroirHorizontal(img1, img2) qui place dans img2 l’image corres-
pondant au miroir horizontal de img1.
Exercice 2.4.18 Écrire une fonction rotation90(img1, img2) qui place dans img2 l’image
img1 tournée de 90 degrés vers la droite, c’est-à-dire dans le sens horaire.
Pourquoi est-on obligé d’utiliser une deuxième image, plutôt que faire la rotation « en place »,
c’est-à-dire en n’utilisant qu’une image ?
Exercice 2.4.19 1. Écrire une fonction rotationCoincoin(img1, img2, angle) qui stocke
dans img2 l’image img1 tournée de angle radians vers la droite par rapport au coin
supérieur gauche de l’image. Quelques conseils :
• Parcourir les pixels de l’image img2 et calculer la position du pixel source correspon-
dant dans l’image img1 ; s’il est en-dehors de l’image, stocker un pixel noir.
x′ = x · cos(φ) + y · sin(φ)
y ′ = −x · sin(φ) + y · cos(φ)
2. Écrire une fonction rotationCentre(img, angle) qui retourne une image correspondant
à l’image img1 tournée de angle radians par rapport au centre de l’image.
Image floue
Exercice 2.4.20 Modifiez la fonction flou(img) de l’exercice 2.4.14 pour qu’elle retourne une
version floutée de l’image img. Créez des images de plus en plus floues en appelant de façon
répétée cette fonction.
Ajoutez à la fonction des paramètres x1,x2,y1,y2 qui désignent les coordonnées d’une
portion rectangulaire de l’image qui doit être floutée plutôt que toute l’image. Floutez ainsi
seulement un visage apparaissant sur une photo de votre choix (on pourra par exemple utiliser
le logiciel gimp pour déterminer les coordonnées à utiliser).
32
Agrandissement d’une image
Exercice 2.4.21 Écrire une fonction agrandirFacteur2(img) qui retourne une image corres-
pondant à l’agrandissement d’un facteur deux de l’image img. Pour réaliser cet agrandissement,
chaque pixel de l’image source donnera un carré 2 × 2 pixels dans l’image destination.
Tester cette fonction sur l’image teapot.png. Appeler plusieurs fois la fonction pour produire
un agrandissement d’un facteur 8 de cette même image. L’image apparait quelque peu pixelisée,
comment atténuer facilement ce phénomène ?
Exercice 2.4.22 Écrire une fonction decoder_composante(n) qui, à partir d’une valeur n com-
prise entre 0 et 99 999 retourne la valeur de la composante cachée.
Appliquons maintenant cette technique à une composante d’un pixel dont la valeur est
comprise en 0 et 255. Pour ce faire on exploite l’écriture en base 2 d’une composante : une telle
valeur est codée sur un octet en binaire, soit 8 chiffres binaires. Pour camoufler une image on
conserve les 5 premiers chiffres de la composante issue de A et les trois premiers de celle issue
de B. Ainsi à partir de deux octets a7 a6 a5 a4 a3 a2 a1 a0 et b7 b6 b5 b4 b3 b2 b1 b0 on obtient le nombre
binaire a7 a6 a5 a4 a3 b7 b6 b5 . Réciproquement pour découvrir la valeur cachée dans une composante,
il s’agit d’isoler les 3 derniers chiffres binaires de celle-ci puis de les décaler de 5 chiffres. À partir
du nombre binaire a7 a6 a5 a4 a3 b7 b6 b5 , on isole b7 b6 b5 pour obtenir b7 b6 b5 00000. Maintenant on
sait que la composante originale doit avoir une valeur comprise entre b7 b6 b5 00000 et b7 b6 b5 11111 :
l’erreur maximale possible vaut donc 11111 (soit 31 en base 10). Aussi, en ajoutant 10000 (soit
16) à la composante décodée on réduit l’erreur maximale à 16.
Exercice 2.4.23 L’objectif est d’écrire une fonction permettant de découvrir une image cachée
à partir d’une image source.
33
1. Écrire une fonction decoder_composante(n) qui, à partir d’une valeur n comprise entre
0 et 255 retourne la valeur de la composante cachée.
3. Utiliser cette fonction pour décoder l’image cachée dans stegano.png disponible sur le
site du cours.
Exercice 2.4.24 Écrire une fonction dissimuler_image(image1, image2) qui retourne une
nouvelle image où l’image1 cache l’image2. On supposera que les images sont de même taille (on
peut facilement utiliser un outil externe pour redimensionner une des deux images au besoin).
34
Chapitre 3. Boucle conditionnelle
La boucle while (tant que) permet de répéter une partie de programme tant qu’une condition
est vraie. Attention, cela signifie que si vous vous trompez, éventuellement votre programme va
planter, c’est-à-dire répéter indéfiniment la boucle while sans jamais s’arrêter, si la condition
ne devient jamais fausse. Vous pouvez alors appuyer sur Control - c pour interrompre python.
s = 0
s = 0 x = 0
Par exemple, for x in range (10): peut s’écrire while x < 10:
s = s + x s = s + x
x = x + 1
Certains problèmes ne peuvent cependant pas se résoudre à l’aide d’une boucle for mais
uniquement à l’aide d’une boucle while, le nombre d’itérations n’étant pas connu a priori.
Considérons par exemple le problème suivant.
Exercice 3.0.1 On place 100 euros sur un compte bancaire avec 1% d’intérêts par an. Écrire
une suite d’instructions calculant le nombre d’années nécessaires pour que ce placement soit au
minimum doublé.
Essayez de résoudre ce problème en utilisant une boucle for. On constate que l’on ne sait
pas à l’avance combien de tour il faut effectuer (c’est justement l’objectif du problème). Utilisez
donc à la place une boucle while.
1. Quelle est la valeur de mystere(2501). De façon générale, que calcule la fonction mystere ?
2. Pourquoi est-il plus pratique d’utiliser un while qu’un for pour coder la boucle de la
fonction mystere ?
4. Écrire une fonction plusGrandChiffre(n) qui retourne le plus grand chiffre contenu dans
le nombre entier n. Par exemple, la valeur de plusGrandChiffre(2501) est 5.
Exercice 3.1.2 (extrait épreuve de mathématiques Bac S, 2019) Soit A un nombre réel
strictement positif. On considère l’algorithme suivant :
i = 0
while 2** i <= A :
i = i + 1
35
où “**” représente l’élévation à la puissance. On observe que la variable i contient la valeur
15 en fin d’exécution de cet algorithme. L’affirmation suivante est elle vraie ou fausse (justifier) :
mystere(2,8)
i
x
y
a 2 3
n 6 4
valeur retournée
3. Comment interpréter la valeur retournée par la fonction mystere en général, pour deux
valeurs a et n quelconques ?
36
Exercice 3.2.2 (extrait DST 2014-2015) Pour tout entier n ≥ 0, le nombre de Cullen d’in-
dice n est le nombre n × 2n + 1.
Primalité
Exercice 3.3.2 L’objectif est d’écrire un test de primalité, c’est à dire une fonction premier(n)
qui retourne True si l’entier naturel n > 1 est premier et False sinon. Pour cela on parcourt les
nombres supérieurs à 2 pour chercher un diviseur d de n : dès que l’on en trouve un on arrête
les calculs, n n’est pas premier.
1. Écrire la fonction premier(n) à l’aide d’une boucle for implémentant cet algorithme.
Tester cette fonction en affichant tous les nombres premiers inférieurs à 100.
4. Améliorer 1 premier(n) en traitant à part le cas où n est pair ; dans le cas où n est impair,
il suffit ensuite de chercher un diviseur d impair.
Exercice 3.3.3 On suppose dans cet exercice que l’on dispose de la fonction premier(n) décrite
√
dans l’exercice 3.3.2, et que son temps de calcul est proportionnel à n lorsque n est premier.
1. Écrire une fonction premierSuivant(n) qui calcule le plus petit nombre premier p > n.
2. Sachant que le calcul de premierSuivant(10**12) prend environ une seconde, quel est
l’ordre de grandeur maximal de n pour que le calcul de premierSuivant(n) dure moins
d’une minute ? moins d’une heure ? moins d’une journée ?
1. il existe des tests de primalité sophistiqués radicalement plus efficaces que le test naïf décrit dans l’exer-
cice 3.3.2 ; ils permettent de tester en quelques secondes la primalité d’un nombre dont l’écriture décimale com-
porte plusieurs centaines de chiffres.
37
Quelle est la durée approximative du calcul de premierSuivant(2**40) ? Même question
pour 250 .
Note : pour le traitement de cette question on suppose que le temps de calcul de premier(n)
est négligeable lorsque n n’est pas premier, ce qui est très souvent le cas (la plupart des
entiers possèdent un petit facteur, découvert très vite lors de l’exécution de premier(n)).
1. Écrire une fonction facteurImpair(n), qui, étant donné un entier naturel n non-nul,
renvoie le plus grand diviseur impair de n. Le résultat sera obtenu par une succession de
divisions de n par 2 tant que n est pair. Par exemple, facteurImpair(504) retournera
63, puisque 504 est pair, 252 (504 divisé par 2) et 126 (252//2) sont pairs, et 63 (126//2)
est impair.
2. Écrire une fonction puissanceDiviseur(p,n), qui, étant donné un entier naturel n non-
nul, renvoie la plus grande puissance de p qui divise n.
Par exemple, puissanceDiviseur(2,504) retournera 8, puisque 504 est divisible par
8 = 23 , mais pas par 16 = 24 .
Suites
Exercice 3.3.5 Une suite de Syracuse est définie par récurrence de la façon suivante :
u0 =a
{
un /2 si un est pair,
un+1 =
3un + 1 sinon.
2. Écrire une fonction syracuse(a, n) qui calcule le terme de rang n de cette suite lorsque
le premier terme u0 est égal à a. Tester cette fonction pour a = 5 puis pour a = 7.
38
4. On conjecture (consulter par exemple Wikipedia) qu’une suite de Syracuse finit toujours
par atteindre la valeur 1. Écrire une fonction longueur(a) qui calcule et retourne la
première valeur de n telle que un = 1 lorsque le premier terme u0 vaut a.
5. Vérifier la conjecture pour tous les entiers a < 100 (utilisez une boucle bien sûr, en utilisant
print pour montrer les résultats !) Parmi ces valeurs de a, quelle est celle qui fournit une
suite de longueur maximale ?
pour calculer longueur(27). Améliorer le code de la fonction longueur(a) pour éviter les
calculs inutiles.
[u0 = a, u1 , u2 , ..., un = 1]
où un désigne le premier terme égal à 1. Par exemple, avec a = 7 on obtient la liste [7,
22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1].
8. Écrire une fonction hauteur(a) qui calcule et retourne la valeur maximale de un lorsque
le premier terme u0 vaut a ; par exemple hauteur(7) vaut 52.
√
Exercice 3.3.6 Comment calculer 2 avec k chiffres après la virgule ? Une méthode simple est
d’utiliser la suite un suivante :
{
u0 =3
un+1 = u2n + 1
un
2.5
1.5
x -> x
0.5
x -> x/2 + 1/x
suite u_n
0
0 0.5 1 1.5 2 2.5 3 3.5
1. Écrire une fonction suite(n) qui calcule et retourne le terme de rang n de cette suite.
39
2. Utilisez
√ une boucle pour afficher les 10 premiers termes de la suite. Une valeur approchée
de 2 est 1.414213562373095048[...]. On constate effectivement que la suite converge vers
cette valeur, mais sans pouvoir toutefois l’atteindre : le nombre de chiffres des valeurs de
l’ordinateur est limité !
√
3. Plus généralement, pour calculer x, on peut utiliser la suite
{
u0 =x
un+1 = 21 (un + x
un )
√
où u0 est une première estimation grossière de x, on a utilisé x lui-même pour simplifier.
√
Écrire une fonction sqrt(x) qui retourne une approximation de x en calculant u10 et
imprimant les valeurs intermédiaires un au passage. Tester avec 2, 3, 10.
4. Tester avec 1000. On constate que la convergence est lente, on n’est pas sûr que 10 ité-
rations suffisent. Remplacer la boucle for par une boucle while pour continuer le calcul
tant que la différence entre deux termes consécutifs est plus grande que 0.0000001. Tester
avec 100000.
2. Cette suite est souvent divergente, mais d’une manière irrégulière. On s’intéresse au cas
où le module de zn dépasse 2, et surtout au nombre d’itérations n nécessaire pour cela.
On se limitera cependant à 256 itérations.
En s’inspirant de la fonction suiteComplexe, définir avec une boucle while une fonction
suiteComplexeDiverge(x, y, size) qui retourne le plus petit entier n tel que l’on n’a
plus la condition « n < 256 et le module de zn est inférieur à 2 ».
3. Définir la fonction mandelbrot(size) qui retourne une image de taille (size, size) telle
que le niveau de gris du pixel de coordonnées (x, y) est déterminé par la valeur calculée
par suiteComplexeDiverge(x,y, size).
Dessiner l’image retournée par mandelbrot(256).
40
4. Définir la fonction mandelbrotCouleur(size) sur le même schéma que la fonction mandelbrot(size)
mais cette fois-ci la couleur de chaque pixel est :
41
Chapitre 4. Sommets d’un graphe
Un graphe est une modélisation d’un ensemble (non vide) d’objets reliés entre eux ; les objets
sont appelés sommets, et les liens entre les objets sont appelés arêtes.
On peut utiliser les graphes pour représenter diverses situations courantes : les liens d’amitié
entre étudiants, les matches entre équipes de sport, les liaisons moléculaires entre des atomes,
les routes entre les villes, ...
Nous vous fournissons une définition python de la classe des graphes, ainsi que des autres
classes (sommets et arêtes) nécessaires. Ces définitions se trouvent dans le module bibgraphes.py
écrit par des enseignants, disponible en téléchargement sur le site https://moodle1.u-bordeaux.
fr/course/view.php. Utiliser un clic droit et “enregistrer sous” pour l’enregistrer à côté de vos
autres fichiers python. Ce module comporte aussi une vingtaine de fonctions qui permettent de
manipuler graphes, sommets et arêtes sans connaître les détails des classes correspondantes.
Pour utiliser un module il faut commencer par l’importer, et toute session de travail sur les
graphes doit commencer par la phrase magique :
from bibgraphes import *
Lille Strasbourg
On peut stocker toutes les informations d’un graphe dans un fichier de format .dot. Pour
manipuler un graphe dans un programme python, on utilisera la fonction suivante :
Pour travailler sur le graphe du TGV (fichier tgv2005.dot disponible sur le site du cours), on
commencera donc par l’instruction suivante :
tgv = ouvrirGraphe ( " tgv2005 . dot " )
Avec Python Tutor, le graphe apparait à l’écran. Si l’on utilise Spyder, il faut utiliser l’instruction
suivante :
dessiner ( tgv )
42
Si dans une session python, à la suite de cette instruction, on tape simplement tgv, ou
print(tgv), l’interprète (en jargon : Python Shell) répond : <graphe: 'tgv2005'> pour in-
diquer que c’est un graphe dont le nom est 'tgv2005'. Pour désigner le sommet Bordeaux
on pourrait croire qu’il suffit de taper Bordeaux, hélas l’interprète répond, rouge de colère :
NameError: name 'Bordeaux' is not defined.
En effet il n’y a pas de variable appelée Bordeaux qui contiendrait ce sommet. On peut
obtenir la liste complète des sommets d’un graphe G avec la fonction listeSommets(G). En
reprenant le même exemple, si l’on tape listeSommets(tgv) on obtient :
Chaque sommet est affiché avec confirmation de sa classe, suivie du nom du sommet et de sa
couleur — pour l’instant ’white’, donc coloré en blanc ; la dernière composante est booléenne et
indique si le sommet est marqué ou non : ces marques seront utilisées section 4.5, pour l’instant
False est affiché partout car aucun sommet n’est marqué.
Le nom d’un sommet, par exemple 'Bordeaux', est une simple chaîne de caractères utilisée
pour identifier ce sommet à l’intérieur du graphe lorsque l’on affiche le sommet ou lorsque l’on
dessine le graphe. Comme on l’a expliqué ci-dessus, ce n’est pas le nom d’une variable, c’est juste
une étiquette appliquée au sommet. Il faut utiliser la fonction sommetNom(G,nom) pour accéder
au sommet par son nom : sommetNom (tgv, 'Bordeaux') est une expression correcte pour
désigner ce sommet, et on peut ensuite le stocker dans une variable en utilisant une affectation :
bx = sommetNom (tgv, 'Bordeaux'). Pour bien distinguer les deux, nous avons choisi ici un
nom de variable bx distinct de l’étiquette Bordeaux.
Quelques graphes dont celui du TGV sont disponibles sur le site du cours https://moodle1.
u-bordeaux.fr/course/view.php. Il est aussi possible de récupérer des graphes sur Internet.
On pourra par exemple consulter la bibliothèque https://networkdata.ics.uci.edu/index.
php qui contient d’autres exemples. Les formats supportés par le module bibgraphes.py sont
.dot, .gml et .paj. Attention à la taille des graphes, certains contiennent de millions de sommets
(nodes) ou d’arêtes (edges) et seront très longs à traiter !
Dans les exercices suivants on suppose que la variable tgv contient le graphe du TGV
(Figure 4.1).
43
Exercice 4.1.1
Exercice 4.1.2 Puisque la fonction listeSommets retourne une liste des sommets du graphe,
on peut l’utiliser au sein d’une boucle for pour effectuer une opération sur chacun des sommets
du graphe.
Écrire une fonction toutMarquer(G) qui marque tous les sommets du graphe G. Utiliser
cette fonction pour marquer tous les sommets du graphe tgv ; vérifier le résultat de deux
façons :
a) en affichant la liste des sommets du graphe,
b) en dessinant le graphe.
Écrire l’instruction qui permet d’annuler l’opération précédente, c’est-à-dire de démarquer les
sommets ; vérifier que les sommets du graphe tgv sont bien demarqués.
Exercice 4.1.3 Écrire une fonction existeMarque(G) qui renvoie True s’il existe au moins un
sommet marqué dans le graphe G et False sinon.
Exercice 4.1.4 Écrire une fonction tousMarques(G) qui renvoie True si tous les sommets du
graphe G sont marqués, et False sinon.
Exercice 4.1.5 Écrire une fonction nbSommetsMarque(G) qui compte les sommets du graphe G
qui sont marqués.
4.2 Voisins
Deux sommets s et t sont appelés voisins s’il existe une arête e ayant s et t comme extrémités ;
on dit que l’arête e est incidente à chacun des sommets s et t.
Une boucle est une arête dont les deux extrémités sont confondues et correspondent au
même sommet.
La fonction listeVoisins(s) retourne la liste des voisins du sommet s, obtenue en suivant
chacune des arêtes incidentes. Un même sommet peut se retrouver plusieurs fois dans cette
liste : par exemple B apparaît deux fois dans la liste des voisins de A.
Une boucle autour du sommet s est, par convention, deux fois incidente à s : la liste des
voisins de B contient deux fois le sommet B lui-même, à cause de la boucle autour de B (que
l’on peut considérer dans un sens ou dans l’autre).
Le degré d’un sommet s est le nombre d’incidences d’arêtes, et la fonction degre(s) retourne
sa valeur ; c’est aussi le nombre de brins issus de s lorsqu’on regarde le dessin — une boucle
compte pour deux dans le calcul du degré. Attention : il ne faut jamais de lettre accentuée dans
le nom d’une fonction python.
44
e1
A B e5
Par exemple, les sommets A et B du graphe ci-
e2
contre sont voisins, ainsi que A et C, tandis que les e3
sommets A et D ne sont pas voisins. Il peut exister
plusieurs arêtes entre deux sommets, par exemple C D e6
ici entre A et B, on parle alors d’arête multiple. e4
Sur le graphe ci-contre, il y a une boucle autour
du sommet B et deux boucles autour du sommet e7
D.
Figure 4.2 – un graphe avec une arête
double et trois boucles
Exercice 4.2.1 Pour chaque sommet du graphe de la figure 4.2, noter sur papier son nom,
son degré et écrire la liste de ses voisins (leur ordre dans la liste est sans importance). Écrire
l’instruction python qui permet de vérifier cela en TP (le fichier correspondant à ce graphe est
fig32.dot).
Exercice 4.2.2 Appeler la fonction listeVoisins pour afficher la liste des villes voisines de
Nantes dans le graphe du TGV.
Exercice 4.2.3 Écrire une fonction sontVoisins(s1,s2) qui teste si les sommets s1 et s2 sont
voisins, c’est-à-dire qui renvoie True si c’est le cas et False sinon.
Tester cette fonction sur tous les couples de sommets du graphe de la figure 4.2.
Écrire l’instruction qui permet de tester si en 2005 il y avait une ligne directe de TGV entre
Bordeaux et Nantes.
On rappelle que le degré d’un sommet est le nombre d’arêtes incidentes à ce sommet. Une
boucle compte pour deux dans le degré. Par exemple, dans le graphe de la figure 4.2 (reproduite
ci-dessous) :
45
Exercice 4.3.1 Soit la fonction suivante : e1
def mystere ( G ):
A B e5
n = nbSommets ( G )
x = 0 e2
for s in listeSommets ( G ): e3
x = x + degre ( s )
return x / n e6
C e4 D
Exercice 4.3.2 1. Écrire une fonction degreMax(G) qui calcule et retourne le maximum des
degrés des sommets d’un graphe G.
2. Écrire une fonction degreMin(G) qui calcule et retourne le minimum des degrés des som-
mets d’un graphe G. Pourquoi cette question est-elle un peu plus difficile que la précé-
dente ?
Note : la fonction elementAleatoireListe(L) (avec L une liste d’éléments) peut être utile
pour la seconde question de cet exercice, voir aide-mémoire, page 86, en fin de fascicule.
Exercice 4.3.3 Écrire une fonction nbSommetsDegre(G,d) qui calcule et retourne le nombre de
sommets du graphe G ayant pour degré d.
Exercice 4.3.4 On dit qu’un sommet est isolé s’il n’a aucune arête incidente. Écrire une fonction
existeIsole(G) qui teste si un graphe G a au moins un sommet isolé.
Exercice 4.3.5 Ouvrez le graphe Power Grid qui représente le réseau électrique américain, à
télécharger depuis le site du cours (fichier power.gml). N’essayez pas de le faire dessiner, il est
très gros, cela prendrait beaucoup de temps !
En utilisant les fonctions des exercices précédents et la fonction nbSommets, vérifier qu’il n’y
a pas de sommet isolé, compter le nombre de sommets de degré 1 et de sommets de degré 2,
calculer le degré maximum des sommets, et calculer la moyenne des degrés des sommets. On
peut ainsi avoir une idée de la robustesse du réseau électrique américain.
Dans cette section, on cherche à établir une relation liant le nombre d’arêtes d’un graphe
à la somme des degrés de ses sommets. Cette relation, appelée formule générale des poignées
de mains, fait partie des résultats à mémoriser. Dès que vous l’aurez comprise, vous la noterez
dans l’encadré ci-dessous :
46
Exercice 4.4.1 Un graphe est dit cubique si tous ses sommets sont de degré 3.
1. Dessiner un graphe cubique ayant 4 sommets ; même question avec 3 sommets, 5 sommets.
Que constate-t-on ?
Exercice 4.4.2 Écrire une fonction estCubique(G) qui teste si le graphe G est cubique.
Exercice 4.4.3 On dispose de 235 machines, que l’on souhaite relier en réseau. Est-il possible de
relier chaque machine à exactement 17 autres machines ? Justifier la réponse, soit en expliquant
comment relier les machines, soit en expliquant pourquoi ce n’est pas possible.
Exercice 4.4.4
1. Dessiner un graphe à 6 sommets tel que la liste des degrés des sommets soit :
[2, 1, 4, 0, 2, 1].
Exercice 4.4.5 En utilisant la formule de poignées de mains, écrire une fonction nbAretes(G)
qui calcule et retourne le nombre d’arêtes d’un graphe G.
Appliquer votre fonction nbAretes(G) au graphe fig32.dot de la figure 4.2 page 45. Vérifier
que votre fonction calcule correctement le nombre d’arêtes.
Exercice 4.5.1 Écrire une fonction nbOccurrences(L, elt) qui renvoie le nombre d’occur-
rences de l’élément elt dans la liste L, c’est-à-dire le nombre de fois où il apparaît dans la
liste.
47
Écrire une fonction estSimple(G) qui teste si le graphe G est simple, en s’aidant de la
fonction nbOccurrences(L, elt) pour vérifier qu’un sommet n’apparaît pas deux fois dans
une liste de voisins.
Exercice 4.5.2 Un graphe complet est un graphe où tout sommet est relié à chacun des autres
par une arête. Évaluer le nombre de comparaisons nécessaires à la fonction estSimple(G)
lorsque G désigne un graphe complet à n sommets.
Une méthode plus efficace pour tester si tous les sommets d’une liste sont distincts est de
marquer chaque sommet en parcourant la liste, et si l’on rencontre un sommet déjà marqué
pendant ce parcours on sait que ce sommet est présent plusieurs fois dans la liste.
Cette méthode comporte un piège, car un sommet marqué le reste ! Si un utilisateur applique
deux fois la fonction à la même liste on va trouver, lors de la seconde passe, que le premier
sommet est marqué, et on va en déduire bêtement qu’il s’agit d’un sommet répété. Il faut
donc commencer par démarquer tous les sommets avant d’appliquer l’algorithme. Les fonctions
disponibles pour manipuler les marques sur les sommets sont :
Exercice 4.5.3
1. Marquez le sommet Bordeaux du graphe du TGV. Dessinez le graphe pour observer com-
ment c’est illustré.
2. Écrire une fonction demarquerVoisins(s) qui démarque tous les voisins du sommet s.
3. Écrire une fonction voisinsDistincts(s) qui teste si tous les voisins du sommet s sont
distincts en utilisant l’algorithme expliqué en haut de la section 4.5 — le résultat est True
ou False. Tester la fonction sur chaque sommet s du graphe de la figure 4.2, et afficher la
liste des voisins de s après chaque test pour repérer les sommets marqués et vérifier que
ce sont bien les sommets prévus.
4. Utiliser les fonctions précédentes pour écrire la fonction estSimple(G) qui teste si un
graphe G est simple.
Tester la fonction estSimple(G) sur quelques uns des graphes disponibles sur le site du cours.
Après exécution du test sur un graphe G, dessiner G et/ou afficher la liste de ses sommets pour
repérer ceux qui sont marqués ; interpréter le résultat, en particulier pour les graphes simples.
Exercice 4.5.4
1. Essayer de construire un graphe simple ayant 4 sommets, et tel que les degrés de sommets
soient tous distincts.
2. On se propose de démontrer par l’absurde qu’il n’existe pas de graphe simple de n sommets
(n ≥ 2) tel que tous ses sommets soient de degrés distincts. Supposons qu’un tel graphe
G existe.
48
b) En déduire les degrés possibles pour les n sommets.
c) Montrer que ceci entraîne une absurdité.
Voisins
Exercice 4.6.1 (extrait DST 2015-16)
2. Écrire une fonction estVoisinDAuMoinsUn(x, L) qui renvoie True si le sommet x n’est pas
dans la liste L et est voisin d’au moins un des sommets de L, et qui renvoie False sinon.
Pour écrire cette fonction, vous pourrez tirer avantage à utiliser la fonction précédente.
Exercice 4.6.3 Écrire une fonction verifieMolecule(G) qui vérifie que tous les sommets blancs
sont de degré 1, tous les sommets noirs sont de degré 4, et tous les sommets rouges sont de degré
2. Elle renverra soit un sommet qui ne vérifie pas ces conditions, soit None pour indiquer que
tous les sommets les vérifient. Ouvrez les graphes représentant des molécules disponibles sur le
site du cours https://moodle1.u-bordeaux.fr/course/view.phpet testez verifieMolecule
dessus.
Quelle fonction a-t-on envie d’écrire pour simplifier l’écriture de verifieMolecule ?
Exercice 4.6.4 Écrivez une fonction moyenneDegresVoisins(s) qui compte la moyenne des
degrés des voisins du sommet s. Écrivez une fonction nbDegreMoindreVoisins(G) qui compte le
nombre de sommets pour lesquels leur degré est inférieur à la moyenne des degrés de leurs voisins.
Appelez-la sur différents graphes et comparez à chaque fois au nombre de sommets. Écrivez une
fonction nbDegreMoindre(G) qui compte le nombre de sommets dont le degré est inférieur à
la moyenne des degrés des sommets du graphe (réutilisez la fonction de l’exercice 4.3.1). Que
remarquez-vous ?
49
C’est un effet bien connu : sur les réseaux sociaux, on a l’impression d’avoir moins d’amis
que nos amis ont d’amis, alors qu’en fait globalement non. C’est simplement parce que les
personnes ayant beaucoup d’amis sont sur-représentées dans la moyenne ; c’est expliqué dans la
vidéo Micmaths https://www.youtube.com/watch?v=MySkCFFgiRQ
Boucles
Dans la suite, on testera les fonctions de cette section sur le graphe de la figure 4.2 (le nom du
fichier correspondant est fig32.dot).
Exercice 4.6.7 Écrire une fonction existeBoucle(s) qui teste si le sommet s possède une
boucle incidente, c’est-à-dire une arête qui relie le sommet s à lui-même , autrement dit que le
sommet s apparaît dans sa propre liste de voisins — on dit aussi dans ce cas qu’il existe « une
boucle autour de s ».
Par exemple sur le graphe de la figure 4.2, la fonction doit retourner True pour les sommets
B et D, et False pour les sommets A et C.
Exercice 4.6.8 Écrire une fonction nbBoucles(s) qui compte le nombre de boucles autour d’un
sommet s.
Exercice 4.6.9 Écrire une fonction sansBoucle(G) qui teste si un graphe G est sans boucle.
Appliquer cette fonction sur quelques graphes disponibles sur le site du cours.
Boucle conditionnelle
Exercice 4.6.10 Une marche aléatoire dans un graphe est un chemin construit aléatoirement :
partant d’un sommet initial, on tire au hasard le sommet suivant parmi ses voisins et, en répétant
(k − 1) autres fois ce processus, on obtient un chemin de longueur k.
Dans cet exercice, on cherche à mesurer expérimentalement, pour un graphe et un sommet
donnés, la longueur moyenne des marches aléatoires qui reviennent au sommet de départ.
1. Écrire une fonction longueurCycleAleatoire(G,s) qui retourne la longueur d’une marche
aléatoire partant du sommet s et s’arrêtant dès que l’on revient sur ce même sommet.
2. Tester votre fonction sur un chemin "s0" – "s1" – ... – "s9" de longueur 10 créé à
l’aide de l’appel construireGrille(1,10). On pourra afficher le nom des sommets visités
successivement.
50
3. Écrire une fonction moyenneCycleAleatoire(G,etiquette,k) qui retourne la longueur
moyenne de k marches aléatoires formant un cycle et partant du sommet initial dont le
nom est etiquette.
51
Chapitre 5. Chaînes et connexité
Une chaîne dans un graphe est une suite alternée de sommets et d’arêtes :
[s0 , a1 , s1 , a2 , s2 . . . an , sn ]
où l’arête ai relie le sommet si−1 qui la précède et le sommet si qui la suit ; on dit que cette
chaîne relie les sommets s0 et sn , ou qu’elle représente un chemin de s0 vers sn .
Un cycle est une chaîne dont les deux extrémités coïncident (s0 = sn ) ; on peut choisir
n’importe quel sommet du cycle comme sommet de départ.
Le nombre d’arêtes n est la longueur de la chaîne (ou du cycle). Une chaîne peut être réduite
à un seul sommet, elle est alors de longueur nulle. C’est d’ailleurs même un cycle.
Une chaîne est élémentaire si ses sommets et arêtes sont distincts deux à deux, sauf les
sommets extrêmités qui peuvent être égaux (c’est dans ce cas un cycle élémentaire).
Il ne peut donc y avoir d’allers-retours de la forme [s, a, t, a, s] (où a désigne une arête qui
relie les sommets s et t).
Un graphe est connexe si, par définition : pour tous sommets s et t, il existe une chaîne qui
relie s et t.
Une composante connexe d’un graphe G = (S, A) est un sous-ensemble maximal de sommets
tels que deux quelconques d’entre eux soient reliés par une chaîne. Pour tout sommet d’un
graphe, la composante connexe à laquelle appartient ce sommet est donc l’ensemble des sommets
auquel il est relié par au moins une chaîne. Un graphe connexe est donc un graphe qui possède
une seule composante connexe.
5.1 Échauffement
e5
Exercice 5.1.1 Soit le graphe suivant :
e2 e3
A C E
e1 e7 e8 e4
D e6 B
Exercice 5.1.2 Soit Γ une chaîne d’extrémités s et t. On suppose que Γ n’est pas élémentaire.
2. En déduire qu’il existe une chaîne strictement plus courte que Γ qui relie s et t.
52
Exercice 5.1.3 Le graphe suivant est-il connexe ?
Exercice 5.1.4 Indiquer si les propositions suivantes sont vraies ou fausses en justifiant votre
réponse (rappel : un sommet isolé est un sommet de degré zéro) :
3. Pour qu’un graphe à plusieurs sommets soit connexe il est nécessaire que tous ses sommets
soient de degré supérieur ou égal à 1.
Exercice 5.1.5
1. La proposition suivante :
« un graphe est connexe si et seulement si il existe une chaîne passant (au moins
une fois) par chaque sommet du graphe ».
53
5.2 Algorithmes
Accessibilité
On dit que le sommet t est accessible à partir du sommet s s’il existe une chaîne reliant s et
t. En théorie, il est facile de construire progressivement l’ensemble A des sommets accessibles
depuis s en utilisant l’algorithme suivant :
1. initialisation : A = {s} ;
Lorsque cet algorithme se termine, l’ensemble A contient tous les sommets accessibles depuis s.
Pour savoir si le sommet t est accessible depuis s, il suffit donc de tester si le sommet t appartient
à l’ensemble A, alors t est accessible depuis s, sinon il ne l’est pas.
Exercice 5.2.1 On travaille sur le graphe G de l’exercice 5.1.1. Appliquer à la main l’algorithme
de construction de l’ensemble A des sommets accessibles à partir de E en choisissant toujours
le sommet de plus petit dans l’ordre alphabétique à l’étape 2. Recommencer en faisant varier le
sommet de départ.
Expérimentation
Pour rappel, les fonctions qui permettent de manipuler le marquage d’un sommet sont les
suivantes :
• appeler marquerSommet pour marquer l’un des sommets (ne pas choisir Strasbourg),
• marquer ce sommet,
54
• continuer ainsi à marquer quelques sommets. Quand cela s’arrêtera-t-il ?
Plutôt que de faire tout cela à la main, écrire une fonction marquerAccessibles(G,s) qui
effectue les étapes suivantes :
2. elle utilise ensuite une boucle while : tant que sommetAccessible retourne un sommet
(et non None), elle le marque.
Pour que cela soit moins coûteux, arrangez votre code de façon à n’appeler sommetAccessible
qu’une seule fois par tour de boucle while.
1. sommetsTousMarques(G) teste si tous les sommets du graphe G sont marqués (déjà faite
à l’exercice 4.1.4) ;
Exercice 5.2.5 Montrer que l’ensemble A calculé par l’algorithme d’accessibilité correspond à
l’ensemble des sommets appartenant à la composante connexe du sommet s choisi initialement.
Connexité
L’algorithme mis en œuvre dans l’exercice 5.2.3 teste si le graphe G est connexe avec le
même genre d’algorithme : on choisit un sommet s, on construit l’ensemble A des sommets
accessibles depuis s, puis l’on teste si tous les sommets de G appartiennent à A.
Exercice 5.2.6 Montrer que le résultat de cet algorithme ne dépend pas du choix du sommet
initial s.
55
Exercice 5.2.7 Dans le cas où l’algorithme termine sans marquer tous les sommets (le graphe
G n’est pas connexe), l’ensemble A obtenu est seulement l’une des composantes connexes du
graphe G.
Écrire une fonction sommetNonMarque qui retourne un sommet non marqué. Un sommet
retourné par cette fonction appartient donc à une composante connexe dont les sommets ne
sont pas encore marqués.
Écrire une fonction nbComposantesConnexes(G) qui calcule le nombre de composantes
connexes du graphe G.
Exercice 5.2.8 Combien le graphe stocké dans le fichier europe.dot possède-t-il de compo-
santes connexes ? Comptez manuellement les composantes connexes en dessinant le graphe.
Comparez le résultat obtenu avec celui renvoyé par la fonction nbComposantesConnexes. Note :
la Russie est absente du graphe, d’où une composante connexe surprenante — laquelle ?
Exercice 5.2.9 Améliorer la fonction précédente afin qu’elle colore les composantes connexes
de différentes couleurs. Pour ce faire, vous pourrez utiliser une palette préféfinie de couleurs (cf.
Annexe : palettes page 79).
Arêtes (hors-programme)
Pour traiter les arêtes le module de manipulation de graphes contient les fonctions suivantes :
ce qui est un peu plus compliqué, mais permet d’accéder à l’arête a qui relie les sommets s
et t. Note : si le graphe n’est pas simple plusieurs arêtes incidentes à s peuvent mener au même
voisin t, qui dans ce cas apparaît aussi plusieurs fois dans la liste des voisins de s.
Parcours aléatoire
Le module de manipulation de graphes contient la fonction :
56
melange(u) retourne une copie de la liste u dont les éléments
ont été permutés de façon aléatoire
Exercice 5.3.1 Modifier la fonction sommetAccessible de l’exercice précédent pour que le ré-
sultat ne dépende plus de l’ordre dans lequel sont rangés les sommets du graphe, ni de l’ordre
des arêtes incidentes à un sommet.
Tester à nouveau la fonction estAccessibleDepuis comme dans l’exercice 5.2.4, puis des-
siner le graphe de l’Europe : le chemin entre la Belgique et la Hongrie (par exemple) devrait
changer à chaque exécution de l’algorithme.
3. Estimer de même la complexité (au pire) des fonctions estConnexe (exercice 5.2.3) et
estAccessibleDepuis (exercice 5.2.4).
Remarque : il existe des méthodes plus sophistiquées pour programmer ces algorithmes,
qui fournissent des fonctions de complexité (au pire) proportionnelle à (|A| + |S|).
Chemin
Exercice 5.3.3 On voudrait maintenant obtenir un chemin. Il existe des algorithmes efficaces
pour obtenir un chemin optimal, mais pour simplifier nous allons écrire un algorithme relative-
ment peu efficace, et qui ne trouvera pas forcément un chemin optimal.
L’idée est d’utiliser une fonction récursive : pour savoir si l’on peut aller de s à t, il suffit
de tester pour chaque voisin v de s si l’on peut aller de v à t, et le cas échéant d’ajouter s au
chemin obtenu entre v et t. Puisqu’on cherche un seul chemin, on peut le retourner dès que l’on
en a trouvé un.
57
Pour éviter ce problème, il suffit de marquer le sommet s avant de parcourir ses voisins, et
en tête de fonction, vérifier si le sommet est déjà marqué, auquel cas on retourne tout de suite
None.
ii. Écrire donc la fonction chemin(G,s,t) qui retourne un chemin de s à t s’il en existe un
(sous forme de la liste des sommets à parcourir), et sinon None. N’oubliez pas de nettoyer
le graphe au début, il vous faudra donc écrire deux fonctions : l’une qui nettoie le graphe et
appelle simplement l’autre, cette dernière s’appelant elle-même récursivement. N’oubliez
pas non plus le cas de base où t == s.
58
Chapitre 6. Problèmes et algorithmes de
coloration (hors-programme)
En plus du marquage des sommets, on dispose des fonctions suivantes pour donner des
couleurs aux sommets.
colorierSommet(s,c) colorie le sommet s avec la couleur c (par exemple ’red’)
couleurSommet(s) retourne la couleur du sommet s.
dessiner(G) dessine le graphe G
Exercice 6.1.1 Écrire une fonction bienColorie(G) qui teste si un graphe est bien colorié.
Exercice 6.1.2 Un graphe complet d’ordre n est un graphe de n sommets tel que chaque sommet
est relié aux autres sommets par une arête ; on appelle Kn un tel graphe. Dessiner K2 , K3 , K4
et K5 . Quel est le nombre chromatique de Kn ?
s2 s3
Exercice 6.1.3 En remarquant que le graphe ci-contre contient
des sous-graphes complets (lesquels ?) montrer que son nombre s6 s1
chromatique est supérieur ou égal à 4. Vérifier que l’on peut ef-
fectivement le colorier avec 4 couleurs.
s5 s4
59
v1
v0
v3 v9
v2 v8 Exercice 6.1.4 Calculer le nombre chromatique du graphe de
Petersen, représenté ci-contre à gauche.
v4 v6
v5 v7
Exercice 6.1.5 Indiquer si les propositions suivantes sont vraies ou fausses en justifiant votre
réponses :
2. Pour montrer que le nombre chromatique d’un graphe est n, il suffit d’établir un coloriage
avec n couleurs.
3. Pour montrer que le nombre chromatique d’un graphe est n, il suffit de montrer qu’il
contient un graphe complet Kn
5. Pour montrer que le nombre chromatique d’un graphe est au plus n−1, il suffit de montrer
qu’il ne contient pas de graphe complet Kn .
Exercice 6.1.6 Quel est le nombre chromatique d’une grille triangulaire Tn (voir exercice 4.6.6
pour la définition) ?
Même question pour une grille carrée.
A B C
S D E
F
G H
Pour rompre une éventuelle monotonie, le conservateur du musée souhaite différencier chaque
salle de sa ou des salles voisines (c’est-à-dire accessibles par une porte) par la moquette posée
au sol. Quel est le nombre minimum de types de moquettes nécessaires pour répondre à ce
souhait ? Justifier.
60
Exercice 6.1.8 Un aquariophile souhaite acquérir 6 espèces de poissons : A, B, C, D, E, F.
Certaines espèces ne peuvent cohabiter dans un même aquarium. La liste des incompatibilités
est la suivante : A avec E, F avec D, E avec F, C avec D, B avec C, A avec F, B avec D, B avec
F. Il se pose la question de savoir de combien d’aquariums il doit disposer au minimum.
61
Exercice 6.1.9 Un opérateur de télécommunications mobiles veut couvrir une zone géogra-
phique à l’aide de quelques bornes de téléphonie mobile. Pour éviter les interférences, on utilise
différents canaux : deux bornes éloignées de moins de 600 m doivent utiliser des canaux diffé-
rents. La figure 6.2 montre la position des différentes bornes sur une grille dont les carreaux
sont de taille 100 m × 100 m.
Quel est le nombre minimum de canaux que l’opérateur de télécommunications devra utiliser
pour que son réseau de téléphonie mobile puisse fonctionner sans interférence ?
Si la borne en bas du bord droit avait été 100 m plus à gauche, est-ce que le résultat serait
le même ? Justifier.
Un cycle impair est un cycle de longueur impaire (voir chapitre 5), autrement dit un cycle
avec un nombre impair d’arêtes (et donc un nombre impair de sommets si l’on ne compte pas
deux fois le sommet de départ qui est aussi le sommet d’arrivée) ; le cycle impair le plus trivial
est le triangle.
62
Exercice 6.2.1 Parmi les graphes suivant :
C A
D G
E F
Algorithme
Pour tester si un graphe connexe G est coloriable avec deux couleurs données c1 et c2 , on dispose
d’un algorithme qui ressemble au test de connexité (voir section 5.2) :
Cet algorithme prouve en même temps le théorème 6.2, c’est l’objet de l’exercice suivant.
Exercice 6.2.2
1. Montrer que lorsque cet algorithme colorie tous les sommets du graphe, celui-ci est bien
colorié.
3. En déduire le théorème.
Exercice 6.2.3
1. Écrire une fonction effacerCouleurs(G) qui colorie en blanc tous les sommets de G.
3. Écrire une fonction monoCouleurVoisins(s) qui, si les voisins non blancs du sommet s
sont tous de la même couleur, renvoie cette couleur et dans le cas contraire (s a deux
voisins de couleurs non blanches différentes) renvoie None.
4. Écrire une fonction deuxColoration(G,c1,c2) qui tente de colorier le graphe G avec les
deux couleurs c1 et c2 en utilisant l’algorithme détaillé plus haut, et renvoie True en cas
de succès, False sinon.
63
5. Tester la fonction sur :
Après chaque essai dessiner le graphe pour vérifier soit qu’il est bien colorié, soit qu’un
sommet non coloré t possède deux voisins de couleurs distinctes ; dans ce dernier cas
vérifier qu’un cycle impair relie t et certains des sommets déjà coloriés.
Conseils : lorsque la fonction deuxColoration découvre un sommet t non coloré avec deux
voisins de couleurs différentes (cas d’un graphe non 2-coloriable), afficher ce sommet en ajoutant
simplement une instruction print(t).
Les graphes de cette section sont pour la plupart mieux dessinés en spécifiant l’algorithme
de dessin comme suit : dessiner(G,algo=’neato’). Voir http://www.graphviz.org pour une
description rapide des algorithmes disponibles avec ce logiciel de dessin de graphes : dot, neato,
fdp, twopi et circo.
Exercice 6.2.4 Écrire une fonction areteEntre(s1,s2) qui retourne une arête entre les som-
mets s1 et s2 s’il en existe une, None sinon. Comme dans l’exercice 5.2.10 modifier la fonction
sommetColoriable pour marquer l’arête qui relie ce sommet non coloré à son voisin coloré ; ne
pas oublier de modifier aussi la fonction effacerCouleurs pour démarquer les arêtes en même
temps.
Tester à nouveau la fonction deuxColoration comme dans l’exercice précédent, et dessiner à
chaque fois le graphe : que remarque-t-on à propos du sous-graphe formé par les arêtes marquées
(et leurs extrémités) ? Lorsque le graphe n’est pas 2-coloriable vérifier qu’il existe toujours un
cycle impair dont toutes les arêtes, sauf une, sont marquées.
Exercice 6.2.5 Utiliser la fonction melange comme dans l’exercice 5.3.1 pour modifier la fonc-
tion sommetColoriable afin que le résultat ne dépende plus de l’ordre dans lequel sont rangés
les sommets du graphe, ni de l’ordre des arêtes incidentes à un sommet.
Une fois cette modification effectuée, appliquer plusieurs fois la fonction deuxColoration au
dodécaèdre ; après chaque calcul dessiner le graphe et observer quel est le sommet non coloré t
avec deux voisins de couleurs différentes qui a stoppé l’exécution de l’algorithme ; observer que
le sommet t est situé sur un cycle impair dont toutes les arêtes, sauf une, sont marquées, et que
ce cycle n’est pas toujours un pentagone (bonne chance).
64
Annexe A. Annales de devoirs surveillés et
d’examens
Dans les pages suivantes figurent les textes du DS et l’examen de l’année 2018/2019. On
trouvera l’ensemble des annales sous :
http://dept-info.labri.fr/ENSEIGNEMENT/INITINFO/initinfo/annales-examens.html
65
Nom: Prénom: Groupe:
Exercice 1 Considérons la fonction mystere suivante prenant en paramètre une liste L composée
de 0 ou de 1 :
def mystere(L):
c=0
j=1
for i in L :
c=c+i*j
j=j*2
return c
c
j
i
4. Écrire une fonction laListeEstBonne qui prend en paramètre une liste L composée de
chiffres quelconques et retourne True si la liste L ne comporte que des 0 ou des 1, False
dans le cas contraire.
1/7
Exercice 2 Pixels négatifs
L’objectif de cet exercice est d’appliquer un filtre sur la moitié droite d’une image img. Plus
précisément, nous souhaitons inverser en négatif les couleurs de chaque pixel de l’image img : si
un pixel a la couleur (r,g,b), alors sa nouvelle couleur est modifiée en (255-r,255-g,255-b).
Voici un exemple :
2/7
Nom: Prénom: Groupe:
2. Écrire une fonction amplitude(L) qui, en parcourant une seule fois la liste, calcule et re-
tourne la différence entre le maximum et le minimum des notes dans L. Par exemple,
amplitude([9,10.5,17,15.5,11,5,11]) retournera 12 (c’est à dire 17-5).
3/7
Exercice 4 Écrire les fonctions suivantes prenant en paramètre une liste de nombres L.
1. Écrire une fonction positionPremierNegatif(L) qui retourne la position du premier
nombre négatif dans L, numérotée à partir de 0, ou -1 si L n’en contient aucun.
Par exemple, positionPremierNegatif([-3,4,-2,1]) retournera 0.
On dispose d’une image du drapeau suisse, où l’on a une croix blanche au sein d’un rectangle
rouge. On ne connait pas la taille de la croix, l’image ci-dessus n’est qu’un exemple. On souhaite
calculer la largeur de la croix, en détectant le bord extrême gauche et le bord extrême droit de
la croix.
4/7
Nom: Prénom: Groupe:
1. Écrire une fonction trouverMinX(image) qui retourne le minimum des coordonnées X des
pixels blancs de l’image image (donc le bord extrême gauche)
2. De même, écrire une fonction trouverMaxX(image) qui retourne le maximum des coor-
données X des pixels blancs de l’image image (donc le bord extrême droit)
5/7
Exercice 6 On considère le code de la fonction triangleSuperieur(img, c) qui colorie avec
la couleur c tous les pixels de l’image img au dessus de la diagonale, diagonale comprise.
def tri angleS uperieur ( img , c ):
largeur = largeurImage ( img )
hauteur = hauteurImage ( img )
if largeur > hauteur :
for x in range ( largeur ):
for y in range (0 , (( x * ( hauteur - 1)) // ( largeur - 1)) + 1):
colorierPixel ( img , x , y , c )
else :
for y in range ( hauteur ):
for x in range (( y * ( largeur - 1)) // ( hauteur - 1) , largeur ):
colorierPixel ( img , x , y , c )
1. On crée une image monImage et l’on appelle la fonction triangleSuperieur sur monImage
ainsi :
monImage = nouvelleImage (8 , 5)
tria ngleSuperieur ( monImage , (0 ,0 ,255))
Voici une représentation de l’image monImage. Cochez les pixels se retrouvant colorés par
l’appel à la fonction triangleSuperieur.
6/7
Numéro d’anonymat :
Exercice 1 Les questions de cet exercice portent toutes sur ces trois graphes : G0 , G1 et G2 .
1
A
2 M P
B C
6 0
5 J N
D E F
3 K
G H O
4 L
I
G0 G1 G2
Donner un sommet de
degré maximal et pré-
ciser son degré.
1/9
Exercice 2 Dans les deux questions suivantes, on supposera que l’appel à :
elementAleatoireListe(range(1,7)) retourne successivement les entiers 1, 6, 4, 5, 6, 6, 3, 6, 2, 5,
5, 6,... (c’est à dire que la fonction retourne la valeur 1 lors du premier appel, puis 6 au deuxième
appel, puis 4 au troisième, etc.)
On considère tout d’abord la fonction mystere1 suivante :
def mystere1 ( n ):
test = 0
cpt = 0
while test < n :
e = elem entA lea t o ir e Li st e ( range (1 ,7))
if e == 6 :
test = test + 1
cpt = cpt + 1
return cpt
test 0 0 0
cpt 0 0
e 1
test 0 0 0
cpt 0 0
e 1
2/9
Numéro d’anonymat :
3. De façon générale donner la signification (le sens) de la valeur retournée par les appels à
mystere1(k) et mystere2(k) pour un entier positif k.
Exercice 3 On souhaite incruster une image dans une plus grande image selon deux manières :
dans le coin supérieur gauche ou bien de façon centrée.
petite
copieCoin(grande,petite) copieCentre(grande,petite)
grande
1. Écrire une fonction copieCoin(grande,petite) qui copie l’image petite dans le coin
supérieur gauche de l’image grande. On pourra supposer que largeur et hauteur de l’image
petite sont inférieures ou égales à celles de l’image grande.
3/9
2. Écrire une fonction copieCentre(grande,petite) qui incruste l’image petite au centre
de l’image grande (à l’arrondi près). On pourra supposer que largeur et hauteur de l’image
petite sont inférieures ou égales à celles de l’image grande.
A A A
B C
F
E B B C
J G
D H
F
I H
D C F E G D E
4/9
Numéro d’anonymat :
2. Écrire une fonction tousMarques(s) qui renvoie True si tous les voisins du sommet s sont
marqués, False sinon.
3. Écrire une fonction aretesCouvertes(G) qui renvoie True si le graphe G satisfait la pro-
priété P, False sinon.
Exercice 5 Pour un sommet donné, on cherche à déterminer le nombre de ses voisins différents.
Pour ce faire, nous allons utiliser la technique de marquage des sommets afin de ne pas compter
plusieurs fois un sommet relié par plusieurs arêtes au sommet donné. On pourra utiliser sans la
redéfinir la fonction demarquerVoisins(s) qui démarque tous les voisins du sommet donné en
paramètre.
5/9
2. Un sommet est dit simplement universel s’il n’a pas de boucle et s’il est relié par exactement
une arête à chaque autre sommet du graphe. En utilisant la fonction nbVoisinsDifferents,
écrire la fonction estSimplementUniversel(s,G) qui retourne True si le sommet donné
en paramètre est simplement universel et False autrement.
Propriété 1 : s’il existe une chaîne élémentaire dans G reliant x et y qui passe par l’arête e, alors il
existe une autre chaîne (pas forcément élémentaire) reliant x et y mais qui évite l’arête e.
1. Dessiner un exemple de graphe simple qui illustre cette propriété 1. Sur votre exemple,
vous penserez à désigner le sommet x, le sommet y, l’arête e ainsi que la chaîne élémentaire
qui relie x à y et qui emprunte l’arête e.
6/9
Numéro d’anonymat :
2. Démontrer la propriété 1.
3. Soit G un graphe simple, soit C un cycle élémentaire dans G, soit e une arête de ce cycle.
Notons GÕ = G \ e le graphe obtenu à partir de G en supprimant l’arête e (mais en gardant
ses extrémités). En supposant que la propriété 1 est vraie et démontrée, cochez parmi les
propositions suivantes celle qui est vraie :
soient x et y deux sommets distincts de G. S’il existe une chaîne reliant x et y dans G,
alors :
⇤ il existe une chaîne reliant x et y dans GÕ , uniquement si G est un graphe connexe.
⇤ il existe une chaîne reliant x et y dans GÕ .
⇤ il n’existe pas de chaîne reliant x et y dans GÕ .
⇤ il peut dans certains cas exister et dans d’autres cas ne pas exister de chaîne reliant
x et y dans GÕ .
⇤ Aucune des 4 affirmations précédentes n’est vraie.
7/9
Annexe B. Palettes
Du point de vue informatique, une palette de couleurs n’est rien d’autre qu’une liste de
couleurs, que l’on peut construire manuellement :
Mais construire des palettes harmonieuses est une autre histoire, c’est le travail des gra-
phistes, et le même site propose plusieurs dizaines de palettes prédéfinies (avec de nombreuses
variantes suivant le nombre de couleurs souhaitées). Le module palettes, à charger par :
79
Annexe C. Aide-mémoire
C.1 Environnement de TP
Deux environnements de travail sont utilisés. L’un, Python Tutor, est disponible depuis le
site web du cours. Il est utilisable depuis n’importe quel navigateur web supportant javascript.
L’intérêt de Python Tutor est qu’il permet d’observer l’exécution du programme pas à pas. Le
défaut est qu’il est difficile de sauvegarder ses programmes, et il limite le nombre de pas à 10000
seulement.
L’autre, idle3, contient à la fois un éditeur de texte et un interpréteur interactif, ce qui permet
à la fois de facilement enregistrer ses programmes, et d’expérimenter avec. Il est disponible sur
les postes du CREMI, mais vous pouvez également l’installer sur votre propre ordinateur depuis
www.python.org
Selon les situations, on préfèrera donc utiliser l’un ou l’autre.
Connexion/Déconnexion
Tapez votre nom de login, puis votre mot de passe dans la fenêtre de connexion 1 . À la fin
du TP, il ne faut pas oublier de se déconnecter (se “déloger” du système).
Terminal
On tape les commandes (ls, python3,...) dans une fenêtre particulière appelée terminal. On
lance une fenêtre de ce type à partir des menus disponibles.
1. Si le système Linux n’est pas déjà chargé, il faut redémarrer l’ordinateur et choisir l’option Linux au
moment opportun.
80
Fichiers et répertoires
Chaque utilisateur dispose d’un répertoire personnel où il peut créer les fichiers et répertoires
nécessaires à son travail. On parle aussi de répertoire d’accueil car c’est le répertoire courant
(“celui dans lequel on se trouve”) lorsqu’on vient de se connecter.
Un fichier contient des données (texte, programme, image,...) Les fichiers que vous allez créer
et utiliser dans le cadre de cet enseignement contiendront des programmes écrits en langage
Python. Par convention, on choisit pour les fichiers python un nom se terminant par .py, que
l’on range dans son répertoire personnel.
Depuis un terminal, la commande ls permet de faire afficher tous les fichiers se trouvant
dans le répertoire.
idle3 &
Attention : la version 3 du langage Python n’est pas compatible avec la version 2, il faut
écrire idle3 en un seul mot, sans espace, pour bien choisir la version 3 ; la version du langage
apparaît sur la première ligne de la fenêtre qui s’ouvre en réponse au lancement de IDLE.
Le signe final & est important : il permet de continuer à entrer des commandes dans la
fenêtre terminal, que l’on peut fermer (ce n’est pas conseillé) sans fermer en même temps la
fenêtre IDLE.
Python Shell
Dans cette fenêtre on entre des instructions destinées à l’interprète Python ; chaque instruc-
tion est exécutée, puis IDLE affiche à nouveau l’invite :
>>>
qui signale qu’on peut entrer une nouvelle instruction. Une instruction peut occuper plusieurs
lignes et dans ce cas IDLE les indente automatiquement. Voici quelques problèmes courants et
leur solution :
• L’invite >>> n’apparaît pas : IDLE attend des instructions supplémentaires, appuyer
à nouveau sur la touche Entrée pour faire apparaître l’invite.
• Comment modifier une instruction sans tout retaper ? Cliquer n’importe où dans
l’instruction et appuyer sur la touche Entrée : l’instruction est copiée en face de la dernière
invite, et on peut la modifier comme si le texte était en cours de frappe.
Autre méthode : la combinaison de touches Alt-p (p = previous) affiche l’instruction
précédente ; continuer à appuyer sur Alt-p pour faire défiler les instructions déjà entrées ;
si nécessaire utiliser Alt-n (n = next) pour inverser l’ordre de défilement.
• L’indentation automatique n’est pas correcte : cela se produit chaque fois qu’il faut
revenir en arrière (par exemple pour entrer else: après avoir traité le cas if ... :) et
il suffit d’utiliser la touche effacement arrière (Backspace) située au-dessus de la touche
Entrée.
81
IDLE propose aussi de compléter automatiquement un mot en cours de frappe (code comple-
tion), il suffit d’utiliser la touche de tabulation (au-dessus de la touche de verrouillage majuscule)
pour activer ce mécanisme.
Fenêtre d’édition
Pour ne pas mélanger développement et tests, il faut ouvrir une fenêtre d’édition d’un fichier
qu’on appellera tpx.py en remplaçant x par le numéro du TP. Il y a trois méthodes pour ouvrir
cette fenêtre :
• ou bien, une fois IDLE lancé, choisir dans le menu : File -> New Window
• on peut aussi modifier la configuration de IDLE comme suit : menu Options ->
Configure IDLE, onglet General, section Startup Preference, cliquer sur
Open Edit Windows.
La fenêtre qui apparaît sert à entrer les définitions de fonctions Python. Pour tester ces
fonctions dans la fenêtre Python Shell appuyer sur la touche F5. Le message :
apparaît alors dans la fenêtre Python Shell, et vous êtes prêt à tester vos fonctions.
A chaque appui sur la touche F5 dans la fenêtre d’édition, IDLE demande que le contenu
de cette fenêtre soit sauvegardé, pour qu’il puisse être lu dans l’autre fenêtre. Si le fichier n’a
pas encore reçu de nom, choisir comme nom de fichier tpx.py en remplaçant x par le numéro
du TP.
Attention : il est impératif que le fichier soit de type .py pour qu’IDLE et Python le re-
connaissent comme un fichier source, c’est-à-dire comportant des instructions écrites en langage
Python.
Une demande de confirmation de sauvegarde apparaît à chaque appui sur la touche F5.
Lorsque la répétition de ce message devient irritante, modifier la configuration IDLE comme
suit :
• Menu Options -> Configure IDLE, onglet General, section Autosave Preference, cli-
quer sur No prompt.
Bonne chance !
82
Touche F5 et RESTART
La réinitialisation totale (restart) de l’interprète Python à chaque appui sur F5 peut être
pénible, car toutes les définitions entrées dans la fenêtre Python Shell sont oubliées. Pour éviter
ce désagrément il suffit de lancer IDLE avec l’option -n (no subprocess), par exemple :
83
C.2 Rappel de la syntaxe
if (condition): Exemple :
instructions exécutées quand if age <= age_reduction:
condition est vraie prix = prix / 2
if (condition): Exemple :
instructions exécutées quand
if age <= age_reduction:
condition est vraie prix = 5
else: else:
instructions exécutées quand prix = 10
condition est fausse
Exemple :
while (condition):
i = 1
instructions exécutées tant que while i < n:
condition est vraie i = i * 2
Exemple :
def fonction (parametres,avec,virgules): def f(n,m):
instructions exécutées quand if n < m:
fonction est appelée return n
return m
list(range(10)) [0,1,2,3,4,5,6,7,8,9]
list(range(3,7)) [3,4,5,6]
list(range(1,20,4)) [1,5,9,13,17]
84
C.3 Utilisation de la bibliothèque de graphes
Il faut commencer par importer le module bibgraphes :
85
L’argument u est une liste
melange(u) retourne une copie mélangée aléatoirement de la
liste u. Exemple : melange(listeSommets(G)) où G
contient un graphe
retourne un élément choisi aléatoirement dans la liste
elementAleatoireListe(u) u si celle-ci est non vide. Si la liste u est vide la
fonction retourne une erreur IndexError. Exemple :
elementAleatoireListe(listeSommets(G)) où G
contient un graphe
86
C.4 Utilisation de la bibliothèque d’images
Il faut commencer par importer le module bibimages.py :
87
C.5 Comprendre les messages d’erreur
Nous reprenons ici la liste des messages d’erreur que vous verrez souvent, et dans les pages suivantes
des explications du problème et ses solutions potentielles. Cette liste est également disponible, de manière
plus pratique, sur la page moodle du cours, "Comprendre les messages d’erreur".
Exemple 1 :
def blablaBla(x):
return x * x
y = blablabla(2)
Origine du problème : nous avons mal orthographié “blablabla” : il y un B majuscule dans le 3ième
“bla” de la définition de la fonction et pas de majuscule dans l’appel de la fonction.
88
Exemple 2 :
j = 5
x = 2 * i
i = 4
Origine du problème : on utilise le nom ’i’ dans cette expression alors qu’il n’a jamais été défini
avant. Soit on aurait dû initialiser la variable ’i’ avant (déplacer l’instruction i = 4 avant l’instruction
x = 2 * i), soit on a mal orthographié la variable (on voulait taper ’j’ au lieu de ’i’).
def f(x):
m = x*x
return m
f(5)
y = m
Origine du problème : la variable “m” est une variable locale à la fonction “f”, elle ne “vit” qu’à
l’intérieur de la fonction “f”.
Exemple 4 :
monImage = ouvrirImage(teapot.png)
Origine du problème : comme on a oublié les guillemets, python pense que teapot est le nom d’une
variable... qui n’est donc pas définie.
Solution :
monImage = ouvrirImage("teapot.png")
Exemple 1 :
def f(x)
^
SyntaxError: invalid syntax
def f(x):
89
Exemple 2 :
if i = 6:
^
Origine du problème : après le “if”, python s’attend à une expression booléenne, Ici, il se retrouve
avec une affectation, et est donc perdu.
Solution : remplacer l’opérateur d’affectation “=” par l’opérateur de test d’égalité “==”
if i == 6:
Exemple 3 :
if i == 9
^
SyntaxError: invalid syntax
if i==9 :
Exemple 4 :
def f(x):
return sqrt((x*x - x)
print(f(5))
^
def f(x):
return sqrt((x*x - x))
print(f(5))
Exemple 5 :
def f(x):
return sqrt((x*x - x)
print f(5)
^
Origine du problème : en python 3 (contrairement à python 2), print est une fonction comme les
autres. Pour appeler cette fonction, il faut donc utiliser des parenthèses.
Solution :
def f(x):
return sqrt((x*x - x)
print (f(5))
90
C.5.3 SyntaxError : expected an indented block
Erreur : problème d’indentation. Le plus fréquemment, il manque une ou plusieurs tabulations à
l’endroit pointé par le message d’erreur (voir exemple 1). Parfois, l’origine du problème vient de plus
haut dans votre programme. Par exemple, lorsqu’on a commencé une fonction, un if ou un for, que l’on
n’a pas fait suivre par une instruction (voir exemple 2) ou qu’on a commenté l’instruction en question
(exemple 3).
Exemple 1 :
if i == 9:
toto = 9
Solution :
if i == 9 :
toto = 9
Exemple 2 :
def f(x):
y = 5*2
Origine du problème : vous avez déclaré une fonction sans définir son code.
Solution : rajouter un return dans votre fonction.
def f(x):
return
y = 5*2
Exemple 3 :
for i in range(5):
## print(i)
y = 5*2
Origine du problème : vous avez commenté une partie du code, ce qui perturbe son interprétation.
Solution : commenter tout le bloc.
##for i in range(5):
## print(i)
y = 5*2
C.5.4 SyntaxError : unindent does not match any outer indentation level
if i == 9:
titi = 5
toto = 4
^
SyntaxError: unindent does not match any outer indentation level
91
Origine du problème : le niveau d’indentation (nombre d’espaces) ne correspond à aucun niveau
d’indentation externe. Dans l’exemple ci-dessus, l’instruction “toto = 9” est soit trop à gauche, soit
trop à droite. Cela arrive souvent lorsqu’on mélange les caractères de tabulation et d’espace.
Solution :
if i == 9:
titi = 5
toto = 4
ou (selon le contexte) :
if i == 9:
titi = 5
toto = 4
def f(x):
y = x*x
return y
Origine du problème : on ne peut pas affecter une valeur à une expression qui ne représente pas une
variable. Ici, à gauche du symbole d’affectation “=”, on trouve l’expression “i + 1, qui ne définit pas une
variable dans laquelle stocker la valeur qui est à droite du symbole d’affectation. Ici, on voulait peut-être
écrire “i = 5 - 1”.
f(5) = y
^
SyntaxError: can't assign to function call
Origine du problème : on ne peut pas affecter une valeur au résultat d’un appel de fonction. En
effet, le résultat d’un appel de fonction est une valeur constante (par exemple, “12”), et non une variable
permettant de stocker une valeur.
Solution : vous vouliez probablement écrire :
def f(x):
return x*x
y = f(5)
92
C.5.8 SyntaxError : unexpected EOF while parsing
Erreur : on arrive à la fin du fichier (EOF = End Of File) alors qu’on n’a pas terminé l’instruction
ou le bloc d’instruction en cours.
Exemple :
def f(n):
s = 0
for i in range(n):
def f(n):
s = 0
for i in range(n):
s = s + i
return s
### fin du fichier ####
Exemple 1 :
L = [5,2,3]
for i in range(L):
...
Ici on passe une liste en paramètre à la fonction range() alors qu’elle s’attend à avoir un entier.
Solution : ne pas utiliser la fonction range, mais directement la liste :
L = [5,2,3]
for i in L:
...
Exemple :
def f(x,y):
return x + y
print(f(5,6,7))
Solution : appeler la fonction avec le bon nombre d’arguments
93
C.5.12 TypeError : f() missing 1 required positional argument : ’y’
Erreur : on appelle la fonction ’f()’ en ne lui passant pas assez d’arguments.
Exemple :
def f(x,y):
return x + y
print(f(5))
Exemple :
n = 5
for i in n:
print(i)
Solution :
n = 5
for i in range (n):
print(i)
Exemple 1 :
def f(x):
return x*x
y = 2
z = y(5)
def f(x):
return x*x
y = 2
z = f(5)
94
Exemple 2 :
monImage = nouvelleImage(300,200)
for y in range(largeurImage(monImage)):
colorierPixel(monImage,0,y(255,255,255))
monImage = nouvelleImage(300,200)
for y in range(largeurImage(monImage)):
colorierPixel(monImage,0,y,(255,255,255))
c = 5
for s in listeSommets(G):
if s <= c:
Solution : ne pas utiliser le sommet s mais un entier (comme par exemple le degré de s) :
c = 5
for s in listeSommets(G):
if degre(s) <= c:
monImage = nouvelleImage(300,200)
colorierPixel(monImage,200,200,(255,255,255))
Origine du problème : ici, l’image est de largeur 200 et le pixel le plus à droite a pour abscisse 199
(car la numérotation commence à 0).
Origine du problème : python ne trouve pas le fichier bibimages.py. Il y a deux causes principales à
ce problème :
1. soit vous n’avez pas encore récupéré le fichier bibimages.py sur la page https://moodle1.
u-bordeaux.fr/course/view.php ;
2. soit vous l’avez bien récupérée, mais elle est dans un autre répertoire.
95