Nom : Prénom : Informatique Pour Tous Interrogation n°3 I-Syntaxe Python I-1) Quelle est la commande Python qui permet d’ouvrir en lecture un fichier nommé MonFichier.txt dans le répertoire courant du disque dur pour en utiliser ensuite le contenu ? VarFichier = open(‘MonFichier.txt’,’r’) I-2) On rappelle qu’en Python, la fonction sum(liste) produit la somme de tous les éléments de liste et que la forme liste = [valeur for i in range(entier)] produit exactement la même chose que : liste = [] for i in range(entier) liste.append(valeur) Soit la variable var = [(0,0,0,0),(1,0,0,0),(0,1,0,0),(0,0,1,0),(1,1,1,1)] a) Quelle est la valeur de var[2] (0, 1, 0, 0) b) Quelle est la valeur de len(var) 5 c) Quelle est la valeur de len(var[1]) 4 d) Quelle est la valeur de [var[i][1] for i in range(2,4)] [1, 0] e) Quelle est la valeur de [var[1][i] for i in range(2,4)] [0, 0] f) Quelle est la valeur de [var[i][i] for i in range(4)] [0, 0, 0, 0] II-Analyse de code II-1) On rappelle qu’en Python l’opérateur % donne le reste de la division. Par exemple, 10%2 donne 0, 10%3 donne 1. Qu’affiche à l’écran le script suivant : def fonction(n, a): terme = a for k in range(n): terme = (k*a*terme+a**2) % 256 return terme Informatique Pour Tous page 1/6 PCSI1 2016-2017 n = 2 a = 10 print("resultat1 = ", fonction (n, a)) print("resultat2 = ", fonction (a, n)) print("resultat3 = ",(n, a)) resultat1 = 76 resultat2 = 204 resultat3 = (2, 10) II-2) Extrait de la documentation Python : « enumerate(thing), where thing is either an iterator or a sequence, returns a iterator that will return the tuples (0, thing[0]), (1, thing[1]), (2, thing[2]), and so forth.. » Qu’affiche à l’écran le script suivant : def fonction(t,p): t1, t2 = [], t for (i, x) in enumerate(t): if x <= p : t1.append(x) else: t2[i] = p return t1, t2 t1 = [10, 1515, 2048, -10, 42] t2 = [42, 73] print(t1,t2) print(t1,t2,fonction(t1 , 42)) [10, 1515, 2048, -10, 42] [42, 73] [10, 42, 42, -10, 42] [42, 73] ([10, -10, 42], [10, 42, 42, -10, 42]) III-Projet : Prévention des collisions aériennes (d’après Centrale Informatique commune MP, PC, PSI, TSI ) Lors du dépôt d’un plan de vol, une compagnie aérienne doit préciser à quel niveau de vol elle souhaite faire évoluer son avion lors de la phase de croisière. Ce niveau de vol souhaité, le RFL pour requested flight level, correspond le plus souvent à l’altitude à laquelle la consommation de carburant sera minimale. Cette altitude dépend du type d’avion, de sa charge, de la distance à parcourir, des conditions météorologiques, etc. Cependant, du fait des similitudes entre les différents avions qui équipent les compagnies aériennes, certains niveaux de vols sont très demandés ce qui engendre des conflits potentiels, deux avions risquant de se croiser à des altitudes proches. Les contrôleurs aériens de la région concernée par un conflit doivent alors gérer le croisement de ces deux avions. Pour alléger le travail des contrôleurs et diminuer les risques, le système de régulation s’autorise à faire voler un avion à un niveau différent de son RFL. Cependant, cela engendre généralement une augmentation de la consommation de carburant. C’est pourquoi on limite le choix aux niveaux immédiatement supérieur et inférieur au RFL. Ce problème de régulation est modélisé par un graphe dans lequel chaque vol est représenté par trois sommets. Le sommet 0 correspond à l’attribution du RFL, le sommet + au niveau supérieur et le sommet − au niveau inférieur. Chaque conflit potentiel entre deux vols sera représenté par une arête reliant les Informatique Pour Tous page 2/6 PCSI1 2016-2017 deux sommets concernés. Le coût d’un conflit potentiel (plus ou moins important en fonction de sa durée, de la distance minimale entre les avions, etc.) sera représenté par une valuation sur l’arête correspondante. Exemple de conflits potentiels entre trois vols Dans l’exemple de la figure , faire voler les trois avions à leur RFL engendre un coût de régulation entre A et B de 100 et un coût de régulation entre B et C de 400, soit un coût total de la régulation de 500 (il n’y a pas de conflit entre A et C). Faire voler l’avion A à son RFL et les avions B et C au-dessus de leur RFL engendre un conflit potentiel de coût 100 entre A et B et 150 entre A et C, soit un coût total de 250 (il n’y a plus de conflit entre B et C). On peut observer que cet exemple possède des solutions de coût nul, par exemple faire voler A et C à leur RFL et B au-dessous de son RFL. Mais en général le nombre d’avions en vol est tel que des conflits potentiels sont inévitables. Le but de la régulation est d’imposer des plans de vol qui réduisent le plus possible le coût total de la résolution des conflits. Chaque vol étant représenté par trois sommets, le graphe des conflits associé à n vols v0, v1, …, vn–1 possède 3n sommets que nous numéroterons de 0 à 3n − 1. Nous conviendrons que pour 0 ≤ k < n : le sommet 3k représente le vol vk à son RFL ; le sommet 3k + 1 représente le vol vk au-dessus de son RFL ; le sommet 3k + 2 représente le vol vk au-dessous de son RFL ; Le coût de chaque conflit potentiel est stocké dans une liste de 3n listes de 3n entiers (tableau 3n × 3n) accessible grâce à la variable globale conflit (donc utilisable si nécessaire dans les fonctions à écrire cidessous) : si i et j désignent deux sommets du graphe, alors conflit[i][j] est égal au coût du conflit potentiel (s’il existe) entre les plans de vol représentés par les sommets i et j. S’il n’y a pas de conflit entre ces deux sommets, conflit[i][j] vaut 0. On convient que conflit[i][j] vaut 0 si les sommets i et j correspondent au même vol (figure 4). On notera que pour tout couple de sommets (i, j), conflit[i][j] et conflit[j][i], représentent un seul et même conflit et donc conflit[i][j] = = conflit[j][i]. Tableau des coûts des conflits associé au graphe représenté sur la figure précédente Informatique Pour Tous page 3/6 PCSI1 2016-2017 III-1-a) Écrire en Python une fonction nb_conflits() sans paramètre qui renvoie le nombre de conflits potentiels, c’est-à-dire le nombre d’arêtes de valuation non nulles du graphe décrit par la variable globale conflit. def nb_conflits() : nb_lst = len(conflit) #nombre de listes contenues dans de la liste conflit nb= 0 for i in range(nb_lst): # on boucle sur l’indice de toutes les lignes for j in range(i+1, nb_lst): # on boucle sur les éléments au dessus de la diagonale if conflit[i][j] != 0 : # il y a conflit dans ce cas nb = nb + 1 return nb print(nb_conflits()) b) Exprimer la complexité de cette fonction en fonction de n. La boucle Comme nb_lst = 3n, la complexité de la fonction est donc . III-2) Régulation Pour un vol vk on appelle niveau relatif l’entier rk valant 0, 1 ou 2 tel que : rk = 0 représente le vol vk à son RFL ; rk = 1 représente le vol vk au-dessus de son RFL ; rk = 2 représente le vol vk au-dessous de son RFL. On appelle régulation la liste (r0, r1,..., rn). Par exemple, la régulation (0, 0, …, 0) représente la situation dans laquelle chaque avion se voit attribuer son RFL. Une régulation sera implantée en Python par une liste d’entiers. Il pourra être utile d’observer que les sommets du graphe des conflits choisis par la régulation r portent les numéros 3k + rk pour 0 ≤ k < n. Écrire en Python une fonction nb_vol_par_niveau_relatif(regulation) nb_vol_par_niveau_relatif(regulation) qui prend en paramètre une régulation (liste de n entiers) et qui renvoie une liste de 3 entiers [a, b, c] dans laquelle a est le nombre de vols à leurs niveaux RFL, b le nombre de vols au-dessus de leurs niveaux RFL et c le nombre de vols au-dessous de leurs niveaux RFL. proposition simple def nb_vol_par_niveau_relatif(regulation) : a,b,c = 0,0,0 # initialisation des variables for i in range(len(regulation)) :# on boucle sur les indices de tous les éléments de la liste regulation r = regulation[i] if r == 0 : a = a + 1 elif r == 1: b = b + 1 else : c = c + 1 return [a,b,c] Informatique Pour Tous # on prend l’élément d’indice i # on teste les différents cas possibles page 4/6 PCSI1 2016-2017 III-3) Coût d’une régulation On appelle coût d’une régulation la somme des coûts des conflits potentiels que cette régulation engendre. a) Écrire en Python une fonction cout_regulation(regulation) cout_regulation(regulation) qui prend en paramètre une liste représentant une régulation et qui renvoie le coût de celle-ci. def cout_regulation1(regulation) : cout = 0 # on initialise le cout à 0 lst_vols = [] # on commence par créer la liste des vols associés à la régulation for (k, r) in enumerate(regulation) : # on utilise la remarque de l’énoncé pour fabriquer ... lst_vols.append(3*k + r ) nb_vols = len(lst_vols) # le numéro du vol correspondant à chaque élément de regulation # c’est le nombre de vols for i in range(nb_vols) : # on boucle sur l’indice de toutes les vols for j in range(i+1,nb_vols): # on boucle sur les éléments au dessus de la diagonale cout = cout + conflit[lst_vols[i]][lst_vols[j]] #on ajoute le coût #de l’éventuel conflit entre les deux vols d’indice i et j return cout b) Évaluer la complexité de cette fonction en fonction de n. On remarque que le nb_vols == len(regulation) == n. La première boucle for fait n itérations à 2 opérations donc une complexité en O(n). Les deux boucles imbriquées suivantes en fo nt n(n – 1 ) comme vu plus haut donc la complexité totale de la fonction est aussi en c) Déduire de la question a) une fonction cout_RFL() qui renvoie le coût de la régulation pour laquelle chaque avion vole à son RFL. Il suffit d’appliquer la fonction cout_regulation à une liste regulation ne contenant que des 0. def cout_RFL() : n = len(conflit[0])//3 « » » on détermine le nombre de vols à partir du premier élément de la liste conflit. Attention à utiliser // pour obtenir un int, si l’on utilise /, on obtient un float qui ne permet pas de faire la concaténation # multiple qui suit « » » regul = [0] * n # on crée la régulation RFL return cout_regulation(regul) d) Combien existe-t-il de régulations possibles pour n vols ? e) Est-il envisageable de calculer les coûts de toutes les régulations possibles pour trouver celle de cout minimal ? Informatique Pour Tous page 5/6 PCSI1 2016-2017 III-4) Recuit simulé L’algorithme de recuit simulé part d’une régulation initiale quelconque (par exemple la régulation pour laquelle chacun des avions vole à son RFL) et d’une valeur positive T choisie empiriquement. Il réalise un nombre fini d’étapes se déroulant ainsi : un vol vk est tiré au hasard ; on modifie rk en tirant au hasard parmi les deux autres valeurs possibles ; si cette modification diminue le coût de la régulation, cette modification est conservée ; sinon, cette modification n’est conservée qu’avec une probabilité p = exp(–∆c/T), où ∆c est l’augmentation de coût liée à la modification de la régulation ; le paramètre T est diminué d’une certaine quantité. Remarque. Dans la pratique, l’algorithme de recuit simulé est appliqué plusieurs fois de suite en partant à chaque fois de la régulation obtenue à l’étape précédente, jusqu’à ne plus trouver d’amélioration notable. On suppose importées les fonctions suivantes, que l’on pourra utiliser : exp(x) qui renvoie l’exponentielle de x ; randint(0,n) qui renvoie un entier tiré au sort dans [0, n] ; random() qui renvoie un réel tiré au sort dans [0, 1]. Ainsi, un événement qui ne se produit que si random() <= p a une probabilité p de se produire. Écrire en Python une fonction recuit(regulation) recuit(regulation) qui modifie la liste regulation passée en paramètre en appliquant l’algorithme du recuit simulé. On fera débuter l’algorithme avec la valeur T = 1000 et à chaque étape la valeur de T sera diminuée de 1%. L’algorithme se terminera lorsque T < 1. def recuit(regulation) : n = len(regulation) # on calcule le nombre de vols cout = cout_regulation(regulation) # on calcule le coût de la régulation initiale T = 1000 # on initialise la variable de boucle while T >= 1 : vol = randint(0,n-1) # on tire au sort l'indice d'un vol dans la liste regulation old_r = regulation[vol] # on garde la valeur actuelle du niveau du vol r = randint(0,2) # on tire au sort un niveau de vol while r == old_r : # on recommence tant que r n'est pas différent du niveau initial du vol r = randint(0,2) # une formule comme r = (old_r + randint (0,1) +1) % 3 # peut remplace la boucle regulation[vol] = r # on change le niveau du vol nouv_cout = cout_regulation(regulation) # on calcule le coût de la nouvelle # régulation delta_c = nouv_cout - cout p = exp(-delta_c/T) # calcul de la probabilité if nouv_cout >= cout and random() > p: # si le coût augmente ... # et si la nouvelle régulation n’est pas conservée regulation[vol] = old_r Informatique Pour Tous #on remet l'ancienne valeur du niveau, page 6/6 PCSI1 2016-2017