<?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>John Hearn</title>
<link>https://johnhearn.github.io/</link>
<atom:link href="https://johnhearn.github.io/index.xml" rel="self" type="application/rss+xml"/>
<description>Science and software</description>
<generator>quarto-1.8.27</generator>
<lastBuildDate>Tue, 17 Dec 2024 16:03:00 GMT</lastBuildDate>
<item>
  <title>Matrices of Boolean Nets</title>
  <link>https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/</link>
  <description><![CDATA[ 




<p>When studying the boolean networks on the <a href="../2024-12-05-kauffman-networks/">last post</a> I wondered what the state update rule would look like as a matrix. These things can <a href="https://en.wikipedia.org/wiki/Representation_theory">always be represented by matrices</a>. Working out how to do it led to some nice links to quantum computing and category theory.</p>
<div class="page-columns page-full"><p>A few things led me to the way to construct the boolean net matrices. I knew that representation theory says it should be so but that doesn’t make it easier to construct them. Trial and error didn’t really get me anywhere.  Then I found <a href="https://ozaner.github.io/boolean-logic-with-matrices/">this article</a> describing a simple boolean matrix construction which reminded me that this is deeply related to quantum computing qubit circuit construction that I already know something about, but without all the annoying quantum restrictions.</p><div class="no-row-height column-margin column-container"><span class="">Later found this paper describing a different encoding: <a href="https://academic.oup.com/comjnl/article/15/3/247/480639"><em>The logic of Boolean matrices</em></a> - C. R. Edwards. It might be worth reviewing this to see if this method maintains the same categorical structure.</span></div></div>
<section id="boolean-algebra" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="boolean-algebra">Boolean algebra</h2>
<p>The thing to notice is that a bit (<img src="https://latex.codecogs.com/png.latex?0"> or <img src="https://latex.codecogs.com/png.latex?1">) can be represented as a vector: <img src="https://latex.codecogs.com/png.latex?%20F%20=%20%5Cbegin%7Bpmatrix%7D%0A%20%201%20%5C%5C%0A%20%200%0A%5Cend%7Bpmatrix%7D%20"> and <img src="https://latex.codecogs.com/png.latex?%20T%20=%20%5Cbegin%7Bpmatrix%7D%0A%20%200%20%5C%5C%0A%20%201%0A%5Cend%7Bpmatrix%7D%20"></p>
<p>An identity (NoOp) gate is then <img src="https://latex.codecogs.com/png.latex?%20%5Cbegin%7Bpmatrix%7D%0A%20%201%20&amp;%200%20%5C%5C%0A%20%200%20&amp;%201%0A%5Cend%7Bpmatrix%7D%20"> and a NOT gate is <img src="https://latex.codecogs.com/png.latex?%20%5Cbegin%7Bpmatrix%7D%0A%20%200%20&amp;%201%20%5C%5C%0A%20%201%20&amp;%200%0A%5Cend%7Bpmatrix%7D%20">.</p>
<p>To operate on multiple bits at the same time we <em>tensor</em> them together by applying the <a href="https://en.wikipedia.org/wiki/Kronecker_product">Krondecker product</a>. So the boolean number <img src="https://latex.codecogs.com/png.latex?01_b"> is equal to <img src="https://latex.codecogs.com/png.latex?F%20%5Cotimes%20T">, for example. We end up with a vector of length <img src="https://latex.codecogs.com/png.latex?2%5En"> with an entry for each possible value of the binary number, in order<sup>1</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;Note the most significant bit is on the left in these expressions. The ordering tripped me up a couple of times.</p></div></div><p>Higher order operators are easier here than in the quantum case. We can just write out the result that we want as columns in a matrix, where each column represents <img src="https://latex.codecogs.com/png.latex?00_b">, <img src="https://latex.codecogs.com/png.latex?01_b">, <img src="https://latex.codecogs.com/png.latex?10_b">, <img src="https://latex.codecogs.com/png.latex?11_b">, respectively. So for example the <img src="https://latex.codecogs.com/png.latex?AND"> gate is simply: <img src="https://latex.codecogs.com/png.latex?%20AND%20=%20%5Cbegin%7Bpmatrix%7D%0A%20%201%20&amp;%201%20&amp;%201%20&amp;%200%20%5C%5C%0A%20%200%20&amp;%200%20&amp;%200%20&amp;%201%0A%5Cend%7Bpmatrix%7D%20">.</p>
<p>When we multiply a pair of binary digits (tensored together) by this matrix then we get the answer we want. Example: $ AND * (T F) F$.</p>
<p>The beautiful thing is that we can then use <a href="https://arxiv.org/pdf/0908.3347">wiring diagrams</a> to build more elaborate calculations, like we do in quantum computing circuits. It works because this boolean algebra is an example of a <a href="https://en.wikipedia.org/wiki/Symmetric_monoidal_category">symmetric monoidal category</a> having a braiding that is essentially a SWAP operation between bits. This category allows us to compose operations by <em>shifting</em> bits into place with an appropriate sequence of swaps. This is very similar to the quantum computing equivalents but without the restriction to unitary (reversible) operations. Dropping this restriction means that we can give the category <em>copy</em><sup>2</sup> and <em>discard</em><sup>3</sup> operations, turning it into a <em>copy-discard category</em><sup>4</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn2"><p><sup>2</sup>&nbsp;Also sometimes called <em>clone</em>, as in the <em>no-cloning theorem</em>.</p></div><div id="fn3"><p><sup>3</sup>&nbsp;Or <em>drop</em> or <em>delete</em>, as in the <em>no-deleting theorem</em>.</p></div><div id="fn4"><p><sup>4</sup>&nbsp;Also called a <em>garbage share category</em> but whoever thought up that name should take a deep look at themselves.</p></div></div><p>Examples like this make applied category theory such a powerful thinking tool.</p>
</section>
<section id="kauffmans-example" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="kauffmans-example">Kauffman’s example</h2>
<p>A simple circuit for Kauffman’s 3 node example is fairly easy to construct. The three operators correspond to the three truth tables, one for each node. The <img src="https://latex.codecogs.com/png.latex?Y"> node value is cloned/copied. This is not allowed in quantum computing circuits but no problem here.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/kauffman-circuit.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Kauffman’s example circuit</figcaption>
</figure>
</div>
<p>This circuit does a trick to avoid an extra copy. The copied bit is dropped at the end to make a routine with matching inputs and outputs. This allows multiple similar operations to be chained together to evolve the system.</p>
<p>Some more tricks are required<sup>5</sup> to implement the swapping and shifting of registers in code but luckily I had already done <a href="../../notes/2019-05-09-building-a-qpu-simulator-in-julia-part-2/">something similar</a> for the quantum computing simulator I wrote some years ago. The <img src="https://latex.codecogs.com/png.latex?COPY"> and <img src="https://latex.codecogs.com/png.latex?DROP"> gates were relatively easy to think through and the tensor product just worked perfectly for all these unfamiliar operations (there are <a href="https://en.wikipedia.org/wiki/No-cloning_theorem">no-cloning</a> and <a href="https://en.wikipedia.org/wiki/No-deleting_theorem">no-deleting</a> restrictions in quantum circuits which make things harder in that context).</p>
<div class="no-row-height column-margin column-container"><div id="fn5"><p><sup>5</sup>&nbsp;I went back again to <a href="https://arxiv.org/abs/1608.03355">this paper</a> which I found helpful to understand this process.</p></div></div><p>Of course with this simple example (and the benefit of hindsight) the matrix corresponding to this entire circuit could have been been constructed from scratch from the extended truth table. However this way the actual relations themselves are baked into the circuit. The final matrix, let’s call it <img src="https://latex.codecogs.com/png.latex?M">, will be the same anyway. Here’s what it looks like in code (note that matrix multiplication is from the right, the opposite of the circuit diagram):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1">OPX <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;">op</span>(kauffman_truth_table[<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>
<span id="cb1-2">OPY <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;">op</span>(kauffman_truth_table[<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>
<span id="cb1-3">OPZ <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;">op</span>(kauffman_truth_table[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>])</span>
<span id="cb1-4"></span>
<span id="cb1-5">M <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;">lift</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,DROP)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*lift</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,OPZ)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*lift</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,OPY)</span>
<span id="cb1-6">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*row_swap</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*row_swap</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*lift</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,OPX)</span>
<span id="cb1-7">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*row_swap</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*lift</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,CLONE)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*row_swap</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb1-8"></span>
<span id="cb1-9"><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;">8</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;">8</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">SparseMatrixCSC</span>{<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int64</span>, <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Int64</span>} with <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span> stored entries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb1-10">    <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="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="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>
<span id="cb1-11">    <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="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>
<span id="cb1-12">    <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="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="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="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>
<span id="cb1-13">    <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="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="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="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="cb1-14">    <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="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="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="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>
<span id="cb1-15">    <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="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="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="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">⋅</span></span>
<span id="cb1-16">    <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="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="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="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">⋅</span></span>
<span id="cb1-17">    <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="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="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="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></code></pre></div></div>
<p>Quite a lot of work went into getting that matrix mostly full of zeros!</p>
<p>Testing out the circuit we do get back the results from the original paper:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb2-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> state <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</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;">7</span></span>
<span id="cb2-2">    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;">Bool</span>.(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">digits</span>(state, base<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>, pad<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;">3</span>))</span>
<span id="cb2-3">    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;">transform</span>(s)</span>
<span id="cb2-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">println</span>(s <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;">measure</span>(M<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>S))</span>
<span id="cb2-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-6"></span>
<span id="cb2-7">[<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;">0</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;">=&gt;</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;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb2-8">[<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;">0</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="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="cb2-9">[<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;">0</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;">0</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="cb2-10">[<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 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="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="cb2-11">[<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;">0</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;">0</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;">0</span>]</span>
<span id="cb2-12">[<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="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="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>
<span id="cb2-13">[<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="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="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="cb2-14">[<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;">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;">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></code></pre></div></div>
<p>So now the whole point of doing this wasn’t just to build the circuit in a new way. It was to use the power of linear algebra to tell us something about the network and its properties. Being a matrix we can calculate its eigenvalues and eigenvectors. If we can find eigenvalues with a value of exactly 1 then we will have found stationary points in the network, i.e.&nbsp;cycles.</p>
<p>The eigenvalues $= { _1, _2, …, _8 } $ of <img src="https://latex.codecogs.com/png.latex?M"> turn out to be:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb3-1">λ <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;">eigvals</span>(M)</span>
<span id="cb3-2"></span>
<span id="cb3-3"><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>element <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector</span>{<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">ComplexF64</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-4">   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8660254037844388im</span></span>
<span id="cb3-5">   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8660254037844388im</span></span>
<span id="cb3-6">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.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;">0.0im</span></span>
<span id="cb3-7">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.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;">0.0im</span></span>
<span id="cb3-8">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.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;">0.0im</span></span>
<span id="cb3-9">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.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;">0.0im</span></span>
<span id="cb3-10">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.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;">0.0im</span></span>
<span id="cb3-11">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.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;">0.0im</span></span></code></pre></div></div>
<p>Now it just so happens that those non-zero values are the cube roots of unity. Using the fact that the cubes of the eigenvalues of a matrix are the eigenvalues of the matrix cubed then we should get all ones.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb4-1">λ <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;">eigvals</span>(M<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;">3</span>)</span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>element <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector</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>
<span id="cb4-4">   <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span>
<span id="cb4-5">   <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span>
<span id="cb4-6">   <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span>
<span id="cb4-7">   <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span>
<span id="cb4-8">   <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span>
<span id="cb4-9">   <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span></span>
<span id="cb4-10">   <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span></span>
<span id="cb4-11">   <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span></span></code></pre></div></div>
<p>The last 3 eigenvalues are now exactly one! So let’s look at the last 3 eigenvectors and convert them back to the corresponding states:</p>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/kauffman-kimatograph-3-2.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">The <em>kimatograph</em> depicted in the original paper. In more mordern language we might call this a <a href="https://en.wikipedia.org/wiki/State_diagram"><em>state (transition) diagram</em></a>, a <a href="https://en.wikipedia.org/wiki/Pseudoforest#Graphs_of_functions"><em>pseudoforest</em></a> or a <a href="https://en.wikipedia.org/wiki/Pseudoforest#Graphs_of_functions"><em>functional graph</em></a>. The states <img src="https://latex.codecogs.com/png.latex?001_b">, <img src="https://latex.codecogs.com/png.latex?101_b"> and <img src="https://latex.codecogs.com/png.latex?110_b"> are in the cycle. <img src="https://latex.codecogs.com/png.latex?000_b"> is missing 🤷.</figcaption>
</figure>
</div></div><div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb5-1">[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">measure</span>(ν) for ν <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;">eachcol</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">eigvecs</span>(M<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;">3</span>)[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</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;">8</span>])]</span>
<span id="cb5-2"></span>
<span id="cb5-3"><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>element <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector</span>{<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Vector</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>
<span id="cb5-4"> [<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>
<span id="cb5-5"> [<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;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb5-6"> [<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></code></pre></div></div>
<p>These are exactly the states which form the only cycle in the example kimatograph.</p>
<p>It is not coincidence that the other eigenvalues are zero. The fact that <img src="https://latex.codecogs.com/png.latex?rank(M)%20%3C%208"> is also no coincidence. There is much more to learn about the spectral properties of these matrices.</p>
</section>
<section id="wolframs-cellular-automata" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="wolframs-cellular-automata">Wolfram’s cellular automata</h2>
<p>Once that had worked, I was interested in matrix operations for bigger boolean networks. As before we can apply the same process to Wolfram’s cellular automata which are just specialisations of the general boolean network. This network can be as big as you like. How can we go about building it systematically? This was an interesting problem to mull over and I eventually worked it out. First we can come up with a trinary operator representing the rule.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolfram-rule-op.png" class="img-fluid figure-img" width="200"></p>
<figcaption class="margin-caption">Wolfram rule operation</figcaption>
</figure>
</div>
<p>This operator has 3 inputs, two of which just pass through to the outputs. The other output is the result of the <a href="https://en.wikipedia.org/wiki/Wolfram_code">Wolfram coded rule</a>. The reason for passing through the two outputs is to be able to chain them together easily. Of course we could just copy the values but this way seems neater. To create the complete circuit it also has to wrap around the ends to form a periodic boundary. That’s done by just copying the bottom bit to the top and the top bit to the bottom. The extra two bits are dropped at the end to make a composable operation. So we’re left with this circuit:</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolfram-circuit.png" class="img-fluid figure-img" width="400"></p>
<figcaption class="margin-caption">Wolfram circuit</figcaption>
</figure>
</div>
<p>Note that there are <img src="https://latex.codecogs.com/png.latex?n"> input states and <img src="https://latex.codecogs.com/png.latex?n"> output states so the operation can again be chained by matrix multiplication on the left.</p>
<p>What does this look like in code? Something like this although I expect there are many ways to do it:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb6-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;">Rule</span>(code<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;">Integer</span>)</span>
<span id="cb6-2">    outputs <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;">binary</span>(code, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb6-3">    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;">zeros</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Bool</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span>
<span id="cb6-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="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;">7</span></span>
<span id="cb6-5">        X,Y,Z <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;">reverse</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">binary</span>(k,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb6-6">        R[<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</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> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">transform</span>([outputs[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>], Y, Z])</span>
<span id="cb6-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb6-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sb</span>(R)</span>
<span id="cb6-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb6-10"></span>
<span id="cb6-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;">update</span>(N, rule)</span>
<span id="cb6-12">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Clone the ends and shift to top or bottom respectively</span></span>
<span id="cb6-13">    WRAP <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;">row_shift</span>(N<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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,N<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="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*lift</span>(N<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>,N,CLONE)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*row_shift</span>(N<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>,N<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 class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*lift</span>(N,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,CLONE)</span>
<span id="cb6-14"></span>
<span id="cb6-15">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Build the rule gate</span></span>
<span id="cb6-16">    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;">Rule</span>(rule)</span>
<span id="cb6-17"></span>
<span id="cb6-18">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Chain the rule N times from the left</span></span>
<span id="cb6-19">    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;">foldl</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;">lift</span>(N<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;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,i,R) <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> N<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>
<span id="cb6-20"></span>
<span id="cb6-21">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Drop the last two bits</span></span>
<span id="cb6-22">    PRUNE <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;">lift</span>(N,N,DROP)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*lift</span>(N<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>,N<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>,DROP)</span>
<span id="cb6-23"></span>
<span id="cb6-24">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Build the full circuit</span></span>
<span id="cb6-25">    PRUNE<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>Rᴺ<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>WRAP</span>
<span id="cb6-26"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div></div>
<p>Took a while to get the <a href="https://en.wikipedia.org/wiki/Bit_numbering#Order">bit order</a> of all this right but the idea was right. I did some nice testing and got it working as it should. As a big test I used the circuit to build and run different systems and compare to existing catalogues. This was the result and I’m pretty happy with it.</p>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/ref_wolframca.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Excerpt from <a href="https://atlas.wolfram.com/01/01/views/87/TableView.html">summary grid</a> on the Wolfram website. The slight differences are due only to slight modifications to the starting states.</figcaption>
</figure>
</div></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolframca.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">My results</figcaption>
</figure>
</div>
<p>Looking at the spectra of the update matrices is pretty interesting. As a simple example we can discover eigensystem of the different rules.</p>
<p>In fact we can look at all the eigenvalues of the same group of rules as above. These are plots of the complex plane from (-1,1) in both axes. <img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolfram-eigenvalues.png" class="img-fluid" alt="Wolfram eigenvalue plots"></p>
<p>A few interesting things immediately jump out. First, <strong>every rule has zero eigenvalues</strong> and <strong>the rest are on the unit circle</strong>. This is consistent with what we saw for the simple boolean network above.</p>
<p>The rules with eigenvalues in $ ,0,1 $ correspond to the simplest rules: 123, 127, 128, 132, 136. In fact, rules with widely and evenly spaced eigenvalues seems to lead to simple periodic behaviour. Rules 130 and 134 are examples.</p>
<p>Rules 122, 126 and 129 share the same eigenvalue distributions have triangular run-in evolutions although all different in detail. Rule 131 also has uneven eigenvalues and a triangular update rule.</p>
<p>Rules known to be complex like 124 and 137 have a large number of eigenvalues. There can be a maximum of <img src="https://latex.codecogs.com/png.latex?2%5E%7B11%7D%20=%202048"> eigenvalues so the natural question is if any reach this maximum? Rule 120 has many eigenvalues but the pattern is simple. I suspect that in this case the behaviour is highly dependent on the initial state.</p>
<p>There is a strong resemblance here with the permutation matrices and that’s not surprising. The update rules are, in a sense, permutations with degeneracies. Those degeneracies are the “spider’s legs” in the state diagram. The results suggest that those degeneracies correspond to the zero eigenvalues of the matrix. The degeneracies are zero rows in the transition matrix. Powers of the transition matrix essentially <em>zero out</em> rows associated with the spider’s legs of the permutations, eventually converging on the cycles of a true permutation.</p>
<section id="the-spectrum-of-the-update-rule" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="the-spectrum-of-the-update-rule">The spectrum of the update rule</h3>
<p>We can remove zero rows and the corresponding columns from the transition matrix without changing the cycle dynamics. This essentially means removing the “leaves” of the state diagram. The outer leaves are sometimes called “Eden” states because they can only be initial states and cannot be reached by any other transition. Continuing this process will result in a <strong>permutation matrix with specific cycle characteristics</strong>.</p>
<p>We can formalise this: let <img src="https://latex.codecogs.com/png.latex?Q_k"> be the matrix that, when multiplied with another matrix, removes its <img src="https://latex.codecogs.com/png.latex?k">th row. The matrix which does this has <img src="https://latex.codecogs.com/png.latex?n-1"> rows and <img src="https://latex.codecogs.com/png.latex?n"> columns. To construct it, take the <img src="https://latex.codecogs.com/png.latex?n%20%5Ctimes%20n"> identity matrix, remove row <img src="https://latex.codecogs.com/png.latex?k"> and set the <img src="https://latex.codecogs.com/png.latex?k">th column to zeros. The result looks something like this for the case where <img src="https://latex.codecogs.com/png.latex?n=6"> and <img src="https://latex.codecogs.com/png.latex?k=3">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%20Q%20=%20%5Cbegin%7Bpmatrix%7D%0A%20%20%20%201%20&amp;%200%20&amp;%200%20&amp;%200%20&amp;%200%20&amp;%200%5C%5C%0A%20%20%20%200%20&amp;%201%20&amp;%200%20&amp;%200%20&amp;%200%20&amp;%200%5C%5C%0A%20%20%20%200%20&amp;%200%20&amp;%200%20&amp;%201%20&amp;%200%20&amp;%200%5C%5C%0A%20%20%20%200%20&amp;%200%20&amp;%200%20&amp;%200%20&amp;%201%20&amp;%200%5C%5C%0A%20%20%20%200%20&amp;%200%20&amp;%200%20&amp;%200%20&amp;%200%20&amp;%201%0A%5Cend%7Bpmatrix%7D%20"></p>
<p>If we have a <img src="https://latex.codecogs.com/png.latex?n%20%5Ctimes%20n"> matrix, <img src="https://latex.codecogs.com/png.latex?M">, then multiplying it from the left by <img src="https://latex.codecogs.com/png.latex?Q_k"> will remove one row. To remove the corresponding column it turns out that we have to multiply from the <em>right</em> by the <em>transpose</em>. So the final <img src="https://latex.codecogs.com/png.latex?(n-1)%20%5Ctimes%20(n-1)"> matrix is given as $ M^{} = Q_k M Q_k^T $.</p>
<p>To remove multiple rows and columns, indexed as <img src="https://latex.codecogs.com/png.latex?a,b,c,...">, just repeat the process: <img src="https://latex.codecogs.com/png.latex?...%20Q_c%20Q_b%20Q_a%20M%20Q_a%5ET%20Q_b%5ET%20Q_c%5ET%20...">. Of course, the sequence can be combined so that <img src="https://latex.codecogs.com/png.latex?Q%20=%20...%20Q_c%20Q_b%20Q_a"> and by basic matrix rules<sup>6</sup> we have $ M^{} = Q M Q^T $.</p>
<div class="no-row-height column-margin column-container"><div id="fn6"><p><sup>6</sup>&nbsp;<img src="https://latex.codecogs.com/png.latex?(A_1A_2...A_%7Bk%E2%88%921%7DA_k)%5ET%20=%20A_k%5ETA_%7Bk%E2%88%921%7D%5ET%E2%80%A6A_2%5ETA_1%5ET"> (<a href="https://en.wikipedia.org/wiki/Transpose#Properties">wiki</a>)</p></div></div><p>This matrix operation is different from the operations we’ve seen before. It doesn’t discard bits but rather <strong>discards individual states</strong> or, more specifically, unreachable states. I’m not sure what the categorical construction is for this but it’s hard to see how it would fit on the kinds of a wiring diagram we’ve been using.</p>
<p>This procedure might result in more rows with all zeros. These are the new unreachable leaf states that replace the removed one. This procedure is essentially pruning the leaf states one by one until we’re left with a pure permutation matrix and its cyclic structure. This construction has the effect of removing the zero eigenvalues from the matrix <img src="https://latex.codecogs.com/png.latex?M">.</p>
<p>I <em>think</em> that this is related to <a href="https://en.wikipedia.org/wiki/Krohn%E2%80%93Rhodes_theory">Krohn–Rhodes theory</a> somehow. That theory relates this kind of cellular automata with <a href="https://en.wikipedia.org/wiki/Semigroup_action">actions of semigroups</a>. I’m trying to learn about that stuff but it’s <em>hard</em>. There is a categorical treatment of the Krohn–Rhodes theory<sup>7</sup> that I would like to look at. This stuff spirals off into all kinds of directions that I find fascinating but time is finite. Nevertheless it’s something to put on the todo list.</p>
<div class="no-row-height column-margin column-container page-columns page-full"><div id="fn7"><p><sup>7</sup>&nbsp;Wells, Charles. ‘A Krohn-Rhodes Theorem for Categories’. Journal of Algebra 64, no. 1 (May 1980): 37–45. <a href="https://doi.org/10.1016/0021-8693(80)90130-1">doi.org/10.1016/0021-8693(80)90130-1</a>.</p></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://images-na.ssl-images-amazon.com/images/S/compressed.photo.goodreads.com/books/1348612346i/8667274.jpg" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">I bought the book by John Rhodes which tries to explain this and the scientific and philosophical ramifications. It’s called <em>Applications of Automata Theory and Algebra via the Mathematical Theory of Complexity to Biology, Physics, Psychology, Philosophy, and Games</em> - John Rhodes; Chrystopher L. Nehaniv (Ed.) (2009)</figcaption>
</figure>
</div></div>
<p>So what? The useful thing about this is only seen when considering processes more generally. There is an argument that says that processes can be designed to naturally be attracted towards desired behaviour, wherever they may start. We might say that an particular iterative approach, akin to the update rule, might be likely to result in a stable end state (which may be cyclic but identifiably stable). This has been investigated and used in the field. For example, Barry O’Reilly work on <a href="https://leanpub.com/residuality">Residuality Theory</a> bases some his philosophy this kind of stability.</p>
</section>
<section id="nothing-is-black-and-white" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="nothing-is-black-and-white">Nothing is black and white</h3>
<p>Another interesting thing that comes out naturally from the categorial approach (and the semigroup approach actually) is that the states don’t have to be restricted to <img src="https://latex.codecogs.com/png.latex?0">s and <img src="https://latex.codecogs.com/png.latex?1">s. It turns out that not only are our update rules examples of cd-categories, they are also examples of <a href="https://ncatlab.org/nlab/show/Markov+category">Markov categories</a>. The additional restriction here is that the weights of the states sum to <img src="https://latex.codecogs.com/png.latex?1">. This means that rather than apply boolean logic to our circuits we can apply <a href="https://golem.ph.utexas.edu/category/2024/08/introduction_to_categorical_pr.html">probabilistic (fuzzy) logic</a>. Take the <img src="https://latex.codecogs.com/png.latex?AND"> operator. In category theory this is often called the <em>conjunction</em> or <em>join</em> operator and it’s fundamental to these (<a href="https://ncatlab.org/nlab/show/semicartesian+monoidal+category">cartesian</a>) monoidal categories. In the world of probabilities this same construction represents the probability of two events occurring together. Likewise the <img src="https://latex.codecogs.com/png.latex?OR"> operation corresponds to the probability of either event happening or both. The complement rule is the NOT operator<sup>8</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn8"><p><sup>8</sup>&nbsp;What we don’t have with this construction is conditionals. I think it’s <a href="https://ncatlab.org/nlab/show/Markov+category#conditionals">possible</a> just haven’t needed it.</p></div></div><p>The beautiful thing about these categories is that they automatically capture dependence between probabilities. Take a look at this: <img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/and-prob.png" class="img-fluid" alt="AND probability"></p>
<p>The AND gate has two inputs and they are both ½. So then why does it output ½ in one case and ¼ oin the other? The reason the outputs are different is because the COPY operation has created a dependency between them. In the first case there are two independent variables and therefore 4 possibilities <img src="https://latex.codecogs.com/png.latex?00_b,01_b,10_b,11_b"> and hence the probability of both being 1 is 1 in 4 or ¼. In the other case, since the inputs are effectively the <em>same</em> variable, they necessarily have the same value so the only possibilities are <img src="https://latex.codecogs.com/png.latex?00_b"> or <img src="https://latex.codecogs.com/png.latex?11_b"> and therefore the probability of both being 1 is ½. I think that’s pretty nice.</p>
<p>Anyway, the upshot is that we can create variables as real numbers in the form <img src="https://latex.codecogs.com/png.latex?%20S%20=%20%5Cbegin%7Bpmatrix%7D%0A%20%201-p%20%5C%5C%0A%20%20p%0A%5Cend%7Bpmatrix%7D%20"> where <img src="https://latex.codecogs.com/png.latex?p%20%5Cin%20%5B0,1%5D">. <img src="https://latex.codecogs.com/png.latex?T"> and <img src="https://latex.codecogs.com/png.latex?F"> (as defined above) correspond to the special cases where <img src="https://latex.codecogs.com/png.latex?p=1"> and <img src="https://latex.codecogs.com/png.latex?p=0"> respectively. The construction automatically ensures that the state elements sum to 1. The tensoring ensures that this is honoured for any number of variables.</p>
<p>Now that we’ve done it we can just plug real numbers into our cellular automata and see what happens: <img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolframca-prob.png" class="img-fluid" alt="Wolfram probability"></p>
<p>The update rule is exactly the same. It just works. In this case the initial state in each case is set to a single value of <img src="https://latex.codecogs.com/png.latex?0.6"> in the center cell, rather than <img src="https://latex.codecogs.com/png.latex?1"> as in the diagram above. The cells are grey-scaled, 0 is white and 1 is black, so 0.6 is a medium grey. Notice that the grey cells emanate away from the starting cell and seem to be superimposed onto a background pattern. I think this nicely shows how the update rule permeates through the cells.</p>
<p>There are all kinds of experiments to be done with this. What if multiple cells are initialised to 0.6 in the initial state? <img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolframca-prob2.png" class="img-fluid" alt="Wolfram probability2"></p>
<p>You can see how the effects of the initial state radiate and seem to interact with each other and create interference patterns.</p>
<p>Talking of interference patterns, this category will work on complex numbers too, a sort of analog to a quantum state. Of course, true quantum states don’t have copy and delete operators so let’s just call them complex states? Our bits will be defined this time as <img src="https://latex.codecogs.com/png.latex?%20S%20=%20%5Cbegin%7Bpmatrix%7D%0A%20%20%5Csqrt%7B1-a%5E2%7D%20%5C%5C%0A%20%20a%0A%5Cend%7Bpmatrix%7D%20"> where <img src="https://latex.codecogs.com/png.latex?a"> is complex and <img src="https://latex.codecogs.com/png.latex?%7Ca%7C%20%3C%201">. In this case their square sum to 1 and the tensor product will honour the L2 norm here too. Let’s generate the same diagrams with this new input state. Remember the update rules are still boolean matrices and haven’t changed at all.</p>
<p>This first one shows the magnitude of the complex states with a simple initial state of <img src="https://latex.codecogs.com/png.latex?0.6%20%5Ctimes%20e%5E%7B2%5Cpi%20%E2%88%9A2%7D">. Again a 60% magnitude but with an irrational phase: <img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolframca-cplx-mag1.png" class="img-fluid" alt="Wolfram complex magnitudes 1"></p>
<p>And this one shows the phases: <img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolframca-cplx-ang1.png" class="img-fluid" alt="Wolfram complex phases 1"></p>
<p>There is a very similar kind of pattern emerging from in both the magnitude and phase of the state vector. What if we have two cells set in the initial state? <img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolframca-cplx-mag2.png" class="img-fluid" alt="Wolfram complex magnitudes 2"></p>
<p>And this one shows the phases: <img src="https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/wolframca-cplx-ang2.png" class="img-fluid" alt="Wolfram complex phases 2"></p>
<p>Some nice patterns emerging as the two initialised elements interfere with each other. You could play with this all day long. I haven’t looked at all on what patterns come out of this but I suspect that the phases sort of x-ray into the patterns, seeing through static or repeating background behaviour.</p>
</section>
</section>
<section id="more-questions" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="more-questions">More questions</h2>
<p>Some things that have occurred to me as I was doing this:</p>
<ul>
<li>Curious now for a deeper understanding of the Krohn-Rhodes theorem, to understand it and to see it in the light of category theory. What, if any, is the relation to <a href="https://en.wikipedia.org/wiki/Signal-flow_graph">signal-flow diagrams</a>?</li>
<li>What would the phase space of a probability or complex state be like as different operators are applied to them. Do they tend to go be attracted to the fixed points or do they spins about in other ways? It would be quite easy to set up a 2D (or maybe 3D is minimum?) state and just apply random operators to it and display the path. It would be quite cool if there were strange attractors hidden there somewhere.</li>
<li>Intuition is telling me that we could use cycles to represent classical probabilities and “compress” deterministic algorithms to probabilistic ones. In other words, move computation from the time domain into a wider state space. I’m not sure if <img src="https://latex.codecogs.com/png.latex?%5Cepsilon">-machine<sup>9</sup> does something similar. Curious to look more at this.</li>
<li>Can we construct a <strong>fourier transform operator</strong> by combining cycles of lengths <img src="https://latex.codecogs.com/png.latex?2%5Ek"> and working backwards from the transition matrix to a boolean network? Is there there anything like a Shor’s algorithm, for example?</li>
<li>Is there such a thing as an “indivisible” permutation which would link this to probability in the way that indivisible unitary matrices link probability to Hilbert spaces? See Barandes.</li>
</ul>
<div class="no-row-height column-margin column-container"><div id="fn9"><p><sup>9</sup>&nbsp;Shalizi, Cosma Rohilla, and James P. Crutchfield. ‘Computational Mechanics: Pattern and Prediction, Structure and Simplicity’. Journal of Statistical Physics 104, no. 3/4 (2001): 817–79. <a href="https://doi.org/10.1023/A:1010388907793">doi.org/10.1023/A:1010388907793</a>.</p></div></div></section>
<section id="so-what" class="level2">
<h2 class="anchored" data-anchor-id="so-what">So what?</h2>
<p>I spent quite a few hours on this, actually whole days, over several weeks. It’s been a fascinating journey and I’ve come away with a much deeper understanding of boolean networks and Wolfram’s cellular automata. I’ve got some additional intuition and respect about it relates to category theory and a renewed interest in the Applied Category Theory book I bought some time ago but have been slow to read. Nothing i this article is particularly useful in itself. The categorial construction of the update rules are far too inefficient to be practical but the string diagram reasoning and formalisms have become more familiar and I can see the real power. I didn’t really belive David Spivak when he said somewhere that category theory can be used even for philosophical reasoning, but I think I’m starting to see what he means. It’s a very powerful language but also formal and mathematical. That’s the sort of thing I should like, I guess. ANyway I’m going to leave it there, this write up is never ending. Glad it’s done now.</p>


</section>


 ]]></description>
  <category>mathematics</category>
  <category>complexity-systems</category>
  <category>quantum-computing</category>
  <guid>https://johnhearn.github.io/posts/2024-12-17-boolean-matrices/</guid>
  <pubDate>Tue, 17 Dec 2024 16:03:00 GMT</pubDate>
</item>
<item>
  <title>Kauffmann’s Basic Gene Nets</title>
  <link>https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/</link>
  <description><![CDATA[ 




<p>Stuart Kauffman’s 1969 paper <em><a href="https://citeseerx.ist.psu.edu/document?repid=rep1&amp;type=pdf&amp;doi=93e430fc351766b408c39a89c4421546d12632d0">Metabolic Stability and Epigenesis in Randomly Constructed Genetic Nets</a></em> introduced a simple model of gene interaction which seemed to capture certain characteristics of real biological systems. It was a precursor for later work on <a href="https://en.wikipedia.org/wiki/NK_model">NK-models</a> and <a href="https://en.wikipedia.org/wiki/Cellular_automaton">cellular automata</a>. They have come up recently in different forms such as Stephen Wolfram’s work on biological computability<sup>1</sup><sup>2</sup> and Barry O’Reilly’s <a href="https://www.sciencedirect.com/science/article/pii/S1877050922004975">Residuality Theory</a>.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;<a href="https://writings.stephenwolfram.com/2024/05/why-does-biological-evolution-work-a-minimal-model-for-biological-evolution-and-other-adaptive-processes/">Why Does Biological Evolution Work? A Minimal Model for Biological Evolution and Other Adaptive Processes</a> (Wolfram - May 2024).</p></div><div id="fn2"><p><sup>2</sup>&nbsp;<a href="https://writings.stephenwolfram.com/2024/12/foundations-of-biological-evolution-more-results-more-surprises/">Foundations of Biological Evolution: More Results &amp; More Surprises</a> (Wolfram - December 2024).</p></div></div><p>I’m going to take the approach of just reproducing Kauffman’s initial results, as I like to do, including some additional work to link it to Wolfram’s classes. I have also done some work on the separability, divisibility and reversibility of these nets but that will be in another post.</p>
<section id="the-setup" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="the-setup">The setup</h2>
<p>The paper begins like this:</p>
<blockquote class="blockquote">
<p>Proto-organisms probably were randomly aggregated nets of chemical reactions. The hypothesis that contemporary organisms are also randomly constructed molecular automata is examined by modeling the gene as a binary (on-off) device and studying the behavior of large, randomly constructed nets of these binary “genes”.</p>
</blockquote>
<p>First some terminology. Kauffman refers to his net as “<em>a binary (on-off) device</em>”. We will call this a <a href="https://en.wikipedia.org/wiki/Boolean_network">boolean network</a> because each node has a boolean value attached to it, on or off. When he uses the word “gene” (in quotes) he’s referring to the individual nodes of the network.</p>
<p>There are <img src="https://latex.codecogs.com/png.latex?N"> nodes and each node is attached to <img src="https://latex.codecogs.com/png.latex?K"> other nodes. By way of example Kauffman uses a simple network with 3 nodes and 2 connections.</p>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/kauffman-network-3-2.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Comparison with figure from the original paper which includes the truth table for each node.</figcaption>
</figure>
</div></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/network-3-2.png" class="img-fluid figure-img" width="250"></p>
<figcaption class="margin-caption">The example that Kauffman uses in the paper is a (N=3,K=2) network. By necessity it is a complete graph and is small enough to be worked through by hand.</figcaption>
</figure>
</div>
<p>The network is allowed to evolve in a particular way:</p>
<blockquote class="blockquote">
<p>… the inputs to each binary “gene” may be chosen at random; the effect of those inputs on the recipient element’s output behavior may be randomly decided by assigning at random to each element one of the possible Boolean functions of its inputs.</p>
</blockquote>
<p>For example, if a node has two inputs A and B (K=2) then the rule might be or <img src="https://latex.codecogs.com/png.latex?A"> AND <img src="https://latex.codecogs.com/png.latex?B"> or <img src="https://latex.codecogs.com/png.latex?A"> XOR <img src="https://latex.codecogs.com/png.latex?B">, assigned at random, and the node’s value would be updated accordingly.</p>
<p>Alternatively, these rules can be represented in full generality as a <a href="https://en.wikipedia.org/wiki/Truth_table">truth table</a>. Since for this study we don’t care what the actual rules are in terms of ANDs and ORs, we will construct the update rules simply by taking a random truth table.</p>
<p>To reproduce Kauffman’s simple example in the paper we assign the following truth table to the network:</p>
<div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">As an aside, there are <img src="https://latex.codecogs.com/png.latex?2%5EK%20%5Ctimes%20N"> entries in the truth table. This suggests to me that a tensor representation might be more efficient for simulation, especially for larger values of <img src="https://latex.codecogs.com/png.latex?K">.</span></div></div>
<table class="table">
<thead>
<tr class="header">
<th style="text-align: center;">Node</th>
<th style="text-align: center;">Inputs</th>
<th style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?00"></th>
<th style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?01"></th>
<th style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?10"></th>
<th style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?11"></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?X_%7BT+1%7D"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?YZ"></td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">0</td>
</tr>
<tr class="even">
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?Y_%7BT+1%7D"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?XZ"></td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">1</td>
</tr>
<tr class="odd">
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?Z_%7BT+1%7D"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?XY"></td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">1</td>
</tr>
</tbody>
</table>
<p>Enumerating the small number of possible states in this example we find the following update rule:</p>
<p><img src="https://latex.codecogs.com/png.latex?f:%20X%20%5Ctimes%20Y%20%5Ctimes%20Z%20%5Crightarrow%20X%20%5Ctimes%20Y%20%5Ctimes%20Z"></p>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/kauffman-truth_table-3-2.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Comparison with truth table depicted in the original paper.</figcaption>
</figure>
</div></div><div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1"> [<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;">0</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;">=&gt;</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;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb1-2"> [<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;">0</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="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="cb1-3"> [<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;">0</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;">0</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="cb1-4"> [<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 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="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="cb1-5"> [<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;">0</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;">0</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;">0</span>]</span>
<span id="cb1-6"> [<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="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="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>
<span id="cb1-7"> [<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="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="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="cb1-8"> [<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;">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;">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></code></pre></div></div>
<!---
| T<br/>X Y Z || T+1<br/>X Y Z|
|:-:|:-:|:-:|
| 0 0 0 | $\rightarrow$ | 0 0 1|
| 0 0 1 | $\rightarrow$ | 1 0 1|
| 0 1 0 | $\rightarrow$ | 0 0 1|
| 0 1 1 | $\rightarrow$ | 0 0 1|
| 1 0 0 | $\rightarrow$ | 0 0 0|
| 1 0 1 | $\rightarrow$ | 1 1 0|
| 1 1 0 | $\rightarrow$ | 0 0 1|
| 1 1 1 | $\rightarrow$ | 0 1 1|
-->
<p>When the update rule is applied multiple times, the values of the nodes enter a dynamic wholly defined by the truth table. Since this is a finite system, at some point the values will enter a cycle. The maximum possible cycle length is <img src="https://latex.codecogs.com/png.latex?2%5EN"> (or <img src="https://latex.codecogs.com/png.latex?2%5E3=8"> in our small example) but often the cycles will be shorter. By tracing the dynamics for each of the possible state values we can draw a graph of their trajectories<sup>3</sup>.</p>
<div class="no-row-height column-margin column-container page-columns page-full"><div id="fn3"><p><sup>3</sup>&nbsp;Kauffman calls these diagrams <em>kimatograph</em> in the paper but it doesn’t seem to be a term that caught on, although I quite like it.</p></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/kauffman-kimatograph-3-2.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">The <em>kimatograph</em> depicted in the original paper. The state <img src="https://latex.codecogs.com/png.latex?000"> has been omitted for some reason.</figcaption>
</figure>
</div></div>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/kimatograph-3-2.png" class="img-fluid figure-img" width="450"></p>
<figcaption class="margin-caption">Example kimatograph from paper</figcaption>
</figure>
</div>
<p>By looking at the diagram and following the arrows, it’s clear that all the states eventually fall into the same cyclic behaviour. There is a <em>transient</em> (or <em>run-in</em>) period between the initial state and the first state encountered on a cycle. Kauffman defines a <em>confluent</em> as the set of states leading into, or on, a cycle. In this case there is only one.</p>
</section>
<section id="the-results" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="the-results">The results</h2>
<p>In the paper, Kauffman studied the dynamics of large networks, keeping <img src="https://latex.codecogs.com/png.latex?K=2">. Just by way of example a graph representation of a network with <img src="https://latex.codecogs.com/png.latex?N=14,K=2"> might look like the following diagram.</p>
<div class="page-columns page-full"><p> <img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/random-network-14-2.png" class="img-fluid" width="450" alt="Random boolean network"></p><div class="no-row-height column-margin column-container"><span class="">This network has 14 nodes labelled from 1 to 14 (<img src="https://latex.codecogs.com/png.latex?N=14">). Each node has two incoming connections (<img src="https://latex.codecogs.com/png.latex?K=2">).</span></div></div>
<p>The situation clearly becomes more complicated very quickly and you’d expect the dynamics to be equally complicated. However, Kauffman goes on to say:</p>
<blockquote class="blockquote">
<p>The results suggest that, if each “gene” is directly affected by two or three other “genes”, then such random nets: behave with great order and stability.</p>
</blockquote>
<p>This is the crux of the study and mostly borne out but we will see that there are important exceptions. Kauffman realised this and the nuance became of central importance in the development of complex systems theory although it is understated in this early paper.</p>
<p>Take, for example the histogram of cycle length. Kauffman discovered that the average cycle length for (<img src="https://latex.codecogs.com/png.latex?N=400,K=2">) nets with random truth tables was smaller than might be expected. We can reproduce the result fairly well.</p>
<div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">A histogram of cycles detected in 400 node random boolean nets.</span></div></div>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/kauffman-cycles-hist-400-2.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">The histogram of cycle length depicted in the original paper. Note the cut-off at 55 and the preponderance of cycles of length 2.</figcaption>
</figure>
</div></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/cycles-hist-400-2.png" class="img-fluid figure-img" width="350"></p>
<figcaption class="margin-caption">Histogram nets N=400</figcaption>
</figure>
</div>
<p>There are immediately some things to note. First the <strong>similarity is remarkable</strong>, especially considering that this is a run of 200 random samples out of a possible <img src="https://latex.codecogs.com/png.latex?2%5E%7B400%7D"> states. There are peaks at 1, 2, 4, 6, 8, 10, 12, 16, 20, 24, etc. and the trend is decreasing with larger cycle lengths.</p>
<p>There are two important caveats, though.</p>
<p>The preponderance of cycles of length two in Kauffman’s results is not present in mine. Initially, I thought this was a bug in my code but I checked and double checked the calculations by hand and couldn’t find a problem. Moreover, closer study reveals a second, related caveat worth mentioning.</p>
<p>I have artificially chopped the histogram at the value of 55 to match Kauffman’s. However, my results include cycles of lengths much greater then 55, some having exceeded the limit of 10,000 which I had to add to stop the simulations running forever. I have individual instances of cycle lengths of 60, 62, 72, 78, 80, 84, 96, 102, 111, 116, 168, 186, 248, 282, 292, 320, 381, 438, 458, 482, 508, 1017, 1260, 1281, 1552, 3066, 3500, 3628, 6527 and eight more reaching the upper limit.</p>
<p>Suspiciously, my results typically show a similar number of cycle lengths above 55 as the difference in Kauffman’s and my results for 2-cycles. For example, the 2-cycle count from my experiment shown in the figure, was 9. The number of cycles of length greater than 55 was 39. Kauffman’s 2-cycle count was 40.</p>
<p>I don’t have Kauffman’s original code and I can’t formally prove my code is correct. Nonetheless I have found an interesting way of testing it which is instructive in itself. The idea is to narrow in on Stephen Wolfram’s well-known 1D cellular automata as a <em>special case</em> of Kauffman’s boolean nets.</p>
</section>
<section id="wolframs-classes" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="wolframs-classes">Wolfram’s classes</h2>
<p>It turns out that Wolfram’s famous study of <a href="https://en.wikipedia.org/wiki/Elementary_cellular_automaton">elementary 1D cellular automata</a> (which he discusses in great depth in his book “<em>A New Kind of Science</em> (2002)”) can easily be modelled as a boolean net. The good thing is that the results are visually quite distinctive and can serve as a reference.</p>
<div class="page-columns page-full"><p>To build it, start with the <img src="https://latex.codecogs.com/png.latex?N"> nodes arranged in a line. Connect each node to itself and its two immediate neighbours, making <img src="https://latex.codecogs.com/png.latex?K=3">. The system is closed by wrapping around the ends of the line so that the nodes at both extremes are connected together.</p><div class="no-row-height column-margin column-container"><span class="">These are sometimes called <em>periodic boundaries</em>.</span></div></div>
<p>Make a truth table based on one of the <img src="https://latex.codecogs.com/png.latex?2%5E3"> possible rules. Wolfram <a href="https://en.wikipedia.org/wiki/Wolfram_code">codified</a> them as numbers from 0 to 255. The truth table is identical for each of the nodes.</p>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/rule26.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Example of the history of evolution of a boolean net with 100 nodes arranged in a line. Each time step is a row on the image. The pattern is cyclic and, in fact, is classified as “class 2” in Wolfram’s scheme.</figcaption>
</figure>
</div></div><p>Allow the system to evolve, keeping records on the history of states as the rows of an image. This is what you get, for example for rule 26:</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/9/94/Rule26rand.png" width="150" height="150" style="padding:25px; background-color:white;"></p>
<p>Wolfram and others have studies these nets in depth and famously found that they exhibit behaviour that fits into 4 classes:</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://files.wolframcdn.com/pub/www.wolframscience.com/nks/page0231a-600.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Wolfram’s four classes</figcaption>
</figure>
</div>
<p>The first class leads to a single terminal, stationary state. All 0s or all 1s. In terms of Kauffman’s nets, the cycle length in this class is 1 and we have seen that many rules lead to this outcome. Kauffman notes that removing rules which always resolve to 0 or 1<sup>4</sup> significantly reduces the occurrence of this class.</p>
<div class="no-row-height column-margin column-container"><div id="fn4"><p><sup>4</sup>&nbsp;He calls them <em>contradictions</em> and <em>tautologies</em> respectively.</p></div></div><p>The second class reduces to fixed patterns with simple periodic behaviour. <a href="https://conwaylife.com/wiki/One-dimensional_cellular_automaton/Wolfram_rule">Rule 26 shown above falls into this class</a>. While it is a fairly complicated (using the term advisedly) pattern it is periodic and predictable.</p>
<p>The third class is entirely chaotic. The pattern does not converge and is only periodic to the extent of the finite state space (which may be extremely large). The appearance is of white noise and randomness and, in fact, is <a href="https://reference.wolfram.com/language/tutorial/RandomNumberGeneration.html#185956823">available as a random number generator</a> in Mathematica.</p>
<p>The fourth class demonstrates complexity. The patterns are non-periodic but also not chaotic. These configurations are on the <em>edge of chaos</em>, neither periodic nor chaotic. One interesting property that at least two of the rules in this category have is <em>universality</em><sup>5</sup>, or in other words the ability to perform any calculation.</p>
<div class="no-row-height column-margin column-container"><div id="fn5"><p><sup>5</sup>&nbsp;<a href="https://wpmedia.wolfram.com/sites/13/2018/02/15-1-1.pdf">Universality in Elementary Cellular Automata</a> - Matthew Cook</p></div></div><p>What’s the relevance of all this? Well, by converting the well-documented Wolfram rules to Boolean nets I’m much more comfortable saying that my simulation is working as expected. I’ve tried many different rules and the patterns are identical to the published ones.</p>
<p>On top of that, since the simple cellular automata studied by Wolfram is an example of very simple Kauffman network then the Kauffman networks in general must necessarily admit such classes of behaviour, including class 3 and 4, the chaotic and universal ones. In this light, Kauffman’s discovery that the average cycle length remains smaller than might be expected is just a part of a much richer picture.</p>
<p>At this point I got side tracked onto a parallel way of modelling the networks which has some promise. The write up of that will have to wait until the next post.</p>


</section>


 ]]></description>
  <category>complexity-systems</category>
  <category>mathematics</category>
  <guid>https://johnhearn.github.io/posts/2024-12-05-kauffman-networks/</guid>
  <pubDate>Thu, 05 Dec 2024 06:53:00 GMT</pubDate>
</item>
<item>
  <title>Christopher Alexander and Network Theory</title>
  <link>https://johnhearn.github.io/posts/2024-11-16-christopher-alexander-network-theory/</link>
  <description><![CDATA[ 




<div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">The aim of this article is not to give a complete picture of 60 years of his work. I suggest you read his books for that. Rather it is to explain just enough to see the arc and place it in context.</span></div></div>
<p>In his early work, “<em>Notes on the Synthesis of Form (1964)</em>” (abbreviated in the following as <em>NotSoF</em>), Christopher Alexander explored a mathematical, network-based approach to design. He conceptualised design as an interrelated network of “misfit variables” to be optimised through computational analysis, algorithmically <em>solving</em> conflicts between interconnected elements.</p>
<p>His thesis was that to solve a design problem it should be reduced to multiple smaller problems and that, crucially, we have been limited to using existing concepts that have come down to us as “<em>arbitrary historical accidents</em>” rather than being an optimal description of the situation at hand. At this stage, Alexander’s approach was reductionist and analytical, believing that a design could be synthesised and studied through rigorous structural optimization. He suggested algorithms (precursors to <a href="https://en.wikipedia.org/wiki/Community_structure">community structure</a> algorithms) to cluster elements together in such a way as to reduce the overall design problem to a hierarchical tree of simpler ones which in turn could be solved and optimised <em>independently</em>.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-11-16-christopher-alexander-network-theory/diagrams.jpg" class="img-fluid figure-img" style="width:80.0%" alt="Diagrams from Notes on the Synthesis of Form showing design variables and their interactions."></p>
<figcaption class="margin-caption">A figure from NotSoF which shows design variables (small black circles, so-called <em>nodes</em> in the network) and their interactions (lines). The nodes are grouped into clusters (represented as the larger circles).</figcaption>
</figure>
</div>
<p>In this work, the clusters of variables Alexander calls “<em>diagrams</em>” (which he would later rename to the “<em>patterns</em>” which he became famous for) and this is where his thinking began to change. As he states in the preface to later editions:</p>
<blockquote class="blockquote">
<p>As you can see, it is the independence of the diagrams which gives them these powers. At the time I wrote this book, I was very much concerned with the formal definition of “independence,” and the idea of using a mathematical method to discover systems of forces and diagrams which are independent. But once the book was written, I discovered that it is quite unnecessary to use such a complicated and formal way of getting at the independent diagrams.</p>
</blockquote>
<p>What does modern network science tell us about this? To answer this we can use the example described in depth at the end of NotSoF.</p>
<div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">The example from the book NotSoF which in turn is taken from the study “<em>The De­termination of Components for an Indian Village</em>” - Conference on Design Method (Oxford : Pergamon, 1963). The layout is force directed, meaning that related nodes are attracted toward each other and unconnected nodes are pushed apart. Sometimes clusters appear naturally but in this case none are easily identified. The graph is interactive, feel free to try and pull the clusters apart yourself.</span></div></div>
<iframe width="55%" height="400" frameborder="0" src="https://observablehq.com/embed/e954fd2bd1ba27cb@219?cells=chart">
</iframe>
<p>This is the full and extensive design problem that Alexander studied. Although he was able to group this into 12 hierarchical clusters (represented by the colours off the nodes), the nature of the <em>independence</em> of those clusters is far from clear. Force directed layouts such as this one sometimes identify underlying structure but not in this case. Even so, visually it might be deceiving so we can apply modern summary statistics to this network and see the difficulty in clustering this network at all.</p>
<p><br></p>
<div class="network-metrics">
<table class="table">
<thead>
<tr class="header">
<th>Metric</th>
<th style="text-align: right;">Value</th>
<th>Interpretation</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Average degree</strong></td>
<td style="text-align: right;">~20</td>
<td>Each node, on average, interacts with 20 other nodes.</td>
</tr>
<tr class="even">
<td><strong>Edge density</strong></td>
<td style="text-align: right;">0.14</td>
<td>About 1 in 7 of all possible interactions are present. This is a dense graph.</td>
</tr>
<tr class="odd">
<td><strong><a href="https://en.wikipedia.org/wiki/Average_path_length">Average&nbsp;Path&nbsp;Length</a></strong></td>
<td style="text-align: right;">2.0</td>
<td>On average there are just 2 hops between each node.</td>
</tr>
<tr class="even">
<td><strong><a href="https://en.wikipedia.org/wiki/Clustering_coefficient#Global_clustering_coefficient">Global&nbsp;clustering coefficient</a></strong></td>
<td style="text-align: right;">0.06</td>
<td>Higher values mean better clusters. This is a very low value.</td>
</tr>
<tr class="odd">
<td><strong><a href="https://en.wikipedia.org/wiki/Algebraic_connectivity">Algebraic connectivity</a></strong></td>
<td style="text-align: right;">&gt;6</td>
<td>Very high. By comparison tree-like graphs, scale-free and small-world networks have this typically less then 1.0.</td>
</tr>
</tbody>
</table>
</div>
<p><br></p>
<p>These metrics all point at this being a highly connected network without any clear clusters or community structure. Although the <em>diagrams</em> suggested by Alexander in the book do, to some measure, minimise the links between clusters, the result is still very far from the tree-like structure that is espoused.</p>
<p>Alexander realised this, of course, and the beginnings of a perspective shift are clear in his essay the very next year “<em>A City is Not a Tree (1965)</em>”, where he claimed that cities and urban structures cannot be fully explained by hierarchical models or purely tree-like networks. He argued that successful cities are not trees but are “semi-lattices” — networks with overlapping connections that resemble the organic, intertwined complexity of real-life. Here, Alexander is reflecting on and challenging his own reductionist assumptions, positing that cities function best with fluid, overlapping, and non-hierarchical connections, allowing diverse elements to interrelate dynamically.</p>
<p>Alexander’s reflexivity is to be admired. Remember he was writing this 60 years ago, when hard science was a raging success explaining the unexplainable and we were still optimistic for “Grand Theories of Everything” even though computers filled an entire room.</p>
<p>By the time Alexander finished “<em>A Pattern Language (1977)</em>”, his thinking had moved even further away from strict optimization schemes toward a more life-centered philosophy. He recognized that human environments thrive on the richness of overlapping networks rather than static or strictly hierarchical arrangements. Rather than optimizing individual design problems, he focused on identifying “patterns” — recurring, archetypal solutions that reflect timeless principles of habitability. Each pattern addressed a design aspect that could contribute to a “whole” design when combined with others in rich and intricate ways. Patterns were interconnected in what Alexander saw as a more organic network, linked by relationships that encouraged cohesion and harmony within the design. Rather than algorithmic clustering, these patterns represented design wisdom drawn from observation and experience, creating environments that intuitively supported human needs and preferences.</p>
<p>Taking this idea further, in “<em>The Nature of Order series (2002–2005)</em>”, Alexander considers “centers,” a concept intended to capture essential order that appears naturally within vibrant environments. Alexander believed these centers were interrelated and overlapping, embedded in a “living” structure that achieved harmony through wholeness rather than quantifiable connections.</p>
<p>By this point Alexander’s perspective has shifted entirely to a holistic one. He is no longer using tree structures and prefers using words like "<em>wholeness</em>" to describe this shift requiring experience and expertise to understand the full picture.</p>
<hr class="slender" width="50%">
<p>I will admit that the mathematical approach of Alexander’s early work still very much appeals to the logical side of my brain and 30+ years of western education: if I follow this procedure, I can solve the problem in the abstract using maths and computers. This is one extreme of a philosophical framework which emphasises narrowing the vision and focusing in on breaking down and solving component problems and then reintegrating them. Some people use the left-hemisphere as a metaphor for this kind of thinking.</p>
<p>This is also the thinking that leads us to search for optimal efficiency through gradient descent to cost reduction and maximal productivity.</p>
<div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">Ironically the left-right distinction is itself a left-hemisphere concept. Using such terms encumbers us with a recursive limitation.</span></div></div>
<p>However, shifting too dramatically from a left-hemisphere to right-hemisphere approach (System A to System B, as he called them) causes unresolvable tension, poles so far apart that there simply is no sweet spot. Christopher Alexander himself documented these problems in the book “<em>The Battle for the Life and Beauty of the Earth: A Struggle between Two World-Systems (2012)</em>”. System A drives for cold, modern efficiency and System B for life and harmony. I live in a System A building. How much better it could have been with a little System B. Too much System B and it wouldn’t even exist. As Daniel Schmachtenberger says “<em>we’re creating a future that <strong>nobody</strong> wants</em>”.</p>
<p>Can we apply modern efficiency to find life and harmony and get the best of both worlds? It doesn’t seem like an impossible goal to me.</p>
<p>In modern network theory, <em>patterns</em>, <em>diagrams</em> and even <em>centres</em> might be better considered as <a href="https://en.wikipedia.org/wiki/Network_motif">motifs</a> rather than clusters determined by the density of their interactions. Motifs are repeating, stable structures with the potential to identify key functional properties embedded within a network of a particular type - certain configurations that always seem to work well together. Importantly, they do not need to be disconnected from the rest of the network but can mix and overlap with other nodes and motifs while maintaining their own essential structure. Although there are modern algorithms for detecting motifs, just like clusters, at this point Alexander was arguing that algorithms could not capture the fundamental quality of “<em>life</em>” that great designs embody; only an intuitive, holistic understanding could bring the sense of harmony aspired to.</p>
<p>There is a certain circularity in Alexander’s story. With the aim of trying to get away from subjective, accidental concepts to a more objective approach he ended up saying that only through expertise are we able to detect and evaluate the concepts in the first place.</p>
<p>I am more optimistic. I wonder if we will be able to complete the circle and detect natural but explainable motifs. For example, new language models seem to be able to glean underlying patterns that maybe even the experts are not aware of. I can envision a world, not too far away, where we will need both the algorithmic tools <em>and</em> expert evaluation to keep things in check.</p>
<p>A nice example of a similar circularity has happened in chess. Many believed that computers could not play chess due to the unfathomable number of possible moves while others believed that even if they did, the game would become boring and predictable. Nonetheless modern engines have far surpassed humans and are now helping professional players to develop new intuitions. Rather than mechanising the game, modern encounters are quick to leave theory behind and explore more novel openings than they did before the engines existed.</p>
<p>The evolution of Christopher Alexander’s design philosophy also has an interesting analogy with the modern tension between systems thinking and complexity theory. When viewed through the lens of network theory we can place his journey in a firm conceptual framework and show his battles in a modern light. He moved from clustering design variables to a more holistic, fluid approach. This is very similar to the comparison by some of traditional and structural systems thinking approaches (such as lines and circles and systems dynamics) to more fluid approaches from Complexity Theory. Bearing in mind Alexander’s philosophical journey, I am eager to see the evolution and synthesis of both of these subjects.</p>



 ]]></description>
  <category>complexity-systems</category>
  <category>modelling</category>
  <category>software-architecture</category>
  <guid>https://johnhearn.github.io/posts/2024-11-16-christopher-alexander-network-theory/</guid>
  <pubDate>Sat, 16 Nov 2024 07:30:00 GMT</pubDate>
</item>
<item>
  <title>Predictability and batch size</title>
  <link>https://johnhearn.github.io/posts/2024-09-29-predictability-and-batch-size/</link>
  <description><![CDATA[ 




<p>Some results from a little Monte Carlo simulation of delivery times <a href="https://www.linkedin.com/posts/phil-ledgerwood_in-my-last-post-on-this-httpslnkdin-activity-7245467832489046017-sk_N">posted on LinkedIn</a> showed that <strong>predictability decreases with larger batch sizes</strong>. A little maths shows clearly why this is the case.</p>
<section id="the-model" class="level3">
<h3 class="anchored" data-anchor-id="the-model">The model</h3>
<p>The post compared a team delivering one work item per day with a team delivering 5 work items together every 5 days. The teams have a batch size of 1 and 5 respectively. In this situation we’d expect the mean delivery rate to be the same, namely 1 item per day on average. We’ll call the batch size <img src="https://latex.codecogs.com/png.latex?b">.</p>
<p>In our model, a team will deliver <img src="https://latex.codecogs.com/png.latex?W"> work items (doesn’t matter the size of each item, we’re only using the finishing rate in this model) in batches with <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7BW%7D%7Bb%7D"> items in each batch. Let’s call the number of batches <img src="https://latex.codecogs.com/png.latex?r=%5Cfrac%7BW%7D%7Bb%7D">.</p>
<p>In this idealised model, Team 1’s probability of delivering each day is close to 1, so for this case let’s say <img src="https://latex.codecogs.com/png.latex?p=1">. Team 2’s probability of delivering 5 work items on any particular day is <img src="https://latex.codecogs.com/png.latex?p=%5Cfrac%7B1%7D%7B5%7D">. So in general on a given day a team delivers <img src="https://latex.codecogs.com/png.latex?b"> work items with a probability of <img src="https://latex.codecogs.com/png.latex?p=%5Cfrac%7B1%7D%7Bb%7D">.</p>
<p>We want to know the probability of delivering <img src="https://latex.codecogs.com/png.latex?W"> items of work in <img src="https://latex.codecogs.com/png.latex?n"> days. This requirement is captured by a <a href="https://en.wikipedia.org/wiki/Negative_binomial_distribution">Negative Binomial</a> distribution and, luckily for us, all the maths has been previously worked out. We’ll break the total delivery time down into two parts. First, the the number of times that a team <em>fails</em> to deliver on a specific day, that is the gaps between deliveries. We’ll call that number <img src="https://latex.codecogs.com/png.latex?k">. Secondly, we need the number of days that it does deliver, this is <img src="https://latex.codecogs.com/png.latex?r">. We can then say that the total number of days is the sum of the delivery days, <img src="https://latex.codecogs.com/png.latex?r">, plus the non-delivery days, <img src="https://latex.codecogs.com/png.latex?k">. In other words, <img src="https://latex.codecogs.com/png.latex?n=k+r">. In this case then <img src="https://latex.codecogs.com/png.latex?k"> follows:</p>
<p><img src="https://latex.codecogs.com/png.latex?n-r%20=%20k%20%5Csim%20NegativeBinomial(r,%20p)"></p>
<p>And from this we can work out the distribution of <img src="https://latex.codecogs.com/png.latex?n">.</p>
</section>
<section id="what-does-the-model-tell-us" class="level3">
<h3 class="anchored" data-anchor-id="what-does-the-model-tell-us">What does the model tell us?</h3>
<p>Given the distribution defined above, and remembering that <img src="https://latex.codecogs.com/png.latex?r"> is a constant, then the expected value of <img src="https://latex.codecogs.com/png.latex?n"> is:</p>
<p><img src="https://latex.codecogs.com/png.latex?E%5Bn%5D%20=%20E%5Bk+r%5D%20=%20E%5Bk%5D%20+%20r%20=%20%5Cfrac%7Br(1-p)%7D%7Bp%7D%20+%20r%20=%20%5Cfrac%7Br%7D%7Bp%7D%20=%20%5Cfrac%7B%5Cfrac%7BW%7D%7Bb%7D%7D%7B%5Cfrac%7B1%7D%7Bb%7D%7D%20=%20W"></p>
<p>So, in this model, to deliver <img src="https://latex.codecogs.com/png.latex?W"> work items <strong>the average total delivery time is independent of the batch size</strong>, as expected.</p>
<p>What about its variance? The variance of the mean (a measure of predictability) is:</p>
<p><img src="https://latex.codecogs.com/png.latex?Var%5Bn%5D%20=%20Var%5Bk+r%5D%20=%20Var%5Bk%5D%20=%20%5Cfrac%7Br(1-p)%7D%7Bp%5E2%7D%20=%20%5Cfrac%7BW%7D%7Bb%7D%20%5Cfrac%7B(1-%5Cfrac%7B1%7D%7Bb%7D)%7D%7B%5Cleft(%20%5Cfrac%7B1%7D%7Bb%7D%20%5Cright)%5E2%7D%20=%20W(b-1)"></p>
<p>So <strong>the variance <em>increases linearly</em> with batch size</strong>. Since the greater the variance the less predictable the result we can say that the predictability <em>decreases</em> with batch size.</p>
<p>The variance <strong>also increases linearly with the amount of work</strong>. This captures the fact that the predictability decreases the further into the future you look, even if the delivery rate remains constant. This is just one of the factors comprising the <a href="https://en.wikipedia.org/wiki/Cone_of_uncertainty">cone of uncertainty</a> that results solely from batch size.</p>
</section>
<section id="a-model-is-a-model" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="a-model-is-a-model">A model is a model</h3>
<p>In any real team the batch size won’t be constant but, all other things being equal, this model is good enough to tell us that regular delivery of smaller batches is preferable to larger ones.<sup>1</sup></p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;There are other reasons too, like the accumulation of changes increasing the probability of bugs but that is not covered in this model.</p></div></div><p>Also in real teams the work items are generally not completely independent. This can be due to internal team dynamics, one piece of work being a prerequisite of another, etc. The practical effect of this is to increase the variance further. One nice thing about the negative binomial as a modelling tool is that it can easily be tuned to the teams actual data by increasing its variance slightly while keeping the mean constant. In the past I have found this to be a very good approximation of data gathered from real teams.</p>
<p>Another nice thing about using a known distribution is that we can go beyond normal Monte Carlo and use Bayesian inference for forecasting. Having a Bayesian model has the advantage of being deterministic and smoother, regulating and reducing noise or small sample effects that are sometimes evident in Monte Carlo simulations.</p>
<p>As always these results need to be used with caution and a full understanding of what they mean. Nonetheless having models to help us understand the mechanisms and principles behind our intuitions can be very handy at times.</p>
</section>
<section id="validation" class="level3">
<h3 class="anchored" data-anchor-id="validation">Validation</h3>
<p>Just to check that the model we’ve described actually works, the shaded area in the plot below shows 100,000 results from Monte Carlo simulations of delivery times for 40 pieces of work when 5 items are delivered together. The red line represents the negative binomial model described here. Hopefully, they match as perfectly now as they did when I wrote this.</p>
<iframe title="Monte Carlo delivery-time simulation compared with the negative binomial model" width="700" height="470" src="negative-binomial-plot.html" frameborder="0">
</iframe>


</section>


 ]]></description>
  <category>software-engineering</category>
  <category>statistics</category>
  <guid>https://johnhearn.github.io/posts/2024-09-29-predictability-and-batch-size/</guid>
  <pubDate>Sat, 28 Sep 2024 16:30:00 GMT</pubDate>
</item>
<item>
  <title>Dunbar’s number deconstructed (again)</title>
  <link>https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/</link>
  <description><![CDATA[ 




<p><a href="../2024-09-10-dunbars-number-good-science-within-limits/">Last week</a> I was looking at how Dunbar arrived at his famous number and learnt a lot about the effects of different types of linear regression and the limits of their predictive power. I concluded that, while the science was good, the wide error margin in the linear regression over log transformed data means that we need to apply a good deal of caution about arriving at any specific number.</p>
<p>The data I used was from one of his more recent papers<sup>1</sup> so my results were slightly different from his. It was tabulated in the paper and I was just too lazy to copy it out. Nevertheless I was left with some curiosity about how the results might have changed using the original data.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;Dunbar, Robin I. M., and Susanne Shultz. ‘Social Complexity and the Fractal Structure of Group Size in Primate Social Evolution’. Biological Reviews 96, no. 5 (October 2021): 1889–1906. <a href="https://doi.org/10.1111/brv.12730">doi.org/10.1111/brv.12730</a>.</p></div></div><section id="reproducing-dunbars-exact-results" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="reproducing-dunbars-exact-results">Reproducing Dunbar’s exact results</h2>
<p>So yesterday, with a combination of OCR and careful copying, I recovered Dunbar’s original data from his paper. Here’s a reproduction of a plot of the data - satisfyingly similar to the original.</p>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/dunbars data.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Comparison with Dunbar’s data taken from his original paper.</figcaption>
</figure>
</div></div><p><br> <img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/dunbars data original.png" class="img-fluid" alt="Figure 1. Mean group size for individual genera plotted against neocortex ratio (relative to rest of brain; i.e., total brain volume less neocortex). (●) Polygamous anthropoids; (+) monogamous anthropoids; (○) diurnal prosimians; (□) nocturnal prosimians; (△) hominoids."></p>
<p>Not sure why those axis limits were chosen, maybe just rounding to orders of ten. In any case group sizes less than 1 make no sense and neocortex ratios beyond that of humans are not useful. From now on the plots will focus on the meaningful ranges. They’ll also have the vertical axis on the right so that predicted values are easier to read off.</p>
<p>To this graph Dunbar’s original fit is overlaid. One again his famous number, 150, appears as the predicted value for human group size.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/dunbars result original.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 2: Same plot restricting the axes to a meaningful range and extending Dunbar’s fit to the measured neocortex ratio for humans (4.102).</figcaption>
</figure>
</div>
<p>Using this data and using exactly the same RMA (aka Geometric) linear regression we can recover his results almost<sup>2</sup> exactly. The next plot shows the agreement along with the 95% confidence interval as calculated following Rayner<sup>3</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn2"><p><sup>2</sup>&nbsp;I believe there are some minor transcription errors in the original paper (or my reading of it) which produce a very slightly different line but the difference is minimal and changes nothing.</p></div><div id="fn3"><p><sup>3</sup>&nbsp;Rayner, J. M. V. ‘Linear Relations in Biomechanics: The Statistics of Scaling Functions’. Journal of Zoology 206, no. 3 (July 1985): 415–39. <a href="https://doi.org/10.1111/j.1469-7998.1985.tb05668.x">10.1111/j.1469-7998.1985.tb05668.x</a>.</p></div></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/my result original.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 3: plot extending the 95% confidence interval of the geometric mean regression out to the measured neocortex ratio for humans (4.102), confirming agreement with Dunbar’s original results.</figcaption>
</figure>
</div>
<p>This agreement was exactly what I was hoping for by using the original data and reproduces Dunbar’s result satisfactorily.</p>
</section>
<section id="residuals" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="residuals">Residuals</h2>
<p>One again we can apply simple residual checks on the data to ensure we are satisfying the linear regression assumptions. The <a href="https://en.wikipedia.org/wiki/Q%E2%80%93Q_plot">qqplot</a> shows the residuals close to a normal distribution.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/residuals distribution original.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 4: Q-Q plot comparing the standardised residuals with a standard normal distribution.</figcaption>
</figure>
</div>
<p>The residuals plot itself shows some variance but no obvious <a href="https://en.wikipedia.org/wiki/Homoscedasticity_and_heteroscedasticity">heteroscedasticity</a>.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/residuals plot original.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 5: Plot of the residuals.</figcaption>
</figure>
</div>
</section>
<section id="confidence-in-the-mean" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="confidence-in-the-mean">Confidence in the mean</h2>
<p>While the fit itself is statistically sound, if we look again at Figure 3, we can see that the logarithmic scale underplays the numerical range. Looking at the same graph with the vertical axis scaled linearly then the problem is clear.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/predict original.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 6: plot extending the 95% confidence interval of the geometric mean regression out to the measured neocortex ratio for humans (4.102).</figcaption>
</figure>
</div>
<p>The confidence interval (which is <em>only for the mean itself</em>) is from under 100 to nearly 250. This is worse than the previous data because the slope is greater. I think you will agree that this is a wide error margin which is partially obscured by the log-log view. If we don’t believe the confidence interval calculation (and we shouldn’t, some doubt has been placed on it<sup>4</sup>, see below) then let’s take a different approach and compare.</p>
<div class="no-row-height column-margin column-container"><div id="fn4"><p><sup>4</sup>&nbsp;Changyong Feng, Hongyue Wang, Naiji Lu, Tian Chen, Hua He, Ying Lü, and Xin Tu. ‘Log-Transformation and Its Implications for Data Analysis’. Shanghai Archives of Psychiatry 26, no. 2 (1 April 2014): 105–9. <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4120293/">10.3969/j.issn.1002-0829.2014.02.009</a>.</p></div></div><p>Assuming the parameters of the fit are normal, <em>as we must because it was an assumption of the regression itself and has been somewhat confirmed empirically</em>, then we can generate random samples of regression lines drawn from those distributions. This is a so-called Monte-Carlo simulation of the regression distributions and gives us an alternative way to histogram the predicted values. The following plot shows 3000 such samples together with a histogram of the predicted values for human group size.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/ncr vs gs mc.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 7: plot of Monte Carlo random samples of the regression line together with a histogram of the predicted value for human group size.</figcaption>
</figure>
</div>
<p>Again we find an average in the right range (see below) but once more with very wide error margins for the prediction. Actually it’s worse. The distribution is clearly heavy tailed towards higher group sizes. This is an expected effect of converting a Normal distribution on a log scale to a linear scale where it becomes Log Normal and therefore long tailed. Taking 1 million such predictions it’s evident that it conforms very closely.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/prediction histogram.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 8: histogram of 1 million predictions fitting very closely with a LogNormal distribution. 95% quantiles are shown as vertical lines at 71 and 368 respectively. Mean is 176.</figcaption>
</figure>
</div>
<p>Taking these results we can confirm that the 95% confidence interval has widened further, from 71 as a lower bound to 368 as the upper. Remember that this is still the range for the mean itself and does not take into account the variability in the samples.</p>
<p>There is another insight here too. The mean of the LogNormal distribution is <strong>not 150 but rather 176</strong>. The reason for this is exactly as stated in <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4120293/">Feng et al.</a> and can be confirmed by direct calculation. The mean of the distribution when transformed back into natural units is <em>not</em> <img src="https://latex.codecogs.com/png.latex?exp(%5Cmu)%20=%20150"> but rather <img src="https://latex.codecogs.com/png.latex?exp(%5Cmu%20+%20%5Csigma%5E2/2)%20=%20176">. The variance shifts the mean.</p>
</section>
<section id="confidence-in-the-prediction" class="level1 page-columns page-full">
<h1>Confidence in the prediction</h1>
<p>We’ve stated several times that until now we have been looking at inferences related only to the prediction of the mean of the regression line, not including the variance in the data itself. Let’s take that into account now. We know the variance in the residuals and under the assumption they are normally distributed in log space then, in principle, we can model the residuals in the predicted value.</p>
<div class="page-columns page-full"><p>The normal distribution of the mean regression and the normal distribution of the residuals is combined using the relation: <img src="https://latex.codecogs.com/png.latex?%F0%9D%92%A9(%5Cmu_1,%20%5Csigma_1%5E2)+%F0%9D%92%A9(%5Cmu_2,%5Csigma_2%5E2)%20=%20%F0%9D%92%A9(%5Cmu_1+%5Cmu_2,%20%5Csigma_1%5E2+%5Csigma_2%5E2)">. We can then carefully extend this to linear space by expressing as a <em>Lognormal</em> distribution with parameters <img src="https://latex.codecogs.com/png.latex?%5Cmu%20=%20ln(10)(%5Cmu_1+%5Cmu_2)"> and <img src="https://latex.codecogs.com/png.latex?%5Csigma%20=%20ln(10)%5Csqrt%7B%5Csigma_1%5E2+%5Csigma_2%5E2%7D">. </p><div class="no-row-height column-margin column-container"><span class="">The <img src="https://latex.codecogs.com/png.latex?ln(10)"> factors are necessary because the original data was transformed base 10 and the relation between the normal and the Lognormal is via the natural logarithm.</span></div></div>
<p>Using this new distribution the confidence interval has now widened still further. The 95% interval ranging between 31 to over 740. The mean now is above 200 due to the upward effect of the increased variance.</p>
</section>
<section id="conclusion" class="level1 page-columns page-full">
<h1>Conclusion</h1>
<p>With the original data it’s been possible to reproduce Dunbar’s famous results almost perfectly.</p>
<p>However it has become even clearer that the extrapolation of the regression line to human scales is highly questionable. The prediction is well outside the existing data, leading to wide error margins, and the log transformation exaggerates the error still further. If we also take into account the residual variance in the data, the confidence interval of any prediction widens beyond useful limits (according to my analysis, the 95% interval is from 71 up to 740).</p>
<p>This is not an issue related to the type of regression nor any internal structure in the samples but rather the overwhelming error margins that make sensible prediction based on the available data unreasonable.</p>
<p>This is all consistent with the Stockholm University group’s “deconstruction”<sup>5</sup> of not only the number itself, but the notion that such a number is even sensible to talk about.</p>


<div class="no-row-height column-margin column-container"><div id="fn5"><p><sup>5</sup>&nbsp;Patrik Lindenfors, Patrik Lindenfors, Andreas Wartel, Andreas Wartel, Johan Lind, and Johan Lind. ‘“Dunbar’s Number” Deconstructed’. Biology Letters 17, no. 5 (1 May 2021): 20210158–20210158. <a href="https://doi.org/10.1098/rsbl.2021.0158">10.1098/rsbl.2021.0158</a>.</p></div></div></section>


 ]]></description>
  <category>science</category>
  <category>statistics</category>
  <guid>https://johnhearn.github.io/posts/2024-09-17-dunbars-number-deconstructed-again/</guid>
  <pubDate>Tue, 17 Sep 2024 06:30:00 GMT</pubDate>
</item>
<item>
  <title>Investigating Dunbar’s number</title>
  <link>https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/</link>
  <description><![CDATA[ 




<p>In a seminal paper<sup>1</sup> from 1992, <a href="https://en.wikipedia.org/wiki/Robin_Dunbar">Robin Dunbar</a> extrapolated from the brain measurements of different animal species and their typical social group sizes, to make a now famous prediction about human social group size. His analysis led him to what has become known as <em>Dunbar’s number</em>, 150, which has had multiple <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number#Applications">applications</a> in different organisational contexts.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;Dunbar, R. I. M. ‘Neocortex Size as a Constraint on Group Size in Primates’. Journal of Human Evolution 22, no. 6 (1 June 1992): 469–93. doi: <a href="https://doi.org/10.1016/0047-2484(92)90081-j">10.1016/0047-2484(92)90081-j</a>.</p></div><div id="fn2"><p><sup>2</sup>&nbsp;Patrik Lindenfors, Patrik Lindenfors, Andreas Wartel. ‘“Dunbar’s Number” Deconstructed’. Biology Letters 17, no. 5 (1 May 2021): 20210158–20210158. <a href="https://doi.org/10.1098/rsbl.2021.0158">10.1098/rsbl.2021.0158</a>.</p></div></div><p>Prompted by a definition in this <a href="https://martyoo.medium.com/stop-team-topologies-fd954ea26eca">blog post</a>, and out of pure curiosity, I searched for a bit more information and stumbled on an relatively recent <a href="https://theconversation.com/dunbars-number-why-my-theory-that-humans-can-only-maintain-150-friendships-has-withstood-30-years-of-scrutiny-160676">article by him</a> in which he gives an overview of his research. The article sounded a little snarky to me and snarkiness continued in the comments. It seems he was responding to some research<sup>2</sup> published by a group at Stockholm University who ran a set of modern statistical tools over the original dataset and were unable to draw the same conclusions that Mr Dunbar had. This group then responded to Dunbar’s article by writing another <a href="https://theconversation.com/why-we-dispute-dunbars-number-the-claim-humans-can-only-maintain-150-friendships-161944">article</a> explaining their position in more detail.</p>
<p>Since working with real data and reading the work of different research groups is a fantastic way to learn, I decided to do a bit of amateur data analysis. I learned <em>a lot</em> and hopefully by writing down what I saw, I’ll learn even more.</p>
<section id="fitting-the-data" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="fitting-the-data">Fitting the data</h2>
<blockquote class="blockquote">
<p>On a double log-log plot, my grandmother fits on a straight line - <a href="https://en.wikiquote.org/wiki/Fritz_Houtermans">Fritz Houtermans</a></p>
</blockquote>
<div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">Much of the mathematics of this section can be found in Rayner, J. M. V. ‘Linear Relations in Biomechanics: The Statistics of Scaling Functions’. Journal of Zoology 206, no. 3 (July 1985): 415–39. <a href="https://doi.org/10.1111/j.1469-7998.1985.tb05668.x">10.1111/j.1469-7998.1985.tb05668.x</a>.</span></div></div>
<p>Here’s an example of a similar data set to the one used in the original studies. The data is tabulated in the paper but it’s a lot to copy out so I took a similar data set published by the same author in a later paper. Figure 1 is a plot of the data. For multiple species of animal, it shows the ratio of the size of the neocortext to the size of the rest of the brain (<img src="https://latex.codecogs.com/png.latex?C_r">) on the horizontal axis and the average social group size (<img src="https://latex.codecogs.com/png.latex?N">) for that species on the vertical axis.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/ncr vs gs.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 1: a plot of neocortext ratio <img src="https://latex.codecogs.com/png.latex?N_r"> against average social group size <img src="https://latex.codecogs.com/png.latex?G"> for 39 animal species.</figcaption>
</figure>
</div>
<p>Neither Dunbar nor his critics used the data in this form however, they used its logarithm. This is a common technique used under the assumption that it will make skewed data (as this is) appear more symmetrical (normal). There is no explanation of the reasons for the transform in this particular case. Nonetheless it has an important effect on the results. We’ll come back to this point later. Here’s the transformed data.</p>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/dunbars data.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Comparison with Dunbar’s data taken from his original paper.</figcaption>
</figure>
</div></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/log10ncr vs log10gs.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 2: a plot of <img src="https://latex.codecogs.com/png.latex?log_%7B10%7DN_r"> against <img src="https://latex.codecogs.com/png.latex?log_%7B10%7DG"> for the same 39 animal species.</figcaption>
</figure>
</div>
<p>I’ve presented it in exactly the same way as Dunbar’s paper. Although the data is slightly different the similarity is clear. Also, it does <em>look</em> a bit more like a straight line now and the variance is a little less pronounced. I’m not sure how valid this kind of subjective judgement is.</p>
<p>Figure 3 overlays Dunbar’s original result onto this data set and there is no surprise. The line (the equation for which is given explicitly in the paper) is projected out to show the predicted human mean group size which can be seen to be close to 150. This is the source of Dunbar’s number.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/dunbars result.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Figure 3: plot extending the 95% confidence interval of the geometric mean regression out to the measured neocortex ratio for humans (4.102).</figcaption>
</figure>
</div>
<p>I’m tried to reproduce this result but for now we note that for the analysis to work we have to make the strong assumption that an errors in the measurements are normally distributed. The choice of using the log-log transformation another strong assumption that we’re taking as fact for the moment but we will return to it.</p>
<p>The parameters of the line are determined using linear regression which attempts to find the best straight line through the points. The question arises: what is the best straight line? It turns out that there are multiple ways of defining best fit and depending on which you chose you can get different results.</p>
<p>The most common type of linear regression is most commonly called <strong>Ordinary Least Squares</strong><sup>3</sup> (OLS) where the the best line is chosen to be the one that minimises the squares of the vertical difference between each point and itself. This is the most basic regression technique taught in statistics classes.</p>
<div class="no-row-height column-margin column-container"><div id="fn3"><p><sup>3</sup>&nbsp;Dunbar calls it LSR (Least Squares Regression) in his paper.</p></div></div><div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">For more discussion about regression with <em>known</em> error weights in both axes for each sample see this <a href="https://doi.org/10.1119/1.1632486">paper</a>. In this case we don’t know the error margins in the data.</span></div></div>
<p>The problem with OLS, as Dunbar points out in his original paper and again in his recent article, is that by minimising only the vertical distances there is an implicit assumption that there are no errors in the measurements on the x-axis, which is not true in this case.</p>
<p>To take these (unknown) error margins into account in both axes we can choose to minimise the <em>geometric</em> distance between the points and the line. This is called <strong>Geometric Mean Regression</strong><sup>4</sup> in much of the modern literature. The geometric distance is the <em>area</em> between the point and the line, the triangle spanning both the distance along the x-axis and the distance along the y-axis.</p>
<div class="no-row-height column-margin column-container"><div id="fn4"><p><sup>4</sup>&nbsp;Dunbar calls it RMA (Reduced Major Axis) but just as heads up it turns out the the web page that Dunbar references in his article to explain RMA is wrong. For a neat overview of the main types of regression I’d recommend the paper by Xu, S. (2014). A Property of Geometric Mean Regression. The American Statistician, 68(4), 277–281. doi:<a href="https://doi.org/10.1080/00031305.2014.962763">10.1080/00031305.2014.962763</a>.</p></div></div><p>One <a href="https://doi.org/10.1016/0096-3003(94)00161-V">cited</a> problem with geometric regression is the extra difficulty in the interpretation of confidence intervals for the parameters. I haven’t seen that as being any more of a problem for this type of regression than for any other but I might be wrong. Please read the paper if you are interested.</p>
<p>I did both geometric and OLS regression to compare the difference. Figure 4 shows the results of both types of linear regression transformed back into the original, untransformed scales.</p>
<p><br> <img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/ols vs gmr.png" class="img-fluid" alt="Figure 4: plot showing the regression results of both OLS and Geometric regressions with a 95% confidence interval."></p>
<p>This confirms Dunbar’s assertion that OLS considerably <em>underestimates</em> the slope of the regression line, as compared to geometric one.</p>
<p>There are two other important things to note here beyond the difference between the two lines. First notice the upward curve of the regression lines over the original data. This is a result of the log transformations, essentially producing an approximately exponential fit due to the differing scales of the two axes.</p>
<p>The second thing to notice is the wide spread of the confidence interval for this line. This is also exaggerated by the log transformation. In fact, the validity of the confidence intervals after transformation is highly questionable. See <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4120293/">Feng et al.</a> for more details.</p>
<p>Notwithstanding the above caveats, what happens if we extrapolate the curve in an attempt to predict a typical group size for humans?</p>
<p><br> <img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/predict.png" class="img-fluid" alt="Figure 5: plot extending the 95% confidence interval of the geometric mean regression out to the measured neocortex ratio for humans (4.102)."></p>
<p>A direct extrapolation of this data using the geometric fit gives a group size prediction for humans as very approximately ~100. This well below Dunbar’s result but some difference should be expected due to the different data. It does however highlight the disproportionate effect of the log-log transformation on the prediction. It also puts into question the conceptual validity of extrapolating so far outside the available data. Remember that this is the spread of the confidence interval of just the mean itself and does not extrapolate from the variance seen in the rest of the data. This is a key point and an interesting realisation for me personally.</p>
<p>Until now we have collected a series of assumptions about the data that we’ll look at in turn in light of the analysis.</p>
<section id="log-log-transformation" class="level3">
<h3 class="anchored" data-anchor-id="log-log-transformation">Log-log transformation</h3>
<p>It is evident that by taking the log-log transformation of the data we have made the confidence intervals of the predictions extremely wide. Was this choice justified? Let’s take a look at the distributions of the data before and after the transformation. <br> <img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/data distributions.png" class="img-fluid" alt="Figure 6: Distribution of original and log transformed neocortex ratio, N_r, and mean group size, G."></p>
<p>They show that the transformation has gone some way to make the distributions more symmetrical, especially the group size. It might be interesting to see the results without taking the log of the neocortex ratio but it’s confirmed that this transformation does make sense in this case, even though it does introduce other problems elsewhere. It’s a trade-off I guess.</p>
</section>
<section id="distribution-of-errors" class="level3">
<h3 class="anchored" data-anchor-id="distribution-of-errors">Distribution of errors</h3>
<p>It was assumed that the errors in the measurements in both axes were normally distributed. Figure 7 takes a closer look at the distributions of the residuals of the log transformed data against their regression line.</p>
<p><br> <img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/residuals distribution.png" class="img-fluid" alt="Figure 7: Q-Q plot comparing the standardised residuals with a normal distribution N(0,1)."></p>
<p>This residuals are reasonably close to a normal distribution which is one possible justification for the log-log transformation on the data.</p>
<p>We would like to check for the presence of <a href="https://en.wikipedia.org/wiki/Homoscedasticity_and_heteroscedasticity">heteroscedasticity</a> which can cause ordinary least squares estimates of the variance (and, thus, standard errors) of the coefficients to be biased, possibly above or below the true of population variance. A quick plot of the residuals doesn’t give us too much cause for concern.</p>
<p><br> <img src="https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/residuals plot.png" class="img-fluid" alt="Figure 8: Plot of the residuals."></p>
<p>We might like to check that more formally with a Breusch-Pagan test. Again this can be taken as further justification for the log-log transformation.</p>
</section>
</section>
<section id="confirmation-bias" class="level2">
<h2 class="anchored" data-anchor-id="confirmation-bias">Confirmation bias</h2>
<p>More recently additional evidence has been gathered to support the original Dunbar number of 150. As we’ve seen, this number is at best a very rough guess of the mean and doesn’t include the potential variance over the extrapolated range. Nonetheless there is a very real possibility of confirmation bias in later results. The phenomena starts when people latch on to these specific numbers and then <a href="https://teamtopologies.com/news-blogs-newsletters/dunbars-numbers-and-communities-of-practice-q-and-a-with-emily-webber">send</a> their correlates to Dunbar who then catalogues them as supporting evidence.</p>
<p>What have military units got to do with Christmas card lists? Christmas card lists are definitely a social phenomenon but it if far from clear which band they should be in. If the results had been 50, say, then it would have been taken as evidence for that smaller group size. It’s a post-hoc correlation.</p>
</section>
<section id="conclusion" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>So, after all this analysis, I learnt a great deal about regression considerations. Least squares never seemed so controversial until I started this. My results came in below Dunbar’s original results. This means nothing, of course, but it does lend some credence to the critics suspicions which would be compatible with my little investigation here.</p>
<p>I also learnt a lot about what can and can’t be said about Dunbar’s number as a concept.</p>
<p>First, none of this says anything about the nested structure of the group sizes and other predictions made subsequently, which have also been used widely<sup>5</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn5"><p><sup>5</sup>&nbsp;The Team Topologies book uses Dunbar’s work as a basis for team size discussions. For them, “Dunbar’s number” (as defined in the glossary) actually refers to results from Dunbar’s <a href="https://onlinelibrary.wiley.com/doi/pdf/10.1111/brv.12730">later work on nested group sizes</a> and is related but different to Dunbar’s number as usually understood.</p></div></div><p>Secondly, it is most <strong>definitely not a maximum or upper limit</strong>, as often <a href="https://martyoo.medium.com/stop-team-topologies-fd954ea26eca">stated</a>. We need to be careful not to confuse the confidence interval of the sample mean with a measure of confidence of the prediction.</p>
<p>It is clear to me now that stating Dunbar’s number as 150 is misleading and misses a great deal of context. Even assuming the validity of the model and the regression, it is a predicted mean value extrapolated far outside the underlying data with extremely wide error bars and <strong>needs to be treated with a great deal of caution</strong>. The prediction has even wider margins to the point of losing some of its meaning as a useful concept.</p>


</section>


 ]]></description>
  <category>science</category>
  <category>statistics</category>
  <category>organisations</category>
  <guid>https://johnhearn.github.io/posts/2024-09-10-dunbars-number-good-science-within-limits/</guid>
  <pubDate>Tue, 10 Sep 2024 07:30:00 GMT</pubDate>
</item>
<item>
  <title>On not having a map</title>
  <link>https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/</link>
  <description><![CDATA[ 





<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/map_grid.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Dora and Boots are on one side of an island and they want to get to the other side.</figcaption>
</figure>
</div></div><p>Dora the Exploradora and her monkey friend Boots are on a mission. They are on one side of a magical island and they need to get to the other.</p>
<p>She gets out her trusty map from her purple rucksack and sees that there are no roads or paths so she carefully plans the very best route she can with the information she has, avoiding the scary dark forest valley and skirting the rocky mountains. On the way they are met with unexpected obstacles: gullies, fallen trees and riddling trolls. Undeterred and with a little of our help, they finally get to their destination. We did it! We did it!</p>
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/map_planned.png" class="img-fluid"></p>
<p>Some time later, Diego (and Baby Jaguar, presumably) are faced with the same challenge. Unfortunately it’s now really foggy. (“Niebla”, you say it!) Poor chap doesn’t have a map and only has a compass to guide him roughly in the right direction. Diego looks around and bravely heads along the easiest route he can see, roughly east, feeling his way across the island the best he can, avoiding only the obstacles he can see around him. He makes it to the other side.</p>
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/map_diego.png" class="img-fluid"></p>
<p>Dora did great, she feels lucky she had her map! However, Diego made it too. They wonder how much having the map helped. Now that they’re across the island they look back at the route they took. With the benefit of hindsight they can see that perhaps the route she took based on the map wasn’t the best one and, in fact, it might have been better to go a different way.</p>
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/map_hindsight.png" class="img-fluid"></p>
<p>It turns out that in this case Diego actually did better than Dora, even without the map. In fact he’s not far from the best route in hindsight.</p>
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/map_all.png" class="img-fluid"></p>
<p>By not sticking to a predefined plan he was able to navigate around those fallen trees and even some of those pesky trolls.</p>
<p>Is this true in general or just a fluke. Let’s try and find out.</p>
<section id="so-how-much-did-the-map-help" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="so-how-much-did-the-map-help">So how much did the map help?</h2>
<p>To answer this question I had an idea for a toy model to compare Dora’s and Diego’s adventures and did a bit of programming to try it out. The images above are actual screenshots. Here’s the setup.</p>
<p>The island is a grid. Getting from one point on the grid to an adjacent point has a difficulty representing the lie of the land (the difficulty of movement). This is calculated numerically as a cost function where the cost depends on the change in height<sup>1</sup>. This corresponds to the intuitive notion that steeper sections are more difficult to traverse than flat sections and any bumps on the ground make the going harder.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;Mathematically, the cost function at between any two adjacent points <img src="https://latex.codecogs.com/png.latex?c"> is calculated as <img src="https://latex.codecogs.com/png.latex?c%20=%201+%5Cdelta%20h"> where <img src="https://latex.codecogs.com/png.latex?%5Cdelta%20h"> is the change on height.</p></div><div id="fn2"><p><sup>2</sup>&nbsp;The use of the word “ruggedness” here is deliberate. We can draw on some sophisticated science to crystallise this idea and give it real-world meaning.</p></div></div><p>Then we consider two grids. One grid is set up like a <em>map</em>, an idealised representation of the contours of valleys and mountains and a few of the largest features. Another grid represents the <em>actual terrain</em>, with additional detail of smaller obstacles which are not marked on the map. The <em>ruggedness</em><sup>2</sup> of the terrain is applied randomly but its magnitude is parametrisable.</p>
<p>For different levels of ruggedness, I ran a shortest path finding algorithm <sup>3</sup> across the map (Dora’s planned route) and across the terrain using step sizes of varying lengths. Think about the size of these steps as corresponding to different amounts of fog for Diego: <em>visibility</em> is the second parameter. In every case calculating the total difficulty over the whole journey.</p>
<div class="no-row-height column-margin column-container"><div id="fn3"><p><sup>3</sup>&nbsp;<a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra’s algorithm</a>.</p></div></div><p>Since this is a numerical model we can get a feeling for what’s happening by studying how the model behaves as the parameters (<em>ruggedness</em> and <em>visibility</em>) change. I ran the model thousands of times to get a distribution of results for different parameter settings.</p>
</section>
<section id="diego-vs-dora" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="diego-vs-dora">Diego vs Dora</h2>
<p>First let’s see how Diego’s and Dora’s experience compares in general as the ruggedness of the terrain changes.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/dora vs diego.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">This graph shows the difficulty of the route followed as the ruggedness of the terrain increases. The width of the ribbon represents the variability of the results over thousands of runs of the model. The model is set up in such a way that <em>ruggedness</em> and <em>difficulty</em> are directly related, in fact linearly related. This is visible as the slope of the lines. Similarly, the intercept of the line is the <em>minimal</em> difficultly of the map. There are no units on the axes. That’s because it’s not clear to me how those units would map to the real world anyway. By removing the units I’m saying that I don’t know: as Carveth Read astutely pointed out, “<em>It is better to be vaguely right than exactly wrong.</em>”.</figcaption>
</figure>
</div>
<p>As you might guess, Dora did well when the map was highly accurate (the far left of the graph), but, unfortunately for her, any additional ruggedness of the terrain which was not marked on the map made her experience much more difficult than expected when following the route she planned in advance.</p>
<p>Diego on the other hand didn’t stick to a predefined route so sometimes was able to adapt to obstacles not on the map. As the ruggedness of the terrain increases past a certain point he consistently does better than Dora.</p>
<p>This is the first observation: <strong>there is a trade-off between following a plan and adapting as you go and it depends (at least) on the <em>ruggedness</em> of your terrain</strong>. There is a book in that statement<sup>4</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn4"><p><sup>4</sup>&nbsp;Just as a teaser, Simon Wardley talks at great length about how <a href="https://blog.gardeviance.org/2015/06/why-agile-lean-and-six-sigma-must-die.html">novelty generates uncertainty</a>, leading to a rugged terrain while mature components can be planned more confidently. Bent Flyvbjerg has researched <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4924942">uniqueness bias</a> and a tendency for us to believe that our situation is different from any other, <em>over</em>estimating the uncertainty. Or Chris Rodgers’ Wiggly</p></div></div><p>A second observation here, often overlooked, is predictability. This can be interpreted on the graph as the width of the ribbon. A narrow ribbon means low variability which corresponds to greater predictability. Again Dora’s progress is very predictable when the map matches reality but that predictability decreases rapidly as reality bites. Interestingly, <strong>Diego’s progress is much more predictable than Dora’s as the terrain becomes more and more unpredictable; the variability in his routes is, in fact, fairly constant</strong>.</p>
<p>More predictability means being able to have greater confidence in the final outcome. In many projects involving multiple external stakeholders this predictability is actually more important than the details of any plan itself. Read that again.</p>
<p>Third observation: <strong>Past a certain point of ruggedness, not only does Diego consistently do better than Dora, he also tends to pick a path close to the best route in hindsight</strong>. Let’s see this on a graph.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/diego vs hindsight.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Although rarely finding the absolute best route, Diego’s route deviates in a relatively small and consistent way.</figcaption>
</figure>
</div>
<p>Intuition holds in the sense that the best route also gets more and more difficult (and variable) as the ruggedness of the actual terrain increases. Diego hardly ever finds perfection but, interestingly, his experience tracks surprisingly closely the best possible one. Again we can see that Diego’s strategy is more predictable than Dora’s as he can “think on his feet” and avoid any trouble encountered on the way.</p>
</section>
<section id="so-how-much-does-doras-experience-deviate-from-her-best-made-plans" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="so-how-much-does-doras-experience-deviate-from-her-best-made-plans">So how much does Dora’s experience deviate from her best made plans?</h2>
<p>The relationship between the plan and reality has become a cliché. As Field Marshal Helmuth von Moltke is <a href="https://quoteinvestigator.com/2021/05/04/no-plan/">said</a> to have said:</p>
<div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">Often shorted to “<em>No plan survives first contact with the enemy.</em>”. Also compare with Mike Tyson’s rather more <a href="https://quoteinvestigator.com/2021/08/25/plans-hit/">pithy</a> version. I’m not a big fan of quotes related to violence but they do seem to abound in this context.</span></div></div>
<blockquote class="blockquote">
<p>“<em>No plan of operations extends with any certainty beyond the first encounter with the main enemy forces.</em>”</p>
</blockquote>
<p>Can we see this in our little model? The answer is yes and very strikingly.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/dora plan vs reality.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Dora made the very best plan with the information available to her. Nonetheless she typically ends up deviating a lot from the plan.</figcaption>
</figure>
</div>
<p>When the map perfectly matches the terrain then her experience is as expected but as the map fails to show the detail, the difficulty and variability of her experience increases enormously. Compare this to Diego’s experience compared to the very best route. Field Marshal Helmuth von Moltke was definitely right.</p>
<p>There is another maxim which is usually <a href="https://quoteinvestigator.com/2017/11/18/planning/">attributed</a> to Eisenhower:</p>
<blockquote class="blockquote">
<p>“<em>Plans are worthless, but planning is everything.</em>”</p>
</blockquote>
<p>The strategies used by Dora and Diego are two extremes but they can be combined. We can plan and we can adapt too. What happens if we lift the fog on Diego to allow him to “look ahead” with greater visibility to the future.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/diego fog.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Diego’s experience improves as the fog lifts and he has greater visibility of the future.</figcaption>
</figure>
</div>
<p>If we give Diego predictive superpowers he gets closer and closer to the best possible route. Perfect prediction is equivalent to 20/20 hindsight.</p>
<p>If we believe Winston Churchill who said:</p>
<blockquote class="blockquote">
<p>“<em>…the best generals are those who arrive at the results of planning without being tied to plans.</em>”</p>
</blockquote>
<p>Then Diego would have made a pretty good general!</p>
</section>
<section id="a-model-is-just-a-model" class="level1 page-columns page-full">
<h1>A model is just a model</h1>
<p>Erica Thomson, in her book <em>Escape from Model Land: How Mathematical Models Can Lead Us Astray and What We Can Do About It (2022)</em> wrote:</p>
<blockquote class="blockquote">
<p>“<em>Models are not simple tools that we can take up, use and put down again. The process of generating a model changes the way that we think about a situation, encourages rationalisation and storytelling, strengthens some concepts and weakens others.</em>”</p>
</blockquote>
<p>This is a model with many implicit assumptions, for example, there are no existing paths or roads on the map. Assuming these were clear of obstacles then these would potentially give Dora a significant advantage. What roads would do in effect is to reduce uncertainty in the map, making her strategy more effective. Likewise dead ends like impassable cliffs or rivers are unlikely to be present.</p>
<p>Also there is some flexibility in the destination, it’s not a specific location. If it were then Diego would have a more difficult time finding it because he wouldn’t be able to “go roughly east”. There is some scope here for further study. Are there strategies that Diego could follow to get to a specific spot in a reliable way?</p>
<p>The model is set up in such a way that <em>ruggedness</em> and <em>difficulty</em> are directly related, in fact linearly related. This is visible as the slope of the line on the graph. Similarly the intercept of the line is the <em>minimal</em> difficultly of the map. On the other hand, there are no units on the axes. That’s because it’s not clear to me how those units would map to the real world anyway. By removing the units I’m saying that I don’t know<sup>5</sup>. I could attempt to build them in but then it would be a different model.</p>
<div class="no-row-height column-margin column-container"><div id="fn5"><p><sup>5</sup>&nbsp;“<em>It is better to be vaguely right than exactly wrong.</em>” ― Carveth Read, Logic: Deductive and Inductive (1920)</p></div></div><p>In fact, where did the the parameters of <em>ruggedness</em> and <em>visibility</em> even come from? Well, they came from my intuition and I had to play around with the model to see if my intuition was valid or not. It turned out that it was but it doesn’t preclude other parametrisations and observations.</p>
<p>As it stand, it does do two things, however. Firstly, it reifies my intuition. It’s not just some fuzzy idea in my head, or me being persuaded by appeal to authority. It’s a numerical model that has built-in assumptions and a story to tell. You might have another.</p>
<p>Secondly, it uses data to demonstrate the results, not hand wavy suppositions. Assumptions in, observations of data out. Both ends require a certain leap of faith but at least it’s an honest, transparent and verifiable one. That’s one way to escape Model Land.</p>
<p>It took me a couple of full days to create this model and another couple to write up the results. My intuition is stronger now and I have a model which generates interpretable data. When someone says Alfred Korzybski’s phrase “<em>the map is not the terrain</em>” again, I will think back to this model. The next time someone asks me why we need a plan, I’ll have an honest answer.</p>
<p>Next draft:</p>
<p>Remove repetition of the “no axis” stuff.</p>
<p>Need a “So what?” section which explicitly interprets the model in terms of project management.</p>
<p>GPS?</p>


</section>


 ]]></description>
  <category>modelling</category>
  <category>statistics</category>
  <guid>https://johnhearn.github.io/posts/2024-08-22-on-not-having-a-map/</guid>
  <pubDate>Thu, 22 Aug 2024 19:30:00 GMT</pubDate>
</item>
<item>
  <title>Flow and Cognitive Load</title>
  <link>https://johnhearn.github.io/posts/2024-02-06-flow-and-cognitive-load/</link>
  <description><![CDATA[ 




<p>“Maximise flow by minimising cognitive load”. Wait a minute…</p>
<p>I’ve had a bad back recently and have been scrolling LinkedIn more than I usually do. One thing I noticed was the words “flow” and “cognitive load” coming up a lot, quite often together. Now I’ve heard three people in real life saying almost the exact phrase above and I think it warrants a bit of extra thought.</p>
<p>I guess the first whiff of something fishy is that it smacks a bit of our old friend and adversary Mr Frederick Winslow Taylor. The suggestion of optimisation and words like “cognitive”, sound quite sciency, don’t they? Scientific management has been around a long time. It tends to get sidelined during times of boom to be wheeled out again during the bust. We are no longer in a boom cycle so fair enough but the deserved concern around its dehumanising aspect still remains and we need to be careful. (Also, to me, cognitive load and flow seem to have something vaguely reminiscent of time and motion. Probably my imagination.)</p>
<p>There’s also something fishy about the use of the phrase “cognitive load” itself. Are we talking about an individual’s capacity for learning the skills required to do the work or the whole team’s ability to assimilate that knowledge as a group? It seems quite confused. In either case, there is no better formula to demotivate a skilled person than to remove the need for their skill, especially if you say it’s for their own good. I hope that what is really being meant by “cognitive load” is to minimise the bureaucracy, the burdensome tools, the handoff coordination, the form filling, the approval seeking, all the stuff that really gets in the way of flow.</p>
<p>And talking of flow… secondly, and obviously, flow means so many things. It could just mean not being blocked. It could refer to a simple experience like an easy payment process. It could imply a certain grace and ease such as the flow of a passage of text or a piece of music while at the same time, and less elegantly, it could mean a slicker pipe through which material can be discharged quickly.</p>
<p>Most interestingly to me, “flow” could mean a mental disposition such as the one conceived by Mihály Csíkszentmihályi where work is energising, engaging and enjoyable. Everyone from programmers to PowerPoint wranglers know and enjoy that feeling. However Csíkszentmihályi proposed that the most productive and satisfying work wasn’t done by minimising the difficulty of the task, but by balancing the difficulty with the skill of the person or people involved. If that were the case we don’t want to minimise cognitive load but to balance it.</p>
<p>Whatever the case, whatever maximising fast flow means to you and whatever minimising cognitive load means to you, we’ve been saying for years that it’s velocity, not speed that’s important, that is direction and purpose over how fast you go. We’ve also said that we need skilled and motivated employees fully engaged in the work they are doing. Maximising flow and minimising cognitive load sounds like it could be a recipe for the best possible feature factory.</p>



 ]]></description>
  <category>software-engineering</category>
  <category>philosophy</category>
  <guid>https://johnhearn.github.io/posts/2024-02-06-flow-and-cognitive-load/</guid>
  <pubDate>Tue, 06 Feb 2024 12:30:00 GMT</pubDate>
</item>
<item>
  <title>A Little Every Day</title>
  <link>https://johnhearn.github.io/posts/2023-02-22-a-little-every-day/</link>
  <description><![CDATA[ 




<p>People have given me a lot of advise over the years. “Do what you love.” Ha ha. “Measure twice, cut once.” Well, that would depend, wouldn’t it.</p>
<p>In the end there are only a couple of phrases which stick with me. One was “Always run to something, not from something.” Run to a new job, not from an old one. Run to safety, not from a fire. Maybe I’ll write about why that helps sometime.</p>
<p>Another piece of advice which I still apply is “Do a bit every day.” Let me explain.</p>
<p>This was given to me by a friend of my parents when I had a young family and I was renovating our home. The size of the task ahead was daunting and time was in short supply because nappies needed changing, bread needed winning and the basic necessities of life needed attending to. It was overwhelming.</p>
<p>I tried planning the work and sticking to the plan but I always slipped behind which was stressful in itself, just adding to the problem. I suffered and the family suffered.</p>
<p>Then I tried to “do one job every day” and it changed everything. The “one job”, Joe told me, needn’t be big, in fact it could be as simple as placing a single tile or laying a single floorboard. Sometimes the job was just 5 minutes when everyone else was in bed. No pressure to finish, no schedule to keep to.</p>
<p>The amazing thing was that as the days passed, stuff got done. As if by magic walls were tiled and floors were laid. And the stress was gone.</p>
<p>I put the success of this “technique” down to two things. First, sometimes just getting started is the hardest part. After that the job becomes easier than you thought and it’s done before you know it. The other factor is that as the days pass you maintain some momentum. A couple of times I stopped doing a job everyday and it became harder to get that momentum back. Each and every day something gets done and you move closer to your goal.</p>
<p>When the house was finally complete it turned out to be an immensely rewarding experience.</p>



 ]]></description>
  <category>organisations</category>
  <category>philosophy</category>
  <guid>https://johnhearn.github.io/posts/2023-02-22-a-little-every-day/</guid>
  <pubDate>Wed, 22 Feb 2023 09:30:00 GMT</pubDate>
</item>
<item>
  <title>Inverse Markov</title>
  <link>https://johnhearn.github.io/posts/2022-10-29-inverse-markov/</link>
  <description><![CDATA[ 




<p>Markov chains are a fantastic tool for modelling how stuff moves about over a network of possible states. Think about them as probabilistic state machines. Its uses are widespread, from Google’s <a href="https://saattrupdan.github.io/2020-08-07-pagerank/">PageRank algorithm</a> which models the way users move about the internet to analysing the ways players move around a <a href="http://www.bewersdorff-online.de/amonopoly/">Monopoly board</a>. We can also use it as a simple model of workload in a distributed system or team.</p>
<div class="page-columns page-full"><p>In my case I had some economic data and I wanted to see if I could make a fortune finding a trend in the market so I found myself wanting to determine a Markov chain model from real-world data.</p><div class="no-row-height column-margin column-container"><span class="">Needless to say the result was negative and my wealth has increased only in terms of knowledge.</span></div></div>
<p>It turns out that this topic was studied extensively in the last century<sup>1</sup>’<sup>2</sup> and, although simple and well understood, it took me a while to get my head around it. I’m writing it up here to help me remember.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;Lee, T. C., Judge, George G., Takayama, T., 1965. On Estimating the Transition Probabilities of a Markov Process. American Journal of Agricultural Economics 47, 742–762. <a href="https://doi.org/10.2307/1236285">https://doi.org/10.2307/1236285</a></p></div><div id="fn2"><p><sup>2</sup>&nbsp;Lee, T. C., Judge, George G., Zellner, A., 1968. Maximum Likelihood and Bayesian Estimation of Transition Probabilities. Journal of the American Statistical Association 63, 1162–1179. <a href="https://doi.org/10.1080/01621459.1968.10480918">https://doi.org/10.1080/01621459.1968.10480918</a></p></div></div><p>For the background of the maths behind Markov chains in general there are numerous resources <a href="https://www.google.com/search?q=markov+chain">online</a>. Basically we repeatedly apply a transformation to the current state to turn it into a new state. We then apply the same transformation to the new state to create the next state and so on. Remarkably, no matter which state we start in, while conditions stay constant the system <em>always</em> converges to the same steady state (plus a bit of noise). We can use this fact to work backwards from observations of the sequence of states and infer the model that would have generated them.</p>
<p>Say we have a state represented by a vector <img src="https://latex.codecogs.com/png.latex?%5Cnu"> and a transformation represented by a matrix <img src="https://latex.codecogs.com/png.latex?P">. Based on a sequence of noisy observations of the state, <img src="https://latex.codecogs.com/png.latex?%5Cleft(%5Cnu_1,%20%5Cnu_2...%5Cnu_n%5Cright)">, what is our best estimate of <img src="https://latex.codecogs.com/png.latex?P">?</p>
<p>We’ll need plenty of observations so let’s put them together into the same matrix: <img src="https://latex.codecogs.com/png.latex?V%20=%20%5Cleft%5B%5Cnu_1,%20%5Cnu_2...%5Cnu_%7Bn-1%7D%5Cright%5D"></p>
<p>Each application of <img src="https://latex.codecogs.com/png.latex?P"> takes us to the subsequent state so we have <img src="https://latex.codecogs.com/png.latex?VP%20=%20%5Cleft%5B%5Cnu_2,%20%5Cnu_3...%5Cnu_n%5Cright%5D%20=%20U"></p>
<p>We end up with an equation involving <img src="https://latex.codecogs.com/png.latex?%5Cnu_1,%20%5Cnu_2...%5Cnu_n">.</p>
<p>Since <img src="https://latex.codecogs.com/png.latex?P"> is a square matrix we will need <img src="https://latex.codecogs.com/png.latex?n"> to be at least equal to the number of states. If we have more then even better. Using the <a href="https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse"><em>pseudo-inverse</em></a> of the states we can get the <a href="https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse#Linear_least-squares">least squares</a> best estimate for P. <img src="https://latex.codecogs.com/png.latex?%5Chat%20P%20=%20V%5E+%20%5Ctimes%20U"></p>
<p>Where the <img src="https://latex.codecogs.com/png.latex?%5E+"> symbol represents the generalised inverse which in fact is easy enough to calculate, <img src="https://latex.codecogs.com/png.latex?V%5E+%20=%20(V'V)%5E%7B-1%7DV'">.</p>
<p>In Julia, assuming we already have the state data in the variable <img src="https://latex.codecogs.com/png.latex?%5Cnu">, this becomes</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1">V <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ν[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="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>
<span id="cb1-2">U <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;">:</span>n,<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>]</span>
<span id="cb1-3"></span>
<span id="cb1-4">V⁺ <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;">inv</span>(V<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">'</span>V)V<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">'</span></span>
<span id="cb1-5"></span>
<span id="cb1-6">P̂ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> V⁺<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>U</span></code></pre></div></div>
<p>This works fairly well but it has problem. The pseudo-inverse knows nothing of the constraint on the probabilities which must all be positive. Various workarounds exist but in the end we end up having to fiddle with the numbers to get them all positive in the optimal way.</p>
<p>Luckily for us, optimisation algorithms for situations like these have also been studied extensively. Julia’s <a href="https://jump.dev/">JuMP eco-system</a>, for instance, provides tools which eat these kinds problems for breakfast.</p>
<p>We are optimising for the minimum square difference between <img src="https://latex.codecogs.com/png.latex?U"> and <img src="https://latex.codecogs.com/png.latex?VP"> where the entries in <img src="https://latex.codecogs.com/png.latex?P">, always positive, are the variables we are trying to determine, <img src="https://latex.codecogs.com/png.latex?p_%7Bij%7D%20%3E%200%20%5Cspace%20%5Cforall%20i,j"></p>
<p>Specifically, we are finding values for <img src="https://latex.codecogs.com/png.latex?p_%7Bij%7D"> with the objective of minimising <img src="https://latex.codecogs.com/png.latex?(U-VP)%5E2%20=%20(U-VP)'%20%5Ccdot%20(U-VP)"></p>
<p>We also have the condition that the entries must be positive and the constraint that the rows must sum to 1, <img src="https://latex.codecogs.com/png.latex?%5Csum_%7Bj%7D%7Bp_%7Bij%7D%7D%20=%201">.</p>
<p>Assuming <img src="https://latex.codecogs.com/png.latex?r"> is the number of states, in JuMP we can define the problem like this:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb2-1">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;">Model</span>(Ipopt.Optimizer)</span>
<span id="cb2-2"></span>
<span id="cb2-3"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@variable</span>(model, p[<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>r<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> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>)</span>
<span id="cb2-4"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@objective</span>(model, Min, (U <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> V<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>P)<span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'*(U - V*P))</span></span>
<span id="cb2-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> j <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>r</span>
<span id="cb2-6">    <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">@constraint</span>(model, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(p[i] <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> j<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>r<span class="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;">==</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>)</span>
<span id="cb2-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-8"></span>
<span id="cb2-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">optimize!</span>(model)</span>
<span id="cb2-10"></span>
<span id="cb2-11">Pest <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;">reshape</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">value</span>.(p), r,r)</span></code></pre></div></div>
<p>With this code I’ve been able to recover a good approximation to the transition matrix in testing, the approximation becoming better with increasing sample size.</p>
<p>We could give the algorithm an initial hint based on the pseudo-inverse described above but in my experiments the optimisation algorithm is fast enough to not require it.</p>
<p>The method could be improved by quantifying the uncertainty in the results. On way would be to batch observations and look at the distribution of results. Another might be to apply a bayesian approach using a Dirichlet multinomial as the prior and updating with the observations. A problem for another time.</p>




 ]]></description>
  <category>statistics</category>
  <category>modelling</category>
  <guid>https://johnhearn.github.io/posts/2022-10-29-inverse-markov/</guid>
  <pubDate>Sat, 29 Oct 2022 06:46:00 GMT</pubDate>
</item>
<item>
  <title>Accelerate and Farmers’ Gates</title>
  <link>https://johnhearn.github.io/posts/2022-07-08-accelerate-and-farmers-gates/</link>
  <description><![CDATA[ 





<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2022-07-08-accelerate-and-farmers-gates/accelerate-book.jpg" class="img-fluid figure-img"></p>
<figcaption class="margin-caption"><a href="https://www.goodreads.com/book/show/35747076-accelerate">Accelerate: Building and Scaling High-Performing Technology Organizations</a> by Nicole Forsgren, Jez Humble, Gene Kim</figcaption>
</figure>
</div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://upload.wikimedia.org/wikipedia/commons/b/bd/Farm_gate_-_geograph.org.uk_-_538713.jpg" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">The kind of gate I’m talking about.</figcaption>
</figure>
</div></div>
<p>In the rural community where I grew up there was a common aphorism: “<em>A good farmer has good gates</em>” and generations of experience showed that this is a pretty good rule of thumb.</p>
<p>If you took a group of researchers and surveyed the local farmers’ general habits, including how well maintained their gates are, do you think they could infer a relation? Could they even <strong>predict</strong> which were the better farmers based on their gates? Yes they probably could, because <em>a good farmer has good gates</em>.</p>
<p>In the jargon, this is <em>predictive inference</em>, and it is the kind of inference that <em>Accelerate</em> describes<sup>1</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;In chapter 12 they go into some detail.</p></div></div><p>Does having good gates <em>make</em> you a good farmer? Of course not. The relation between gates and the type of farmer is <strong>not causal</strong>.</p>
<p>Can a farmer become a better farmer through better maintenance of his gates? Hmm. <em>Accelerate</em> might say that “good gates <em>drive</em> good farming”. IMO the word “drive” is bearing quite a lot of weight to make that statement.</p>
<p>The unfortunate situation is that predictive inference explains nothing. It may validate a hypothesis based on a theory but the scientific literature is littered with such validations that later turned out to be false<sup>2</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn2"><p><sup>2</sup>&nbsp;Try <a href="https://projects.fivethirtyeight.com/p-hacking/">this website</a> to demonstrate your political point.</p></div></div><p>For explanation you need, at least, <em>causal inference</em> and that is much much harder. Causal inference requires a causal statistical model which is notoriously hard to get right.</p>
<p>My feeling is that some of the key indicators in <em>Accelerate</em> really are causal but others are just the equivalent of good gates.</p>




 ]]></description>
  <category>statistics</category>
  <category>software-engineering</category>
  <guid>https://johnhearn.github.io/posts/2022-07-08-accelerate-and-farmers-gates/</guid>
  <pubDate>Fri, 08 Jul 2022 18:01:00 GMT</pubDate>
</item>
<item>
  <title>Why Lognormal?</title>
  <link>https://johnhearn.github.io/posts/2021-08-19-why-log-normal/</link>
  <description><![CDATA[ 




<div class="page-columns page-full"><p>The <a href="https://en.wikipedia.org/wiki/Log-normal_distribution">log-normal distribution</a> is <a href="https://www.semanticscholar.org/paper/What-Do-You-Mean-Revisiting-Statistics-for-Web-Time-Ciemiewicz/65162028a420dbefdcb71c6def616e4aa1b126b1?p2df">sometimes</a> used as a simple model for the distribution of latencies from real-world systems. By no means is it a perfect model and sometimes <a href="https://newrelic.com/blog/best-practices/expected-distributions-website-response-times">alternatives</a> are better, especially when the load is far below maximum capacity but at high load I’ve empirically found it to be a reasonable fit.</p><div class="no-row-height column-margin column-container"><span class="">It’s important to understand that models are just models. Under different situations the latency distributions may be completely different.</span></div></div>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-08-19-why-log-normal/log-normal-fit.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Real world data from proprietary production system under high load.</figcaption>
</figure>
</div>
<p>One reason that this is important is that the log-normal is long-tailed. This means that while the average response time under these conditions might be excellent, the top percentiles might be totally unacceptable so we end up having to oversize more than we might like.</p>
<p>I’ve often wondered why this might be the case and answers to this question are often very hand-wavey. Here I attempt a totally unscientific explanation.</p>
<p>Let’s take a <a href="https://erikbern.com/2018/03/27/waiting-time-load-factor-and-queueing-theory.html">standard result</a> from queueing theory and say that the latency is a function of the load factor,<img src="https://latex.codecogs.com/png.latex?f">, defined as the ratio of arrival rate to service rate.</p>
<p><img src="https://latex.codecogs.com/png.latex?Latency%20%5Cpropto%20%5Cfrac%7B1%7D%7B1-f%7D"></p>
<p>Latencies fly off to infinity when the load factor approaches 1. Makes sense because if the requests arrive faster than they can be serviced then the queue will grow until something else gives.</p>
<p>Now we might assume there is some dispersal in the load factor due to the natural burstiness of incoming traffic. We don’t want to model this noise with a normal distribution because our load factor is strictly between 0 and 1. A better choice is the <a href="https://en.wikipedia.org/wiki/Beta_distribution">beta distribution</a> which has exactly that property and just so happens to nicely approximate the normal distribution if we <a href="https://www.johndcook.com/blog/normal_approx_to_beta/">choose the right parameters</a>.</p>
<p>Now what happens to the distribution of latencies? Well, luck would have it that the transformation of the beta distribution by the formula above gives us the so called <a href="https://en.wikipedia.org/wiki/Beta_prime_distribution">beta-prime distribution</a>. And that approximates a LogNormal distribution surprisingly well, especially around the tail.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-08-19-why-log-normal/log-normal-vs-beta-prime.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Beta-prime distribution compared to the Log Normal distribution by method of moments.</figcaption>
</figure>
</div>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-08-19-why-log-normal/log-normal-vs-beta-prime-error.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Absolute error tapers away.</figcaption>
</figure>
</div>
<p>What does this mean? Absolutely nothing and it’s wrong for all kinds of reasons. Nonetheless it might give a clue to the usefulness of the LogNormal distribution and its tail and why the Erlang/Gamma distributions sometimes are more indicative.</p>
<p>The intuition would be that the natural variance in the load produces latencies heavily skewed by the <a href="https://www.r-bloggers.com/2015/07/hockey-elbow-and-other-response-time-injuries/">elbow curve</a> of the latency formula, especially when under high load, producing the long tail. Under lower loads the skewing effect is less and the distribution loses it’s long tail, in fact becoming more like an Erlang distribution after all.</p>
<p>Source code for the graphs is <a href="https://github.com/johnhearn/notebooks/blob/master/beta-prime.ipynb">here</a>.</p>



 ]]></description>
  <category>statistics</category>
  <category>software-architecture</category>
  <guid>https://johnhearn.github.io/posts/2021-08-19-why-log-normal/</guid>
  <pubDate>Thu, 19 Aug 2021 06:21:00 GMT</pubDate>
</item>
<item>
  <title>Load Balancing Strategies and their Distributions</title>
  <link>https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/</link>
  <description><![CDATA[ 




<p>Results of a simulation to compare four of the most well known load balancer strategies:</p>
<ol type="1">
<li><strong>Round robin</strong> - requests are routed to each of the available servers in turn</li>
<li><strong>Least occupied</strong> - requests are routed to the server with least current requests</li>
<li><strong>Random</strong> - requests are routed to a randomly selected server</li>
<li><strong>Random 2</strong> - requests are routed to one of two randomly selected servers, where the chosen server has least current requests (see <a href="https://www.haproxy.com/blog/power-of-two-load-balancing/">here</a> and <a href="https://www.nginx.com/blog/nginx-power-of-two-choices-load-balancing-algorithm">here</a>)</li>
</ol>
<section id="the-experiment" class="level2">
<h2 class="anchored" data-anchor-id="the-experiment">The experiment</h2>
<ul>
<li><strong>Arrival rate</strong>: requests arrive with a Poisson process with mean <img src="https://latex.codecogs.com/png.latex?%5Clambda">.</li>
<li><strong>Service rate</strong>: request completions are distributed with a Log-Normal distribution (although any realistic distribution shows the same characteristics).</li>
<li><strong>Load factor</strong> is the ratio of arrival rate to completion rate, ranging strictly from 0.0 to 1.0. If greater than 1 then the requests would accumulate without end.</li>
</ul>
<p>We keep a record of the number of requests in the system for a single server. The <a href="https://nbviewer.jupyter.org/github/johnhearn/notebooks/blob/0209bfb5a128fd332250cf341b97064281ea4feb/Smadex/Load%20Balancing%20Stats.ipynb">Julia code</a> is here.</p>
</section>
<section id="the-results" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="the-results">The results</h2>
<p>The difference in the distributions of the concurrent requests in with the different strategies is clear.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/hist-20-75.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Distribution of concurrent requests under different load balancing strategies. The requests are distributed over 20 servers with average arrival rate of 10 per step at 75% load factor.</figcaption>
</figure>
</div>
<p>Notice how remnants of the input and output distributions are still visible in the <em>round robin</em> strategy. The <em>least occupied</em> and <em>random 2</em> strategies tend to concentrate the distribution around its average. On the other hand the <em>random</em> strategy seems to spread the distribution still further.</p>
<p>How does the average vary with load factor?</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/mean-20-p.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Change in average concurrent requests as load factory varies, keeping number of servers at 20.</figcaption>
</figure>
</div>
<p>All strategies perform progressively worse as load factor increases, as would be expected. However the <em>least occupied</em> and <em>random 2</em> strategies are noticeably better that the others, even at higher load factors.</p>
<p>And how does it change with number of servers?</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/mean-c-80.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Change in average concurrent requests as number of servers varies, keeping load factor constant at 80%.</figcaption>
</figure>
</div>
<p>Clearly the best strategies require a minimum number of servers over which to spread the requests. That number is relatively small (in this example around 10) and very little improvement is observed with additional servers. The others are unaffected by number of servers.</p>
</section>
<section id="variance" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="variance">Variance</h2>
<p>The spread in concurrent requests will translate to a spread in latencies too. For a distributed systems we are usually interested in maintaining predictable latencies and minimising long-tails, so we want to minimise this spread. It’s visibly clear that <em>least occupied</em> is the best in this case as it has the narrowest distribution. Let’s have a look at the variance for each one, taking <em>round robin</em> as the base.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/variance-20-p.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Comparison of variance of the distribution of concurrent requests under different load balancing strategies, keeping the number of servers at 20.</figcaption>
</figure>
</div>
<p>What is the relationship between number of servers and the variance?</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/variance-c-80.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Change in variance under different load balancing strategies as number of servers increases.</figcaption>
</figure>
</div>
<p>We can see that when there is only a single server, all strategies are the same (obviously). Both the <em>round robin</em> and <em>random</em> strategies have little or no effect on the variance, no matter how many servers there are in the cluster. Although bot <em>least occupied</em> and <em>random 2</em> fare better, the <em>least occupied</em> has a clear advantage here and seems to be able to capitalise on additional servers more effectively.</p>
</section>
<section id="shedding" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="shedding">Shedding</h2>
<p>We employ a shedding mechanism to help keep request distributions under control independently of the load balancing strategy. How does this affect the results? Here we apply a simple shedding of requests by disallowing more than 20 concurrent requests per server.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/hist-20-75-shedding20.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Distribution of concurrent requests under different load balancing strategies, shedding requests above 20 per server.</figcaption>
</figure>
</div>
<p>The mean of the worse strategies has actually gone down, however much more shedding is being done. That means that server throughput (serviced requests) should be lower. On the other hand the average latencies will also be higher due to the higher load on the server.</p>
</section>
<section id="conclusion" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>

<div class="no-row-height column-margin column-container page-columns page-full"><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/entropy-c-80.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">As an aside, we can also calculate the entropy of the distribution and see (as shown in the graph above) that it has also has <strong>decreased</strong> for the <em>least occupied</em> and <em>random 2</em> strategies while it has actually <strong>increased</strong> for the random one. One interpretation of these results is that the <em>random</em> strategy introduces a little bit of new uncertainty into the system. On the other hand <em>least occupied</em> and <em>random 2</em> actually remove uncertainty. This is the load balancer equivalent of <a href="https://en.wikipedia.org/wiki/Maxwell's_demon">Maxwell’s demon</a>, applying work to each request in order to reduce its uncertainty.</figcaption>
</figure>
</div></div><p>Of all the strategies <em>round robin</em> and <em>random</em> are disastrous and either do nothing to improve the distribution of requests or actually make it worse. However, the <em>least occupied</em> and <em>random 2</em> strategies are able to take advantage of multiple servers to not only reduce the mean but also reduce the variance across the cluster.</p>
<p>While the <em>least occupied</em> is slightly better in terms of the spread of requests, the <em>random 2</em> has some other advantages. Firstly, it’s slightly simpler and therefore faster in practice because only 2 servers are checked for each request rather than all of them. More importantly, it avoids servers which are (re)starting receiving all the load immediately. This is useful when the server needs some time to warmup caches, etc.</p>


</section>

 ]]></description>
  <category>software-architecture</category>
  <category>statistics</category>
  <guid>https://johnhearn.github.io/posts/2021-04-03-load-balancing-strategies/</guid>
  <pubDate>Sat, 03 Apr 2021 16:27:00 GMT</pubDate>
</item>
<item>
  <title>Polynomial Chaos</title>
  <link>https://johnhearn.github.io/posts/2020-05-1-polynomial-chaos/</link>
  <description><![CDATA[ 




<div class="page-columns page-full margin-video">
<iframe class="margin-video-frame" src="https://www.youtube.com/embed/Z-Qio-n6yPc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="">
</iframe>
<div class="no-row-height column-margin column-container margin-video-caption">
<span><strong>Emily Gorcenski - Polynomial Chaos: A technique for modeling uncertainty</strong> - <em>Polynomial chaos is a somewhat obscure technique that leverages a natural connection between probability distributions and orthogonal polynomial families. This talk demonstrates the technique and its applications</em>.</span>
</div>
</div>
<p><em>(The Julia code for this blog is available in my GitHub notebooks repo and online <a href="https://nbviewer.jupyter.org/github/johnhearn/notebooks/blob/master/Poly%20Chaos%20Approximation.ipynb" target="_blank">here</a>.)</em></p>
<p>This talk appeared recently in my YouTube recommendations and with a title like “Polynomial Chaos” I had to take a look. This is a summary of what I learnt mainly to help my own understanding.</p>
<p><strong>Polynomial Chaos Expansion</strong> (aka PCE, also known as Wiener Chaos Expansion.) was a technique introduced just before the second world war by Norbert Wiener. The use of the word chaos is different from the way we understand it today and seems to come from its application to the statistical study of white noise.</p>
<p>In a very similar way to how the <a href="https://en.wikipedia.org/wiki/Fourier_series#Hilbert_space_interpretation">Fourier</a> and <a href="https://en.wikipedia.org/wiki/Laplace_transform">Laplace</a> transforms are related to the exponential functions, there are <strong>strong relationships</strong> between certain <strong>probability distributions</strong> and corresponding families<sup>1</sup> of <strong>orthogonal polynomials</strong>.</p>
<div class="no-row-height column-margin column-container page-columns page-full"><div id="fn1"><p><sup>1</sup>&nbsp;Catalogued in the <a href="https://en.wikipedia.org/wiki/Askey_scheme">Wiener-Askey scheme</a>.</p></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2020-05-1-polynomial-chaos/hermite-polynomials.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">I’m imagining it in a similar way to how a continuous oscillation can be parameterised by only its frequency and amplitude in the Fourier case, though I’m not sure how far that analogy goes. This plot of the polynomials themselves does seem a bit sine-wavey.</figcaption>
</figure>
</div></div>
<p>Also like the Fourier and Laplace versions, the transformed version of the distribution has many useful properties which can be used for similar purposes, like <strong>approximation</strong> and <strong>solving differential equations</strong>.</p>
<p>In these notes, and following closely the talk mentioned above, I’ll try and describe how you might approximate a general probability distributions using this technique.</p>
<p>Polynomial chaos extends from the fact<sup>2</sup> that any stochastic variable (within reason) can be transformed into a system of orthogonal polynomials: <img src="https://latex.codecogs.com/png.latex?X%20=%20%5Csum_%7Bi=0%7D%5E%5Cinfty%20X_i%20%5Cphi_i(%5Czeta)">.</p>
<div class="no-row-height column-margin column-container"><div id="fn2"><p><sup>2</sup>&nbsp;The <a href="https://en.wikipedia.org/wiki/Karhunen%E2%80%93Lo%C3%A8ve_theorem">Kosambi–Karhunen–Loève theorem</a> states that a stochastic process can be represented as an infinite linear combination of orthogonal functions, analogous to a Fourier series representation of a function on a bounded interval.</p></div></div><p>If the polynomials are chosen correctly then they can represent certain probability distributions very compactly. For example, for a normally distributed random variable the polynomials are <a href="https://en.wikipedia.org/wiki/Hermite_polynomials">Hermite polynomials</a>, <img src="https://latex.codecogs.com/png.latex?%5Cphi_i(%5Czeta)%20%5Cequiv%20H_i(%5Czeta)">, and the transformed random variable can be written <img src="https://latex.codecogs.com/png.latex?X%20=%20%5Cmu%20H_0(%5Czeta)%20+%20%5Csigma%20H_1(%5Czeta)%20=%20%5Cmu%20+%20%5Csigma%20%5Czeta">, where <img src="https://latex.codecogs.com/png.latex?%5Cmu"> and <img src="https://latex.codecogs.com/png.latex?%5Csigma"> are the mean and standard deviation respectively, which makes sense.</p>
<p>The relationship between the distribution and the polynomials can be seen most clearly in the definition of the inner product of the polynomials themselves. In this case the Hermite polynomial inner product is defined like this:</p>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Clangle%20H_i(%5Czeta)%5C,%20H_j(%5Czeta)%20%5Crangle%20%20=%20%5Cint_%7B-%5Cinfty%7D%5E%5Cinfty%20H_i(%5Czeta)%20H_j(%5Czeta)%20%5Ccolor%7Bred%7D%7Be%5E%7B-%5Cfrac%7B%5Czeta%5E2%7D%7B2%7D%7D%7D%5C,%20d%5Czeta%20=%20%5Ccolor%7Bred%7D%7B%5Csqrt%7B2%5Cpi%7D%7D%20i!%20%5Cdelta_%7Bij%7D"></p>
<p>The elements in <img src="https://latex.codecogs.com/png.latex?%5Ccolor%7Bred%7D%7Bred%7D"> being both the weighting function for the product and the distribution itself.</p>
<p>We want to approximate a general probability distribution, <img src="https://latex.codecogs.com/png.latex?F(k)"> by expanding in terms of a chosen set of polynomials belonging to another distribution, say <img src="https://latex.codecogs.com/png.latex?G(%5Czeta)">. To do this the trick is to transform both <img src="https://latex.codecogs.com/png.latex?F(k)"> and <img src="https://latex.codecogs.com/png.latex?G(%5Czeta)"> into the same, uniform distribution using an inverse transformation of both:</p>
<p><img src="https://latex.codecogs.com/png.latex?k%20=%20F%5E%7B-1%7D(u)%20%5Cstackrel%7B%5Csmall%7B%5Ctextrm%7Bdef%7D%7D%7D%7B=%7D%20h(u)"></p>
<p><img src="https://latex.codecogs.com/png.latex?%5Czeta%20=%20G%5E%7B-1%7D(u)%20%5Cstackrel%7B%5Csmall%7B%5Ctextrm%7Bdef%7D%7D%7D%7B=%7D%20l(u)"></p>
<p>Then use the Galerkin projection to compute the individual coefficients:</p>
<p><img src="https://latex.codecogs.com/png.latex?k_i%20=%20%5Cfrac%7B%5Clangle%20k%20H_i(%5Czeta)%20%5Crangle%7D%7B%5Clangle%20H_i%5E2(%5Czeta)%20%5Crangle%7D%20=%20%5Cfrac%7B1%7D%7B%5Clangle%20H_i%5E2%20%5Crangle%7D%20%5Cint_%7B-%5Cinfty%7D%5E%5Cinfty%20k%20H_i(%5Czeta)%20e%5E%7B-%5Cfrac%7B%5Czeta%5E2%7D%7B2%7D%7D%5C,%20d%5Czeta%20=%20%5Cfrac%7B1%7D%7B%5Clangle%20H_i%5E2%20%5Crangle%7D%5Cint_0%5E1%20h(u)%20H_i(l(u))%5C,%20du%20"></p>
<p>All this is verbatim from the talk. I also planned to transcribe her code (to Julia of course) but I found a better plan.</p>
<p>Dealing with the polynomials from scratch is pretty tedious so I looked for a package that would do it for me. As it turns out there is a Julia package called <a href="https://timueh.github.io/PolyChaos.jl/stable">PolyChaos</a> which does most of this. Looking through the documentation I didn’t see this actual use case so I did it myself.</p>
<div class="page-columns page-full"><p>Using the PolyChaos package we can easily define our Hermite polynomials. In PolyChaos they are called <code>GaussOrthPoly</code><sup>3</sup>:</p><div class="no-row-height column-margin column-container"><img src="https://upload.wikimedia.org/wikipedia/commons/9/9e/HarmOsziFunktionen.png" class="img-fluid" alt="Quantum_harmonic_oscillator)."></div></div>
<div class="no-row-height column-margin column-container"><div id="fn3"><p><sup>3</sup>&nbsp;The name Hermite is used for the variant of the Hermite polynomials used by physicists. I remember they appear as part of the study of the quantum linear harmonic oscillator which I studied in university.</p></div></div><div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-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;">PolyChaos</span></span>
<span id="cb1-2"></span>
<span id="cb1-3">op_gauss <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;">GaussOrthoPoly</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)</span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">H</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;">evaluate</span>(i, x, op_gauss)</span></code></pre></div></div>
<p>We also compute the inner (scalar) products, <img src="https://latex.codecogs.com/png.latex?%5Clangle%20H_i%5E2(%5Czeta)%20%5Crangle"> for our polynomials, PolyChaos conveniently does this for us:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb2-1">sp <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;">computeSP2</span>(op_gauss)</span></code></pre></div></div>
<p>Then we define our inverse functions for testing:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb3-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="cb3-2"></span>
<span id="cb3-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">inv_cdf</span>(dist) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">quantile</span>(dist, u)</span>
<span id="cb3-4"></span>
<span id="cb3-5">h <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;">inv_cdf</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Exponential</span>())</span>
<span id="cb3-6">l <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;">inv_cdf</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Normal</span>())</span>
<span id="cb3-7"></span>
<span id="cb3-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">integrand</span>(i) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> u <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h</span>(u)<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">*H</span>(i, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">l</span>(u))</span></code></pre></div></div>
<p>In this case the distribution we want to approximate if the <code>Exponential</code> distribution, <code>h</code>, and is defined as a partial function. The Gassian we will approximate it with is defined as the partial function <code>l</code>. Finally de define our integrand in terms of <code>h(u)</code>, <code>H</code> and <code>l(u)</code>, for a particular index, <code>i</code>.</p>
<p>Now we perform the integration, for which PolyChaos also has us covered.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb4-1">int_op <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;">Uniform01OrthoPoly</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, addQuadrature<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>
<p>We’ll truncate the approximation to <code>p</code> polynomials:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb5-1">p <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;">21</span></span>
<span id="cb5-2">ki <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;">integrate</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">integrand</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>), int_op) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> sp[i] for 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>p]</span></code></pre></div></div>
<p>Then we can reconstitute the approximated distribution using 5000 Gaussian random variables, <img src="https://latex.codecogs.com/png.latex?%5Czeta_i">:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb6-1">ζ <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>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span>)</span>
<span id="cb6-2">Σ <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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span>)</span>
<span id="cb6-3"><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>p</span>
<span id="cb6-4">    Σ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> ki[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;">H</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="cb6-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb6-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">histogram</span>(Σ, normed<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>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2020-05-1-polynomial-chaos/reconstitutes-exponential-5000.png" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">Exponential distribution constituted as a sum of transformed gaussian random variables.</figcaption>
</figure>
</div>
<p>With this same code we can now approximate any distribution using random variables drawn from a more manageable distribution of our choice. This would allow us to perform other transformations or analysis which may have been difficult in the original form. It may also be a faster alternative to sampling techniques, like Monte Carlo variants.</p>




 ]]></description>
  <category>mathematics</category>
  <category>statistics</category>
  <guid>https://johnhearn.github.io/posts/2020-05-1-polynomial-chaos/</guid>
  <pubDate>Fri, 01 May 2020 17:00:09 GMT</pubDate>
</item>
<item>
  <title>Stop Using @Autowire</title>
  <link>https://johnhearn.github.io/posts/2020-04-03-stop-using-autowire/</link>
  <description><![CDATA[ 




<p>The <a href="https://spring.io/">Spring Framework</a> is one of the most widely used Java frameworks around. There is a lot of great stuff in the Spring eco-system so it’s a shame to see its flagship feature, a dependency injection container, being widely misused.</p>
<div class="page-columns page-full"><p>First some history.</p><div class="no-row-height column-margin column-container"><span class="">Cheesy quote of the day: „<em>You have to know the past to understand the present.</em>“ — Carl Sagan</span></div></div>
<p>Spring has been around since the early-2000s and was conceived as an <a href="https://www.amazon.com/Expert-One-One-Design-Development/dp/0764543857">antidote</a> to the messy J2EE situation at the time. Its principal (but certainly not its only) attraction was a <strong>strong focus on Inversion of Control</strong> (IoC) and its dependency injection framework emerged amongst a plethora of competing DI containers.</p>
<p>In the beginning we had <em>bean descriptors</em> written in XML (best forgotten) and then<sup>1</sup>, when annotations became fashionable, and driven partly by competing frameworks like PicoContainer and Guice, (much of) the XML was replaced with <code>@Autowire</code>.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;In 2007, apparently.</p></div><div id="fn2"><p><sup>2</sup>&nbsp;<code>@Autowire</code> and the standardised <code>@Inject</code> annotations are essentially the same and Spring supports both. I’ll consider them as synonyms in this post.</p></div></div><p>The strength of <code>@Autowire</code> (and, equally, <code>@Inject</code><sup>2</sup>) is its simplicity: add the annotation and let the framework do the rest.</p>
<p>Even at that time there was a big debate about whether to use constructor or field injection, the former better by design and the latter simpler to apply, but in either case the annotation was required to be present somewhere in the class.</p>
<p>The rather unfortunate consequence of having to add Spring specific code to otherwise clean domain objects was considered a worthwhile trade-off. And since we’re using the annotation anyway why not just add it everywhere?</p>
<p><strong>The annotation is no longer required on constructors and the trade-off is no longer worthwhile</strong>. Nonetheless millions of developers are dragging it into the 2020s needlessly along with its disadvantages.</p>
<p>As an example consider this code:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> MyClass <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-2">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Autowire</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> Foo foo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Autowire</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> Bar bar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-4"></span>
<span id="cb1-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">...</span></span>
<span id="cb1-6"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>This can be converted to the following code without having to do any other changes. Spring will handle it just fine.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> MyClass <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> Foo foo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> Bar bar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-4"></span>
<span id="cb2-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">MyClass</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Foo foo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Bar bar<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>
<span id="cb2-6">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</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;">foo</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> foo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-7">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</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;">bar</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> bar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-8">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-9"></span>
<span id="cb2-10">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">...</span></span>
<span id="cb2-11"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Granted that there are a couple of extra lines of boilerplate code<sup>3</sup> but there are <a href="https://kinbiko.com/java/dependency-injection-patterns/">strong arguments</a> why the second option should be preferred and <code>@Autowire</code> <strong>should now be considered a code smell</strong>, especially on fields or accessors. This post outlines some of them.</p>
<div class="no-row-height column-margin column-container"><div id="fn3"><p><sup>3</sup>&nbsp;If this is important to you then consider using <a href="https://www.baeldung.com/spring-injection-lombok">Lombok to generate the appropriate constructor automatically</a>, but note that that has its own trade-offs.</p></div><div id="fn4"><p><sup>4</sup>&nbsp;From maintainability issues to the IDE warnings about unassigned fields.</p></div></div><p>There are also stylistic reasons<sup>4</sup> but I’ll skip them here and concentrate on pure, cold engineering. Much of the same reasoning can be applied to the use of the <code>@Value</code> annotation as well. The objections can be grouped into two main categories.</p>
<p>Firstly, <strong>it makes it impossible to use the final modifier</strong>. Using the final modifier on fields is an important feature for multiple reasons:</p>
<p>Compilation fails if you have not provided all the necessary dependencies, whereas <code>@Autowire</code> fails at runtime. <strong>Compile time guarantees are stronger and safer than runtime testing</strong>, they just are. It’s easier and quicker to fix compilation errors than it is to find runtime bugs. So much magic makes configuration problems really hard to debug at runtime. <em>You will lose time over this</em>.</p>
<p>The simple fact that a value cannot change after construction gives <strong>additional assurances about the behaviour of the code</strong> just by looking at it. It explicitly declares intent and can help avoid some very hard to find bugs.</p>
<p>Final fields are <a href="https://www.javamex.com/tutorials/synchronization_final.shtml">guaranteed to be synchronised</a> between threads. If you don’t declare fields final, then you must cover thread-safety by some other means, or accept that you don’t have it.</p>
<p>The JVM adds extra care-taking to non-final fields to ensure <a href="https://dzone.com/articles/final-keyword-and-jvm-memory-impact">correct memory ordering</a> which is not needed in final fields. Additionally, <a href="https://bugs.openjdk.java.net/browse/JDK-8233873">there are plans</a> to allow the JIT compiler to aggressively optimise code in the knowledge that a field value will not change, as <a href="https://shipilev.net/jvm/anatomy-quarks/15-just-in-time-constants/">currently happens with static final fields</a>.</p>
<p>That should be enough by itself but there is another major group of objections, namely that it <strong>hides dependencies instead of making them explicit</strong>.</p>
<p>It’s so easy to add an <code>@Autowire</code> annotation to a field that the structure of the object graph almost inevitably becomes messy over time and, if not careful, can even lead to hard to maintain <a href="https://softwareengineering.stackexchange.com/a/12030">circular dependencies</a>.</p>
<p>A long list of dependencies in a constructor is a signal that a class has too many responsibilities (violating the <a href="https://en.wikipedia.org/wiki/Single-responsibility_principle">SRP</a>) but it’s easy for the same number of annotations to go unnoticed inside a class with many fields.</p>
<p><code>@Autowired</code> classes are needlessly harder to test. Either we have to bootstrap the entire framework (see below), make our fields public or use something like Mockito’s <code>@InjectMocks</code>, a good example of engineering a solution to a problem that can been avoided altogether.</p>
<p>It’s a NullPointerException <a href="http://olivergierke.de/2013/11/why-field-injection-is-evil/">waiting to happen</a>. If you construct an instance outside of Spring then the fields must be public or otherwise initialised using setters, breaking encapsulation. It also means it’s possible to create an object in an invalid state breaking the “make invalid state unrepresentable” advice.</p>
<p>Finally, it unnecessarily ties your code to the Spring framework binaries making migrations between frameworks<sup>5</sup> and restructuring of the domain much harder. This also applies to <code>@Service</code>, <code>@Component</code>, etc. which can also be removed but that’s another story.</p>
<div class="no-row-height column-margin column-container"><div id="fn5"><p><sup>5</sup>&nbsp;Unfortunately I’ve had to do several over the years: EBJ -&gt; Spring, Spring -&gt; EJB, Spring Boot 1.x -&gt; Spring Boot 2.x 😠</p></div></div><p>Having said all that, as always there are some notable exceptions to the general rule.</p>
<p>Autowiring with <code>@Bean</code> annotations can (and probably should) be used in Spring configuration classes, which you are likely already using if you’re using Spring. In this case <code>@Autowire</code> is still mostly unnecessary and again you can keep Spring stuff out of your domain. For example:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb3-1"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Configuration</span></span>
<span id="cb3-2"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">static</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> SomeConfiguration <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-3"></span>
<span id="cb3-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Bean</span></span>
<span id="cb3-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> MyClass <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">myClass</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Foo foo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Bar bar<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>
<span id="cb3-6">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">MyClass</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>foo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> bar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb3-7">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-8"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>This may be useful if you want to perform some additional configuration and avoids the <code>@PostConstruct</code> nonsense. Again, the idea is to keep all the Spring based annotations inside the configurations and outside the domain classes. This way your domain classes will be clean and typically easier to test without the heavy machinery of…</p>
<p><code>@SpringBootTest</code> <a href="https://www.baeldung.com/spring-boot-testing">automagically</a> uses <code>@Autowire</code> to inject fully configured objects into your tests. A suitable constructor would be better but JUnit<sup>6</sup> has its limitations. Take for example:</p>
<div class="no-row-height column-margin column-container"><div id="fn6"><p><sup>6</sup>&nbsp;Another ubiquitous annotation magic wielding library</p></div></div><div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb4-1"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@RunWith</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>SpringJUnit4ClassRunner<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;">class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb4-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@ActiveProfiles</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"test"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb4-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@SpringBootTest</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>classes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ApplicationConfig<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;">class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb4-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> BigOldServiceTestIT <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-5"></span>
<span id="cb4-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Autowired</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> BigOldService service<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-7"></span>
<span id="cb4-8">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">...</span></span>
<span id="cb4-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>There are probably more exceptions, there always are. I’ll add them as I think of them. On the other had there are definitely more reasons not to, we haven even talked about anaemic domains and good OO design here. That’ll be for another post.</p>




 ]]></description>
  <category>programming-languages</category>
  <category>software-architecture</category>
  <category>software-engineering</category>
  <guid>https://johnhearn.github.io/posts/2020-04-03-stop-using-autowire/</guid>
  <pubDate>Fri, 03 Apr 2020 12:25:00 GMT</pubDate>
  <media:content url="https://johnhearn.github.io/posts/2020-04-03-stop-using-autowire/icon.png" medium="image" type="image/png" height="129" width="144"/>
</item>
<item>
  <title>Technical Practices for Continuous Delivery</title>
  <link>https://johnhearn.github.io/posts/2020-02-02-cd-dependency-network/</link>
  <description><![CDATA[ 




<p><a href="https://cloud.google.com/devops/#technical">DORA</a> recommends strengthening a core set of <a href="https://cloud.google.com/devops#technical"><strong>technical practices</strong></a><sup>1</sup> to “drive”<sup>2</sup> Continuous Delivery, which in turn “drives” business performance.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;Go to the <a href="https://www.devops-research.com/research.html">website</a> and click on the “Technical Practices” node. Alternatively take a look at their book Accelerate which lays all of this out in detail.</p></div><div id="fn2"><p><sup>2</sup>&nbsp;Causal inference is a stated assumption. It’s debatable whether this is the case but that’s for another time.</p></div><div id="fn3"><p><sup>3</sup>&nbsp;See, for example, <a href="https://vanderburg.org/writing/xpannealed.pdf">Extreme Programming Annealed</a> - Glenn Vanderburg</p></div></div><p>They clearly have internal relationships and, like XP<sup>3</sup>, there is a dependency graph of interlocking practices. For example, it’s difficult to image trunk-based development without some kind of version control. I was curious what it looked like so I gave it a first stab.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2020-02-02-cd-dependency-network/cd-dependency-graph.svg" class="img-fluid figure-img"></p>
<figcaption class="margin-caption">CD Dependency Web</figcaption>
</figure>
</div>
<p>Arrows represent a “supports” relationship. For example: “trunk-based development <em>supports</em> continuous integration”. Some comments:</p>
<hr class="slender" width="50%">
<p><strong>Version control is at the root of the practices</strong>. This is obvious to any practitioner and hardly worth saying. Is anyone not using a VCS in 2020?</p>
<hr class="slender" width="50%">
<div class="page-columns page-full"><p><strong>A loosely coupled architecture <em>supports</em> deployment automation</strong>. Difficulties arise with deployment automation when the <a href="https://www.thoughtworks.com/en-es/insights/blog/architecting-continuous-delivery">codebase is overly monolithic</a> or if distributed components are coupled. Monolithic codebases, even when properly modularised, can result in conflicts. Also overly coupled components result in so called “distributed monoliths” and require complicated deployment sequences. Here we need to distinguish deployment coupling from runtime coupling and talk more about contracts and DDD-style strategic integration patterns.</p><div class="no-row-height column-margin column-container"><span class="">Contracts between distributed components and multiple teams can be nicely understood through <a href="https://twitter.com/hashtag/PromiseTheory">#PromiseTheory</a> which also gives us a model for scaling. A subject for another time.</span></div></div>
<hr class="slender" width="50%">
<p><strong>Database change management <em>supports</em> deployment automation</strong>. If you’ve worked in projects without DB change management you’ll know that it can lead to many problems. Before tools such as Flyway and Liquibase were available maintaining database schema in line with the code base was a serious headache. Database changes had to be synchronised with code changes, often resulting in outages, cache problems and delays.</p>
<hr class="slender" width="50%">
<p>I’ve said that <strong>shifting left on security <em>supports</em> continuous testing</strong>. Testing is not just about features. How many of us have been stung by security concerns appearing late in the development cycle which could have been solved so much more easily if detected earlier? For example penetration testing is nearly always done as late as possible, for whatever reasons. Exposed services or plain text parameters in a development environment are not an issue but penetration tests flag them immediately.</p>
<hr class="slender" width="50%">
<p>Though not listed amongst the main practices, performance concerns appear in two separate guises. First, <strong>comprehensive monitoring and observability</strong> enables performance issues to be made visible and picked up quickly. Second, performance testing is part of any <strong>continuous testing</strong> strategy.</p>
<p>In common with security, performance concerns raised early in development can actually be an antidote to premature optimisation and lead to better design choices through real feedback. For example, if a query is correct but too slow under production load then that can be dealt with early rather than unnecessary DB scaling in production<sup>4</sup>. A box for <strong>shifting left on performance</strong> would fit beautifully between <strong>comprehensive monitoring and observability</strong> and <strong>continuous testing</strong>.</p>
<div class="no-row-height column-margin column-container"><div id="fn4"><p><sup>4</sup>&nbsp;DB level scaling in the presence of slow queries often goes under the euphemism of “tuning”.</p></div></div><hr class="slender" width="50%">
<p>It’s no use building releasable binaries after every commit, multiple times a day, if you are going to deploy to production once a month. This breaks the feedback mechanism and will result in a call for hot-fixes. Hot fixes require separate branches, break TBD and require separate deployment pipelines. Rollback becomes more difficult because ALL the commits in the release will be rolled-back even if they are giving value.</p>
<p>In general I prefer to have a single binary for any version of the software. The corollary is that configuration should be done externally to the binary. There are two main ways to do that. (1) by externalising everything, for example in a properties file in a well know location or (2) packaging configuration inside the binary for ALL environments and configuring a variable with the name of the configuration to load. The first is usually the preferred, if nothing else it means that worries about the security of production keys etc. can be separated from the management of the build itself.</p>
<!--

```graphviz
digraph G {

    node [shape="box"]; // Like XP diagram

    //"Continuous Delivery" // The goal
    "Test automation" // The use of comprehensive automated test suites primarily created and maintained by developers. Effective test suites are reliable—that is, tests find real failures and only pass releasable code.
    "Deployment automation" // The degree to which deployments are fully automated and do not require manual intervention.
    "Trunk-based development" // Characterized by fewer than three active branches in a code repository; branches and forks having very short lifetimes (e.g., less than a day) before being merged into master; and application teams rarely or never having “code lock” periods when no one can check in code or do pull requests due to merging conflicts, code freezes, or stabilization phases.
    "Shift left on security" // Integrating security into the design and testing phases of the software development process. This process includes conducting security reviews of applications, including the infosec team in the design and demo process for applications, using pre-approved security libraries and packages, and testing security features as a part of the automated test suite.
    "A loosely coupled architecture" // Architecture that lets teams test and deploy their applications on demand, without requiring orchestration with other services. Having a loosely coupled architecture allows your teams to work independently without relying on other teams for support and services, which in turn enables them to work quickly and deliver value to the organization.
    "Empowering teams to choose tools" // Teams that can choose which tools to use do better at continuous delivery. No one knows better than practitioners what they need to be effective.
    "Continuous integration (CI)" // A development practice where code is regularly checked in, and each check-in triggers a set of quick tests to discover regressions, which developers fix immediately. The CI process creates canonical builds and packages that are ultimately deployed and released.
    "Continuous testing" // Testing throughout the software delivery lifecycle rather than as a separate phase after “dev complete.” With continuous testing, developers and testers work side by side. High performers practice test-driven development, get feedback from tests in less than ten minutes, and continuously review and improve their test suites (for example, to better find defects and keep complexity under control).
    "Version control" // The use of a version control system, such as Git or Subversion, for all production artifacts, including application code, application configurations, system configurations, and scripts for automating build and configuration of environments.
    "Test data management" // An increasingly important part of automated testing. Effective practices include having adequate data to run your test suite, the ability to acquire necessary data on demand, and the data not limiting the number of tests you can run. We caution that your teams should minimize, whenever possible, the amount of test data needed to run automated tests.
    "Comprehensive monitoring and observability" // Allows teams to understand the health of their systems. Effective solutions enable teams to monitor predefined metrics, including system state as experienced by users, as well as allowing engineers to interactively debug systems and explore properties and patterns as they emerge.
    "Proactive notifications" // Monitoring system health using threshold and rate-of-change warnings to enable teams to preemptively detect and mitigate problems.
    "Database change management" // Database changes don’t slow teams down if they follow a few key practices, including storing database changes as scripts in version control (and managing these changes the same way as production application changes), making database changes visible to everyone in the software delivery lifecycle (including engineers), and communicating with all parties when changes to the application require database changes.
    "Code maintainability" // Systems and tools that make it easy for developers to change code maintained by others, to find examples in the codebase, to reuse other people’s code, and to add, upgrade, and migrate to new versions of dependencies without breaking their code.   

    "Shift left on performance" // Not part of the 

    "Test automation" -> "Continuous testing" // Test automation is a necessary but NOT sufficient requirement for continuous testing. Testers and QA processes are involved.
    "Test automation" -> "Continuous integration (CI)"
    "Version control" -> "Continuous integration (CI)"
    "Version control" -> "Trunk-based development"
    "Trunk-based development" -> "Continuous integration (CI)" // This is necessary because of the requirement to produce canonical builds.
    "Test data management" -> "Test automation"
    "Version control" -> "Database change management"
    "Database change management" -> "Deployment automation"
    "Proactive notifications" -> "Comprehensive monitoring and observability"
    "Continuous integration (CI)" -> "Deployment automation"
    "A loosely coupled architecture" -> "Code maintainability"
    "Shift left on security" -> "Continuous testing"

    "A loosely coupled architecture" -> "Deployment automation" [style=dashed]

    //"Test automation" -> "Continuous Delivery"
    //"Deployment automation" -> "Continuous Delivery"
    //"Trunk-based development" -> "Continuous Delivery"
    //"Shift left on security" -> "Continuous Delivery"
    #"A loosely coupled architecture" -> "Continuous Delivery"
    //"Empowering teams to choose tools" -> "Continuous Delivery"
    //"Continuous integration (CI)" -> "Continuous Delivery"
    //"Continuous testing" -> "Continuous Delivery"
    //"Version control" -> "Continuous Delivery"
    //"Test data management" -> "Continuous Delivery"
    //"Comprehensive monitoring and observability" -> "Continuous Delivery"
    //"Proactive notifications" -> "Continuous Delivery"
    #"Database change management" -> "Continuous Delivery"
    //"Code maintainability" -> "Continuous Delivery"

}
```

-->




 ]]></description>
  <category>software-engineering</category>
  <category>software-architecture</category>
  <guid>https://johnhearn.github.io/posts/2020-02-02-cd-dependency-network/</guid>
  <pubDate>Mon, 03 Feb 2020 07:25:00 GMT</pubDate>
  <media:content url="https://johnhearn.github.io/posts/2020-02-02-cd-dependency-network/cd-dependency-graph.svg" medium="image" type="image/svg+xml"/>
</item>
<item>
  <title>Teams, Systems and Catastrophe</title>
  <link>https://johnhearn.github.io/posts/2020-01-26-teams-systems-and-catastrophe/</link>
  <description><![CDATA[ 




<div class="page-columns page-full"><p>Many surprising discoveries were made in the last century about how groups of connected things behave and interact. I would like to present a couple of the simplest results which, I think, can help us understand some of the phenomena that we see in our daily lives.</p><div class="no-row-height column-margin column-container"><span class="">You’ve probably seen the <a href="https://www.youtube.com/watch?v=VBjxsKNIHD8">murmurations of swallows</a> and the <a href="https://www.youtube.com/watch?v=dU2rLhpaMAY">mesmerising bees</a> which are examples of this.</span></div></div>
<p>To avoid over-abstraction I’ll talk specifically about <strong>people connected through teams</strong> and <strong>distributed software systems connected by dependence</strong>, but the same ideas and mechanisms are widely applicable to many other situations.</p>
<section id="dependency-hell" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="dependency-hell">Dependency Hell</h2>
<p>The first one I want to cover was discovered by mathematicians <a href="https://en.wikipedia.org/wiki/Paul_Erdős">Paul Erdős</a> and <a href="https://en.wikipedia.org/wiki/Alfréd_Rényi">Alfréd Rényi</a> in the late 1950s<sup>1</sup> and concerns the way networks tend to join together as new connections are added.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;Presented in a pair of seminal papers: <a href="http://www.renyi.hu/~p_erdos/1959-11.pdf">On Random Graphs. I</a> [1959] and <a href="http://www.renyi.hu/~p_erdos/1960-10.pdf">On the evolution of random graphs</a> [1960].</p></div></div><p>They considered what would happen if you start with a fixed set of independent things and then progressively add new connections between them at random.</p>
<p>One might think that the connectivity on the whole would increase in proportion with the number of connections, but this is not the case. The connectivity is not only <strong>non-linear</strong><sup>2</sup> but undergoes a <strong>phase transition</strong><sup>3</sup> at which nearly everything joins together very quickly. Let’s see it happening.</p>
<div class="no-row-height column-margin column-container"><div id="fn2"><p><sup>2</sup>&nbsp;<strong>Non-linear: The output changing in a way that is not proportional to the change in the input.</strong> Like the temperature of the shower when it goes from freezing cold to scolding hot after the tiniest of adjustments. We tend to expect linearity, either by nature or nurture, but non-linearity is the norm rather than the exception. To paraphrase Stanislaw Ulam: studying non-linearity is like studying non-elephants.</p></div><div id="fn3"><p><sup>3</sup>&nbsp;<strong>Phase-transition: When a collective undergoes a sudden structural reordering as some parameter of the system is gradually changed.</strong> Most often applied to thermo-dynamic systems but complex systems share many of their characteristics.</p></div></div><p>We start with 20 completely independent objects (people or system components) then start adding connections randomly. What you find is that initially nothing much happens: you have some pairs of things and a few threesomes.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2020-01-26-teams-systems-and-catastrophe/few-connections.png" class="img-fluid figure-img" width="250"></p>
<figcaption class="margin-caption">Few connections</figcaption>
</figure>
</div>
<p>Adding a few more connections and we can see groups starting to coalesce.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2020-01-26-teams-systems-and-catastrophe/transition.png" class="img-fluid figure-img" width="250"></p>
<figcaption class="margin-caption">Transition</figcaption>
</figure>
</div>
<p>However add just a couple more connections and the different connected groups<sup>4</sup> of the network quickly connect together to form much a larger (so-called <em>giant</em>) group.</p>
<div class="no-row-height column-margin column-container"><div id="fn4"><p><sup>4</sup>&nbsp;This are called <em>components</em> in network jargon but that might be bit confusing for software people for whom everything is a component!</p></div></div><div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2020-01-26-teams-systems-and-catastrophe/giant-component.png" class="img-fluid figure-img" width="250"></p>
<figcaption class="margin-caption">Giant component</figcaption>
</figure>
</div>
<p><strong>This happens every time</strong>. If we run the above scenario many many times with a thousand points and plot the size of the largest group, the tendency is remarkable.</p>
<div class="page-columns page-full"><p><img src="https://johnhearn.github.io/posts/2020-01-26-teams-systems-and-catastrophe/phase-transition-erdos-renyi.png" class="img-fluid" style="width:80.0%" alt="Phase transition"></p><div class="no-row-height column-margin column-container"><span class="">Source code for generating these graphics with Julia can be found <a href="https://nbviewer.jupyter.org/github/johnhearn/notebooks/blob/master/Phase%20transitions%20in%20networks.ipynb">here</a>.</span></div></div>
<div class="page-columns page-full"><p>The effect is surprisingly non-linear. In other words, as the number of random connections between things reaches a certain threshold then <strong>nearly all the things will be connected together</strong>. In the simplest model, the number of connections just needs to be greater than half the number of things.</p><div class="no-row-height column-margin column-container"><span class="">This morning I had to remove some oil from the engine of my car. I very very gently adjusted the sump bold to allow the dark oil to escape gradually. Instead, it went jumped from a dribble to a great stream of blackness all down my arm. That’s non-linearity.</span></div></div>
<p>For people networks this is the first part<sup>5</sup> of the Kevin Bacon game, you are certainly connected to Kevin Bacon and indeed to everyone else on the planet.</p>
<div class="no-row-height column-margin column-container"><div id="fn5"><p><sup>5</sup>&nbsp;For the other part see <a href="http://worrydream.com/refs/Watts-CollectiveDynamicsOfSmallWorldNetworks.pdf">The dynamics of ‘small-world’ networks</a> by Watts and Strogatz, which significantly reduces the number of ‘hops’ between you and Mr Bacon.</p></div></div><div class="page-columns page-full"><p>In the case of software dependencies the situation is less fun. The principle implies that <strong>the number of dependencies in our software is unintuitively highly transitive</strong>. That is, the chains of dependencies in our code and components tends to make everything depend on everything else. We see why a single fault can bring down an entire company’s infrastructure and is the reason we must be draconian when choosing our dependencies to stand any chance against this effect.</p><div class="no-row-height column-margin column-container"><span class="">Dependencies are not only transitive but many are hidden and bi-directional. I describe this in more detail in my first ever talk <a href="http://youtube.com/watch?v=m1VsoanstAY"><strong>Predictably Unpredictable</strong></a>.</span></div></div>
<p>Another lesson to be learnt from this scenario originated some years ago in a paper<sup>6</sup> building on the originals mentioned above. It adds to the model a destructive process where connected groups are “burnt down” periodically. The key is that the building and burning down of the groups balances to a precarious and dynamic equilibrium<sup>7</sup>, so-called <a href="https://en.wikipedia.org/wiki/Self-organized_criticality">self-organised criticality</a>.</p>
<div class="no-row-height column-margin column-container"><div id="fn6"><p><sup>6</sup>&nbsp;See <a href="https://arxiv.org/abs/0808.2116">Erdos-Renyi random graphs + forest fires = self-organized criticality</a> by Balazs Rath and Balint Toth</p></div><div id="fn7"><p><sup>7</sup>&nbsp;A nice interactive model <a href="https://www.complexity-explorables.org/explorables/critically-inflammatory/">Critically Inflammatory</a> is available on the Complexity Explorables website for you to play with.</p></div></div><p>The take-away for systems designers is that we sometimes see outages in our systems and then “repair” them by scaling or using tools like circuit-breakers and time-outs. At the same time other connections are being added by new features and services. We find ourselves more often than not on the critical line between stable and unstable.</p>
</section>
<section id="tipping-points" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="tipping-points">Tipping Points</h2>
<p>Let’s look at a second model. This time, rather than taking completely independent objects and gradually connecting them together, we take <strong>a set of object which are all connected together, but with varying weights</strong>.</p>
<p>This might represent the number of times that one person interrupts another person per day, or the number of requests from one service to another in a distributed system.</p>
<p>We then gradually increase all the weights using some common scaling factor.</p>
<p>This scenario was first proposed by <a href="https://en.wikipedia.org/wiki/Robert_May,_Baron_May_of_Oxford">Lord Robert May</a> in a famous paper<sup>8</sup> from 1972. He found<sup>9</sup> that the interactions between the individual parts become unstable (that is move away from a balanced and steady equilibrium) at a certain sudden, non-linear transition.</p>
<div class="no-row-height column-margin column-container"><div id="fn8"><p><sup>8</sup>&nbsp;See <strong>Will a large complex system be stable?</strong> by RM May, Nature 238 (5364), 413-414</p></div><div id="fn9"><p><sup>9</sup>&nbsp;See also this <a href="https://youtu.be/6KvQPHdZuoU?t=1934">course</a> on random matrices for an in-depth description of the reasoning.</p></div></div><p>We start with a network where all objects, this time just 10 of them, are connected to each other by differing strength interactions.</p>
<div class="quarto-figure quarto-figure-center page-columns page-full">
<figure class="figure page-columns page-full">
<p><img src="https://johnhearn.github.io/posts/2020-01-26-teams-systems-and-catastrophe/complete-weighted-network.png" class="img-fluid figure-img" width="350"></p>
<figcaption class="margin-caption">Complete weighted network</figcaption>
</figure>
</div>
<p>Using May’s model we can calculate the threshold where the loops and feedback in the network make the whole system unstable. As before, rather that try and study specific configurations, lets run the example many times with different random networks of this type to see the tendency.</p>
<div class="page-columns page-full"><p><img src="https://johnhearn.github.io/posts/2020-01-26-teams-systems-and-catastrophe/may-threshold.png" class="img-fluid" style="width:80.0%" alt="May threshold"></p><div class="no-row-height column-margin column-container"><span class="">Again the source code for generating these graphics with Julia can be found <a href="https://nbviewer.jupyter.org/github/johnhearn/notebooks/blob/master/Phase%20transitions%20in%20networks.ipynb">here</a>.</span></div></div>
<p>May’s criteria for stability has drawn some controversy<sup>10</sup> but the finding is still striking. There is a definite tipping point where network effects produce a phase shift in the dynamics of the system.</p>
<div class="no-row-height column-margin column-container"><div id="fn10"><p><sup>10</sup>&nbsp;<a href="https://www.sciencedirect.com/science/article/pii/S0022519385800813">When will a large complex system be stable?</a> by Joel E.Cohen and Charles M.Newman</p></div></div><p>Imagine the network being a team of 10 people each communicating freely with everyone else. The team members which work most closely together would have the strongest interactions. At the tipping point, <strong>a slight change in the situation or team dynamic</strong> might be amplified by the network effects of interactions with multiple people and <strong>could cause a cascade that affects the team as a whole</strong>. This is of course just a model and no doubt unrealistic in detail but it wouldn’t be the first time that a seemingly trivial change would destabilise a team.</p>
<p>Alternatively, imagine the network being a distributed software system. If a peak in load is experienced and a component is pushed beyond its response threshold once again it can affect the entire system disproportionately.</p>
<p>As with the previous example, teams will naturally detect and counteract these tipping points - people with too many interactions will turn off Slack if they can’t keep up. Profilers will be brought to bear to optimise some code just enough to stop overloading the system. This has the result of leaving us constantly on the brink of catastrophe.</p>
</section>
<section id="wrap-up" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="wrap-up">Wrap up</h2>
<p>In this article there was no intention to make precise predictions about the dynamics of any particular team or system but rather demonstrate <strong>universal tendencies</strong> using basic ensemble techniques.</p>
<p>We’ve seen a couple of simple examples of how small increases in interactions, either in number or in strength, can have significant, non-linear effects for a system as a whole.</p>
<p>Furthermore, our naturally reactions tend to balance the network effects and leave us at a critical point<sup>11</sup> where dangerous tipping points are continually at the doorstep. To a certain extent this explains the universal saying “if it ain’t broke, don’t fix it”.</p>
<div class="no-row-height column-margin column-container"><div id="fn11"><p><sup>11</sup>&nbsp;For an deeper look at self-organised criticality the book <a href="https://www.goodreads.com/book/show/869836.How_Nature_Works">How Nature Works</a> by Per Bak is the seminal work. For a nice summary of the current situation see Watkins, N.W., Pruessner, G., Chapman, S.C. et al.&nbsp;<a href="https://doi.org/10.1007/s11214-015-0155-x">25 Years of Self-organized Criticality: Concepts and Controversies</a>. Space Sci Rev 198, 3–44 (2016).</p></div></div><p>The combination of these dynamics is why a single new team member can bring a working team to a standstill or a small change in load can wreak havoc on a seemingly well oiled system. Note that this doesn’t mean that we should avoid change, just that we need to bear in mind how the system might respond.</p>
<p>Strict minimisation of direct and indirect dependencies is not just about clean architectures. Removal of dependencies and working towards additional quality measures beyond the minimal “it works” moves systems further from the critical point and hence makes them considerably more stable. On the other hand, increasing code entropy and poor design choices will push a system towards the critical point, making them less stable, even if they continue working.</p>
<p>I’m aware that the software industry is not used to talking about systems in these terms, some of these ideas could be considered technical and abstract. Nevertheless these examples are real and can help us increase our literacy with complex systems, our “<a href="https://www.morebeyond.co.za/navigate-complexity-three-habits-of-mind/">lived, practical complexity</a>”. They are just couple of the many results of this type that could be applied more generally.</p>


</section>


 ]]></description>
  <category>complexity-systems</category>
  <category>organisations</category>
  <category>software-architecture</category>
  <guid>https://johnhearn.github.io/posts/2020-01-26-teams-systems-and-catastrophe/</guid>
  <pubDate>Sun, 26 Jan 2020 15:17:00 GMT</pubDate>
</item>
<item>
  <title>DIKUW for Programmers</title>
  <link>https://johnhearn.github.io/posts/2019-05-18-dikuw-for-programmers/</link>
  <description><![CDATA[ 




<p>One of the most interesting models that I’ve seen in recent months is from a talk on <a href="https://youtu.be/EbLh7rZ3rhU">Systems Thinking</a> by <a href="https://en.wikipedia.org/wiki/Russell_L._Ackoff">Dr.&nbsp;Russell Ackoff</a>. It’s variously called the <a href="https://en.wikipedia.org/wiki/DIKW_pyramid">DIKW Pyramid</a> (a mneumonic for <strong>D</strong>ata, <strong>I</strong>nformation, <strong>K</strong>nowledge, <strong>W</strong>isdom) or the Information Chain, amongst many other names. Dr.&nbsp;Ackoff also includes a category called “<strong>U</strong>nderstanding” which is avoided under some philosophical treatments but I’ll include it because I think it provides valuable insight. Hence and henceforth I’ll call it the <strong>DIKUW</strong> model.</p>
<p>It’s one of those models which is hard to describe but easy to grasp. In a nutshell it’s this:</p>
<p>Data⇒Information⇒Knowledge⇒Understanding⇒Wisdom</p>
<p>How each of these layers is interpreted varies. I’m going to try and approach it from three angles: as a programmer with programming constructs, with de Bono’s Mechanics of Mind model and, finally, from an AI perspective.</p>
<p>This first post treats it as a programmer.</p>
<section id="data" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="data">Data</h2>
<p>Imagine a random area of a memory chip full of transistors, each either on or off. One might suppose that those states mean something to someone but without any context it remains data and, actually, <strong>does not provide information at all</strong>.</p>
<p>That may seem counter intuitive because we are used to seeing data as information but, thinking about it, it can’t be. First, we don’t even know if it is a complete representation of anything. It’s just a state with no context. It might as well, in fact, be random<sup>1</sup>.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;We may be able to apply techniques from the higher levels to extract more data from the data: average, variance, repeating patterns, etc. but until we apply the higher levels the data remains data.</p></div></div><p>Often, as programmers we confuse data with information and pay the price with bugs and errors, as we’ll see in a moment.</p>
</section>
<section id="information" class="level2">
<h2 class="anchored" data-anchor-id="information">Information</h2>
<p>Let’s say we have observed the state of our transistors somehow and we know which states represent either 0s or 1s, and we know it’s an 8-bit representation. Then our random piece of RAM might look like this:</p>
<pre><code>01101100 01101001 01100110 01100101 11100010 10000110 10010000 01111011 
11100010 10000110 10010001 00110001 00100000 11100010 10001101 10110101 
11100010 10001000 10101000 00101110 11100010 10001000 10100111 00110011 
00100000 00110100 00111101 00101011 00101111 00101100 11000010 10101111 
00110001 00100000 00110000 00100000 00110001 11100010 10001000 10011000 
00101110 11100010 10001010 10010110 11000010 10101111 00110001 00100000 
00110000 00100000 00110001 11100010 10001000 10011000 00101110 11100010 
10001100 10111101 11100010 10001010 10000010 11100010 10001101 10110101 
01111101 00001101 00001010</code></pre>
<p>So we have some information. Hurray! Or do we? Actually no. We’re still missing context. Is it part of the Chemical Brothers’ new album or an amusing cat video?</p>
<p>Let’s say someone tells me it’s text. OK, great, no problem. <em>Looks online for binary text converter.</em> This means we really do have some information, right?</p>
<pre><code>lifeâ{â1 âµâ¨.â§3 4=+/,Â¯1 0 1â.âÂ¯1 0 1â.â½ââµ}</code></pre>
<p>Ups, something is still wrong. Nobody told us the encoding. This is a common programming error and due to a confusion over data and information. Let’s try with UTF-8 instead of ASCII.</p>
<pre><code>life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}</code></pre>
<p>Well, the encoding is now correct and <strong>we now finally have some information</strong> (yeah!). However, it’s still gobbledygook, at least to me. Even so, just to get this far we needed to know: 1. <em>how</em> to observe some state (transistors on or off, in this case) 2. <em>how</em> to read that state (0s or 1s) 3. <em>what</em> it represents (image, text, audio, etc.) 4. <em>how</em> it’s represented, the format (UTF-8, ASCII, etc.)</p>
<p>The good news is that information, like energy, can be manipulated and changed in form. We could convert it to base-7 or EBCIDIC, if we wanted, and it wouldn’t lose it’s content, <strong>as long as we remember the context</strong>, the meta-data if you like, our information is safe. But what do we do with it?</p>
</section>
<section id="knowledge" class="level2">
<h2 class="anchored" data-anchor-id="knowledge">Knowledge</h2>
<p>We still have a problem. <strong>We have no idea what the information means</strong>. It looks like we have some symbols and someone probably knows what those symbols mean but I’m going to guess that most people don’t. This is beyond encoding and into the area of semiotics and language. The symbols are <em>signifiers</em>.</p>
<p>Now, let me tell you, that is actually a piece APL code. If you know something about APL maybe you can follow what it’s doing. If not, then I can point you towards the <a href="https://aplwiki.com/">APL wiki</a> or the <a href="https://en.wikipedia.org/wiki/APL_(programming_language)">Wikipedia</a> entry and maybe after (considerable) study you might be able to follow what it’s doing. You could even <a href="https://www.youtube.com/watch?v=a9xAKttWgP4">watch the video</a>. If you can then hat’s off to you sir! I personally have no idea.</p>
<p>As it is given, this is a recipe which solves a problem. But then we might ask ourselves: what problem?</p>
</section>
<section id="understanding" class="level2">
<h2 class="anchored" data-anchor-id="understanding">Understanding</h2>
<p>Even when we know what the program <em>does</em> we might ask ourselves: why did someone write this code in the first place? What’s its purpose? There are no comments, the variables are greek (literally). The only clue is the name of the function….</p>
<p>In actual fact it is a <a href="https://en.wikipedia.org/wiki/APL_(programming_language)#Game_of_Life">famous one-liner</a> for <a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway’s Game of Life</a>. If you don’t know what the Game of Life is, it’s a famous programming toy from computer science which turns out to be in a class of systems which are Turing complete, that is universal computing machines. The person who wrote the code probably knew that.</p>
<p>They also knew intimately <em>how</em> to solve the problem with the given language. That require a deeper level of reasoning than merely learning the language. It means many hours of experimentation and practice. That is why we do katas and continuous practice to hone these skills.</p>
<p>Understanding why and how is very different from following the rules.</p>
</section>
<section id="wisdom" class="level2">
<h2 class="anchored" data-anchor-id="wisdom">Wisdom</h2>
<p>OK, so we understand universal computation and the game of life, the APL language, the text encodings, the bytes and the transistors. We might understand the concepts but how do we know when and if to apply them? When would I consider APL over some other language? When should I use a programming language at all or and when should I be playing with my children?</p>
<p>You might have noticed that the ideas become more abstract and general as we move along the chain. This last level is the most difficult of all and the subject of most debate. If understanding requires reflection then this require still more, even a personal philosophy about ones own values.</p>
<p>This has been just one trivial example of the many levels of knowledge or understanding behind anything we do. We are knowledge workers, using information everyday. I wonder sometimes if we really stop to really understand some of the things we do (he says, copy/pasting from Wikipedia) or whether we are content with <em>just</em> knowledge.</p>
<p>(That’s the first part. The next part will deal with applying mental models to the different stages to understand them better in general.)</p>


</section>


 ]]></description>
  <category>philosophy</category>
  <category>communication</category>
  <category>software-engineering</category>
  <guid>https://johnhearn.github.io/posts/2019-05-18-dikuw-for-programmers/</guid>
  <pubDate>Sun, 07 Jul 2019 18:30:00 GMT</pubDate>
</item>
<item>
  <title>The Hodgepodge Machine</title>
  <link>https://johnhearn.github.io/posts/2019-06-08-hodgepodge-machine-in-julia/</link>
  <description><![CDATA[ 




<blockquote class="blockquote">
<p>“<em>The pleasure of complexity… the inconceivable nature of nature</em>” - <a href="https://youtu.be/tD_XAX--Ono?t=67">Richard Feynmann</a></p>
</blockquote>
<p>Back in the 80s, my Dad used to work as a security guard at a <a href="https://en.wikipedia.org/wiki/Rosemanowes_Quarry">geothermal energy research site</a> and sometimes I would accompany him on his rounds. The facility was well funded and very advanced for its time and there was all kinds of computer equipment which was at that time both fascinating and alien to me. There was also a collection of science and technology magazines and sometimes I would read them for hours.</p>
<p>The magazines I liked most were Computer Weekly and Scientific American. I liked them mostly for their programming sections. Back in those pre-internet days it was common for the articles to include listings, mostly in Fortran, BASIC and maybe Pascal and even Assembler<sup>1</sup>. That’s how I learned to code.</p>
<div class="no-row-height column-margin column-container"><div id="fn1"><p><sup>1</sup>&nbsp;Yep, we used to type machine code by hand!</p></div><div id="fn2"><p><sup>2</sup>&nbsp;Dewdney, A. (1988). COMPUTER RECREATIONS. <em>Scientific American</em>, <em>259(2)</em>, 104-107. Retrieved from http://www.jstor.org/stable/24989205</p></div></div><p>One <a href="https://www.jstor.org/stable/24989205?seq=1#page_scan_tab_contents">article</a> I remember particularly fondly was in Scientific American’s Computer Recreations section with the caption “<em>The hodgepodge machine makes waves</em>”<sup>2</sup>. The date was August 1988. It described a set of rules which mimicked a type of chemical reaction, the so called <a href="https://en.wikipedia.org/wiki/Belousov%E2%80%93Zhabotinsky_reaction">Belousov-Zhabotinsky reaction</a>, and resulted in fantastic shapes and behaviours emerging almost like magic. I was able to reproduce that at the time on my Amstrad CPC even though it took ages to update each frame. It was one of my first programming successes.</p>
A few weeks ago one of my colleagues at Codurance wrote an article called <a href="https://codurance.com/2019/05/30/nature-in-code/"><em>Nature in Code</em></a> where she simulated biological interactions in code and how interesting phenomena emerge naturally. It reminded me of the Hodgepodge Machine and inspired me to try it again with more modern techniques (thank you Solange). So I sat down this morning, and with a little help from this <a href="https://softologyblog.wordpress.com/2017/02/04/the-belousov-zhabotinsky-reaction-and-the-hodgepodge-machine/">blog post</a>, wrote it in Julia. This is the result.
<p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/9HPaottA9tE" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="">
</iframe>
Compare that to this real reaction:
</p><p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/8tArShb1fhw?start=57" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="">
</iframe>
</p><p>This ties in with recent work I’ve been doing on dynamical systems and complexity. The hodgepodge machine <em>is</em> a dynamical system: deterministic but, under certain conditions, totally unpredictable.</p>
<p>As Feynman said, “<em>And it’s all really there…but you’ve got to stop and think about it to really get the pleasure about the complexity; the inconceivable [he chuckles] nature of nature.</em>”.</p>
<p>Code is on GitHub <a href="https://gist.github.com/johnhearn/e17cc9d2e98f7bf3db1012d2046fba78">here</a>.</p>




 ]]></description>
  <category>complexity-systems</category>
  <category>simulation</category>
  <category>programming-languages</category>
  <guid>https://johnhearn.github.io/posts/2019-06-08-hodgepodge-machine-in-julia/</guid>
  <pubDate>Sat, 08 Jun 2019 15:16:00 GMT</pubDate>
</item>
<item>
  <title>Chaotic Waterwheel with Planck</title>
  <link>https://johnhearn.github.io/posts/2019-06-02-simulate-chaotic-water-wheel-with-planck/</link>
  <description><![CDATA[ 




<blockquote class="blockquote">
<p>(Update: Many thanks to <a href="https://github.com/shakiba">shakiba</a> for fixing this and adding it to the <a href="https://github.com/shakiba/planck.js">Plank.js</a> homepage as an example.)</p>
</blockquote>
<div class="page-columns page-full"><p> I’m just finishing <a href="https://twitter.com/stevenstrogatz?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">Steven Strogatz</a>’s <a href="https://www.youtube.com/playlist?list=PLbN57C5Zdl6j_qJA-pARJnKsmROzPnO9V">Nonlinear Dynamics and Chaos</a> course and one of the systems he discusses is the chaotic Malkus water wheel. This is a real set up devised to mimic the famous <a href="https://en.wikipedia.org/wiki/Lorenz_system">Lorenz equations</a>.</p><div class="no-row-height column-margin column-container"><img src="https://johnhearn.github.io/posts/2019-06-02-simulate-chaotic-water-wheel-with-planck/malkus_wheel.gif" class="img-fluid" alt="watch?v=HljJv7Hf6Zo) of his course."></div></div>
<blockquote class="blockquote">
<p>“<em>In the 1960s… a real system was needed to demonstrate that chaos and the butterfly effect were realities and not mere mathematical artefacts… W.V.R. Malkus, a mathematician at MIT, realized that the Lorenz-Equations can be transformed into the equations of motion of a waterwheel. This waterwheel was built at MIT in the 1970s and helped to convince the sceptical physicists of the reality of chaos</em>” - taken from <a href="http://goodshare.org/wp/climate-bai/">here</a></p>
</blockquote>
<div class="page-columns page-full"><p>It consists of a stream of water feeding into multiple, leaky cups mounted on a rotating wheel. The weights of the cups containing water produce a chaotic behaviour causing the wheel to rotate in different directions unpredictably.  So today I thought I’d play with this idea and try to reproduce it in a 2D physics engine. I chose <a href="http://piqnt.com/planck.js/">Planck</a>, a JavaScript physics engine based on the Box2D implementation in C++.</p><div class="no-row-height column-margin column-container"><img src="https://johnhearn.github.io/posts/2019-06-02-simulate-chaotic-water-wheel-with-planck/malkus_wheel.jpeg" class="img-fluid" alt="watch?v=51FgNhrS6jg)’s another one with a video."></div></div>
<p>It took a while to tune the size of the balls representing the water flow and the gaps in the cups which regulate the outflow. It’s far from perfect but it demonstrates the idea.</p>
<p>Anyway here’s the result.</p>
<iframe title="Chaotic waterwheel simulation" width="700" height="520" src="chaos-wheel-planck.html" frameborder="0">
</iframe>



 ]]></description>
  <category>simulation</category>
  <category>complexity-systems</category>
  <guid>https://johnhearn.github.io/posts/2019-06-02-simulate-chaotic-water-wheel-with-planck/</guid>
  <pubDate>Sun, 02 Jun 2019 16:22:00 GMT</pubDate>
</item>
</channel>
</rss>
