Algorithme au cours de l'histoire Sommaire Vue historique Introduction et position du problème le principe de l’algorithmique. Le principe de machine Turing. complexité. Les algorithmes classes P et NP. Conclusion. Vue historique Introduction Un algorithme est une procédure de résolution de problème, s’appliquant à une famille d’instances du problème et produisant, en un nombre fini d’étapes consécutives, effectives, non-ambigües et organisées, la réponse au problème pour toute instance de cette famille. Position du problème. Peut-on tout écrire sous forme d’un algorithme? Si oui, quel serait l’approche universelle? Dans le cas d’une réponse négative, quelle catégorie de problèmes ne s’apprête-elle pas à « l’algorithmisabilité »? le principe de l’algorithmique Problème 1 Réflexion Analyse 2 Solution Algorithme 3 Identification du problème Analyse et réflexion Plan d'action Exemple: Résolution à l’aide de l’algorithme d’Euclide. Algorithme Comment fonction une machine de Turing. Exemple indiquant ainsi que 27×45=1215. Complexité La complexité dans le meilleur des cas: 𝒎𝒊𝒏 𝒏 = 𝒄𝒐𝒖𝒕 𝒅 /𝒅 ∈ 𝑫 𝒏 𝑨 𝑨 La complexité dans le pire des cas: 𝒎𝒂𝒙 𝒏 = 𝒄𝒐𝒖𝒕 𝒅 /𝒅 ∈ 𝑫 𝒏 𝑨 𝑨 Complexité O(1) Complexité constante ou temps constant Complexité O(log(n)) Complexité logarithmique. Complexité O(n) Complexité linéaire Complexité O(n log(n)) Complexité n-logarithmique Complexité O(n^2) Complexité quadratique Complexité O(n^3) Complexité cubique Complexité O(n^p) Complexité polynomiale graphique représentant les différentes courbes des fonctions utilisées dans les complexités usuelles dans l’intervalle [0;20] un algorithme est dit praticable, efficace s’il est polynomial. Classes de complexité Parmi les classes les plus courantes, on distingue: Classe P (polynomial) Classe NP (Non déterministe Polynomial) Classes de complexité Classe P (polynomial): un problème de décision est dans P s'il peut être décidé par un algorithme déterministe en un temps polynomial par rapport à la taille de l'instance. Classes de complexité Classe NP (Non déterministe Polynomial) : c'est la classe des problèmes de décision pour lesquels la réponse oui peut être décidée par un algorithme nondéterministe en un temps polynomial par rapport à la taille de l'instance. La classe NP De manière intuitive, dire qu'un problème peut être décidé à l'aide d'un algorithme nondéterministe polynomial signifie qu'il est facile, pour une solution donnée, de vérifier en un temps polynomial si celle-ci répond au problème pour une instance donnée mais que le nombre de solutions à tester pour résoudre le problème est exponentiel par rapport à la taille de l'instance. Le non-déterminisme permet de masquer la taille exponentielle des solutions à tester tout en permettant à l'algorithme de rester polynomial. Classes de complexité On a trivialement P NP, En revanche : NP P ? car un algorithme déterministe est un algorithme non déterministe particulier. que l'on résume généralement à P = NP ? est l'un des problèmes ouverts les plus fondamentaux et intéressants en informatique théorique. 1970 : le premier qui arrivera à décider si P et NP sont différents ou égaux recevra le prix Clay (plus de 1.000.000 $) P = NP ?? Pourquoi c'est difficile de prouver ? (1 sur 2) Le problème de fond est que les algorithmes que l'on programme sont tous déterministes. Pour la bonne et simple raison que l'on ne sait pas construire de machine non déterministe. Ce qui fait que l'on ne peut que simuler un algorithme non déterministe par un algorithme déterministe Pourquoi c'est difficile de prouver ? (2 sur 2) Or il est démontré qu'un algorithme déterministe qui simule un algorithme non-déterministe qui fonctionne en temps polynomial, fonctionne en temps exponentiel. Ce qui fait que pour de grandes entrées on ne peut pas résoudre le problème en pratique, quelle que soit la puissance de la machine. Relation entre P et NP (supposé…) Si NP P NP P NP difficile Un problème est NP difficile si ce problème est au moins aussi dur que tous les problèmes dans NP. (on utilise parfois la traduction incorrecte NP-dur) Relation entre P,NP et NP difficile (supposé…) Si NP P NP P NP difficile NP complet On dit qu'un problème est NP-complet si il est dans NP il est NP-difficile NP complet On dit qu'un problème est NP-complet si il est dans NP (borne supérieure ..) il est NP-difficile (borne inférieure ..) Relation entre P,NP, NP difficile, et NP complet (supposé…) Si NP P NP P NP complet NP difficile NP complet Propriétés : Il n’y a pas un seul problème NP complet où il existe une preuve qu'il puisse fournir une réponse correcte en temps polynomial Si pour un problème NP complet on trouve une réponse correcte en temps polynomial, on peut trouver une réponse correcte en temps polynomial pour tous les problèmes en NP complet Réduction Formellement on définit une notion de réduction : Soient p et q deux problèmes, une réduction de q à p est un algorithme transformant toute instance de q en une instance de p. Ainsi, si l'on a un algorithme pour résoudre p, on sait aussi résoudre q. p est donc au moins aussi difficile à résoudre que q. q est donc au plus aussi difficile à résoudre que p. On écrit aussi q ≤ p ou bien q est réductible à p Réduction polynomiale Formellement on définit une notion de réduction polynomiale Soient p et q deux problèmes, avec le but d’utiliser la solution de p pour résoudre q une réduction de q à p est un algorithme en temps polynomial transformant toute instance de q en une instance de p. Ainsi, si l'on a un algorithme pour résoudre p, on sait aussi résoudre q. p est donc au moins aussi difficile à résoudre que q q est au plus aussi difficile à résoudre que p. On écrit aussi q ≤p p Transitivité La réduction polynomiale est en fait une relation transitive Si q ≤p p et p ≤p o alors q ≤p o « aussi dur » La réduction polynomiale est en fait une relation transitive Si q ≤p p, alors « q est au plus aussi difficile que p » Si aussi p ≤p q, alors « p est au plus aussi difficile que q » p et q sont « à peu près la même difficulté » NP complet On dit qu'un problème est NP-complet si il est dans NP il est NP-difficile Prouver si un problème p est NP complet 1. On suppose p NP, et on argumente comment pour une solution sp donnée, elle peut être vérifié en un temps polynomial 2. q NP complet avec q ≤p p , et il existe une fonction f qui transforme une solution sq de q en solution f (sq) = sp de p 3. Expliquer pourquoi f est polynomial EXEMPLE TSP TSP – Traveling Salesman Problem (Problème du voyageur de commerce) étant donné - n sommets (des « villes ») - et les distances séparant chaque sommet, 3 variantes Variante 1 : Est-ce qu’il y a une chaîne de longueur totale minimale inférieur à B ? Variante 2 : Quel est la longueur totale minimale ? Variante 3 : Quelle est la chaîne de longueur totale minimale ? TSP Voici un énoncé plus formel du problème du voyageur de commerce sous forme de problème de décision. Données : un graphe complet G = (V,E,φ) avec V un ensemble de sommets, E un ensemble d'arêtes et φ une matrice de distances; un entier B Question : Existe-t-il un cycle passant une et une seule fois par chaque sommet tel que la somme des coûts des arcs utilisés soit inférieure à B TSP : Calcul de compléxité Nombre de chemins candidats en fonction du nombre de villes TSP est NP complet Nombre de villes n Nombre de chemins candidats 3 1 4 3 5 12 6 60 7 360 8 2 520 9 20 160 10 181 440 15 43 589 145 600 20 6,082 × 1016 71 5,989 × 1099 TSP : Algorithme Une approche de résolution naïve, mais qui donne un résultat exact, est l'énumération de tous les chemins possibles par recherche (𝑛−1)! , exhaustive. La complexité en temps de cet algorithme est en 𝑂(𝑛!) (plus exactement ce qui devient vite impraticable 2 même pour de petites instances. Par exemple, si le calcul d'un chemin prend une microseconde, alors le calcul de tous les chemins pour 10 points est de 181 440 microsecondes soit 0,18 seconde, mais pour 15 points, cela représente déjà 43 589 145 600 microsecondes soit un peu plus de 12 heures et pour 20 points de 6 × 10 microsecondes soit presque deux millénaires (1 901 années). Pour 25 villes, le temps de calcul dépasse l'âge de l'Univers. 16 Held et Karp ont montré que la programmation dynamique permettait de résoudre le problème en 𝑂(𝑛2 2𝑛 ) Les méthodes d'optimisation linéaire sont à ce jour parmi les plus efficaces pour la résolution du problème de voyageur de commerce et désormais de résoudre des problèmes de grande taille (à l'échelle d'un pays), moyennant éventuellement un temps de calcul important. TSP : Réflexion %matplotlib inline Populating the interactive namespace from numpy and matplotlib import random n = 30 x = [ random.random() for _ in range(n) ] y = [ random.random() for _ in range(n) ] import matplotlib.pyplot as plt plt.plot(x,y,"o") TSP : Réflexion plt.plot(x + [ x[0] ], y + [ y[0] ], "o-") def longueur (x,y, ordre): i = ordre[-1] x0,y0 = x[i], y[i] d = 0 for o in ordre: x1,y1 = x[o], y[o] d += (x0-x1)**2 + (y0-y1)**2 x0,y0 = x1,y1 return d ordre = list(range(len(x))) print("longueur initiale", longueur(x,y,ordre)) def permutation(x,y,ordre): d = longueur(x,y,ordre) d0 = d+1 it = 1 while d < d0 : it += 1 print("iteration",it, "d=",d) d0 = d for i in range(0,len(ordre)-1) : for j in range(i+2,len(ordre)): r = ordre[i:j].copy() r.reverse() ordre2 = ordre[:i] + r + ordre[j:] t = longueur(x,y,ordre2) if t < d : d = t ordre = ordre2 return ordre ordre = permutation (x,y,list(range(len(x)))) print("longueur min", longueur(x,y,ordre)) xo = [ x[o] for o in ordre + [ordre[0]]] yo = [ y[o] for o in ordre + [ordre[0]]] plt.plot(xo,yo, "o-") longueur initiale 9.088214152577255 iteration 2 d= 9.088214152577255 iteration 3 d= 1.8810860903995525 iteration 4 d= 1.4267273563131075 iteration 5 d= 1.294543808915691 iteration 6 d= 0.9886582784000091 def longueur (x,y, ordre): # on change cette fonction d = 0 for i in range(1,len(ordre)): n = ordre[i-1] o = ordre[i] x0,y0 = x[n], y[n] x1,y1 = x[o], y[o] d += (x0-x1)**2 + (y0-y1)**2 return d ordre = list(range(len(x))) print("longueur initiale", longueur(x,y,ordre)) ordre = permutation (x,y,list(range(len(x)))) print("longueur min", longueur(x,y,ordre)) xo = [ x[o] for o in ordre] yo = [ y[o] for o in ordre] plt.plot(xo,yo, "o-") longueur initiale 8.224935150348868 iteration 2 d= 8.224935150348868 iteration 3 d= 1.4864813285014096 iteration 4 d= 0.8977401460581786 iteration 5 d= 0.8363214570582255 iteration 6 d= 0.8112951461233574 longueur min 0.8112951461233574 def longueur (x,y, ordre): i = ordre[-1] x0,y0 = x[i], y[i] d = 0 for o in ordre: x1,y1 = x[o], y[o] d += (x0-x1)**2 + (y0-y1)**2 x0,y0 = x1,y1 return d ordre = list(range(len(x))) print("longueur initiale", longueur(x,y,ordre)) def permutation(x,y,ordre): d = longueur(x,y,ordre) d0 = d+1 it = 1 while d < d0 : it += 1 print("iteration",it, "d=",d, "ordre[0]", ordre[0]) d0 = d for i in range(1,len(ordre)-1) : # on part de 1 et plus de 0, on est sûr que le premier noeud ne bouge pas for j in range(i+2,len(ordre)): r = ordre[i:j].copy() r.reverse() ordre2 = ordre[:i] + r + ordre[j:] t = longueur(x,y,ordre2) if t < d : d = t ordre = ordre2 return ordre ordre = permutation (x,y,list(range(len(x)))) print("longueur min", longueur(x,y,ordre)) xo = [ x[o] for o in ordre + [ordre[0]]] yo = [ y[o] for o in ordre + [ordre[0]]] plt.plot(xo,yo, "o-") plt.text(xo[0],yo[0],"0",color="r",weight="bold",size="x-large") plt.text(xo[-2],yo[-2],"N-1",color="r",weight="bold",size="x-large") longueur initiale 9.088214152577255 iteration 2 d= 9.088214152577255 ordre[0] 0 iteration 3 d= 2.5487629282495905 ordre[0] 0 iteration 4 d= 2.0525351013235587 ordre[0] 0 iteration 5 d= 1.9682052771032004 ordre[0] 0 iteration 6 d= 1.9626694831332183 ordre[0] 0 ordre = list(range(len(x))) print("longueur initiale", longueur(x,y,ordre)) def permutation(x,y,ordre): d = longueur(x,y,ordre) d0 = d+1 it = 1 while d < d0 : it += 1 print("iteration",it, "d=",d, "ordre[0]", ordre[0]) d0 = d for i in range(1,len(ordre)-1) : # on part de 1 et plus de 0, on est sûr que le premier noeud ne bouge pas for j in range(i+2,len(ordre)+ 1): # correction ! r = ordre[i:j].copy() r.reverse() ordre2 = ordre[:i] + r + ordre[j:] t = longueur(x,y,ordre2) if t < d : d = t ordre = ordre2 return ordre ordre = permutation (x,y,list(range(len(x)))) print("longueur min", longueur(x,y,ordre)) xo = [ x[o] for o in ordre + [ordre[0]]] yo = [ y[o] for o in ordre + [ordre[0]]] plt.plot(xo,yo, "o-") plt.text(xo[0],yo[0],"0",color="r",weight="bold",size="x-large") plt.text(xo[-2],yo[-2],"N-1",color="r",weight="bold",size="x-large") longueur initiale 9.088214152577255 iteration 2 d= 9.088214152577255 ordre[0] 0 iteration 3 d= 2.15274032488533 ordre[0] 0 iteration 4 d= 1.5871321718676845 ordre[0] 0 iteration 5 d= 1.4761768065688674 ordre[0] 0 iteration 6 d= 1.305681395064649 ordre[0] 0 iteration 7 d= 1.1729692207112679 ordre[0] 0 iteration 8 d= 1.1696656744721234 ordre[0] 0 iteration 9 d= 1.0944778856037314 ordre[0] 0 longueur min 1.094477885603731 ordre = list(range(len(x))) print("longueur initiale", longueur(x,y,ordre)) def permutation_rnd(x,y,ordre): d = longueur(x,y,ordre) d0 = d+1 it = 1 while d < d0 : it += 1 print("iteration",it, "d=",d, "ordre[0]", ordre[0]) d0 = d for i in range(1,len(ordre)-1) : for j in range(i+2,len(ordre)+ 1): k = random.randint(1,len(ordre)-1) l = random.randint(k+1,len(ordre)) r = ordre[k:l].copy() r.reverse() ordre2 = ordre[:k] + r + ordre[l:] t = longueur(x,y,ordre2) if t < d : d = t ordre = ordre2 return ordre ordre = permutation_rnd (x,y,list(range(len(x)))) print("longueur min", longueur(x,y,ordre)) xo = [ x[o] for o in ordre + [ordre[0]]] yo = [ y[o] for o in ordre + [ordre[0]]] plt.plot(xo,yo, "o-") plt.text(xo[0],yo[0],"0",color="r",weight="bold",size="x-large") plt.text(xo[-2],yo[-2],"N-1",color="r",weight="bold",size="x-large") longueur initiale 9.088214152577255 iteration 2 d= 9.088214152577255 ordre[0] 0 iteration 3 d= 2.0752331652833953 ordre[0] 0 iteration 4 d= 1.5498126598925794 ordre[0] 0 iteration 5 d= 1.0632204732444923 ordre[0] 0 iteration 6 d= 0.9586894082016447 ordre[0] 0 longueur min 0.9586894082016447 <matplotlib.text.Text at 0x95ce3b0> ordre = permutation_rnd (x,y,list(range(len(x)))) print("longueur min", longueur(x,y,ordre)) xo = [ x[o] for o in ordre + [ordre[0]]] yo = [ y[o] for o in ordre + [ordre[0]]] plt.plot(xo,yo, "o-") plt.text(xo[0],yo[0],"0",color="r",weight="bold",size="x-large") plt.text(xo[-2],yo[-2],"N-1",color="r",weight="bold",size="x-large") iteration 2 d= 9.088214152577255 ordre[0] 0 iteration 3 d= 2.2142449917653977 ordre[0] 0 iteration 4 d= 1.5041710703267277 ordre[0] 0 iteration 5 d= 1.3132407450526207 ordre[0] 0 iteration 6 d= 1.172238044178559 ordre[0] 0 iteration 7 d= 1.1522114915981128 ordre[0] 0 longueur min 1.1522114915981128 <matplotlib.text.Text at 0x9b054b0> ordre = list(range(len(x))) print("longueur initiale", longueur(x,y,ordre)) def permutation_rnd(x,y,ordre,miniter): d = longueur(x,y,ordre) d0 = d+1 it = 1 while d < d0 or it < miniter : it += 1 d0 = d for i in range(1,len(ordre)-1) : for j in range(i+2,len(ordre)+ 1): k = random.randint(1,len(ordre)-1) l = random.randint(k+1,len(ordre)) r = ordre[k:l].copy() r.reverse() ordre2 = ordre[:k] + r + ordre[l:] t = longueur(x,y,ordre2) if t < d : d = t ordre = ordre2 return ordre def n_permutation(x,y, miniter): ordre = list(range(len(x))) bordre = ordre.copy() d0 = longueur(x,y,ordre) for i in range(0,20): print("iteration",i, "d=",d0) random.shuffle(ordre) ordre = permutation_rnd (x,y,ordre, 20) d = longueur(x,y,ordre) if d < d0 : d0 = d bordre = ordre.copy() return bordre ordre = n_permutation (x,y, 20) print("longueur min", longueur(x,y,ordre)) xo = [ x[o] for o in ordre + [ordre[0]]] yo = [ y[o] for o in ordre + [ordre[0]]] plt.plot(xo,yo, "o-") plt.text(xo[0],yo[0],"0",color="r",weight="bold",size= "x-large") plt.text(xo[-2],yo[-2],"N1",color="r",weight="bold",size="x-large") longueur initiale 9.088214152577255 iteration 0 d= 9.088214152577255 iteration 1 d= 0.9257857251290083 iteration 2 d= 0.9257857251290083 iteration 3 d= 0.9257857251290083 iteration 4 d= 0.9257857251290083 iteration 5 d= 0.9257857251290083 iteration 6 d= 0.9257857251290083 iteration 7 d= 0.9257857251290083 iteration 9 d= 0.9257857251290083 iteration 10 d= 0.9257857251290083 iteration 11 d= 0.9257857251290083 iteration 12 d= 0.9257857251290083 iteration 13 d= 0.9257857251290083 iteration 14 d= 0.9257857251290083 iteration 15 d= 0.890296113557742 iteration 16 d= 0.890296113557742 iteration 17 d= 0.890296113557742 iteration 18 d= 0.890296113557742 iteration 19 d= 0.890296113557742 longueur min 0.890296113557742 Réflexion Un algorithme pour résoudre en temps polynomial le problème du voyageur de commerce peut en faire de même pour tout problème dans NP. L’équivalent médical serait une maladie universelle : si vous savez la traiter, alors vous savez aussi soigner toutes les autres maladies ! Le problème TSP est-il le seul NP-complet ? Pas vraiment. On en connaît des milliers. Conclusion Concluons sur une note psychologique cette introduction au mystère de P et NP. Les spécialistes misent sur leur inégalité. Pourquoi ? Il y a beaucoup de raisons, dont aucune n’est très convaincante. L’argument anthropomorphique rejette l’égalité P=NP comme un affront à notre humanité. Si prouver n’est pas plus difficile que vérifier, alors créer une œuvre d’art n’est pas plus difficile que de l’apprécier. Références [1] Muhtar, F. (2014). Abu Abdullah Ibn Musa Al-Khawarizmi (Pelopor Matematika Dalam Islam). Beta: Jurnal Tadris Matematika, 7(2), 82-97. [2] Karimi, A. H., Barthe, G., Schölkopf, B., & Valera, I. (2020). A survey of algorithmic recourse: definitions, formulations, solutions, and prospects. arXiv preprint arXiv:2010.04050. [3] Berry G., Penser, modéliser, et maîtriser le calcul informatique, Collège de France / Fayard, coll. « Leçons inaugurales », no 208, 2009. [4] Knuth, D. E. (1973). The Art of Computer Programming, Volume I : Fundamental Algorithms (2e éd.). Addison-Wesley [5] Copeland, B. J., & Sylvan, R. (1999). Beyond the universal Turing machine. Australasian Journal of Philosophy, 77(1), 46-66. [6] Copeland, B. J. (1997). The church-turing thesis. [7] https://www.inria.fr/fr/quest-ce-quun-algorithme [8] Arora S. et Barak B., Computational Complexity: A Modern Approach, Cambridge University Press, 2009. [9] Deutsch, D. (1985). Quantum theory, the Church–Turing principle and the universal quantum computer. Proceedings of the Royal Society of London. A. Mathematical and Physical Sciences, 400(1818), 97-117. Merci pour votre attention