<?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>All Your Bayes</title>
<link>https://allyourbayes.com/</link>
<atom:link href="https://allyourbayes.com/index.xml" rel="self" type="application/rss+xml"/>
<description>thoughts on risk and uncertainty in decision support</description>
<generator>quarto-1.7.30</generator>
<lastBuildDate>Sun, 01 Mar 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>diff all the things! Part 2</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/gradients_pt2/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>After reading <a href="https://allyourbayes.com/posts/gradients/">Part 1</a>, we know how great autodiff is, and how <code>Julia</code> lets us use it freely. We introduced the <code>Enzyme</code> library and showed some example applications.</p>
<p>Here in Part 2, we look at an emerging competing library, <code>Mooncake</code>, and why it’s worth keeping an eye on 👀</p>
<hr>
<section id="recap-enzyme-is-great" class="level4">
<h4 class="anchored" data-anchor-id="recap-enzyme-is-great">recap: <code>Enzyme</code> is great 🧪</h4>
<p>As we saw in <a href="https://allyourbayes.com/posts/gradients/">Part 1</a>, <code>Enzyme</code> solves the reliability problems that <code>Zygote</code> can (occasionally) exhibit. It differentiates our code at the LLVM level and is mega performant.</p>
<p>We also discussed in <a href="https://allyourbayes.com/posts/gradients/">Part 1</a>, how nice it is that <code>Julia</code> projects use only <code>Julia</code> code and the benefits of this for interoperability. This isn’t strictly true for <code>Enzyme</code>. Since it operates at the LLVM level, it can differentiate code in any language that compiles to the LLVM IR (including <code>C++</code>, and <code>Rust</code>!). We call a <code>Julia</code> API, but the differentiation is actually happening in the <code>Enzyme</code> software, outside of <code>Julia</code>.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-1-contents" aria-controls="callout-1" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
What is LLVM?
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-1" class="callout-1-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>We’ve mentioned it a few times as if it’s basic knowledge - wasn’t for me! <a href="https://en.wikipedia.org/wiki/LLVM">LLVM</a> is a compiler framework used by many languages (including <code>Julia</code>) as a shared backend for generating machine code.</p>
<p>When you write <code>Julia</code>, your code eventually gets lowered to the LLVM level (we even saw how you can display this, using <code>@code_llvm</code> in <a href="https://allyourbayes.com/posts/gradients/">Part 1</a>).</p>
<p><code>Enzyme</code> operates at this level. This means your high-level code has already been simplified and optimised a fair bit before any autodiff is attempted. This is a big reason why <code>Enzyme</code> is so performant.</p>
<p>The downside is that at the LLVM level, there is no concept of <code>Julia</code> types, dispatch, or packages. There are challenges (read on for details) associated with needing to cross this boundary.</p>
</div>
</div>
</div>
<p>So how good can autodiff be, if we learn lessons from <code>Zygote</code> and <code>Enzyme</code>, but stay entirely in <code>Julia</code>….</p>
</section>
<section id="enter-mooncake" class="level4">
<h4 class="anchored" data-anchor-id="enter-mooncake">enter <code>Mooncake</code> 🥮</h4>
<p>The pitch is as follows: an AD library, written entirely in <code>Julia</code> and competitive with <code>Enzyme</code>.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExZ290cWtoaGE3aTJqeTZtYzI4b2t0cHp6dXpscmxld3psOTEzcWR6ayZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/6AnUuBECREYeTr5n0t/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Oh, Mooncake</figcaption>
</figure>
</div>
<p>Like <code>Enzyme</code>, <code>Mooncake</code> handles mutation, control flow, and provides reliable correctness - stuff that <code>Zygote</code> can struggle with.</p>
<p>…but unlike <code>Enzyme</code>, it does all of this without leaving <code>Julia</code>. It is a <a href="https://github.com/chalk-lab/Mooncake.jl">self-described</a> <em>language-level autograd compiler</em>.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-2-contents" aria-controls="callout-2" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
How does <code>Mooncake</code> work?
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-2" class="callout-2-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p><code>Zygote</code> (and <code>ReverseDiff</code>) are <em>tracing</em> AD libraries. They execute the function and record all operations on a <em>tape</em>. The tape can then be replayed in reverse to compute the gradients neatly - especially for simple functions.</p>
<p>The tape is data, not code, so <code>Julia</code> can’t optimise it.</p>
<p>A tape records a path (as your code runs), but <code>Enzyme</code> and <code>Mooncake</code> can apply the chain rule to the code before it runs, and then produce new code that: (a) preserves mutation and control flow, and (b) returns gradients with very little overhead, and (c) can be optimised by the compiler. This is only possible because (as we saw in <a href="https://allyourbayes.com/posts/gradients/">Part 1</a>), <code>Julia</code>’s compiler produces an IR that retains the loops, branches, types, and all, of your code. <code>Python</code> doesn’t have this and so it has to trace.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
</colgroup>
<thead>
<tr class="header">
<th>autodiff library</th>
<th>reads</th>
<th>generates</th>
<th>consequence</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Zygote</strong></td>
<td><code>Julia</code> IR</td>
<td>tape (via fragile IR transforms)</td>
<td>slow on control flow, can silently mishandle edge cases</td>
</tr>
<tr class="even">
<td><strong>ReverseDiff</strong></td>
<td>runtime trace</td>
<td>tape</td>
<td>can’t be compiler-optimised</td>
</tr>
<tr class="odd">
<td><strong>Enzyme</strong></td>
<td>LLVM IR</td>
<td>new LLVM code</td>
<td>fast, but outside <code>Julia</code></td>
</tr>
<tr class="even">
<td><strong>Mooncake</strong></td>
<td><code>Julia</code> IR</td>
<td>new <code>Julia</code> functions</td>
<td>fast, and stays in <code>Julia</code></td>
</tr>
</tbody>
</table>
<p>All of the major <code>Python</code> AD libraries (<code>PyTorch</code>, <code>TensorFlow</code>, <code>JAX</code>) implement some kind of tape or tracing. AFAIK, the only one that doesn’t re-trace every operation is <code>JAX</code>, which uses a method that imposes a fixed control flow - hence the self-described “sharp bits” <span class="emoji" data-emoji="knife">🔪</span>.</p>
</div>
</div>
</div>
<p>Why does staying in <code>Julia</code> matter?</p>
<ul>
<li><strong>debugging</strong>: we get <code>Julia</code> errors - not messages from LLVM-land, which I certainly can’t follow.</li>
<li><strong>new custom rules</strong>: adding new derivatives just requires a <code>Julia</code> function. <code>Mooncake</code> provides helpful macros for this too!</li>
<li><strong>stability</strong>: we won’t get breaking changes on new <code>Julia</code> releases if something changes with the LLVM. I have read that <code>Enzyme</code> has previously had to make fixes for this.</li>
</ul>
<p>If you still aren’t sure whether to take notice, then listen to the man himself, <a href="https://www.stochasticlifestyle.com">Chris Rackauckas</a>, “<em>Mooncake is Zygote, but done good, with mutation support</em>” (see clip below)</p>
<div class="quarto-video ratio ratio-16x9"><iframe data-external="1" src="https://www.youtube.com/embed/dD07UC3cW94" title="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div>
</section>
<section id="lets-be-honest-about-current-trade-offs" class="level4">
<h4 class="anchored" data-anchor-id="lets-be-honest-about-current-trade-offs">lets be honest about current trade-offs</h4>
<p>It’s tricky trying to find definitive benchmarks for the <code>Julia</code> AD ecosystem. The discourse pages will provide one-off examples of older libraries occasionally outperforming newer ones in terms of speed and reliability. However, the general consensus seems to be that <code>Enzyme</code> is currently the most performant, with <code>Mooncake</code> not far behind.</p>
<p>Let’s do our own….</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># loading our autodiff libraries</span></span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">using</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">ReverseDiff</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Zygote</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Enzyme</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Mooncake</span></span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># and to test</span></span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">using</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">BenchmarkTools</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Random</span></span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a simple function</span></span>
<span id="cb1-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">test_function</span>(x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sin</span>.(x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cos</span>.(x<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</span>))</span>
<span id="cb1-9"></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># and an example with some control flow (the *if*'s can be a problem for some AD libraries)</span></span>
<span id="cb1-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">control_flow_function</span>(x)</span>
<span id="cb1-12">    s <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>
<span id="cb1-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">eachindex</span>(x)</span>
<span id="cb1-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> x[i] <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.0</span></span>
<span id="cb1-15">            s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sin</span>(x[i])</span>
<span id="cb1-16">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span></span>
<span id="cb1-17">            s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cos</span>(x[i])</span>
<span id="cb1-18">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-19">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-20">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> s</span>
<span id="cb1-21"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-22"></span>
<span id="cb1-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># simulate some reproducible inputs</span></span>
<span id="cb1-24">x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rand</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">MersenneTwister</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2311</span>), <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>)</span></code></pre></div>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-3-contents" aria-controls="callout-3" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Why do we care about control flow?
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-3" class="callout-3-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>Loops, if/else branches, and recursion are how we naturally write scientific code. In this example, the control flow example has a for loop (with <img src="https://latex.codecogs.com/png.latex?1000"> iterations) and a branching if/else statement. A tape-based AD (see callout above, “<em>How does <code>Mooncake</code> work</em>”) needs to trace every iteration and record whichever branch was taken, each with its own allocation!</p>
<p>The tape-free approach taken by <code>Enzyme</code> and <code>Mooncake</code> avoids this overhead entirely, producing derivative code where the loop is still a loop. They are especially powerful when differentiating through code with lots of control flow.</p>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb2-1"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@btime</span> ReverseDiff.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gradient</span>(test_function, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x)[begin]</span>
<span id="cb2-2"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@btime</span> ReverseDiff.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gradient</span>(control_flow_function, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x)[begin]</span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@btime</span> Zygote.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gradient</span>(test_function, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x)</span>
<span id="cb2-5"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@btime</span> Zygote.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gradient</span>(control_flow_function, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x)</span>
<span id="cb2-6"></span>
<span id="cb2-7"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@btime</span> Enzyme.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gradient</span>(Reverse, test_function, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x)</span>
<span id="cb2-8"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@btime</span> Enzyme.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gradient</span>(Reverse, control_flow_function, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x)</span></code></pre></div>
</div>
<p>Unlike <code>Enzyme</code>, which has both <code>gradient()</code> (convenience) and <code>autodiff()</code> (more explicit specification), <code>Mooncake</code>’s <code>value_and_gradient!!</code> is the main API. There isn’t a separate “advanced” form.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-4-contents" aria-controls="callout-4" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<code>!!</code> mutate, or obliterate?
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-4" class="callout-4-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>In <code>Julia</code>, the familiar single <code>!</code> denotes a function that may mutate its arguments (but leaving them in a valid state), like how <code>sort!(x)</code> redefines <code>x</code> as a sorted array.</p>
<p>The double <code>!!</code> is new to me, and is apparently a convention from the AD ecosystem, and not base <code>Julia</code>. It signifies that arguments may be mutated, with no guarantees about how meaningful/useful they are afterwards. Presumably in the below example, it is the aggressive recycling of memory that is being signposted i.e.&nbsp;previous contents of the cache are being overwritten and shouldn’t be referenced? But maybe there is more to it.</p>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Mooncake needs a prepared cache</span></span>
<span id="cb3-2">cache <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Mooncake.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prepare_gradient_cache</span>(test_function, x);</span>
<span id="cb3-3"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@btime</span> Mooncake.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">value_and_gradient!!</span>(cache, test_function, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x)</span>
<span id="cb3-4"></span>
<span id="cb3-5">cache <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Mooncake.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prepare_gradient_cache</span>(control_flow_function, x);</span>
<span id="cb3-6"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@btime</span> Mooncake.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">value_and_gradient!!</span>(cache, control_flow_function, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x)</span></code></pre></div>
</div>
<p>The results… 🥇 🥈 🥉</p>
</section>
<section id="test_function" class="level4">
<h4 class="anchored" data-anchor-id="test_function"><code>test_function()</code></h4>
<table class="caption-top table">
<thead>
<tr class="header">
<th>library</th>
<th style="text-align: right;">time (μs)</th>
<th style="text-align: right;">allocations</th>
<th style="text-align: right;">memory</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Enzyme</strong></td>
<td style="text-align: right;">15.4</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">24.16 KiB</td>
</tr>
<tr class="even">
<td><strong>Zygote</strong></td>
<td style="text-align: right;">16.5</td>
<td style="text-align: right;">49</td>
<td style="text-align: right;">97.14 KiB</td>
</tr>
<tr class="odd">
<td><strong>ReverseDiff</strong></td>
<td style="text-align: right;">23.7</td>
<td style="text-align: right;">105</td>
<td style="text-align: right;">67.78 KiB</td>
</tr>
<tr class="even">
<td><strong>Mooncake</strong></td>
<td style="text-align: right;">24.8</td>
<td style="text-align: right;">11</td>
<td style="text-align: right;">16.48 KiB</td>
</tr>
</tbody>
</table>
</section>
<section id="control_flow_function" class="level4">
<h4 class="anchored" data-anchor-id="control_flow_function"><code>control_flow_function()</code></h4>
<table class="caption-top table">
<thead>
<tr class="header">
<th>library</th>
<th style="text-align: right;">time</th>
<th style="text-align: right;">allocations</th>
<th style="text-align: right;">memory</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Enzyme</strong></td>
<td style="text-align: right;">3.2 μs</td>
<td style="text-align: right;">3</td>
<td style="text-align: right;">8.06 KiB</td>
</tr>
<tr class="even">
<td><strong>Mooncake</strong></td>
<td style="text-align: right;">14.5 μs</td>
<td style="text-align: right;">3</td>
<td style="text-align: right;">352 B</td>
</tr>
<tr class="odd">
<td><strong>ReverseDiff</strong></td>
<td style="text-align: right;">257.0 μs</td>
<td style="text-align: right;">8,023</td>
<td style="text-align: right;">375.70 KiB</td>
</tr>
<tr class="even">
<td><strong>Zygote</strong></td>
<td style="text-align: right;">3,481 μs</td>
<td style="text-align: right;">42,118</td>
<td style="text-align: right;">9.51 MiB</td>
</tr>
</tbody>
</table>
<p>As expected, <code>Enzyme</code> is fast. It sees this already-optimised LLVM code and differentiates that.</p>
<p>Although <code>Mooncake</code> was the slowest on the simple test function, it was only <img src="https://latex.codecogs.com/png.latex?1.6"> times slower than <code>Enzyme</code> - same order of magnitude, still competitive. The newer libraries really shone on the control flow function, hundreds (<code>Mooncake</code>) to thousands (<code>Enzyme</code>) times faster than <code>Zygote</code>.</p>
<p>And look at the memory! <span class="emoji" data-emoji="eyes">👀</span></p>
<p><code>Mooncake</code> allocates so little! After the initial cache preparation, the gradients calculated in training or inference loops will be almost zero-allocation, which is fantastic for performance or memory bottlenecks.</p>
</section>
<section id="reviewing-the-bayesian-model-from-part-1" class="level4">
<h4 class="anchored" data-anchor-id="reviewing-the-bayesian-model-from-part-1">reviewing the Bayesian model from <a href="https://allyourbayes.com/posts/gradients/">Part 1</a></h4>
<p>Using the same simulated data and priors, let’s run the linear regression using <code>Turing</code> (look how much neater it is) and swap AD backends with a single argument.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">using</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Turing</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Distributions</span></span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@model</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">linear_regression</span>(x, y)</span>
<span id="cb4-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># priors</span></span>
<span id="cb4-5">    α <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> α_prior; β <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> β_prior; σ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> σ_prior</span>
<span id="cb4-6">    </span>
<span id="cb4-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># there are ofc lots of ways to vector/optim-ise the likelihood, but...</span></span>
<span id="cb4-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">eachindex</span>(y)</span>
<span id="cb4-9">        y[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Normal</span>(α <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> β <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x[i], σ)</span>
<span id="cb4-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb4-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb4-12"></span>
<span id="cb4-13">linear_model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">linear_regression</span>(x, y); n_draws <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_000</span></span></code></pre></div>
</div>
<p>just running a single chain for <img src="https://latex.codecogs.com/png.latex?1,000"> post-warmup samples for the purposes of this example:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb5-1">mooncake_draws <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(linear_model, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">NUTS</span>(; adtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">AutoMooncake</span>(; config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">nothing</span>)), n_draws)</span>
<span id="cb5-2"></span>
<span id="cb5-3">enzyme_draws <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(linear_model, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">NUTS</span>(; adtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">AutoEnzyme</span>(; mode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>Enzyme.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_runtime_activity</span>(Enzyme.Reverse))), n_draws)</span></code></pre></div>
</div>
<p>not ideal syntax, but within each sample you can specify an AD backend. Actually in the above example, I wouldn’t expect any benefit from using <code>Mooncake</code> or <code>Enzyme</code> - it’s a tiny model (<img src="https://latex.codecogs.com/png.latex?3"> parameters, <img src="https://latex.codecogs.com/png.latex?20"> data points) and, as discussed in <a href="https://allyourbayes.com/posts/gradients/">Part 1</a>, a Forward Mode AD library like <code>ForwardDiff</code> would likely be the best bet. As I mentioned in <a href="https://allyourbayes.com/posts/gradients/">Part 1</a>, there have been cases where I benefitted enormously from simply switching the AD backend to <code>AutoMooncake()</code>.</p>
</section>
<section id="my-current-thoughts" class="level4">
<h4 class="anchored" data-anchor-id="my-current-thoughts">my current thoughts</h4>
<p>Please keep in mind, I don’t feel best placed to comment on direction of travel. I am a user (and fan) of the <code>Julia</code> scientific computing ecosystem, but I am not an open source developer.</p>
<p><code>Mooncake</code> is still being developed by that community, with the stated goal to: <em>“improve on ForwardDiff.jl, ReverseDiff.jl, and Zygote.jl in several ways.”</em> It encourages us to use it, in a seemingly arduous way. Either by adding an extra step (<code>prepare_gradient()</code>), or by using <code>DifferentiationInterface</code> - a common interface for multiple <code>Julia</code> AD libraries.</p>
<p>As with most statistical software, I expect the future success of these libraries will be tied to how well they integrate with the rest of the ecosystem. If <code>Mooncake</code> can be subbed in for <code>Enzyme</code> in libraries like <code>Turing</code> and <code>Flux</code>, then it will be easy to switch and benefit from its features.</p>
<p>Or will the <code>Julia</code> AD ecosystem fail to converge and I’ll end up writing a Part 3 in this series? 🤔</p>


</section>
</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2026,
  author = {Di Francesco, Domenic},
  title = {Diff All the Things! {Part} 2},
  date = {2026-03-01},
  url = {https://allyourbayes.com/posts/gradients_pt2/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2026" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2026. <span>“Diff All the Things! Part 2.”</span>
March 1, 2026. <a href="https://allyourbayes.com/posts/gradients_pt2/">https://allyourbayes.com/posts/gradients_pt2/</a>.
</div></div></section></div> ]]></description>
  <category>automatic differentiation</category>
  <category>deep learning</category>
  <category>Bayes</category>
  <category>Julia</category>
  <category>Enzyme</category>
  <category>Mooncake</category>
  <guid>https://allyourbayes.com/posts/gradients_pt2/</guid>
  <pubDate>Sun, 01 Mar 2026 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/gradients_pt2/mooncake.png" medium="image" type="image/png" height="124" width="144"/>
</item>
<item>
  <title>advent of code 2025</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/AoC/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>Advent of code is a website created by Eric Wastl, releasing a (increasingly challenging) programming puzzle each day. This year we will not be receiving the usual 25 days worth (I have never made it that far anyway), but it will instead be finishing on 12th December <a href="https://www.reddit.com/r/adventofcode/comments/1ocwh04/changes_to_advent_of_code_starting_this_december/">(see announcement on Reddit)</a>. This is a welcome change of pace for me.</p>
<p>Spoiler alert: super un-optimised, but hopefully readable Julia solutions ahead, so you may only want to look after you have had a go yourself. Let’s see how we go…</p>
<p>Play along: <a href="https://adventofcode.com">https://adventofcode.com</a></p>
<hr>
<section id="day-1-a-password-from-a-decoy-safe" class="level4">
<h4 class="anchored" data-anchor-id="day-1-a-password-from-a-decoy-safe">Day 1: a password from a decoy safe 🔓</h4>
<p>So we have this safe, with a dial set to <code>50</code>, and a sequence of turns to make, see below:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1">seq <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;">"L68"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"L30"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R48"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"L5"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R60"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"L55"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"L1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"L99"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R14"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"L82"</span>]</span></code></pre></div>
</div>
<p>Here an “R” means we are turning the dial to the right, and an “L” means we are turning it to the left, followed by the number indicating how many turns. “L68” means turn the dial left 68 times. The dial wraps around, so if we turn left from 0, we go to 99, 98, and so on.</p>
<p>We are asked:</p>
<ul>
<li>part 1: how many times do we end up on zero after a turn?</li>
<li>part 2: how many times do we turn through zero in total?</li>
</ul>
<p>Floor division <code>fld()</code> will count how many times we lap around zero (and in which direction).</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_passwords</span>(seq<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector{String}</span>, dial_start<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int </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;">50</span>, dial_mod<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int </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;">100</span>)</span>
<span id="cb2-2"></span>
<span id="cb2-3">    dial <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dial_start; pass_zeros <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</span>; end_zeros <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</span></span>
<span id="cb2-4"></span>
<span id="cb2-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> turn <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> seq</span>
<span id="cb2-6">        direction <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> turn[begin]; turns <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, turn[<span class="fl" 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="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>])</span>
<span id="cb2-7">        </span>
<span id="cb2-8">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> direction <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'R'</span></span>
<span id="cb2-9"></span>
<span id="cb2-10">            pass_zeros <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fld</span>(dial <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> turns, dial_mod)</span>
<span id="cb2-11">            dial <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> turns</span>
<span id="cb2-12"></span>
<span id="cb2-13">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">elseif</span> direction <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'L'</span></span>
<span id="cb2-14"></span>
<span id="cb2-15">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># we need to catch the case where the dial starts at 0 and not count that first turn</span></span>
<span id="cb2-16">            pass_zeros <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fld</span>(dial <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> turns <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</span>, dial_mod) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fld</span>(dial <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</span>, dial_mod)</span>
<span id="cb2-17">            dial <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-=</span> turns</span>
<span id="cb2-18">            </span>
<span id="cb2-19">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-20"></span>
<span id="cb2-21">        dial <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mod</span>(dial, dial_mod)</span>
<span id="cb2-22"></span>
<span id="cb2-23">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> dial <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</span></span>
<span id="cb2-24">            end_zeros <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</span></span>
<span id="cb2-25">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-26">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-27"></span>
<span id="cb2-28">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (end_zeros<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>end_zeros, pass_zeros<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>pass_zeros)</span>
<span id="cb2-29"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>get_passwords (generic function with 3 methods)</code></pre>
</div>
</div>
<p>A nice opener, and I did make a mistake in my first guess for part 2, forgetting the case where the dial starts on zero and we turn left. We shouldn’t count that first turn as going through zero, and so I had to add the start and end points, with that -1 offset.</p>
<p>It appears I wasn’t the only one…</p>
<blockquote class="reddit-embed-bq blockquote" style="height:500px" data-embed-height="546">
<a href="https://www.reddit.com/r/adventofcode/comments/1pc0yfg/2025_day_1_part_2_public_service_announcement/">[2025 Day 1 Part 2] Public Service Announcement</a><br> by<a href="https://www.reddit.com/user/StaticMoose/">u/StaticMoose</a> in<a href="https://www.reddit.com/r/adventofcode/">adventofcode</a>
</blockquote>
<script async="" src="https://embed.reddit.com/widgets.js" charset="UTF-8"></script>
<div class="cell">
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb4-1">seq <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> get_passwords</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>(end_zeros = 3, pass_zeros = 6)</code></pre>
</div>
</div>
<p>⭐⭐</p>
</section>
<section id="day-2-fake-ids-at-the-gift-shop" class="level4">
<h4 class="anchored" data-anchor-id="day-2-fake-ids-at-the-gift-shop">Day 2: fake IDs at the gift shop 🎁</h4>
<p>We’re given these ‘product IDs’ from the gift shop, and we need to sort through them to find which ones are invalid. Problematic IDs that we are looking for are made up <em>exclusively</em> of repeating sequences of numbers.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb6-1">product_ids <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;">"11-22"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"95-115"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"998-1012"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1188511880-1188511890"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"222220-222224"</span>,</span>
<span id="cb6-2">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1698522-1698528"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"446443-446449"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"38593856-38593862"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"565653-565659"</span>,</span>
<span id="cb6-3">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"824824821-824824827"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2121212118-2121212124"</span>]</span></code></pre></div>
</div>
<p>In part 1, we were looking for a single repeated sequence, so the first half of the ID is the same as the second half. Then in part 2, the length of that sequence could change. Here’s my solution:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb7-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is_invalid</span>(id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>; part_1<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Bool </span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">false</span>)</span>
<span id="cb7-2">    </span>
<span id="cb7-3">    id_string <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">string</span>(id); midpoint <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(id_string) <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</span></span>
<span id="cb7-4"></span>
<span id="cb7-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> part_1</span>
<span id="cb7-6">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> id_string[begin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>midpoint] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> id_string[midpoint<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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>]</span>
<span id="cb7-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb7-8"></span>
<span id="cb7-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> pattern_length <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>midpoint </span>
<span id="cb7-10">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a pattern more than half the length can't repeat</span></span>
<span id="cb7-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> id_string <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> id_string[begin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>pattern_length] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(id_string) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">÷</span> pattern_length)</span>
<span id="cb7-12">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># is the id made *only* of this repeated pattern?</span></span>
<span id="cb7-13">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">true</span></span>
<span id="cb7-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb7-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb7-16"></span>
<span id="cb7-17">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">false</span></span>
<span id="cb7-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>is_invalid (generic function with 1 method)</code></pre>
</div>
</div>
<p>The puzzle itself felt simpler than yesterday, but only after I read the description a few times. I initially thought that we were going to be asking to find IDs that contained <em>some</em> (any) repeated sequence, but knowing that the entire ID had to be a repetition simplified things.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb9-1">invalid_ids <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>[]</span>
<span id="cb9-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> id <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> product_ids</span>
<span id="cb9-3"></span>
<span id="cb9-4">    parts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">split</span>(id, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-"</span>)</span>
<span id="cb9-5">    id_start <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, parts[begin]); id_end <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, parts[<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>])</span>
<span id="cb9-6"></span>
<span id="cb9-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> id <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> id_start<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>id_end</span>
<span id="cb9-8">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is_invalid</span>(id)</span>
<span id="cb9-9">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push!</span>(invalid_ids, id)</span>
<span id="cb9-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb9-11">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb9-12"></span>
<span id="cb9-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> </span>
<span id="cb9-14"></span>
<span id="cb9-15">invalid_ids <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> sum</span></code></pre></div>
</div>
<div class="cell">
<div class="cell-output cell-output-stdout">
<pre><code>4174379265</code></pre>
</div>
</div>
<p><code>BenchmarkTools.jl</code> tells me this runs in <code>459.768 ms</code>, with lots of allocations <code>606.35 MiB</code>, presumably due to all of the string splitting, concatenation, and going back and forth to integers. I don’t think I’ll have time to think about smarter ways to do this, but I’m sure I’ll be forced to in the coming days. Happy to be brute-forcing for now.</p>
<p>My young children happened to wake me up super early today, so I will have scored highly on the leaderboard, but I’m in it for the puzzles, not the glory.</p>
<p>⭐⭐</p>
</section>
<section id="day-3-maximum-joltage" class="level4">
<h4 class="anchored" data-anchor-id="day-3-maximum-joltage">Day 3: maximum joltage ⚡</h4>
<p>We find batteries, each with their own joltage rating, arranged in banks (rows).</p>
<p>Going from left to right, which batteries should we connect up to get the maximum joltage possible from each row?</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb11-1">joltages <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb11-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"987654321111111"</span></span>
<span id="cb11-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"811111111111119"</span></span>
<span id="cb11-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"234234234234278"</span></span>
<span id="cb11-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"818181911112111"</span></span>
<span id="cb11-6">    ]</span></code></pre></div>
</div>
<p>For instance, if we were asked to connect 4 batteries in the third row, we can’t make a 4 digit number higher than <code>4478</code> (selecting batteries <code>3</code> (joltage = <code>4</code>), <code>6</code> (joltage = <code>4</code>), <code>14</code> (joltage = <code>7</code>), and <code>15</code> (joltage = <code>8</code>)).</p>
<p>In part 1 we were asked to select <code>2</code> batteries from each bank, and in part 2 we were to select <code>12</code>. Here’s a solution:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb12-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">max_joltage_for_bank</span>(bank<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">String</span>; n_batteries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int </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;">2</span>)</span>
<span id="cb12-2"></span>
<span id="cb12-3">    digits <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>.(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect</span>(bank)) </span>
<span id="cb12-4"></span>
<span id="cb12-5">    max_joltage <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []; index <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</span></span>
<span id="cb12-6"></span>
<span id="cb12-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_batteries</span>
<span id="cb12-8"></span>
<span id="cb12-9">        digits_needed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n_batteries <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> k</span>
<span id="cb12-10">        search_end <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(digits) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> digits_needed</span>
<span id="cb12-11"></span>
<span id="cb12-12">        max_val <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;">1</span>; max_idx <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;">1</span></span>
<span id="cb12-13">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>search_end</span>
<span id="cb12-14">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> digits[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> max_val</span>
<span id="cb12-15">                <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># keep track of the biggest digit in this range and it's index...</span></span>
<span id="cb12-16">                max_val <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> digits[i]; max_idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i</span>
<span id="cb12-17">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb12-18">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb12-19"></span>
<span id="cb12-20">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...so we can update the new starting point</span></span>
<span id="cb12-21">        index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> max_idx <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</span></span>
<span id="cb12-22">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push!</span>(max_joltage, max_val)</span>
<span id="cb12-23">    </span>
<span id="cb12-24">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb12-25"></span>
<span id="cb12-26">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> max_joltage <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> join <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, x)</span>
<span id="cb12-27"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>max_joltage_for_bank (generic function with 1 method)</code></pre>
</div>
</div>
<p>This is based on selecting the maximum digit we can, whilst still leaving space for however many remaining batteries we need to select.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb14-1">joltages <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">max_joltage_for_bank</span>.(x, n_batteries <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;">12</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> sum</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>3121910778619</code></pre>
</div>
</div>
<p>Don’t forget to then update your starting index accordingly, rather than just adding 1, otherwise you’ll keep selecting the same battery over and over - although seeing this helpded me fix it.</p>
<p>Check out some smarter solutions than mine:</p>
<blockquote class="reddit-embed-bq blockquote" style="height:316px" data-embed-height="316">
<a href="https://www.reddit.com/r/adventofcode/comments/1pcvaj4/2025_day_3_solutions/">-❄️- 2025 Day 3 Solutions -❄️-</a><br> by<a href="https://www.reddit.com/user/daggerdragon/">u/daggerdragon</a> in<a href="https://www.reddit.com/r/adventofcode/">adventofcode</a>
</blockquote>
<script async="" src="https://embed.reddit.com/widgets.js" charset="UTF-8"></script>
<p>⭐⭐</p>
</section>
<section id="day-4-dunder-mifflin-warehouse" class="level4">
<h4 class="anchored" data-anchor-id="day-4-dunder-mifflin-warehouse">Day 4: Dunder Mifflin warehouse 📄</h4>
<p>There are only so many types of AoC puzzles, and today I recognised bts of code I write every year. Namely, checking where I can safely move in in a grid while staying within bounds.</p>
<p>We’re given the layout of warehouse floor - specifically, where a reams of paper are located <code>@</code>, and where there is an empty space <code>.</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb16-1">grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb16-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..@@.@@@@."</span></span>
<span id="cb16-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"@@@.@.@.@@"</span></span>
<span id="cb16-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"@@@@@.@.@@"</span></span>
<span id="cb16-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"@.@@@@..@."</span></span>
<span id="cb16-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"@@.@@@@.@@"</span></span>
<span id="cb16-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".@@@@@@@.@"</span></span>
<span id="cb16-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".@.@.@.@@@"</span></span>
<span id="cb16-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"@.@@@.@@@@"</span></span>
<span id="cb16-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".@@@@@@@@."</span></span>
<span id="cb16-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"@.@.@@@.@."</span></span>
<span id="cb16-12">    ]</span></code></pre></div>
</div>
<p>We are asked:</p>
<ul>
<li>part 1: If we can only move reams with less than 4 neighbouring reams - how many can we move?</li>
<li>part 2: Once we’ve removed them, we might be able to move more. How many are left that can never be moved?</li>
</ul>
<p>Here’s a solution:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb17-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_accessible</span>(warehouse<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Matrix{Char}</span>; n_aux<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int </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;">4</span>)</span>
<span id="cb17-2"></span>
<span id="cb17-3">    n_rows, n_cols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">size</span>(warehouse); labelled_warehouse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">copy</span>(warehouse)</span>
<span id="cb17-4">    </span>
<span id="cb17-5">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># all 8 directions: (row_offset, col_offset)</span></span>
<span id="cb17-6">    directions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb17-7">        (<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</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</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</span>, <span class="fl" 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</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb17-8">        ( <span class="fl" 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</span>),          ( <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb17-9">        ( <span class="fl" 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;">1</span>), ( <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), ( <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb17-10">    ]</span>
<span id="cb17-11">    </span>
<span id="cb17-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> row <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_rows</span>
<span id="cb17-13">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> col <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_cols</span>
<span id="cb17-14">            </span>
<span id="cb17-15">            warehouse[row, col] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'@'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># we're only checking the papers</span></span>
<span id="cb17-16">            </span>
<span id="cb17-17">            neighbouring_papers <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</span></span>
<span id="cb17-18">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (Δr, Δc) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> directions</span>
<span id="cb17-19">                check_row, check_col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> row <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> Δr, col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> Δc</span>
<span id="cb17-20">                </span>
<span id="cb17-21">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">≤</span> check_row <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">≤</span> n_rows <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">≤</span> check_col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">≤</span> n_cols <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># stay in the grid!</span></span>
<span id="cb17-22">                    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> warehouse[check_row, check_col] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'@'</span></span>
<span id="cb17-23">                        neighbouring_papers <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</span></span>
<span id="cb17-24">                    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb17-25">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb17-26">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb17-27">            </span>
<span id="cb17-28">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> neighbouring_papers <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> n_aux</span>
<span id="cb17-29">                labelled_warehouse[row, col] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span></span>
<span id="cb17-30">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb17-31">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb17-32">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb17-33">    </span>
<span id="cb17-34">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> labelled_warehouse</span>
<span id="cb17-35"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>find_accessible (generic function with 1 method)</code></pre>
</div>
<div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb19-1"></span>
<span id="cb19-2">grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb19-3">    lines <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span>  [lines[r][c] for r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">eachindex</span>(lines), c <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(lines[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb19-4">    warehouse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span>(<span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_accessible</span>(warehouse))</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>13</code></pre>
</div>
</div>
<p>Not super elegeant. I replace the reams that can be moved with an <code>x</code> and then count them. It was important to make this change to a copy of the warehouse grid, otherwise we would be changing the grid as we go, and thinking there are less neighbouring reams than there actually are.</p>
<p>…and for part 2, we can just keep calling this function until there are no more reams that can be moved:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb21-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">remove_all_reams</span>(grid<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Matrix{Char}</span>)</span>
<span id="cb21-2">    labelled_warehouse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">copy</span>(grid)</span>
<span id="cb21-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">true</span></span>
<span id="cb21-4">        new_labelled_warehouse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_accessible</span>(labelled_warehouse)</span>
<span id="cb21-5">        new_labelled_warehouse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> labelled_warehouse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span>
<span id="cb21-6">        labelled_warehouse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> new_labelled_warehouse</span>
<span id="cb21-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb21-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span>(<span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>), labelled_warehouse)</span>
<span id="cb21-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
</div>
<p>loevely visualisation on the reddit of clearing out the warehouse:</p>
<blockquote class="reddit-embed-bq blockquote" style="height:500px" data-embed-height="740">
<a href="https://www.reddit.com/r/adventofcode/comments/1pdrfl0/2025_day_4_part_2/">[2025 Day 4 Part 2]</a><br> by<a href="https://www.reddit.com/user/EverybodyCodes/">u/EverybodyCodes</a> in<a href="https://www.reddit.com/r/adventofcode/">adventofcode</a>
</blockquote>
<script async="" src="https://embed.reddit.com/widgets.js" charset="UTF-8"></script>
<p>⭐⭐</p>
</section>
<section id="day-5-fresh-ingredients" class="level4">
<h4 class="anchored" data-anchor-id="day-5-fresh-ingredients">Day 5: fresh ingredients 🥗</h4>
<p>Part 2 got me today.</p>
<p>Our inputs are a list of ranges, followed by ingredient id’s.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb22-1">ingredients_db <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb22-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"3-5"</span></span>
<span id="cb22-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"10-14"</span></span>
<span id="cb22-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"16-20"</span></span>
<span id="cb22-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"12-18"</span></span>
<span id="cb22-6"></span>
<span id="cb22-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1"</span></span>
<span id="cb22-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"5"</span></span>
<span id="cb22-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"8"</span></span>
<span id="cb22-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"11"</span></span>
<span id="cb22-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"17"</span></span>
<span id="cb22-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"32"</span></span>
<span id="cb22-13">]</span></code></pre></div>
</div>
<p>An ingredient is fresh if its id falls within any of the ranges given. After a little pre-processing, we can collect all of the ranges that fresh ingredient fall into</p>
<p>…because we suspect we will need that for part 2, even though they end up going in a different, more complicated direction.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb23-1">fresh_ingredients <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dict</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">{Int, Vector{UnitRange{Int}}}</span>()</span>
<span id="cb23-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> ingredients</span>
<span id="cb23-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> ranges</span>
<span id="cb23-4">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> r</span>
<span id="cb23-5">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push!</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get!</span>(fresh_ingredients, i, <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">UnitRange</span>{<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>}[]), r)</span>
<span id="cb23-6">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb23-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb23-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
</div>
<p>and then returning the number of fresh ingredients.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb24-1">fresh_ingredients <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> length</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>3</code></pre>
</div>
</div>
<p>Part 2 instead asks to find the number of possible fresh ingredients i.e.&nbsp;how many unique ingredient IDs fall within any of the given ranges.</p>
<p>…and in the real input data, the ranges were large, and overlapped. <em>So</em>, in cases where there was overlap, I combined them into a single new range (with the smaller of the start values, and larger of the end values).</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb26-1">sorted_ranges <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span>(ranges, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> first)</span>
<span id="cb26-2"></span>
<span id="cb26-3">fresh_ingredients_merged <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [sorted_ranges[begin]]</span>
<span id="cb26-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> sorted_ranges[<span class="fl" 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="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>]</span>
<span id="cb26-5">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># start a new range when the lower value is outside the largest value of the merge</span></span>
<span id="cb26-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last</span>(fresh_ingredients_merged[<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">first</span>(range)</span>
<span id="cb26-7">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push!</span>(fresh_ingredients_merged, range)</span>
<span id="cb26-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span></span>
<span id="cb26-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the start of the new range stays the same, but the end needs to be extended if it's bigger for the new range</span></span>
<span id="cb26-10">    new_max_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last</span>(fresh_ingredients_merged[<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>]), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last</span>(range)] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> maximum</span>
<span id="cb26-11">    fresh_ingredients_merged[<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">first</span>(fresh_ingredients_merged[<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>])<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>new_max_range</span>
<span id="cb26-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>    </span>
<span id="cb26-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
</div>
<p>…and then summed the lengths of the now non-overlapping ranges (without duplicate ingredient IDs):</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb27-1">[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(x) for x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> fresh_ingredients_merged] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> sum</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>14</code></pre>
</div>
</div>
<p>⭐⭐</p>
</section>
<section id="day-6-cephalopod-maths" class="level4">
<h4 class="anchored" data-anchor-id="day-6-cephalopod-maths">Day 6: Cephalopod Maths 🐙</h4>
<p>I googled <em>cephalopod</em> - it means a creature with a head and tentacles.</p>
<p>In the advent of code universe, they get maths homework, and this is what it looks like:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb29-1">sums <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb29-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"123 328  51 64 "</span>,</span>
<span id="cb29-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" 45 64  387 23 "</span>,</span>
<span id="cb29-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  6 98  215 314"</span>,</span>
<span id="cb29-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"*   +   *   +  "</span></span>
<span id="cb29-6">]</span></code></pre></div>
</div>
<p>This is asking us to apply the operator in the last row, to the numbers above it. In part 1, the numbers above the first (leftmost) <code>*</code> are <code>123</code>, <code>45</code>, <code>6</code>. In part 2 we are told the numbers are written in coluns (not rows) so we instead have to multiply <code>356</code>, <code>24</code>, and <code>1</code>.</p>
<p>So the difference is in fiddling the parsing of the numbers. Here’s a solution:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb30-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">solve_sums</span>(lines<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector{String}</span>; part_2<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Bool </span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">false</span>)</span>
<span id="cb30-2">    </span>
<span id="cb30-3">    n_cols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lines[<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> length</span>
<span id="cb30-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># need to break until the next sum when there is a column of spaces</span></span>
<span id="cb30-5">    no_sum <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(line[c] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">' '</span> for line <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> lines) for c <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_cols]</span>
<span id="cb30-6"></span>
<span id="cb30-7">    results <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>[]; col <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</span></span>
<span id="cb30-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> n_cols</span>
<span id="cb30-9">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># skip the separator columns that split the sums</span></span>
<span id="cb30-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> n_cols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> no_sum[col]</span>
<span id="cb30-11">            col <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</span></span>
<span id="cb30-12">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb30-13">        col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> n_cols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span>
<span id="cb30-14">        </span>
<span id="cb30-15">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># otherwise we start a new sum</span></span>
<span id="cb30-16">        start_sum <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> col</span>
<span id="cb30-17">        </span>
<span id="cb30-18">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># and keep going until the next separator</span></span>
<span id="cb30-19">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> n_cols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> !no_sum[col]</span>
<span id="cb30-20">            col <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</span></span>
<span id="cb30-21">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb30-22"></span>
<span id="cb30-23">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the operator is always in the first col of each sum, in the last row</span></span>
<span id="cb30-24">        op <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lines[<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>][start_sum]</span>
<span id="cb30-25">        </span>
<span id="cb30-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> part_2</span>
<span id="cb30-27">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pt.2: each column is a number (read top-down)</span></span>
<span id="cb30-28">            numbers <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>[]</span>
<span id="cb30-29">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> nums_col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> start_sum<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>col<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</span></span>
<span id="cb30-30">                digits <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [line[nums_col] for line <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> lines[<span class="fl" 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="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</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</span>] if line[nums_col] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">' '</span>]</span>
<span id="cb30-31">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> !<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">isempty</span>(digits)</span>
<span id="cb30-32">                    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push!</span>(numbers, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">String</span>(digits)))</span>
<span id="cb30-33">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> </span>
<span id="cb30-34">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb30-35">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span></span>
<span id="cb30-36">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pt.1: each row is a number, but they can have leading spaces</span></span>
<span id="cb30-37">            numbers <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">strip</span>(line[start_sum<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>col<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</span>])) for line <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> lines[<span class="fl" 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="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</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</span>]]</span>
<span id="cb30-38">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb30-39">        </span>
<span id="cb30-40">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># an excuse to use Julia metaprogramming :)</span></span>
<span id="cb30-41">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push!</span>(results, op <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Symbol</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> eval <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reduce</span>(x, numbers))</span>
<span id="cb30-42">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb30-43">        </span>
<span id="cb30-44">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> results</span>
<span id="cb30-45"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>solve_sums (generic function with 1 method)</code></pre>
</div>
</div>
<p>Not completed on the day for the first time, but life is very hectic.</p>
<p>Oh, and an excuse to use <code>Julia</code> metaprogramming! We could have put in some conditional logic to take products when the operator is <code>*</code> and sums when it’s <code>+</code>, but instead we can directly convert to a symbol and evaluate it. Not at all required for this problem, but hey…</p>
<p>And then add up the results:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb32-1">sums <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> solve_sums <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> sum</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>4277556</code></pre>
</div>
</div>
<p>I’m inferring from the below meme, but I guess some people created matrices for all the numbers in each sum, rather than just strip the whitespace 🤔</p>
<p>Neat - wish I did it that way 🤷🏻</p>
<blockquote class="reddit-embed-bq blockquote" style="height:316px" data-embed-height="316">
<a href="https://www.reddit.com/r/adventofcode/comments/1pflq1c/2025_day_6_part_2_the_solution_be_like/">[2025 Day 6 (Part 2)] The solution be like…</a><br> by<a href="https://www.reddit.com/user/HotTop7260/">u/HotTop7260</a> in<a href="https://www.reddit.com/r/adventofcode/">adventofcode</a>
</blockquote>
<script async="" src="https://embed.reddit.com/widgets.js" charset="UTF-8"></script>
<p>⭐⭐</p>
</section>
<section id="day-7-tachyon-beam-splitting" class="level4">
<h4 class="anchored" data-anchor-id="day-7-tachyon-beam-splitting">Day 7: Tachyon beam splitting ⚛️</h4>
<p>After yesterday, we’ve got 12 ⭐’s on the board</p>
<p><em>we’re 1/2 way there</em> [Jon Bon Jovi voice]</p>
<p>A beam of tachyons, <code>|</code> flows from a starting point, <code>S</code> down a grid. When it hits a splitter, <code>^</code>, two beams emerge (one either side).</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb34-1">tachyon_manifold <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb34-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".......S......."</span>,</span>
<span id="cb34-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..............."</span>,</span>
<span id="cb34-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".......^......."</span>,</span>
<span id="cb34-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..............."</span>,</span>
<span id="cb34-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"......^.^......"</span>,</span>
<span id="cb34-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..............."</span>,</span>
<span id="cb34-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".....^.^.^....."</span>,</span>
<span id="cb34-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..............."</span>,</span>
<span id="cb34-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"....^.^...^...."</span>,</span>
<span id="cb34-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..............."</span>,</span>
<span id="cb34-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"...^.^...^.^..."</span>,</span>
<span id="cb34-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..............."</span>,</span>
<span id="cb34-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..^...^.....^.."</span>,</span>
<span id="cb34-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..............."</span>,</span>
<span id="cb34-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".^.^.^.^.^...^."</span>,</span>
<span id="cb34-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"..............."</span></span>
<span id="cb34-18">]</span></code></pre></div>
</div>
<p>In part 1, we are asked how many times the beam is split, and in part 2 we are asked how many parallel timelines (possible paths) exist for the beam.</p>
<p>Here’s my solution:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb35" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb35-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">analyse_beams</span>(beam_rows<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector{String}</span>)</span>
<span id="cb35-2"></span>
<span id="cb35-3">    n_rows <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> beam_rows <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> length</span>
<span id="cb35-4">    n_cols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> beam_rows[<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> length</span>
<span id="cb35-5">    grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [beam_rows[row][col] for row <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_rows, col <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_cols]</span>
<span id="cb35-6"></span>
<span id="cb35-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># find starting position</span></span>
<span id="cb35-8">    start_pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">findfirst</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span>(<span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'S'</span>), grid)</span>
<span id="cb35-9">    start_row, start_col <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> start_pos[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], start_pos[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span>
<span id="cb35-10"></span>
<span id="cb35-11">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># initialise beams and timelines...</span></span>
<span id="cb35-12">    splits <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</span>; timelines <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dict</span>(start_col <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;">1</span>)</span>
<span id="cb35-13">    </span>
<span id="cb35-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> row <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> (start_row <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</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_rows</span>
<span id="cb35-15">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...and then keep track of new ones</span></span>
<span id="cb35-16">        new_timelines <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dict</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">{Int, Int}</span>()</span>
<span id="cb35-17">        </span>
<span id="cb35-18">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (col, count) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> timelines</span>
<span id="cb35-19">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> grid[row, col] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'^'</span></span>
<span id="cb35-20">                <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># for part 1, we count the splits</span></span>
<span id="cb35-21">                splits <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</span> </span>
<span id="cb35-22">                <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># for part 2, we "do" the split and count the timelines (add beams to the left and right - after an in-bounds check)</span></span>
<span id="cb35-23">                col <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</span> <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;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> (new_timelines[col <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</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(new_timelines, col <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</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> count)</span>
<span id="cb35-24">                col <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</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> n_cols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> (new_timelines[col <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</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(new_timelines, col <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</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> count)</span>
<span id="cb35-25">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span></span>
<span id="cb35-26">                new_timelines[col] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>(new_timelines, col, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> count</span>
<span id="cb35-27">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb35-28">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb35-29"></span>
<span id="cb35-30">        timelines <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> new_timelines</span>
<span id="cb35-31"></span>
<span id="cb35-32">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb35-33"></span>
<span id="cb35-34">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"splits"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=&gt;</span> splits, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"timelines"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=&gt;</span> timelines)</span>
<span id="cb35-35"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>analyse_beams (generic function with 1 method)</code></pre>
</div>
</div>
<p>This is a tidied up version, because I was initially separately tracking a variable <code>beams</code>, which I ended up separately recording in my part 2 dictionary. Also, I’ve got no idea if I needed the in-bounds checks (where I discount any beams that stray off the edges of the tachyon manifold).</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb37" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb37-1">tachyon_manifold <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> analyse_beams</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>("splits" =&gt; 21, "timelines" =&gt; Dict(5 =&gt; 10, 13 =&gt; 1, 15 =&gt; 1, 7 =&gt; 11, 11 =&gt; 2, 9 =&gt; 11, 12 =&gt; 1, 3 =&gt; 2, 1 =&gt; 1))</code></pre>
</div>
</div>
</section>
<section id="day-8-connecting-junction-boxes" class="level4">
<h4 class="anchored" data-anchor-id="day-8-connecting-junction-boxes">Day 8: Connecting junction boxes 🔌</h4>
<p>We are given 3-d (x, y, z) coordinates of electrical junction boxes and ask to connect the closest ones (shortest Euclidean distance) together to form circuits.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb39" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb39-1">junction_boxes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb39-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"162,817,812"</span>,</span>
<span id="cb39-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"57,618,57"</span>,</span>
<span id="cb39-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"906,360,560"</span>,</span>
<span id="cb39-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"592,479,940"</span>,</span>
<span id="cb39-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"352,342,300"</span>,</span>
<span id="cb39-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"466,668,158"</span>,</span>
<span id="cb39-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"542,29,236"</span>,</span>
<span id="cb39-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"431,825,988"</span>,</span>
<span id="cb39-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"739,650,466"</span>,</span>
<span id="cb39-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"52,470,668"</span>,</span>
<span id="cb39-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"216,146,977"</span>,</span>
<span id="cb39-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"819,987,18"</span>,</span>
<span id="cb39-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"117,168,530"</span>,</span>
<span id="cb39-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"805,96,715"</span>,</span>
<span id="cb39-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"346,949,466"</span>,</span>
<span id="cb39-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"970,615,88"</span>,</span>
<span id="cb39-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"941,993,340"</span>,</span>
<span id="cb39-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"862,61,35"</span>,</span>
<span id="cb39-20">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"984,92,344"</span>,</span>
<span id="cb39-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"425,690,689"</span></span>
<span id="cb39-22">]</span></code></pre></div>
</div>
<p><strong>The key insight</strong>: We don’t need to track every box in each circuit, just whether two boxes share a common “root”. This is a <strong>Union-Find</strong> (∪ + 🔎) problem.</p>
<p>Each box starts as it’s own standalone circuit. When we connect two boxes, one joins the other’s (the root’s) circuit. To check if two boxes are in the same circuit, we can then follow the chain and check if they share the same root.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb40" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb40-1">coords <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> junction_boxes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb40-2">    boxes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">split</span>.(boxes, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb40-3">    boxes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>.(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, b) for b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> boxes]</span>
<span id="cb40-4"></span>
<span id="cb40-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># each box starts as its own root</span></span>
<span id="cb40-6">n_boxes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(coords); parent <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_boxes)</span>
<span id="cb40-7"></span>
<span id="cb40-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># follow the chain upward to find the root</span></span>
<span id="cb40-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_circuit_root</span>(box_index)</span>
<span id="cb40-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> parent[box_index] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> box_index</span>
<span id="cb40-11">        box_index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> parent[box_index]</span>
<span id="cb40-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb40-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> box_index</span>
<span id="cb40-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb40-15"></span>
<span id="cb40-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># connect two circuits by making one root point to the other</span></span>
<span id="cb40-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">connect_boxes!</span>(box_from, box_to)</span>
<span id="cb40-18">    root_from <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_circuit_root</span>(box_from)</span>
<span id="cb40-19">    root_to <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_circuit_root</span>(box_to)</span>
<span id="cb40-20">    </span>
<span id="cb40-21">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># already in same circuit?</span></span>
<span id="cb40-22">    root_from <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> root_to <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">false</span></span>
<span id="cb40-23">    </span>
<span id="cb40-24">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># otherwise =&gt; merge</span></span>
<span id="cb40-25">    parent[root_from] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> root_to</span>
<span id="cb40-26">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">true</span></span>
<span id="cb40-27"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
</div>
<p>Here I check the distance between every pair of boxes, and arrange shortest to longest:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb41" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb41-1">distances <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb41-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> box <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_boxes</span>
<span id="cb41-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> alt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> (box<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</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_boxes  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># avoid double-counting pairs</span></span>
<span id="cb41-4">        dist <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (coords[box] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.-</span> coords[alt])<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</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> sum <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> sqrt</span>
<span id="cb41-5">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push!</span>(distances, (dist <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dist, from <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> box, to <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> alt))</span>
<span id="cb41-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb41-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb41-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort!</span>(distances, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> first)</span></code></pre></div>
</div>
<p>Part 1 asks us to attempt to connect the <code>1000</code> shortest connections and part 2 asks wants us to keep going until we end up with 1 big circuit and a final connection. Here’s my solution:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb42" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb42-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">size_circuits</span>(distances; n_attempts<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Union{Int, Nothing} </span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">nothing</span>)</span>
<span id="cb42-2">    </span>
<span id="cb42-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># each box starts as is its own circuit</span></span>
<span id="cb42-4">    parent <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_boxes)</span>
<span id="cb42-5">    last_connection <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">nothing</span></span>
<span id="cb42-6"></span>
<span id="cb42-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (attempt, d) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">enumerate</span>(distances)</span>
<span id="cb42-8">        </span>
<span id="cb42-9">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">connect_boxes!</span>(d.from, d.to)</span>
<span id="cb42-10">            last_connection <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> d</span>
<span id="cb42-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb42-12"></span>
<span id="cb42-13">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># part 1: stop after N attempts</span></span>
<span id="cb42-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> !<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">isnothing</span>(n_attempts) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> attempt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> n_attempts</span>
<span id="cb42-15">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span>
<span id="cb42-16">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb42-17">        </span>
<span id="cb42-18">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># part 2: stop when everything is connected</span></span>
<span id="cb42-19">        roots <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_circuit_root</span>(i) for i <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_boxes]</span>
<span id="cb42-20">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unique</span>(roots)) <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</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span>
<span id="cb42-21">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb42-22"></span>
<span id="cb42-23">    roots <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_circuit_root</span>(i) for i <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_boxes]</span>
<span id="cb42-24">    circuit_sizes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span>(r), roots) for r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unique</span>(roots)]</span>
<span id="cb42-25">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort!</span>(circuit_sizes, rev<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">true</span>)</span>
<span id="cb42-26"></span>
<span id="cb42-27">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dict</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"circuit_sizes"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=&gt;</span> circuit_sizes, </span>
<span id="cb42-28">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"last_connection"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=&gt;</span> last_connection)</span>
<span id="cb42-29"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>size_circuits (generic function with 1 method)</code></pre>
</div>
</div>
<p>There are some lovely visualisations of the growing mega-circuit of part 2:</p>
<blockquote class="reddit-embed-bq blockquote" style="height:500px" data-embed-height="688">
<a href="https://www.reddit.com/r/adventofcode/comments/1phelxp/2025_day_8_part_2_visualisation/">[2025 Day 8 (Part 2)] Visualisation</a><br> by<a href="https://www.reddit.com/user/Derailed_Dash/">u/Derailed_Dash</a> in<a href="https://www.reddit.com/r/adventofcode/">adventofcode</a>
</blockquote>
<script async="" src="https://embed.reddit.com/widgets.js" charset="UTF-8"></script>
<div class="cell">
<div class="sourceCode cell-code" id="cb44" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb44-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">size_circuits</span>(distances)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"last_connection"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb44-2">    last <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> coords[last.from][<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> coords[last.to][<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>25272</code></pre>
</div>
</div>
<p>The puzzles are getting tricky. This is possibly the first one that can’t be brute-forced? My naive approach of adding new boxes to sets of circuits was pretty slow (O(n)). This is also the first puzzle I was unable to solve them on the day of release due to other commitments, but I’m not fussed about that.</p>
<p>⭐⭐</p>
</section>
<section id="day-9-red-and-green-tiles" class="level4">
<h4 class="anchored" data-anchor-id="day-9-red-and-green-tiles">Day 9: Red and Green tiles 🟥 🟩</h4>
<p>We are provided with coordinates (in 2-d today) of red tiles:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb46" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb46-1">red_tiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb46-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"7,1"</span>,</span>
<span id="cb46-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"11,1"</span>,</span>
<span id="cb46-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"11,7"</span>,</span>
<span id="cb46-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"9,7"</span>,</span>
<span id="cb46-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"9,5"</span>,</span>
<span id="cb46-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2,5"</span>,</span>
<span id="cb46-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2,3"</span>,</span>
<span id="cb46-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"7,3"</span></span>
<span id="cb46-10">]</span></code></pre></div>
</div>
<p>We are asked to find the largest (by area) rectangle that can be made, if we took two red tiles as opposite corners. Part 1 didn’t have any further restrictions and so was one of the simplest stars to get so far this year. Part 2 was not…</p>
<p>In part 2, we connect sequential red tiles using green tiles. We then have a border of green tiles since, <em>adjacent tiles are always in the same row or column</em> (thankfully!) and we also fill in the inside of this shape with green tiles. The large rectangles we are trying to form cannot include any coordinates that are not either red or green tiles.</p>
<p>How do we know which tiles are “inside” the loop?</p>
<p>I think there are some clever ways to do this by flooding the outer grid with empty tiles or the inner grid with green tiles, until we hit the border.</p>
<p>I used a simpler approach. For each empty tile, walk left and count how many times you cross vertical boundaries. After an odd number of crossings, you must be inside (green tile). 🪄 Trick: be carefull to ignore horizontal boundaries, as they will just run parallel to our walk (we won’t cross them). This is why I added the <code>above</code> check.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb47" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb47-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># connect sequential red tiles with green tiles</span></span>
<span id="cb47-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">draw_green_line!</span>(grid, from, to)</span>
<span id="cb47-3">    x_min, x_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">minmax</span>(from[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], to[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb47-4">    y_min, y_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">minmax</span>(from[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], to[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])</span>
<span id="cb47-5">    </span>
<span id="cb47-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> x_min<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>x_max</span>
<span id="cb47-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> y_min<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>y_max</span>
<span id="cb47-8">            grid[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</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> (grid[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;">2</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># only fill empties</span></span>
<span id="cb47-9">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb47-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb47-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>draw_green_line! (generic function with 1 method)</code></pre>
</div>
<div class="sourceCode cell-code" id="cb49" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb49-1"></span>
<span id="cb49-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># are we inside the shape?</span></span>
<span id="cb49-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is_inside</span>(grid, x, y)</span>
<span id="cb49-4">    grid[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</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">false</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># already filled</span></span>
<span id="cb49-5">    </span>
<span id="cb49-6">    crossings <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</span></span>
<span id="cb49-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> check_x <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</span><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><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb49-8">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># counting vertical boundaries</span></span>
<span id="cb49-9">        at_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> grid[check_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;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb49-10">        above <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;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> grid[check_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;">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;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb49-11">        at_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> above <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> (crossings <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</span>)</span>
<span id="cb49-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb49-13">    </span>
<span id="cb49-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">isodd</span>(crossings)</span>
<span id="cb49-15"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>is_inside (generic function with 1 method)</code></pre>
</div>
</div>
<p>Turns out the grid is enormous - <code>9655610113</code> tiles.</p>
<p>Since we only care about red tiles, we can index their sparse coordinates. I eventually remembered to use the original (enormous) grid coordinates to calculate how big the rectangle areas are. Here’s my solution:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb51" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb51-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># check rectangle contains only red/green tiles</span></span>
<span id="cb51-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is_valid_rectangle</span>(grid, c1, c2)</span>
<span id="cb51-3">    x_min, x_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">minmax</span>(c1[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c2[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb51-4">    y_min, y_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">minmax</span>(c1[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], c2[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])</span>
<span id="cb51-5">    </span>
<span id="cb51-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> x_min<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>x_max</span>
<span id="cb51-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> y_min<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>y_max</span>
<span id="cb51-8">            grid[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</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">false</span></span>
<span id="cb51-9">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb51-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb51-11">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">true</span></span>
<span id="cb51-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>is_valid_rectangle (generic function with 1 method)</code></pre>
</div>
<div class="sourceCode cell-code" id="cb53" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb53-1"></span>
<span id="cb53-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">max_area</span>(red_tiles_coords<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector{Vector{Int}}</span>; part_2<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Bool </span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">false</span>)</span>
<span id="cb53-3">    </span>
<span id="cb53-4">    n_tiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(red_tiles_coords)</span>
<span id="cb53-5">    max_area <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</span></span>
<span id="cb53-6">    best_pair <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">nothing</span></span>
<span id="cb53-7"></span>
<span id="cb53-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> part_2</span>
<span id="cb53-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># coordinate compression</span></span>
<span id="cb53-10">        all_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unique</span>(c[<span class="fl" 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;">for</span> c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> red_tiles_coords))</span>
<span id="cb53-11">        all_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unique</span>(c[<span class="fl" 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> c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> red_tiles_coords))</span>
<span id="cb53-12">        </span>
<span id="cb53-13">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># big grid =&gt; compressed index</span></span>
<span id="cb53-14">        x_to_idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dict</span>(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=&gt;</span> i <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (i, x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">enumerate</span>(all_x))</span>
<span id="cb53-15">        y_to_idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dict</span>(y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=&gt;</span> i <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (i, y) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">enumerate</span>(all_y))</span>
<span id="cb53-16">        </span>
<span id="cb53-17">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compress all red tile coordinates</span></span>
<span id="cb53-18">        compressed_coords <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [[x_to_idx[c[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]], y_to_idx[c[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]]] for c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> red_tiles_coords]</span>
<span id="cb53-19">        </span>
<span id="cb53-20">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># using reduced grid dims...</span></span>
<span id="cb53-21">        max_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(all_x)</span>
<span id="cb53-22">        max_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(all_y)</span>
<span id="cb53-23">        grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">zeros</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, max_x, max_y)</span>
<span id="cb53-24">        </span>
<span id="cb53-25">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...mark red tiles and connect with greens</span></span>
<span id="cb53-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> compressed_coords</span>
<span id="cb53-27">            grid[c[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c[<span class="fl" 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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb53-28">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-29">        </span>
<span id="cb53-30">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_tiles</span>
<span id="cb53-31">            next_i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> n_tiles ? <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb53-32">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">draw_green_line!</span>(grid, compressed_coords[i], compressed_coords[next_i])</span>
<span id="cb53-33">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-34">        </span>
<span id="cb53-35">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># and paint the interior green too</span></span>
<span id="cb53-36">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>max_x</span>
<span id="cb53-37">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> 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;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>max_y</span>
<span id="cb53-38">                <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is_inside</span>(grid, x, y) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> (grid[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;">2</span>)</span>
<span id="cb53-39">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-40">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-41">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-42"></span>
<span id="cb53-43">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_tiles</span>
<span id="cb53-44">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> (i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_tiles</span>
<span id="cb53-45">            </span>
<span id="cb53-46">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># part 2: check validity using compressed coords</span></span>
<span id="cb53-47">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> part_2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> !<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is_valid_rectangle</span>(grid, compressed_coords[i], compressed_coords[j])</span>
<span id="cb53-48">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb53-49">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-50"></span>
<span id="cb53-51">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...but then calculate the area on the big grid</span></span>
<span id="cb53-52">            width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(red_tiles_coords[i][<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> red_tiles_coords[j][<span class="fl" 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;">1</span></span>
<span id="cb53-53">            height <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(red_tiles_coords[i][<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> red_tiles_coords[j][<span class="fl" 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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb53-54">                        </span>
<span id="cb53-55">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> height <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> max_area</span>
<span id="cb53-56">                max_area <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> height</span>
<span id="cb53-57">                best_pair <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (i, j)</span>
<span id="cb53-58">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-59">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-60">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb53-61"></span>
<span id="cb53-62">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> max_area</span>
<span id="cb53-63"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>max_area (generic function with 1 method)</code></pre>
</div>
</div>
<p>which matches the example answer:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb55" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb55-1">red_tiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb55-2">    tiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">split</span>.(tiles, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb55-3">    tiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> [<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>.(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>, t) for t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">∈</span> tiles] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb55-4">    coords <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">max_area</span>(coords, part_2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">true</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>24</code></pre>
</div>
</div>
<p>A hodgepodge of a solution, which may have some breaking edge cases, but got me there. This is the first time I have been 3 puzzles away from completing advent of code…</p>
<p>⭐⭐</p>
</section>
<section id="day-10" class="level4">
<h4 class="anchored" data-anchor-id="day-10">Day 10: ⏳</h4>
<p>…</p>


</section>
</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2026,
  author = {Di Francesco, Domenic},
  title = {Advent of Code 2025},
  date = {2026-01-07},
  url = {https://allyourbayes.com/posts/AoC/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2026" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2026. <span>“Advent of Code 2025.”</span> January
7, 2026. <a href="https://allyourbayes.com/posts/AoC/">https://allyourbayes.com/posts/AoC/</a>.
</div></div></section></div> ]]></description>
  <category>Julia</category>
  <category>puzzles</category>
  <guid>https://allyourbayes.com/posts/AoC/</guid>
  <pubDate>Wed, 07 Jan 2026 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/AoC/santa.png" medium="image" type="image/png" height="125" width="144"/>
</item>
<item>
  <title>diff all the things! Part 1</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/gradients_pt1/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>Gradients guide us through daunting and unwieldy, high-dimensional models to draw samples from posterior distributions, take steps towards loss minimising parameter values, identify model vulnerabilities using adversarial methods, and more. One (of many) fun features about the <code>Julia</code> programming language is its unique approach to autodiff.</p>
<p>In Part 1, I provide an intro to autodiff workflow in <code>Julia</code> and the emergence of the <code>Enzyme</code> library.I personally found some documentation a little difficult to follow, so this is intended to be a practical guide, with a couple of example use cases.</p>
<hr>
<section id="autodiff-ad" class="level4">
<h4 class="anchored" data-anchor-id="autodiff-ad">autodiff (AD)</h4>
<p>So much of computational statistics and machine learning is built on automatic (algorithmic) differentiation - AD, “autodiff”, or “autograd”. Dig into literature on Bayesian inference, or deep learning, and you will find parameters being nudged in a direction informed by a gradient. I’m sometimes surprised at the extent of the ‘gradient-based’ monopoly in scientific computing, but I don’t mean to trivialise! …getting gradients of complex functions, very quickly and without error, is a powerful tool and its great that we are able to leverage this.</p>
<p>AD works by <em>“the relentless application of the chain rule”</em>, as I vaguely recall one of the <code>Stan</code> developers saying. Large functions are differentiated piece by piece (for which look-up rules can be applied), and the results are stitched together.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Cpartial%20%5Cmathcal%7BL%7D%7D%7B%5Cpartial%20x_i%7D%20=%20%5Cfrac%7B%5Cpartial%20%5Cmathcal%7BL%7D%7D%7B%5Cpartial%20x_n%7D%20%5Ctimes%20%5Cfrac%7B%5Cpartial%20x_n%7D%7B%5Cpartial%20x_%7Bn-1%7D%7D%20%5Ctimes%20%5Ccdots%20%5Ctimes%20%5Cfrac%7B%5Cpartial%20x_%7Bi+1%7D%7D%7B%5Cpartial%20x_i%7D%0A"></p>
</section>
<section id="inter-operability-and-julia" class="level4">
<h4 class="anchored" data-anchor-id="inter-operability-and-julia">inter-operability and <code>Julia</code> ♥️💚💜</h4>
<p>Perhaps my favourite feature of <code>Julia</code> is its inter-operability. Look at a GitHub repo for a <code>Julia</code> package and you will generally find the following:</p>
<p><img src="https://allyourbayes.com/posts/gradients_pt1/julia_repo.png" class="img-fluid"></p>
<p><code>Julia</code> is so performant, that its libraries for scientific computing will work with normal variables - without needing to package up their own types. So solvers from <code>DifferentialEquations</code>, or neural networks defined in <code>Flux</code> can be immediately combined with the <code>Julia</code> probabilistic programming language, <code>Turing</code>.</p>
<p>If a new framework emerges in <code>Python</code>, an entirely new ecosystem may need to be developed to prop it up. This may involve duplicating existing but now incompatible functionality - think of <code>JAX</code> needing to implement its own <code>NumPy</code> module. …whereas if you write a new <code>Julia</code> library, it could offer a vast range of applications as it is combined with other packages, which feels like potential for a multiplicative, rather than additive, impact.</p>
<p>Here I am, impressed that the interoperability of the <code>Copulas</code> package:</p>
<blockquote class="twitter-tweet blockquote" data-conversation="none">
<p lang="en" dir="ltr">
<a href="https://t.co/ySAg1SM98g">pic.twitter.com/ySAg1SM98g</a>
</p>
— Domenic Denicola (<span class="citation" data-cites="Domenic_DF">@Domenic_DF</span>) <a href="https://twitter.com/Domenic_DF/status/1620520031565275136?ref_src=twsrc%5Etfw">January 31, 2023</a>
</blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</section>
<section id="ad-in-julia" class="level4">
<h4 class="anchored" data-anchor-id="ad-in-julia">AD in <code>Julia</code></h4>
<p>ML frameworks in <code>Python</code> require you to work in their own syntax, with their specific types, and use their own in-built AD methods. Locking into a framework is not ideal, as you are limited to the methods they support and you need to juggle types of inputs and outputs.</p>
<p>Conversely, <code>Julia</code> works the other way around. You write your code, using whichever libraries, functions and types you want, <em>and then</em> you choose an AD library to get you the gradients you need.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/gradients_pt1/autodiff_joy.png" class="img-fluid figure-img"></p>
<figcaption>the joy of gradients - image courtesy of Google Gemini</figcaption>
</figure>
</div>
<p>Why does this feel so powerful? its the promise of gradient-based methods for your scientific problem, rather than a walled-off machine learning model. You can point an AD engine at the aspect of your analysis that you are interested in for more bespoke interrogation or optimisation.</p>
<p>I recently completed a project, which had an element of adversarial AI (counterfactual analysis and saliency maps), which I wrote in <code>JAX</code>, mainly as an excuse to learn <code>JAX</code>. I used their <code>NNX</code> module for neural networks, and found this to be unexpectedly restrictive. I wasn’t able to run analysis that required gradients of outputs w.r.t. inputs, as I hit <code>NNX</code> errors/limitations that I wasn’t able to resolve. I ended up re-writing everything in <code>Julia</code>.</p>
<p>Once upon a time there was <code>Zygote</code>: an AD library that powered ML in <code>Julia</code>. A great achievement, but limitations began to emerge. Because of how it operates on your code, it can struggle with certain features. This is similar to the so-called “sharp bits” of <code>JAX</code> …though those limitations emerge for very different reasons.</p>
<p><code>Zygote</code> is also sometimes described as “<em>too permissive</em>”. This is because it intercepts your code at some <em>intermediate representation</em> level (see note below), performs AD and then reassembles. <code>Julia</code>’s IR levels were designed for performance, not AD and so doesn’t reliably detect and report errors in <code>Zygote</code>’s process.</p>
<p>It is possible for AD solutions to work with the compiler, rather than against it — more on this in Part 2! But for now…</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-1-contents" aria-controls="callout-1" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
IR in <code>Julia</code>
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-1" class="callout-1-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>The <code>Julia</code> compiler doesn’t go straight from your source text to machine code. It passes through several intermediate representations (progressively lower-level versions that are easier for the compiler to analyse and optimise).</p>
<p>What’s cool is that we can actually view these with the below macros:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># some nice high-level code</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nice_function</span>(x) <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</span>x <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</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>nice_function (generic function with 1 method)</code></pre>
</div>
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb3-1"></span>
<span id="cb3-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the "lowered" IR</span></span>
<span id="cb3-3"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@code_lowered</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nice_function</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>CodeInfo(
1 ─ %1 = Main.:+
│   %2 = Main.:*
│   %3 = (%2)(2, x)
│   %4 = (%1)(%3, 1)
└──      return %4
)</code></pre>
</div>
<div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb5-1"></span>
<span id="cb5-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the "typed" IR</span></span>
<span id="cb5-3"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@code_typed</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nice_function</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>CodeInfo(
1 ─ %1 = Base.mul_float(2.0, x)::Float64
│   %2 = Base.add_float(%1, 1.0)::Float64
└──      return %2
) =&gt; Float64</code></pre>
</div>
<div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb7-1"></span>
<span id="cb7-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the LLVM level</span></span>
<span id="cb7-3"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@code_llvm</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nice_function</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>; Function Signature: nice_function(Float64)
;  @ none:3 within `nice_function`
define double @julia_nice_function_7614(double %"x::Float64") #0 {
top:
;  @ none:5 within `nice_function`
; ┌ @ promotion.jl:430 within `*` @ float.jl:493
   %0 = fmul double %"x::Float64", 2.000000e+00
; └
; ┌ @ promotion.jl:429 within `+` @ float.jl:491
   %1 = fadd double %0, 1.000000e+00
   ret double %1
; └
}</code></pre>
</div>
<div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb9-1"></span>
<span id="cb9-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># finally, actual machine code</span></span>
<span id="cb9-3"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@code_native</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nice_function</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 15, 0
    .globl  _julia_nice_function_7864       ; -- Begin function julia_nice_function_7864
    .p2align    2
_julia_nice_function_7864:              ; @julia_nice_function_7864
; Function Signature: nice_function(Float64)
; ┌ @ none:3 within `nice_function`
; %bb.0:                                ; %top
; │ @ none within `nice_function`
    ;DEBUG_VALUE: nice_function:x &lt;- $d0
    ;DEBUG_VALUE: nice_function:x &lt;- $d0
; │ @ none:5 within `nice_function`
; │┌ @ promotion.jl:430 within `*` @ float.jl:493
    fadd    d0, d0, d0
    fmov    d1, #1.00000000
; │└
; │┌ @ promotion.jl:429 within `+` @ float.jl:491
    fadd    d0, d0, d1
    ret
; └└
                                        ; -- End function
    .section    __DATA,__const
    .p2align    3, 0x0                          ; @"+Core.Float64#7866"
"l_+Core.Float64#7866":
    .quad   "l_+Core.Float64#7866.jit"

.set "l_+Core.Float64#7866.jit", 6237349104
.subsections_via_symbols</code></pre>
</div>
</div>
</div>
</div>
</div>
<p>And then came <code>Enzyme</code>: an AD library that works at the LLVM level (your code is compiled first, and then the gradients are computed). This led to improvements in both performance and flexibility - we can now differentiate through mutation and control flow. This more resilient library has a steeper learning curve (imo), but (also imo) requiring more explicit instructions ends up making things clearer.</p>
<p>I hope the below examples will help get you started.</p>
</section>
<section id="example-1-a-bayesian-linear-regression" class="level4">
<h4 class="anchored" data-anchor-id="example-1-a-bayesian-linear-regression">example 1: a Bayesian linear regression</h4>
<p>How about computing the gradients we need for Hamiltonian Monte Carlo sampling. For a linear regression model, with inputs, <img src="https://latex.codecogs.com/png.latex?X"> and outputs, <img src="https://latex.codecogs.com/png.latex?y">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ay%20%5Csim%20N(%5Calpha%20+%20%5Cbeta%20X,%20%5Csigma)%0A"></p>
<p>with priors:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Calpha%20%5Csim%20N(0,%203)%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbeta%20%5Csim%20N(0,%203)%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Csigma%20%5Csim%20%5Ctext%7BExponential%7D(1)%0A"></p>
<p>Let’s put these in a tuple:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb11-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">using</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Distributions</span></span>
<span id="cb11-2"></span>
<span id="cb11-3">priors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb11-4">    α_prior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Normal</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), </span>
<span id="cb11-5">    β_prior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Normal</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), </span>
<span id="cb11-6">    σ_prior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Exponential</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-7">)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>(α_prior = Normal{Float64}(μ=0.0, σ=3.0), β_prior = Normal{Float64}(μ=0.0, σ=3.0), σ_prior = Exponential{Float64}(θ=1.0))</code></pre>
</div>
</div>
<p>For numerical stability reasons MCMC typically works in negative log space, so the below function finds the unnormalised negative log posterior for our model. This could of course be sped-up, but I’ve tried to keep it friendly 😊</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb13-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">using</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Random</span></span>
<span id="cb13-2"></span>
<span id="cb13-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">neg_log_posterior</span>(params<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">NamedTuple</span>, priors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">NamedTuple</span>,</span>
<span id="cb13-4">                          x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector</span>)</span>
<span id="cb13-5"></span>
<span id="cb13-6">    α <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> params.α; β <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> params.β; σ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> params.σ</span>
<span id="cb13-7">    </span>
<span id="cb13-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># mean of likelihood</span></span>
<span id="cb13-9">    μ_pred <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> x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> β</span>
<span id="cb13-10">    </span>
<span id="cb13-11">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># increment the negative log likelihood for all observations</span></span>
<span id="cb13-12">    neg_log_lik <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>
<span id="cb13-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fl" 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="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(y)</span>
<span id="cb13-14">        neg_log_lik <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">-logpdf</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Normal</span>(μ_pred[i], σ), y[i])</span>
<span id="cb13-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb13-16">    </span>
<span id="cb13-17">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...and for the priors</span></span>
<span id="cb13-18">    neg_log_prior_α <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">-logpdf</span>(priors.α_prior, α)</span>
<span id="cb13-19">    neg_log_prior_β <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">-logpdf</span>(priors.β_prior, β)</span>
<span id="cb13-20">    neg_log_prior_σ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">-logpdf</span>(priors.σ_prior, σ)</span>
<span id="cb13-21">    </span>
<span id="cb13-22">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># summing in log space is equivalent to multiplying priors and likelihoods 😉</span></span>
<span id="cb13-23">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> neg_log_lik <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> neg_log_prior_α <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> neg_log_prior_β <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> neg_log_prior_σ</span>
<span id="cb13-24"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>neg_log_posterior (generic function with 1 method)</code></pre>
</div>
</div>
<p>To use this function, we need to define some inputs. Here, I’m just simulating some data, using “true” parameter values:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb15-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 20 data points, why not...</span></span>
<span id="cb15-2">n_samples <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;">20</span></span>
<span id="cb15-3"></span>
<span id="cb15-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># define a PRNG for reproducibility</span></span>
<span id="cb15-5">prng <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">MersenneTwister</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">231123</span>)</span>
<span id="cb15-6"></span>
<span id="cb15-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># inputs from a standard Gaussian</span></span>
<span id="cb15-8">x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">randn</span>(prng, n_samples)</span>
<span id="cb15-9"></span>
<span id="cb15-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># outputs by sending inputs through a "true" model</span></span>
<span id="cb15-11">α_true <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</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;">2</span>; β_true <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;">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;">2</span>; σ_true <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</span></span>
<span id="cb15-12"></span>
<span id="cb15-13">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> α_true <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> β_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.+</span> σ_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">randn</span>(prng, n_samples)</span></code></pre></div>
</div>
<p>We can use <code>Enzyme</code> to get the gradients of the negative log posterior w.r.t. the model parameters - as required by Hamiltonian Monte Carlo.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb16-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># where do i want gradients?</span></span>
<span id="cb16-2">params_init <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb16-3">    α <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rand</span>(prng, priors.α_prior),</span>
<span id="cb16-4">    β <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rand</span>(prng, priors.β_prior),</span>
<span id="cb16-5">    σ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rand</span>(prng, priors.σ_prior)</span>
<span id="cb16-6">)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>(α = -6.290988779313054, β = 3.9183834605694834, σ = 1.6155587713748865)</code></pre>
</div>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-2-contents" aria-controls="callout-2" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
quick note on forward vs.&nbsp;reverse mode AD
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-2" class="callout-2-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>Imagine a function with <img src="https://latex.codecogs.com/png.latex?n_%7Bin%7D"> inputs and <img src="https://latex.codecogs.com/png.latex?n_%7Bout%7D"> outputs.</p>
<p><strong>Forward mode</strong> answers: “if I nudge <strong>one input</strong>, how do <strong>all outputs</strong> change?” — so you need <img src="https://latex.codecogs.com/png.latex?n_%7Bin%7D"> passes to cover every input.</p>
<p><strong>Reverse mode</strong> answers: “for <strong>one output</strong>, how did <strong>all inputs</strong> contribute?” — so you need <img src="https://latex.codecogs.com/png.latex?n_%7Bout%7D"> passes to cover every output.</p>
<p>Often, ML and Bayesian inference problems have many parameters (large <img src="https://latex.codecogs.com/png.latex?n_%7Bin%7D">) but a single scalar output i.e.&nbsp;a loss, or a log probability density (small <img src="https://latex.codecogs.com/png.latex?n_%7Bout%7D">). Reverse mode gets us gradients w.r.t. <strong>all</strong> parameters in one backward pass.</p>
<p>That said, the threshold isn’t always obvious and I’ve had cases where switching modes gave a noticeable speedup, so it’s worth experimenting!</p>
<p><code>Julia</code> has dedicated packages for each: <code>ForwardDiff.jl</code> and <code>ReverseDiff.jl</code> as part of its AD ecosystem. These are solid and well-established, but aren’t the focus of this post.</p>
</div>
</div>
</div>
<p>I am giving the <code>gradient()</code> function three arguments:</p>
<ul>
<li><p><strong>the mode/direction to apply AD</strong>, <code>Reverse</code>. Each pass of a reverse-mode AD computes gradients of all inputs w.r.t. a single output (as a vector-Jacobian product). In Forward mode, each pass computes gradients of a single input w.r.t. all outputs (as a Jacobian-vector product).</p>
<p>See above callout note for more on this and why reverse mode is likely not an optimal choice for so few parameters.</p>
<p>Consequently, there are efficiency trade-offs associated with this selection, depending on the number of inputs and outputs of…</p></li>
<li><p><strong>…the function we are differentiating</strong>, <code>params -&gt; neg_log_posterior(params, priors, x, y)</code>. Here, an anonymous function that takes <code>params</code> as input and returns the negative log posterior, using <code>neg_log_posterior()</code>, which we defined above.</p></li>
<li><p><strong>the point at which we want gradients</strong>, <code>params_init</code>. This is the current location of the Markov chain. In the first instance we need an initial guess, for which we have drawn from the priors.</p></li>
</ul>
<div class="cell">
<div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb18-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">using</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Enzyme</span></span>
<span id="cb18-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># computing the gradients</span></span>
<span id="cb18-3">∇θ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Enzyme.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gradient</span>(</span>
<span id="cb18-4">    Reverse, </span>
<span id="cb18-5">    params <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">neg_log_posterior</span>(params, priors, x, y), </span>
<span id="cb18-6">    params_init</span>
<span id="cb18-7">)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>((α = -54.13440425830732, β = 25.990919631591435, σ = -323.2246379556173),)</code></pre>
</div>
</div>
<p>We can then use these gradients to update the momentum of our Hamiltonian ‘particles’, generating proposals guided by the geometry of the posterior distribution. Unlike random walks or Gibbs samplers, this generation of samplers remain efficient in high dimensions 🥳</p>
</section>
<section id="example-2-an-mlp-simple-neural-network" class="level4">
<h4 class="anchored" data-anchor-id="example-2-an-mlp-simple-neural-network">example 2: an MLP (simple neural network)</h4>
<p>I defined a simple, densely connected neural network without anything clever (no layer normalisations, recurrent connections or attention mechanisms), sometimes referred to as a multi-layer perceptron (MLP).</p>
<p>I’ll spare you this set-up code here as we are focussing on autodiff, but you can find the full code <a href="https://github.com/DomDF/autodiff_experiments">on GitHub</a>.</p>
<p>Instead, let’s look at my training function. Notice that I am now using a different function, <code>Enzyme.autodiff()</code> for backpropagation. It has more arguments:</p>
<ul>
<li><strong>the mode/direction to apply AD</strong>, <code>set_runtime_activity(Reverse)</code>. Similar to <code>gradient()</code>, but here we are specifying that we want to use reverse-mode AD, with runtime activity analysis. As a rule of 👍, I start with regular <code>Reverse</code> mode AD. If I get compilation errors about, for instance, type inference or broadcasting, then I add <code>set_runtime_activity()</code>.</li>
<li><strong>the function we are differentiating</strong>, <code>(net, funs, inputs, targets) -&gt; find_loss(net, funs, inputs, targets)</code>. Here, an anonymous function that takes the neural network, its functions, inputs and targets as arguments, and returns the loss.</li>
<li><strong>the activity of the function</strong> <code>Active</code>. we need to make the output to the loss function active, because it is the starting point of the chain rule.</li>
<li><strong>the activity of each argument</strong>, <code>Active</code>, <code>Const()</code>, or <code>Duplicated()</code>. This is where things get more explicit. We need to tell <code>Enzyme</code> which arguments we want gradients for (<code>Active</code>), and which we don’t (<code>Const</code>) - the derivative of a constant is zero. Finally, we also want gradients for <code>Duplicated</code> variables, but they could be large. So we create a shadow copy of the neural network, <code>nn_shadow</code>, which we use to accumulate gradients in-place (without allocating new memory each time!)</li>
</ul>
<div class="cell">
<div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb20-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">train</span>(nn<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">neural_network</span>, nn_funs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">neural_network_funs</span>, </span>
<span id="cb20-2">               a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Array{Float64}</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Array{Float64}</span>;</span>
<span id="cb20-3">               a_test<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Array{Float64} </span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> a, y_test<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Array{Float64} </span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y, </span>
<span id="cb20-4">               n_epochs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int </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;">10</span>, η<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Float64 </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.01</span>)</span>
<span id="cb20-5">    <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@assert</span> n_epochs <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</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n_epochs must be greater than 0"</span></span>
<span id="cb20-6"></span>
<span id="cb20-7">    training_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">DataFrame</span>(epoch <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int</span>[], loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Float64</span>[], test_loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Float64</span>[])</span>
<span id="cb20-8"></span>
<span id="cb20-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_epochs</span>
<span id="cb20-10"></span>
<span id="cb20-11">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># initiate our memory-saving shadow</span></span>
<span id="cb20-12">        ∇nn <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Enzyme.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">make_zero</span>(nn)</span>
<span id="cb20-13"></span>
<span id="cb20-14">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># find ∂ℒ/∂θ</span></span>
<span id="cb20-15">        Enzyme.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">autodiff</span>(</span>
<span id="cb20-16">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_runtime_activity</span>(Reverse),</span>
<span id="cb20-17">            (net, funs, inputs, targets) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_loss</span>(net, funs, inputs, targets)[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb20-18">            Active,</span>
<span id="cb20-19">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Duplicated</span>(nn, ∇nn),</span>
<span id="cb20-20">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Const</span>(nn_funs),</span>
<span id="cb20-21">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Const</span>(a),</span>
<span id="cb20-22">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Const</span>(y)</span>
<span id="cb20-23">        )</span>
<span id="cb20-24"></span>
<span id="cb20-25">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># nudge all weights and biases towards a lower loss, using learning rate, η</span></span>
<span id="cb20-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <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</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(nn.Ws)</span>
<span id="cb20-27">            nn.Ws[j] <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> ∇nn.Ws[j]</span>
<span id="cb20-28">            nn.bs[j] <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> ∇nn.bs[j]</span>
<span id="cb20-29">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb20-30">        </span>
<span id="cb20-31">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># record losses</span></span>
<span id="cb20-32">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">append!</span>(training_df, </span>
<span id="cb20-33">                <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">DataFrame</span>(epoch <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i, </span>
<span id="cb20-34">                          loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_loss</span>(nn, nn_funs, a, y)[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb20-35">                          test_loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find_loss</span>(nn, nn_funs, a_test, y_test)[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]))</span>
<span id="cb20-36"></span>
<span id="cb20-37">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb20-38">    </span>
<span id="cb20-39">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> nn, training_df</span>
<span id="cb20-40"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div>
</div>
<p><code>Enzyme.make_zero(nn)</code> creates a structural copy of <code>nn</code> with the same type (neural_network), field names (Ws, bs), and dimensions …but with all numerical values set to zero. This memory-saving trick is important for large vectors of parameters, as we will generally have in deep learning.</p>
<p>The example applications that I selected are already very well equipped with sophisticated <code>Julia</code> libraries. If you are interested in probabilistic modelling in <code>Julia</code>, use <code>Turing</code>, if you are interested in deep learning, use <code>Flux</code>. Both are Enzyme compatible, but the later has specific guidance on how to set this up, using the <code>Duplicated</code> method that we used above:</p>
<p><img src="https://allyourbayes.com/posts/gradients_pt1/Flux_Enzyme.png" class="img-fluid"></p>
</section>
<section id="some-references" class="level4">
<h4 class="anchored" data-anchor-id="some-references">some references</h4>
<p>The <code>Julia</code> autodiff ecosystem, which is more vast than the examples covered in this blog post, <a href="https://juliadiff.org">link</a></p>
<p>A summary of the key trade-offs accross various autodiff methods, <a href="https://www.stochasticlifestyle.com/engineering-trade-offs-in-automatic-differentiation-from-tensorflow-and-pytorch-to-jax-and-julia/">link</a></p>
<p>Professor Simone Scardapone’s book, “Alice’s adventures in a differential wonderland” <a href="https://www.sscardapane.it/assets/alice/Alice_book_volume_1.pdf">link</a>.</p>
<p><em>“As the name differentiable implies, gradients play a pivotal role”</em></p>
<p><img src="https://allyourbayes.com/posts/gradients_pt1/alice.png" class="img-fluid"></p>
<p>JuliaCon talk on <code>Julia</code>’s unique approach to autodiff: </p><div class="quarto-video ratio ratio-16x9"><iframe data-external="1" src="https://www.youtube.com/embed/ww3ntpyxNtI" title="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div><p></p>


</section>
</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2025,
  author = {Di Francesco, Domenic},
  title = {Diff All the Things! {Part} 1},
  date = {2025-09-09},
  url = {https://allyourbayes.com/posts/gradients_pt1/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2025" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2025. <span>“Diff All the Things! Part 1.”</span>
September 9, 2025. <a href="https://allyourbayes.com/posts/gradients_pt1/">https://allyourbayes.com/posts/gradients_pt1/</a>.
</div></div></section></div> ]]></description>
  <category>automatic differentiation</category>
  <category>deep learning</category>
  <category>Bayes</category>
  <category>Julia</category>
  <category>Enzyme</category>
  <guid>https://allyourbayes.com/posts/gradients_pt1/</guid>
  <pubDate>Mon, 08 Sep 2025 23:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/gradients_pt1/meme.jpg" medium="image" type="image/jpeg"/>
</item>
<item>
  <title>The Turing Podcast</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/Turing_Podcast/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>Last year, I participated in an episode of the Alan Turing Institute’s Coffee Pod podcast. It was hosted by my friend <a href="https://twitter.com/mooniean">Bea</a> and we talked about my background in engineering, my PhD and transition into computational statistics and machine learning, my interest in football, and my (then) new puppy Ada.</p>
<p>Here’s the episode, I hope you enjoy it!</p>
<hr>
<iframe style="border-radius:12px" src="https://open.spotify.com/embed/episode/5FqU7ZRATxp9CIwHvD7pvP?utm_source=generator&amp;theme=0&amp;t=0" width="100%" height="352" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy">
</iframe>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2024,
  author = {Di Francesco, Domenic},
  title = {The {Turing} {Podcast}},
  date = {2024-01-25},
  url = {https://allyourbayes.com/posts/Turing_Podcast/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2024" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2024. <span>“The Turing Podcast.”</span> January
25, 2024. <a href="https://allyourbayes.com/posts/Turing_Podcast/">https://allyourbayes.com/posts/Turing_Podcast/</a>.
</div></div></section></div> ]]></description>
  <category>podcast</category>
  <category>Bayes</category>
  <category>engineering</category>
  <category>dogs</category>
  <guid>https://allyourbayes.com/posts/Turing_Podcast/</guid>
  <pubDate>Thu, 25 Jan 2024 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/Turing_Podcast/alan_turing.png" medium="image" type="image/png" height="104" width="144"/>
</item>
<item>
  <title>Who Am I?</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/Who_Am_I/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>At a previous job, my colleagues and I would occasionally create football (soccer) quizzes for each other. The game I used to send them would involve me sequentially sending a list of (increasingly helpful) clues, from which they had to guess which player I was thinking of. I have now turned this into a web app using the <a href="https://shiny.rstudio.com">shiny</a> and <a href="https://deanattali.com/shinyjs/">shinyjs</a> <code>R</code> libraries, and you can play it here. You can find the code on the GitHub link that I have included in the app.</p>
<p>I hope you enjoy it!</p>
<p>Edit: I will try and update this regularly with new players &amp; clues, so keep checking back. Suggestions are welcome - you can <a href="https://twitter.com/Domenic_DF">message me on Twitter</a>.</p>
<hr>
<iframe height="750" width="100%" frameborder="no" src="https://domdf.shinyapps.io/who_am_i/">
</iframe>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2023,
  author = {Di Francesco, Domenic},
  title = {Who {Am} {I?}},
  date = {2023-03-21},
  url = {https://allyourbayes.com/posts/Who_Am_I/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2023" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2023. <span>“Who Am I?”</span> March 21, 2023. <a href="https://allyourbayes.com/posts/Who_Am_I/">https://allyourbayes.com/posts/Who_Am_I/</a>.
</div></div></section></div> ]]></description>
  <category>football</category>
  <category>R</category>
  <category>Shiny</category>
  <guid>https://allyourbayes.com/posts/Who_Am_I/</guid>
  <pubDate>Tue, 21 Mar 2023 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/Who_Am_I/game.png" medium="image" type="image/png" height="77" width="144"/>
</item>
<item>
  <title>Bayes@Lund2023</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/Bayes@Lund/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>A recording of my presentation on value of information analysis at the Bayes@Lund2023 conference.</p>
<hr>
<section id="bayeslund2023-conference" class="level4">
<h4 class="anchored" data-anchor-id="bayeslund2023-conference">Bayes@Lund2023 Conference</h4>
<p>I have been following the Bayes@Lund conference since I started my PhD, and have often found the work presented to be very useful. This year I was able to attend and I presented on the topic of <em>value of information analysis</em> (how much should we be willing to pay for data).</p>
<p>Conventional experimental design is used to identify where our next mesaurement(s) should be obtained on the bases of reducing uncertainty. However, this scale (some measure of information entropy) is not always intuitive, and it won’t tell you the point at which paying for another measurement becomes uneconomical.</p>
<p>Value of information analysis is used to quantify how much we should be willing to pay for data of a specified quality (precision, bias, reliability, completeness, etc.), in the context of helping us make decisions.</p>
<p>Below is the recording of my talk, which breifly introduces the topic and provides a couple of examples.</p>
<div class="quarto-video ratio ratio-16x9"><iframe data-external="1" src="https://www.youtube.com/embed/zJgUnjJjFrk" title="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div>


</section>
</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2023,
  author = {Di Francesco, Domenic},
  title = {Bayes@Lund2023},
  date = {2023-01-23},
  url = {https://allyourbayes.com/posts/Bayes@Lund/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2023" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2023. <span>“Bayes@Lund2023.”</span> January 23,
2023. <a href="https://allyourbayes.com/posts/Bayes@Lund/">https://allyourbayes.com/posts/Bayes@Lund/</a>.
</div></div></section></div> ]]></description>
  <category>Bayes</category>
  <category>Stan</category>
  <category>Julia</category>
  <category>decisions</category>
  <category>value of information</category>
  <guid>https://allyourbayes.com/posts/Bayes@Lund/</guid>
  <pubDate>Mon, 23 Jan 2023 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/Bayes@Lund/VoPI.png" medium="image" type="image/png" height="103" width="144"/>
</item>
<item>
  <title>All Your Bayes 2.0</title>
  <link>https://allyourbayes.com/posts/welcome/</link>
  <description><![CDATA[ 






<p>I’ve recreated this site in <a href="https://quarto.org">quarto</a>, and plan on writing more jargon-free articles on risk, uncertainty, decisions, statistics, and football.</p>



 ]]></description>
  <category>news</category>
  <guid>https://allyourbayes.com/posts/welcome/</guid>
  <pubDate>Mon, 23 Jan 2023 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Player form. Part 1: Overview</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/player_form/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>When is a player <strong>in form</strong> (over performing, or enjoying a hot streak) and how long does this last? If there is such an effect, I suspect it will be a result of some complicated system of personal circumstances. In this post I suggest a popular statistical model (Gaussian process) for approximating the dependencies (how many games back should we look?) and non-linearities (rise and fall of form) that we need. Again, I am suggesting that we should care about uncertainty when trying to model just about anything in football, and using probability is a helpful way of doing so.</p>
<p>Ellen White’s data from the 2019-20 WSL season (courtesy of StatsBomb) is used as an example.</p>
<p>Similarly to the <a href="https://allyourbayes.com/posts/xg_pt2/">posts on multi-level models</a>, this will also be split into 2 parts. Part 1 (here) will focus on the features of a Gaussian process that are well suited to approximating player form. Part 2 (in preparation) will include more technical details and more code.</p>
<hr>
</section>
<section id="a-questionable-measure-of-player-form" class="level3">
<h3 class="anchored" data-anchor-id="a-questionable-measure-of-player-form">A (Questionable) Measure of Player Form</h3>
<p>As I alluded to in the TLDR above, I suspect a players form is somehow linked to their current mental state. When they are feeling confident they may be less likely to doubt their abilities, and more decisive. This could mean they act quicker and become more difficult to play against.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/STYcRDzNO6AYNmMgvA/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Confidence is key …probably</figcaption>
</figure>
</div>
<p>I will not propose a detailed causal model here, just a statistical proxy. But, I will be assuming that form can rise and decay over time. For some players even a single good or bad performance may be enough to drastically impact their next game, and for others this process may be smoother and less volatile. More on this later.</p>
<p>For the purposes of this post, goalscoring form on a given match day, <img src="https://latex.codecogs.com/png.latex?i">, is defined as the difference between the number of goals that were scored on that match day, minus the expected number of goals, <img src="https://latex.codecogs.com/png.latex?xG"> associated with the opportunities in that game.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AForm_%7B%5Bi%5D%7D%20=%20Goals_%7B%5Bi%5D%7D%20-%20xG_%7B%5Bi%5D%7D%0A"></p>
<p>A nice feature of this is that, in principle, it is invariant to the quality of opposition. A striker may have a higher xG when performing against a weaker team, but will therefore need to score more goals in such a game to be considered in the same form. By the same token, it should also account for the fact that a player will generally get fewer scoring opportunities as a substitute.</p>
<p>…As for the not so nice features, there are plenty! For instance, what good is a measure of form that only considers goals scored? Is xG not also conditional on how well a striker is paying? Would it be more useful to standardise the result?</p>
<p>These are all fair questions, and with a little thought could all be integrated into a more comprehensive characterisation. However, the type of model that I will introduce will be equally compatible with alternative definitions, so let’s imagine we just care about whether a striker is scoring as many goals as they should be, and whether this will continue.</p>
</section>
<section id="ellen-white" class="level3">
<h3 class="anchored" data-anchor-id="ellen-white">Ellen White</h3>
<p>Ellen White is a clinical striker who, at the time of writing this, plays for Manchester City and England. She is a former winner of the Women’s Super League (WSL) golden boot, and is England’s all-time top scorer. So plenty of opportunities to see her distinctive celebration:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/SVlBW8O5jw3dtU17dv/giphy-downsized-large.gif" class="img-fluid figure-img"></p>
<figcaption>Ellen’s goal goggles</figcaption>
</figure>
</div>
<p>StatsBomb have kindly made data from the WSL (2019/20 season) freely available in <a href="https://github.com/statsbomb/StatsBombR">their R package</a>, and so we will consider this league season of Ellen White’s career here.</p>
<p>Here is a plot of Ellen’s <strong>form</strong> (performance vs.&nbsp;xG) over the 12 league games that she featured in, during that season. Her biggest over performance vs.&nbsp;xG was when she scored in a <a href="https://womenscompetitions.thefa.com/Article/TottenhamManCity05012020">4-1 win away at Tottenham</a> despite a cumulative xG of 0.597. Her worst performance by the same measure was the following week, failing to score in the <a href="https://womenscompetitions.thefa.com/Article/Manchester-City-3-1-Everton-110120">3-1 win at home to Everton</a>. Although she only played the final <img src="https://latex.codecogs.com/png.latex?25"> minutes of this game, she accrued a match xG of 0.302. The fact that these games were back to back could be tricky for a form model to accommodate!</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/player_form/index_files/figure-html/unnamed-chunk-4-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="what-would-such-a-model-need-to-do" class="level3">
<h3 class="anchored" data-anchor-id="what-would-such-a-model-need-to-do">What would such a model need to do?</h3>
<p>Essentially, we are looking for are some numbers to help us understand the following:</p>
<ul>
<li>What form is a player currently in?</li>
<li>How long will a player remain in good (or bad) form?</li>
<li>What is the uncertainty in our predictions?</li>
</ul>
<p>Since players can enter good and bad patches of form over the course of a season, we need a model that is able to twist and turn accordingly. This means we need some <em>non-linearity</em>.</p>
<p>We also want future predictions to be based on recent games - if a player has over performed for the last 3 games in a row, then we generally expect them to continue on this path, at least in the short-term. But how far back should we look? Does a single great performance from <img src="https://latex.codecogs.com/png.latex?3"> months ago have any impact on a players current form? We need to quantify this <em>dependency</em> in our model too.</p>
<p>Finally, a probabilistic model has the benefit of <em>quantifying uncertainty</em>. I emphasise the importance of this in the ‘final thoughts’ at the end of this post and for anyone interested, here is <a href="https://www.allyourbayes.com/post/2020-03-24-why-go-bayesian/">more Bayesian statistics propaganda</a>. But, in summary we should not neglect uncertainty in this model because (a) We are not even sure what form is, and (b) we are estimating it from a small amount of indirect observations. So let’s not pretend we will end up with a single number. Enough preaching and back to the task at hand….</p>
<p>One solution that checks the above requirements is the Gaussian Process (GP).</p>
</section>
<section id="what-does-it-look-like" class="level3">
<h3 class="anchored" data-anchor-id="what-does-it-look-like">What does it look like?</h3>
<p>So we have this probabilistic model of smooth, non-linear functions. Let’s see what it looks like. In the below plot, the match days are the same as those presented in the above plot, we just have a new y-axis scale, and we have ‘days’ (rather than date) along the x-axis.</p>
<p>There are multiple functions that are consistent with Ellen White’s form in the league that season, so let’s look at one example first:</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/player_form/index_files/figure-html/unnamed-chunk-6-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Where there is a large gap between successive games (such as the 3 weeks between White’s first and second appearances of the season), there is less evidence to guide predictions of form. This is also true for the period around day 60 (late December). Here though, she was on an upward trajectory. In both cases, this lack of data results in higher uncertainty, as is apparent when we look at more samples, which are shown on top of the full predictive distribution below.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/player_form/index_files/figure-html/unnamed-chunk-7-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="and-so-what" class="level3">
<h3 class="anchored" data-anchor-id="and-so-what">And, so what?</h3>
<p>Some squiggly lines that approximately go through some points? What is the value of this when you could scribble something similar without knowing anything about statistics?</p>
<p>Well, underlying all of these lines is a model of dependency. We have quantified how similar (correlated) form should be in successive games, and how this correlation will decrease with time. I will talk about the parameters that do this and how they can be interpreted in part 2 (in preparation), but to summarise, the model quantifies how correlation in form decreases as time progresses and this can be seen in the smoothness of the lines.</p>
<p>For example, if form was always shown to be very similar to that of the previous game, then transitioning from good to bad performances would be gradual, and the samples from the associated GP model would be very smooth. Conversely, in the case where performance in subsequent games were completely independent, even if very little time had passed, the GP regression lines would need to be able to change direction very sharply.</p>
<p>Below are some predictions from the model in the period just after White’s last game of the season (to the right of the final match day on the above plots). She appeared to be on a slight upward trend at this point, over performing in her final game at home to Chelsea. This is shown in the uppermost histogram. As we move away from this game, into the off-season, we see the uncertainty gradually increase in our predictions and the average move towards zero. This is consistent with the considerations discussed above.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/player_form/index_files/figure-html/unnamed-chunk-8-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="some-final-thoughts" class="level3">
<h3 class="anchored" data-anchor-id="some-final-thoughts">Some final thoughts…</h3>
<section id="uncertainty" class="level4">
<h4 class="anchored" data-anchor-id="uncertainty">Uncertainty</h4>
<p>Any football models we propose will only vaguely resemble the ‘true’ data generating process and though we can incrementally add more parameters we do not automatically find more evidence for them. We can build big datasets by combining observations from multiple players, and leagues, but ignoring possible variation between such data is misleading. If your big football models need big data, why stop there? Feed it some Sunday league football, or some basketball, or some handwritten digits.</p>
<p>Alternatively, we acknowledge that our system of parameters are not perfectly precise, and our predictions will span credible ranges. Quantifying this variability is a strength, not a weakness of our models, and is actually of more direct use in decision support.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/3otPoyudZ18xASX0rK/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Yes we can!</figcaption>
</figure>
</div>
</section>
<section id="sources-of-information" class="level4">
<h4 class="anchored" data-anchor-id="sources-of-information">Sources of Information</h4>
<p>What can we do about long periods in time where no competitive games are taking place?</p>
<p>There may be other sources of information that could help, such as performances in other competitions or even in training. Given we are not sure of the extent that these should inform the model, there is an argument to use a multi-level (partial pooling) structure, as was used to improve <a href="https://allyourbayes.com/posts/xg_pt2/">player-specifc xG estimates</a>.</p>
<p>Finally, the other source of information is that contained in the priors, which I have not included here. But don’t panic, some prior predictive sampling is on the way in part 2 (in preparation).</p>


</section>
</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2023,
  author = {Di Francesco, Domenic},
  title = {Player {Form.} {Part} 1},
  date = {2023-01-19},
  url = {https://allyourbayes.com/posts/player_form/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2023" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2023. <span>“Player Form. Part 1.”</span> January
19, 2023. <a href="https://allyourbayes.com/posts/player_form/">https://allyourbayes.com/posts/player_form/</a>.
</div></div></section></div> ]]></description>
  <category>football</category>
  <category>analysis</category>
  <category>Stan</category>
  <category>uncertainty</category>
  <category>Bayes</category>
  <category>gaussian process</category>
  <guid>https://allyourbayes.com/posts/player_form/</guid>
  <pubDate>Thu, 19 Jan 2023 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/player_form/plot.png" medium="image" type="image/png" height="96" width="144"/>
</item>
<item>
  <title>Uncertainty in xG. Part 2: Partial Pooling</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/xg_pt2/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>This is part 2 of an article on fitting a Bayesian partial pooling model to predict expected goals. It has the benefits of (a) quantifying <em>aleatory and epistemic</em> uncertainty, and (b) making both group-level (player-specific) and population-level (team-specific) probabilistic predictions. If you are interested in these ideas but not in statistical language, then you can also check out <a href="https://allyourbayes.com/posts/xg_pt1/">part 1</a>.</p>
<hr>
</section>
<section id="expected-goals" class="level3">
<h3 class="anchored" data-anchor-id="expected-goals">Expected Goals</h3>
<p>Expected Goals (or <em>xG</em>) is a metric that was developed to predict the probability of a football (soccer) player scoring a goal, conditional on some mathematical characterisation of the shooting opportunity. Since we have a binary outcome (he or she will either score or not score) we can use everyone’s favourite GLM - logistic regression.</p>
<p>Unfortunately this causes some overlap with a <a href="https://www.allyourbayes.com/post/2020-02-14-bayesian-logistic-regression-with-stan/">previous blog post - ‘<em>Bayesian Logistic Regression with Stan</em>’</a>, but don’t worry - the focus here is all about <em>Partial Pooling</em>.</p>
<p>First let’s look at a non-Bayesian base case. <a href="https://statsbomb.com/">StatsBomb</a> have kindly made lots of football data freely available in <a href="https://github.com/statsbomb/StatsBombR">their R package</a>. The below creates a dataframe of the shots taken by Arsenal FC during the <code>2003</code>-<code>04</code> Premier League winning season.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(StatsBombR); <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidyverse)</span>
<span id="cb1-2"></span>
<span id="cb1-3">Prem_SB_matches <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">FreeMatches</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Competitions =</span> SB_comps <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-4">                               dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(competition_name <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Premier League'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-5">                               dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(competition_gender <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'male'</span>))</span>
<span id="cb1-6"></span>
<span id="cb1-7">Arsenal_0304_shots <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">StatsBombFreeEvents</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">MatchesDF =</span> Prem_SB_matches, </span>
<span id="cb1-8">                                          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Parallel =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">allclean</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-10">  dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(type.name <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Shot'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-11">  dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(possession_team.name <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Arsenal'</span>)</span></code></pre></div>
</div>
<p>Using <code>R</code>’s <code>tidymodels</code> framework - make sure to have a look at <a href="https://www.youtube.com/channel/UCTTBgWyJl2HrrhQOOc710kA">Julia Silge’s tutorials</a> if you are unfamiliar - we can specify and fit a logistic regression. The below compares our results (including confidence intervals) to those from StatsBomb.</p>
<p>If you are interested in creating something similar yourself, this model has standardised inputs for parameters with relatively large values (such as angles and distances) and one hot encoding of categorical inputs (such as whether or not the shot was taken with a players weaker foot).</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt2/index_files/figure-html/unnamed-chunk-4-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Since we have used StatsBomb data (though their model will no doubt be based on a much larger collection) we would expect our results to be similar to theirs, and they are. Considering just the point estimates, the two models appear to broadly agree, especially when both are predicting a very low or a very high xG.</p>
<p>However, some of the confidence intervals on our <code>tidymodels</code> predictions are very large. Although we would generally expect these to decrease as we introduced more data, we know that football matches (and especially specific events within football matches) are full of uncertainty. If we want to be able to quantify this uncertainty in a more useful way (we do) - we want a Bayesian model. The below section details the specific type of Bayesian model that I’m proposing for estimating xG.</p>
</section>
<section id="multi-level-partial-pooling-models" class="level3">
<h3 class="anchored" data-anchor-id="multi-level-partial-pooling-models">Multi-Level (Partial Pooling) Models</h3>
<p>Hierarchical (or ‘nested’) data contains multiple groups within a population, such as players with a football team. Unfortunately, this information is lost (and bias is introduced) when such data is modelled as a single population. At the other extreme we can assume each group is fully independent, and the difficulty here is that there will be less data available and therefore more variance in our predictions.</p>
<p>Consequently, we want an intermediate solution, acknowledging variation between groups, but allowing for data from one group to inform predictions about others. This is achieved by using a multi-level (or hierarchical) model structure. Such models allow partial sharing (or <em>pooling</em>) of information between groups, to the extent that the data indicate is appropriate. This approach results in reduced variance (when compared to a set of corresponding independent models), a shift towards a population mean (known as <em>shrinkage</em>), and generally an improved predictive performance.</p>
<p>Sounds great, right? So why would anyone ever not use this kind of model? In his <a href="https://elevanth.org/blog/2017/08/24/multilevel-regression-as-default/">excellent blog</a>, Richard McElreath makes the case that multi-level models should be our default approach. His greatest criticism of them is that they require some experience or training to specify and interpret. <a href="https://xcelab.net/rm/statistical-rethinking/">His book</a> has a dedicated chapter to help with that. Of course, there are many better descriptions of multi-level modelling than you will get from me, but I personally found the examples in <a href="http://www.stat.columbia.edu/~gelman/arm/">Andrew Gelman and Jennifer Hill’s book</a> to be very helpful. Finally, <a href="https://betanalpha.github.io/assets/case_studies/hierarchical_modeling.html">Michael Betancourt has written a much more comprehensive blog post on the topic</a>, which includes a discussion on the underlying assumption of <em>exchangeability</em>.</p>
<p>We can create a partial pooling model by re-writing the below:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AxG%20=%20Inverse%20%5C;%20Logit(%5Calpha%20+%20%5Cbeta%20%5Ccdot%20X)%0A"></p>
<p>To look like this:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AxG%20=%20Inverse%20%5C;%20Logit(%5Calpha_%7B%5BPlayer%5D%7D%20+%20%5Cbeta_%7B%5BPlayer%5D%7D%20%5Ccdot%20X)%0A"></p>
<p>In this new structure, each parameter will now be a vector of length <img src="https://latex.codecogs.com/png.latex?N"> (where <img src="https://latex.codecogs.com/png.latex?N"> players are being considered). This means there will be a different co-efficient describing how <img src="https://latex.codecogs.com/png.latex?xG"> varies with distance from goal for each player. This makes sense as we would expect variation between players and we want our model to be able to describe it.</p>
<p>If each of these parameters had their own priors, we would essentially have specified <img src="https://latex.codecogs.com/png.latex?N"> independent models - one for each player. But there is a twist here: each of the vectors of co-efficients share a single prior.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbeta%20%5Csim%20N(%5Cmu_%7B%5Cbeta%7D,%20%5C;%20%5Csigma_%7B%5Cbeta%7D)%0A"></p>
<p>This will pull each of the individual co-efficients towards a shared mean, <img src="https://latex.codecogs.com/png.latex?%5Cmu_%7B%5Cbeta%7D">. The variation between the players (for a given parameter) is characterised by <img src="https://latex.codecogs.com/png.latex?%5Csigma_%7B%5Cbeta%7D">. Rather than specify these ourselves, we will also estimate these as part of the model. This means that the extent of the pooling is conditional on the data, which is an extremely useful feature. However, we then need to include priors on these parameters, which are known as <em>hyperpriors</em>.</p>
<p>Note that this process has introduced an extra layer (or level) to the model structure. This is why they are known as <em>multi-level</em> or <em>hierarchical</em> models. The term <em>partial pooling</em> is more a description of what they do.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/nXvirfLCf99rG/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>In the Absence of Multi-Level Models</figcaption>
</figure>
</div>
<p>We see the greatest benefit of this approach when only limited data is available for one or more groups. If one player took very few shots during a period of data collection, then there will be a lot of uncertainty in their xG predictions ….<em>unless</em> we can make use of the data we have for the rest of the team.</p>
</section>
<section id="what-does-this-look-like-in-stan" class="level3">
<h3 class="anchored" data-anchor-id="what-does-this-look-like-in-stan">What does this look like in <code>Stan</code>?</h3>
<p>The below is a reduced <code>Stan</code> model, with just one co-efficient (concerning the distance from goal of the shot). This is not me being secretive, its just that the full model is quite large. You can simply add more parameters like a multi-variate linear regression on the log-odds scale, but remember that they will each require priors, hyperpriors, and data.</p>
<div class="cell" data-output.var="xG_model_reduced">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode stan code-with-copy"><code class="sourceCode stan"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">data</span> {</span>
<span id="cb2-2"></span>
<span id="cb2-3">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> &lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>&gt; n_shots;</span>
<span id="cb2-4">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> &lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">upper</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>&gt; goal [n_shots];</span>
<span id="cb2-5">  </span>
<span id="cb2-6">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> &lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>&gt; n_players;</span>
<span id="cb2-7">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> &lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>&gt; player_id [n_shots];</span>
<span id="cb2-8">  </span>
<span id="cb2-9">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">vector</span> [n_shots] dist_goal;</span>
<span id="cb2-10"></span>
<span id="cb2-11">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> mu_mu_alpha;</span>
<span id="cb2-12">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> &lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>&gt; sigma_mu_alpha;</span>
<span id="cb2-13">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span>&lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>&gt; rate_sigma_alpha;</span>
<span id="cb2-14">  </span>
<span id="cb2-15">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> mu_mu_beta_dist_goal;</span>
<span id="cb2-16">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> &lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>&gt; sigma_mu_beta_dist_goal;</span>
<span id="cb2-17">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span>&lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>&gt; rate_sigma_beta_dist_goal;</span>
<span id="cb2-18">  </span>
<span id="cb2-19">}</span>
<span id="cb2-20"></span>
<span id="cb2-21"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">parameters</span> {</span>
<span id="cb2-22">  </span>
<span id="cb2-23">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">vector</span> [n_players] alpha;</span>
<span id="cb2-24">  </span>
<span id="cb2-25">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">vector</span> [n_players] beta_dist_goal;</span>
<span id="cb2-26"></span>
<span id="cb2-27">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> mu_alpha;</span>
<span id="cb2-28">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> &lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>&gt; sigma_alpha;</span>
<span id="cb2-29">  </span>
<span id="cb2-30">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> mu_beta_dist_goal;</span>
<span id="cb2-31">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> &lt;<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lower</span> = <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>&gt; sigma_beta_dist_goal;</span>
<span id="cb2-32">  </span>
<span id="cb2-33">}</span>
<span id="cb2-34"></span>
<span id="cb2-35"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">model</span> {</span>
<span id="cb2-36"></span>
<span id="cb2-37">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Logistic model </span></span>
<span id="cb2-38">  </span>
<span id="cb2-39">  goal ~ bernoulli_logit(alpha[player_id] + beta_dist_goal[player_id] .* dist_goal); </span>
<span id="cb2-40"></span>
<span id="cb2-41">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Priors </span></span>
<span id="cb2-42">  </span>
<span id="cb2-43">  alpha ~ normal(mu_alpha, sigma_alpha);</span>
<span id="cb2-44">  beta_dist_goal ~ normal(mu_beta_dist_goal, sigma_beta_dist_goal);</span>
<span id="cb2-45"></span>
<span id="cb2-46">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Hyperpriors</span></span>
<span id="cb2-47">  </span>
<span id="cb2-48">  mu_alpha ~ normal(mu_mu_alpha, sigma_mu_alpha);</span>
<span id="cb2-49">  sigma_alpha ~ exponential(rate_sigma_alpha);</span>
<span id="cb2-50">  </span>
<span id="cb2-51">  mu_beta_dist_goal ~ normal(mu_mu_beta_dist_goal, sigma_mu_beta_dist_goal);</span>
<span id="cb2-52">  sigma_beta_dist_goal ~ exponential(rate_sigma_beta_dist_goal);</span>
<span id="cb2-53">  </span>
<span id="cb2-54">}</span>
<span id="cb2-55"></span>
<span id="cb2-56"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">generated quantities</span> {</span>
<span id="cb2-57">  </span>
<span id="cb2-58">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> alpha_pp = normal_rng(mu_alpha, sigma_alpha);</span>
<span id="cb2-59">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">real</span> beta_dist_goal_pp = normal_rng(mu_beta_dist_goal, sigma_beta_dist_goal);</span>
<span id="cb2-60"></span>
<span id="cb2-61">}</span></code></pre></div>
</div>
<p>A few things that I’d like to note:</p>
<ul>
<li>My input data is of length <code>n_shots</code> and my parameters are vectors of length <code>n_players</code>.</li>
<li>I’ve included my hyperpriors (the <code>mu_mu_...</code>, <code>sigma_mu...</code>, and <code>rate_sigma...</code> terms) as data, rather than <em>hard code</em> values into the file. This is so I can re-run the model with new hyperpriors without <code>Stan</code> needing to recompile.</li>
<li>Even though I have included the <code>mu...</code> and <code>sigma..</code> terms as priors in my comment, this is just to help describe the model structure. They are all included in the Parameters block of the model. As discussed above, they are inferred as part of the joint posterior distribution, meaning that we are estimating the extent of the pooling from the data.</li>
<li>I’m using the generated quantities to produce my population-level parameters, so that I have everything I need to put together probabilistic predictions in either <code>R</code> or <code>Python</code>.</li>
</ul>
<p>#### Model Parameters</p>
<p>The posterior distribution (which <code>Stan</code> has sampled from) is a joint probabilistic model of all parameters. Let’s have a look at a few, specifically those corresponding to the effect of distance between the shot taker and goalkeeper. Shown below is the co-efficient for <img src="https://latex.codecogs.com/png.latex?6"> players (indexed <img src="https://latex.codecogs.com/png.latex?1%20%5Crightarrow%206">). We can see that the distance to the keeper is predicted to influence each player differently.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt2/index_files/figure-html/unnamed-chunk-6-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Some of the players will have taken fewer shots and therefore we will have less data to fit their player-specific parameters. The <code>mu_beta_dist_keeper</code> and <code>sigma_beta_dist_keeper</code> parameters in the above plot are the shared ‘<em>priors</em>’ that control how the data from each of the players can be used to inform one another. The <code>beta_dist_keeper_pp</code> parameter is specified in the generated quantities block of my <code>Stan</code> model. It is correlated samples from the distribution characterised by the shared priors. This becomes the population (team) level co-efficient in my predictions.</p>
<p>I’ve included some predictions for some actual shots taken that season in <a href="https://allyourbayes.com/posts/xg_pt1/">part 1</a> of this article, but since this is the purpose of the model let’s look at one more.</p>
<p>Here is Robert Pirès goal from just outside the box at home to Bolton Wanderers in 2004. It was on his stronger (right) foot and he was not under pressure from any defenders.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt2/index_files/figure-html/unnamed-chunk-7-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>As labelled on the above plot, the StatsBomb model only gave Pirès a 5% chance of scoring this chance. The below xG predictions are from the Bayesian partial pooling model, both for Robert Pirès (upper) and for the case where any Arsenal player could be shooting (lower). Also shown is the StatsBomb prediction. We see an improvement (since we know this chance was scored) when we make a player-specific prediction.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt2/index_files/figure-html/unnamed-chunk-8-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Our probabilistic predictions contain more information than point estimates, but for the purposes of a simpler comparison we can consider the mean value. The mean value of our team-level prediction is 20%, but conditional on the knowledge that Pirès was shooting, this becomes 33%.</p>
<p>If Arsène Wenger could’ve chosen which of his players was presented with this opportunity, Robert Pirès would’ve been one of his top choices (though possible behind Thierry Henry). We have an intuitive understanding that such players have the necessary attributes to score from relatively difficult opportunities such as this, and this is accounted for in our model. We have tackled the challenge of greatly reduced (player-specific) datasets, by allowing them to share information on the basis of how similar they are.</p>
</section>
<section id="challenges" class="level3">
<h3 class="anchored" data-anchor-id="challenges">Challenges</h3>
<p>Multi-level models capture the multi-level structure of hierarchical (nested) datasets, accounting for both variability and commonality between different groups (in this example: between different players in a team). However, as we can see from the previous plot, by introducing a set of parameters for each group and relating them all in this way, the posterior distribution now has many more dimensions and is more challenging to sample from. If you are using <code>Stan</code> you may now see more warning messages regarding <em>divergent transitions</em> - a concept that José Mourinho is acting out, below. If you do run into these problems, I would recommend reviewing the <a href="https://mc-stan.org/docs/2_25/stan-users-guide/reparameterization-section.html">guidance in the Stan manual on reparameterisation</a> (writing your same model on a new scale, such that it is easier for the software to work with).</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/140EFtM0NCyjHq/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Mou’s Divergent Transitions</figcaption>
</figure>
</div>
<p>Finally, I have published a paper demonstrating this modelling approach in an engineering context, which includes additional details for anyone who is interested: <a href="https://www.sciencedirect.com/science/article/abs/pii/S0951832020306189?via=ihub">‘Consistent and coherent treatment of uncertainties and dependencies in fatigue crack growth calculations using multi-level Bayesian models’</a>.</p>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2021,
  author = {Di Francesco, Domenic},
  title = {Uncertainty in {xG.} {Part} 2},
  date = {2021-01-07},
  url = {https://allyourbayes.com/posts/xg_pt2/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2021" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2021. <span>“Uncertainty in xG. Part 2.”</span>
January 7, 2021. <a href="https://allyourbayes.com/posts/xg_pt2/">https://allyourbayes.com/posts/xg_pt2/</a>.
</div></div></section></div> ]]></description>
  <category>football</category>
  <category>analysis</category>
  <category>xg</category>
  <category>Stan</category>
  <category>uncertainty</category>
  <category>Bayes</category>
  <category>multi-level modelling</category>
  <category>partial pooling</category>
  <guid>https://allyourbayes.com/posts/xg_pt2/</guid>
  <pubDate>Thu, 07 Jan 2021 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/xg_pt2/xg2.png" medium="image" type="image/png" height="104" width="144"/>
</item>
<item>
  <title>Uncertainty in xG. Part 1: Overview</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/xg_pt1/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>The Expected Goals (xG) metric is now widely recognised as numerical measure of the <em>quality</em> of a goal scoring opportunity in a football (soccer) match. In this article we consider how to deal with uncertainty in predicting xG, and how each players individual abilities can be accounted for. This is part 1 of the article, which is intended to be free of stats jargon, maths and code. If you are interested in those details, you can also check out <a href="https://allyourbayes.com/posts/xg_pt2/">part 2</a>.</p>
<hr>
</section>
<section id="what-are-expected-goals" class="level3">
<h3 class="anchored" data-anchor-id="what-are-expected-goals">What are Expected Goals?</h3>
<p><a href="https://www.optasports.com/services/analytics/advanced-metrics/#:~:text=Expected%20goals%20(xG)%20measures%20the,defined%20as%20a%20big%20chance.">Opta sports</a> tell us that the <em>Expected Goals</em> (or <strong>xG</strong>) of a shot describe how likely it is to be scored. The cumulative xG over a game will therefore give an indication of how many goals a team would usually score, based on the chances they created.</p>
<p>Why would anyone be interested in this? Because if the xG model is any good, it can be the basis for an evidence-based style of play. If certain individuals in a team enjoy shooting from long-distance (or any other set of circumstances associated with a low xG), they may be encouraged to keep possession until a more favourable (higher xG) chance arises.</p>
<p>There is no universally accepted way of calculating xG, so there are many competing models around. In this article I will describe a statistical model that cares about who is taking the shot, but does not treat each player as a separate independent case. More on this later…</p>
</section>
<section id="data-arsenals-invincibles-courtesy-of-statsbomb" class="level3">
<h3 class="anchored" data-anchor-id="data-arsenals-invincibles-courtesy-of-statsbomb">Data: Arsenal’s Invincibles (Courtesy of StatsBomb)</h3>
<p>Once upon a time (in the <code>2003</code>-<code>04</code> season), Arsenal FC were brilliant. That squad is still referred to as <em>the Invincibles</em> after finishing the season without a defeat in the league, scoring the most goals and conceding the fewest. Their top scorer, <a href="https://en.wikipedia.org/wiki/Thierry_Henry">Thierry Henry</a>, finished 4th in the Ballon d’Or voting this season (having finished 2nd the season before). Unfortunately José Mourinho arrived at Chelsea the following season and Arsenal haven’t won the league since.</p>
<p>I’m using Arsenal’s unbeaten league season as an example because <a href="https://statsbomb.com/">StatsBomb</a> have kindly made all this data freely available in <a href="https://github.com/statsbomb/StatsBombR">their R package</a>.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/uBxP06JlaB7VCIaYXm/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>The Invincibles</figcaption>
</figure>
</div>
<p>Here are their league goal scorers:</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt1/index_files/figure-html/unnamed-chunk-3-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>And here’s where the goals were scored from:</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt1/index_files/figure-html/unnamed-chunk-4-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>The above plot shows that many of these goals were scored, even though the (StatsBomb) xG was relatively low. In fact the mean xG of the shots they scored was 0.33. This isn’t necessarily a problem as we do see improbable goals. Below is Giorgian De Arrascaeta’s contender for the 2020 FIFA Puskas award. Was anyone expecting him to score this chance? Could he do it again?</p>
<div class="quarto-video ratio ratio-16x9"><iframe data-external="1" src="https://www.youtube.com/embed/3icTC--cHfA" title="Arrascaeta's nominated goal for the 2020 FIFA Puskas award" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div>
<p>An ideal xG model would correctly predict every goal without error, but the many sources of variability in the game means that this isn’t happening any time soon. A <strong>Bayesian</strong> model (such as the one I’m proposing) will include uncertainty in it’s predictions, letting us know when it can narrow down a predicted xG, and when there is a larger range of credible values based on the available information.</p>
</section>
<section id="would-henry-have-scored-it" class="level3">
<h3 class="anchored" data-anchor-id="would-henry-have-scored-it">Would Henry have scored it?</h3>
<p>Another feature that I’ve introduced to the model is the relationship between the data from different players. I want the model to distinguish between whether a team creates an opportunity for their top scorer, or their full-back who has never scored. One is clearly preferable, and should have a higher xG to reflect this. Why would this matter? Shooting from wide positions may (on average) be unlikely to pay off, but if your team has a winger who is especially adept at it, then it may be a strategy they should pursue.</p>
<p>For instance, Giorgian De Arrascaeta may have had a higher chance of scoring that bicycle kick when you consider that he was also nominated for the 2018 FIFA Puskas award for scoring another acrobatic volley.</p>
<p>The practical issue with considering each player separately is you now have many, smaller datasets. Larger datasets contain more information allowing for model parameters to be estimated more precisely. This sometimes encourages us to throw all our data into a single population and pretend we have a larger dataset. Your software will be happy, since it won’t know the difference, but you will lose the valuable player-specific information.</p>
<p>Bayesian models can do even better than this though. Consider some data that was collected from Arsenal’s defensive midfielder, <a href="https://en.wikipedia.org/wiki/Gilberto_Silva">Gilberto Silva</a>. He scored 3 league goals in their invincible season, but his primary duties were defensive. He had different characteristics than Thierry Henry, but there is some commonality to take advantage of here. If Gilberto Silva scores an opportunity that gives me <em>some</em> information about whether Thierry Henry could have scored it too. How much information? That depends on how similar they are. Unless we tell the model, it will assume we cannot learn anything about these players from the other. Both were professional footballers. Neither was a hockey player, or a tree, or a kitten - though a statistical model could not intuit this. If the data did indicate that they were in fact very different players, then the special model structure that we are using would recognise this and not share information between them to the same extent.</p>
<p>If the above concept make sense to you, then congratulations - you appreciate the utility of multi-level (partial-pooling) Bayesian models. This <em>sharing of information</em> is one of many reasons Bayesian methods can perform so well on small (and imperfect) datasets.</p>
</section>
<section id="what-does-the-model-do" class="level3">
<h3 class="anchored" data-anchor-id="what-does-the-model-do">What does the Model do?</h3>
<p>We have a model that describes uncertainty (using probability) and makes both team-level and player-specific predictions. Here are some examples:</p>
<p>How about <a href="https://en.wikipedia.org/wiki/Dennis_Bergkamp">Dennis Bergkamp’s</a> dinked finish when clear through on goal against Birmingham. Remember it? Me neither - here’s where the shot was taken from:</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt1/index_files/figure-html/unnamed-chunk-6-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>And our predicted xG is shown below, both for Dennis Bergkamp (upper) and for the case where any Arsenal player could be shooting (lower). Here is a great example of being able to make a better prediction conditional on the information of who is taking the shot. The model has identified that Bergkamp was very capable of scoring these kind of chances and was therefore able to identify a narrow range of very high xG values. However, if we were considering a generic player in the Arsenal team, there is more uncertainty in our prediction.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt1/index_files/figure-html/unnamed-chunk-7-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>What about Thierry Henry’s long range goal against Man Utd? (Note that the straight arrow in the below plot does not reflect the true trajectory of his shot).</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt1/index_files/figure-html/unnamed-chunk-8-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt1/index_files/figure-html/unnamed-chunk-9-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>OK, so I wouldn’t have seen that one coming either ….but I would have given it more of a chance knowing who was shooting.</p>
<p>Here is a final example - a shot from Gilberto Silva, on his stronger foot, which was saved by Neil Sullivan (who I’d completely forgotten had <a href="http://news.bbc.co.uk/sport1/hi/football/teams/c/chelsea/3190149.stm">signed for Chelsea that season</a>). I thought this was worth looking at because StatsBomb’s xG suggests this was a very good chance.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt1/index_files/figure-html/unnamed-chunk-10-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Our model did not expect him to score, and also predicted that <a href="https://en.wikipedia.org/wiki/Freddie_Ljungberg">Freddie Ljungberg</a> would have missed. Henry (unsurprisingly) is expected to have had a better chance, but <strong>interestingly</strong>, our model thinks that Arsenal’s goalscoring winger <a href="https://en.wikipedia.org/wiki/Robert_Pires">Robert Pirès</a> would have been most likely to score this opportunity.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/xg_pt1/index_files/figure-html/unnamed-chunk-11-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="final-thought-making-sense-of-probabilistic-predictions" class="level3">
<h3 class="anchored" data-anchor-id="final-thought-making-sense-of-probabilistic-predictions">Final Thought: Making Sense of Probabilistic Predictions</h3>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/e78UID432cQGA/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Thoughtful Pirlo</figcaption>
</figure>
</div>
<p>What should we make of the above predictions? The single values (<em>point estimates</em>) provided by analytics companies may be a bit easier to read, but I’m suggesting that they are not as useful. We should want our models to tell us when they are not sure. There is more information in a probabilistic prediction than a point estimate, which means you can go from the former to the latter, but not vice-versa. The type of model we have discussed in this article has the added benefit of sharing information between different players in a mathematically coherent way (see <a href="https://allyourbayes.com/posts/xg_pt2/">part 2</a>) for the technical details).</p>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2020,
  author = {Di Francesco, Domenic},
  title = {Uncertainty in {xG.} {Part} 1},
  date = {2020-12-10},
  url = {https://allyourbayes.com/posts/xg_pt1/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2020" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2020. <span>“Uncertainty in xG. Part 1.”</span>
December 10, 2020. <a href="https://allyourbayes.com/posts/xg_pt1/">https://allyourbayes.com/posts/xg_pt1/</a>.
</div></div></section></div> ]]></description>
  <category>football</category>
  <category>analysis</category>
  <category>xg</category>
  <category>Stan</category>
  <category>uncertainty</category>
  <category>Bayes</category>
  <category>multi-level modelling</category>
  <category>partial pooling</category>
  <guid>https://allyourbayes.com/posts/xg_pt1/</guid>
  <pubDate>Thu, 10 Dec 2020 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/xg_pt1/xg1.png" medium="image" type="image/png" height="99" width="144"/>
</item>
<item>
  <title>Why be Bayesian?</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/Why_Bayes/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>This post is intended to be a high-level discussion of the merits and challenges of applied Bayesian statistics. It is intended to help the reader answer: <em>Is it worth me learning Bayesian statistics?</em> or <em>Should I look into using Bayesian statistics in my project?</em> No maths or code in this post.</p>
<hr>
<section id="bayes" class="level4">
<h4 class="anchored" data-anchor-id="bayes">Bayes</h4>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/TJBbXQooivUNq/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Bayes</figcaption>
</figure>
</div>
</section>
</section>
<section id="introduction" class="level3">
<h3 class="anchored" data-anchor-id="introduction">Introduction</h3>
<p>Firstly, Bayesian…</p>
<ul>
<li>Statistics</li>
<li>Inference</li>
<li>Modelling</li>
<li>Updating</li>
<li>Data Analysis</li>
</ul>
<p>…can boradly be considered the same thing (certainly for the purposes of this post): <strong>the application of Bayes theorem to quantify uncertainty</strong>.</p>
<p>Depending on your background, you may have preconceptions about Bayesian methods being specialist or complicated. However, analysts and researchers in many domains are increasingly experimenting with the growing catalogue of open source software and resources that is making probabilistic programming more accessible.</p>
</section>
<section id="what-does-a-bayesian-approach-provide" class="level3">
<h3 class="anchored" data-anchor-id="what-does-a-bayesian-approach-provide">What does a Bayesian approach provide?</h3>
<p>Bayesian statistics is not the only way to account for uncertainty in calculations. The below points describe what a Bayesian approach offers, that others don’t. Note that I am only really discussing methods involving probability here, though <a href="https://www.springer.com/gp/book/9783540402947">alternative approaches are available</a>.</p>
<section id="intuitive-interpretation-of-results" class="level4">
<h4 class="anchored" data-anchor-id="intuitive-interpretation-of-results">Intuitive Interpretation of Results</h4>
<p>Bayesian methods give you distributions. Your parameters (and so also your predictions) are all described as distributions. A single, joint distribution in fact, which is aligned with the evidence that you provide your model. This allows you to propagate all the uncertainties and inter-dependencies when making predictions for some new input data. By comparison, alternative (frequentist) methods typically describes uncertainty in predictions using confidence intervals, which are widely used but easy to misinterpret.</p>
<p>Confidence intervals are calculated so that they will contain the <em>true</em> value of whatever you are trying to predict with some desired frequency. They provide no information (in the absence of additional assumptions) on how credible various possible results are. The Bayesian equivalent (sometimes called credible intervals) can be drawn anywhere on a predictive distribution. In <a href="https://mitpress.mit.edu/books/introduction-statistical-decision-theory">Pratt, Raiffa and Schlaiffer’s textbook</a> an example is used to highlight this difference:</p>
<p><em>Imagine the plight of the manager who exclaims, ‘I understand [does he?] the meaning that the demand for XYZ will lie in the interval 973 to 1374 with confidence .90. However, I am particularly interested in the interval 1300 to 1500. What confidence can I place on that interval?’</em> <em>Unfortunately, this question cannot be answered. Of course, however, it is possible to give a posterior probability to that particular interval - or any other - based on the sample data and on a codification of the manager’s prior judgements.</em></p>
<p>This is a nice example (aside from assuming the manager is a male) of a simple question that we need a Bayesian posterior distribution to answer. A more succinct description of the same view from <a href="https://www.weirdfishes.blog/">Dan Ovando’s fishery statistics blog</a>:</p>
<p><em>Bayesian credible intervals mean what we’d like Frequentist confidence intervals to mean.</em></p>
</section>
<section id="seamless-integration-with-decision-analysis" class="level4">
<h4 class="anchored" data-anchor-id="seamless-integration-with-decision-analysis">Seamless Integration with Decision Analysis</h4>
<p>Following on from the previous point, an analysis that directly describes the probability of any outcome is fully compatible with a decision analysis. After completing a Bayesian analysis, identifying the optimal strategy implied by your model becomes simpler and more understandable.</p>
<p>As stated in <a href="https://www.springer.com/gp/book/9780387960982">James Berger’s (quite theoretical) book on Bayesian statistics</a>:</p>
<p><em>Bayesian analysis and decision theory go rather naturally together, partly because of their common goal of utilizing non-experimental sources of information, and partly because of deep theoretical ties.</em></p>
</section>
<section id="flexible-modelling" class="level4">
<h4 class="anchored" data-anchor-id="flexible-modelling">Flexible Modelling</h4>
<p>So this one is based on a point made in <a href="https://uk.sagepub.com/en-gb/eur/a-student%E2%80%99s-guide-to-bayesian-statistics/book245409">Ben Lambert’s book on Bayesian statistics</a>. It is regarding how modern Bayesian statistics is achieved in practice. The computational methods may require some effort to pick up, especially if you do not have experience with programming (though Ben’s book gives a nice introduction to <a href="https://mc-stan.org/">Stan</a>). However, they can be readily extended to larger and more complex models.</p>
<p>Essentially, we can propose weird and bespoke model structures, and then use the same approach to fit them.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/WiyczarN2XMm4/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Some Compelling Arguments</figcaption>
</figure>
</div>
</section>
</section>
<section id="challenges-difficulties" class="level3">
<h3 class="anchored" data-anchor-id="challenges-difficulties">Challenges &amp; Difficulties</h3>
<p>So why would anyone ever <em>not</em> use Bayesian models when making predictions?</p>
<section id="subjectivity" class="level4">
<h4 class="anchored" data-anchor-id="subjectivity">Subjectivity</h4>
<p>Perhaps the most common criticism of Bayesian statistics is the requirement for priors - i.e.&nbsp;a starting point for your model. This initial estimate of uncertainty is a term in Bayes’ theorem - but how can you estimate the extent of variability before you see it in your data? This will surely be completely subjective, so the results will vary depending on who is doing the analysis. This, understandably, doesn’t seem right with a lot of casual enquirers.</p>
<p>A common response to this accusation is that subjectivity is not an exclusive feature of Bayesian analysis (how about the whole approach you are taking to solving your problem !) <em>…but</em> at least Bayesians are required to be explicit about it. Priors mean that any subjective inputs have no-where to hide (in the code or the reporting) and so they are open to criticism. This point is discussed in <strong>much</strong> more detail in this paper from <a href="http://www.stat.columbia.edu/~gelman/research/published/gelman_hennig_full_discussion.pdf">Colombia University</a>.</p>
<p>Priors can contain, as much or as little, information as desired. However, even in instances where you may feel you don’t have any upfront knowledge of a problem, they represent a valuable opportunity for introducing regularisation (which protects against bad predictions due to overfitting). This idea is discussed in detail in <a href="https://www.crcpress.com/Statistical-Rethinking-A-Bayesian-Course-with-Examples-in-R-and-STAN/McElreath/p/book/9780367139919">Richard McElreath’s textbook</a>. I would suggest that in plenty of cases, we often have a fair idea of what is happening even before we collect and analyse data, and starting from zero everytime is just not sensible. Will a doctor who has just evaluated you base their diagnosis entirely on a test outcome, or will they incorporate that eveidence into their existing understanding of your circumstances and symptoms? Bayesian statistics is the means by which this can be done mathematically.</p>
</section>
<section id="computational-requirements" class="level4">
<h4 class="anchored" data-anchor-id="computational-requirements">Computational Requirements</h4>
<p>In practice, statisticians estimate Bayesian posterior distributions using very clever Markov Chain Monte Carlo (MCMC) sampling algorithms, that are run by their favourite probabilistic programming software. The models that I have worked with during my PhD have taken several hours to finish sampling from, but I have met statisticians whose models run for days or even weeks. Following this, there are checks that need to be completed as there are plenty of things that can go wrong with MCMC. There is a nice discussion of a recommended Bayesian workflow to make sure you are checking what you need to <a href="https://arxiv.org/abs/2011.01808">here</a>.</p>
<p>My background is in mechanical and civil engineering. In discussions with engineering researchers at conferences I have often been told that the errors and complications they encountered when playing around with Bayesian software caused them to abandon the approach in favour of more established, less informative analysis. These are challenges that I imagine everyone who has attempted modern Bayesian statistics will have encountered and resolving them can require a deep understanding of your model, and perhaps some formal training. In addition some programming <em>tricks</em> like reparameterisation (describing your model in a seemingly equivalent way, but one that is much friendlier to your software) can also help.</p>
</section>
</section>
<section id="conclusions" class="level3">
<h3 class="anchored" data-anchor-id="conclusions">Conclusions</h3>
<p>Regardless of whether you believe we exist in a deterministic universe or not, you will never have perfect state of knowledge describing your problem: uncertainty exists, so we need a sensible and safe way of accounting for it. It’s difficult to escape the implications of the Maths - for instance, in avoiding quantifying uncertainty, we are often making some implicit assumptions (the implications of which can be difficult to justify) that we may not want to propagate into our decision-making. There is generally a trade-off for apparent conveniences.</p>
<p>I believe that Bayesian statistics is actually well suited to traditional engineering problems, which are concerned with managing risk when confronted with small, messy datasets and models with plenty of uncertainty. As suggested in the earlier description of confidence intervals, frequentist statistics defines probability based on occurrences of events following a large number of trials or samples. When trying to understand the behaviour of small datasets (or even unique structural systems), Bayesian statistics can shine by comparison.</p>
<p>Very large datasets may contain enough information to precisely estimate parameters in a model using conventional machine learning methods, and so it becomes less worthwhile running simulations to characterise variability. But how common are these big data problems in science and engineering? Sometimes large populations of data are better described as multiple smaller constituent groups, after accounting for key differences between them. Bayesian statistics has a very useful way of managing such problems by structuring models hierarchically. This method allows for <strong>partial pooling of information</strong> between groups, so that predictions account for the variability and commonality between groups. I will provide a detailed example of this in a future post.</p>
<p>Bayesian inference requires (computational and personal) effort to apply. But it provides results that are generally more interpretable and closely related to the actual questions we want to answer. Whether or not these methods are worth learning will of course depend on personal circumstances. I encountered this field during my PhD, and so had plenty of time to read and play with them, which I appreicate is a privelidged position to be in.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/WPLPEu0GUp41W/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Boring, isn’t it? Writing, Fitting and Evaluating Bayesian Models All Day….</figcaption>
</figure>
</div>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2020,
  author = {Di Francesco, Domenic},
  title = {Why Be {Bayesian?}},
  date = {2020-03-24},
  url = {https://allyourbayes.com/posts/Why_Bayes/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2020" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2020. <span>“Why Be Bayesian?”</span> March 24,
2020. <a href="https://allyourbayes.com/posts/Why_Bayes/">https://allyourbayes.com/posts/Why_Bayes/</a>.
</div></div></section></div> ]]></description>
  <category>Bayes</category>
  <category>uncertainty</category>
  <category>decisions</category>
  <guid>https://allyourbayes.com/posts/Why_Bayes/</guid>
  <pubDate>Tue, 24 Mar 2020 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/Why_Bayes/gp.png" medium="image" type="image/png" height="84" width="144"/>
</item>
<item>
  <title>Bayesian Logistic Regression with Stan</title>
  <dc:creator>Domenic Di Francesco</dc:creator>
  <link>https://allyourbayes.com/posts/Logistic_Bayes/</link>
  <description><![CDATA[ 






<section id="tldr" class="level3">
<h3 class="anchored" data-anchor-id="tldr">TLDR</h3>
<p>Logistic regression is a popular statistical model for making predictions on outcomes between zero and one - like probabilities. One application of it in an engineering context is quantifying the effectiveness of inspection technologies at detecting damage. This post describes the additional information provided by a Bayesian application of logistic regression (and how it can be implemented using the <code>Stan</code> probabilistic programming language). I’ve also included some recommendations for giving your model a sensible starting point (using prior information).</p>
<hr>
</section>
<section id="introductions" class="level3">
<h3 class="anchored" data-anchor-id="introductions">Introductions</h3>
<p>So there are a couple of key topics discussed here: logistic regression, and Bayesian inference. Before jumping straight into the example application, I’ve provided some <strong>very</strong> brief introductions below.</p>
<section id="bayesian-inference" class="level4">
<h4 class="anchored" data-anchor-id="bayesian-inference">Bayesian Inference</h4>
<p>At a very high level, Bayesian models quantify uncertainty, so that our predictions and decisions take into account the ways in which our knowledge is limited or imperfect. We specify a statistical model, and identify probabilistic estimates for the parameters. My preferred software for writing a fitting Bayesian models is <a href="https://mc-stan.org/"><code>Stan</code></a>. If you are not yet familiar with Bayesian statistics, then I imagine you won’t be fully satisfied with that 3 sentence summary, so I will put together a separate post on the merits and challenges of applied Bayesian inference, which will include much more detail.</p>
</section>
<section id="logistic-regression" class="level4">
<h4 class="anchored" data-anchor-id="logistic-regression">Logistic Regression</h4>
<p>Logistic regression is used to estimate the probability of a binary outcome, such as <em>Pass</em> or <em>Fail</em> (though it can be extended for <code>&gt; 2</code> outcomes). This is achieved by transforming a standard regression using the logit function, shown below. The term in the brackets may be familiar to gamblers as it is how odds are calculated from probabilities (p). You may see <em>logit</em> and <em>log-odds</em> used exchangeably for this reason.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctextrm%7BLog%20odds%7D%20=%20%5Clog%5CBigg(%7B%5Cfrac%7Bp%7D%7B1%20-%20p%7D%7D%5CBigg)%0A"></p>
<p>Since the logit function transformed data <em>from</em> a probability scale, the inverse logit (or logistic) function transforms data <em>to</em> a probability scale. We can re-arrange this equation ourselves to see this:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cexp(%5Ctextrm%7BLog%20odds%7D)%20=%20%5CBigg(%7B%5Cfrac%7Bp%7D%7B1%20-%20p%7D%7D%5CBigg)%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cexp(%5Ctextrm%7BLog%20odds%7D)%20%5Ctimes%20(1%20-%20p)%20=%20p%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cexp(%5Ctextrm%7BLog%20odds%7D)%20-%20p%20%5Ctimes%20%5Cexp(%5Ctextrm%7BLog%20odds%7D)%20=%20p%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cexp(%5Ctextrm%7BLog%20odds%7D)%20=%20p%20+%20p%20%5Ctimes%20%5Cexp(%5Ctextrm%7BLog%20odds%7D)%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cexp(%5Ctextrm%7BLog%20odds%7D)%20=%20p%20(1%20+%20%5Cexp(%5Ctextrm%7BLog%20odds%7D))%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Cexp(%5Ctextrm%7BLog%20odds%7D)%7D%20%7B1%20+%20%5Cexp(%5Ctextrm%7BLog%20odds%7D)%7D%20=%20p%0A"></p>
<p>because multiplying by <img src="https://latex.codecogs.com/png.latex?%5Cexp(x)"> is the same as diviving by <img src="https://latex.codecogs.com/png.latex?%5Cexp(-x)">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B1%7D%20%7B%5Cexp(%5Ctextrm%7B-Log%20odds%7D)%20%5Ctimes%20(1%20+%20%5Cexp(%5Ctextrm%7BLog%20odds%7D))%7D%20=%20p%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B1%7D%20%7B%5Cexp(%5Ctextrm%7B-Log%20odds%7D)%20%20+%201%7D%20=%20p%0A"></p>
<p>As shown in the below plot, the values of this function range from <code>0</code> to <code>1</code>.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctextrm%7BInverse%20Logit%7D%20(x)%20=%20%5Cfrac%7B1%7D%7B1%20+%20%5Cexp(-x)%7D%0A"></p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/Logistic_Bayes/index_files/figure-html/unnamed-chunk-2-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>The reason we start with with log-odds is because we can define a linear model on this scale, with a gradient, <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> and an intercept <img src="https://latex.codecogs.com/png.latex?%5Calpha">, and then transform it to a prediction on the probability scale, using the above steps. When a linear regression is combined with a re-scaling function such as this, it is known as a Generalised Linear Model (<strong>GLM</strong>).</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctextrm%7BLog%20odds%7D%20=%20%5Calpha%20+%20%5Cbeta%20%5Ctimes%20%5Ctextrm%7Binput%20variables%7D%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap%20=%20%5Cfrac%7B1%7D%7B1%20+%20%5Cexp(-%5B%5Calpha%20+%20%5Cbeta%20%5Ctimes%20%5Ctextrm%7Binput%20variables%7D%5D)%7D%0A"></p>
<p>You may be familiar with libraries that automate the fitting of logistic regression models, either in <code>Python</code> (via <code>sklearn</code>):</p>
<div class="cell">
<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> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LogisticRegression</span>
<span id="cb1-2"></span>
<span id="cb1-3">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LogisticRegression()</span>
<span id="cb1-4">model.fit(X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'input_variables'</span>], y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'predictions'</span>])</span></code></pre></div>
</div>
<p>…or in <code>R</code>:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">model_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> preditions <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> input_variables,</span>
<span id="cb2-2">                 <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> dataset, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">binomial</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">link =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'logit'</span>))</span></code></pre></div>
</div>
</section>
</section>
<section id="example-application-probability-of-detection" class="level3">
<h3 class="anchored" data-anchor-id="example-application-probability-of-detection">Example Application: Probability of Detection</h3>
<p>To demonstrate how a Bayesian logistic regression model can be fit (and utilised), I’ve included an example from one of my papers. Engineers make use of data from inspections to understand the condition of structures. Modern inspection methods, whether remote, autonomous or manual application of sensor technologies, are very good. They are generally evaluated in terms of the accuracy and reliability with which they size damage. Engineers never receive perfect information from an inspection, such as:</p>
<ul>
<li>There is a crack of <strong>exact</strong> length <code>30 mm</code> and <strong>exact</strong> depth <code>5 mm</code> at this <strong>exact</strong> location, or</li>
<li>There is <strong>definitely</strong> no damage at this location.</li>
</ul>
<p>For various reasons, the information we receive from inspections is imperfect and this is something that engineers need to deal with. As a result, providers of inspection services should be requested to provide some measure of how good their product is. This typically includes some measure of how accurately damage is sized and how reliable an outcome (detection or no detection) is.</p>
<p>This example will consider trials of an inspection tool looking for damage of varying size, to fit a model that will predict the probability of detection for any size of damage. Since various forms of damage can initiate in structures, each requiring inspection methods that are suitable, let’s avoid ambiguity and imagine we are only looking for cracks.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/42wQXwITfQbDGKqUP7/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Detecting damage: never 100% reliable</figcaption>
</figure>
</div>
<section id="test-data" class="level4">
<h4 class="anchored" data-anchor-id="test-data">Test Data</h4>
<p>For the purposes of this example we will simulate some data. Let’s imagine we have introduced some cracks (of known size) into some test specimens and then arranged for some blind trials to test whether an inspection technology is able to detect them.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1008</span>)</span>
<span id="cb3-2"></span>
<span id="cb3-3">N <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>; lower <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>; upper <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>; alpha_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</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>; beta_true <span class="ot" style="color: #003B4F;
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-4"></span>
<span id="cb3-5">depth <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> N, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">min =</span> lower, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max =</span> upper)</span>
<span id="cb3-6"></span>
<span id="cb3-7">PoD_1D <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(depth, alpha_1D, beta_1D){</span>
<span id="cb3-8">  PoD <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">exp</span>(alpha_1D <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta_1D <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(depth)) <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="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">exp</span>(alpha_1D <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> beta_1D <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(depth)))</span>
<span id="cb3-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span> (PoD)</span>
<span id="cb3-10">}</span>
<span id="cb3-11"></span>
<span id="cb3-12">pod_df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">depth =</span> depth, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">det =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">double</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length =</span> N))</span>
<span id="cb3-13"></span>
<span id="cb3-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (i <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">from =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">to =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(pod_df), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)) {</span>
<span id="cb3-15">  </span>
<span id="cb3-16">  pod_df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>det[i] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rbernoulli</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, </span>
<span id="cb3-17">                             <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">p =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PoD_1D</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">depth =</span> pod_df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>depth[i], </span>
<span id="cb3-18">                                       <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha_1D =</span> alpha_true, </span>
<span id="cb3-19">                                       <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">beta_1D =</span> beta_true))</span>
<span id="cb3-20">  </span>
<span id="cb3-21">}</span></code></pre></div>
</div>
<p>The above code is used to create 30 crack sizes (depths) between 0 and 10 mm. We then use a log-odds model to back calculate a probability of detection for each. This is based on some fixed values for <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta">. In a real trial, these would not be known, but since we are inventing the data we can see how successful our model ends up being in estimating these values.</p>
<p>The below plot shows the size of each crack, and whether or not it was detected (in our simulation). The smallest crack that was detected was 2.22 mm deep, and the largest undetected crack was 5.69 mm deep. Even so, it’s already clear that larger cracks are more likely to be detected than smaller cracks, though that’s just about all we can say at this stage.</p>
<p>After fitting our model, we will be able to predict the probability of detection for a crack of any size.</p>
<div class="cell" data-ouput="false">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/Logistic_Bayes/index_files/figure-html/unnamed-chunk-6-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p><code>Stan</code> is a <a href="https://en.wikipedia.org/wiki/Probabilistic_programming">probabilistic programming language</a>. In a future post I will explain why it has been my preferred software for statistical inference throughout my PhD.</p>
<p>The below is a simple <code>Stan</code> program to fit a Bayesian Probability of Detection (PoD) model:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">PoD_model <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> cmdstanr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cmdstan_model</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stan_file =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PoD_model.stan'</span>)</span></code></pre></div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning in readLines(stan_file): incomplete final line found on
'PoD_model.stan'</code></pre>
</div>
<div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">PoD_model<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>()</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>data {

  int &lt;lower = 0&gt; N; // Defining the number of defects in the test dataset
  array [N] int &lt;lower = 0, upper = 1&gt; det; // A variable that describes whether each defect was detected (1) or not (0)
  vector &lt;lower = 0&gt; [N] depth; // A variable that describes the corresponding depth of each defect
  
  int &lt;lower = 0&gt; K; // Defining the number of probabilistic predictions required from the model
  vector &lt;lower = 0&gt; [K] depth_pred;
  
}

parameters {
  
  // The (unobserved) model parameters that we want to recover
  real alpha;
  real beta;
  
}

model {

  // A logistic regression model relating the defect depth to whether it will be detected
  det ~ bernoulli_logit(alpha + beta * log(depth));
  
  // Prior models for the unobserved parameters
  alpha ~ normal(0, 1);
  beta ~ normal(1, 1);

}

generated quantities {
  
  // Using the fitted model for probabilistic prediction.
  // K posterior predictive distributions will be estimated for a corresponding crack depth
  vector [K] postpred_pr;
  
  for (k in 1:K) {
    
    postpred_pr[k] = inv_logit(alpha + beta * log(depth_pred[k]));
    
  }
  
}</code></pre>
</div>
</div>
<p>The <code>generated quantities</code> block will be used to make predictions for the <code>K</code> values of <code>depth_pred</code> that we provide.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">K <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>; depth_pred <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">from =</span> lower, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">to =</span> upper, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length.out =</span> K)</span></code></pre></div>
</div>
<p>The above code generates 50 evenly spaced values, which we will eventually combine in a plot. In some instances we may have specific values that we want to generate probabilistic predictions for, and this can be achieved in the same way.</p>
</section>
<section id="fitting-the-model" class="level4">
<h4 class="anchored" data-anchor-id="fitting-the-model">Fitting the model</h4>
<p>Data can be pre-processed in any language for which a <code>Stan</code> interface has been developed. This includes, <code>R</code>, <code>Python</code>, and <code>Julia</code>. In this example we will use <code>R</code> and the accompanying package, <code>cmdstanr</code>.</p>
<p>Our <code>Stan</code> model is expecting data for three variables: <strong>N</strong>, <strong>det</strong>, <strong>depth</strong>, <strong>K</strong> and <strong>depth_pred</strong> and <code>cmdstanr</code> requires this in the form of a list.</p>
</section>
<section id="results" class="level4">
<h4 class="anchored" data-anchor-id="results">Results</h4>
<p>Once we have our data, and are happy with our model, we can set off the Markov chains. There are plenty of opportunities to control the way that the <code>Stan</code> algorithm will run, but I won’t include that here, rather we will mostly stick with the default arguments in <code>cmdstanr</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">PoD_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> PoD_model<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">N =</span> N, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">det =</span> pod_df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>det, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">depth =</span> pod_df<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>depth,</span>
<span id="cb9-2">                                        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">K =</span> K, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">depth_pred =</span> depth_pred), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2408</span>)</span></code></pre></div>
</div>
<p><strong>Note</strong>:I’ve not included any detail here on the checks we need to do on our samples. There are some common challenges associated with MCMC methods, each with plenty of associated guidance on how to diagnose and resolve them. For now, let’s assume everything has gone to plan.</p>
<p>Now, there are a few options for extracting samples from a stanfit object such as <code>PoD_samples</code>, including <code>cmdstanr::as_draws()</code>. However, these usually require a little post-processing to get them into a tidy format. There is a function in my <a href="https://github.com/DomDF/DomDF">DomDF R package</a> for this, which we can use to create a tidy output that specifies the iteration, parameter value and chain associated with each data point:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">PoD_samples <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> PoD_fit <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> DomDF<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tidy_mcmc_draws</span>()</span>
<span id="cb10-2"></span>
<span id="cb10-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> PoD_samples, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 5 × 4
  Parameter Chain Iteration value
  &lt;chr&gt;     &lt;int&gt;     &lt;int&gt; &lt;dbl&gt;
1 lp__          1         1 -15.6
2 lp__          1         2 -15.2
3 lp__          1         3 -15.5
4 lp__          1         4 -16.0
5 lp__          1         5 -16.2</code></pre>
</div>
</div>
<p>We have sampled from a 2-dimensional posterior distribution of the unobserved parameters in the model: <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta">. Below is a density plot of their corresponding marginal distributions based on the <code>1000</code> samples collected from each of the <code>4</code> Markov chains that have been run.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/Logistic_Bayes/index_files/figure-html/unnamed-chunk-12-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>So our estimates are beginning to converge on the values that were used to generate the data, but this plot also shows that there is still plenty of uncertainty in the results. Unlike many alternative approaches, Bayesian models account for the statistical uncertainty associated with our limited dataset - remember that we are estimating these values from 30 trials. These results describe the possible values of <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> in our model that are consistent with the limited available evidence. If more data was available, we could expect the uncertainty in our results to decrease. I think there are some great reasons to keep track of this statistical (sometimes called <em>epistemic</em>) uncertainty - a primary example being that we should be interested in how confident our predictive models are in their own results! …but I’ll leave it at that for now, and try to stay on topic.</p>
<p>How do we know what do these estimates of <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> mean for the PoD (what we are ultimately interested in)? We can check this using the posterior predictive distributions that we have (thanks to the <code>generated quantities</code> block of the <code>Stan</code> program).</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/Logistic_Bayes/index_files/figure-html/unnamed-chunk-13-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>One thing to note from these results is that the model is able to make much more confident predictions for larger crack sizes. The increased uncertainty associated with shallow cracks reflects the lack of data available in this region - this could be useful information for a decision maker!</p>
<p>There are only 3 trials in our dataset considering cracks shallower than 3 mm (and only 1 for crack depths <code>&lt; 2</code> mm). If we needed to make predictions for shallow cracks, this analysis could be extended to quantify the value of future tests in this region.</p>
</section>
<section id="final-thought-where-did-those-priors-come-from-and-are-they-any-good" class="level4">
<h4 class="anchored" data-anchor-id="final-thought-where-did-those-priors-come-from-and-are-they-any-good">Final Thought: Where Did Those Priors Come From and Are They Any Good?</h4>
<p>There are many approaches for specifying prior models in Bayesian statistics. <em>Weakly informative</em> and <em>MaxEnt</em> priors are advocated by various authors. Unfortunately, <em>Flat Priors</em> are sometimes proposed too, particularly (but not exclusively) in older books. A flat prior is a wide distribution - in the extreme this would be a uniform distribution across all real numbers, but in practice distribution functions with very large variance parameters are sometimes used. In either case, a very large range prior of credible outcomes for our parameters is introduced the model. This may sound innocent enough, and in many cases could be harmless.</p>
<p>Flat priors have the appeal of describing a state of complete uncertainty, which we may believe we are in before seeing any data - but is this really the case?</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://media.giphy.com/media/UgM7H8OEmf4mQ/giphy.gif" class="img-fluid figure-img"></p>
<figcaption>Prior Expectations: Can We Do Better?</figcaption>
</figure>
</div>
<p>Suppose you are using Bayesian methods to model the speed of some athletes. Even before seeing any data, there is some information that we can build into the model. For instance, we can discount negative speeds. We also wouldn’t need to know anything about the athletes to know that they would not be travelling faster than the speed of light. This may sound facetious, but flat priors are implying that we should treat all outcomes as equally likely. In fact, there are some cases where flat priors cause models to require large amounts of data to make good predictions (meaning we are failing to take advantage of Bayesian statistics ability to work with limited data).</p>
<p>In this example, we would probably just want to constrain outcomes to the range of metres per second, but the amount of information we choose to include is ultimately a modelling choice. Another helpful feature of Bayesian models is that the priors are part of the model, and so must be made explicit - fully visible and ready to be scrutinised.</p>
<p>A common challenge, which was evident in the above PoD example, is lacking an intuitive understanding of the meaning of our model parameters. Here <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> required prior models, but I don’t think there is an obvious way to relate their values to the result we were interested in. They are linear regression parameters on a log-odds scale, but this is then transformed into a probability scale using the logit function.</p>
<p>This problem can be addressed using a process known as <strong>Prior Predictive Simulation</strong>, which I was first introduced to in <a href="https://www.crcpress.com/Statistical-Rethinking-A-Bayesian-Course-with-Examples-in-R-and-STAN/McElreath/p/book/9780367139919">Richard McElreath’s fantastic book</a>. This involves evaluating the predictions that our model would make, based only on the information in our priors. Relating our predictions to our parameters provides a clearer understanding of the implications of our priors.</p>
<p>Back to our PoD parameters - both <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> can take positive or negative values, but I could not immediately tell you a sensible range for them. Based on our lack of intuition it may be tempting to use a variance for both, right? Well, before making that decision, we can always simulate some predictions from these priors. The below code is creating a data frame of prior predictions for the PoD (<code>PoD_pr</code>) for many possible crack sizes.</p>
<p><em>(Thank you to Jiun for your kind message that helped me tidy up the below)</em></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Calpha%20%5Csim%20N(%5Cmu_%7B%5Calpha%7D,%20%5Csigma_%7B%5Calpha%7D)%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbeta%20%5Csim%20N(%5Cmu_%7B%5Cbeta%7D,%20%5Csigma_%7B%5Cbeta%7D)%0A"></p>
<p>And we can visualise the information contained within our priors for a couple of different cases.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/Logistic_Bayes/index_files/figure-html/unnamed-chunk-15-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Our wide, supposedly <em>non</em>-informative priors result in some pretty useless predictions. I’ve suggested some more sensible priors that suggest that larger cracks are more likely to be detected than small cracks, without overly constraining our outcome (see that there is still prior credible that very small cracks are detected reliably and that very large cracks are often missed).</p>
<p>Why did our predictions end up looking like this?</p>
<p>Borrowing from McElreath’s explanation, it’s because <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> are linear regression parameters on a log-odds (logit) scale. Since we are estimating a PoD we end up transforming out predictions onto a probability scale. Flat priors for our parameters imply that extreme values of log-odds are credible. All that prior credibility of values <code>&lt; - 3</code> and <code>&gt; 3</code> ends up getting concentrated at probabilities near <code>0</code> and <code>1</code>. I think this is a really good example of flat priors containing a lot more information than they appear to.</p>
<p>I’ll end by directing you towards some additional (generally non-technical) discussion of choosing priors, written by the <code>Stan</code> development team <a href="https://github.com/stan-dev/stan/wiki/Prior-Choice-Recommendations">(link)</a>. It provides a definition of <em>weakly informative priors</em>, some words of warning against <em>flat priors</em> and more general detail than this humble footnote.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://allyourbayes.com/posts/Logistic_Bayes/index_files/figure-html/unnamed-chunk-16-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>


</section>
</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{di_francesco2020,
  author = {Di Francesco, Domenic},
  title = {Bayesian {Logistic} {Regression} with {Stan}},
  date = {2020-02-15},
  url = {https://allyourbayes.com/posts/Logistic_Bayes/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-di_francesco2020" class="csl-entry quarto-appendix-citeas">
Di Francesco, Domenic. 2020. <span>“Bayesian Logistic Regression with
Stan.”</span> February 15, 2020. <a href="https://allyourbayes.com/posts/Logistic_Bayes/">https://allyourbayes.com/posts/Logistic_Bayes/</a>.
</div></div></section></div> ]]></description>
  <category>Bayes</category>
  <category>logistic regression</category>
  <category>MCMC</category>
  <category>Stan</category>
  <category>R</category>
  <guid>https://allyourbayes.com/posts/Logistic_Bayes/</guid>
  <pubDate>Sat, 15 Feb 2020 00:00:00 GMT</pubDate>
  <media:content url="https://allyourbayes.com/posts/Logistic_Bayes/logistic_priors.png" medium="image" type="image/png" height="108" width="144"/>
</item>
</channel>
</rss>
