<?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>Victor S HUANG</title>
<link>https://vsh852.com/blog.html</link>
<atom:link href="https://vsh852.com/blog.xml" rel="self" type="application/rss+xml"/>
<description>Victor S HUANG&#39;s Website</description>
<generator>quarto-1.9.38</generator>
<lastBuildDate>Sat, 23 May 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Hello, Quarto. Bye, Zensical.</title>
  <dc:creator>Victor S HUANG</dc:creator>
  <link>https://vsh852.com/posts/2026-05-23-hello-quarto-bye-zensical/</link>
  <description><![CDATA[ 





<div class="light-content">
<p><img src="https://vsh852.com/posts/2026-05-23-hello-quarto-bye-zensical/thumbnail-light.png" class="img-fluid" style="width:100.0%" alt="Hello, Quarto. Bye, Zensical."></p>
</div>
<div class="dark-content">
<p><img src="https://vsh852.com/posts/2026-05-23-hello-quarto-bye-zensical/thumbnail-dark.png" class="img-fluid" style="width:100.0%" alt="Hello, Quarto. Bye, Zensical."></p>
</div>
<p>This site used to run on <a href="https://zensical.org/">Zensical</a>. It now runs on <a href="https://quarto.org/">Quarto</a>.</p>
<section id="why-move" class="level2">
<h2 class="anchored" data-anchor-id="why-move">Why move</h2>
<p>Zensical is the spiritual successor to Material for MkDocs, from the same author. The direction is right. The execution is early. Plugin coverage is thin, theming hooks are still shifting, and the documentation lags the code. Fine for a landing page. Not where I want to spend cycles when I’m trying to publish.</p>
<p>Quarto sits in a different place. It is a scientific publishing system first and a static site generator second. That ordering matters. <code>.qmd</code> and <code>.ipynb</code> are first-class inputs. Code executes at render time and the outputs are pinned via <code>freeze</code>. Math, citations, cross-references, and figure numbering are part of the format, not bolted on. The same source renders to HTML, PDF, and reveal.js without a second toolchain.</p>
<p>For a site that will mix prose with notebooks and blog posts, that is the whole game.</p>
</section>
<section id="the-migration" class="level2">
<h2 class="anchored" data-anchor-id="the-migration">The migration</h2>
<p>Content was straightforward. Markdown is markdown. Front matter shifted from MkDocs conventions to Quarto’s:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb1-1"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">---</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">title</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hello, Quarto. Bye, Zensical."</span></span>
<span id="cb1-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">date</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2026-05-23"</span></span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">categories</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">[</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">news</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">]</span></span>
<span id="cb1-5"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">---</span></span></code></pre></div></div>
<p>The blog index is a Quarto listing page. No plugin, no template hacking:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb2-1"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">---</span></span>
<span id="cb2-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">title</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Blog"</span></span>
<span id="cb2-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">listing</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb2-4"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">contents</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> posts</span></span>
<span id="cb2-5"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"date desc"</span></span>
<span id="cb2-6"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">type</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> default</span></span>
<span id="cb2-7"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">categories</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">true</span></span>
<span id="cb2-8"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">feed</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">true</span></span>
<span id="cb2-9"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">---</span></span></code></pre></div></div>
<p>Theming is Bootstrap plus SCSS overrides. I kept Litera and added a <code>styles-dark.scss</code> for dark mode tweaks. Highlight styles are split per scheme so code blocks read well in both:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb3-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">html</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb3-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb3-4"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">light</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> litera</span></span>
<span id="cb3-5"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dark</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">[</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">litera</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">,</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> styles-dark.scss</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">]</span></span>
<span id="cb3-6"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">highlight-style</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb3-7"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">light</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> github</span></span>
<span id="cb3-8"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dark</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> monokai</span></span></code></pre></div></div>
</section>
<section id="cloudflare-pages" class="level2">
<h2 class="anchored" data-anchor-id="cloudflare-pages">Cloudflare Pages</h2>
<p>This is the part that needed care. Cloudflare Pages does not ship Quarto in its build image. The official path is to install it yourself in the build step.</p>
<p>I pin the version. Floating versions are a great way to wake up to a broken site:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#!/usr/bin/env bash</span></span>
<span id="cb4-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-euo</span> pipefail</span>
<span id="cb4-3"></span>
<span id="cb4-4"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">QUARTO_VERSION</span><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><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${QUARTO_VERSION</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:-</span>1.9.37<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb4-5"></span>
<span id="cb4-6"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">curl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-fsSL</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://github.com/quarto-dev/quarto-cli/releases/download/v</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${QUARTO_VERSION}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/quarto-</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${QUARTO_VERSION}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">-linux-amd64.tar.gz"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb4-7">  <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;">tar</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-xz</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-C</span> /opt</span>
<span id="cb4-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">export</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">PATH</span><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;">"/opt/quarto-</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${QUARTO_VERSION}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/bin:</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${PATH}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb4-9"></span>
<span id="cb4-10"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">quarto</span> render</span></code></pre></div></div>
<p>In the Pages project settings:</p>
<ul>
<li>Build command: <code>./build.sh</code></li>
<li>Build output directory: <code>_site</code></li>
<li>Root directory: project root</li>
</ul>
<p>A few things worth knowing if you walk this path:</p>
<p>Pin the Quarto version explicitly. Quarto’s HTML output evolves between minor releases. The inline theme-toggle script in particular references DOM nodes that older versions did not emit. If your build image and your local version drift, you can ship a site whose JavaScript throws on load and silently falls back to defaults. Ask me how I know.</p>
<p>Commit <code>_freeze/</code>. Cloudflare’s builders are ephemeral and do not have your Python or R environment. Freezing computational output locally and checking it in means the builder only needs Quarto and pandoc, not your full data stack. Build times drop to seconds.</p>
<p>Skip <code>output-dir</code> surprises. Quarto writes to <code>_site</code> by default. Match Cloudflare’s output directory to that and resist the urge to rename.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>news</category>
  <guid>https://vsh852.com/posts/2026-05-23-hello-quarto-bye-zensical/</guid>
  <pubDate>Sat, 23 May 2026 00:00:00 GMT</pubDate>
  <media:content url="https://vsh852.com/posts/2026-05-23-hello-quarto-bye-zensical/thumbnail-light.png" medium="image" type="image/png" height="104" width="144"/>
</item>
<item>
  <title>Planetary Parade — seven great circles and one lucky region</title>
  <dc:creator>Victor S HUANG</dc:creator>
  <link>https://vsh852.com/posts/2026-04-04-planetary-parade/</link>
  <description><![CDATA[ 





<p>Another writeup I owed myself. The March 2026 <a href="https://www.janestreet.com/puzzles/planetary-parade-index/">Jane Street puzzle</a> asked:</p>
<blockquote class="blockquote">
<p>An alien friend lives on Pyrknot, a planet well modeled as a perfect sphere orbiting a single star. Six other planets share the system. Their orbits are so chaotic that each night every planet appears at an independent, uniformly random point in Pyrknot’s sky, and none are visible during daylight. Given that <em>some</em> point on the surface can see all six planets at once, the friend at their own location has probability <img src="https://latex.codecogs.com/png.latex?%5Calpha"> of also seeing all six. The friend then builds a tower and can view any body visible from at least one surface point within distance <img src="https://latex.codecogs.com/png.latex?r"> of the tower’s base. For small <img src="https://latex.codecogs.com/png.latex?r"> relative to Pyrknot’s radius <img src="https://latex.codecogs.com/png.latex?R">, the probability rises to about <img src="https://latex.codecogs.com/png.latex?%5Calpha%20+%20%5Cbeta%5C,(r/R)">. Find <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> in exact terms.</p>
</blockquote>
<p>I <a href="https://github.com/vicw0ng-hk/puzzles">solved it</a> with pen and paper and want to write it up properly. It looks like an astronomy word problem, but it’s really a geometry puzzle in disguise. The whole thing turns on one translation: <em>a planet in the sky becomes a great circle on the ground</em>. Once you see that, the first answer is a counting exercise and the second is one derivative.</p>
<section id="a-planet-is-a-great-circle" class="level2">
<h2 class="anchored" data-anchor-id="a-planet-is-a-great-circle">A planet is a great circle</h2>
<p>Start with one planet. The friend can see it only if it sits above their local horizon. The set of surface points that can see a faraway object is exactly the half of the sphere facing it — a hemisphere. The edge of that hemisphere, where the object sits right on the horizon, is a <a href="https://en.wikipedia.org/wiki/Great_circle">great circle</a>.</p>
<p>Make this precise with vectors. Let <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bu%7D"> be the outward unit normal at a surface point, and let <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bd%7D"> point toward a planet. The planet is above the horizon at <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bu%7D"> exactly when</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbf%7Bu%7D%20%5Ccdot%20%5Cmathbf%7Bd%7D%20%3E%200.%0A"></p>
<p>Because each planet lands uniformly in the sky, <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bd%7D"> is a uniform random direction, so <img src="https://latex.codecogs.com/png.latex?%5C%7B%5Cmathbf%7Bu%7D%20:%20%5Cmathbf%7Bu%7D%5Ccdot%5Cmathbf%7Bd%7D%20%3E%200%5C%7D"> is a uniformly random hemisphere with a random great circle for its rim.</p>
<p>The star plays the same game with one sign flipped. You can only see planets at night, which means the star must be <em>below</em> your horizon: <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bu%7D%5Ccdot%5Cmathbf%7Bd%7D_%7B%5Ctext%7Bstar%7D%7D%20%3C%200">. That’s a seventh hemisphere, the “night” side, bounded by a seventh great circle.</p>
<p>So six planets plus one star give <strong>seven random great circles</strong>. Seeing the full parade from a point <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bu%7D"> means landing on the correct side of all seven at once: inside all six planet hemispheres and on the night side of the star.</p>
</section>
<section id="counting-the-regions" class="level2">
<h2 class="anchored" data-anchor-id="counting-the-regions">Counting the regions</h2>
<p>Seven great circles in <a href="https://en.wikipedia.org/wiki/General_position">general position</a> slice the sphere’s surface into flat-faced regions, and every region sees its own fixed subset of the seven bodies. How many regions? <a href="https://en.wikipedia.org/wiki/Euler_characteristic">Euler’s formula</a> for any graph drawn on a sphere settles it:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AV%20-%20E%20+%20F%20=%202.%0A"></p>
<p>Count each piece for <img src="https://latex.codecogs.com/png.latex?n%20=%207"> circles:</p>
<ul>
<li><strong>Vertices.</strong> Any two distinct great circles cross at two antipodal points, so <img src="https://latex.codecogs.com/png.latex?V%20=%202%5Cbinom%7B7%7D%7B2%7D%20=%2042">.</li>
<li><strong>Edges.</strong> Each circle is cut by the other six into <img src="https://latex.codecogs.com/png.latex?2%20%5Ccdot%206%20=%2012"> arcs, so <img src="https://latex.codecogs.com/png.latex?E%20=%207%20%5Ccdot%2012%20=%2084">.</li>
<li><strong>Faces.</strong> Rearranging Euler, <img src="https://latex.codecogs.com/png.latex?F%20=%202%20-%20V%20+%20E%20=%202%20-%2042%20+%2084%20=%2044">.</li>
</ul>
<p>The sky carves the ground into exactly <strong>44 regions</strong>. Hold that number.</p>
</section>
<section id="getting-alpha" class="level2">
<h2 class="anchored" data-anchor-id="getting-alpha">Getting <img src="https://latex.codecogs.com/png.latex?%5Calpha"></h2>
<p>Two facts about those 44 regions do all the work.</p>
<p>First, <strong>at most one region ever sees the full parade</strong>. The parade region is the intersection of seven half-spaces (six “above the horizon,” one “below”). An intersection of half-spaces is convex, and on a sphere a convex set lands inside a single region — it can’t be split across two. So on any given night, either exactly one of the 44 regions is the lucky one, or none is.</p>
<p>Second, <strong>by symmetry every region is equally likely to be the friend’s home</strong>. The friend’s location is just one more fixed point; the seven circles are placed uniformly at random around it. Nothing distinguishes one of the 44 regions from another ahead of time, so the friend’s point is equally likely to fall in any of them.</p>
<p>Now read the question again. We’re told a parade is visible <em>somewhere</em> — exactly one region is lucky. The friend wins if their home is that one region out of 44. With every region equally likely,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cboxed%7B%5Calpha%20=%20%5Cfrac%7B1%7D%7B44%7D.%7D%0A"></p>
<p>It’s worth checking that “a parade is visible somewhere” is even possible to condition on — it has to have positive probability. A fixed point sees the parade with probability <img src="https://latex.codecogs.com/png.latex?(1/2)%5E7%20=%201/128"> (each of the seven independent half-space tests is a fair coin). Summing that chance over all 44 regions, the probability that <em>some</em> region is lucky works out to <img src="https://latex.codecogs.com/png.latex?44/128%20=%2011/32">. This is a clean special case of <a href="https://en.wikipedia.org/wiki/Wendel%27s_theorem">Wendel’s theorem</a> on random hemispheres. The ratio is what matters: one lucky region in <img src="https://latex.codecogs.com/png.latex?44">, so <img src="https://latex.codecogs.com/png.latex?%5Calpha%20=%20(1/128)%20/%20(11/32)%20=%201/44">. The conditioning is well posed and the count is honest.</p>
</section>
<section id="the-tower-and-getting-beta" class="level2">
<h2 class="anchored" data-anchor-id="the-tower-and-getting-beta">The tower, and getting <img src="https://latex.codecogs.com/png.latex?%5Cbeta"></h2>
<p>The tower extends the friend’s reach. They can now see a body if it clears the horizon at <em>any</em> surface point within distance <img src="https://latex.codecogs.com/png.latex?r"> of the tower’s base, not just at the base itself. Climbing higher effectively pushes each horizon outward by a small angle.</p>
<p>Two competing effects show up, and the sign of each is the whole puzzle.</p>
<p><strong>Planets help.</strong> Reaching <img src="https://latex.codecogs.com/png.latex?r"> toward a planet that is just below your horizon can pull it into view. So for each of the six planets, the region that “sees” it grows outward by a band of width <img src="https://latex.codecogs.com/png.latex?r">. The lucky region inherits six of these expanding edges.</p>
<p><strong>The star hurts.</strong> Here’s the trap. The star is a celestial body too, and the same reach can pull the <em>star</em> above the horizon — meaning the top of your tower is in daylight, which kills the parade. So along the one edge of the lucky region that borders the star’s night-circle, the region <em>shrinks</em> by a band of width <img src="https://latex.codecogs.com/png.latex?r">.</p>
<p>To first order in <img src="https://latex.codecogs.com/png.latex?r">, the area a band adds (or removes) is just its length times its width:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CDelta(%5Ctext%7Barea%7D)%20%5C;%5Capprox%5C;%20r%20%5Ccdot%20(%5Ctext%7Blength%20of%20the%20six%20planet%20edges%7D)%20%5C;-%5C;%20r%20%5Ccdot%20(%5Ctext%7Blength%20of%20the%20one%20star%20edge%7D).%0A"></p>
<p>So I need the expected perimeter of the lucky region, split by edge type. Symmetry hands me both pieces.</p>
<p>The seven great circles have total length <img src="https://latex.codecogs.com/png.latex?7%20%5Ccdot%202%5Cpi%20R">. Each arc borders exactly two of the 44 regions, so summing every region’s perimeter double-counts the arcs: the grand total of all perimeters is <img src="https://latex.codecogs.com/png.latex?2%20%5Ccdot%207%20%5Ccdot%202%5Cpi%20R%20=%2028%5Cpi%20R">. All 44 regions are symmetric, so each has expected perimeter</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B28%5Cpi%20R%7D%7B44%7D%20%5C;=%5C;%20%5Cfrac%7B7%5Cpi%20R%7D%7B11%7D.%0A"></p>
<p>And the seven circles are interchangeable, so each contributes <img src="https://latex.codecogs.com/png.latex?1/7"> of that perimeter. Six circles are planets, one is the star:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7Bplanet%20edges%7D%20=%20%5Cfrac%7B6%7D%7B7%7D%5Ccdot%5Cfrac%7B7%5Cpi%20R%7D%7B11%7D%20=%20%5Cfrac%7B6%5Cpi%20R%7D%7B11%7D,%20%5Cqquad%0A%5Ctext%7Bstar%20edge%7D%20=%20%5Cfrac%7B1%7D%7B7%7D%5Ccdot%5Cfrac%7B7%5Cpi%20R%7D%7B11%7D%20=%20%5Cfrac%7B%5Cpi%20R%7D%7B11%7D.%0A"></p>
<p>Plug in. The expected area change is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CDelta(%5Ctext%7Barea%7D)%20%5C;%5Capprox%5C;%20r%5Ccdot%5Cfrac%7B6%5Cpi%20R%7D%7B11%7D%20%5C;-%5C;%20r%5Ccdot%5Cfrac%7B%5Cpi%20R%7D%7B11%7D%20%5C;=%5C;%20%5Cfrac%7B5%5Cpi%20R%5C,r%7D%7B11%7D.%0A"></p>
<p>The friend’s base is uniform on the whole surface of area <img src="https://latex.codecogs.com/png.latex?4%5Cpi%20R%5E2">, so the probability rises by</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5CDelta(%5Ctext%7Barea%7D)%7D%7B4%5Cpi%20R%5E2%7D%20%5C;=%5C;%20%5Cfrac%7B5%5Cpi%20R%5C,r/11%7D%7B4%5Cpi%20R%5E2%7D%20%5C;=%5C;%20%5Cfrac%7B5%7D%7B44%7D%5Ccdot%5Cfrac%7Br%7D%7BR%7D.%0A"></p>
<p>Matching this to <img src="https://latex.codecogs.com/png.latex?%5Cbeta%5C,(r/R)">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cboxed%7B%5Cbeta%20=%20%5Cfrac%7B5%7D%7B44%7D.%7D%0A"></p>
<p>Six edges push out, one edge pulls in, <img src="https://latex.codecogs.com/png.latex?6%20-%201%20=%205">, all over the same <img src="https://latex.codecogs.com/png.latex?44">. The day/night boundary is the only thing that makes <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> smaller than “six bands’ worth,” and it’s exactly the detail the puzzle is built around.</p>
</section>
<section id="checking-it-in-code" class="level2">
<h2 class="anchored" data-anchor-id="checking-it-in-code">Checking it in code</h2>
<p>The hand argument leans on a small-angle picture, so I want a closed form to differentiate and confirm. Translate the tower reach <img src="https://latex.codecogs.com/png.latex?r"> into an angle <img src="https://latex.codecogs.com/png.latex?%5Cdelta%20=%20r/R"> (arc length over radius). Reaching <img src="https://latex.codecogs.com/png.latex?%5Cdelta"> toward a planet drops its horizon, so you see planet <img src="https://latex.codecogs.com/png.latex?i"> when <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bu%7D%5Ccdot%5Cmathbf%7Bd%7D_i%20%3E%20-%5Csin%5Cdelta">; the star must stay down even from the tower top, so night means <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bu%7D%5Ccdot%5Cmathbf%7Bd%7D_%7B%5Ctext%7Bstar%7D%7D%20%3C%20-%5Csin%5Cdelta">. Since <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7Bu%7D%5Ccdot%5Cmathbf%7Bd%7D"> is uniform on <img src="https://latex.codecogs.com/png.latex?%5B-1,%201%5D">, a fixed tower sees the parade with probability</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ag(%5Cdelta)%20%5C;=%5C;%20%5CBigl(%5Ctfrac%7B1+%5Csin%5Cdelta%7D%7B2%7D%5CBigr)%5E%7B6%7D%5CBigl(%5Ctfrac%7B1-%5Csin%5Cdelta%7D%7B2%7D%5CBigr)%20%5C;=%5C;%20%5Cfrac%7B(1+%5Csin%5Cdelta)%5E6%5C,(1-%5Csin%5Cdelta)%7D%7B128%7D.%0A"></p>
<p>Dividing by the same <img src="https://latex.codecogs.com/png.latex?11/32"> (a parade still has to exist somewhere), I get the conditional probability as a function of <img src="https://latex.codecogs.com/png.latex?%5Cdelta">. Its value and slope at <img src="https://latex.codecogs.com/png.latex?%5Cdelta%20=%200"> are <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta">.</p>
<div id="solver" class="cell" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sympy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sp</span>
<span id="cb1-2"></span>
<span id="cb1-3">delta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sp.symbols(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"delta"</span>, positive<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="cb1-4">s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sp.sin(delta)</span>
<span id="cb1-5"></span>
<span id="cb1-6">g <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> s)<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="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> s) <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;">128</span>          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fixed tower sees the full parade</span></span>
<span id="cb1-7">P_exists <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sp.Rational(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span>)          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># parade visible somewhere (Wendel, 7 circles)</span></span>
<span id="cb1-8">p <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> P_exists                        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># conditional probability, as a function of delta</span></span>
<span id="cb1-9"></span>
<span id="cb1-10">alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sp.simplify(p.subs(delta, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb1-11">beta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sp.simplify(sp.diff(p, delta).subs(delta, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># d/d(r/R) at r = 0</span></span>
<span id="cb1-12">series <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sp.series(p, delta, <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;">2</span>).removeO()</span>
<span id="cb1-13"></span>
<span id="cb1-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"alpha          ="</span>, alpha)</span>
<span id="cb1-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"beta           ="</span>, beta)</span>
<span id="cb1-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p(r/R) approx  ="</span>, sp.expand(series))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>alpha          = 1/44
beta           = 5/44
p(r/R) approx  = 5*delta/44 + 1/44</code></pre>
</div>
</div>
<p>Both fall straight out: <img src="https://latex.codecogs.com/png.latex?%5Calpha%20=%201/44"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta%20=%205/44">, with the linear expansion <img src="https://latex.codecogs.com/png.latex?%5Ctfrac%7B1%7D%7B44%7D%20+%20%5Ctfrac%7B5%7D%7B44%7D%5C,(r/R)"> exactly matching the by-hand answer.</p>
<p>It’s also worth confirming the region count and the existence probability independently. Euler’s formula gives the faces, and <a href="https://en.wikipedia.org/wiki/Wendel%27s_theorem">Wendel’s theorem</a> gives the chance a parade is possible at all.</p>
<div id="counts" class="cell" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> math <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> comb</span>
<span id="cb3-2"></span>
<span id="cb3-3">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;">7</span>                                   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 6 planets + 1 star</span></span>
<span id="cb3-4">V <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> comb(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)                      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># antipodal crossings</span></span>
<span id="cb3-5">E <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> 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;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (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;">1</span>)                     <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># arcs per circle, times circles</span></span>
<span id="cb3-6">F <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> V <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> E                           <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Euler: V - E + F = 2</span></span>
<span id="cb3-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"V = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>V<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, E = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>E<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, F = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>F<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> regions"</span>)</span>
<span id="cb3-8"></span>
<span id="cb3-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Wendel: P(all n random hemispheres share a common point) in 3D</span></span>
<span id="cb3-10">P <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sp.Rational(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(comb(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;">1</span>, k) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</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>(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;">1</span>))</span>
<span id="cb3-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"P(parade possible) = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>P<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>F<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">/128"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>V = 42, E = 84, F = 44 regions
P(parade possible) = 11/32 = 44/128</code></pre>
</div>
</div>
</section>
<section id="monte-carlo-gut-check" class="level2">
<h2 class="anchored" data-anchor-id="monte-carlo-gut-check">Monte Carlo gut-check</h2>
<p>Before I trust either the region count or the tower correction, I want to drop a few million random skies on a fixed friend and watch the empirical numbers land. I put the friend at the north pole (one fixed point is as good as any), scatter seven uniform directions for each night, and apply the same horizon tests.</p>
<div id="monte-carlo" class="cell" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb5-2"></span>
<span id="cb5-3">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20260330</span>)</span>
<span id="cb5-4">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;">4_000_000</span></span>
<span id="cb5-5"></span>
<span id="cb5-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> unit(n):</span>
<span id="cb5-7">    v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.standard_normal((n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb5-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.linalg.norm(v, axis<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>, keepdims<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="cb5-9"></span>
<span id="cb5-10">friend <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>])      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># WLOG, by symmetry</span></span>
<span id="cb5-11"></span>
<span id="cb5-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> parade_prob(rR):</span>
<span id="cb5-13">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""P(friend with tower reach r/R sees the parade | a parade exists)."""</span></span>
<span id="cb5-14">    sin_d <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sin(rR)</span>
<span id="cb5-15">    seen <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.ones(N, dtype<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;">bool</span>)</span>
<span id="cb5-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>):                  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># planets: must clear the horizon</span></span>
<span id="cb5-17">        seen <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;=</span> friend <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> unit(N).T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>sin_d</span>
<span id="cb5-18">    seen <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;=</span> friend <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> unit(N).T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>sin_d  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># star: must stay below it (night)</span></span>
<span id="cb5-19">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> seen.mean() <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;">11</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;">32</span>)      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># condition on a parade existing</span></span>
<span id="cb5-20"></span>
<span id="cb5-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"alpha empirical : </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>parade_prob(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.5f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   exact 1/44 = </span><span class="sc" 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;">44</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.5f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-22"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> rR <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> (<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>):</span>
<span id="cb5-23">    pred <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;">44</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;">5</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;">44</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> rR</span>
<span id="cb5-24">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"r/R=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>rR<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: sim </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>parade_prob(rR)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.5f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">   alpha+beta(r/R) </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pred<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.5f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>alpha empirical : 0.02279   exact 1/44 = 0.02273
r/R=0.02: sim 0.02506   alpha+beta(r/R) 0.02500
r/R=0.05: sim 0.02893   alpha+beta(r/R) 0.02841</code></pre>
</div>
</div>
<p>The base rate sits on <img src="https://latex.codecogs.com/png.latex?1/44">, and the small-<img src="https://latex.codecogs.com/png.latex?r"> values track <img src="https://latex.codecogs.com/png.latex?%5Ctfrac%7B1%7D%7B44%7D%20+%20%5Ctfrac%7B5%7D%7B44%7D(r/R)"> closely. The fit drifts as <img src="https://latex.codecogs.com/png.latex?r/R"> grows, which is expected — <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> is only the first-order slope, and the curvature of <img src="https://latex.codecogs.com/png.latex?g(%5Cdelta)"> shows up once the band stops being thin.</p>
</section>
<section id="a-picture-of-the-lucky-region" class="level2">
<h2 class="anchored" data-anchor-id="a-picture-of-the-lucky-region">A picture of the lucky region</h2>
<p>To see why <img src="https://latex.codecogs.com/png.latex?%5Calpha"> is so small, it helps to draw the 44 regions for one random sky and shade the single region that sees every planet at night.</p>
<div id="cell-fig-parade" class="cell" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb7-2"></span>
<span id="cb7-3">rng2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">28</span>)</span>
<span id="cb7-4">normals <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng2.standard_normal((<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb7-5">normals <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/=</span> np.linalg.norm(normals, axis<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>, keepdims<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="cb7-6">planets, star <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> normals[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>], normals[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>]</span>
<span id="cb7-7"></span>
<span id="cb7-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dense grid of surface points in lat/lon</span></span>
<span id="cb7-9">lon <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>np.pi, np.pi, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">720</span>)</span>
<span id="cb7-10">lat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<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;">2</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;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">360</span>)</span>
<span id="cb7-11">LON, LAT <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.meshgrid(lon, lat)</span>
<span id="cb7-12">U <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.stack([np.cos(LAT)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>np.cos(LON), np.cos(LAT)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>np.sin(LON), np.sin(LAT)], <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="cb7-13"></span>
<span id="cb7-14">sees_planets <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;">all</span>(U <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> planets.T <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;">0</span>, axis<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="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># all six above horizon</span></span>
<span id="cb7-15">night <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> U <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> star <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;">0</span>                                <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># star below horizon</span></span>
<span id="cb7-16">parade <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sees_planets <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> night</span>
<span id="cb7-17"></span>
<span id="cb7-18">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb7-19">ax.contourf(LON, LAT, parade.astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>), levels<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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>], colors<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;">"#2a9fd6"</span>], alpha<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.85</span>)</span>
<span id="cb7-20"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nrm, col <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [(p, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#888888"</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> p <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> planets] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> [(star, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#d62728"</span>)]:</span>
<span id="cb7-21">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the great circle u . n = 0, drawn as its locus in lat/lon</span></span>
<span id="cb7-22">    val <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> U <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> nrm</span>
<span id="cb7-23">    ax.contour(LON, LAT, val, levels<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>], colors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[col], linewidths<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;">1.2</span>)</span>
<span id="cb7-24">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"longitude"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"latitude"</span>)</span>
<span id="cb7-25">ax.set_xticks([])<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> ax.set_yticks([])</span>
<span id="cb7-26">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"one random night on Pyrknot"</span>)</span>
<span id="cb7-27">plt.savefig(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"thumbnail.png"</span>, dpi<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;">110</span>, bbox_inches<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;">"tight"</span>)</span>
<span id="cb7-28">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div id="fig-parade" class="quarto-float quarto-figure quarto-figure-center anchored" data-fig-align="center">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-parade-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://vsh852.com/posts/2026-04-04-planetary-parade/index_files/figure-html/fig-parade-output-1.png" class="quarto-figure quarto-figure-center figure-img" width="558" height="353">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-parade-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Seven random great circles (six planet horizons, one star horizon) cut the globe into 44 regions. The shaded patch is the lone region that sees all six planets while the star is down — the friend lands there with probability <img src="https://latex.codecogs.com/png.latex?1/44">.
</figcaption>
</figure>
</div>
</div>
</div>
<p>Gray circles are planet horizons, the red circle is the star’s night boundary, and the blue patch is the parade region. On most nights that patch is tiny or absent — which is exactly why landing in it is a <img src="https://latex.codecogs.com/png.latex?1">-in-<img src="https://latex.codecogs.com/png.latex?44"> event.</p>
</section>
<section id="what-made-it-nice" class="level2">
<h2 class="anchored" data-anchor-id="what-made-it-nice">What made it nice</h2>
<p>The whole puzzle hinges on one change of view: a planet in the sky is a hemisphere on the ground, and its rim is a great circle. After that, <img src="https://latex.codecogs.com/png.latex?%5Calpha"> is Euler’s formula (<img src="https://latex.codecogs.com/png.latex?44"> regions, one of them lucky) and <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> is a perimeter split six-to-one between planets that help and a star that hurts. No integrals, no heavy machinery — just careful counting and one sign you can’t afford to miss.</p>
<p>The official Jane Street <a href="https://www.janestreet.com/puzzles/planetary-parade-solution/">solution</a> takes the same great-circle route and lands on the same pair, <img src="https://latex.codecogs.com/png.latex?%5Calpha%20=%20%5Ctfrac%7B1%7D%7B44%7D"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta%20=%20%5Ctfrac%7B5%7D%7B44%7D">.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>puzzle</category>
  <category>math</category>
  <category>python</category>
  <guid>https://vsh852.com/posts/2026-04-04-planetary-parade/</guid>
  <pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate>
  <media:content url="https://vsh852.com/posts/2026-04-04-planetary-parade/thumbnail.png" medium="image" type="image/png" height="91" width="144"/>
</item>
<item>
  <title>From source to bytecode: a walk through CPython</title>
  <dc:creator>Victor S HUANG</dc:creator>
  <link>https://vsh852.com/posts/2026-02-21-cpython-internals/</link>
  <description><![CDATA[ 





<p>When you run <code>python script.py</code>, a lot happens before your first line of code does anything. <a href="https://github.com/python/cpython">CPython</a> is the reference implementation of Python, written in C, and it puts your source through a small assembly line: text comes in one end, a stream of tokens forms, those tokens become a tree, the tree becomes bytecode, and a virtual machine runs the bytecode. Underneath all of that sits a runtime that manages memory, decides which thread gets to run, and cleans up after you.</p>
<p>This post walks that pipeline end to end. The goal is a map, not a manual. I keep each stage short, link to the <a href="https://docs.python.org/3/">official docs</a> and the <a href="https://github.com/python/cpython">CPython source</a> so you can dig in, and point out what changed in the recent releases (3.13, 3.14, and the in-development 3.15). Everything here runs on CPython 3.14, the current stable release.</p>
<div id="cell-fig-pipeline" class="cell" data-execution_count="1">
<div class="cell-output cell-output-display">
<div id="fig-pipeline" class="quarto-float quarto-figure quarto-figure-center anchored" data-fig-align="center">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-pipeline-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://vsh852.com/posts/2026-02-21-cpython-internals/index_files/figure-html/fig-pipeline-output-1.png" class="quarto-figure quarto-figure-center figure-img" width="733" height="374">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-pipeline-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: The CPython pipeline. Source text becomes tokens, then an abstract syntax tree, then bytecode stored in a code object, which the evaluation loop runs. The whole engine sits on a runtime that handles memory and scheduling.
</figcaption>
</figure>
</div>
</div>
</div>
<p>Each box in that diagram is a stage with its own module you can poke at from Python itself. Let me take them in order.</p>
<section id="tokenizing-text-becomes-words" class="level2">
<h2 class="anchored" data-anchor-id="tokenizing-text-becomes-words">Tokenizing: text becomes words</h2>
<p>The first job is to chop the raw text into tokens — the smallest meaningful pieces. Names, numbers, string literals, operators, and the structural markers that make Python Python: newlines that end a logical line, and the <code>INDENT</code>/<code>DEDENT</code> tokens that stand in for the braces other languages use. CPython’s real tokenizer is written in C and lives under <a href="https://github.com/python/cpython/tree/main/Parser"><code>Parser/</code></a>, but the standard library ships a pure-Python one you can run yourself, the <a href="https://docs.python.org/3/library/tokenize.html"><code>tokenize</code></a> module.</p>
<div id="a2859647" class="cell" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> tokenize, io</span>
<span id="cb1-2"></span>
<span id="cb1-3">src <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;">"x = 2 + 3 * 4</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb1-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tok <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> tokenize.generate_tokens(io.StringIO(src).readline):</span>
<span id="cb1-5">    name <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tokenize.tok_name[tok.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">type</span>]</span>
<span id="cb1-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> name <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENCODING"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENDMARKER"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL"</span>):</span>
<span id="cb1-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb1-8">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:9}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tok<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>string<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!r}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>NAME      'x'
OP        '='
NUMBER    '2'
OP        '+'
NUMBER    '3'
OP        '*'
NUMBER    '4'
NEWLINE   '\n'</code></pre>
</div>
</div>
<p>Each token carries its type, its text, and its position in the source. The numeric values behind names like <code>NAME</code> and <code>OP</code> are generated from <a href="https://github.com/python/cpython/blob/main/Grammar/Tokens"><code>Grammar/Tokens</code></a> and can shift between releases, so you always refer to them by name through the <a href="https://docs.python.org/3/library/token.html"><code>token</code></a> module, never by number.</p>
<p>The tokenizer is where one of the more interesting recent reworks happened. Through Python 3.11 an f-string was handed to the parser as a single opaque <code>STRING</code> token, and a separate hand-written C routine picked it apart. That was fragile and full of special cases. <a href="https://peps.python.org/pep-0701/">PEP 701</a>, in Python 3.12, formalized f-strings into the real grammar. The tokenizer now emits structured pieces — <code>FSTRING_START</code>, <code>FSTRING_MIDDLE</code>, <code>FSTRING_END</code> — and the parser handles the <code>{...}</code> expressions like any other code.</p>
<div id="e21bafab" class="cell" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">src <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;">'f"hi </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{name}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="cb3-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tok <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> tokenize.generate_tokens(io.StringIO(src).readline):</span>
<span id="cb3-3">    n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tokenize.tok_name[tok.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">type</span>]</span>
<span id="cb3-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> n <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENCODING"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENDMARKER"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEWLINE"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL"</span>):</span>
<span id="cb3-5">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb3-6">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:14}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>tok<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>string<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!r}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>FSTRING_START  'f"'
FSTRING_MIDDLE 'hi '
OP             '{'
NAME           'name'
OP             '}'
FSTRING_END    '"'</code></pre>
</div>
</div>
<p>The practical payoff: f-strings stopped having weird arbitrary limits. You can nest quotes of the same kind, use backslashes, and write multi-line expressions inside the braces. The lexer change is what made all of it fall out for free.</p>
</section>
<section id="parsing-words-become-a-tree" class="level2">
<h2 class="anchored" data-anchor-id="parsing-words-become-a-tree">Parsing: words become a tree</h2>
<p>A flat list of tokens has no structure. Parsing turns it into an <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">abstract syntax tree</a> (AST) — a nested representation where <code>2 + 3 * 4</code> knows that the multiplication binds tighter than the addition. Since Python 3.9, CPython uses a <a href="https://peps.python.org/pep-0617/">PEG parser</a> (a parsing expression grammar) that replaced the old hand-maintained LL(1) parser; the old <code>parser</code> module was removed in 3.10. The grammar itself is a readable file, <a href="https://github.com/python/cpython/blob/main/Grammar/python.gram"><code>Grammar/python.gram</code></a>, and the C parser is generated from it.</p>
<p>The key idea behind PEG is <em>ordered choice</em>. When a rule lists alternatives, they’re tried in written order and the first match wins. That removes the ambiguity that plagues older grammar styles, at the cost of needing memoization to stay fast (so-called packrat parsing). The full rationale is in the <a href="https://github.com/python/cpython/blob/main/InternalDocs/parser.md">parser guide</a> in the CPython internals docs.</p>
<p>You rarely touch the parser directly. You reach for the <a href="https://docs.python.org/3/library/ast.html"><code>ast</code></a> module, which gives you the tree as Python objects you can inspect, walk, or rewrite.</p>
<div id="67a9ad9e" class="cell" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ast</span>
<span id="cb5-2"></span>
<span id="cb5-3">tree <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ast.parse(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x = 2 + 3 * 4"</span>)</span>
<span id="cb5-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(ast.dump(tree, indent<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></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Module(
  body=[
    Assign(
      targets=[
        Name(id='x', ctx=Store())],
      value=BinOp(
        left=Constant(value=2),
        op=Add(),
        right=BinOp(
          left=Constant(value=3),
          op=Mult(),
          right=Constant(value=4))))])</code></pre>
</div>
</div>
<p>Read the nesting: the assignment’s value is a <code>BinOp</code> for <code>+</code>, whose right side is another <code>BinOp</code> for <code>*</code>. Precedence is baked into the shape of the tree, not decided later. This is the level tools like linters, formatters, and type checkers operate on, because it’s the first representation that actually understands the structure of your code.</p>
</section>
<section id="compiling-the-tree-becomes-bytecode" class="level2">
<h2 class="anchored" data-anchor-id="compiling-the-tree-becomes-bytecode">Compiling: the tree becomes bytecode</h2>
<p>The AST is still a description of your program, not something to execute. The compiler (<a href="https://github.com/python/cpython/blob/main/Python/compile.c"><code>Python/compile.c</code></a>) lowers it into bytecode: a flat sequence of simple instructions for a stack machine. Along the way it builds a symbol table to work out which names are local, global, or captured from an enclosing scope, then turns the tree into a control-flow graph and emits instructions. The <a href="https://devguide.python.org/internals/compiler/">compiler design page</a> in the developer guide walks the full path.</p>
<p>The result is a <em>code object</em>: bytecode plus everything needed to run it — constants, names, argument counts, line-number tables. The <a href="https://docs.python.org/3/library/dis.html"><code>dis</code></a> module disassembles it into something readable.</p>
<div id="6680d7ba" class="cell" data-execution_count="5">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> dis</span>
<span id="cb7-2"></span>
<span id="cb7-3">dis.dis(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">compile</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x = 2 + 3 * 4"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"&lt;demo&gt;"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exec"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>  0           RESUME                   0

  1           LOAD_SMALL_INT          14
              STORE_NAME               0 (x)
              LOAD_CONST               1 (None)
              RETURN_VALUE</code></pre>
</div>
</div>
<p>Two things to notice. First, there’s no <code>2</code>, <code>3</code>, <code>4</code>, or any arithmetic in the output. The compiler folded the constant expression <code>2 + 3 * 4</code> down to <code>14</code> at compile time, so the running program just loads the answer. Second, <code>LOAD_SMALL_INT</code> is a specialized instruction for small integers — one of many narrow, fast opcodes CPython has grown over the years.</p>
<p>Disassembling a function shows more of that flavor:</p>
<div id="c8d1d9ed" class="cell" data-execution_count="6">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> add(a, b):</span>
<span id="cb9-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b</span>
<span id="cb9-3"></span>
<span id="cb9-4">dis.dis(add)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>  1           RESUME                   0

  2           LOAD_FAST_BORROW_LOAD_FAST_BORROW 1 (a, b)
              BINARY_OP                0 (+)
              RETURN_VALUE</code></pre>
</div>
</div>
<p><code>LOAD_FAST_BORROW_LOAD_FAST_BORROW</code> is a single fused instruction that loads two local variables at once, and <code>BINARY_OP</code> is a generic operation the interpreter can later <em>specialize</em> once it sees what types actually flow through it. More on that in a moment.</p>
<p>One warning that the docs repeat and I’ll repeat too: <strong>bytecode is not stable.</strong> The instruction set changes every minor release, sometimes a lot. Never pickle it, never ship it between versions, never depend on a specific opcode existing. It’s an internal detail. <code>dis</code> is for understanding, not for building on.</p>
</section>
<section id="the-evaluation-loop-running-the-bytecode" class="level2">
<h2 class="anchored" data-anchor-id="the-evaluation-loop-running-the-bytecode">The evaluation loop: running the bytecode</h2>
<p>The bytecode finally runs in the <em>evaluation loop</em>, the heart of the interpreter, in <a href="https://github.com/python/cpython/blob/main/Python/ceval.c"><code>Python/ceval.c</code></a>. At its core is a function, <code>_PyEval_EvalFrameDefault</code>, that walks the instructions of a <em>frame</em> (one call’s worth of execution state — its locals, its value stack, its position in the bytecode) and does what each one says. Call a function and a new frame goes on the stack; return and it pops off.</p>
<p>For most of Python’s history this was a big dispatch loop: fetch an instruction, jump to the code for it, repeat. The last few releases have made it considerably cleverer, and that’s where a chunk of recent performance work lives.</p>
<p><strong>The specializing adaptive interpreter</strong> (<a href="https://peps.python.org/pep-0659/">PEP 659</a>, Python 3.11) is the big one. The interpreter watches which instructions run hot and rewrites them in place into specialized forms. A generic <code>BINARY_OP</code> that keeps seeing two integers quietly becomes an int-only add that skips the type checks. If the assumption later breaks — someone passes strings — it falls back to the general version. You write ordinary Python; the interpreter adapts the bytecode to your actual data as it runs.</p>
<p><strong>The experimental JIT</strong> (<a href="https://peps.python.org/pep-0744/">PEP 744</a>, Python 3.13) goes a step further. Hot code is translated into a lower-level sequence of micro-operations, optimized, and then compiled to actual machine code using a technique called copy-and-patch. It’s off by default and has to be built in explicitly, so it’s still a preview rather than something most people run. What’s new in 3.14 is that the official Windows and macOS installers now <em>ship</em> the experimental JIT in the binary, so it’s far easier to try — but it remains experimental.</p>
<p><strong>The tail-call interpreter</strong> (Python 3.14) is a different, quieter speedup. Instead of one giant loop, each opcode becomes a small C function that hands control to the next via a guaranteed tail call, which lets the C compiler keep interpreter state in registers. It needs a recent Clang and is opt-in at build time, and it changes nothing you can observe from Python — same bytecode, same behavior, just a faster engine. (Worth a caution: the early headline numbers were inflated by a compiler regression in the baseline; the <a href="https://blog.nelhage.com/post/cpython-tail-call/">honest figure</a> is a few percent.)</p>
</section>
<section id="the-runtime-underneath" class="level2">
<h2 class="anchored" data-anchor-id="the-runtime-underneath">The runtime underneath</h2>
<p>The pipeline above tells you how code gets executed. It doesn’t tell you how the engine keeps house: who’s allowed to run, where objects live, and when they get cleaned up. That’s the runtime, and it’s where three of the most-discussed pieces of CPython sit.</p>
<section id="the-gil" class="level3">
<h3 class="anchored" data-anchor-id="the-gil">The GIL</h3>
<p>The <a href="https://docs.python.org/3/glossary.html#term-global-interpreter-lock">global interpreter lock</a> is a single mutex that lets only one thread execute Python bytecode at a time. It exists because CPython’s memory management — reference counting, which we’ll get to — isn’t thread-safe on its own, and a single lock is a simple, fast way to keep it correct. The lock is released around blocking I/O, so threads waiting on the network or disk run fine in parallel. The cost lands on pure-Python CPU work: ten threads doing math share one core’s worth of interpreter, not ten.</p>
<p>For decades the usual advice was “use processes for CPU parallelism, threads for I/O.” That’s now changing, and it’s the headline story of the last two releases.</p>
<p><a href="https://peps.python.org/pep-0703/">PEP 703</a> makes the GIL optional. It’s a separate build of CPython — the executable is named with a <code>t</code> suffix, like <code>python3.14t</code> — that removes the global lock and instead protects shared state with finer-grained mechanisms (biased reference counting, per-object locks, a different memory allocator). It arrived as <strong>experimental</strong> in 3.13. In <strong>3.14 it became officially supported</strong> (<a href="https://peps.python.org/pep-0779/">PEP 779</a>) — still a separate, opt-in build and not the default, but no longer a preview. The single-threaded cost has come down to roughly 5–10%, and the specializing interpreter now works in the free-threaded build too. You can check at runtime:</p>
<div id="4ff129e0" class="cell" data-execution_count="7">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys, sysconfig</span>
<span id="cb11-2"></span>
<span id="cb11-3">free_threaded <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;">bool</span>(sysconfig.get_config_var(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Py_GIL_DISABLED"</span>))</span>
<span id="cb11-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"free-threaded build:"</span>, free_threaded)</span>
<span id="cb11-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GIL currently enabled:"</span>, sys._is_gil_enabled())</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>free-threaded build: False
GIL currently enabled: True</code></pre>
</div>
</div>
<p>This is the standard build, so the GIL is present and on. On a <code>python3.14t</code> build the first line would say <code>True</code>, and threads could run Python in genuine parallel. Even on a free-threaded build the GIL can be switched back on at runtime (via <code>PYTHON_GIL</code> or <code>-X gil=1</code>), and it re-enables itself if you import a C extension that hasn’t declared itself safe without it.</p>
<p>A related route to multiple cores is <a href="https://peps.python.org/pep-0684/">PEP 684</a> (Python 3.12): a <em>per-interpreter</em> GIL. Multiple subinterpreters can live in one process, each with its own lock, so they run in parallel without sharing the single global one. That’s the foundation for the subinterpreter concurrency model I’ll come back to.</p>
</section>
<section id="memory-reference-counting-first" class="level3">
<h3 class="anchored" data-anchor-id="memory-reference-counting-first">Memory: reference counting first</h3>
<p>Every Python object carries a count of how many references point at it. Bind it to a new name, put it in a list, pass it to a function — the count goes up. Drop one of those — it goes down. When the count hits zero, the object is freed immediately. This is the primary memory manager, and it’s why so much Python memory is reclaimed the instant it’s no longer used, with no pause.</p>
<div id="d45cc67f" class="cell" data-execution_count="8">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb13-2"></span>
<span id="cb13-3">data <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;">"a"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"b"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"c"</span>]</span>
<span id="cb13-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"refs to the list:"</span>, sys.getrefcount(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="cb13-5">also <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> data</span>
<span id="cb13-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"after a second name:"</span>, sys.getrefcount(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></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>refs to the list: 1
after a second name: 2</code></pre>
</div>
</div>
<p>(<code>getrefcount</code> itself holds a temporary reference while it runs, hence the <code>- 1</code>.)</p>
<p>Under reference counting sits the allocator. CPython doesn’t ask the operating system for memory one object at a time; that would be slow. A specialized allocator called <a href="https://docs.python.org/3/c-api/memory.html">pymalloc</a> grabs memory in big arenas and hands out small slices for the many short-lived little objects a Python program churns through. The free-threaded build swaps in a different allocator (mimalloc) suited to many threads allocating at once.</p>
<p>One detail that quietly enables a lot of the above: <a href="https://peps.python.org/pep-0683/">immortal objects</a> (PEP 683, Python 3.12). A handful of objects that live for the entire program — <code>None</code>, <code>True</code>, <code>False</code>, small integers, interned strings — have their reference count pinned so it’s never touched. That avoids constantly writing to their counts, which matters for shared memory in pre-fork servers and for making the per-interpreter and free-threaded work tractable.</p>
</section>
<section id="the-garbage-collector-cleaning-up-cycles" class="level3">
<h3 class="anchored" data-anchor-id="the-garbage-collector-cleaning-up-cycles">The garbage collector: cleaning up cycles</h3>
<p>Reference counting has one blind spot: cycles. If <code>a</code> refers to <code>b</code> and <code>b</code> refers back to <code>a</code>, their counts never reach zero even after you drop every outside reference. That’s what the <a href="https://docs.python.org/3/library/gc.html"><code>gc</code></a> module is for. It’s a <em>secondary</em> collector that exists only to find and break reference cycles; everything else is handled by counting. The mechanics are written up in the <a href="https://github.com/python/cpython/blob/main/InternalDocs/garbage_collector.md">garbage collector internals doc</a>.</p>
<div id="1d16831a" class="cell" data-execution_count="9">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> gc</span>
<span id="cb15-2"></span>
<span id="cb15-3">gc.collect()        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># start from a clean slate</span></span>
<span id="cb15-4">a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {}</span>
<span id="cb15-5">b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {}</span>
<span id="cb15-6">a[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"b"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> b          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a -&gt; b</span></span>
<span id="cb15-7">b[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"a"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> a          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># b -&gt; a, a cycle</span></span>
<span id="cb15-8"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">del</span> a, b            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># outside references gone; refcounts still nonzero</span></span>
<span id="cb15-9"></span>
<span id="cb15-10">unreachable <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gc.collect()   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># find and free the cycle</span></span>
<span id="cb15-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"objects reclaimed by the cyclic collector:"</span>, unreachable)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>objects reclaimed by the cyclic collector: 2</code></pre>
</div>
</div>
<p>Those two dicts couldn’t be freed by counting alone. The cyclic collector found them unreachable and reclaimed them. Classically it’s <em>generational</em>: new objects are checked often, survivors get promoted to older generations that are scanned less. The thresholds are tunable, and the default first-generation trigger was relaxed in 3.13 to collect less aggressively:</p>
<div id="934055ed" class="cell" data-execution_count="10">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gc thresholds (gen0, gen1, gen2):"</span>, gc.get_threshold())</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>gc thresholds (gen0, gen1, gen2): (2000, 10, 10)</code></pre>
</div>
</div>
<p>The collector’s exact strategy has been an area of active churn. The team has experimented with an <em>incremental</em> design that spreads each collection out to avoid long pauses, and walked it back more than once when it caused memory-pressure regressions in real workloads. The headline for someone writing Python: cycles are collected automatically, the policy keeps getting tuned, and the conceptual model (counting does the bulk, the cyclic GC mops up cycles) is stable even as the internals move.</p>
</section>
<section id="so-where-do-memory-leaks-come-from" class="level3">
<h3 class="anchored" data-anchor-id="so-where-do-memory-leaks-come-from">So where do memory leaks come from?</h3>
<p>With all this, “leak” in Python rarely means the C sense of orphaned memory. It usually means objects that are still reachable, so neither mechanism is allowed to free them. The usual suspects:</p>
<ul>
<li>A long-lived container (a module-level list, a cache dict) you keep appending to and never trim. Everything in it is alive by definition.</li>
<li>A cache without eviction — the most common one in practice. <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache"><code>functools.lru_cache</code></a> with a bound, or a <a href="https://docs.python.org/3/library/weakref.html"><code>weakref</code></a>-based structure, fixes it.</li>
<li>Objects that define <code>__del__</code> <em>and</em> sit in a cycle, which historically could stall collection (much improved in modern versions).</li>
<li>A C extension that miscounts references — the one place a true low-level leak can still creep in.</li>
</ul>
<p>The tools to chase these live in the standard library: <a href="https://docs.python.org/3/library/tracemalloc.html"><code>tracemalloc</code></a> to see where allocations come from, <code>gc.get_objects()</code> and <code>gc.get_referrers()</code> to ask what’s keeping something alive, and <code>sys.getrefcount</code> for a quick check.</p>
</section>
</section>
<section id="branching-out-the-concurrency-models" class="level2">
<h2 class="anchored" data-anchor-id="branching-out-the-concurrency-models">Branching out: the concurrency models</h2>
<p>Once you understand the GIL, the menu of concurrency tools makes sense. Each one is a different answer to “how do I do more than one thing, given that lock?”</p>
<p><strong>Threads</strong> (<a href="https://docs.python.org/3/library/threading.html"><code>threading</code></a>) are real OS threads, but on the standard build the GIL means only one runs Python at a time. Perfect for I/O-bound work, where threads spend their time waiting and the lock is free. Not a path to multi-core CPU speed — unless you’re on the free-threaded build, which is exactly the wall PEP 703 is tearing down.</p>
<p><strong>Processes</strong> (<a href="https://docs.python.org/3/library/multiprocessing.html"><code>multiprocessing</code></a>) sidestep the GIL by running separate Python interpreters in separate processes, each with its own lock and memory. True parallelism, at the cost of no shared memory by default and the overhead of pickling data across the boundary. A safety-relevant change landed in <strong>3.14</strong>: on most Unix systems the default start method moved from <code>fork</code> to <code>forkserver</code>, because <code>fork</code> in a multi-threaded program is a long-standing source of deadlocks. If you relied on <code>fork</code>, you now request it explicitly.</p>
<p><strong>Async</strong> (<a href="https://docs.python.org/3/library/asyncio.html"><code>asyncio</code></a>) is single-threaded concurrency. One thread, one event loop, many coroutines that voluntarily yield at <code>await</code> points. No GIL contention because there’s only one thread; the win is handling thousands of mostly-waiting connections without thread overhead. It’s cooperative, so one coroutine that blocks on CPU work stalls everything — the model is for I/O, not computation.</p>
<p><strong>Subinterpreters</strong> (<a href="https://peps.python.org/pep-0734/">PEP 734</a>) are the newest branch, and they sit between threads and processes. Built on the per-interpreter GIL, multiple isolated interpreters run inside <em>one</em> process, each with its own lock, so they execute Python in parallel — but with far less isolation cost than separate processes. Python 3.14 exposed them to Python code for the first time, through the new <a href="https://docs.python.org/3/library/concurrent.interpreters.html"><code>concurrent.interpreters</code></a> module, plus an <code>InterpreterPoolExecutor</code> in <a href="https://docs.python.org/3/library/concurrent.futures.html"><code>concurrent.futures</code></a> that runs each worker in its own interpreter.</p>
<p>The rule of thumb, slightly rewritten for 2026:</p>
<ul>
<li>I/O-bound, many connections → <code>asyncio</code></li>
<li>I/O-bound, simpler or blocking-library code → threads</li>
<li>CPU-bound → processes, or subinterpreters, or the free-threaded build if you can use it</li>
</ul>
<div id="febbb29a" class="cell" data-execution_count="11">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> os</span>
<span id="cb19-2"></span>
<span id="cb19-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># A neutral way to size a thread/process pool to the machine.</span></span>
<span id="cb19-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CPUs available to this process:"</span>, os.process_cpu_count())</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>CPUs available to this process: 6</code></pre>
</div>
</div>
</section>
<section id="whats-new-gathered-up" class="level2">
<h2 class="anchored" data-anchor-id="whats-new-gathered-up">What’s new, gathered up</h2>
<p>The recent releases touch almost every stage above. Pulling the thread together:</p>
<p><strong>Python 3.13</strong> was the foundation release for the big shifts. Experimental free-threading (PEP 703) and the experimental JIT (PEP 744) both landed as previews. It also shipped a <a href="https://docs.python.org/3.13/whatsnew/3.13.html">much nicer REPL</a> — multiline editing, colors, paste handling — borrowed from PyPy, and gave <code>locals()</code> well-defined behavior in <a href="https://peps.python.org/pep-0667/">PEP 667</a>.</p>
<p><strong>Python 3.14</strong> (released October 2025) is where several of those grew up. Free-threading became <a href="https://docs.python.org/3.14/whatsnew/3.14.html">officially supported</a>, subinterpreters got a real stdlib API, and the JIT started shipping in the official installers. On the language side it added two features worth knowing:</p>
<p><a href="https://peps.python.org/pep-0649/">Deferred annotations</a> (PEP 649) changed how type hints are stored. Annotations are no longer evaluated when a function or class is defined; they’re computed lazily on demand, so forward references just work without quoting them in strings. A new <a href="https://docs.python.org/3/library/annotationlib.html"><code>annotationlib</code></a> module gives you control over how you read them back.</p>
<p><a href="https://peps.python.org/pep-0750/">Template strings</a> (PEP 750), or t-strings, are a new sibling of f-strings. A <code>t"..."</code> doesn’t produce a finished string — it produces a <code>Template</code> object that keeps the literal parts and the interpolated values <em>separate</em>, so a library can process them safely before assembling the result. It’s built for the exact situations where f-strings are dangerous: SQL, shell commands, HTML.</p>
<div id="7e3ef056" class="cell" data-execution_count="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> string.templatelib <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Template, Interpolation</span>
<span id="cb21-2"></span>
<span id="cb21-3">name <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;">"world"</span></span>
<span id="cb21-4">template <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">t"hello </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb21-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"type:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">type</span>(template).<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">__name__</span>)</span>
<span id="cb21-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> part <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> template:</span>
<span id="cb21-7">    <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;">isinstance</span>(part, Interpolation):</span>
<span id="cb21-8">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  interpolation: expr=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>part<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>expression<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!r}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> value=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>part<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>value<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!r}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb21-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb21-10">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"  literal text:  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>part<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!r}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>type: Template
  literal text:  'hello '
  interpolation: expr='name' value='world'</code></pre>
</div>
</div>
<p>The static text and the substituted value stay distinct, which is what lets a template-aware function escape the value correctly instead of trusting an already-flattened string. 3.14 also added <a href="https://peps.python.org/pep-0784/">Zstandard compression</a> (<code>compression.zstd</code>) and a <a href="https://peps.python.org/pep-0768/">remote debugging hook</a> that lets you attach <code>pdb</code> to a running process by PID.</p>
<p><strong>Python 3.15</strong> is in development — feature-frozen and in beta as of this writing, with a release planned for October 2026, so treat all of this as tentative until it ships. The draft what’s-new points at some genuinely interesting items: <a href="https://peps.python.org/pep-0810/">lazy imports</a> (PEP 810) via a <code>lazy import</code> form that defers loading a module until first use, <a href="https://peps.python.org/pep-0686/">UTF-8 as the default text encoding</a> regardless of locale (PEP 686), and a <a href="https://docs.python.org/3.15/whatsnew/3.15.html">new profiling package</a> including a low-overhead statistical sampling profiler. The free-threading and JIT work continues underneath. I’ll write these up properly once 3.15 is final and the list stops moving.</p>
</section>
<section id="the-shape-of-it" class="level2">
<h2 class="anchored" data-anchor-id="the-shape-of-it">The shape of it</h2>
<p>Step back and the whole thing is one straight line with a support structure beneath it. Text becomes tokens, tokens become a tree, the tree becomes bytecode, and a loop runs the bytecode — and under that loop, reference counting and a cyclic collector manage memory while the GIL (or its absence) decides who runs. Every stage is inspectable from Python itself: <code>tokenize</code>, <code>ast</code>, <code>dis</code>, <code>gc</code>, <code>sys</code>. That openness is the nicest thing about CPython. You don’t have to take the pipeline on faith; you can print it out and watch it work.</p>
<p>If you want to go deeper, the two best maps are the <a href="https://devguide.python.org/internals/">Python Developer’s Guide</a> and the <a href="https://github.com/python/cpython/tree/main/InternalDocs"><code>InternalDocs/</code></a> folder in the CPython source. Both are written for people seeing this for the first time, and both are kept current with the code.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>python</category>
  <category>internals</category>
  <guid>https://vsh852.com/posts/2026-02-21-cpython-internals/</guid>
  <pubDate>Sat, 21 Feb 2026 00:00:00 GMT</pubDate>
  <media:content url="https://vsh852.com/posts/2026-02-21-cpython-internals/thumbnail.png" medium="image" type="image/png" height="73" width="144"/>
</item>
<item>
  <title>Robot Javelin — counter-exploiting a one-bit information leak</title>
  <dc:creator>Victor S HUANG</dc:creator>
  <link>https://vsh852.com/posts/2026-01-04-robot-javelin/</link>
  <description><![CDATA[ 





<p>Another writeup I owed myself. The December 2025 <a href="https://www.janestreet.com/puzzles/robot-javelin-index/">Jane Street puzzle</a> asked:</p>
<blockquote class="blockquote">
<p>Two robots throw a javelin head-to-head. Each makes a first throw drawn uniformly from <img src="https://latex.codecogs.com/png.latex?%5B0,%201%5D">, then privately decides whether to keep it or take a fresh second throw (also uniform on <img src="https://latex.codecogs.com/png.latex?%5B0,%201%5D">, must be kept). Higher final distance wins. Historically robots play the Nash equilibrium of this game. But Spears Robot has a one-bit leak on you (Java-lin): they receive a bit telling whether your first throw was above or below a threshold <img src="https://latex.codecogs.com/png.latex?d"> of their choosing, and they pick <img src="https://latex.codecogs.com/png.latex?d"> to maximise their winning probability assuming you still play Nash. They don’t know that you know about the leak. Adjust your strategy to maximise your winning probability. Give the answer to <strong>10 decimal places</strong>.</p>
</blockquote>
<p>I <a href="https://github.com/vicw0ng-hk/puzzles">solved it</a> and want to write it up properly. The puzzle is a clean exploit/counter-exploit story. There’s a fair-game Nash baseline, then one player gains a bit of information, then the other player learns of the leak and shifts a single threshold to claw the edge back.</p>
<section id="the-nash-baseline" class="level2">
<h2 class="anchored" data-anchor-id="the-nash-baseline">The Nash baseline</h2>
<p>Each robot’s strategy is a single number: a rethrow threshold <img src="https://latex.codecogs.com/png.latex?t">. Keep the first throw if <img src="https://latex.codecogs.com/png.latex?X%20%5Cge%20t">, otherwise take a fresh throw. (Why a threshold? Holding the opponent’s strategy fixed, the value of keeping <img src="https://latex.codecogs.com/png.latex?x"> is increasing in <img src="https://latex.codecogs.com/png.latex?x"> while the value of rethrowing is constant — so the keep/rethrow decision flips at one cutoff.)</p>
<p>If a robot uses threshold <img src="https://latex.codecogs.com/png.latex?t">, its final score <img src="https://latex.codecogs.com/png.latex?Y"> has CDF</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AF(y;%5C,t)%20%5C;=%5C;%20%5Cbegin%7Bcases%7D%20t%5C,y%20&amp;%20y%20%5Cle%20t,%5C%5C%20y(1+t)%20-%20t%20&amp;%20y%20%3E%20t.%20%5Cend%7Bcases%7D%0A"></p>
<p>(Below <img src="https://latex.codecogs.com/png.latex?t">, the only way to land at <img src="https://latex.codecogs.com/png.latex?y"> is a rethrow, with weight <img src="https://latex.codecogs.com/png.latex?t">; above <img src="https://latex.codecogs.com/png.latex?t">, kept first throws contribute too.)</p>
<p>In a symmetric <a href="https://en.wikipedia.org/wiki/Nash_equilibrium">Nash equilibrium</a> both robots use the same <img src="https://latex.codecogs.com/png.latex?t">, and the player at the cutoff is indifferent between keeping and rethrowing. The win probability from keeping a score of exactly <img src="https://latex.codecogs.com/png.latex?t"> is <img src="https://latex.codecogs.com/png.latex?F(t;%20t)%20=%20t%5E2">. The win probability from rethrowing is <img src="https://latex.codecogs.com/png.latex?%5Cint_0%5E1%20F(r;%20t)%5C,%20dr%20=%20(1%20-%20t%20+%20t%5E2)/2">. Setting them equal,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0At%5E2%20%5C;=%5C;%20%5Ctfrac%7B1%20-%20t%20+%20t%5E2%7D%7B2%7D%5Cquad%5CLongrightarrow%5Cquad%20t%5E2%20+%20t%20-%201%20=%200%5Cquad%5CLongrightarrow%5Cquad%20t%20=%20%5Cvarphi%20=%20%5Ctfrac%7B%5Csqrt%7B5%7D%20-%201%7D%7B2%7D%20%5Capprox%200.618.%0A"></p>
<p>The <a href="https://en.wikipedia.org/wiki/Golden_ratio">golden-ratio conjugate</a>. At Nash both robots win half the time.</p>
</section>
<section id="spears-leak" class="level2">
<h2 class="anchored" data-anchor-id="spears-leak">Spears’ leak</h2>
<p>Spears picks <img src="https://latex.codecogs.com/png.latex?d">, then gets the bit <img src="https://latex.codecogs.com/png.latex?b%20=%20%5Cmathbb%7B1%7D%5BX_J%20%3E%20d%5D"> before deciding whether to rethrow. Under the assumption that Java-lin plays Nash with threshold <img src="https://latex.codecogs.com/png.latex?%5Cvarphi">, the most informative choice is <img src="https://latex.codecogs.com/png.latex?d%20=%20%5Cvarphi"> — the bit then exactly distinguishes “Java-lin rethrew” from “Java-lin kept”. Any other <img src="https://latex.codecogs.com/png.latex?d"> leaves Spears uncertain about whether Java-lin’s final score is uniform on <img src="https://latex.codecogs.com/png.latex?%5B0,1%5D"> or on <img src="https://latex.codecogs.com/png.latex?%5B%5Cvarphi,%201%5D">, which is the only thing the bit can resolve. (You can verify this by writing out Spears’ win probability as a function of <img src="https://latex.codecogs.com/png.latex?d"> and checking that <img src="https://latex.codecogs.com/png.latex?d%20=%20%5Cvarphi"> is the maximum; the derivative changes sign there.)</p>
<p>So under Spears’ (mistaken) belief, after observing <img src="https://latex.codecogs.com/png.latex?b"> Java-lin’s final score is</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?b%20=%200">: <img src="https://latex.codecogs.com/png.latex?Y_J%20%5Csim%20U(0,%201)"> (Java-lin rethrew).</li>
<li><img src="https://latex.codecogs.com/png.latex?b%20=%201">: <img src="https://latex.codecogs.com/png.latex?Y_J%20%5Csim%20U(%5Cvarphi,%201)"> (Java-lin kept).</li>
</ul>
<p>Spears now picks a rethrow threshold <img src="https://latex.codecogs.com/png.latex?r_b"> for each value of <img src="https://latex.codecogs.com/png.latex?b">, again by indifference.</p>
<p><strong><img src="https://latex.codecogs.com/png.latex?b%20=%200">.</strong> Java-lin’s score is uniform on <img src="https://latex.codecogs.com/png.latex?%5B0,1%5D">. Keeping <img src="https://latex.codecogs.com/png.latex?x_S"> wins with probability <img src="https://latex.codecogs.com/png.latex?x_S">; rethrowing wins with probability <img src="https://latex.codecogs.com/png.latex?1/2">. So <img src="https://latex.codecogs.com/png.latex?r_0%20=%201/2">.</p>
<p><strong><img src="https://latex.codecogs.com/png.latex?b%20=%201">.</strong> Java-lin’s score is uniform on <img src="https://latex.codecogs.com/png.latex?%5B%5Cvarphi,%201%5D">. Keeping <img src="https://latex.codecogs.com/png.latex?x_S%20%5Cge%20%5Cvarphi"> wins with probability <img src="https://latex.codecogs.com/png.latex?(x_S%20-%20%5Cvarphi)/(1%20-%20%5Cvarphi)">; rethrowing wins with probability <img src="https://latex.codecogs.com/png.latex?(1%20-%20%5Cvarphi)/2">. Setting them equal,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ar_1%20%5C;=%5C;%20%5Cvarphi%20+%20%5Ctfrac%7B(1-%5Cvarphi)%5E2%7D%7B2%7D%20%5C;=%5C;%201%20-%20%5Ctfrac%7B%5Cvarphi%7D%7B2%7D%20%5C;=%5C;%20%5Ctfrac%7B5%20-%20%5Csqrt%7B5%7D%7D%7B4%7D%20%5Capprox%200.691,%0A"></p>
<p>using <img src="https://latex.codecogs.com/png.latex?%5Cvarphi%5E2%20=%201%20-%20%5Cvarphi">.</p>
</section>
<section id="java-lins-counter-shift" class="level2">
<h2 class="anchored" data-anchor-id="java-lins-counter-shift">Java-lin’s counter-shift</h2>
<p>Now Java-lin secretly knows the leak. Spears is <em>committed</em> to thresholds <img src="https://latex.codecogs.com/png.latex?r_0%20=%201/2"> and <img src="https://latex.codecogs.com/png.latex?r_1%20=%201%20-%20%5Cvarphi/2">, regardless of what Java-lin does. Java-lin picks a new threshold <img src="https://latex.codecogs.com/png.latex?T"> to maximise its win probability. Crucially, the bit Spears receives is still <img src="https://latex.codecogs.com/png.latex?b%20=%20%5Cmathbb%7B1%7D%5BX_J%20%3E%20%5Cvarphi%5D"> (because Spears chose <img src="https://latex.codecogs.com/png.latex?d%20=%20%5Cvarphi"> before this game began).</p>
<p>Suppose <img src="https://latex.codecogs.com/png.latex?T%20%5Cle%20%5Cvarphi">. Java-lin’s behaviour splits into three intervals:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th style="text-align: left;"><img src="https://latex.codecogs.com/png.latex?X_J"> in</th>
<th style="text-align: center;">Java-lin does</th>
<th style="text-align: center;">Bit <img src="https://latex.codecogs.com/png.latex?b"></th>
<th style="text-align: center;">Spears’ threshold</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><img src="https://latex.codecogs.com/png.latex?%5B0,%20T)"></td>
<td style="text-align: center;">rethrow</td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?0"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?r_0%20=%201/2"></td>
</tr>
<tr class="even">
<td style="text-align: left;"><img src="https://latex.codecogs.com/png.latex?%5BT,%20%5Cvarphi%5D"></td>
<td style="text-align: center;"><strong>keep</strong></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?0"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?r_0%20=%201/2"></td>
</tr>
<tr class="odd">
<td style="text-align: left;"><img src="https://latex.codecogs.com/png.latex?(%5Cvarphi,%201%5D"></td>
<td style="text-align: center;">keep</td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?1"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?r_1%20=%201%20-%20%5Cvarphi/2"></td>
</tr>
</tbody>
</table>
<p>The middle row is the trick. On <img src="https://latex.codecogs.com/png.latex?%5BT,%20%5Cvarphi%5D"> Java-lin keeps a score that the Nash version would have thrown away. Spears, still believing Java-lin played Nash, expects a uniform rethrow from these <img src="https://latex.codecogs.com/png.latex?X_J"> values and sets <img src="https://latex.codecogs.com/png.latex?r_0%20=%201/2"> — leaving Java-lin’s <em>actual</em> score in <img src="https://latex.codecogs.com/png.latex?%5BT,%20%5Cvarphi%5D"> pleasantly above Spears’ rethrow target. The leak says “Java-lin rethrew”, but Java-lin didn’t.</p>
<p>Let <img src="https://latex.codecogs.com/png.latex?F_S(y;%20r)%20=%20ry"> for <img src="https://latex.codecogs.com/png.latex?y%20%5Cle%20r"> and <img src="https://latex.codecogs.com/png.latex?y(1+r)%20-%20r"> for <img src="https://latex.codecogs.com/png.latex?y%20%3E%20r"> be Spears’ CDF when using threshold <img src="https://latex.codecogs.com/png.latex?r">. Java-lin’s win probability is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AW(T)%20%5C;=%5C;%20T%20%5Ccdot%20%5Cunderbrace%7B%5Cint_0%5E1%20F_S(r;%20r_0)%5C,%20dr%7D_%7B%5Ctext%7BJava-lin%20rethrows%7D%7D%20%5C;+%5C;%20%5Cint_T%5E%7B%5Cvarphi%7D%20F_S(x;%20r_0)%5C,%20dx%20%5C;+%5C;%20%5Cint_%5Cvarphi%5E1%20F_S(x;%20r_1)%5C,%20dx.%0A"></p>
<p>The first integral evaluates to <img src="https://latex.codecogs.com/png.latex?(1%20-%20r_0%20+%20r_0%5E2)/2%20=%203/8">. The other two don’t depend on <img src="https://latex.codecogs.com/png.latex?T">. Differentiating,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AW'(T)%20%5C;=%5C;%20%5Ctfrac%7B3%7D%7B8%7D%20%5C;-%5C;%20F_S(T;%20%5Ctfrac%7B1%7D%7B2%7D)%20%5C;=%5C;%20%5Ctfrac%7B3%7D%7B8%7D%20%5C;-%5C;%20%5Cbigl(%5Ctfrac%7B3%7D%7B2%7DT%20-%20%5Ctfrac%7B1%7D%7B2%7D%5Cbigr)%20%5Cquad%20(T%20%5Cge%20%5Ctfrac%7B1%7D%7B2%7D).%0A"></p>
<p>Setting <img src="https://latex.codecogs.com/png.latex?W'(T)%20=%200"> gives</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cboxed%7B%5C,T%5E%5Cstar%20%5C;=%5C;%20%5Ctfrac%7B7%7D%7B12%7D.%5C,%7D%0A"></p>
<p>And <img src="https://latex.codecogs.com/png.latex?7/12%20%5Capprox%200.583%20%3C%20%5Cvarphi">, so the assumption <img src="https://latex.codecogs.com/png.latex?T%20%5Cle%20%5Cvarphi"> holds. Below <img src="https://latex.codecogs.com/png.latex?T%20=%201/2"> the marginal benefit of nudging <img src="https://latex.codecogs.com/png.latex?T"> up is positive too (the integrand is <img src="https://latex.codecogs.com/png.latex?r_0%20%5Ccdot%20T%20=%20T/2%20%3C%203/8"> for <img src="https://latex.codecogs.com/png.latex?T%20%3C%203/4">), so <img src="https://latex.codecogs.com/png.latex?7/12"> is the unique maximiser.</p>
</section>
<section id="solving-in-code" class="level2">
<h2 class="anchored" data-anchor-id="solving-in-code">Solving in code</h2>
<div id="solver" class="cell" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sympy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Rational, sqrt, simplify, integrate, Symbol, Piecewise, nsimplify</span>
<span id="cb1-2"></span>
<span id="cb1-3">x, T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Symbol(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, positive<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>), Symbol(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>, positive<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="cb1-4">phi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (sqrt(<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="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>
<span id="cb1-5">r0  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Rational(<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;">2</span>)</span>
<span id="cb1-6">r1  <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> phi<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="cb1-7"></span>
<span id="cb1-8"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> F_S(y, r):</span>
<span id="cb1-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Piecewise((r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>y, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> r), (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> r) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> r, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>))</span>
<span id="cb1-10"></span>
<span id="cb1-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Win prob with Java-lin threshold T (assumes 1/2 &lt;= T &lt;= phi):</span></span>
<span id="cb1-12">W_expr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb1-13">    T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> Rational(<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="cb1-14">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> integrate(F_S(x, r0), (x, T, phi))</span>
<span id="cb1-15">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> integrate(F_S(x, r1), (x, phi, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb1-16">)</span>
<span id="cb1-17">W_star <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> simplify(W_expr.subs(T, Rational(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)))</span>
<span id="cb1-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Closed form:"</span>, nsimplify(W_star))</span>
<span id="cb1-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Decimal:    </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(W_star)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.12f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb1-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Submission: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(W_star)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.10f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Closed form: 229/192 - 5*sqrt(5)/16
Decimal:    0.493937090365
Submission: 0.4939370904</code></pre>
</div>
</div>
<p>Tidied up, the closed form is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AW%5E%5Cstar%20%5C;=%5C;%20%5Cfrac%7B229%20-%2060%5Csqrt%7B5%7D%7D%7B192%7D%20%5C;=%5C;%200.4939370904%5Cldots%0A"></p>
<p>Just below <img src="https://latex.codecogs.com/png.latex?1/2">. Spears’ bit was worth more than Java-lin’s counter-shift could fully recover, but the gap is tiny — the Nash baseline of <img src="https://latex.codecogs.com/png.latex?0.5"> is almost reached.</p>
</section>
<section id="monte-carlo-gut-check" class="level2">
<h2 class="anchored" data-anchor-id="monte-carlo-gut-check">Monte Carlo gut-check</h2>
<p>Before I trust the recursion, I want to play a few million games at <img src="https://latex.codecogs.com/png.latex?T%20=%207/12"> against Spears’ fixed thresholds and watch the empirical win rate land on <img src="https://latex.codecogs.com/png.latex?W%5E%5Cstar">.</p>
<div id="monte-carlo" class="cell" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb3-2"></span>
<span id="cb3-3">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20251204</span>)</span>
<span id="cb3-4">phi_f <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;">float</span>(phi)</span>
<span id="cb3-5">r0_f, r1_f <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;">float</span>(r1)</span>
<span id="cb3-6">T_f <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;">7</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;">12</span></span>
<span id="cb3-7"></span>
<span id="cb3-8">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;">2_000_000</span></span>
<span id="cb3-9">XJ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<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>, N)</span>
<span id="cb3-10">XS <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<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>, N)</span>
<span id="cb3-11">RJ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<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>, N)</span>
<span id="cb3-12">RS <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<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>, N)</span>
<span id="cb3-13"></span>
<span id="cb3-14">YJ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(XJ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> T_f, XJ, RJ)</span>
<span id="cb3-15">bit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> XJ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> phi_f</span>
<span id="cb3-16">r_used <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(bit, r1_f, r0_f)</span>
<span id="cb3-17">YS <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(XS <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> r_used, XS, RS)</span>
<span id="cb3-18"></span>
<span id="cb3-19">wins <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;">float</span>((YJ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> YS).mean())</span>
<span id="cb3-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Empirical win prob: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>wins<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.6f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Analytic  win prob: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(W_star)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.6f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Empirical win prob: 0.493868
Analytic  win prob: 0.493937</code></pre>
</div>
</div>
<p>The two agree to within Monte Carlo noise, which is a relief — small mistakes in the bit-conditioning logic are easy to make.</p>
</section>
<section id="a-picture-of-the-optimum" class="level2">
<h2 class="anchored" data-anchor-id="a-picture-of-the-optimum">A picture of the optimum</h2>
<div id="cell-fig-W" class="cell" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb5-2"></span>
<span id="cb5-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> F_S_num(y, r):</span>
<span id="cb5-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.where(y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> r, r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>y, 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>r) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> r)</span>
<span id="cb5-5"></span>
<span id="cb5-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> W(T):</span>
<span id="cb5-7">    rethrow_win <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> r0_f <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> r0_f<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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb5-8">    xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(T, phi_f, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>)</span>
<span id="cb5-9">    mid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.trapezoid(F_S_num(xs, r0_f), xs)</span>
<span id="cb5-10">    xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(phi_f, <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;">400</span>)</span>
<span id="cb5-11">    top <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.trapezoid(F_S_num(xs, r1_f), xs)</span>
<span id="cb5-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> rethrow_win <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> mid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> top</span>
<span id="cb5-13"></span>
<span id="cb5-14">Ts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.30</span>, phi_f, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>)</span>
<span id="cb5-15">Ws <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([W(T) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> T <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> Ts])</span>
<span id="cb5-16">T_star <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;">7</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;">12</span></span>
<span id="cb5-17">W_num <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;">float</span>(W_star)</span>
<span id="cb5-18"></span>
<span id="cb5-19">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb5-20">ax.plot(Ts, Ws, color<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;">"#1f77b4"</span>, lw<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="cb5-21">ax.axvline(phi_f, color<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;">"grey"</span>, lw<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.8</span>, ls<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>, alpha<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.8</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"Nash </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\v</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">arphi</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-22">ax.axvline(T_star, color<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;">"black"</span>, lw<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.8</span>, ls<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>, alpha<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.7</span>)</span>
<span id="cb5-23">ax.axhline(W_num,  color<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;">"black"</span>, lw<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.8</span>, ls<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>, alpha<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.7</span>)</span>
<span id="cb5-24">ax.plot([T_star], [W_num], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, color<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;">"#d62728"</span>, ms<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;">7</span>)</span>
<span id="cb5-25">ax.annotate(</span>
<span id="cb5-26">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"$T^</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">star = 7/12$</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$W^</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">star </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">approx </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>W_num<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.10f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$"</span>,</span>
<span id="cb5-27">    xy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(T_star, W_num), xytext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(T_star <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.18</span>, W_num <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.012</span>),</span>
<span id="cb5-28">    arrowprops<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;">dict</span>(arrowstyle<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;">"-&gt;"</span>, color<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;">"black"</span>, lw<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.8</span>),</span>
<span id="cb5-29">)</span>
<span id="cb5-30">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Java-lin's rethrow threshold $T$"</span>)</span>
<span id="cb5-31">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"win probability"</span>)</span>
<span id="cb5-32">ax.legend(loc<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;">"lower right"</span>)</span>
<span id="cb5-33">ax.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<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.3</span>)</span>
<span id="cb5-34">plt.savefig(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"thumbnail.png"</span>, dpi<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;">110</span>, bbox_inches<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;">"tight"</span>)</span>
<span id="cb5-35">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div id="fig-w" class="quarto-float quarto-figure quarto-figure-center anchored" data-fig-align="center">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-w-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://vsh852.com/posts/2026-01-04-robot-javelin/index_files/figure-html/fig-w-output-1.png" class="quarto-figure quarto-figure-center figure-img" width="606" height="431">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-w-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Java-lin’s win probability as a function of its rethrow threshold <img src="https://latex.codecogs.com/png.latex?T">, against Spears’ fixed exploit. The red dot marks the counter-exploit optimum <img src="https://latex.codecogs.com/png.latex?T%5E%5Cstar%20=%207/12">; the grey line shows the Nash threshold <img src="https://latex.codecogs.com/png.latex?%5Cvarphi"> for reference.
</figcaption>
</figure>
</div>
</div>
</div>
<p>The shape makes sense. Pushing <img src="https://latex.codecogs.com/png.latex?T"> down from <img src="https://latex.codecogs.com/png.latex?%5Cvarphi"> keeps more of the band <img src="https://latex.codecogs.com/png.latex?%5BT,%20%5Cvarphi%5D"> — exactly the band Spears mis-reads as a uniform rethrow — and that pays until <img src="https://latex.codecogs.com/png.latex?T"> drops below <img src="https://latex.codecogs.com/png.latex?7/12">. Past that point, the kept scores are too weak to beat Spears’ <img src="https://latex.codecogs.com/png.latex?r_0%20=%201/2"> often enough, and the gain from extra band-keeping turns negative.</p>
</section>
<section id="what-made-it-nice" class="level2">
<h2 class="anchored" data-anchor-id="what-made-it-nice">What made it nice</h2>
<p>The trick was the asymmetry of belief. Spears’ threshold <img src="https://latex.codecogs.com/png.latex?d%20=%20%5Cvarphi"> is locked in by Spears’ assumption that Java-lin plays Nash; Java-lin can break that assumption without Spears noticing, and the bit Spears receives turns into mild misinformation on the interval <img src="https://latex.codecogs.com/png.latex?%5BT,%20%5Cvarphi%5D">. One derivative picks the right <img src="https://latex.codecogs.com/png.latex?T">, and the rest is integrals.</p>
<p>The official Jane Street <a href="https://www.janestreet.com/puzzles/robot-javelin-solution/">solution</a> follows the same path and lands on the same answer, <img src="https://latex.codecogs.com/png.latex?0.4939370904">.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>puzzle</category>
  <category>math</category>
  <category>python</category>
  <guid>https://vsh852.com/posts/2026-01-04-robot-javelin/</guid>
  <pubDate>Sun, 04 Jan 2026 00:00:00 GMT</pubDate>
  <media:content url="https://vsh852.com/posts/2026-01-04-robot-javelin/thumbnail.png" medium="image" type="image/png" height="103" width="144"/>
</item>
<item>
  <title>Robot Baseball — tuning the strike zone for maximum drama</title>
  <dc:creator>Victor S HUANG</dc:creator>
  <link>https://vsh852.com/posts/2025-11-04-robot-baseball/</link>
  <description><![CDATA[ 





<p>Another writeup I owed myself. The October 2025 <a href="https://www.janestreet.com/puzzles/robot-baseball-index/">Jane Street puzzle</a> asked:</p>
<blockquote class="blockquote">
<p>Games are composed of a series of independent at-bats in which the batter is trying to maximize expected score and the pitcher is trying to minimize expected score. An at-bat is a series of pitches with a running count of balls and strikes, both starting at zero. For each pitch, the pitcher decides whether to throw a ball or strike, and the batter decides whether to wait or swing; these decisions are made secretly and simultaneously. (…) An at-bat ends when either the count of balls reaches <img src="https://latex.codecogs.com/png.latex?4"> (batter receives <img src="https://latex.codecogs.com/png.latex?1"> point), the count of strikes reaches <img src="https://latex.codecogs.com/png.latex?3"> (batter receives <img src="https://latex.codecogs.com/png.latex?0"> points), or the batter hits a home run (batter receives <img src="https://latex.codecogs.com/png.latex?4"> points). (…) Let <img src="https://latex.codecogs.com/png.latex?q"> be the probability of at-bats reaching full count; <img src="https://latex.codecogs.com/png.latex?q"> is dependent on <img src="https://latex.codecogs.com/png.latex?p">. Assume the batter and pitcher are both using optimal mixed strategies and Quad-A has chosen the <img src="https://latex.codecogs.com/png.latex?p"> that maximizes <img src="https://latex.codecogs.com/png.latex?q">. Find this <img src="https://latex.codecogs.com/png.latex?q">, the maximal probability at-bats reach full count, to <strong>10 decimal places</strong>.</p>
</blockquote>
<p>I <a href="https://github.com/vicw0ng-hk/puzzles">solved it</a> and want to write it up properly. The puzzle has two layers: a 2-by-2 game played at every count, and a single dial <img src="https://latex.codecogs.com/png.latex?p"> that the league turns to maximise drama. Each layer is short on its own — what makes the puzzle nice is that they fit together cleanly.</p>
<section id="reading-the-rules" class="level2">
<h2 class="anchored" data-anchor-id="reading-the-rules">Reading the rules</h2>
<p>At each pitch the pitcher picks a probability <img src="https://latex.codecogs.com/png.latex?t%20%5Cin%20%5B0,1%5D"> of throwing a strike, and the batter picks a probability <img src="https://latex.codecogs.com/png.latex?%5Csigma%20%5Cin%20%5B0,1%5D"> of swinging. The four cells of the resulting 2-by-2 give</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th style="text-align: left;">pitcher &nbsp;batter</th>
<th style="text-align: center;">wait</th>
<th style="text-align: center;">swing</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">ball</td>
<td style="text-align: center;">balls <img src="https://latex.codecogs.com/png.latex?+1"></td>
<td style="text-align: center;">strikes <img src="https://latex.codecogs.com/png.latex?+1"></td>
</tr>
<tr class="even">
<td style="text-align: left;">strike</td>
<td style="text-align: center;">strikes <img src="https://latex.codecogs.com/png.latex?+1"></td>
<td style="text-align: center;">home run with prob <img src="https://latex.codecogs.com/png.latex?p">, else strikes <img src="https://latex.codecogs.com/png.latex?+1"></td>
</tr>
</tbody>
</table>
<p>An at-bat is a Markov chain on counts <img src="https://latex.codecogs.com/png.latex?(b,%20s)"> with <img src="https://latex.codecogs.com/png.latex?b%20%5Cin%20%5C%7B0,1,2,3%5C%7D"> and <img src="https://latex.codecogs.com/png.latex?s%20%5Cin%20%5C%7B0,1,2%5C%7D">. It terminates when <img src="https://latex.codecogs.com/png.latex?b%20=%204"> (walk, <img src="https://latex.codecogs.com/png.latex?1"> point), <img src="https://latex.codecogs.com/png.latex?s%20=%203"> (strikeout, <img src="https://latex.codecogs.com/png.latex?0"> points), or a home run (<img src="https://latex.codecogs.com/png.latex?4"> points).</p>
<p>Let <img src="https://latex.codecogs.com/png.latex?V(b,%20s)"> be the at-bat value to the batter under <a href="https://en.wikipedia.org/wiki/Nash_equilibrium">Nash equilibrium</a> play. Boundary conditions are <img src="https://latex.codecogs.com/png.latex?V(b,%203)%20=%200"> and <img src="https://latex.codecogs.com/png.latex?V(4,%20s)%20=%201">.</p>
</section>
<section id="a-symmetry-that-does-most-of-the-work" class="level2">
<h2 class="anchored" data-anchor-id="a-symmetry-that-does-most-of-the-work">A symmetry that does most of the work</h2>
<p>Write <img src="https://latex.codecogs.com/png.latex?V_b%20=%20V(b+1,%20s)"> and <img src="https://latex.codecogs.com/png.latex?V_s%20=%20V(b,%20s+1)">. Combining the four cells, the expected payoff at <img src="https://latex.codecogs.com/png.latex?(b,%20s)"> is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AV%20%5C;=%5C;%20(1-t)(1-%5Csigma)%5C,%20V_b%20%5C;+%5C;%20%5Cbigl%5Bt%20+%20%5Csigma%20-%20t%5Csigma(1+p)%5Cbigr%5D%20V_s%20%5C;+%5C;%204%20p%5C,%20t%5Csigma.%0A"></p>
<p>Stare at that for a moment. <strong>It’s symmetric in <img src="https://latex.codecogs.com/png.latex?t"> and <img src="https://latex.codecogs.com/png.latex?%5Csigma"></strong>: swap them and nothing changes. The pitcher minimises this and the batter maximises it, but they’re playing against the same expression. So at equilibrium</p>
<p><img src="https://latex.codecogs.com/png.latex?%0At%5E%5Cstar%20=%20%5Csigma%5E%5Cstar.%0A"></p>
<p>That single observation collapses two unknowns per state into one. The Jane Street <a href="https://www.janestreet.com/puzzles/robot-baseball-solution/">solution</a> calls it out as the trick: “the outcome of a pitch is symmetric with respect to the pitcher’s choice and the batter’s choice.”</p>
</section>
<section id="solving-the-per-state-game" class="level2">
<h2 class="anchored" data-anchor-id="solving-the-per-state-game">Solving the per-state game</h2>
<p>In a <a href="https://en.wikipedia.org/wiki/Strategy_(game_theory)#Mixed_strategy">mixed-strategy equilibrium</a> of a <img src="https://latex.codecogs.com/png.latex?2%5Ctimes%202"> game, each player picks the probability that makes the <em>opponent</em> indifferent between their two pure actions. From the batter’s side, the batter is indifferent between always waiting (value <img src="https://latex.codecogs.com/png.latex?V_b"> if the pitcher’s pitch lands as a ball, <img src="https://latex.codecogs.com/png.latex?V_s"> if a strike — overall <img src="https://latex.codecogs.com/png.latex?(1-t)V_b%20+%20t%20V_s">) and always swinging (value <img src="https://latex.codecogs.com/png.latex?(1-t)V_s%20+%20t%5B(1-p)V_s%20+%204p%5D%20=%20V_s%20+%20tp(4%20-%20V_s)">).</p>
<p>Setting those equal and solving for <img src="https://latex.codecogs.com/png.latex?t%20=%20%5Csigma"> gives</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Csigma%20%5C;=%5C;%20%5Cfrac%7BV_b%20-%20V_s%7D%7B%5C,4p%20-%20(1+p)V_s%20+%20V_b%5C,%7D.%0A"></p>
<p>And the equilibrium value (just plug <img src="https://latex.codecogs.com/png.latex?t%20=%200"> into the always-swing expression — both pure actions give the same answer by indifference) is the very tidy</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AV(b,%20s)%20%5C;=%5C;%20V_s%20+%20%5Csigma%20%5Ccdot%20p%20%5Ccdot%20(4%20-%20V_s).%0A"></p>
<p>That’s the recursion. Walk the count grid from the terminal states inward and you get <img src="https://latex.codecogs.com/png.latex?V"> and <img src="https://latex.codecogs.com/png.latex?%5Csigma"> at every state in twelve assignments.</p>
</section>
<section id="counting-the-path-to-a-full-count" class="level2">
<h2 class="anchored" data-anchor-id="counting-the-path-to-a-full-count">Counting the path to a full count</h2>
<p>Once <img src="https://latex.codecogs.com/png.latex?%5Csigma"> is known at every state, the state-to-state transition probabilities follow from the same payoff matrix. Reading off the cells:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5CPr(%5Ctext%7Bball%20count%7D%5C%20+1)%20&amp;=%20(1-%5Csigma)%5E2,%20%5C%5C%0A%5CPr(%5Ctext%7Bstrike%20count%7D%5C%20+1)%20&amp;=%202%5Csigma%20-%20%5Csigma%5E2(1+p),%20%5C%5C%0A%5CPr(%5Ctext%7Bhome%20run%7D)%20&amp;=%20p%5Csigma%5E2.%0A%5Cend%7Baligned%7D%0A"></p>
<p>(The three add to <img src="https://latex.codecogs.com/png.latex?1">, as a sanity check.) Starting from <img src="https://latex.codecogs.com/png.latex?(0,0)"> with mass <img src="https://latex.codecogs.com/png.latex?1"> and pushing forward through this Markov chain, <img src="https://latex.codecogs.com/png.latex?q"> is just the mass that lands on <img src="https://latex.codecogs.com/png.latex?(3,%202)">.</p>
</section>
<section id="backward-then-forward-in-code" class="level2">
<h2 class="anchored" data-anchor-id="backward-then-forward-in-code">Backward, then forward, in code</h2>
<div id="solver" class="cell" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> solve(p):</span>
<span id="cb1-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Return q(p) and the equilibrium swing probabilities."""</span></span>
<span id="cb1-5">    V <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros((<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb1-6">    V[<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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># walk</span></span>
<span id="cb1-7">    V[:, <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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># strikeout</span></span>
<span id="cb1-8">    sigma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros((<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb1-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tot <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="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="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>
<span id="cb1-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> b <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>):</span>
<span id="cb1-11">            s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tot <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> b</span>
<span id="cb1-12">            <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> (<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;">&lt;=</span> s <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;">2</span>):</span>
<span id="cb1-13">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb1-14">            Vb, Vs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> V[b<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>, s], V[b, s<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="cb1-15">            sg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (Vb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> Vs) <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>p <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>p)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>Vs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> Vb)</span>
<span id="cb1-16">            sigma[b, s] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sg</span>
<span id="cb1-17">            V[b, s] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Vs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> sg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p <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> Vs)</span>
<span id="cb1-18">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># forward: probability of reaching each state</span></span>
<span id="cb1-19">    q <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros((<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb1-20">    q[<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>] <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;">1.0</span></span>
<span id="cb1-21">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> tot <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>):</span>
<span id="cb1-22">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> b <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>):</span>
<span id="cb1-23">            s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tot <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> b</span>
<span id="cb1-24">            <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> (<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;">&lt;=</span> s <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;">2</span>) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> (b, s) <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb1-25">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb1-26">            sg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sigma[b, s]</span>
<span id="cb1-27">            p_strike <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>sg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> sg<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>sg<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>p)</span>
<span id="cb1-28">            p_ball <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> sg)<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="cb1-29">            q[b, s<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> q[b, s] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p_strike</span>
<span id="cb1-30">            q[b<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>, s] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> q[b, s] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p_ball</span>
<span id="cb1-31">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> q[<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;">2</span>], sigma, V</span>
<span id="cb1-32"></span>
<span id="cb1-33">q0, _, V <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> solve(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb1-34"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"At p = 0.5: q = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>q0<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.6f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">,  V(0,0) = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>V[<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>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.6f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>At p = 0.5: q = 0.184180,  V(0,0) = 0.919179</code></pre>
</div>
</div>
<p>A quick sanity check at <img src="https://latex.codecogs.com/png.latex?p%20=%200.5"> — half of swung-at strikes leave the park, which is way too generous for the pitcher. The batter’s expected score should be high, and reaching full count should be unlikely. Both come out as expected.</p>
</section>
<section id="optimising-p" class="level2">
<h2 class="anchored" data-anchor-id="optimising-p">Optimising <img src="https://latex.codecogs.com/png.latex?p"></h2>
<p>We want <img src="https://latex.codecogs.com/png.latex?%5Carg%5Cmax_p%20q(p)">. It’s a one-dimensional problem and <img src="https://latex.codecogs.com/png.latex?q"> is smooth on <img src="https://latex.codecogs.com/png.latex?(0,%201)">, so <a href="https://en.wikipedia.org/wiki/Brent%27s_method">Brent’s method</a> on the interior is more than enough.</p>
<div id="optimise" class="cell" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.optimize <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> minimize_scalar</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> mpmath <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> mp, mpf</span>
<span id="cb3-3"></span>
<span id="cb3-4">res <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> minimize_scalar(</span>
<span id="cb3-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> p: <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>solve(p)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>],</span>
<span id="cb3-6">    bounds<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;">1e-6</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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-6</span>),</span>
<span id="cb3-7">    method<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;">"bounded"</span>,</span>
<span id="cb3-8">    options<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;">"xatol"</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-13</span>},</span>
<span id="cb3-9">)</span>
<span id="cb3-10">p_star <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> res.x</span>
<span id="cb3-11">q_star <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>res.fun</span>
<span id="cb3-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"p* = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.12f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"q* = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>q_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.12f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Submission: q* = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>q_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.10f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>p* = 0.226973229098
q* = 0.295967993374
Submission: q* = 0.2959679934</code></pre>
</div>
</div>
<p>To ten decimal places, <img src="https://latex.codecogs.com/png.latex?q%5E%5Cstar%20=%200.2959679934">, attained near <img src="https://latex.codecogs.com/png.latex?p%5E%5Cstar%20%5Capprox%200.2269732">.</p>
</section>
<section id="monte-carlo-gut-check" class="level2">
<h2 class="anchored" data-anchor-id="monte-carlo-gut-check">Monte Carlo gut-check</h2>
<p>Before I trust either the recursion or the optimiser, I want to play a few hundred thousand at-bats at the optimal <img src="https://latex.codecogs.com/png.latex?p"> and the equilibrium <img src="https://latex.codecogs.com/png.latex?%5Csigma">, and see the empirical full-count rate land on <img src="https://latex.codecogs.com/png.latex?q%5E%5Cstar">.</p>
<div id="monte-carlo" class="cell" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20251004</span>)</span>
<span id="cb5-2"></span>
<span id="cb5-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> simulate(p, sigma, 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;">400_000</span>):</span>
<span id="cb5-4">    full <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="cb5-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <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>(n):</span>
<span id="cb5-6">        b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s <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="cb5-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> b <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;">4</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> s <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;">3</span>:</span>
<span id="cb5-8">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (b, s) <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb5-9">                full <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="cb5-10">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span>
<span id="cb5-11">            sg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sigma[b, s]</span>
<span id="cb5-12">            t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> sg     <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pitcher throws strike with prob sigma</span></span>
<span id="cb5-13">            sw <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> sg    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># batter swings with prob sigma</span></span>
<span id="cb5-14">            <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> t <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> sw:</span>
<span id="cb5-15">                b <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="cb5-16">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">elif</span> t <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> sw:</span>
<span id="cb5-17">                s <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="cb5-18">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">elif</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> t <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> sw:</span>
<span id="cb5-19">                s <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="cb5-20">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb5-21">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> rng.random() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> p:</span>
<span id="cb5-22">                    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span>             <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># home run</span></span>
<span id="cb5-23">                s <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="cb5-24">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> full <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n</span>
<span id="cb5-25"></span>
<span id="cb5-26">_, sigma_star, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> solve(p_star)</span>
<span id="cb5-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Empirical q at p* : </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>simulate(p_star, sigma_star)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-28"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Analytic  q at p* : </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>q_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Empirical q at p* : 0.2962
Analytic  q at p* : 0.2960</code></pre>
</div>
</div>
<p>The two agree to within Monte Carlo noise. Good — both halves of the solver are honest.</p>
</section>
<section id="a-picture-of-the-optimum" class="level2">
<h2 class="anchored" data-anchor-id="a-picture-of-the-optimum">A picture of the optimum</h2>
<div id="cell-fig-q" class="cell" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb7-2"></span>
<span id="cb7-3">ps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>)</span>
<span id="cb7-4">qs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([solve(pp)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> pp <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> ps])</span>
<span id="cb7-5"></span>
<span id="cb7-6">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb7-7">ax.plot(ps, qs, color<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;">"#1f77b4"</span>, lw<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="cb7-8">ax.axvline(p_star, color<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;">"black"</span>, lw<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.8</span>, ls<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>, alpha<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.7</span>)</span>
<span id="cb7-9">ax.axhline(q_star, color<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;">"black"</span>, lw<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.8</span>, ls<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>, alpha<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.7</span>)</span>
<span id="cb7-10">ax.plot([p_star], [q_star], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ko"</span>, ms<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>
<span id="cb7-11">ax.annotate(</span>
<span id="cb7-12">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"$p^</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">star </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">approx </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$q^</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">star </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">approx </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>q_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.10f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$"</span>,</span>
<span id="cb7-13">    xy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(p_star, q_star), xytext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(p_star <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.15</span>, q_star <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.04</span>),</span>
<span id="cb7-14">    arrowprops<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;">dict</span>(arrowstyle<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;">"-&gt;"</span>, color<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;">"black"</span>, lw<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.8</span>),</span>
<span id="cb7-15">)</span>
<span id="cb7-16">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"home-run probability $p$ on a swung strike"</span>)</span>
<span id="cb7-17">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"probability of reaching full count"</span>)</span>
<span id="cb7-18">ax.set_xlim(<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>)</span>
<span id="cb7-19">ax.set_ylim(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(qs) <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;">1.1</span>)</span>
<span id="cb7-20">ax.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<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.3</span>)</span>
<span id="cb7-21">plt.savefig(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"thumbnail.png"</span>, dpi<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;">110</span>, bbox_inches<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;">"tight"</span>)</span>
<span id="cb7-22">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div id="fig-q" class="quarto-float quarto-figure quarto-figure-center anchored" data-fig-align="center">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-q-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://vsh852.com/posts/2025-11-04-robot-baseball/index_files/figure-html/fig-q-output-1.png" class="quarto-figure quarto-figure-center figure-img" width="608" height="431">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-q-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Probability <img src="https://latex.codecogs.com/png.latex?q(p)"> of an at-bat reaching a full count, under optimal mixed-strategy play. The maximum sits at <img src="https://latex.codecogs.com/png.latex?p%5E%5Cstar%20%5Capprox%200.227"> with <img src="https://latex.codecogs.com/png.latex?q%5E%5Cstar%20%5Capprox%200.2960">.
</figcaption>
</figure>
</div>
</div>
</div>
<p>The shape makes sense. As <img src="https://latex.codecogs.com/png.latex?p%20%5Cto%200">, batters never bother swinging and pitchers always throw strikes, so at-bats end in three pitches (strikeouts) — full counts are rare. As <img src="https://latex.codecogs.com/png.latex?p%20%5Cto%201">, every swung strike is a home run; batters swing freely and at-bats end fast for the other reason. The sweet spot for <em>length</em> sits in between, just below <img src="https://latex.codecogs.com/png.latex?p%20=%20%5Ctfrac%7B1%7D%7B4%7D">.</p>
</section>
<section id="what-made-it-nice" class="level2">
<h2 class="anchored" data-anchor-id="what-made-it-nice">What made it nice</h2>
<p>The trick was the <img src="https://latex.codecogs.com/png.latex?t%20%5Cleftrightarrow%20%5Csigma"> symmetry. Once you spot that, every state collapses to a one-variable indifference equation, and the value recursion fits in a few lines of code. Wrapping it in a 1D optimiser over <img src="https://latex.codecogs.com/png.latex?p"> does the rest.</p>
<p>The official Jane Street <a href="https://www.janestreet.com/puzzles/robot-baseball-solution/">solution</a> follows the same backward-induction-plus-1D-search and lands on the same answer, <img src="https://latex.codecogs.com/png.latex?0.2959679934">.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>puzzle</category>
  <category>math</category>
  <category>python</category>
  <guid>https://vsh852.com/posts/2025-11-04-robot-baseball/</guid>
  <pubDate>Tue, 04 Nov 2025 00:00:00 GMT</pubDate>
  <media:content url="https://vsh852.com/posts/2025-11-04-robot-baseball/thumbnail.png" medium="image" type="image/png" height="103" width="144"/>
</item>
<item>
  <title>Robot Road Trip — picking the perfect lane speed</title>
  <dc:creator>Victor S HUANG</dc:creator>
  <link>https://vsh852.com/posts/2025-08-04-robot-road-trip/</link>
  <description><![CDATA[ 





<p>Another writeup I owed myself. The July 2025 <a href="https://www.janestreet.com/puzzles/robot-road-trip-index/">Jane Street puzzle</a> asked:</p>
<blockquote class="blockquote">
<p>Robot cars have a top speed (which they prefer to maintain at all times while driving) that’s a real number randomly drawn uniformly between <img src="https://latex.codecogs.com/png.latex?1"> and <img src="https://latex.codecogs.com/png.latex?2"> miles per minute. A two-lane highway for robot cars has a fast lane (with minimum speed <img src="https://latex.codecogs.com/png.latex?a">) and a slow lane (with maximum speed <img src="https://latex.codecogs.com/png.latex?a">). When a faster car overtakes a slower car in the same lane, the slower car is required to decelerate to either change lanes (if both cars start in the fast lane) or stop on the shoulder (if both cars start in the slow lane). Robot cars decelerate and accelerate at a constant rate of <img src="https://latex.codecogs.com/png.latex?1"> mile per minute per minute, timed so the faster, overtaking car doesn’t have to change speed at all, and passing happens instantaneously. If cars rarely meet (…) and you want to minimize the miles not driven due to passing, what should <img src="https://latex.codecogs.com/png.latex?a"> be set to? Give your answer to <strong>10 decimal places</strong>.</p>
</blockquote>
<p>I <a href="https://github.com/vicw0ng-hk/puzzles">solved it</a> and want to write it up properly. Two ingredients carry the whole thing: a base rate that comes from a parallelogram, and a cost-per-pass that’s just a quadratic.</p>
<section id="reading-the-rules" class="level2">
<h2 class="anchored" data-anchor-id="reading-the-rules">Reading the rules</h2>
<p>Speeds <img src="https://latex.codecogs.com/png.latex?u,%20v"> are independent uniform on <img src="https://latex.codecogs.com/png.latex?%5B1,%202%5D">. A pass between two cars with speeds <img src="https://latex.codecogs.com/png.latex?u%20%3C%20v"> does one of three things, depending on where <img src="https://latex.codecogs.com/png.latex?a"> sits:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?u,%20v%20%5Cle%20a">: both in the slow lane. The slower car must brake to <img src="https://latex.codecogs.com/png.latex?0"> and stop on the shoulder.</li>
<li><img src="https://latex.codecogs.com/png.latex?u,%20v%20%5Cge%20a">: both in the fast lane. The slower car brakes to <img src="https://latex.codecogs.com/png.latex?a"> and changes lanes.</li>
<li><img src="https://latex.codecogs.com/png.latex?u%20%3C%20a%20%3C%20v">: different lanes, no interaction.</li>
</ul>
<p>Constant deceleration of <img src="https://latex.codecogs.com/png.latex?1"> mi/min² means braking from speed <img src="https://latex.codecogs.com/png.latex?u"> down to target speed <img src="https://latex.codecogs.com/png.latex?s"> takes time <img src="https://latex.codecogs.com/png.latex?u%20-%20s">. The distance you <em>would</em> have covered at speed <img src="https://latex.codecogs.com/png.latex?u"> minus the distance you <em>actually</em> covered (a triangle of base <img src="https://latex.codecogs.com/png.latex?u-s"> and height <img src="https://latex.codecogs.com/png.latex?u-s">, plus a matching acceleration triangle on the way back up — actually, let me just compute it).</p>
<p>If you cruise at <img src="https://latex.codecogs.com/png.latex?u"> for time <img src="https://latex.codecogs.com/png.latex?2(u-s)"> you travel <img src="https://latex.codecogs.com/png.latex?2u(u-s)">. If you instead brake linearly to <img src="https://latex.codecogs.com/png.latex?s"> (takes <img src="https://latex.codecogs.com/png.latex?u-s"> minutes, average speed <img src="https://latex.codecogs.com/png.latex?(u+s)/2">, distance <img src="https://latex.codecogs.com/png.latex?%5Ctfrac12(u+s)(u-s)">) and accelerate back (same), you travel <img src="https://latex.codecogs.com/png.latex?(u+s)(u-s)%20=%20u%5E2%20-%20s%5E2">. So the lost distance is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A2u(u-s)%20-%20(u%5E2%20-%20s%5E2)%20=%20(u-s)%5E2.%0A"></p>
<p>Lost distance <img src="https://latex.codecogs.com/png.latex?=%20(u-s)%5E2">. Sanity check the puzzle’s worked examples:</p>
<ul>
<li>Slow lane, <img src="https://latex.codecogs.com/png.latex?u=1.0"> braking to <img src="https://latex.codecogs.com/png.latex?s=0">: cost <img src="https://latex.codecogs.com/png.latex?(1-0)%5E2%20=%201"> mile. The puzzle says “exactly <img src="https://latex.codecogs.com/png.latex?1"> mile”. Match.</li>
<li>Fast lane, <img src="https://latex.codecogs.com/png.latex?u=1.7">, <img src="https://latex.codecogs.com/png.latex?a=1.2">: cost <img src="https://latex.codecogs.com/png.latex?(1.7-1.2)%5E2%20=%200.25"> miles. Match.</li>
</ul>
</section>
<section id="how-often-two-cars-meet" class="level2">
<h2 class="anchored" data-anchor-id="how-often-two-cars-meet">How often two cars meet</h2>
<p>This is the tricky bit and it’s where I got stuck for a while. A car’s speed alone doesn’t tell you how many other cars it meets — a fast car catches more slow cars per minute, and it spends <em>less</em> time on the road for a given trip length <img src="https://latex.codecogs.com/png.latex?N">. Both effects matter.</p>
<p>Fix the faster car at speed <img src="https://latex.codecogs.com/png.latex?v"> and trace its journey from <img src="https://latex.codecogs.com/png.latex?(0,%200)"> to <img src="https://latex.codecogs.com/png.latex?(N,%20N/v)"> in <img src="https://latex.codecogs.com/png.latex?(%5Ctext%7Bdistance%7D,%20%5Ctext%7Btime%7D)"> space. A second car at speed <img src="https://latex.codecogs.com/png.latex?u%20%3C%20v"> is overtaken iff it starts at a <img src="https://latex.codecogs.com/png.latex?(%5Ctext%7Bdistance%7D,%20%5Ctext%7Btime%7D)"> that puts it on a collision course inside the highway. That set of starts is a parallelogram with sides parallel to the two cars’ worldlines.</p>
<p>Two of its sides are the <img src="https://latex.codecogs.com/png.latex?v">-car’s worldline (length <img src="https://latex.codecogs.com/png.latex?N%5Csqrt%7B1%20+%201/v%5E2%7D">, slope <img src="https://latex.codecogs.com/png.latex?1/v">) and a translate of the <img src="https://latex.codecogs.com/png.latex?u">-car’s worldline (slope <img src="https://latex.codecogs.com/png.latex?1/u">). The cross-product / shoelace formula gives the area as</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BArea%7D%20=%20N%5E2%5Cleft(%5Cfrac%7B1%7D%7Bu%7D%20-%20%5Cfrac%7B1%7D%7Bv%7D%5Cright).%0A"></p>
<p>Since trip starts arrive uniformly at rate <img src="https://latex.codecogs.com/png.latex?z"> per (mile <img src="https://latex.codecogs.com/png.latex?%5Ccdot"> minute), the expected number of <img src="https://latex.codecogs.com/png.latex?u">-speed cars overtaken (per <img src="https://latex.codecogs.com/png.latex?du">) is <img src="https://latex.codecogs.com/png.latex?z%20%5Ccdot%20N%5E2%20(1/u%20-%201/v)%20%5C,%20du">. The <img src="https://latex.codecogs.com/png.latex?N%5E2"> factor and the rate <img src="https://latex.codecogs.com/png.latex?z"> both factor out of the optimisation — they don’t depend on <img src="https://latex.codecogs.com/png.latex?a"> — so we can drop them.</p>
<div id="cell-fig-parallelogram" class="cell" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-3"></span>
<span id="cb1-4">N, u, v <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;">1.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.8</span></span>
<span id="cb1-5">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># v-car worldline from (0,0) to (N, N/v)</span></span>
<span id="cb1-8">ax.plot([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, N], [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>v], color<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;">"#d62728"</span>, lw<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;">2.2</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"$v$-car ($v=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>v<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$)"</span>)</span>
<span id="cb1-9">ax.annotate(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>, xy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(N, N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>v), xytext<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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb1-10">            arrowprops<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;">dict</span>(arrowstyle<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;">"-&gt;"</span>, color<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;">"#d62728"</span>, lw<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;">2.2</span>))</span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Parallelogram of u-car starts: corners at (0,0), (N, N/v), (N, N/v - N/u + N/u) ... let's compute</span></span>
<span id="cb1-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># u-car starts at (x0, t0) and reaches (x0 + N, t0 + N/u). For an overtake in [0,N], we need</span></span>
<span id="cb1-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the u-car's worldline to cross the v-car's worldline somewhere in distance [0, N].</span></span>
<span id="cb1-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Parametrise: at time t, v-car at v*t, u-car at x0 + u*(t - t0). Equal =&gt; t = (x0 - u t0) / (v - u).</span></span>
<span id="cb1-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Want 0 &lt;= v*t &lt;= N. The start region is a parallelogram.</span></span>
<span id="cb1-17">corners <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([</span>
<span id="cb1-18">    [<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>],</span>
<span id="cb1-19">    [N, N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>v],</span>
<span id="cb1-20">    [N <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>u<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>v, N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>u],   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># actually let's just shade by enumeration below</span></span>
<span id="cb1-21">    [<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>u<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>v <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>N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>u],</span>
<span id="cb1-22">])</span>
<span id="cb1-23"></span>
<span id="cb1-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Shade by sampling</span></span>
<span id="cb1-25">xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<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;">1.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span>)</span>
<span id="cb1-26">ts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<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;">1.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span>)</span>
<span id="cb1-27">X, T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.meshgrid(xs, ts)</span>
<span id="cb1-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># u-car at speed u starting at (X, T) reaches highway position v*tt at time tt where</span></span>
<span id="cb1-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># X + u*(tt - T) = v*tt  =&gt;  tt = (X - u*T) / (v - u)</span></span>
<span id="cb1-30">tt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> u<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>T) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> u)</span>
<span id="cb1-31">pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> tt</span>
<span id="cb1-32">mask <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (pos <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;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> N) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (tt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> T) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (tt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>u)</span>
<span id="cb1-33">ax.contourf(X, T, mask.astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>), levels<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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>], colors<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;">"#1f77b4"</span>], alpha<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.25</span>)</span>
<span id="cb1-34"></span>
<span id="cb1-35"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Draw a sample u-car worldline through the parallelogram</span></span>
<span id="cb1-36">x0, t0 <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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, <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.2</span></span>
<span id="cb1-37">ax.plot([x0, x0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> N], [t0, t0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> N<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>u], color<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;">"#1f77b4"</span>, lw<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;">1.6</span>, ls<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>,</span>
<span id="cb1-38">        label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"$u$-car ($u=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>u<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$)"</span>)</span>
<span id="cb1-39"></span>
<span id="cb1-40">ax.axhline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<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;">"black"</span>, lw<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.4</span>)</span>
<span id="cb1-41">ax.axvline(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, color<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;">"black"</span>, lw<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.4</span>)</span>
<span id="cb1-42">ax.axvline(N, color<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;">"black"</span>, lw<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.4</span>, ls<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>)</span>
<span id="cb1-43">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"distance"</span>)</span>
<span id="cb1-44">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"time"</span>)</span>
<span id="cb1-45">ax.set_xlim(<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;">1.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>)</span>
<span id="cb1-46">ax.set_ylim(<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;">1.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span>)</span>
<span id="cb1-47">ax.legend(loc<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;">"upper left"</span>)</span>
<span id="cb1-48">ax.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<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.3</span>)</span>
<span id="cb1-49">plt.savefig(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"thumbnail.png"</span>, dpi<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;">110</span>, bbox_inches<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;">"tight"</span>)</span>
<span id="cb1-50">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div id="fig-parallelogram" class="quarto-float quarto-figure quarto-figure-center anchored" data-fig-align="center">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-parallelogram-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://vsh852.com/posts/2025-08-04-robot-road-trip/index_files/figure-html/fig-parallelogram-output-1.png" class="quarto-figure quarto-figure-center figure-img" width="608" height="429">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-parallelogram-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Worldlines of the <img src="https://latex.codecogs.com/png.latex?v">-car (red, <img src="https://latex.codecogs.com/png.latex?v=1.8">) and a translated <img src="https://latex.codecogs.com/png.latex?u">-car worldline (blue, <img src="https://latex.codecogs.com/png.latex?u=1.1">). The shaded parallelogram is the set of <img src="https://latex.codecogs.com/png.latex?(x,t)"> start points for which the <img src="https://latex.codecogs.com/png.latex?u">-car gets overtaken on the highway <img src="https://latex.codecogs.com/png.latex?%5B0,%20N%5D">.
</figcaption>
</figure>
</div>
</div>
</div>
</section>
<section id="the-objective" class="level2">
<h2 class="anchored" data-anchor-id="the-objective">The objective</h2>
<p>Putting the rate and the cost together, the expected lost distance per pass (up to constants that don’t depend on <img src="https://latex.codecogs.com/png.latex?a">) is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AJ(a)%20=%20%5Cunderbrace%7B%5Cint_1%5Ea%5C!%5Cint_u%5Ea%20u%5E2%20%5Cleft(%5Cfrac%7B1%7D%7Bu%7D%20-%20%5Cfrac%7B1%7D%7Bv%7D%5Cright)%20dv%5C,%20du%7D_%7B%5Ctext%7Bslow-lane%20passes,%20target%20%7D%200%7D%0A%5C;+%5C;%20%5Cunderbrace%7B%5Cint_a%5E2%5C!%5Cint_u%5E2%20(u%20-%20a)%5E2%20%5Cleft(%5Cfrac%7B1%7D%7Bu%7D%20-%20%5Cfrac%7B1%7D%7Bv%7D%5Cright)%20dv%5C,%20du%7D_%7B%5Ctext%7Bfast-lane%20passes,%20target%20%7D%20a%7D.%0A"></p>
<p>Both integrals are over pairs <img src="https://latex.codecogs.com/png.latex?u%20%3C%20v"> in the appropriate lane, weighted by the parallelogram area <img src="https://latex.codecogs.com/png.latex?1/u%20-%201/v"> and the cost <img src="https://latex.codecogs.com/png.latex?(u%20-%20s)%5E2"> with <img src="https://latex.codecogs.com/png.latex?s%20=%200"> or <img src="https://latex.codecogs.com/png.latex?s%20=%20a">.</p>
</section>
<section id="doing-the-inner-integrals" class="level2">
<h2 class="anchored" data-anchor-id="doing-the-inner-integrals">Doing the inner integrals</h2>
<p>The inner integral over <img src="https://latex.codecogs.com/png.latex?v"> is elementary:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cint_u%5Ea%20%5Cleft(%5Cfrac%7B1%7D%7Bu%7D%20-%20%5Cfrac%7B1%7D%7Bv%7D%5Cright)%20dv%20=%20%5Cfrac%7Ba%20-%20u%7D%7Bu%7D%20-%20%5Cln%5Cfrac%7Ba%7D%7Bu%7D.%0A"></p>
<p>So the slow-lane piece is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AJ_1(a)%20=%20%5Cint_1%5Ea%20u%5E2%20%5Cleft%5B%5Cfrac%7Ba%20-%20u%7D%7Bu%7D%20-%20%5Cln%5Cfrac%7Ba%7D%7Bu%7D%5Cright%5D%20du%20=%20%5Cint_1%5Ea%20%5Cleft%5Bu(a-u)%20-%20u%5E2%20%5Cln%5Cfrac%7Ba%7D%7Bu%7D%5Cright%5D%20du.%0A"></p>
<p>And the fast-lane piece is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AJ_2(a)%20=%20%5Cint_a%5E2%20(u%20-%20a)%5E2%20%5Cleft%5B%5Cfrac%7B2%20-%20u%7D%7Bu%7D%20-%20%5Cln%5Cfrac%7B2%7D%7Bu%7D%5Cright%5D%20du.%0A"></p>
</section>
<section id="differentiating-with-leibniz" class="level2">
<h2 class="anchored" data-anchor-id="differentiating-with-leibniz">Differentiating with Leibniz</h2>
<p>We want <img src="https://latex.codecogs.com/png.latex?J'(a)%20=%200">. Both pieces have <img src="https://latex.codecogs.com/png.latex?a"> in their limits <em>and</em> in the integrand, so <a href="https://en.wikipedia.org/wiki/Leibniz_integral_rule">Leibniz’s rule</a> is the right tool.</p>
<p><strong>Slow lane.</strong> The boundary term at <img src="https://latex.codecogs.com/png.latex?u%20=%20a"> is <img src="https://latex.codecogs.com/png.latex?a(a-a)%20-%20a%5E2%5Cln%201%20=%200">. So</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AJ_1'(a)%20=%20%5Cint_1%5Ea%20%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20a%7D%5C!%5Cleft%5Bu(a-u)%20-%20u%5E2%20%5Cln%5Cfrac%7Ba%7D%7Bu%7D%5Cright%5D%20du%20=%20%5Cint_1%5Ea%20%5Cleft(u%20-%20%5Cfrac%7Bu%5E2%7D%7Ba%7D%5Cright)%20du%20=%20%5Cfrac%7Ba%5E2%7D%7B6%7D%20-%20%5Cfrac%7B1%7D%7B2%7D%20+%20%5Cfrac%7B1%7D%7B3a%7D.%0A"></p>
<p><strong>Fast lane.</strong> The boundary term at <img src="https://latex.codecogs.com/png.latex?u%20=%20a"> is <img src="https://latex.codecogs.com/png.latex?(a-a)%5E2%5B%5Ccdots%5D%20=%200">. So</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AJ_2'(a)%20=%20-%5Cint_a%5E2%202(u%20-%20a)%5Cleft%5B%5Cfrac%7B2%20-%20u%7D%7Bu%7D%20-%20%5Cln%5Cfrac%7B2%7D%7Bu%7D%5Cright%5D%20du.%0A"></p>
<p>The first term in the bracket is a polynomial in <img src="https://latex.codecogs.com/png.latex?u"> (after dividing); the second yields to integration by parts with <img src="https://latex.codecogs.com/png.latex?w%20=%20%5Cln(2/u)">. Dropping the algebra,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AJ_2'(a)%20=%20-2%5Cleft%5B%5Cfrac%7B4%20-%20a%5E2%7D%7B2%7D%20-%202a%5Cln%5Cfrac%7B2%7D%7Ba%7D%20-%201%20+%202a%20-%20%5Cfrac%7B3a%5E2%7D%7B4%7D%20-%20%5Cfrac%7Ba%5E2%7D%7B2%7D%5Cln%5Cfrac%7B2%7D%7Ba%7D%5Cright%5D.%0A"></p>
<p>Setting <img src="https://latex.codecogs.com/png.latex?J_1'(a)%20+%20J_2'(a)%20=%200"> and tidying gives the optimality condition</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cboxed%7B%5C,16%20a%5E3%20-%2024%20a%5E2%20-%2015%20a%20+%202%20=%206%20a%5E2%20(a%20+%204)%5C,%20%5Cln%5C!%5Cfrac%7Ba%7D%7B2%7D.%5C,%7D%0A"></p>
<p>A transcendental equation, but a tame one — the LHS is a cubic and the RHS is the cubic <img src="https://latex.codecogs.com/png.latex?6a%5E2(a+4)"> times <img src="https://latex.codecogs.com/png.latex?%5Cln(a/2)"> (which is negative on <img src="https://latex.codecogs.com/png.latex?(1,2)">). One root in <img src="https://latex.codecogs.com/png.latex?(1,%202)">.</p>
</section>
<section id="solving-numerically" class="level2">
<h2 class="anchored" data-anchor-id="solving-numerically">Solving numerically</h2>
<div id="foc-root" class="cell" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> mpmath <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> mp, mpf, log, findroot</span>
<span id="cb2-2"></span>
<span id="cb2-3">mp.dps <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;">30</span></span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> foc(a):</span>
<span id="cb2-6">    a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> mpf(a)</span>
<span id="cb2-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</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><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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</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><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;">15</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> <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;">6</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>(a <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>log(a<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="cb2-8"></span>
<span id="cb2-9">a_star <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> findroot(foc, mpf(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1.18"</span>))</span>
<span id="cb2-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"a* = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mp<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nstr(a_star, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb2-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Submission: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>mp<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nstr(a_star, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>a* = 1.17714141681551
Submission: 1.1771414168</code></pre>
</div>
</div>
<p>To ten decimal places, <img src="https://latex.codecogs.com/png.latex?a%5E%7B%5Cstar%7D%20=%201.1771414168">.</p>
</section>
<section id="monte-carlo-gut-check" class="level2">
<h2 class="anchored" data-anchor-id="monte-carlo-gut-check">Monte Carlo gut-check</h2>
<p>Before I trust either the cost formula or the rate, I want to see them line up with a simulation. I drop <img src="https://latex.codecogs.com/png.latex?N"> pairs of speeds, simulate every pass under the rules, and average the lost distance — weighted by the parallelogram-area rate so the <em>base rate</em> is honest too.</p>
<div id="monte-carlo" class="cell" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb4-2"></span>
<span id="cb4-3">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20250704</span>)</span>
<span id="cb4-4"></span>
<span id="cb4-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> expected_loss(a, 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;">400_000</span>):</span>
<span id="cb4-6">    u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<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;">2</span>, N)</span>
<span id="cb4-7">    v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.uniform(<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;">2</span>, N)</span>
<span id="cb4-8">    lo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.minimum(u, v)</span>
<span id="cb4-9">    hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.maximum(u, v)</span>
<span id="cb4-10">    rate <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>lo <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>hi</span>
<span id="cb4-11">    cost <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(</span>
<span id="cb4-12">        hi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> a, lo<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="cb4-13">        np.where(lo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> a, (lo <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><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>),</span>
<span id="cb4-14">    )</span>
<span id="cb4-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(np.mean(rate <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> cost))</span>
<span id="cb4-16"></span>
<span id="cb4-17"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> a <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.10</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1771414168</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.25</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.40</span>]:</span>
<span id="cb4-18">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"a = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>a<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.10f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: J = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>expected_loss(a)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.6f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>a = 1.1000000000: J = 0.007327
a = 1.1771414168: J = 0.006015
a = 1.2500000000: J = 0.007328
a = 1.4000000000: J = 0.018900</code></pre>
</div>
</div>
<p>The minimum sits firmly at <img src="https://latex.codecogs.com/png.latex?a%20%5Capprox%201.1771">, exactly where the FOC says it should.</p>
</section>
<section id="a-picture-of-the-cost" class="level2">
<h2 class="anchored" data-anchor-id="a-picture-of-the-cost">A picture of the cost</h2>
<div id="cell-fig-cost" class="cell" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb6-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb6-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.integrate <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> dblquad</span>
<span id="cb6-4"></span>
<span id="cb6-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> J(a):</span>
<span id="cb6-6">    j1, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dblquad(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> v, u: u<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>u<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>u <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>v), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, a, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> u: u, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> u: a) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> a <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;">1</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> (<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>)</span>
<span id="cb6-7">    j2, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dblquad(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> v, u: (u<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><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;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>u <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>v), a, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> u: u, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> u: <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;">if</span> a <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;">2</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> (<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>)</span>
<span id="cb6-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> j1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> j2</span>
<span id="cb6-9"></span>
<span id="cb6-10">aa <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.001</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.999</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>)</span>
<span id="cb6-11">vals <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([J(a) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> a <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> aa])</span>
<span id="cb6-12">a_star <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;">1.1771414168</span></span>
<span id="cb6-13"></span>
<span id="cb6-14">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb6-15">ax.plot(aa, vals, color<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;">"#1f77b4"</span>, lw<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="cb6-16">ax.axvline(a_star, color<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;">"black"</span>, lw<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.8</span>, ls<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>, alpha<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.7</span>)</span>
<span id="cb6-17">ax.plot([a_star], [J(a_star)], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ko"</span>, ms<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>
<span id="cb6-18">ax.annotate(</span>
<span id="cb6-19">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"$a^</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">star </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">approx </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>a_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.10f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$"</span>,</span>
<span id="cb6-20">    xy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(a_star, J(a_star)), xytext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(a_star <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.1</span>, J(a_star) <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.005</span>),</span>
<span id="cb6-21">    arrowprops<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;">dict</span>(arrowstyle<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;">"-&gt;"</span>, color<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;">"black"</span>, lw<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.8</span>),</span>
<span id="cb6-22">)</span>
<span id="cb6-23">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lane speed $a$"</span>)</span>
<span id="cb6-24">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"expected lost distance per pass (up to constant)"</span>)</span>
<span id="cb6-25">ax.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<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.3</span>)</span>
<span id="cb6-26">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div id="fig-cost" class="quarto-float quarto-figure quarto-figure-center anchored" data-fig-align="center">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-cost-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://vsh852.com/posts/2025-08-04-robot-road-trip/index_files/figure-html/fig-cost-output-1.png" class="quarto-figure quarto-figure-center figure-img" width="597" height="431">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-cost-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Expected lost distance per pass as a function of the lane speed <img src="https://latex.codecogs.com/png.latex?a">. The minimum is at <img src="https://latex.codecogs.com/png.latex?a%5E%7B%5Cstar%7D%20%5Capprox%201.1771">.
</figcaption>
</figure>
</div>
</div>
</div>
<p>The curve is convex with a single interior minimum. As <img src="https://latex.codecogs.com/png.latex?a%20%5Cto%201%5E+"> the slow-lane region shrinks but every slow-lane pass still costs almost a full mile. As <img src="https://latex.codecogs.com/png.latex?a%20%5Cto%202%5E-"> the fast-lane region shrinks but fast-lane passes get expensive because the slower car has to brake far. The optimum balances those two costs.</p>
</section>
<section id="what-made-it-nice" class="level2">
<h2 class="anchored" data-anchor-id="what-made-it-nice">What made it nice</h2>
<p>The trick was untangling the <em>rate</em> from the <em>cost</em>. Once I drew the parallelogram, the base rate <img src="https://latex.codecogs.com/png.latex?1/u%20-%201/v"> for a pair of speeds fell out and the rest was a calculus exercise. Constant-acceleration kinematics give a clean <img src="https://latex.codecogs.com/png.latex?(u-s)%5E2"> for the cost, and Leibniz’s rule keeps the differentiation honest even with <img src="https://latex.codecogs.com/png.latex?a"> inside the limits.</p>
<p>The official Jane Street <a href="https://www.janestreet.com/puzzles/robot-road-trip-solution/">solution</a> follows the same path and lands on the same answer, <img src="https://latex.codecogs.com/png.latex?1.1771414168">.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>puzzle</category>
  <category>math</category>
  <category>python</category>
  <guid>https://vsh852.com/posts/2025-08-04-robot-road-trip/</guid>
  <pubDate>Mon, 04 Aug 2025 00:00:00 GMT</pubDate>
  <media:content url="https://vsh852.com/posts/2025-08-04-robot-road-trip/thumbnail.png" medium="image" type="image/png" height="102" width="144"/>
</item>
<item>
  <title>Sum One, Somewhere — counting paths through an infinite random tree</title>
  <dc:creator>Victor S HUANG</dc:creator>
  <link>https://vsh852.com/posts/2025-05-03-sum-one-somewhere/</link>
  <description><![CDATA[ 





<p>Another writeup I owed myself. The April 2025 <a href="https://www.janestreet.com/puzzles/sum-one-somewhere-index/">Jane Street puzzle</a> asked:</p>
<blockquote class="blockquote">
<p>For a fixed <img src="https://latex.codecogs.com/png.latex?p">, independently label the nodes of an infinite complete binary tree <img src="https://latex.codecogs.com/png.latex?0"> with probability <img src="https://latex.codecogs.com/png.latex?p">, and <img src="https://latex.codecogs.com/png.latex?1"> otherwise. For what <img src="https://latex.codecogs.com/png.latex?p"> is there exactly a <img src="https://latex.codecogs.com/png.latex?%5Ctfrac%7B1%7D%7B2%7D"> probability that there exists an infinite path down the tree that sums to <strong>at most <img src="https://latex.codecogs.com/png.latex?1"></strong> (that is, all nodes visited, with the possible exception of one, will be labeled <img src="https://latex.codecogs.com/png.latex?0">). Find this value of <img src="https://latex.codecogs.com/png.latex?p"> accurate to <strong>10 decimal places</strong>.</p>
</blockquote>
<p>I <a href="https://github.com/vicw0ng-hk/puzzles">solved it</a> and want to write it up properly. The puzzle is on the easier end — once you spot the right recursion, the rest is bookkeeping — so I’ll take the chance to spend a few extra paragraphs on <em>why</em> the recursion works and what could go wrong if you set it up carelessly.</p>
<section id="what-were-really-being-asked" class="level2">
<h2 class="anchored" data-anchor-id="what-were-really-being-asked">What we’re really being asked</h2>
<p>The tree is infinite, complete, and binary: every node has exactly two children, forever. Each node is independently labeled <img src="https://latex.codecogs.com/png.latex?0"> (probability <img src="https://latex.codecogs.com/png.latex?p">) or <img src="https://latex.codecogs.com/png.latex?1"> (probability <img src="https://latex.codecogs.com/png.latex?1-p">). A <em>path down the tree</em> starts at the root and, at each step, picks one of the two children — so a path is an infinite sequence of nodes.</p>
<p>“Sum at most <img src="https://latex.codecogs.com/png.latex?1">” means the labels along the path add up to <img src="https://latex.codecogs.com/png.latex?%5Cle%201">. Since labels are <img src="https://latex.codecogs.com/png.latex?0"> or <img src="https://latex.codecogs.com/png.latex?1">, that’s the same as saying the path uses <strong>at most one</strong> node labeled <img src="https://latex.codecogs.com/png.latex?1">.</p>
<p>Define two events on the subtree rooted at any given node:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?A"> = “some infinite path down this subtree has sum <img src="https://latex.codecogs.com/png.latex?%5Cle%201">” (at most one <img src="https://latex.codecogs.com/png.latex?1">),</li>
<li><img src="https://latex.codecogs.com/png.latex?B"> = “some infinite path down this subtree has sum <img src="https://latex.codecogs.com/png.latex?%5Cle%200">” (all <img src="https://latex.codecogs.com/png.latex?0">s).</li>
</ul>
<p>Let <img src="https://latex.codecogs.com/png.latex?a%20=%20%5CPr(A)"> and <img src="https://latex.codecogs.com/png.latex?b%20=%20%5CPr(B)">. Both are well-defined: every node’s subtree is statistically identical to every other node’s subtree, so the probabilities don’t depend on which node you root at. The puzzle asks for the <img src="https://latex.codecogs.com/png.latex?p"> that makes <img src="https://latex.codecogs.com/png.latex?a%20=%20%5Ctfrac%7B1%7D%7B2%7D">.</p>
</section>
<section id="setting-up-the-recursion" class="level2">
<h2 class="anchored" data-anchor-id="setting-up-the-recursion">Setting up the recursion</h2>
<p>The trick is to condition on the root’s label and on the two child subtrees. The two children are independent copies of the whole tree, so their events are independent of each other and of the root.</p>
<p><strong>Equation for <img src="https://latex.codecogs.com/png.latex?b">.</strong> A subtree contains an all-zero path iff (i) the root is <img src="https://latex.codecogs.com/png.latex?0">, <strong>and</strong> (ii) at least one of the two child subtrees contains an all-zero path.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ab%20=%20p%20%5Ccdot%20%5Cbigl%5B1%20-%20(1-b)%5E2%5Cbigr%5D%20=%20p%20%5Ccdot%20b(2-b).%0A"></p>
<p><strong>Equation for <img src="https://latex.codecogs.com/png.latex?a">.</strong> A subtree contains a “<img src="https://latex.codecogs.com/png.latex?%5Cle%201"> ones” path iff:</p>
<ul>
<li>the root is <img src="https://latex.codecogs.com/png.latex?0"> (probability <img src="https://latex.codecogs.com/png.latex?p">), and a child subtree continues with a <img src="https://latex.codecogs.com/png.latex?%5Cle%201"> ones path — at least one of the two children must succeed, so probability <img src="https://latex.codecogs.com/png.latex?1%20-%20(1-a)%5E2%20=%20a(2-a)">; or</li>
<li>the root is <img src="https://latex.codecogs.com/png.latex?1"> (probability <img src="https://latex.codecogs.com/png.latex?1-p">), in which case the path has already used its one <img src="https://latex.codecogs.com/png.latex?1">, and a child subtree must continue with an <em>all-zero</em> path — probability <img src="https://latex.codecogs.com/png.latex?b(2-b)">.</li>
</ul>
<p><img src="https://latex.codecogs.com/png.latex?%0Aa%20=%20p%20%5Ccdot%20a(2-a)%20+%20(1-p)%20%5Ccdot%20b(2-b).%0A"></p>
<p>That’s the whole setup. Now we have to solve.</p>
</section>
<section id="picking-the-right-branch" class="level2">
<h2 class="anchored" data-anchor-id="picking-the-right-branch">Picking the right branch</h2>
<p>The first equation factors as <img src="https://latex.codecogs.com/png.latex?b%5Cbigl%5B1%20-%20p(2-b)%5Cbigr%5D%20=%200">, so</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ab%20=%200%20%5Cqquad%20%5Ctext%7Bor%7D%20%5Cqquad%20b%20=%202%20-%20%5Ctfrac%7B1%7D%7Bp%7D.%0A"></p>
<p>Both are honest fixed points. Which one is the actual probability?</p>
<p>This is a <a href="https://en.wikipedia.org/wiki/Galton%E2%80%93Watson_process">classical Galton–Watson</a> survival question in disguise. Walk down the tree taking only <img src="https://latex.codecogs.com/png.latex?0">-labeled nodes; at each step you have <img src="https://latex.codecogs.com/png.latex?0">, <img src="https://latex.codecogs.com/png.latex?1">, or <img src="https://latex.codecogs.com/png.latex?2"> surviving children, with mean <img src="https://latex.codecogs.com/png.latex?2p">. The branching process survives forever with positive probability iff its mean offspring is <img src="https://latex.codecogs.com/png.latex?%3E%201">, i.e.&nbsp;<img src="https://latex.codecogs.com/png.latex?p%20%3E%20%5Ctfrac%7B1%7D%7B2%7D">. Below that threshold the all-zero path dies out almost surely and <img src="https://latex.codecogs.com/png.latex?b%20=%200">. Above it, the survival probability is the <em>non-trivial</em> root, <img src="https://latex.codecogs.com/png.latex?b%20=%202%20-%201/p">.</p>
<p>A puzzle with answer “exactly <img src="https://latex.codecogs.com/png.latex?%5Ctfrac%7B1%7D%7B2%7D">” can’t live in the <img src="https://latex.codecogs.com/png.latex?b%20=%200"> regime (we’ll see why momentarily), so we take</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ab%20=%202%20-%20%5Ctfrac%7B1%7D%7Bp%7D,%20%5Cqquad%20p%20%3E%20%5Ctfrac%7B1%7D%7B2%7D.%0A"></p>
</section>
<section id="the-cubic" class="level2">
<h2 class="anchored" data-anchor-id="the-cubic">The cubic</h2>
<p>Substitute that <img src="https://latex.codecogs.com/png.latex?b"> into the equation for <img src="https://latex.codecogs.com/png.latex?a">. First simplify <img src="https://latex.codecogs.com/png.latex?b(2-b)">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ab(2-b)%20=%20%5Cleft(2%20-%20%5Ctfrac%7B1%7D%7Bp%7D%5Cright)%5C!%5Cleft(%5Ctfrac%7B1%7D%7Bp%7D%5Cright)%20=%20%5Cfrac%7B2p-1%7D%7Bp%5E2%7D.%0A"></p>
<p>So the <img src="https://latex.codecogs.com/png.latex?a">-equation becomes</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Aa%20=%20p%20%5Ccdot%20a(2-a)%20+%20(1-p)%20%5Ccdot%20%5Cfrac%7B2p-1%7D%7Bp%5E2%7D.%0A"></p>
<p>Setting <img src="https://latex.codecogs.com/png.latex?a%20=%20%5Ctfrac%7B1%7D%7B2%7D"> (the puzzle’s condition), so <img src="https://latex.codecogs.com/png.latex?a(2-a)%20=%20%5Ctfrac%7B3%7D%7B4%7D">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctfrac%7B1%7D%7B2%7D%20=%20%5Ctfrac%7B3p%7D%7B4%7D%20+%20%5Cfrac%7B(1-p)(2p-1)%7D%7Bp%5E2%7D.%0A"></p>
<p>Multiply through by <img src="https://latex.codecogs.com/png.latex?4p%5E2">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A2p%5E2%20=%203p%5E3%20+%204(1-p)(2p-1).%0A"></p>
<p>Expand the last term: <img src="https://latex.codecogs.com/png.latex?4(1-p)(2p-1)%20=%204(2p%20-%201%20-%202p%5E2%20+%20p)%20=%20-8p%5E2%20+%2012p%20-%204">. Collecting,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A2p%5E2%20=%203p%5E3%20-%208p%5E2%20+%2012p%20-%204%20%5Cquad%5CLongrightarrow%5Cquad%20%5Cboxed%7B%5C,3p%5E3%20-%2010p%5E2%20+%2012p%20-%204%20=%200.%5C,%7D%0A"></p>
<p>A cubic in <img src="https://latex.codecogs.com/png.latex?p">. The puzzle says “find <img src="https://latex.codecogs.com/png.latex?p"> to 10 decimal places,” so we just need its root in <img src="https://latex.codecogs.com/png.latex?(%5Ctfrac%7B1%7D%7B2%7D,%201)">.</p>
</section>
<section id="monte-carlo-gut-check" class="level2">
<h2 class="anchored" data-anchor-id="monte-carlo-gut-check">Monte Carlo gut-check</h2>
<p>Before I trust the cubic, I want to see the recursion match a simulation. Sampling an infinite tree is impossible, but the path either “fails” within the first few dozen levels or it doesn’t — at depth <img src="https://latex.codecogs.com/png.latex?D"> around 100, the probability of a <img src="https://latex.codecogs.com/png.latex?%5Cle%201">-ones path of length <img src="https://latex.codecogs.com/png.latex?D"> is already indistinguishable from the limit at the precision we care about.</p>
<div id="monte-carlo" class="cell" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> survives(p, depth, k, rng):</span>
<span id="cb1-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Does some path of length `depth` use at most k ones, under labelling p?"""</span></span>
<span id="cb1-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> depth <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="cb1-6">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb1-7">    label <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="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> rng.random() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> p <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb1-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> label <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="cb1-9">        k <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="cb1-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> k <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;">0</span>:</span>
<span id="cb1-11">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span>
<span id="cb1-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (</span>
<span id="cb1-13">        survives(p, depth <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>, k, rng)</span>
<span id="cb1-14">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> survives(p, depth <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>, k, rng)</span>
<span id="cb1-15">    )</span>
<span id="cb1-16"></span>
<span id="cb1-17"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-18">sys.setrecursionlimit(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span>)</span>
<span id="cb1-19"></span>
<span id="cb1-20">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20250403</span>)</span>
<span id="cb1-21">p_star <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.5306035754</span></span>
<span id="cb1-22">N, depth <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;">5000</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">120</span></span>
<span id="cb1-23">hits <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;">sum</span>(survives(p_star, depth, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, rng) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <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>(N))</span>
<span id="cb1-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Monte Carlo at p = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>hits <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> N<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">  (target 0.5)"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Monte Carlo at p = 0.5306035754: 0.5008  (target 0.5)</code></pre>
</div>
</div>
<p>The simulator does the recursion the same way the math does — try the left subtree, and if that fails, try the right. With 5,000 trials at depth 120 the estimate sits around <img src="https://latex.codecogs.com/png.latex?0.5">, exactly as the analytic answer demands.</p>
</section>
<section id="solving-the-cubic-exactly" class="level2">
<h2 class="anchored" data-anchor-id="solving-the-cubic-exactly">Solving the cubic exactly</h2>
<p><code>sympy</code> solves it symbolically. Three real roots fall out; only one of them lies in <img src="https://latex.codecogs.com/png.latex?(%5Ctfrac%7B1%7D%7B2%7D,%201)">.</p>
<div id="sympy-exact" class="cell" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sympy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Rational, solve, sqrt, simplify, cbrt, nsimplify, latex</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sympy.abc <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> p</span>
<span id="cb3-3"></span>
<span id="cb3-4">cubic <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>p<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="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>p<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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>p <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="cb3-5">roots <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> solve(cubic, p)</span>
<span id="cb3-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> roots:</span>
<span id="cb3-7">    val <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;">complex</span>(r.evalf())</span>
<span id="cb3-8">    <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;">abs</span>(val.imag) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-10</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> val.real <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;">1</span>:</span>
<span id="cb3-9">        p_root <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> r</span>
<span id="cb3-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Exact root:"</span>)</span>
<span id="cb3-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(p_root)</span>
<span id="cb3-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>()</span>
<span id="cb3-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Decimal:    </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_root<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>evalf(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Submission: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_root<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>evalf(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Exact root:
-(134/27 + 2*sqrt(57)/3)**(1/3)/3 + 8/(27*(134/27 + 2*sqrt(57)/3)**(1/3)) + 10/9

Decimal:    0.530603575430005
Submission: 0.53060357543</code></pre>
</div>
</div>
<p>Tidied up, the closed form is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap%5E%7B%5Cstar%7D%20=%20%5Cfrac%7B10%7D%7B9%7D%20-%20%5Cfrac%7B1%7D%7B3%7D%5Csqrt%5B3%5D%7B%5Ctfrac%7B134%7D%7B27%7D%20+%20%5Ctfrac%7B2%5Csqrt%7B57%7D%7D%7B3%7D%7D%20+%20%5Cfrac%7B8%7D%7B27%7D%5CBigl(%5Ctfrac%7B134%7D%7B27%7D%20+%20%5Ctfrac%7B2%5Csqrt%7B57%7D%7D%7B3%7D%5CBigr)%5E%7B-1/3%7D.%0A"></p>
<p>That comes out of <a href="https://en.wikipedia.org/wiki/Cubic_equation#Cardano's_formula">Cardano’s formula</a> applied to the depressed cubic; it’s not pretty, but it’s exact. To ten decimal places,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap%5E%7B%5Cstar%7D%20=%200.5306035754.%0A"></p>
</section>
<section id="a-picture-of-the-bifurcation" class="level2">
<h2 class="anchored" data-anchor-id="a-picture-of-the-bifurcation">A picture of the bifurcation</h2>
<p>The reason picking the right branch matters is best seen as a graph. Plot <img src="https://latex.codecogs.com/png.latex?a"> and <img src="https://latex.codecogs.com/png.latex?b"> as functions of <img src="https://latex.codecogs.com/png.latex?p">:</p>
<ul>
<li>For <img src="https://latex.codecogs.com/png.latex?p%20%5Cle%20%5Ctfrac%7B1%7D%7B2%7D">, the branching process dies. Both <img src="https://latex.codecogs.com/png.latex?a"> and <img src="https://latex.codecogs.com/png.latex?b"> are <img src="https://latex.codecogs.com/png.latex?0">.</li>
<li>For <img src="https://latex.codecogs.com/png.latex?p%20%3E%20%5Ctfrac%7B1%7D%7B2%7D">, the non-trivial fixed points kick in and rise smoothly toward <img src="https://latex.codecogs.com/png.latex?1"> as <img src="https://latex.codecogs.com/png.latex?p%20%5Cto%201">.</li>
</ul>
<p>The puzzle’s answer is the <img src="https://latex.codecogs.com/png.latex?p"> at which the red curve crosses <img src="https://latex.codecogs.com/png.latex?%5Ctfrac%7B1%7D%7B2%7D">.</p>
<div id="cell-fig-bifurcation" class="cell" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb5-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb5-3"></span>
<span id="cb5-4">ps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<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>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span>)</span>
<span id="cb5-5">b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(ps <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.5</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="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>np.where(ps <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;">0</span>, ps, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>)</span>
<span id="cb5-6">b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.clip(b, <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>)</span>
<span id="cb5-7"></span>
<span id="cb5-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a satisfies a = p a(2-a) + (1-p) b(2-b); solve the quadratic in a per p.</span></span>
<span id="cb5-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> a_of(p, b):</span>
<span id="cb5-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>:</span>
<span id="cb5-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span>
<span id="cb5-12">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># p a^2 - (2p - 1) a + (1-p) b (2-b) wait — rearrange:</span></span>
<span id="cb5-13">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a = p a (2 - a) + (1-p) b (2-b)</span></span>
<span id="cb5-14">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a - 2p a + p a^2 = (1-p) b (2 - b)</span></span>
<span id="cb5-15">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># p a^2 - (2p - 1) a - (1-p) b (2-b) = 0</span></span>
<span id="cb5-16">    A, B, C <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> p, <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>p <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> p) <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> (<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> b)</span>
<span id="cb5-17">    disc <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>B <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>A<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>C</span>
<span id="cb5-18">    r1 <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>B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> np.sqrt(disc)) <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>
<span id="cb5-19">    r2 <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>B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.sqrt(disc)) <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>
<span id="cb5-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Pick the root in (0, 1] — the one that grows continuously from 0 at p = 0.5.</span></span>
<span id="cb5-21">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> r1 <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</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;">&lt;=</span> r1 <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;">1</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> r2</span>
<span id="cb5-22"></span>
<span id="cb5-23">a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([a_of(pp, bb) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> pp, bb <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;">zip</span>(ps, b)])</span>
<span id="cb5-24">p_star <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.5306035754</span></span>
<span id="cb5-25"></span>
<span id="cb5-26">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb5-27">ax.plot(ps, a, color<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;">"#d62728"</span>, lw<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>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">Pr</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">A</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> — at most one 1"</span>)</span>
<span id="cb5-28">ax.plot(ps, b, color<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;">"#1f77b4"</span>, lw<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>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">Pr</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">(</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">B</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> — all zeros"</span>)</span>
<span id="cb5-29">ax.axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, color<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;">"black"</span>, lw<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.8</span>, ls<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>, alpha<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.6</span>)</span>
<span id="cb5-30">ax.axvline(p_star, color<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;">"black"</span>, lw<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.8</span>, ls<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>, alpha<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.6</span>)</span>
<span id="cb5-31">ax.plot([p_star], [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ko"</span>, ms<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>
<span id="cb5-32">ax.annotate(</span>
<span id="cb5-33">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"$p^</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">star </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">approx </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>p_star<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">$"</span>,</span>
<span id="cb5-34">    xy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(p_star, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>), xytext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(p_star <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.04</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.42</span>),</span>
<span id="cb5-35">    arrowprops<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;">dict</span>(arrowstyle<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;">"-&gt;"</span>, color<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;">"black"</span>, lw<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.8</span>),</span>
<span id="cb5-36">)</span>
<span id="cb5-37">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"$p$ (probability a node is labelled 0)"</span>)</span>
<span id="cb5-38">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"survival probability"</span>)</span>
<span id="cb5-39">ax.set_xlim(<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>)</span>
<span id="cb5-40">ax.set_ylim(<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>)</span>
<span id="cb5-41">ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>)</span>
<span id="cb5-42">ax.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, alpha<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.3</span>)</span>
<span id="cb5-43">ax.legend(loc<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;">"upper left"</span>)</span>
<span id="cb5-44">plt.savefig(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"thumbnail.png"</span>, dpi<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;">110</span>, bbox_inches<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;">"tight"</span>)</span>
<span id="cb5-45">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div id="fig-bifurcation" class="quarto-float quarto-figure quarto-figure-center anchored" data-fig-align="center">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-bifurcation-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://vsh852.com/posts/2025-05-03-sum-one-somewhere/index_files/figure-html/fig-bifurcation-output-1.png" class="quarto-figure quarto-figure-center figure-img" width="448" height="436">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-bifurcation-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Survival probabilities vs <img src="https://latex.codecogs.com/png.latex?p">. Below <img src="https://latex.codecogs.com/png.latex?p%20=%201/2"> both events have probability <img src="https://latex.codecogs.com/png.latex?0">; above it, the non-trivial branch is active. The puzzle asks for the <img src="https://latex.codecogs.com/png.latex?p"> where <img src="https://latex.codecogs.com/png.latex?%5CPr(A)%20=%201/2">.
</figcaption>
</figure>
</div>
</div>
</div>
</section>
<section id="what-made-it-nice" class="level2">
<h2 class="anchored" data-anchor-id="what-made-it-nice">What made it nice</h2>
<p>Two ideas carried the whole solution. First, fixing on the right <em>event</em> — “the subtree rooted here contains a good path” — turned an infinite-tree question into a recursion of one variable per event. Second, recognising the all-zero path as a Galton–Watson process picked the right branch of the quadratic without any hand-waving, and gave a clean threshold at <img src="https://latex.codecogs.com/png.latex?p%20=%20%5Ctfrac%7B1%7D%7B2%7D">.</p>
<p>The puzzle is a nice miniature for a more general technique: whenever you have a self-similar random structure, write down the probability of an event in terms of its restriction to the children, solve the resulting fixed-point equation, and use a separate principle (here, sub-/super-criticality) to pick the physically meaningful root. The same recipe handles “is there an infinite open path?” in <a href="https://en.wikipedia.org/wiki/Percolation_theory">percolation on a tree</a> — the puzzle’s <img src="https://latex.codecogs.com/png.latex?b"> is exactly the percolation probability with parameter <img src="https://latex.codecogs.com/png.latex?p">.</p>
<p>The official Jane Street <a href="https://www.janestreet.com/puzzles/sum-one-somewhere-solution/">solution</a> follows the same path and lands on the same cubic and the same root, <img src="https://latex.codecogs.com/png.latex?0.5306035754">.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>puzzle</category>
  <category>math</category>
  <category>python</category>
  <guid>https://vsh852.com/posts/2025-05-03-sum-one-somewhere/</guid>
  <pubDate>Sat, 03 May 2025 00:00:00 GMT</pubDate>
  <media:content url="https://vsh852.com/posts/2025-05-03-sum-one-somewhere/thumbnail.png" medium="image" type="image/png" height="141" width="144"/>
</item>
<item>
  <title>Beside the Point — a Jane Street puzzle in geometric probability</title>
  <dc:creator>Victor S HUANG</dc:creator>
  <link>https://vsh852.com/posts/2024-12-01-beside-the-point/</link>
  <description><![CDATA[ 





<p>A short writeup I owed myself. The November 2024 <a href="https://www.janestreet.com/puzzles/beside-the-point-index/">Jane Street puzzle</a> asked:</p>
<blockquote class="blockquote">
<p>Two random points, one red and one blue, are chosen uniformly and independently from the interior of a square. To ten decimal places, what is the probability that there exists a point on the side of the square closest to the blue point that is equidistant to both the blue point and the red point?</p>
</blockquote>
<p>I <a href="https://github.com/vicw0ng-hk/puzzles">solved it</a> and wrote it up. Here we go.</p>
<section id="reading-the-condition" class="level2">
<h2 class="anchored" data-anchor-id="reading-the-condition">Reading the condition</h2>
<p>Place the square as <img src="https://latex.codecogs.com/png.latex?S%20=%20%5B0,1%5D%5E2">. Call the blue point <img src="https://latex.codecogs.com/png.latex?B"> and the red point <img src="https://latex.codecogs.com/png.latex?R">. Let <img src="https://latex.codecogs.com/png.latex?%5Cell"> be the side of <img src="https://latex.codecogs.com/png.latex?S"> closest to <img src="https://latex.codecogs.com/png.latex?B">.</p>
<p>The puzzle asks for the probability that some <img src="https://latex.codecogs.com/png.latex?C%20%5Cin%20%5Cell"> satisfies <img src="https://latex.codecogs.com/png.latex?d(B,%20C)%20=%20d(R,%20C)">.</p>
<p>The set of points equidistant from <img src="https://latex.codecogs.com/png.latex?B"> and <img src="https://latex.codecogs.com/png.latex?R"> is the <a href="https://en.wikipedia.org/wiki/Bisection#Perpendicular_bisector_of_a_segment">perpendicular bisector</a> of segment <img src="https://latex.codecogs.com/png.latex?BR">. So the condition is:</p>
<blockquote class="blockquote">
<p>The perpendicular bisector of <img src="https://latex.codecogs.com/png.latex?BR"> crosses the closest side <img src="https://latex.codecogs.com/png.latex?%5Cell">.</p>
</blockquote>
<p>Equivalently: the two endpoints of <img src="https://latex.codecogs.com/png.latex?%5Cell"> lie on opposite sides of the bisector. Translating “side of the bisector” back to distance, that means <strong>one endpoint is closer to <img src="https://latex.codecogs.com/png.latex?B"> and the other is closer to <img src="https://latex.codecogs.com/png.latex?R"></strong>.</p>
<p>That is the form I’ll use.</p>
</section>
<section id="cutting-the-work-down-with-symmetry" class="level2">
<h2 class="anchored" data-anchor-id="cutting-the-work-down-with-symmetry">Cutting the work down with symmetry</h2>
<p>The square has 8-fold dihedral symmetry. By rotating and reflecting, I can assume <img src="https://latex.codecogs.com/png.latex?B"> lives in one specific octant — the lower triangle below the line <img src="https://latex.codecogs.com/png.latex?y%20=%20x"> with <img src="https://latex.codecogs.com/png.latex?x%20%3C%201/2">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AB%20=%20(x,%20y),%20%5Cqquad%200%20%3C%20y%20%3C%20x%20%3C%20%5Ctfrac%7B1%7D%7B2%7D.%0A"></p>
<p>In this octant the closest side is the bottom edge from <img src="https://latex.codecogs.com/png.latex?(0,0)"> to <img src="https://latex.codecogs.com/png.latex?(1,0)">. Its endpoints are the two corners <img src="https://latex.codecogs.com/png.latex?P_0%20=%20(0,0)"> and <img src="https://latex.codecogs.com/png.latex?P_1%20=%20(1,0)">.</p>
<p>By the law of total probability,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CPr(A)%20=%208%20%5Cint_0%5E%7B1/2%7D%5C!%5C!%5Cint_0%5E%7Bx%7D%20%5CPr(A%20%5Cmid%20B%20=%20(x,y))%5C,%20dy%5C,%20dx.%0A"></p>
<p>The factor 8 absorbs the symmetry.</p>
</section>
<section id="a-tale-of-two-circles" class="level2">
<h2 class="anchored" data-anchor-id="a-tale-of-two-circles">A tale of two circles</h2>
<p>For a fixed <img src="https://latex.codecogs.com/png.latex?B%20=%20(x,y)">, the event becomes:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?P_0"> is closer to <img src="https://latex.codecogs.com/png.latex?B"> than to <img src="https://latex.codecogs.com/png.latex?R">, <strong>and</strong> <img src="https://latex.codecogs.com/png.latex?P_1"> is closer to <img src="https://latex.codecogs.com/png.latex?R"> than to <img src="https://latex.codecogs.com/png.latex?B">, <strong>or</strong></li>
<li>the same with <img src="https://latex.codecogs.com/png.latex?P_0"> and <img src="https://latex.codecogs.com/png.latex?P_1"> swapped.</li>
</ul>
<p>“<img src="https://latex.codecogs.com/png.latex?P_i"> is closer to <img src="https://latex.codecogs.com/png.latex?B"> than to <img src="https://latex.codecogs.com/png.latex?R">” means <img src="https://latex.codecogs.com/png.latex?R"> is <strong>outside</strong> the circle centered at <img src="https://latex.codecogs.com/png.latex?P_i"> that passes through <img src="https://latex.codecogs.com/png.latex?B">. Call those circles <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BC%7D_0"> and <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BC%7D_1">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathcal%7BC%7D_0:%5C%20u%5E2%20+%20v%5E2%20=%20r_0%5E2,%5Cquad%20r_0%20=%20%5Csqrt%7Bx%5E2%20+%20y%5E2%7D,%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathcal%7BC%7D_1:%5C%20(u-1)%5E2%20+%20v%5E2%20=%20r_1%5E2,%5Cquad%20r_1%20=%20%5Csqrt%7B(1-x)%5E2%20+%20y%5E2%7D.%0A"></p>
<p>So the favourable region for <img src="https://latex.codecogs.com/png.latex?R"> is the <a href="https://en.wikipedia.org/wiki/Symmetric_difference">symmetric difference</a> of the two disks, intersected with <img src="https://latex.codecogs.com/png.latex?S">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CPr(A%20%5Cmid%20B)%20=%20%5Cfrac%7B%5Coperatorname%7BArea%7D%5Cbigl((D_0%20%5Ctriangle%20D_1)%20%5Ccap%20S%5Cbigr)%7D%7B1%7D%0A=%20%5Coperatorname%7BArea%7D(D_0%20%5Ccap%20S)%20+%20%5Coperatorname%7BArea%7D(D_1%20%5Ccap%20S)%20-%202%5C,%5Coperatorname%7BArea%7D(D_0%20%5Ccap%20D_1%20%5Ccap%20S),%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?D_i"> is the disk bounded by <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BC%7D_i">.</p>
<p>Let me draw it.</p>
<div id="cell-fig-setup" class="cell" data-execution_count="1">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> matplotlib.patches <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Circle, Rectangle</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> matplotlib.path <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Path</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> matplotlib.patches <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PathPatch</span>
<span id="cb1-6"></span>
<span id="cb1-7">x, y <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.35</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.18</span></span>
<span id="cb1-8">r0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.hypot(x, y)</span>
<span id="cb1-9">r1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.hypot(<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, y)</span>
<span id="cb1-10"></span>
<span id="cb1-11">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb1-12">ax.add_patch(Rectangle((<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>), <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>, fill<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;">False</span>, lw<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;">1.5</span>, ec<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;">"black"</span>))</span>
<span id="cb1-13"></span>
<span id="cb1-14">theta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<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;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>)</span>
<span id="cb1-15"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> disk_in_square(cx, cy, r):</span>
<span id="cb1-16">    u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.cos(theta)</span>
<span id="cb1-17">    v <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sin(theta)</span>
<span id="cb1-18">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.clip(u, <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>), np.clip(v, <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>)</span>
<span id="cb1-19"></span>
<span id="cb1-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Shade D0 \ D1 and D1 \ D0 by sampling the unit square</span></span>
<span id="cb1-21">gx, gy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.meshgrid(np.linspace(<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>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span>), np.linspace(<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>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span>))</span>
<span id="cb1-22">in0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gx<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> gy<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;">&lt;=</span> r0<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="cb1-23">in1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (gx <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> gy<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;">&lt;=</span> r1<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="cb1-24">sym_diff <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> in0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> in1</span>
<span id="cb1-25">ax.imshow(</span>
<span id="cb1-26">    sym_diff, extent<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="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>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), origin<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;">"lower"</span>,</span>
<span id="cb1-27">    cmap<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;">"Blues"</span>, alpha<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.35</span>, aspect<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;">"equal"</span>,</span>
<span id="cb1-28">)</span>
<span id="cb1-29"></span>
<span id="cb1-30">ax.add_patch(Circle((<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>), r0, fill<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;">False</span>, ec<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;">"#1f77b4"</span>, lw<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;">1.2</span>))</span>
<span id="cb1-31">ax.add_patch(Circle((<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>), r1, fill<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;">False</span>, ec<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;">"#1f77b4"</span>, lw<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;">1.2</span>))</span>
<span id="cb1-32">ax.plot([x], [y], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>, color<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;">"blue"</span>, ms<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="cb1-33">ax.annotate(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"B"</span>, (x, y), xytext<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;">8</span>), textcoords<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;">"offset points"</span>)</span>
<span id="cb1-34">ax.plot([<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>], [<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>], color<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;">"black"</span>, lw<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;">2.5</span>)</span>
<span id="cb1-35">ax.text(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <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.05</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"closest side $</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">ell$"</span>, ha<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;">"center"</span>, va<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;">"top"</span>)</span>
<span id="cb1-36"></span>
<span id="cb1-37">ax.set_xlim(<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.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-38">ax.set_ylim(<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.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-39">ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"equal"</span>)</span>
<span id="cb1-40">ax.set_xticks([<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>])<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> ax.set_yticks([<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>])</span>
<span id="cb1-41">plt.savefig(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"thumbnail.png"</span>, dpi<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;">110</span>, bbox_inches<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;">"tight"</span>)</span>
<span id="cb1-42">plt.show()</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div id="fig-setup" class="quarto-float quarto-figure quarto-figure-center anchored" data-fig-align="center">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-setup-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://vsh852.com/posts/2024-12-01-beside-the-point/index_files/figure-html/fig-setup-output-1.png" class="quarto-figure quarto-figure-center figure-img" width="461" height="485">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-setup-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Blue point <img src="https://latex.codecogs.com/png.latex?B"> in the lower octant. The favourable region for <img src="https://latex.codecogs.com/png.latex?R"> is the symmetric difference of the two disks (shaded blue).
</figcaption>
</figure>
</div>
</div>
</div>
</section>
<section id="quick-monte-carlo-gut-check" class="level2">
<h2 class="anchored" data-anchor-id="quick-monte-carlo-gut-check">Quick Monte Carlo gut-check</h2>
<p>Before grinding through an integral I always like to run the simulation. If the analytic answer disagrees with a million random trials, the analytic answer is wrong.</p>
<div id="monte-carlo" class="cell" data-execution_count="2">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">rng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.default_rng(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20241201</span>)</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;">1_000_000</span></span>
<span id="cb2-3"></span>
<span id="cb2-4">B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random((N, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb2-5">R <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rng.random((N, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb2-6"></span>
<span id="cb2-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Closest side of B: 0=bottom, 1=top, 2=left, 3=right.</span></span>
<span id="cb2-8">dists <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.stack([B[:, <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> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> B[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], B[:, <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> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> B[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]], axis<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="cb2-9">side <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmin(dists, axis<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="cb2-10"></span>
<span id="cb2-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Reflect/rotate so that the closest side is always the bottom.</span></span>
<span id="cb2-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Equivalent to working in the octant — but here I just transform B and R together.</span></span>
<span id="cb2-13">Bp, Rp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> B.copy(), R.copy()</span>
<span id="cb2-14">top <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> side <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="cb2-15">Bp[top, <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> Bp[top, <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> Rp[top, <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> Rp[top, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb2-16">left <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> side <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="cb2-17">Bp[left] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Bp[left, ::<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> Rp[left] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Rp[left, ::<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="cb2-18">right <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> side <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>
<span id="cb2-19">Bp[right] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Bp[right, ::<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> Rp[right] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Rp[right, ::<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="cb2-20">Bp[right, <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> Bp[right, <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> Rp[right, <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> Rp[right, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb2-21"></span>
<span id="cb2-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Two-circles condition: R inside one disk and outside the other.</span></span>
<span id="cb2-23">in0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Bp[:, <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="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> Bp[:, <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;">&gt;=</span> Rp[:, <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="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> Rp[:, <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>
<span id="cb2-24">in1 <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> Bp[:, <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="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> Bp[:, <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;">&gt;=</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> Rp[:, <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="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> Rp[:, <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>
<span id="cb2-25"></span>
<span id="cb2-26">estimate <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;">float</span>(np.mean(in0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> in1))</span>
<span id="cb2-27"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Monte Carlo (N = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>N<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:,}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>estimate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.6f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Monte Carlo (N = 1,000,000): 0.491470</code></pre>
</div>
</div>
<p>That gives <img src="https://latex.codecogs.com/png.latex?%5Capprox%200.4914">. Now the closed form.</p>
</section>
<section id="the-integrand-geometrically" class="level2">
<h2 class="anchored" data-anchor-id="the-integrand-geometrically">The integrand, geometrically</h2>
<p>Two convenient facts about the octant <img src="https://latex.codecogs.com/png.latex?0%20%3C%20y%20%3C%20x%20%3C%201/2">:</p>
<ol type="1">
<li><p>Both radii satisfy <img src="https://latex.codecogs.com/png.latex?r_i%20%5Cle%201"> throughout the octant. (Worst case for <img src="https://latex.codecogs.com/png.latex?r_1"> is <img src="https://latex.codecogs.com/png.latex?x%20%5Cto%200%5E+">, where <img src="https://latex.codecogs.com/png.latex?r_1%5E2%20%5Cto%201%20+%20y%5E2"> — but in the octant <img src="https://latex.codecogs.com/png.latex?y%20%3C%20x">, so <img src="https://latex.codecogs.com/png.latex?r_1%5E2%20%3C%201%20+%20x%5E2%20%5Cle%205/4">, and a quick check shows <img src="https://latex.codecogs.com/png.latex?r_1%20%3C%201"> whenever <img src="https://latex.codecogs.com/png.latex?y%20%3C%20x">.) That means each disk’s intersection with <img src="https://latex.codecogs.com/png.latex?S"> is a clean <strong>quarter disk</strong>: <img src="https://latex.codecogs.com/png.latex?%5Coperatorname%7BArea%7D(D_i%20%5Ccap%20S)%20=%20%5Ctfrac%7B%5Cpi%20r_i%5E2%7D%7B4%7D."></p></li>
<li><p>The two disks meet at <img src="https://latex.codecogs.com/png.latex?B%20=%20(x,%20y)"> and at its reflection <img src="https://latex.codecogs.com/png.latex?(x,%20-y)"> below the <img src="https://latex.codecogs.com/png.latex?x">-axis. Inside <img src="https://latex.codecogs.com/png.latex?S"> we only see the upper half of the lens. Its area splits cleanly into two <a href="https://en.wikipedia.org/wiki/Circular_segment">circular segments</a>, one carved off each disk by the vertical chord <img src="https://latex.codecogs.com/png.latex?u%20=%20x">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Coperatorname%7BArea%7D(D_0%20%5Ccap%20D_1%20%5Ccap%20S)%20=%20s_0%20+%20s_1,%0A"> where, using the <a href="https://en.wikipedia.org/wiki/Circular_sector#Area">sector area formula</a> <img src="https://latex.codecogs.com/png.latex?%5Ctfrac12%20r%5E2%20%5Ctheta"> minus a triangle, <img src="https://latex.codecogs.com/png.latex?%0As_0%20=%20%5Ctfrac%7B1%7D%7B2%7D%5Cbigl(r_0%5E2%20%5Carctan(y/x)%20-%20x%20y%5Cbigr),%20%5Cqquad%0As_1%20=%20%5Ctfrac%7B1%7D%7B2%7D%5Cbigl(r_1%5E2%20%5Carctan(y/(1-x))%20-%20(1-x)%20y%5Cbigr).%0A"></p></li>
</ol>
<p>Putting it together,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CPr(A%20%5Cmid%20x,%20y)%20=%20%5Cfrac%7B%5Cpi%20(r_0%5E2%20+%20r_1%5E2)%7D%7B4%7D%20-%202(s_0%20+%20s_1).%0A"></p>
</section>
<section id="closed-form-via-sympy" class="level2">
<h2 class="anchored" data-anchor-id="closed-form-via-sympy">Closed form via sympy</h2>
<p><code>sympy</code> handles the double integral exactly.</p>
<div id="cell-sympy-exact" class="cell" data-execution_count="3">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sympy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Rational, atan, integrate, pi, log, simplify, latex</span>
<span id="cb4-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sympy.abc <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> x, y</span>
<span id="cb4-3"></span>
<span id="cb4-4">us <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [x, <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>
<span id="cb4-5">radii_sq <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [u<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> 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;">2</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> u <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> us]</span>
<span id="cb4-6">angles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [atan(y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> u) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> u <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> us]</span>
<span id="cb4-7">slices <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [(rsq <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> u <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;">2</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> u, rsq, a <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;">zip</span>(us, radii_sq, angles)]</span>
<span id="cb4-8">quarter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> rsq <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="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> rsq <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> radii_sq]</span>
<span id="cb4-9"></span>
<span id="cb4-10">p_xy <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;">sum</span>(quarter) <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="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(slices)</span>
<span id="cb4-11">prob <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> simplify(<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> integrate(p_xy, (y, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, x), (x, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, Rational(<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;">2</span>))))</span>
<span id="cb4-12">prob</span></code></pre></div></div>
<div id="sympy-exact" class="cell-output cell-output-display cell-output-markdown" data-execution_count="3">
<p><img src="https://latex.codecogs.com/png.latex?%5Cdisplaystyle%20-%20%5Cfrac%7B%5Clog%7B%5Cleft(2%20%5Cright)%7D%7D%7B6%7D%20+%20%5Cfrac%7B1%7D%7B12%7D%20+%20%5Cfrac%7B%5Cpi%7D%7B6%7D"></p>
</div>
</div>
<div id="sympy-decimal" class="cell" data-execution_count="4">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Closed form: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Decimal:     </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>evalf(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Submission:  </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>prob<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>evalf(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Closed form: -log(2)/6 + 1/12 + pi/6
Decimal:     0.491407578838308
Submission:  0.49140757884</code></pre>
</div>
</div>
<p>Tidying the symbolic answer:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CPr(A)%20%5C;=%5C;%20%5Cfrac%7B1%20+%202%5Cpi%20-%20%5Cln%204%7D%7B12%7D%20%5C;=%5C;%20%5Cfrac%7B1%7D%7B12%7D%20+%20%5Cfrac%7B%5Cpi%7D%7B6%7D%20-%20%5Cfrac%7B%5Cln%202%7D%7B6%7D.%0A"></p>
<p>To ten decimal places, <strong>0.4914075788</strong>.</p>
<p>The Monte Carlo estimate above lands within 0.001 of this — consistent with the <img src="https://latex.codecogs.com/png.latex?O(1/%5Csqrt%7BN%7D)"> standard error of a million-sample Bernoulli.</p>
</section>
<section id="what-made-it-nice" class="level2">
<h2 class="anchored" data-anchor-id="what-made-it-nice">What made it nice</h2>
<p>Two moves did most of the work. First, restating “perpendicular bisector hits the side” as “one corner closer to <img src="https://latex.codecogs.com/png.latex?B">, the other closer to <img src="https://latex.codecogs.com/png.latex?R">” turned a metric question into a region-membership question. Second, the 8-fold symmetry collapsed the problem to a single octant, where the geometry is clean enough that every relevant area is either a quarter disk or a circular segment.</p>
<p>The official Jane Street <a href="https://www.janestreet.com/puzzles/beside-the-point-solution/">solution</a> follows the same path and arrives at the same closed form, <img src="https://latex.codecogs.com/png.latex?(1%20+%202%5Cpi%20-%20%5Cln%204)/12">.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>puzzle</category>
  <category>math</category>
  <category>python</category>
  <guid>https://vsh852.com/posts/2024-12-01-beside-the-point/</guid>
  <pubDate>Sun, 01 Dec 2024 00:00:00 GMT</pubDate>
  <media:content url="https://vsh852.com/posts/2024-12-01-beside-the-point/thumbnail.png" medium="image" type="image/png" height="151" width="144"/>
</item>
</channel>
</rss>
