2023-12-21T15:47:52+01:00https://onnoeberhard.com/feed.xmlOnno EberhardML & Mathematicshttps://onnoeberhard.com/main/salto.pngOnno Eberhardhttps://onnoeberhard.comonnoeberhard@gmail.comhttps://onnoeberhard.com/main/salto.png0ab246Cool logic in the face of fire2019-08-21T13:07:00+02:002019-08-21T13:07:00+02:00https://onnoeberhard.com/2019/08/21/cool-logic<link rel="stylesheet" href="/css/syntax_prolog.css" />
<p style="margin-left: 20%; margin-right: 20%; font-family: 'EB Garamond', serif;">
“Well, look at it logically,” said Hermione, turning to the rest of the group. “I mean, Binky didn't even die today, did he? Lavender just got the news today.” <br /><i>Lavender wailed loudly.</i>
</p>
<p style="margin-top: -1rem; margin-left: 20%; margin-right: 20%; text-align: right; font-family: 'EB Garamond', serif;">
— Hermione Granger in <i>Prisoner of Azkaban</i>
</p>
<p>Again and again Hermione manages to demonstrate her emotional range being that of a robotic teaspoon. Because of that, I think it would be fair to build our very own Hermione (using Prolog), and try and win ourselves “50 points for Gryffindor”!</p>
<p>In <em>Philosopher’s Stone</em>, Harry and Hermione find themselves trapped in a chamber on the way to get the stone. There are a number of flasks on a table together with a piece of paper bearing a riddle:</p>
<p><img src="/assets/cool-logic/potions.jpg" alt="Potions -fullwidth" /></p>
<!-- more -->
<p><i style="text-align: center; display: block; line-height: 170%">
Danger lies before you, while safety lies behind, <br />
Two of us will help you, whichever you would find, <br />
One among us seven will let you move ahead, <br />
Another will transport the drinker back instead, <br />
Two among our number hold only nettle wine, <br />
Three of us are killers, waiting hidden in line. <br />
Choose, unless you wish to stay here forevermore, <br />
To help you in your choice, we give you these clues four: <br />
First, however slyly the poison tries to hide <br />
You will always find some on nettle wine’s left side; <br />
Second, different are those who stand at either end, <br />
But if you would move onward, neither is your friend; <br />
Third, as you see clearly, all are different size, <br />
Neither dwarf nor giant holds death in their insides; <br />
Fourth, the second left and the second on the right <br />
Are twins once you taste them, though different at first sight
</i></p>
<p>Harry might be the most capable of the lot <em>emotionally</em>, but sadly he did not win the lottery when it comes to brain power. Because of this, it’ll have to be Hermione who solves Snape’s riddle. Here she is:</p>
<div class="language-prolog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">:-</span> <span class="ss">use_module</span><span class="p">(</span><span class="ss">library</span><span class="p">(</span><span class="ss">clpfd</span><span class="p">)).</span>
<span class="ss">ahead</span><span class="p">(</span><span class="m">1</span><span class="p">).</span>
<span class="ss">back</span><span class="p">(</span><span class="m">2</span><span class="p">).</span>
<span class="ss">wine</span><span class="p">(</span><span class="m">3</span><span class="p">).</span>
<span class="ss">poison</span><span class="p">(</span><span class="m">4</span><span class="p">).</span>
<span class="ss">hermione</span> <span class="p">:-</span>
<span class="nv">Flasks</span> <span class="o">=</span> <span class="p">[</span><span class="nv">First</span><span class="p">,</span> <span class="nv">SecondLeft</span><span class="p">,</span> <span class="nv">_</span><span class="p">,</span> <span class="nv">_</span><span class="p">,</span> <span class="nv">_</span><span class="p">,</span> <span class="nv">SecondRight</span><span class="p">,</span> <span class="nv">Last</span><span class="p">],</span>
<span class="nv">Sizes</span> <span class="o">=</span> <span class="p">[</span><span class="nv">_</span><span class="p">,</span> <span class="nv">_</span><span class="p">,</span> <span class="nv">Dwarf</span><span class="p">,</span> <span class="nv">_</span><span class="p">,</span> <span class="nv">_</span><span class="p">,</span> <span class="nv">Giant</span><span class="p">,</span> <span class="nv">_</span><span class="p">],</span> <span class="c1">% Taken from the picture, not mentioned in book.</span>
<span class="nv">Flasks</span> <span class="ss">ins</span> <span class="m">1</span><span class="p">..</span><span class="m">4</span><span class="p">,</span>
<span class="nv">Flasks</span> <span class="o">=</span> <span class="nv">Sizes</span><span class="p">,</span>
<span class="nv">First</span> <span class="o">#</span><span class="err">\</span><span class="o">=</span> <span class="nv">Last</span><span class="p">,</span> <span class="c1">% Different are those who stand at either end,</span>
<span class="nv">First</span> <span class="o">#</span><span class="err">\</span><span class="o">=</span> <span class="m">1</span><span class="p">,</span> <span class="c1">% But if you would move onward,</span>
<span class="nv">Last</span> <span class="o">#</span><span class="err">\</span><span class="o">=</span> <span class="m">1</span><span class="p">,</span> <span class="c1">% neither is your friend;</span>
<span class="nv">Dwarf</span> <span class="o">#</span><span class="err">\</span><span class="o">=</span> <span class="m">4</span><span class="p">,</span> <span class="c1">% Neither dwarf-</span>
<span class="nv">Giant</span> <span class="o">#</span><span class="err">\</span><span class="o">=</span> <span class="m">4</span><span class="p">,</span> <span class="c1">% nor giant holds death in their insides; </span>
<span class="nv">SecondLeft</span> <span class="o">#=</span> <span class="nv">SecondRight</span><span class="p">,</span> <span class="c1">% The second left and the second on the right are twins ..</span>
<span class="ss">labeling</span><span class="p">([],</span> <span class="nv">Flasks</span><span class="p">),</span>
<span class="ss">count</span><span class="p">(</span><span class="nv">Flasks</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="c1">% One among us seven will let you move ahead,</span>
<span class="ss">count</span><span class="p">(</span><span class="nv">Flasks</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> <span class="c1">% Another will transport the drinker back instead, </span>
<span class="ss">count</span><span class="p">(</span><span class="nv">Flasks</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">2</span><span class="p">),</span> <span class="c1">% Two among our number hold only nettle wine,</span>
<span class="ss">count</span><span class="p">(</span><span class="nv">Flasks</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">3</span><span class="p">),</span> <span class="c1">% Three of us are killers, waiting hidden in line. (actually implied)</span>
<span class="ss">poison_left_of_wine</span><span class="p">(</span><span class="nv">Flasks</span><span class="p">),</span> <span class="c1">% However slyly the poison tries to hide, you will always find some on nettle wine’s left side;</span>
<span class="ss">write_names</span><span class="p">(</span><span class="nv">Flasks</span><span class="p">),</span> <span class="p">!.</span>
<span class="c1">% Predicate for checking if the estimate contains the correct number of each substance</span>
<span class="ss">count</span><span class="p">(</span><span class="nv">L</span><span class="p">,</span> <span class="nv">X</span><span class="p">,</span> <span class="nv">N</span><span class="p">)</span> <span class="p">:-</span>
<span class="ss">findall</span><span class="p">(</span><span class="nv">P</span><span class="p">,</span> <span class="p">(</span><span class="ss">member</span><span class="p">(</span><span class="nv">P</span><span class="p">,</span> <span class="nv">L</span><span class="p">),</span> <span class="nv">P</span> <span class="o">=</span> <span class="nv">X</span><span class="p">),</span> <span class="nv">CP</span><span class="p">),</span>
<span class="ss">length</span><span class="p">(</span><span class="nv">CP</span><span class="p">,</span> <span class="nv">N</span><span class="p">).</span>
<span class="c1">% Predicates for checking if there is always poison on "nettle wine's left side"</span>
<span class="ss">poison_left_of_wine</span><span class="p">([</span><span class="nv">_</span><span class="p">]).</span>
<span class="ss">poison_left_of_wine</span><span class="p">([</span><span class="nv">H</span><span class="p">|</span><span class="nv">T</span><span class="p">])</span> <span class="p">:-</span>
<span class="ss">poison_left_of_wine</span><span class="p">(</span><span class="nv">T</span><span class="p">),</span>
<span class="nv">T</span> <span class="o">=</span> <span class="p">[</span><span class="nv">X</span><span class="p">|</span><span class="nv">_</span><span class="p">],</span>
<span class="ss">poison_left_of_wine</span><span class="p">(</span><span class="nv">H</span><span class="p">,</span> <span class="nv">X</span><span class="p">).</span>
<span class="ss">poison_left_of_wine</span><span class="p">(</span><span class="nv">_</span><span class="p">,</span> <span class="nv">W</span><span class="p">)</span> <span class="p">:-</span>
<span class="ss">not</span><span class="p">(</span><span class="ss">wine</span><span class="p">(</span><span class="nv">W</span><span class="p">)).</span>
<span class="ss">poison_left_of_wine</span><span class="p">(</span><span class="nv">P</span><span class="p">,</span> <span class="nv">_</span><span class="p">)</span> <span class="p">:-</span>
<span class="ss">poison</span><span class="p">(</span><span class="nv">P</span><span class="p">).</span>
<span class="c1">% Predicates for writing out the result</span>
<span class="ss">write_names</span><span class="p">([]).</span>
<span class="ss">write_names</span><span class="p">([</span><span class="nv">H</span><span class="p">|</span><span class="nv">T</span><span class="p">])</span> <span class="p">:-</span>
<span class="p">(</span><span class="ss">ahead</span><span class="p">(</span><span class="nv">H</span><span class="p">),</span> <span class="ss">write</span><span class="p">(</span><span class="s2">"Ahead Potion"</span><span class="p">);</span>
<span class="ss">back</span><span class="p">(</span><span class="nv">H</span><span class="p">),</span> <span class="ss">write</span><span class="p">(</span><span class="s2">"Back Potion"</span><span class="p">);</span>
<span class="ss">wine</span><span class="p">(</span><span class="nv">H</span><span class="p">),</span> <span class="ss">write</span><span class="p">(</span><span class="s2">"Nettle Wine"</span><span class="p">);</span>
<span class="ss">poison</span><span class="p">(</span><span class="nv">H</span><span class="p">),</span> <span class="ss">write</span><span class="p">(</span><span class="s2">"Poison"</span><span class="p">)),</span>
<span class="ss">comma</span><span class="p">(</span><span class="nv">T</span><span class="p">),</span>
<span class="ss">write_names</span><span class="p">(</span><span class="nv">T</span><span class="p">),</span> <span class="p">!.</span>
<span class="ss">comma</span><span class="p">([])</span> <span class="p">:-</span> <span class="p">!.</span>
<span class="ss">comma</span><span class="p">(</span><span class="nv">_</span><span class="p">)</span> <span class="p">:-</span> <span class="ss">write</span><span class="p">(</span><span class="s2">", "</span><span class="p">).</span>
</code></pre></div></div>
<p>All we have to do is call her:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>?- hermione.
Poison, Nettle Wine, Ahead Potion, Poison, Poison, Nettle Wine, Back Potion
true.
</code></pre></div></div>
<p>Is this fan-fiction?</p>
<hr />
<p><em>Source of the picture: <a href="https://www.pottermore.com/features/every-harry-potter-puzzle-hermione-solved-that-made-us-kick-ourselves">Pottermore</a></em></p>
Onno Eberhardhttps://onnoeberhard.comonnoeberhard@gmail.com“Well, look at it logically,” said Hermione, turning to the rest of the group. “I mean, Binky didn't even die today, did he? Lavender just got the news today.” Lavender wailed loudly. — Hermione Granger in Prisoner of Azkaban Again and again Hermione manages to demonstrate her emotional range being that of a robotic teaspoon. Because of that, I think it would be fair to build our very own Hermione (using Prolog), and try and win ourselves “50 points for Gryffindor”! In Philosopher’s Stone, Harry and Hermione find themselves trapped in a chamber on the way to get the stone. There are a number of flasks on a table together with a piece of paper bearing a riddle:Fibonacci spirals and the mind of plants2018-12-21T00:00:00+01:002018-12-16T00:00:00+01:00https://onnoeberhard.com/2018/12/16/fibonacci<p>Plants are bimbos. Beautiful, but stupid–at least that’s what most people think. But in this post I want to talk about why I think plants are much more intelligent than people give them credit for. You’ve probably seen the pretty spirally patterns that emerge in many plants when leaves or seeds grow outwards (see figure below). I think they are very interesting and I want to convince you that plants do need to be intelligent to be able to create them.</p>
<p><img src="/assets/fibonacci/plants.png" alt="Plants -fullwidth" /></p>
<p class="caption">Spirals!<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup></p>
<p><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></p>
<p>A well known fun-fact about these spirals is their connection to the Fibonacci numbers. These are the numbers belonging to the Fibonacci sequence: $1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …$ (every number is the sum of its two preceding numbers). In plants, these spirals almost always<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> seem to have a Fibonacci number of arms (see the figure below).</p>
<!-- more -->
<!-- ![Fibonacci patterns in sunflower seeds -fullwidth](/assets/fibonacci/fibsun.jpg) -->
<div class="responsive-image dark-inv fibsun" style="width: 100%">
<img class="responsive-image-background fibsun" src="/assets/resized/320/fibsun.jpg" onclick="" style="" />
<div class="responsive-image-placeholder fibsun" data-class="fibsun" data-src="/{width}"></div>
</div>
<script>
var orig_width = parseFloat("1024");
var orig_path = "assets/fibonacci/fibsun.jpg";
var resize_path = "assets/resized/";
var sizes = [320, 480, 640, 800, 960];
new Imager('.responsive-image-placeholder.fibsun', {
className: 'responsive-image-replace',
availableWidths: sizes,
widthInterpolator: function(width, pixelRatio) {
var goal = 1.5 * pixelRatio * width;
if (goal >= orig_width)
return orig_path;
var closest = sizes.reduce(function(prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
return resize_path + closest + "/fibsun.jpg";
},
onImagesReplaced: function() {
$('.responsive-image-replace.fibsun').attr('style', "")
$('.responsive-image-background.fibsun').imageLoad(function(){
var aspect = $('.responsive-image-background.fibsun').width() / $('.responsive-image-background.fibsun').height()
$('.responsive-image.fibsun').css('aspect-ratio', String(aspect));
$('.responsive-image-background.fibsun').css('aspect-ratio', String(aspect));
$('.responsive-image-replace.fibsun').css('aspect-ratio', String(aspect));
$('.responsive-image-placeholder.fibsun').css('aspect-ratio', String(aspect));
});
$('.responsive-image-replace.fibsun').attr('onClick', "");
$('.responsive-image-replace.fibsun').imageLoad(function(){
$('.responsive-image-background.fibsun').hide();
});
}
})
</script>
<p class="caption">The spirals add up to a Fibonacci number<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup></p>
<p><sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup></p>
<p>The spirals can be found everywhere in the plant universe, so it definitely can’t be a coincidence that they always appear in Fibonacci multiplicities; there must be some reason why evolution favours this arrangement over others.
To understand why the seeds are not arranged in a different way, let’s try to visualize what other patterns would look like. Regardless whether it’s with leaves, seeds or something different, the spirals only appear if single bits get created at some center point, and then get pushed outwards by newer bits growing from the same center. Actually, they don’t grow from a <em>point</em>, but get created on the edge of the meristem, at a fixed distance from the center point.
So with this constraint, what other patterns could the plant produce?
If the seeds were all just created at a random point on the edge of the meristem and then grow outwards at a fixed speed, it would look something like this:</p>
<video width="100%" autoplay="" muted="" loop="" playsinline="" class="dark-inv">
<source src="/assets/fibonacci/random_small.webm" type="video/webm" />
<source src="/assets/fibonacci/random_small.mp4" type="video/mp4" />
</video>
<p class="caption">Pattern if the seeds are all placed at a random position on the edge of the meristem (<a href="#notebook"><i>Code</i></a>)</p>
<p>It looks kind of weird, definitely not as pretty as the spirals. But prettiness is probably not what evolution was selecting for. I think it is reasonable to assume some kind of energy efficiency to be the driving force behind this phenomenon, as is he case in many (or maybe all<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>) cases of natural selection. But why would it be more efficient to assemble the seeds or leaves in this special manner?</p>
<p>One theory for why leaves arranged in the Fibonacci spirals are beneficial, is that it is the form that ensures the most sunlight hitting each leave, because they are placed at such an angle from each other that a newer leave never fully blocks the light of an older leave. From the plant’s perspective, the most simple thing (much easier than the random arrangement above) would be to just have everything grow out in one place, like this:</p>
<video width="100%" autoplay="" muted="" loop="" class="dark-inv">
<source src="/assets/fibonacci/same_small.webm" type="video/webm" />
<source src="/assets/fibonacci/same_small.mp4" type="video/mp4" />
</video>
<p class="caption">Pattern if the seeds are all placed at exactly the same position (<a href="#notebook"><i>Code</i></a>)</p>
<p>Here, every new leave would block all the light of the previous one. To fix this problem, the plant does what is probably the second-most simple thing, and also probably the best solution. It actually just puts the new seed at a fixed angle relative to the last one, and that’s everything:</p>
<video width="100%" autoplay="" muted="" loop="" playsinline="" class="dark-inv">
<source src="/assets/fibonacci/golden_small.webm" type="video/webm" />
<source src="/assets/fibonacci/golden_small.mp4" type="video/mp4" />
</video>
<p class="caption">Pattern if every seed is placed at a fixed angle $\theta$ from the previous seed (<a href="#notebook"><i>Code</i></a>)</p>
<p>The fixed angle in this case, which is the one that plants do use and that will result in the Fibonacci numbers, is the so-called <em>golden angle</em>:
\begin{equation}
\theta = \frac{2\pi}{\phi^2} = \pi (3 - \sqrt{5}) \approx 138^{\circ},
\end{equation}
with $\phi = \frac{1 + \sqrt{5}}{2}$ being the golden ratio. By the way, this has nothing to do with <a href="/assets/fibonacci/wrongspiral.png" data-lightbox="wrong" data-title="Nope (<a href='https://commons.wikimedia.org/wiki/File:Fibonacci_spiral.svg'>Source</a>)">this</a> kind of spiral, although that one is also closely related to the golden ratio and Fibonacci numbers! If we zoom out a bit, the spirals become obvious:</p>
<video width="100%" autoplay="" muted="" loop="" playsinline="" class="dark-inv">
<source src="/assets/fibonacci/golden.webm" type="video/webm" />
<source src="/assets/fibonacci/golden.mp4" type="video/mp4" />
</video>
<p class="caption">When there are many seeds, it starts to look like a flower (<a href="#notebook"><i>Code</i></a>)</p>
<p>Now let’s just accept that this is the angle the plant “wants” to have. How does it do this? Try to put yourself in the shoes of a plant; or better, a plant-design-god. If you wanted to build a mechanical flower, how would you do it? Probably some kind of mechanism that turns $\theta$ degrees every time it places a new seed or leave. For this, there needs to be some kind of memory, where the value for $\theta$, and the previous angle are saved (at least approximately, because of their irrationality). Then there needs to be some kind of processing unit that adds $\theta$ to the previous angle and converts this sum into electrical signals to turn a motor to the right position, to place the new seed.</p>
<p>This seems far too complicated. Is the value of $\theta$ really engraved into these plants’ DNA? Do plants have some kind of neural network-like computation system that adds the angle from the DNA to the angle of the previous seed and then uses this new angle to compute where the next seed should go? This does not scream “energy efficiency” as hoped.</p>
<p>It would be very convenient, if this magically perfect angle can somehow be deduced from the laws of physics or maths without the need for complicated computation! Then the plant would just have to find the right law and use it to do the calculation for it. If a simple mathematical formula can be found, that, through iteration, produces the golden angle, in a way that could realistically be similar to what goes on in actual plants, I think it is safe to say, that this formula, not some memory or processing unit, is the key to the spirally patterns formed on plants.</p>
<p>To find that formula / algorithm, let’s first clarify what the the result should be. The optimal angle should be found, so that the seed placed at that angle has the largest possible space around it. This seems like a very straightforward problem (is what I thought).</p>
<p>The simplest way I could think of to get this angle, is to just take a weighted mean of the angles of all previous seeds, so that the newest angles count the most, and then invert that angle (add $\pi$), to get the place opposite this mean angle. Then place the new seed exactly there. A naïve (and completely wrong) idea would be to pretend angles were normal numbers and use the following equation to calculate the weighted mean:
\begin{align}
\theta_j &= \frac{\sum_{i=1}^{j}{\theta_i i}}{\sum_{i=1}^j{i}} + \pi \mod 2 \pi
\\ &= \frac{2}{j(j+1)} \sum_{i=1}^{j}{\theta_i i} + \pi \mod 2 \pi
\end{align}</p>
<p>Let’s write some Python code to test out if this works:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">N</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">theta</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">N</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">N</span><span class="p">):</span>
<span class="n">mean</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">(</span><span class="n">i</span> <span class="o">*</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> <span class="o">*</span> <span class="p">(</span><span class="n">theta</span><span class="p">[:</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">r_</span><span class="p">[:</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)).</span><span class="nb">sum</span><span class="p">()</span> <span class="c1"># Calculate the weighted "mean" angle
</span> <span class="n">theta</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">mean</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="c1"># Invert angle (add pi) and adjust for mod 2pi
</span>
<span class="k">print</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span>
<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">111</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">theta</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">N</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">r_</span><span class="p">[:</span><span class="n">N</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="s">'o'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Seeds"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">theta</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="mi">1</span><span class="p">,</span> <span class="s">'rx'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Next Seed"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
</code></pre></div></div>
<p>The output reads:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0. 3.14159265 5.23598776 0.52359878 5.55014702]
</code></pre></div></div>
<!-- ![Wrong wrong wrong -fullwidth](/assets/fibonacci/wrong_mean.svg) -->
<p><img src="/assets/fibonacci/wrong_mean.svg" class="dark-inv" width="100%" /></p>
<p class="caption">Wrong, wrong, wrong</p>
<p>The algorithm quickly returns wrong results. For example, if it were to calculate the mean of the two angles $1$° and $359$° (equally weighted), its answer would be $\frac{1^\circ + 359^\circ}{2} = 180$°. Inverting the angle would then give $360$°, which is obviously not the most optimal angle. The algorithm fails to account for the modulo nature of angles.</p>
<p>So how <em>can</em> the mean angle be calculated? Because we are essentially dealing with 2d coordinates, the electrical engineer in me is already screaming “complex numbers”. Why not just take the mean of two complex numbers and then take the angle of the result as mean? The mean can be weighted by just changing the magnitudes of the complex numbers:</p>
<p>\begin{align}
\theta_j &= \arg\left(\frac{\sum_{i=1}^j{s_i i}}{\sum_{i=1}^j{i}}\right) + \pi \mod 2 \pi
\\&= \arg\left(\sum_{i=1}^j{s_i i}\right) + \pi \mod 2 \pi,
\end{align}</p>
<p>$s$ being the complex vector of seeds.</p>
<p>This actually works quite well:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">rect</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">/</span><span class="mi">2</span><span class="p">),</span> <span class="n">rect</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">)])</span>
<span class="n">sum_</span> <span class="o">=</span> <span class="p">(</span><span class="n">seeds</span> <span class="o">*</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">r_</span><span class="p">[:</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)).</span><span class="nb">sum</span><span class="p">()</span>
<span class="n">mean</span> <span class="o">=</span> <span class="n">sum_</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> <span class="c1"># Multiplying a complex number by a real number does not change the argument
</span><span class="n">next_seed</span> <span class="o">=</span> <span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">sum_</span><span class="p">)</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span>
<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">111</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Seeds"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">sum_</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">sum_</span><span class="p">),</span> <span class="s">"x"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Weighted sum"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">mean</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">mean</span><span class="p">),</span> <span class="s">"x"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Weighted mean"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">next_seed</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">next_seed</span><span class="p">),</span> <span class="s">"x"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Next seed"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
</code></pre></div></div>
<!-- ![Complex angles -fullwidth](/assets/fibonacci/complex_angles.svg) -->
<p><img src="/assets/fibonacci/complex_angles.svg" class="dark-inv" width="100%" /></p>
<p>When testing it out, it becomes clear that there is one obvious problem with this algorithm. If we place the first seed at $1 + 0i$, the mean will be the same ($1 + 0i$), resulting in an optimal angle of 180°, but this means the weighted mean of these two seeds is still only on the real axis, so the next “optimal” angle will be 0° again. To try to fix this, we’ll use some random noise, amplified by the parameter $x$, to place the next seed:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">complex_seeds</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)])</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">500</span><span class="p">):</span>
<span class="n">seeds</span> <span class="o">+=</span> <span class="n">seeds</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">)</span> <span class="c1"># Growing
</span> <span class="n">sum_</span> <span class="o">=</span> <span class="p">(</span><span class="n">seeds</span> <span class="o">*</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">r_</span><span class="p">[:</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)).</span><span class="nb">sum</span><span class="p">()</span>
<span class="n">next_seed</span> <span class="o">=</span> <span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">sum_</span><span class="p">)</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">rand</span><span class="p">()</span><span class="o">*</span><span class="n">x</span><span class="p">)</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">seeds</span><span class="p">,</span> <span class="n">next_seed</span><span class="p">))</span>
<span class="k">return</span> <span class="n">seeds</span>
<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">complex_seeds</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">221</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"."</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"x = 0"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">complex_seeds</span><span class="p">(</span><span class="mf">1e-3</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">222</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"."</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"x = 0.001"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">complex_seeds</span><span class="p">(</span><span class="mf">1e-2</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">223</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"."</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"x = 0.01"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">complex_seeds</span><span class="p">(</span><span class="mf">1e-1</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">224</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"."</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"x = 0.1"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
</code></pre></div></div>
<!-- ![Complex spirals -fullwidth](/assets/fibonacci/complex_stuff.svg) -->
<p><img src="/assets/fibonacci/complex_stuff.svg" class="dark-inv" width="100%" /></p>
<p>Ok, this looks awful. It’s time for a new plan. Because we know the seed gets placed on the edge of the meristem at the place where there is the most room<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup>, a good idea may be to construct a sort of energy function $E(\theta)$ along the meristem edge that we then try to minimize. This function must be high (at angle $\theta$), if there is a seed close to the point $r e^{i \theta}$, with $r = 1$ being the radius of the meristem.
I thought a sum of Gaussian bell curves could do exactly what we want: Each bell corresponds to one old seed, scaled by how far away the seed is:</p>
<p>\begin{equation}
E(\theta) = \frac{1}{N^a} \sum_{i=1}^{N}{i^a e^{-(N - i + 1)^b (\theta - \theta_i)^2}},
\end{equation}</p>
<p>using the parameter $a$ to scale the height of the bell curve, so that it gets smaller the farther away the seed is (low $i$), and $b$ to change the width of the curve, so that it gets wider the closer the seed is to the stem.</p>
<p>In Python, this function can be implemented as follows:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="mi">1000</span><span class="p">)</span> <span class="c1"># Minimization resolution = 1000 (take the best of 1000 possible thetas)
</span>
<span class="k">def</span> <span class="nf">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
<span class="n">N</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">seeds</span><span class="p">)</span>
<span class="n">i</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">r_</span><span class="p">[</span><span class="s">'1,2'</span><span class="p">,</span> <span class="mi">1</span> <span class="p">:</span> <span class="n">N</span><span class="o">+</span><span class="mi">1</span><span class="p">].</span><span class="n">T</span>
<span class="n">phi</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">)[</span><span class="n">np</span><span class="p">.</span><span class="n">newaxis</span><span class="p">].</span><span class="n">T</span>
<span class="c1"># Copy the whole function +- 2pi to emulate modularity
</span> <span class="n">E</span> <span class="o">=</span> <span class="mi">1</span><span class="o">/</span><span class="n">N</span><span class="o">**</span><span class="n">a</span> <span class="o">*</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">i</span><span class="o">**</span><span class="n">a</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">N</span> <span class="o">-</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">**</span><span class="n">b</span> <span class="o">*</span> <span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">phi</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">),</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">i</span><span class="o">**</span><span class="n">a</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">N</span> <span class="o">-</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">**</span><span class="n">b</span> <span class="o">*</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">-</span> <span class="n">phi</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">),</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">i</span><span class="o">**</span><span class="n">a</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">N</span> <span class="o">-</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">**</span><span class="n">b</span> <span class="o">*</span> <span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">-</span> <span class="n">phi</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">),</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">))</span>
<span class="k">return</span> <span class="n">E</span>
</code></pre></div></div>
<p>Let’s try to see if how it performs on the same points where we used the complex-mean method before (using $a = 1$ and $b = 1$):</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">rect</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">/</span><span class="mi">2</span><span class="p">),</span> <span class="n">rect</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">)])</span>
<span class="n">E</span> <span class="o">=</span> <span class="n">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">angle</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmin</span><span class="p">(</span><span class="n">E</span><span class="p">)]</span> <span class="c1"># Mimimize by just taking the coordinate of lowest energy value (resolution = 1000)
</span><span class="n">next_seed</span> <span class="o">=</span> <span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">angle</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Next angle: </span><span class="si">{</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">next_seed</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span><span class="si">}</span><span class="s"> rad"</span><span class="p">)</span>
<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">211</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Seeds"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">E</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Energy"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">next_seed</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">next_seed</span><span class="p">),</span> <span class="s">"x"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Next seed"</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">212</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"$</span><span class="se">\\</span><span class="s">theta$"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">((</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"o"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">E</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">((</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">next_seed</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">next_seed</span><span class="p">),</span> <span class="s">"x"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">borderaxespad</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
</code></pre></div></div>
<p>This prints <code class="language-plaintext highlighter-rouge">Next angle: 3.377447957913351 rad</code> and returns the following figure:</p>
<!-- ![Energy 1 demo -fullwidth](/assets/fibonacci/energy1_demo.svg) -->
<p><img src="/assets/fibonacci/energy1_demo.svg" class="dark-inv" width="100%" /></p>
<p>This actually looks quite promising. But we still have to determine the best parameters $a$ and $b$ that result in the golden angle after enough iterations. This is pretty easily done by experimentation. The key here is that this function should describe a stable system, so that through iteration it approaches the golden angle. The parameters shouldn’t be too precise, because then again they would have to be “saved” somewhere, and that is counterproductive to our preconditions. If the energy function is stable enough, it should result in the golden angle, even if the parameters are changed (by a small amount).</p>
<p>So let’s try all combinations $a, b \in \{0, 1, 2, 3, 4\}$, and see how the resulting flower would look like:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">seeds</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)])</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">200</span><span class="p">):</span>
<span class="n">seeds</span> <span class="o">+=</span> <span class="n">seeds</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">)</span> <span class="c1"># Growing
</span> <span class="n">angle</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmin</span><span class="p">(</span><span class="n">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">))]</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">seeds</span><span class="p">,</span> <span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">angle</span><span class="p">)))</span>
<span class="k">return</span> <span class="n">seeds</span>
<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">seeds</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="o">*</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">yaxis</span><span class="p">.</span><span class="n">set_major_formatter</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">NullFormatter</span><span class="p">())</span>
<span class="n">ax</span><span class="p">.</span><span class="n">xaxis</span><span class="p">.</span><span class="n">set_major_formatter</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">NullFormatter</span><span class="p">())</span>
<span class="k">if</span> <span class="n">b</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">ax</span><span class="p">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">f</span><span class="s">"$a = </span><span class="si">{</span><span class="n">a</span><span class="si">}</span><span class="s">$"</span><span class="p">,</span>
<span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">.</span><span class="mi">9</span><span class="p">),</span>
<span class="n">xycoords</span><span class="o">=</span><span class="s">'axes fraction'</span><span class="p">,</span>
<span class="n">size</span><span class="o">=</span><span class="mi">14</span><span class="p">,</span>
<span class="n">bbox</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">boxstyle</span><span class="o">=</span><span class="s">"round"</span><span class="p">,</span> <span class="n">fc</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">alpha</span><span class="o">=</span><span class="p">.</span><span class="mi">5</span><span class="p">))</span>
<span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">ax</span><span class="p">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">f</span><span class="s">"$b = </span><span class="si">{</span><span class="n">b</span><span class="si">}</span><span class="s">$"</span><span class="p">,</span>
<span class="n">xy</span><span class="o">=</span><span class="p">(.</span><span class="mi">7</span><span class="p">,</span> <span class="p">.</span><span class="mi">9</span><span class="p">),</span>
<span class="n">xycoords</span><span class="o">=</span><span class="s">'axes fraction'</span><span class="p">,</span>
<span class="n">size</span><span class="o">=</span><span class="mi">14</span><span class="p">,</span>
<span class="n">bbox</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">boxstyle</span><span class="o">=</span><span class="s">"round"</span><span class="p">,</span> <span class="n">fc</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">alpha</span><span class="o">=</span><span class="p">.</span><span class="mi">5</span><span class="p">))</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">s</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">s</span><span class="p">),</span> <span class="s">"."</span><span class="p">)</span>
</code></pre></div></div>
<!-- ![Energy 1 mosaic 1 -fullwidth](/assets/fibonacci/many_seeds.svg) -->
<p><img src="/assets/fibonacci/many_seeds.svg" class="dark-inv" width="100%" /></p>
<p>These definitely look much better than the previous attempt. Especially $b = 1$ and $b = 2$ with a high value for $a$ look promising. Let’s also visualize the final energy function that would decide where the next seed should go:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">seeds</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="o">*</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">xaxis</span><span class="p">.</span><span class="n">set_major_formatter</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="n">NullFormatter</span><span class="p">())</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">energy</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">))</span>
</code></pre></div></div>
<!-- ![Energy 1 mosaic 2 -fullwidth](/assets/fibonacci/many_energies.svg) -->
<p><img src="/assets/fibonacci/many_energies.svg" class="dark-inv" width="100%" /></p>
<p>Lastly, let’s also plot the relative angles between each seed and the previous seed, and see if they approach the golden angle (the red line is the golden angle):</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="n">sharex</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">sharey</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">seeds</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="n">angles</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">diff</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">s</span><span class="p">))</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">].</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"Iteration"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">].</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"$</span><span class="se">\\</span><span class="s">theta$"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">].</span><span class="n">axhline</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">),</span> <span class="n">color</span><span class="o">=</span><span class="s">'r'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">].</span><span class="n">plot</span><span class="p">(</span><span class="n">angles</span><span class="p">)</span>
</code></pre></div></div>
<!-- ![Energy 1 mosaic 3 -fullwidth](/assets/fibonacci/many_iterations.svg) -->
<p><img src="/assets/fibonacci/many_iterations.svg" class="dark-inv" width="100%" /></p>
<p>It seems like if $b$ is around 1 and $a$ isn’t too small, the minimum energy angle will approach the golden angle after enough iteration steps. So let’s try to use this to find the golden angle!</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">b</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)])</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">500</span><span class="p">):</span>
<span class="n">seeds</span> <span class="o">+=</span> <span class="n">seeds</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">)</span>
<span class="n">angle</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmin</span><span class="p">(</span><span class="n">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="o">=</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="n">b</span><span class="p">))]</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">seeds</span><span class="p">,</span> <span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">angle</span><span class="p">)))</span>
<span class="n">E</span> <span class="o">=</span> <span class="n">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="o">=</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="n">b</span><span class="p">)</span> <span class="c1"># Energy at the end of simulation
</span>
<span class="n">angles</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">diff</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">))</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span>
<span class="n">fa</span> <span class="o">=</span> <span class="n">angles</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">angles</span><span class="p">)</span><span class="o">/</span><span class="mi">3</span><span class="p">):].</span><span class="n">mean</span><span class="p">()</span> <span class="c1"># Final angle: mean angle of last 2/3 of the simulation
</span><span class="k">print</span><span class="p">(</span><span class="n">dd</span><span class="p">(</span><span class="sa">f</span><span class="s">"""</span><span class="se">\
</span><span class="s"> Final angle: </span><span class="si">{</span><span class="n">fa</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">
Error: </span><span class="si">{</span><span class="nb">abs</span><span class="p">(</span><span class="n">fa</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">))</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span> <span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">%"""</span><span class="p">))</span>
<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">221</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"Seeds</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"."</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">222</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"Energy at the end (t=500)</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">E</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">212</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"$</span><span class="se">\\</span><span class="s">theta$"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"Iteration (t)"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">),</span> <span class="n">color</span><span class="o">=</span><span class="s">'r'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Golden angle"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">angles</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"$</span><span class="se">\\</span><span class="s">theta_t - </span><span class="se">\\</span><span class="s">theta_{t - 1} </span><span class="se">\\</span><span class="s">mathrm{mod} 2</span><span class="se">\\</span><span class="s">pi$"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Final angle: 2.47
Error: 1.59%
</code></pre></div></div>
<!-- ![Energy 1 simulation -fullwidth](/assets/fibonacci/not_very_good.svg) -->
<p><img src="/assets/fibonacci/not_very_good.svg" class="dark-inv" width="100%" /></p>
<p>The value is <em>okay</em>, but as seen in the simulation, the function is not actually very stable, in the last part it deviates significantly from the golden angle. There seems to be more than one stable point, and as a result we see some bifurcation. In the plots above, where the minimum energy angle is plotted against iteration, we see that our choice of $b$ has a great impact on the final stable point we land on. If $b=0,$ it looks like it approaches the golden angle, but actually it stays at an angle slightly larger, which is why the spirals for $b=1$ look different from what we expect. Where $b=3$ or $b=4$, the angle also seems to find very stable points far away from the golden angle, so those spirals also look very different from the ones created with the golden angle.</p>
<p>It seems we are not done yet! Maybe it would be better to have a function without parameters, because the less information is needed, the better! Because I still think the Gaussian functions are an elegant way to model how much room there is at a point on the meristem, I kept the energy function as a sum of Gaussians. This is the second try for an energy function:
\begin{equation}
E(\theta) = \frac{1}{N} \sum_{i=0}^{N - 1}{\frac{1}{1 - \frac{i}{N}} e^{-(\theta - \theta_i)^2}}
\end{equation}
In the previous function, $b$ specified how the width of the function should change with the distance from the meristem. I thought it would be a good idea to have the bell be broader if the seed was near to the stem, but conversely this also meant that it would get much narrower if it got farther away. This does not seem like it really should be the case, so I just removed the whole term in the exponential function. It is still scaled in a way so that seeds farther from the origin (lower $i$) have a smaller bell, but without the parameter $a$, and in a hyperbolic manner instead of polynomially.</p>
<p>Let’s check how well it performs on the same two points that until now only the naïve mean of angles couldn’t handle:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Instead of np.linspace: add more points around x, provide a better resolution in the meaningful region
</span><span class="k">def</span> <span class="nf">curvedspace</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">num</span><span class="o">=</span><span class="mi">50</span><span class="p">):</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">cbrt</span><span class="p">(</span><span class="n">a</span> <span class="o">-</span> <span class="n">x</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="n">cbrt</span><span class="p">(</span><span class="n">b</span> <span class="o">-</span> <span class="n">x</span><span class="p">),</span> <span class="n">num</span><span class="p">)</span>
<span class="k">return</span> <span class="n">s</span><span class="o">**</span><span class="mi">3</span> <span class="o">+</span> <span class="n">x</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">curvedspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">),</span> <span class="mi">1000</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
<span class="n">N</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">seeds</span><span class="p">)</span>
<span class="n">Z</span> <span class="o">=</span> <span class="n">N</span>
<span class="n">i</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">r_</span><span class="p">[</span><span class="s">'0,2'</span><span class="p">,</span> <span class="n">N</span><span class="o">-</span><span class="n">Z</span><span class="p">:</span><span class="n">N</span><span class="p">].</span><span class="n">T</span>
<span class="n">phi</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">)[</span><span class="o">-</span><span class="n">Z</span><span class="p">:][</span><span class="n">np</span><span class="p">.</span><span class="n">newaxis</span><span class="p">].</span><span class="n">T</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span>
<span class="n">s</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">i</span><span class="o">/</span><span class="n">N</span><span class="p">)</span>
<span class="n">E</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">phi</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="o">/</span> <span class="n">s</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">-</span> <span class="n">phi</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="o">/</span> <span class="n">s</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="mi">4</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">-</span> <span class="n">phi</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="o">/</span> <span class="n">s</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">-</span> <span class="n">phi</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="o">/</span> <span class="n">s</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">4</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">-</span> <span class="n">phi</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="o">/</span> <span class="n">s</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">))</span> <span class="o">/</span> <span class="n">N</span>
<span class="k">return</span> <span class="n">E</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">rect</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">/</span><span class="mi">2</span><span class="p">),</span> <span class="n">rect</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">)])</span>
<span class="n">E</span> <span class="o">=</span> <span class="n">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
<span class="n">angle</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmin</span><span class="p">(</span><span class="n">E</span><span class="p">)]</span> <span class="c1"># Mimimize by just taking the coordinate of lowest energy value (resolution = 1000)
</span><span class="n">next_seed</span> <span class="o">=</span> <span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">angle</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Next angle: </span><span class="si">{</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">next_seed</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span><span class="si">}</span><span class="s"> rad"</span><span class="p">)</span>
<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">211</span><span class="p">,</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"o"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Seeds"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">E</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Energy"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">next_seed</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">next_seed</span><span class="p">),</span> <span class="s">"x"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Next seed"</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">212</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"$</span><span class="se">\\</span><span class="s">theta$"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">((</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"o"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">E</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="n">plot</span><span class="p">((</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">next_seed</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">next_seed</span><span class="p">),</span> <span class="s">"x"</span><span class="p">)</span>
<span class="n">fig</span><span class="p">.</span><span class="n">legend</span><span class="p">(</span><span class="n">borderaxespad</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
</code></pre></div></div>
<p>This prints <code class="language-plaintext highlighter-rouge">Next angle: 3.6987772510159513 rad</code> and returns the following figure:</p>
<!-- ![Energy 1 demo -fullwidth](/assets/fibonacci/energy2_demo.svg) -->
<p><img src="/assets/fibonacci/energy2_demo.svg" class="dark-inv" width="100%" /></p>
<p>Alright, that is pretty much what we would have expected, not too different from the last attempt. Because there are no parameters, let’s directly run a simulation and see if we get the golden angle!</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">full</span><span class="p">(</span><span class="mi">500</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">nan</span><span class="p">)</span>
<span class="n">i</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">500</span><span class="p">)</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)])</span>
<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">tight_layout</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">grid</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">GridSpec</span><span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">wspace</span><span class="o">=</span><span class="mf">0.4</span><span class="p">,</span> <span class="n">hspace</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
<span class="n">ax0</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">grid</span><span class="p">[:</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax0</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">500</span><span class="p">)</span>
<span class="n">ax0</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"Seeds</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="n">ln0</span><span class="p">,</span> <span class="o">=</span> <span class="n">ax0</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="s">"."</span><span class="p">)</span>
<span class="n">ax1</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">grid</span><span class="p">[:</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">projection</span><span class="o">=</span><span class="s">'polar'</span><span class="p">)</span>
<span class="n">ax1</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">ax1</span><span class="p">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">"Energy</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="n">ln1</span><span class="p">,</span> <span class="o">=</span> <span class="n">ax1</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="mi">3</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">ones</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">))</span>
<span class="n">ax3</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">grid</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="p">:])</span>
<span class="n">ax3</span><span class="p">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">ax2</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">grid</span><span class="p">[</span><span class="mi">4</span><span class="p">:,</span> <span class="p">:])</span>
<span class="n">ax2</span><span class="p">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="p">.</span><span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">+</span> <span class="p">.</span><span class="mi">5</span><span class="p">)</span>
<span class="n">ax2</span><span class="p">.</span><span class="n">axhline</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">),</span> <span class="n">color</span><span class="o">=</span><span class="s">'r'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">"Golden angle"</span><span class="p">)</span>
<span class="n">ax2</span><span class="p">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s">"$</span><span class="se">\\</span><span class="s">theta$"</span><span class="p">)</span>
<span class="n">ax2</span><span class="p">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s">"Iteration (t)"</span><span class="p">)</span>
<span class="n">ln2</span><span class="p">,</span> <span class="o">=</span> <span class="n">ax2</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="mi">500</span><span class="p">),</span> <span class="n">label</span><span class="o">=</span><span class="s">"$</span><span class="se">\\</span><span class="s">theta_t - </span><span class="se">\\</span><span class="s">theta_{t - 1} </span><span class="se">\\</span><span class="s">mathrm{mod} 2</span><span class="se">\\</span><span class="s">pi$"</span><span class="p">)</span>
<span class="n">ax2</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
<span class="k">global</span> <span class="n">a</span><span class="p">,</span> <span class="n">seeds</span>
<span class="n">E</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="mf">1j</span> <span class="o">*</span> <span class="n">x</span><span class="p">)</span> <span class="o">*</span> <span class="n">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
<span class="n">seeds</span> <span class="o">+=</span> <span class="n">seeds</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">)</span> <span class="c1"># Growing
</span> <span class="n">angle</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmin</span><span class="p">(</span><span class="n">energy</span><span class="p">(</span><span class="n">seeds</span><span class="p">,</span> <span class="n">x</span><span class="p">))]</span>
<span class="n">seeds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">seeds</span><span class="p">,</span> <span class="n">rect</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">angle</span><span class="p">)))</span>
<span class="n">ln0</span><span class="p">.</span><span class="n">set_data</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">seeds</span><span class="p">))</span>
<span class="n">ln1</span><span class="p">.</span><span class="n">set_data</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">E</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">E</span><span class="p">))</span>
<span class="n">angle</span> <span class="o">=</span> <span class="p">(</span><span class="n">angle</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">)[</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span>
<span class="n">average</span> <span class="o">=</span> <span class="p">((</span><span class="n">np</span><span class="p">.</span><span class="n">diff</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">angle</span><span class="p">(</span><span class="n">seeds</span><span class="p">))</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)).</span><span class="n">mean</span><span class="p">()</span>
<span class="n">ax3</span><span class="p">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">ax3</span><span class="p">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">ax3</span><span class="p">.</span><span class="n">text</span><span class="p">(.</span><span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">dd</span><span class="p">(</span><span class="sa">f</span><span class="s">"""</span><span class="se">\
</span><span class="s"> Minimum Energy Angle: </span><span class="si">{</span><span class="n">angle</span><span class="si">:</span><span class="mf">12.9</span><span class="n">f</span><span class="si">}</span><span class="s">
Average Angle: </span><span class="si">{</span><span class="n">average</span><span class="si">:</span><span class="mf">12.9</span><span class="n">f</span><span class="si">}</span><span class="s">
Golden Angle: </span><span class="si">{</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">)</span><span class="si">:</span><span class="mf">12.9</span><span class="n">f</span><span class="si">}</span><span class="s">
Difference: </span><span class="si">{</span><span class="nb">abs</span><span class="p">(</span><span class="n">average</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">))</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span><span class="si">:</span><span class="mf">12.9</span><span class="n">f</span><span class="si">}</span><span class="s">%
π ≈ </span><span class="si">{</span><span class="n">average</span><span class="o">/</span><span class="p">(</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">5</span><span class="o">**</span><span class="p">.</span><span class="mi">5</span><span class="p">)</span><span class="si">:</span><span class="mf">12.9</span><span class="n">f</span><span class="si">}</span><span class="s"> """</span><span class="p">),</span>
<span class="n">ha</span><span class="o">=</span><span class="s">'center'</span><span class="p">,</span>
<span class="n">family</span><span class="o">=</span><span class="s">'monospace'</span><span class="p">)</span>
<span class="n">a</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="n">angle</span>
<span class="n">ln2</span><span class="p">.</span><span class="n">set_data</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span>
<span class="k">return</span> <span class="n">ln0</span><span class="p">,</span> <span class="n">ln1</span><span class="p">,</span> <span class="n">ln2</span>
<span class="n">anim</span> <span class="o">=</span> <span class="n">FuncAnimation</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">draw</span><span class="p">,</span> <span class="mi">500</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">blit</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>
<video width="100%" autoplay="" muted="" loop="" playsinline="" class="dark-inv">
<source src="/assets/fibonacci/finsim.webm" type="video/webm" />
<source src="/assets/fibonacci/finsim.mp4" type="video/mp4" />
There's a problem with the video, <a href="https://youtu.be/D-a_4-sQdi8">try this link</a>.
</video>
<p>It works!<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup> The difference between the average minimum energy angle and the golden angle is constantly getting smaller, and there do not seem to be the same bifurcation issues as before.
Because the only two mathematical functions used here are the Gaussian $e^{-x^2}$ and that for the hyperbolic decay $\frac{1}{x}$, and these functions are not uncommon in natural phenomena, it seems possible for this, or a function similar to this, to be how plants “calculate” the golden angle.
But how does it help the plant that there exists this formula to compute the golden angle?</p>
<p>A theory on how the seeds know in which direction to grow, i.e. where the most space is, has to do with the distribution of growth hormones on the meristem. This distribution can probably be modelled by a function similar to our energy function, so that the place, where the most growth hormones are (or where the energy function has its lowest value), is the place where the next seed begins to form. Of course there is no mathematical formula engraved in the plant’s DNA, and there are no processing cells that calculate this distribution, it simply arises naturally by how the hormones are used by the seed–if one seed forms, it uses a lot of the growth hormones that were on that spot on the meristem, so the next seed will form somewhere else, where there is now the largest amount of growth hormones. If you were to plot this distribution, it would probably look very similar to the (inverted) energy function that we have found.</p>
<p>Of course the plant does not know this. Evolution does not know this. Evolution was just selecting via trial and error for energy efficient spirals, and its solution happens to be something that can be expressed mathematically as well. The plant doesn’t care about this. It just used evolution as a tool to maximize efficiency, and evolution came up with a solution. But now, we can measure this solution. If we take a plant and measure the angle between two leaves, we get the golden angle, and we did not have to calculate it ourselves. But the plant also didn’t calculate it, because it has no processing abilities. But someone had to calculate it! The calculator here was evolution by natural selection. Evolution can, by the simple process of a binary answer (reproduce or don’t reproduce) and constant iteration, calculate the golden angle (or anything else, for that matter). So even if plants are still pretty dumb, they have access to a cross-generational superbrain.</p>
<p>I was inspired to write this post by ViHart’s amazing videos on these spirals<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">7</a></sup>. If you found this post even a tiny bit interesting, do check them out, they’re much better.</p>
<hr />
<p><small id="notebook"><a href="/assets/fibonacci/notebook.ipynb"><i>Download the Jupyter Notebook file for this post</i></a></small></p>
<h4 id="footnotes">Footnotes</h4>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p><a href="https://www.flickr.com/photos/colinwarren/158628063/">Source 1</a>, <a href="http://in-lakech-ala-kin.tumblr.com/post/2512330097">Source 2</a>, <a href="https://commons.wikimedia.org/wiki/File:Espiral_de_semillas_de_Girasol.jpg">Source 3</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Swinton, J., Ochu, E., & MSI Turing’s Sunflower Consortium. (2016). <a href="https://royalsocietypublishing.org/doi/full/10.1098/rsos.160091">Novel Fibonacci and non-Fibonacci structure in the sunflower: results of a citizen science experiment</a>. Royal Society open science, 3(5), 160091. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p><a href="https://liaisonwithalison.files.wordpress.com/2015/03/fibonacci-sunflower.jpg">Source</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p><a href="https://www.quantamagazine.org/a-new-thermodynamics-theory-of-the-origin-of-life-20140122/">A New Physics Theory of Life - Quanta Magazine</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>Douady, S., & Couder, Y. (1996). <a href="http://www.uvm.edu/pdodds/files/papers/others/1996/douady1996a.pdf">Phyllotaxis as a dynamical self organizing process part I: the spiral modes resulting from time-periodic iterations</a>. Journal of theoretical biology, 178(3), 255-273. <a href="#fnref:5" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:6" role="doc-endnote">
<p>If there is an issue with playing the animation, <a href="https://youtu.be/D-a_4-sQdi8">try this link</a>. <a href="#fnref:6" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:7" role="doc-endnote">
<p>ViHart’s videos on the topic: <a href="https://www.youtube.com/playlist?list=PLRH2gUvTc1Lzx7Q_Ijo9CTnB4VsArQqbB">link</a><br />There’s also a great video by Mathologer <a href="https://www.youtube.com/watch?v=_GkxCIW46to">here</a> <a href="#fnref:7" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Onno Eberhardhttps://onnoeberhard.comonnoeberhard@gmail.comPlants are bimbos. Beautiful, but stupid–at least that’s what most people think. But in this post I want to talk about why I think plants are much more intelligent than people give them credit for. You’ve probably seen the pretty spirally patterns that emerge in many plants when leaves or seeds grow outwards (see figure below). I think they are very interesting and I want to convince you that plants do need to be intelligent to be able to create them. Spirals!1 1 A well known fun-fact about these spirals is their connection to the Fibonacci numbers. These are the numbers belonging to the Fibonacci sequence: $1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …$ (every number is the sum of its two preceding numbers). In plants, these spirals almost always2 seem to have a Fibonacci number of arms (see the figure below). Source 1, Source 2, Source 3 ↩ Swinton, J., Ochu, E., & MSI Turing’s Sunflower Consortium. (2016). Novel Fibonacci and non-Fibonacci structure in the sunflower: results of a citizen science experiment. Royal Society open science, 3(5), 160091. ↩Having a blog2018-09-09T00:00:00+02:002018-09-09T00:00:00+02:00https://onnoeberhard.com/2018/09/09/having-a-blog<p>The first rule of writing is “Know your reader.” I don’t know my reader. In fact, there is no reader yet. So this makes things a bit more difficult, but I’ll try my best.</p>
<p>To get a grasp of the audience, maybe some code can help us analyse the situation. To be realistic, I will assume that there are one million people currently reading this.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> They are randomly distributed on the so-called “Nerd Scale”:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">N</span> <span class="o">=</span> <span class="mi">1000000</span> <span class="c1"># That's just the beginning!
</span><span class="n">initial_readers</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">randn</span><span class="p">(</span><span class="n">N</span><span class="p">)</span> <span class="c1"># Draw N random people from the global population (normally distributed along nerd scale)
</span></code></pre></div></div>
<p>If we plot a histogram of the current readers regarding their nerd factors, this is what we get:</p>
<!-- ![Initial Readers -fullwidth](/assets/having-a-blog/initial.png) -->
<!-- <img src="/assets/having-a-blog/initial.png" class="dark-inv" width="100%"/> -->
<div class="responsive-image dark-inv initial" style="width: 100%">
<img class="responsive-image-background initial" src="/assets/resized/320/initial.png" onclick="" style="" />
<div class="responsive-image-placeholder initial" data-class="initial" data-src="/{width}"></div>
</div>
<script>
var orig_width = parseFloat("1800");
var orig_path = "assets/having-a-blog/initial.png";
var resize_path = "assets/resized/";
var sizes = [320, 480, 640, 800, 960, 1280, 1440, 1600];
new Imager('.responsive-image-placeholder.initial', {
className: 'responsive-image-replace',
availableWidths: sizes,
widthInterpolator: function(width, pixelRatio) {
var goal = 1.5 * pixelRatio * width;
if (goal >= orig_width)
return orig_path;
var closest = sizes.reduce(function(prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
return resize_path + closest + "/initial.png";
},
onImagesReplaced: function() {
$('.responsive-image-replace.initial').attr('style', "")
$('.responsive-image-background.initial').imageLoad(function(){
var aspect = $('.responsive-image-background.initial').width() / $('.responsive-image-background.initial').height()
$('.responsive-image.initial').css('aspect-ratio', String(aspect));
$('.responsive-image-background.initial').css('aspect-ratio', String(aspect));
$('.responsive-image-replace.initial').css('aspect-ratio', String(aspect));
$('.responsive-image-placeholder.initial').css('aspect-ratio', String(aspect));
});
$('.responsive-image-replace.initial').attr('onClick', "");
$('.responsive-image-replace.initial').imageLoad(function(){
$('.responsive-image-background.initial').hide();
});
}
})
</script>
<p>To clarify how this scale works, one may refer to the table below:</p>
<!-- more -->
<table>
<thead>
<tr>
<th style="text-align: center">Nerd Factor</th>
<th style="text-align: center">Example<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">-5</td>
<td style="text-align: center">A Sperm Whale</td>
</tr>
<tr>
<td style="text-align: center">-4</td>
<td style="text-align: center">A Bowl of Petunias</td>
</tr>
<tr>
<td style="text-align: center">-3</td>
<td style="text-align: center">Prostetnic Vogon Jeltz</td>
</tr>
<tr>
<td style="text-align: center">-2</td>
<td style="text-align: center">Arthur Dent</td>
</tr>
<tr>
<td style="text-align: center">-1</td>
<td style="text-align: center">Zaphod Beeblebrox</td>
</tr>
<tr>
<td style="text-align: center">0</td>
<td style="text-align: center">Ford Prefect (the car)</td>
</tr>
<tr>
<td style="text-align: center">1</td>
<td style="text-align: center">Marvin</td>
</tr>
<tr>
<td style="text-align: center">2</td>
<td style="text-align: center">Slartibartfast</td>
</tr>
<tr>
<td style="text-align: center">3</td>
<td style="text-align: center">Trillian</td>
</tr>
<tr>
<td style="text-align: center">4</td>
<td style="text-align: center">Lunkwill and Fook</td>
</tr>
<tr>
<td style="text-align: center">5</td>
<td style="text-align: center">Deep Thought</td>
</tr>
</tbody>
</table>
<p>All right, because there has now been Python code and H2G2 references, I think it’s probably fair to assume most of our million initial readers have left, because they have better things to do. Good thing that I have nothing better to do than to calculate who left!</p>
<p>To find this out, it’s best to carry out a study where we take a large number of individuals from everywhere on the nerd scale and ask them whether they would continue reading after the first paragraphs. The collected data can then give us a function to predict who of our initial readers left.</p>
<p>This study is easily simulated on a computer:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">norm</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mi">6</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">500</span><span class="p">)</span> <span class="c1"># 500 carefully chosen individuals that are evenly distributed along the nerd scale
</span><span class="n">probability</span> <span class="o">=</span> <span class="n">norm</span><span class="p">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># Asking them whether they would read on
</span><span class="n">probability</span> <span class="o">/=</span> <span class="n">probability</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span> <span class="c1"># Normalizing
</span></code></pre></div></div>
<!-- ![Python Tolerance -fullwidth](/assets/having-a-blog/prob.png) -->
<!-- <img src="/assets/having-a-blog/prob.png" class="dark-inv" width="100%"/> -->
<div class="responsive-image dark-inv prob" style="width: 100%">
<img class="responsive-image-background prob" src="/assets/resized/320/prob.png" onclick="" style="" />
<div class="responsive-image-placeholder prob" data-class="prob" data-src="/{width}"></div>
</div>
<script>
var orig_width = parseFloat("1800");
var orig_path = "assets/having-a-blog/prob.png";
var resize_path = "assets/resized/";
var sizes = [320, 480, 640, 800, 960, 1280, 1440, 1600];
new Imager('.responsive-image-placeholder.prob', {
className: 'responsive-image-replace',
availableWidths: sizes,
widthInterpolator: function(width, pixelRatio) {
var goal = 1.5 * pixelRatio * width;
if (goal >= orig_width)
return orig_path;
var closest = sizes.reduce(function(prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
return resize_path + closest + "/prob.png";
},
onImagesReplaced: function() {
$('.responsive-image-replace.prob').attr('style', "")
$('.responsive-image-background.prob').imageLoad(function(){
var aspect = $('.responsive-image-background.prob').width() / $('.responsive-image-background.prob').height()
$('.responsive-image.prob').css('aspect-ratio', String(aspect));
$('.responsive-image-background.prob').css('aspect-ratio', String(aspect));
$('.responsive-image-replace.prob').css('aspect-ratio', String(aspect));
$('.responsive-image-placeholder.prob').css('aspect-ratio', String(aspect));
});
$('.responsive-image-replace.prob').attr('onClick', "");
$('.responsive-image-replace.prob').imageLoad(function(){
$('.responsive-image-background.prob').hide();
});
}
})
</script>
<p>As expected, it seems like more nerdy people stick around with a higher probability. Interestingly, the biggest nerds left, they probably really do have better things to do.</p>
<p>Now we can apply this function to the people from before and see who’s still with us!</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p_still_reading</span> <span class="o">=</span> <span class="n">norm</span><span class="p">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">initial_readers</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># Now ask the 'real' readers if they want to continue reading
</span><span class="n">p_still_reading</span> <span class="o">/=</span> <span class="n">p_still_reading</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span> <span class="c1"># Normalize
</span><span class="n">nerds</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">where</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">rand</span><span class="p">(</span><span class="n">N</span><span class="p">)</span> <span class="o"><</span> <span class="n">p_still_reading</span><span class="p">,</span>
<span class="n">initial_readers</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">full</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">nan</span><span class="p">))</span> <span class="c1"># Filter out those that don't want to continue
</span></code></pre></div></div>
<!-- ![Still reading -fullwidth](/assets/having-a-blog/nerds.png) -->
<!-- <img src="/assets/having-a-blog/nerds.png" class="dark-inv" width="100%"/> -->
<div class="responsive-image dark-inv nerds" style="width: 100%">
<img class="responsive-image-background nerds" src="/assets/resized/320/nerds.png" onclick="" style="" />
<div class="responsive-image-placeholder nerds" data-class="nerds" data-src="/{width}"></div>
</div>
<script>
var orig_width = parseFloat("1800");
var orig_path = "assets/having-a-blog/nerds.png";
var resize_path = "assets/resized/";
var sizes = [320, 480, 640, 800, 960, 1280, 1440, 1600];
new Imager('.responsive-image-placeholder.nerds', {
className: 'responsive-image-replace',
availableWidths: sizes,
widthInterpolator: function(width, pixelRatio) {
var goal = 1.5 * pixelRatio * width;
if (goal >= orig_width)
return orig_path;
var closest = sizes.reduce(function(prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
return resize_path + closest + "/nerds.png";
},
onImagesReplaced: function() {
$('.responsive-image-replace.nerds').attr('style', "")
$('.responsive-image-background.nerds').imageLoad(function(){
var aspect = $('.responsive-image-background.nerds').width() / $('.responsive-image-background.nerds').height()
$('.responsive-image.nerds').css('aspect-ratio', String(aspect));
$('.responsive-image-background.nerds').css('aspect-ratio', String(aspect));
$('.responsive-image-replace.nerds').css('aspect-ratio', String(aspect));
$('.responsive-image-placeholder.nerds').css('aspect-ratio', String(aspect));
});
$('.responsive-image-replace.nerds').attr('onClick', "");
$('.responsive-image-replace.nerds').imageLoad(function(){
$('.responsive-image-background.nerds').hide();
});
}
})
</script>
<p>So even though the maximal probability of reading on was at 3, the mean nerd factor of the remaining readers is below 2, because there were so few 3’s to begin with!</p>
<p>Okay so how many readers are left overall?</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Audience reduced to </span><span class="si">{</span><span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">isnan</span><span class="p">(</span><span class="n">nerds</span><span class="p">))</span> <span class="o">/</span> <span class="n">N</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span> <span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">% of what was zero to begin with."</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Audience reduced to 7.43% of what was zero to begin with.
</code></pre></div></div>
<p>Ok then, I think that’s enough of that. Thank you for not yet fleeing my site, I hope you had a great day so far. Now that I feel comfortable around my audience, I think it’s time to introduce myself.</p>
<p>I’m Onno (in case you haven’t spotted the tiny subtle letters in the sidebar). By day I study electrical engineering, and by night I usually sleep. Whenever I have too much time or enthusiasm on my hands, I start a project–like this blog! Some of my biggest projects so far were <a href="/epotato">ePotato</a>, <a href="/tau">tau</a> and <a href="/kevinBacon">6Ω of Separation</a>. These are all projects I worked on for at least a few months, and for each of them I built a separate website. But for most of my smaller projects I don’t have the time to do that, so in the past I just put a link to the GitHub repository on my (now defunct) <a href="/oldarchive">archive</a> page.</p>
<p>A lot of the time, I don’t think this is doing these smaller projects justice. Last year I worked about 50 hours on a small project called “Snowflake”; a few LEDs controlled by an ATtiny13A<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>, using pulse width modulation to blink. It was a lot of fun, but much more challenging than I expected! For example, I had to use Assembly to program these things because all my C programs compiled to files too large for the AVR’s memory. I did upload my code to GitHub<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>, but what use is that? If somebody were to have the same problems I had building it, I want them to be able to find my solutions. That won’t happen if all there is is a code file hidden somewhere on GitHub.</p>
<p>I have replaced the old archive page with a new <a href="/projects">projects</a> page, where I at least provide a description for each project. But in the future, I want to share my projects more in-depth, that’s why I’m starting this blog. I’ve tried Medium before, for the “6Ω of Separation project”<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup>, but I think this Jekyll-powered blog is much more fun. There’s a lot more room for possibilities, for example to embed interactive widgets in posts. Also, Jupyter Notebooks:</p>
<div style="position: relative; width: 100%; margin: -1em auto 1.5em auto;">
<iframe width="100%" class="dark-inv" height="100%" style="position: absolute; top: 0; left: 0; border-style: none;" src="/assets/having-a-blog/rwth.html" onload="this.parentElement.style.paddingBottom = (this.contentWindow.document.documentElement.scrollHeight + 10) + 'px'">
</iframe>
</div>
<p>So we’ll see where this goes, I hope for the best.</p>
<p>Thank you very much for reading my first blog post! I hope to post about once a month, so as to improve my writing skills, and also to force me to engage in projects, so that I have something to write about. You can subscribe via RSS / Atom using the button in the sidebar, but I will probably also crosspost future posts to Medium.</p>
<p>By the way, maybe none of us are nerds, according to the “Nerd Manual”<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup> there are six steps to becoming a real nerd:</p>
<ul>
<li>Raise your GPA to a 3.5,</li>
<li>Make one friend who is more physically fit than you are,</li>
<li>Make one friend who is better at computer science than you are,</li>
<li>Distance yourself from Phil who always talks you into smoking with him,</li>
<li>Be able to program mobile apps,</li>
<li>Crush the 100 burpee challenge.</li>
</ul>
<p>So just try to keep that in mind. But don’t be too rude to Phil please.<br /> Who is Phil? Are you Phil?</p>
<hr />
<p><small><a href="/assets/having-a-blog/blog.ipynb"><i>Download the Jupyter Notebook file for this post</i></a></small></p>
<h4 id="footnotes">Footnotes</h4>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>Proof (live analytics): <img src="https://img.shields.io/badge/Currently%20reading-~%201%20Million%20People-green.svg" style="display: inline; margin: 0 0 -4px 0;" /> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>It’s been a while since I’ve read the book. If you have an objection, feel free to argue. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>These are amazing, basically a whole computer the size of a fingernail! <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/doc8126.pdf">Datasheet (microchip.com)</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p><a href="https://github.com/onnoeberhard/snowflake/blob/master/snowflake/snowflake.asm">Link (github.com)</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p><a href="https://medium.com/@onnoeberhard/6%CF%89-of-separation-af1b67007423">Link (medium.com)</a> <a href="#fnref:5" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:6" role="doc-endnote">
<p><a href="https://www.nerdmanual.com/2017/06/nerd-q-how-do-i-accomplish-this.html">Link (nerdmanual.com)</a> <a href="#fnref:6" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Onno Eberhardhttps://onnoeberhard.comonnoeberhard@gmail.comThe first rule of writing is “Know your reader.” I don’t know my reader. In fact, there is no reader yet. So this makes things a bit more difficult, but I’ll try my best. To get a grasp of the audience, maybe some code can help us analyse the situation. To be realistic, I will assume that there are one million people currently reading this.1 They are randomly distributed on the so-called “Nerd Scale”: N = 1000000 # That's just the beginning! initial_readers = np.random.randn(N) # Draw N random people from the global population (normally distributed along nerd scale) If we plot a histogram of the current readers regarding their nerd factors, this is what we get: To clarify how this scale works, one may refer to the table below: Proof (live analytics): ↩