<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tri | Dr. Goulu</title><link>https://drgoulu.com/tags/tri/</link><atom:link href="https://drgoulu.com/tags/tri/index.xml" rel="self" type="application/rss+xml"/><description>Tri</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>fr-FR</language><lastBuildDate>Sat, 19 Jan 2013 00:00:00 +0000</lastBuildDate><image><url>https://drgoulu.com/media/icon_hu_eee4a95885829ab2.png</url><title>Tri</title><link>https://drgoulu.com/tags/tri/</link></image><item><title>Comment bien brasser les cartes</title><link>https://drgoulu.com/2013/01/19/comment-bien-brasser-les-cartes/</link><pubDate>Sat, 19 Jan 2013 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2013/01/19/comment-bien-brasser-les-cartes/</guid><description>&lt;p&gt;Les amateurs de jeux de cartes savent qu&amp;rsquo;il faut accorder beaucoup d&amp;rsquo;attention au brassage des cartes pour éviter la triche, mais qu&amp;rsquo;en est-il par exemple dans les jeux de poker en ligne ?&lt;/p&gt;
&lt;p&gt;Les informaticiens se sont beaucoup
, mais relativement peu sur les problèmes de brassage, moins fréquents et apparemment plus simples. Mais comme disait
 : &amp;ldquo;il faut se méfier des appâts rances&amp;rdquo; ©&amp;hellip;&lt;/p&gt;
&lt;p&gt;Examinons pour commencer un algorithme tout bête que j&amp;rsquo;avoue avoir utilisé plusieurs fois  : on échange la première carte (ou donnée) avec une autre choisie au hasard parmi les N cartes*, puis on fait de même pour la 2ème carte, la 3ème et ainsi de suite jusqu&amp;rsquo;à la N-ième. Cette méthode semble réunir toutes les caractéristiques d&amp;rsquo;un bon algorithme : simplicité, rapidité, et efficacité.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Si vous avez un vrai browser, 
. C&amp;rsquo;est ma première oeuvre faite avec
, fortement inspirée de
, et que j&amp;rsquo;essaie désespérément d&amp;rsquo;inclure directement dans cet article&amp;hellip;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Et pourtant, un tel brassage s&amp;rsquo;avère &amp;ldquo;biaisé&amp;rdquo; : toutes les
 possibles n&amp;rsquo;ont pas la même probabilité d&amp;rsquo;être produites. Déjà en ne brassant que N=3 cartes par cette méthode, 3 des 6 permutations possibles sont nettement moins probables que les 3 autres  
.&lt;/p&gt;
&lt;figure class="alignright" style="max-width: 240px; width: 100%;"&gt;&lt;a href="http://bost.ocks.org/mike/shuffle/compare.html" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2013/images/fdd88ca55a8f211b9fc8f978d988744c_hu_42fde1d106c510f.webp" srcset="https://drgoulu.com/posts/2013/images/fdd88ca55a8f211b9fc8f978d988744c_hu_42fde1d106c510f.webp 240w" sizes="(max-width: 640px) 100vw, 240px" alt="biais naïve swap (i ↦ random)" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;/a&gt;&lt;figcaption&gt;biais naïve swap (i ↦ random)&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Avec N=60 cartes, ce biais est bien visible sur la figure ci-contre, produite par une autre 
  en ligne
. Elle effectue 10'000 mélanges avec le même algo, compte dans une matrice le nombre de fois ou la i-ième carte se retrouve à la j-ième position après le brassage, et représente les
 positifs en vert et les négatifs en rouge.&lt;/p&gt;
&lt;p&gt;La variante &amp;ldquo;swap (random ↦ random)&amp;rdquo; dans laquelle on échange N fois 2 cartes choisies au hasard n&amp;rsquo;est pas meilleure : elle présente un biais positif sur la diagonale (i=j) qui s&amp;rsquo;atténue si on effectue 2N échanges, et disparaît presque pour 3N échanges.&lt;/p&gt;
&lt;p&gt;Signifierait-ce qu&amp;rsquo;il faut plus de N opérations pour obtenir un &amp;ldquo;bon&amp;rdquo; brassage de N cartes ? On pourrait le penser car il existe un algorithme tout simple sans biais : extraire successivement des cartes prises au hasard dans le tas pour en constituer un deuxième, mais il nécessite N.log(N) opérations***, voire N² s&amp;rsquo;il est mal programmé
. Or N.log(N) est la complexité des algorithmes de tri, donc on pourrait avoir l&amp;rsquo;idée aussi surprenante que séduisante de se faire un brassage en utilisant
 auquel on passe une fonction aléatoire comme critère de tri.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est tellement beau que j&amp;rsquo;exhibe même ici le petit bout de code Javascript qui fait ça:&lt;/p&gt;
\[source language="javascript"\]&lt;p&gt; function shuffle(array) { array.sort(function() {return Math.random() - .5}); }&lt;/p&gt;
\[/source\]&lt;figure class="alignright" style="max-width: 240px; width: 100%;"&gt;&lt;a href="http://bost.ocks.org/mike/shuffle/compare.html" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2013/images/4515a7fe42f5229307c0f50570d991ca_hu_23c38f7925303819.webp" srcset="https://drgoulu.com/posts/2013/images/4515a7fe42f5229307c0f50570d991ca_hu_23c38f7925303819.webp 239w" sizes="(max-width: 640px) 100vw, 240px" alt="biais sort (random comparator)" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;/a&gt;&lt;figcaption&gt;biais sort (random comparator)&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;random() renvoie un nombre aléatoire entre 0 et 1, donc Math.random() - .5 tire à pile ou face si une carte est &amp;ldquo;plus grande&amp;rdquo; que l&amp;rsquo;autre lors du tri, ce qui est supposé mélanger au lieu de trier.&lt;/p&gt;
&lt;p&gt;Cette méthode produit la matrice de biais ci-contre, dont la non-trivialité me laisse pantois.&lt;/p&gt;
&lt;p&gt;Par contre, la variante dans laquelle on commence par générer un vecteur de nombres aléatoires, puis on &amp;ldquo;dé-trie&amp;rdquo; les données en utilisant ces nombres aléatoires pour les comparaisons donne un résultat non biaisé. (voir &amp;ldquo;sort (random order)&amp;rdquo; dans
)&lt;/p&gt;
&lt;p&gt;Et une fois qu&amp;rsquo;on est tout content d&amp;rsquo;avoir trouvé un algorithme de brassage non biaisé de complexité N.log(N), on découvre celui de
 datant de 1938, non biaisé, assez simple : &lt;/p&gt;
\[source language="javascript"\]&lt;p&gt; function shuffle(array) { var j = array.length, t, i; while (j) { i = Math.floor(Math.random() * j&amp;ndash;); t = array&lt;/p&gt;
\[j\]&lt;p&gt;; array&lt;/p&gt;
\[j\]&lt;p&gt; = array&lt;/p&gt;
\[i\]&lt;p&gt;; array&lt;/p&gt;
\[i\]&lt;p&gt; = t; } }&lt;/p&gt;
\[/source\]&lt;p&gt; Les 3 dernières lignes échangent les cartes en i-ième et en j-ième position tout comme dans notre premier algorithme naïf, mais ici on ne choisit la carte à échanger que parmi celles qui n&amp;rsquo;ont pas encore été traitées. Et pour des raisons de simplicité du code, on mélange le tableau &amp;ldquo;depuis la fin&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Et le plus beau est que sa
est proportionnelle à N, ce qui est in exemple de plus de l’universalité du principe de Murphy de la thermodynamique de la tartine beurrée qui dit qu&amp;rsquo;il est toujours plus facile de générer du désordre que de l&amp;rsquo;ordre.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;autre part, si vous devez brasser beaucoup de données de manière irréversible, je ne sais pas moi, pour une application de vote par internet par exemple, souvenez-vous de Fisher-Yates. Et utilisez un
 , car un
 peut non seulement souffrir de biais, mais surtout être reproductible à partir de la &amp;ldquo;graine&amp;rdquo; et permettre ainsi d&amp;rsquo;inverser le brassage.&lt;/p&gt;
&lt;p&gt;Bon, je voulais encore modéliser différentes techniques de brassage de vraies cartes en JavaScript pour déterminer combien d&amp;rsquo;opérations sont nécessaires pour obtenir un mélange sans biais, mais je préfère laisser ça en exercice pour ChipRaptor et d&amp;rsquo;autres.&lt;/p&gt;
&lt;div class="my-6 mx-auto" style="max-width: 640px; width: 100%;"&gt;
&lt;div class="w-full relative rounded-lg overflow-hidden shadow-md bg-black" style="padding-bottom: 56.25%; height: 0;"&gt;
&lt;iframe
src="https://www.youtube-nocookie.com/embed/UYmcmIgL1yA"
title="YouTube video player"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
loading="lazy"&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="notes"&gt;Notes:&lt;/h3&gt;
&lt;p&gt;Gag © Pierre-Alain de 
&lt;/p&gt;
&lt;p&gt;* et non N-1, car il faut garder une chance sur N que la carte soit &amp;ldquo;échangée avec elle même&amp;rdquo; et reste à sa place dans le tas.&lt;/p&gt;
&lt;p&gt;** félicitations au premier lecteur qui calculera les probabilités respectives de ces permutations et expliquera ainsi le biais&amp;hellip;&lt;/p&gt;
&lt;p&gt;*** parce qu&amp;rsquo;on doit alors forcément parcourir des
&lt;/p&gt;
&lt;h3 id="références"&gt;Références:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span id="ref-1"&gt;&lt;/span&gt;
,  &amp;ldquo;
&amp;rdquo;, 14 janvier 2012&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-2"&gt;&lt;/span&gt;Mike Bostock,  &amp;ldquo;
&amp;rdquo;, 21 janvier 2012&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-3"&gt;&lt;/span&gt;Jeff Atwood &amp;ldquo;
&amp;rdquo;, 2007, Coding Horror&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Le &amp;quot;Sleep sort&amp;quot;</title><link>https://drgoulu.com/2011/06/19/le-sleep-sort/</link><pubDate>Sun, 19 Jun 2011 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2011/06/19/le-sleep-sort/</guid><description>&lt;p&gt;Tout a commencé* par un
: un anonyme propose un algorithme de tri en 2 lignes de code
:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;function f() {sleep &amp;quot;$1&amp;quot; echo &amp;quot;$1&amp;quot;} while [ -n &amp;quot;$1&amp;quot; ] do f &amp;quot;$1&amp;quot; &amp;amp; shift done wait&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Lorsqu&amp;rsquo;il est appelé avec une liste de N nombres comme dans &lt;code&gt;./sleepsort.bash 5 3 6 3 6 3 1 4 7 ,&lt;/code&gt; ce code lance un processus pour chacun des nombres n. Chaque processus effectue la fonction f, qui utilise la fonction
pour attendre n secondes avant d&amp;rsquo;afficher le nombre n. Dans l&amp;rsquo;exemple, le 7ème processus n&amp;rsquo;attendra qu&amp;rsquo;une seconde avant d&amp;rsquo;afficher &amp;ldquo;1&amp;rdquo;, le 4ème et le 6ème attendront 3 secondes avant d&amp;rsquo;afficher &amp;ldquo;3&amp;rdquo; dans un ordre qui n&amp;rsquo;a aucune importance et ainsi de suite jusqu&amp;rsquo;au dernier processus qui affichera &amp;ldquo;7&amp;rdquo; après 7 secondes. L&amp;rsquo;utilisateur verra ainsi s&amp;rsquo;afficher progressivement les N nombres triés dans l&amp;rsquo;ordre croissant.&lt;/p&gt;
&lt;p&gt;Depuis ce message on voit des implémentations de &amp;ldquo;Sleep sort&amp;rdquo; fleurir dans
programmation en utilisant
, et des
, anglophones surtout pour l&amp;rsquo;instant.&lt;/p&gt;
&lt;p&gt;Prétextant que ce programme mettrait plus de 11 jours à trier les deux nombres 1000000 et 673, certains considèrent le &amp;ldquo;sleep sort&amp;rdquo; comme un bon gag, ce qu&amp;rsquo;il est certainement à l&amp;rsquo;origine. Pour ma part j&amp;rsquo;ai 
de la 
. Voici pourquoi.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;abord, ce code est simple et fait l&amp;rsquo;éloge d&amp;rsquo;une grande qualité du programmeur : la paresse. Faire quelque chose d&amp;rsquo;utile simplement en attendant, quoi de plus beau ? A ce titre il mérite amplement sa place à côté du 
dont 
en français, du
ou des 
et 
sans intérêt, mais qui ont leur page Wikipédia.&lt;/p&gt;
&lt;figure class="alignright" style="max-width: 240px; width: 100%;"&gt;&lt;a href="http://www.flickr.com/photos/30271386@N04/3016524792/in/photostream/" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2011/images/3016524792_cdb7edf4c8_m-1_hu_3d3e671f745d1e2e.webp" srcset="https://drgoulu.com/posts/2011/images/3016524792_cdb7edf4c8_m-1_hu_3d3e671f745d1e2e.webp 240w" sizes="(max-width: 640px) 100vw, 240px" alt="Photo par Eben Regis sur flickr" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;/a&gt;&lt;figcaption&gt;Photo par Eben Regis sur flickr&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Plus sérieusement, &amp;ldquo;Sleep sort&amp;rdquo; exploite de manière active l&amp;rsquo;écoulement du temps au lieu de le subir, ce qui est déjà intéressant en soi, mais pose également des questions intéressantes sur la
.&lt;/p&gt;
&lt;p&gt;Car le &amp;ldquo;génie&amp;rdquo; de cet algorithme, s&amp;rsquo;il vous avait échappé, est qu&amp;rsquo;il prend en apparence un temps proportionnel à max(n), le plus grand des nombres à trier, pour s&amp;rsquo;exécuter, plus un temps proportionnel à N pour créer les processus. Or les 
existants prennent un temps proportionnel à N.log(N). Il pourrait donc exister des cas où le &amp;ldquo;sleep sort&amp;rdquo; serait plus rapide. Mais est-ce vraiment le cas ?&lt;/p&gt;
&lt;p&gt;Traitons d&amp;rsquo;abord de la partie la plus perceptible du temps d&amp;rsquo;exécution, l&amp;rsquo;attente de max(n) secondes. Sur les machines actuelles,
, et on pourrait probablement passer aux microsecondes. En fait il faut simplement garantir que deux processus associés à deux nombres x et x+1 se réveillent dans le bon ordre et aient le temps de produire leur sortie sans perturber le réveil des processus suivants. Déjà ceci soulève plein de problèmes intéressants au niveau des systèmes d&amp;rsquo;exploitation, de l&amp;rsquo;accès aux ressources critiques etc. Mais quelles que soient les solutions techniques, il reste qu&amp;rsquo;on ne sait pas bien exprimer théoriquement la complexité d&amp;rsquo;un tel algorithme : en principe, une durée d&amp;rsquo;exécution proportionnelle à l&amp;rsquo;une des données conduit à une complexité O(1) supposée largement inférieure à O(N), ce qui n&amp;rsquo;est pas le cas en pratique ici.&lt;/p&gt;
&lt;p&gt;Ensuite la partie &amp;ldquo;proportionnelle à N&amp;rdquo; dans laquelle on crée les N processus est elle vraiment O(N) ? En principe oui, mais il existe une partie invisible : la gestion interne de la fonction système &amp;ldquo;sleep&amp;rdquo;. Dans tous les systèmes d&amp;rsquo;exploitation que je connais (au moins deux&amp;hellip;), &amp;ldquo;sleep&amp;rdquo; provoque l&amp;rsquo;insertion du processus dans une liste de tous les processus suspendus en attente de l&amp;rsquo;échéance d&amp;rsquo;un certain temps. Et pour éviter de parcourir toute la liste à chaque interruption du timer pour trouver quels processus doivent être réveillés, on la maintient triée dans l&amp;rsquo;ordre des réveils programmés. &amp;ldquo;Triée&amp;rdquo; ? Et oui&amp;hellip; : à chaque instruction &amp;ldquo;sleep&amp;rdquo;, rencontrée le processus est inséré au bon endroit. &amp;ldquo;Inséré&amp;rdquo; ? Et re-oui&amp;hellip; : l&amp;rsquo;exécution des N &amp;ldquo;sleep&amp;rdquo; revient à un &amp;ldquo;
&amp;rdquo;, d&amp;rsquo;une complexité O(N²) rédhibitoire.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Sleep sort&amp;rdquo; n&amp;rsquo;est donc pas un tri linéaire, du moins sur un ordinateur ayant beaucoup moins de N processeurs. Mais il soulève plein de questions intéressantes sur les algorithmes, les systèmes d&amp;rsquo;exploitation, l&amp;rsquo;architecture des ordinateurs et la psychologie des programmeurs.
!&lt;/p&gt;
&lt;p&gt;Note* : en fait l&amp;rsquo;idée est plus ancienne comme le montre ce post &amp;ldquo;
&amp;rdquo; datant de 2006&lt;/p&gt;</description></item><item><title>Tri réversible ?</title><link>https://drgoulu.com/2010/01/30/tri-reversible/</link><pubDate>Sat, 30 Jan 2010 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2010/01/30/tri-reversible/</guid><description>&lt;figure class="alignright" style="max-width: 280px; width: 100%;"&gt;&lt;a href="http://commons.wikimedia.org/wiki/File:Sorting_quicksort_anim.gif" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2010/images/d4e5d0a778dba725091d8317e6bac939.gif" alt="animation de l&amp;#39;algorithme Quick Sort" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" /&gt;&lt;/a&gt;&lt;figcaption&gt;animation de l&amp;rsquo;algorithme Quick Sort&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;En informatique, le tri est une opération incontournable car il est beaucoup plus rapide de rechercher une information dans une liste triée que dans un fouillis. C&amp;rsquo;est pourquoi j&amp;rsquo;ai longtemps cru qu&amp;rsquo;une liste triée contenait plus d&amp;rsquo;information qu&amp;rsquo;une liste non triée, car je voyais le tri comme un pré-traitement permettant d&amp;rsquo;accélérer les opérations suivantes, donc un &amp;ldquo;plus&amp;rdquo; par rapport à une situation &amp;ldquo;moins&amp;rdquo; performante.&lt;/p&gt;
&lt;p&gt;Pris d&amp;rsquo;un doute il y a quelques années, j&amp;rsquo;avais posé la question sur un forum consacré à l&amp;rsquo;informatique théorique :&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&amp;ldquo;est-ce qu’une liste triée contient vraiment plus d’information qu’une liste non triée ?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Un érudit professeur m’avait répondu simplement ceci :&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&amp;ldquo;ce contient d’ est- information liste liste? non plus qu&amp;rsquo; qu&amp;rsquo; triée triée une une vraiment&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;J’ai mis un moment à comprendre la profondeur de cette réponse : ma question, une fois les mots triés par ordre alphabétique, était devenue incompréhensible, et contenait donc moins d’information que la phrase originale ! Depuis je sais que
.&lt;/p&gt;
&lt;p&gt;
a reposé la question sous un angle intéressant : est-il possible de programmer un algorithme de tri &amp;ldquo;réversible&amp;rdquo;, permettant de remettre une liste triée dans son état initial ? Évidemment oui : il suffit de stocker en plus l&amp;rsquo;information perdue lors du tri, le plus simple étant de mémoriser l&amp;rsquo;état initial de la liste par exemple en ajoutant à chaque élément trié son numéro d&amp;rsquo;ordre :&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&amp;ldquo;ce2 contient7 d’10 est-1 information11 liste5 liste14 non15 plus9 qu'3 qu'12 triée6 triée?16 une4 une13 vraiment8 ”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour une liste contenant n éléments, on a besoin de log(n) bits* pour stocker chaque numéro, donc de n.log(n) bits au total.&lt;/p&gt;
&lt;p&gt;Peut-on faire mieux? On pourrait se dire que beaucoup d&amp;rsquo;
comme
permutent des éléments après les avoir comparés, et qu&amp;rsquo;il suffirait donc de stocker le résultat des comparaisons effectuées, soit un bit par test, pour pouvoir ensuite &amp;ldquo;défaire le tri&amp;rdquo; en parcourant la liste des bits à l&amp;rsquo;envers. Combien faut-ils de bits ? ben &amp;hellip; au moins n.log(n) aussi puisque c&amp;rsquo;est justement le nombre de comparaisons qui détermine la &amp;ldquo;complexité&amp;rdquo; des algorithmes de tri, et que les bons algorithmes ont une complexité de n.log(n).&lt;/p&gt;
&lt;p&gt;Rien ne sert de se casser la tête sur &amp;ldquo;algorithme de tri réversible&amp;rdquo;, il ne peut pas être plus efficace que de simplement stocker l&amp;rsquo;ordre initial des données. Etonnant non ?&lt;/p&gt;
&lt;p&gt;Le problème, c&amp;rsquo;est que la donnée du concours spécifie qu&amp;rsquo;on n&amp;rsquo;a le droit de stocker que 50% d&amp;rsquo;information supplémentaire par rapport à la taille des données : si on trie 4K octets, on n&amp;rsquo;a droit qu&amp;rsquo;à 2K de données supplémentaires. Or en fonction de ce qui précède on a besoin de 4096*log(4096) bits, soit 6K, plus que les données! En passant, ça signifie qu&amp;rsquo;en
de petites données, on peut perdre plus de la moitié de l&amp;rsquo;information contenu dans la liste initiale !&lt;/p&gt;
&lt;p&gt;Bref, personne n&amp;rsquo;a gagné le petit concours parce que ce n&amp;rsquo;était tout simplement pas possible.,&lt;/p&gt;
&lt;p&gt;Note* : en informatique, log(n) dénote évidemment le
binaire ou base 2&lt;/p&gt;</description></item><item><title>Google trie 1 PetaByte de données !</title><link>https://drgoulu.com/2008/11/22/tri/</link><pubDate>Sat, 22 Nov 2008 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2008/11/22/tri/</guid><description>&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt=""
srcset="https://drgoulu.com/posts/2008/images/12217e99baa824ef61d7941a70ea03f7_hu_5f0929e09bf105c7.webp 240w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://drgoulu.com/posts/2008/images/12217e99baa824ef61d7941a70ea03f7_hu_5f0929e09bf105c7.webp"
width="240"
height="161"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
Pour trier un jeu de 72 cartes, je prends une carte de mon jeu mélangé, et je la pose sur la table. J&amp;rsquo;en prends une seconde, et je la place sur la table avant ou après la première selon l&amp;rsquo;ordre que je souhaite. La troisième carte peut aller avant ou après les deux premières, ou être insérée entre les précédentes, et ainsi de suite jusqu&amp;rsquo;à ce que toutes les cartes soient triées dans l&amp;rsquo;ordre sur la table, ce qui me prend un peu plus d&amp;rsquo;une minute.&lt;/p&gt;
&lt;h3 id="un-terabyte-pour-commencer"&gt;Un TeraByte pour commencer&lt;/h3&gt;
&lt;p&gt;Dans le même temps de 68 secondes,
, améliorant d&amp;rsquo;un facteur 3 le
obtenu plus tôt cette année. Suivant les règles du  &amp;ldquo;
&amp;rdquo; proposé par
en 1998, les cartes contenaient 100 bytes, ce qui représente au total un TeraByte, l&amp;rsquo;équivalent, grosso-modo, d&amp;rsquo;un annuaire qui inclurait tous les habitants de la planète.&lt;/p&gt;
&lt;p&gt;Un TeraByte, c&amp;rsquo;est la capacité d&amp;rsquo;un gros disque dur actuel, mais on ne peut y lire ou écrire &amp;ldquo;que&amp;rdquo; 300 MegaByte par seconde : il faudrait au mieux une heure pour lire les donner à trier dans une mémoire de 1000 GigaByte (qui n&amp;rsquo;existe pas&amp;hellip;) et une autre heure pour réécrire la liste triée, sans compter le temps du tri proprement dit . Google a donc utilisé 1000 ordinateurs, et au moins autant de disques durs formant une partie du &amp;ldquo;Google File System&amp;rdquo;
, le gigantesque système de stockage de Google.&lt;/p&gt;
&lt;h3 id="trions-en-parallèle"&gt;Trions en parallèle&lt;/h3&gt;
&lt;p&gt;Mais comment trier les mêmes données à plusieurs? Reprenons le jeu de 72 cartes et divisions le en 2 tas de 36 cartes mélangées, un pour toi, un pour moi. Nous pourrions placer nos cartes sur une seule ligne sur la table et espérer le faire 2 fois plus vite, mais problème peut survenir si nous voulons simultanément insérer nos cartes au même endroit : comment les placer dans le bon ordre dans ce cas ?  Soit on doit alors comparer nos deux cartes et éventuellement les intervertir avant de les insérer, soit on doit convenir d&amp;rsquo;insérer les cartes à tour de rôle, ce qui ralentit considérablement l&amp;rsquo;opération. Avec 1000 ordinateurs, on ne va pas s&amp;rsquo;en sortir beaucoup mieux car c&amp;rsquo;est visiblement l&amp;rsquo;accès à la table (=mémoire), unique, qui forme un goulot d&amp;rsquo;étranglement : pas efficace.&lt;/p&gt;
&lt;p&gt;Une autre approche serait que je trie mes 36 cartes et toi tes 36 cartes indépendamment, puis que nous réunissions nos deux piles triées, ce qui est très rapide : je pose mes cartes une à une tant qu&amp;rsquo;elles viennent avant celle que je vois sur le haut de ta pile, et quand je ne peux plus en poser, tu poses les tiennes tant qu&amp;rsquo;elles viennent avant celle que je ne pouvais plus poser etc.&lt;/p&gt;
&lt;p&gt;On peut faire même mieux en échangeant astucieusement nos cartes plutôt que de reformer une seule pile. Si je trie les carreaux et coeur, et toi les trèfles et pique, plus besoin de reformer une pile unique à la fin : commençons par nous échanger les cartes qui n&amp;rsquo;ont pas la bonne couleur, puis trions nos tas chacun sur notre table, et voilà !&lt;/p&gt;
&lt;figure class="alignright" style="max-width: 280px; width: 100%;"&gt;&lt;img src="https://drgoulu.com/posts/2008/images/d4e5d0a778dba725091d8317e6bac939.gif" alt="Animation de lalgorithme de tri quicksort, nettement plus efficace sur un ordinateur que le tri par insertion" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" /&gt;&lt;figcaption&gt;Animation de l&amp;rsquo;algorithme de tri &amp;quot;quicksort&amp;quot;.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id="quicksort"&gt;QuickSort&lt;/h3&gt;
&lt;p&gt;Voilà qui ressemble furieusement à l&amp;rsquo;
illustré ci-contre : on commence par échanger les données plus grande qu&amp;rsquo;un pivot (seuil bleu) de la première moitié contre celles plus petites que le seuil de la 2ème moitié. Puis on peut répéter l&amp;rsquo;opération entre le premier quart et le second d&amp;rsquo;une part, et le 3ème et le 4ème d&amp;rsquo;autre part, et ainsi de suite. Si on a un nombre de données qui est une puissance de 2, on peut tout trier par simples échanges, et si on dispose aussi d&amp;rsquo;un nombre de processeurs qui soit une puissance de deux, on peut répartir le travail très efficacement. A quelques variations près, c&amp;rsquo;est cet algorithme
qui est utilisé pour trier de très grosses quantités de données.&lt;/p&gt;
&lt;h3 id="mapreduce"&gt;MapReduce&lt;/h3&gt;
&lt;p&gt;S&amp;rsquo;il y a un sujet sur lesquel j&amp;rsquo;aurais du me documenter avant d&amp;rsquo;
, c&amp;rsquo;est
. Le principe est tout simple :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le programmeur écrit :
&lt;ul&gt;
&lt;li&gt;une fonction &amp;ldquo;map&amp;rdquo; qui sera appliquée à chaque donnée et produira un résultat intermédiaire&lt;/li&gt;
&lt;li&gt;une fonction &amp;ldquo;reduce&amp;rdquo; qui regroupera les résultats intermédiaires de &amp;ldquo;map&amp;rdquo; pour produire le résultat final&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;on donne ces deux fonctions à MapReduce, qui se charge de les exécuter de façon efficace sur beaucoup de donnée sur beaucoup de disques durs et beaucoup d&amp;rsquo;ordinateurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le MapReduce de Google contient en fait un algorithme de partitionnement qui répartir les résultats des &amp;ldquo;map&amp;rdquo; sur les &amp;ldquo;reduce&amp;rdquo;, et un algorithme de tri incorporé à la partie &amp;ldquo;Reduce&amp;rdquo;, car les fonctions &amp;ldquo;reduce&amp;rdquo; peuvent presque toujours être rendues plus efficaces si leurs données sont triées. De ce fait, il semblerait que le record du tri ait été obtenu avec une fonction &amp;ldquo;map&amp;rdquo; triviale, et une &amp;ldquo;reduce&amp;rdquo; qui ne l&amp;rsquo;est pas moins!&lt;/p&gt;
&lt;p&gt;MapReduce est probablement la plus géniale idée des ingénieurs de Google, et une contribution majeure à l&amp;rsquo;informatique du futur. Le code n&amp;rsquo;est pas public, mais
.  D&amp;rsquo;autre part la fondation Apache a un
, qui se base sur
, leur équivalent du Google File System. C&amp;rsquo;est en utilisant ce système + 1000 lignes de Java seulement que Yahoo! a pu trier le TeraByte en 209 secondes
. 3x moins bien que Google, c&amp;rsquo;est quand même pas mal du tout&amp;hellip;&lt;/p&gt;
&lt;p&gt;Pour en savoir plus sur MapReduce vous pouvez lire la référence
, et/ou :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;regarder cette vidéo &lt;div class="my-6 mx-auto" style="max-width: 760px; width: 100%;"&gt;
&lt;div class="w-full relative rounded-lg overflow-hidden shadow-md bg-black" style="padding-bottom: 56.25%; height: 0;"&gt;
&lt;iframe
src="https://www.youtube-nocookie.com/embed/NXCIItzkn3E"
title="YouTube video player"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
loading="lazy"&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;consulter ces
, plus techniques, avec exemple de code
et performances&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="et-un-petabyte-un-"&gt;Et un
, un !&lt;/h3&gt;
&lt;p&gt;Une fois qu&amp;rsquo;on a un stockage distribué (GFS), un système de traitement parallèle massif (MapReduce) et quelques milliers d&amp;rsquo;ordinateurs, pourquoi se limiter à trier un TeraByte ? Comme ils le disent dans
, Google était &amp;ldquo;curieux de voir ce qui arrive si on essaie avec un PetaByte&amp;rdquo;. 1000x plus quoi. Juste pour voir&amp;hellip;&lt;/p&gt;
&lt;p&gt;Ca a pris 6 heures et 2 minutes, soit 21720 secondes sur 4000 ordinateurs. Ramené au même nombre d&amp;rsquo;ordinateurs, ça a donc pris &amp;ldquo;seulement&amp;rdquo; 1277x plus de temps pour trier 1000x plus de données. C&amp;rsquo;est assez efficace si l&amp;rsquo;on considère que la complexité d&amp;rsquo;un algorithme comme QuickSort est O(N.log N) : sur un seul ordinateur, trier 1000x plus de données prend théoriquement 1000x10 = 10'000x plus de temps. Mais en répartissant le tri sur 4 fois plus d&amp;rsquo;ordinateurs, on divise ce temps par 4 et en plus on divise par 4 la taille des données : on devrait se retrouver avec 250x8/4 = environ 500x plus de temps. Un facteur 1277 c&amp;rsquo;peut sembler nettement plus, mais c&amp;rsquo;est normal en raison des communications supplémentaires entre les ordinateurs.&lt;/p&gt;
&lt;p&gt;Le tri du PetaByte pose une autre problème intéressant : les données étaient réparties sur 48'000 disques durs et statistiquement, en 6 heures de calcul, au moins un des disques tombe en panne
! Il faut donc que les données triées soient redondantes pour que l&amp;rsquo;on puisse remplacer le disque fautif sans interrompre l&amp;rsquo;exécution du tri, ce qui illustre une autre fonctionnalité remarquable du Google File System &amp;hellip;&lt;/p&gt;
&lt;h3 id="et-après-"&gt;Et après ?&lt;/h3&gt;
&lt;p&gt;Peu de groupes au monde disposent d&amp;rsquo;assez de ressources pour tenter de faire mieux que Google. Mais heureusement, les
sont ouverts à d&amp;rsquo;autres catégories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la catégorie &amp;ldquo;penny&amp;rdquo; consiste à trier le plus de nombres possibles pour un &amp;ldquo;cout&amp;rdquo; d&amp;rsquo;un penny, environ 1.3 centimes d&amp;rsquo;Euro. Le record actuel a été obtenu sur un PC doté d&amp;rsquo;un AMD 64 sous Linux, mais surtout de 4 disques dur SATA, qui a trié 1'812'000 enregistrements de 100 bytes en 2.408 secondes&lt;/li&gt;
&lt;li&gt;la catégorie &amp;ldquo;Minute&amp;rdquo; limite le temps de calcul à 60 secondes. Une machine parallèle du MIT a trié 2.140 Milliards d&amp;rsquo;enregistrements de 100 bytes toujours en 2007.&lt;/li&gt;
&lt;li&gt;la catégorie &amp;ldquo;
&amp;rdquo; me semble plus intéressante au niveau du matériel que du logiciel : il s&amp;rsquo;agit de trier un maximum de nombres par
d&amp;rsquo;énergie consommée par l&amp;rsquo;ordinateur. Le record appartient à un ordinateur portable utilisant un processeur intel Mobile Core 2 Duo doté de 13 (!) disques durs, et qui trie environ 11'300 enregistrements par Joule
. Si les machines de Google avaient la même efficacité énergiétique, le tri du PetyBytes aurait consommé 0.885 GigaJoule, soit 246KWh. Répartis sur 6 jours, ça donne une puissance de 1.7 KW seulement.
. Mais avec 4000 gros PC et 48'000 disques durs, Google est probablemet autour de 20x plus.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="et-les-spaghetti-dans-tout-ça-"&gt;Et les spaghetti dans tout ça ?&lt;/h3&gt;
&lt;p&gt;Je ne peux me résoudre à terminer un article sur le tri sans parler du
qui m&amp;rsquo;avait émerveillé il y a près de 25 ans déjà
.&lt;/p&gt;
&lt;p&gt;Comme on l&amp;rsquo;a vu plus haut, les meilleurs algorithmes de tri existant ont une complexité O(N.Log N) : le temps de calcul augmente plus vite que le nombre des données, et malgré quelques progrès dus à la parallélisation, il n&amp;rsquo;existe pas de tri informatique général* en O(N).&lt;/p&gt;
&lt;p&gt;Pourtant, des spaghettis pourraient réussir là où les
patinent :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;on coupe un spaghetti à une longueur représentant le premier enregistrement à trier ramené à un nombre. On coupe un autre spaghetti à la longueur du second nombre, et ainsi de suite pour tous les nombres, et en un temps O(N) on obtient N spaghettis.&lt;/li&gt;
&lt;li&gt;on pose verticalement la botte de spaghettis sur une table plane de façon à tasser tous les spaghettis contre la table. Ceci prend un temps constant, très court et indépendant de N et ne compte donc pas dans la complexité globale&lt;/li&gt;
&lt;li&gt;En posant une planche enduite de colle sur la botte, on extrait le spaghetti le plus long, on le mesure, on retransforme le nombre en une donnée qu&amp;rsquo;on écrit au bas de la liste triée et on recommence N fois, pour chaque spaghetti.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Voilà, les spaghettis permettent de trier nos enregistrements en un temps proportionnel à N ! Trier 1000x plus de spaghettis prendra exactement 1000x plus de temps. En fait, si on disposait d&amp;rsquo;une machine capable de couper puis de mesurer 150 millions de spaghetti à la seconde, elle aurait égalé la machine de Google sur le TeraByte, et l&amp;rsquo;aurait battu sur le PetaByte, en 18.8 heures seulement :-)&lt;/p&gt;
&lt;p&gt;Plus sérieusement, si on a besoin de trier des objets physiques (des grains de sable, des protéines, des ADN ?), il pourrait être intéressant de ne pas oublier la leçon des spaghetti : certains dispositifs physiques peuvent être plus rapides que les plus puissants ordinateurs
&lt;/p&gt;
&lt;h3 id="références"&gt;Références&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span id="ref-1"&gt;&lt;/span&gt;Sanjay Ghemawat, Howard Gobioff, and Shun-Tak Leung &amp;ldquo;
&amp;rdquo;, 19th ACM Symposium on Operating Systems Principles, Lake George, NY, October, 2003.&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-2"&gt;&lt;/span&gt;Jeffrey Dean and Sanjay Ghemawat, &amp;ldquo;
&amp;rdquo; OSDI'04: Sixth Symposium on Operating System Design and Implementation, San Francisco, CA, December, 2004.&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-3"&gt;&lt;/span&gt;Jim Wyllie, &amp;ldquo;
&amp;rdquo;, IBM, February 4, 1999&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-4"&gt;&lt;/span&gt;Owen O’Malley, &amp;ldquo;
&amp;rdquo;, Yahoo!, May 2008&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-5"&gt;&lt;/span&gt;
: records de tri de données depuis 1987&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-6"&gt;&lt;/span&gt;“
“  Datamation, V 31.7, April 1985, pp 112-118.&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-7"&gt;&lt;/span&gt;Eduardo Pinheiro, Wolf-Dietrich Weber and Luiz André Barroso, &amp;ldquo;
&amp;rdquo;, Google Inc. Proceedings of the 5th USENIX Conference on File and Storage Technologies (FAST’07), February 2007.&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-8"&gt;&lt;/span&gt;Suzanne Rivoire et al. &amp;ldquo;
&amp;quot;,SIGMOD’07, June 11–14, 2007, Beijing, China&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-9"&gt;&lt;/span&gt;Dewdney, A. K.&amp;ldquo;On the spaghetti computer and other analog gadgets for problem solving&amp;rdquo;, Scientific American, (June 1984), 250 (6): 19-26&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-10"&gt;&lt;/span&gt;Niall Murphy et al. &amp;ldquo;
&amp;rdquo;,
,2008, Vol 4 nr 1, pages 3-12&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Note* : il existe des algorithmes de tri de complexité linéaire sur des données satisfaisant certaines hypothèses, comme Hervé me l&amp;rsquo;a fait remarquer dans un commentaire&lt;/em&gt;&lt;/p&gt;</description></item></channel></rss>