<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Virgile Andreani</title>
<link>https://normalesup.org/~andreani/blog.html</link>
<atom:link href="https://normalesup.org/~andreani/blog.xml" rel="self" type="application/rss+xml"/>
<description></description>
<generator>quarto-1.9.22</generator>
<lastBuildDate>Sun, 12 Apr 2026 22:00:00 GMT</lastBuildDate>
<item>
  <title>Retour au FCSC</title>
  <dc:creator>Virgile Andreani</dc:creator>
  <link>https://normalesup.org/~andreani/blog/2026-04-13-fcsc-2026/</link>
  <description><![CDATA[ 






<p>Après quelques années d’absence, j’ai eu le plaisir de participer à nouveau au <a href="https://www.france-cybersecurity-challenge.fr">France Cybersecurity Challenge</a> qui vient de se terminer. C’est une compétition de cybersécurité organisée par l’<a href="https://www.ssi.gouv.fr">ANSSI</a> consistant à résoudre des épreuves en temps limité. Les épreuves étaient cette année comme d’habitude très originales et de difficultés variées, ce qui en fait une de mes compétitions préférées et que je m’amuse beaucoup même si je ne fais de la cybersécurité qu’en amateur et une semaine par an.</p>
<p>Cette année, je me suis concentré sur les épreuves de <em>hardware</em>, <em>forensics</em> et « tutti frutti » de la catégorie <em>misc</em>. Ce qui est un peu frustrant pendant le concours, mais ce que j’aime bien finalement, c’est que les techniques qui me sont utiles une année semblent ne jamais beaucoup m’aider les années suivantes, ce qui fait que je dois constamment réinventer des méthodes et apprendre de nouvelles choses. C’est pas plus mal et c’est une des raisons pour lesquelles j’aime beaucoup cette compétition. Bref, passons au vif du sujet avec les writeups de quelques épreuves que j’ai le plus appréciées.</p>
<section id="crypto" class="level1">
<h1>Crypto</h1>
<section id="this-is-fine" class="level2">
<h2 class="anchored" data-anchor-id="this-is-fine">This is fine</h2>
<p>On avait une liste de polynômes entiers (de degré 16 et avec des nombres très grands), un par lettre du flag. Pour chaque polynôme <img src="https://latex.codecogs.com/png.latex?P">, il fallait trouver un <img src="https://latex.codecogs.com/png.latex?x"> entier tel que <img src="https://latex.codecogs.com/png.latex?P(x)%20=%20c"> avec <img src="https://latex.codecogs.com/png.latex?0%20%5Cleq%20c%20%3C%20256">. Ça semble compliqué à première vue (il y a beaucoup de <img src="https://latex.codecogs.com/png.latex?x"> à tester), mais il y a une astuce. Décomposons :</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbegin%7Balign*%7D%0AP(x)%20&amp;=%20c%5C%5C%0Aa_n%20x%5En%20+%20%5Ccdots%20+%20a_2%20x%5E2%20+%20a_1%20x%20+%20a_0%20&amp;=%20c%5C%5C%0A(a_n%20x%5E%7Bn-1%7D%20+%20%5Ccdots%20+%20a_2%20x%20+%20a_1)%20x%20&amp;=%20c%20-%20a_0%5C%5C%0A%5Cend%7Balign*%7D"></p>
<p>Par conséquent, <img src="https://latex.codecogs.com/png.latex?x"> est un diviseur de <img src="https://latex.codecogs.com/png.latex?c%20-%20a_0"> (ou son opposé). Comme il n’y a que 256 valeurs de <img src="https://latex.codecogs.com/png.latex?c"> possibles, on peut donc les énumérer, et pour chacune énumérer les diviseurs de <img src="https://latex.codecogs.com/png.latex?c%20-%20a_0">, et regarder si un de ces nombres satisfait <img src="https://latex.codecogs.com/png.latex?P(x)%20=%20c"> (ou <img src="https://latex.codecogs.com/png.latex?P(-x)%20=%20c">). Ça se fait très bien avec sympy.</p>
</section>
</section>
<section id="hardware" class="level1">
<h1>Hardware</h1>
<section id="convolu-quoi" class="level2">
<h2 class="anchored" data-anchor-id="convolu-quoi">Convolu-quoi ?</h2>
<p>Le flag était d’abord décomposé en une séquence binaire, puis on regardait une fenêtre glissante de 8 bits sur cette séquence et on enregistrait deux valeurs à chaque offset : la parité de <code>state &amp; G0</code> et celle de <code>state &amp; G1</code> avec <code>G0</code> et <code>G1</code> deux <code>uint8</code>s. On nous donnait le résultat de cette convolution.</p>
<p>On pouvait donc simplement deviner les bits du flags les uns après les autres, en essayant d’ajouter un <code>0</code> ou un <code>1</code> et en regardant si ça correspondait avec le flag encodé. Il y avait sûrement plus malin et efficace mais ça suffisait largement.</p>
</section>
<section id="maintenant-lesp" class="level2">
<h2 class="anchored" data-anchor-id="maintenant-lesp">Maintenant, l’ESP !</h2>
<p>En ouvrant le fichier avec wireshark, il m’a sauté aux yeux que le dernier octet des premiers blocs <code>data.data</code> formaient <code>FCSC</code>. J’ai commencé par sélectionner tous ces blocs avec</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">tshark</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-r</span> capture.pcapng <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-e</span> data.data <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-Tfields</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cut</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c25-26</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tr</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-d</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'\n'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">xxd</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-r</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span></span></code></pre></div></div>
<p>J’ai obtenu un flag avec semble-t-il toutes les lettres en doubles, mais en les dédoublant j’ai obtenu un flag invalide. En regardant de plus près les échanges, ils étaient bidirectionnels : probablement un message et sa confirmation. Or, certains paquets manquaient : parfois le message, et parfois sa confirmation (mais jamais les deux heureusement). J’ai donc dédoublé les lettres à la main, ce qui m’a probablement pris plus de temps que d’écrire un script pour ce faire mais avait l’avantage de ne pas demander de réfléchir.</p>
</section>
<section id="tortoise-say" class="level2">
<h2 class="anchored" data-anchor-id="tortoise-say">Tortoise Say</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2026-04-13-fcsc-2026/tortoise-say.jpg" class="img-fluid figure-img"></p>
<figcaption>Image du challenge représentant un écran e-ink avec un dessin de tortue.</figcaption>
</figure>
</div>
<p>J’adore ce genre d’épreuves. On avait un enregistrement réalisé par un analyseur logique de la programmation d’un écran e-ink et il fallait retrouver ce qui était affiché à l’écran.</p>
<p>J’ouvre le fichier vcd avec Pulseview, j’ajoute un décodeur SPI (comme suggérait la doc de l’écran) en associant les bonnes bornes aux bon fils, et ça me décode les octets.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2026-04-13-fcsc-2026/pulseview-say.png" class="img-fluid figure-img"></p>
<figcaption>Octets décodés par Pulseview.</figcaption>
</figure>
</div>
<p>J’enregistre les octets dans un fichier que j’analyse avec Python.</p>
<p>Visuellement, Pulseview montrait aussi des pulses d’activité à intervalles réguliers, j’ai interprété ça comme des frames. En comptant le nombre d’octets par frames, ça faisait à peu près le nombre de pixels de l’écran (ou peut-être deux fois ce nombre je crois), ce qui a confirmé mon intuition. J’ai donc créé un tableau de la taille de l’écran et l’ai rempli avec les valeurs des octets, puis affiché avec matplotlib. Il a fallu que je m’y reprenne à plusieurs fois pour gérer le petit-endian (ou grand endian) et le sens de remplissage.</p>
</section>
<section id="transport-me-too" class="level2">
<h2 class="anchored" data-anchor-id="transport-me-too">Transport me too</h2>
<p>Pareil, une épreuve que j’ai beaucoup aimée. On avait accès à une carte de transport de STMicroElectronics, et il fallait lui envoyer des commandes pour lui permettre de faire 1000 voyages alors qu’elle n’en autorisait normalement qu’un maximum de 5.</p>
<p>Il suffisait de télécharger la documentation de la carte sur le site de STM, qui expliquait le format des commandes à envoyer pour lire et écrire dans les registres de la carte. Ils donnaient même un fichier C implémentant le code de vérification utilisé à chaque message, que j’ai traduit en Python.</p>
<p>Ce qui m’a fait lire la doc plusieurs fois, c’est que certains registres n’étaient débloqués en écriture qu’une fois après avoir modifié d’autres registres, et que ces registres-là n’étaient modifiables que vers le bas (une fois un 0 écrit c’était définitif). Il fallait donc faire un petit jeu de modifier tel registre pour débloquer tel autre pour pouvoir voyager 32 fois de plus, et de faire ça autant de fois que nécessaire pour arriver à 1000.</p>
</section>
</section>
<section id="forensics" class="level1">
<h1>Forensics</h1>
<p>J’ai résolu 5 épreuves sur 7 dans cette catégorie mais je suis loin d’être le seul. Elles fournissaient des logs d’accès, d’activité ou de connexion entre machines, et il fallait trouver des activités suspectes. J’ai résolu ça grâce à une utilisation intensive de <code>grep</code>.</p>
</section>
<section id="misc" class="level1">
<h1>Misc</h1>
<section id="times-square" class="level2">
<h2 class="anchored" data-anchor-id="times-square">Times Square</h2>
<p>C’était une connexion ssh qui ne donnait un message que si la taille du terminal était suffisamment grande. Même avec la fonte la plus petite, impossible de créer une taille suffisamment grande en redimensionnant la fenêtre. Heureusement il existe une commande <code>stty cols 50000 rows 40000</code> qui aide à définir une taille arbitraire. Mais du coup le message était affiché au milieu de la fenêtre, hors de l’écran. Là je pense qu’il y avait peut-être une meilleure méthode, mais j’ai pipé la connexion ssh dans un fichier pour le lire (un peu laborieusement). Impossible de me souvenir comment j’avais fait pendant la compétation, mais là en m’y repenchant au calme j’ai écrit un script pour parser les codes d’affichage en les changeant pour les faire rentrer dans une fenêtre de taille raisonnable.</p>
<p>Ça donnait donc la condition un peu énigmatique suivante : <code>X + Y + t = 42 &amp;&amp; X &gt; 300 &amp;&amp; Y &gt; 200</code> (<code>t</code> était un compteur de secondes qui commençait à 0 quand on se connectait). Mais comme ces valeurs sont sur 16 bits, il suffisait de sommer à <code>2^16 + 42</code> : <code>stty cols 50000 rows 15578</code> et le flag était affiché à la première seconde.</p>
</section>
<section id="tunnel-routier-12" class="level2">
<h2 class="anchored" data-anchor-id="tunnel-routier-12">Tunnel routier (1/2)</h2>
<p>J’ai bien galéré sur cette épreuve, je crois que c’est parce que j’y ai travaillé pendant une coupure du service, ce qui faisait que la connexion ne me retournait absolument rien et je croyais que c’était ma faute.</p>
<p>Les infos utiles étaient volontairement dissimulées dans l’énoncé, avec des formulations vagues comme « un protocole industriel sur le port TCP/502 ». Wikipedia m’apprend que le port 502 est en général utilisé pour le protocole Modbus, qui semble complètement approprié pour gérer un automate tel que décrit dans l’épreuve. Je télécharge donc <code>pymodbus</code> qui me permet de me connecter.</p>
<p>L’énoncé disait qu’un token était caché dans les données d’identification de l’automate, un coup d’œil à l’API de <code>pymodbus</code> m’indique une fonction <code>read_device_information</code> qui me semble prometteuse, bingo.</p>
<p>J’ai pas réussi à faire la partie 2 qui semblait être plus intéressante.</p>
</section>
<section id="fizzbuzz-12-et-22" class="level2">
<h2 class="anchored" data-anchor-id="fizzbuzz-12-et-22">FizzBuzz (1/2 et 2/2)</h2>
<p>J’ai vraiment aimé ces deux épreuves, qui consistaient simplement à programmer le programme classique FizzBuzz en assembleur. Dans la deuxième épreuve, on n’avait pas le droit au modulo ni à la division (des instructions assez naturelles pour programmer FizzBuzz), donc j’ai implémenté un modulo à la main avec des soustractions, avant de me rendre compte qu’il fallait être un peu efficace parce qu’on était limité à 65536 cycles de processeur (c’est un peu short pour un FizzBuzz jusqu’à 1000, sans modulo, si on ne fait pas un peu attention). J’ai vraiment adoré écrire ces programmes et les optimiser.</p>
</section>
<section id="las-vegas-baby" class="level2">
<h2 class="anchored" data-anchor-id="las-vegas-baby">Las Vegas Baby</h2>
<p>Ahh, peut-être mon épreuve préférée, en tout cas la plus dure que j’ai résolue (on est seulement 25 à l’avoir réussie) et rien à voir avec de la cybersécurité (mais ça change un peu et c’est rafraîchissant). On avait l’énoncé suivant :</p>
<blockquote class="blockquote">
<p>Vous êtes à Las Vegas, en plein tournoi de poker Texas Hold’em. Tous les joueurs sont partis en pause, et vous vous retrouvez seul avec le paquet de cartes et votre conscience. L’envie vous prend alors de tricher.</p>
<p>Cependant, la tâche n’est pas si facile: le croupier coupe le deck à une position aléatoire avant la distribution des cartes. Il vous faut alors être malin pour que la distribution vous donne le meilleur jeu, quel que soit la coupe effectuée par le croupier. De plus, vous savez que vous allez être à la petite blinde, mais ne savez pas encore si il y aura 3 ou 4 joueurs après la pause.</p>
<p>Votre objectif est de trier le paquet de carte de manière à être certain de gagner la prochaine main.</p>
</blockquote>
<p>C’est original et amusant ! J’ai vu ça comme un problème d’optimisation / de programmation par contraintes. Pour la programmation par contraintes ou la satisfiabilité, ça m’aurait demandé d’implémenter les mains de poker en un langage de contraintes et ça avait l’air pénible, je n’avais pas envie de m’infliger ça. Idem pour l’optimisation ILP. J’ai donc décidé de prendre la fonction d’évaluation des mains comme une boîte noire, et d’utiliser une méta-heuristique, celle avec laquelle je suis le plus familier, soit le <a href="https://fr.wikipedia.org/wiki/Recuit_simul%C3%A9">recuit simulé</a>. C’est une méthode particulièrement adaptée aux problèmes où l’on peut transformer graduellement un état en un autre (un état étant ici un deck, qu’on peut réordonner petit à petit).</p>
<p>À chaque étape, on propose un changement aléatoire et assez élémentaire à l’état (par exemple, échanger deux cartes prises au hasard dans le deck). Ce changement peut faire augmenter ou diminuer le score (le nombre de mains remportées). Si ça améliore le score on garde le changement, et si ça rend le score moins bon on le garde avec une certaine probabilité qui dépend de la différence de score, et d’un paramètre qu’on nomme habituellement la température. Plus la température est élevée, plus la probabilité de conserver des changements qui détériorent le score est élevée, et avec une température de zéro, on ne garde que les changements qui améliorent le score. On commence avec une température très élevée (pour pouvoir bien explorer l’espace d’états possibles), et on diminue progressivement la température pour se concentrer sur les meilleurs scores.</p>
<p>Cet algorithme a été très étudié pendant des décennies, et il s’adapte à beaucoup de problèmes, mais ce n’est pas forcément évident de choisir une bonne fonction de score, une bonne fonction de proposition (les étapes élémentaires qu’on utilise pour passer d’un état à un autre état voisin), et un bon programme de refroidissement. Si on refroidit trop vite on peut se retrouver bloqué dans un optimum local, et si on refroidit trop lentement ben ça prend trop de temps<sup>1</sup>.</p>
<p>Bon, comme ça demande en général beaucoup d’étapes, il faut que l’évaluation soit rapide et j’ai donc RIIR le programme d’exemple qu’on nous fournissait en Python. Ça m’a permis de multiplier par 15000 la vitesse d’évaluation, et passer de ~2 decks évalués par seconde à ~30000. Vive Rust.</p>
<p>Au lieu de manipuler un paramètre de température je trouve en général plus pratique d’utiliser son inverse. J’ai donc commencé par une température inverse de 0 (donc température infinie : tous les mouvements sont acceptés) que je faisais augmenter linéairement. En traçant le nombre de mains perdues (que je cherchais donc à minimiser) en fonction de la température, j’ai vu une descente assez régulière jusqu’à une température inverse de 2,5, puis une descente beaucoup plus lente, qui est quand même descendue à 2 mais est restée bloquée là.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2026-04-13-fcsc-2026/recuit1.svg" class="img-fluid figure-img"></p>
<figcaption>Nombre de mains perdues (on veut le faire descendre à zéro) en fonction de la température.</figcaption>
</figure>
</div>
<p>Ça m’a montré que ce n’est pas forcément la peine de s’attarder sur la première phase, mais que la température inverse critique semble être 2,5 et que c’est probablement à ce moment-là et après qu’il faut particulièrement insister.</p>
<p>J’ai donc un peu changé le programme de refroidissement : j’ai commencé à 2, et quand j’arrivais à 10 je considérais que j’étais bloqué dans un minimum local dont il fallait sortir. Pour ça, je redescendais tout à coup la température inverse à 2 et je recommençais (les fameux recuits).</p>
<p>J’ai lancé un run et je suis allé me coucher, quand je me suis réveillé ça avait trouvé une solution, au bout de 2h30 de calcul et 236 millions de decks testés. Vive le recuit simulé.</p>


</section>
</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Notes de bas de page</h2>

<ol>
<li id="fn1"><p>Mais ce que je trouve incroyable c’est qu’on peut démontrer que si on refroidit suffisamment lentement, on arrive forcément à l’optimum global ! Le hic c’est que ça peut prendre des siècles.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>contest</category>
  <category>optimization</category>
  <guid>https://normalesup.org/~andreani/blog/2026-04-13-fcsc-2026/</guid>
  <pubDate>Sun, 12 Apr 2026 22:00:00 GMT</pubDate>
</item>
<item>
  <title>Conventions d’origami 2025</title>
  <dc:creator>Virgile Andreani</dc:creator>
  <link>https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/</link>
  <description><![CDATA[ 






<section id="lyon-ooraa" class="level1">
<h1>Lyon (OORAA)</h1>
<p>Je rattrapais mon retard sur le toujours excellent podcast <a href="https://www.vodio.fr/vodiotheque/c/999/il-ne-plie-plus-il-cause/"><em>Il ne plie plus, il cause !</em></a> de <a href="https://pouet.chapril.org/@Marvin_Rouge">Stéphane</a> cet été quand j’arrive sur <a href="https://www.vodio.fr/vodiotheque/i/21173/l-emulation/">l’épisode sur l’émulation</a> et que je me dis que ça fait longtemps que je ne suis pas allé à une convention d’origami. L’enthousiasme avec lequel il a décrit celle de l’OORAA étant communicatif, je me renseigne et j’apprends qu’elle se déroulera fin octobre. Je lance alors un appel sur Mastodon pour trouver quelqu’un qui serait intéressé·e de partager une chambre pour réduire un peu le prix de l’hébergement. <a href="https://shelter.moe/@alicesutaren">Laurence</a> (qui a d’ailleurs écrit un <a href="https://blog.alicesutaren.nanami.fr/2025/11/05/lyon-ultimate-origami-convention-2025-18/">super article sur la convention</a>) m’a tout de suite répondu, et comme c’est d’autant plus sympa d’y aller entre potes, je pose mon vendredi et je réserve mes billets de train.</p>
<section id="vendredi" class="level2">
<h2 class="anchored" data-anchor-id="vendredi">Vendredi</h2>
<p>Quelques mois plus tard, j’arrive à Lyon sans trop savoir à quoi m’attendre. Nicolas Terry en personne me souhaite la bienvenue très chaleureusement et donne le ton : ici tout le monde se tutoie et il blague qu’il est même prêt à dégager quiconque oserait le vouvoyer !</p>
<p>Pour le premier atelier, je choisis un peu au hasard le chat de <a href="https://gotaniorigami.wixsite.com/hello?lang=fr">Tetsuya Gotani</a>. On prend place dans une petite salle de classe, on nous distribue du papier de toute beauté (shadow thai orange) et c’est parti. Je me souviendrai toujours des <em>floup floup floup</em>, jolis chuchotements de 25 grandes feuilles se faisant plier tout autour de moi dans une petite salle : un sacré ASMR, comme a dit Laurence !</p>
<p>Tetsuya est un super prof, et l’enseignement de son chat est bien rôdé : on a terminé en avance, et dans les cinq dernières minutes il nous explique au tableau sa méthode de conception du chat : design traditionnel (22.5°) par la technique des molécules, dont je n’avais jamais entendu parler mais qui m’a donné envie d’en savoir plus.</p>
<p>J’étais content d’avoir terminé mon chat quand je remarque celui d’<a href="https://www.anice-claudeon.com/">Anicé Claudéon</a> qui avait aussi suivi l’atelier. Il avait complètement transformé le modèle : réduit le dos, retourné les pattes avant, donné du mouvement et le chat svelte et élégant de Tetsuya est devenu sous ses doigts rond, joufflu et vivant. Alors que j’allais partir manger, je repose mes affaires et je décide de l’étudier et d’essayer de le reproduire sur mon modèle. Pendant une demi-heure et grâce aux conseils d’Anicé, je retravaille mon chat jusqu’à lui donner une apparence un peu similaire. Cette première grosse claque a orienté mon début de convention : alors que je suis capable de suivre des pliages même difficiles, il y a une dimension tout aussi importante qui consiste à considérer un modèle comme une base de départ qui laisse la possibilité à l’origamiste de s’exprimer par le modelage ou la réinterprétation. Certains et certaines sont des maîtres en la matière, mais j’en suis au niveau zéro de ce point de vue, et j’ai décidé d’essayer de profiter de la convention pour travailler cela.</p>
<div class="quarto-layout-panel" data-layout-ncol="3">
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 33.3%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/tetsuya-debut.jpg" class="img-fluid figure-img" alt="Une salle de classe, je suis assis au fond avec une superbe feuille à motifs orangés et gris sur ma table."></p>
<figcaption>Au début de l’atelier</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 33.3%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/tetsuya-fin.jpg" class="img-fluid figure-img" alt="Même endroit mais la feuille a été pliée en forme de chat qui se tient la queue dressée et avec une posture un peu joueuse."></p>
<figcaption>À la fin de l’atelier</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 33.3%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/tetsuya-extra.jpg" class="img-fluid figure-img" alt="Gros plan sur le chat qui a pris des formes et des courbes."></p>
<figcaption>Avec les conseils d’Anicé</figcaption>
</figure>
</div>
</div>
</div>
</div>
<p>Ce n’est qu’au moment du déjeuner à la cantine que j’ai vraiment réalisé où j’étais et avec qui : des passionné·es qui plient tout ce qui leur tombe sous la main. En regardant l’un plier machinalement sa serviette et l’autre son ticket de caisse, je pose une question à quelqu’un autre qui sort une feuille de sa poche pour m’expliquer un pli… C’était vraiment quelque chose !</p>
<p>Je poursuis la journée par la corneille (forcément !) de <a href="https://pbsorigami.co.uk/">Peter Buchan-Symons</a> et l’ours d’<a href="https://www.flickr.com/photos/186310415@N06/">Eliot Ori</a>. Première petite déception : on n’a pas réussi à aller au bout de la corneille dans le temps imparti pour l’atelier. Même sans parler de modelage avancé comme pour le chat, alors que je pensais repartir de l’atelier avec une corneille complète, il aurait manqué 30 à 45 minutes pour que ce soit le cas.</p>
</section>
<section id="samedi" class="level2">
<h2 class="anchored" data-anchor-id="samedi">Samedi</h2>
<p>Samedi matin, deuxième petite déception parce que l’atelier que je voulais suivre était complet quand je suis arrivé dans la salle. Leçon apprise pour l’après-midi : celui que je ne voulais pas rater était l’écureuil en <em>wet folding</em> de <a href="https://keepfoldingon.com/">Daniel Chang</a>. Ça fait longtemps que j’avais envie d’essayer le <em>wet folding</em>, mais je ne savais pas vraiment d’où partir et cet atelier était l’initiation idéale. Ce que je remarque avant tout dans ce modèle, réalisé avec une épaisse feuille de Canson, est la queue de l’écureuil, qui est toute en courbes. Daniel nous a donné plein de conseils : combien d’eau ajouter, comment savoir si c’est trop ou pas assez, les bons gestes, etc. Une vraie masterclass. Je pensais que mon premier pliage en wet folding allait être catastrophique mais j’ai été très agréablement surpris par mon résultat que j’ai trouvé assez chouette étant donné combien je redoutais cette technique de pliage.</p>
<p>L’autre raison pour laquelle je me souviendrai de cet atelier est que partager les flacons d’eau et quelques outils a contribué à briser la glace entre les participant·es, et que j’ai découvert à quel point il était agréable de plier à plusieurs avec mes voisins et voisines de table. On a bien rigolé, c’était vraiment super et on a même mis en scène nos créations à la fin entre les éponges et outils :)</p>
<div class="quarto-layout-panel" data-layout-ncol="2">
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/ecureuil-1.jpg" class="img-fluid figure-img" alt="Un écureuil en Canson blanc qui a une jolie volute touffue en guise de queue."></p>
<figcaption>Mon écureuil :)</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/ecureuils.jpg" class="img-fluid figure-img" alt="Nos quatre écureuils placés ensemble autour des éponges, flacons et outils que l'on a utilisés pour les plier."></p>
<figcaption>Nos écureuils :)</figcaption>
</figure>
</div>
</div>
</div>
</div>
<p>Dernier atelier avec Nicolas Terry qui nous a enseigné son crocodile. On était peu nombreux·ses, ambiance très décontractée et agréable de fin de journée ! Peut-être que cette ambiance a contribué à nous empêcher de terminer le modèle, Nicolas s’est fait surprendre par le temps (qui avait certes été raccourci par la prise de la photo de groupe) et on a dû arrêter avec un croco à 80% terminé. Nicolas a eu la gentillesse de nous envoyer le diagramme pour qu’on puisse terminer le modèle.</p>
</section>
<section id="dimanche" class="level2">
<h2 class="anchored" data-anchor-id="dimanche">Dimanche</h2>
<p>Seulement deux ateliers le dimanche : le matin j’ai choisi le gorille de <a href="https://www.flickr.com/photos/131815212@N05/">Yuta Katsuzaki</a>. Les gens qui en sortaient la veille l’avaient dit extrêmement difficile et je voulais me challenger. Malgré un setup de caméra et vidéo projecteur qui filmait les mains de Yuta, la caméra ne donnait pas une image extraordinaire et la première heure a été très longue : essayer de comprendre ce que Yuta venait de faire, ne pas arriver à le voir, et se résigner à attendre qu’il passe pour montrer individuellement. Je pense que la caméra n’ajoutait rien et qu’il aurait été plus efficace qu’il nous montre les étapes en direct, comme le faisaient tous les autres invités. Après la première heure ça a été plus facile, mais à la fin de l’atelier on n’était quand même arrivé qu’à 50% du pliage du modèle. Yuta nous a lui aussi permis de prendre des photos de son diagramme pour pouvoir terminer le gorille.</p>
<p>Dernier atelier, la base de masque d’<a href="https://www.flickr.com/photos/92471729@N03/">Yvon Toledano</a>. Ça aussi c’était quelque chose dont j’étais curieux : réaliser un visage me semblait être quelque chose d’assez inaccessible. Mais le masque d’Ynon se plie vraiment tout seul, et offre une grande part à l’interprétation personnelle en laissant pas mal de papier un peu partout pour ajouter des détails. Ça m’a vraiment plu, et donné envie d’en faire des variations.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/masques.jpg" class="img-fluid figure-img" alt="Quatre masques en origami, en papier peau d'éléphant. Ce sont des visages avec sourcils, bouche, nez, cheveux, menton, en relief, qui font un peu penser à des sculptures."></p>
<figcaption>Mon masque (à droite) et ceux de mes voisin·es</figcaption>
</figure>
</div>
<p>Le départ a été un peu difficile : j’étais un peu triste de quitter les gens avec qui j’avais passé le weekend, mais on a échangé des informations de contact et on s’est donné rendez-vous à la prochaine convention… le weekend d’après à Paris :)</p>
</section>
</section>
<section id="rencontres-dautomne-mfpp" class="level1">
<h1>Rencontres d’automne (MFPP)</h1>
<p>Je n’en avais pas assez alors je réserve à la dernière minute, je pose mon vendredi après-midi et je me retrouve la semaine d’après aux rencontres d’automne du MFPP à Paris. C’est un avis partagé des participant·es des deux conventions qu’elles n’ont rien à voir ! Je comparerai mon impression des deux à la fin de cet article, mais on m’avait prévenu qu’alors que Lyon est très technique et internationale, Paris est plus locale et abordable.</p>
<section id="vendredi-1" class="level2">
<h2 class="anchored" data-anchor-id="vendredi-1">Vendredi</h2>
<p>Accueilli par Aurèle Duda tout aussi chaleureusement que par Nicolas la semaine dernière, je vais saluer les quelques personnes que je reconnais de Lyon. C’est un peu la même chose mais en plus petit : on passe de 4 salles à une seule, la boutique qui prenait une salle entière tient maintenant sur une seule table, mais une différence notable concerne justement les tables : alors qu’à Lyon on était alignés comme à l’école, ici il y a trois groupes de tables en U.</p>
<p>Je commence par l’atelier de Chtik qui commence par s’asseoir près de nous et par nous expliquer sa vision de l’origami : des pliages simples à plier, à retenir et à enseigner, avec le moins de préparation possible (seulement des feuilles carrées : pas d’hexagones ou de pentagones à découper), à plier sans table par exemple dans les transports, et qui donnent envie d’être pliés et repliés. Rien à voir avec Lyon en effet ! Il nous montre alors comment faire des feuilles d’arbre en trois plis, et en plus de nous expliquer quels plis faire il nous explique aussi comment les faire : Chtik plie sans table et ça peut dérouter mais il a passé beaucoup de temps à trouver les bonnes positions et les bons mouvements et tient à nous les transmettre pour essayer de nous convaincre que se passer de la table n’est pas une contrainte mais au contraire une liberté.</p>
<p>Avec la demi-heure qu’il nous restait à la fin de l’atelier Chtik nous a distribué du papier et invité à créer des compositions de branches et de feuilles avec autant de papier qu’on voulait mais à condition de l’utiliser entièrement ! Ça demandait un peu de préparation pour savoir comment découper son papier en carrés et rectangles pour faire les feuilles et les tiges et comment organiser sa composition : j’ai fait 8 feuilles et 4 tiges.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/feuilles.jpg" class="img-fluid figure-img" alt="Une composition en origami avec 8 feuilles d'arbre ovales et quatre tiges qui s'emboîtent les unes dans les autres. Le tout est planté dans un socle aussi en origami."></p>
<figcaption>Ma composition de feuilles</figcaption>
</figure>
</div>
<p>Pour l’atelier suivant, je suis allé voir Hong qui enseignait le modèle <em>Seeds in the Wind</em> de Toshikazu Kawasaki : un joli enchevêtrement géométrique. J’ai été tellement fasciné par ce système d’accroche que j’en ai plié trois autres variations pendant le weekend, en faisant varier la taille et le nombre de bandes, et la géométrie du modèle.</p>
<div class="quarto-layout-panel" data-layout="[[1,1], [1]]">
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/seeds-1.jpg" class="img-fluid figure-img" alt="À gauche : le modèle *Seeds in the Wind* en couleurs de Noël (rouge et vert). C'est une sorte de ballon aplati avec trois bandes rouges et trois bandes vertes qui s'enchevêtrent. À droite : un modèle un peu ressemblant mais avec le double de bandes, et deux fois plus fines, et lisses (au lieu d'être quadrillées de plis). C'est un peu plus circulaire, mais un peu aplati quand même, comme un ballon de baudruche rempli d'eau un peu écrasé par son propre poids."></p>
<figcaption>Version d’origine (à gauche) et ma première variation</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/seeds-2.jpg" class="img-fluid figure-img" alt="Les bandes sont longues et fines, mais l'objet n'a plus deux pôles mais quatre, disposés en tétraèdre. Il y a trois bandes par arrête, donc 18 bandes en tout."></p>
<figcaption>Ma deuxième variation</figcaption>
</figure>
</div>
</div>
</div>
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 100.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/seeds-3.jpg" class="img-fluid figure-img" alt="Les bandes ont repris la taille initiale et sont à nouveau quadrillées de plis. C'est toujours un tétraètre, et toujours trois bandes par arrête mais cette fois il y a une des trois bandes qui s'enfonce dans l'intérieur du modèle pour rejoindre le sommet. C'est très dense et bien rempli, un peu inextricable."></p>
<figcaption>Ma troisième variation</figcaption>
</figure>
</div>
</div>
</div>
</div>
</section>
<section id="samedi-1" class="level2">
<h2 class="anchored" data-anchor-id="samedi-1">Samedi</h2>
<p>Samedi matin des participant·es avaient apporté des gâteaux pour le petit déjeuner ! Je suis allé à l’atelier de Chtik pour faire des fleurs avec du joli papier imprimé, puis on est allé s’acheter à manger avec plusieurs participant·es et on a mangé ensemble dans la salle en discutant d’origami. C’était vraiment sympa. Une fois les tables essuyées on s’est remis au travail, pour ma part avec une version simple du gland de <a href="https://bethjohnsonorigami.com/">Beth Johnson</a>, enseignée par Camille, puis avec un cadre photo tessellé créé et enseigné par Valérie, une experte en tesselations, qui nous a dit s’être inspirée des cheveux du <em>Green man</em> de <a href="https://nickorigami.com/">Nick Robinson</a>.</p>
<div class="quarto-layout-panel" data-layout-ncol="2">
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/fleurs.jpg" class="img-fluid figure-img" alt="Une vingtaine de fleurs en papier coloré posés sur une table. Toutes ont quatre pétales."></p>
<figcaption>L’ensemble des fleurs pliées par les participant·es de l’atelier</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/cadre.jpg" class="img-fluid figure-img" alt="Un hexagone rempli de piques, qui contient un petit espace au milieu pour glisser une petite photo."></p>
<figcaption>Le cadre photo tessellé</figcaption>
</figure>
</div>
</div>
</div>
</div>
<p>On termine la journée par un pliage surprise plié dans le noir complet (autant que possible compte tenu des lumières de sécurité) réalisé sur un papier phosphorescent ! Une expérience que j’ai trouvée très originale. On est ensuite passé au dîner pizza, suivi d’une session de pliage libre <del>jusqu’au bout de la nuit</del> jusqu’à 22 heures, pendant laquelle on a formé des petits groupes spontanés pour plier ensemble, avec notre salade de fruits ou notre boisson à portée de main : j’ai plié dans le groupe de Cécile qui révisait son atelier du lendemain.</p>
</section>
<section id="dimanche-1" class="level2">
<h2 class="anchored" data-anchor-id="dimanche-1">Dimanche</h2>
<p>J’ai choisi le petit requin de Tu Kaiming, enseigné par Jonathan, et le troisième atelier de Chtik, d’<em>origamikebana</em>, dans lequel on a vu une fleur supplémentaire, une base en hydrangea, et la souris de <a href="https://www.itsjustabitofpaper.co.uk/">Rikki Donachie</a>.</p>
<div class="quarto-layout-panel" data-layout-ncol="2">
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/requin.jpg" class="img-fluid figure-img" alt="Un requin en origami, avec le dos et les nageoires violettes et le ventre blanc, qui a sa gueule tout autour de mon petit doigt."></p>
<figcaption>Le requin de Tu Kaiming qui me mord le petit doigt</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/souris.jpg" class="img-fluid figure-img" alt="Une petite souris blanche avec le museau brun qui lève la tête vers une fleur jaune au bout d'une tige verte qui prend son origine dans un socle rouge."></p>
<figcaption>La souris de Rikki Donachie qui contemple une fleur jaune qui pourrait être une tulipe</figcaption>
</figure>
</div>
</div>
</div>
</div>
<p>Pendant la pause déjeuner, Valérie nous a laissé fouiller dans son incroyable boîte à tessellations et nous a expliqué les merveilles qui s’y trouvaient.</p>
<p>Comme au moins trois choses se passent à la fois, je ne pouvais pas être partout, mais je me dois de mentionner deux ateliers auxquels je n’ai pas participé : l’atelier de Cécile de création de papier bullé (originale technique de peinture avec un rendu incroyable), et le stop motion d’Aurèle qui a animé une petite scène dans un décor entièrement réalisé en origami par les participant·es. J’ai trouvé ce concept de réalisation collective une super idée, et je voyais certain·es participant·es plier ensemble du mobilier pour les scènes du film : une théière, des meubles, etc., à partir de plusieurs livres remplis de diagrammes de maisons de poupées. Je regrette de ne pas y avoir pris part et j’ai hâte de voir la scène montée.</p>
</section>
</section>
<section id="bilan" class="level1">
<h1>Bilan</h1>
<p>C’était assez fou de participer à deux conventions d’origami à une semaine d’écart. Même si j’ai apprécié les deux, je crois que j’ai une préférence pour les rencontres du MFPP même si je sais que l’OORAA essaie de résoudre certains des problèmes de la convention de Lyon.</p>
<p>Un des gros problèmes de Lyon à mes yeux était le manque de diversité du public et des invités. Je ne sais pas si c’est une exception de 2025, mais sur cinq invités cette année, il y avait cinq hommes, ce que je ne trouve vraiment pas correct, et qui n’envoie pas une bonne image. Je crois que l’équipe organisatrice était elle aussi exclusivement masculine. J’ai l’impression que ça se reflète dans le public qui était lui aussi principalement masculin. Par comparaison, le planning des ateliers des rencontres du MFPP était strictement paritaire : 10,5 ateliers animés par des hommes et 10,5 animés par des femmes. J’ai l’impression que le public à Paris était lui aussi beaucoup plus mixte, en termes de genre mais aussi d’âges et d’origines.</p>
<p>Un autre problème de Lyon, c’était le nombre d’ateliers dont on sortait avec un modèle inachevé. On m’a dit que c’était un peu moins le cas les autres années, mais cette année, avec mon choix d’ateliers, 3 sur 8 donc presque la moitié étaient dans ce cas. C’est une chose de repartir avec un modèle qui nécessite encore un peu de travail de modelage, mais c’en est une autre, et c’est un peu décevant, s’il reste des plis à faire qui nécessitent le diagramme.</p>
<p>Enfin, c’est un peu paradoxal étant donnée la configuration des lieux et que la plupart des gens logent dans le centre de conventions, mais je pense qu’il y a un énorme potentiel sous-exploité à Lyon pour le pliage en commun. La quasi totalité des gens évitent la cantine (qui souffre à tort d’une mauvaise réputation : elle est très bonne quoique chère) et vont manger dehors, ce qui prend au moins deux heures par repas, parce qu’il n’y a pas de restaus à proximité. On était 10 à 12 max par repas à la cantine et le centre était désert sur les temps des repas. Les salles étaient systématiquement fermées en dehors des ateliers, ce qui n’encourageait pas la pratique libre. Les moments réservés au pliage libre ont souvent été très raccourcis par du retard à l’organisation des conférences, qui étaient plutôt intéressantes mais qui prenaient beaucoup de temps, notamment en raison de l’interprétation parfois un peu laborieuse en anglais/français des propos des conférenciers. J’ai cru comprendre que les organisateurs regrettaient eux-même la disparition des moments de pliage libre et réfléchissaient à des solutions pour en proposer malgré les contraintes auxquelles ils sont soumis.</p>
<p>C’est vraiment dommage, parce que je pense qu’une convention d’origami devrait être quelque chose de plus qu’un tuto vidéo en direct. La configuration des tables en U au MFPP rendait déjà l’enseignement un peu moins magistral et scolaire, mais surtout, la salle était ouverte en permanence, de 9 heures à 22 heures, et il y avait tout le temps au moins un groupe en train de plier. Personnellement, je crois c’est cette spontanéité ce que je recherche dans les conventions. Je n’ai aucun problème pour suivre les diagrammes de modèles complexes, et c’est quelque chose que je prefère faire chez moi au calme, donc une convention où des créateur·ices se contentent d’enseigner leurs modèles diagrammés ne m’apporte pas grand-chose. Alors qu’être face à face avec quelqu’un qui m’enseigne sur un coin de table un modèle qui n’existe que dans sa tête, ou qui m’explique sa conception de l’origami ou sa méthode de préparation de papier, de wet folding ou de finitions au MC, c’est irremplaçable.</p>
<p>J’ai trouvé aussi, mais ça tient peut-être un peu à ma personnalité, qu’il était plus difficile de s’intégrer à Lyon qu’à Paris. À Lyon il y avait des groupes de participant·es qui se connaissaient déjà et qui interagissaient très peu avec les autres (à quelques exceptions près). À Paris c’était plutôt le contraire : l’ambiance était beaucoup plus familiale, comme si on se connaissait déjà tous et toutes depuis longtemps, et que les nouveaux·elles comme moi et d’autres étaient immédiatement et très naturellement accueillis au sein du groupe. Tout le monde parlait avec tout le monde.</p>
<p>Une dernière différence que j’ai notée entre Lyon et Paris, c’est que même si je suis sorti des deux conventions avec des étoiles (en origami) dans les yeux et plein d’idées de nouvelles choses à plier, je serais incapable de replier le moindre modèle de Lyon par cœur, alors que je pourrais plier par cœur quasiment tous les modèles que j’ai appris à Paris. Et ce ne sont pas des modèles si simples qu’ils en sont ennuyeux, ce sont des modèles qui donnent au contraire envie de se faire plier, replier, diffuser, enseigner. Même si le monde des <em>crease patterns</em> et de la création de modèles ultra complexes m’attire indéniablement, je crois que c’est l’origami simple et élégant qui correspond le plus à ce que je recherche en ce moment.</p>
<p>Il y aurait bien d’autres choses à mentionner sur ces conventions : les magnifiques expositions par exemple, le fait que n’importe qui est libre d’exposer ses œuvres aux côtés des œuvres d’artistes professionnels, l’inventivité de certain·es créateur·ices dans des styles très différents, un petit groupe qui s’attroupe autour d’une feuille de papier et qui la caressent délicatement parce qu’elle est vraiment très jolie et qu’ils veulent savoir quelle sensation elle donne entre les doigts, et la passion partagée de personnes qui parlent très sérieusement mais quand même sans trop se prendre au sérieux de leur passion commune : manipuler des bouts de papier.</p>
<div class="quarto-layout-panel" data-layout="[[1,1,1], [1,1]]">
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 33.3%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/penance.jpg" class="img-fluid figure-img" alt="Un visage d'un homme barbu, chevelu et moustachu, d'un certain âge, qui a un visage sévère, réalisé en wet folding. L'œuvre porte le nom *Facing his penance*."></p>
<figcaption>Une des œuvres de l’exposition de Daniel Chang à Lyon</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 33.3%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/expo-cecile.jpg" class="img-fluid figure-img" alt="Des papiers sur lesquels ont éclaté des bulles d'encre, des papiers marbrés et striés de belles couleurs."></p>
<figcaption>Les magnifiques papiers bullés et marbrés de Cécile à Paris</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 33.3%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/expo-chtik.jpg" class="img-fluid figure-img" alt="Des fleurs et des arbres en origami."></p>
<figcaption>Une partie de l’expo de Chtik à Paris</figcaption>
</figure>
</div>
</div>
</div>
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/expo-anice.jpg" class="img-fluid figure-img" alt="Des personnages très complexes : une tête d'homme sur un poulpe, des chevaux fantastiques, des personnages de la *Commedia del Arte*, les quatre mousquetaires pliés dans la même feuille."></p>
<figcaption>L’expo d’Anicé Claudéon à Lyon</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/expo-colin.jpg" class="img-fluid figure-img" alt="De très beaux papillons, des masques partiels, une main qui plie la feuille avec laquelle elle est pliée."></p>
<figcaption>L’expo de Colin à Lyon</figcaption>
</figure>
</div>
</div>
</div>
</div>
<p>Je reviendrai sûrement aux rencontres du MFPP, et peut-être aussi à Lyon. Les deux conventions m’ont fait beaucoup progresser et même si j’ai des choses à reprocher à celle de Lyon, c’était quand même une bonne expérience globalement. Je tiens donc à adresser un grand merci aux deux équipes organisatrices, à Laurence qui m’a permis de ne pas me retrouver tout seul à Lyon, et à tous les participant·es qui m’ont chaleureusement accueilli aux deux endroits : j’ai très envie de citer des prénoms mais j’ai trop peur d’en oublier, donc je vais me contenter de dire à tous et toutes à très bientôt, et bon pli :)</p>


</section>

 ]]></description>
  <category>origami</category>
  <guid>https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/</guid>
  <pubDate>Mon, 10 Nov 2025 23:00:00 GMT</pubDate>
  <media:content url="https://normalesup.org/~andreani/blog/2025-11-09-ooraa-mfpp/souris.jpg" medium="image" type="image/jpeg"/>
</item>
<item>
  <title>Lost in regression</title>
  <dc:creator>Virgile Andreani</dc:creator>
  <link>https://normalesup.org/~andreani/blog/2024-07-lost-in-regression/</link>
  <description><![CDATA[ 






<p>I was recently very confused with a linear regression. More precisely, I realized that my mental model of a linear regression was completely wrong, even though linear regressions are not exactly a new thing to me.</p>
<p>If I gave you the scatter plot below, and asked you to draw the regression line, which line would you draw? The orange, the green, or the purple one?</p>
<div id="49041696" class="cell" data-execution_count="1">
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2024-07-lost-in-regression/index_files/figure-html/cell-2-output-1.png" width="779" height="395" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>My intuitive answer was to draw the purple one, the one that goes through the major axis of the ellipsoid-shaped cloud. Hence my surprise when I used a statistics programming library to compute the regression, and found the orange one.</p>
<section id="three-different-regression-lines" class="level1">
<h1>Three different regression lines</h1>
<p>It turns out that all three answers are correct, in some way. The purple line, the one aligned with the ellipse, is defined by the eigenvectors of the covariance matrix of the data. It is also known as <a href="https://en.wikipedia.org/wiki/Deming_regression">Deming regression</a>. Here, I used the covariance matrix</p>
<img src="https://latex.codecogs.com/png.latex?%5Cbegin%7Bpmatrix%7D1&amp;%5Cfrac%7B1%7D%7B2%7D%5C%5C%5Cfrac%7B1%7D%7B2%7D&amp;1%5Cend%7Bpmatrix%7D">
<p>whose eigenvectors are aligned with the diagonals <img src="https://latex.codecogs.com/png.latex?y%20=%20x"> and <img src="https://latex.codecogs.com/png.latex?y%20=%20-x">.</p>
<p>But a simple linear regression is doing something different. A way I like to reason about it is to think of the residuals of the regression, i.e.&nbsp;<img src="https://latex.codecogs.com/png.latex?y_i%20-%0A%5Cbeta_x%5C,x_i">, which squares are being minimized.</p>
<p>What minimizes the squares of the residuals is bringing the residuals as close to zero as possible. We can see that this isn’t the case for the purple curve: for example, at <img src="https://latex.codecogs.com/png.latex?x=2">, there are no samples above the purple curve, and plenty below. In contrast, the orange line goes through the “vertical center” of the points and results in much lower sum of squared residuals. I plotted these residuals below the same dataset with the same three lines, but where I subtract different values from <img src="https://latex.codecogs.com/png.latex?y">. Look at how the lines and dataset seem to transform!</p>
<p><video src="video.mp4" class="img-fluid" controls=""><a href="video.mp4">Video</a></video></p>
<p>I think that one reason for this mismatch between what we “want” to draw, and the actual regression line, comes from the fact that it might be easier to picture ourselves a rotation of the dataset than this linear translation.</p>
<p>As you may have guessed, the green line is the “other” regression line: the one that regresses <img src="https://latex.codecogs.com/png.latex?x"> on <img src="https://latex.codecogs.com/png.latex?y">, i.e.&nbsp;that makes <img src="https://latex.codecogs.com/png.latex?x_i%20-%20%5Cbeta_y%5C,y_i"> unbiased and independent from <img src="https://latex.codecogs.com/png.latex?y_i">. For this one to make sense, one would need to translate points horizontally instead of vertically.</p>
<p>Another property of these two regression lines is that they pass through the vertical and horizontal tangents of the contour ellipses of the distribution:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2024-07-lost-in-regression/tangents.png" class="img-fluid figure-img"></p>
<figcaption>Figure from the book <em>Applied Linear Regression Models</em> by Neter, Wasserman and Kutner.</figcaption>
</figure>
</div>
</section>
<section id="the-maths-behind-these-lines" class="level1">
<h1>The maths behind these lines</h1>
<p>I wanted to understand the relationships between these three regression lines, so I assumed a dataset constructed as follows:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbegin%7Balign*%7D%0Ax_i%20&amp;%5Csim%20%5Cmathrm%7BNormal%7D(0,%20%5Csigma_x)%5C%5C%0Ay_i%20&amp;%5Csim%20%5Cmathrm%7BNormal%7D(%5Cbeta_x%5C,x_i,%20%5Csigma_%7Bxy%7D)%5C%5C%0A%5Cend%7Balign*%7D"></p>
<p>Because of properties of the normal distribution, this creates a multivariate normal distribution with the following covariance matrix:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CSigma%20=%20%5Cbegin%7Bpmatrix%7D%0A%5Csigma_x%5E2%20&amp;%20%5Cbeta_x%5C,%5Csigma_x%5E2%5C%5C%0A%5Cbeta_x%5C,%5Csigma_x%5E2%20&amp;%20%5Cbeta_x%5E2%5C,%5Csigma_x%5E2+%5Csigma_%7Bxy%7D%5E2%5C%5C%0A%5Cend%7Bpmatrix%7D%0A"></p>
<p>Note that we could have obtained the same dataset if we had constructed the dataset starting from <img src="https://latex.codecogs.com/png.latex?y">, with</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbegin%7Balign*%7D%0Ay_i%20&amp;%5Csim%20%5Cmathrm%7BNormal%7D(0,%20%5Csigma_y)%5C%5C%0Ax_i%20&amp;%5Csim%20%5Cmathrm%7BNormal%7D(%5Cbeta_y%5C,y_i,%20%5Csigma_%7Byx%7D)%5C%5C%0A%5Cend%7Balign*%7D"></p>
<p>In that case, we would have obtained the following covariance matrix:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CSigma%20=%20%5Cbegin%7Bpmatrix%7D%0A%5Cbeta_y%5E2%5C,%5Csigma_y%5E2+%5Csigma_%7Byx%7D%5E2%20&amp;%20%5Cbeta_y%5C,%5Csigma_y%5E2%5C%5C%0A%5Cbeta_y%5C,%5Csigma_y%5E2%20&amp;%20%5Csigma_y%5E2%5C%5C%0A%5Cend%7Bpmatrix%7D%0A"></p>
<p>These two matrices being equal, we can identify their elements to obtain the expressions of one parameterization as a function of the other:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbegin%7Balign*%7D%0A%5Csigma_x%20&amp;=%20%5Csqrt%7B%5Cbeta_y%5E2%5C,%5Csigma_y%5E2+%5Csigma_%7Byx%7D%5E2%7D%5C%5C%0A%5Cbeta_x%20&amp;=%20%5Cfrac%7B%5Cbeta_y%5C,%5Csigma_y%5E2%7D%7B%5Cbeta_y%5E2%5C,%5Csigma_y%5E2+%5Csigma_%7Byx%7D%5E2%7D%5C%5C%0A%5Csigma_%7Bxy%7D%20&amp;=%20%5Cfrac%7B%5Csigma_y%5C,%5Csigma_%7Byx%7D%7D%7B%5Csqrt%7B%5Cbeta_y%5E2%5C,%5Csigma_y%5E2+%5Csigma_%7Byx%7D%5E2%7D%7D%5C%5C%0A%5Cend%7Balign*%7D"></p>
<p>Notably, the regression coefficient for <img src="https://latex.codecogs.com/png.latex?y%20=%20%5Cbeta_x%5C,x"> is in general <em>not</em> the inverse of the coefficient for the inverse regression <img src="https://latex.codecogs.com/png.latex?x%20=%20%5Cbeta_y%5C,y">! This is understandable in retrospect: <img src="https://latex.codecogs.com/png.latex?%5Cbeta_x"> is the slope of the orange line and <img src="https://latex.codecogs.com/png.latex?%5Cbeta_y"> the inverse slope of the green line, and these lines don’t correspond unless <img src="https://latex.codecogs.com/png.latex?%5Csigma_%7Bxy%7D%20=%20%5Csigma_%7Byx%7D%20=%200">.</p>
<hr>
<p>Thank you to Christian Luhmann and Bill Engels for pointing me to relevant resources to improve an earlier version of this post.</p>


</section>

 ]]></description>
  <category>statistics</category>
  <guid>https://normalesup.org/~andreani/blog/2024-07-lost-in-regression/</guid>
  <pubDate>Sun, 07 Jul 2024 22:00:00 GMT</pubDate>
</item>
<item>
  <title>Le FCSC sans se fatiguer</title>
  <dc:creator>Virgile Andreani</dc:creator>
  <link>https://normalesup.org/~andreani/blog/2022-05-le-fcsc-sans-se-fatiguer/</link>
  <description><![CDATA[ 






<p>C’est le printemps, la saison du <a href="https://www.france-cybersecurity-challenge.fr">France Cybersecurity Challenge</a> et donc de mon billet de blog annuel, apparemment. Organisé par l’<a href="https://www.ssi.gouv.fr">ANSSI</a>, l’agence de cybersécurité française, le FCSC est l’occasion de sélectionner les membres de l’équipe de France pour l’ECSC, le challenge européen. Le challenge est généreusement aussi ouvert aux vieux comme moi qui ne sont pas éligibles pour raisons d’âge<sup>1</sup>.</p>
<p>La diversité et l’originalité des épreuves en font facilement l’un de mes concours préférés. Je m’étais <a href="https://suboptimal.fr/2021-05-la-radio-pour-les-nuls/">beaucoup amusé</a> avec les épreuves hardware l’année dernière, et cette année j’ai eu à nouveau beaucoup de plaisir dans de multiples catégories d’épreuves, mais surtout en crypto.</p>
<p>Comme c’est de tradition, je prolonge le plaisir en me prêtant au jeu des <em>writeups</em> pour quelques unes des épreuves que j’ai le plus appréciées.</p>
<section id="hardware" class="level2">
<h2 class="anchored" data-anchor-id="hardware">Hardware</h2>
<section id="mommy-morse-77-résolutions" class="level3">
<h3 class="anchored" data-anchor-id="mommy-morse-77-résolutions">Mommy Morse (77 résolutions)</h3>
<p>Il est demandé de transmettre un signal en morse, où les points et les traits sont représentés par une «&nbsp;porteuse pure à une fréquence de 5&nbsp;kHz&nbsp;», et les espacements par une fréquence de 1&nbsp;kHz. Un signal d’exemple est fourni, et comme j’aime bien visualiser, j’ai fait un graphe:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2022-05-le-fcsc-sans-se-fatiguer/mommymorse_signal.svg" class="img-fluid figure-img"></p>
<figcaption>point trait point point ESPACE point etc.</figcaption>
</figure>
</div>
<p>Comme d’habitude, je trouve que tracer l’argument complexe du signal aide bien, parce que dans ce cas il évolue de manière linéaire (modulo le modulo <img src="https://latex.codecogs.com/png.latex?2%5Cpi">), avec une pente qui dépend de la fréquence de la porteuse. C’est exactement la manière dont je m’y suis pris pour créer le signal dont j’avais besoin&nbsp;: j’ai créé l’argument qu’il fallait, que j’ai mis dans une exponentielle complexe et c’est passé.</p>
</section>
</section>
<section id="crypto" class="level2">
<h2 class="anchored" data-anchor-id="crypto">Crypto</h2>
<section id="hash-ish-71-résolutions-et-khal-hash-10-résolutions" class="level3">
<h3 class="anchored" data-anchor-id="hash-ish-71-résolutions-et-khal-hash-10-résolutions">Hash-ish (71 résolutions) et Khal Hash (10 résolutions)</h3>
<p>Sûrement mes deux épreuves préférées :)</p>
<p>Hash-ish donne un entier <code>H</code> et demande de trouver deux entiers <code>a</code> et <code>b</code> tels que la valeur de <code>hash((a, b))</code> soit <code>H</code> (<code>hash</code> étant la fonction de hachage par défaut de Python).</p>
<p>Mais comment ça fonctionne, <code>hash</code>, d’abord&nbsp;? Pour les tuples, <a href="https://github.com/python/cpython/blob/f298ba1f2712ad10530a30bb225548a6889820b5/Objects/tupleobject.c#L321">son code est là</a> ou bien simplifié<sup>2</sup> ici en Python (<code>PH1</code>, <code>PH2</code> et <code>PH5</code> sont des constantes définies dans le code de CPython, et <code>MOD</code> vaut <img src="https://latex.codecogs.com/png.latex?2%5E%7B64%7D">)&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> myhash(integer_tuple: Tuple[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>, ...]):</span>
<span id="cb1-2">    acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PH5</span>
<span id="cb1-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> element <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> integer_tuple:</span>
<span id="cb1-4">        acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> element <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> PH2) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> MOD</span>
<span id="cb1-5">        acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ((acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">31</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> (acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">33</span>)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> MOD</span>
<span id="cb1-6">        acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> PH1) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> MOD</span>
<span id="cb1-7">    acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(t) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> (PH5 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3527539</span>)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> MOD</span>
<span id="cb1-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> acc</span></code></pre></div></div>
<p>C’est donc cette fonction qu’il faut inverser (on sait ce qu’elle doit retourner, et on veut savoir quel argument lui donner pour qu’elle fasse ça).</p>
<p>Entre <a href="https://github.com/Z3Prover/z3">Z3</a>, un «&nbsp;prouveur de théorèmes&nbsp;» développé par <em>Microsoft Research</em>. Plus précisément, c’est un solveur <a href="https://en.wikipedia.org/wiki/Satisfiability_modulo_theories">SMT</a>. Sans rentrer dans les détails, un solveur SMT est une généralisation d’un solveur <a href="https://en.wikipedia.org/wiki/Boolean_satisfiability_problem">SAT</a>. Alors qu’un solveur SAT détermine la satisfiabilité de formules logiques (avec des portes logiques et des booléens), un solveur SMT détermine la satisfiabilité de formules impliquant des objets plus complexes, comme des nombres ou des structures de données. Ici, c’est exactement ce qu’il faut&nbsp;: on a une formule mathématique à résoudre sur les entiers modulo <img src="https://latex.codecogs.com/png.latex?2%5E%7B64%7D">.</p>
<p>Z3 possède des variables de type entier, mais vu qu’ici on a des opérations sur des bits, j’ai préféré utiliser les <code>BitVec</code>s, qui sont comme leur nom l’indique des tableaux de bits de taille fixée, et sur lesequels on peut quand même faire des opérations arithmétiques facilement.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> solve(h):</span>
<span id="cb2-2">    N <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">64</span></span>
<span id="cb2-3">    s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.Solver()</span>
<span id="cb2-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a and b are the integers that we are looking for</span></span>
<span id="cb2-5">    a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.BitVec(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'a'</span>, N)</span>
<span id="cb2-6">    b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.BitVec(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b'</span>, N)</span>
<span id="cb2-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># they need to be less than 2**60, or they don't hash to themselves</span></span>
<span id="cb2-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ULT = Unsigned Less Than: `a &lt; 2**60` doesn't work unless we also add `0 &lt;= a`</span></span>
<span id="cb2-9">    s.add(z3.ULT(a, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>))</span>
<span id="cb2-10">    s.add(z3.ULT(b, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>))</span>
<span id="cb2-11">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># hashing the first integer</span></span>
<span id="cb2-12">    acc0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.BitVec(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc0'</span>, N)</span>
<span id="cb2-13">    s.add(acc0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> PH5 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> PH2)</span>
<span id="cb2-14">    acc1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.BitVec(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc1'</span>, N)</span>
<span id="cb2-15">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># LShR stands for Logical Shift Right, &gt;&gt; being the arithmetic one</span></span>
<span id="cb2-16">    s.add(acc1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> (acc0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">31</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> z3.LShR(acc0, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">33</span>))</span>
<span id="cb2-17">    acc2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.BitVec(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc2'</span>, N)</span>
<span id="cb2-18">    s.add(acc2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> acc1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> PH1)</span>
<span id="cb2-19">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># hashing the second integer</span></span>
<span id="cb2-20">    acc3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.BitVec(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc3'</span>, N)</span>
<span id="cb2-21">    s.add(acc3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> acc2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> PH2)</span>
<span id="cb2-22">    acc4 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.BitVec(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc4'</span>, N)</span>
<span id="cb2-23">    s.add(acc4 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> (acc3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">31</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> z3.LShR(acc3, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">33</span>))</span>
<span id="cb2-24">    acc5 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> z3.BitVec(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc5'</span>, N)</span>
<span id="cb2-25">    s.add(acc5 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> acc4 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> PH1)</span>
<span id="cb2-26">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the final hash value should be the one specified</span></span>
<span id="cb2-27">    s.add(h <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> acc5 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> (PH5 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3527539</span>)))</span>
<span id="cb2-28">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># calling the solver</span></span>
<span id="cb2-29">    sol <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s.check()</span>
<span id="cb2-30">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>(sol) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'sat'</span>:</span>
<span id="cb2-31">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a solution was found: return it</span></span>
<span id="cb2-32">        model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s.model()</span>
<span id="cb2-33">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (model.evaluate(a).as_long(), model.evaluate(b).as_long())</span></code></pre></div></div>
<p>Appelée avec <code>h = 42</code> (au hasard), la fonction retourne le tuple suivant: <code>(471024597674449489, 129304832457527322)</code>. On vérifie&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;&gt;&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">hash</span>((<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">471024597674449489</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">129304832457527322</span>))</span>
<span id="cb3-2"><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span></span></code></pre></div></div>
<p>Ça suffisait pour passer Hash-ish. En revanche, le grand frère Khal Hash est plus coriace. En effet, il demande toujours de trouver un tuple d’entiers dont le hash est une valeur donnée, mais avec la contrainte que les entiers doivent être des caractères ascii (compris entre 0 et 127). Or, deux entiers ne suffisent plus&nbsp;: en effet, le hash étant une valeur de 64 bits, il faut environ le même nombre de paramètres pour avoir une chance, soit environ 9 ou 10 entiers (puisque chacun a 7 bits utilisables et que <img src="https://latex.codecogs.com/png.latex?64%20/%207%20%5Capprox%209">). Z3 est malheureusement dépassé par ces contraintes (le problème est beaucoup plus <em>profond</em>&nbsp;: non seulement il y a plus de variables intermédiaires, mais aussi le chemin est plus long entre le hash final et l’entrée à trouver).</p>
<p>J’ai donc écrit une version optimisée de la fonction <code>hash</code> en Rust, qui tourne en une poignée de nanosecondes pour une entrée de 10 entiers. C’est rapide&nbsp;! Il ne reste plus qu’à essayer des tuples au hasard jusqu’à tomber sur la valeur qu’on voulait. Pas vrai&nbsp;? <em>Pas vrai&nbsp;?</em></p>
<p>On peut essayer d’estimer combien de temps ça peut prendre&nbsp;: la probabilité de tomber sur la valeur qu’on veut en hachant un tuple est environ <img src="https://latex.codecogs.com/png.latex?2%5E%7B-64%7D">. Donc la probabilité de ne pas tomber dessus est de <img src="https://latex.codecogs.com/png.latex?1-2%5E%7B-64%7D">. La probabilité de ne jamais être tombé dessus après avoir haché <img src="https://latex.codecogs.com/png.latex?n"> tuples est donc <img src="https://latex.codecogs.com/png.latex?(1-2%5E%7B-64%7D)%5En">. Quelle valeur doit avoir <img src="https://latex.codecogs.com/png.latex?n"> pour que cette probabilité soit assez basse, disons à <img src="https://latex.codecogs.com/png.latex?1/2">&nbsp;? La réponse est <img src="https://latex.codecogs.com/png.latex?n%20%5Capprox%202%5E%7B64%7D">, à peu de choses près. Même avec la fonction optimisée, ça prendrait plus de 2000 ans de hacher ce nombre de tuples<sup>3</sup>. Le FCSC ne durant que 10 jours, il faut trouver une autre technique.</p>
<p>La clé ici était de se rendre compte que les opérations de la fonction de hash sont toutes inversibles. En effet, reprenons la fonction ligne par ligne:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> element <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> PH2) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> MOD</span></code></pre></div></div>
<p>Pour inverser cette addition, il suffit de retirer <code>element * PH2</code> modulo <code>MOD</code> à <code>acc</code>.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ((acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">31</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> (acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">33</span>)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> MOD</span></code></pre></div></div>
<p>Cette ligne réalise en fait une rotation des bits de <code>acc</code>, de 33 bits vers la droite (ou 31 vers la gauche). Pour l’inverser, il suffit donc de faire la même rotation à l’envers.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> PH1) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> MOD</span></code></pre></div></div>
<p>Pour inverser cette multiplication, on multiplie <code>acc</code> par l’inverse modulaire de <code>PH1</code> modulo <code>MOD</code>. On peut calculer facilement cet inverse en python avec la fonction <code>pow</code> du langage: <code>pow(PH1, -1, MOD)</code>.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(t) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> (PH5 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3527539</span>)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> MOD</span></code></pre></div></div>
<p>La dernière ligne est également facile à inverser puisqu’il s’agit encore juste d’une addition.</p>
<p>Tout cela signifie qu’en partant de la valeur finale connue du hash, on peut prendre les éléments du tuple à l’envers et revenir à la valeur initiale de l’accumulateur <code>acc</code> (<code>PH5</code>). Mais chercher dans un sens ou dans l’autre ne change rien en termes de temps de calcul. L’astuce est de chercher par les deux bouts et de faire se retrouver la recherche au milieu.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2022-05-le-fcsc-sans-se-fatiguer/meetinthemiddle.jpeg" class="img-fluid figure-img" style="width:50.0%"></p>
<figcaption>Meet in the middle</figcaption>
</figure>
</div>
<p>Imaginons qu’on commence par le faisceau de droite, et qu’on enregistre tous ses points d’arrivée. Maintenant, le faisceau de gauche peut se raccorder non plus juste au point final, mais à chacun des <img src="https://latex.codecogs.com/png.latex?n"> points du faisceau de droite. On arrive ainsi à <img src="https://latex.codecogs.com/png.latex?n%20%5Capprox%202%5E%7B32%7D"> au lieu des <img src="https://latex.codecogs.com/png.latex?2%5E%7B64%7D"> de la première méthode, pour la même probabilité de succès. C’est un sacré progrès, et ça se calcule à présent en quelques secondes ou minutes au lieu de miliers d’années<sup>4</sup>.</p>
<p>En pratique, j’ai calculé tous les tuples de taille 4 en partant d’un côté, et cherché les tuples de taille 6 en partant de l’autre côté, et je suis tombé sur une solution en une ou deux minutes.</p>
</section>
<section id="t-rex-67-résolutions" class="level3">
<h3 class="anchored" data-anchor-id="t-rex-67-résolutions">T-Rex (67 résolutions)</h3>
<p>Je passe des détails, mais en gros on nous donnait le résultat de <img src="https://latex.codecogs.com/png.latex?F%5E%7B31337%7D(k)"> où <img src="https://latex.codecogs.com/png.latex?F"> est l’application <img src="https://latex.codecogs.com/png.latex?x%20%5Cmapsto%20(2x+1)x"> modulo <img src="https://latex.codecogs.com/png.latex?2%5E%7B128%7D">, et on veut remonter à <img src="https://latex.codecogs.com/png.latex?k"> qui est la clé de chiffrement du message. Après m’être rendu compte que <img src="https://latex.codecogs.com/png.latex?F"> était bijective, j’ai passé un bon moment à essayer de l’inverser à la main sans succès, avant de réaliser que je pouvais utiliser là aussi Z3 (31337 fois de suite).</p>
</section>
<section id="gaston-la-paffe-29-résolutions" class="level3">
<h3 class="anchored" data-anchor-id="gaston-la-paffe-29-résolutions">Gaston La Paffe (29 résolutions)</h3>
<p>On avait ici un algorithme de signature à base de polynomes, qui fonctionnait de la manière suivante (là aussi, j’omets des détails)&nbsp;:</p>
<ul>
<li><code>s1</code> et <code>s2</code> des polynomes choisis au hasard, constituent la clé privée&nbsp;;</li>
<li>On nous donne <code>a</code> et <code>t</code>, polynomes tels que <code>t = a*s1 + s2</code>&nbsp;;</li>
<li>Pour signer un message <code>m</code>, <code>y1</code> et <code>y2</code> sont d’abord générés aléatoirement. Puis on calcule <code>c = H(a*y1 + y2, m)</code> où <code>H</code> est une fonction à sens unique. Enfin, on retourne <code>z1 = s1*c + y1</code> et <code>z2 = s2*c + y2</code>, ainsi que <code>y1</code> «&nbsp;par erreur&nbsp;».</li>
</ul>
<p>Quelques calculs permettent de se rendre compte que connaître <code>y1</code> permet de trouver aussi <code>y2</code>:</p>
<pre><code>y2 = a*(z1 - y1) + z2 - t*c</code></pre>
<p>et qu’à partir de là, on a les équations</p>
<pre><code>s1 * c = z1 - y1
s2 * c = z2 - y2</code></pre>
<p>dans lesquelles on connaît toutes les variables à part les secrets <code>s1</code> et <code>s2</code>.</p>
<p>Pour trouver les coefficients des secrets, j’ai choisi d’utiliser <code>ortools</code>, une suite de solveurs développée par Google. Z3 aurait peut-être pu aussi fonctionner, mais il s’agissait ici en fait d’un problème de programmation linéaire sur les entiers, ce sur quoi <code>ortools</code> est plus efficace.</p>
</section>
</section>
<section id="side-channels-and-fault-attacks" class="level2">
<h2 class="anchored" data-anchor-id="side-channels-and-fault-attacks">Side Channels and Fault Attacks</h2>
<section id="never-skip-class-nor-multiplication-85-résolutions" class="level3">
<h3 class="anchored" data-anchor-id="never-skip-class-nor-multiplication-85-résolutions">Never Skip Class Nor Multiplication (85 résolutions)</h3>
<p>On avait accès à un oracle RSA chiffrant des messages choisis, à l’aide d’une fonction d’exponentiation modulaire «&nbsp;buguée&nbsp;» de manière à ce qu’on puisse choisir quelle multiplication elle allait sauter. L’objectif était de déterminer la clé privée <img src="https://latex.codecogs.com/png.latex?d"> (l’exposant de l’opération <img src="https://latex.codecogs.com/png.latex?c%20=%20m%5Ed%20%5Cmod%20n">).</p>
<p>La question à se poser est la suivante&nbsp;: Si je saute la multiplication du bit <img src="https://latex.codecogs.com/png.latex?k"> de la clé <img src="https://latex.codecogs.com/png.latex?d">, quel est l’exposant <img src="https://latex.codecogs.com/png.latex?d'"> qui a alors été utilisé&nbsp;?</p>
<pre><code>    Exposant d initial                       Exposant d' réel
N-1          K            0    skip K    N-1          K            0
[    dH    ] 0 [    dL    ]    -----&gt;    [    dH    ] 0 [    dL    ]

N-1          K            0    skip K    N-1          K            0
[    dH    ] 1 [    dL    ]    -----&gt;    [    dH    ] 0 [    dL    ]</code></pre>
<p>On remarque facilement que sauter un bit nul ne modifie pas l’exposant, alors que sauter un bit non-nul le change. Il suffit alors de demander à chiffrer le même message en sautant tous les bits un par un, et de comparer ces résultats à la situation où on ne saute aucun bit. On a alors une correspondance directe entre les résultats et la clé.</p>
</section>
<section id="never-skip-class-nor-squaring-70-résolutions" class="level3">
<h3 class="anchored" data-anchor-id="never-skip-class-nor-squaring-70-résolutions">Never Skip Class Nor Squaring (70 résolutions)</h3>
<p>Même principe, mais la fonction est buguée de manière à sauter l’étape de mise au carré. La question est la même&nbsp;: si on saute le bit <img src="https://latex.codecogs.com/png.latex?K"> de l’exposant <img src="https://latex.codecogs.com/png.latex?d">, quel exposant <img src="https://latex.codecogs.com/png.latex?d'"> a-t-on alors vraiment utilisé&nbsp;?</p>
<pre><code>    Exposant d initial                       Exposant d' réel
N-1          K            0    skip K    N-2        K            0
[    dH    ] 0 [    dL    ]    -----&gt;    [    dH    ] [    dL    ]

N-1          K            0    skip K    N-2        K            0
[    dH    ] 1 [    dL    ]    -----&gt;    [  dH + 1  ] [    dL    ]</code></pre>
<p>Grâce à quelques dessins dans ce genre, on se rend compte que peu importe la valeur du bit <img src="https://latex.codecogs.com/png.latex?K">, on a toujours <img src="https://latex.codecogs.com/png.latex?d%20-%20d'%20=%20d_H%20%5Ccdot%202%5EK">. Cette observation permet de déterminer <img src="https://latex.codecogs.com/png.latex?d"> bit par bit. En effet, si on appelle <img src="https://latex.codecogs.com/png.latex?c"> la vraie valeur de <img src="https://latex.codecogs.com/png.latex?m%5Ed%20%5Cmod%20n">, en sautant le bit <img src="https://latex.codecogs.com/png.latex?N-2"> on obtient pour <img src="https://latex.codecogs.com/png.latex?m%5E%7Bd'%7D"> deux valeurs possibles selon que le bit <img src="https://latex.codecogs.com/png.latex?N-1"> est nul ou non&nbsp;: soit <img src="https://latex.codecogs.com/png.latex?c"> (s’il est nul), soit <img src="https://latex.codecogs.com/png.latex?c%5Ccdot%20m%5E%7B-2%5E%7BN-2%7D%7D"> (s’il ne l’est pas). Armé de cette information, on saute alors le bit <img src="https://latex.codecogs.com/png.latex?N-3"> pour déterminer la valeur du bit <img src="https://latex.codecogs.com/png.latex?N-2">, etc.</p>
</section>
</section>
<section id="misc" class="level2">
<h2 class="anchored" data-anchor-id="misc">Misc</h2>
<section id="guess-me-too-68-résolutions" class="level3">
<h3 class="anchored" data-anchor-id="guess-me-too-68-résolutions">Guess Me Too (68 résolutions)</h3>
<p>Un nombre de 128 bits est tiré au hasard et il faut le deviner. On ne peut poser que 136 questions de la forme «&nbsp;Parmi les bits numéros <img src="https://latex.codecogs.com/png.latex?x_0">, <img src="https://latex.codecogs.com/png.latex?x_1">, <img src="https://latex.codecogs.com/png.latex?x_2">, etc. du nombre secret, quelle est la parité du nombre de bits non nuls&nbsp;?&nbsp;» (en choisissant les <img src="https://latex.codecogs.com/png.latex?x_i">). De plus, on sait qu’une des réponses sera fausse mais on ne sait pas laquelle.</p>
<p>Il semble logique de commencer par demander les 128 bits un à un. On a déjà presque 6% de chance d’avoir deviné le nombre (si la réponse incorrecte tombe dans les 8 autres questions), donc on pourrait déjà s’arrêter là et faire plusieurs tentatives jusqu’à ce que ça marche (17 fois en moyenne).</p>
<p>Pour deviner le nombre à coup sûr, il faut faire de la correction d’erreur.</p>
<p>On commence par demander la parité de la somme de tous les bits, et on compare avec le résultat des 128 premières questions. Si les résultats concordent, on sait qu’on n’est pas encore tombé sur la réponse incorrecte. Sinon, c’est qu’il y a une erreur soit dans les questions individuelles, soit dans la question de contrôle. Pour la déterminer, on demande alors la parité de la somme de tous les bits impairs, que l’on compare à nouveau au résultat des questions individuelles. On sait que le résultat de cette question sera correct, puisqu’on a déjà détecté une erreur et qu’il ne peut y en avoir qu’une seule. Si les résultats concordent, on sait que l’erreur est dans les bits pairs, sinon c’est qu’elle est dans les bits impairs. On peut alors continuer à préciser la position de l’erreur en demandant la parité de la somme des bits impairs des bits suspects d’être erronés, jusqu’à ce qu’il n’y ait plus qu’une seule possibilité.</p>
<p>En pratique, toutes les questions doivent être posées en même temps au début. Qu’à cela ne tienne, les huit questions supplémentaires à poser qui fonctionnent dans tous les cas sont les suivantes&nbsp;:</p>
<pre><code>11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010
11001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100
11110000111100001111000011110000111100001111000011110000111100001111000011110000111100001111000011110000111100001111000011110000
11111111000000001111111100000000111111110000000011111111000000001111111100000000111111110000000011111111000000001111111100000000
11111111111111110000000000000000111111111111111100000000000000001111111111111111000000000000000011111111111111110000000000000000
11111111111111111111111111111111000000000000000000000000000000001111111111111111111111111111111100000000000000000000000000000000
11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000</code></pre>
<p>Si on regarde par exemple la ligne <code>11001100...</code>, elle contient bien tous les bits impairs des bits impairs, ainsi que tous les bits impairs des bits pairs, et ainsi de suite.</p>
</section>
</section>
<section id="coda" class="level2">
<h2 class="anchored" data-anchor-id="coda">Coda</h2>
<p>Z3 et <code>ortools</code> se sont avérés être un arsenal efficace cette année, me permettant de résoudre 5 challenges (dont 4 de crypto) sans trop d’effort. Ils rendent aussi service en dehors du FCSC&nbsp;: ce sont des outils à connaître.</p>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>et qui ne l’ont d’ailleurs jamais été :’(↩︎</p></li>
<li id="fn2"><p>notamment en profitant du fait que <code>hash(n) == n</code> pour tout <code>n</code> entier inférieur à <img src="https://latex.codecogs.com/png.latex?2%5E%7B60%7D">↩︎</p></li>
<li id="fn3"><p>Et au bout du compte, on aurait encore une chance sur deux de ne pas avoir trouvé la bonne valeur…↩︎</p></li>
<li id="fn4"><p>C’est un exemple d’application du <a href="https://fr.wikipedia.org/wiki/Paradoxe_des_anniversaires">paradoxe des anniversaires</a>, un grand classique de la cryptanalyse, qui, en échange de la mémoire utilisée pour stocker des hashes, divise l’exposant du nombre de calculs à faire par deux.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>contest</category>
  <category>optimization</category>
  <guid>https://normalesup.org/~andreani/blog/2022-05-le-fcsc-sans-se-fatiguer/</guid>
  <pubDate>Sat, 07 May 2022 22:00:00 GMT</pubDate>
</item>
<item>
  <title>La radio pour les nuls</title>
  <dc:creator>Virgile Andreani</dc:creator>
  <link>https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/</link>
  <description><![CDATA[ 






<p>J’ai eu le plaisir de participer pour la deuxième année au <a href="https://www.france-cybersecurity-challenge.fr/">France Cybersecurity Challenge</a> organisé par l’<a href="https://www.ssi.gouv.fr">ANSSI</a>, l’agence de cybersécurité française. Parmi les épreuves proposées, une des catégories qui m’attirait le plus cette année était la catégorie “hardware”, dédiée à l’analyse de signaux radio. Le truc, c’est que je n’y connais absolument rien, et je n’avais pas le temps d’apprendre à me servir de <a href="https://www.gnuradio.org/">GNURadio</a>, le logiciel de référence du domaine. J’ai quand même réussi à être la première personne à valider <a href="https://www.france-cybersecurity-challenge.fr/challenges#B.A.%20BA-52">B.A. BA</a> (137 résolutions / 1732 joueurs), le deuxième à valider <a href="https://www.france-cybersecurity-challenge.fr/challenges#Phase%20%C3%A0%20phase-53">Phase à phase</a> (20 résolutions), et à avoir presque résolu <a href="https://www.france-cybersecurity-challenge.fr/challenges#Zodiaque-59">Zodiaque</a> (6 résolutions), tout ça en une soirée.</p>
<p>Malgré son titre, ce post n’est pas une explication de la radio logicielle, parce que je n’y connais toujours rien, c’est juste un writeup de ces trois épreuves sans autre prérequis que d’être à l’aise en Python.</p>
<section id="b.a.-ba" class="level1">
<h1>B.A. BA</h1>
<p>On a un fichier <code>challenge.iq</code> à analyser. IQ, qu’est-ce que c’est que ça&nbsp;? Google donne une page de la doc de <a href="https://pysdr.org/content/iq_files.html">PySDR</a>, qui dit que c’est des valeurs complexes qui décrivent le signal. Admettons. Ils disent aussi comment les lire avec <code>numpy</code> (tant mieux parce qu’on n’a pas le temps d’apprendre PySDR non plus)&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1">iqs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.fromfile(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'challenge.iq'</span>, np.complex64)</span>
<span id="cb1-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(iqs.shape)    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (3675100,)</span></span></code></pre></div></div>
<p>Bon, faisons un graphe. Ce sont des valeurs complexes donc on va tracer la partie réelle, imaginaire, le module et l’argument au cas où certaines représentations seraient plus intéressantes que d’autres.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">fig, axs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, sharex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb2-2">axs[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(np.real(iqs))</span>
<span id="cb2-3">axs[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].plot(np.imag(iqs))</span>
<span id="cb2-4">axs[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(iqs))</span>
<span id="cb2-5">axs[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].plot(np.angle(iqs))</span>
<span id="cb2-6">plt.show()</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/baba_plot_complex.svg" class="img-fluid figure-img"></p>
<figcaption>En zoomant un peu, ça ressemble à un signal</figcaption>
</figure>
</div>
<p>Donc il semblerait que ce soient des nombres soit grands, soit petits. Le module semble le plus pratique pour décider de ça. On va choisir de dire qu’au-dessus de 0.75 c’est grand, et en dessous c’est petit&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">discrete <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(iqs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span></span></code></pre></div></div>
<p>Maintenant, on a un tableau rempli de <code>True</code> et de <code>False</code>, et sur le graphe précédent ça a l’air de passer de l’un à l’autre quand même assez rarement. On va calculer les longueurs des groupes consécutifs de <code>True</code> et <code>False</code> avec <code>groupby</code>, une fonction du package <code>itertools</code>&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">signals <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [(value, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(group)))</span>
<span id="cb4-2">           <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> value, group <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> it.groupby(discrete)]</span>
<span id="cb4-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(signals[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>])</span>
<span id="cb4-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [(False, 4994), (True, 150), (False, 1000), (True, 500), (False, 999)]</span></span></code></pre></div></div>
<p>Regardons quelles sont les durées les plus fréquentes, pour les deux valeurs&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">sizesT <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Counter(l <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> v, l <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> signals <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> v)</span>
<span id="cb5-2">sizesF <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Counter(l <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> v, l <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> signals <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> v)</span>
<span id="cb5-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(sizesT)</span>
<span id="cb5-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Counter({150: 820, 500: 506, 499: 161, 149: 114, 151: 19, 501: 2})</span></span>
<span id="cb5-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(sizesF)</span>
<span id="cb5-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Counter({1000: 518, 999: 475, 3498: 472, 3499: 154, 3497: 2, 4994: 1, 3489: 1})</span></span></code></pre></div></div>
<p>Donc les valeurs <code>True</code> sont là en paquets de 150±1 et 500±1, et les valeurs <code>False</code> en paquets de 1000±1 et 3500±2. Le sujet parle de Morse, donc probablement 150 c’est un point, 500 un trait, 1000 ça doit être la séparation entre les symboles, et 3500 c’est entre deux lettres. Il reste donc à traduire ça en texte&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>.join((<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'.'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> l <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'-'</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> v <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">' '</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> l <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>)</span>
<span id="cb6-2">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> v, l <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> signals)</span>
<span id="cb6-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(m)    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  .-.. . -.-. --- -.. . -- --- etc.</span></span></code></pre></div></div>
<p>On copie-colle ça dans <a href="https://www.dcode.fr/code-morse">dcode</a> et on a le premier flag.</p>
</section>
<section id="phase-à-phase" class="level1">
<h1>Phase à phase</h1>
<p>Encore un fichier <code>challenge.iq</code>. Cette fois, on sait déjà le lire et faire un premier graphe.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/pap_plot_complex.svg" class="img-fluid figure-img"></p>
<figcaption>Cette fois-ci c’est un peu moins clair</figcaption>
</figure>
</div>
<p>Cette fois-ci, le module semble constant, c’est l’argument qui fait des choses étranges. Même son de cloche pour les parties réelle et imaginaire qui semblent décrire une sinusoïde qui change de phase brutalement, et assez souvent. Comme c’est le titre de l’épreuve, j’imagine que les données sont encodées ici dans ces changements de phase.</p>
<p>En tout cas on n’est pas encore très avancé. La page de tout à l’heure suggérait une autre représentation, en “constellation”. Allez, essayons ça&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">plt.plot(np.real(iqs), np.imag(iqs), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'.'</span>)</span>
<span id="cb7-2">plt.show()</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/pap_plot_constellation.svg" class="img-fluid figure-img"></p>
<figcaption>Ouah&nbsp;! Alors ça c’est joli</figcaption>
</figure>
</div>
<p>Ok&nbsp;! On voit bien le module constant, et là on découvre que l’argument est discrétisé, et ne peut prendre que 20 valeurs. Ça doit être parce que la fréquence d’échantillonnage est un multiple de la fréquence d’émission. Bon, il est évident qu’il faut discrétiser ça&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">discrete <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.angle(iqs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>), <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb8-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(discrete[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>])</span>
<span id="cb8-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [ 3  4  5  6  7  8  9 10 -9 -8 -7 -6 -5  6  7  8  9 10 -9 -8]</span></span></code></pre></div></div>
<p>C’est une suite qui a l’air d’être incrémentée de 1 en général, et parfois de nombres plus grands. Analysons donc les différences successives.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(Counter(discrete[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> discrete[:<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]))</span>
<span id="cb9-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Counter({1: 18228, -19: 1014, 11: 490, -9: 483})</span></span></code></pre></div></div>
<p>Comme il semblait, la plupart du temps on a un incrément de 1. De temps en temps on a un saut de <code>-19 = 1 - 20</code> à cause du modulo, et parfois on a des sauts de <code>11 = 1 + 10</code> ou <code>-9 = 1 - 10</code>, qui sont visiblement des inversions de phase. A priori, une différence de <code>11</code> ou de <code>-9</code>, c’est la même chose modulo 20. Donc reprenons ça proprement&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">differences <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (discrete[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> discrete[:<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span></span>
<span id="cb10-2">plt.plot(differences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'.-'</span>)</span>
<span id="cb10-3">plt.show()</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/pap_plot_differences.svg" class="img-fluid figure-img"></p>
<figcaption>Et voilà le signal</figcaption>
</figure>
</div>
<p>Bon, on a des périodes longues ou courtes en bas, et apparemment en haut c’est toujours un seul point. On peut vérifier avec un <code>groupby</code> ici aussi&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">signals <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [(value, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(group)))</span>
<span id="cb11-2">           <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> value, group <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> it.groupby(differences)]</span>
<span id="cb11-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(Counter(signals))</span>
<span id="cb11-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Counter({(10, 1): 973, (0, 15): 682, (0, 31): 290, (0, 12): 1, (0, 10): 1})</span></span></code></pre></div></div>
<p>C’est correct. On pourrait être tenté de décoder ça avec un 0 pour les courtes (15) et un 1 pour les longues (31), ou inversement, mais là il faut lire l’énoncé, qui donne un indice&nbsp;: <a href="https://en.wikipedia.org/wiki/Manchester_code">Manchester</a>. On voit sur la page qu’en effet, un code Manchester est constitué de périodes courtes (une unité), et des longues (deux unités). On dirait qu’on est sur la bonne voie&nbsp;!</p>
<p>En réfléchissant un peu avec la figure de Wikipédia, je me rends compte qu’une période longue signifie qu’on change de symbole (0 à 1, ou 1 à 0), et deux périodes courtes (qui viennent toujours par deux) signifient qu’on ne change pas de symbole (si on était à 0, on reste à 0, et pareil pour 1). Avec cette technique, on ne sait pas de quel symbole on démarre, mais ce n’est pas grave&nbsp;: il n’y en a que deux (0 et 1), on peut essayer les deux si besoin.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb12-2">i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb12-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(signals):</span>
<span id="cb12-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> signals[i][<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>:</span>
<span id="cb12-5">        data.append(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> data[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb12-6">        i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb12-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb12-8">        data.append(data[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb12-9">        i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb12-10">msg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>.join(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>(x) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> data)</span>
<span id="cb12-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(msg[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>])</span>
<span id="cb12-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 10110011100101100001011000100011001101100011001101</span></span></code></pre></div></div>
<p>On a la suite de bits, qu’il faut maintenant transformer en texte&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">bytes</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(msg[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>i:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(msg)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span>
<span id="cb13-2">text <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s.decode(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'utf8'</span>, errors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ignore'</span>)</span>
<span id="cb13-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(s)</span>
<span id="cb13-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ƞɝƞƙʙʛƙȝΜϙȚϞʛǂ</span></span></code></pre></div></div>
<p>Hmm. Ça n’a pas l’air d’être ça. Essayons d’inverser les 0 et les 1&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">msg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>.join(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>x) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> data)</span>
<span id="cb14-2">s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">bytes</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(msg[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>i:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(msg)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span>
<span id="cb14-3">text <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s.decode(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'utf8'</span>, errors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ignore'</span>)</span>
<span id="cb14-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(s)</span>
<span id="cb14-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># FCSC{9ab3c6bc...}</span></span></code></pre></div></div>
<p>Et voilà un deuxième flag&nbsp;!</p>
</section>
<section id="zodiaque" class="level1">
<h1>Zodiaque</h1>
<p>C’était l’épreuve la plus difficile de cette catégorie. Je n’ai pas réussi à la terminer pendant la compétition, mais en lisant des writeups après coup je me suis rendu compte que j’étais vraiment très proche, et j’ai juste eu à changer un seul nombre dans mon code pour obtenir le flag. Même principe, on démarre encore avec un fichier <code>challenge.iq</code>.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/zodiaque_plot_complex.svg" class="img-fluid figure-img"></p>
<figcaption>L’argument semble intéressant</figcaption>
</figure>
</div>
<p>Alors là, les parties réelle et imaginaires ne sont d’aucun secours, le module est un peu bizarre, mais l’argument est clairement intéressant. Il est discrétisé en semble-t-il quatre valeurs, qui varient linéairement dans le temps. Je vois une discrétisation dans un signal analogique, je suis content parce que ça sent le signal numérique. Commençons par retirer cette dérive. On dérive de <code>2pi</code> en 1000 points de temps, donc on peut construire une fonction linéaire qui a cette dérivée, modulo <code>2pi</code>, et la soustraire de l’argument pour avoir des valeurs stables&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1">refs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(iqs)) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>np.pi) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.pi</span>
<span id="cb15-2">plt.plot(np.angle(iqs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> refs)</span>
<span id="cb15-3">plt.show()</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/zodiaque_plot_argument_redresse.svg" class="img-fluid figure-img"></p>
<figcaption>On voit mieux les valeurs discrétisées</figcaption>
</figure>
</div>
<p>C’est un peu moche parce qu’on a pris un modulo, mais c’est mieux pour discrétiser. En zoomant encore un peu, on se rend compte que c’est moins discret que ça en a l’air, et il y a en fait des points partout.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/zodiaque_plot_argument_redresse_zoom.svg" class="img-fluid figure-img"></p>
<figcaption>Pas si discret que ça</figcaption>
</figure>
</div>
<p>Il va falloir sous-échantillonner. Les transitions brutales semblent être des artefacts du modulo. Les maximums et minimums “doux” semblent plus fiables. On compte les points entre deux maximums ou minimums&nbsp;: c’est toujours un multiple de 8. Ça semble donc bien de prendre un point sur 8. Un peu de tâtonnement à la main plus tard pour trouver le bon offset&nbsp;:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/zodiaque_plot_argument_redresse_zoom_subsampled.svg" class="img-fluid figure-img"></p>
<figcaption>Ça semble correct</figcaption>
</figure>
</div>
<p>On dézoome un peu pour vérifier que ça marche toujours&nbsp;:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/zodiaque_plot_argument_redresse_subsampled.svg" class="img-fluid figure-img"></p>
<figcaption>Ça commence à ressembler à quelque chose</figcaption>
</figure>
</div>
<p>Donc reprenons proprement&nbsp;:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">subsample <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (np.angle(iqs) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> refs)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>::<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>]</span>
<span id="cb16-2">discrete <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> subsample <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.pi), <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb16-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(discrete[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>])</span>
<span id="cb16-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [2 1 0 2 2 0 1 1 3 3 3 2 0 0 3 0 2 0 1 2]</span></span>
<span id="cb16-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(Counter(discrete))</span>
<span id="cb16-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Counter({0: 4159, 1: 3053, 2: 2911, 3: 1976})</span></span></code></pre></div></div>
<p>Il y a un peu plus de 0 et un peu moins de 3 que le reste, mais ce n’est pas déraisonnable. J’ai envie de décoder ces quatre valeurs avec <code>00, 01, 10, 11</code> mais dans quel ordre&nbsp;? Il n’y a que 24 possibilités, essayons-les toutes. <sup>1</sup> On sait qu’il y a <code>FCSC</code> dans le texte donc servons-nous en.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">decode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'00'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'01'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'10'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'11'</span>]</span>
<span id="cb17-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> perm <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> it.permutations(decode):</span>
<span id="cb17-3">    msg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>.join(perm[x] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> discrete)</span>
<span id="cb17-4">    s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">bytes</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(msg[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>i:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(msg)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span>
<span id="cb17-5">    text <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s.decode(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'utf8'</span>, errors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ignore'</span>)</span>
<span id="cb17-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> text.find(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'FCSC'</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:</span>
<span id="cb17-7">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(text)</span></code></pre></div></div>
<p>Et voilà comment on obtient un troisième flag. C’était l’étape de sous-échantillonnage dont je n’avais pas réussi à trouver les paramètres pendant le concours.</p>
</section>
<section id="coda" class="level1">
<h1>Coda</h1>
<p>J’ai eu de la chance que 15 lignes de Python suffisent pour ces épreuves cette année, mais pour en savoir plus je recommande fortement la lecture de writeups plus sérieux (<a href="https://github.com/PVaub/FCSC2021">exemple</a>) où on apprend à faire les choses correctement.</p>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>En fait, il faudrait aussi idéalement itérer sur l’offset (4 valeurs possibles) parce qu’on ne sait pas si le premier symbole que l’on reçoit est au début d’un octet ou au milieu.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>radio</category>
  <category>contest</category>
  <guid>https://normalesup.org/~andreani/blog/2021-05-la-radio-pour-les-nuls/</guid>
  <pubDate>Fri, 14 May 2021 22:00:00 GMT</pubDate>
</item>
<item>
  <title>Guessing lottery game</title>
  <dc:creator>Virgile Andreani</dc:creator>
  <link>https://normalesup.org/~andreani/blog/2019-05-guessing-game/</link>
  <description><![CDATA[ 






<p>I found a fun problem <a href="https://www.reddit.com/r/dataisbeautiful/comments/acow6y/asking_over_8500_students_to_pick_a_random_number/eda56jd">on reddit</a> some time ago:</p>
<blockquote class="blockquote">
<p>A number is randomly selected between two bounds. Each player can make one guess, the closest to the selected number wins.</p>
</blockquote>
<p>The author of this comment notes that they “always use a random number generator for [their] pick rather than guessing to avoid accidentally clustering with others”. This relies on the idea illustrated by this reddit thread, that people tend to favour the same numbers when asked to make a random choice, thus generating non-uniform distributions that can create lumps. Picking a number from a uniform distribution might then increase the chances to pick it in a less preferred region, and thus, the chances to be the closest from the target.</p>
<p>But could we do better than that? What is the optimal strategy?</p>
<section id="against-unbiased-opponents" class="level1">
<h1>Against unbiased opponents</h1>
<p>We could start assuming that the opponents are unbiased and all pick numbers from the uniform distribution on the allowed range. Knowing that, where should we play?</p>
<p>First of all, we should decide on a couple of details on the lottery that we will be modelling: discrete (we can pick any integer from <img src="https://latex.codecogs.com/png.latex?1"> to <img src="https://latex.codecogs.com/png.latex?N"> included), or continuous (we can pick any real number between <img src="https://latex.codecogs.com/png.latex?0"> and <img src="https://latex.codecogs.com/png.latex?1">, and what should we do in case of tie. These rules lead to slightly different behaviours, but I suggest we study both the discrete and continuous cases. Ties will not happen in the continuous case, but in the discrete case, we could either</p>
<ul>
<li>give a whole prize to everyone tied first;</li>
<li>make another lottery among only the people tied first, and repeatedly until only one person remains;</li>
<li>split the prize equally between the people tied first;</li>
<li>decide that everyone lost.</li>
</ul>
<p>The second case is a bit more delicate to study because it would be reasonable to allow a change of strategy between the rounds, depending on the number of opponents, so I propose that we restrain ourselves to the simple cases where ties cause the prize to be either multiplied, split, or destroyed.</p>
<section id="discrete-case" class="level2">
<h2 class="anchored" data-anchor-id="discrete-case">Discrete case</h2>
<p>We are searching for the winning expectancy <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7BE%7D(N,K,C)"> against <img src="https://latex.codecogs.com/png.latex?K"> opponents, if we play at <img src="https://latex.codecogs.com/png.latex?C"> (between <img src="https://latex.codecogs.com/png.latex?1"> and <img src="https://latex.codecogs.com/png.latex?N">).</p>
<p>Assume the selected number is <img src="https://latex.codecogs.com/png.latex?S">. Then we can count the number <img src="https://latex.codecogs.com/png.latex?N_="> of numbers <img src="https://latex.codecogs.com/png.latex?X"> at the same distance from the target as we are: such that <img src="https://latex.codecogs.com/png.latex?%7CX-S%7C%0A=%20%7CC-S%7C">. This will be <img src="https://latex.codecogs.com/png.latex?1"> or <img src="https://latex.codecogs.com/png.latex?2">. We can also count the number <img src="https://latex.codecogs.com/png.latex?N_%5Cgt"> of numbers <img src="https://latex.codecogs.com/png.latex?X"> farther from the target than we are: such that <img src="https://latex.codecogs.com/png.latex?%7CX-S%7C%20%5Cgt%20%7CC-S%7C">. If <img src="https://latex.codecogs.com/png.latex?E"> of our opponents are at the same distance from the target as we are, and all the others are farther, then in case we split the prize, we win <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B1%7D%7BE+1%7D"> of the prize. This happens with probability <img src="https://latex.codecogs.com/png.latex?%5Cbinom%7BK%7D%7BE%7D%20%5Cleft(%5Cfrac%7BN_=%7D%7BN%7D%5Cright)%5EE%0A%5Cleft(%5Cfrac%7BN_%5Cgt%7D%7BN%7D%5Cright)%5E%7BK-E%7D"> for given <img src="https://latex.codecogs.com/png.latex?C"> and <img src="https://latex.codecogs.com/png.latex?S">. The total winning expectancy is then</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbf%7BE%7D(N,K,C)%20=%20%5Cfrac%7B1%7D%7BN%7D%5Csum_%7BS=1%7D%5E%7BN%7D%7B%0A%20%20%20%20%5Csum_%7BE=0%7D%5E%7BK%7D%7B%0A%20%20%20%20%5Cfrac%7B%5Cbinom%7BK%7D%7BE%7D%20%5Cleft(%5Cfrac%7BN_=(C,S)%7D%7BN%7D%5Cright)%5EE%0A%20%20%20%20%5Cleft(%5Cfrac%7BN_%3E(C,S)%7D%7BN%7D%5Cright)%5E%7BK-E%7D%7D%7BE+1%7D%0A%20%20%20%20%7D%0A%7D%0A"></p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-guessing-game/lottery_fdiscrete1.svg" class="img-fluid figure-img"></p>
<figcaption>Expectancy to win in the uniform discrete case if the prize is split between the exaequos, for N=10</figcaption>
</figure>
</div>
<p>From this graph, we indeed win every time when we have no opponent, we win less often as the number of opponents increases, and picking the middle region seems in general to be a good choice.</p>
<p>But as the number of opponents goes up, the winning expectancy goes down and it becomes more difficult to distinguish the strategy. To make it appear more clearly, I will normalize each curve such that their integrals are equal (more precisely I divide them by the total winning expectancy for this number of opponents).</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-guessing-game/lottery_fdiscrete2.svg" class="img-fluid figure-img"></p>
<figcaption>Strategies for the uniform discrete case if the prize is split between the exaequos, for N=10</figcaption>
</figure>
</div>
<p>What jumps to the eye is that for enough opponents, the best strategy is not to play in the middle any more. We can also note that the strategies against 1 or 2 opponents are identical. Finally, when the number of opponents becomes very large, the best strategy becomes to chose uniformly: indeed in this case all the numbers will probably have been chosen by several people, so that we only win if we pick exactly the selected number.</p>
<p>Similar reasoning allows to obtain formulas for the other rules:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-guessing-game/lottery_uniform.svg" class="img-fluid figure-img"></p>
<figcaption>Strategies for the uniform discrete case, for N=10</figcaption>
</figure>
</div>
</section>
<section id="continuous-case" class="level2">
<h2 class="anchored" data-anchor-id="continuous-case">Continuous case</h2>
<p>A closed-form formula is easier to find for the continuous case: following a similar reasoning, the winning expectancy if we play at <img src="https://latex.codecogs.com/png.latex?x%5Cin%5B0,1%5D"> against <img src="https://latex.codecogs.com/png.latex?K"> opponents is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbf%7BE%7D(K,%20x)%20=%20%5Cfrac%7B2+x%5EK(1+K-x%5C,(2+K))+(1-x)%5EK(x%5C,(2+K)-1)%7D%7B2%5C,(1+K)%7D%0A"></p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-guessing-game/lottery_fcontinuous1.svg" class="img-fluid figure-img"></p>
<figcaption>Expectancy to win in the continuous case</figcaption>
</figure>
</div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-guessing-game/lottery_fcontinuous2.svg" class="img-fluid figure-img"></p>
<figcaption>Strategies in the continuous case</figcaption>
</figure>
</div>
<p>A small advantage seems to subsist in the continuous case, since we can make a guess as close to the border as we want. The positions of the two peaks of the strategy <img src="https://latex.codecogs.com/png.latex?p(K)"> and <img src="https://latex.codecogs.com/png.latex?1-p(K)"> are such that <img src="https://latex.codecogs.com/png.latex?p(K)%5Csim%5Cfrac%7B2%7D%7B2+K%7D"> when <img src="https://latex.codecogs.com/png.latex?K"> tends to infinity, and <img src="https://latex.codecogs.com/png.latex?(1+K)%5C%5C,%5Cmathbf%7BE%7D(K,p(K))%20=%0A(1+K)%5C%5C,%5Cmathbf%7BE%7D(K,1-p(K))%20%5Cto%201+%5Cfrac%7B1%7D%7B2%5C%5C,%5Cmathrm%7Be%7D%5E2%7D%20%5Capprox%0A1.068">, the demonstration of these properties is left as an exercise to the reader.</p>
</section>
</section>
<section id="back-to-the-real-world" class="level1">
<h1>Back to the real world</h1>
<p>Ok but the point of the reddit post was that humans don’t pick numbers uniformly. What does everything become if the selected number is still uniformly random, but the opponents pick at random according to the distribution given in the post (favouring 7 and choosing infrequently 10 or 1)?</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-guessing-game/lottery_realworld.svg" class="img-fluid figure-img"></p>
<figcaption>Strategies for the real world, for N=10</figcaption>
</figure>
</div>
<p>Depending on the rules of the lottery, it is either beneficial to pick the 7, or to avoid the 7. Until at some point, the less preferred numbers 10 and 1 become the best options, at least in the versions that encourage winning alone (all ties lose, and to a lesser extent all ties split).</p>
<p>But as nice as all this seems, I wouldn’t encourage betting your house with this strategy. Indeed, it assumes random opponents and is not protected against smart opponents which might observe you play a couple of times and adapt their strategy accordingly. To handle this kind of adversaries, we can’t play the same number every time: a constant strategy would be too easy to exploit. We then need a mixed strategy, which is a probability distribution over our possible actions. This will be for another post.</p>


</section>

 ]]></description>
  <category>optimization</category>
  <category>game theory</category>
  <guid>https://normalesup.org/~andreani/blog/2019-05-guessing-game/</guid>
  <pubDate>Tue, 14 May 2019 22:00:00 GMT</pubDate>
</item>
<item>
  <title>Stockholm visit guide</title>
  <dc:creator>Virgile Andreani</dc:creator>
  <link>https://normalesup.org/~andreani/blog/2019-05-stockholm/</link>
  <description><![CDATA[ 






<p>I spent two weeks in Stockholm, one of them dedicated to visiting the city. Here are some notes that could be useful for travelers. It is not at all exhaustive though, but just the result of my tastes and peregrinations. I would appreciate to know if you think I missed interesting places!</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/vasa_kyrkan.jpg" class="img-fluid figure-img"></p>
<figcaption>The Gustav Vasa church in Vasastan</figcaption>
</figure>
</div>
<section id="if-you-are-in-a-hurry-my-top-3" class="level1">
<h1>If you are in a hurry, my top 3</h1>
<ul>
<li><em>Östermalms saluhall</em>;</li>
<li><em>Nordiska museet</em> after 13 o’clock;</li>
<li><em>Historiska museet</em>.</li>
</ul>
</section>
<section id="general-tips" class="level1">
<h1>General tips</h1>
<ul>
<li>1 EUR {{katex(body=“”)}} 10&nbsp;SEK, local currency can be withdrawn at the airport (and at least with my bank, it is cheaper to withdraw directly in SEK rather than accept the offered conversion in EUR, which includes a significant change tax);</li>
<li>“Hello” = “Hej” or “Hejhej”, pronounced not too far from the american “Hey”; “Thank you” = “Tack”, but almost everyone is willing and able to help in English anyway;</li>
<li>Museums have a tendency to open late (10-11&nbsp;AM) and close early (4-5&nbsp;PM);</li>
<li>Single metro tickets bought at machines in metro stations are very expensive (45&nbsp;SEK). If you buy one anyway, you obtain a paper ticket that you are supposed to show to the clerk to enter the metro. It is cheaper to buy a rechargable card for 20&nbsp;SEK (lasts for life) at the counter and charge it with trips.</li>
<li>Some metro stations are really pretty. But in general I prefer walking, which is especially suitable in Stockholm since the city is not too large. Walking is also the only way to stumble on random places that one wouldn’t have discovered otherwise. Be aware though that Stockholm is a relatively hilly city and some of the paved streets in the old city are in a rather poor condition, so good shoes and a good physical condition are appropriate.</li>
<li>Stockholm is spread over a handful of islands of different sizes and ambiances, whose main ones are:
<ul>
<li>the continent,
<ul>
<li>Kungsholmen (“The King’s islet”), where my hostel was, but not the island that I found the most interesting,</li>
<li>Gamla Stan (the old city) with the King’s palace, a lot of old paved streets, tiny passages and many tourists. Consequently, it is not the place where the food is the cheapest.
<ul>
<li>Riddarholmen (“The Knights’ islet”), a small island with mostly administrative buildings and courthouses, but it is prettier than it sounds,</li>
</ul></li>
<li>Skeppsholmen (“The islet of the ships”),</li>
<li>Djurgården (“The animal park”), also nicknamed “museum island”,</li>
<li>Södermalm.</li>
</ul></li>
</ul></li>
</ul>
</section>
<section id="points-of-interest" class="level1">
<h1>Points of interest</h1>
<section id="continent" class="level2">
<h2 class="anchored" data-anchor-id="continent">Continent</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/observatory.jpg" class="img-fluid figure-img"></p>
<figcaption>Stockholm’s 18th century observatory</figcaption>
</figure>
</div>
<ul>
<li><a href="https://www.openstreetmap.org/#map=18/59.33458/18.09006">Historiska museet</a> Museum of the history of Sweden, free and interesting;</li>
<li><a href="https://www.openstreetmap.org/#map=19/59.33594/18.07908">Östermalms saluhall</a> Covered market, closed on Sundays. It is a <em>very</em> nice place to buy all kinds of fancy food (fish, meat, bread), and also to eat traditional Swedish meals that can be heated up and served on the spot. It is in a temporary location until winter 2020, while the historical building is being renovated. Without contest one of my very favourite places in Stockholm;</li>
<li><a href="https://www.openstreetmap.org/#map=17/59.34182/18.05457">The observatory hill</a> Nice point of view to see the sunrise over Stockholm;</li>
<li><a href="https://www.openstreetmap.org/#map=19/59.34792/18.07239">KTH library</a> seems open to everyone, is a pretty nice building and is a nice place to study, or prepare the rest of the day;</li>
<li><a href="https://www.openstreetmap.org/#map=19/59.35008/18.06806">KTH R1</a> The dismantled (and safe) remains of the first nuclear reactor in Sweden. It is now used as a culture center and exhibitions and parties are regularly organized there.</li>
</ul>
</section>
<section id="kungsholmen" class="level2">
<h2 class="anchored" data-anchor-id="kungsholmen">Kungsholmen</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/city_hall.jpg" class="img-fluid figure-img"></p>
<figcaption>Stockholm’s city hall</figcaption>
</figure>
</div>
<ul>
<li><a href="https://www.openstreetmap.org/#map=18/59.32742/18.05477">The city hall</a> is open to visits during the summer, but the view from under the archs is very pretty all year long. This is where the Nobel gala dinner is served on December 10th. Fun fact: the restaurant is open all year long and can serve the menu from any given year’s gala, on the porcelain actually used for the banquet.</li>
</ul>
</section>
<section id="gamla-stan" class="level2">
<h2 class="anchored" data-anchor-id="gamla-stan">Gamla Stan</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/riksdag.jpg" class="img-fluid figure-img"></p>
<figcaption>The Swedish parliament, not exactly on Gamla Stan but close enough</figcaption>
</figure>
</div>
<p>Not my favourite part of the city: too many tourists.</p>
<ul>
<li><a href="https://www.openstreetmap.org/#map=19/59.32677/18.07168">The royal palace</a>, the official residence of the royal family (but they don’t usually live here) can be visited. As for the city hall, it is a massive building but finely decorated inside. Watching the changing of the guard in the palace’s courtyard is a fun attraction;</li>
<li><a href="https://www.openstreetmap.org/#map=19/59.32527/18.07066">The Nobel museum</a> was a little bit underwhelming but I probably had too high expectations. It is rather small, presents two showcases about Alfred Nobel, a temporary exhibition and a permanent collection of some of the personal items that the Nobel laureates are invited to donate to the museum. Among them, the scarf that Malala Yousafzai wore during her speech at UN, Geim and Novoselov’s original scotch tape dispenser, or the sample jar Barry Marshall drank his <em>Helicobacter pylori</em> broth from, but also a trumpet, a calculator, an abacus belonging to the laureates… Most notably, some of the prize diplomas were also exposed. Each of them is unique, and are expectedly some of the finest works of art there are, drawn and colored by hand by Swedish artists. They also have a video room with short introductions to the work of the laureates playing in random order: I could have spent hours in this room…</li>
</ul>
</section>
<section id="riddarholmen" class="level2">
<h2 class="anchored" data-anchor-id="riddarholmen">Riddarholmen</h2>
<ul>
<li><a href="https://www.openstreetmap.org/#map=19/59.32466/18.06461">Riddarholmskyrkan</a> The visit costs a couple dozens of crowns, but I recommend it. This church is the sepulchre of the royal family. It is better to see it after the visit of <em>Historiska museet</em> to have some of the genealogy in mind (it doesn’t help that everyone is named Gustav).</li>
</ul>
</section>
<section id="skeppsholmen" class="level2">
<h2 class="anchored" data-anchor-id="skeppsholmen">Skeppsholmen</h2>
<ul>
<li><a href="https://www.openstreetmap.org/#map=19/59.32738/18.08182">The museum of east-asian art</a>: free and open late (20 o’clock). I have seen a nice exhibition on traditional paper making in asian countries, and the Japan section of the museum appealed to me. The museum also hosts an extensive collection of ancient chinese books (not that I could read them);</li>
<li><a href="https://www.openstreetmap.org/#map=19/59.32631/18.08400">Moderna museet</a> that I didn’t have time to visit.</li>
</ul>
</section>
<section id="djurgården" class="level2">
<h2 class="anchored" data-anchor-id="djurgården">Djurgården</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/nordiska.jpg" class="img-fluid figure-img"></p>
<figcaption>Nordiska museet, the museum of Nordic life</figcaption>
</figure>
</div>
<ul>
<li><a href="https://www.openstreetmap.org/#map=18/59.32912/18.09367">Nordiska museet</a>: go in the afternoon, it is free after 13 o’clock. This is the museum of nordic life and exposes the daily life of Swedes during the last 6 centuries. The building itself looks like a fairy tale castle. Really worth the visit;</li>
<li><a href="https://www.openstreetmap.org/#map=18/59.32808/18.09126">Vasamuseet</a> exposes the local Titanic: a battle ship that sunk in 1628 in her maiden trip and was resurfaced in 1961;</li>
</ul>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/sami_storehouse.jpg" class="img-fluid figure-img"></p>
<figcaption>A traditional sami storehouse, elevated to protect the food from animals and snow</figcaption>
</figure>
</div>
<ul>
<li><a href="https://www.openstreetmap.org/#map=16/59.3265/18.1043">Skansen</a> is an old and large open air museum / ecomuseum / zoo. The public is mostly Swedish: families, or school classes. I understood that Stockholmers generally buy a ticket allowing entry all year long, and come back regularly for the animations proposed all along the year around the traditional holidays. I visited over Easter and have seen for example a Swedish grandma prepare traditional Easter cakes. Furthermore, the shop is nice, and there is a couple of restaurants and hot dog stands inside: I would recommend to visit Skansen in the morning, eat there and wait for 13 o’clock to go visit <em>Nordiska museet</em> just in front;</li>
<li>The botanical garden was unfortunately closed for restauration.</li>
</ul>
</section>
<section id="södermalm" class="level2">
<h2 class="anchored" data-anchor-id="södermalm">Södermalm</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/stockholm_pano_cropped.png" class="img-fluid figure-img"></p>
<figcaption>View of Kungsholmen from Södermalm</figcaption>
</figure>
</div>
<ul>
<li><a href="https://www.openstreetmap.org/#map=17/59.31999/18.04984">This part of the island</a>, besides being a nice picnic place, has very old traditional wooden houses once occupied by the working class. The view from this bank to the north side of the city is alone worth the trip;</li>
<li><a href="https://www.openstreetmap.org/#map=19/59.31961/18.07116">Stockholm’s city museum</a>, closed for restauration until a couple of days after my return date…</li>
</ul>
</section>
<section id="further" class="level2">
<h2 class="anchored" data-anchor-id="further">Further</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/vintervik.jpg" class="img-fluid figure-img"></p>
<figcaption>Lindholmen from Vinterviken</figcaption>
</figure>
</div>
<ul>
<li>The furthest I went by foot is <a href="https://www.openstreetmap.org/#map=16/59.3113/17.9859">Vinterviken</a>, a very bucolic place once owned by Nobel where he installed his dynamite factory. The beauty of the landscape contrasts with the rocks torn by the experiments. The place seems to be appreciated by Stockholmers since I saw many of them jogging in the park, or going out with a baby stroller. The old acid factory was converted into an exhibition center, and a really nice restaurant. You can take a tray, order one of the three meals of the day, grab bread and water and go eat it outside at one of the picnic tables, as a reward for the walk to arrive here from Stockholm. I warmly recommend it.</li>
</ul>
</section>
<section id="even-further" class="level2">
<h2 class="anchored" data-anchor-id="even-further">Even further</h2>
<ul>
<li>I wish I had the time to go pick a rock at <a href="https://www.openstreetmap.org/#map=18/59.42643/18.35363">Ytterby</a>’s ytterbium quarry but that will be for another time.</li>
</ul>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2019-05-stockholm/cherrytree.jpg" class="img-fluid figure-img"></p>
<figcaption>One of the cherry trees of Kungsträdgården, a square that I discovered completely randomly on my last day</figcaption>
</figure>
</div>


</section>
</section>

 ]]></description>
  <category>travel</category>
  <guid>https://normalesup.org/~andreani/blog/2019-05-stockholm/</guid>
  <pubDate>Sun, 05 May 2019 22:00:00 GMT</pubDate>
</item>
<item>
  <title>The perfect speed bump</title>
  <dc:creator>Virgile Andreani</dc:creator>
  <link>https://normalesup.org/~andreani/blog/2018-10-perfect-speed-bump/</link>
  <description><![CDATA[ 






<p>As he regularly does, Jason Cole recently delighted the readers of his blog with <a href="https://jasmcole.com/2018/10/07/the-perfect-speed-bump/">an interesting problem</a> that I will quickly sum up.</p>
<section id="the-problem" class="level1">
<h1>The problem</h1>
<blockquote class="blockquote">
<p>You have been assigned the task to use a given amount of concrete <img src="https://latex.codecogs.com/png.latex?A"> to build a speed bump over a section of a road of length <img src="https://latex.codecogs.com/png.latex?2%5C%5C,%5Cell">. But being a regular user of the road, you are trying to do your job while minimizing the jolt felt by a driver passing above it.</p>
</blockquote>
<p>We will consider the road as a 2D curve and the car as a point-like particle on this curve. We are then searching for a function <img src="https://latex.codecogs.com/png.latex?x%20%5Cmapsto%20y(x)">, with domain and values <img src="https://latex.codecogs.com/png.latex?%5B-%5Cell,%5Cell%5D%20%5Cto%20%5Cmathbb%7BR%7D">. We will assume that the road outside of this interval lies at <img src="https://latex.codecogs.com/png.latex?y=0">; the continuity conditions are then <img src="https://latex.codecogs.com/png.latex?y(-%5Cell)%20=%20y(%5Cell)%20=%0A0">, and we will also impose the nullity of the first derivatives of <img src="https://latex.codecogs.com/png.latex?y"> at these two points, which we will note with a parenthesized subscript <img src="https://latex.codecogs.com/png.latex?y_%7B(x)%7D(-%5Cell)%20=%20y_%7B(x)%7D(%5Cell)%20=%200">.</p>
<p>The author chose to minimize the integral of the square of the vertical acceleration felt by the car passing over the bump, <img src="https://latex.codecogs.com/png.latex?%5Cint_0%5ET%7Ba_y(t)%5E2%5Cmathrm%7Bd%7Dt%7D">.</p>
</section>
<section id="analytical-results" class="level1">
<h1>Analytical results</h1>
<p>Going quickly over the details because they already are in the original post, conservation of energy and geometrical considerations give</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cvec%7Bv%7D(x)%20=%0A%5Csqrt%7B%5Cfrac%7B%7Bv_0%7D%5E2-2%5C,g%5C,y%7D%7B1+%7By_%7B(x)%7D%7D%5E2%7D%7D%0A%5Cleft(%5Cvec%7Bx%7D+y_%7B(x)%7D%5C,%5Cvec%7By%7D%5Cright)%0A"></p>
<p>which, derived with respect to time, yields</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cvec%7Ba%7D(x)%20=%0A%5Cfrac%7B%7Bv_0%7D%5E2-2%5C,g%5C,y%7D%7B1+%7By_%7B(x)%7D%7D%5E2%7D%5Cleft%5B%0A-%5Cleft(%5Cfrac%7Bg%5C,y_%7B(x)%7D%7D%7B%7Bv_0%7D%5E2-2%5C,g%5C,y%7D+%5Cfrac%7By_%7B(x)%7D%5C,y_%7B(x,x)%7D%7D%7B1+%7By_%7B(x)%7D%7D%5E2%7D%5Cright)%5Cvec%7Bx%7D%0A+%5Cleft(%5Cfrac%7By_%7B(x,x)%7D%7D%7B1+%7By_%7B(x)%7D%7D%5E2%7D-%5Cfrac%7Bg%5C,%7By_%7B(x)%7D%7D%5E2%7D%7B%7Bv_0%7D%5E2-2%5C,g%5C,y%7D%5Cright)%5Cvec%7By%7D%0A%5Cright%5D%0A"></p>
<p>The quantity that we want to minimize is then</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5Cint_0%5ET%7B%7Ba_y%7D%5E2%5Cmathrm%7Bd%7Dt%7D%20&amp;=%20%5Cint_%7B-%5Cell%7D%5E%7B%5Cell%7D%7B%5Cfrac%7B%7Ba_y%7D%5E2%7D%7Bv_x%7D%5Cmathrm%7Bd%7Dx%7D%5C%5C%0A&amp;=%0A%5Cint_%7B-%5Cell%7D%5E%7B%5Cell%7D%7B%5Cleft(%5Cfrac%7B%7Bv_0%7D%5E2-2%5C,g%5C,y%7D%7B1+%7By_%7B(x)%7D%7D%5E2%7D%5Cright)%5E%7B3/2%7D%0A%5Cleft(%5Cfrac%7By_%7B(x,x)%7D%7D%7B1+%7By_%7B(x)%7D%7D%5E2%7D-%5Cfrac%7Bg%5C,%7By_%7B(x)%7D%7D%5E2%7D%7B%7Bv_0%7D%5E2-2%5C,g%5C,y%7D%5Cright)%5E2%5Cmathrm%7Bd%7Dx%7D%0A%5Cend%7Baligned%7D%0A"></p>
<p>The author then proceeds to two approximations. The first one is the limit of “infinite velocity”, which seems more appropriate for some drivers than some others, but is actually justified for everyone if we compute the quantity <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B%7Bv_0%7D%5E2%7D%7B2%5C%5C,g%5C%5C,y%7D%20%5Capprox%2035%0A%5Cgg%201">. This approximation allows to set <img src="https://latex.codecogs.com/png.latex?g"> to <img src="https://latex.codecogs.com/png.latex?0">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5Cint_0%5ET%7B%7Ba_y%7D%5E2%5Cmathrm%7Bd%7Dt%7D%20&amp;%5Capprox%0A%5Cint_%7B-%5Cell%7D%5E%7B%5Cell%7D%7B%5Cleft(%5Cfrac%7B%7Bv_0%7D%5E2%7D%7B1+%7By_%7B(x)%7D%7D%5E2%7D%5Cright)%5E%7B3/2%7D%0A%5Cleft(%5Cfrac%7By_%7B(x,x)%7D%7D%7B1+%7By_%7B(x)%7D%7D%5E2%7D%5Cright)%5E2%5Cmathrm%7Bd%7Dx%7D%5C%5C%0A&amp;%5Capprox%0A%7Bv_0%7D%5E3%5Cint_%7B-%5Cell%7D%5E%7B%5Cell%7D%7B%5Cfrac%7B%7By_%7B(x,x)%7D%7D%5E2%7D%7B%5Cleft(1+%7By_%7B(x)%7D%7D%5E2%5Cright)%5E%7B7/2%7D%7D%5Cmathrm%7Bd%7Dx%7D%0A%5Cend%7Baligned%7D%0A"></p>
<p>The second one is that of small angles, consisting of neglecting <img src="https://latex.codecogs.com/png.latex?y_%7B(x)%7D"> in front of <img src="https://latex.codecogs.com/png.latex?1">. This ones strips the criterion even further:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5Cint_0%5ET%7B%7Ba_y%7D%5E2%5Cmathrm%7Bd%7Dt%7D%20&amp;%5Capprox%20%7Bv_0%7D%5E3%5Cint_%7B-%5Cell%7D%5E%7B%5Cell%7D%7B%7By_%7B(x,x)%7D%7D%5E2%5Cmathrm%7Bd%7Dx%7D%0A%5Cend%7Baligned%7D%0A"></p>
<p>such that the problem becomes tractable. Indeed, applying the <a href="https://en.wikipedia.org/wiki/Euler%E2%80%93Lagrange_equation">Euler-Lagrange equation</a> on the Lagrangian <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BL%7D(y,y_%7B(x)%7D,y_%7B(x,x)%7D)%20=%0A%7Bv_0%7D%5E3%7By_%7B(x,x)%7D%7D%5E2-%5Clambda%20y"> yields the optimal solution of this twice simplified problem:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Cell%7D%7BA%7Dy(x)%20=%20%5Cfrac%7B15%7D%7B16%7D%5Cleft(1-%5Cleft(%5Cfrac%7Bx%7D%7B%5Cell%7D%5Cright)%5E2%5Cright)%5E2%0A"></p>
<p>He finally programs a stochastic optimizer with the exact equations, and looks how this solution changes. He didn’t observe many changes, and concluded that the approximations were not too coarse.</p>
</section>
<section id="numerical-optimization-of-the-exact-problem" class="level1">
<h1>Numerical optimization of the exact problem</h1>
<p>I decided to challenge this observation, and proceeded to submit the problem to <a href="https://www.bocop.org/">Bocop</a>, an optimal control solver developed by the <a href="https://www.inria.fr/en">Inria</a> team <a href="https://team.inria.fr/commands/">COMMANDS</a>. Bocop takes as input a system of ordinary differential equations involving one or several control variables, a criterion to optimize, and possibly constraints, and determines the temporal profile of the control variables that optimizes the criterion while satisfying the constraints.</p>
<p>For example, <a href="https://www.bocop.org/micro-swimmer-in-low-reynolds-number-fluid/">it is able to determine</a> how a model micro-swimmer should twist in order to move fast. Or how a rocket should <a href="https://www.bocop.org/goddard/">adapt its thrust during flight</a> to go the highest.</p>
<p>Bocop is designed to models dynamical systems (with time derivatives), and even though the equation of motion of the car involves time derivatives, it seemed more natural here to remove the time and only reason with the independent variable <img src="https://latex.codecogs.com/png.latex?x">. Since we go numeric, let’s make the problem dimensionless with the change of variables <img src="https://latex.codecogs.com/png.latex?%5Chat%7Bx%7D%20=%20%5Cfrac%7Bx%7D%7B%5Cell%7D">, <img src="https://latex.codecogs.com/png.latex?%5Chat%7By%7D%20=%0Ay%5Cfrac%7B%5Cell%7D%7BA%7D">, <img src="https://latex.codecogs.com/png.latex?%5Chat%7BA%7D%20=%0A%5Cfrac%7BA%7D%7B%5Cell%5E2%7D">, <img src="https://latex.codecogs.com/png.latex?%5Chat%7Bg%7D%20=%20g%5Cfrac%7B%5Cell%7D%7B%7Bv_0%7D%5E2%7D">. The criterion becomes</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Cell%7D%7B%5Chat%7BA%7D%5E2%5C,%7Bv_0%7D%5E3%7D%5Cint_0%5ET%7B%7Ba_y%7D%5E2%5Cmathrm%7Bd%7Dt%7D%20=%0A%5Cint_%7B-1%7D%5E1%7B%5Cleft(%5Cfrac%7B1-2%5C,%5Chat%7BA%7D%5C,%5Chat%7Bg%7D%5C,%5Chat%7By%7D%7D%7B1+%5Chat%7BA%7D%5E2%7B%5Chat%7By%7D_%7B(%5Chat%7Bx%7D)%7D%7D%5E2%7D%5Cright)%5E%7B3/2%7D%0A%5Cleft(%5Cfrac%7B%5Chat%7By%7D_%7B(%5Chat%7Bx%7D,%5Chat%7Bx%7D)%7D%7D%7B1+%5Chat%7BA%7D%5E2%7B%5Chat%7By%7D_%7B(%5Chat%7Bx%7D)%7D%7D%5E2%7D-%0A%5Cfrac%7B%5Chat%7BA%7D%5C,%5Chat%7Bg%7D%5C,%7B%5Chat%7By%7D_%7B(%5Chat%7Bx%7D)%7D%7D%5E2%7D%7B1-2%5C,%5Chat%7BA%7D%5C,%5Chat%7Bg%7D%5C,%5Chat%7By%7D%7D%5Cright)%5E2%5Cmathrm%7Bd%7D%5Chat%7Bx%7D%7D%0A"></p>
<p>and from now on, I will drop all the hats and work only in reduced variables.</p>
<p>The system can be modelled with a system of four first-order ordinary differential equations: <img src="https://latex.codecogs.com/png.latex?y(x)"> the profile of the road, <img src="https://latex.codecogs.com/png.latex?y_%7B(x)%7D(x)"> its first derivative, <img src="https://latex.codecogs.com/png.latex?c(x)"> the criterion and <img src="https://latex.codecogs.com/png.latex?Y(x)%20=%0A%5Cint_%7B-1%7D%5Ex%7By(u)%5Cmathrm%7Bd%7Du%7D"> the quantity of concrete used. The control variable is <img src="https://latex.codecogs.com/png.latex?y_%7B(x,x)%7D">, the second derivative of the profile. The dynamics is straightforward:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5Cfrac%7B%5Cmathrm%7Bd%7Dy%7D%7B%5Cmathrm%7Bd%7Dx%7D%20&amp;=%20y_%7B(x)%7D%5C%5C%0A%5Cfrac%7B%5Cmathrm%7Bd%7Dy_%7B(x)%7D%7D%7B%5Cmathrm%7Bd%7Dx%7D%20&amp;=%20y_%7B(x,x)%7D%5C%5C%0A%5Cfrac%7B%5Cmathrm%7Bd%7Dc%7D%7B%5Cmathrm%7Bd%7Dx%7D%20&amp;=%0A%5Cleft(%5Cfrac%7B1-2%5C,A%5C,g%5C,y%7D%7B1+A%5E2%7By_%7B(x)%7D%7D%5E2%7D%5Cright)%5E%7B3/2%7D%0A%5Cleft(%5Cfrac%7By_%7B(x,x)%7D%7D%7B1+A%5E2%7By_%7B(x)%7D%7D%5E2%7D-%5Cfrac%7BA%5C,g%5C,%7By_%7B(x)%7D%7D%5E2%7D%7B1-2%5C,A%5C,g%5C,y%7D%5Cright)%5E2%5C%5C%0A%5Cfrac%7B%5Cmathrm%7Bd%7DY%7D%7B%5Cmathrm%7Bd%7Dx%7D%20&amp;=%20y%0A%5Cend%7Baligned%7D%0A"></p>
<p>and is implemented in the <code>dynamics.tpp</code> file</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode cpp code-with-copy"><code class="sourceCode cpp"><span id="cb1-1">Tdouble yxx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> control<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb1-2">Tdouble y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb1-3">Tdouble yx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb1-4">Tdouble c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb1-5">Tdouble Y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb1-6"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> constants<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb1-7"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> constants<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb1-8"></span>
<span id="cb1-9">Tdouble vx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sqrt<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">((</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>A<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>g<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)/(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>A<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>A<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>yx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>yx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb1-10">Tdouble ay <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> yxx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>A<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>A<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>yx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>yx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> A<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>g<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>yx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>yx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>A<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>g<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb1-11"></span>
<span id="cb1-12">state_dynamics<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> yx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>             <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// dy/dx</span></span>
<span id="cb1-13">state_dynamics<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> yxx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// dyx/dx</span></span>
<span id="cb1-14">state_dynamics<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> vx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>vx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>vx<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>ay<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>ay<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// dc/dx</span></span>
<span id="cb1-15">state_dynamics<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>              <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// dY/dx</span></span></code></pre></div></div>
<p>The criterion is the final state of <img src="https://latex.codecogs.com/png.latex?c">:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode cpp code-with-copy"><code class="sourceCode cpp"><span id="cb2-1">criterion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> final_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span></code></pre></div></div>
<p>The boundary conditions take care of the continuity conditions, initialize the criterion, and enforce the area constraint on the profile:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode cpp code-with-copy"><code class="sourceCode cpp"><span id="cb3-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> constants<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb3-2">boundary_conditions<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> initial_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// y(-1)  = 0</span></span>
<span id="cb3-3">boundary_conditions<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>   final_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// y(1)   = 0</span></span>
<span id="cb3-4">boundary_conditions<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> initial_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// yx(-1) = 0</span></span>
<span id="cb3-5">boundary_conditions<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>   final_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// yx(1)  = 0</span></span>
<span id="cb3-6">boundary_conditions<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> initial_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// c(-1)  = 0</span></span>
<span id="cb3-7">boundary_conditions<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> initial_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Y(-1)  = 0</span></span>
<span id="cb3-8">boundary_conditions<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>   final_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Y(1)   = 1</span></span></code></pre></div></div>
<p>Finally we can run the solver, let’s first check if we can reach the analytical solution of the simple problem (<code>Tdouble vx = 1, ay = yxx;</code>):</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2018-10-perfect-speed-bump/f1.svg" class="img-fluid figure-img"></p>
<figcaption>Analytical and numerical solutions of the simplified problem</figcaption>
</figure>
</div>
<p>It seems to work, and the objective value <img src="https://latex.codecogs.com/png.latex?22.5"> is consistent with what we could have expected from the analytical result. Now let’s try the exact problem, with different values of <img src="https://latex.codecogs.com/png.latex?A"> and <img src="https://latex.codecogs.com/png.latex?g">:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2018-10-perfect-speed-bump/f1234.svg" class="img-fluid figure-img"></p>
<figcaption>Numerical solutions of the exact problem</figcaption>
</figure>
</div>
<p>Note that “realistic” values of <img src="https://latex.codecogs.com/png.latex?A"> and <img src="https://latex.codecogs.com/png.latex?g"> could be, respectively, <img src="https://latex.codecogs.com/png.latex?0.1"> and <img src="https://latex.codecogs.com/png.latex?0.15">. In this regime, the two approximations (infinite speed, and small angles) are indeed very reasonable. However, for higher bumps, the exact solution starts to diverge noticeably from the approximation. Could we guess the analytical form of the solution? That seems difficult in the general case, but we could try it in the limit of infinite speed (<img src="https://latex.codecogs.com/png.latex?g=0">). Actually, the objective value for the solution calculated by Bocop for the condition <img src="https://latex.codecogs.com/png.latex?A=1">, <img src="https://latex.codecogs.com/png.latex?g=0"> is <img src="https://latex.codecogs.com/png.latex?6.30">, which is suspiciously close to an interesting number, and the profile itself looks like four arcs of circles. Coincidence?</p>
</section>
<section id="hypothesis-for-the-infinite-speed-limit" class="level1">
<h1>Hypothesis for the infinite speed limit</h1>
<p>Let’s do the maths in the infinite speed limit, for the function</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7Bcircles%7D(x)%20=%0A%5Cbegin%7Bcases%7D%0A%5Cfrac%7B1%7D%7B2%7D-%5Csqrt%7B%5Cfrac%7B1%7D%7B4%7D-(x+1)%5E2%7D&amp;,%20-1%20%5Cleq%20x%20%5Cleq%20-%5Cfrac%7B1%7D%7B2%7D%5C%5C%0A%5Cfrac%7B1%7D%7B2%7D+%5Csqrt%7B%5Cfrac%7B1%7D%7B4%7D-x%5E2%7D&amp;,%20-%5Cfrac%7B1%7D%7B2%7D%20%5Cleq%20x%20%5Cleq%20%5Cfrac%7B1%7D%7B2%7D%5C%5C%0A%5Cfrac%7B1%7D%7B2%7D-%5Csqrt%7B%5Cfrac%7B1%7D%7B4%7D-(x-1)%5E2%7D&amp;,%20%5Cfrac%7B1%7D%7B2%7D%20%5Cleq%20x%20%5Cleq%201%0A%5Cend%7Bcases%7D%0A"></p>
<p>The objective is reduced to <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BObj%7D%5C_%7Bg=0%7D%5By%5D%20=%20%5Cint_%7B-1%7D%5E%7B1%7D%7B%5Cfrac%7B%7By_%7B(x,x)%7D%7D%5E2%7D%7B(1+A%5E2%7By_%7B(x)%7D%7D%5E2)%5E%7B7/2%7D%7D%5Cmathrm%7Bd%7Dx%7D">.</p>
<p>Mathematica helps and indeed <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BObj%7D_%7BA=1,g=0%7D%5B%5Cmathrm%7Bcircles%7D%5D%20=%0A2%5C%5C,%5Cpi">. To know if it is actually the optimal profile, we need to plug it into the Euler-Lagrange equation. Spoilers, it is not.</p>
<p>This profile is not optimal, but we can at least compare it with <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7Bapprox%7D(x)%20=%20%5Cfrac%7B15%7D%7B16%7D(1-x%5E2)%5E2">, the analytical solution of the approximated problem. Using the same criterion, we get <img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BOpt%7D_%7BA=1,g=0%7D%5B%5Cmathrm%7Bapprox%7D%5D%0A=%2010.39">, which proves that the four circles are a better profile for the limit of infinite speed, at <img src="https://latex.codecogs.com/png.latex?A=1">. We can also compare these profiles as a function of <img src="https://latex.codecogs.com/png.latex?A">:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://normalesup.org/~andreani/blog/2018-10-perfect-speed-bump/f_comparison.svg" class="img-fluid figure-img"></p>
<figcaption>Comparison of the fitnesses of the two profiles</figcaption>
</figure>
</div>
<p>It was expected that the polynomial would win at low <img src="https://latex.codecogs.com/png.latex?A"> since low <img src="https://latex.codecogs.com/png.latex?A"> means small angles. As we have seen, the solution in circles is better at high <img src="https://latex.codecogs.com/png.latex?A">. What was more difficult to understand for me was that the circles become infinitely bad at low <img src="https://latex.codecogs.com/png.latex?A"> (like <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B16%7D%7B15%5C%5C,a%5E4%7D">). I think that the reason for this behaviour is the two points of infinite slope at <img src="https://latex.codecogs.com/png.latex?x=%0A%5Cpm%5Cfrac%7B1%7D%7B2%7D">, which never disappear even when the profile gets flattened by a decreasing <img src="https://latex.codecogs.com/png.latex?A">, and create two discontinuity points where most of the acceleration is taken.</p>
<p>Can we find a better solution? Is the optimal solution tractable in the limit of infinite speed? What if we wanted to minimize the maximum of the acceleration over the period (the infinite norm) instead of the L2 norm? Perhaps for another time!</p>


</section>

 ]]></description>
  <category>optimization</category>
  <category>bocop</category>
  <guid>https://normalesup.org/~andreani/blog/2018-10-perfect-speed-bump/</guid>
  <pubDate>Fri, 19 Oct 2018 22:00:00 GMT</pubDate>
</item>
</channel>
</rss>
