<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Algorithmes | Dr. Goulu</title><link>https://drgoulu.com/tags/algorithmes/</link><atom:link href="https://drgoulu.com/tags/algorithmes/index.xml" rel="self" type="application/rss+xml"/><description>Algorithmes</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>fr-FR</language><lastBuildDate>Mon, 26 Jun 2017 00:00:00 +0000</lastBuildDate><image><url>https://drgoulu.com/media/icon_hu_eee4a95885829ab2.png</url><title>Algorithmes</title><link>https://drgoulu.com/tags/algorithmes/</link></image><item><title>Suites infinies en Python</title><link>https://drgoulu.com/2017/06/26/series-infinies-et-oeis-en-python/</link><pubDate>Mon, 26 Jun 2017 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2017/06/26/series-infinies-et-oeis-en-python/</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/2017/images/E6fJJ_hu_3b7898a4ec4efc1d.webp 320w, https://drgoulu.com/posts/2017/images/E6fJJ_hu_85290121cecac221.webp 480w, https://drgoulu.com/posts/2017/images/E6fJJ_hu_a5739bbe4b0b5dde.webp 600w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://drgoulu.com/posts/2017/images/E6fJJ_hu_3b7898a4ec4efc1d.webp"
width="600"
height="500"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
Depuis que je programme en Python, j&amp;rsquo;entasse les petits bouts de code utiles ou potentiellement réutilisables dans &amp;ldquo;Goulib&amp;rdquo;, ma librairie perso et néanmoins disponible en open-source (licence LGPL)  sur
, 
, ReadTheDocs pour
, avec des
&lt;/p&gt;
&lt;p&gt;Comme la valeur d&amp;rsquo;un code se mesure surtout par les tests qui vérifient son bon fonctionnement, je me suis lancé dans un ambitieux projet (de plus&amp;hellip;) : tester un maximum de fonctions de mes modules
et
 en calculant des suites de l&amp;rsquo; 
, plus connue sous son acronyme anglais OEIS.&lt;/p&gt;
&lt;p&gt;Pour cela j&amp;rsquo;ai fait un truc dont je suis vachement fier* :&lt;/p&gt;
&lt;h2 id="la-classe-sequence"&gt;La classe Sequence&lt;/h2&gt;
&lt;p&gt;Ce
(
) permet de représenter une
(sequence en anglais) finie ou infinie de nombres** à partir d&amp;rsquo;&amp;lsquo;une ou plusieurs fonctions passées à
:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iterf : un
ou générateur produisant les termes de la suite l&amp;rsquo;un après l&amp;rsquo;autre&lt;/li&gt;
&lt;li&gt;itemf : une fonction  retournant le i-ème paramètre de la suite&lt;/li&gt;
&lt;li&gt;containf : une fonction renvoyant vrai (True) si son paramètre appartient à la suite.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On peut créer par exemple la série (infinie) des nombres premiers ainsi :&lt;/p&gt;
&lt;p&gt;
=Sequence(containf=
)&lt;/p&gt;
&lt;p&gt;Ensuite, l&amp;rsquo;objet ainsi créé avec n&amp;rsquo;importe quelle combinaison de ces 3 paramètres peut être utilisé indifféremment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;comme un générateur : for p in A000040() : print(p) # affiche les nombres premiers (jusqu&amp;rsquo;à l&amp;rsquo;infini)&lt;/li&gt;
&lt;li&gt;comme une liste: A000040
\[999\]# renvoie le 1000ème nombre premier (parce que Python indice à partir de 0&amp;hellip;)&lt;/li&gt;
&lt;li&gt;comme un ensemble: 201420142013 in A000040 # renvoie True car ce nombre est premier.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Evidemment, si on dispose de fonctions plus efficaces pour chacun de ces paramètres, on peut les utiliser pour rendre les calculs bien plus rapides. Par exemple pour la suite de Fibonacci, on peut exploiter trois algorithmes différents :&lt;/p&gt;
&lt;p&gt;
=Sequence(iterf=
, itemf=
, containf=
)&lt;/p&gt;
&lt;p&gt;En passant, voici comment est définie la séquence &amp;ldquo;auto descriptrice&amp;quot;qui orne la bannière de l&amp;rsquo;OEIS ci-dessus:&lt;/p&gt;
&lt;p&gt;
=Sequence( 
( lambda x: 
( 
( 
( 
( 
(x))))) ,1))&lt;/p&gt;
&lt;p&gt;Compact et presque clair, non ?&lt;/p&gt;
&lt;h2 id="dérivation"&gt;Dérivation&lt;/h2&gt;
&lt;p&gt;Une Sequence peut être dérivée d&amp;rsquo;une autre grâce à plusieurs méthodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
renvoie une Sequence correspondant à la Sequence source filtrée par une fonction. Par exemple:
=A000040.filter(
) renvoie les &amp;ldquo;exposants de Mersenne&amp;rdquo;, les nombres premiers p tels que $2^p - 1$ est premier.&lt;/li&gt;
&lt;li&gt;
applique une fonction à chaque terme de la Sequence source. Par exemple la série des carrés des nombres premiers peut se définir ainsi:
=A000040.apply(lambda n:n*n)&lt;/li&gt;
&lt;li&gt;Pour éviter l&amp;rsquo;utilisation d&amp;rsquo;apply dans des cas trivialement simples, l&amp;rsquo;addition (et la soustraction) d&amp;rsquo;une Sequence et d&amp;rsquo;un entier sont définies. Par exemple:
=
+1 définit les
à partir des nombres de la forme $2^{2^n}$&lt;/li&gt;
&lt;li&gt;
renvoie une Sequence dont le n-ième terme est obtenu en sommant les n premiers termes de la Sequence source:
=A000040.accumulate()&lt;/li&gt;
&lt;li&gt;
renvoie une Sequence produite en appliquant applique une fonction à chaque paire de termes consécutifs. Ainsi la suite des différences entre nombres premiers consécutifs s&amp;rsquo;écrit:
=A000040.pairwise(operator.sub)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On peut aussi combiner deux Sequences pour en créer une nouvelle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;L&amp;rsquo;opérateur % (modulo, pourquoi pas&amp;hellip;) renvoie les termes de la Sequence opérande de gauche qui ne sont PAS dans l&amp;rsquo;opérande de droite. Ainsi:
=A000040 %
définit la Sequence des nombres premiers qui ne sont pas 
&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;opérateur &amp;amp; (and) renvoie les termes de la Sequence opérande de gauche qui sont aussi dans l&amp;rsquo;opérande de droite. Ainsi:
=
&amp;amp; A000040 définit la suite des nombres premiers dont qui ne s&amp;rsquo;écrivent qu&amp;rsquo;avec des 0 et des 1.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;opérateur | (or) renvoie la fusion de deux séquences à l&amp;rsquo;aide du génial
. Ainsi:
=
|
définit les nombres ayant 4 diviseurs (dont 1 et eux-mêmes) comme l&amp;rsquo;union de ceux qui sont le produit de deux nombres premiers avec ceux qui sont le cube d&amp;rsquo;un nombre premier.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il y a encore deux méthodes un peu &amp;ldquo;tirées par les cheveux&amp;rdquo; du point de vue mathématique, mais qui fonctionnent très bien informatiquement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
 renvoie une Sequence
(par défaut) en triant les termes de la Sequence d&amp;rsquo;origine. Par exemple, voici la suites des surfaces des
 dans l&amp;rsquo;ordre croissant:
=Sequence(math2.primitive_triples).apply(lambda x:x
\[0\]*x
\[1\]//2) .sort()&lt;/li&gt;
&lt;li&gt;
 renvoie une Sequence où les termes redondants de la suite d&amp;rsquo;origine sont absents, par exemple:
 =
 .unique() // oui, parce que le 5 appartient à deux paires de nombres premiers jumeaux &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ces méthodes utilisent respectivement 
 et 
 qui fonctionnent tant que la suite initiale est &amp;ldquo;presque&amp;rdquo; triée, à savoir tant que l&amp;rsquo;écart n entre un terme $a_i+n \leq a_i$ n&amp;rsquo;excède pas le paramètre &amp;ldquo;buffer&amp;rdquo; de la fonction. On peut évidemment trouver des suites qui ne pourront &amp;ldquo;mathématiquement&amp;rdquo; pas être traitées ainsi, mais informatiquement j&amp;rsquo;arrive à reproduire les suites de l&amp;rsquo;OEIS rencontrées jusqu&amp;rsquo;ici avec buffer=100 seulement&lt;/p&gt;
&lt;h2 id="le-dictionnaire-oeis"&gt;Le dictionnaire OEIS&lt;/h2&gt;
&lt;p&gt;J&amp;rsquo;ai ainsi constitué peu à peu le fichier 
 qui définit actuellement environ 150 séries de l&amp;rsquo;OEIS, et que j&amp;rsquo;étoffe lorsque l&amp;rsquo;occasion se présente. A la fin de ce module, j&amp;rsquo;utilise la géniale possibilité d&amp;rsquo;introspection de Python pour regrouper toutes les Sequence définies dans un dictionnaire fort utile pour les tests:&lt;/p&gt;
\[python\]&lt;p&gt;# Construit le dictionnaire OEIS par introspection : Simple et WOW ! oeis={} # on crée le dictionnaire vide seqs=globals().copy() # on copie tous les objets déclarés dans ce module for id in seqs: # on parcourt tous les identificateurs des objets if id&lt;/p&gt;
\[0\]&lt;p&gt;==&amp;lsquo;A&amp;rsquo; and len(id)==7: # et s&amp;rsquo;ils ont un nom de séquence OEIS &amp;hellip; oeis&lt;/p&gt;
\[id\]&lt;p&gt;=seqs&lt;/p&gt;
\[id\]&lt;p&gt; # on les ajoute au dictionnaire &amp;hellip; seqs&lt;/p&gt;
\[id\]&lt;p&gt;.name=id # et on définit leur champ name &lt;/p&gt;
\[/python\]&lt;h2 id="performance"&gt;Performance&lt;/h2&gt;
&lt;p&gt;Un point important est qu&amp;rsquo;aucun calcul n&amp;rsquo;est effectué lors des opérations ci-dessus. Ce n&amp;rsquo;est qu&amp;rsquo;au moment d&amp;rsquo;utiliser les Sequence ainsi définies que les fonctions iterf, itemf, containf et leurs éventuelles compositions sont évaluées.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est un peu &amp;ldquo;automagique&amp;rdquo;, mais il faut tout de même veiller à utiliser les algorithmes les plus efficaces, et c&amp;rsquo;est même un des buts que je poursuis avec ce projet. Par exemple la suite des nombres premiers dont qui ne s&amp;rsquo;écrivent qu&amp;rsquo;avec des 0 et des 1
=
&amp;amp; A000040 aurait pu s’écrire également: A020449=A000040 &amp;amp; A007088 mais la première formulation est beaucoup plus rapide car la série A007088 des nombres ne s&amp;rsquo;écrivant qu&amp;rsquo;avec des 0 et des 1 croît beaucoup plus vite que celle des nombres premiers A000040. Il est par conséquent beaucoup plus rapide de tester si les nombres du genre 1101010101011101 sont premiers que d&amp;rsquo;énumérer tous les nombres premiers de 16 chiffres et de jeter ceux qui contiennent d&amp;rsquo;autres chiffres que des 0 ou 1.&lt;/p&gt;
&lt;p&gt;Malgré toutes ces précautions, parcourir une suite infinie prendra forcément un temps infini, et ces idiots d&amp;rsquo;ordinateurs ne sont toujours pas foutus de gérer le
. J&amp;rsquo;ai donc écrit un
 qui limite le temps de calcul d&amp;rsquo;une boucle ainsi :&lt;/p&gt;
&lt;p&gt;for x in
(suite,1): print(x) # affiche tous les termes calculables en 1 seconde (au total)&lt;/p&gt;
&lt;p&gt;Ce décorateur est utilisé en particulier dans
 la fonction appelée par 
 pour afficher les dix premiers termes d&amp;rsquo;une Sequence, ou du moins ceux qu&amp;rsquo;on peut calculer en moins d&amp;rsquo;une seconde.&lt;/p&gt;
&lt;p&gt;Les suites particulièrement lentes sont par exemple
ou 
 dont le n-ième terme donne le nombre de nombres inférieurs à 10^n  satisfaisant une certaine condition. Faute de meilleur algorithme, chaque terme prend 10x plus de temps que le précédent &amp;hellip;&lt;/p&gt;
&lt;h2 id="tests"&gt;Tests&lt;/h2&gt;
&lt;p&gt;Voià, tous les ingrédients sont prêts pour tester si mes beaux algorithmes fonctionnent correctement, ce qui était le but initial je le rappelle.&lt;/p&gt;
&lt;p&gt;Pour ceci, il suffit de vérifier que chaque Sequence fournit bien les mêmes termes que ceux disponibles dans l&amp;rsquo;OEIS. Ceci est facilité par le fait que l&amp;rsquo;OEIS fournit pour chaque suite les n premières valeurs dans un fichier texte en
accessible par le web. Par exemple 
 fournit les 10'000 premiers nombres premiers.&lt;/p&gt;
&lt;p&gt;Donc mon fichier 
 est lui aussi génialement simple* : il traverse le dictionnaire oeis et pour chaque Sequence il télécharge les N termes de référence du site OEIS, vérifie que les n premiers termes de la Sequence sont bien ceux attendus, et produit une erreur sinon. Ou un avertissement si itimeout a limité n à moins de 10.&lt;/p&gt;
&lt;p&gt;Ces tests sont automatiquement exécutés (avec beaucoup d&amp;rsquo;autres)
chaque fois que je pousse une nouvelle version de
, ce qui fait que je suis averti si modification crée un problème avec une ancienne version de Python ou si un Pingouin détecte un problème invisible de mes Fenêtres.&lt;/p&gt;
&lt;h2 id="débogage-de-loeis-"&gt;Débogage&amp;hellip; de l&amp;rsquo;OEIS !&lt;/h2&gt;
&lt;p&gt;J&amp;rsquo;ai ainsi beaucoup débogué, amélioré et optimisé la plupart des fonctions de  
et beaucoup d&amp;rsquo;
, et je compte poursuivre dans cette voie qui permet d&amp;rsquo;utiliser les données de l&amp;rsquo;OEIS comme une référence, validées par de nombreux utilisateurs.&lt;/p&gt;
&lt;p&gt;Sauf que des fois, le bug était chez eux. Et je ne suis pas peu fier d&amp;rsquo;
sur l&amp;rsquo;OEIS :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
 , comme déjà mentionné dans
, le 20ème terme de la série est 145, pas 142.&lt;/li&gt;
&lt;li&gt;
, dont certains termes avaient besoins de 0 supplémentaires. Tant qu&amp;rsquo;à faire j&amp;rsquo;ai fourni un B-file contenant les 1000 premiers termes exacts pour remplacer l&amp;rsquo;ancien qui n&amp;rsquo;en avait que 500.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A cette occasion j&amp;rsquo;ai remarqué que l&amp;rsquo;édition de l&amp;rsquo;OEIS est un peu rébarbative, ce qui peut décourager les contributeurs débutants. Peut-être que mon modeste projet pourrait servir de base à un site plus interactif, utilisant du code (Python of course) pour calculer dynamiquement les suites requises &amp;hellip;&lt;/p&gt;
&lt;p&gt;Ce long article mijoté pendant plus de six mois se termine par un appel aux allumés du code bonnes volontés : si cet article vous a motivé , n&amp;rsquo;hésitez pas à contribuer à la Goulib sur GitHub.&lt;/p&gt;
&lt;p&gt;Pour ma part je m&amp;rsquo;attaque aux
et
qui seront l&amp;rsquo;occasion de nettoyer le code du 
  en utilisant et testant le module 
&lt;/p&gt;
&lt;h3 id="notes"&gt;Notes&lt;/h3&gt;
&lt;p&gt;*sinon je n&amp;rsquo;en parlerais pas ici&amp;hellip; **ou d&amp;rsquo;autres objets mais je n&amp;rsquo;ai pas encore trouvé quoi&amp;hellip;&lt;/p&gt;</description></item><item><title>Comment calculer le 10'000'000'000'000'000'000 ème terme de la suite de Fibonacci</title><link>https://drgoulu.com/2017/04/25/comment-calculer-le-1e19-eme-terme-de-la-suite-de-fibonacci/</link><pubDate>Tue, 25 Apr 2017 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2017/04/25/comment-calculer-le-1e19-eme-terme-de-la-suite-de-fibonacci/</guid><description>&lt;p&gt;Tombé l&amp;rsquo;autre jour sur un problème idiot
mais intéressant : calculer le 1019 ème terme de la
. Idiot parce que ça ne sert à rien. Intéressant parce que ça sous-entend qu&amp;rsquo;il existe une manière de calculer le n-ième terme de cette suite définie par récurrence sans calculer tous les termes précédents. En effet, calculer les termes les uns après les autres prendrait dans les 300'000 ans à raison d&amp;rsquo;une microseconde par terme&amp;hellip;&lt;/p&gt;
&lt;h2 id="un-nombre-dor-mais-flottant"&gt;Un nombre d&amp;rsquo;or, mais flottant&lt;/h2&gt;
&lt;p&gt;Comme même les ésotéristes le savent, la suite de Fibonacci est liée au
 A partir de ce fait, Moivre, Euler et Binet ont indépendamment obtenu ce qu&amp;rsquo;on appelle aujourd&amp;rsquo;hui la
, et qui donne directement le n-ième terme de la suite:&lt;/p&gt;
&lt;p&gt;$\mathcal F_n=\frac1{\sqrt5}(\varphi^n-\varphi'^n)$, avec $ \varphi=\frac{1+\sqrt5}2$, et $ \varphi'=-\frac1\varphi$ .&lt;/p&gt;
&lt;p&gt;En pratique, le terme en $ \varphi'$ devient rapidement négligeable et il suffit de chercher l&amp;rsquo;entier le plus proche de $\frac{\varphi^n}{\sqrt5}$. Par exemple pour n=50, on peut calculer très vite $\mathcal F_{50}\approx\frac{\varphi^{50}}{\sqrt5}$ = 12586269025&lt;/p&gt;
&lt;p&gt;Mais on se heurte rapidement au problème de la précision de calcul en nombres flottants sur nos ordinateurs : $\varphi$ étant
(mais pas aussi
que $\pi$ &amp;hellip;), il faut calculer $\varphi^n$ avec au moins autant de décimales que $\mathcal F_n$ comporte de chiffres. Dès n=71 on dépasse les 53 bits de la mantisse des nombres &amp;ldquo;extended precision&amp;rdquo; et les dernières décimales des termes calculés sont faux.&lt;/p&gt;
&lt;p&gt;Dit autrement, à partir de n=70 la division $\mathcal F_n/\mathcal F_{n-1}$ donne au moins autant de décimales de $ \varphi$ que son calcul en nombres flottants&lt;/p&gt;
&lt;h2 id="la-matrice-salvatrice"&gt;La Matrice salvatrice&lt;/h2&gt;
&lt;p&gt;Pour une méthode de calcul en nombres entiers atteignant (presque) la rapidité de la formule de Binet, il faut utiliser l&amp;rsquo;idée d&amp;rsquo;un certain Brenner : écrire la récurrence de Fibonacci sous forme matricielle
. La matrice toute simple $Q=\begin{pmatrix}1&amp;1\\\\1&amp;0\end{pmatrix}$ permet d&amp;rsquo;obtenir un nouveau terme de la série de Fibonacci en la multipliant par un vecteur formé des deux termes précédents:&lt;/p&gt;
&lt;p&gt;$\begin{pmatrix}1&amp;1\\\\1&amp;0\end{pmatrix}\begin{pmatrix}\mathcal F_{n-1}\\\\\mathcal F_{n-2}\end{pmatrix}=\begin{pmatrix}\mathcal F_{n}\\\\\mathcal F_{n-1}\end{pmatrix}$&lt;/p&gt;
&lt;p&gt;En enchaînant les multiplications matricielles, on obtient le n-ième terme à partir des deux premiers (0,1) ainsi :&lt;/p&gt;
&lt;p&gt;$\begin{pmatrix}1&amp;1\\\\1&amp;0\end{pmatrix}^{n-1}\begin{pmatrix}1\\\\0\end{pmatrix}=\begin{pmatrix}\mathcal F_{n}\\\\\mathcal F_{n-1}\end{pmatrix}$&lt;/p&gt;
&lt;p&gt;En fait on retrouve les termes de la suite directement dans la matrice  $Q^n = \begin{pmatrix}\mathcal F_{n+1}&amp;\mathcal F_{n}\\\\\mathcal F_{n}&amp;\mathcal F_{n-1}\end{pmatrix}$.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;algorithme de l&amp;rsquo;
permet d&amp;rsquo;élever la matrice Q à la puissance n en effectuant log2(n) multiplications de matrices 2x2, soit
pour n=1019. Ultra rapide, et facilement généralisable à d&amp;rsquo;autres formules de récurrence !&lt;/p&gt;
&lt;p&gt;Malheureusement, la fonction
 souffre d&amp;rsquo;une
qui empêche de l&amp;rsquo;utiliser dès n=71 car elle utilise les nombres flottants. Il m&amp;rsquo;a donc fallu la réécrire, en résolvant une petite contrainte technologique au passage.&lt;/p&gt;
&lt;h2 id="vers-les-pétaoctets-et-au-delà-"&gt;Vers les pétaoctets et au delà &amp;hellip;&lt;/h2&gt;
&lt;p&gt;Il se trouve que le 1019-ième terme de la suite de Fibonacci est trop grand pour tenir dans le plus super des ordinateurs. En effet, la longueur du n-ième terme de la suite s&amp;rsquo;obtient facilement en prenant le log (base 10)  de la formule de Binet : $\mathcal L_n=\lceil n\log{\varphi}\rceil$ , soit grosso-modo n*0.208987640249978733769272089237555416822459239918210953539&amp;hellip;&lt;/p&gt;
&lt;p&gt;Vérifions. Pour n=1000, on obtient:&lt;/p&gt;
&lt;p&gt;$\mathcal F_{1000}$=43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875 qui comporte bien pile 209 chiffres.&lt;/p&gt;
&lt;p&gt;Donc $\mathcal F_{10^{19}}$ comporte 2089876402499787337 chiffres &amp;hellip; Il faudrait 
 
octets de RAM (de préférence&amp;hellip;) pour stocker ce nombre &amp;hellip;&lt;/p&gt;
&lt;figure class="alignright" style="max-width: 500px; width: 100%;"&gt;&lt;img src="https://drgoulu.com/posts/2017/images/1nv66i_hu_7b93cc781b3ade88.webp" srcset="https://drgoulu.com/posts/2017/images/1nv66i_hu_7b93cc781b3ade88.webp 320w, https://drgoulu.com/posts/2017/images/1nv66i_hu_b71a7d5dd930ae.webp 480w, https://drgoulu.com/posts/2017/images/1nv66i_hu_8e32ab0b43c8315.webp 500w" sizes="(max-width: 640px) 100vw, 500px" alt="(mon premier meme ... désolé ...)" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;figcaption&gt;(mon premier meme &amp;hellip; désolé &amp;hellip;)&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id="et-modulo1000000007-"&gt;Et modulo 1000000007 ?&lt;/h2&gt;
&lt;p&gt;Fort heureusement, le problème idiot avait un petit détail en prime : il fallait calculer le résultat
1000000007, et ça, ça change tout.&lt;/p&gt;
&lt;p&gt;Ce nombre est premier (pour que ça soit plus intéressant), mais surtout il est inférieur à 230, ce qui fait que la multiplication modulo 1000000007 ne nécessite que des opérations sur des 
32 bits (signés), ultra rapide.&lt;/p&gt;
&lt;p&gt;Voici donc quelques fonctions Python tirées du
 qui effectuent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le produit matriciel, optionnellement modulaire&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;exponentiation rapide d&amp;rsquo;une matrice, optionnellement modulaire, et qui corrige le bug de numpy.matrix_power&lt;/li&gt;
&lt;li&gt;le calcul quasi instantané du n-ième terme de la série de Fibonacci, avec une option modulaire vivement recommandée pour de grands n&lt;/li&gt;
&lt;/ul&gt;
\[gist id="f56725fa32fbb4840c855a8309662c9d"\]&lt;p&gt;Avec ça on obtient fibonacci(int(1E19),1000000007) = 647754067 ce qui nous fait une belle jambe,  mais nous a appris pas mal de choses intéressantes, non ?&lt;/p&gt;
&lt;p&gt;Prochaine étape : trouver la
correspondante &amp;hellip;&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;
 sur StackOverflow (et
qui m&amp;rsquo;a inspiré cet article)&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-2"&gt;&lt;/span&gt;Weisstein, Eric W. &amp;ldquo;
.&amp;rdquo; From MathWorld&amp;ndash;A Wolfram Web Resource.&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-3"&gt;&lt;/span&gt;Arthur Charpentier &amp;ldquo;
, 2016 sur Freakonometrics (mention spéciale pour l&amp;rsquo;image de la spirale&amp;hellip;)&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Répartition proportionnelle</title><link>https://drgoulu.com/2013/12/02/repartition-proportionnelle/</link><pubDate>Mon, 02 Dec 2013 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2013/12/02/repartition-proportionnelle/</guid><description>&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="problème d&amp;rsquo;arrondi 99%"
srcset="https://drgoulu.com/posts/2013/images/2013-11-18_201919_hu_5a85885c885e7716.webp 215w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://drgoulu.com/posts/2013/images/2013-11-18_201919_hu_5a85885c885e7716.webp"
width="215"
height="129"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
Voici un petit problème qui se présente assez fréquemment sous diverses formes, et pour lequel j&amp;rsquo;ai été surpris de ne pas trouver de solution bien documentée.&lt;/p&gt;
&lt;p&gt;Le cas le plus simple apparaît souvent dans les tableurs : en calculant des pourcentages arrondis, le total ne fait parfois pas 100%. En effet, rien ne garantit que les arrondis &amp;ldquo;vers le haut&amp;rdquo; compensent ceux &amp;ldquo;vers le bas&amp;rdquo;. Autrement dit, une somme d&amp;rsquo;arrondis n&amp;rsquo;est pas égale à la somme arrondie.&lt;/p&gt;
&lt;p&gt;Autre exemple assez différent en apparence. Un berger veut répartir ses 
 moutons sur sa parcelle carrée d&amp;rsquo;un hectare où il veut faire paître a moutons, son parc rond de π hectares qui peut en accueillir b, et les c restants sur la parcelle louée à son voisin le père Néper, qui fait
hectares, de manière à ce que chaque mouton ait la même surface à brouter. Sur les conseils de l&amp;rsquo;instituteur du village, il commence par écrire la petite équation a.(1+π+e) = 1548 pour obtenir a = 225.66 puis b=708.93 et c=613.41, mais ensuite, comment arrondir chacun de ces nombres vers le haut ou le bas de façon à obtenir exactement un total de 1548 et que les rapports b/a et c/a restent respectivement proches de π et de e ?&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est en planchant sur un problème de ce type que m&amp;rsquo;est venue une idée : utiliser une méthode du
 !&lt;/p&gt;
&lt;p&gt;Certains parlements comme le
sont élus à la &amp;ldquo;proportionnelle par liste&amp;rdquo; : le nombre de sièges étant fixé, on commence par répartir ces sièges entre les partis proportionnellement aux nombre de listes portant l&amp;rsquo;entête d&amp;rsquo;un parti choisies par les électeurs. Dans une deuxième phase, les n candidats ayant reçu le plus de voix de chaque parti sont élus aux n sièges attribués à leur parti, mais ceci n&amp;rsquo;est pas le sujet ici.&lt;/p&gt;
&lt;p&gt;La phase de répartition des sièges entre partis rencontre exactement les difficultés liées aux arrondis mentionnées plus haut, et comme l&amp;rsquo;enjeu est d&amp;rsquo;importance politique, le problème a été non seulement étudié depuis longtemps, mais les solutions sont mêmes formalisées dans les lois régissant le système électoral de bon nombre d&amp;rsquo;Etats (voir
par exemple). Le hic, c&amp;rsquo;est qu&amp;rsquo;il n&amp;rsquo;y a pas une seule solution définitive mais plusieurs, chacune avec ses avantages et inconvénients.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright" style="max-width: 256px; width: 100%;"&gt;&lt;a href="http://www.madore.org/~david/weblog/2009-06.html#d.2009-06-10.1650" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2013/images/7578a0ca33df1f5abcb0b7798361c72b_hu_1ff38e46472e6008.webp" srcset="https://drgoulu.com/posts/2013/images/7578a0ca33df1f5abcb0b7798361c72b_hu_1ff38e46472e6008.webp 320w, https://drgoulu.com/posts/2013/images/7578a0ca33df1f5abcb0b7798361c72b_hu_84f0211333e8c757.webp 480w, https://drgoulu.com/posts/2013/images/7578a0ca33df1f5abcb0b7798361c72b_hu_7212d0bae7f8e8fa.webp 511w" sizes="(max-width: 640px) 100vw, 256px" alt="Représentation graphique de la méthode de Hare avec 3 partis [[2]](#ref-2)" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;/a&gt;&lt;figcaption&gt;Représentation graphique de la méthode de Hare avec 3 partis&lt;/figcaption&gt;&lt;/figure&gt;
La &amp;ldquo;méthode de
&amp;rdquo; est la plus simple des méthodes dites &amp;ldquo;du plus fort reste&amp;rdquo;. On commence par calculer un &amp;ldquo;quotient électoral&amp;rdquo; en divisant le nombre total de votes valides par le nombre de sièges à pourvoir. Dans le cas d&amp;rsquo;une élection on obtient en principe un nombre assez grand, mais pour les prés de notre berger, on a: q = (1+π+e)/1548 = 0.004431 , ce qui n&amp;rsquo;est autre que la surface à brouter par chaque mouton.&lt;/p&gt;
&lt;p&gt;Puis on effectue la
(ou entière) du nombre de votes obtenus par chaque parti par ce nombre q. Peu importe que dans notre cas, les votes soient remplacés par des nombres réels, l&amp;rsquo;important est que l&amp;rsquo;on souhaite diviser un nombre entier en entiers suivant cette proportion.&lt;/p&gt;
&lt;p&gt;On commence par ne considérer que les quotients des divisions entières (notées // en Python) et assigner a = 1//q = 225, b = π//q = 708 et c = e//q = 613 moutons aux trois champs. Mais a+b+c ne totalisant que 1546 moutons, il reste à attribuer les moutons restants aux deux &amp;ldquo;plus fort restes&amp;rdquo; des divisions entières. Dans notre cas, 1-a.q = 0.0029, π-b.q = 0.0041 et e-c.q = 0.0018, donc on alloue un mouton de plus aux champs b et a pour obtenir finalement a=226, b=709 et c=613.&lt;/p&gt;
&lt;p&gt;La méthode de Hare souffre d&amp;rsquo;un défaut appelé
 : le fait d&amp;rsquo;augmenter de 1 le nombre de sièges/moutons peut dans certains cas faire diminuer de 1 le nombre alloué à l&amp;rsquo;un des partis/prés, ce qui est illogique. De plus, la méthode de Hare avantage les petits partis qui pourraient gagner leur seul élu au plus fort reste. Les grands partis pourraient même être tentés de déposer plusieurs listes
 pour gagner des sièges, c&amp;rsquo;est pourquoi les législations introduisent souvent un quorum ou &amp;ldquo;seuil de représentativité&amp;rdquo; sous la forme d&amp;rsquo;un pourcentage minimum de votes à atteindre pour qu&amp;rsquo;une liste soit prise en considération*.&lt;/p&gt;
&lt;p&gt;On peut diminuer la probabilité d&amp;rsquo;apparition de ces défauts à l&amp;rsquo;aide d&amp;rsquo;une astuce due à
 (1833-1910), scientifique suisse qui proposa de calculer le &amp;ldquo;quotient électoral&amp;rdquo; en divisant le nombre total de votes valides par le nombre de sièges à pourvoir augmenté de 1. Le &amp;ldquo;quotient de Hagenbach-Bischoff&amp;rdquo; vaut dans notre cas  q = (1+π+e)/(1548+1) = 0.004429. La différence par rapport à la méthode de Hare est très faible, mais suffit à répartir 225+709+613=1547 moutons du premier coup, n&amp;rsquo;en laissant qu&amp;rsquo;un à attribuer au parti/pré a puisqu&amp;rsquo;il présente le reste de division le plus élevé, ce qui nous donne le même résultat qu&amp;rsquo;Hare dans ce cas précis : a=226, b=709 et c=613&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright" style="max-width: 256px; width: 100%;"&gt;&lt;a href="http://www.madore.org/~david/weblog/2009-06.html#d.2009-06-10.1650" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2013/images/702521c7f4a83b8930179de63280619a_hu_ae9bdda36ae9f33d.webp" srcset="https://drgoulu.com/posts/2013/images/702521c7f4a83b8930179de63280619a_hu_ae9bdda36ae9f33d.webp 320w, https://drgoulu.com/posts/2013/images/702521c7f4a83b8930179de63280619a_hu_eb9efe622e2686ca.webp 480w, https://drgoulu.com/posts/2013/images/702521c7f4a83b8930179de63280619a_hu_20fd22353aba00b0.webp 511w" sizes="(max-width: 640px) 100vw, 256px" alt="Représentation graphique de la méthode D&amp;#39;Hondt avec 3 partis  [[2]](#ref-2)" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;/a&gt;&lt;figcaption&gt;Représentation graphique de la méthode D&amp;rsquo;Hondt avec 3 partis&lt;/figcaption&gt;&lt;/figure&gt;
Il existe d&amp;rsquo;autres variantes de quotients électoraux (de Droop, de Imperiali), ainsi que des méthodes dites &amp;ldquo;
&amp;rdquo; dans lesquelles on attribue un des sièges restants au parti dont la moyenne des votes/sièges est la plus élevée, puis on recommence tous les calculs jusqu&amp;rsquo;à ce que tous les postes soient attribués. L&amp;rsquo;une des plus utilisées, y compris en France pour les élections au Parlement Européen, est est la méthode du belge D&amp;rsquo;Hondt, connue pour avantager les grands partis, alors que celle du français Sainte-Laguë qui représente mieux les petits partis est plutôt utilisée en Allemagne et au Nord de l&amp;rsquo;Europe&amp;hellip;&lt;/p&gt;
&lt;p&gt;Mais revenons à nos moutons : la méthode Hare suffit parfaitement à mon problème, mais le quotient de Hagenbach-Bischoff ajoute un petit plus de science helvétique qui me plaît assez&amp;hellip;&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai donc codé la méthode du plus fort reste
 exportable en Excel. Trois onglets résolvent le cas des 1548 moutons, celui des pourcentages du début de l&amp;rsquo;article, et celui du scrutin proportionnel utilisé comme exemple dans la
 et qui donne des résultats différents selon le quotient électoral ( Hare, Hagenbach-Bischoff ou Imperiali) choisi. Pour les curieux, la cellule F1 utilise la fonction Excel LARGE,
en français pour obtenir la n-ième plus grande valeur des restes calculés dans la colonne E, où n est le nombre de sièges restant à attribuer. Ensuite un simple test permet de déterminer dans la colonne F si un siège/mouton/pourcent doit être ajouté.&lt;/p&gt;
&lt;p&gt;Le &amp;ldquo;bug connu&amp;rdquo;, c&amp;rsquo;est qu&amp;rsquo;en cas d&amp;rsquo;égalité des restes il se pourrait qu&amp;rsquo;on en ajoute trop, mais je ne sais pas trop comment empêcher ceci en Excel sans macro&amp;hellip; Par contre ce problème est évité dans
que j&amp;rsquo;ai réalisée pour mon application:&lt;/p&gt;
\[gist id="7531147"\]&lt;p&gt;Si vous trouvez ce code utile ou intéressant, vous pouvez voter pour
 à une question sur StackOverflow, ça me fera une voix de plus en attendant un siège &amp;hellip;&lt;/p&gt;
&lt;p&gt;Note : * à mon humble avis le quorum devrait donc être approximativement égal à 1 / le nombre de sièges à pourvoir, donc autour de 1% plutôt que 5 ou 7% dans certains parlements&amp;hellip;&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;quot;
&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-2"&gt;&lt;/span&gt;David Madore &amp;ldquo;
&amp;rdquo;, 10 juin 2009&lt;/li&gt;
&lt;/ol&gt;</description></item><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>Comment dire 33 avec 3 cubes ?</title><link>https://drgoulu.com/2012/06/20/comment-dire-33-avec-3-cubes/</link><pubDate>Wed, 20 Jun 2012 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2012/06/20/comment-dire-33-avec-3-cubes/</guid><description>&lt;p&gt;Le gars qui m&amp;rsquo;a pourri ma dernière soirée du printemps s&amp;rsquo;appelle Mike Croucher.
 il a négligemment posé le problème suivant:&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;Il est possible d&amp;rsquo;écrire beaucoup d&amp;rsquo;entiers comme la somme des cubes de 3 entiers, par exemple: 99 = (-5)&lt;sup&gt;3 + 2&lt;/sup&gt;3+ 6^3 Un exemple plus compliqué est: 91 = (-67134)&lt;sup&gt;3 + (-65453)&lt;sup&gt;3+(83538)&lt;sup&gt;3 Votre tâche est de trouver les entiers x,y, et z tels que: 33 = x&lt;/sup&gt;3 + y&lt;/sup&gt;3 + z&lt;/sup&gt;3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Comme j&amp;rsquo;ai bien vu que la solution pour 91 impliquait de grands entiers, je me suis dit que 33 demanderait probablement des nombres encore plus grands, mais j&amp;rsquo;ai quand même vite pondu le programme Python suivant pour voir:&lt;/p&gt;
\[sourcecode lang="Python"\]&lt;p&gt; res={} #dictionary of results def store(n,x,y,z): if n&amp;gt;=0 and n&amp;lt;100 and n not in res: res&lt;/p&gt;
\[n\]&lt;p&gt;=(x,y,z) print n,res&lt;/p&gt;
\[n\]&lt;p&gt;cube=[] x=0 while True: x3=x*x*x cube.append(x3) for y in range(x+1): y3=cube&lt;/p&gt;
\[y\]&lt;p&gt; for z in range(x+1): z3=cube&lt;/p&gt;
\[z\]&lt;p&gt; store(x3+y3+z3,x,y,z) store(x3-y3+z3,x,-y,z) store(x3+y3-z3,x,y,-z) store(x3-y3-z3,x,-y,-z) store(-x3+y3+z3,-x,y,z) store(-x3-y3+z3,-x,-y,z) store(-x3+y3-z3,-x,y,-z) # store(-x3-y3-z3,-x,-y,-z) #you&amp;rsquo;re right Neamar, it&amp;rsquo;s useless x+=1 if x==50: #show &amp;ldquo;small&amp;rdquo; results for n in range(100): if n in res: print n,res&lt;/p&gt;
\[n\]&lt;p&gt; else: print n,&amp;rsquo;?&amp;rsquo; &lt;/p&gt;
\[/sourcecode\]&lt;p&gt;En moins d&amp;rsquo;une seconde il trouve les 69 des 100 premiers entiers qui sont des sommes de cubes d&amp;rsquo;entiers inférieurs à 100. Le plus &amp;ldquo;compliqué&amp;rdquo; est 78=-55³+53³+26³ .&lt;/p&gt;
&lt;p&gt;Ensuite il mouline pendant des heures pour trouver 51=-796³+659³+602³ et 16=1626³-1609³-511³, et pendant ce temps j&amp;rsquo;ai exploré les liens émaillant les premiers commentaires 
.&lt;/p&gt;
&lt;p&gt;Il s&amp;rsquo;avère que le problème soumis par Mike Croucher est extrêmement difficile, voire impossible.
liste les solutions trouvées par mon programme, et d&amp;rsquo;autres qui ont nécessité des algorithmes beaucoup plus fûtés que le mien pour résoudre cette 
 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;87 = 4271³ - 4126³ - 1972³ , découvert en 1964
&lt;/li&gt;
&lt;li&gt;96 = -15250³ + 13139³ + 10853³&lt;/li&gt;
&lt;li&gt;91 = 83538³ - 67134³ - 65453³&lt;/li&gt;
&lt;li&gt;80 = -112969³ + 103532³ + 69241³&lt;/li&gt;
&lt;li&gt;39 = -159380³ + 134476³ + 117367³ découvert en 1991
&lt;/li&gt;
&lt;li&gt;75 = - 435203231³ + 435203083³ + 4381159³  découvert en 1993 
&lt;/li&gt;
&lt;li&gt;84 = 41639611³ - 41531726³ - 8241191³ découvert en 1994
&lt;/li&gt;
&lt;li&gt;30 =  2220422932³ - 2218888517³ - 283059965³ ainsi que 52 = -61922712865³ + 60702901317³ + 60702901317³ par la même équipe, qui a mis au point l&amp;rsquo;algo le plus performant du moment 
&lt;/li&gt;
&lt;li&gt;24 =15584139827³ - 15550555555³ - 2901096694³ a été découvert avec l&amp;rsquo;algo précédent en 2001 par D. J. Bernstein, dont la page
est consacrée à ce problème et son historique&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A part ça, les matheux démontrent (essayez&amp;hellip;) que les nombres de la forme 9n+4 et 9n+5 ne peuvent pas être la somme de trois cubes, ce qui règle le cas de 4,5,13,14,22,23 etc.&lt;/p&gt;
&lt;figure class="aligncenter" style="max-width: 412px; width: 100%;"&gt;&lt;a href="http://www.geluck.com/" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2012/images/9b493f196263e591d63658b2997f5b5b_hu_ac819ab557304383.webp" srcset="https://drgoulu.com/posts/2012/images/9b493f196263e591d63658b2997f5b5b_hu_ac819ab557304383.webp 320w, https://drgoulu.com/posts/2012/images/9b493f196263e591d63658b2997f5b5b_hu_5216f8ac3ff226ad.webp 412w" sizes="(max-width: 640px) 100vw, 412px" alt="Bon... je n ai pas vraiment le droit d&amp;#39;utiliser ce dessin, mais il va tellement bien là que j espère que vous ne m en voudrez pas, cher Docteur G..." loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;/a&gt;&lt;figcaption&gt;Bon&amp;hellip; je n ai pas vraiment le droit d&amp;rsquo;utiliser ce dessin, mais il va tellement bien là que j espère que vous ne m en voudrez pas, cher Docteur G&amp;hellip;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Reste 33 (et 42 et beaucoup d&amp;rsquo;autres), qui résistent effrontément aux informaticiens cherchant à les obtenir, ainsi qu&amp;rsquo;aux mathématiciens essayant de prouver que c&amp;rsquo;est peine perdue&amp;hellip;&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est énervant qu&amp;rsquo;un petit problème tout bête comme celui-ci puisse résister ainsi aux ordinateurs les plus puissants.  Et motivant de penser qu&amp;rsquo;une solution est peut-être à la portée d&amp;rsquo;amateurs éclairés. Des idées ?&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;Gardiner, V. L., Lazarus, R. B., &amp;amp; Stein, P. R. &amp;ldquo;
. &amp;ldquo;, 1964, Mathematics of Computation, 18, 408-413&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-2"&gt;&lt;/span&gt;Heath-Brown, D. R., Lioen, W. M., &amp;amp; te Riele, H. J. J.&amp;quot;
&amp;rdquo;, 1993, Mathematics of Computation, 61, 235-244&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-3"&gt;&lt;/span&gt;Andrew Bremner, &amp;ldquo;
&amp;rdquo;, 1993&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-4"&gt;&lt;/span&gt;B. Conn and L. Vaserstein, &amp;ldquo;On sums of three integral cubes&amp;rdquo;, 1994, Contemp. Math. 166, 285-294.&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-5"&gt;&lt;/span&gt;Eric Pine, Kim Yarbrough, Wayne Tarrant and Michael Beck, Noam D. Elkies, &amp;ldquo;
&amp;rdquo;, 2000, ANTS IV&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-6"&gt;&lt;/span&gt;Michael Beck, Eric Pine, Wayne Tarrant, Kim Yarbrough Jensen &amp;ldquo;New integer representations as the sum of three cubes&amp;rdquo;, 2007, Math. Comp. 76, 1683-1690 (
)&lt;/li&gt;
&lt;li&gt;&lt;span id="ref-7"&gt;&lt;/span&gt;&lt;span class="openbook_template5"&gt;&lt;a href="http://openlibrary.org/authors/OL4281353A/Wacław_Sierpiński" title="Click to view author in Open Library" target="_blank" rel="noopener"&gt;Wacław Sierpiński&lt;/a&gt; (1988). &lt;a href="http://openlibrary.org/books/OL2722939M/Elementary_theory_of_numbers" title="Click to view title in Open Library" target="_blank" rel="noopener"&gt;Elementary theory of numbers&lt;/a&gt;. North-Holland.&lt;span class="Z3988" title="ctx_ver=Z39.88-2004&amp;amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook&amp;amp;rft.genre=book&amp;amp;rft.btitle=Elementary+theory+of+numbers&amp;amp;rft.isbn=0444866620&amp;amp;rft.au=Wac%C5%82aw+Sierpi%C5%84ski&amp;amp;rft.pub=North-Holland&amp;amp;rft.date=1988"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; (
)&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Al-Khawarizmismes</title><link>https://drgoulu.com/2010/07/12/al-khawarizmismes/</link><pubDate>Mon, 12 Jul 2010 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2010/07/12/al-khawarizmismes/</guid><description>&lt;figure class="alignright" style="max-width: 400px; width: 100%;"&gt;&lt;a href="http://www.flickr.com/photos/heathendawn/169138578/in/photostream/" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2010/images/5_169138578_e50f81f93c_m_d_hu_450a81ee104f1190.webp" srcset="https://drgoulu.com/posts/2010/images/5_169138578_e50f81f93c_m_d_hu_450a81ee104f1190.webp 240w" sizes="(max-width: 640px) 100vw, 400px" alt="%image_alt%" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;/a&gt;&lt;figcaption&gt;statue d&amp;rsquo;Al-Khawarizmi en Ousbekistan, par Heathen Dawn sur Flickr&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Dans les années 800, le mathématicien perse
 introduit le zéro (indien) dans les chiffres arabes, décrit comment résoudre les équations du second degré, et propose de résoudre certains problèmes mathématiques en répétant une séquence d&amp;rsquo;opérations jusqu&amp;rsquo;à ce qu&amp;rsquo;un &amp;ldquo;critère d&amp;rsquo;arrêt&amp;rdquo; soit satisfait. Au XIIème siècle, les moines latins nomment &amp;ldquo;algorismus&amp;rdquo; cette méthode d&amp;rsquo;Al Khuwarizmi, qui devient &amp;ldquo;algorithme&amp;rdquo; en français en 1554.&lt;/p&gt;
&lt;p&gt;Pour cette idée fondamentale des mathématiques et indispensable en informatique, Al-Khwarizmi a reçu à titre posthume un
, et environ
commises par des ignares qui mettent un y grec à la place d&amp;rsquo;un  ī persan&amp;hellip;&lt;/p&gt;
&lt;p&gt;Après que des fous aient passé leur vie à calculer à la main des 
ou des
, c&amp;rsquo;est évidemment l&amp;rsquo;arrivée des ordinateurs qui a donné à l&amp;rsquo;algorithmique son importance actuelle. Aujourd&amp;rsquo;hui, vous utilisez des algorithmes tous les jours, sans le savoir. Par exemple lorsque vous cliquez sur le titre d&amp;rsquo;une colonne sur votre ordinateur, et que les lignes sont
. Ou lorsque vous
. A chaque fois que vous téléphonez ou utilisez votre carte de crédit, vous utilisez des algorithmes de cryptographie qui étaient de la science-fiction il y a 50 ans.&lt;/p&gt;
&lt;p&gt;Bon, ça c&amp;rsquo;était l&amp;rsquo;introduction. En fait cet article est motivé par la coïncidence de trois événements survenus la semaine passée :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mes collègues ont (enfin) réussi à faire fonctionner un algo que j&amp;rsquo;avais pondu pour optimiser les mouvements d&amp;rsquo;une machine. Un algo assez simple (optimisation 
, évidemment&amp;hellip;), bien testé, mais pas suffisamment documenté, donc pas bien utilisé, donc inspirant une certaine méfiance&amp;hellip; Mais là ça marche! Vidéo bientôt.&lt;/li&gt;
&lt;li&gt;La découverte de l&amp;rsquo;existence du
attribué tous les 4 ans aux auteurs d&amp;rsquo;un logiciel de calcul numérique particulièrement efficace, dont certains que je connaissais depuis peu (
et
) et d&amp;rsquo;autres à découvrir (
)&lt;/li&gt;
&lt;li&gt;Enfin, sur les
, un lien vers la page d&amp;rsquo;un chercheur listant
par ses collègues et lui. Il y en a 32, assez pour évaluer vos connaissances en la matière ou les rafraîchir, et apprendre éventuellement des choses:&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;l&amp;rsquo;
trouve le chemin &amp;ldquo;le plus court ou presque&amp;rdquo; entre deux nœuds d&amp;rsquo; un graphe. Il est 
et dans les jeux vidéo pour  les déplacements des personnages par &amp;ldquo;intelligence artificielle&amp;rdquo;&lt;/li&gt;
&lt;li&gt;
peut dans certains cas trouver un chemin meilleur qu&amp;rsquo;A*, mais nécessite plus de calculs.&lt;/li&gt;
&lt;li&gt;La
est la technique que les enfants utilisent pour chercher un mot dans le dictionnaire : on l&amp;rsquo;ouvre à la moitié, puis à la moitié de la moitié où se trouve le mot et ainsi de suite jusqu&amp;rsquo;à trouver la bonne page.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Branch and bound&amp;rdquo; :
est une méthode générique d&amp;rsquo;
permettant d&amp;rsquo;éviter d&amp;rsquo;évaluer toutes les possibilités.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;
est un truc de matheux datant de 1976, qui généralise à la fois le plus ancien algorithme connu, (l&amp;rsquo;
) et celui de l&amp;rsquo;
 (connue des Chinois déjà 1700 ans plus tôt&amp;hellip;)&lt;/li&gt;
&lt;li&gt;La
omniprésente dans nos fichiers informatiques. Il existe de nombreux algorithmes spécifiques, parmi lesquels la
me parait particulièrement géniale.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;
permet à deux personnes qui ne se connaissent pas d&amp;rsquo;échanger des informations confidentielles sur un canal non sécurisé. Indispensable en télécommunications.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;
détermine le chemin le plus court entre deux nœuds d&amp;rsquo;un graphe, sous certaines contraintes expliquées dans
encore.&lt;/li&gt;
&lt;li&gt;Les
permettent d&amp;rsquo;approximer des dérivées, comme dans la formule f&amp;rsquo;(x) = (f(x+h) - f(x-h)) / 2h. (Je les utilise tous les jours, mais est-ce vraiment des algorithmes ?)&lt;/li&gt;
&lt;li&gt;La
est une méthode d&amp;rsquo;optimisation sous contrainte. Elle permet d&amp;rsquo;obtenir une solution optimale à partir des solutions optimales de sous-problèmes. Curieusement, en 1976, on  a montré que les algorithmes de programmation dynamique sont équivalents à ceux de recherche d&amp;rsquo;un chemin optimal dans un graphe&amp;hellip;&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;
pour déterminer le plus grand diviseur commun (PGCD) de deux entiers est le plus ancien algorithme connu. Il est paru dans les &amp;ldquo;Eléments&amp;rdquo; d&amp;rsquo;Euclide autour de 300 av J.C et ne nécessite pas de factorisation des nombres.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;
 est très utilisé en traitement d&amp;rsquo;images.&lt;/li&gt;
&lt;li&gt;La
(FFT) est extrêmement utilisée en traitement du signal, et plein d&amp;rsquo;autres domaines, jusque dans
.&lt;/li&gt;
&lt;li&gt;La
est l&amp;rsquo;algorithme le plus connu pour obtenir le minimum d&amp;rsquo;une fonction à plusieurs variables.&lt;/li&gt;
&lt;li&gt;Les
 permettent de manipuler plus facilement de grosses données en les réduisant à des empreintes.
de manière spectaculairement efficace. Mais ici aussi, j&amp;rsquo;hésiterais à parler d&amp;rsquo;algorithme pour une &amp;ldquo;simple&amp;rdquo; fonction&amp;hellip;&lt;/li&gt;
&lt;li&gt;Le
 est une structure de données exploitée dans beaucoup d&amp;rsquo;algorithmes informatiques très efficaces comme le
. ( Il faut absolument que je trouve le temps d&amp;rsquo;étudier le &amp;ldquo;
&amp;rdquo;, une structure de données &amp;ldquo;miraculeuse&amp;rdquo; découverte en 2000 )&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;
permet de multiplier 2 (grands) nombres plus vite qu&amp;rsquo;avec la méthode que vous avez apprise à l&amp;rsquo;école.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;
détermine des vecteurs de base &amp;ldquo;presque&amp;rdquo; orthogonaux à partir d&amp;rsquo;un grand nombre de vecteurs. Il est utilisé en cryptographie.&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;
permet de résoudre le
&lt;/li&gt;
&lt;li&gt;Le
permet de réarranger rapidement une liste dans un ordre spécifique&lt;/li&gt;
&lt;li&gt;La
permet de trouver une  approximation des zéros d&amp;rsquo;une fonction, des solutions d&amp;rsquo;une équation à plusieurs variables, ou les minima/maxima.&lt;/li&gt;
&lt;li&gt;
est une technique d&amp;rsquo;&amp;ldquo;apprentissage renforcé&amp;rdquo;&lt;/li&gt;
&lt;li&gt;le
est la meilleure méthode de factorisation d&amp;rsquo;un nombre, à part l&amp;rsquo;
qui est à peine meilleur mais beaucoup plus compliqué. Si vous voulez casser une clé RSA, c&amp;rsquo;est ce qu&amp;rsquo;il vous faut, en plus de beaucoup de gros ordinateurs&amp;hellip;&lt;/li&gt;
&lt;li&gt;
, pour &amp;ldquo;RANdom SAmple Consensus&amp;rdquo; est un algorithme d&amp;rsquo;ajustement de paramètres à des données qui ignore les données &amp;ldquo;visiblement complètement fausses&amp;rdquo;&lt;/li&gt;
&lt;li&gt;RSA, pour
, est le génial algorithme de cryptographie a clé révélée utilisé dans la plupart des systèmes de sécurité actuels : carte bancaire, commerce électronique etc.&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;
effectue des multiplications de grands entiers en utilisant la FFT. Sacrés mathématiciens&amp;hellip;&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;
permet de résoudre les problèmes dits de
, dans lesquels on cherche à optimiser la valeurs d&amp;rsquo;une fonction de plusieurs variables devant satisfaire des contraintes d&amp;rsquo;inégalités.&lt;/li&gt;
&lt;li&gt;La
permet de factoriser des matrices rectangulaires, donc de résoudre des systèmes linéaires surdéterminés (avec plus d&amp;rsquo;équations que d&amp;rsquo;inconnues). Elle est utilisée dans de nombreux domaines, de la robotique aux prévisions météo.&lt;/li&gt;
&lt;li&gt;Résoudre des systèmes d&amp;rsquo;équations linéaires par
ou
est l&amp;rsquo;une des opérations les plus communes en analyse numérique, utilisée dans pratiquement tous les domaines de l&amp;rsquo;ingénierie.&lt;/li&gt;
&lt;li&gt;les &amp;ldquo;tenseurs de structure&amp;rdquo; (
 en anglais) sont très utilisées en traitement d&amp;rsquo;image : ils permettent de quantifier l&amp;rsquo;appartenance d&amp;rsquo;un pixel à une région homogène. Méritent-ils de figurer dans les algorithmes ? la question est ouverte.&lt;/li&gt;
&lt;li&gt;
est une structure de données permettant de partitionner des données dans des ensembles disjoints, et de trouver rapidement à quel ensemble appartient une donnée ainsi que de réunir rapidement des ensembles.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;
, une
permettant de corriger les erreurs de transmission en télécommunication. Il est bien caché dans vos téléphones portables, mais il est là.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Connaissez-vous d&amp;rsquo;autres algorithmes dignes de figurer dans la liste ? les commentaires sont là pour les proposer.&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>Comment marche Shazam</title><link>https://drgoulu.com/2009/07/11/comment-marche-shazam/</link><pubDate>Sat, 11 Jul 2009 00:00:00 +0000</pubDate><guid>https://drgoulu.com/2009/07/11/comment-marche-shazam/</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/2009/images/e47ef30951dab1d02fbd45117ec61e0c_hu_a08e6b1033e5dc62.webp 260w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://drgoulu.com/posts/2009/images/e47ef30951dab1d02fbd45117ec61e0c_hu_a08e6b1033e5dc62.webp"
width="260"
height="232"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
Si vous ne connaissez pas
, demandez à un propriétaire d&amp;rsquo;iPhone (eux) ou de Google Phone sous Androïd (
) de vous montrer cette application incroyable. Si personne dans votre entourage ne vit au 21ème siècle, vous  pouvez toujours regarder 
.&lt;/p&gt;
&lt;p&gt;Vous ne rêvez pas : Shazam est capable d&amp;rsquo;identifier en quelques secondes la musique que vous êtes en train d&amp;rsquo;écouter à la radio, dans un bar bruyant, ou le générique d&amp;rsquo;une émission TV ou que sais-je. On dirige le micro du téléphone vers un haut-parleur, on clique un seul bouton et Shazam! le titre du morceau apparait, avec les liens qu&amp;rsquo;il faut pour l&amp;rsquo;acheter, évidemment. Business is business.&lt;/p&gt;
&lt;p&gt;Ce qui nous intéresse ici, c&amp;rsquo;est de savoir comment diable Shazam fait pour reconnaitre quasi-instantanément 10 secondes de son parmi 8 millions de morceaux de musique de 3 minutes chacun, soit un total de 1.44 milliards de secondes, ou 45 ans de musique, et ceci même lorsque la musique est diffusée par une mauvaise sono et captée par un mauvais micro dans un environnement bruité. Ca ne vous épate peut être pas si vous n&amp;rsquo;êtes pas dans la technique, mais moi je suis resté coi d&amp;rsquo;une hébétude aussi stupéfaite qu&amp;rsquo;interloquée. Sur le cul, quoi.&lt;/p&gt;
&lt;p&gt;Pour comprendre, j&amp;rsquo;ai un peu fouillé et trouvé que la technologie appartient à
qui a notamment acquis la propriété intellectuelle de dénommés
et David Culbert. Leur brevet de 2003 &lt;/p&gt;
\[1\]&lt;p&gt; est un modèle du genre : il décrit le système en termes suffisamment généraux pour comprendre le principe, mais en évitant soigneusement de donner des informations précises sur comment ça marche vraiment. Mais voici tout de même ce que j&amp;rsquo;en ai compris.&lt;/p&gt;
&lt;p&gt;Shazam compare des &amp;ldquo;empreintes&amp;rdquo; calculées à des instants remarquables du morceau, par exemple lorsque des notes apparaissent nettement dans le diagramme temps/fréquence du morceau. Pour des raisons expliquées plus bas il faut comparer environ une centaine d&amp;rsquo;empreintes, et comme Shazam demande d&amp;rsquo;enregistrer une dizaine de secondes de musique, j&amp;rsquo;en déduis qu&amp;rsquo;ils prennent environ 10 empreintes par seconde, donc que chaque morceau est stocké chez eux sous la forme de 1800 empreintes environ.&lt;/p&gt;
&lt;figure class="aligncenter" style="max-width: 382px; width: 100%;"&gt;&lt;a href="http://www.rejc2.co.uk/programs/fft/" target="_blank" rel="noopener"&gt;&lt;img src="https://drgoulu.com/posts/2009/images/a89524a9c5e8c9a9e2b18ea8e0ea116c_hu_7e5edd1d87d5e2fe.webp" srcset="https://drgoulu.com/posts/2009/images/a89524a9c5e8c9a9e2b18ea8e0ea116c_hu_7e5edd1d87d5e2fe.webp 320w, https://drgoulu.com/posts/2009/images/a89524a9c5e8c9a9e2b18ea8e0ea116c_hu_dffe0df684e6bd48.webp 480w, https://drgoulu.com/posts/2009/images/a89524a9c5e8c9a9e2b18ea8e0ea116c_hu_e287a51fba415566.webp 760w" sizes="(max-width: 640px) 100vw, 382px" alt="FFT est un joli petit programme qui affiche le diagramme temps/fréquence dun mp3" loading="lazy" class="rounded-lg shadow-sm w-full h-auto" data-zoomable /&gt;&lt;/a&gt;&lt;figcaption&gt;&amp;quot;FFT&amp;quot; est un joli petit programme qui affiche le diagramme temps/fréquence d&amp;rsquo;un mp3&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Le brevet est extrêmement vague sur le problème clé du calcul des empreintes. Il mentionne une liste de caractéristiques du son qui pourraient être utilisées, et indique qu&amp;rsquo;un choix judicieux permet de s&amp;rsquo;affranchir de diverses perturbations du son, en particulier de décalages fréquentiels, mais surtout que l&amp;rsquo;empreinte peut être ramenée à un nombre de 32 bits seulement. Avec ce qui précède, il en résulte que les empreintes d&amp;rsquo;un morceau complet ne nécessitent que 7K de mémoire, et que toute la base de données de Shazam tient sur 54 Gigabytes seulement, ce qui veut dire qu&amp;rsquo;elle peut tenir dans la mémoire RAM d&amp;rsquo;une vingtaine de PC actuels.&lt;/p&gt;
&lt;p&gt;Reste à retrouver dans cette masse d&amp;rsquo;empreintes la centaine d&amp;rsquo;empreintes obtenues à partir de la musique transmise depuis votre téléphone. Et là, la méthode est génialement simple : Pour chaque empreinte, Shazam regarde à quels morceaux elle pourrait appartenir en utilisant simplement l&amp;rsquo;empreinte comme une clé dans la base de données. En effet, comme 32 bits permettent de coder plus de 4 milliards de possibilités alors que la base ne contient &amp;ldquo;que&amp;rdquo; 14 milliards d&amp;rsquo;empreintes, une empreinte donnée se retrouve en moyenne dans 3 morceaux seulement. Puisque les empreintes tirées de l&amp;rsquo;échantillon sont bruitées, il faut comparer une centaine d&amp;rsquo;empreinte qui vont chacune correspondre à 3 morceaux, donc on se retrouvera avec 300 morceaux potentiellement candidats.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est là que le brevet de Shazam frappe fort : si 2 empreintes seulement correspondent à un même morceau, on considère que c&amp;rsquo;est celui-là ! En effet, il n&amp;rsquo;y a qu&amp;rsquo;environ un risque sur 25'000 que l&amp;rsquo;un des 300 morceaux suspecté à cause d&amp;rsquo;une empreinte bruitée corresponde à l&amp;rsquo;un des 3 morceaux identifié par une empreinte correcte.&lt;/p&gt;
&lt;p&gt;La technologie de Shazam/Landmark permet aussi d&amp;rsquo;autres applications, comme reconnaître la musique utilisée dans les bandes son des vidéos sur YouTube et la virer si elle est soumise à copyright, ou peut-être aussi identifier des mp3 échangés sur des réseaux p2p, des trucs comme ça &amp;hellip;&lt;/p&gt;
&lt;p&gt;Car pour la reconnaissance de la musique, il y a désormais encore plus fort que Shazam :
. Avec Midomi, il suffit de chantonner, siffloter ou hmmm-hmmm-er un air pour qu&amp;rsquo;il en retrouve le titre et l&amp;rsquo;auteur. Mais ça m&amp;rsquo;épate moins parce qu&amp;rsquo;avec moi, ça ne marche pas. Ni &amp;ldquo;Yellow Submarine&amp;rdquo;, ni &amp;ldquo;Frère Jacques&amp;rdquo;, ni même 
, rien.&lt;/p&gt;
&lt;h3 id="référence"&gt;Référence&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;WANG, Avery Li-Chun and CULBERT, Daniel, &amp;ldquo;Robust and invariant audio pattern matching&amp;rdquo;, 2003,
&lt;/li&gt;
&lt;li&gt;Avery Wang, &amp;ldquo;An Industrial-Strength Audio Search Algorithm&amp;rdquo;, 2003, ISMIR 2003, 4th International Conference on Music Information Retrieval, Baltimore, Maryland, USA  
\[article pdf](http://www.ee.columbia.edu/~dpwe/papers/Wang03-shazam.pdf)\]
\[[slides pdf\](
]_[[slides_pdf)(http://ismir2003.ismir.net/presentations/Wang.pdf)&lt;/li&gt;
&lt;li&gt;
\[altmetric doi="10.1145/1145287.1145312" float="right"\]Avery Wang &amp;ldquo;The Shazam music recognition service&amp;rdquo;, 2006 , Communications of the ACM - Music information retrieval Volume 49 Issue 8, Pages 44-48  
&lt;/li&gt;
&lt;/ol&gt;</description></item></channel></rss>