Dans les algorithmes et la complexité, nous nous concentrons sur la complexité asymptotique des algorithmes, c'est-à-dire la quantité de ressources qu'un algorithme utilise lorsque la taille de l'entrée va à l'infini.
En pratique, nous avons besoin d’un algorithme qui fonctionnerait rapidement pour un nombre fini (bien que possiblement très grand) d’instances.
Un algorithme qui fonctionne bien dans la pratique sur le nombre fini d'instances qui nous intéresse n'a pas besoin d'avoir une bonne complexité asymptotique (une bonne performance sur un nombre fini d'instances n'implique rien en ce qui concerne la complexité asymptotique). De même, un algorithme avec une bonne complexité asymptotique peut ne pas fonctionner correctement sur le nombre fini d'instances qui nous intéresse (par exemple, en raison de la taille des constantes).
Pourquoi utilisons-nous la complexité asymptotique? Comment ces analyses asymptotiques sont-elles liées à la conception d'algorithmes dans la pratique?
Réponses:
La question intéressante est: quelle est l'alternative? La seule autre méthode que je connaisse est le test / l'analyse comparative. Nous programmons les algorithmes, les laissons exécuter (sur un échantillon représentatif) l'ensemble d'entrées finies et comparons les résultats. Cela pose quelques problèmes.
Cela dit, il est typique d’ignorer toutes sortes d’effets et de constantes dans l’analyse, mais on peut parler de paresseux (en ce qui concerne la pratique). Il sert plus à comparer les idées algorithmiques qu’à cerner les performances d’une implémentation donnée (même pseudocode). La communauté sait pertinemment que cela est grossier et qu’il est souvent nécessaire d’examiner de plus près. Par exemple, Quicksort est moins efficace que le type Insertion pour les (très) petites entrées. Pour être juste, une analyse plus précise est généralement difficile ².
Une autre justification, a posteriori, du point de vue formel et abstrait est que, à ce niveau, les choses sont souvent plus claires. Ainsi, des décennies d’études théoriques ont donné lieu à une foule d’idées algorithmiques et de structures de données utiles dans la pratique. L’algorithme théoriquement optimal n’est pas toujours celui que vous souhaitez utiliser en pratique - il faut prendre en compte d’autres considérations, mais il faut améliorer les performances; pense Fibonacci tas - et cette étiquette peut même ne pas être unique. Il est difficile pour un programmeur typique soucieux d'optimiser les expressions arithmétiques de proposer une nouvelle idée à ce niveau (pour ne pas dire que cela n'arrive pas); elle peut (et devrait) effectuer ces optimisations sur l'idée assimilée, cependant.
Il existe des outils théoriques formels pour combler le fossé de la pratique dans une certaine mesure. Des exemples sont
Par exemple, Knuth est connu pour compter littéralement le nombre d'instructions différentes (pour une implémentation donnée dans un modèle donné), permettant ainsi une comparaison précise des algorithmes. Cette approche est impossible sur un plan abstrait et difficile à appliquer dans des modèles plus complexes (pensez à Java). Voir [4] pour un exemple moderne.
Il y aura toujours un fossé entre la théorie et la pratique. Nous travaillons actuellement sur un outil³ dans le but de combiner le meilleur des deux mondes afin de faire des prédictions fiables à la fois pour les coûts algorithmiques et le temps d’exécution (en moyenne), mais nous n’avons pas pu éliminer jusqu’à présent les scénarios dans lesquels un algorithme a une valeur supérieure. coûts d'exécution plus faibles (sur certaines machines) que leurs équivalents (bien que nous puissions le détecter et aider à en trouver la raison).
Je recommande aux praticiens d'utiliser la théorie pour filtrer l'espace des algorithmes avant d'exécuter des tests de performance:
la source
Je suppose que cette question découle de l’enseignement d’un cours comportant une analyse asymptotique. Il y a plusieurs réponses possibles pour expliquer pourquoi ce matériel est enseigné dans les cours d'introduction:
L'analyse asymptotique est une abstraction mathématique qui se livre à l'analyse. En tant que mathématiciens, nous voulons pouvoir analyser des algorithmes, et le seul moyen d’apprivoiser leur complexité consiste à utiliser une analyse asymptotique.
L'évaluation de la performance asymptotique d'un algorithme met en évidence certains principes utiles en pratique: par exemple, concentrez-vous sur la partie du code qui prend la majorité du temps et mettez à l'écart toute partie du code qui prend une partie du temps asymptotiquement négligeable. .
Certaines des techniques d'analyse asymptotique sont utiles. Je parle ici principalement du "théorème maître", qui dans de nombreuses circonstances est une bonne description de la réalité.
Il y a aussi une raison historique: quand les gens ont commencé à analyser des algorithmes, ils ont pensé sérieusement que la complexité asymptotique reflétait une utilisation pratique. Cependant, ils se sont finalement avérés faux. La même chose s’est produite avec P en tant que classe de problèmes pouvant être résolus efficacement, et NP en tant que classe de problèmes insolubles, qui sont en pratique trompeurs.
Personnellement, je pense que l'analyse asymptotique est une partie raisonnable du programme. Les parties les plus discutables incluent la théorie du langage formel et la théorie de la complexité (tout ce qui concerne une machine de Turing). Certaines personnes avancent que si ces sujets ne sont pas utiles en soi au programmeur, ils lui inculquent une certaine pensée qui est nécessaire pour être un bon praticien. D'autres soutiennent que la théorie influence parfois la pratique et que ces rares cas suffisent à justifier l'enseignement de ces sujets plutôt obscurs au grand public de l'informatique. Je préférerais qu'ils apprennent l'histoire, la littérature ou tout autre sujet qui les intéresse réellement; les deux sont aussi pertinents pour leurs perspectives d'emploi futures et plus importants pour eux en tant qu'êtres humains.
la source
L’utilisation de l’analyse asymptotique des temps d’exécution a deux raisons sérieuses:
pour permettre la traçabilité mathématique. Les cas tels qu'il est possible de trouver des expressions exactes pour le nombre d'opérations sont exceptionnels. L'étude des asymptotiques ouvre plus de possibilités (comme les approximations asymptotiques de fonctions compliquées sont pratiques).
Et il y en a beaucoup d'autres (comme l'indépendance de la machine, le sens, la comparabilité, etc.).
la source
Comme indiqué dans la réponse de Raphaël, il peut être très difficile de calculer avec exactitude la durée d'exécution la plus défavorable. Le calcul exact peut également être inutile puisque le modèle RAM introduit déjà des approximations. Par exemple, toutes les opérations prennent-elles vraiment le même temps? Des implémentations spécifiques (matériel, optimisations) peuvent accélérer un algorithme par des facteurs constants. Nous voulons comprendre l'efficacité d'un algorithme indépendamment de ces facteurs. C'est une grande motivation pour l'utilisation de l'analyse asymptotique.
la source
Parce que les asymptotiques sont "simples" (enfin, plus simples que de faire l'analyse exacte pour les cas finis, en tout cas).
Comparez, par exemple, l'encyclopédie "The Art of Computer Programming" de Knuth, qui analyse en détail tous les algorithmes importants (et de nombreux algorithmes moins importants) avec l'analyse de règle empirique qui est souvent suffisante pour obtenir une estimation asymptotique ( ou simplement une limite), comme pratiqué dans la plupart des livres "d'algorithmes".
Vous avez certainement raison. Si le problème est suffisamment important, une analyse de type Knuth (ou peut-être un peu moins détaillée) pourrait bien être justifiée. Dans de nombreux cas, un indice de la complexité asymptotique (peut-être moyenne avec dispersion) ajusté aux données expérimentales est suffisant. Dans la plupart des cas , une classification approximative des algorithmes en concurrence, en tant que premier tour complet, en comparant les asymptotiques peut être suffisamment précise. Et s’il n’ya pas de prétendants, le masochisme est ce qu’il ya de mieux en ce qui concerne le coût exact.
la source
Ici, par analyse asymptotique, je suppose que nous entendons le comportement de l’algorithme lorsque la taille de l’entrée va à l’infini.
Nous utilisons l'analyse asymptotique parce qu'elle est utile pour prédire le comportement des algorithmes en pratique . Les prédictions nous permettent de prendre des décisions, par exemple lorsque nous avons différents algorithmes pour un problème, lequel devons-nous utiliser? (Être utile ne veut pas dire que c'est toujours correct.)
La même question peut être posée à propos de tout modèle simplifié du monde réel. Pourquoi utilisons-nous des modèles mathématiques simplifiés du monde réel?
Pensez à la physique. La physique newtonienne classique n’est pas aussi bonne que la physique relativiste pour prédire le monde réel. Mais c’est un modèle suffisant pour la construction de voitures, de gratte-ciel, de sous-marins, d’avions, de ponts, etc. Dans certains cas, cela ne suffit pas, par exemple si nous voulons construire un satellite ou envoyer une sonde spatiale à Pluton ou prévoir le mouvement. des objets célestes massifs comme les étoiles et les planètes ou des objets à très grande vitesse comme les électrons. Il est important de savoir quelles sont les limites d'un modèle.
C'est typiquement une assez bonne approximation du monde réel. En pratique, nous voyons souvent qu’un algorithme avec une meilleure analyse asymptotique fonctionne mieux dans la pratique. Il est rare qu'un algorithme ait un meilleur comportement asymptotique. Ainsi, si les entrées peuvent être assez grandes, nous pouvons généralement nous baser sur une analyse asymptotique comme première prédiction du comportement des algorithmes. Ce n'est pas le cas si nous savons que les intrants vont être réduits. En fonction de la performance souhaitée, nous pouvons être amenés à effectuer une analyse plus minutieuse. Par exemple, si nous disposons d'informations sur la distribution des entrées, nous pouvons effectuer une analyse plus minutieuse pour atteindre les objectifs que nous avons définis. % d'intrants). L’analyse asymptotique est un bon point de départ. En pratique, nous devrions également faire des tests de performance, mais gardez à l'esprit que cela a aussi ses propres problèmes.
En résumé, la complexité asymptotique est une approximation relativement facile de la complexité réelle des algorithmes pour des tâches de base simples (problèmes dans un manuel d’algorithmes). Au fur et à mesure que nous élaborons des programmes plus complexes, les exigences de performances changent et deviennent de plus en plus complexes. Une analyse asymptotique peut ne pas être aussi utile.
Il est bon de comparer l'analyse asymptotique à d'autres approches permettant de prédire la performance d'algorithmes et de les comparer. Les tests de performance par rapport à des entrées aléatoires ou de référence constituent une approche courante. Il est courant que le calcul de la complexité asymptotique soit difficile ou irréalisable, par exemple lorsque nous utilisons des méthodes heuristiques, comme par exemple la résolution SAT. Un autre cas de figure est celui où les exigences sont plus complexes, par exemple lorsque les performances d’un programme dépendent de facteurs extérieurs et que notre objectif peut être d’obtenir quelque chose qui se termine dans des délais déterminés (par exemple, pensez à mettre à jour l’interface affichée à un utilisateur) sur 99% des utilisateurs. contributions.
Mais gardez à l'esprit que l'analyse de la performance a aussi ses problèmes. Nous n'effectuons pas le test de performance sur toutes les entrées qui seront données à l'algorithme (souvent infaillibles sur le plan informatique) (et il est souvent impossible de décider que certaines entrées ne seront jamais données). Si nous testons sur un échantillon aléatoire ou un point de référence, nous supposons implicitement une certaine régularité concernant les performances des algorithmes, autrement dit, l'algorithme fonctionnera de la même manière sur d'autres entrées qui ne faisaient pas partie du test de performance.
Le deuxième problème avec les tests de performance est qu'ils dépendent de l'environnement de test. Par exemple, les performances d’un programme ne dépendent pas uniquement des entrées, mais de facteurs extérieurs (type de machine, système d’exploitation, efficacité de l’algorithme codé, utilisation de la CPU, temps d’accès à la mémoire, etc.), dont certains peuvent varier entre différentes exécutions de programmes. le test sur la même machine. Ici encore, nous supposons que les environnements particuliers testés sont similaires à l'environnement réel, à moins que nous ne fassions les tests de performance sur tous les environnements sur lesquels nous pouvons exécuter le programme (et comment pouvons-nous prédire sur quelles machines une personne peut exécuter un tri) algorithme dans 10 ans?).
la source
Imaginez maintenant que l' attente soit répétée dans le code autant de fois que le code est appelé. comment quantifier / justifier mathématiquement cette supériorité apparente de l'algorithme quicksort? (C'est-à-dire que son nom est vraiment justifié ou s'agit-il simplement d'un slogan marketing?) via des mesures de complexité asymptotiques. il suffit de regarder les animations subjectivement pour penser que bubbleort est en quelque sorte un algorithme plus faible et une analyse asymptotique de la complexité peut le prouver quantitativement. mais notez que l’analyse asymptotique de la complexité n’est qu’un outil parmi d’autres pour analyser des algorithmes et qu’elle n’est pas toujours optimale.
et sa vaut la peine de regarder le code côte à côte également. Bubblesort semble être conceptuellement plus simple et n'utilise pas de récursivité. quicksort n’est pas immédiatement compris, en particulier le principe de pivot "médian de 3". Bubblesort peut être implémenté uniquement dans les boucles sans sous-programme, alors que QuickSort peut généralement avoir au moins un sous-programme. Cela montre à quel point une sophistication accrue du code peut parfois améliorer la complexité asymptotique au détriment de la simplicité du code. il existe parfois un compromis extrême similaire au concept de rendements marginaux décroissants (provenant de l’économie), où de très grandes quantités de complexité de code [exigeant des papiers entiers pleins de preuves et de preuves pour justifier] n’achètent que de très petites améliorations de la complexité asymptotique. cela apparaît à titre d'exemple esp avecmultiplication matricielle et peut même être représentée graphiquement .
la source