Add posts
|
@ -24,6 +24,18 @@
|
||||||
Here you can find all my previous posts:
|
Here you can find all my previous posts:
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="./posts/ising-apl.html">Ising model simulation in APL</a> - March 5, 2018
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="./posts/ising-model.html">Ising model simulation</a> - February 5, 2018
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="./posts/lsystems.html">Generating and representing L-systems</a> - January 18, 2018
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
_site/images/adsb.png
Normal file
After Width: | Height: | Size: 646 KiB |
BIN
_site/images/boards.jpg
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
_site/images/bubbles.jpg
Normal file
After Width: | Height: | Size: 109 KiB |
BIN
_site/images/communities.png
Normal file
After Width: | Height: | Size: 600 KiB |
BIN
_site/images/datasaurus.gif
Normal file
After Width: | Height: | Size: 6.3 MiB |
BIN
_site/images/datasaurus.png
Normal file
After Width: | Height: | Size: 609 KiB |
BIN
_site/images/dpll.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
_site/images/headers/bubbles-wide.jpg
Normal file
After Width: | Height: | Size: 304 KiB |
BIN
_site/images/headers/getting-started.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
_site/images/icon-192.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
_site/images/icon.png
Normal file
After Width: | Height: | Size: 862 B |
BIN
_site/images/ising.gif
Normal file
After Width: | Height: | Size: 570 KiB |
BIN
_site/images/lsystems/dragon.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
_site/images/lsystems/gosper.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
_site/images/lsystems/levyC.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
_site/images/lsystems/penroseP3.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
_site/images/lsystems/plant.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
_site/images/lsystems/sierpinskiArrow.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
_site/images/orbit.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
_site/images/portrait.jpg
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
_site/images/satrap.png
Normal file
After Width: | Height: | Size: 160 KiB |
BIN
_site/images/ww2-bombings.png
Normal file
After Width: | Height: | Size: 530 KiB |
|
@ -38,6 +38,18 @@
|
||||||
<h2>Recent Posts</h2>
|
<h2>Recent Posts</h2>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="./posts/ising-apl.html">Ising model simulation in APL</a> - March 5, 2018
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="./posts/ising-model.html">Ising model simulation</a> - February 5, 2018
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="./posts/lsystems.html">Generating and representing L-systems</a> - January 18, 2018
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
229
_site/posts/ising-apl.html
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Dimitri Lozeve - Ising model simulation in APL</title>
|
||||||
|
<link rel="stylesheet" href="../css/default.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="logo">
|
||||||
|
<a href="../">Dimitri Lozeve</a>
|
||||||
|
</div>
|
||||||
|
<nav>
|
||||||
|
<a href="../">Home</a>
|
||||||
|
<a href="../contact.html">Contact</a>
|
||||||
|
<a href="../archive.html">Archive</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main role="main">
|
||||||
|
<h1>Ising model simulation in APL</h1>
|
||||||
|
<article>
|
||||||
|
<section class="header">
|
||||||
|
Posted on March 5, 2018
|
||||||
|
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h1 id="the-apl-family-of-languages">The APL family of languages</h1>
|
||||||
|
<h2 id="why-apl">Why APL?</h2>
|
||||||
|
<p>I recently got interested in <a href="https://en.wikipedia.org/wiki/APL_(programming_language)">APL</a>, an <em>array-based</em> programming language. In APL (and derivatives), we try to reason about programs as series of transformations of multi-dimensional arrays. This is exactly the kind of style I like in Haskell and other functional languages, where I also try to use higher-order functions (map, fold, etc) on lists or arrays. A developer only needs to understand these abstractions once, instead of deconstructing each loop or each recursive function encountered in a program.</p>
|
||||||
|
<p>APL also tries to be a really simple and <em>terse</em> language. This combined with strange Unicode characters for primitive functions and operators, gives it a reputation of unreadability. However, there is only a small number of functions to learn, and you get used really quickly to read them and understand what they do. Some combinations also occur so frequently that you can recognize them instantly (APL programmers call them <em>idioms</em>).</p>
|
||||||
|
<h2 id="implementations">Implementations</h2>
|
||||||
|
<p>APL is actually a family of languages. The classic APL, as created by Ken Iverson, with strange symbols, has many implementations. I initially tried <a href="https://www.gnu.org/software/apl/">GNU APL</a>, but due to the lack of documentation and proper tooling, I went to <a href="https://www.dyalog.com/">Dyalog APL</a> (which is proprietary, but free for personal use). There are also APL derivatives, that often use ASCII symbols: <a href="http://www.jsoftware.com/">J</a> (free) and <a href="https://code.kx.com/q/">Q/kdb+</a> (proprietary, but free for personal use).</p>
|
||||||
|
<p>The advantage of Dyalog is that it comes with good tooling (which is necessary for inserting all the symbols!), a large ecosystem, and pretty good <a href="http://docs.dyalog.com/">documentation</a>. If you want to start, look at <a href="http://www.dyalog.com/mastering-dyalog-apl.htm"><em>Mastering Dyalog APL</em></a> by Bernard Legrand, freely available online.</p>
|
||||||
|
<h1 id="the-ising-model-in-apl">The Ising model in APL</h1>
|
||||||
|
<p>I needed a small project to try APL while I was learning. Something array-based, obviously. Since I already implemented a Metropolis-Hastings simulation of the <a href="./ising-model.html">Ising model</a>, which is based on a regular lattice, I decided to reimplement it in Dyalog APL.</p>
|
||||||
|
<p>It is only a few lines long, but I will try to explain what it does step by step.</p>
|
||||||
|
<p>The first function simply generates a random lattice filled by elements of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">{</mo><mo>−</mo><mn>1</mn><mo>,</mo><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">\{-1,+1\}</annotation></semantics></math>.</p>
|
||||||
|
<pre class="apl"><code>L←{(2×?⍵ ⍵⍴2)-3}
|
||||||
|
</code></pre>
|
||||||
|
<p>Let’s deconstruct what is done here:</p>
|
||||||
|
<ul>
|
||||||
|
<li>⍵ is the argument of our function.</li>
|
||||||
|
<li>We generate a ⍵×⍵ matrix filled with 2, using the <code>⍴</code> function: <code>⍵ ⍵⍴2</code></li>
|
||||||
|
<li><code>?</code> draws a random number between 1 and its argument. We give it our matrix to generate a random matrix of 1 and 2.</li>
|
||||||
|
<li>We multiply everything by 2 and subtract 3, so that the result is in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">{</mo><mo>−</mo><mn>1</mn><mo>,</mo><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">\{-1,+1\}</annotation></semantics></math>.</li>
|
||||||
|
<li>Finally, we assign the result to the name <code>L</code>.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Sample output:</p>
|
||||||
|
<pre class="apl"><code> ising.L 5
|
||||||
|
1 ¯1 1 ¯1 1
|
||||||
|
1 1 1 ¯1 ¯1
|
||||||
|
1 ¯1 ¯1 ¯1 ¯1
|
||||||
|
1 1 1 ¯1 ¯1
|
||||||
|
¯1 ¯1 1 1 1
|
||||||
|
</code></pre>
|
||||||
|
<p>Next, we compute the energy variation (for details on the Ising model, see <a href="./ising-model.html">my previous post</a>).</p>
|
||||||
|
<pre class="apl"><code>∆E←{
|
||||||
|
⎕IO←0
|
||||||
|
(x y)←⍺
|
||||||
|
N←⊃⍴⍵
|
||||||
|
xn←N|((x-1)y)((x+1)y)
|
||||||
|
yn←N|(x(y-1))(x(y+1))
|
||||||
|
⍵[x;y]×+/⍵[xn,yn]
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<ul>
|
||||||
|
<li>⍺ is the left argument (coordinates of the site), ⍵ is the right argument (lattice).</li>
|
||||||
|
<li>We extract the x and y coordinates of the site.</li>
|
||||||
|
<li><code>N</code> is the size of the lattice.</li>
|
||||||
|
<li><code>xn</code> and <code>yn</code> are respectively the vertical and lateral neighbours of the site. <code>N|</code> takes the coordinates modulo <code>N</code> (so the lattice is actually a torus). (Note: we used <code>⎕IO←0</code> to use 0-based array indexing.)</li>
|
||||||
|
<li><code>+/</code> sums over all neighbours of the site, and then we multiply by the value of the site itself to get <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Δ</mi><mi>E</mi></mrow><annotation encoding="application/x-tex">\Delta E</annotation></semantics></math>.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Sample output, for site <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mn>3</mn><mo>,</mo><mn>3</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(3, 3)</annotation></semantics></math> in a random <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>5</mn><mo>×</mo><mn>5</mn></mrow><annotation encoding="application/x-tex">5\times 5</annotation></semantics></math> lattice:</p>
|
||||||
|
<pre class="apl"><code> 3 3ising.∆E ising.L 5
|
||||||
|
¯4
|
||||||
|
</code></pre>
|
||||||
|
<p>Then comes the actual Metropolis-Hastings part:</p>
|
||||||
|
<pre class="apl"><code>U←{
|
||||||
|
⎕IO←0
|
||||||
|
N←⊃⍴⍵
|
||||||
|
(x y)←?N N
|
||||||
|
new←⍵
|
||||||
|
new[x;y]×←(2×(?0)>*-⍺×x y ∆E ⍵)-1
|
||||||
|
new
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<ul>
|
||||||
|
<li>⍺ is the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>β</mi><annotation encoding="application/x-tex">\beta</annotation></semantics></math> parameter of the Ising model, ⍵ is the lattice.</li>
|
||||||
|
<li>We draw a random site <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(x,y)</annotation></semantics></math> with the <code>?</code> function.</li>
|
||||||
|
<li><code>new</code> is the lattice but with the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(x,y)</annotation></semantics></math> site flipped.</li>
|
||||||
|
<li>We compute the probability <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi><mo>=</mo><mo>exp</mo><mo stretchy="false" form="prefix">(</mo><mo>−</mo><mi>β</mi><mi>Δ</mi><mi>E</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\alpha = \exp(-\beta\Delta E)</annotation></semantics></math> using the <code>*</code> function (exponential) and our previous <code>∆E</code> function.</li>
|
||||||
|
<li><code>?0</code> returns a uniform random number in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mn>0</mn><mo>,</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">[0,1)</annotation></semantics></math>. Based on this value, we decide whether to update the lattice, and we return it.</li>
|
||||||
|
</ul>
|
||||||
|
<p>We can now bring everything together for display:</p>
|
||||||
|
<pre class="apl"><code>Ising←{' ⌹'[1+1=({10 U ⍵}⍣⍵)L ⍺]}
|
||||||
|
</code></pre>
|
||||||
|
<ul>
|
||||||
|
<li>We draw a random lattice of size ⍺ with <code>L ⍺</code>.</li>
|
||||||
|
<li>We apply to it our update function, with $<em>β</em>$=10, ⍵ times (using the <code>⍣</code> function, which applies a function <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math> times.</li>
|
||||||
|
<li>Finally, we display -1 as a space and 1 as a domino ⌹.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Final output, with a <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>80</mn><mo>×</mo><mn>80</mn></mrow><annotation encoding="application/x-tex">80\times 80</annotation></semantics></math> random lattice, after 50000 update steps:</p>
|
||||||
|
<pre class="apl"><code> 80ising.Ising 50000
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹
|
||||||
|
⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
</code></pre>
|
||||||
|
<p>Complete code, with the namespace:</p>
|
||||||
|
<pre class="apl"><code>:Namespace ising
|
||||||
|
|
||||||
|
L←{(2×?⍵ ⍵⍴2)-3}
|
||||||
|
|
||||||
|
∆E←{
|
||||||
|
⎕IO←0
|
||||||
|
(x y)←⍺
|
||||||
|
N←⊃⍴⍵
|
||||||
|
xn←N|((x-1)y)((x+1)y)
|
||||||
|
yn←N|(x(y-1))(x(y+1))
|
||||||
|
⍵[x;y]×+/⍵[xn,yn]
|
||||||
|
}
|
||||||
|
|
||||||
|
U←{
|
||||||
|
⎕IO←0
|
||||||
|
N←⊃⍴⍵
|
||||||
|
(x y)←?N N
|
||||||
|
new←⍵
|
||||||
|
new[x;y]×←(2×(?0)>*-⍺×x y ∆E ⍵)-1
|
||||||
|
new
|
||||||
|
}
|
||||||
|
|
||||||
|
Ising←{' ⌹'[1+1=({10 U ⍵}⍣⍵)L ⍺]}
|
||||||
|
|
||||||
|
:EndNamespace
|
||||||
|
</code></pre>
|
||||||
|
<h1 id="conclusion">Conclusion</h1>
|
||||||
|
<p>The algorithm is very fast (I think it can be optimized by the interpreter because there is no branching), and is easy to reason about. The whole program fits in a few lines, and you clearly see what each function and each line does. It could probably be optimized further (I don’t know every APL function yet…), and also could probably be golfed to a few lines (at the cost of readability?).</p>
|
||||||
|
<p>It took me some time to write this, but Dyalog’s tools make it really easy to insert symbols and to look up what they do. Next time, I will look into some ASCII-based APL descendants. J seems to have a <a href="http://code.jsoftware.com/wiki/NuVoc">good documentation</a> and a tradition of <em>tacit definitions</em>, similar to the point-free style in Haskell. Overall, J seems well-suited to modern functional programming, while APL is still under the influence of its early days when it was more procedural. Another interesting area is K, Q, and their database engine kdb+, which seems to be extremely performant and actually used in production.</p>
|
||||||
|
<p>Still, Unicode symbols make the code much more readable, mainly because there is a one-to-one link between symbols and functions, which cannot be maintained with only a few ASCII characters.</p>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
Site proudly generated by
|
||||||
|
<a href="http://jaspervdj.be/hakyll">Hakyll</a>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
145
_site/posts/ising-model.html
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Dimitri Lozeve - Ising model simulation</title>
|
||||||
|
<link rel="stylesheet" href="../css/default.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="logo">
|
||||||
|
<a href="../">Dimitri Lozeve</a>
|
||||||
|
</div>
|
||||||
|
<nav>
|
||||||
|
<a href="../">Home</a>
|
||||||
|
<a href="../contact.html">Contact</a>
|
||||||
|
<a href="../archive.html">Archive</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main role="main">
|
||||||
|
<h1>Ising model simulation</h1>
|
||||||
|
<article>
|
||||||
|
<section class="header">
|
||||||
|
Posted on February 5, 2018
|
||||||
|
|
||||||
|
by Dimitri Lozeve
|
||||||
|
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<p>The <a href="https://en.wikipedia.org/wiki/Ising_model">Ising model</a> is a model used to represent magnetic dipole moments in statistical physics. Physical details are on the Wikipedia page, but what is interesting is that it follows a complex probability distribution on a lattice, where each site can take the value +1 or -1.</p>
|
||||||
|
<p><img src="../images/ising.gif" /></p>
|
||||||
|
<h1 id="mathematical-definition">Mathematical definition</h1>
|
||||||
|
<p>We have a lattice <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>Λ</mi><annotation encoding="application/x-tex">\Lambda</annotation></semantics></math> consisting of sites <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math>. For each site, there is a moment <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>σ</mi><mi>k</mi></msub><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo>−</mo><mn>1</mn><mo>,</mo><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">\sigma_k \in \{ -1, +1 \}</annotation></semantics></math>. <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>σ</mi><mi>k</mi></msub><msub><mo stretchy="false" form="postfix">)</mo><mrow><mi>k</mi><mo>∈</mo><mi>Λ</mi></mrow></msub></mrow><annotation encoding="application/x-tex">\sigma =
|
||||||
|
(\sigma_k)_{k\in\Lambda}</annotation></semantics></math> is called the <em>configuration</em> of the lattice.</p>
|
||||||
|
<p>The total energy of the configuration is given by the <em>Hamiltonian</em> <math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>H</mi><mo stretchy="false" form="prefix">(</mo><mi>σ</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo>−</mo><munder><mo>∑</mo><mrow><mi>i</mi><mo>∼</mo><mi>j</mi></mrow></munder><msub><mi>J</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><mspace width="0.167em"></mspace><msub><mi>σ</mi><mi>i</mi></msub><mspace width="0.167em"></mspace><msub><mi>σ</mi><mi>j</mi></msub><mo>,</mo></mrow><annotation encoding="application/x-tex">
|
||||||
|
H(\sigma) = -\sum_{i\sim j} J_{ij}\, \sigma_i\, \sigma_j,
|
||||||
|
</annotation></semantics></math> where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo>∼</mo><mi>j</mi></mrow><annotation encoding="application/x-tex">i\sim j</annotation></semantics></math> denotes <em>neighbours</em>, and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>J</mi><annotation encoding="application/x-tex">J</annotation></semantics></math> is the <em>interaction matrix</em>.</p>
|
||||||
|
<p>The <em>configuration probability</em> is given by: <math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>π</mi><mi>β</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>σ</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mfrac><msup><mi>e</mi><mrow><mo>−</mo><mi>β</mi><mi>H</mi><mo stretchy="false" form="prefix">(</mo><mi>σ</mi><mo stretchy="false" form="postfix">)</mo></mrow></msup><msub><mi>Z</mi><mi>β</mi></msub></mfrac></mrow><annotation encoding="application/x-tex">
|
||||||
|
\pi_\beta(\sigma) = \frac{e^{-\beta H(\sigma)}}{Z_\beta}
|
||||||
|
</annotation></semantics></math> where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>β</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>k</mi><mi>B</mi></msub><mi>T</mi><msup><mo stretchy="false" form="postfix">)</mo><mrow><mo>−</mo><mn>1</mn></mrow></msup></mrow><annotation encoding="application/x-tex">\beta = (k_B T)^{-1}</annotation></semantics></math> is the inverse temperature, and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>Z</mi><mi>β</mi></msub><annotation encoding="application/x-tex">Z_\beta</annotation></semantics></math> the normalisation constant.</p>
|
||||||
|
<p>For our simulation, we will use a constant interaction term <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>J</mi><mo>></mo><mn>0</mn></mrow><annotation encoding="application/x-tex">J > 0</annotation></semantics></math>. If <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>σ</mi><mi>i</mi></msub><mo>=</mo><msub><mi>σ</mi><mi>j</mi></msub></mrow><annotation encoding="application/x-tex">\sigma_i = \sigma_j</annotation></semantics></math>, the probability will be proportional to <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>exp</mo><mo stretchy="false" form="prefix">(</mo><mi>β</mi><mi>J</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\exp(\beta J)</annotation></semantics></math>, otherwise it would be <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>exp</mo><mo stretchy="false" form="prefix">(</mo><mi>β</mi><mi>J</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\exp(\beta J)</annotation></semantics></math>. Thus, adjacent spins will try to align themselves.</p>
|
||||||
|
<h1 id="simulation">Simulation</h1>
|
||||||
|
<p>The Ising model is generally simulated using Markov Chain Monte Carlo (MCMC), with the <a href="https://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm">Metropolis-Hastings</a> algorithm.</p>
|
||||||
|
<p>The algorithm starts from a random configuration and runs as follows:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Select a site <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>i</mi><annotation encoding="application/x-tex">i</annotation></semantics></math> at random and reverse its spin: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi><msub><mi>′</mi><mi>i</mi></msub><mo>=</mo><mo>−</mo><msub><mi>σ</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">\sigma'_i = -\sigma_i</annotation></semantics></math></li>
|
||||||
|
<li>Compute the variation in energy (hamiltonian) <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Δ</mi><mi>E</mi><mo>=</mo><mi>H</mi><mo stretchy="false" form="prefix">(</mo><mi>σ</mi><mi>′</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mi>H</mi><mo stretchy="false" form="prefix">(</mo><mi>σ</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Delta E = H(\sigma') - H(\sigma)</annotation></semantics></math></li>
|
||||||
|
<li>If the energy is lower, accept the new configuration</li>
|
||||||
|
<li>Otherwise, draw a uniform random number <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi><mo>∈</mo><mo stretchy="false" form="postfix">]</mo><mn>0</mn><mo>,</mo><mn>1</mn><mo stretchy="false" form="prefix">[</mo></mrow><annotation encoding="application/x-tex">u \in ]0,1[</annotation></semantics></math> and accept the new configuration if <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi><mo><</mo><mo>min</mo><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo>,</mo><msup><mi>e</mi><mrow><mo>−</mo><mi>β</mi><mi>Δ</mi><mi>E</mi></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">u < \min(1, e^{-\beta \Delta E})</annotation></semantics></math>.</li>
|
||||||
|
</ol>
|
||||||
|
<h1 id="implementation">Implementation</h1>
|
||||||
|
<p>The simulation is in Clojure, using the <a href="http://quil.info/">Quil library</a> (a <a href="https://processing.org/">Processing</a> library for Clojure) to display the state of the system.</p>
|
||||||
|
<p>This post is “literate Clojure”, and contains <a href="https://github.com/dlozeve/ising-model/blob/master/src/ising_model/core.clj"><code>core.clj</code></a>. The complete project can be found on <a href="https://github.com/dlozeve/ising-model">GitHub</a>.</p>
|
||||||
|
<div class="sourceCode" id="cb1"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb1-1" title="1">(<span class="kw">ns</span> ising-model.core</a>
|
||||||
|
<a class="sourceLine" id="cb1-2" title="2"> (<span class="at">:require</span> [quil.core <span class="at">:as</span> q]</a>
|
||||||
|
<a class="sourceLine" id="cb1-3" title="3"> [quil.middleware <span class="at">:as</span> m]))</a></code></pre></div>
|
||||||
|
<p>The application works with Quil’s <a href="https://github.com/quil/quil/wiki/Functional-mode-(fun-mode)">functional mode</a>, with each function taking a state and returning an updated state at each time step.</p>
|
||||||
|
<p>The <code>setup</code> function generates the initial state, with random initial spins. It also sets the frame rate. The matrix is a single vector in row-major mode. The state also holds relevant parameters for the simulation: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>β</mi><annotation encoding="application/x-tex">\beta</annotation></semantics></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>J</mi><annotation encoding="application/x-tex">J</annotation></semantics></math>, and the iteration step.</p>
|
||||||
|
<div class="sourceCode" id="cb2"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb2-1" title="1">(<span class="bu">defn</span><span class="fu"> setup </span>[size]</a>
|
||||||
|
<a class="sourceLine" id="cb2-2" title="2"> <span class="st">"Setup the display parameters and the initial state"</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-3" title="3"> (q/frame-rate <span class="dv">300</span>)</a>
|
||||||
|
<a class="sourceLine" id="cb2-4" title="4"> (q/color-mode <span class="at">:hsb</span>)</a>
|
||||||
|
<a class="sourceLine" id="cb2-5" title="5"> (<span class="kw">let</span> [matrix (<span class="kw">vec</span> (<span class="kw">repeatedly</span> (<span class="kw">*</span> size size) #(<span class="kw">-</span> (<span class="kw">*</span> <span class="dv">2</span> (<span class="kw">rand-int</span> <span class="dv">2</span>)) <span class="dv">1</span>)))]</a>
|
||||||
|
<a class="sourceLine" id="cb2-6" title="6"> {<span class="at">:grid-size</span> size</a>
|
||||||
|
<a class="sourceLine" id="cb2-7" title="7"> <span class="at">:matrix</span> matrix</a>
|
||||||
|
<a class="sourceLine" id="cb2-8" title="8"> <span class="at">:beta</span> <span class="dv">10</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-9" title="9"> <span class="at">:intensity</span> <span class="dv">10</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-10" title="10"> <span class="at">:iteration</span> <span class="dv">0</span>}))</a></code></pre></div>
|
||||||
|
<p>Given a site <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>i</mi><annotation encoding="application/x-tex">i</annotation></semantics></math>, we reverse its spin to generate a new configuration state.</p>
|
||||||
|
<div class="sourceCode" id="cb3"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb3-1" title="1">(<span class="bu">defn</span><span class="fu"> toggle-state </span>[state i]</a>
|
||||||
|
<a class="sourceLine" id="cb3-2" title="2"> <span class="st">"Compute the new state when we toggle a cell's value"</span></a>
|
||||||
|
<a class="sourceLine" id="cb3-3" title="3"> (<span class="kw">let</span> [matrix (<span class="at">:matrix</span> state)]</a>
|
||||||
|
<a class="sourceLine" id="cb3-4" title="4"> (<span class="kw">assoc</span> state <span class="at">:matrix</span> (<span class="kw">assoc</span> matrix i (<span class="kw">*</span> <span class="dv">-1</span> (matrix i))))))</a></code></pre></div>
|
||||||
|
<p>In order to decide whether to accept this new state, we compute the difference in energy introduced by reversing site <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>i</mi><annotation encoding="application/x-tex">i</annotation></semantics></math>: <math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Δ</mi><mi>E</mi><mo>=</mo><mi>J</mi><msub><mi>σ</mi><mi>i</mi></msub><munder><mo>∑</mo><mrow><mi>j</mi><mo>∼</mo><mi>i</mi></mrow></munder><msub><mi>σ</mi><mi>j</mi></msub><mi>.</mi></mrow><annotation encoding="application/x-tex"> \Delta E =
|
||||||
|
J\sigma_i \sum_{j\sim i} \sigma_j. </annotation></semantics></math></p>
|
||||||
|
<p>The <code>filter some?</code> is required to eliminate sites outside of the boundaries of the lattice.</p>
|
||||||
|
<div class="sourceCode" id="cb4"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb4-1" title="1">(<span class="bu">defn</span><span class="fu"> get-neighbours </span>[state idx]</a>
|
||||||
|
<a class="sourceLine" id="cb4-2" title="2"> <span class="st">"Return the values of a cell's neighbours"</span></a>
|
||||||
|
<a class="sourceLine" id="cb4-3" title="3"> [(<span class="kw">get</span> (<span class="at">:matrix</span> state) (<span class="kw">-</span> idx (<span class="at">:grid-size</span> state)))</a>
|
||||||
|
<a class="sourceLine" id="cb4-4" title="4"> (<span class="kw">get</span> (<span class="at">:matrix</span> state) (<span class="kw">dec</span> idx))</a>
|
||||||
|
<a class="sourceLine" id="cb4-5" title="5"> (<span class="kw">get</span> (<span class="at">:matrix</span> state) (<span class="kw">inc</span> idx))</a>
|
||||||
|
<a class="sourceLine" id="cb4-6" title="6"> (<span class="kw">get</span> (<span class="at">:matrix</span> state) (<span class="kw">+</span> (<span class="at">:grid-size</span> state) idx))])</a>
|
||||||
|
<a class="sourceLine" id="cb4-7" title="7"></a>
|
||||||
|
<a class="sourceLine" id="cb4-8" title="8">(<span class="bu">defn</span><span class="fu"> delta-e </span>[state i]</a>
|
||||||
|
<a class="sourceLine" id="cb4-9" title="9"> <span class="st">"Compute the energy difference introduced by a particular cell"</span></a>
|
||||||
|
<a class="sourceLine" id="cb4-10" title="10"> (<span class="kw">*</span> (<span class="at">:intensity</span> state) ((<span class="at">:matrix</span> state) i)</a>
|
||||||
|
<a class="sourceLine" id="cb4-11" title="11"> (<span class="kw">reduce</span> <span class="kw">+</span> (<span class="kw">filter</span> some? (get-neighbours state i)))))</a></code></pre></div>
|
||||||
|
<p>We also add a function to compute directly the hamiltonian for the entire configuration state. We can use it later to log its values across iterations.</p>
|
||||||
|
<div class="sourceCode" id="cb5"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb5-1" title="1">(<span class="bu">defn</span><span class="fu"> hamiltonian </span>[state]</a>
|
||||||
|
<a class="sourceLine" id="cb5-2" title="2"> <span class="st">"Compute the Hamiltonian of a configuration state"</span></a>
|
||||||
|
<a class="sourceLine" id="cb5-3" title="3"> (<span class="kw">-</span> (<span class="kw">reduce</span> <span class="kw">+</span> (<span class="kw">for</span> [i (<span class="kw">range</span> (<span class="kw">count</span> (<span class="at">:matrix</span> state)))</a>
|
||||||
|
<a class="sourceLine" id="cb5-4" title="4"> j (<span class="kw">filter</span> some? (get-neighbours state i))]</a>
|
||||||
|
<a class="sourceLine" id="cb5-5" title="5"> (<span class="kw">*</span> (<span class="at">:intensity</span> state) ((<span class="at">:matrix</span> state) i) j)))))</a></code></pre></div>
|
||||||
|
<p>Finally, we put everything together in the <code>update-state</code> function, which will decide whether to accept or reject the new configuration.</p>
|
||||||
|
<div class="sourceCode" id="cb6"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb6-1" title="1">(<span class="bu">defn</span><span class="fu"> update-state </span>[state]</a>
|
||||||
|
<a class="sourceLine" id="cb6-2" title="2"> <span class="st">"Accept or reject a new state based on energy</span></a>
|
||||||
|
<a class="sourceLine" id="cb6-3" title="3"><span class="st"> difference (Metropolis-Hastings)"</span></a>
|
||||||
|
<a class="sourceLine" id="cb6-4" title="4"> (<span class="kw">let</span> [i (<span class="kw">rand-int</span> (<span class="kw">count</span> (<span class="at">:matrix</span> state)))</a>
|
||||||
|
<a class="sourceLine" id="cb6-5" title="5"> new-state (toggle-state state i)</a>
|
||||||
|
<a class="sourceLine" id="cb6-6" title="6"> alpha (q/exp (<span class="kw">-</span> (<span class="kw">*</span> (<span class="at">:beta</span> state) (delta-e state i))))]</a>
|
||||||
|
<a class="sourceLine" id="cb6-7" title="7"> <span class="co">;;(println (hamiltonian new-state))</span></a>
|
||||||
|
<a class="sourceLine" id="cb6-8" title="8"> (<span class="kw">update</span> (<span class="kw">if</span> (<span class="kw"><</span> (<span class="kw">rand</span>) alpha) new-state state)</a>
|
||||||
|
<a class="sourceLine" id="cb6-9" title="9"> <span class="at">:iteration</span> <span class="kw">inc</span>)))</a></code></pre></div>
|
||||||
|
<p>The last thing to do is to draw the new configuration:</p>
|
||||||
|
<div class="sourceCode" id="cb7"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb7-1" title="1">(<span class="bu">defn</span><span class="fu"> draw-state </span>[state]</a>
|
||||||
|
<a class="sourceLine" id="cb7-2" title="2"> <span class="st">"Draw a configuration state as a grid"</span></a>
|
||||||
|
<a class="sourceLine" id="cb7-3" title="3"> (q/background <span class="dv">255</span>)</a>
|
||||||
|
<a class="sourceLine" id="cb7-4" title="4"> (<span class="kw">let</span> [cell-size (<span class="kw">quot</span> (q/width) (<span class="at">:grid-size</span> state))]</a>
|
||||||
|
<a class="sourceLine" id="cb7-5" title="5"> (<span class="kw">doseq</span> [[i v] (map-indexed <span class="kw">vector</span> (<span class="at">:matrix</span> state))]</a>
|
||||||
|
<a class="sourceLine" id="cb7-6" title="6"> (<span class="kw">let</span> [x (<span class="kw">*</span> cell-size (<span class="kw">rem</span> i (<span class="at">:grid-size</span> state)))</a>
|
||||||
|
<a class="sourceLine" id="cb7-7" title="7"> y (<span class="kw">*</span> cell-size (<span class="kw">quot</span> i (<span class="at">:grid-size</span> state)))]</a>
|
||||||
|
<a class="sourceLine" id="cb7-8" title="8"> (q/no-stroke)</a>
|
||||||
|
<a class="sourceLine" id="cb7-9" title="9"> (q/fill</a>
|
||||||
|
<a class="sourceLine" id="cb7-10" title="10"> (<span class="kw">if</span> (<span class="kw">=</span> <span class="dv">1</span> v) <span class="dv">0</span> <span class="dv">255</span>))</a>
|
||||||
|
<a class="sourceLine" id="cb7-11" title="11"> (q/rect x y cell-size cell-size))))</a>
|
||||||
|
<a class="sourceLine" id="cb7-12" title="12"> <span class="co">;;(when (zero? (mod (:iteration state) 50)) (q/save-frame "img/ising-######.jpg"))</span></a>
|
||||||
|
<a class="sourceLine" id="cb7-13" title="13"> )</a></code></pre></div>
|
||||||
|
<p>And to reset the simulation when the user clicks anywhere on the screen:</p>
|
||||||
|
<div class="sourceCode" id="cb8"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb8-1" title="1">(<span class="bu">defn</span><span class="fu"> mouse-clicked </span>[state event]</a>
|
||||||
|
<a class="sourceLine" id="cb8-2" title="2"> <span class="st">"When the mouse is clicked, reset the configuration to a random one"</span></a>
|
||||||
|
<a class="sourceLine" id="cb8-3" title="3"> (setup <span class="dv">100</span>))</a></code></pre></div>
|
||||||
|
<div class="sourceCode" id="cb9"><pre class="sourceCode clojure"><code class="sourceCode clojure"><a class="sourceLine" id="cb9-1" title="1">(q/defsketch ising-model</a>
|
||||||
|
<a class="sourceLine" id="cb9-2" title="2"> <span class="at">:title</span> <span class="st">"Ising model"</span></a>
|
||||||
|
<a class="sourceLine" id="cb9-3" title="3"> <span class="at">:size</span> [<span class="dv">300</span> <span class="dv">300</span>]</a>
|
||||||
|
<a class="sourceLine" id="cb9-4" title="4"> <span class="at">:setup</span> #(setup <span class="dv">100</span>)</a>
|
||||||
|
<a class="sourceLine" id="cb9-5" title="5"> <span class="at">:update</span> update-state</a>
|
||||||
|
<a class="sourceLine" id="cb9-6" title="6"> <span class="at">:draw</span> draw-state</a>
|
||||||
|
<a class="sourceLine" id="cb9-7" title="7"> <span class="at">:mouse-clicked</span> mouse-clicked</a>
|
||||||
|
<a class="sourceLine" id="cb9-8" title="8"> <span class="at">:features</span> [<span class="at">:keep-on-top</span> <span class="at">:no-bind-output</span>]</a>
|
||||||
|
<a class="sourceLine" id="cb9-9" title="9"> <span class="at">:middleware</span> [m/fun-mode])</a></code></pre></div>
|
||||||
|
<h1 id="conclusion">Conclusion</h1>
|
||||||
|
<p>The Ising model is a really easy (and common) example use of MCMC and Metropolis-Hastings. It allows to easily and intuitively understand how the algorithm works, and to make nice visualizations!</p>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
Site proudly generated by
|
||||||
|
<a href="http://jaspervdj.be/hakyll">Hakyll</a>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
159
_site/posts/lsystems.html
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Dimitri Lozeve - Generating and representing L-systems</title>
|
||||||
|
<link rel="stylesheet" href="../css/default.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="logo">
|
||||||
|
<a href="../">Dimitri Lozeve</a>
|
||||||
|
</div>
|
||||||
|
<nav>
|
||||||
|
<a href="../">Home</a>
|
||||||
|
<a href="../contact.html">Contact</a>
|
||||||
|
<a href="../archive.html">Archive</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main role="main">
|
||||||
|
<h1>Generating and representing L-systems</h1>
|
||||||
|
<article>
|
||||||
|
<section class="header">
|
||||||
|
Posted on January 18, 2018
|
||||||
|
|
||||||
|
by Dimitri Lozeve
|
||||||
|
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<p>L-systems are a formal way to make interesting visualisations. You can use them to model a wide variety of objects: space-filling curves, fractals, biological systems, tilings, etc.</p>
|
||||||
|
<p>See the Github repo: <a href="https://github.com/dlozeve/lsystems" class="uri">https://github.com/dlozeve/lsystems</a></p>
|
||||||
|
<h1 id="what-is-an-l-system">What is an L-system?</h1>
|
||||||
|
<h2 id="a-few-examples-to-get-started">A few examples to get started</h2>
|
||||||
|
<p><img src="../images/lsystems/dragon.png" /></p>
|
||||||
|
<p><img src="../images/lsystems/gosper.png" /></p>
|
||||||
|
<p><img src="../images/lsystems/plant.png" /></p>
|
||||||
|
<p><img src="../images/lsystems/penroseP3.png" /></p>
|
||||||
|
<h2 id="definition">Definition</h2>
|
||||||
|
<p>An <a href="https://en.wikipedia.org/wiki/L-system">L-system</a> is a set of rewriting rules generating sequences of symbols. Formally, an L-system is a triplet of:</p>
|
||||||
|
<ul>
|
||||||
|
<li>an <em>alphabet</em> <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>V</mi><annotation encoding="application/x-tex">V</annotation></semantics></math> (an arbitrary set of symbols)</li>
|
||||||
|
<li>an <em>axiom</em> <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>ω</mi><annotation encoding="application/x-tex">\omega</annotation></semantics></math>, which is a non-empty word of the alphabet (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ω</mi><mo>∈</mo><msup><mi>V</mi><mo>+</mo></msup></mrow><annotation encoding="application/x-tex">\omega \in V^+</annotation></semantics></math>)</li>
|
||||||
|
<li>a set of <em>rewriting rules</em> (or <em>productions</em>) <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>, each mapping a symbol to a word: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo>⊂</mo><mi>V</mi><mo>×</mo><msup><mi>V</mi><mo>*</mo></msup></mrow><annotation encoding="application/x-tex">P \subset V \times V^*</annotation></semantics></math>. Symbols not present in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math> are assumed to be mapped to themselves.</li>
|
||||||
|
</ul>
|
||||||
|
<p>During an iteration, the algorithm takes each symbol in the current word and replaces it by the value in its rewriting rule. Not that the output of the rewriting rule can be absolutely <em>anything</em> in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mi>V</mi><mo>*</mo></msup><annotation encoding="application/x-tex">V^*</annotation></semantics></math>, including the empty word! (So yes, you can generate symbols just to delete them afterwards.)</p>
|
||||||
|
<p>At this point, an L-system is nothing more than a way to generate very long strings of characters. In order to get something useful out of this, we have to give them <em>meaning</em>.</p>
|
||||||
|
<h2 id="drawing-instructions-and-representation">Drawing instructions and representation</h2>
|
||||||
|
<p>Our objective is to draw the output of the L-system in order to visually inspect the output. The most common way is to interpret the output as a sequence of instruction for a LOGO-like drawing turtle. For instance, a simple alphabet consisting only in the symbols <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>F</mi><annotation encoding="application/x-tex">F</annotation></semantics></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mo>+</mo><annotation encoding="application/x-tex">+</annotation></semantics></math>, and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mo>−</mo><annotation encoding="application/x-tex">-</annotation></semantics></math> could represent the instructions “move forward”, “turn right by 90°”, and “turn left by 90°” respectively.</p>
|
||||||
|
<p>Thus, we add new components to our definition of L-systems:</p>
|
||||||
|
<ul>
|
||||||
|
<li>a set of <em>instructions</em>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>I</mi><annotation encoding="application/x-tex">I</annotation></semantics></math>. These are limited by the capabilities of our imagined turtle, so we can assume that they are the same for every L-system we will consider:
|
||||||
|
<ul>
|
||||||
|
<li><code>Forward</code> makes the turtle draw a straight segment.</li>
|
||||||
|
<li><code>TurnLeft</code> and <code>TurnRight</code> makes the turtle turn on itself by a given angle.</li>
|
||||||
|
<li><code>Push</code> and <code>Pop</code> allow the turtle to store and retrieve its position on a stack. This will allow for branching in the turtle’s path.</li>
|
||||||
|
<li><code>Stay</code>, which orders the turtle to do nothing.</li>
|
||||||
|
</ul></li>
|
||||||
|
<li>a <em>distance</em> <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mo>∈</mo><mstyle mathvariant="double-struck"><msub><mi>ℝ</mi><mo>+</mo></msub></mstyle></mrow><annotation encoding="application/x-tex">d \in \mathbb{R_+}</annotation></semantics></math>, i.e. how long should each forward segment should be.</li>
|
||||||
|
<li>an <em>angle</em> <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>θ</mi><annotation encoding="application/x-tex">\theta</annotation></semantics></math> used for rotation.</li>
|
||||||
|
<li>a set of <em>representation rules</em> <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi><mo>⊂</mo><mi>V</mi><mo>×</mo><mi>I</mi></mrow><annotation encoding="application/x-tex">R \subset V \times I</annotation></semantics></math>. As before, they will match a symbol to an instruction. Symbols not matched by any rule will be associated to <code>Stay</code>.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Finally, our complete L-system, representable by a turtle with capabilities <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>I</mi><annotation encoding="application/x-tex">I</annotation></semantics></math>, can be defined as <math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>L</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>V</mi><mo>,</mo><mi>ω</mi><mo>,</mo><mi>P</mi><mo>,</mo><mi>d</mi><mo>,</mo><mi>θ</mi><mo>,</mo><mi>R</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi></mrow><annotation encoding="application/x-tex"> L = (V, \omega, P, d, \theta,
|
||||||
|
R). </annotation></semantics></math></p>
|
||||||
|
<p>One could argue that the representation is not part of the L-system, and that the same L-system could be represented differently by changing the representation rules. However, in our setting, we won’t observe the L-system other than by displaying it, so we might as well consider that two systems differing only by their representation rules are different systems altogether.</p>
|
||||||
|
<h1 id="implementation-details">Implementation details</h1>
|
||||||
|
<h2 id="the-lsystem-data-type">The <code>LSystem</code> data type</h2>
|
||||||
|
<p>The mathematical definition above translate almost immediately in a Haskell data type:</p>
|
||||||
|
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb1-1" title="1"><span class="co">-- | L-system data type</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-2" title="2"><span class="kw">data</span> <span class="dt">LSystem</span> a <span class="fu">=</span> <span class="dt">LSystem</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-3" title="3"> {<span class="ot"> name ::</span> <span class="dt">String</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-4" title="4"> ,<span class="ot"> alphabet ::</span> [a] <span class="co">-- ^ variables and constants used by the system</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-5" title="5"> ,<span class="ot"> axiom ::</span> [a] <span class="co">-- ^ initial state of the system</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-6" title="6"> ,<span class="ot"> rules ::</span> [(a, [a])] <span class="co">-- ^ production rules defining how each</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-7" title="7"> <span class="co">-- variable can be replaced by a sequence of</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-8" title="8"> <span class="co">-- variables and constants</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-9" title="9"> ,<span class="ot"> angle ::</span> <span class="dt">Float</span> <span class="co">-- ^ angle used for the representation</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-10" title="10"> ,<span class="ot"> distance ::</span> <span class="dt">Float</span> <span class="co">-- ^ distance of each segment in the representation</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-11" title="11"> ,<span class="ot"> representation ::</span> [(a, <span class="dt">Instruction</span>)] <span class="co">-- ^ representation rules</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-12" title="12"> <span class="co">-- defining how each variable</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-13" title="13"> <span class="co">-- and constant should be</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-14" title="14"> <span class="co">-- represented</span></a>
|
||||||
|
<a class="sourceLine" id="cb1-15" title="15"> } <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Show</span>, <span class="dt">Generic</span>)</a></code></pre></div>
|
||||||
|
<p>Here, <code>a</code> is the type of the literal in the alphabet. For all practical purposes, it will almost always be <code>Char</code>.</p>
|
||||||
|
<p><code>Instruction</code> is just a sum type over all possible instructions listed above.</p>
|
||||||
|
<h2 id="iterating-and-representing">Iterating and representing</h2>
|
||||||
|
<p>From here, generating L-systems and iterating is straightforward. We iterate recursively by looking up each symbol in <code>rules</code> and replacing it by its expansion. We then transform the result to a list of <code>Instruction</code>.</p>
|
||||||
|
<h2 id="drawing">Drawing</h2>
|
||||||
|
<p>The only remaining thing is to implement the virtual turtle which will actually execute the instructions. It goes through the list of instructions, building a sequence of points and maintaining an internal state (position, angle, stack). The stack is used when <code>Push</code> and <code>Pop</code> operations are met. In this case, the turtle builds a separate line starting from its current position.</p>
|
||||||
|
<p>The final output is a set of lines, each being a simple sequence of points. All relevant data types are provided by the <a href="https://hackage.haskell.org/package/gloss">Gloss</a> library, along with the function that can display the resulting <code>Picture</code>.</p>
|
||||||
|
<h1 id="common-file-format-for-l-systems">Common file format for L-systems</h1>
|
||||||
|
<p>In order to define new L-systems quickly and easily, it is necessary to encode them in some form. We chose to represent them as JSON values.</p>
|
||||||
|
<p>Here is an example for the <a href="https://en.wikipedia.org/wiki/Gosper_curve">Gosper curve</a>:</p>
|
||||||
|
<div class="sourceCode" id="cb2"><pre class="sourceCode json"><code class="sourceCode json"><a class="sourceLine" id="cb2-1" title="1"><span class="fu">{</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-2" title="2"> <span class="dt">"name"</span><span class="fu">:</span> <span class="st">"gosper"</span><span class="fu">,</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-3" title="3"> <span class="dt">"alphabet"</span><span class="fu">:</span> <span class="st">"AB+-"</span><span class="fu">,</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-4" title="4"> <span class="dt">"axiom"</span><span class="fu">:</span> <span class="st">"A"</span><span class="fu">,</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-5" title="5"> <span class="dt">"rules"</span><span class="fu">:</span> <span class="ot">[</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-6" title="6"> <span class="ot">[</span><span class="st">"A"</span><span class="ot">,</span> <span class="st">"A-B--B+A++AA+B-"</span><span class="ot">],</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-7" title="7"> <span class="ot">[</span><span class="st">"B"</span><span class="ot">,</span> <span class="st">"+A-BB--B-A++A+B"</span><span class="ot">]</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-8" title="8"> <span class="ot">]</span><span class="fu">,</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-9" title="9"> <span class="dt">"angle"</span><span class="fu">:</span> <span class="fl">60.0</span><span class="fu">,</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-10" title="10"> <span class="dt">"distance"</span><span class="fu">:</span> <span class="fl">10.0</span><span class="fu">,</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-11" title="11"> <span class="dt">"representation"</span><span class="fu">:</span> <span class="ot">[</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-12" title="12"> <span class="ot">[</span><span class="st">"A"</span><span class="ot">,</span> <span class="st">"Forward"</span><span class="ot">],</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-13" title="13"> <span class="ot">[</span><span class="st">"B"</span><span class="ot">,</span> <span class="st">"Forward"</span><span class="ot">],</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-14" title="14"> <span class="ot">[</span><span class="st">"+"</span><span class="ot">,</span> <span class="st">"TurnRight"</span><span class="ot">],</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-15" title="15"> <span class="ot">[</span><span class="st">"-"</span><span class="ot">,</span> <span class="st">"TurnLeft"</span><span class="ot">]</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-16" title="16"> <span class="ot">]</span></a>
|
||||||
|
<a class="sourceLine" id="cb2-17" title="17"><span class="fu">}</span></a></code></pre></div>
|
||||||
|
<p>Using this format, it is easy to define new L-systems (along with how they should be represented). This is translated nearly automatically to the <code>LSystem</code> data type using <a href="https://hackage.haskell.org/package/aeson">Aeson</a>.</p>
|
||||||
|
<h1 id="variations-on-l-systems">Variations on L-systems</h1>
|
||||||
|
<p>We can widen the possibilities of L-systems in various ways. L-systems are in effect deterministic context-free grammars.</p>
|
||||||
|
<p>By allowing multiple rewriting rules for each symbol with probabilities, we can extend the model to <a href="https://en.wikipedia.org/wiki/Probabilistic_context-free_grammar">probabilistic context-free grammars</a>.</p>
|
||||||
|
<p>We can also have replacement rules not for a single symbol, but for a subsequence of them, thus effectively taking into account their neighbours (context-sensitive grammars). This seems very close to 1D cellular automata.</p>
|
||||||
|
<p>Finally, L-systems could also have a 3D representation (for instance space-filling curves in 3 dimensions).</p>
|
||||||
|
<h1 id="usage-notes">Usage notes</h1>
|
||||||
|
<ol>
|
||||||
|
<li>Clone the repository: <code>git clone [[https://github.com/dlozeve/lsystems]]</code></li>
|
||||||
|
<li>Build: <code>stack build</code></li>
|
||||||
|
<li>Execute <code>stack exec lsystems-exe -- examples/penroseP3.json</code> to see the list of options</li>
|
||||||
|
<li>(Optional) Run tests and build documentation: <code>stack test --haddock</code></li>
|
||||||
|
</ol>
|
||||||
|
<p>Usage: <code>stack exec lsystems-exe -- --help</code></p>
|
||||||
|
<pre><code>lsystems -- Generate L-systems
|
||||||
|
|
||||||
|
Usage: lsystems-exe FILENAME [-n|--iterations N] [-c|--color R,G,B]
|
||||||
|
[-w|--white-background]
|
||||||
|
Generate and draw an L-system
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
FILENAME JSON file specifying an L-system
|
||||||
|
-n,--iterations N Number of iterations (default: 5)
|
||||||
|
-c,--color R,G,B Foreground color RGBA
|
||||||
|
(0-255) (default: RGBA 1.0 1.0 1.0 1.0)
|
||||||
|
-w,--white-background Use a white background
|
||||||
|
-h,--help Show this help text
|
||||||
|
</code></pre>
|
||||||
|
<p>Apart from the selection of the input JSON file, you can adjust the number of iterations and the colors.</p>
|
||||||
|
<p><code>stack exec lsystems-exe -- examples/levyC.json -n 12 -c 0,255,255</code></p>
|
||||||
|
<p><img src="../images/lsystems/levyC.png" /></p>
|
||||||
|
<h1 id="references">References</h1>
|
||||||
|
<ol>
|
||||||
|
<li>Prusinkiewicz, Przemyslaw; Lindenmayer, Aristid (1990). <em>The Algorithmic Beauty of Plants.</em> Springer-Verlag. ISBN 978-0-387-97297-8. <a href="http://algorithmicbotany.org/papers/#abop" class="uri">http://algorithmicbotany.org/papers/#abop</a></li>
|
||||||
|
<li>Weisstein, Eric W. “Lindenmayer System.” From MathWorld–A Wolfram Web Resource. <a href="http://mathworld.wolfram.com/LindenmayerSystem.html" class="uri">http://mathworld.wolfram.com/LindenmayerSystem.html</a></li>
|
||||||
|
<li>Corte, Leo. “L-systems and Penrose P3 in Inkscape.” <em>The Brick in the Sky.</em> <a href="https://thebrickinthesky.wordpress.com/2013/03/17/l-systems-and-penrose-p3-in-inkscape/" class="uri">https://thebrickinthesky.wordpress.com/2013/03/17/l-systems-and-penrose-p3-in-inkscape/</a></li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
Site proudly generated by
|
||||||
|
<a href="http://jaspervdj.be/hakyll">Hakyll</a>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
images/adsb.png
Normal file
After Width: | Height: | Size: 646 KiB |
BIN
images/boards.jpg
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
images/bubbles.jpg
Normal file
After Width: | Height: | Size: 109 KiB |
BIN
images/communities.png
Normal file
After Width: | Height: | Size: 600 KiB |
BIN
images/datasaurus.gif
Normal file
After Width: | Height: | Size: 6.3 MiB |
BIN
images/datasaurus.png
Normal file
After Width: | Height: | Size: 609 KiB |
BIN
images/dpll.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
images/headers/bubbles-wide.jpg
Normal file
After Width: | Height: | Size: 304 KiB |
BIN
images/headers/getting-started.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
images/icon-192.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
images/icon.png
Normal file
After Width: | Height: | Size: 862 B |
BIN
images/ising.gif
Normal file
After Width: | Height: | Size: 570 KiB |
BIN
images/lsystems/dragon.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
images/lsystems/gosper.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
images/lsystems/levyC.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
images/lsystems/penroseP3.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
images/lsystems/plant.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
images/lsystems/sierpinskiArrow.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
images/orbit.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
images/portrait.jpg
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
images/satrap.png
Normal file
After Width: | Height: | Size: 160 KiB |
BIN
images/ww2-bombings.png
Normal file
After Width: | Height: | Size: 530 KiB |
272
posts/ising-apl.org
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
---
|
||||||
|
title: Ising model simulation in APL
|
||||||
|
date: 2018-03-05
|
||||||
|
tags: ising simulation montecarlo apl
|
||||||
|
---
|
||||||
|
|
||||||
|
* The APL family of languages
|
||||||
|
|
||||||
|
** Why APL?
|
||||||
|
|
||||||
|
I recently got interested in [[https://en.wikipedia.org/wiki/APL_(programming_language)][APL]], an /array-based/ programming
|
||||||
|
language. In APL (and derivatives), we try to reason about programs as
|
||||||
|
series of transformations of multi-dimensional arrays. This is exactly
|
||||||
|
the kind of style I like in Haskell and other functional languages,
|
||||||
|
where I also try to use higher-order functions (map, fold, etc) on
|
||||||
|
lists or arrays. A developer only needs to understand these
|
||||||
|
abstractions once, instead of deconstructing each loop or each
|
||||||
|
recursive function encountered in a program.
|
||||||
|
|
||||||
|
APL also tries to be a really simple and /terse/ language. This
|
||||||
|
combined with strange Unicode characters for primitive functions and
|
||||||
|
operators, gives it a reputation of unreadability. However, there is
|
||||||
|
only a small number of functions to learn, and you get used really
|
||||||
|
quickly to read them and understand what they do. Some combinations
|
||||||
|
also occur so frequently that you can recognize them instantly (APL
|
||||||
|
programmers call them /idioms/).
|
||||||
|
|
||||||
|
** Implementations
|
||||||
|
|
||||||
|
APL is actually a family of languages. The classic APL, as created by
|
||||||
|
Ken Iverson, with strange symbols, has many implementations. I
|
||||||
|
initially tried [[https://www.gnu.org/software/apl/][GNU APL]], but due to the lack of documentation and
|
||||||
|
proper tooling, I went to [[https://www.dyalog.com/][Dyalog APL]] (which is proprietary, but free
|
||||||
|
for personal use). There are also APL derivatives, that often use
|
||||||
|
ASCII symbols: [[http://www.jsoftware.com/][J]] (free) and [[https://code.kx.com/q/][Q/kdb+]] (proprietary, but free for personal
|
||||||
|
use).
|
||||||
|
|
||||||
|
The advantage of Dyalog is that it comes with good tooling (which is
|
||||||
|
necessary for inserting all the symbols!), a large ecosystem, and
|
||||||
|
pretty good [[http://docs.dyalog.com/][documentation]]. If you want to start, look at [[http://www.dyalog.com/mastering-dyalog-apl.htm][/Mastering
|
||||||
|
Dyalog APL/]] by Bernard Legrand, freely available online.
|
||||||
|
|
||||||
|
* The Ising model in APL
|
||||||
|
|
||||||
|
I needed a small project to try APL while I was learning. Something
|
||||||
|
array-based, obviously. Since I already implemented a
|
||||||
|
Metropolis-Hastings simulation of the [[./ising-model.html][Ising
|
||||||
|
model]], which is based on a regular lattice, I decided to reimplement
|
||||||
|
it in Dyalog APL.
|
||||||
|
|
||||||
|
It is only a few lines long, but I will try to explain what it does
|
||||||
|
step by step.
|
||||||
|
|
||||||
|
The first function simply generates a random lattice filled by
|
||||||
|
elements of $\{-1,+1\}$.
|
||||||
|
|
||||||
|
#+BEGIN_SRC apl
|
||||||
|
L←{(2×?⍵ ⍵⍴2)-3}
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Let's deconstruct what is done here:
|
||||||
|
- ⍵ is the argument of our function.
|
||||||
|
- We generate a ⍵×⍵ matrix filled with 2, using the ~⍴~ function: ~⍵ ⍵⍴2~
|
||||||
|
- ~?~ draws a random number between 1 and its argument. We give it our matrix to generate a random matrix of 1 and 2.
|
||||||
|
- We multiply everything by 2 and subtract 3, so that the result is in $\{-1,+1\}$.
|
||||||
|
- Finally, we assign the result to the name ~L~.
|
||||||
|
|
||||||
|
Sample output:
|
||||||
|
#+BEGIN_SRC apl
|
||||||
|
ising.L 5
|
||||||
|
1 ¯1 1 ¯1 1
|
||||||
|
1 1 1 ¯1 ¯1
|
||||||
|
1 ¯1 ¯1 ¯1 ¯1
|
||||||
|
1 1 1 ¯1 ¯1
|
||||||
|
¯1 ¯1 1 1 1
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Next, we compute the energy variation (for details on the Ising model,
|
||||||
|
see [[./ising-model.html][my previous post]]).
|
||||||
|
|
||||||
|
#+BEGIN_SRC apl
|
||||||
|
∆E←{
|
||||||
|
⎕IO←0
|
||||||
|
(x y)←⍺
|
||||||
|
N←⊃⍴⍵
|
||||||
|
xn←N|((x-1)y)((x+1)y)
|
||||||
|
yn←N|(x(y-1))(x(y+1))
|
||||||
|
⍵[x;y]×+/⍵[xn,yn]
|
||||||
|
}
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
- ⍺ is the left argument (coordinates of the site), ⍵ is the right argument (lattice).
|
||||||
|
- We extract the x and y coordinates of the site.
|
||||||
|
- ~N~ is the size of the lattice.
|
||||||
|
- ~xn~ and ~yn~ are respectively the vertical and lateral neighbours of the site. ~N|~ takes the coordinates modulo ~N~ (so the lattice is actually a torus). (Note: we used ~⎕IO←0~ to use 0-based array indexing.)
|
||||||
|
- ~+/~ sums over all neighbours of the site, and then we multiply by the value of the site itself to get $\Delta E$.
|
||||||
|
|
||||||
|
Sample output, for site $(3, 3)$ in a random $5\times 5$ lattice:
|
||||||
|
|
||||||
|
#+BEGIN_SRC apl
|
||||||
|
3 3ising.∆E ising.L 5
|
||||||
|
¯4
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Then comes the actual Metropolis-Hastings part:
|
||||||
|
|
||||||
|
#+BEGIN_SRC apl
|
||||||
|
U←{
|
||||||
|
⎕IO←0
|
||||||
|
N←⊃⍴⍵
|
||||||
|
(x y)←?N N
|
||||||
|
new←⍵
|
||||||
|
new[x;y]×←(2×(?0)>*-⍺×x y ∆E ⍵)-1
|
||||||
|
new
|
||||||
|
}
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
- ⍺ is the $\beta$ parameter of the Ising model, ⍵ is the lattice.
|
||||||
|
- We draw a random site $(x,y)$ with the ~?~ function.
|
||||||
|
- ~new~ is the lattice but with the $(x,y)$ site flipped.
|
||||||
|
- We compute the probability $\alpha = \exp(-\beta\Delta E)$ using the ~*~ function (exponential) and our previous ~∆E~ function.
|
||||||
|
- ~?0~ returns a uniform random number in $[0,1)$. Based on this value, we decide whether to update the lattice, and we return it.
|
||||||
|
|
||||||
|
We can now bring everything together for display:
|
||||||
|
|
||||||
|
#+BEGIN_SRC apl
|
||||||
|
Ising←{' ⌹'[1+1=({10 U ⍵}⍣⍵)L ⍺]}
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
- We draw a random lattice of size ⍺ with ~L ⍺~.
|
||||||
|
- We apply to it our update function, with $\beta$=10, ⍵ times (using the ~⍣~ function, which applies a function $n$ times.
|
||||||
|
- Finally, we display -1 as a space and 1 as a domino ⌹.
|
||||||
|
|
||||||
|
Final output, with a $80\times 80$ random lattice, after 50000 update
|
||||||
|
steps:
|
||||||
|
|
||||||
|
#+BEGIN_SRC apl
|
||||||
|
80ising.Ising 50000
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹
|
||||||
|
⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹ ⌹⌹⌹⌹ ⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹⌹
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Complete code, with the namespace:
|
||||||
|
|
||||||
|
#+BEGIN_SRC apl
|
||||||
|
:Namespace ising
|
||||||
|
|
||||||
|
L←{(2×?⍵ ⍵⍴2)-3}
|
||||||
|
|
||||||
|
∆E←{
|
||||||
|
⎕IO←0
|
||||||
|
(x y)←⍺
|
||||||
|
N←⊃⍴⍵
|
||||||
|
xn←N|((x-1)y)((x+1)y)
|
||||||
|
yn←N|(x(y-1))(x(y+1))
|
||||||
|
⍵[x;y]×+/⍵[xn,yn]
|
||||||
|
}
|
||||||
|
|
||||||
|
U←{
|
||||||
|
⎕IO←0
|
||||||
|
N←⊃⍴⍵
|
||||||
|
(x y)←?N N
|
||||||
|
new←⍵
|
||||||
|
new[x;y]×←(2×(?0)>*-⍺×x y ∆E ⍵)-1
|
||||||
|
new
|
||||||
|
}
|
||||||
|
|
||||||
|
Ising←{' ⌹'[1+1=({10 U ⍵}⍣⍵)L ⍺]}
|
||||||
|
|
||||||
|
:EndNamespace
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Conclusion
|
||||||
|
|
||||||
|
The algorithm is very fast (I think it can be optimized by the
|
||||||
|
interpreter because there is no branching), and is easy to reason
|
||||||
|
about. The whole program fits in a few lines, and you clearly see what
|
||||||
|
each function and each line does. It could probably be optimized
|
||||||
|
further (I don't know every APL function yet...), and also could
|
||||||
|
probably be golfed to a few lines (at the cost of readability?).
|
||||||
|
|
||||||
|
It took me some time to write this, but Dyalog's tools make it really
|
||||||
|
easy to insert symbols and to look up what they do. Next time, I will
|
||||||
|
look into some ASCII-based APL descendants. J seems to have a [[http://code.jsoftware.com/wiki/NuVoc][good
|
||||||
|
documentation]] and a tradition of /tacit definitions/, similar to the
|
||||||
|
point-free style in Haskell. Overall, J seems well-suited to modern
|
||||||
|
functional programming, while APL is still under the influence of its
|
||||||
|
early days when it was more procedural. Another interesting area is K,
|
||||||
|
Q, and their database engine kdb+, which seems to be extremely
|
||||||
|
performant and actually used in production.
|
||||||
|
|
||||||
|
Still, Unicode symbols make the code much more readable, mainly
|
||||||
|
because there is a one-to-one link between symbols and functions,
|
||||||
|
which cannot be maintained with only a few ASCII characters.
|
197
posts/ising-model.org
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
---
|
||||||
|
title: Ising model simulation
|
||||||
|
author: Dimitri Lozeve
|
||||||
|
date: 2018-02-05
|
||||||
|
tags: ising visualization simulation montecarlo
|
||||||
|
---
|
||||||
|
|
||||||
|
The [[https://en.wikipedia.org/wiki/Ising_model][Ising model]] is a
|
||||||
|
model used to represent magnetic dipole moments in statistical
|
||||||
|
physics. Physical details are on the Wikipedia page, but what is
|
||||||
|
interesting is that it follows a complex probability distribution on a
|
||||||
|
lattice, where each site can take the value +1 or -1.
|
||||||
|
|
||||||
|
[[../images/ising.gif]]
|
||||||
|
|
||||||
|
* Mathematical definition
|
||||||
|
|
||||||
|
We have a lattice $\Lambda$ consisting of sites $k$. For each site,
|
||||||
|
there is a moment $\sigma_k \in \{ -1, +1 \}$. $\sigma =
|
||||||
|
(\sigma_k)_{k\in\Lambda}$ is called the /configuration/ of the
|
||||||
|
lattice.
|
||||||
|
|
||||||
|
The total energy of the configuration is given by the /Hamiltonian/
|
||||||
|
\[
|
||||||
|
H(\sigma) = -\sum_{i\sim j} J_{ij}\, \sigma_i\, \sigma_j,
|
||||||
|
\]
|
||||||
|
where $i\sim j$ denotes /neighbours/, and $J$ is the
|
||||||
|
/interaction matrix/.
|
||||||
|
|
||||||
|
The /configuration probability/ is given by:
|
||||||
|
\[
|
||||||
|
\pi_\beta(\sigma) = \frac{e^{-\beta H(\sigma)}}{Z_\beta}
|
||||||
|
\]
|
||||||
|
where $\beta = (k_B T)^{-1}$ is the inverse temperature,
|
||||||
|
and $Z_\beta$ the normalisation constant.
|
||||||
|
|
||||||
|
For our simulation, we will use a constant interaction term $J > 0$.
|
||||||
|
If $\sigma_i = \sigma_j$, the probability will be proportional to
|
||||||
|
$\exp(\beta J)$, otherwise it would be $\exp(\beta J)$. Thus, adjacent
|
||||||
|
spins will try to align themselves.
|
||||||
|
|
||||||
|
* Simulation
|
||||||
|
|
||||||
|
The Ising model is generally simulated using Markov Chain Monte Carlo
|
||||||
|
(MCMC), with the
|
||||||
|
[[https://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm][Metropolis-Hastings]]
|
||||||
|
algorithm.
|
||||||
|
|
||||||
|
The algorithm starts from a random configuration and runs as follows:
|
||||||
|
|
||||||
|
1. Select a site $i$ at random and reverse its spin: $\sigma'_i = -\sigma_i$
|
||||||
|
2. Compute the variation in energy (hamiltonian) $\Delta E = H(\sigma') - H(\sigma)$
|
||||||
|
3. If the energy is lower, accept the new configuration
|
||||||
|
4. Otherwise, draw a uniform random number $u \in ]0,1[$ and accept the new configuration if $u < \min(1, e^{-\beta \Delta E})$.
|
||||||
|
|
||||||
|
* Implementation
|
||||||
|
|
||||||
|
The simulation is in Clojure, using the [[http://quil.info/][Quil
|
||||||
|
library]] (a [[https://processing.org/][Processing]] library for
|
||||||
|
Clojure) to display the state of the system.
|
||||||
|
|
||||||
|
This post is "literate Clojure", and contains
|
||||||
|
[[https://github.com/dlozeve/ising-model/blob/master/src/ising_model/core.clj][=core.clj=]]. The
|
||||||
|
complete project can be found on
|
||||||
|
[[https://github.com/dlozeve/ising-model][GitHub]].
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(ns ising-model.core
|
||||||
|
(:require [quil.core :as q]
|
||||||
|
[quil.middleware :as m]))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
The application works with Quil's
|
||||||
|
[[https://github.com/quil/quil/wiki/Functional-mode-(fun-mode)][functional
|
||||||
|
mode]], with each function taking a state and returning an updated
|
||||||
|
state at each time step.
|
||||||
|
|
||||||
|
The ~setup~ function generates the initial state, with random initial
|
||||||
|
spins. It also sets the frame rate. The matrix is a single vector in
|
||||||
|
row-major mode. The state also holds relevant parameters for the
|
||||||
|
simulation: $\beta$, $J$, and the iteration step.
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(defn setup [size]
|
||||||
|
"Setup the display parameters and the initial state"
|
||||||
|
(q/frame-rate 300)
|
||||||
|
(q/color-mode :hsb)
|
||||||
|
(let [matrix (vec (repeatedly (* size size) #(- (* 2 (rand-int 2)) 1)))]
|
||||||
|
{:grid-size size
|
||||||
|
:matrix matrix
|
||||||
|
:beta 10
|
||||||
|
:intensity 10
|
||||||
|
:iteration 0}))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Given a site $i$, we reverse its spin to generate a new configuration
|
||||||
|
state.
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(defn toggle-state [state i]
|
||||||
|
"Compute the new state when we toggle a cell's value"
|
||||||
|
(let [matrix (:matrix state)]
|
||||||
|
(assoc state :matrix (assoc matrix i (* -1 (matrix i))))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
In order to decide whether to accept this new state, we compute the
|
||||||
|
difference in energy introduced by reversing site $i$: \[ \Delta E =
|
||||||
|
J\sigma_i \sum_{j\sim i} \sigma_j. \]
|
||||||
|
|
||||||
|
The ~filter some?~ is required to eliminate sites outside of the
|
||||||
|
boundaries of the lattice.
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(defn get-neighbours [state idx]
|
||||||
|
"Return the values of a cell's neighbours"
|
||||||
|
[(get (:matrix state) (- idx (:grid-size state)))
|
||||||
|
(get (:matrix state) (dec idx))
|
||||||
|
(get (:matrix state) (inc idx))
|
||||||
|
(get (:matrix state) (+ (:grid-size state) idx))])
|
||||||
|
|
||||||
|
(defn delta-e [state i]
|
||||||
|
"Compute the energy difference introduced by a particular cell"
|
||||||
|
(* (:intensity state) ((:matrix state) i)
|
||||||
|
(reduce + (filter some? (get-neighbours state i)))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
We also add a function to compute directly the hamiltonian for the
|
||||||
|
entire configuration state. We can use it later to log its values
|
||||||
|
across iterations.
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(defn hamiltonian [state]
|
||||||
|
"Compute the Hamiltonian of a configuration state"
|
||||||
|
(- (reduce + (for [i (range (count (:matrix state)))
|
||||||
|
j (filter some? (get-neighbours state i))]
|
||||||
|
(* (:intensity state) ((:matrix state) i) j)))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Finally, we put everything together in the ~update-state~ function,
|
||||||
|
which will decide whether to accept or reject the new configuration.
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(defn update-state [state]
|
||||||
|
"Accept or reject a new state based on energy
|
||||||
|
difference (Metropolis-Hastings)"
|
||||||
|
(let [i (rand-int (count (:matrix state)))
|
||||||
|
new-state (toggle-state state i)
|
||||||
|
alpha (q/exp (- (* (:beta state) (delta-e state i))))]
|
||||||
|
;;(println (hamiltonian new-state))
|
||||||
|
(update (if (< (rand) alpha) new-state state)
|
||||||
|
:iteration inc)))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
The last thing to do is to draw the new configuration:
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(defn draw-state [state]
|
||||||
|
"Draw a configuration state as a grid"
|
||||||
|
(q/background 255)
|
||||||
|
(let [cell-size (quot (q/width) (:grid-size state))]
|
||||||
|
(doseq [[i v] (map-indexed vector (:matrix state))]
|
||||||
|
(let [x (* cell-size (rem i (:grid-size state)))
|
||||||
|
y (* cell-size (quot i (:grid-size state)))]
|
||||||
|
(q/no-stroke)
|
||||||
|
(q/fill
|
||||||
|
(if (= 1 v) 0 255))
|
||||||
|
(q/rect x y cell-size cell-size))))
|
||||||
|
;;(when (zero? (mod (:iteration state) 50)) (q/save-frame "img/ising-######.jpg"))
|
||||||
|
)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
|
||||||
|
And to reset the simulation when the user clicks anywhere on the screen:
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(defn mouse-clicked [state event]
|
||||||
|
"When the mouse is clicked, reset the configuration to a random one"
|
||||||
|
(setup 100))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
#+BEGIN_SRC clojure
|
||||||
|
(q/defsketch ising-model
|
||||||
|
:title "Ising model"
|
||||||
|
:size [300 300]
|
||||||
|
:setup #(setup 100)
|
||||||
|
:update update-state
|
||||||
|
:draw draw-state
|
||||||
|
:mouse-clicked mouse-clicked
|
||||||
|
:features [:keep-on-top :no-bind-output]
|
||||||
|
:middleware [m/fun-mode])
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Conclusion
|
||||||
|
|
||||||
|
The Ising model is a really easy (and common) example use of MCMC and
|
||||||
|
Metropolis-Hastings. It allows to easily and intuitively understand
|
||||||
|
how the algorithm works, and to make nice visualizations!
|
221
posts/lsystems.org
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
---
|
||||||
|
title: Generating and representing L-systems
|
||||||
|
author: Dimitri Lozeve
|
||||||
|
date: 2018-01-18
|
||||||
|
tags: lsystems visualization algorithms haskell
|
||||||
|
---
|
||||||
|
|
||||||
|
L-systems are a formal way to make interesting visualisations. You can
|
||||||
|
use them to model a wide variety of objects: space-filling curves,
|
||||||
|
fractals, biological systems, tilings, etc.
|
||||||
|
|
||||||
|
See the Github repo: [[https://github.com/dlozeve/lsystems]]
|
||||||
|
|
||||||
|
* What is an L-system?
|
||||||
|
|
||||||
|
** A few examples to get started
|
||||||
|
|
||||||
|
[[../images/lsystems/dragon.png]]
|
||||||
|
|
||||||
|
[[../images/lsystems/gosper.png]]
|
||||||
|
|
||||||
|
[[../images/lsystems/plant.png]]
|
||||||
|
|
||||||
|
[[../images/lsystems/penroseP3.png]]
|
||||||
|
|
||||||
|
** Definition
|
||||||
|
|
||||||
|
An [[https://en.wikipedia.org/wiki/L-system][L-system]] is a set of
|
||||||
|
rewriting rules generating sequences of symbols. Formally, an L-system
|
||||||
|
is a triplet of:
|
||||||
|
+ an /alphabet/ $V$ (an arbitrary set of symbols)
|
||||||
|
+ an /axiom/ $\omega$, which is a non-empty word of the alphabet
|
||||||
|
($\omega \in V^+$)
|
||||||
|
+ a set of /rewriting rules/ (or /productions/) $P$, each mapping a
|
||||||
|
symbol to a word: $P \subset V \times V^*$. Symbols not present in
|
||||||
|
$P$ are assumed to be mapped to themselves.
|
||||||
|
|
||||||
|
During an iteration, the algorithm takes each symbol in the current
|
||||||
|
word and replaces it by the value in its rewriting rule. Not that the
|
||||||
|
output of the rewriting rule can be absolutely /anything/ in $V^*$,
|
||||||
|
including the empty word! (So yes, you can generate symbols just to
|
||||||
|
delete them afterwards.)
|
||||||
|
|
||||||
|
At this point, an L-system is nothing more than a way to generate very
|
||||||
|
long strings of characters. In order to get something useful out of
|
||||||
|
this, we have to give them /meaning/.
|
||||||
|
|
||||||
|
** Drawing instructions and representation
|
||||||
|
|
||||||
|
Our objective is to draw the output of the L-system in order to
|
||||||
|
visually inspect the output. The most common way is to interpret the
|
||||||
|
output as a sequence of instruction for a LOGO-like drawing
|
||||||
|
turtle. For instance, a simple alphabet consisting only in the symbols
|
||||||
|
$F$, $+$, and $-$ could represent the instructions "move forward",
|
||||||
|
"turn right by 90°", and "turn left by 90°" respectively.
|
||||||
|
|
||||||
|
Thus, we add new components to our definition of L-systems:
|
||||||
|
+ a set of /instructions/, $I$. These are limited by the capabilities of
|
||||||
|
our imagined turtle, so we can assume that they are the same for
|
||||||
|
every L-system we will consider:
|
||||||
|
+ ~Forward~ makes the turtle draw a straight segment.
|
||||||
|
+ ~TurnLeft~ and ~TurnRight~ makes the turtle turn on itself by a
|
||||||
|
given angle.
|
||||||
|
+ ~Push~ and ~Pop~ allow the turtle to store and retrieve its
|
||||||
|
position on a stack. This will allow for branching in the turtle's
|
||||||
|
path.
|
||||||
|
+ ~Stay~, which orders the turtle to do nothing.
|
||||||
|
+ a /distance/ $d \in \mathbb{R_+}$, i.e. how long should each forward segment should be.
|
||||||
|
+ an /angle/ $\theta$ used for rotation.
|
||||||
|
+ a set of /representation rules/ $R \subset V \times I$. As before,
|
||||||
|
they will match a symbol to an instruction. Symbols not matched by
|
||||||
|
any rule will be associated to ~Stay~.
|
||||||
|
|
||||||
|
Finally, our complete L-system, representable by a turtle with
|
||||||
|
capabilities $I$, can be defined as \[ L = (V, \omega, P, d, \theta,
|
||||||
|
R). \]
|
||||||
|
|
||||||
|
One could argue that the representation is not part of the L-system,
|
||||||
|
and that the same L-system could be represented differently by
|
||||||
|
changing the representation rules. However, in our setting, we won't
|
||||||
|
observe the L-system other than by displaying it, so we might as well
|
||||||
|
consider that two systems differing only by their representation rules
|
||||||
|
are different systems altogether.
|
||||||
|
|
||||||
|
* Implementation details
|
||||||
|
|
||||||
|
** The ~LSystem~ data type
|
||||||
|
|
||||||
|
The mathematical definition above translate almost immediately in a
|
||||||
|
Haskell data type:
|
||||||
|
|
||||||
|
#+BEGIN_SRC haskell
|
||||||
|
-- | L-system data type
|
||||||
|
data LSystem a = LSystem
|
||||||
|
{ name :: String
|
||||||
|
, alphabet :: [a] -- ^ variables and constants used by the system
|
||||||
|
, axiom :: [a] -- ^ initial state of the system
|
||||||
|
, rules :: [(a, [a])] -- ^ production rules defining how each
|
||||||
|
-- variable can be replaced by a sequence of
|
||||||
|
-- variables and constants
|
||||||
|
, angle :: Float -- ^ angle used for the representation
|
||||||
|
, distance :: Float -- ^ distance of each segment in the representation
|
||||||
|
, representation :: [(a, Instruction)] -- ^ representation rules
|
||||||
|
-- defining how each variable
|
||||||
|
-- and constant should be
|
||||||
|
-- represented
|
||||||
|
} deriving (Eq, Show, Generic)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Here, ~a~ is the type of the literal in the alphabet. For all
|
||||||
|
practical purposes, it will almost always be ~Char~.
|
||||||
|
|
||||||
|
~Instruction~ is just a sum type over all possible instructions listed
|
||||||
|
above.
|
||||||
|
|
||||||
|
** Iterating and representing
|
||||||
|
|
||||||
|
From here, generating L-systems and iterating is straightforward. We
|
||||||
|
iterate recursively by looking up each symbol in ~rules~ and replacing
|
||||||
|
it by its expansion. We then transform the result to a list of ~Instruction~.
|
||||||
|
|
||||||
|
** Drawing
|
||||||
|
|
||||||
|
The only remaining thing is to implement the virtual turtle which will
|
||||||
|
actually execute the instructions. It goes through the list of
|
||||||
|
instructions, building a sequence of points and maintaining an
|
||||||
|
internal state (position, angle, stack). The stack is used when ~Push~
|
||||||
|
and ~Pop~ operations are met. In this case, the turtle builds a
|
||||||
|
separate line starting from its current position.
|
||||||
|
|
||||||
|
The final output is a set of lines, each being a simple sequence of
|
||||||
|
points. All relevant data types are provided by the
|
||||||
|
[[https://hackage.haskell.org/package/gloss][Gloss]] library, along
|
||||||
|
with the function that can display the resulting ~Picture~.
|
||||||
|
|
||||||
|
* Common file format for L-systems
|
||||||
|
|
||||||
|
In order to define new L-systems quickly and easily, it is necessary
|
||||||
|
to encode them in some form. We chose to represent them as JSON
|
||||||
|
values.
|
||||||
|
|
||||||
|
Here is an example for the [[https://en.wikipedia.org/wiki/Gosper_curve][Gosper curve]]:
|
||||||
|
#+BEGIN_SRC json
|
||||||
|
{
|
||||||
|
"name": "gosper",
|
||||||
|
"alphabet": "AB+-",
|
||||||
|
"axiom": "A",
|
||||||
|
"rules": [
|
||||||
|
["A", "A-B--B+A++AA+B-"],
|
||||||
|
["B", "+A-BB--B-A++A+B"]
|
||||||
|
],
|
||||||
|
"angle": 60.0,
|
||||||
|
"distance": 10.0,
|
||||||
|
"representation": [
|
||||||
|
["A", "Forward"],
|
||||||
|
["B", "Forward"],
|
||||||
|
["+", "TurnRight"],
|
||||||
|
["-", "TurnLeft"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Using this format, it is easy to define new L-systems (along with how
|
||||||
|
they should be represented). This is translated nearly automatically
|
||||||
|
to the ~LSystem~ data type using
|
||||||
|
[[https://hackage.haskell.org/package/aeson][Aeson]].
|
||||||
|
|
||||||
|
* Variations on L-systems
|
||||||
|
|
||||||
|
We can widen the possibilities of L-systems in various ways. L-systems
|
||||||
|
are in effect deterministic context-free grammars.
|
||||||
|
|
||||||
|
By allowing multiple rewriting rules for each symbol with
|
||||||
|
probabilities, we can extend the model to
|
||||||
|
[[https://en.wikipedia.org/wiki/Probabilistic_context-free_grammar][probabilistic
|
||||||
|
context-free grammars]].
|
||||||
|
|
||||||
|
We can also have replacement rules not for a single symbol, but for a
|
||||||
|
subsequence of them, thus effectively taking into account their
|
||||||
|
neighbours (context-sensitive grammars). This seems very close to 1D
|
||||||
|
cellular automata.
|
||||||
|
|
||||||
|
Finally, L-systems could also have a 3D representation (for instance
|
||||||
|
space-filling curves in 3 dimensions).
|
||||||
|
|
||||||
|
* Usage notes
|
||||||
|
|
||||||
|
1. Clone the repository: =git clone [[https://github.com/dlozeve/lsystems]]=
|
||||||
|
2. Build: =stack build=
|
||||||
|
3. Execute =stack exec lsystems-exe -- examples/penroseP3.json= to see the list of options
|
||||||
|
4. (Optional) Run tests and build documentation: =stack test --haddock=
|
||||||
|
|
||||||
|
Usage: =stack exec lsystems-exe -- --help=
|
||||||
|
#+BEGIN_SRC
|
||||||
|
lsystems -- Generate L-systems
|
||||||
|
|
||||||
|
Usage: lsystems-exe FILENAME [-n|--iterations N] [-c|--color R,G,B]
|
||||||
|
[-w|--white-background]
|
||||||
|
Generate and draw an L-system
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
FILENAME JSON file specifying an L-system
|
||||||
|
-n,--iterations N Number of iterations (default: 5)
|
||||||
|
-c,--color R,G,B Foreground color RGBA
|
||||||
|
(0-255) (default: RGBA 1.0 1.0 1.0 1.0)
|
||||||
|
-w,--white-background Use a white background
|
||||||
|
-h,--help Show this help text
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Apart from the selection of the input JSON file, you can adjust the
|
||||||
|
number of iterations and the colors.
|
||||||
|
|
||||||
|
=stack exec lsystems-exe -- examples/levyC.json -n 12 -c 0,255,255=
|
||||||
|
|
||||||
|
[[../images/lsystems/levyC.png]]
|
||||||
|
|
||||||
|
* References
|
||||||
|
|
||||||
|
1. Prusinkiewicz, Przemyslaw; Lindenmayer, Aristid (1990). /The Algorithmic Beauty of Plants./ Springer-Verlag. ISBN 978-0-387-97297-8. [[http://algorithmicbotany.org/papers/#abop]]
|
||||||
|
2. Weisstein, Eric W. "Lindenmayer System." From MathWorld--A Wolfram Web Resource. [[http://mathworld.wolfram.com/LindenmayerSystem.html]]
|
||||||
|
3. Corte, Leo. "L-systems and Penrose P3 in Inkscape." /The Brick in the Sky./ [[https://thebrickinthesky.wordpress.com/2013/03/17/l-systems-and-penrose-p3-in-inkscape/]]
|
2
site.hs
|
@ -11,7 +11,7 @@ import Hakyll
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = hakyll $ do
|
main = hakyll $ do
|
||||||
match "images/*" $ do
|
match "images/**" $ do
|
||||||
route idRoute
|
route idRoute
|
||||||
compile copyFileCompiler
|
compile copyFileCompiler
|
||||||
|
|
||||||
|
|