<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.2">Jekyll</generator><link href="https://alexandrugris.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://alexandrugris.github.io/" rel="alternate" type="text/html" /><updated>2023-05-20T18:31:05+02:00</updated><id>https://alexandrugris.github.io/feed.xml</id><title type="html">From The Trenches - The Code</title><subtitle>Alexandru Gris - Personal Blog
</subtitle><entry><title type="html">Timeseries Analysis with PyTorch</title><link href="https://alexandrugris.github.io/machine/learning/2022/05/19/timeseries-pytorch.html" rel="alternate" type="text/html" title="Timeseries Analysis with PyTorch" /><published>2022-05-19T09:15:16+02:00</published><updated>2022-05-19T09:15:16+02:00</updated><id>https://alexandrugris.github.io/machine/learning/2022/05/19/timeseries-pytorch</id><content type="html" xml:base="https://alexandrugris.github.io/machine/learning/2022/05/19/timeseries-pytorch.html"><![CDATA[<p>PyTorch is a widely used machine learning library, has an beautiful pythonic syntax and, above all, runs extremely fast on my M1 MacBook with no hacking required to make it run. I write this post following the steps I made to learn the library, by roughly translating the <a href="https://www.tensorflow.org/tutorials/structured_data/time_series">Time series forecasting with TensorFlow</a> tutorial to PyTorch, while making changes to it along the line to satisfy my curiosity.</p>

<h3 id="hello-world">Hello World</h3>

<p>Before starting, let’s make sure we have the right libraries installed.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$pip install torch matplotlib numpy pandas torchvision torchaudio
</code></pre></div></div>

<p>Then, import the right libraries and select a device for running accelerated PyTorch code.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">torch</span> 
<span class="kn">from</span> <span class="nn">torch</span> <span class="kn">import</span> <span class="n">nn</span>
<span class="kn">from</span> <span class="nn">torch.utils.data</span> <span class="kn">import</span> <span class="n">DataLoader</span><span class="p">,</span> <span class="n">Dataset</span>
<span class="kn">from</span> <span class="nn">torchvision.transforms</span> <span class="kn">import</span> <span class="n">ToTensor</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="nn">os</span> <span class="kn">import</span> <span class="n">path</span>

<span class="n">device</span> <span class="o">=</span> <span class="p">(</span>
    <span class="s">"cuda"</span>
    <span class="k">if</span> <span class="n">torch</span><span class="p">.</span><span class="n">cuda</span><span class="p">.</span><span class="n">is_available</span><span class="p">()</span>
    <span class="k">else</span> <span class="s">"mps"</span>
    <span class="k">if</span> <span class="n">torch</span><span class="p">.</span><span class="n">backends</span><span class="p">.</span><span class="n">mps</span><span class="p">.</span><span class="n">is_available</span><span class="p">()</span>
    <span class="k">else</span> <span class="s">"cpu"</span>
<span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</code></pre></div></div>

<p>In my case, the device will be <code class="language-plaintext highlighter-rouge">mps</code>, as I am running this on a MacBook Pro M1 Max.</p>

<h3 id="loading-and-processing-the-data">Loading and processing the data</h3>

<p>For this example I will use the <a href="https://www.kaggle.com/datasets/mnassrib/jena-climate">Jena Climate dataset</a> and the goal will be to predict the temperature (Celsius) over the future 1 or more hours. We are going to use 4 different approaches, a basic linear regression, a simple neural network, a convolutional neural network and, then, a recurrent neural network. They all give pretty good results and we will discuss the differences throughout the post.</p>

<p>Unlike in the TensorFlow tutorial on which this code is based, I will remove the temperature-related features from the training data and only keep them in the target variable. As such, we make the work of the ML models a bit harder.</p>

<p>The first step is loading the data and separating the <code class="language-plaintext highlighter-rouge">date_time</code> variable. We will process the <code class="language-plaintext highlighter-rouge">date_time</code> a bit later to include it back in the trianing set.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># df contains hourly data
</span><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s">"jena_climate_2009_2016.csv"</span><span class="p">)[</span><span class="mi">5</span><span class="p">::</span><span class="mi">6</span><span class="p">]</span>
<span class="n">date_time</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">df</span><span class="p">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'Date Time'</span><span class="p">),</span> <span class="nb">format</span><span class="o">=</span><span class="s">'%d.%m.%Y %H:%M:%S'</span><span class="p">)</span>
<span class="n">df</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch1.jpg" alt="Results" /></p>

<p>Next, we are going to do a bit of data cleanup and transform some of the variables:</p>
<ul>
  <li>Ensure there is no windspeed lower than 0</li>
  <li>Convert wind direction from degrees to vectors (maintaining magnitude)</li>
  <li>Standardize all numeric features for better processing by the neural networks</li>
  <li>Validate the periodicity of the time signal and transform from <code class="language-plaintext highlighter-rouge">date_time</code> to continuous variables that can be used in training.</li>
</ul>

<p>One by one, in the order specified above.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">df</span><span class="p">[</span><span class="s">'wv (m/s)'</span><span class="p">][</span><span class="n">df</span><span class="p">[</span><span class="s">'wv (m/s)'</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">df</span><span class="p">[</span><span class="s">'max. wv (m/s)'</span><span class="p">][</span><span class="n">df</span><span class="p">[</span><span class="s">'max. wv (m/s)'</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">df</span><span class="p">.</span><span class="n">describe</span><span class="p">().</span><span class="n">transpose</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch2.jpg" alt="Highlighted the wind speed and direction" /></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># convert the wind degrees and wind speed to a wind vector
</span><span class="n">wv</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'wv (m/s)'</span><span class="p">)</span>
<span class="n">max_wv</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'max. wv (m/s)'</span><span class="p">)</span>

<span class="c1"># Convert to radians.
</span><span class="n">wd_rad</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'wd (deg)'</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mi">180</span>

<span class="c1"># Calculate the wind x and y components.
</span><span class="n">df</span><span class="p">[</span><span class="s">'Wx'</span><span class="p">]</span> <span class="o">=</span> <span class="n">wv</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">wd_rad</span><span class="p">)</span>
<span class="n">df</span><span class="p">[</span><span class="s">'Wy'</span><span class="p">]</span> <span class="o">=</span> <span class="n">wv</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">wd_rad</span><span class="p">)</span>

<span class="c1"># Calculate the max wind x and y components.
</span><span class="n">df</span><span class="p">[</span><span class="s">'max Wx'</span><span class="p">]</span> <span class="o">=</span> <span class="n">max_wv</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">wd_rad</span><span class="p">)</span>
<span class="n">df</span><span class="p">[</span><span class="s">'max Wy'</span><span class="p">]</span> <span class="o">=</span> <span class="n">max_wv</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">wd_rad</span><span class="p">)</span>

<span class="c1"># show wind vectors looking great
</span><span class="n">plt</span><span class="p">.</span><span class="n">hist2d</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="s">'Wx'</span><span class="p">],</span> <span class="n">df</span><span class="p">[</span><span class="s">'Wy'</span><span class="p">],</span> <span class="n">bins</span><span class="o">=</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="mi">50</span><span class="p">),</span> <span class="n">vmax</span><span class="o">=</span><span class="mi">400</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">colorbar</span><span class="p">()</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">'Wind X [m/s]'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">'Wind Y [m/s]'</span><span class="p">)</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">gca</span><span class="p">()</span>
<span class="n">ax</span><span class="p">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'tight'</span><span class="p">)</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch3.jpg" alt="Wind as vector with direction and magnitude" /></p>

<p>Nothing fancy so far, just similar procesing as in the <a href="https://www.tensorflow.org/tutorials/structured_data/time_series">TensorFlow tutorial</a>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># standardize all numeric features
</span><span class="n">df</span> <span class="o">=</span> <span class="p">(</span><span class="n">df</span><span class="o">-</span><span class="n">df</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">))</span> <span class="o">/</span> <span class="n">df</span><span class="p">.</span><span class="n">std</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="n">df</span><span class="p">[</span><span class="s">"T (degC)"</span><span class="p">].</span><span class="n">plot</span><span class="p">()</span>
<span class="n">df</span><span class="p">[</span><span class="s">"p (mbar)"</span><span class="p">].</span><span class="n">plot</span><span class="p">()</span>
</code></pre></div></div>

<p>The following snippet of code is slightly more intersting. While in this case our intuition tells us that we have yearly and daily periodicity, the safest way to approach the problem of timeseries is to validate. We are going to analyse the spectrum of the signal and confirm our intuition. Comments inline, in the code.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># check for seasonality
</span><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span>

<span class="c1"># confirm the data is sampled hourly
</span><span class="k">print</span><span class="p">(</span><span class="n">date_time</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">10</span><span class="p">])</span>

<span class="c1"># compute the fast fourier transform of the temperature
</span><span class="n">temp</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="s">"T (degC)"</span><span class="p">])</span>
<span class="n">fft</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="n">fft</span><span class="p">(</span><span class="n">temp</span><span class="p">)</span>

<span class="n">N</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">temp</span><span class="p">)</span> <span class="c1"># length
</span><span class="n">T</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># sample frequency, 1/hour
</span><span class="n">D</span> <span class="o">=</span> <span class="n">N</span> <span class="o">*</span> <span class="n">T</span> <span class="c1"># duration
# the following line computes the actual frequencies in the spectrum
</span><span class="n">frequency</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="n">fftfreq</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">d</span><span class="o">=</span><span class="n">T</span><span class="p">)</span>

<span class="c1"># we are interested only in the first half of the array
# the second half is filled with the conjugates for the first half
</span><span class="n">fft</span> <span class="o">=</span> <span class="n">fft</span><span class="p">[:</span><span class="nb">int</span><span class="p">(</span><span class="n">N</span><span class="o">/</span><span class="mi">2</span><span class="p">)]</span>
<span class="n">frequency</span> <span class="o">=</span> <span class="n">frequency</span><span class="p">[:</span><span class="nb">int</span><span class="p">(</span><span class="n">N</span><span class="o">/</span><span class="mi">2</span><span class="p">)]</span>

<span class="c1"># take the highest 10 frequencies and compute their amplitude
</span><span class="nb">max</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">fft</span><span class="p">).</span><span class="n">argsort</span><span class="p">()[::</span><span class="o">-</span><span class="mi">1</span><span class="p">][:</span><span class="mi">10</span><span class="p">]</span>

<span class="c1"># compute the lengh of the period (1/freq) an the magnitudes
</span><span class="n">periods</span> <span class="o">=</span> <span class="p">(</span><span class="mf">1.0</span> <span class="o">/</span> <span class="n">frequency</span><span class="p">[</span><span class="nb">max</span><span class="p">])</span> <span class="o">/</span> <span class="mi">24</span> <span class="c1"># 24 == convert from hours to days
</span><span class="n">magnitudes</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">fft</span><span class="p">[</span><span class="nb">max</span><span class="p">])</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">/</span> <span class="n">N</span>

<span class="c1"># sampling is not perfect, hence some of the frequencies may fall in 
# two different buckets: e.g. 0.99h and 1.01h
</span><span class="n">cnt</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="o">+</span><span class="mf">0.1</span><span class="p">))</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">periods</span><span class="p">],</span> <span class="n">magnitudes</span><span class="p">):</span>
    <span class="n">cnt</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">+=</span> <span class="n">v</span>

<span class="c1"># plot the frequencies and their magnitude
</span><span class="n">plt</span><span class="p">.</span><span class="n">bar</span><span class="p">(</span><span class="n">cnt</span><span class="p">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">cnt</span><span class="p">.</span><span class="n">values</span><span class="p">())</span>

<span class="c1"># we see clearly there is a yearly fundamental and a daily fundamental 
# (2920 days == 8 years - the number of years we have data for)
</span></code></pre></div></div>

<p>Periods in days - outstanding at 365 days and 1 day, as expected:</p>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch4.jpg" alt="Periods in days - outsanding at 365 days and 1 day" /></p>

<p>Given the information above, we can safely encode time as <code class="language-plaintext highlighter-rouge">sin</code> and <code class="language-plaintext highlighter-rouge">cos</code> for two different periods - yearly and daily. We are using both <code class="language-plaintext highlighter-rouge">sin</code> and <code class="language-plaintext highlighter-rouge">cos</code> in order to not confuse the algorithm as each <code class="language-plaintext highlighter-rouge">sin</code> and <code class="language-plaintext highlighter-rouge">cos</code> cross the 0 axis twice, having twice the same values over a period.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">timestamp_s</span> <span class="o">=</span> <span class="n">date_time</span><span class="p">.</span><span class="nb">map</span><span class="p">(</span><span class="n">pd</span><span class="p">.</span><span class="n">Timestamp</span><span class="p">.</span><span class="n">timestamp</span><span class="p">)</span>

<span class="n">day</span> <span class="o">=</span> <span class="mi">24</span><span class="o">*</span><span class="mi">60</span><span class="o">*</span><span class="mi">60</span>
<span class="n">year</span> <span class="o">=</span> <span class="p">(</span><span class="mf">365.2425</span><span class="p">)</span><span class="o">*</span><span class="n">day</span> <span class="c1"># a bit of correction
</span>
<span class="c1"># normalized already
</span><span class="n">df</span><span class="p">[</span><span class="s">'Day sin'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">timestamp_s</span> <span class="o">*</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">day</span><span class="p">))</span> <span class="o">*</span> <span class="mf">0.5</span>
<span class="n">df</span><span class="p">[</span><span class="s">'Day cos'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">timestamp_s</span> <span class="o">*</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">day</span><span class="p">))</span> <span class="o">*</span> <span class="mf">0.5</span>
<span class="n">df</span><span class="p">[</span><span class="s">'Year sin'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">sin</span><span class="p">(</span><span class="n">timestamp_s</span> <span class="o">*</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">year</span><span class="p">))</span> <span class="o">*</span> <span class="mf">0.5</span>
<span class="n">df</span><span class="p">[</span><span class="s">'Year cos'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">cos</span><span class="p">(</span><span class="n">timestamp_s</span> <span class="o">*</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span> <span class="o">/</span> <span class="n">year</span><span class="p">))</span> <span class="o">*</span> <span class="mf">0.5</span>
</code></pre></div></div>

<h3 id="generating-the-datasets">Generating the datasets</h3>

<p>After ensuring we have clean data, we are going to generate 3 data splits: training, validation and test.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># timeseries, so no random split
</span><span class="n">train_df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span> <span class="p">:</span> <span class="nb">int</span><span class="p">(</span><span class="mf">0.7</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">df</span><span class="p">))]</span>
<span class="n">val_df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="mf">0.7</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">df</span><span class="p">))</span> <span class="p">:</span> <span class="nb">int</span><span class="p">(</span><span class="mf">0.9</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">df</span><span class="p">))]</span>
<span class="n">test_df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="mf">0.9</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">df</span><span class="p">))</span> <span class="p">:</span> <span class="p">]</span>
</code></pre></div></div>

<p>In PyTorch, data is fed to the training loop through a <code class="language-plaintext highlighter-rouge">DataLoader</code> object. It handles batching and shuffling, and wraps a user-defined <code class="language-plaintext highlighter-rouge">Dataset</code>. The <code class="language-plaintext highlighter-rouge">Dataset</code> object needs to implement the standard <code class="language-plaintext highlighter-rouge">__len__</code> and <code class="language-plaintext highlighter-rouge">__getitem__</code> functions, so it behaves like an array.</p>

<p>For our code, we will implement a custom <code class="language-plaintext highlighter-rouge">Dataset</code> which wraps a <code class="language-plaintext highlighter-rouge">Pandas</code> dataframe and returns a specified number of time points as features and another number of time points as targets. In addition, it will have plotting functions for easier debugging and vizualization.</p>

<p>The parameters for the <code class="language-plaintext highlighter-rouge">Dataset</code> construction are as follows:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">df</code> - the Pandas dataframe to wrap</li>
  <li><code class="language-plaintext highlighter-rouge">input_window_len</code> - how many past points of time (hours in our case) to return as features</li>
  <li><code class="language-plaintext highlighter-rouge">target_len</code> - how many points in the future to return as target, for one-shot predictions</li>
  <li><code class="language-plaintext highlighter-rouge">shift</code> - when moving through the dataset, by how many datapoints to advance the cursor,</li>
  <li><code class="language-plaintext highlighter-rouge">var_columns</code> - which columns to include in the features</li>
  <li><code class="language-plaintext highlighter-rouge">target_columns</code> - which columns to include in the target</li>
  <li><code class="language-plaintext highlighter-rouge">transform</code> and <code class="language-plaintext highlighter-rouge">target_transform</code> - how to transform the resulting data, in our case it will be transformed to a <code class="language-plaintext highlighter-rouge">torch.Tensor</code> and dispatched to the GPU.</li>
</ul>

<p>One thing to note is to never-ever use Pandas in the training loop as it will slowdown training by at least 100x. Only use numpy arrays and do the conversion outside of the <code class="language-plaintext highlighter-rouge">__getitem__</code> function. We do this update in the <code class="language-plaintext highlighter-rouge">preprocess</code> method of the class.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">WindowedDataset</span><span class="p">(</span><span class="n">Dataset</span><span class="p">):</span>
    
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">df</span><span class="p">,</span>  
                        <span class="n">input_window_len</span><span class="p">,</span> 
                        <span class="n">target_len</span><span class="p">,</span> <span class="n">shift</span><span class="p">,</span> <span class="n">v</span>
                        <span class="n">ar_columns</span><span class="p">,</span> <span class="n">target_columns</span><span class="p">,</span> 
                        <span class="n">transform</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> 
                        <span class="n">target_transform</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span> <span class="p">:</span>
        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">()</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">df</span> <span class="o">=</span> <span class="n">df</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span> <span class="o">=</span> <span class="n">input_window_len</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">target_len</span> <span class="o">=</span> <span class="n">target_len</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">shift</span> <span class="o">=</span> <span class="n">shift</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">transform</span> <span class="o">=</span> <span class="n">transform</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">target_transform</span> <span class="o">=</span> <span class="n">target_transform</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">target_columns</span> <span class="o">=</span> <span class="n">target_columns</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">var_columns</span> <span class="o">=</span> <span class="n">var_columns</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">precompute</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">get_input_size</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">var_columns</span><span class="p">)</span>
    
    <span class="k">def</span> <span class="nf">get_target_size</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">target_len</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">target_columns</span><span class="p">)</span>
    
    <span class="k">def</span> <span class="nf">count_channels</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">var_columns</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">int</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">df</span><span class="p">)</span> <span class="o">-</span> <span class="bp">self</span><span class="p">.</span><span class="n">target_len</span> <span class="o">-</span> <span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span><span class="p">)</span> <span class="o">/</span> <span class="bp">self</span><span class="p">.</span><span class="n">shift</span><span class="p">)</span>
    
    <span class="k">def</span> <span class="nf">precompute</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">variables_</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">df</span><span class="p">[</span><span class="bp">self</span><span class="p">.</span><span class="n">var_columns</span><span class="p">])</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">target_</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">df</span><span class="p">[</span><span class="bp">self</span><span class="p">.</span><span class="n">target_columns</span><span class="p">])</span>
    
    <span class="k">def</span> <span class="nf">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">):</span>
        <span class="n">start</span> <span class="o">=</span> <span class="n">idx</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">shift</span>

        <span class="n">variables</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">variables_</span><span class="p">[</span><span class="n">start</span> <span class="p">:</span> <span class="n">start</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span><span class="p">]</span>
        <span class="n">variables</span> <span class="o">=</span> <span class="n">variables</span><span class="p">.</span><span class="n">flatten</span><span class="p">()</span>
        
        <span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">target_</span><span class="p">[</span><span class="n">start</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span> <span class="p">:</span> <span class="n">start</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">target_len</span><span class="p">]</span>
        <span class="n">target</span> <span class="o">=</span> <span class="n">target</span><span class="p">.</span><span class="n">flatten</span><span class="p">()</span>

        <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">transform</span><span class="p">:</span>
            <span class="n">variables</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">variables</span><span class="p">)</span>
        <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">target_transform</span><span class="p">:</span>
            <span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">target_transform</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">variables</span><span class="p">,</span> <span class="n">target</span>
    
    <span class="k">def</span> <span class="nf">plot</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">,</span> <span class="n">col_name</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="s">'__iter__'</span><span class="p">):</span>
            <span class="n">idx</span> <span class="o">=</span> <span class="p">[</span><span class="n">idx</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">idx</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span> 
            <span class="n">var_tmp</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">var_columns</span>
            <span class="n">target_tmp</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">target_columns</span>

            <span class="bp">self</span><span class="p">.</span><span class="n">var_columns</span> <span class="o">=</span> <span class="p">[</span><span class="n">col_name</span><span class="p">]</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">target_columns</span> <span class="o">=</span> <span class="p">[</span><span class="n">col_name</span><span class="p">]</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">precompute</span><span class="p">()</span>

            <span class="n">cnt</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">target_len</span> <span class="o">+</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">shift</span>
            <span class="n">v</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span> <span class="o">+</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">shift</span><span class="p">)</span>
            <span class="n">t</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">target_len</span> <span class="o">+</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">shift</span><span class="p">)</span>

            <span class="n">start</span> <span class="o">=</span> <span class="n">idx</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">shift</span>

            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">idx</span><span class="p">:</span>
                <span class="n">v_</span><span class="p">,</span> <span class="n">t_</span> <span class="o">=</span> <span class="bp">self</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>

                <span class="n">ii</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">shift</span>
                <span class="n">v</span> <span class="p">[</span><span class="n">ii</span> <span class="p">:</span> <span class="n">ii</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">v_</span><span class="p">)]</span> <span class="o">=</span> <span class="n">v_</span> 
                <span class="n">t</span> <span class="p">[</span><span class="n">ii</span> <span class="p">:</span> <span class="n">ii</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">t_</span><span class="p">)]</span> <span class="o">=</span> <span class="n">t_</span>

            <span class="n">axis</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">start</span> <span class="o">+</span> <span class="n">cnt</span><span class="p">)</span>
            <span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">axis</span><span class="p">[</span><span class="mi">0</span> <span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">)],</span> <span class="n">v</span><span class="p">)</span>
            <span class="n">plt</span><span class="p">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">axis</span><span class="p">[</span><span class="bp">self</span><span class="p">.</span><span class="n">input_window_len</span> <span class="p">:</span> <span class="n">cnt</span><span class="p">],</span> <span class="n">t</span><span class="p">)</span>

            <span class="k">return</span> <span class="n">axis</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">cnt</span>
        
        <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">e</span>
        <span class="k">finally</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">var_columns</span> <span class="o">=</span> <span class="n">var_tmp</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">target_columns</span> <span class="o">=</span> <span class="n">target_tmp</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">precompute</span><span class="p">()</span>

    
    <span class="k">def</span> <span class="nf">plot_prediction</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">,</span> <span class="n">col_name</span><span class="p">,</span> <span class="n">model</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="s">'__iter__'</span><span class="p">):</span>
            <span class="n">idx</span> <span class="o">=</span> <span class="p">[</span><span class="n">idx</span><span class="p">]</span>

        <span class="n">axis</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">cnt</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">col_name</span><span class="o">=</span><span class="n">col_name</span><span class="p">)</span>

        <span class="k">with</span> <span class="n">torch</span><span class="p">.</span><span class="n">no_grad</span><span class="p">():</span>
            <span class="n">preds</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="c1"># slow way to infer
</span>            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">idx</span><span class="p">:</span>
                <span class="n">X</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
                <span class="n">X</span> <span class="o">=</span> <span class="n">X</span><span class="p">[</span><span class="bp">None</span><span class="p">,</span> <span class="p">:]</span> <span class="c1"># add batch dimension
</span>                <span class="n">X</span> <span class="o">=</span> <span class="n">X</span><span class="p">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
                <span class="n">y</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">X</span><span class="p">).</span><span class="n">item</span><span class="p">()</span>

                <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="s">"__iter__"</span><span class="p">):</span>
                    <span class="n">preds</span> <span class="o">+=</span> <span class="nb">list</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">preds</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>

            <span class="n">plt</span><span class="p">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">axis</span><span class="p">[</span><span class="n">cnt</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">preds</span><span class="p">)</span> <span class="p">:</span> <span class="n">cnt</span><span class="p">],</span> <span class="n">preds</span><span class="p">)</span>
            <span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>

<p>Let’s test the <code class="language-plaintext highlighter-rouge">WindowedDataset</code> and ask it to plot something.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># build a test dataset based on train_df
# return 100 points for each index
# return 10 points for each target
# advance by 1
</span><span class="n">wds</span> <span class="o">=</span> <span class="n">WindowedDataset</span><span class="p">(</span><span class="n">train_df</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">df</span><span class="p">.</span><span class="n">columns</span><span class="p">,</span> <span class="s">"T (degC)"</span> <span class="p">)</span>

<span class="c1"># print the last object from the set
</span><span class="k">print</span><span class="p">(</span><span class="n">wds</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">wds</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">])</span>

<span class="c1"># plot the series starting at index 10
# and use only the temperature
# the feature will be plotted with continuous line
# the target with dots
</span><span class="n">wds</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s">"T (degC)"</span><span class="p">)</span>
</code></pre></div></div>

<p>And the result of the plot - 100 points for the features, only the degrees Celsius (continous line) and the target, 10 points, as dots. The X-axis starts from 10 (starting index) to 120 (10 + 100 + 10).</p>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch5.jpg" alt="Plot result" /></p>

<p>We finish this part of data preparation and dataset construction by presenting the functions that construct 3 <code class="language-plaintext highlighter-rouge">Dataloader</code> objects for train, validation and test respectively. To note the <code class="language-plaintext highlighter-rouge">transform</code> lambda which transforms from <code class="language-plaintext highlighter-rouge">numpy</code> to a <code class="language-plaintext highlighter-rouge">torch.Tensor</code> of <code class="language-plaintext highlighter-rouge">float32</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">make_dataloader</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">input_window_len</span><span class="p">,</span> <span class="n">target_len</span><span class="p">,</span> <span class="n">shift</span><span class="p">):</span>
    <span class="n">cols</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">df</span><span class="p">.</span><span class="n">columns</span><span class="p">)</span>

    <span class="c1"># make it a bit more complicated, remove the temperature completely
</span>    <span class="c1"># usually this is not needed for timeseries prediction
</span>    <span class="c1"># but more interesting to see how the models behave
</span>    <span class="n">cols</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="s">"T (degC)"</span><span class="p">)</span>
    <span class="n">cols</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="s">"Tpot (K)"</span><span class="p">)</span>
    <span class="n">cols</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="s">"Tdew (degC)"</span><span class="p">)</span>
    
    <span class="k">print</span><span class="p">(</span><span class="n">cols</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">DataLoader</span><span class="p">(</span>
        <span class="n">WindowedDataset</span><span class="p">(</span>
            <span class="n">df</span><span class="p">,</span> <span class="n">input_window_len</span><span class="p">,</span> <span class="n">target_len</span><span class="p">,</span> <span class="n">shift</span><span class="p">,</span> <span class="n">cols</span><span class="p">,</span> <span class="p">[</span><span class="s">"T (degC)"</span><span class="p">],</span>  
            <span class="n">transform</span><span class="o">=</span><span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="p">.</span><span class="n">float32</span><span class="p">),</span>
            <span class="n">target_transform</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="p">.</span><span class="n">float32</span><span class="p">)</span>
        <span class="p">),</span> 
        <span class="n">batch_size</span><span class="o">=</span><span class="mi">128</span><span class="p">,</span> 
        <span class="n">shuffle</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">make_loaders</span><span class="p">(</span><span class="n">input_window_len</span><span class="p">,</span> <span class="n">target_len</span><span class="p">,</span> <span class="n">shift</span><span class="p">):</span>
    <span class="n">train_loader</span> <span class="o">=</span> <span class="n">make_dataloader</span><span class="p">(</span><span class="n">train_df</span><span class="p">,</span> <span class="n">input_window_len</span><span class="p">,</span> <span class="n">target_len</span><span class="p">,</span> <span class="n">shift</span><span class="p">)</span>
    <span class="n">valid_loader</span> <span class="o">=</span> <span class="n">make_dataloader</span><span class="p">(</span><span class="n">val_df</span><span class="p">,</span> <span class="n">input_window_len</span><span class="p">,</span> <span class="n">target_len</span><span class="p">,</span> <span class="n">shift</span><span class="p">)</span>
    <span class="n">test_loader</span> <span class="o">=</span> <span class="n">make_dataloader</span><span class="p">(</span><span class="n">test_df</span><span class="p">,</span> <span class="n">input_window_len</span><span class="p">,</span> <span class="n">target_len</span><span class="p">,</span> <span class="n">shift</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">train_loader</span><span class="p">,</span> <span class="n">valid_loader</span><span class="p">,</span> <span class="n">test_loader</span>
</code></pre></div></div>

<h3 id="training-loop-and-evaluating">Training loop and evaluating</h3>

<p>PyTorch uses Autograd and a pretty straightforward training loop. To note are:</p>
<ul>
  <li>Transferring the tensors to the GPU with the <code class="language-plaintext highlighter-rouge">.to(device)</code> calls.</li>
  <li>Defining a custom loss (<code class="language-plaintext highlighter-rouge">RMSELoss</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">with torch.not_grad()</code> when making predictions</li>
  <li>How backpropagation is implemented and using the optimizer</li>
  <li>Saving and loading a model</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">RMSELoss</span><span class="p">(</span><span class="n">yhat</span><span class="p">,</span><span class="n">y</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">torch</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">torch</span><span class="p">.</span><span class="n">mean</span><span class="p">((</span><span class="n">yhat</span><span class="o">-</span><span class="n">y</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">eval_</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">dl</span><span class="p">):</span>
    <span class="n">res</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">with</span> <span class="n">torch</span><span class="p">.</span><span class="n">no_grad</span><span class="p">():</span>
        <span class="k">for</span> <span class="n">batch</span><span class="p">,</span> <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">dl</span><span class="p">):</span>
            <span class="n">X</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">X</span><span class="p">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">),</span> <span class="n">y</span><span class="p">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
            <span class="n">pred</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
            <span class="n">res</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">RMSELoss</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">pred</span><span class="p">).</span><span class="n">item</span><span class="p">())</span>

            <span class="c1"># take only the first 20 batches top
</span>            <span class="k">if</span> <span class="n">batch</span> <span class="o">&gt;</span> <span class="mi">20</span><span class="p">:</span>
                <span class="k">break</span>

    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">eval</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">train_ds</span><span class="p">,</span> <span class="n">valid_ds</span><span class="p">,</span> <span class="n">test_ds</span><span class="p">):</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Training loss:"</span><span class="p">,</span> <span class="n">eval_</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">dl</span><span class="o">=</span><span class="n">train_ds</span><span class="p">))</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Validation loss:"</span><span class="p">,</span> <span class="n">eval_</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">dl</span><span class="o">=</span><span class="n">valid_ds</span><span class="p">))</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Test loss:"</span><span class="p">,</span> <span class="n">eval_</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">dl</span><span class="o">=</span><span class="n">test_ds</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">create_trainer</span><span class="p">(</span><span class="n">dataloader</span><span class="p">,</span> <span class="n">model</span><span class="p">,</span> <span class="n">epochs</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">torch</span><span class="p">.</span><span class="n">_dynamo</span><span class="p">.</span><span class="n">config</span><span class="p">.</span><span class="n">suppress_errors</span> <span class="o">=</span> <span class="bp">True</span>
        <span class="n">model</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
    <span class="k">except</span><span class="p">:</span>
        <span class="k">print</span> <span class="p">(</span><span class="s">"torch.compile() not available."</span><span class="p">)</span>

    <span class="n">losses</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">m</span> <span class="o">=</span> <span class="n">model</span>
    
    <span class="n">loss_fn</span> <span class="o">=</span> <span class="n">RMSELoss</span>
    <span class="n">optimizer</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">optim</span><span class="p">.</span><span class="n">Adam</span><span class="p">(</span><span class="n">model</span><span class="p">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="mf">2e-4</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">train</span><span class="p">():</span>
        <span class="c1"># loop through the dataset and perform backpropagation"
</span>
        <span class="n">size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">dataloader</span><span class="p">.</span><span class="n">dataset</span><span class="p">)</span>
        <span class="n">model</span><span class="p">.</span><span class="n">train</span><span class="p">()</span>

        <span class="k">for</span> <span class="n">batch</span><span class="p">,</span> <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">dataloader</span><span class="p">):</span>
            <span class="n">X</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">X</span><span class="p">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">),</span> <span class="n">y</span><span class="p">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>

            <span class="c1"># Compute prediction error
</span>            <span class="n">pred</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
            <span class="n">loss</span> <span class="o">=</span> <span class="n">loss_fn</span><span class="p">(</span><span class="n">pred</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>

            <span class="c1"># Backpropagation
</span>            <span class="n">optimizer</span><span class="p">.</span><span class="n">zero_grad</span><span class="p">()</span>
            <span class="n">loss</span><span class="p">.</span><span class="n">backward</span><span class="p">()</span>
            <span class="n">optimizer</span><span class="p">.</span><span class="n">step</span><span class="p">()</span>

            <span class="c1"># save losses for plotting
</span>            <span class="n">losses</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">loss</span><span class="p">.</span><span class="n">item</span><span class="p">())</span>

            <span class="k">if</span> <span class="n">batch</span> <span class="o">%</span> <span class="mi">100</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">loss</span><span class="p">,</span> <span class="n">current</span> <span class="o">=</span> <span class="n">loss</span><span class="p">.</span><span class="n">item</span><span class="p">(),</span> <span class="p">(</span><span class="n">batch</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
                <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"loss: </span><span class="si">{</span><span class="n">loss</span><span class="p">:</span><span class="o">&gt;</span><span class="mi">7</span><span class="n">f</span><span class="si">}</span><span class="s">  [</span><span class="si">{</span><span class="n">current</span><span class="p">:</span><span class="o">&gt;</span><span class="mi">5</span><span class="n">d</span><span class="si">}</span><span class="s">/</span><span class="si">{</span><span class="n">size</span><span class="p">:</span><span class="o">&gt;</span><span class="mi">5</span><span class="n">d</span><span class="si">}</span><span class="s">]"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">trainer</span><span class="p">():</span>
        <span class="c1"># load a model if already exists
</span>        <span class="c1"># else loop (epochs) times through the train function
</span>
        <span class="n">model_str</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
        <span class="n">model_str</span> <span class="o">=</span> <span class="s">''</span><span class="p">.</span><span class="n">join</span><span class="p">([</span><span class="n">s</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">model_str</span> <span class="k">if</span> <span class="n">s</span><span class="p">.</span><span class="n">isalnum</span><span class="p">()])</span>
        <span class="n">model_str</span> <span class="o">=</span> <span class="n">model_str</span><span class="p">[</span><span class="mi">0</span> <span class="p">:</span> <span class="nb">min</span><span class="p">(</span><span class="mi">150</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">model_str</span><span class="p">))]</span>

        <span class="k">if</span> <span class="n">path</span><span class="p">.</span><span class="n">exists</span><span class="p">(</span><span class="n">model_str</span><span class="p">):</span>
            <span class="k">return</span> <span class="n">torch</span><span class="p">.</span><span class="n">load</span><span class="p">(</span><span class="n">model_str</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">epochs</span><span class="p">):</span>
                <span class="k">print</span><span class="p">(</span><span class="s">"Epoch "</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
                <span class="n">train</span><span class="p">()</span>
            <span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">losses</span><span class="p">)</span>
            <span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
            <span class="n">torch</span><span class="p">.</span><span class="n">save</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">model_str</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">m</span>

    <span class="k">return</span> <span class="n">trainer</span>
</code></pre></div></div>

<h3 id="basic-linear-regression">Basic Linear Regression</h3>

<p>The simplest model will take the atmospheric parameters for one hour and predicts the temperature for the next hour. It’s a basic neural network with 1 neuron and no activation, equivalent to a simple linear regression.</p>

<p>The interesting things to note are:</p>
<ul>
  <li>The structure of a neural network in PyTorch, inheriting from the <code class="language-plaintext highlighter-rouge">nn.Module</code> base class</li>
  <li>The <code class="language-plaintext highlighter-rouge">forward()</code> function which performs the forward propagation and evalution step</li>
  <li>The use of an <code class="language-plaintext highlighter-rouge">nn.Linear</code> object which is the equivalent of a Dense layer</li>
  <li>The use of <code class="language-plaintext highlighter-rouge">.to(device)</code> to ensure all parameters are submitted to the GPU</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">BasicLinear</span><span class="p">(</span><span class="n">nn</span><span class="p">.</span><span class="n">Module</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_size</span><span class="p">,</span> <span class="n">target_size</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">()</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">linear_stack</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Sequential</span><span class="p">(</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="n">target_size</span><span class="p">),</span>
        <span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">linear_stack</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>

<span class="c1"># one hour of data and predict the following hour
</span><span class="n">t</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">tt</span> <span class="o">=</span> <span class="n">make_loaders</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">BasicLinear</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">get_input_size</span><span class="p">(),</span> <span class="n">t</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">get_target_size</span><span class="p">()).</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
</code></pre></div></div>

<p>As a side note, if I were to build a custom linear layer, <code class="language-plaintext highlighter-rouge">CustomDense</code>, which does exactly the same thing as the <code class="language-plaintext highlighter-rouge">nn.Linear</code>, it would be as follows. Please note the use of <code class="language-plaintext highlighter-rouge">nn.Parameter()</code> to allow the system to keep track of the trainable weights.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">CustomDense</span><span class="p">(</span><span class="n">nn</span><span class="p">.</span><span class="n">Module</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">size_in</span><span class="p">,</span> <span class="n">size_out</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">()</span>

        <span class="c1">#1. Explicit what is trainable parameters
</span>        <span class="c1"># nn.Parameter - trainable parameters
</span>        <span class="c1"># it's what we send to the constructor of the Optimizier.
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">weights</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Parameter</span><span class="p">(</span>
            <span class="n">torch</span><span class="p">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">size_out</span><span class="p">,</span> <span class="n">size_in</span><span class="p">)</span>
        <span class="p">)</span>  

        <span class="bp">self</span><span class="p">.</span><span class="n">bias</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Parameter</span><span class="p">(</span>
            <span class="n">torch</span><span class="p">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">size_out</span><span class="p">)</span>
        <span class="p">)</span> 

        <span class="c1">#2. Initialize weights and biases
</span>        <span class="c1"># He initialization
</span>        <span class="n">nn</span><span class="p">.</span><span class="n">init</span><span class="p">.</span><span class="n">kaiming_uniform_</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">weights</span><span class="p">,</span> <span class="n">a</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>
        <span class="n">nn</span><span class="p">.</span><span class="n">init</span><span class="p">.</span><span class="n">uniform_</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">bias</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="c1"># w times x + b
</span>        <span class="n">w_times_x</span><span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">mm</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">weights</span><span class="p">.</span><span class="n">t</span><span class="p">())</span>
        <span class="k">return</span> <span class="n">torch</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">w_times_x</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">bias</span><span class="p">)</span>
</code></pre></div></div>

<p>Now let’s use the basic network above.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># train for 5 epochs
</span><span class="n">model</span> <span class="o">=</span> <span class="n">create_trainer</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">model</span><span class="p">,</span> <span class="mi">5</span><span class="p">)()</span>
<span class="nb">eval</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">tt</span><span class="p">)</span>

<span class="c1"># plot the temperature - actual: blue dots, predicted: organge dots
</span><span class="n">v</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">plot_prediction</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">),</span> <span class="s">"T (degC)"</span><span class="p">,</span> <span class="n">model</span><span class="p">)</span>
</code></pre></div></div>

<p>We observe the loss values for all sets, showing we don’t overfit but also not fit too well the data.</p>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch6.jpg" alt="Plot result" /></p>

<h3 id="deep-neural-network">Deep Neural Network</h3>

<p>We are going to proceed similarly as before but add more neurons to the mix. We now send 24h of data to predict 1h in advance. The code can be changed to predict as many hours as we want in advance, buy changing only the second parameter in the <code class="language-plaintext highlighter-rouge">make_loaders(24, 1, 1)</code> call.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># deep learning, dense, given 24h of data, predict 1h in advance,
</span><span class="k">class</span> <span class="nc">DNNRegressor</span><span class="p">(</span><span class="n">nn</span><span class="p">.</span><span class="n">Module</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_size</span><span class="p">,</span> <span class="n">target_size</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">()</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">linear_stack</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Sequential</span><span class="p">(</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="n">input_size</span><span class="p">),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">ReLU</span><span class="p">(),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="mi">64</span><span class="p">),</span>
            <span class="c1">#nn.Dropout(p=0.2),
</span>            <span class="n">nn</span><span class="p">.</span><span class="n">ReLU</span><span class="p">(),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="mi">64</span><span class="p">),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">ReLU</span><span class="p">(),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="n">target_size</span><span class="p">)</span>
        <span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">linear_stack</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
    
<span class="n">t</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">tt</span> <span class="o">=</span> <span class="n">make_loaders</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">DNNRegressor</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">get_input_size</span><span class="p">(),</span> <span class="n">t</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">get_target_size</span><span class="p">()).</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Total params: "</span><span class="p">,</span> <span class="nb">sum</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">numel</span><span class="p">()</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">model</span><span class="p">.</span><span class="n">parameters</span><span class="p">()</span> <span class="k">if</span> <span class="n">p</span><span class="p">.</span><span class="n">requires_grad</span><span class="p">))</span>
</code></pre></div></div>

<p>With the model structure and number of parameters:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DNNRegressor(
  (linear_stack): Sequential(
    (0): Linear(in_features=384, out_features=384, bias=True)
    (1): ReLU()
    (2): Linear(in_features=384, out_features=64, bias=True)
    (3): ReLU()
    (4): Linear(in_features=64, out_features=64, bias=True)
    (5): ReLU()
    (6): Linear(in_features=64, out_features=1, bias=True)
  )
)
Total params:  176705
</code></pre></div></div>

<p>The results are as follows, and we immediately notice the lower loss while still not overfitting the dataset. Also visually, the predictions look more precise than in the linear regression case, which is expected.</p>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch7.jpg" alt="Plot result" /></p>

<h3 id="convolutional-neural-network">Convolutional Neural Network</h3>

<p>We are now going to replace one of the dense layers above with a convolutional layer. CNNs tend to have less parameters than basic DNNs due to the locality of the convolutional transform. They also tend to incorporate better local relationships in the data and extract patterns. This is why they are widely used for image processing.</p>

<p>To ensure the right data format is sent to the <code class="language-plaintext highlighter-rouge">Conv1D</code> layer, we first play a bit with arrays. Fortunately PyTorch allows immediate results, so here they are:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">x</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span>
    <span class="p">[</span>
        <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">],</span>
        <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">],</span>
        <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">],</span>
    <span class="p">],</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="p">.</span><span class="n">float32</span><span class="p">)</span>

<span class="n">x</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="mi">2</span><span class="p">)).</span><span class="n">permute</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">numpy</span><span class="p">())</span>
</code></pre></div></div>

<p>Outputting</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[[[1. 3. 5. 7.]
  [2. 4. 6. 8.]]

 [[1. 3. 5. 7.]
  [2. 4. 6. 8.]]

 [[1. 3. 5. 7.]
  [2. 4. 6. 8.]]]
</code></pre></div></div>

<p>This is inline with our expectation that Conv1D operation will convolve along the time dimension. With this knowledge, we build our network.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">CNNRegressor</span><span class="p">(</span><span class="n">nn</span><span class="p">.</span><span class="n">Module</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">in_channels</span><span class="p">,</span> <span class="n">target_size</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">()</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">in_channels</span> <span class="o">=</span> <span class="n">in_channels</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">seq_stack</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Sequential</span><span class="p">(</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Conv1d</span><span class="p">(</span><span class="n">in_channels</span><span class="o">=</span><span class="n">in_channels</span><span class="p">,</span> <span class="n">out_channels</span><span class="o">=</span><span class="mi">256</span><span class="p">,</span> <span class="n">kernel_size</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">ReLU</span><span class="p">(),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">AdaptiveAvgPool1d</span><span class="p">(</span><span class="n">output_size</span><span class="o">=</span><span class="mi">8</span><span class="p">),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Flatten</span><span class="p">(),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">256</span> <span class="o">*</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">64</span><span class="p">),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">ReLU</span><span class="p">(),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="mi">64</span><span class="p">),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">ReLU</span><span class="p">(),</span>
            <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="n">target_size</span><span class="p">)</span>
        <span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">/</span> <span class="bp">self</span><span class="p">.</span><span class="n">in_channels</span><span class="p">),</span> <span class="bp">self</span><span class="p">.</span><span class="n">in_channels</span><span class="p">)).</span><span class="n">permute</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">seq_stack</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
    

<span class="n">t</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">tt</span> <span class="o">=</span> <span class="n">make_loaders</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">CNNRegressor</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">count_channels</span><span class="p">(),</span> <span class="n">t</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">get_target_size</span><span class="p">()).</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Total params: "</span><span class="p">,</span> <span class="nb">sum</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">numel</span><span class="p">()</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">model</span><span class="p">.</span><span class="n">parameters</span><span class="p">()</span> <span class="k">if</span> <span class="n">p</span><span class="p">.</span><span class="n">requires_grad</span><span class="p">))</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CNNRegressor(
  (seq_stack): Sequential(
    (0): Conv1d(16, 256, kernel_size=(5,), stride=(1,), padding=same)
    (1): ReLU()
    (2): AdaptiveAvgPool1d(output_size=8)
    (3): Flatten(start_dim=1, end_dim=-1)
    (4): Linear(in_features=2048, out_features=64, bias=True)
    (5): ReLU()
    (6): Linear(in_features=64, out_features=64, bias=True)
    (7): ReLU()
    (8): Linear(in_features=64, out_features=1, bias=True)
  )
)
Total params:  156097
</code></pre></div></div>

<p>We immediately see the number of total parameters is smaller, even if I did no real tuning to the layer shapes, while the end results are not significantly different from the DNN. For this toy example, I did not expect much improvement.</p>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch8.jpg" alt="Plot result" /></p>

<h3 id="recurrent-neural-network">Recurrent Neural Network</h3>

<p>I will finish my post by showing the same algorithm, but this time using RNNs. I will replace all the deep layers with 4 LSTM layers. We will notice a huge decrease (3x compared to the CNN) in the number model parameters, while keeping the same performance, even a notch better. To note the way data is transmitted to the LSTM block; again we make sure the series is sent to the network along the time axis.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">LSTMRegressor</span><span class="p">(</span><span class="n">nn</span><span class="p">.</span><span class="n">Module</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_size</span><span class="p">,</span> <span class="n">target_size</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">()</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">lstm</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">LSTM</span><span class="p">(</span>
            <span class="n">input_size</span><span class="o">=</span><span class="n">input_size</span><span class="p">,</span> 
            <span class="n">hidden_size</span><span class="o">=</span><span class="n">input_size</span> <span class="o">*</span> <span class="mi">2</span><span class="p">,</span> 
            <span class="n">num_layers</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span>
            <span class="n">batch_first</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
        
        <span class="bp">self</span><span class="p">.</span><span class="n">input_size</span> <span class="o">=</span> <span class="n">input_size</span> <span class="c1"># number of channels
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">linear</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">input_size</span> <span class="o">*</span> <span class="mi">2</span><span class="p">,</span> <span class="n">target_size</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="n">seq_len</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">/</span> <span class="bp">self</span><span class="p">.</span><span class="n">input_size</span><span class="p">)</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">seq_len</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">input_size</span><span class="p">)).</span><span class="n">permute</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
        <span class="n">ret_lstm</span><span class="p">,</span> <span class="p">(</span><span class="n">hn</span><span class="p">,</span> <span class="n">cn</span><span class="p">)</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">lstm</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
        <span class="n">lin_input</span> <span class="o">=</span> <span class="n">ret_lstm</span><span class="p">[:,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="p">:]</span> <span class="c1"># take the last output from the sequence
</span>        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">linear</span><span class="p">(</span><span class="n">lin_input</span><span class="p">)</span>
    

<span class="n">t</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">tt</span> <span class="o">=</span> <span class="n">make_loaders</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">LSTMRegressor</span><span class="p">(</span><span class="n">input_size</span><span class="o">=</span><span class="n">t</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">count_channels</span><span class="p">(),</span> <span class="n">target_size</span><span class="o">=</span><span class="n">t</span><span class="p">.</span><span class="n">dataset</span><span class="p">.</span><span class="n">get_target_size</span><span class="p">()).</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Total params: "</span><span class="p">,</span> <span class="nb">sum</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">numel</span><span class="p">()</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">model</span><span class="p">.</span><span class="n">parameters</span><span class="p">()</span> <span class="k">if</span> <span class="n">p</span><span class="p">.</span><span class="n">requires_grad</span><span class="p">))</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LSTMRegressor(
  (lstm): LSTM(16, 32, num_layers=4, batch_first=True)
  (linear): Linear(in_features=32, out_features=1, bias=True)
)
Total params:  31777
</code></pre></div></div>

<p>The LSTM cells will memorize the most important features of th data, processing the input as a sequence passed through the network in one timestep at a time.</p>

<p>The results applying this network to the validation data, below:</p>

<p><img src="https://alexandrugris.github.io/assets/ts-pytorch9.jpg" alt="Plot result" /></p>]]></content><author><name></name></author><category term="machine" /><category term="learning" /><summary type="html"><![CDATA[PyTorch is a widely used machine learning library, has an beautiful pythonic syntax and, above all, runs extremely fast on my M1 MacBook with no hacking required to make it run. I write this post following the steps I made to learn the library, by roughly translating the Time series forecasting with TensorFlow tutorial to PyTorch, while making changes to it along the line to satisfy my curiosity.]]></summary></entry><entry><title type="html">Timeseries Analysis in Python</title><link href="https://alexandrugris.github.io/programming/2021/08/14/timeseries-analysis.html" rel="alternate" type="text/html" title="Timeseries Analysis in Python" /><published>2021-08-14T09:15:16+02:00</published><updated>2021-08-14T09:15:16+02:00</updated><id>https://alexandrugris.github.io/programming/2021/08/14/timeseries-analysis</id><content type="html" xml:base="https://alexandrugris.github.io/programming/2021/08/14/timeseries-analysis.html"><![CDATA[<p>This post is about statistical models for timeseries analysis in Python. We will cover the ARIMA model to a certain depth.</p>

<h3 id="linear-regression-and-timeseries">Linear Regression and Timeseries</h3>

<p>Using a statistical tools such as linear regression with time series can be problematic. Linear regression  assumes you have independently and normally distributed data, while, in time series data, points near in time tend to be strongly correlated with one another. This is precisely the property that makes timeseries analysis important as, if there aren’t temporal correlations, it would be impossible to perform tasks such as predicting the future or understanding temporal dynamics.</p>

<p>Linear regression can be used with timeseries when linear regression assumptions hold, for instance when the predicted variable is fully dependent on its predictors and the errors preserve the normality assumption with no autocorrelation. In such a case, the timeseries element is entirely embedded in one of the features.</p>

<h3 id="the-statistics-of-time-series">The Statistics Of Time Series</h3>

<p>An excellent introduction on time series can be found <a href="https://www.youtube.com/playlist?list=PLvcbYUQ5t0UHOLnBzl46_Q6QKtFgfMGc3">here</a>.</p>

<p>Timeseries bring several concepts of interest</p>

<ul>
  <li>Stationarity: constant statistical properties of the timeseries (mean, variance, no seasonality)</li>
  <li>Self-correlation: correlation between subsequent values of a timeseries</li>
  <li>Seasonality: time-based patterns tha repeat at set intervals</li>
  <li>Spurious correlations: the propensity of timeseries to correlate with other unrelated timeseries especially when seasonality or trends are present.</li>
</ul>

<p>A log transformation or a square root transformation are two usually good options for making a timeseries stationary,particularly in the case of changing variance over time.</p>

<p>Most of the timeseries have a trend, that is the mean is not constant - <a href="https://en.wikipedia.org/wiki/Trend-stationary_process">trend-stationarity</a> and <a href="https://en.wikipedia.org/wiki/Unit_root">difference-stationarity</a>. Removing a trend is most commonly done by differencing. Sometimes a series must be differenced more than once. However, if you find yourself differencing too much (more than two or three times) it is unlikely that you can fix your stationarity problem with differencing.</p>

<p>If <code class="language-plaintext highlighter-rouge">v(t_i+1) - v(t_i)</code> is random and stationary, then the process generating the series is a random walk, else a more refined model is required.</p>

<p>The test that is mainly used for testing stationarity is called the <a href="https://en.wikipedia.org/wiki/Augmented_Dickey%E2%80%93Fuller_test">Augmented Dickey Fuller Test</a>. It removes the autocorrelation and tests for equal mean and equal variance throughout the series. The null hypothesis is the non-stationarity.</p>

<p>The Dickey Fuller test assumes that the time series is an AR1 process (auto-regressive one), that is, it can be written as <code class="language-plaintext highlighter-rouge">y(t) = phi * y(t-1) + constant + error</code>. The DF test’s null hypothesis is <code class="language-plaintext highlighter-rouge">phi &gt;= 1</code>. The alternate hypothesis is that <code class="language-plaintext highlighter-rouge">phi &lt; 1</code>.  This <code class="language-plaintext highlighter-rouge">phi == 1</code> is called a unit root. A good explanation of unit roots can be found <a href="https://www.youtube.com/watch?v=ugOvehrTRRw">here</a>.</p>

<p>ADF extends the test to ARn series and this null hypothesis is that <code class="language-plaintext highlighter-rouge">sum(phi_i)&gt;=1</code>. The difference between the basic DF test and the ADF test is that the latter makes is to account for more lags. The test of whether a series is stationary is a test of whether a series is integrated. An integrated series of order <code class="language-plaintext highlighter-rouge">n</code> is a series that must be differenced <code class="language-plaintext highlighter-rouge">n</code> times to become stationary.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">random</span>
<span class="kn">from</span> <span class="nn">statsmodels.tsa.stattools</span> <span class="kn">import</span> <span class="n">adfuller</span>

<span class="k">def</span> <span class="nf">gen_ts</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">coefs</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">error</span><span class="p">):</span>
  <span class="k">assert</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">coefs</span><span class="p">))</span>
  <span class="k">assert</span><span class="p">(</span><span class="n">count</span> <span class="o">&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">start</span><span class="p">))</span>

  <span class="n">lst</span> <span class="o">=</span> <span class="n">start</span> <span class="o">+</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="n">count</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">start</span><span class="p">))</span>

  <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">start</span><span class="p">),</span> <span class="n">count</span><span class="p">):</span>
    <span class="n">lst</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">random</span><span class="p">.</span><span class="n">uniform</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">)</span> <span class="o">*</span> <span class="n">error</span>
    <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">start</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
      <span class="n">lst</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+=</span> <span class="n">coefs</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">lst</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="n">j</span><span class="p">]</span>

  <span class="k">return</span> <span class="n">lst</span>

<span class="n">v</span> <span class="o">=</span> <span class="n">gen_ts</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">],</span> <span class="mi">100</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span> <span class="c1"># sum of coefficients &lt; 1
</span><span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>

<span class="c1"># automatically test for the best lag to use
# AIC comes from https://en.wikipedia.org/wiki/Akaike_information_criterion
</span><span class="n">p_value</span> <span class="o">=</span> <span class="n">adfuller</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">autolag</span><span class="o">=</span><span class="s">'AIC'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="n">p_value</span><span class="p">)</span>
</code></pre></div></div>

<p>For detecting auto correlation, we introduce two measures:</p>
<ul>
  <li>The <em>ACF</em> - the autocorrelation between the value at <code class="language-plaintext highlighter-rouge">t</code> and <code class="language-plaintext highlighter-rouge">t-n</code>, <em>including</em> the intermediary values, <code class="language-plaintext highlighter-rouge">(t-1 .. t-n-1)</code>. E.g. the effect of prices 2 months ago vs the prices today, including the effect of the prices 2 months ago on the prices 1 month ago and the prices from 1 month ago on today’s prices.</li>
  <li>The <em>PACF</em> - the autocorrelation between the value at <code class="language-plaintext highlighter-rouge">t</code> and <code class="language-plaintext highlighter-rouge">t-n</code> <em>excluding</em> the intermediary values.</li>
</ul>

<p>The ACF is the Pearson correlation between the values <code class="language-plaintext highlighter-rouge">ti</code> and the lagged <code class="language-plaintext highlighter-rouge">ti-k</code> values. For the PACF we do a regression on the values of the timeseries at time <code class="language-plaintext highlighter-rouge">ti</code> on the <code class="language-plaintext highlighter-rouge">ti-k</code> of the form <code class="language-plaintext highlighter-rouge">ti=phi_1*ti_-1 + phi_2*ti_-2 + ... + phi_k*ti_-k + error_term</code> - autoregressive lag <code class="language-plaintext highlighter-rouge">k</code>. <code class="language-plaintext highlighter-rouge">phi_k</code> is our PACF(k).</p>

<p>To plot these a real dataset:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>

<span class="n">lynx_df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s">"/content/drive/MyDrive/Datasets/LYNXdata.csv"</span><span class="p">,</span> 
    <span class="n">index_col</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> 
    <span class="n">header</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> 
    <span class="n">names</span><span class="o">=</span><span class="p">[</span><span class="s">'year'</span><span class="p">,</span> <span class="s">'trappings'</span><span class="p">])</span>
</code></pre></div></div>

<p>And then transform it to time-annotated series:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">lynx_ts</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">Series</span><span class="p">(</span>
    <span class="n">lynx_df</span><span class="p">[</span><span class="s">"trappings"</span><span class="p">].</span><span class="n">values</span><span class="p">,</span> 
    <span class="n">pd</span><span class="p">.</span><span class="n">date_range</span><span class="p">(</span><span class="s">'31/12/1821'</span><span class="p">,</span> 
    <span class="n">periods</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">lynx_df</span><span class="p">),</span> 
    <span class="n">freq</span><span class="o">=</span><span class="s">'A-DEC'</span><span class="p">))</span>

<span class="n">lynx_ts</span><span class="p">.</span><span class="n">plot</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/tsa_lynx.png" alt="Lynx TS" /></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">statsmodels.graphics.tsaplots</span> <span class="kn">import</span> <span class="n">plot_acf</span><span class="p">,</span> <span class="n">plot_pacf</span>
<span class="n">plot_acf</span><span class="p">(</span><span class="n">lynx_ts</span><span class="p">,</span> <span class="n">lags</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
<span class="n">plot_pacf</span><span class="p">(</span><span class="n">lynx_ts</span><span class="p">,</span> <span class="n">lags</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/tsa_acf.png" alt="ACF" /></p>

<p><img src="https://alexandrugris.github.io/assets/tsa_pacf.png" alt="PACF" /></p>

<p>We see in these charts that autocorrelation decreases as we look backwards in the series. This means that we are likely dealing with an auto-regressive process. If we are to build an auto-regressive model for this series we’ll probably consider the coefficients for the 1, 2, 4 and 6 lags. The blue bands are the error margin; everything within the bands are not statistically significant. The coefficient with index 0 is always 1, as it is the correlation of the timeseries with itself.</p>

<p>A series can be stationary, that is the mean is 0 and the variance constant with time, but with no lag auto-correlation, no matter the lag value. Such a series is called white noise and it is not predictable.</p>

<p>Let’s plot some generated time series to explore the PCF and PACF charts for various cases.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">white_noise</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">normal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
<span class="n">plot_acf</span><span class="p">(</span><span class="n">white_noise</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
<span class="n">plot_pacf</span><span class="p">(</span><span class="n">white_noise</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/ts_acf_white_noise.png" alt="ACF White Noise" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_pacf_white_noise.png" alt="PACF White Noise" /></p>

<p>Let’s plot a perfect AR(1) model, with no noise.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ar(1) process
</span><span class="n">ts2</span> <span class="o">=</span> <span class="p">[</span><span class="n">white_noise</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
<span class="n">phi_0</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">phi_1</span> <span class="o">=</span> <span class="mf">0.8</span>
<span class="n">k</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># 0 = perfectly noiseless, 1 = very noisy
</span>
<span class="c1"># Expected value of the timeseries (perfect timeseries converges to this value)
</span><span class="n">miu</span> <span class="o">=</span> <span class="n">phi_0</span> <span class="o">/</span> <span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">phi_1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Expected value: "</span><span class="p">,</span> <span class="n">miu</span><span class="p">)</span>

<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">):</span>
    <span class="c1"># note that without the error term this goes fast to the mean
</span>    <span class="c1"># AR(1)
</span>    <span class="n">ts2</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">phi_0</span> <span class="o">+</span> <span class="n">ts2</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">phi_1</span> <span class="o">+</span> <span class="n">k</span> <span class="o">*</span> <span class="n">white_noise</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>

<span class="n">ts2</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">ts2</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">ts2</span><span class="p">)</span>

<span class="n">plot_acf</span><span class="p">(</span><span class="n">ts2</span><span class="p">,</span> <span class="n">lags</span><span class="o">=</span><span class="mi">40</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
<span class="n">plot_pacf</span><span class="p">(</span><span class="n">ts2</span><span class="p">,</span> <span class="n">lags</span><span class="o">=</span><span class="mi">40</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>

<p>The time series converges to <code class="language-plaintext highlighter-rouge">miu=phi_0 / (1-phi_1) = 50</code>.</p>

<p><img src="https://alexandrugris.github.io/assets/ts_perfect_ar_1.png" alt="Perfect AR converges to expected value" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_perfect_ar_1_acf.png" alt="Perfect AR(1) ACF" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_perfect_ar_1_pacf.png" alt="Perfect AR(1) PACF" /></p>

<p>The same expected value can be observed if we increase the noise:</p>

<p><img src="https://alexandrugris.github.io/assets/ts_ar1_noisy.png" alt="Noisy AR(1)" /></p>

<p>Now, let’s plot an MA (moving average) process:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ts3</span> <span class="o">=</span> <span class="p">[</span><span class="n">white_noise</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
<span class="n">mean</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">phi_1</span> <span class="o">=</span> <span class="mf">0.8</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">):</span>
    <span class="c1"># MA(1) - coef applied to the previous error
</span>    <span class="n">ts3</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">mean</span> <span class="o">+</span> <span class="n">white_noise</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">theta_1</span> <span class="o">*</span> <span class="n">white_noise</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>

<span class="n">ts3</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">ts3</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">ts3</span><span class="p">)</span>

<span class="n">plot_acf</span><span class="p">(</span><span class="n">ts3</span><span class="p">,</span> <span class="n">lags</span><span class="o">=</span><span class="mi">40</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
<span class="n">plot_pacf</span><span class="p">(</span><span class="n">ts3</span><span class="p">,</span> <span class="n">lags</span><span class="o">=</span><span class="mi">40</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/ts_ma1.png" alt="MA(1)" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_ma1_acf.png" alt="MA(1) ACF" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_ma1_pacf.png" alt="MA(1) PACF" /></p>

<p>Unlike an autoregressive process, which has a slowly decaying ACF, the definition of the MA process ensures a sharp cutoff of the ACF for any value greater than q, the order of the MA process. This is because an autoregressive process depends on previous terms, and they incorporate previous impulses to the system, whereas an MA model, incorporating the impulses directly through their value, has a mechanism to stop the impulse propagation from progressing indefinitely. This also means that, forecasting beyond the value lag value of q will only return the mean, since there is no more noise to incorporate.</p>

<p>To summarize, when trying to identify what kind of model we try to fit, we have the following rules:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">AR(p)</code> - ACF falls off slowly, PACF has sharp drop after lag = p</li>
  <li><code class="language-plaintext highlighter-rouge">MA(q)</code> - ACF has a sharp drop after lag = q,  PACF falls off slowly</li>
  <li><code class="language-plaintext highlighter-rouge">ARMA(p,q)</code> - No sharp cutoff, neither for ACF nor for PACF</li>
</ul>

<h3 id="fitting-arima-models">Fitting ARIMA Models</h3>

<p>An ARIMA model has 3 parameters:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">p</code> : the order of autoregression (the summation of the weighted lags) - <code class="language-plaintext highlighter-rouge">AR</code></li>
  <li><code class="language-plaintext highlighter-rouge">d</code> : the degree of differencing (used to make the dataset stationary if it is not) - <code class="language-plaintext highlighter-rouge">I</code></li>
  <li><code class="language-plaintext highlighter-rouge">q</code> : the order of moving average (the summation of the lags of the forecast errors) - <code class="language-plaintext highlighter-rouge">MA</code></li>
</ul>

<p>Examples (<code class="language-plaintext highlighter-rouge">ARIMA(p, d, q)</code>):</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">ARIMA (p=1, d=0, q=0) &lt;=&gt; Y(t) = coef + phi_1 * Y(t-1) + error(t)</code> - lag 1 autoregressive model</li>
  <li><code class="language-plaintext highlighter-rouge">ARIMA (p=1, d=0, q=1) &lt;=&gt; Y(t) = coef + phi_1 * Y(t-1) + theta_1 * error(t-1) + error(t)</code> -</li>
  <li><code class="language-plaintext highlighter-rouge">ARIMA (p=0, d=1, q=0) &lt;=&gt; Y(t) = coef + Y(t-1) + error(t)</code> is a random walk. The differencing equation, <code class="language-plaintext highlighter-rouge">Y(t) - Y(t-1) = coef + error(t)</code>, is needed so that the remaining <code class="language-plaintext highlighter-rouge">ARMA</code> model is applied on stationary data. A random walk is not stationary.</li>
  <li><code class="language-plaintext highlighter-rouge">ARIMA(p=0, d=1, q=1)</code> is an exponential smoothing model</li>
</ul>

<h3 id="arima-model-parameter-selection">ARIMA Model Parameter Selection</h3>

<p>First step is to check for stationarity using the Augmented Dickey-Fuller test. If the data is not stationary, we need to set the <code class="language-plaintext highlighter-rouge">d</code> parameter.</p>

<p>The second step is to set the <code class="language-plaintext highlighter-rouge">p</code> and <code class="language-plaintext highlighter-rouge">q</code> parameters by inspecting the <code class="language-plaintext highlighter-rouge">ACF</code> and <code class="language-plaintext highlighter-rouge">PACF</code> plots, as described before.</p>

<p>To avoid over-fitting, a rule of thumb is to start the parameter selection with the plot that has the least amount of lags outside of the significance bands and then consider the lowest reasonable amount of lags. The ARIMA model is not necessary unique, as we will see in the following example where we start from a complex timeseries which can be approximated very well with a simpler model.</p>

<p>Let’s generate some data:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">arma_series</span> <span class="o">=</span> <span class="p">[</span><span class="n">white_noise</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">white_noise</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span>
<span class="n">m</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">phi_1</span> <span class="o">=</span> <span class="mf">0.4</span>
<span class="n">phi_2</span> <span class="o">=</span> <span class="mf">0.3</span>
<span class="n">theta_1</span> <span class="o">=</span> <span class="mf">0.2</span>
<span class="n">theta_2</span> <span class="o">=</span> <span class="mf">0.2</span>

<span class="c1"># AR(2) I(0) MA(2)
</span><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">100</span><span class="p">):</span>
    <span class="n">arma_series</span><span class="p">.</span><span class="n">append</span><span class="p">(</span> \
        <span class="n">m</span> <span class="o">+</span> \
        <span class="n">arma_series</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">phi_1</span> <span class="o">+</span> <span class="n">arma_series</span> <span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span> <span class="o">*</span> <span class="n">phi_2</span> <span class="o">+</span> \
        <span class="n">white_noise</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">theta_1</span> <span class="o">*</span> <span class="n">white_noise</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">theta_2</span> <span class="o">*</span> <span class="n">white_noise</span> <span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">2</span><span class="p">])</span>

<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">arma_series</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>

<span class="n">adf</span> <span class="o">=</span> <span class="n">adfuller</span><span class="p">(</span><span class="n">arma_series</span><span class="p">,</span> <span class="n">autolag</span><span class="o">=</span><span class="s">'AIC'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="n">adf</span><span class="p">)</span> <span class="c1"># stationary
</span>
<span class="n">arma_series</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">arma_series</span><span class="p">)</span>

<span class="c1"># fit the model
</span><span class="n">plot_acf</span><span class="p">(</span><span class="n">arma_series</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
<span class="n">plot_pacf</span><span class="p">(</span><span class="n">arma_series</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<p><img src="https://alexandrugris.github.io/assets/ts_ts.png" alt="Time Series" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_ts_acf.png" alt="Time Series ACF" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_ts_pacf.png" alt="Time Series PACF" /></p>

<p>We observe a sharp cutoff in the PACF after lag 1 and slow decay in the ACF. This leads to try to fit an <code class="language-plaintext highlighter-rouge">ARIMA(1, 0, 0)</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">statsmodels.tsa.arima.model</span> <span class="kn">import</span> <span class="n">ARIMA</span>

<span class="n">m</span> <span class="o">=</span> <span class="n">ARIMA</span><span class="p">(</span><span class="n">arma_series</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
<span class="n">results</span> <span class="o">=</span> <span class="n">m</span><span class="p">.</span><span class="n">fit</span><span class="p">()</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">arma_series</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">results</span><span class="p">.</span><span class="n">fittedvalues</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"orange"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">results</span><span class="p">.</span><span class="n">arparams</span><span class="p">)</span> <span class="c1"># 0.78
</span></code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/ts_ts_fitted.png" alt="Fitted time series (orange)" /></p>

<p>A pretty good approximation of the initial complex model can be obtained with an AR(1) model. Let’s analyse the residuals to see how much information did we capture in our model and if there are autoregressive behaviors we have missed. In our case residuals are normally distributed as seen in the histogram and proven by the Shapiro test and in the ACF and PACF plots we do not see any autoregressive tendencies we might have missed.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resid</span> <span class="o">=</span> <span class="n">arma_series</span> <span class="o">-</span> <span class="n">results</span><span class="p">.</span><span class="n">fittedvalues</span>
<span class="n">plt</span><span class="p">.</span><span class="n">hist</span><span class="p">(</span><span class="n">resid</span><span class="p">)</span>

<span class="kn">import</span> <span class="nn">scipy.stats</span> <span class="k">as</span> <span class="n">stats</span>
<span class="c1"># visual inspection of the residuals
</span><span class="n">plt</span><span class="p">.</span><span class="n">hist</span><span class="p">(</span><span class="n">resid</span><span class="p">)</span>
<span class="c1"># Shapiro test for normality
</span><span class="n">stats</span><span class="p">.</span><span class="n">shapiro</span><span class="p">(</span><span class="n">stats</span><span class="p">.</span><span class="n">zscore</span><span class="p">(</span><span class="n">resid</span><span class="p">))[</span><span class="mi">1</span><span class="p">]</span>

<span class="c1"># no autocorrelation
</span><span class="n">plot_acf</span><span class="p">(</span><span class="n">resid</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
<span class="n">plot_pacf</span><span class="p">(</span><span class="n">resid</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/ts_residuals.png" alt="Residuals Histogram" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_residuals_acf.png" alt="Residuals ACF" /></p>

<p><img src="https://alexandrugris.github.io/assets/ts_residuals_pacf.png" alt="Residuals PACF" /></p>

<p>Returning to our Lynx timeseries which was shown earlier, let’s train an ARIMA model and see how it fits.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">statsmodels.tsa.arima.model</span> <span class="kn">import</span> <span class="n">ARIMA</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">ARIMA</span><span class="p">(</span><span class="n">lynx_ts</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="p">([</span><span class="mi">1</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="n">results</span> <span class="o">=</span> <span class="n">m</span><span class="p">.</span><span class="n">fit</span><span class="p">()</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">lynx_ts</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">results</span><span class="p">.</span><span class="n">fittedvalues</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"orange"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">results</span><span class="p">.</span><span class="n">arparams</span><span class="p">)</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/tsa_lynx_arima.png" alt="Lynx model fit" /></p>

<p>Exported notebook is <a href="https://alexandrugris.ro/timeseries.html">here</a></p>

<p>A good introductory video <a href="https://www.youtube.com/watch?v=xg2-9DhE5vc&amp;list=PLvcbYUQ5t0UHOLnBzl46_Q6QKtFgfMGc3&amp;index=18">here</a></p>]]></content><author><name></name></author><category term="programming" /><summary type="html"><![CDATA[This post is about statistical models for timeseries analysis in Python. We will cover the ARIMA model to a certain depth.]]></summary></entry><entry><title type="html">Simulated Annealing in Go</title><link href="https://alexandrugris.github.io/programming/2021/02/26/golang-annealing.html" rel="alternate" type="text/html" title="Simulated Annealing in Go" /><published>2021-02-26T08:15:16+01:00</published><updated>2021-02-26T08:15:16+01:00</updated><id>https://alexandrugris.github.io/programming/2021/02/26/golang-annealing</id><content type="html" xml:base="https://alexandrugris.github.io/programming/2021/02/26/golang-annealing.html"><![CDATA[<p>As Go is quickly becoming my favourite programming language, in this post we switch gears and implement an optimization algorithm - simulated annealing. We will solve the travelling salesman problem and, in the process, we will build a desktop app and a bare bones charting library.</p>

<h3 id="simulated-annealing">Simulated Annealing</h3>

<p>Simulated annealing is an optimization algorithm used for solving complex problems where direct algorithmic solutions are hard to find. In cases where gradient descent cannot be used because the optimization function is not continuous we need a different approach, mostly based on trial and error. In such a situation, the solution is to make random moves in the solution space and only accept those moves that offer an optimization over the current state. However such moves can easily converge to a local optimum and get stuck. Therefore, a mechanism in needed to allow escape from the local optimum. Simulated annealing offers a solution to this problem allowing random non-optimal moves to be accepted with decreasing probability, based on a temperature schedule. The solution is borrowed from metalurgy where the steel is forged under slow cooling in order to allow for an optimal alignment of metal particles for increased durability.</p>

<p>For our problem the metric we want to optimize is the total length of the path. In the picture below you can see such a layout with a shortest path determined by the algorithm.</p>

<p><img src="https://alexandrugris.github.io/assets/sim_annealing2.jpg" alt="Simulated Annealing Travelling Salesman" /></p>

<p>For the very same configuration we see the total path length plotted for each iteration.It is interesting to see the inflection point where, after settling on a higher length equilibrium, an local optimum, and a random move, the total length resettles to another, global optimum. We also see how fewer and fewer random moves are accepted, with lower and lower distance increase.</p>

<p><img src="https://alexandrugris.github.io/assets/sim_annealing1.jpg" alt="Simulated Annealing Distance Evolution" /></p>

<h3 id="solution-implementation">Solution Implementation</h3>

<p>The full code is listed below. In short, we are computing the algorithm on a separate thread from the main rendering thread. The config can be reset by pressing <code class="language-plaintext highlighter-rouge">ESC</code>. You can add new points to the path by simply clicking somewhere on the screen. The distance evolution over each iteration can be displayed by pressing the <code class="language-plaintext highlighter-rouge">P</code> key.</p>

<p>The algorithm can be tuned by adjusting:</p>
<ul>
  <li>The total number of iterations</li>
  <li>The temperature decay function</li>
  <li>The function for the probability of acceptance of a bad move</li>
</ul>

<p>The algorithm has also a back step - if after accepting a bad move a better move is not found in a predefined number of steps, we backtrack to the best known configuration.</p>

<p>The move is made by randomly selecting two edges and switching their ends between themselves. Once the swap has been performed, in order fo maintain the path consistency, all edges between the two end points are inverted. This happens in the <code class="language-plaintext highlighter-rouge">ComputeNewPath</code> function.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"GoAI/plt"</span>
	<span class="s">"fmt"</span>
	<span class="s">"github.com/tfriedel6/canvas/sdlcanvas"</span>
	<span class="s">"math"</span>
	<span class="s">"math/rand"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">Point</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">X</span> <span class="kt">float64</span>
	<span class="n">Y</span> <span class="kt">float64</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">Connection</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">Start</span> <span class="kt">int</span>
	<span class="n">End</span>   <span class="kt">int</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="n">Point</span><span class="p">)</span> <span class="n">Subtract</span><span class="p">(</span><span class="n">other</span> <span class="o">*</span><span class="n">Point</span><span class="p">)</span> <span class="n">Point</span> <span class="p">{</span>
	<span class="k">return</span> <span class="n">Point</span><span class="p">{</span>
		<span class="n">X</span><span class="o">:</span> <span class="n">p</span><span class="o">.</span><span class="n">X</span> <span class="o">-</span> <span class="n">other</span><span class="o">.</span><span class="n">X</span><span class="p">,</span>
		<span class="n">Y</span><span class="o">:</span> <span class="n">p</span><span class="o">.</span><span class="n">Y</span> <span class="o">-</span> <span class="n">other</span><span class="o">.</span><span class="n">Y</span><span class="p">,</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="n">Point</span><span class="p">)</span> <span class="n">DistanceTo</span><span class="p">(</span><span class="n">other</span> <span class="o">*</span><span class="n">Point</span><span class="p">)</span> <span class="kt">float64</span> <span class="p">{</span>
	<span class="n">d</span> <span class="o">:=</span> <span class="n">other</span><span class="o">.</span><span class="n">Subtract</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
	<span class="k">return</span> <span class="n">math</span><span class="o">.</span><span class="n">Sqrt</span><span class="p">(</span><span class="n">d</span><span class="o">.</span><span class="n">X</span><span class="o">*</span><span class="n">d</span><span class="o">.</span><span class="n">X</span> <span class="o">+</span> <span class="n">d</span><span class="o">.</span><span class="n">Y</span><span class="o">*</span><span class="n">d</span><span class="o">.</span><span class="n">Y</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">ConnsCollection</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">Points</span> <span class="p">[]</span><span class="n">Point</span>
	<span class="n">Conns</span>  <span class="p">[]</span><span class="n">Connection</span>

	<span class="c">// map ending to index in Conn</span>
	<span class="n">endsIn</span> <span class="p">[]</span><span class="kt">int</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">cc</span> <span class="o">*</span><span class="n">ConnsCollection</span><span class="p">)</span> <span class="n">BuildEndsInMap</span><span class="p">()</span> <span class="p">{</span>

	<span class="k">if</span> <span class="n">cc</span><span class="o">.</span><span class="n">endsIn</span> <span class="o">==</span> <span class="no">nil</span> <span class="o">||</span> <span class="nb">len</span><span class="p">(</span><span class="n">cc</span><span class="o">.</span><span class="n">endsIn</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">cc</span><span class="o">.</span><span class="n">Conns</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">cc</span><span class="o">.</span><span class="n">endsIn</span> <span class="o">=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">cc</span><span class="o">.</span><span class="n">Conns</span><span class="p">))</span>
	<span class="p">}</span>

	<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">cn</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">cc</span><span class="o">.</span><span class="n">Conns</span> <span class="p">{</span>
		<span class="n">cc</span><span class="o">.</span><span class="n">endsIn</span><span class="p">[</span><span class="n">cn</span><span class="o">.</span><span class="n">End</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">cc</span> <span class="o">*</span><span class="n">ConnsCollection</span><span class="p">)</span> <span class="n">ComputeDistance</span><span class="p">()</span> <span class="p">(</span><span class="kt">float64</span><span class="p">,</span> <span class="kt">bool</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">d</span> <span class="o">:=</span> <span class="m">0.0</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">c</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">cc</span><span class="o">.</span><span class="n">Conns</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">Start</span> <span class="o">&gt;=</span> <span class="nb">len</span><span class="p">(</span><span class="n">cc</span><span class="o">.</span><span class="n">Points</span><span class="p">)</span> <span class="o">||</span> <span class="n">c</span><span class="o">.</span><span class="n">End</span> <span class="o">&gt;=</span> <span class="nb">len</span><span class="p">(</span><span class="n">cc</span><span class="o">.</span><span class="n">Points</span><span class="p">)</span> <span class="p">{</span>
			<span class="k">return</span> <span class="o">-</span><span class="m">1</span><span class="p">,</span> <span class="no">false</span>
		<span class="p">}</span>
		<span class="n">d</span> <span class="o">+=</span> <span class="n">cc</span><span class="o">.</span><span class="n">Points</span><span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">Start</span><span class="p">]</span><span class="o">.</span><span class="n">DistanceTo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cc</span><span class="o">.</span><span class="n">Points</span><span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">End</span><span class="p">])</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">d</span><span class="p">,</span> <span class="no">true</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">cc</span> <span class="o">*</span><span class="n">ConnsCollection</span><span class="p">)</span> <span class="n">DuplicateConnectionsTo</span><span class="p">(</span><span class="n">other</span> <span class="o">**</span><span class="n">ConnsCollection</span><span class="p">)</span> <span class="p">{</span>

	<span class="k">if</span> <span class="o">*</span><span class="n">other</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="o">*</span><span class="n">other</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">ConnsCollection</span><span class="p">{</span>
			<span class="n">Points</span><span class="o">:</span> <span class="n">cc</span><span class="o">.</span><span class="n">Points</span><span class="p">,</span>
			<span class="n">Conns</span><span class="o">:</span>  <span class="nb">make</span><span class="p">([]</span><span class="n">Connection</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">cc</span><span class="o">.</span><span class="n">Conns</span><span class="p">)),</span>
			<span class="n">endsIn</span><span class="o">:</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">cc</span><span class="o">.</span><span class="n">endsIn</span><span class="p">)),</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="nb">copy</span><span class="p">((</span><span class="o">*</span><span class="n">other</span><span class="p">)</span><span class="o">.</span><span class="n">Conns</span><span class="p">,</span> <span class="n">cc</span><span class="o">.</span><span class="n">Conns</span><span class="p">)</span>
	<span class="nb">copy</span><span class="p">((</span><span class="o">*</span><span class="n">other</span><span class="p">)</span><span class="o">.</span><span class="n">endsIn</span><span class="p">,</span> <span class="n">cc</span><span class="o">.</span><span class="n">endsIn</span><span class="p">)</span>

<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">cc</span> <span class="o">*</span><span class="n">ConnsCollection</span><span class="p">)</span> <span class="n">ComputeNewPath</span><span class="p">()</span> <span class="kt">float64</span> <span class="p">{</span>

	<span class="n">conns</span> <span class="o">:=</span> <span class="n">cc</span><span class="o">.</span><span class="n">Conns</span>

	<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">conns</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="m">1</span> <span class="p">{</span>
		<span class="k">return</span> <span class="m">0.0</span>
	<span class="p">}</span>

	<span class="n">i1</span> <span class="o">:=</span> <span class="n">rand</span><span class="o">.</span><span class="n">Int</span><span class="p">()</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">conns</span><span class="p">)</span>
	<span class="n">i2</span> <span class="o">:=</span> <span class="n">rand</span><span class="o">.</span><span class="n">Int</span><span class="p">()</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">conns</span><span class="p">)</span>
	<span class="k">if</span> <span class="n">i1</span> <span class="o">==</span> <span class="n">i2</span> <span class="p">{</span>
		<span class="n">i2</span><span class="o">++</span>
		<span class="k">if</span> <span class="n">i2</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">conns</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">i2</span> <span class="o">=</span> <span class="m">0</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="n">p1</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">conns</span><span class="p">[</span><span class="n">i1</span><span class="p">]</span>
	<span class="n">p2</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">conns</span><span class="p">[</span><span class="n">i2</span><span class="p">]</span>

	<span class="c">// swap edges</span>
	<span class="n">p1</span><span class="o">.</span><span class="n">End</span><span class="p">,</span> <span class="n">p2</span><span class="o">.</span><span class="n">Start</span> <span class="o">=</span> <span class="n">p2</span><span class="o">.</span><span class="n">Start</span><span class="p">,</span> <span class="n">p1</span><span class="o">.</span><span class="n">End</span>

	<span class="k">for</span> <span class="n">idx</span> <span class="o">:=</span> <span class="n">p1</span><span class="o">.</span><span class="n">End</span><span class="p">;</span> <span class="n">idx</span> <span class="o">!=</span> <span class="n">p2</span><span class="o">.</span><span class="n">Start</span><span class="p">;</span> <span class="p">{</span>
		<span class="n">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">conns</span><span class="p">[</span><span class="n">cc</span><span class="o">.</span><span class="n">endsIn</span><span class="p">[</span><span class="n">idx</span><span class="p">]]</span>
		<span class="n">c</span><span class="o">.</span><span class="n">Start</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">End</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">End</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">Start</span>
		<span class="n">idx</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">End</span>
	<span class="p">}</span>

	<span class="n">d</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">cc</span><span class="o">.</span><span class="n">ComputeDistance</span><span class="p">()</span>
	<span class="k">return</span> <span class="n">d</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">InitConnectionsFromPoints</span><span class="p">(</span><span class="n">points</span> <span class="p">[]</span><span class="n">Point</span><span class="p">)</span> <span class="o">*</span><span class="n">ConnsCollection</span> <span class="p">{</span>

	<span class="n">c</span> <span class="o">:=</span> <span class="n">ConnsCollection</span><span class="p">{</span>
		<span class="n">Points</span><span class="o">:</span> <span class="n">points</span><span class="p">,</span>
		<span class="n">Conns</span><span class="o">:</span>  <span class="nb">make</span><span class="p">([]</span><span class="n">Connection</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">20</span><span class="p">),</span>
	<span class="p">}</span>

	<span class="c">// crate a path where each point is travelled only once</span>
	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">c</span><span class="o">.</span><span class="n">Points</span> <span class="p">{</span>

		<span class="n">s</span> <span class="o">:=</span> <span class="n">i</span>
		<span class="n">e</span> <span class="o">:=</span> <span class="n">i</span> <span class="o">+</span> <span class="m">1</span>

		<span class="k">if</span> <span class="n">e</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">Points</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">e</span> <span class="o">=</span> <span class="m">0</span>
		<span class="p">}</span>

		<span class="n">c</span><span class="o">.</span><span class="n">Conns</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">Conns</span><span class="p">,</span> <span class="n">Connection</span><span class="p">{</span>
			<span class="n">Start</span><span class="o">:</span> <span class="n">s</span><span class="p">,</span>
			<span class="n">End</span><span class="o">:</span>   <span class="n">e</span><span class="p">,</span>
		<span class="p">})</span>
	<span class="p">}</span>

	<span class="n">c</span><span class="o">.</span><span class="n">BuildEndsInMap</span><span class="p">()</span>

	<span class="k">return</span> <span class="o">&amp;</span><span class="n">c</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">TravellingSalesman</span><span class="p">(</span><span class="n">in</span> <span class="o">&lt;-</span><span class="k">chan</span> <span class="p">[]</span><span class="n">Point</span><span class="p">,</span> <span class="n">out</span> <span class="k">chan</span><span class="o">&lt;-</span> <span class="o">*</span><span class="n">ConnsCollection</span><span class="p">)</span> <span class="p">{</span>

	<span class="k">for</span> <span class="p">{</span>

		<span class="c">// read all points and only start the computation once I finished points</span>
		<span class="n">points</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">in</span>
		<span class="k">for</span> <span class="nb">len</span><span class="p">(</span><span class="n">in</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span> <span class="p">{</span>
			<span class="n">points</span> <span class="o">=</span> <span class="o">&lt;-</span><span class="n">in</span>
		<span class="p">}</span>

		<span class="k">var</span> <span class="n">conns</span><span class="p">,</span> <span class="n">conns2</span><span class="p">,</span> <span class="n">resetPoint</span> <span class="o">*</span><span class="n">ConnsCollection</span>
		<span class="n">conns</span> <span class="o">=</span> <span class="n">InitConnectionsFromPoints</span><span class="p">(</span><span class="n">points</span><span class="p">)</span>
		<span class="n">conns</span><span class="o">.</span><span class="n">DuplicateConnectionsTo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">conns2</span><span class="p">)</span>
		<span class="n">conns</span><span class="o">.</span><span class="n">DuplicateConnectionsTo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">resetPoint</span><span class="p">)</span>

		<span class="n">d</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">conns</span><span class="o">.</span><span class="n">ComputeDistance</span><span class="p">()</span>
		<span class="n">dReset</span> <span class="o">:=</span> <span class="n">d</span>
		<span class="n">MaxDriftFromGlobalMinimum</span> <span class="o">:=</span> <span class="m">10</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">points</span><span class="p">)</span>
		<span class="n">countSinceReset</span> <span class="o">:=</span> <span class="n">MaxDriftFromGlobalMinimum</span>

		<span class="n">MaxIterations</span> <span class="o">:=</span> <span class="m">100000</span>
		<span class="n">distanceEvolution</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">float64</span><span class="p">,</span> <span class="n">MaxIterations</span><span class="p">)</span>

		<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">MaxIterations</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>

			<span class="n">temperature</span> <span class="o">:=</span> <span class="m">0.1</span> <span class="o">*</span> <span class="kt">float64</span><span class="p">(</span><span class="n">MaxIterations</span><span class="o">-</span><span class="n">i</span><span class="p">)</span> <span class="o">/</span> <span class="kt">float64</span><span class="p">(</span><span class="n">MaxIterations</span><span class="p">)</span>
			<span class="n">temperature</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">Pow</span><span class="p">(</span><span class="n">temperature</span><span class="p">,</span> <span class="m">5</span><span class="p">)</span>

			<span class="c">// switch two nodes</span>
			<span class="n">d2</span> <span class="o">:=</span> <span class="n">conns2</span><span class="o">.</span><span class="n">ComputeNewPath</span><span class="p">()</span>

			<span class="c">// found a better move</span>
			<span class="c">// or the temperature is high enough to accept other moves</span>
			<span class="k">if</span> <span class="n">d2</span> <span class="o">&lt;</span> <span class="n">d</span> <span class="o">||</span> <span class="p">(</span><span class="n">d2</span><span class="o">-</span><span class="n">d</span><span class="p">)</span><span class="o">*</span><span class="n">temperature</span> <span class="o">&gt;</span> <span class="n">rand</span><span class="o">.</span><span class="n">Float64</span><span class="p">()</span> <span class="p">{</span>

				<span class="k">if</span> <span class="n">d2</span> <span class="o">&gt;</span> <span class="n">d</span> <span class="o">&amp;&amp;</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="p">(</span><span class="n">MaxIterations</span><span class="o">/</span><span class="m">100</span><span class="p">)</span><span class="o">*</span><span class="m">50</span> <span class="p">{</span>
					<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Accepted bad move: iter: %v, temp: %v, distance: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">temperature</span><span class="p">,</span> <span class="n">d2</span><span class="o">-</span><span class="n">d</span><span class="p">)</span>
				<span class="p">}</span>

				<span class="n">conns2</span><span class="o">.</span><span class="n">BuildEndsInMap</span><span class="p">()</span>
				<span class="n">conns2</span><span class="o">.</span><span class="n">DuplicateConnectionsTo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">conns</span><span class="p">)</span>
				<span class="n">d</span> <span class="o">=</span> <span class="n">d2</span>

				<span class="k">if</span> <span class="n">d</span> <span class="o">&lt;</span> <span class="n">dReset</span> <span class="p">{</span>
					<span class="n">dReset</span> <span class="o">=</span> <span class="n">d</span>
					<span class="n">countSinceReset</span> <span class="o">=</span> <span class="n">MaxDriftFromGlobalMinimum</span>
					<span class="n">conns2</span><span class="o">.</span><span class="n">DuplicateConnectionsTo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">resetPoint</span><span class="p">)</span>
				<span class="p">}</span>

			<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="n">countSinceReset</span> <span class="o">&lt;</span> <span class="m">0</span> <span class="p">{</span>
				<span class="n">d</span> <span class="o">=</span> <span class="n">dReset</span>
				<span class="n">countSinceReset</span> <span class="o">=</span> <span class="n">MaxDriftFromGlobalMinimum</span>
				<span class="n">resetPoint</span><span class="o">.</span><span class="n">DuplicateConnectionsTo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">conns</span><span class="p">)</span>
				<span class="n">resetPoint</span><span class="o">.</span><span class="n">DuplicateConnectionsTo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">conns2</span><span class="p">)</span>
				<span class="c">//fmt.Println("Reset")</span>
			<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
				<span class="n">conns</span><span class="o">.</span><span class="n">DuplicateConnectionsTo</span><span class="p">(</span><span class="o">&amp;</span><span class="n">conns2</span><span class="p">)</span> <span class="c">// re-init conns2</span>
			<span class="p">}</span>

			<span class="n">countSinceReset</span><span class="o">--</span>

			<span class="c">// save for analysis</span>
			<span class="n">distanceEvolution</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">d</span>
		<span class="p">}</span>

		<span class="n">plt</span><span class="o">.</span><span class="n">Reset</span><span class="p">()</span>
		<span class="n">plt</span><span class="o">.</span><span class="n">LinePlot</span><span class="p">(</span><span class="n">distanceEvolution</span><span class="p">,</span> <span class="s">"Distance Evolution"</span><span class="p">,</span> <span class="m">1000</span><span class="p">)</span>

		<span class="k">if</span> <span class="n">d</span> <span class="o">&gt;</span> <span class="n">dReset</span> <span class="p">{</span>
			<span class="n">out</span> <span class="o">&lt;-</span> <span class="n">resetPoint</span>
		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
			<span class="n">out</span> <span class="o">&lt;-</span> <span class="n">conns</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="n">wnd</span><span class="p">,</span> <span class="n">cv</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">sdlcanvas</span><span class="o">.</span><span class="n">CreateWindow</span><span class="p">(</span><span class="m">1280</span><span class="p">,</span> <span class="m">720</span><span class="p">,</span> <span class="s">"Travelling Salesman"</span><span class="p">)</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="nb">panic</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>
	<span class="k">defer</span> <span class="n">wnd</span><span class="o">.</span><span class="n">Destroy</span><span class="p">()</span>

	<span class="n">points</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="n">Point</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
	<span class="n">connections</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="n">Connection</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
	<span class="n">distance</span> <span class="o">:=</span> <span class="m">0.0</span>

	<span class="n">submitPoints</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="p">[]</span><span class="n">Point</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>
	<span class="n">receiveConnections</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="o">*</span><span class="n">ConnsCollection</span><span class="p">)</span>

	<span class="k">go</span> <span class="n">TravellingSalesman</span><span class="p">(</span><span class="n">submitPoints</span><span class="p">,</span> <span class="n">receiveConnections</span><span class="p">)</span>

	<span class="n">wnd</span><span class="o">.</span><span class="n">MouseDown</span> <span class="o">=</span> <span class="k">func</span><span class="p">(</span><span class="n">btn</span> <span class="kt">int</span><span class="p">,</span> <span class="n">x</span> <span class="kt">int</span><span class="p">,</span> <span class="n">y</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
		<span class="c">// on mouse down add new points</span>
		<span class="n">points</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">points</span><span class="p">,</span> <span class="n">Point</span><span class="p">{</span>
			<span class="n">X</span><span class="o">:</span> <span class="kt">float64</span><span class="p">(</span><span class="n">x</span><span class="p">),</span>
			<span class="n">Y</span><span class="o">:</span> <span class="kt">float64</span><span class="p">(</span><span class="n">y</span><span class="p">),</span>
		<span class="p">})</span>

		<span class="c">// send the points to be computed</span>
		<span class="n">submitPoints</span> <span class="o">&lt;-</span> <span class="n">points</span>
	<span class="p">}</span>

	<span class="n">wnd</span><span class="o">.</span><span class="n">KeyDown</span> <span class="o">=</span> <span class="k">func</span><span class="p">(</span><span class="n">scancode</span> <span class="kt">int</span><span class="p">,</span> <span class="n">rn</span> <span class="kt">rune</span><span class="p">,</span> <span class="n">name</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">switch</span> <span class="n">name</span> <span class="p">{</span>
		<span class="k">case</span> <span class="s">"Escape"</span><span class="o">:</span>
			<span class="n">points</span> <span class="o">=</span> <span class="nb">make</span><span class="p">([]</span><span class="n">Point</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
			<span class="n">connections</span> <span class="o">=</span> <span class="nb">make</span><span class="p">([]</span><span class="n">Connection</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
			<span class="n">distance</span> <span class="o">=</span> <span class="m">0.0</span>
		<span class="k">case</span> <span class="s">"KeyP"</span><span class="o">:</span>
			<span class="n">plt</span><span class="o">.</span><span class="n">Execute</span><span class="p">()</span> <span class="c">// show plot only when key is pressed</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="n">wnd</span><span class="o">.</span><span class="n">MainLoop</span><span class="p">(</span><span class="k">func</span><span class="p">()</span> <span class="p">{</span>

		<span class="k">select</span> <span class="p">{</span>

		<span class="k">case</span> <span class="n">cc</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">receiveConnections</span><span class="o">:</span>
			<span class="k">if</span> <span class="n">dd</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">cc</span><span class="o">.</span><span class="n">ComputeDistance</span><span class="p">();</span> <span class="n">ok</span> <span class="p">{</span>
				<span class="n">distance</span> <span class="o">=</span> <span class="n">dd</span>
				<span class="n">connections</span> <span class="o">=</span> <span class="n">cc</span><span class="o">.</span><span class="n">Conns</span>
				<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"New paths with distance %f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">distance</span><span class="p">)</span>
			<span class="p">}</span>

		<span class="k">default</span><span class="o">:</span>

		<span class="p">}</span>

		<span class="c">// background</span>
		<span class="n">w</span><span class="p">,</span> <span class="n">h</span> <span class="o">:=</span> <span class="kt">float64</span><span class="p">(</span><span class="n">cv</span><span class="o">.</span><span class="n">Width</span><span class="p">()),</span> <span class="kt">float64</span><span class="p">(</span><span class="n">cv</span><span class="o">.</span><span class="n">Height</span><span class="p">())</span>
		<span class="n">cv</span><span class="o">.</span><span class="n">SetFillStyle</span><span class="p">(</span><span class="s">"#000"</span><span class="p">)</span>
		<span class="n">cv</span><span class="o">.</span><span class="n">FillRect</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">w</span><span class="p">,</span> <span class="n">h</span><span class="p">)</span>

		<span class="c">// circles</span>
		<span class="n">cv</span><span class="o">.</span><span class="n">SetStrokeStyle</span><span class="p">(</span><span class="s">"#FFF"</span><span class="p">)</span>
		<span class="n">cv</span><span class="o">.</span><span class="n">SetLineWidth</span><span class="p">(</span><span class="m">2</span><span class="p">)</span>
		<span class="n">cv</span><span class="o">.</span><span class="n">SetFillStyle</span><span class="p">(</span><span class="m">255</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)</span>

		<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">c</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">connections</span> <span class="p">{</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">BeginPath</span><span class="p">()</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">MoveTo</span><span class="p">(</span><span class="n">points</span><span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">Start</span><span class="p">]</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">points</span><span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">Start</span><span class="p">]</span><span class="o">.</span><span class="n">Y</span><span class="p">)</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">LineTo</span><span class="p">(</span><span class="n">points</span><span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">End</span><span class="p">]</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">points</span><span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">End</span><span class="p">]</span><span class="o">.</span><span class="n">Y</span><span class="p">)</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">Stroke</span><span class="p">()</span>
		<span class="p">}</span>

		<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">p</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">points</span> <span class="p">{</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">BeginPath</span><span class="p">()</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">Arc</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">Y</span><span class="p">,</span> <span class="m">10</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">math</span><span class="o">.</span><span class="n">Pi</span><span class="o">*</span><span class="m">2</span><span class="p">,</span> <span class="no">false</span><span class="p">)</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">ClosePath</span><span class="p">()</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">Fill</span><span class="p">()</span>
			<span class="n">cv</span><span class="o">.</span><span class="n">Stroke</span><span class="p">()</span>
		<span class="p">}</span>

		<span class="n">cv</span><span class="o">.</span><span class="n">SetFont</span><span class="p">(</span><span class="s">"Righteous-Regular.ttf"</span><span class="p">,</span> <span class="m">12</span><span class="p">)</span>
		<span class="n">cv</span><span class="o">.</span><span class="n">FillText</span><span class="p">(</span><span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"Total distance: %f"</span><span class="p">,</span> <span class="n">distance</span><span class="p">),</span> <span class="m">20</span><span class="p">,</span> <span class="m">20</span><span class="p">)</span>

	<span class="p">})</span>
<span class="p">}</span>

</code></pre></div></div>

<h3 id="easy-charting-from-go">Easy Charting From Go</h3>

<p>Since I couldn’t find any charting library that met my needs, to be easy to use from a desktop application, I’ve decided to build my own. It relies on the excellent matplotlib library from python. The solution is simple: it generates a python script containing all the values I need to plot and, then, it launches that script in a separate process with its own window. For this we are using golang text templates to generate the script. I will extend the library for future use with other types of charts. Below you can see the code:</p>

<p>The template:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import matplotlib.pyplot as plt

 

values=
plt.plot(values)

 

plt.show()
</code></pre></div></div>

<p>The code for generating the template:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">plt</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"fmt"</span>
	<span class="s">"io/ioutil"</span>
	<span class="s">"log"</span>
	<span class="s">"os"</span>
	<span class="s">"os/exec"</span>
	<span class="s">"strings"</span>
	<span class="s">"text/template"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">Plot</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">Type</span>   <span class="kt">string</span>
	<span class="n">Values</span> <span class="p">[][]</span><span class="kt">float64</span>
	<span class="n">Name</span>   <span class="kt">string</span>
	<span class="n">Count</span>  <span class="kt">int</span>
<span class="p">}</span>

<span class="k">var</span> <span class="n">plots</span> <span class="p">[]</span><span class="n">Plot</span> <span class="o">=</span> <span class="no">nil</span>
<span class="k">var</span> <span class="n">tmpl</span> <span class="o">*</span><span class="n">template</span><span class="o">.</span><span class="n">Template</span> <span class="o">=</span> <span class="no">nil</span>

<span class="k">func</span> <span class="n">min</span><span class="p">(</span><span class="n">a</span> <span class="kt">int</span><span class="p">,</span> <span class="n">b</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">a</span> <span class="o">&lt;</span> <span class="n">b</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">a</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">b</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">compressByMean</span><span class="p">(</span><span class="n">count</span> <span class="kt">int</span><span class="p">,</span> <span class="n">arr</span> <span class="p">[]</span><span class="kt">float64</span><span class="p">)</span> <span class="p">[]</span><span class="kt">float64</span> <span class="p">{</span>

	<span class="n">ret</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">float64</span><span class="p">,</span> <span class="n">count</span><span class="p">)</span>
	<span class="n">intvLen</span> <span class="o">:=</span> <span class="nb">len</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="o">/</span> <span class="n">count</span>
	<span class="n">cnt</span> <span class="o">:=</span> <span class="kt">float64</span><span class="p">(</span><span class="n">intvLen</span><span class="p">)</span>

	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">count</span><span class="o">-</span><span class="m">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>

		<span class="n">upperLimit</span> <span class="o">:=</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="m">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">intvLen</span>
		<span class="n">lowerLimit</span> <span class="o">:=</span> <span class="n">i</span> <span class="o">*</span> <span class="n">intvLen</span>

		<span class="n">ret</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">lowerLimit</span><span class="p">]</span> <span class="o">/</span> <span class="n">cnt</span>

		<span class="k">for</span> <span class="n">j</span> <span class="o">:=</span> <span class="n">lowerLimit</span> <span class="o">+</span> <span class="m">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">upperLimit</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span> <span class="p">{</span>
			<span class="n">ret</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+=</span> <span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">/</span> <span class="n">cnt</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="c">// last one is the last value - a hack for the simulated annealing problem</span>
	<span class="n">ret</span><span class="p">[</span><span class="n">count</span><span class="o">-</span><span class="m">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span>
	<span class="k">return</span> <span class="n">ret</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">toPythonArray</span><span class="p">(</span><span class="n">arr</span> <span class="p">[]</span><span class="kt">float64</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="n">sb</span> <span class="o">:=</span> <span class="n">strings</span><span class="o">.</span><span class="n">Builder</span><span class="p">{}</span>
	<span class="n">sb</span><span class="o">.</span><span class="n">WriteString</span><span class="p">(</span><span class="s">"["</span><span class="p">)</span>

	<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">arr</span> <span class="p">{</span>
		<span class="n">sb</span><span class="o">.</span><span class="n">WriteString</span><span class="p">(</span><span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%f"</span><span class="p">,</span> <span class="n">v</span><span class="p">))</span>
		<span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">sb</span><span class="o">.</span><span class="n">WriteString</span><span class="p">(</span><span class="s">", "</span><span class="p">)</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="n">sb</span><span class="o">.</span><span class="n">WriteString</span><span class="p">(</span><span class="s">"]"</span><span class="p">)</span>
	<span class="k">return</span> <span class="n">sb</span><span class="o">.</span><span class="n">String</span><span class="p">()</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">init</span><span class="p">()</span> <span class="p">{</span>

	<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">Getwd</span><span class="p">())</span>

	<span class="n">fn</span> <span class="o">:=</span> <span class="n">template</span><span class="o">.</span><span class="n">FuncMap</span><span class="p">{</span>
		<span class="s">"CompressByMean"</span><span class="o">:</span> <span class="n">compressByMean</span><span class="p">,</span>
		<span class="s">"ToPythonArray"</span><span class="o">:</span>  <span class="n">toPythonArray</span><span class="p">,</span>
	<span class="p">}</span>

	<span class="n">tmpl</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">Must</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="s">"chart_template.gopy"</span><span class="p">)</span><span class="o">.</span><span class="n">Funcs</span><span class="p">(</span><span class="n">fn</span><span class="p">)</span><span class="o">.</span><span class="n">ParseFiles</span><span class="p">(</span><span class="s">"chart_template.gopy"</span><span class="p">))</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">LinePlot</span><span class="p">(</span><span class="n">arr</span> <span class="p">[]</span><span class="kt">float64</span><span class="p">,</span> <span class="n">name</span> <span class="kt">string</span><span class="p">,</span> <span class="n">count</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>

	<span class="n">v</span> <span class="o">:=</span> <span class="n">Plot</span><span class="p">{</span>
		<span class="n">Type</span><span class="o">:</span>   <span class="s">"line"</span><span class="p">,</span>
		<span class="n">Values</span><span class="o">:</span> <span class="nb">make</span><span class="p">([][]</span><span class="kt">float64</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span>
		<span class="n">Name</span><span class="o">:</span>   <span class="n">name</span><span class="p">,</span>
		<span class="n">Count</span><span class="o">:</span>  <span class="n">count</span><span class="p">,</span>
	<span class="p">}</span>

	<span class="n">v</span><span class="o">.</span><span class="n">Values</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span>
	<span class="n">plots</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">plots</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">Reset</span><span class="p">()</span> <span class="p">{</span>
	<span class="c">// clear the plots</span>
	<span class="n">plots</span> <span class="o">=</span> <span class="no">nil</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">Execute</span><span class="p">()</span> <span class="p">{</span>

	<span class="k">var</span> <span class="n">fileName</span> <span class="kt">string</span>

	<span class="k">func</span><span class="p">(</span><span class="n">fn</span> <span class="o">*</span><span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">f</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">ioutil</span><span class="o">.</span><span class="n">TempFile</span><span class="p">(</span><span class="s">"./plots"</span><span class="p">,</span> <span class="s">"plt*.py"</span><span class="p">)</span>

		<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
			<span class="k">return</span>
		<span class="p">}</span>

		<span class="k">defer</span> <span class="n">f</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>
		<span class="o">*</span><span class="n">fn</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">Name</span><span class="p">()</span>

		<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">tmpl</span><span class="o">.</span><span class="n">Execute</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">plots</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">log</span><span class="o">.</span><span class="n">Panic</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
		<span class="p">}</span>

		<span class="n">Reset</span><span class="p">()</span>

	<span class="p">}(</span><span class="o">&amp;</span><span class="n">fileName</span><span class="p">)</span>

	<span class="k">go</span> <span class="k">func</span><span class="p">(</span><span class="n">fileName</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">out</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">exec</span><span class="o">.</span><span class="n">Command</span><span class="p">(</span><span class="s">"python"</span><span class="p">,</span> <span class="n">fileName</span><span class="p">)</span><span class="o">.</span><span class="n">Output</span><span class="p">();</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
			<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>
		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
			<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>
		<span class="p">}</span>
	<span class="p">}(</span><span class="n">fileName</span><span class="p">)</span>

<span class="p">}</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="programming" /><summary type="html"><![CDATA[As Go is quickly becoming my favourite programming language, in this post we switch gears and implement an optimization algorithm - simulated annealing. We will solve the travelling salesman problem and, in the process, we will build a desktop app and a bare bones charting library.]]></summary></entry><entry><title type="html">First Steps In Go - WebSockets</title><link href="https://alexandrugris.github.io/programming/2021/01/23/golang-first-websockets.html" rel="alternate" type="text/html" title="First Steps In Go - WebSockets" /><published>2021-01-23T08:15:16+01:00</published><updated>2021-01-23T08:15:16+01:00</updated><id>https://alexandrugris.github.io/programming/2021/01/23/golang-first-websockets</id><content type="html" xml:base="https://alexandrugris.github.io/programming/2021/01/23/golang-first-websockets.html"><![CDATA[<p>These are my first steps in Go, this time learning how to extend my previous web service with WebSockets. The brower subscribes to changes to a set of products by sending one or more Subscribe or Unsubscribe JSON messages to the service, through a WebSocket connection. Each message contains a series of product IDs. The server maintains the map connection - subscriptions and listens to notifications on product changes from a Postgres database. The post also touches HTTPS, HTTP/2 and server push.</p>

<h3 id="testing">Testing</h3>

<p>We will be building on the foundations laid in the previous blogpost. The code is on GitHub, <a href="https://github.com/alexandrugris/learngolang1/tree/with_websockets">here</a></p>

<p>To open and send commands to our WebSocket server, in Javascript Console, in any browser, you can do:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// connect to our websocket endpoint</span>
<span class="kd">let</span> <span class="nx">ret</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebSocket</span><span class="p">(</span><span class="dl">"</span><span class="s2">ws://localhost:8080/websocket</span><span class="dl">"</span><span class="p">)</span>

<span class="c1">// subscribe to changes to the first 1024 product IDs</span>
<span class="nx">req</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span><span class="na">command</span><span class="p">:</span> <span class="dl">"</span><span class="s2">subscribe</span><span class="dl">"</span><span class="p">,</span> <span class="na">productIDs</span><span class="p">:</span> <span class="p">[...</span><span class="nb">Array</span><span class="p">(</span><span class="mi">1024</span><span class="p">).</span><span class="nx">keys</span><span class="p">()]}))</span>
<span class="nx">req</span><span class="p">.</span><span class="nx">onmessage</span> <span class="o">=</span> <span class="p">(</span><span class="nx">msg</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">msg</span><span class="p">)</span>
</code></pre></div></div>

<p>Later, when we want to test the connection closing, do</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">req</span><span class="p">.</span><span class="nx">close</span><span class="p">()</span>
</code></pre></div></div>

<p>Meanwhile, from a different console, we will be performing <code class="language-plaintext highlighter-rouge">POST</code>, <code class="language-plaintext highlighter-rouge">PUT</code> and <code class="language-plaintext highlighter-rouge">DELETE</code> requests to change the products in the database. These requests are similar to the following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST http://localhost:8080/products
Content-Type: application/json

{
  "productId": 0,
  "manufacturer": "Apple",
  "pricePerUnit": "500EUR",
  "unitsAvailable": 6,
  "productName": "MacBook Pro"
}
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/gowsws1.png" alt="Sending Requests From IntelliJ Ultimate" /></p>

<h3 id="database-changes">Database Changes</h3>

<p>In order to be able to listen to changes in the database, we will use the <code class="language-plaintext highlighter-rouge">LISTEN</code> / <code class="language-plaintext highlighter-rouge">NOTIFY</code> system from Postgresql. We are going to create a trigger which sends <code class="language-plaintext highlighter-rouge">JSON</code> messages whenever an update to the Products table occurs and we are going to initialize a listener in our service code to such events.</p>

<p>The trigger procedure below:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">OR</span> <span class="k">REPLACE</span> <span class="k">FUNCTION</span> <span class="n">notify_event_on_products_update</span><span class="p">()</span> <span class="k">RETURNS</span> <span class="k">TRIGGER</span> <span class="k">AS</span> <span class="err">$$</span>
	<span class="k">DECLARE</span> 
		<span class="k">data</span> <span class="n">json</span><span class="p">;</span>
		<span class="n">notif</span> <span class="n">json</span><span class="p">;</span>
	<span class="k">BEGIN</span>
		<span class="n">IF</span> <span class="p">(</span><span class="n">TG_OP</span> <span class="o">=</span> <span class="s1">'DELETE'</span><span class="p">)</span> <span class="k">THEN</span>
			<span class="k">data</span> <span class="o">=</span> <span class="n">row_to_json</span><span class="p">(</span><span class="k">OLD</span><span class="p">);</span>
		<span class="k">ELSE</span>
			<span class="k">data</span> <span class="o">=</span> <span class="n">row_to_json</span><span class="p">(</span><span class="k">NEW</span><span class="p">);</span>
		<span class="k">END</span> <span class="n">IF</span><span class="p">;</span>

		<span class="n">notif</span> <span class="o">=</span> <span class="n">json_build_object</span><span class="p">(</span>
			<span class="s1">'action'</span><span class="p">,</span> <span class="n">TG_OP</span><span class="p">,</span>
			<span class="s1">'product'</span><span class="p">,</span> <span class="k">data</span> 
		<span class="p">);</span>		
		<span class="n">PERFORM</span> <span class="n">pg_notify</span><span class="p">(</span><span class="s1">'product_change'</span><span class="p">,</span> <span class="n">notif</span><span class="p">::</span><span class="nb">text</span><span class="p">);</span>
	
		<span class="k">RETURN</span> <span class="k">NULL</span><span class="p">;</span>
	<span class="k">END</span>
<span class="err">$$</span> <span class="k">LANGUAGE</span> <span class="n">plpgsql</span><span class="p">;</span>

<span class="k">DROP</span> <span class="k">TRIGGER</span> <span class="n">IF</span> <span class="k">EXISTS</span> <span class="n">products_change_trigger</span> <span class="k">ON</span> <span class="n">products</span><span class="p">;</span>

<span class="k">CREATE</span> <span class="k">TRIGGER</span> <span class="n">products_change_trigger</span> <span class="k">AFTER</span> <span class="k">INSERT</span> <span class="k">OR</span> <span class="k">UPDATE</span> <span class="k">OR</span> <span class="k">DELETE</span> <span class="k">ON</span> <span class="n">products</span>
	<span class="k">FOR</span> <span class="k">EACH</span> <span class="k">ROW</span> <span class="k">EXECUTE</span> <span class="k">PROCEDURE</span> <span class="n">notify_event_on_products_update</span><span class="p">();</span>
</code></pre></div></div>

<p>Now, that we have this procedure, the code that listens to the emitted events, is listed below. It is invoked as a goroutine and acts as a backgorund service. It uses directly the <code class="language-plaintext highlighter-rouge">pq</code> package instead of the <code class="language-plaintext highlighter-rouge">sql</code> package because it relies on native Postgres functionality - the listen/notify mechanism.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// ListenForNotifications should be invoked as a goroutine</span>
<span class="k">func</span> <span class="n">ListenForNotifications</span><span class="p">(</span><span class="n">event</span> <span class="kt">string</span><span class="p">,</span> <span class="n">notif</span> <span class="k">func</span><span class="p">(</span><span class="n">json</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">))</span> <span class="kt">error</span> <span class="p">{</span>

	<span class="n">listener</span> <span class="o">:=</span> <span class="n">pq</span><span class="o">.</span><span class="n">NewListener</span><span class="p">(</span><span class="n">ConnectionString</span><span class="p">,</span> <span class="m">1</span><span class="o">*</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span> <span class="m">10</span><span class="o">*</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">,</span> 
	<span class="k">func</span><span class="p">(</span><span class="n">ev</span> <span class="n">pq</span><span class="o">.</span><span class="n">ListenerEventType</span><span class="p">,</span> <span class="n">err</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">ev</span><span class="p">)</span>
		<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
		<span class="p">}</span>
	<span class="p">})</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">listener</span><span class="o">.</span><span class="n">Listen</span><span class="p">(</span><span class="n">event</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span>
	<span class="p">}</span>

	<span class="k">for</span> <span class="p">{</span>
		<span class="k">select</span> <span class="p">{</span>
		<span class="k">case</span> <span class="n">n</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">listener</span><span class="o">.</span><span class="n">Notify</span><span class="o">:</span>
			<span class="c">// updates</span>
			<span class="n">notif</span><span class="p">([]</span><span class="kt">byte</span><span class="p">(</span><span class="n">n</span><span class="o">.</span><span class="n">Extra</span><span class="p">))</span>

		<span class="k">case</span> <span class="o">&lt;-</span><span class="n">time</span><span class="o">.</span><span class="n">After</span><span class="p">(</span><span class="m">90</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span><span class="o">:</span>

			<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"No events, pinging the connection"</span><span class="p">)</span>
			<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">listener</span><span class="o">.</span><span class="n">Ping</span><span class="p">();</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
				<span class="k">return</span> <span class="n">err</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The snippent which launches listening is in the main function,</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">database</span><span class="o">.</span><span class="n">ListenForNotifications</span><span class="p">(</span><span class="s">"product_change"</span><span class="p">,</span> 
		<span class="n">product</span><span class="o">.</span><span class="n">HandleChangeProductNotification</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}()</span>
</code></pre></div></div>

<h3 id="the-websocket-endpoint">The WebSocket Endpoint</h3>

<p>First, initialize the route. Please notice the <code class="language-plaintext highlighter-rouge">websocket</code> package instead of the <code class="language-plaintext highlighter-rouge">http</code> used above.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">GetHTTPHandlers</span><span class="p">()</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">http</span><span class="o">.</span><span class="n">Handler</span> <span class="p">{</span>
	<span class="k">return</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">http</span><span class="o">.</span><span class="n">Handler</span><span class="p">{</span>
		<span class="s">"/products"</span><span class="o">:</span>  <span class="n">http</span><span class="o">.</span><span class="n">HandlerFunc</span><span class="p">(</span><span class="n">productsHandler</span><span class="p">),</span>
		<span class="s">"/products/"</span><span class="o">:</span> <span class="n">http</span><span class="o">.</span><span class="n">HandlerFunc</span><span class="p">(</span><span class="n">productHandler</span><span class="p">),</span>
		<span class="c">// new handler for websocket</span>
		<span class="c">// notice the websocket. package instead of the http.</span>
		<span class="s">"/websocket"</span><span class="o">:</span> <span class="n">websocket</span><span class="o">.</span><span class="n">Handler</span><span class="p">(</span><span class="n">productChangeWSHandler</span><span class="p">),</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And then the handler itself. Its structure is straight forward:</p>
<ul>
  <li>Exit the function when the connection closes.</li>
  <li>Register a cleanup sequence for when the connection finished.</li>
  <li>Launch a goroutine to listen to incoming messages and EOF error, signifing the connection closing.</li>
  <li>Loop in the same goroutine to send the relevant data to the client.</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">productChangeWSHandler</span><span class="p">(</span><span class="n">ws</span> <span class="o">*</span><span class="n">websocket</span><span class="o">.</span><span class="n">Conn</span><span class="p">)</span> <span class="p">{</span>

	<span class="c">// make the chan buffered so we can receive more messages until we process them</span>
	<span class="n">inMsgChan</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="n">inMessage</span><span class="p">,</span> <span class="m">1024</span><span class="p">)</span>
	<span class="n">inProductsUpdated</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="o">*</span><span class="n">Product</span><span class="p">,</span> <span class="m">1024</span><span class="p">)</span>

	<span class="k">defer</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
		<span class="n">addRemoveSubscription</span> <span class="o">&lt;-</span> <span class="n">chanSubscriptionCmd</span><span class="p">{</span>
			<span class="n">Cmd</span><span class="o">:</span>      <span class="s">"closeconn"</span><span class="p">,</span>
			<span class="n">CommChan</span><span class="o">:</span> <span class="n">inProductsUpdated</span><span class="p">,</span>
		<span class="p">}</span>

		<span class="c">// drain the channel</span>
		<span class="k">for</span> <span class="k">range</span> <span class="n">inProductsUpdated</span> <span class="p">{</span>
		<span class="p">}</span>

	<span class="p">}()</span>

	<span class="k">go</span> <span class="k">func</span><span class="p">(</span><span class="n">ws</span> <span class="o">*</span><span class="n">websocket</span><span class="o">.</span><span class="n">Conn</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">for</span> <span class="p">{</span>
			<span class="n">ws</span><span class="o">.</span><span class="n">MaxPayloadBytes</span> <span class="o">=</span> <span class="m">1024</span> <span class="o">*</span> <span class="m">256</span>
			<span class="k">var</span> <span class="n">msg</span> <span class="n">inMessage</span>

			<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">websocket</span><span class="o">.</span><span class="n">JSON</span><span class="o">.</span><span class="n">Receive</span><span class="p">(</span><span class="n">ws</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">msg</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
				<span class="k">break</span>
			<span class="p">}</span>
			<span class="n">inMsgChan</span> <span class="o">&lt;-</span> <span class="n">msg</span>
		<span class="p">}</span>
		<span class="nb">close</span><span class="p">(</span><span class="n">inMsgChan</span><span class="p">)</span>
	<span class="p">}(</span><span class="n">ws</span><span class="p">)</span>

	<span class="k">for</span> <span class="p">{</span>
		<span class="k">select</span> <span class="p">{</span>
		<span class="k">case</span> <span class="n">msg</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">inMsgChan</span><span class="o">:</span>
			<span class="c">// subscribe - unsubscribe</span>
			<span class="k">if</span> <span class="o">!</span><span class="n">ok</span> <span class="p">{</span>
				<span class="k">return</span> <span class="c">// connection close</span>
			<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>

				<span class="n">addRemoveSubscription</span> <span class="o">&lt;-</span> <span class="n">chanSubscriptionCmd</span><span class="p">{</span>
					<span class="n">Cmd</span><span class="o">:</span>        <span class="n">msg</span><span class="o">.</span><span class="n">Cmd</span><span class="p">,</span>
					<span class="n">ProductIDs</span><span class="o">:</span> <span class="n">msg</span><span class="o">.</span><span class="n">ProductIDs</span><span class="p">,</span>
					<span class="n">CommChan</span><span class="o">:</span>   <span class="n">inProductsUpdated</span><span class="p">,</span>
				<span class="p">}</span>

			<span class="p">}</span>
		<span class="k">case</span> <span class="n">product</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">inProductsUpdated</span><span class="o">:</span>
			<span class="c">// updated products</span>
			<span class="k">if</span> <span class="o">!</span><span class="n">ok</span> <span class="p">{</span>
				<span class="k">return</span>
			<span class="p">}</span>

			<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">websocket</span><span class="o">.</span><span class="n">JSON</span><span class="o">.</span><span class="n">Send</span><span class="p">(</span><span class="n">ws</span><span class="p">,</span> <span class="n">product</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
				<span class="k">return</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="the-algorithm">The Algorithm</h3>

<p>The algorithm is straight forward. It keeps a map of productIDs - channels listening for updates. When an update comes for a specific product ID, all the channels are notified. The interesting part is the use of goroutines for synchronization between processes. The map is local to a goroutine, which is launched as a service when the application starts, and all communications with it happen over channels. There is no shared memory involved and no shared-memory-specific synchronization primitives. The commented ode below.</p>

<p>A notable mention is the fact that clearing the subscription on <code class="language-plaintext highlighter-rouge">connclose</code> event is very slow as the function has to iterate through all the registered products. In a production scenario, I’d keep another map, a reversed index, so that I the relationship channel -&gt; productID is faster to navigate. In our case it would have only make the code longer and less readable.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// shared channel on which the listen-notify db mechanism sends the products</span>
<span class="k">var</span> <span class="n">prodChan</span> <span class="o">=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="n">productNotification</span><span class="p">,</span> <span class="m">1024</span><span class="p">)</span>

<span class="c">// shared channel on which subscriptions are added / removed</span>
<span class="k">var</span> <span class="n">addRemoveSubscription</span> <span class="o">=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="n">chanSubscriptionCmd</span><span class="p">)</span>

<span class="k">func</span> <span class="n">handleDistributionGoroutine</span><span class="p">()</span> <span class="p">{</span>

	<span class="c">// our map, product id -&gt; channels</span>
	<span class="c">// the second map is used because there is no Set in go</span>
	<span class="n">notifyUpdates</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="k">map</span><span class="p">[</span><span class="k">chan</span> <span class="o">*</span><span class="n">Product</span><span class="p">]</span><span class="kt">bool</span><span class="p">)</span>

	<span class="k">for</span> <span class="p">{</span>

		<span class="k">select</span> <span class="p">{</span>

		<span class="k">case</span> <span class="n">incomingProduct</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">prodChan</span><span class="o">:</span>

			<span class="n">notifChans</span><span class="p">,</span> <span class="n">exists</span> <span class="o">:=</span> <span class="n">notifyUpdates</span><span class="p">[</span><span class="n">incomingProduct</span><span class="o">.</span><span class="n">Product</span><span class="o">.</span><span class="n">ProductID</span><span class="p">]</span>
			<span class="k">if</span> <span class="n">exists</span> <span class="o">&amp;&amp;</span> <span class="n">notifChans</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">notifChans</span> <span class="p">{</span>
					<span class="k">if</span> <span class="n">v</span> <span class="p">{</span>
				<span class="c">// this will block all threads in case of a single slow reader</span>
				<span class="c">// the chan will fill and it will not be possible to send other</span>
				<span class="c">// notifications to other readers.</span>
				<span class="c">// option is to do launch each as a separate goroutine</span>
				<span class="c">// but it will not guarantee order at the receiving side</span>
						<span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span> <span class="n">k</span> <span class="o">&lt;-</span> <span class="o">&amp;</span><span class="n">incomingProduct</span><span class="o">.</span><span class="n">Product</span> <span class="p">}()</span>
					<span class="p">}</span>
				<span class="p">}</span>
			<span class="p">}</span>

		<span class="k">case</span> <span class="n">subscription</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">addRemoveSubscription</span><span class="o">:</span>

			<span class="k">switch</span> <span class="n">subscription</span><span class="o">.</span><span class="n">Cmd</span> <span class="p">{</span>

			<span class="k">case</span> <span class="s">"subscribe"</span><span class="o">:</span>
				<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">prd</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">subscription</span><span class="o">.</span><span class="n">ProductIDs</span> <span class="p">{</span>
					<span class="n">ret</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">notifyUpdates</span><span class="p">[</span><span class="n">prd</span><span class="p">]</span>
					<span class="k">if</span> <span class="o">!</span><span class="n">ok</span> <span class="p">{</span>
						<span class="n">ret</span> <span class="o">=</span> <span class="nb">make</span><span class="p">(</span><span class="k">map</span><span class="p">[</span><span class="k">chan</span> <span class="o">*</span><span class="n">Product</span><span class="p">]</span><span class="kt">bool</span><span class="p">)</span>
						<span class="n">notifyUpdates</span><span class="p">[</span><span class="n">prd</span><span class="p">]</span> <span class="o">=</span> <span class="n">ret</span>
					<span class="p">}</span>
					<span class="n">ret</span><span class="p">[</span><span class="n">subscription</span><span class="o">.</span><span class="n">CommChan</span><span class="p">]</span> <span class="o">=</span> <span class="no">true</span>
				<span class="p">}</span>
			<span class="k">case</span> <span class="s">"unsubscribe"</span><span class="o">:</span>
				<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">prd</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">subscription</span><span class="o">.</span><span class="n">ProductIDs</span> <span class="p">{</span>
					<span class="nb">delete</span><span class="p">(</span><span class="n">notifyUpdates</span><span class="p">,</span> <span class="n">prd</span><span class="p">)</span>
				<span class="p">}</span>

			<span class="k">case</span> <span class="s">"closeconn"</span><span class="o">:</span>

				<span class="c">// empty the rest</span>
				<span class="c">// we might wrap the following in a goroutine </span>
				<span class="c">// so we don't block futher incoming messages </span>
				<span class="n">emptyKeys</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>

				<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">notifyUpdates</span> <span class="p">{</span>
					<span class="nb">delete</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">subscription</span><span class="o">.</span><span class="n">CommChan</span><span class="p">)</span>
					<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span> <span class="p">{</span>
						<span class="n">emptyKeys</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">emptyKeys</span><span class="p">,</span> <span class="n">k</span><span class="p">)</span>
					<span class="p">}</span>
				<span class="p">}</span>
				<span class="c">// clear the map of empty keys</span>
				<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">k</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">emptyKeys</span> <span class="p">{</span>
					<span class="nb">delete</span><span class="p">(</span><span class="n">notifyUpdates</span><span class="p">,</span> <span class="n">k</span><span class="p">)</span>
				<span class="p">}</span>
				<span class="nb">close</span><span class="p">(</span><span class="n">subscription</span><span class="o">.</span><span class="n">CommChan</span><span class="p">)</span>

			<span class="k">default</span><span class="o">:</span>
				<span class="n">log</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Unhandled command %v"</span><span class="p">,</span> <span class="n">subscription</span><span class="o">.</span><span class="n">Cmd</span><span class="p">)</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="c">// module init function to start the map service</span>
<span class="k">func</span> <span class="n">init</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">go</span> <span class="n">handleDistributionGoroutine</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/gowsws2.png" alt="Running in IntelliJ" /></p>

<h3 id="https-and-http2">HTTPS and HTTP/2</h3>

<p>Before we launch to production our service, we need to make sure we secure it. In order to accept connections over HTTPS, we need to change our <code class="language-plaintext highlighter-rouge">http.ListenAndServe</code> invocation to <code class="language-plaintext highlighter-rouge">http.ListenAndServeTLS</code> and provide the call a certificate. We are going to generate ourselves such a certificate using <code class="language-plaintext highlighter-rouge">generate_cert.go</code> utility from the <code class="language-plaintext highlighter-rouge">crypto/tls</code> package.</p>

<p><img src="https://alexandrugris.github.io/assets/gowsws3.png" alt="Generating Certificates" /></p>

<p>The <code class="language-plaintext highlighter-rouge">cert.pem</code> file is the certificate with my public key inside while <code class="language-plaintext highlighter-rouge">key.pem</code> is my private key. When the session is established, a shared session key is generated by the client, signed with my public key. It is only I who can decode the shared key using my private key. The shared key is used to symmetrically encrypt messages</p>

<p>If I try to open now my service in Fireforx I get a security warning, but after I accept the warning I can access my service over https.</p>

<p><img src="https://alexandrugris.github.io/assets/gowsws4.png" alt="Running over HTTPS" /></p>

<p>The nice thing about go is that, once I upgrade to HTTPS, I automatically upgrade to HTTP/2. This change comes for free and includes out-of-the-box features such as:</p>
<ul>
  <li>Request multiplexing</li>
  <li>Header compression</li>
  <li>Security by default, since it is running over HTTPS</li>
  <li>Server push</li>
</ul>

<p>From these, we will discuss a bit server push. What server push does is to send to the client assets which were not previously requested before they are requested. An example is when the browser requires <code class="language-plaintext highlighter-rouge">index.html</code> and we know that it is styled with <code class="language-plaintext highlighter-rouge">main.css</code>, append to the request this file also. This saves loading times and browser roundripts. A problem arises when the asset is cached with <code class="language-plaintext highlighter-rouge">Cache-Control</code> in which condition it will get pushed anyway, increasing the size of the request. A simple solution to this issue is to set a cookie when the page is visited and, if the cookie is present, do not send the asset with server push. If the cookie is present we can safely assume the browser has the asset already cached and, if not, it will be requested anyway when it encounters it.</p>

<p>Since not all connections have the ability to do server push, we need to check for this capability. In our handler we do:</p>

<div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">mySeverPushRequest</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>

	<span class="c">// get the pusher interface out of our writer</span>
	<span class="k">if</span> <span class="n">pusher</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">w</span><span class="o">.</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">Pusher</span><span class="p">);</span> <span class="n">ok</span> <span class="p">{</span>

		<span class="k">if</span> <span class="n">cookieAssetsPushed</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">Cookie</span><span class="p">(</span><span class="s">"assetspushed"</span><span class="p">);</span> <span class="n">err</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="c">// set cookie and cache control for one hour</span>
			<span class="n">pusher</span><span class="o">.</span><span class="n">Push</span><span class="p">(</span><span class="s">"main.css"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">http</span><span class="o">.</span><span class="n">PushOptions</span> <span class="p">{</span>
				<span class="n">Header</span><span class="o">:</span> <span class="n">http</span><span class="o">.</span><span class="n">Header</span><span class="p">{</span> 
					<span class="s">"Content-Type"</span><span class="o">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">"text/css"</span><span class="p">}</span> <span class="p">,</span>
					<span class="s">"Cache-Control"</span><span class="o">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">"max-age=3600"</span><span class="p">},</span>
					<span class="p">}</span>
			<span class="p">})</span>

			<span class="c">// 1h expiration time</span>
 			<span class="n">expiration</span> <span class="o">:=</span> <span class="n">time</span><span class="o">.</span><span class="n">Now</span><span class="p">()</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Hour</span><span class="p">)</span>
        	<span class="n">cookie</span> <span class="o">:=</span>    <span class="n">http</span><span class="o">.</span><span class="n">Cookie</span><span class="p">{</span>
				<span class="n">Name</span><span class="o">:</span> 		<span class="s">"assetspushed"</span><span class="p">,</span>
				<span class="n">Value</span><span class="o">:</span>		<span class="s">"true"</span><span class="p">,</span>
				<span class="n">Expires</span><span class="o">:</span>	<span class="n">expiration</span><span class="p">,</span>
			<span class="p">}</span>
        	<span class="n">http</span><span class="o">.</span><span class="n">SetCookie</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cookie</span><span class="p">)</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="c">// continue serving files or executing templates</span>
	<span class="p">[</span><span class="o">.......................</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="programming" /><summary type="html"><![CDATA[These are my first steps in Go, this time learning how to extend my previous web service with WebSockets. The brower subscribes to changes to a set of products by sending one or more Subscribe or Unsubscribe JSON messages to the service, through a WebSocket connection. Each message contains a series of product IDs. The server maintains the map connection - subscriptions and listens to notifications on product changes from a Postgres database. The post also touches HTTPS, HTTP/2 and server push.]]></summary></entry><entry><title type="html">First Steps In Go - Web Services</title><link href="https://alexandrugris.github.io/programming/2021/01/12/golang-first-web-services.html" rel="alternate" type="text/html" title="First Steps In Go - Web Services" /><published>2021-01-12T08:15:16+01:00</published><updated>2021-01-12T08:15:16+01:00</updated><id>https://alexandrugris.github.io/programming/2021/01/12/golang-first-web-services</id><content type="html" xml:base="https://alexandrugris.github.io/programming/2021/01/12/golang-first-web-services.html"><![CDATA[<p>These are my first steps in Go, this time learning how to build web services. The post touches handling requests, json serialization, middleware, logging, database access and concurrency. Websockets and templates will be covered in a future post.</p>

<h3 id="listening-to-incoming-requests">Listening to Incoming Requests</h3>

<p>For building HTTP services, golang comes with all batteries included. There’s no need to install any additional package, everything is already available in the standard library. The APIs are straight forward and the code is short and fast.</p>

<div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"log"</span>
	<span class="s">"net/http"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">customEndpoint</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">w</span><span class="o">.</span><span class="n">Write</span><span class="p">([]</span><span class="n">bytes</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">))</span>
	<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Served."</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>

	<span class="c">// a /custom endpoint</span>
	<span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/custom"</span><span class="p">,</span> <span class="n">customEndpoint</span><span class="p">)</span>

	<span class="c">// listen on localhost, port :8080</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="no">nil</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>

<span class="p">}</span>
</code></pre></div></div>

<h3 id="handling-json">Handling JSON</h3>

<p>If we want to export a field from a structure to JSON, its name has to start with a capital letter, making it a public symbol. Otherwise it will be considered as private and it will not appear in the output string.</p>

<p>We use annotations, which are accessible at runtime through reflection, to specify how the field will be serialized. There is no space between <code class="language-plaintext highlighter-rouge">json</code>, <code class="language-plaintext highlighter-rouge">:</code> and the name. If we skip the annotation, the structure will be serialized with its fields as JSON fields.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="s">"encoding/json"</span>

<span class="k">type</span> <span class="n">Product</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">ProductID</span>      <span class="kt">int</span>    <span class="s">`json:"productId"`</span>
	<span class="n">Manufacturer</span>   <span class="kt">string</span> <span class="s">`json:"manufacturer"`</span>
	<span class="n">PricePerUnit</span>   <span class="kt">string</span> <span class="s">`json:"pricePerUnit"`</span>
	<span class="n">UnitsAvailable</span> <span class="kt">int</span>    <span class="s">`json:"unitsAvailable"`</span>
	<span class="n">ProductName</span>    <span class="kt">string</span> <span class="s">`json:"productName"`</span>
<span class="p">}</span>
</code></pre></div></div>

<p>To serialize JSON we do the following:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">bytes</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">json</span><span class="o">.</span><span class="n">Marshal</span><span class="p">(</span><span class="o">&amp;</span><span class="n">Product</span><span class="p">{</span>
	<span class="n">ProductID</span><span class="o">:</span>      <span class="m">0</span><span class="p">,</span>
	<span class="n">Manufacturer</span><span class="o">:</span>   <span class="s">"Apple"</span><span class="p">,</span>
	<span class="n">PricePerUnit</span><span class="o">:</span>   <span class="s">"2500EUR"</span><span class="p">,</span>
	<span class="n">UnitsAvailable</span><span class="o">:</span> <span class="m">15</span><span class="p">,</span>
	<span class="n">ProductName</span><span class="o">:</span>    <span class="s">"MacBook Pro"</span><span class="p">,</span>
<span class="p">});</span> <span class="n">err</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
	<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Successfully serialized to JSON"</span><span class="p">)</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
	<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Failed to serialize object"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>To deserialize, the following:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">product</span> <span class="o">:=</span> <span class="n">Product</span><span class="p">{}</span>
<span class="n">err</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">Unmarshal</span><span class="p">(</span><span class="n">serializedJSONString</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">product</span><span class="p">)</span>

<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
	<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Could not unmarshal"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="handling-of-http-verbs">Handling of HTTP Verbs</h3>

<p>A simple WebService, handling the GET method, returning a list of products from an in-memory structure.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"encoding/json"</span>
	<span class="s">"fmt"</span>
	<span class="s">"log"</span>
	<span class="s">"math/rand"</span>
	<span class="s">"net/http"</span>
<span class="p">)</span>

<span class="c">// Product type</span>
<span class="k">type</span> <span class="n">Product</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">ProductID</span>      <span class="kt">int</span>    <span class="s">`json:"productId"`</span>
	<span class="n">Manufacturer</span>   <span class="kt">string</span> <span class="s">`json:"manufacturer"`</span>
	<span class="n">PricePerUnit</span>   <span class="kt">string</span> <span class="s">`json:"pricePerUnit"`</span>
	<span class="n">UnitsAvailable</span> <span class="kt">int</span>    <span class="s">`json:"unitsAvailable"`</span>
	<span class="n">ProductName</span>    <span class="kt">string</span> <span class="s">`json:"productName"`</span>
<span class="p">}</span>

<span class="c">// some products stored in memory to play a bit</span>
<span class="k">var</span> <span class="n">products</span> <span class="p">[]</span><span class="o">*</span><span class="n">Product</span>

<span class="c">// endpoint handler</span>
<span class="k">func</span> <span class="n">productsHandler</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>

	<span class="k">switch</span> <span class="n">r</span><span class="o">.</span><span class="n">Method</span> <span class="p">{</span>

	<span class="c">// handling the GET verb</span>
	<span class="k">case</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="o">:</span>
		<span class="n">jsonStr</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">json</span><span class="o">.</span><span class="n">Marshal</span><span class="p">(</span><span class="n">products</span><span class="p">)</span>
		<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
			<span class="n">w</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusInternalServerError</span><span class="p">)</span>
		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
			<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Content-Type"</span><span class="p">,</span> <span class="s">"application/json"</span><span class="p">)</span>
			<span class="n">w</span><span class="o">.</span><span class="n">Write</span><span class="p">([]</span><span class="kt">byte</span><span class="p">(</span><span class="n">jsonStr</span><span class="p">))</span>
		<span class="p">}</span>
	<span class="c">// everything else, not impemented</span>
	<span class="k">default</span><span class="o">:</span>
		<span class="n">w</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusNotImplemented</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>

	<span class="c">// init a few products in memory</span>
	<span class="n">products</span> <span class="o">=</span> <span class="p">[]</span><span class="o">*</span><span class="n">Product</span><span class="p">{}</span>

	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="m">10</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
		<span class="n">products</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">products</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">Product</span><span class="p">{</span>
			<span class="n">ProductID</span><span class="o">:</span>      <span class="n">i</span><span class="p">,</span>
			<span class="n">Manufacturer</span><span class="o">:</span>   <span class="s">"Apple"</span><span class="p">,</span>
			<span class="n">PricePerUnit</span><span class="o">:</span>   <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%vEUR"</span><span class="p">,</span> <span class="p">(</span><span class="n">rand</span><span class="o">.</span><span class="n">Int</span><span class="p">()</span><span class="o">%</span><span class="m">10</span><span class="p">)</span><span class="o">*</span><span class="m">100</span><span class="o">+</span><span class="m">500</span><span class="p">),</span>
			<span class="n">UnitsAvailable</span><span class="o">:</span> <span class="n">rand</span><span class="o">.</span><span class="n">Int</span><span class="p">()</span> <span class="o">%</span> <span class="m">15</span><span class="p">,</span>
			<span class="n">ProductName</span><span class="o">:</span>    <span class="s">"MacBook Pro"</span><span class="p">,</span>
		<span class="p">})</span>
	<span class="p">}</span>

	<span class="c">// handler</span>
	<span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/products"</span><span class="p">,</span> <span class="n">productsHandler</span><span class="p">)</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="no">nil</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And the output:</p>

<p><img src="https://alexandrugris.github.io/assets/gows1.png" alt="Basic Service Running" /></p>

<p>To create a new product, we update the switch block from above with the following:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodPost</span><span class="o">:</span>
	<span class="n">body</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">ioutil</span><span class="o">.</span><span class="n">ReadAll</span><span class="p">(</span>
		<span class="o">&amp;</span><span class="n">io</span><span class="o">.</span><span class="n">LimitedReader</span><span class="p">{</span> <span class="c">// ensure we don't get DoS</span>
			<span class="n">R</span><span class="o">:</span> <span class="n">r</span><span class="o">.</span><span class="n">Body</span><span class="p">,</span>
			<span class="n">N</span><span class="o">:</span> <span class="m">1024</span><span class="p">})</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
		<span class="n">w</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusBadRequest</span><span class="p">)</span>
		<span class="k">return</span>
	<span class="p">}</span>

	<span class="n">product</span> <span class="o">:=</span> <span class="n">Product</span><span class="p">{}</span>
	<span class="n">err</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">Unmarshal</span><span class="p">(</span><span class="n">body</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">product</span><span class="p">)</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="o">||</span> <span class="n">product</span><span class="o">.</span><span class="n">ProductID</span> <span class="o">!=</span> <span class="m">0</span> <span class="p">{</span>

		<span class="k">if</span> <span class="n">err</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">err</span> <span class="o">=</span> <span class="n">errors</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="s">"ProductID should be 0 - if you know the ID, use PUT"</span><span class="p">)</span>
		<span class="p">}</span>

		<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
		<span class="n">w</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusBadRequest</span><span class="p">)</span>
		<span class="k">return</span>
	<span class="p">}</span>

	<span class="c">// give them an increment</span>
	<span class="c">// for now assume products are in incremental order, sorted</span>
	<span class="c">// ensure safe to this data structure</span>
	<span class="n">mtx</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
	<span class="k">defer</span> <span class="n">mtx</span><span class="o">.</span><span class="n">Unlock</span><span class="p">()</span>

	<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">products</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span> <span class="p">{</span>
		<span class="n">product</span><span class="o">.</span><span class="n">ProductID</span> <span class="o">=</span> <span class="n">products</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">products</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">]</span><span class="o">.</span><span class="n">ProductID</span> <span class="o">+</span> <span class="m">1</span>
	<span class="p">}</span>

	<span class="n">products</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">products</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">product</span><span class="p">)</span>
	<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Location"</span><span class="p">,</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"/products/%v"</span><span class="p">,</span> <span class="n">product</span><span class="o">.</span><span class="n">ProductID</span><span class="p">))</span>
	<span class="n">w</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusCreated</span><span class="p">)</span>
</code></pre></div></div>

<p>To test the service we just do</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$curl -D - -X POST -H "Content-Type: application/json" -d '{"productId" : 0, "manufacturer": "Microsoft", "productName": "MS Surface"}' localhost:8080/products
</code></pre></div></div>

<p>And we get the expected response back</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 201 Created
Date: Sat, 16 Jan 2021 09:09:20 GMT
Content-Length: 0
</code></pre></div></div>

<p>What we are going to do now is to implement <code class="language-plaintext highlighter-rouge">GET</code> for a specific product ID and <code class="language-plaintext highlighter-rouge">PUT</code> for updating a specific ID.</p>

<p>To do this, we need a new handler which we add to the main function. This will match the trailing <code class="language-plaintext highlighter-rouge">/</code>.</p>

<div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// handler for GET id and PUT id</span>
<span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/products/"</span><span class="p">,</span> <span class="n">productHandler</span><span class="p">)</span>
</code></pre></div></div>

<p>The URLs that will go to this handler take the form <code class="language-plaintext highlighter-rouge">http://localhost:8080/products/id</code>. We are also going to structure a bit better the handler, so the error handling is factored out of the main function.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">productHandler</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>

	<span class="n">retCode</span> <span class="o">:=</span> <span class="k">func</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>

		<span class="n">pathSegments</span> <span class="o">:=</span> <span class="n">strings</span><span class="o">.</span><span class="n">Split</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Path</span><span class="p">,</span> <span class="s">"/products/"</span><span class="p">)</span>

		<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">pathSegments</span><span class="p">)</span> <span class="o">!=</span> <span class="m">2</span> <span class="p">{</span>
			<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusBadRequest</span>
		<span class="p">}</span>

		<span class="n">productID</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">strconv</span><span class="o">.</span><span class="n">Atoi</span><span class="p">(</span><span class="n">pathSegments</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">pathSegments</span><span class="p">)</span><span class="o">-</span><span class="m">1</span><span class="p">])</span>

		<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusBadRequest</span>
		<span class="p">}</span>

		<span class="n">product</span> <span class="o">:=</span> <span class="n">findProductByID</span><span class="p">(</span><span class="n">productID</span><span class="p">)</span>

		<span class="k">if</span> <span class="n">product</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusNotFound</span>
		<span class="p">}</span>

		<span class="k">switch</span> <span class="n">r</span><span class="o">.</span><span class="n">Method</span> <span class="p">{</span>
		<span class="k">case</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span><span class="o">:</span>

			<span class="n">mtx</span><span class="o">.</span><span class="n">RLock</span><span class="p">()</span>
			<span class="k">defer</span> <span class="n">mtx</span><span class="o">.</span><span class="n">RUnlock</span><span class="p">()</span>

			<span class="n">jsonStr</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">json</span><span class="o">.</span><span class="n">Marshal</span><span class="p">(</span><span class="n">product</span><span class="p">)</span>
			<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusInternalServerError</span>
			<span class="p">}</span>

			<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Content-Type"</span><span class="p">,</span> <span class="s">"application/json"</span><span class="p">)</span>
			<span class="n">w</span><span class="o">.</span><span class="n">Write</span><span class="p">([]</span><span class="kt">byte</span><span class="p">(</span><span class="n">jsonStr</span><span class="p">))</span>

			<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span>

		<span class="k">case</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodPut</span><span class="o">:</span>

			<span class="n">mtx</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
			<span class="k">defer</span> <span class="n">mtx</span><span class="o">.</span><span class="n">Unlock</span><span class="p">()</span>

			<span class="n">body</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">ioutil</span><span class="o">.</span><span class="n">ReadAll</span><span class="p">(</span>
				<span class="o">&amp;</span><span class="n">io</span><span class="o">.</span><span class="n">LimitedReader</span><span class="p">{</span>
					<span class="n">R</span><span class="o">:</span> <span class="n">r</span><span class="o">.</span><span class="n">Body</span><span class="p">,</span>
					<span class="n">N</span><span class="o">:</span> <span class="m">1024</span><span class="p">})</span>

			<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="o">||</span> <span class="n">json</span><span class="o">.</span><span class="n">Unmarshal</span><span class="p">(</span><span class="n">body</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">product</span><span class="p">)</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusBadRequest</span>
			<span class="p">}</span>

			<span class="c">// ensure ID stays the same</span>
			<span class="n">product</span><span class="o">.</span><span class="n">ProductID</span> <span class="o">=</span> <span class="n">productID</span>
			<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusAccepted</span>
		<span class="k">default</span><span class="o">:</span>
			<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusMethodNotAllowed</span>
		<span class="p">}</span>

	<span class="p">}(</span><span class="n">w</span><span class="p">,</span> <span class="n">r</span><span class="p">)</span>

	<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">Method</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Path</span><span class="p">)</span>
	<span class="n">w</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">retCode</span><span class="p">)</span>

<span class="p">}</span>
</code></pre></div></div>

<p>Since we store the products in an array in memory, the find function is as simple as it gets.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">var</span> <span class="n">mtx</span> <span class="n">sync</span><span class="o">.</span><span class="n">RWMutex</span>

<span class="k">func</span> <span class="n">findProductByID</span><span class="p">(</span><span class="n">id</span> <span class="kt">int</span><span class="p">)</span> <span class="o">*</span><span class="n">Product</span> <span class="p">{</span>

	<span class="n">mtx</span><span class="o">.</span><span class="n">RLock</span><span class="p">()</span>
	<span class="k">defer</span> <span class="n">mtx</span><span class="o">.</span><span class="n">RUnlock</span><span class="p">()</span>

	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">p</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">products</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">p</span> <span class="o">!=</span> <span class="no">nil</span> <span class="o">&amp;&amp;</span> <span class="n">p</span><span class="o">.</span><span class="n">ProductID</span> <span class="o">==</span> <span class="n">id</span> <span class="p">{</span>
			<span class="k">return</span> <span class="n">p</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We can test our code easily from the command line invoking</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$curl -D - -X GET http://localhost:8080/products/2
</code></pre></div></div>

<p>and</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$curl -D - -X PUT -H "Content-Type: application/json" -d '{"productId": 0, "manufacturer": "Microsoft", "productName": "MS Surface"}' localhost:8080/products/2
</code></pre></div></div>

<h3 id="adding-middlewares---cors-example">Adding Middlewares - CORS Example</h3>

<p>The http package allows for easy addition of middleware. Such middleware can do things like authentication, caching (memoizing), logging or session management. For this example, we will modify our code to add a CORS middleware.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">corsMiddleware</span><span class="p">(</span><span class="n">handler</span> <span class="n">http</span><span class="o">.</span><span class="n">Handler</span><span class="p">)</span> <span class="n">http</span><span class="o">.</span><span class="n">Handler</span> <span class="p">{</span>

	<span class="k">return</span> <span class="n">http</span><span class="o">.</span><span class="n">HandlerFunc</span><span class="p">(</span><span class="k">func</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>

		<span class="c">// before the handler</span>
		<span class="c">// add the cors middleware headers</span>
		<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Access-Control-Allow-Origin"</span><span class="p">,</span><span class="s">"*"</span><span class="p">)</span>
		<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Access-Control-Allow-Methods"</span><span class="p">,</span><span class="s">"POST, GET, OPTIONS, PUT, DELETE"</span><span class="p">)</span>
		<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Access-Control-Allow-Headers"</span><span class="p">,</span><span class="s">"Accept, Content-Type, Content-Length"</span><span class="p">)</span>
		<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Content-Type"</span><span class="p">,</span> <span class="s">"application/json"</span><span class="p">)</span>

		<span class="k">if</span> <span class="n">r</span><span class="o">.</span><span class="n">Method</span> <span class="o">==</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodOptions</span> <span class="p">{</span>
			<span class="c">// the pre-flight request, make sure it is handled</span>
			<span class="k">return</span>
		<span class="p">}</span>

		<span class="c">// the actual handler</span>
		<span class="n">handler</span><span class="o">.</span><span class="n">ServeHTTP</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">r</span><span class="p">)</span>

		<span class="c">// after handler</span>
	<span class="p">})</span>
<span class="p">}</span>


<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>

	<span class="c">// handler for GET all and POST</span>
	<span class="n">http</span><span class="o">.</span><span class="n">Handle</span><span class="p">(</span><span class="s">"/products"</span><span class="p">,</span> <span class="n">corsMiddleware</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">HandlerFunc</span><span class="p">(</span><span class="n">productsHandler</span><span class="p">)))</span>
	<span class="c">// handler for GET id and PUT</span>
	<span class="n">http</span><span class="o">.</span><span class="n">Handle</span><span class="p">(</span><span class="s">"/products/"</span><span class="p">,</span> <span class="n">corsMiddleware</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">HandlerFunc</span><span class="p">(</span><span class="n">productHandler</span><span class="p">)))</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="no">nil</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The full code, refactored with persitence in an in-memory map can be found <a href="https://github.com/alexandrugris/learngolang1/tree/persistence_in_memory_map">here</a></p>

<h3 id="database-access">Database Access</h3>

<p>First thing, we are going to install Postgres. Assuming docker is installed and running, we do</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$docker run -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres
</code></pre></div></div>

<p>Now I am running the Postgres server portmapped on 5432, with usename <code class="language-plaintext highlighter-rouge">posgres</code> having the password <code class="language-plaintext highlighter-rouge">mysecretpassword</code></p>

<p>To connect to the server we do</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$psql -p 5432 -h localhost -U postgres
</code></pre></div></div>

<p>In the screenshot below, I have also created a database called <code class="language-plaintext highlighter-rouge">products</code> and connected to it using the <code class="language-plaintext highlighter-rouge">\c</code> command</p>

<p><img src="https://alexandrugris.github.io/assets/gows2.png" alt="Postgres running" /></p>

<p>The next thing to do is to get the Postgres Go driver.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$go get github.com/lib/pq
</code></pre></div></div>

<p>At the time of this writing, the recommended database driver for go is <a href="https://github.com/jackc/pgx">pgx</a>. Its authors recommend to use its own API instead of the standard go SQL package due to higher performance in most Postgres-specific scenarios. For the purpose of this demo we will use the standard SQL package though, as it is portable across databases.</p>

<p>In a production scenario we’d also be using an external connection pooler, the recommended solution being <a href="https://www.pgbouncer.org/">pgbouncer</a>. This is because for each new connection to the database server pgsql launches a new Postgres database backend, a new system process, with its launching system heavy and memory intensive.</p>

<p>Let’s dive into the code.</p>

<p>First step is to blank import the driver into our <code class="language-plaintext highlighter-rouge">main.go</code> file. That is because drivers need to register themselves with the SQL package in their <code class="language-plaintext highlighter-rouge">init function</code>(https://golang.org/doc/effective_go.html#init)</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="n">_</span> <span class="s">"github.com/lib/pq"</span>
</code></pre></div></div>

<p>The next step is to declare a database connection pool and open it. The names are exported hence capitalized.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">database</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"database/sql"</span>
	<span class="s">"log"</span>
<span class="p">)</span>

<span class="c">// DbConn is our database connection pool</span>
<span class="k">var</span> <span class="n">DbConn</span> <span class="o">*</span><span class="n">sql</span><span class="o">.</span><span class="n">DB</span>

<span class="c">// Connect opens the connection to the database</span>
<span class="k">func</span> <span class="n">Connect</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">var</span> <span class="n">err</span> <span class="kt">error</span>
	<span class="n">DbConn</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">sql</span><span class="o">.</span><span class="n">Open</span><span class="p">(</span>
	<span class="s">"postgres"</span><span class="p">,</span> 
	<span class="s">"user=pqgotest dbname=products sslmode=verify-full password=mysecretpassword"</span>
	<span class="p">)</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We are going to create the Products table and seed our database, but only if a <code class="language-plaintext highlighter-rouge">--dbinit</code> flag is sent to our executable. We add to our main function the following:</p>

<div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">os</span><span class="o">.</span><span class="n">Args</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="p">]</span> <span class="p">{</span>
	<span class="k">switch</span> <span class="n">v</span> <span class="p">{</span>
	<span class="k">case</span> <span class="s">"--dbinit"</span><span class="o">:</span>
		<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">database</span><span class="o">.</span><span class="n">Init</span><span class="p">();</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>To create our database, we are going to play a bit with reflection and automatically discover the fields from our <code class="language-plaintext highlighter-rouge">Product</code> type. This discovery by reflection is something that all ORMs do. Since we are not going to build our own ORM here, this is the only place where we will play with reflection.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">Init</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>

	<span class="k">if</span> <span class="n">DbConn</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">errors</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="s">"Database not opened"</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="n">query</span> <span class="o">:=</span> <span class="s">"CREATE TABLE IF NOT EXISTS Products ("</span>

	<span class="n">t</span> <span class="o">:=</span> <span class="n">reflect</span><span class="o">.</span><span class="n">TypeOf</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">Product</span><span class="p">{})</span>

	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">t</span><span class="o">.</span><span class="n">NumField</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
		<span class="n">f</span> <span class="o">:=</span> <span class="n">t</span><span class="o">.</span><span class="n">Field</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
		<span class="n">query</span> <span class="o">+=</span> <span class="n">f</span><span class="o">.</span><span class="n">Name</span> <span class="o">+</span> <span class="s">" "</span>

		<span class="k">switch</span> <span class="n">f</span><span class="o">.</span><span class="n">Type</span><span class="o">.</span><span class="n">Name</span><span class="p">()</span> <span class="p">{</span>
		<span class="k">case</span> <span class="s">"string"</span><span class="o">:</span>
			<span class="n">query</span> <span class="o">+=</span> <span class="s">"varchar (100)"</span>
		<span class="k">default</span><span class="o">:</span>
			<span class="n">query</span> <span class="o">+=</span> <span class="n">f</span><span class="o">.</span><span class="n">Type</span><span class="o">.</span><span class="n">Name</span><span class="p">()</span>
		<span class="p">}</span>

		<span class="k">if</span> <span class="n">i</span><span class="o">+</span><span class="m">1</span> <span class="o">&lt;</span> <span class="n">t</span><span class="o">.</span><span class="n">NumField</span><span class="p">()</span> <span class="p">{</span>
			<span class="n">query</span> <span class="o">+=</span> <span class="s">", "</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="n">query</span> <span class="o">+=</span> <span class="s">");"</span>
	<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>

	<span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">DbConn</span><span class="o">.</span><span class="n">Exec</span><span class="p">(</span><span class="n">query</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span>
	<span class="p">}</span>

	<span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">DbConn</span><span class="o">.</span><span class="n">Exec</span><span class="p">(</span><span class="s">"DELETE FROM Products"</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span>
	<span class="p">}</span>

	<span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">DbConn</span><span class="o">.</span><span class="n">Exec</span><span class="p">(</span><span class="s">"ALTER TABLE Products ADD PRIMARY KEY (ProductID)"</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span>
	<span class="p">}</span>

	<span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">DbConn</span><span class="o">.</span><span class="n">Exec</span><span class="p">(</span>
		<span class="s">`CREATE SEQUENCE IF NOT EXISTS pk_product 
		CACHE 100 OWNED BY Product.ProductID`</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The next step is to implement the full <code class="language-plaintext highlighter-rouge">product.Map</code> interface and switch from an in-memory map to database calls. A better name would have been <code class="language-plaintext highlighter-rouge">product.Repository</code> but we will not refactor the code now. The full code can be found <a href="https://github.com/alexandrugris/learngolang1/blob/with_database/product/product.data.go">here</a> and we are only going to exemplify in this blogpost how to create a new product.</p>

<div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="p">(</span><span class="n">m</span> <span class="o">*</span><span class="n">mapInternal</span><span class="p">)</span> <span class="n">CreateNew</span><span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="n">Product</span><span class="p">)</span> <span class="p">{</span>

	<span class="n">stmt</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">database</span><span class="o">.</span><span class="n">DbConn</span><span class="o">.</span><span class="n">Prepare</span><span class="p">(</span><span class="s">`INSERT INTO 
		Products(Manufacturer, PricePerUnit, UnitsAvailable, ProductName, ProductID) 
		VALUES ($1, $2, $3, $4, nextval('pk_product')) RETURNING ProductID`</span><span class="p">)</span>

	<span class="k">if</span> <span class="n">stmt</span> <span class="o">==</span> <span class="no">nil</span> <span class="o">||</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="n">sqlRow</span> <span class="o">:=</span> <span class="n">stmt</span><span class="o">.</span><span class="n">QueryRow</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">Manufacturer</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">PricePerUnit</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">UnitsAvailable</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">ProductName</span><span class="p">)</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">sqlRow</span><span class="o">.</span><span class="n">Scan</span><span class="p">(</span><span class="o">&amp;</span><span class="n">p</span><span class="o">.</span><span class="n">ProductID</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The full source code for this implementation can be found <a href="https://github.com/alexandrugris/learngolang1/tree/with_database">here</a>.</p>

<h3 id="contexts">Contexts</h3>

<p>If we want to setup a timeout for a query, golang provides the <code class="language-plaintext highlighter-rouge">Context</code> mechanism. Each database function has a <code class="language-plaintext highlighter-rouge">Context</code> method. The call to <code class="language-plaintext highlighter-rouge">cancel()</code> when the operation is completed successfully allows to end the context and release all associated resources.</p>

<p>An example below:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="p">(</span><span class="n">m</span> <span class="o">*</span><span class="n">mapInternal</span><span class="p">)</span> <span class="n">GetAll</span><span class="p">()</span> <span class="p">[]</span><span class="o">*</span><span class="n">Product</span> <span class="p">{</span>

	<span class="c">// this will allow the queries to timeout</span>
	<span class="n">ctx</span><span class="p">,</span> <span class="n">cancel</span> <span class="o">:=</span> <span class="n">context</span><span class="o">.</span><span class="n">WithTimeout</span><span class="p">(</span><span class="n">context</span><span class="o">.</span><span class="n">Background</span><span class="p">(),</span> <span class="m">15</span><span class="o">*</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span>
	<span class="k">defer</span> <span class="n">cancel</span><span class="p">()</span>

	<span class="n">results</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">database</span><span class="o">.</span><span class="n">DbConn</span><span class="o">.</span><span class="n">QueryContext</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="s">`
	SELECT 
		ProductID, 
		Manufacturer, 
		PricePerUnit, 
		UnitsAvailable, 
		ProductName 
	FROM Products
	`</span><span class="p">)</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
		<span class="k">return</span> <span class="no">nil</span>
	<span class="p">}</span>

	<span class="k">defer</span> <span class="n">results</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>

	<span class="n">ret</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="o">*</span><span class="n">Product</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">100</span><span class="p">)</span>

	<span class="k">for</span> <span class="n">results</span><span class="o">.</span><span class="n">Next</span><span class="p">()</span> <span class="p">{</span>
		<span class="n">v</span> <span class="o">:=</span> <span class="n">Product</span><span class="p">{}</span>

		<span class="n">results</span><span class="o">.</span><span class="n">Scan</span><span class="p">(</span>
			<span class="o">&amp;</span><span class="n">v</span><span class="o">.</span><span class="n">ProductID</span><span class="p">,</span>
			<span class="o">&amp;</span><span class="n">v</span><span class="o">.</span><span class="n">Manufacturer</span><span class="p">,</span>
			<span class="o">&amp;</span><span class="n">v</span><span class="o">.</span><span class="n">PricePerUnit</span><span class="p">,</span>
			<span class="o">&amp;</span><span class="n">v</span><span class="o">.</span><span class="n">UnitsAvailable</span><span class="p">,</span>
			<span class="o">&amp;</span><span class="n">v</span><span class="o">.</span><span class="n">ProductName</span><span class="p">)</span>

		<span class="n">ret</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">ret</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">v</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="n">ret</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="programming" /><summary type="html"><![CDATA[These are my first steps in Go, this time learning how to build web services. The post touches handling requests, json serialization, middleware, logging, database access and concurrency. Websockets and templates will be covered in a future post.]]></summary></entry><entry><title type="html">First Steps In Go</title><link href="https://alexandrugris.github.io/programming/2021/01/09/golang-first-steps.html" rel="alternate" type="text/html" title="First Steps In Go" /><published>2021-01-09T08:15:16+01:00</published><updated>2021-01-09T08:15:16+01:00</updated><id>https://alexandrugris.github.io/programming/2021/01/09/golang-first-steps</id><content type="html" xml:base="https://alexandrugris.github.io/programming/2021/01/09/golang-first-steps.html"><![CDATA[<p>My first steps in Go, largely based on the Golang tutorial and Internet side searches.</p>

<h3 id="hello-world">Hello World</h3>

<p>Building a very basic hello world project once the go tools are installed is straight forward:</p>

<ul>
  <li>Create a folder named “helloworld”</li>
  <li><code class="language-plaintext highlighter-rouge">cd ./helloworld</code></li>
  <li>Create a file called <code class="language-plaintext highlighter-rouge">main.go</code></li>
  <li>Add the following code into the file</li>
  <li>Save and at the command prompt type <code class="language-plaintext highlighter-rouge">go build</code>. An executable file called <code class="language-plaintext highlighter-rouge">helloworld</code> will be compiled into the folder.</li>
</ul>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"fmt"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A good editor for <code class="language-plaintext highlighter-rouge">go</code> is Visual Studio Code.</p>

<h3 id="language-basics">Language Basics</h3>

<p>The most basic unit of organizing code in go is the function. Below is an example of a function with several parameters, one of each being a callback (function pointer).</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// function receiving function as a parameter</span>
<span class="k">func</span> <span class="n">arrayOpScalar</span><span class="p">(</span><span class="n">array</span> <span class="p">[]</span><span class="kt">float32</span><span class="p">,</span> <span class="n">constant</span> <span class="kt">float32</span><span class="p">,</span> <span class="n">operation</span> <span class="k">func</span><span class="p">(</span><span class="kt">float32</span><span class="p">,</span> <span class="kt">float32</span><span class="p">)</span> <span class="kt">float32</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">array</span> <span class="p">{</span>
		<span class="n">array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">operation</span><span class="p">(</span><span class="n">array</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">constant</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A function can be passed as a parameter, assigned to a variable or returned from another function.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// use the arrayOpScalar function defined above to </span>
<span class="c">// create another function to double the values in an array</span>
<span class="n">doubleFn</span> <span class="o">:=</span> <span class="k">func</span><span class="p">(</span><span class="n">array</span> <span class="p">[]</span><span class="kt">float32</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">arrayOpScalar</span><span class="p">(</span><span class="n">array</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="k">func</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="kt">float32</span><span class="p">)</span> <span class="kt">float32</span> <span class="p">{</span> <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span> <span class="p">})</span>
	<span class="p">}</span>

<span class="n">doubleFn</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
</code></pre></div></div>

<p>But before we do that, let’s look a bit at arrays and slices. Allocating an array goes like this</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">primes</span> <span class="o">:=</span> <span class="p">[</span><span class="m">6</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="m">11</span><span class="p">,</span> <span class="m">13</span><span class="p">}</span>
</code></pre></div></div>

<p>The length is part of the array so it cannot be resized. Slices are views onto arrays, so when a value is modified on the slice it will automatically propagate to the backing array.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="n">s</span> <span class="p">[]</span><span class="kt">int</span> <span class="o">=</span> <span class="n">primes</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="m">4</span><span class="p">]</span>
</code></pre></div></div>

<p>The internal structure of a slice is as follows:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">slice</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="n">array</span> <span class="o">*</span><span class="n">T</span><span class="p">,</span>
  <span class="nb">len</span> <span class="kt">int</span><span class="p">,</span>
  <span class="nb">cap</span> <span class="kt">int</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Length and capacity can be accessed through <code class="language-plaintext highlighter-rouge">len()</code> and <code class="language-plaintext highlighter-rouge">cap()</code>. Therefore, in golang you can do very cool stuff such as converting from a struct to its underlying byte representation. Such operations are useful when, for instance, memory mapping files to arrays of a specified stucture without additional serialization / deseralization. <a href="https://stackoverflow.com/questions/16330490/in-go-how-can-i-convert-a-struct-to-a-byte-array">Here for an extended thread</a></p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">Struct</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="n">p1</span> <span class="kt">int32</span>
  <span class="n">p2</span> <span class="kt">int32</span>
  <span class="n">p3</span> <span class="kt">uint16</span>
  <span class="n">p3</span> <span class="kt">uint16</span>
<span class="p">}</span>

<span class="c">// read in a compile-time constant the size of the struct</span>
<span class="k">const</span> <span class="n">sz</span> <span class="o">=</span> <span class="kt">int</span><span class="p">(</span><span class="n">unsafe</span><span class="o">.</span><span class="n">SizeOf</span><span class="p">(</span><span class="n">Struct</span><span class="p">{}))</span>

<span class="c">// initialize convert the pointer to the struct to an array of bytes </span>
<span class="c">// of the same size as the struct and take a slice to it.</span>
<span class="k">var</span> <span class="n">asByteSlice</span> <span class="p">[]</span><span class="kt">byte</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">[</span><span class="n">sz</span><span class="p">]</span><span class="kt">byte</span><span class="p">)(</span><span class="n">unsafe</span><span class="o">.</span><span class="n">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="n">struct_value</span><span class="p">)))[</span><span class="o">:</span><span class="p">]</span>
</code></pre></div></div>

<p>Slices can contain other slices.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mat3x3</span> <span class="o">:=</span> <span class="p">[][]</span><span class="kt">float32</span><span class="p">{</span>
	<span class="p">[]</span><span class="kt">float32</span><span class="p">{</span><span class="m">1.0</span><span class="p">,</span> <span class="m">0.0</span><span class="p">,</span> <span class="m">0.0</span><span class="p">},</span>
	<span class="p">[]</span><span class="kt">float32</span><span class="p">{</span><span class="m">0.0</span><span class="p">,</span> <span class="m">1.0</span><span class="p">,</span> <span class="m">0.0</span><span class="p">},</span>
	<span class="p">[]</span><span class="kt">float32</span><span class="p">{</span><span class="m">0.0</span><span class="p">,</span> <span class="m">0.0</span><span class="p">,</span> <span class="m">1.0</span><span class="p">},</span>
<span class="p">}</span>
<span class="c">// elements can be accessed</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">board</span><span class="p">[</span><span class="m">0</span><span class="p">][</span><span class="m">0</span><span class="p">])</span>
</code></pre></div></div>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// dynamic allocation of an array of 10 floats</span>
<span class="n">p</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">float32</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>

<span class="c">// dynamically growing the array by appending</span>
<span class="c">// 10 elements with spread operator</span>
<span class="n">p</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">float32</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span><span class="o">...</span><span class="p">)</span>

<span class="c">// looping over indexes in p</span>
<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">p</span> <span class="p">{</span>
	<span class="n">p</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="kt">float32</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Let’s look also at static initialization.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">slice</span> <span class="o">:=</span> <span class="p">[]</span><span class="k">struct</span> <span class="p">{</span> <span class="c">// annonymous struct of two integers</span>
	<span class="n">i1</span> <span class="kt">int</span>
	<span class="n">i2</span> <span class="kt">int</span>
<span class="p">}{</span> <span class="c">// statically initialized</span>
	<span class="p">{</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">},</span>
	<span class="p">{</span><span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">},</span>
	<span class="p">{</span><span class="m">2</span><span class="p">,</span> <span class="m">2</span><span class="p">},</span> <span class="c">// comma at the end is mandatory</span>
<span class="p">}</span>

<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">x</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">slice</span> <span class="p">{</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%v : %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">x</span><span class="o">.</span><span class="n">i1</span><span class="p">,</span> <span class="n">x</span><span class="o">.</span><span class="n">i2</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="custom-types">Custom Types</h3>

<p>In <code class="language-plaintext highlighter-rouge">go</code>, encapsulation is defined at the package level. Everything in a package is public. Exported symbols start with capital letter, everything starting with lowercase is private outside of the package. Let’s define a custom type.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">Vertex</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">X</span> <span class="kt">float64</span>
	<span class="n">Y</span> <span class="kt">float64</span>
	<span class="n">Z</span> <span class="kt">float64</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Initializing a variable of such a type goes like this:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">v</span> <span class="o">:=</span> <span class="n">Vertex</span><span class="p">{</span><span class="m">0.1</span><span class="p">,</span> <span class="m">0.2</span><span class="p">,</span> <span class="m">0.3</span><span class="p">}</span>
</code></pre></div></div>

<p>or</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">v</span> <span class="o">:=</span> <span class="n">Vertex</span> <span class="p">{</span>
<span class="n">X</span> <span class="o">:</span> <span class="m">0.1</span><span class="p">,</span>
<span class="n">Y</span> <span class="o">:</span> <span class="m">0.2</span><span class="p">,</span>
<span class="n">Z</span> <span class="o">:</span> <span class="m">0.3</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We can return a pointer of such a struct. By default the compiler will favor stack allocation, but it does perform escape analysis and, in case the lifetime of an object cannot be determined at compile time it will switch to allocating it on the heap.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">returnPointerToVertex</span><span class="p">()</span> <span class="o">*</span><span class="n">Vertex</span> <span class="p">{</span>
	<span class="k">return</span> <span class="o">&amp;</span><span class="n">Vertex</span><span class="p">{</span><span class="m">1.0</span><span class="p">,</span> <span class="m">2.0</span><span class="p">,</span> <span class="m">3.0</span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now let’s add some methods to the type.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Length computes the vector norm</span>
<span class="k">func</span> <span class="p">(</span><span class="n">v</span> <span class="n">Vertex</span><span class="p">)</span> <span class="n">Length</span><span class="p">()</span> <span class="kt">float64</span> <span class="p">{</span>
	<span class="k">return</span> <span class="n">math</span><span class="o">.</span><span class="n">Sqrt</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">X</span><span class="o">*</span><span class="n">v</span><span class="o">.</span><span class="n">X</span> <span class="o">+</span> <span class="n">v</span><span class="o">.</span><span class="n">Y</span><span class="o">*</span><span class="n">v</span><span class="o">.</span><span class="n">Y</span> <span class="o">+</span> <span class="n">v</span><span class="o">.</span><span class="n">Z</span><span class="o">*</span><span class="n">v</span><span class="o">.</span><span class="n">Z</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Methods with pointer receivers can modify the value to which the receiver points (as scale does here). ince methods often need to modify their receiver, pointer receivers are more common than value receivers. There are two reasons to use a pointer receiver:</p>
<ul>
  <li>The first is so that the method can modify the value that its receiver points to.</li>
  <li>The second is to avoid copying the value on each method call</li>
</ul>

<p>In general, all methods on a given type should have either value or pointer receivers, but not a mixture of both.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Scale scales the vector by a float</span>
<span class="k">func</span> <span class="p">(</span><span class="n">v</span> <span class="o">*</span><span class="n">Vertex</span><span class="p">)</span> <span class="n">Scale</span><span class="p">(</span><span class="n">s</span> <span class="kt">float64</span><span class="p">)</span> <span class="p">{</span>

  <span class="c">// unlike C++ where invoking a method on a nullptr usually results in a crash</span>
  <span class="c">// in golang this is perfectly acceptable</span>
	<span class="k">if</span> <span class="n">v</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Received nill pointer"</span><span class="p">)</span>
		<span class="k">return</span>
	<span class="p">}</span>

	<span class="n">v</span><span class="o">.</span><span class="n">X</span> <span class="o">*=</span> <span class="n">s</span>
	<span class="n">v</span><span class="o">.</span><span class="n">Y</span> <span class="o">*=</span> <span class="n">s</span>
	<span class="n">v</span><span class="o">.</span><span class="n">Z</span> <span class="o">*=</span> <span class="n">s</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Speaking of types, golang does not allow inheritance, but it does have the interface type.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">Scaler</span> <span class="k">interface</span> <span class="p">{</span>
  <span class="n">Scale</span><span class="p">(</span><span class="kt">float64</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Vector automatically implements this interface by simply implementing the respective methods. Now we can do</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">v</span> <span class="o">:=</span> <span class="n">Vertex</span><span class="p">{</span><span class="n">X</span><span class="o">:</span> <span class="m">0.1</span><span class="p">,</span> <span class="n">Y</span><span class="o">:</span> <span class="m">0.2</span><span class="p">,</span> <span class="n">Z</span><span class="o">:</span> <span class="m">0.3</span><span class="p">}</span>
	
<span class="k">var</span> <span class="n">scaler</span> <span class="n">Scaler</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">v</span>
<span class="n">scaler</span><span class="o">.</span><span class="n">Scale</span><span class="p">(</span><span class="m">10.0</span><span class="p">)</span>
</code></pre></div></div>

<p>Beside interfaces that have functions, go offers the empty interface as a method to hold a variable of any type. Any object can be assigned to the empty interface, including the scalar types. Here is an example:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// empty interface</span>
<span class="k">var</span> <span class="n">intf</span> <span class="k">interface</span><span class="p">{}</span> <span class="o">=</span> <span class="s">"Hello World"</span>

<span class="c">// querying the empty interface for the underlying type</span>
<span class="k">if</span> <span class="n">s</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">intf</span><span class="o">.</span><span class="p">(</span><span class="kt">string</span><span class="p">);</span> <span class="n">ok</span> <span class="p">{</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">// i := intf(float32) would panic</span>
<span class="c">// need to test of OK</span>
<span class="k">if</span> <span class="n">i</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">intf</span><span class="o">.</span><span class="p">(</span><span class="kt">float32</span><span class="p">);</span> <span class="n">ok</span> <span class="p">{</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">// a better way is to test with a type switch</span>
<span class="c">// interesting is that v is the value converted to the type, not the type</span>
<span class="k">switch</span> <span class="n">v</span> <span class="o">:=</span> <span class="n">intf</span><span class="o">.</span><span class="p">(</span><span class="k">type</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">case</span> <span class="kt">string</span><span class="o">:</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"It's a string!"</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
	<span class="k">case</span> <span class="kt">int</span><span class="o">:</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"It's an int!"</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
	<span class="k">case</span> <span class="kt">float32</span><span class="o">:</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"It's a float!"</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>When it comes to interfaces, golang offers a very elegant solution to encapsulation and type aggregation. It reminds me of power of <code class="language-plaintext highlighter-rouge">IUnknown::QueryInterface()</code> from <code class="language-plaintext highlighter-rouge">COM</code>, but embedded in the language itself. It relies on type assertions and embedded types.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="c">/*Beautiful method for embedding types and exposing interfaces in Golang. */</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"fmt"</span>
	<span class="s">"unsafe"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">Writer</span> <span class="k">interface</span><span class="p">{</span>
	<span class="n">Write</span><span class="p">(</span><span class="kt">string</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">Reader</span> <span class="k">interface</span><span class="p">{</span>
	<span class="n">Read</span><span class="p">()</span> <span class="kt">string</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">ReaderWriter</span> <span class="k">struct</span><span class="p">{</span>
	<span class="n">Reader</span>
	<span class="n">Writer</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">rwImplType</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">str</span> <span class="kt">string</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">rw</span> <span class="o">*</span><span class="n">rwImplType</span><span class="p">)</span> <span class="n">Read</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="c">// same underlying pointer</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">unsafe</span><span class="o">.</span><span class="n">Pointer</span><span class="p">(</span><span class="n">rw</span><span class="p">))</span>
	<span class="k">return</span> <span class="n">rw</span><span class="o">.</span><span class="n">str</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">rw</span><span class="o">*</span> <span class="n">rwImplType</span><span class="p">)</span> <span class="n">Write</span><span class="p">(</span><span class="n">msg</span> <span class="kt">string</span><span class="p">){</span>
	<span class="c">// same underlying pointer</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">unsafe</span><span class="o">.</span><span class="n">Pointer</span><span class="p">(</span><span class="n">rw</span><span class="p">))</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%v: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">rw</span><span class="o">.</span><span class="n">str</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>

	<span class="c">// Instatiante a concrete implementation</span>
	<span class="n">rwImpl</span> <span class="o">:=</span> <span class="n">rwImplType</span><span class="p">{</span><span class="n">str</span><span class="o">:</span> <span class="s">"Hello World"</span><span class="p">}</span>
	
	<span class="c">// expose it in an aggregate public interface which</span>
	<span class="c">// implements several interfaces</span>
	<span class="n">rwIntf</span> <span class="o">:=</span> <span class="n">ReaderWriter</span><span class="p">{</span>
		<span class="n">Reader</span><span class="o">:</span> <span class="o">&amp;</span><span class="n">rwImpl</span><span class="p">,</span>
		<span class="n">Writer</span><span class="o">:</span> <span class="o">&amp;</span><span class="n">rwImpl</span><span class="p">,</span> <span class="c">// can be another implementation</span>
	<span class="p">}</span>
	
	<span class="k">var</span> <span class="n">anon</span> <span class="k">interface</span><span class="p">{}</span> <span class="o">=</span> <span class="n">rwIntf</span>
	
	<span class="c">// QueryInterface()</span>
	<span class="n">r</span> <span class="o">:=</span> <span class="n">anon</span><span class="o">.</span><span class="p">(</span><span class="n">Reader</span><span class="p">)</span>
	<span class="n">w</span> <span class="o">:=</span> <span class="n">anon</span><span class="o">.</span><span class="p">(</span><span class="n">Writer</span><span class="p">)</span>
	
	<span class="c">// works like a charm :)</span>
	<span class="n">w</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">Read</span><span class="p">())</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Go playground link <a href="https://play.golang.org/p/lBDFao9Yo4G">here</a></p>

<p>Speaking of the <code class="language-plaintext highlighter-rouge">switch</code> construct, it is quite flexible:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// switch</span>
<span class="c">// with declaration and condition</span>
<span class="k">switch</span> <span class="n">os</span> <span class="o">:=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">GOOS</span><span class="p">;</span> <span class="n">os</span> <span class="p">{</span>
	<span class="k">case</span> <span class="s">"linux"</span><span class="o">:</span>
		<span class="k">fallthrough</span>
	<span class="k">case</span> <span class="s">"windows"</span><span class="p">,</span> <span class="s">"darwin"</span><span class="o">:</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Running on %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">os</span><span class="p">)</span>
	<span class="k">default</span><span class="o">:</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Unknown"</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">// with no condition</span>
<span class="k">switch</span> <span class="p">{</span>
	<span class="k">case</span> <span class="n">time</span><span class="o">.</span><span class="n">Now</span><span class="p">()</span><span class="o">.</span><span class="n">Weekday</span><span class="p">()</span><span class="o">.</span><span class="n">String</span><span class="p">()</span> <span class="o">==</span> <span class="s">"Thursday"</span><span class="o">:</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Today is Thursday"</span><span class="p">)</span>
	<span class="k">default</span><span class="o">:</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Today is not Thursday"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="maps">Maps</h3>

<p>Maps can be initialized as literals or created dinamically with <code class="language-plaintext highlighter-rouge">make</code></p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="c">// dynamic instantiation</span>
<span class="n">m</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">Vertex</span><span class="p">,</span> <span class="m">10</span><span class="p">)</span>
<span class="n">m</span><span class="p">[</span><span class="s">"Iasi"</span><span class="p">]</span> <span class="o">=</span> <span class="n">Vertex</span><span class="p">{</span><span class="m">1.0</span><span class="p">,</span> <span class="m">1.0</span><span class="p">,</span> <span class="m">1.0</span><span class="p">}</span>

<span class="c">// check for existence of an element</span>
<span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">exists</span> <span class="o">:=</span> <span class="n">m</span><span class="p">[</span><span class="s">"Cluj"</span><span class="p">];</span> <span class="o">!</span><span class="n">exists</span> <span class="p">{</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Cluj does not exist in the map"</span><span class="p">)</span>
<span class="p">}</span>

<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="s">"Iasi"</span><span class="p">]</span><span class="o">.</span><span class="n">Length</span><span class="p">())</span>

<span class="c">// literal instantiation</span>
<span class="n">m1</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">Vertex</span><span class="p">{</span>
		<span class="s">"Iasi"</span><span class="o">:</span>      <span class="p">{</span><span class="m">1.0</span><span class="p">,</span> <span class="m">1.0</span><span class="p">,</span> <span class="m">1.0</span><span class="p">},</span> <span class="c">// no need to specify Vertex</span>
		<span class="s">"Bucharest"</span><span class="o">:</span> <span class="p">{</span><span class="m">2.0</span><span class="p">,</span> <span class="m">2.0</span><span class="p">,</span> <span class="m">2.0</span><span class="p">},</span>
<span class="p">}</span>

<span class="c">// map can be increased</span>
<span class="n">m1</span><span class="p">[</span><span class="s">"Cluj"</span><span class="p">]</span> <span class="o">=</span> <span class="n">Vertex</span><span class="p">{</span><span class="m">3.0</span><span class="p">,</span> <span class="m">3.0</span><span class="p">,</span> <span class="m">3.0</span><span class="p">}</span>

<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">m1</span><span class="p">)</span>

<span class="c">// remove the element from the map</span>
<span class="nb">delete</span><span class="p">(</span><span class="n">m1</span><span class="p">,</span> <span class="s">"Cluj"</span><span class="p">)</span>

<span class="c">// or also literal instantiation but with no elements</span>
<span class="n">counts</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{}</span>
</code></pre></div></div>

<h3 id="sample-programs">Sample Programs</h3>

<p>Fibonnaci - function returning a function</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="s">"fmt"</span>

<span class="c">// fibonacci is a function that returns</span>
<span class="c">// a function that returns an int.</span>
<span class="k">func</span> <span class="n">fibonacci</span><span class="p">()</span> <span class="k">func</span><span class="p">()</span> <span class="kt">int</span> <span class="p">{</span>
  
  <span class="c">// declaration - initialization</span>
	<span class="n">first</span><span class="p">,</span> <span class="n">second</span> <span class="o">:=</span> <span class="m">0</span><span class="p">,</span> <span class="m">1</span>

	<span class="k">return</span> <span class="k">func</span><span class="p">()</span> <span class="kt">int</span> <span class="p">{</span>
    <span class="n">ret</span> <span class="o">:=</span> <span class="n">first</span> <span class="o">+</span> <span class="n">second</span>
		<span class="n">first</span><span class="p">,</span> <span class="n">second</span> <span class="o">=</span> <span class="n">second</span><span class="p">,</span> <span class="n">ret</span>
		<span class="k">return</span> <span class="n">ret</span>
	<span class="p">}</span>
	
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="n">f</span> <span class="o">:=</span> <span class="n">fibonacci</span><span class="p">()</span>
	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="m">10</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">f</span><span class="p">())</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Error management and the Error interface:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"fmt"</span>
	<span class="s">"math"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">ErrNegativeSqrt</span> <span class="kt">float64</span>

<span class="k">func</span> <span class="p">(</span><span class="n">v</span> <span class="n">ErrNegativeSqrt</span><span class="p">)</span> <span class="n">Error</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="m">0.0</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"Negative sqrt %v"</span><span class="p">,</span> <span class="kt">float64</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="s">""</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">Sqrt</span><span class="p">(</span><span class="n">x</span> <span class="kt">float64</span><span class="p">)</span> <span class="p">(</span><span class="kt">float64</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
	
	<span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="m">0.0</span><span class="p">{</span>
		<span class="k">return</span> <span class="m">0.0</span><span class="p">,</span> <span class="n">ErrNegativeSqrt</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
	<span class="p">}</span>
	
	<span class="n">z</span> <span class="o">:=</span> <span class="m">1.0</span>
	<span class="n">delta</span> <span class="o">:=</span> <span class="n">z</span> <span class="o">*</span> <span class="n">z</span> <span class="o">-</span> <span class="n">x</span>
	
	<span class="k">for</span> <span class="n">math</span><span class="o">.</span><span class="n">Abs</span><span class="p">(</span><span class="n">delta</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">1e-10</span><span class="p">{</span> 
		<span class="n">z</span> <span class="o">-=</span> <span class="n">delta</span> <span class="o">/</span> <span class="p">(</span><span class="m">2.0</span> <span class="o">*</span> <span class="n">z</span><span class="p">)</span>
		<span class="n">delta</span> <span class="o">=</span> <span class="n">z</span> <span class="o">*</span> <span class="n">z</span> <span class="o">-</span> <span class="n">x</span> 
	<span class="p">}</span>
	
	<span class="k">return</span> <span class="n">z</span><span class="p">,</span> <span class="no">nil</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">v</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">Sqrt</span><span class="p">(</span><span class="o">-</span><span class="m">2</span><span class="p">);</span> <span class="n">err</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>	
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>	
	<span class="p">}</span>	
<span class="p">}</span>
</code></pre></div></div>

<p>Reader implementation. An in-memory stream obtained from a string can be created with <code class="language-plaintext highlighter-rouge">r := strings.NewReader("Hello, Reader!")</code></p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"io"</span>
	<span class="s">"os"</span>
	<span class="s">"strings"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">rot13Reader</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">r</span> <span class="n">io</span><span class="o">.</span><span class="n">Reader</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">r</span> <span class="n">rot13Reader</span><span class="p">)</span> <span class="n">Read</span><span class="p">(</span><span class="n">b</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">error</span><span class="p">){</span>
  
  <span class="c">// returns the number of elements read </span>
  <span class="c">// and an error if an error occured</span>
  <span class="c">// the error can be io.EOF which signifies the end of the stream</span>
	<span class="n">n</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">r</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
	
	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">{</span>
		<span class="k">switch</span> <span class="p">{</span>
		<span class="k">case</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="sc">'A'</span> <span class="o">&amp;&amp;</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="sc">'Z'</span><span class="o">:</span> 
			<span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="sc">'A'</span> <span class="o">+</span> <span class="m">13</span><span class="p">)</span> <span class="o">%</span> <span class="m">26</span> <span class="o">+</span> <span class="sc">'A'</span>
		<span class="k">case</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="sc">'a'</span> <span class="o">&amp;&amp;</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="sc">'z'</span><span class="o">:</span>
			<span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="sc">'a'</span> <span class="o">+</span> <span class="m">13</span><span class="p">)</span> <span class="o">%</span> <span class="m">26</span> <span class="o">+</span> <span class="sc">'a'</span>
		<span class="p">}</span>
	<span class="p">}</span>
	
	<span class="k">return</span> <span class="n">n</span><span class="p">,</span> <span class="n">err</span> 
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="n">s</span> <span class="o">:=</span> <span class="n">strings</span><span class="o">.</span><span class="n">NewReader</span><span class="p">(</span><span class="s">"Lbh penpxrq gur pbqr!"</span><span class="p">)</span>
	<span class="n">r</span> <span class="o">:=</span> <span class="n">rot13Reader</span><span class="p">{</span><span class="n">s</span><span class="p">}</span>
	<span class="n">io</span><span class="o">.</span><span class="n">Copy</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">Stdout</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">r</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="concurrency">Concurrency</h3>

<p>Concurrency in go is achieved through goroutines. Goroutines are language constructs which maps M virtual threads to N CPU threads. The runtime has its own scheduler. The preferred way of of sharing state is through channels, although shared memory is also possible thanks to the <code class="language-plaintext highlighter-rouge">sync</code> standard package. Let’s look at two programs below.</p>

<p>The first program compares two BSTs.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"golang.org/x/tour/tree"</span>
	<span class="s">"fmt"</span>
<span class="p">)</span>

<span class="c">// Walk DFSes the tree t sending all values</span>
<span class="c">// to the channel ch.</span>
<span class="k">func</span> <span class="n">Walk_</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">tree</span><span class="o">.</span><span class="n">Tree</span><span class="p">,</span> <span class="n">ch</span> <span class="k">chan</span> <span class="kt">int</span><span class="p">){</span>

	<span class="k">if</span> <span class="n">t</span><span class="o">.</span><span class="n">Left</span> <span class="o">!=</span> <span class="no">nil</span><span class="p">{</span>
		<span class="n">Walk_</span><span class="p">(</span><span class="n">t</span><span class="o">.</span><span class="n">Left</span><span class="p">,</span> <span class="n">ch</span><span class="p">)</span>
	<span class="p">}</span>

  <span class="c">// send the current value to the channel</span>
	<span class="n">ch</span> <span class="o">&lt;-</span> <span class="n">t</span><span class="o">.</span><span class="n">Value</span>

	<span class="k">if</span> <span class="n">t</span><span class="o">.</span><span class="n">Right</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">Walk_</span><span class="p">(</span><span class="n">t</span><span class="o">.</span><span class="n">Right</span><span class="p">,</span> <span class="n">ch</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">Walk</span><span class="p">(</span><span class="n">t</span> <span class="o">*</span><span class="n">tree</span><span class="o">.</span><span class="n">Tree</span><span class="p">,</span> <span class="n">ch</span> <span class="k">chan</span> <span class="kt">int</span><span class="p">){</span>
  <span class="n">Walk_</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">ch</span><span class="p">)</span>

  <span class="c">// close the channel to signal the end of the tree</span>
	<span class="nb">close</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span> 
<span class="p">}</span>

<span class="c">// Same determines whether the trees</span>
<span class="c">// t1 and t2 contain the same values.</span>

<span class="k">func</span> <span class="n">Same</span><span class="p">(</span><span class="n">t1</span><span class="p">,</span> <span class="n">t2</span> <span class="o">*</span><span class="n">tree</span><span class="o">.</span><span class="n">Tree</span><span class="p">)</span> <span class="kt">bool</span><span class="p">{</span>

  <span class="c">// make two channels</span>
	<span class="n">c1</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">int</span><span class="p">)</span>
	<span class="n">c2</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">int</span><span class="p">)</span>

  <span class="c">// launch the two walks in parallel</span>
	<span class="k">go</span> <span class="n">Walk</span><span class="p">(</span><span class="n">t1</span><span class="p">,</span> <span class="n">c1</span><span class="p">)</span>
	<span class="k">go</span> <span class="n">Walk</span><span class="p">(</span><span class="n">t2</span><span class="p">,</span> <span class="n">c2</span><span class="p">)</span>

  <span class="c">// Read one value at a time from each channel</span>
  <span class="c">// and compare them</span>
	<span class="k">for</span> <span class="n">ok1</span><span class="p">,</span> <span class="n">ok2</span> <span class="o">:=</span> <span class="no">true</span><span class="p">,</span> <span class="no">true</span><span class="p">;</span> <span class="n">ok1</span> <span class="o">&amp;&amp;</span> <span class="n">ok2</span><span class="p">;</span>  <span class="p">{</span>
		<span class="k">var</span> <span class="n">v1</span><span class="p">,</span> <span class="n">v2</span> <span class="kt">int</span>

    <span class="c">// when one channel is closed, its OK value is set to false</span>
		<span class="n">v1</span><span class="p">,</span> <span class="n">ok1</span> <span class="o">=</span> <span class="o">&lt;-</span> <span class="n">c1</span>
		<span class="n">v2</span><span class="p">,</span> <span class="n">ok2</span> <span class="o">=</span> <span class="o">&lt;-</span> <span class="n">c2</span>

		<span class="k">if</span> <span class="n">ok1</span> <span class="o">!=</span> <span class="n">ok2</span> <span class="o">||</span> <span class="n">v1</span> <span class="o">!=</span> <span class="n">v2</span><span class="p">{</span>
			<span class="k">return</span> <span class="no">false</span>
		<span class="p">}</span>

	<span class="p">}</span>
	<span class="k">return</span> <span class="no">true</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">Same</span><span class="p">(</span><span class="n">tree</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="m">1</span><span class="p">),</span> <span class="n">tree</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="m">1</span><span class="p">))</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Same tree"</span><span class="p">)</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Not the same tree"</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><em>Notes:</em></p>

<ul>
  <li>A channel cannot be closed twice</li>
  <li>A write from a closed channel results in a panic</li>
  <li>You can check on read if the channel is closed</li>
  <li>Channel operations are blocking. A channel can have a buffer, in which condition the operation becomes blocking only when the buffer is full</li>
  <li>A channel can be read with a <code class="language-plaintext highlighter-rouge">range</code> construct. The range finishes when the sender closes the channel</li>
</ul>

<p>The second program, also part of the golang tour, introduces <code class="language-plaintext highlighter-rouge">sync.WaitGroups</code> to allow waiting for goroutines to finish as well as sending return channels through input channels for safe reply. To allow for concurrent access, the <code class="language-plaintext highlighter-rouge">Cache</code> is implemented as a process (actor) which is accessible only through its input and output channels.</p>

<p>We are going to send a pair to our cache service, <code class="language-plaintext highlighter-rouge">&lt;string - key, return channel&gt;</code>. The return channel solves a concurrency issue: assuming that we have more concurrent readers waiting, we want to ensure we return the result to the reader that sent the message. Since in our case we use a non-buffered write channel, all writes are blocked until a new read is performed and, since the cache is a single threaded, it will not make a new read until the result is communicated, we could have used a single return channel for all the cache requests. However, if we make the write channel buffered, thus allowing for multiple writes, the returns will be mixed.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"fmt"</span>
	<span class="s">"sync"</span>
<span class="p">)</span>

<span class="c">// the wait group is needed to allow all goroutines </span>
<span class="c">// to signal when they finish execution</span>
<span class="c">// and the main goroutine to wait for them</span>
<span class="k">var</span> <span class="n">wg</span> <span class="n">sync</span><span class="o">.</span><span class="n">WaitGroup</span>

<span class="k">type</span> <span class="n">Fetcher</span> <span class="k">interface</span> <span class="p">{</span>
	<span class="n">Fetch</span><span class="p">(</span><span class="n">url</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="n">body</span> <span class="kt">string</span><span class="p">,</span> <span class="n">urls</span> <span class="p">[]</span><span class="kt">string</span><span class="p">,</span> <span class="n">err</span> <span class="kt">error</span><span class="p">)</span>
<span class="p">}</span>
<span class="c">// message including the return channel</span>
<span class="k">type</span> <span class="n">CacheMsg</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">str</span> <span class="kt">string</span>
	<span class="n">out</span> <span class="k">chan</span> <span class="kt">bool</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">Cache</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">in</span> <span class="k">chan</span> <span class="n">CacheMsg</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="n">Cache</span><span class="p">)</span> <span class="n">Init</span><span class="p">(){</span>
	<span class="n">p</span><span class="o">.</span><span class="n">in</span> <span class="o">=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="n">CacheMsg</span><span class="p">)</span>
	<span class="k">go</span> <span class="n">p</span><span class="o">.</span><span class="n">cache</span><span class="p">()</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="n">Cache</span><span class="p">)</span> <span class="n">Test</span><span class="p">(</span><span class="n">s</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
  
  <span class="c">// create a new return channel for each service request</span>
	<span class="n">msg</span> <span class="o">:=</span> <span class="n">CacheMsg</span> <span class="p">{</span>
		<span class="n">str</span><span class="o">:</span> <span class="n">s</span><span class="p">,</span>
		<span class="n">out</span><span class="o">:</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">bool</span><span class="p">),</span>
	<span class="p">}</span>
	
	<span class="n">p</span><span class="o">.</span><span class="n">in</span> <span class="o">&lt;-</span> <span class="n">msg</span>
	<span class="k">return</span> <span class="o">&lt;-</span> <span class="n">msg</span><span class="o">.</span><span class="n">out</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">p</span> <span class="o">*</span><span class="n">Cache</span><span class="p">)</span> <span class="n">cache</span><span class="p">(){</span>
  
  <span class="c">// our cache map</span>
	<span class="n">cache</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">bool</span><span class="p">)</span>
  
  <span class="c">// read messages with range until the channel is closed</span>
	<span class="k">for</span> <span class="n">msg</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">p</span><span class="o">.</span><span class="n">in</span> <span class="p">{</span>
		<span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">exists</span> <span class="o">:=</span> <span class="n">cache</span><span class="p">[</span><span class="n">msg</span><span class="o">.</span><span class="n">str</span><span class="p">];</span> <span class="n">exists</span> <span class="p">{</span>
			<span class="n">msg</span><span class="o">.</span><span class="n">out</span> <span class="o">&lt;-</span> <span class="no">true</span>
		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
			<span class="n">cache</span><span class="p">[</span><span class="n">msg</span><span class="o">.</span><span class="n">str</span><span class="p">]</span> <span class="o">=</span> <span class="no">true</span>
			<span class="n">msg</span><span class="o">.</span><span class="n">out</span> <span class="o">&lt;-</span> <span class="no">false</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>


<span class="k">func</span> <span class="n">Crawl</span><span class="p">(</span><span class="n">url</span> <span class="kt">string</span><span class="p">,</span> <span class="n">depth</span> <span class="kt">int</span><span class="p">,</span> <span class="n">fetcher</span> <span class="n">Fetcher</span><span class="p">,</span> <span class="n">cache</span> <span class="o">*</span><span class="n">Cache</span><span class="p">)</span> <span class="p">{</span>

  <span class="c">// ensure we call wg.Done() when the method exits</span>
  <span class="k">defer</span> <span class="n">wg</span><span class="o">.</span><span class="n">Done</span><span class="p">()</span>

	<span class="k">if</span> <span class="n">depth</span> <span class="o">&lt;=</span> <span class="m">0</span> <span class="p">{</span>
		<span class="k">return</span>
	<span class="p">}</span>
  
  <span class="c">// the url is already in the cache</span>
	<span class="k">if</span> <span class="n">cache</span><span class="o">.</span><span class="n">Test</span><span class="p">(</span><span class="n">url</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">return</span>
	<span class="p">}</span>
	
	<span class="n">body</span><span class="p">,</span> <span class="n">urls</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">fetcher</span><span class="o">.</span><span class="n">Fetch</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
		<span class="k">return</span>
	<span class="p">}</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"found: %s %q</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">body</span><span class="p">)</span>
  
  <span class="c">// add N new goroutines to the WaitGroup</span>
	<span class="n">wg</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">urls</span><span class="p">))</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">u</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">urls</span> <span class="p">{</span>

    <span class="c">// launch crawl goroutines in parallel</span>
		<span class="k">go</span> <span class="n">Crawl</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">depth</span><span class="o">-</span><span class="m">1</span><span class="p">,</span> <span class="n">fetcher</span><span class="p">,</span> <span class="n">cache</span><span class="p">)</span>
	<span class="p">}</span>
	<span class="k">return</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	
	<span class="k">var</span> <span class="n">cache</span> <span class="n">Cache</span>
	<span class="n">cache</span><span class="o">.</span><span class="n">Init</span><span class="p">()</span>
	
	<span class="n">wg</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>
  <span class="n">Crawl</span><span class="p">(</span><span class="s">"https://golang.org/"</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="n">fetcher</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cache</span><span class="p">)</span>
  <span class="c">// wait for all goroutines to finish</span>
	<span class="n">wg</span><span class="o">.</span><span class="n">Wait</span><span class="p">()</span>
<span class="p">}</span>

<span class="c">// fakeFetcher is Fetcher that returns canned results.</span>
<span class="k">type</span> <span class="n">fakeFetcher</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="o">*</span><span class="n">fakeResult</span>

<span class="k">type</span> <span class="n">fakeResult</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">body</span> <span class="kt">string</span>
	<span class="n">urls</span> <span class="p">[]</span><span class="kt">string</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">f</span> <span class="n">fakeFetcher</span><span class="p">)</span> <span class="n">Fetch</span><span class="p">(</span><span class="n">url</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">string</span><span class="p">,</span> <span class="p">[]</span><span class="kt">string</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">res</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">f</span><span class="p">[</span><span class="n">url</span><span class="p">];</span> <span class="n">ok</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">res</span><span class="o">.</span><span class="n">body</span><span class="p">,</span> <span class="n">res</span><span class="o">.</span><span class="n">urls</span><span class="p">,</span> <span class="no">nil</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="no">nil</span><span class="p">,</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Errorf</span><span class="p">(</span><span class="s">"not found: %s"</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">// fetcher is a populated fakeFetcher.</span>
<span class="k">var</span> <span class="n">fetcher</span> <span class="o">=</span> <span class="n">fakeFetcher</span><span class="p">{</span>
	<span class="s">"https://golang.org/"</span><span class="o">:</span> <span class="o">&amp;</span><span class="n">fakeResult</span><span class="p">{</span>
		<span class="s">"The Go Programming Language"</span><span class="p">,</span>
		<span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
			<span class="s">"https://golang.org/pkg/"</span><span class="p">,</span>
			<span class="s">"https://golang.org/cmd/"</span><span class="p">,</span>
		<span class="p">},</span>
	<span class="p">},</span>
	<span class="s">"https://golang.org/pkg/"</span><span class="o">:</span> <span class="o">&amp;</span><span class="n">fakeResult</span><span class="p">{</span>
		<span class="s">"Packages"</span><span class="p">,</span>
		<span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
			<span class="s">"https://golang.org/"</span><span class="p">,</span>
			<span class="s">"https://golang.org/cmd/"</span><span class="p">,</span>
			<span class="s">"https://golang.org/pkg/fmt/"</span><span class="p">,</span>
			<span class="s">"https://golang.org/pkg/os/"</span><span class="p">,</span>
		<span class="p">},</span>
	<span class="p">},</span>
	<span class="s">"https://golang.org/pkg/fmt/"</span><span class="o">:</span> <span class="o">&amp;</span><span class="n">fakeResult</span><span class="p">{</span>
		<span class="s">"Package fmt"</span><span class="p">,</span>
		<span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
			<span class="s">"https://golang.org/"</span><span class="p">,</span>
			<span class="s">"https://golang.org/pkg/"</span><span class="p">,</span>
		<span class="p">},</span>
	<span class="p">},</span>
	<span class="s">"https://golang.org/pkg/os/"</span><span class="o">:</span> <span class="o">&amp;</span><span class="n">fakeResult</span><span class="p">{</span>
		<span class="s">"Package os"</span><span class="p">,</span>
		<span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
			<span class="s">"https://golang.org/"</span><span class="p">,</span>
			<span class="s">"https://golang.org/pkg/"</span><span class="p">,</span>
		<span class="p">},</span>
	<span class="p">},</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The implementation above is more generic as it can be used as a pattern for other kinds of services. In our case, a faster solution would have been to use shared memory protected through a <code class="language-plaintext highlighter-rouge">sync.Mutex</code>, <code class="language-plaintext highlighter-rouge">sync.RWMutex</code> or through a <code class="language-plaintext highlighter-rouge">sync.Map</code>, a concurrent map.</p>

<p>One thing to note - altough all IO operations in go are blocking the current goroutine, the are implemented as asyncio behind the scenes, in a similar manner to which the <code class="language-plaintext highlighter-rouge">cache.Test()</code> method above is blocking.</p>

<h3 id="timers-and-select">Timers and select</h3>

<p>Select allows to listen to multiple channels and block until one of them has data available. Timers in golang are implemented as channels. Signaling to a goroutine to finish its job can be done also though a channel.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"fmt"</span>
	<span class="s">"sync"</span>
	<span class="s">"time"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>

	<span class="n">seconds</span> <span class="o">:=</span> <span class="n">time</span><span class="o">.</span><span class="n">NewTicker</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span>
	<span class="n">minutes</span> <span class="o">:=</span> <span class="n">time</span><span class="o">.</span><span class="n">NewTicker</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Minute</span><span class="p">)</span>

	<span class="n">done</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">bool</span><span class="p">)</span>

	<span class="n">wg</span> <span class="o">:=</span> <span class="n">sync</span><span class="o">.</span><span class="n">WaitGroup</span><span class="p">{}</span>

	<span class="n">wg</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="m">1</span><span class="p">)</span>
	<span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
		<span class="k">for</span> <span class="p">{</span>
			<span class="k">select</span> <span class="p">{</span>
			<span class="k">case</span> <span class="o">&lt;-</span><span class="n">done</span><span class="o">:</span>
				<span class="n">wg</span><span class="o">.</span><span class="n">Done</span><span class="p">()</span>
				<span class="k">return</span> <span class="c">// exit the routine</span>
			<span class="k">case</span> <span class="o">&lt;-</span><span class="n">seconds</span><span class="o">.</span><span class="n">C</span><span class="o">:</span>
				<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Tick"</span><span class="p">)</span>
			<span class="k">case</span> <span class="o">&lt;-</span><span class="n">minutes</span><span class="o">.</span><span class="n">C</span><span class="o">:</span>
				<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Tock"</span><span class="p">)</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}()</span> <span class="c">// immediately invoked goroutine</span>

	<span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Minute</span> <span class="o">*</span> <span class="m">3</span><span class="p">)</span>
	<span class="n">done</span> <span class="o">&lt;-</span> <span class="no">true</span>

	<span class="n">wg</span><span class="o">.</span><span class="n">Wait</span><span class="p">()</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Done."</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="conclusion">Conclusion</h3>

<p>Go is a very beautiful and performant language. It is low level enough to feel like you have power you have in C and it compiles to native code for super fast startup times, performance and interoperability. It is elegant as it does not have unnecessary constructs yet, though its constructs, it encourages at the language level clean code and excellent concurrency.</p>]]></content><author><name></name></author><category term="programming" /><summary type="html"><![CDATA[My first steps in Go, largely based on the Golang tutorial and Internet side searches.]]></summary></entry><entry><title type="html">Programming Problems In C++</title><link href="https://alexandrugris.github.io/programming/2020/10/24/programming-problems-cpp.html" rel="alternate" type="text/html" title="Programming Problems In C++" /><published>2020-10-24T09:15:16+02:00</published><updated>2020-10-24T09:15:16+02:00</updated><id>https://alexandrugris.github.io/programming/2020/10/24/programming-problems-cpp</id><content type="html" xml:base="https://alexandrugris.github.io/programming/2020/10/24/programming-problems-cpp.html"><![CDATA[<p>This post is a collection of several programming problems implemented in C++. It’s good to keep the edge sharp by solving some algorithmic problems from time to time.</p>

<p>Here are all the problems running in the same executable file:</p>

<p><img src="https://alexandrugris.github.io/assets/prog_cpp.png" alt="Running Problems" /></p>

<h3 id="problem-1---zero-or-one-edits-away">Problem 1 - Zero Or One Edits Away</h3>

<p>Write an algorithm that will return true if a string is zero or one edits away from another string. An edit is a letter changed or deleted. The algorithm should be invoked as:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Zero or one edit: "</span> <span class="o">&lt;&lt;</span> <span class="n">zero_one_edits_away</span><span class="p">(</span><span class="s">"hello"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</code></pre></div></div>

<p>or</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Zero or one edit: "</span> <span class="o">&lt;&lt;</span> <span class="n">zero_one_edits_away</span><span class="p">(</span><span class="s">"helo"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</code></pre></div></div>

<p>and both should return true.</p>

<p>The solution below:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="kt">bool</span> <span class="nf">zero_one_edits_away</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">s1</span><span class="p">,</span> <span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">s2</span><span class="p">)</span> <span class="p">{</span>

	<span class="kt">int</span> <span class="n">l1</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">s1</span><span class="p">.</span><span class="n">length</span><span class="p">();</span>
	<span class="kt">int</span> <span class="n">l2</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">s2</span><span class="p">.</span><span class="n">length</span><span class="p">();</span>

	<span class="k">if</span> <span class="p">(</span><span class="n">abs</span><span class="p">(</span><span class="n">l1</span> <span class="o">-</span> <span class="n">l2</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span>
		<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>

	<span class="kt">int</span> <span class="n">edit_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">l1</span> <span class="o">&amp;&amp;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">l2</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">,</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">s1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">s2</span><span class="p">[</span><span class="n">j</span><span class="p">])</span>
			<span class="k">continue</span><span class="p">;</span>

		<span class="k">if</span> <span class="p">(</span><span class="n">edit_count</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
		<span class="k">else</span> <span class="n">edit_count</span><span class="o">++</span><span class="p">;</span>

		<span class="k">if</span> <span class="p">(</span><span class="n">l1</span> <span class="o">==</span> <span class="n">l2</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
		<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">l1</span> <span class="o">&lt;</span> <span class="n">l2</span><span class="p">)</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span> <span class="c1">// it can only be a delete</span>
		<span class="k">else</span> <span class="n">i</span><span class="o">++</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="problem-2---string-rotation">Problem 2 - String Rotation</h3>

<p>Write an algorithm that, given two strings, will return true if one string is a rotation of the other one and false otherwise. The algorithm should be invoked as:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Is rotation: "</span> <span class="o">&lt;&lt;</span> <span class="n">is_rotation</span><span class="p">(</span><span class="s">"wwaterbottleww"</span><span class="p">,</span> <span class="s">"bottlewwwwater"</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</code></pre></div></div>

<p>and in the case above should return true. The solution written below:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="nf">is_rotation</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">s1</span><span class="p">,</span> <span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">s2</span><span class="p">)</span> <span class="p">{</span>

	<span class="k">if</span> <span class="p">(</span><span class="n">s1</span><span class="p">.</span><span class="n">length</span><span class="p">()</span> <span class="o">!=</span> <span class="n">s2</span><span class="p">.</span><span class="n">length</span><span class="p">())</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
	
	<span class="kt">int</span> <span class="n">start_of_match</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="k">for</span> <span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">s2</span><span class="p">.</span><span class="n">length</span><span class="p">();</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">s1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="n">s2</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="p">{</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">start_of_match</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
				<span class="n">j</span> <span class="o">-=</span> <span class="p">(</span><span class="n">j</span> <span class="o">-</span> <span class="n">start_of_match</span><span class="p">);</span>
			<span class="p">}</span>
			<span class="n">start_of_match</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
			<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
			<span class="k">continue</span><span class="p">;</span>
		<span class="p">}</span>
		<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">start_of_match</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> 
			<span class="n">start_of_match</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
		<span class="n">i</span><span class="o">++</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="c1">// last part of the string matched</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">j</span> <span class="o">==</span> <span class="n">s2</span><span class="p">.</span><span class="n">length</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">start_of_match</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
		<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
	
	<span class="c1">// check the first part</span>
	<span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">cs1</span> <span class="o">=</span> <span class="n">s1</span><span class="p">.</span><span class="n">c_str</span><span class="p">();</span>
	<span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">cs2</span> <span class="o">=</span> <span class="n">s2</span><span class="p">.</span><span class="n">c_str</span><span class="p">();</span>

	<span class="k">return</span> <span class="n">strncmp</span><span class="p">(</span><span class="n">cs1</span> <span class="o">+</span> <span class="n">i</span><span class="p">,</span> <span class="n">cs2</span><span class="p">,</span> <span class="n">start_of_match</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="problem-3---remove-duplicates">Problem 3 - Remove Duplicates</h3>

<p>Given a list of of numbers, remove duplicates without breaking the order in the list. The algorithm should be invoked as:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">auto</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">remove_duplicates</span><span class="p">({</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span> <span class="p">});</span>
<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">l</span> <span class="o">:</span> <span class="n">lst</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">l</span> <span class="o">&lt;&lt;</span> <span class="s">", "</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>and it should print <code class="language-plaintext highlighter-rouge">1, 2, 3</code>.</p>

<p>The constraint to not break the order does not allow us to sort the list before removal of the duplicates, which forces us into a <code class="language-plaintext highlighter-rouge">O(n^2)</code> solution. We are going to use the <code class="language-plaintext highlighter-rouge">std::list</code> structure which allows in-place removal of an element without breaking the iterators. Since <code class="language-plaintext highlighter-rouge">std::list</code> is doubly linked, another slightly lighter solution could involve the <code class="language-plaintext highlighter-rouge">std::forward_list</code>:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">auto</span> <span class="nf">remove_duplicates</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">l</span><span class="p">)</span> <span class="p">{</span>

	<span class="n">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">l</span><span class="p">;</span>

	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">=</span> <span class="n">lst</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">i</span> <span class="o">!=</span> <span class="n">lst</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">auto</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
		<span class="n">j</span><span class="o">++</span><span class="p">;</span>
		<span class="k">for</span> <span class="p">(;</span><span class="n">j</span> <span class="o">!=</span> <span class="n">lst</span><span class="p">.</span><span class="n">end</span><span class="p">();)</span> <span class="p">{</span>
			<span class="k">auto</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">j</span><span class="o">++</span><span class="p">;</span>
			<span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">i</span> <span class="o">==</span> <span class="o">*</span><span class="n">tmp</span><span class="p">)</span> <span class="p">{</span>
				<span class="n">lst</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">lst</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="problem-4---k-to-last">Problem 4 - K-to-last</h3>

<p>Write an algorithm which prints the k-to-last element in a singly linked list. Since we don’t know the number of elements in the list, nor can we traverse it backwards, we need to parse the whole list and keep two pointers at k elements apart. The algorithm should be invoked as:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">k_to_last</span><span class="p">({</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span> <span class="p">},</span> <span class="n">k</span><span class="p">,</span> <span class="n">n</span><span class="p">))</span> <span class="p">{</span>
	<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">k</span> <span class="o">&lt;&lt;</span> <span class="s">" to last is "</span> <span class="o">&lt;&lt;</span> <span class="n">n</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
	<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"k &gt; length(array)"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The solution:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="nf">k_to_last</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">l</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">k</span><span class="p">,</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">ret</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">forward_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">l</span><span class="p">;</span>

	<span class="k">auto</span> <span class="n">it1</span> <span class="o">=</span> <span class="n">lst</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
	<span class="k">auto</span> <span class="n">it2</span> <span class="o">=</span> <span class="n">lst</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
	<span class="k">const</span> <span class="kt">int</span> <span class="n">k_upd</span> <span class="o">=</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>

	<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
	<span class="k">for</span> <span class="p">(;</span> <span class="n">it1</span> <span class="o">!=</span> <span class="n">lst</span><span class="p">.</span><span class="n">end</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">k_upd</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">,</span> <span class="n">it1</span><span class="o">++</span><span class="p">);</span>
	
	<span class="k">if</span> <span class="p">(</span><span class="n">it1</span> <span class="o">==</span> <span class="n">lst</span><span class="p">.</span><span class="n">end</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">k_upd</span><span class="p">)</span> 
		<span class="k">return</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">// not enough elements</span>

	<span class="k">for</span> <span class="p">(;</span> <span class="n">it1</span> <span class="o">!=</span> <span class="n">lst</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="n">it1</span><span class="o">++</span><span class="p">,</span> <span class="n">it2</span><span class="o">++</span><span class="p">);</span>

	<span class="n">ret</span> <span class="o">=</span> <span class="o">*</span><span class="n">it2</span><span class="p">;</span>
	<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="problem-5---build-dependencies">Problem 5 - Build Dependencies</h3>

<p>Given a list of builds, with dependencies between each other, write a program that finds the right compilation order such that each dependency is compiled before its dependents. Here is the example invocation, with first build depending on the builds sent as the second parameter.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"BUILD DEPENDENCIES"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

<span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="n">list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;&gt;</span> <span class="n">dependencies</span><span class="p">;</span> 

<span class="n">dependencies</span><span class="p">.</span><span class="n">emplace</span><span class="p">(</span><span class="sc">'a'</span><span class="p">,</span> <span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">({</span> <span class="sc">'d'</span> <span class="p">}));</span>
<span class="n">dependencies</span><span class="p">.</span><span class="n">emplace</span><span class="p">(</span><span class="sc">'f'</span><span class="p">,</span> <span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">({</span> <span class="sc">'b'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'e'</span><span class="p">}));</span>
<span class="n">dependencies</span><span class="p">.</span><span class="n">emplace</span><span class="p">(</span><span class="sc">'b'</span><span class="p">,</span> <span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">({</span> <span class="sc">'d'</span> <span class="p">}));</span>
<span class="n">dependencies</span><span class="p">.</span><span class="n">emplace</span><span class="p">(</span><span class="sc">'d'</span><span class="p">,</span> <span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">({</span> <span class="sc">'c'</span> <span class="p">}));</span>
<span class="n">dependencies</span><span class="p">.</span><span class="n">emplace</span><span class="p">(</span><span class="sc">'g'</span><span class="p">,</span> <span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">({</span> <span class="p">}));</span>

<span class="n">make_builds</span><span class="p">(</span><span class="n">dependencies</span><span class="p">);</span>

<span class="k">try</span> <span class="p">{</span>
	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">l</span> <span class="o">:</span> <span class="n">build_dependencies</span><span class="p">())</span> <span class="p">{</span>
		<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">l</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">exx</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">exx</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">clear_builds</span><span class="p">();</span>
</code></pre></div></div>

<p>In this case, the printed solution should be:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BUILD DEPENDENCIES
c
e
g
d
a
b
f
</code></pre></div></div>

<p>The algorithm below:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">enum</span> <span class="n">BuildState</span> <span class="p">{</span>
	<span class="n">NOT_TOUCHED</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
	<span class="n">UNDER_CHECK</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
	<span class="n">CAN_BE_BUILT</span> <span class="o">=</span> <span class="mi">2</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">build</span> <span class="p">{</span>

	<span class="n">build</span><span class="p">(</span><span class="kt">char</span> <span class="n">_id</span><span class="p">)</span> <span class="o">:</span>
		<span class="n">id</span><span class="p">(</span><span class="n">_id</span><span class="p">),</span>
		<span class="n">build_state</span><span class="p">(</span><span class="n">NOT_TOUCHED</span><span class="p">)</span>
	<span class="p">{</span>
	<span class="p">}</span>

	<span class="kt">char</span> <span class="n">id</span><span class="p">;</span>
	<span class="n">BuildState</span> <span class="n">build_state</span><span class="p">;</span>
	<span class="n">list</span><span class="o">&lt;</span><span class="n">build</span><span class="o">*&gt;</span> <span class="n">dependencies</span><span class="p">;</span>

<span class="p">};</span>

<span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="n">build</span><span class="o">*&gt;</span> <span class="n">builds</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">make_builds</span><span class="p">(</span><span class="k">const</span> <span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="n">list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;&gt;&amp;</span> <span class="n">prjs</span><span class="p">)</span> <span class="p">{</span>

	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">p</span> <span class="o">:</span> <span class="n">prjs</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">builds</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">first</span><span class="p">);</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">it</span> <span class="o">==</span> <span class="n">builds</span><span class="p">.</span><span class="n">end</span><span class="p">())</span>
			<span class="n">it</span> <span class="o">=</span> <span class="n">builds</span><span class="p">.</span><span class="n">emplace</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">first</span><span class="p">,</span> <span class="k">new</span> <span class="n">build</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">first</span><span class="p">)).</span><span class="n">first</span><span class="p">;</span>

		<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">d</span> <span class="o">:</span> <span class="n">p</span><span class="p">.</span><span class="n">second</span><span class="p">)</span> <span class="p">{</span>

			<span class="k">auto</span> <span class="n">dps</span> <span class="o">=</span> <span class="n">builds</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">d</span><span class="p">);</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">dps</span> <span class="o">==</span> <span class="n">builds</span><span class="p">.</span><span class="n">end</span><span class="p">())</span>
				<span class="n">dps</span> <span class="o">=</span> <span class="n">builds</span><span class="p">.</span><span class="n">emplace</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="k">new</span> <span class="n">build</span><span class="p">(</span><span class="n">d</span><span class="p">)).</span><span class="n">first</span><span class="p">;</span>

			<span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="o">-&gt;</span><span class="n">dependencies</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">dps</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">);</span>

		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">clear_builds</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">b</span> <span class="o">:</span> <span class="n">builds</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">auto</span><span class="o">*</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">b</span><span class="p">.</span><span class="n">second</span><span class="p">;</span>
		<span class="n">b</span><span class="p">.</span><span class="n">second</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">;</span>
		<span class="k">delete</span> <span class="n">tmp</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="n">builds</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span>
<span class="p">}</span>

<span class="n">list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">build_dependencies</span><span class="p">(</span><span class="k">const</span> <span class="n">list</span><span class="o">&lt;</span><span class="n">build</span><span class="o">*&gt;&amp;</span> <span class="n">projects</span><span class="p">)</span> <span class="p">{</span>

	<span class="n">list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">ret</span><span class="p">;</span>

	<span class="c1">// start building in parallel those that don't have dependencies</span>
	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">p</span> <span class="o">:</span> <span class="n">projects</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">build_state</span> <span class="o">==</span> <span class="n">CAN_BE_BUILT</span><span class="p">)</span>
			<span class="k">continue</span><span class="p">;</span>

		<span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">build_state</span> <span class="o">==</span> <span class="n">UNDER_CHECK</span><span class="p">)</span>
			<span class="k">throw</span> <span class="s">"cannot build - circular dependencies"</span><span class="p">;</span>

		<span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">dependencies</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">p</span><span class="o">-&gt;</span><span class="n">build_state</span> <span class="o">=</span> <span class="n">CAN_BE_BUILT</span><span class="p">;</span>
			<span class="n">ret</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">id</span><span class="p">);</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="c1">// finish with the rest of them</span>
	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">p</span> <span class="o">:</span> <span class="n">projects</span><span class="p">)</span> <span class="p">{</span>
		
		<span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">build_state</span> <span class="o">==</span> <span class="n">CAN_BE_BUILT</span><span class="p">)</span>
			<span class="k">continue</span><span class="p">;</span>

		<span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">build_state</span> <span class="o">==</span> <span class="n">UNDER_CHECK</span><span class="p">)</span>
			<span class="k">throw</span> <span class="s">"cannot build - circular dependencies"</span><span class="p">;</span>

		<span class="n">p</span><span class="o">-&gt;</span><span class="n">build_state</span> <span class="o">=</span> <span class="n">UNDER_CHECK</span><span class="p">;</span>

		<span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">d</span> <span class="o">:</span> <span class="n">p</span><span class="o">-&gt;</span><span class="n">dependencies</span><span class="p">)</span> <span class="p">{</span>
			<span class="k">auto</span> <span class="n">lst</span> <span class="o">=</span> <span class="n">build_dependencies</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">dependencies</span><span class="p">);</span>
			<span class="n">copy</span><span class="p">(</span><span class="n">lst</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">lst</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">back_inserter</span><span class="p">(</span><span class="n">ret</span><span class="p">));</span>
		<span class="p">}</span>

		<span class="n">p</span><span class="o">-&gt;</span><span class="n">build_state</span> <span class="o">=</span> <span class="n">CAN_BE_BUILT</span><span class="p">;</span>
		<span class="n">ret</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">id</span><span class="p">);</span>

	<span class="p">}</span>

	<span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">list</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">build_dependencies</span><span class="p">()</span> <span class="p">{</span>

	<span class="n">list</span><span class="o">&lt;</span><span class="n">build</span><span class="o">*&gt;</span> <span class="n">prjs</span><span class="p">;</span>
	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">b</span> <span class="o">:</span> <span class="n">builds</span><span class="p">)</span>
		<span class="n">prjs</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">second</span><span class="p">);</span>

	<span class="k">return</span> <span class="n">build_dependencies</span><span class="p">(</span><span class="n">prjs</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="problem-6---recursive-multiply">Problem 6 - Recursive Multiply</h3>

<p>Write a program that performs multiplication without using the <code class="language-plaintext highlighter-rouge">*</code> symbol while minimizing the number of operations. The only allowed operators are <code class="language-plaintext highlighter-rouge">+</code>, <code class="language-plaintext highlighter-rouge">-</code>, <code class="language-plaintext highlighter-rouge">&lt;&lt;</code> and <code class="language-plaintext highlighter-rouge">&gt;&gt;</code>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// recursive multiply without using *, just +, -, &lt;&lt;, &gt;&gt;</span>
<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">recursive_multiply</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">24</span><span class="p">);</span>
</code></pre></div></div>

<p>The solution below:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">recursive_multiply</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>

	<span class="c1">// take the largest number to add</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">a</span> <span class="o">&lt;</span> <span class="n">b</span><span class="p">)</span>
		<span class="n">swap</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>

	<span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">b_first</span> <span class="o">=</span> <span class="n">b</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> 

	<span class="k">for</span> <span class="p">(;</span> <span class="n">b</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">;</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">,</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
		<span class="n">sum</span> <span class="o">+=</span> <span class="n">sum</span><span class="p">;</span> 

	<span class="n">b</span> <span class="o">=</span> <span class="n">b_first</span> <span class="o">-</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">i</span><span class="p">);</span>

	<span class="k">if</span> <span class="p">(</span><span class="n">b</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span>
		<span class="n">sum</span> <span class="o">+=</span> <span class="n">recursive_multiply</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
	<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">b</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
		<span class="n">sum</span> <span class="o">+=</span> <span class="n">a</span><span class="p">;</span>

	<span class="k">return</span> <span class="n">sum</span><span class="p">;</span> 
<span class="p">}</span>
</code></pre></div></div>

<h3 id="problem-7---all-permutations-no-duplicates">Problem 7 - All Permutations, No Duplicates</h3>

<p>Given a string, write all possible permutations of that string elimiating duplicates. For instance, for the following invocation,</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// permutations without duplicates</span>
<span class="n">all_permutations_no_duplicates</span><span class="p">(</span><span class="s">"aaaab"</span><span class="p">);</span>
</code></pre></div></div>

<p>the printed solution should be:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>a, a, a, a, b,
a, a, a, b, a,
a, a, b, a, a,
a, b, a, a, a,
b, a, a, a, a,
</code></pre></div></div>

<p>The solution involves keeping the count of each duplicated letter so we don’t include it as a different symbol for each permutation:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">all_permutations_no_duplicates</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">current</span><span class="p">,</span>  <span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;&amp;</span> <span class="n">str</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">counts</span><span class="p">)</span> <span class="p">{</span>
	<span class="kt">bool</span> <span class="n">any</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

	<span class="c1">// can be done with forward_list&lt;&gt; insert and erase @ it</span>
	<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">str</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">counts</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">current</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">str</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
			<span class="n">counts</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">--</span><span class="p">;</span>
			<span class="n">all_permutations_no_duplicates</span><span class="p">(</span><span class="n">current</span><span class="p">,</span> <span class="n">str</span><span class="p">,</span> <span class="n">counts</span><span class="p">);</span>
			<span class="n">counts</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">++</span><span class="p">;</span>
			<span class="n">current</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span>
			<span class="n">any</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">any</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">c</span> <span class="o">:</span> <span class="n">current</span><span class="p">)</span>
			<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">c</span> <span class="o">&lt;&lt;</span> <span class="s">", "</span><span class="p">;</span>

		<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
	<span class="p">};</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">all_permutations_no_duplicates</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">str_</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">v</span><span class="p">;</span>
	<span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">cnts</span><span class="p">;</span>
	<span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">c</span><span class="p">;</span>

	<span class="n">string</span> <span class="n">str</span> <span class="o">=</span> <span class="n">str_</span><span class="p">;</span>

	<span class="n">sort</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">str</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>

	<span class="c1">// build counts</span>
	<span class="kt">char</span> <span class="n">prev_c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">c</span> <span class="o">:</span> <span class="n">str</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">prev_c</span> <span class="o">!=</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">v</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">c</span><span class="p">);</span>
			<span class="n">cnts</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
		<span class="p">}</span>
		<span class="k">else</span> <span class="p">{</span>
			<span class="n">cnts</span><span class="p">[</span><span class="n">cnts</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">++</span><span class="p">;</span>
		<span class="p">}</span>
		<span class="n">prev_c</span> <span class="o">=</span> <span class="n">c</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
	<span class="n">all_permutations_no_duplicates</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">cnts</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="problem-8---stacks-of-boxes">Problem 8 - Stacks of Boxes</h3>

<p>Given a list of boxes, find the highest tower that can be built by stacking boxes on top of each other. A box can be stacked on top of another box only if all its dimensions, width, depth and height, are smaller than those of the box below.</p>

<p>For solving the problem we will start by generating an array of 100 boxes, all with randomly generated dimensions.</p>

<p>The algorithm is started by:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">stack_of_boxes</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
</code></pre></div></div>

<p>The solution below:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">Box</span> <span class="p">{</span>
	<span class="n">Box</span><span class="p">(</span><span class="kt">int</span> <span class="n">w_</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l_</span><span class="p">,</span> <span class="kt">int</span> <span class="n">h_</span><span class="p">)</span> <span class="o">:</span> <span class="n">w</span><span class="p">(</span><span class="n">w_</span><span class="p">),</span> <span class="n">l</span><span class="p">(</span><span class="n">l_</span><span class="p">),</span> <span class="n">h</span><span class="p">(</span><span class="n">h_</span><span class="p">){</span>
	<span class="p">}</span>

	<span class="kt">int</span> <span class="n">w</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">h</span><span class="p">;</span>

	<span class="kt">bool</span> <span class="n">sorter</span><span class="p">(</span><span class="k">const</span> <span class="n">Box</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">w</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">.</span><span class="n">w</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="kt">bool</span> <span class="n">can_stack</span><span class="p">(</span><span class="k">const</span> <span class="n">Box</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">w</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">.</span><span class="n">w</span> <span class="o">&amp;&amp;</span> <span class="n">h</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">.</span><span class="n">h</span> <span class="o">&amp;&amp;</span> <span class="n">l</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">.</span><span class="n">l</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">Stack</span> <span class="p">{</span>

	<span class="n">Stack</span><span class="p">(</span><span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int</span> <span class="n">h</span><span class="p">,</span> <span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Stack</span><span class="o">&gt;</span> <span class="n">next_</span><span class="p">)</span> <span class="o">:</span> <span class="n">base_box</span><span class="p">(</span><span class="n">b</span><span class="p">),</span> <span class="n">height</span><span class="p">(</span><span class="n">h</span><span class="p">),</span> <span class="n">next</span><span class="p">(</span><span class="n">next_</span><span class="p">)</span> <span class="p">{}</span>

	<span class="kt">int</span> <span class="n">base_box</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">height</span><span class="p">;</span>
	<span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Stack</span><span class="o">&gt;</span> <span class="n">next</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="nf">stack_sorted_boxes</span><span class="p">(</span>
		<span class="n">list</span><span class="o">&lt;</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Stack</span><span class="o">&gt;&gt;&amp;</span> <span class="n">s</span><span class="p">,</span> 
		<span class="k">const</span> <span class="n">map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> 
		<span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;&amp;</span> <span class="n">can_stack</span><span class="p">,</span> 
		<span class="k">const</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">Box</span><span class="o">&gt;</span> <span class="o">&amp;</span><span class="n">v</span><span class="p">)</span> <span class="p">{</span>
	
	<span class="kt">bool</span> <span class="n">added</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">max_height</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="c1">// it is basically a deque</span>
	<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">i</span> <span class="o">!=</span> <span class="n">s</span><span class="p">.</span><span class="n">end</span><span class="p">();)</span> <span class="p">{</span>

		<span class="k">auto</span> <span class="n">stackables</span> <span class="o">=</span> <span class="n">can_stack</span><span class="p">.</span><span class="n">find</span><span class="p">((</span><span class="o">*</span><span class="n">i</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">base_box</span><span class="p">);</span>
		
		<span class="c1">// cannot stack anything on top, this is the end of the stack</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">stackables</span> <span class="o">==</span> <span class="n">can_stack</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> <span class="p">{</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">max_height</span> <span class="o">&lt;</span> <span class="p">(</span><span class="o">*</span><span class="n">i</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">height</span><span class="p">)</span>
				<span class="n">max_height</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">i</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">height</span><span class="p">;</span>
		<span class="p">}</span>
		<span class="k">else</span> <span class="p">{</span>
			<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">j</span> <span class="o">:</span> <span class="n">stackables</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">)</span> <span class="p">{</span>
				<span class="c1">// here we don't really need the last parameter</span>
				<span class="c1">// if we are only returning the stack height and not the stask itself</span>
				<span class="n">s</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">make_shared</span><span class="o">&lt;</span><span class="n">Stack</span><span class="o">&gt;</span><span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="p">(</span><span class="o">*</span><span class="n">i</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">height</span> <span class="o">+</span> <span class="n">v</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">h</span><span class="p">,</span> <span class="o">*</span><span class="n">i</span><span class="p">));</span>
			<span class="p">}</span>
		<span class="p">}</span>
		<span class="n">i</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> <span class="c1">// I already put something on top of it</span>

		<span class="n">added</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">max_height</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">stack_of_boxes</span><span class="p">()</span> <span class="p">{</span>

	<span class="n">vector</span><span class="o">&lt;</span><span class="n">Box</span><span class="o">&gt;</span> <span class="n">v</span><span class="p">;</span>

	<span class="c1">// randomly generate 100 boxes</span>
	<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">v</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">rand</span><span class="p">()</span> <span class="o">%</span> <span class="mi">100</span><span class="p">,</span> <span class="n">rand</span><span class="p">()</span> <span class="o">%</span> <span class="mi">100</span><span class="p">,</span> <span class="n">rand</span><span class="p">()</span> <span class="o">%</span> <span class="mi">100</span><span class="p">);</span>
	<span class="p">}</span>

	<span class="n">sort</span><span class="p">(</span><span class="n">v</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">v</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[](</span><span class="k">const</span> <span class="n">Box</span><span class="o">&amp;</span> <span class="n">b1</span><span class="p">,</span> <span class="k">const</span> <span class="n">Box</span><span class="o">&amp;</span> <span class="n">b2</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">b1</span><span class="p">.</span><span class="n">sorter</span><span class="p">(</span><span class="n">b2</span><span class="p">);</span>
		<span class="p">});</span>

	<span class="n">map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">can_stack</span><span class="p">;</span>

	<span class="c1">// generate a list of boxes that can be stacked upon each other</span>
	<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">v</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
		<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">v</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
			<span class="k">if</span> <span class="p">(</span><span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">can_stack</span><span class="p">(</span><span class="n">v</span><span class="p">[</span><span class="n">j</span><span class="p">]))</span>
				<span class="n">can_stack</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
		<span class="p">}</span>

	<span class="n">list</span><span class="o">&lt;</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Stack</span><span class="o">&gt;&gt;</span> <span class="n">stacks</span><span class="p">;</span>

	<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">v</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">stacks</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">make_shared</span><span class="o">&lt;</span><span class="n">Stack</span><span class="o">&gt;</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">h</span><span class="p">,</span> <span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">Stack</span><span class="o">&gt;</span><span class="p">()));</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="n">stack_sorted_boxes</span><span class="p">(</span><span class="n">stacks</span><span class="p">,</span> <span class="n">can_stack</span><span class="p">,</span> <span class="n">v</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="problem-9---expression-equivalence">Problem 9 - Expression Equivalence</h3>

<p>Given two expressions, <code class="language-plaintext highlighter-rouge">a * (b + c)</code> and <code class="language-plaintext highlighter-rouge">a * b + a * c</code>, write an algorithm that will determine if the two expressions are equivalent. In our case above, the two expressions are equivalent.</p>

<p>The solution implies expanding the parantheses and bringing the expression to a cannonical form, a sum of products. To shortcut the parsing, we will consider the expression is given in the form of an expression tree, <code class="language-plaintext highlighter-rouge">(left operand, operation, right operand)</code>. After the expression is brought to the cannonical form, each term is sorted alphabetically and then all all terms are again sorted. Then we simply compare the strings in order to decide whether the two expressions are equivalent.</p>

<p>The algorithm is started by defining expressions as follows:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ExprTree</span> <span class="nf">e1</span><span class="p">(</span>
		<span class="sc">'*'</span><span class="p">,</span>
		<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">),</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'a'</span><span class="p">)),</span>
		<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">),</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'a'</span><span class="p">))</span>
	<span class="p">);</span>

<span class="n">ExprTree</span> <span class="nf">e2</span><span class="p">(</span>
		<span class="sc">'*'</span><span class="p">,</span>
		<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">),</span>
		<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">)</span>
	<span class="p">);</span>

<span class="n">ExprTree</span> <span class="nf">e3</span><span class="p">(</span>
		<span class="sc">'*'</span><span class="p">,</span>
		<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span>
			<span class="sc">'*'</span><span class="p">,</span>
			<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">),</span>
			<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">)</span>
		<span class="p">),</span>
		<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span>
			<span class="sc">'*'</span><span class="p">,</span>
			<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">),</span>
			<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">)</span>
		<span class="p">)</span>
	<span class="p">);</span>

<span class="c1">// or creating a random tree for faster testing</span>
<span class="n">ExprTree</span><span class="o">*</span> <span class="n">e4</span> <span class="o">=</span> <span class="n">ExprTree</span><span class="o">::</span><span class="n">make_random_tree</span><span class="p">();</span>
<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">expression_equivalence</span><span class="p">(</span><span class="n">e4</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">e3</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>

<span class="k">delete</span> <span class="n">e4</span>
</code></pre></div></div>

<p>As a complication, the algorithm must not generate any memory leaks and must use C-style pointers.</p>

<p>Below is the full solution:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">ExprTree</span> <span class="p">{</span>

	<span class="n">ExprTree</span><span class="p">(</span><span class="kt">char</span> <span class="n">_op</span><span class="p">,</span> <span class="n">ExprTree</span><span class="o">*</span> <span class="n">_left</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="n">ExprTree</span><span class="o">*</span> <span class="n">_right</span><span class="o">=</span><span class="nb">nullptr</span><span class="p">)</span> <span class="o">:</span>
		<span class="n">op</span><span class="p">(</span><span class="n">_op</span><span class="p">),</span> <span class="n">left</span><span class="p">(</span><span class="n">_left</span><span class="p">),</span> <span class="n">right</span><span class="p">(</span><span class="n">_right</span><span class="p">){</span>
	<span class="p">}</span>

	<span class="n">ExprTree</span><span class="p">(</span><span class="kt">char</span> <span class="n">_op</span><span class="p">,</span> <span class="kt">char</span> <span class="n">a</span><span class="p">,</span> <span class="kt">char</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">op</span> <span class="o">=</span> <span class="n">_op</span><span class="p">;</span>
		<span class="n">left</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
		<span class="n">right</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
	<span class="p">}</span>

	<span class="o">~</span><span class="n">ExprTree</span><span class="p">()</span> <span class="p">{</span>
		<span class="k">if</span><span class="p">(</span><span class="n">left</span> <span class="o">!=</span> <span class="nb">nullptr</span><span class="p">)</span>
			<span class="k">delete</span> <span class="n">left</span><span class="p">;</span>

		<span class="k">if</span><span class="p">(</span><span class="n">right</span> <span class="o">!=</span> <span class="nb">nullptr</span><span class="p">)</span>
			<span class="k">delete</span> <span class="n">right</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="n">ExprTree</span><span class="o">*</span> <span class="n">deep_copy</span><span class="p">()</span> <span class="p">{</span>

		<span class="k">return</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="n">op</span><span class="p">,</span> 
			<span class="n">left</span> <span class="o">?</span> <span class="n">left</span><span class="o">-&gt;</span><span class="n">deep_copy</span><span class="p">()</span> <span class="o">:</span> <span class="nb">nullptr</span><span class="p">,</span> 
			<span class="n">right</span> <span class="o">?</span> <span class="n">right</span><span class="o">-&gt;</span><span class="n">deep_copy</span><span class="p">()</span> <span class="o">:</span> <span class="nb">nullptr</span><span class="p">);</span>
	<span class="p">}</span>

	<span class="c1">// utility function to generate a random tree</span>
	<span class="c1">// not part of the algorithm</span>
	<span class="k">static</span> <span class="n">ExprTree</span><span class="o">*</span> <span class="n">make_random_tree</span><span class="p">()</span> <span class="p">{</span>

		<span class="kt">float</span> <span class="n">f</span> <span class="o">=</span> <span class="p">((</span><span class="kt">float</span><span class="p">)</span><span class="n">rand</span><span class="p">()</span> <span class="o">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="n">RAND_MAX</span><span class="p">);</span>

		 <span class="k">if</span><span class="p">(</span><span class="n">f</span> <span class="o">&lt;</span> <span class="mf">0.3</span><span class="p">)</span>
			 <span class="k">return</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'a'</span><span class="p">);</span>

		 <span class="k">if</span> <span class="p">(</span><span class="n">f</span> <span class="o">&lt;</span> <span class="mf">0.6</span><span class="p">)</span>
			 <span class="k">return</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'b'</span><span class="p">);</span>
		 
		 <span class="k">if</span> <span class="p">(</span><span class="n">f</span> <span class="o">&lt;</span> <span class="mf">0.8</span><span class="p">)</span>
			 <span class="k">return</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">make_random_tree</span><span class="p">(),</span> <span class="n">make_random_tree</span><span class="p">());</span>

		 <span class="k">return</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span> <span class="n">make_random_tree</span><span class="p">(),</span> <span class="n">make_random_tree</span><span class="p">());</span>

	<span class="p">}</span>

	<span class="kt">char</span> <span class="n">op</span><span class="p">;</span>
	<span class="n">ExprTree</span><span class="o">*</span> <span class="n">left</span><span class="p">;</span>
	<span class="n">ExprTree</span><span class="o">*</span> <span class="n">right</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">void</span> <span class="nf">expand_paranthesis</span><span class="p">(</span><span class="n">ExprTree</span><span class="o">*</span> <span class="n">start</span><span class="p">)</span> <span class="p">{</span>

	<span class="k">if</span> <span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">!=</span> <span class="sc">'+'</span> <span class="o">&amp;&amp;</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">!=</span> <span class="sc">'*'</span><span class="p">)</span>
		<span class="k">return</span><span class="p">;</span> <span class="c1">// terminal symbol</span>

	<span class="c1">// we need to start with the recursion condition in order</span>
	<span class="c1">// to bubble up the +'es. we cannot have a * above a +</span>
	<span class="n">expand_paranthesis</span><span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">);</span>
	<span class="n">expand_paranthesis</span><span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">);</span>

	<span class="k">if</span> <span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'*'</span><span class="p">)</span> <span class="p">{</span>

		<span class="k">auto</span> <span class="n">tmpop</span> <span class="o">=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">op</span><span class="p">;</span>

		<span class="c1">// (a + b) * (a + b) </span>
		<span class="k">if</span> <span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'+'</span> <span class="o">&amp;&amp;</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'+'</span><span class="p">)</span> <span class="p">{</span>

			<span class="n">start</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">=</span> <span class="sc">'+'</span><span class="p">;</span>
			
			<span class="k">auto</span> <span class="n">tmp_left_a</span> <span class="o">=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">;</span>
			<span class="k">auto</span> <span class="n">tmp_right_a</span> <span class="o">=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">;</span>
			<span class="k">auto</span> <span class="n">tmp_left_b</span> <span class="o">=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">;</span>
			<span class="k">auto</span> <span class="n">tmp_right_b</span> <span class="o">=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">;</span>

			<span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span>
				<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">tmp_left_a</span><span class="p">,</span> <span class="n">tmp_right_a</span><span class="p">),</span>
				<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">tmp_left_a</span><span class="o">-&gt;</span><span class="n">deep_copy</span><span class="p">(),</span> <span class="n">tmp_right_b</span><span class="p">));</span>

			<span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'+'</span><span class="p">,</span>
				<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">tmp_left_b</span><span class="p">,</span> <span class="n">tmp_right_a</span><span class="o">-&gt;</span><span class="n">deep_copy</span><span class="p">()),</span>
				<span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">tmp_left_b</span><span class="o">-&gt;</span><span class="n">deep_copy</span><span class="p">(),</span> <span class="n">tmp_right_b</span><span class="o">-&gt;</span><span class="n">deep_copy</span><span class="p">()));</span>
		<span class="p">}</span>
		<span class="c1">// a * (b + c)</span>
		<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'+'</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">start</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">=</span> <span class="sc">'+'</span><span class="p">;</span>
			<span class="k">auto</span> <span class="n">deep_copy_left</span> <span class="o">=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">deep_copy</span><span class="p">();</span>
			<span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">,</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">);</span>
			<span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">deep_copy_left</span><span class="p">,</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">);</span>
		<span class="p">}</span>

		<span class="c1">//(b + c) * a</span>
		<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'+'</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">start</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">=</span> <span class="sc">'+'</span><span class="p">;</span>
			<span class="k">auto</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">;</span>
			<span class="k">auto</span> <span class="n">start_right_copy</span> <span class="o">=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="o">-&gt;</span><span class="n">deep_copy</span><span class="p">();</span>
			<span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">tmp</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">,</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">);</span>
			<span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ExprTree</span><span class="p">(</span><span class="sc">'*'</span><span class="p">,</span> <span class="n">tmp</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">,</span> <span class="n">start_right_copy</span><span class="p">);</span>
		<span class="p">}</span>

		<span class="c1">// what has been arranged before is </span>
		<span class="c1">// no longer arranged because we changed the structure of the tree</span>
		<span class="k">if</span> <span class="p">(</span><span class="n">tmpop</span> <span class="o">!=</span> <span class="n">start</span><span class="o">-&gt;</span><span class="n">op</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">expand_paranthesis</span><span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">);</span>
			<span class="n">expand_paranthesis</span><span class="p">(</span><span class="n">start</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">);</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">get_set</span><span class="p">(</span><span class="n">ExprTree</span><span class="o">*</span> <span class="n">e</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;&amp;</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'*'</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">get_set</span><span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span>
		<span class="n">get_set</span><span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="k">else</span> <span class="p">{</span>
		<span class="n">s</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">op</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">to_sorted_vector</span><span class="p">(</span><span class="n">ExprTree</span><span class="o">*</span> <span class="n">e</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="o">&amp;</span> <span class="n">ret</span><span class="p">)</span> <span class="p">{</span>

	<span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'+'</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">to_sorted_vector</span><span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">,</span> <span class="n">ret</span><span class="p">);</span>
		<span class="n">to_sorted_vector</span><span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">,</span> <span class="n">ret</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'*'</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">v</span><span class="p">;</span>

		<span class="n">get_set</span><span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">left</span><span class="p">,</span> <span class="n">v</span><span class="p">);</span>
		<span class="n">get_set</span><span class="p">(</span><span class="n">e</span><span class="o">-&gt;</span><span class="n">right</span><span class="p">,</span> <span class="n">v</span><span class="p">);</span>

		<span class="n">string</span> <span class="n">s</span><span class="p">;</span>
		<span class="n">sort</span><span class="p">(</span><span class="n">v</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">v</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
		<span class="n">copy</span><span class="p">(</span><span class="n">v</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">v</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">back_inserter</span><span class="p">(</span><span class="n">s</span><span class="p">));</span>
		<span class="n">ret</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>

<span class="kt">bool</span> <span class="nf">expression_equivalence</span><span class="p">(</span><span class="n">ExprTree</span><span class="o">*</span> <span class="n">e1</span><span class="p">,</span> <span class="n">ExprTree</span><span class="o">*</span> <span class="n">e2</span><span class="p">)</span> <span class="p">{</span>

	<span class="n">expand_paranthesis</span><span class="p">(</span><span class="n">e1</span><span class="p">);</span>
	<span class="n">expand_paranthesis</span><span class="p">(</span><span class="n">e2</span><span class="p">);</span>
	
	<span class="c1">// each term is sorted alphabetically</span>
	<span class="n">vector</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">e1_str</span><span class="p">;</span>
	<span class="n">to_sorted_vector</span><span class="p">(</span><span class="n">e1</span><span class="p">,</span> <span class="n">e1_str</span><span class="p">);</span>

	<span class="n">vector</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">e2_str</span><span class="p">;</span>
	<span class="n">to_sorted_vector</span><span class="p">(</span><span class="n">e2</span><span class="p">,</span> <span class="n">e2_str</span><span class="p">);</span>

	<span class="c1">// all terms are sorted alphabetically</span>
	<span class="n">sort</span><span class="p">(</span><span class="n">e1_str</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">e1_str</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
	<span class="n">sort</span><span class="p">(</span><span class="n">e2_str</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">e2_str</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>

	<span class="k">auto</span> <span class="n">it1</span> <span class="o">=</span> <span class="n">e1_str</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
	<span class="k">auto</span> <span class="n">it2</span> <span class="o">=</span> <span class="n">e2_str</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>

	<span class="c1">// simple pairwise comparison</span>
	<span class="k">for</span> <span class="p">(;</span> <span class="n">it1</span> <span class="o">!=</span> <span class="n">e1_str</span><span class="p">.</span><span class="n">end</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">it2</span> <span class="o">!=</span> <span class="n">e2_str</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="n">it1</span><span class="o">++</span><span class="p">,</span> <span class="n">it2</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">it1</span> <span class="o">!=</span> <span class="o">*</span><span class="n">it2</span><span class="p">)</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="n">it1</span> <span class="o">==</span> <span class="n">e1_str</span><span class="p">.</span><span class="n">end</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">it2</span> <span class="o">==</span> <span class="n">e2_str</span><span class="p">.</span><span class="n">end</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Below you can see the algorithm running in Visual C++ with the expression expanded. You can notice that all <code class="language-plaintext highlighter-rouge">+</code>-es are above <code class="language-plaintext highlighter-rouge">*</code> in the reorganized expression tree.</p>

<p><img src="https://alexandrugris.github.io/assets/prog_cpp2.jpg" alt="Expanded Cannonical Expression" /></p>]]></content><author><name></name></author><category term="programming" /><summary type="html"><![CDATA[This post is a collection of several programming problems implemented in C++. It’s good to keep the edge sharp by solving some algorithmic problems from time to time.]]></summary></entry><entry><title type="html">3D From Scratch</title><link href="https://alexandrugris.github.io/graphics/3d/2020/04/15/3d-from-scratch.html" rel="alternate" type="text/html" title="3D From Scratch" /><published>2020-04-15T09:15:16+02:00</published><updated>2020-04-15T09:15:16+02:00</updated><id>https://alexandrugris.github.io/graphics/3d/2020/04/15/3d-from-scratch</id><content type="html" xml:base="https://alexandrugris.github.io/graphics/3d/2020/04/15/3d-from-scratch.html"><![CDATA[<p>This post is about implementing a 3D renderer from scratch, with no help from any graphics or maths library. It is implemented in pure JavaScript and it follows roughly the first half of the excellent <a href="https://github.com/ssloy/tinyrenderer">tiny renderer</a> tutorial.</p>

<h3 id="the-end-result">The End Result</h3>

<p>We are going to build our software renderer to show this:</p>

<p><img src="https://alexandrugris.github.io/assets/tiny_1.png" alt="Head" /></p>

<p>The features our software renderer suppors are:</p>

<ul>
  <li>Model loading</li>
  <li>Phong (per pixel) lighting</li>
  <li>Triangle rasterization</li>
  <li>Model, camera, viewport transformations</li>
  <li>Wireframe rendering</li>
  <li>Texturing</li>
  <li>Z-Buffer</li>
  <li>Hidden face removal (backface culling)</li>
</ul>

<p>In addition to these, we will build a small and probably buggy maths library. All the code is included in this file: <a href="https://github.com/alexandrugris/webglfun/blob/master/basics-phong.html">basics-phong</a></p>

<h3 id="coordinate-systems">Coordinate Systems</h3>

<p>First and foremost, we will operate in the coordiate system with the z-axis pointing towards us, y-axis upwards and the x-axis rightwards.</p>

<p><img src="https://alexandrugris.github.io/assets/tiny_2.png" alt="Head" /></p>

<p>In addition to that, the model we will load is oriented towards z-axis. Also, by convention, we will consider triangles defined as counter-clockwise. This will help us later determine what is the front and what is the the back face of the triangle.</p>

<h3 id="loading-the-model">Loading the model</h3>

<p>The format for our model is standard: an indexed geometry, with a set of vertices, vertex normals and texture coordinates. Taking into consideration the counter-clockwise convention, here is how we define a quad.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">generateTexturedQuad</span><span class="p">(</span><span class="nx">mesh</span><span class="p">){</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>

    <span class="nx">mesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">]);</span>

    <span class="nx">mesh</span><span class="p">.</span><span class="nx">txcoords</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]);</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">txcoords</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]);</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">txcoords</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]);</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">txcoords</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]);</span>

    <span class="c1">// all normals pointing towards the camera</span>
    <span class="c1">// in the case when 3d artists are not so kind,</span>
    <span class="c1">// you can recompute the normal vectors as an average of normals to all </span>
    <span class="c1">// facets incident to the vertex</span>

    <span class="nx">mesh</span><span class="p">.</span><span class="nx">vnormals</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]);</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">vnormals</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]);</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">vnormals</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]);</span>
    <span class="nx">mesh</span><span class="p">.</span><span class="nx">vnormals</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]);</span>

    <span class="k">if</span><span class="p">(</span><span class="nx">mesh</span><span class="p">.</span><span class="nx">worldTransform</span> <span class="o">===</span> <span class="kc">undefined</span> <span class="o">||</span> <span class="nx">mesh</span><span class="p">.</span><span class="nx">worldTransform</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span>
      <span class="nx">mesh</span><span class="p">.</span><span class="nx">worldTransform</span> <span class="o">=</span> <span class="nx">getIdentityMatrix</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>

  <span class="p">}</span>

  <span class="k">async</span> <span class="kd">function</span> <span class="nx">loadAsset</span><span class="p">(</span><span class="nx">diffuse</span><span class="p">,</span> <span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
    
    <span class="nx">myMesh</span> <span class="o">=</span> <span class="p">{</span>
      <span class="na">vertices</span><span class="p">:</span> <span class="p">[],</span>
      <span class="na">txcoords</span><span class="p">:</span> <span class="p">[],</span>
      <span class="na">vnormals</span><span class="p">:</span> <span class="p">[],</span>
      <span class="na">faces</span><span class="p">:</span> <span class="p">[],</span>
      <span class="na">diffuse</span><span class="p">:</span> <span class="nx">diffuse</span><span class="p">,</span>
      <span class="na">worldTransform</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span> 
    <span class="p">};</span>

    <span class="nx">generateTexturedQuad</span><span class="p">(</span><span class="nx">myMesh</span><span class="p">);</span>
    
<span class="p">}</span>
</code></pre></div></div>

<p>Rendering this image also assumes the following are set:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">viewportTransform</span> <span class="o">=</span> <span class="nx">makeViewportTransform</span><span class="p">(</span><span class="nx">cvs</span><span class="p">.</span><span class="nx">width</span><span class="p">,</span> <span class="nx">cvs</span><span class="p">.</span><span class="nx">height</span><span class="p">);</span>
<span class="nx">projectionTransform</span> <span class="o">=</span> <span class="nx">getIdentityMatrix</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span> <span class="c1">// no projection</span>
<span class="nx">cameraTransform</span> <span class="o">=</span> <span class="nx">makeIdentityCamMatrix</span><span class="p">();</span> <span class="c1">// no camera transformation</span>
</code></pre></div></div>

<p><img src="https://alexandrugris.github.io/assets/tiny_3.png" alt="Head" /></p>

<p>Since <code class="language-plaintext highlighter-rouge">projectionTransform</code> and <code class="language-plaintext highlighter-rouge">cameraTransform</code> are identity matrices, it means that the only transformation in place is the <code class="language-plaintext highlighter-rouge">viewportTransform</code>. This transform takes a coordiante space defined by the rectangle <code class="language-plaintext highlighter-rouge">x, y = [-1, 1], [-1, 1]</code>, with <code class="language-plaintext highlighter-rouge">y</code> pointing upwards, and transforms it to pixel on the screen coordiantes.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
  * Transforms from [-1..1] to [0, w] and [h, 0] respectively.
  */</span>
<span class="kd">function</span> <span class="nx">makeViewportTransform</span><span class="p">(</span><span class="nx">viewportWidth</span><span class="p">,</span> <span class="nx">viewportHeight</span><span class="p">){</span>
    <span class="c1">// maintain aspect ratio</span>
    <span class="k">return</span> <span class="p">[</span>
      <span class="nx">viewportHeight</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">viewportWidth</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span>
      <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="nx">viewportHeight</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">viewportHeight</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span>
      <span class="c1">// spread a bit the numbers in the zbuffer (can be 1, but let's make it more discrete).</span>
      <span class="c1">// This is useful it we want to store the zbuffer as an integer instead of a float.</span>
      <span class="c1">// This would give the resolution of the depth buffer, mapping -1, 1]</span>
      <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1024</span><span class="p">,</span> <span class="mi">1024</span><span class="p">,</span>
      <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
    <span class="p">]</span>
  <span class="p">}</span>
</code></pre></div></div>

<p>It also transforms the z-buffer, but that is another chapter.</p>

<h3 id="wireframe-rendering">Wireframe Rendering</h3>

<p>Before we move to shading triangles, let’s first render our model in wireframe:</p>

<p><img src="https://alexandrugris.github.io/assets/tiny_4.png" alt="Head" /></p>

<p>For this, let’s look at our <code class="language-plaintext highlighter-rouge">generateImage</code> function and what it does if the <code class="language-plaintext highlighter-rouge">wireframe</code> parameter is set to <code class="language-plaintext highlighter-rouge">true</code>.</p>

<p>The first step is to clear the background and the z-buffer. For wireframe rendering we don’t care about the z-buffer, but we do care about not drawing on top of an older image. So we put all pixels to green.</p>

<p>Another thing we care about is transforming our vertices from their world coordinates to their corresponding screen coordinates. For this we have a chain of transformations (matrix multiplications) we apply to each vertex. Transform <code class="language-plaintext highlighter-rouge">transformsWordToSreen</code> matrix takes a position in world coordinates and transforms it to <code class="language-plaintext highlighter-rouge">[x, y, z]</code> in screen space. We will use the <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code> to put the pixel on the screen and <code class="language-plaintext highlighter-rouge">z</code> to know if it is the topmost pixel and thus not hidden by another pixel. In <code class="language-plaintext highlighter-rouge">varrrayW</code> we keep the vertices in world coordinates, in <code class="language-plaintext highlighter-rouge">varray</code> in screen coordinates.</p>

<p>The loop that follows  generates the faces, the triangles of our model. As mentioned before, this is an indexed geometry so for each face we need to lookup by index the coresponding vertex in vertex array. We do the same for the normals and for the texture coordinates. These are not relevant for the wireframe rendering, but they are relevant for the next chapter when we shade the triangle. In the last loop, we draw the line.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">generateImage</span><span class="p">(</span><span class="nx">wireframe</span><span class="o">=</span><span class="kc">true</span><span class="p">){</span>

    <span class="c1">// clear background and Z buffer:</span>
    <span class="nx">clear</span><span class="p">(</span><span class="mh">0x00</span><span class="p">,</span> <span class="mh">0xff</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">);</span>

    <span class="k">if</span><span class="p">(</span><span class="nx">myMesh</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">triangles</span> <span class="o">=</span> <span class="p">[];</span>

    <span class="cm">/* the following two lines are equivalent to the matrix transformation applied next
    let varray = myMesh.vertices.map(v=&gt;homogeneousTransform(vectorMultiply(projectionTransform, v)));
    varray = varray.map(v=&gt;homogeneousTransform(vectorMultiply(viewportTransform, v)));
     */</span>

    <span class="c1">//multiply first with transform because the vector appears later several times</span>
    <span class="kd">let</span> <span class="nx">transformsWorldToScreen</span> <span class="o">=</span> <span class="nx">chainMultiplyMatrix</span><span class="p">([</span><span class="nx">viewportTransform</span><span class="p">,</span> <span class="nx">projectionTransform</span><span class="p">,</span> <span class="nx">cameraTransform</span><span class="p">])</span>

    <span class="c1">// tranform the vertices to worldspace and then to screen</span>
    <span class="kd">let</span> <span class="nx">varrayW</span> <span class="o">=</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">v</span> <span class="o">=&gt;</span> <span class="nx">homogeneousTransform</span><span class="p">(</span><span class="nx">vectorMultiply</span><span class="p">(</span><span class="nx">myMesh</span><span class="p">.</span><span class="nx">worldTransform</span><span class="p">,</span> <span class="nx">v</span><span class="p">,</span> <span class="kc">true</span><span class="p">)));</span>
    <span class="kd">let</span> <span class="nx">varray</span> <span class="o">=</span> <span class="nx">varrayW</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">v</span> <span class="o">=&gt;</span> <span class="nx">homogeneousTransform</span><span class="p">(</span><span class="nx">vectorMultiply</span><span class="p">(</span><span class="nx">transformsWorldToScreen</span><span class="p">,</span> <span class="nx">v</span><span class="p">,</span> <span class="kc">true</span><span class="p">)));</span>

    <span class="c1">// transform the normals to world</span>
    <span class="c1">// isPosition == false so we don't translate</span>
    <span class="kd">let</span> <span class="nx">narrayW</span> <span class="o">=</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">vnormals</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">v</span> <span class="o">=&gt;</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">vectorMultiply</span><span class="p">(</span><span class="nx">myMesh</span><span class="p">.</span><span class="nx">worldTransform</span><span class="p">,</span> <span class="nx">v</span><span class="p">,</span> <span class="kc">false</span><span class="p">)));</span>

     <span class="c1">// each face has 9 indices, only the 0, 3, 6 are vertex index</span>
    <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>

       <span class="c1">// index in the vertex buffer</span>
       <span class="kd">let</span> <span class="nx">v0</span> <span class="o">=</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
       <span class="kd">let</span> <span class="nx">v1</span> <span class="o">=</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">3</span><span class="p">];</span>
       <span class="kd">let</span> <span class="nx">v2</span> <span class="o">=</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">6</span><span class="p">];</span>

       <span class="c1">// texture vertex index</span>
       <span class="kd">let</span> <span class="nx">tx0</span> <span class="o">=</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">txcoords</span><span class="p">[</span><span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]];</span>
       <span class="kd">let</span> <span class="nx">tx1</span> <span class="o">=</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">txcoords</span><span class="p">[</span><span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">4</span><span class="p">]];</span>
       <span class="kd">let</span> <span class="nx">tx2</span> <span class="o">=</span> <span class="nx">myMesh</span><span class="p">.</span><span class="nx">txcoords</span><span class="p">[</span><span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">7</span><span class="p">]];</span>

       <span class="c1">// vertex normal coords world space</span>
       <span class="kd">let</span> <span class="nx">vn0</span> <span class="o">=</span> <span class="nx">narrayW</span><span class="p">[</span><span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">2</span><span class="p">]].</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
       <span class="kd">let</span> <span class="nx">vn1</span> <span class="o">=</span> <span class="nx">narrayW</span><span class="p">[</span><span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">5</span><span class="p">]].</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
       <span class="kd">let</span> <span class="nx">vn2</span> <span class="o">=</span> <span class="nx">narrayW</span><span class="p">[</span><span class="nx">myMesh</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">8</span><span class="p">]].</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>

       <span class="c1">// world space backface culling</span>
       <span class="kd">let</span> <span class="nx">faceNormal</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">crossProduct3</span><span class="p">(</span>
                      <span class="nx">subtractVector</span><span class="p">(</span><span class="nx">varrayW</span><span class="p">[</span><span class="nx">v2</span><span class="p">],</span> <span class="nx">varrayW</span><span class="p">[</span><span class="nx">v0</span><span class="p">]),</span>
                      <span class="nx">subtractVector</span><span class="p">(</span><span class="nx">varrayW</span><span class="p">[</span><span class="nx">v1</span><span class="p">],</span> <span class="nx">varrayW</span><span class="p">[</span><span class="nx">v0</span><span class="p">])</span>
                    <span class="p">));</span>

       <span class="kd">let</span> <span class="nx">visible</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">cameraDir</span><span class="p">,</span> <span class="nx">faceNormal</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span>

       <span class="k">if</span><span class="p">(</span><span class="nx">visible</span> <span class="o">||</span> <span class="nx">wireframe</span><span class="p">)</span> <span class="p">{</span>
         <span class="nx">triangles</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="nx">varray</span><span class="p">[</span><span class="nx">v0</span><span class="p">],</span> <span class="nx">varray</span><span class="p">[</span><span class="nx">v1</span><span class="p">],</span> <span class="nx">varray</span><span class="p">[</span><span class="nx">v2</span><span class="p">],</span> <span class="nx">vn0</span><span class="p">,</span> <span class="nx">vn1</span><span class="p">,</span> <span class="nx">vn2</span><span class="p">,</span> <span class="nx">tx0</span><span class="p">,</span> <span class="nx">tx1</span><span class="p">,</span> <span class="nx">tx2</span><span class="p">]);</span>
       <span class="p">}</span>

     <span class="p">}</span>

    <span class="k">if</span><span class="p">(</span><span class="nx">wireframe</span><span class="p">)</span> <span class="p">{</span>
      <span class="c1">// TODO: remove duplicated lines, each line is drawn several times</span>
      <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">triangles</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">t</span> <span class="o">=</span> <span class="nx">triangles</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
        <span class="nx">drawLineV</span><span class="p">(</span><span class="nx">t</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">t</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mh">0xff</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="nx">drawLineV</span><span class="p">(</span><span class="nx">t</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">t</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="mh">0xff</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="nx">drawLineV</span><span class="p">(</span><span class="nx">t</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">t</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mh">0xff</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
      <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">else</span><span class="p">{</span>
      <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">&lt;</span><span class="nx">triangles</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
        <span class="kd">let</span> <span class="nx">t</span> <span class="o">=</span> <span class="nx">triangles</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
        <span class="nx">drawTriangle</span><span class="p">(...</span><span class="nx">t</span><span class="p">);</span>
      <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="putpixel-and-line-drawing">PutPixel and Line Drawing</h3>

<p>As mentioned before, we don’t use any library for this demo. So we will implement our <code class="language-plaintext highlighter-rouge">drawLine</code> from scratch. Here it is how it goes. <code class="language-plaintext highlighter-rouge">screenBuffer</code> is our pixel matrix, organized as <code class="language-plaintext highlighter-rouge">RGBA</code>, each one byte in length.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">putPixel</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">r</span><span class="o">=</span><span class="mh">0xff</span><span class="p">,</span> <span class="nx">g</span><span class="o">=</span><span class="mh">0x00</span><span class="p">,</span> <span class="nx">b</span><span class="o">=</span><span class="mh">0x00</span><span class="p">)</span> <span class="p">{</span>

  <span class="kd">const</span> <span class="nx">idx</span> <span class="o">=</span> <span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">round</span><span class="p">(</span><span class="nx">y</span><span class="p">)</span> <span class="o">*</span> <span class="nx">screenBuffer</span><span class="p">.</span><span class="nx">width</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">round</span><span class="p">(</span><span class="nx">x</span><span class="p">))</span> <span class="o">*</span> <span class="mi">4</span><span class="p">;</span>

  <span class="nx">screenBuffer</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">idx</span> <span class="o">+</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">r</span><span class="p">;</span>
  <span class="nx">screenBuffer</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">idx</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">g</span><span class="p">;</span>
  <span class="nx">screenBuffer</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">idx</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="nx">b</span><span class="p">;</span>
  <span class="nx">screenBuffer</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">idx</span> <span class="o">+</span> <span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xff</span><span class="p">;</span>

<span class="p">}</span>

<span class="kd">function</span> <span class="nx">drawLine</span><span class="p">(</span><span class="nx">x0</span><span class="p">,</span> <span class="nx">y0</span><span class="p">,</span> <span class="nx">x1</span><span class="p">,</span> <span class="nx">y1</span><span class="p">,</span> <span class="nx">r</span><span class="p">,</span> <span class="nx">g</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">{</span>

  <span class="c1">// no line</span>
  <span class="k">if</span> <span class="p">(</span><span class="nx">x0</span> <span class="o">===</span> <span class="nx">x1</span> <span class="o">&amp;&amp;</span> <span class="nx">y1</span> <span class="o">===</span> <span class="nx">y0</span><span class="p">)</span>
    <span class="k">return</span><span class="p">;</span>

  <span class="c1">// step</span>
  <span class="kd">let</span> <span class="nx">step</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">/</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">abs</span><span class="p">(</span><span class="nx">x0</span> <span class="o">-</span> <span class="nx">x1</span><span class="p">),</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">abs</span><span class="p">(</span><span class="nx">y0</span> <span class="o">-</span> <span class="nx">y1</span><span class="p">));</span>

  <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span><span class="o">+=</span> <span class="nx">step</span><span class="p">){</span>
    <span class="kd">let</span> <span class="nx">x</span> <span class="o">=</span> <span class="nx">x0</span> <span class="o">+</span> <span class="nx">i</span> <span class="o">*</span> <span class="p">(</span><span class="nx">x1</span><span class="o">-</span><span class="nx">x0</span><span class="p">);</span>
    <span class="kd">let</span> <span class="nx">y</span> <span class="o">=</span> <span class="nx">y0</span> <span class="o">+</span> <span class="nx">i</span> <span class="o">*</span> <span class="p">(</span><span class="nx">y1</span><span class="o">-</span><span class="nx">y0</span><span class="p">);</span>
    <span class="nx">putPixel</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">r</span><span class="p">,</span> <span class="nx">g</span><span class="p">,</span> <span class="nx">b</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="positions-and-directions-in-homogenous-coordinates">Positions and Directions in Homogenous Coordinates</h3>

<p>In order to be able to add a rotation, a translation and a projection in a single matrix multiplication step, we extend our <code class="language-plaintext highlighter-rouge">[x, y, z]</code> notion of a point in 3D space to <code class="language-plaintext highlighter-rouge">[x, y, z, w]</code>, which is congruent to the <code class="language-plaintext highlighter-rouge">[x/w, y/w, z/w, 1]</code>. This division is, in fact, a projection from the 4D space to the 3D space.</p>

<p>For orthogonal transformations, e.g. world-space transformations, vectors that represent points have <code class="language-plaintext highlighter-rouge">w == 1</code> and vectors that represent directions, defined as <code class="language-plaintext highlighter-rouge">p1 - p2</code>, have their <code class="language-plaintext highlighter-rouge">w == 0</code>.</p>

<h3 id="rendering-full-triangles">Rendering Full Triangles</h3>

<p>The most exciting part of our blog post is about rendering full triangles. Before we dive into the actual shading, let’s say the obvious that we only care about the triangles that are facing us. So we do a simple test. This test is called back-face culling. This is why counter-clockwise convetion for defining faces is important. If we weren’t following it, we’d have the normals oriented in the opposite direction.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// world space backface culling</span>
<span class="kd">let</span> <span class="nx">faceNormal</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">crossProduct3</span><span class="p">(</span>
                      <span class="nx">subtractVector</span><span class="p">(</span><span class="nx">varrayW</span><span class="p">[</span><span class="nx">v2</span><span class="p">],</span> <span class="nx">varrayW</span><span class="p">[</span><span class="nx">v0</span><span class="p">]),</span>
                      <span class="nx">subtractVector</span><span class="p">(</span><span class="nx">varrayW</span><span class="p">[</span><span class="nx">v1</span><span class="p">],</span> <span class="nx">varrayW</span><span class="p">[</span><span class="nx">v0</span><span class="p">])</span>
                      <span class="p">));</span>
<span class="kd">let</span> <span class="nx">visible</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">cameraDir</span><span class="p">,</span> <span class="nx">faceNormal</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<p>We compute the face normal using the <code class="language-plaintext highlighter-rouge">crossProduct3</code> function which, given a plane (3 points), computes a fourth vector perpendicular to the others. Then we check to see if the face normal and the <code class="language-plaintext highlighter-rouge">cameraDir</code> face in the opposite direction. This is what the <code class="language-plaintext highlighter-rouge">dot</code> product does.</p>

<p>The remaining part is covered in the <code class="language-plaintext highlighter-rouge">drawTriangle</code> function. The algorithm is very simple and it fits very well on massively parallel hardware as all triangles can be processed in parallel.</p>
<ul>
  <li>Find a bounding box for our triangle</li>
  <li>Shade each point from the bounding box only if inside the triangle</li>
</ul>

<p>The parameters for the function are:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">v1, v2, v3</code> - triangle vertices transformed in screen space</li>
  <li><code class="language-plaintext highlighter-rouge">vn1, vn2, vn3</code> - vertex normals</li>
  <li><code class="language-plaintext highlighter-rouge">tx0, tx1, tx2</code> - texture coordinates for each vertex</li>
</ul>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">drawTriangle</span><span class="p">(</span><span class="nx">v1</span><span class="p">,</span> <span class="nx">v2</span><span class="p">,</span> <span class="nx">v3</span><span class="p">,</span> <span class="nx">vn1</span><span class="p">,</span> <span class="nx">vn2</span><span class="p">,</span> <span class="nx">vn3</span><span class="p">,</span> <span class="nx">tx0</span><span class="p">,</span> <span class="nx">tx1</span><span class="p">,</span> <span class="nx">tx2</span><span class="p">){</span>

    <span class="c1">// find the bounding box</span>
    <span class="kd">let</span> <span class="nx">bb</span> <span class="o">=</span> <span class="p">[</span><span class="nx">v1</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">v1</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">v1</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">v1</span><span class="p">[</span><span class="mi">1</span><span class="p">]];</span>
    <span class="kd">let</span> <span class="nx">v</span> <span class="o">=</span> <span class="p">[</span><span class="nx">v2</span><span class="p">,</span> <span class="nx">v3</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">v</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
      <span class="nx">bb</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">min</span><span class="p">(</span><span class="nx">bb</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">v</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]));</span>
      <span class="nx">bb</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">min</span><span class="p">(</span><span class="nx">bb</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">v</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]));</span>
      <span class="nx">bb</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">ceil</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="nx">bb</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">v</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]));</span>
      <span class="nx">bb</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">ceil</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="nx">bb</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="nx">v</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]));</span>
    <span class="p">}</span>

    <span class="c1">// check if the point is inside the triangle</span>
    <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">bb</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="nx">i</span> <span class="o">&lt;=</span> <span class="nx">bb</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span>
      <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">j</span> <span class="o">=</span> <span class="nx">bb</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> <span class="nx">j</span> <span class="o">&lt;=</span> <span class="nx">bb</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span> <span class="nx">j</span><span class="o">++</span><span class="p">){</span>

        <span class="kd">const</span> <span class="nx">stu</span> <span class="o">=</span> <span class="nx">toBarycentricCoords</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">j</span><span class="p">,</span> <span class="nx">v1</span><span class="p">,</span> <span class="nx">v2</span><span class="p">,</span> <span class="nx">v3</span><span class="p">);</span>

        <span class="k">if</span><span class="p">(</span><span class="nx">insideTriangle</span><span class="p">(</span><span class="nx">stu</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">stu</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">stu</span><span class="p">[</span><span class="mi">2</span><span class="p">]))</span> <span class="p">{</span>

          <span class="c1">// interpolate over the z coord</span>
          <span class="kd">const</span> <span class="nx">pixelZWorld</span> <span class="o">=</span> <span class="nx">stu</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="nx">v1</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="nx">stu</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="nx">v2</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="nx">stu</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">*</span> <span class="nx">v3</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
          <span class="kd">const</span> <span class="nx">zBufferIndex</span> <span class="o">=</span> <span class="nx">zBufferGetIdx</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">j</span><span class="p">);</span>

          <span class="k">if</span> <span class="p">(</span><span class="nx">pixelZWorld</span> <span class="o">&gt;=</span> <span class="nx">zBuffer</span><span class="p">[</span><span class="nx">zBufferIndex</span><span class="p">]){</span>
            <span class="nx">zBuffer</span><span class="p">[</span><span class="nx">zBufferIndex</span><span class="p">]</span> <span class="o">=</span> <span class="nx">pixelZWorld</span><span class="p">;</span>

            <span class="c1">// use again the barycentric coords to interpolate in the texture</span>
            <span class="c1">// matrix multiplication STU * [tx0, tx1, tx2]</span>
            <span class="kd">const</span> <span class="nx">tX</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">stu</span><span class="p">,</span> <span class="p">[</span><span class="nx">tx0</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">tx1</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">tx2</span><span class="p">[</span><span class="mi">0</span><span class="p">]]);</span>
            <span class="kd">const</span> <span class="nx">tY</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">stu</span><span class="p">,</span> <span class="p">[</span><span class="nx">tx0</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">tx1</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">tx2</span><span class="p">[</span><span class="mi">1</span><span class="p">]]);</span>

            <span class="p">[</span><span class="nx">tr</span><span class="p">,</span> <span class="nx">tg</span><span class="p">,</span> <span class="nx">tb</span><span class="p">]</span> <span class="o">=</span> <span class="nx">getTextureData</span><span class="p">(</span><span class="nx">tX</span><span class="p">,</span> <span class="nx">tY</span><span class="p">);</span>

            <span class="c1">// interpolate normals (all in world space)</span>
            <span class="kd">const</span> <span class="nx">n0</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">stu</span><span class="p">,</span> <span class="p">[</span><span class="nx">vn1</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">vn2</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">vn3</span><span class="p">[</span><span class="mi">0</span><span class="p">]]);</span>
            <span class="kd">const</span> <span class="nx">n1</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">stu</span><span class="p">,</span> <span class="p">[</span><span class="nx">vn1</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">vn2</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">vn3</span><span class="p">[</span><span class="mi">1</span><span class="p">]]);</span>
            <span class="kd">const</span> <span class="nx">n2</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">stu</span><span class="p">,</span> <span class="p">[</span><span class="nx">vn1</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">vn2</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">vn3</span><span class="p">[</span><span class="mi">2</span><span class="p">]]);</span>

            <span class="kd">let</span> <span class="nx">intensity</span> <span class="o">=</span> <span class="o">-</span><span class="nx">dot</span><span class="p">(</span><span class="nx">lightDir</span><span class="p">,</span> <span class="p">[</span><span class="nx">n0</span><span class="p">,</span> <span class="nx">n1</span><span class="p">,</span> <span class="nx">n2</span><span class="p">]);</span>
            <span class="kd">let</span> <span class="nx">c</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">intensity</span><span class="p">);</span>

            <span class="nx">putPixel</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">j</span><span class="p">,</span> <span class="nx">c</span> <span class="o">*</span> <span class="nx">tr</span><span class="p">,</span> <span class="nx">c</span> <span class="o">*</span> <span class="nx">tg</span><span class="p">,</span> <span class="nx">c</span> <span class="o">*</span> <span class="nx">tb</span><span class="p">);</span>
            <span class="c1">//putPixel(i, j, 255 * c , 255 * c , 255 * c ); // draw only the light intensity</span>
          <span class="p">}</span>
        <span class="p">}</span>
      <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The most interesting point of this function is transforming each pixel inside the triangle to its <a href="https://en.wikipedia.org/wiki/Barycentric_coordinate_system">barycentric coordinates</a>. These coordiantes are 3 numbers, <code class="language-plaintext highlighter-rouge">s, t, u</code>, which give weights to how close the point is to each vertex. That is, <code class="language-plaintext highlighter-rouge">v1</code> would have barycentric coordiantes of <code class="language-plaintext highlighter-rouge">1, 0, 0</code>, <code class="language-plaintext highlighter-rouge">v2</code> would have its barycentric coordinates at <code class="language-plaintext highlighter-rouge">0, 1, 0</code> and <code class="language-plaintext highlighter-rouge">v3</code> at <code class="language-plaintext highlighter-rouge">0, 0, 1</code>. Obviously, <code class="language-plaintext highlighter-rouge">s + t + u == 1</code> and they allow linear interpolation for each pixel based on values stored in the face vertices. If a pixel is outside of our triangle, at least of its barycentric coordinates is negative.</p>

<p>So what do we do if the pixel is inside the triangle:</p>

<ul>
  <li>
    <p>We check if the pixel is not under another pixel previously rendered (z-buffer check). We can simply interpolate the <code class="language-plaintext highlighter-rouge">z value</code> for the pixel and compare it with what is stored in the z-buffer. Since everything is already projected on the screen, we take the z directly without any other transformation.</p>
  </li>
  <li>
    <p>We interpolate between the texture coordiantes for each vertex and take the corresponding diffuse value.</p>
  </li>
  <li>
    <p>We interpolate between the normals of each vertex to compute a pixel normal and <code class="language-plaintext highlighter-rouge">dot</code> it with the light direction to see how much light falls on that point. This is called <code class="language-plaintext highlighter-rouge">Phong Shading</code>, as opposed to <code class="language-plaintext highlighter-rouge">Gouraud Shading</code> where the light is calculated per vertex and then interpolated over the surphace.</p>
  </li>
</ul>

<h3 id="what-else">What Else?</h3>

<p>Building the camera matrix, which is similar to the <code class="language-plaintext highlighter-rouge">gluLookAt</code> from OpenGL. The two functions are interesting becasue they show two things:</p>
<ul>
  <li>How to make the inverse of an homogenous orthogonal matrix based on the transposed rotation.</li>
  <li>How to extract the axes of abject. Axes are oriented on columns.</li>
</ul>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">inverseOrthogonalMatrix</span><span class="p">(</span><span class="nx">mtx</span><span class="p">){</span>

    <span class="c1">// inverse is the transpose of the rotation part and `-` the translation</span>

    <span class="kd">let</span> <span class="nx">x</span> <span class="o">=</span> <span class="nx">mtx</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
    <span class="kd">let</span> <span class="nx">y</span> <span class="o">=</span> <span class="nx">mtx</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span>
    <span class="kd">let</span> <span class="nx">z</span> <span class="o">=</span> <span class="nx">mtx</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">12</span><span class="p">);</span>

    <span class="kd">let</span> <span class="nx">rotate</span> <span class="o">=</span> <span class="p">[</span>
      <span class="nx">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">y</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">z</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span>
      <span class="nx">x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">y</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">z</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span>
      <span class="nx">x</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">y</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">z</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span>
      <span class="mi">0</span><span class="p">,</span>    <span class="mi">0</span><span class="p">,</span>    <span class="mi">0</span><span class="p">,</span>    <span class="mi">1</span>
    <span class="p">];</span>

    <span class="kd">let</span> <span class="nx">translate</span> <span class="o">=</span> <span class="p">[</span>
      <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="nx">x</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
      <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="nx">y</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
      <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="nx">z</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
      <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
    <span class="p">]</span>

    <span class="c1">// inverse = a) -translate followed by b) -rotate</span>
    <span class="k">return</span> <span class="nx">matrixMultiply</span><span class="p">(</span><span class="nx">rotate</span><span class="p">,</span> <span class="nx">translate</span><span class="p">);</span>

  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">makeCameraTransform</span><span class="p">(</span><span class="nx">camPos</span><span class="p">,</span> <span class="nx">camUp</span><span class="p">,</span> <span class="nx">camLookAt</span><span class="p">){</span>

    <span class="c1">// camera looks towards -z, so here we need to inverse camCenter and camPos</span>
    <span class="kd">let</span> <span class="nx">z</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">subtractVector</span><span class="p">(</span><span class="nx">camPos</span><span class="p">,</span> <span class="nx">camLookAt</span><span class="p">))</span>
    <span class="kd">let</span> <span class="nx">y</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">camUp</span><span class="p">);</span>
    <span class="kd">let</span> <span class="nx">x</span> <span class="o">=</span> <span class="nx">crossProduct3</span><span class="p">(</span><span class="nx">y</span><span class="p">,</span> <span class="nx">z</span><span class="p">);</span>
    <span class="nx">y</span> <span class="o">=</span> <span class="nx">crossProduct3</span><span class="p">(</span><span class="nx">z</span><span class="p">,</span> <span class="nx">x</span><span class="p">);</span>

    <span class="kd">let</span> <span class="nx">camWorld</span> <span class="o">=</span> <span class="p">[</span>
      <span class="nx">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">y</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">z</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">camPos</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
      <span class="nx">x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">y</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">z</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">camPos</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
      <span class="nx">x</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">y</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">z</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">camPos</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
      <span class="mi">0</span><span class="p">,</span>    <span class="mi">0</span><span class="p">,</span>    <span class="mi">0</span><span class="p">,</span>    <span class="mi">1</span><span class="p">,</span>
    <span class="p">]</span>

    <span class="nx">cameraDir</span> <span class="o">=</span> <span class="p">[</span><span class="nx">z</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">z</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">z</span><span class="p">[</span><span class="mi">2</span><span class="p">]];</span>

    <span class="kd">let</span> <span class="nx">ret</span> <span class="o">=</span> <span class="nx">inverseOrthogonalMatrix</span><span class="p">(</span><span class="nx">camWorld</span><span class="p">);</span>
    <span class="c1">//let identity = matrixMultiply(ret, camWorld); // debug</span>
    <span class="k">return</span> <span class="nx">ret</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div></div>

<p>The depth buffer is initialized to the same size as the whole canvas, based on floats. For faster computations it can be initialized to integer numbers, but then care must be taken to defining the resolution in the viewport matrix.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">zBuffer</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Float32Array</span><span class="p">(</span><span class="nx">cvs</span><span class="p">.</span><span class="nx">width</span> <span class="o">*</span> <span class="nx">cvs</span><span class="p">.</span><span class="nx">height</span><span class="p">);</span>
</code></pre></div></div>

<p>Making the render buffer is done as follows:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">makeFullScreenCanvas</span><span class="p">(){</span>

    <span class="kd">const</span> <span class="nx">cvs</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
    <span class="nx">cvs</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span><span class="p">;</span>
    <span class="nx">cvs</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span><span class="p">;</span>

    <span class="kd">const</span> <span class="nx">ctx</span> <span class="o">=</span> <span class="nx">cvs</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">"</span><span class="s2">2d</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">screenBuffer</span> <span class="o">=</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">createImageData</span><span class="p">(</span><span class="nx">cvs</span><span class="p">.</span><span class="nx">width</span><span class="p">,</span> <span class="nx">cvs</span><span class="p">.</span><span class="nx">height</span><span class="p">);</span>
    <span class="nx">zBuffer</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Float32Array</span><span class="p">(</span><span class="nx">cvs</span><span class="p">.</span><span class="nx">width</span> <span class="o">*</span> <span class="nx">cvs</span><span class="p">.</span><span class="nx">height</span><span class="p">);</span>

    <span class="nx">viewportTransform</span> <span class="o">=</span> <span class="nx">makeViewportTransform</span><span class="p">(</span><span class="nx">cvs</span><span class="p">.</span><span class="nx">width</span><span class="p">,</span> <span class="nx">cvs</span><span class="p">.</span><span class="nx">height</span><span class="p">);</span>
    <span class="nx">projectionTransform</span> <span class="o">=</span> <span class="nx">makeProjectionTransform</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="nx">cameraTransform</span> <span class="o">=</span> <span class="nx">makeCameraTransform</span><span class="p">([</span><span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]);</span>

    <span class="nx">render</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And, before we go, let’s have a look once again at our model with all the transformations applied - this should be the output of running the code from github.</p>

<p><img src="https://alexandrugris.github.io/assets/tiny_5.png" alt="Head" /></p>]]></content><author><name></name></author><category term="graphics" /><category term="3D" /><summary type="html"><![CDATA[This post is about implementing a 3D renderer from scratch, with no help from any graphics or maths library. It is implemented in pure JavaScript and it follows roughly the first half of the excellent tiny renderer tutorial.]]></summary></entry><entry><title type="html">WebGL Fun</title><link href="https://alexandrugris.github.io/graphics/3d/2020/04/15/intro-webgl.html" rel="alternate" type="text/html" title="WebGL Fun" /><published>2020-04-15T09:15:16+02:00</published><updated>2020-04-15T09:15:16+02:00</updated><id>https://alexandrugris.github.io/graphics/3d/2020/04/15/intro-webgl</id><content type="html" xml:base="https://alexandrugris.github.io/graphics/3d/2020/04/15/intro-webgl.html"><![CDATA[<p>A post about computer graphics, for the web mostly, with JavaScript, WebGL, ThreeJS and shaders. A little bit of maths also.</p>

<h3 id="threejs-introduction">ThreeJS Introduction</h3>

<p><a href="https://threejs.org/">ThreeJS</a> is a minimalistic 3D game engine for the web, with a very simple to use and very nicely designed API. It comes in the form of a javascript library, accompanied by a set of util libraries, a scene editor running on the web and lots and lots of examples an tutorials.</p>

<p>By the end of this blog post we will build this:</p>

<p><img src="https://alexandrugris.github.io/assets/webgl_2.png" alt="Three JS Editor" /></p>

<p>By default, ThreeJS already has built in materials for most of the effects one might want to add to a scene. I addition to what is already built in, there are lots of samples and pre-made effects in the form of libraries on github. Therefore, for most work, it be used entirely from JavaScript. While the API is clean and short and performs as expected, a little bit of maths and graphics background will still be needed sooner or later in the project.</p>

<p><img src="https://alexandrugris.github.io/assets/webgl_1.png" alt="Three JS Editor" /></p>

<h3 id="initialization-and-the-first-scene">Initialization and The First Scene</h3>

<p>The simplest way to run ThreeJS is to cover the full browser window. It goes like this:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
  <span class="c">&lt;!-- Run everything as a module --&gt;</span>
  <span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"module"</span><span class="nt">&gt;</span>

    <span class="k">import</span> <span class="p">{</span><span class="nx">main</span><span class="p">,</span> <span class="nx">resize</span><span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./js/complex_scene.js</span><span class="dl">"</span><span class="p">;</span>

    <span class="nb">window</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="nx">main</span><span class="p">;</span>
    <span class="nb">window</span><span class="p">.</span><span class="nx">onresize</span> <span class="o">=</span> <span class="nx">resize</span><span class="p">;</span>

  <span class="nt">&lt;/script&gt;</span>

<span class="nt">&lt;/head&gt;</span>

<span class="nt">&lt;body&gt;</span>
  <span class="c">&lt;!-- Full screen, positioned top-left corner --&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"webgl-container"</span> <span class="na">style=</span><span class="s">"position: absolute; top: 0; left:0 ; margin: 0"</span><span class="nt">&gt;&lt;/div&gt;</span>

<span class="nt">&lt;/body&gt;</span>

<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p>Then, in the JavaScript file:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// downloaded beforehand in the libs folder</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">THREE</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./libs/three.module.js</span><span class="dl">"</span> 

<span class="c1">// create new renderer</span>
<span class="kd">const</span> <span class="nx">renderer</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">WebGLRenderer</span><span class="p">();</span>

<span class="c1">// util for variable frame rate</span>
<span class="kd">const</span> <span class="nx">clock</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Clock</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>

</code></pre></div></div>

<p>We are also going to make use of the following two functions, as vectors are kept by reference in the ThreeJS code and, in many cases, we need copies to do transforms only on resulting vector, not on the source.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">newVector</span><span class="p">(</span><span class="nx">v</span><span class="p">){</span>
  <span class="k">return</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Vector3</span><span class="p">(</span><span class="nx">v</span><span class="p">.</span><span class="nx">x</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span> <span class="nx">v</span><span class="p">.</span><span class="nx">z</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">copyVector</span><span class="p">(</span><span class="nx">dest</span><span class="p">,</span> <span class="nx">src</span><span class="p">){</span>
  <span class="nx">dest</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">src</span><span class="p">.</span><span class="nx">x</span><span class="p">;</span>
  <span class="nx">dest</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="nx">src</span><span class="p">.</span><span class="nx">y</span><span class="p">;</span>
  <span class="nx">dest</span><span class="p">.</span><span class="nx">z</span> <span class="o">=</span> <span class="nx">src</span><span class="p">.</span><span class="nx">z</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now we can proceed further to initialization</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">function</span> <span class="nx">resize</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">renderer</span><span class="p">.</span><span class="nx">setSize</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span><span class="p">,</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span><span class="p">);</span>

    <span class="k">if</span><span class="p">(</span><span class="nx">camera</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">camera</span><span class="p">.</span><span class="nx">aspect</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span> <span class="o">/</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span><span class="p">;</span>
      <span class="nx">camera</span><span class="p">.</span><span class="nx">updateProjectionMatrix</span><span class="p">();</span> <span class="c1">// DON'T FORGET!</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>

  <span class="c1">// initialize the renderer</span>
  <span class="nx">renderer</span><span class="p">.</span><span class="nx">setSize</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span><span class="p">,</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span><span class="p">);</span>
  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">webgl-container</span><span class="dl">"</span><span class="p">).</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">domElement</span><span class="p">);</span>

  <span class="c1">// [LOAD SCENE HERE]</span>
  <span class="c1">// for the first demo will we create scene programatically,</span>
  <span class="c1">// for the second we load the scene as exported from the ThreeJS editor</span>

  <span class="c1">// if objects are loaded from the network, initScene should be async / awaited</span>
  <span class="nx">initScene</span><span class="p">();</span>
  <span class="nx">renderScene</span><span class="p">();</span>

<span class="p">}</span>

<span class="k">export</span> <span class="p">{</span> <span class="nx">main</span><span class="p">,</span> <span class="nx">resize</span> <span class="p">}</span>
</code></pre></div></div>

<p>We are also going to use the following global variables:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// the scene object</span>
<span class="kd">const</span> <span class="nx">scene</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Scene</span><span class="p">();</span>

<span class="c1">// a light, must be added to the scene if we want to see something</span>
<span class="kd">const</span> <span class="nx">light</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">AmbientLight</span><span class="p">(</span><span class="mh">0xffffff</span><span class="p">);</span>

<span class="c1">// a camera</span>
<span class="kd">let</span> <span class="nx">camera</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
</code></pre></div></div>

<p>Initialize them, add them to the scene:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">function</span> <span class="nx">initScene</span><span class="p">(){</span>

  <span class="c1">// 1. create the renderer and add its element to the scene</span>
  <span class="nx">renderer</span><span class="p">.</span><span class="nx">setSize</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span><span class="p">,</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span><span class="p">);</span>
  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">webgl-container</span><span class="dl">"</span><span class="p">).</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">domElement</span><span class="p">);</span>

  <span class="c1">// 2. create the camera, position it in the world and add it to the scene</span>
  <span class="nx">camera</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">PerspectiveCamera</span><span class="p">(</span><span class="mi">35</span><span class="p">,</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span><span class="o">/</span><span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
  <span class="nx">camera</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">z</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
  <span class="nx">scene</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">camera</span><span class="p">);</span>

  <span class="c1">// 3. add the light to the scene</span>
  <span class="nx">scene</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">light</span><span class="p">);</span>

  <span class="c1">// 4. Create an object. An object an item of the class THREE.Mesh()</span>
  <span class="c1">// It has two constituents: a geometry and a material</span>

  <span class="c1">// The geometry is created from the library of predefined geometries. </span>
  <span class="c1">// Check the docs for other prefedined geometries</span>

  <span class="c1">// The material is a single color (red) material, rendered in wireframe</span>
  <span class="c1">// wireframe property is set in the constructor.</span>
  <span class="c1">// ThreeJS predefines many materials for everyday use.  </span>
  <span class="kd">let</span> <span class="nx">box</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Mesh</span><span class="p">(</span>
    <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">BoxGeometry</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">20</span><span class="p">),</span>
    <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">MeshBasicMaterial</span><span class="p">(</span>
      <span class="p">{</span>
        <span class="na">color</span><span class="p">:</span> <span class="mh">0xff0000</span><span class="p">,</span>
        <span class="na">wireframe</span><span class="p">:</span> <span class="kc">true</span>
      <span class="p">})</span>
  <span class="p">);</span>

  <span class="c1">// 5. Give a name to my 3D object so we can find it in the scene later</span>
  <span class="nx">box</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">my-box</span><span class="dl">"</span><span class="p">;</span>

  <span class="c1">// 6. A super useful helper for debugging, the AxesHelper, shows the orientation of my 3D object.</span>
  <span class="c1">// This is added as a child to the box so it moves through the scene together with its parent.</span>
  <span class="nx">box</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">AxesHelper</span><span class="p">(</span><span class="mi">30</span><span class="p">));</span>

  <span class="c1">// 7. Add the box to the scene</span>
  <span class="nx">scene</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">box</span><span class="p">);</span>

  <span class="c1">// the next two objects will be detailed later</span>
  <span class="c1">// (a) how to create geometry programatically</span>
  <span class="c1">// (b) how to modify geometry programatically</span>
  <span class="nx">scene</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">createTriangleGeometry</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="kc">false</span><span class="p">));</span>
  <span class="nx">scene</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="k">new</span> <span class="nx">AnimatedPlaneGeometry</span><span class="p">());</span>

<span class="p">}</span>
</code></pre></div></div>

<p>Beside the <code class="language-plaintext highlighter-rouge">THREE.MeshBasicMaterial</code> shown above, which is a flat renderer, not affected by lights, ThreeJS comes with a powerful material library. Some of the classes discussed below:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">LineMaterial</code> - allows drawing lines</li>
  <li><code class="language-plaintext highlighter-rouge">LineDashMaterial</code> - allows drawing dashed lines</li>
  <li><code class="language-plaintext highlighter-rouge">MeshLambertMaterial</code> - basic per-vertex lighting, no specular</li>
  <li><code class="language-plaintext highlighter-rouge">MeshPhongMaterial</code> - per-pixel lighting, specular. Offers interesting properties for setting the diffuse texture, environment map, emissive, displacement map, bump map, light map, normal map, both object space and tangent space, etc.</li>
  <li><code class="language-plaintext highlighter-rouge">MeshToonMaterial</code> - toon shading</li>
  <li><code class="language-plaintext highlighter-rouge">MeshStandardMaterial</code> - physically-based rendering material</li>
  <li><code class="language-plaintext highlighter-rouge">SpriteMaterial</code> - rendering sprites</li>
  <li><code class="language-plaintext highlighter-rouge">DepthMaterial</code> - for rendering the depth buffer</li>
  <li><code class="language-plaintext highlighter-rouge">ShaderMaterial</code> - for custom shaders written in GLSL. We will use this material later on.</li>
</ul>

<p>The wide slection of materials available means that a lot can be done with just JavaScript, without touching any advanced rendering techniques or limiting custom rendering code to very special sections of your scene.</p>

<p>Redering the scene is super easy as well:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">render</span><span class="p">(){</span>

  <span class="c1">// 1. optinally call an update method</span>
  <span class="c1">// to update your scene based on the advance of time</span>
  <span class="nx">update</span><span class="p">(</span><span class="nx">clock</span><span class="p">.</span><span class="nx">getDelta</span><span class="p">())</span>

  <span class="c1">// 2. render the scene</span>
  <span class="nx">renderer</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="nx">scene</span><span class="p">,</span> <span class="nx">camera</span><span class="p">);</span>
  <span class="nx">requestAnimationFrame</span><span class="p">(</span><span class="nx">render</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="fun-with-vertices">Fun With Vertices</h3>

<p>We mentioned two more objects in the scene initialization code above:</p>

<ul>
  <li>Generating geometry</li>
  <li>Updating geometry</li>
</ul>

<p>Here it is how it goes:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">createTriangleGeometry</span><span class="p">(</span><span class="nx">size</span><span class="p">,</span> <span class="nx">singleColor</span> <span class="o">=</span> <span class="kc">false</span><span class="p">){</span>

  <span class="c1">// 1. Create a geometry object and push some vertices to it.</span>
  <span class="c1">// In this case we create a triangle</span>
  <span class="kd">let</span> <span class="nx">geom</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Geometry</span><span class="p">();</span>
  <span class="nx">geom</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Vector3</span><span class="p">(</span><span class="o">-</span><span class="nx">size</span> <span class="o">*</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="nx">geom</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Vector3</span><span class="p">(</span><span class="nx">size</span> <span class="o">*</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
  <span class="nx">geom</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">sqrt</span><span class="p">((</span><span class="mf">3.0</span> <span class="o">/</span> <span class="mf">4.0</span><span class="p">)</span> <span class="o">*</span> <span class="nx">size</span> <span class="o">*</span> <span class="nx">size</span> <span class="p">)),</span> <span class="mi">0</span><span class="p">);</span>

  <span class="c1">// 2. Set the indexes for each triangle constituting the geometry</span>
  <span class="c1">// In our case, we have a single face since we draw a single triangle</span>
  <span class="c1">// ThreeJS uses indexed geometries.</span>
  <span class="nx">geom</span><span class="p">.</span><span class="nx">faces</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Face3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span>

  <span class="kd">let</span> <span class="nx">mat</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>

  <span class="c1">// 3. Set the material properties</span>
  <span class="c1">// in the `else` case we setup vertex colors which will be sent to the shaders as</span>
  <span class="c1">// vertex color parameters.</span>
  <span class="k">if</span> <span class="p">(</span><span class="nx">singleColor</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">mat</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">MeshBasicMaterial</span><span class="p">({</span><span class="na">color</span><span class="p">:</span> <span class="mh">0x00ff00</span><span class="p">});</span>
  <span class="p">}</span>
  <span class="k">else</span><span class="p">{</span>
     <span class="nx">mat</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">MeshBasicMaterial</span><span class="p">({</span>
      <span class="na">side</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">DoubleSide</span><span class="p">,</span>
      <span class="na">vertexColors</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">VertexColors</span>
    <span class="p">})</span>

    <span class="nx">geom</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">vertexColors</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Color</span><span class="p">(</span><span class="mh">0xff0000</span><span class="p">);</span>
    <span class="nx">geom</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">vertexColors</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Color</span><span class="p">(</span><span class="mh">0x00ff00</span><span class="p">);</span>
    <span class="nx">geom</span><span class="p">.</span><span class="nx">faces</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">vertexColors</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Color</span><span class="p">(</span><span class="mh">0x0000ff</span><span class="p">);</span>

  <span class="p">}</span>

  <span class="c1">// 4. Return the mesh that can be added to the Scene</span>
  <span class="k">return</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Mesh</span><span class="p">(</span><span class="nx">geom</span><span class="p">,</span> <span class="nx">mat</span><span class="p">);</span>

  <span class="c1">// 5. Check out ExtrudeGeometry and ShapeGeometry and GeometryUtils </span>
  <span class="c1">// for different means and utilities for generating geometry in code</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And updating geometry on the fly:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nx">AnimatedPlaneGeometry</span> <span class="kd">extends</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Mesh</span><span class="p">{</span>

  <span class="kd">constructor</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// 1. initialize this geomerty as a plane</span>
    <span class="k">super</span><span class="p">(</span><span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">PlaneGeometry</span><span class="p">(</span><span class="mi">40</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">40</span><span class="p">),</span> 
          <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">MeshBasicMaterial</span><span class="p">({</span><span class="na">wireframe</span><span class="p">:</span> <span class="kc">true</span><span class="p">}))</span> <span class="p">;</span>
    
    <span class="c1">// 2. give it a name so it can be accessed from the scene</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">my-wave</span><span class="dl">"</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="nx">update</span><span class="p">(</span><span class="nx">dt</span><span class="p">){</span>

    <span class="c1">// 3. update the geometry, this is a sinosoidal wave</span>
    <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">geometry</span><span class="p">.</span><span class="nx">vertices</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
      <span class="k">this</span><span class="p">.</span><span class="nx">geometry</span><span class="p">.</span><span class="nx">vertices</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">z</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">sin</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">geometry</span><span class="p">.</span><span class="nx">vertices</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">x</span> <span class="o">+</span> <span class="mf">0.05</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="c1">// 4.: must call the following to update the geometry. </span>
    <span class="c1">// otherwise the buffers will not be updated</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">geometry</span><span class="p">.</span><span class="nx">verticesNeedUpdate</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>If all went well, with an update function like the following,</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">update</span><span class="p">(</span><span class="nx">dt</span><span class="p">){</span>
  <span class="kd">let</span> <span class="nx">box</span> <span class="o">=</span> <span class="nx">scene</span><span class="p">.</span><span class="nx">getObjectByName</span><span class="p">(</span><span class="dl">"</span><span class="s2">my-box</span><span class="dl">"</span><span class="p">);</span>
  <span class="nx">box</span><span class="p">.</span><span class="nx">rotation</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="mf">0.1</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span>

  <span class="kd">let</span> <span class="nx">wave</span> <span class="o">=</span> <span class="nx">scene</span><span class="p">.</span><span class="nx">getObjectByName</span><span class="p">(</span><span class="dl">"</span><span class="s2">my-wave</span><span class="dl">"</span><span class="p">);</span>
  <span class="nx">wave</span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">dt</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Something like the following scene should appear in the browser. The full code is in my github account, in the WebGL project.</p>

<p><img src="https://alexandrugris.github.io/assets/webgl_3.png" alt="JS Scene" /></p>

<p>The scene contains:</p>
<ul>
  <li>The red wireframe cube rotating (<code class="language-plaintext highlighter-rouge">my-box</code>) with the <code class="language-plaintext highlighter-rouge">AxesHelper</code> added and rotating with its parent.</li>
  <li>The waving plane, updated geometry (<code class="language-plaintext highlighter-rouge">my-wave</code>).</li>
  <li>The colorful triangle created on the fly.</li>
</ul>

<h3 id="shaders-and-rendering-of-the-earth">Shaders and Rendering Of The Earth</h3>

<p>Why the Earth? Because textures can be found free online, because rendering it requires some specific techniques, like skyboxes, normal mapping, lighting, atmosphere rendering and because the result is guaranteed to be beautiful.</p>

<p>A very good rendering of the Earth can be obtained by using materials already provided by the engine or by the community. However, since this was a pet project, we are doing many things from scratch. Also, being a pet project written among other things, the code is not production ready. I have not tested it on other computer except for my laptop which is quite powerful. Also, I have not optimized the code. It’s just the first thing that worked.</p>

<h3 id="loading-the-scene">Loading the Scene</h3>

<p>Unlike the previous example where we built the scene manually, here I created it in the ThreeJS editor and then exported it. The loading code goes like this:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>

  <span class="c1">//1. initialize the renderer</span>
  <span class="nx">renderer</span><span class="p">.</span><span class="nx">setSize</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span><span class="p">,</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span><span class="p">);</span>
  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">webgl-container</span><span class="dl">"</span><span class="p">).</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">domElement</span><span class="p">);</span>

  <span class="c1">//2. load the scene from editor exported objects</span>
  <span class="nx">scene</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">loadObject</span><span class="p">(</span><span class="dl">"</span><span class="s2">./assets/earth_and_water.json</span><span class="dl">"</span><span class="p">);</span>
  <span class="nx">camera</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">loadObject</span><span class="p">(</span><span class="dl">"</span><span class="s2">./assets/camera.json</span><span class="dl">"</span><span class="p">);</span>

  <span class="c1">//3. fix the camera, the camera has also been loaded from JSON, but its parameters</span>
  <span class="c1">// neeed to be adjusted to our viewport</span>
  <span class="nx">camera</span><span class="p">.</span><span class="nx">aspect</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span><span class="o">/</span><span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span><span class="p">;</span>
  <span class="nx">camera</span><span class="p">.</span><span class="nx">updateProjectionMatrix</span><span class="p">();</span>
  <span class="nx">camera</span><span class="p">.</span><span class="nx">updateMatrixWorld</span><span class="p">();</span>

  <span class="c1">//4. load the FlyControls library (premade) so we can move through the scene</span>
  <span class="nx">cameraControls</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FlyControls</span><span class="p">(</span><span class="nx">camera</span><span class="p">,</span> <span class="nx">renderer</span><span class="p">.</span><span class="nx">domElement</span><span class="p">);</span>
  <span class="nx">cameraControls</span><span class="p">.</span><span class="nx">dragToLook</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
  <span class="nx">cameraControls</span><span class="p">.</span><span class="nx">movementSpeed</span> <span class="o">=</span> <span class="mf">4.0</span><span class="p">;</span> <span class="c1">// scene-units per second</span>
  <span class="nx">cameraControls</span><span class="p">.</span><span class="nx">rollSpeed</span> <span class="o">=</span> <span class="mf">0.1</span><span class="p">;</span> <span class="c1">// radians per second</span>

  <span class="c1">//5. the skybox requires separate treatment, will be coved later in the post</span>
  <span class="c1">// her we remove it from the scene </span>
  <span class="nx">skybox</span> <span class="o">=</span> <span class="nx">scene</span><span class="p">.</span><span class="nx">getObjectByName</span><span class="p">(</span><span class="dl">'</span><span class="s1">SkyBox</span><span class="dl">'</span><span class="p">);</span>
  <span class="nx">scene</span><span class="p">.</span><span class="nx">remove</span><span class="p">(</span><span class="nx">skybox</span><span class="p">);</span>

  <span class="c1">//6. we are also fixing the atmosphere and make it a child of the earth so the move together</span>
  <span class="nx">earth</span> <span class="o">=</span> <span class="nx">scene</span><span class="p">.</span><span class="nx">getObjectByName</span><span class="p">(</span><span class="dl">"</span><span class="s2">Earth</span><span class="dl">"</span><span class="p">);</span>
  <span class="nx">atmosphere</span> <span class="o">=</span> <span class="nx">scene</span><span class="p">.</span><span class="nx">getObjectByName</span><span class="p">(</span><span class="dl">"</span><span class="s2">Atmosphere</span><span class="dl">"</span><span class="p">);</span>
  <span class="nx">scene</span><span class="p">.</span><span class="nx">remove</span><span class="p">(</span><span class="nx">atmosphere</span><span class="p">);</span>
  <span class="nx">earth</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">atmosphere</span><span class="p">);</span>

  <span class="c1">//7. setup the shaders</span>
  <span class="nx">fixMaterials</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>

    <span class="c1">// 8. since we have a skybox rendered as a separate step</span>
    <span class="c1">// we don't want to renderer to erase the scene for us between rendering</span>
    <span class="c1">// also part of the rendering of the skybox</span>
    <span class="nx">renderer</span><span class="p">.</span><span class="nx">autoClear</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
    <span class="nx">scene</span><span class="p">.</span><span class="nx">background</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>

    <span class="c1">// 9. start the renderign loop</span>
    <span class="nx">render</span><span class="p">()</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>For loading the scene and the textures we are going to use two functions:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">loadObject</span><span class="p">(</span><span class="nx">json</span><span class="p">){</span>
  <span class="kd">let</span> <span class="nx">objLoader</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">ObjectLoader</span><span class="p">();</span>
  <span class="k">return</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">(</span> <span class="p">(</span><span class="nx">accept</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">objLoader</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">json</span><span class="p">,</span> <span class="nx">accept</span><span class="p">,</span> <span class="kc">null</span> <span class="p">,</span><span class="nx">reject</span><span class="p">));</span>
<span class="p">}</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nx">loadTexture</span><span class="p">(</span><span class="nx">texture</span><span class="p">){</span>
  <span class="kd">let</span> <span class="nx">imgLoader</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">TextureLoader</span><span class="p">();</span>
  <span class="k">return</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">(</span> <span class="p">(</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">imgLoader</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">texture</span><span class="p">,</span> <span class="p">(</span><span class="nx">tex</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>

    <span class="c1">// here we are intercepting the texture loader</span>
    <span class="c1">// we want the textures to be as beautifully rendered as possible at the cost of performance</span>
    <span class="c1">// therefore, we use the highest anisotropy level the renderer provides</span>
    <span class="c1">// for my device, it is 16</span>
    <span class="c1">// this makes the textures look sharp when seen from the side</span>
    <span class="c1">// https://en.wikipedia.org/wiki/Texture_filtering#Anisotropic_filtering</span>
    <span class="nx">tex</span><span class="p">.</span><span class="nx">anisotropy</span> <span class="o">=</span> <span class="nx">renderer</span><span class="p">.</span><span class="nx">capabilities</span><span class="p">.</span><span class="nx">getMaxAnisotropy</span><span class="p">();</span>
    <span class="nx">resolve</span><span class="p">(</span><span class="nx">tex</span><span class="p">);</span>
    <span class="p">},</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">reject</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Setting up a shader is performed in the <code class="language-plaintext highlighter-rouge">fixMaterials</code> function. Its basic structure as as follows:</p>

<ol>
  <li>Define the set of uniforms and bind them to JS variables. Uniforms are the variables that are set in code and submitted on each rendering pass to the shading programs.</li>
  <li>Create a <code class="language-plaintext highlighter-rouge">ShaderMaterial</code></li>
  <li>Set the uniforms and then load the vertex shader and the pixel shaders. In our case, we store these in our DOM tree, in the html file.</li>
</ol>

<p>Let’s perform these steps to render the sky dome. In our case it’s a sphere, not box.</p>

<h3 id="skydome-and-light">SkyDome And Light</h3>

<ol>
  <li>Setting up the uniforms:</li>
</ol>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">fixMaterials</span><span class="p">()</span> <span class="p">{</span>

  <span class="c1">// first is the SkyBox</span>
  <span class="nx">skyBoxUniforms</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">diffuseTexture</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">t</span><span class="dl">"</span><span class="p">,</span>
      <span class="na">value</span><span class="p">:</span> <span class="k">await</span> <span class="nx">loadTexture</span><span class="p">(</span><span class="dl">"</span><span class="s2">./assets/sky/sky_at_night.jpg</span><span class="dl">"</span><span class="p">)</span>
    <span class="p">},</span>
  <span class="p">}</span>

  <span class="p">[...</span> <span class="nx">more</span> <span class="nx">to</span> <span class="nx">come</span> <span class="nx">here</span> <span class="p">...]</span>
</code></pre></div></div>

<ol>
  <li>Create the <code class="language-plaintext highlighter-rouge">ShaderMaterial</code>:</li>
</ol>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nx">skybox</span><span class="p">.</span><span class="nx">material</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">ShaderMaterial</span><span class="p">({</span>

    <span class="c1">// a) set the uniforms</span>
    <span class="na">uniforms</span><span class="p">:</span> <span class="nx">skyBoxUniforms</span><span class="p">,</span>

    <span class="c1">// b) load the vertex and pixel shader from the HTML DOM</span>
    <span class="na">vertexShader</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">skyBoxVertexShader</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerText</span><span class="p">,</span>
    <span class="na">fragmentShader</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">skyBoxFragmentShader</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerText</span><span class="p">,</span>

    <span class="c1">// c) set other parameters</span>
    <span class="c1">// In our case, always show the skybox behind all other objects</span>
    <span class="na">depthTest</span> <span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
    <span class="na">depthWrite</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>

    <span class="c1">// d) we are always inside the box</span>
    <span class="na">side</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">BackSide</span><span class="p">,</span>

  <span class="p">});</span>
</code></pre></div></div>

<p>Rendering the skybox is a bit trick as the following are done:</p>

<ul>
  <li>The skybox is always as at the same distance from the camera. We don’t get closer to it, we don’t get further from it. It moves with the camera.</li>
  <li>The skybox is behind any object in the scene, it cannot intersect any object. Thus we don’t update the the Z-buffer and we don’t read from it. We render the skybox as a separate step and we don’t erase the background between rendering the skybox and rendering the rest of the scene.</li>
</ul>

<p>Here’s how the rendering loop looks like:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">render</span><span class="p">(){</span>

<span class="c1">// 1. update the scene, geometries, etc</span>
  <span class="nx">update</span><span class="p">(</span><span class="nx">clock</span><span class="p">.</span><span class="nx">getDelta</span><span class="p">())</span>

<span class="c1">// 2. clear the background</span>
  <span class="nx">renderer</span><span class="p">.</span><span class="nx">clear</span><span class="p">();</span>

<span class="c1">// 3. render the skybox</span>
  <span class="k">if</span><span class="p">(</span><span class="nx">skybox</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">){</span>
    <span class="nx">renderer</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="nx">skybox</span><span class="p">,</span> <span class="nx">camera</span><span class="p">);</span>
  <span class="p">}</span>

<span class="c1">// 4. without clearing the background, render the rest of the scene</span>
  <span class="nx">renderer</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="nx">scene</span><span class="p">,</span> <span class="nx">camera</span><span class="p">);</span>
  <span class="nx">requestAnimationFrame</span><span class="p">(</span><span class="nx">render</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The shaders for the skybox are super straight forward, as we don’t apply any lighting to it.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"x-shader/x-vertex"</span> <span class="na">id=</span><span class="s">"skyBoxVertexShader"</span><span class="nt">&gt;</span>

    <span class="nx">uniform</span> <span class="nx">vec3</span>          <span class="nx">lightDirection</span><span class="p">;</span>
    <span class="nx">uniform</span> <span class="nx">vec3</span>          <span class="nx">cameraDirection</span><span class="p">;</span>

    <span class="nx">varying</span> <span class="nx">vec2</span>          <span class="nx">vUv</span><span class="p">;</span> <span class="c1">// pass the uv coordinates of each vertex to the frag shader</span>
    <span class="nx">varying</span> <span class="nx">float</span>         <span class="nx">lightIntensity</span><span class="p">;</span>

    <span class="k">void</span> <span class="nx">main</span><span class="p">()</span>
    <span class="p">{</span>
      <span class="nx">vUv</span> <span class="o">=</span> <span class="nx">uv</span><span class="p">;</span>
      <span class="nx">gl_Position</span> <span class="o">=</span> <span class="nx">projectionMatrix</span> <span class="o">*</span> <span class="nx">modelViewMatrix</span> <span class="o">*</span> <span class="nx">vec4</span><span class="p">(</span><span class="nx">position</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span>

      <span class="c1">// artistic effect: dim when looking at the light source</span>
      <span class="c1">// no special reason for the effect, just feel nicer</span>
      <span class="c1">// it should be computed outside the shader</span>
      <span class="nx">float</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">normalize</span><span class="p">(</span><span class="nx">cameraDirection</span><span class="p">),</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">lightDirection</span><span class="p">));</span>
      <span class="nx">lightIntensity</span> <span class="o">=</span> <span class="nx">clamp</span><span class="p">(</span><span class="nx">i</span> <span class="o">*</span> <span class="nx">i</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="nt">&lt;/script&gt;</span>

  <span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"x-shader/x-fragment"</span> <span class="na">id=</span><span class="s">"skyBoxFragmentShader"</span><span class="nt">&gt;</span>
    <span class="nx">uniform</span> <span class="nx">sampler2D</span> <span class="nx">diffuseTexture</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec2</span> <span class="nx">vUv</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">float</span> <span class="nx">lightIntensity</span><span class="p">;</span>

    <span class="k">void</span> <span class="nx">main</span><span class="p">()</span>
    <span class="p">{</span>
      <span class="nx">gl_FragColor</span> <span class="o">=</span> <span class="nx">texture2D</span><span class="p">(</span><span class="nx">diffuseTexture</span><span class="p">,</span> <span class="nx">vUv</span><span class="p">)</span> <span class="o">*</span> <span class="nx">lightIntensity</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Now, the trickery has not yet finished. We have a sun that needs to stick to the skybox when the skybox rotates and moves through the scene, remember it is bound to the camera, and we want to make sure the light direction is preserved and it accurately comes from the sun. So we do these updates in the update method.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">function</span> <span class="nx">update</span><span class="p">(</span><span class="nx">dt</span><span class="p">){</span>

  <span class="c1">// 1. Allow the camera to move</span>
  <span class="k">if</span><span class="p">(</span><span class="nx">cameraControls</span><span class="p">){</span>
    <span class="nx">cameraControls</span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">dt</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="c1">// 2. ensure the sun and the light have the same direction and they stick to the skybox</span>
  <span class="kd">let</span> <span class="nx">sunLight</span> <span class="o">=</span> <span class="nx">scene</span><span class="p">.</span><span class="nx">getObjectByName</span><span class="p">(</span><span class="dl">'</span><span class="s1">sun_light</span><span class="dl">'</span><span class="p">);</span>
  <span class="kd">let</span> <span class="nx">sunSprite</span> <span class="o">=</span> <span class="nx">scene</span><span class="p">.</span><span class="nx">getObjectByName</span><span class="p">(</span><span class="dl">'</span><span class="s1">sun_sprite</span><span class="dl">'</span><span class="p">);</span>

  <span class="kd">let</span> <span class="nx">lightPos</span> <span class="o">=</span> <span class="nx">sunLight</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">normalize</span><span class="p">();</span>
  <span class="kd">let</span> <span class="nx">lightPosU</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Uniform</span><span class="p">(</span><span class="nx">newVector</span><span class="p">(</span><span class="nx">lightPos</span><span class="p">));</span>

  <span class="k">if</span><span class="p">(</span><span class="nx">skybox</span><span class="p">)</span> <span class="p">{</span>

      <span class="nx">copyVector</span><span class="p">(</span><span class="nx">skybox</span><span class="p">.</span><span class="nx">position</span><span class="p">,</span> <span class="nx">camera</span><span class="p">.</span><span class="nx">position</span><span class="p">);</span>
      <span class="nx">skybox</span><span class="p">.</span><span class="nx">rotation</span><span class="p">.</span><span class="nx">x</span> <span class="o">+=</span> <span class="mf">0.005</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span>
      <span class="nx">skybox</span><span class="p">.</span><span class="nx">rotation</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="o">-</span><span class="mf">0.1</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span>

      <span class="kd">let</span> <span class="nx">cameraDir</span> <span class="o">=</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Vector3</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">setFromMatrixColumn</span><span class="p">(</span><span class="nx">camera</span><span class="p">.</span><span class="nx">matrixWorld</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span><span class="nx">normalize</span><span class="p">();</span>

      <span class="nx">skyBoxUniforms</span><span class="p">.</span><span class="nx">lightDirection</span> <span class="o">=</span> <span class="nx">lightPosU</span><span class="p">;</span>
      <span class="nx">skyBoxUniforms</span><span class="p">.</span><span class="nx">cameraDirection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Uniform</span><span class="p">(</span><span class="nx">cameraDir</span><span class="p">);</span>


      <span class="nx">skybox</span><span class="p">.</span><span class="nx">updateMatrixWorld</span><span class="p">();</span>

      <span class="c1">// keep the sun in the same place in the sky</span>
      <span class="k">if</span> <span class="p">(</span><span class="nx">sunSprite</span><span class="p">.</span><span class="nx">originalPositionSkyboxSpace</span> <span class="o">===</span> <span class="kc">undefined</span><span class="p">){</span>
        <span class="c1">// the sun sprite</span>
        <span class="kd">let</span> <span class="nx">invWorld</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Matrix4</span><span class="p">();</span>

        <span class="nx">sunSprite</span><span class="p">.</span><span class="nx">originalPositionSkyboxSpace</span> <span class="o">=</span> <span class="nx">newVector</span><span class="p">(</span><span class="nx">sunSprite</span><span class="p">.</span><span class="nx">position</span><span class="p">);</span>
        <span class="nx">sunSprite</span><span class="p">.</span><span class="nx">originalPositionSkyboxSpace</span><span class="p">.</span><span class="nx">applyMatrix4</span><span class="p">(</span><span class="nx">invWorld</span><span class="p">.</span><span class="nx">getInverse</span><span class="p">(</span><span class="nx">skybox</span><span class="p">.</span><span class="nx">matrixWorld</span><span class="p">));</span>
        <span class="nx">sunSprite</span><span class="p">.</span><span class="nx">originalSkyboxPosition</span> <span class="o">=</span> <span class="nx">newVector</span><span class="p">(</span><span class="nx">skybox</span><span class="p">.</span><span class="nx">position</span><span class="p">);</span>
      <span class="p">}</span>

      <span class="c1">// make sure the light comes from the sun and not some random point</span>
      <span class="kd">let</span> <span class="nx">newPos</span> <span class="o">=</span> <span class="nx">newVector</span><span class="p">(</span><span class="nx">sunSprite</span><span class="p">.</span><span class="nx">originalPositionSkyboxSpace</span><span class="p">);</span>
      <span class="nx">newPos</span><span class="p">.</span><span class="nx">applyMatrix4</span><span class="p">(</span><span class="nx">skybox</span><span class="p">.</span><span class="nx">matrixWorld</span><span class="p">);</span>
      <span class="nx">copyVector</span><span class="p">(</span><span class="nx">sunSprite</span><span class="p">.</span><span class="nx">position</span><span class="p">,</span> <span class="nx">newPos</span><span class="p">);</span>
      <span class="nx">sunSprite</span><span class="p">.</span><span class="nx">updateMatrixWorld</span><span class="p">();</span>

      <span class="nx">lightPos</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Vector3</span><span class="p">();</span>
      <span class="kd">let</span> <span class="nx">skyboxMovement</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Vector3</span><span class="p">();</span>
      <span class="nx">skyboxMovement</span><span class="p">.</span><span class="nx">subVectors</span><span class="p">(</span><span class="nx">skybox</span><span class="p">.</span><span class="nx">position</span><span class="p">,</span> <span class="nx">sunSprite</span><span class="p">.</span><span class="nx">originalSkyboxPosition</span><span class="p">);</span>
      <span class="nx">lightPos</span><span class="p">.</span><span class="nx">subVectors</span><span class="p">(</span><span class="nx">sunSprite</span><span class="p">.</span><span class="nx">position</span><span class="p">,</span> <span class="nx">skyboxMovement</span><span class="p">);</span>
      <span class="nx">copyVector</span><span class="p">(</span><span class="nx">sunLight</span><span class="p">.</span><span class="nx">position</span><span class="p">,</span> <span class="nx">lightPos</span><span class="p">);</span>
  <span class="p">}</span>
</code></pre></div></div>

<h3 id="rendering-the-earth">Rendering the Earth</h3>

<p>Now, rendering of the Earth and its atmosphere can vastly be improved, especially perfomance-wise. But I am running out of vacation time and I really want to finish this project today so I stop at the current implementation. Some quick wins:</p>

<ul>
  <li>Make lighting done in tangent space. It will reduce some matrix multiplications in the pixel shader.</li>
  <li>Make the atmosphere rendering per-pixel. Now the atmosphere thickness is computed per vertex and this gives some ugly artefacts.</li>
  <li>Tune the clouds and their shadows. While the shadow moves correctly with the camera, when they are brightly lit or when they are not fully lit there are some visual artefacts.</li>
</ul>

<p>But let’s start with the Earth.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 1. setup the uniforms, load the textures</span>
<span class="nx">earthUniforms</span> <span class="o">=</span> <span class="p">{</span>

    <span class="na">diffuseTexture</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">t</span><span class="dl">"</span><span class="p">,</span>
      <span class="na">value</span><span class="p">:</span> <span class="k">await</span> <span class="nx">loadTexture</span><span class="p">(</span><span class="dl">"</span><span class="s2">./assets/earth/earth_diffuse.jpg</span><span class="dl">"</span><span class="p">)</span>
    <span class="p">},</span>

    <span class="na">diffuseNight</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">t</span><span class="dl">"</span><span class="p">,</span>
      <span class="na">value</span><span class="p">:</span> <span class="k">await</span> <span class="nx">loadTexture</span><span class="p">(</span><span class="dl">"</span><span class="s2">./assets/earth/earth_diffuse_night.jpg</span><span class="dl">"</span><span class="p">)</span>
    <span class="p">},</span>

    <span class="na">normalMap</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">t</span><span class="dl">"</span><span class="p">,</span>
      <span class="na">value</span><span class="p">:</span> <span class="k">await</span> <span class="nx">loadTexture</span><span class="p">(</span><span class="dl">"</span><span class="s2">./assets/earth/earth_normal_map.png</span><span class="dl">"</span><span class="p">)</span>
    <span class="p">},</span>

    <span class="na">specularMap</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">t</span><span class="dl">"</span><span class="p">,</span>
      <span class="na">value</span><span class="p">:</span> <span class="k">await</span> <span class="nx">loadTexture</span><span class="p">(</span> <span class="dl">"</span><span class="s2">./assets/earth/earth_specular_map.png</span><span class="dl">"</span><span class="p">)</span>
    <span class="p">},</span>

    <span class="na">cloudsMap</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">t</span><span class="dl">"</span><span class="p">,</span>
      <span class="na">value</span><span class="p">:</span> <span class="k">await</span> <span class="nx">loadTexture</span><span class="p">(</span> <span class="dl">"</span><span class="s2">./assets/earth/clouds1.jpg</span><span class="dl">"</span><span class="p">)</span>
    <span class="p">}</span>

  <span class="p">}</span>

<span class="c1">// 2. Cheat a bit and use a library function to compute the tangets</span>
<span class="c1">// We will be using tangent-space normal mapping. The function was too easy to grab </span>
<span class="c1">// not to use it.</span>

<span class="nx">BufferGeometryUtils</span><span class="p">.</span><span class="nx">computeTangents</span><span class="p">(</span><span class="nx">earth</span><span class="p">.</span><span class="nx">geometry</span><span class="p">);</span>

<span class="c1">// 3. setup the vertex shader and the fragment shader</span>
<span class="nx">earth</span><span class="p">.</span><span class="nx">material</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">ShaderMaterial</span><span class="p">({</span>

    <span class="na">uniforms</span><span class="p">:</span> <span class="nx">earthUniforms</span><span class="p">,</span>

    <span class="na">vertexShader</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">earthVertexShader</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerText</span><span class="p">,</span>
    <span class="na">fragmentShader</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">earthFragmentShader</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerText</span><span class="p">,</span>

    <span class="na">side</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">FrontSide</span>

  <span class="p">});</span>
</code></pre></div></div>

<p>In the update function, we also update the position and we bind the updated light position to the shader:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">update</span><span class="p">(</span><span class="nx">dt</span><span class="p">){</span>

  <span class="p">[....]</span>

  <span class="k">if</span><span class="p">(</span><span class="nx">earth</span><span class="p">){</span>
    <span class="nx">earthUniforms</span><span class="p">.</span><span class="nx">lightDirection</span> <span class="o">=</span> <span class="nx">lightPosU</span><span class="p">;</span>
    <span class="nx">earth</span><span class="p">.</span><span class="nx">rotation</span><span class="p">.</span><span class="nx">x</span> <span class="o">-=</span> <span class="mf">0.001</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span> <span class="c1">// some rotation</span>
    <span class="nx">earth</span><span class="p">.</span><span class="nx">rotation</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="mf">0.05</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And the shaders, with comments:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&lt;</span><span class="nx">script</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">x-shader/x-vertex</span><span class="dl">"</span> <span class="nx">id</span><span class="o">=</span><span class="dl">"</span><span class="s2">earthVertexShader</span><span class="dl">"</span><span class="o">&gt;</span>

    <span class="nx">uniform</span> <span class="nx">vec3</span> <span class="nx">lightDirection</span><span class="p">;</span>

    <span class="c1">// send to fragment shader</span>
    <span class="c1">// all in eye space</span>
    <span class="nx">varying</span> <span class="nx">vec2</span> <span class="nx">vUv</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec3</span> <span class="nx">vEyeDirectionEyeSpace</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec3</span> <span class="nx">vLightDirection</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">mat3</span> <span class="nx">tbn</span><span class="p">;</span>

    <span class="c1">// the tangent, sent per-vertex </span>
    <span class="nx">attribute</span> <span class="nx">vec4</span> <span class="nx">tangent</span><span class="p">;</span>

    <span class="k">void</span> <span class="nx">main</span><span class="p">(){</span>

      <span class="c1">// 1. copy the texture coordinates</span>
      <span class="nx">vUv</span> <span class="o">=</span> <span class="nx">uv</span><span class="p">;</span>

      <span class="c1">// 2. update the position</span>
      <span class="nx">gl_Position</span> <span class="o">=</span> <span class="nx">projectionMatrix</span> <span class="o">*</span> <span class="nx">modelViewMatrix</span> <span class="o">*</span> <span class="nx">vec4</span><span class="p">(</span><span class="nx">position</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span>

      <span class="c1">// 3. compute the light direction from world to eye;</span>
      <span class="c1">// should be computed outside of shader for performance</span>
      <span class="nx">vLightDirection</span> <span class="o">=</span> <span class="nx">mat3</span><span class="p">(</span><span class="nx">viewMatrix</span><span class="p">)</span> <span class="o">*</span> <span class="nx">lightDirection</span><span class="p">;</span> 

      <span class="c1">// 4. compute the direction to the eye</span>
      <span class="nx">vEyeDirectionEyeSpace</span> <span class="o">=</span> <span class="nx">mat3</span><span class="p">(</span><span class="nx">viewMatrix</span><span class="p">)</span> <span class="o">*</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">position</span> <span class="o">-</span> <span class="nx">cameraPosition</span><span class="p">).</span><span class="nx">xyz</span><span class="p">;</span>

      <span class="c1">// 5. prepare the tangent-bitangent-normal matrix for normal mapping</span>
      <span class="nx">vec3</span> <span class="nx">t</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">tangent</span><span class="p">.</span><span class="nx">xyz</span><span class="p">);</span>
      <span class="nx">vec3</span> <span class="nx">n</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">normal</span><span class="p">.</span><span class="nx">xyz</span><span class="p">);</span>
      <span class="nx">vec3</span> <span class="nx">b</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">cross</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">n</span><span class="p">));</span>

      <span class="c1">// everything in eye space</span>
      <span class="nx">t</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">normalMatrix</span> <span class="o">*</span> <span class="nx">t</span><span class="p">);</span>
      <span class="nx">b</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">normalMatrix</span> <span class="o">*</span> <span class="nx">b</span><span class="p">);</span>
      <span class="nx">n</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">normalMatrix</span> <span class="o">*</span> <span class="nx">n</span><span class="p">);</span>

      <span class="nx">tbn</span> <span class="o">=</span> <span class="nx">mat3</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">b</span><span class="p">,</span> <span class="nx">n</span><span class="p">);</span>
    <span class="p">}</span>

<span class="o">&lt;</span><span class="sr">/script</span><span class="err">&gt;
</span>
<span class="o">&lt;</span><span class="nx">script</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">x-shader/x-fragment</span><span class="dl">"</span> <span class="nx">id</span><span class="o">=</span><span class="dl">"</span><span class="s2">earthFragmentShader</span><span class="dl">"</span><span class="o">&gt;</span>

    <span class="c1">// all my textures</span>
    <span class="nx">uniform</span> <span class="nx">sampler2D</span> <span class="nx">diffuseTexture</span><span class="p">;</span>
    <span class="nx">uniform</span> <span class="nx">sampler2D</span> <span class="nx">diffuseNight</span><span class="p">;</span>
    <span class="nx">uniform</span> <span class="nx">sampler2D</span> <span class="nx">specularMap</span><span class="p">;</span>
    <span class="nx">uniform</span> <span class="nx">sampler2D</span> <span class="nx">cloudsMap</span><span class="p">;</span>
    <span class="nx">uniform</span> <span class="nx">sampler2D</span> <span class="nx">normalMap</span><span class="p">;</span>

    <span class="c1">// inputs, interpolated per vertex</span>
    <span class="nx">varying</span> <span class="nx">vec2</span> <span class="nx">vUv</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec3</span> <span class="nx">vEyeDirectionEyeSpace</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec3</span> <span class="nx">vLightDirection</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">mat3</span> <span class="nx">tbn</span><span class="p">;</span>

    <span class="k">void</span> <span class="nx">main</span><span class="p">(){</span>


      <span class="nx">vec3</span> <span class="nx">lightDir</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">vLightDirection</span><span class="p">);</span>

      <span class="c1">// 1. compute the normal based on the texture and bring it to eye space</span>
      <span class="nx">vec3</span> <span class="nx">n</span> <span class="o">=</span> <span class="nx">texture2D</span><span class="p">(</span><span class="nx">normalMap</span><span class="p">,</span> <span class="nx">vUv</span><span class="p">).</span><span class="nx">xyz</span> <span class="o">*</span> <span class="mf">2.0</span> <span class="o">-</span> <span class="mf">1.0</span><span class="p">;</span>
      <span class="nx">vec3</span> <span class="nx">normal</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">tbn</span> <span class="o">*</span> <span class="nx">n</span><span class="p">);</span>

      <span class="c1">// 2. directional light</span>
      <span class="nx">float</span> <span class="nx">lightIntensity</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">normal</span><span class="p">,</span> <span class="nx">lightDir</span><span class="p">);</span>

      <span class="c1">// 3. use the surface normal, stored in tbn[2], as a selector for the day-night texture</span>
      <span class="c1">// we don't do lighting per se, we use a blend of day/night textures for it</span>
      <span class="nx">float</span> <span class="nx">selectImage</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">tbn</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nx">lightDir</span><span class="p">);</span>
      <span class="nx">gl_FragColor</span> <span class="o">=</span> <span class="nx">texture2D</span><span class="p">(</span><span class="nx">diffuseTexture</span><span class="p">,</span> <span class="nx">vUv</span><span class="p">)</span> <span class="o">*</span> <span class="nx">selectImage</span> <span class="o">+</span> <span class="nx">texture2D</span><span class="p">(</span><span class="nx">diffuseNight</span><span class="p">,</span> <span class="nx">vUv</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="mf">1.0</span><span class="o">-</span><span class="nx">selectImage</span><span class="p">);</span>

      <span class="c1">// 4. we light the pixels a bit, true, but we only use the remainer from the intensity-select,</span>
      <span class="c1">// so we don't overlight </span>
      <span class="nx">gl_FragColor</span> <span class="o">*=</span> <span class="p">(</span><span class="mf">1.0</span> <span class="o">+</span> <span class="mf">10.0</span><span class="o">*</span><span class="p">(</span><span class="nx">lightIntensity</span> <span class="o">-</span> <span class="nx">selectImage</span><span class="p">));</span>

      <span class="c1">// 5.  specular</span>
      <span class="nx">vec3</span> <span class="nx">reflection</span> <span class="o">=</span> <span class="nx">reflect</span><span class="p">(</span><span class="nx">lightDir</span><span class="p">,</span> <span class="nx">normal</span><span class="p">);</span>
      <span class="nx">float</span> <span class="nx">specPower</span> <span class="o">=</span> <span class="nx">texture2D</span><span class="p">(</span><span class="nx">specularMap</span><span class="p">,</span> <span class="nx">vUv</span><span class="p">).</span><span class="nx">r</span><span class="p">;</span>

      <span class="nx">float</span> <span class="nx">spec</span> <span class="o">=</span> <span class="mf">4.0</span><span class="p">;</span>
      <span class="nx">float</span> <span class="nx">gloss</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="nx">texture2D</span><span class="p">(</span><span class="nx">specularMap</span><span class="p">,</span> <span class="nx">vUv</span><span class="p">).</span><span class="nx">a</span><span class="p">;</span>

      <span class="nx">float</span> <span class="nx">specular</span> <span class="o">=</span>  <span class="nx">pow</span><span class="p">(</span><span class="nx">clamp</span><span class="p">(</span><span class="nx">dot</span><span class="p">(</span><span class="nx">reflection</span><span class="p">,</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">vEyeDirectionEyeSpace</span><span class="p">)),</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="nx">spec</span><span class="p">)</span> <span class="o">*</span> <span class="nx">gloss</span><span class="p">;</span>
      <span class="nx">gl_FragColor</span> <span class="o">=</span> <span class="nx">gl_FragColor</span> <span class="o">+</span> <span class="nx">specular</span> <span class="o">*</span> <span class="nx">vec4</span><span class="p">(</span><span class="mf">0.26</span><span class="p">,</span> <span class="mf">0.96</span><span class="p">,</span> <span class="mf">0.99</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>

      <span class="c1">// 6. cloud colors</span>
      <span class="nx">vec4</span> <span class="nx">cloudsColor</span> <span class="o">=</span> <span class="nx">texture2D</span><span class="p">(</span><span class="nx">cloudsMap</span><span class="p">,</span> <span class="nx">vUv</span><span class="p">)</span> <span class="o">*</span> <span class="nx">vec4</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span>

      <span class="c1">// 7. fake cloud shadow based on how we are looking at the cloud, to give some impression of depth</span>
      <span class="nx">vec4</span> <span class="nx">cloudsShadow</span> <span class="o">=</span> <span class="nx">texture2D</span><span class="p">(</span><span class="nx">cloudsMap</span><span class="p">,</span> <span class="nx">vec2</span><span class="p">(</span><span class="nx">vUv</span><span class="p">.</span><span class="nx">x</span> <span class="o">+</span> <span class="nx">normal</span><span class="p">.</span><span class="nx">x</span> <span class="o">*</span> <span class="mf">0.005</span><span class="p">,</span> <span class="nx">vUv</span><span class="p">.</span><span class="nx">y</span> <span class="o">+</span> <span class="nx">normal</span><span class="p">.</span><span class="nx">y</span> <span class="o">*</span> <span class="mf">0.005</span><span class="p">));</span>

      <span class="k">if</span> <span class="p">(</span><span class="nx">cloudsColor</span><span class="p">.</span><span class="nx">r</span> <span class="o">&lt;</span> <span class="mf">0.1</span> <span class="o">&amp;&amp;</span> <span class="nx">cloudsShadow</span><span class="p">.</span><span class="nx">r</span> <span class="o">&gt;</span> <span class="mf">0.1</span><span class="p">){</span>
        <span class="nx">gl_FragColor</span> <span class="o">*=</span> <span class="mf">0.75</span><span class="p">;</span>
        <span class="nx">cloudsShadow</span> <span class="o">=</span> <span class="nx">vec4</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
      <span class="p">}</span>

      <span class="nx">gl_FragColor</span> <span class="o">=</span> <span class="nx">gl_FragColor</span> <span class="o">*</span> <span class="p">(</span><span class="nx">vec4</span><span class="p">(</span><span class="mf">1.0</span><span class="p">)</span> <span class="o">-</span> <span class="nx">cloudsColor</span><span class="p">)</span> <span class="o">+</span> <span class="nx">cloudsColor</span> <span class="o">*</span> <span class="p">(</span><span class="nx">lightIntensity</span> <span class="o">*</span> <span class="mf">2.0</span><span class="p">);</span>

    <span class="p">}</span>

<span class="o">&lt;</span><span class="sr">/script</span><span class="err">&gt;
</span></code></pre></div></div>

<p>And last, but not least, the atmosphere. This is the most beautiful part of the model imho.</p>

<p>The first thing to note is that the atmosphere is using alpha blending. Nothing fancy, but without the earth beneath it won’t be visible. The atmosphere itself is a sphere with no texture, rendered on top of the earth and rotating together with it. Here is the shader config:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
  <span class="nx">atmosphereUniforms</span> <span class="o">=</span> <span class="p">{</span>

    <span class="na">earthCenter</span><span class="p">:</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Uniform</span><span class="p">(</span><span class="nx">earth</span><span class="p">.</span><span class="nx">position</span><span class="p">),</span>
    <span class="na">earthRadius</span><span class="p">:</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Uniform</span><span class="p">(</span><span class="mf">10.0</span><span class="p">),</span>
    <span class="na">atmosphereRadius</span><span class="p">:</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Uniform</span><span class="p">(</span><span class="mf">10.4</span><span class="p">),</span>

  <span class="p">}</span>

  <span class="nx">atmosphere</span><span class="p">.</span><span class="nx">material</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">ShaderMaterial</span><span class="p">({</span>
    <span class="na">uniforms</span><span class="p">:</span> <span class="nx">atmosphereUniforms</span><span class="p">,</span>

    <span class="na">vertexShader</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">atmosphereVertexShader</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerText</span><span class="p">,</span>
    <span class="na">fragmentShader</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">atmosphereFragmentShader</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerText</span><span class="p">,</span>

    <span class="na">blending</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">CustomBlending</span><span class="p">,</span>
    <span class="na">blendEquation</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">AddEquation</span><span class="p">,</span>
    <span class="na">blendSrc</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">SrcAlphaFactor</span><span class="p">,</span>
    <span class="na">blendDst</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">OneMinusSrcAlphaFactor</span><span class="p">,</span>
    <span class="na">side</span><span class="p">:</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">FrontSide</span><span class="p">,</span>

    <span class="na">transparent</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
  <span class="p">});</span>
</code></pre></div></div>

<p>And the shaders:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"x-shader/x-vertex"</span> <span class="na">id=</span><span class="s">"atmosphereVertexShader"</span><span class="nt">&gt;</span>

    <span class="nx">uniform</span> <span class="nx">vec3</span> <span class="nx">earthCenter</span><span class="p">;</span>
    <span class="nx">uniform</span> <span class="nx">float</span> <span class="nx">earthRadius</span><span class="p">;</span>
    <span class="nx">uniform</span> <span class="nx">float</span> <span class="nx">atmosphereRadius</span><span class="p">;</span>
    <span class="nx">uniform</span> <span class="nx">vec3</span> <span class="nx">lightDirection</span><span class="p">;</span>

    <span class="nx">varying</span> <span class="nx">float</span> <span class="nx">atmosphereThickness</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec3</span> <span class="nx">vLightDirection</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec3</span> <span class="nx">vNormalEyeSpace</span><span class="p">;</span>


    <span class="k">void</span> <span class="nx">main</span><span class="p">(){</span>

      <span class="c1">// 1. compute the position</span>
      <span class="nx">gl_Position</span> <span class="o">=</span> <span class="nx">projectionMatrix</span> <span class="o">*</span> <span class="nx">modelViewMatrix</span> <span class="o">*</span> <span class="nx">vec4</span><span class="p">(</span><span class="nx">position</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span>


      <span class="c1">// 2. compute the thinckness of the atmosphere</span>
      <span class="c1">// for this, we intersect the vector (eye - current vertex) with the atmosphere and the earth</span>
      <span class="c1">// and we compute how long this line is. In pixel shader we compute the light scattering based on this measure</span>
      <span class="c1">// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection</span>

      <span class="nx">vec3</span> <span class="nx">positionW</span> <span class="o">=</span> <span class="p">(</span><span class="nx">modelMatrix</span> <span class="o">*</span> <span class="nx">vec4</span><span class="p">(</span><span class="nx">position</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)).</span><span class="nx">xyz</span><span class="p">;</span>

      <span class="nx">vec3</span> <span class="nx">vCameraEarth</span> <span class="o">=</span> <span class="nx">cameraPosition</span><span class="p">.</span><span class="nx">xyz</span> <span class="o">-</span> <span class="nx">earthCenter</span><span class="p">;</span>
      <span class="nx">vec3</span> <span class="nx">vCameraVertex</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">cameraPosition</span><span class="p">.</span><span class="nx">xyz</span> <span class="o">-</span> <span class="nx">positionW</span><span class="p">);</span>

      <span class="nx">float</span> <span class="nx">tca</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">vCameraEarth</span><span class="p">,</span>  <span class="nx">vCameraVertex</span><span class="p">);</span>

      <span class="k">if</span> <span class="p">(</span><span class="nx">tca</span> <span class="o">&lt;</span> <span class="mf">0.0</span><span class="p">){</span>
        <span class="c1">// not intesect, looking in opposite direction</span>
        <span class="nx">atmosphereThickness</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">;</span>
        <span class="k">return</span><span class="p">;</span>
      <span class="p">}</span>

      <span class="nx">float</span> <span class="nx">dsq</span> <span class="o">=</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">vCameraEarth</span><span class="p">,</span> <span class="nx">vCameraEarth</span><span class="p">)</span> <span class="o">-</span> <span class="nx">tca</span> <span class="o">*</span> <span class="nx">tca</span><span class="p">;</span>
      <span class="nx">float</span> <span class="nx">thc_sq_atmosphere</span> <span class="o">=</span> <span class="nx">max</span><span class="p">(</span><span class="nx">atmosphereRadius</span> <span class="o">*</span> <span class="nx">atmosphereRadius</span> <span class="o">-</span> <span class="nx">dsq</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">);</span>
      <span class="nx">float</span> <span class="nx">thc_sq_earth</span> <span class="o">=</span> <span class="nx">max</span><span class="p">(</span><span class="nx">earthRadius</span> <span class="o">*</span> <span class="nx">earthRadius</span> <span class="o">-</span> <span class="nx">dsq</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">);</span>

      <span class="nx">float</span> <span class="nx">thc_atmosphere</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="nx">sqrt</span><span class="p">(</span><span class="nx">thc_sq_atmosphere</span><span class="p">);</span>
      <span class="nx">float</span> <span class="nx">thc_earth</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="nx">sqrt</span><span class="p">(</span><span class="nx">max</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span><span class="nx">thc_sq_earth</span><span class="p">));</span>

      <span class="nx">float</span> <span class="nx">thc</span> <span class="o">=</span> <span class="p">(</span><span class="nx">thc_atmosphere</span> <span class="o">-</span> <span class="nx">thc_earth</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.12</span><span class="p">;</span> <span class="c1">// 0.01 - density factor</span>
      <span class="nx">atmosphereThickness</span> <span class="o">=</span> <span class="nx">thc</span><span class="p">;</span>

      <span class="c1">// 3. the normal light calculation</span>
      <span class="nx">vLightDirection</span> <span class="o">=</span> <span class="nx">mat3</span><span class="p">(</span><span class="nx">viewMatrix</span><span class="p">)</span> <span class="o">*</span> <span class="nx">lightDirection</span><span class="p">;</span>
      <span class="nx">vNormalEyeSpace</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">normalMatrix</span> <span class="o">*</span> <span class="nx">normal</span><span class="p">);</span>

    <span class="p">}</span>


  <span class="nt">&lt;/script&gt;</span>

  <span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"x-shader/x-fragment"</span> <span class="na">id=</span><span class="s">"atmosphereFragmentShader"</span><span class="nt">&gt;</span>

    <span class="nx">varying</span> <span class="nx">float</span> <span class="nx">atmosphereThickness</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec3</span> <span class="nx">vLightDirection</span><span class="p">;</span>
    <span class="nx">varying</span> <span class="nx">vec3</span> <span class="nx">vNormalEyeSpace</span><span class="p">;</span>

    <span class="k">void</span> <span class="nx">main</span><span class="p">(){</span>

      <span class="nx">vec3</span> <span class="nx">lightDir</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">vLightDirection</span><span class="p">);</span>
      <span class="nx">vec3</span> <span class="nx">normal</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">vNormalEyeSpace</span><span class="p">);</span>

      <span class="c1">// computing the light intensity as it is scattered through the atmosphere</span>
      <span class="c1">// based on actual lighting extended a bit</span>
      <span class="c1">// and the thickess</span>
      <span class="nx">float</span> <span class="nx">lightIntensity</span> <span class="o">=</span> <span class="nx">max</span><span class="p">(</span><span class="nx">dot</span><span class="p">(</span><span class="nx">normal</span><span class="p">,</span> <span class="nx">lightDir</span><span class="p">)</span> <span class="o">*</span> <span class="mf">1.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.7</span><span class="p">);</span>
      <span class="nx">gl_FragColor</span> <span class="o">=</span> <span class="nx">vec4</span><span class="p">(</span> <span class="p">(</span><span class="nx">vec3</span><span class="p">(</span><span class="mf">57.0</span><span class="p">,</span> <span class="mf">97.0</span><span class="p">,</span> <span class="mf">162.0</span><span class="p">)</span> <span class="o">/</span> <span class="mf">256.0</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="mf">1.0</span> <span class="o">+</span> <span class="nx">lightIntensity</span><span class="p">),</span> <span class="nx">atmosphereThickness</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>And that was my first play with WebGL and ThreeJS. I will soon publish the demo somewhere but might not work on my video cards.</p>

<p><img src="https://alexandrugris.github.io/assets/webgl_4.png" alt="Earth" /></p>

<p><img src="https://alexandrugris.github.io/assets/webgl_5.png" alt="Earth" /></p>

<p><img src="https://alexandrugris.github.io/assets/webgl_6.png" alt="Earth" /></p>]]></content><author><name></name></author><category term="graphics" /><category term="3D" /><summary type="html"><![CDATA[A post about computer graphics, for the web mostly, with JavaScript, WebGL, ThreeJS and shaders. A little bit of maths also.]]></summary></entry><entry><title type="html">Introduction to Cryptography (Part 3)</title><link href="https://alexandrugris.github.io/cryptography/2020/04/04/intro-cryptography-3.html" rel="alternate" type="text/html" title="Introduction to Cryptography (Part 3)" /><published>2020-04-04T09:15:16+02:00</published><updated>2020-04-04T09:15:16+02:00</updated><id>https://alexandrugris.github.io/cryptography/2020/04/04/intro-cryptography%203</id><content type="html" xml:base="https://alexandrugris.github.io/cryptography/2020/04/04/intro-cryptography-3.html"><![CDATA[<p>This is the third part of Introduction to Cryptography. The post covers the Java APIs that implement the same algorithms that we spoke about in the previous posts, symmetric and asymmetric encryption, as well as digital signatures. We also talk a little bit about password security and the principle behind rainbow tables.</p>

<h3 id="java-apis-encryption-decryption-signatures">Java APIs, Encryption, Decryption, Signatures</h3>

<p>I am going to exemplify here the concepts from the previous posts using the Java Cryptography Extensions (JCE). Most programming languages have similar cryptographic support. JCE revolves around the following classes:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">KeyGenerator</code> - key generator for symmetric encryption</li>
  <li><code class="language-plaintext highlighter-rouge">SecretKey</code> - the generated symmetric key</li>
  <li><code class="language-plaintext highlighter-rouge">SecureRandom</code> - cryptographically secure random number generator</li>
  <li><code class="language-plaintext highlighter-rouge">IvParameterSpec</code> - initialization vector for the algorithm (remember that the Cypher Block Chaining (CBC) requires an init vector)</li>
  <li><code class="language-plaintext highlighter-rouge">KeyPairGenerator</code> - key generator for asymmetric encryption</li>
  <li><code class="language-plaintext highlighter-rouge">PublicKey</code> - the public key</li>
  <li><code class="language-plaintext highlighter-rouge">PrivateKey</code> - the private key</li>
  <li><code class="language-plaintext highlighter-rouge">Cipher</code> - perform the work of the symmetric / asymmetric encryption</li>
  <li><code class="language-plaintext highlighter-rouge">Signature</code> - performs the work of the signature algorithm</li>
  <li><code class="language-plaintext highlighter-rouge">CipherInputStream</code> - input stream for decryption</li>
  <li><code class="language-plaintext highlighter-rouge">CipherOutputStream</code> - output stream for encryption</li>
</ul>

<p>The current Java implementation, Java 14, supports the following algorithms: <a href="https://docs.oracle.com/en/java/javase/14/docs/specs/security/standard-names.html">link</a></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Encrypting with symmetric encryption. Only the necessary information is shared with this method.
 * In a production scenario, these would come from a secrets database
 * @param msg - the message
 * @param algorithm - the algorithm
 * @param key - the secret key
 * @param iv - the initialization vector
 */</span>
<span class="kd">static</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">encryptAES</span><span class="o">(</span><span class="nc">String</span> <span class="n">msg</span><span class="o">,</span> <span class="nc">String</span> <span class="n">algorithm</span><span class="o">,</span> <span class="nc">SecretKey</span> <span class="n">key</span><span class="o">,</span> <span class="nc">IvParameterSpec</span> <span class="n">iv</span><span class="o">)</span> 
        <span class="kd">throws</span> <span class="nc">NoSuchPaddingException</span><span class="o">,</span> 
        <span class="nc">NoSuchAlgorithmException</span><span class="o">,</span> 
        <span class="nc">InvalidAlgorithmParameterException</span><span class="o">,</span> 
        <span class="nc">InvalidKeyException</span> <span class="o">{</span>

    <span class="nc">Cipher</span> <span class="n">c</span> <span class="o">=</span> <span class="nc">Cipher</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="n">algorithm</span><span class="o">);</span>
    <span class="n">c</span><span class="o">.</span><span class="na">init</span> <span class="o">(</span><span class="nc">Cipher</span><span class="o">.</span><span class="na">ENCRYPT_MODE</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">iv</span><span class="o">);</span>
    <span class="kt">var</span> <span class="n">output</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ByteArrayOutputStream</span> <span class="o">();</span>
    <span class="k">try</span><span class="o">(</span><span class="kt">var</span> <span class="n">cos</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">CipherOutputStream</span> <span class="o">(</span><span class="n">output</span><span class="o">,</span> <span class="n">c</span><span class="o">)){</span>
        <span class="n">cos</span><span class="o">.</span><span class="na">write</span> <span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">getBytes</span> <span class="o">());</span>
    <span class="o">}</span>
    <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">exx</span><span class="o">){</span>
        <span class="n">exx</span><span class="o">.</span><span class="na">printStackTrace</span> <span class="o">();</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">output</span><span class="o">.</span><span class="na">toByteArray</span> <span class="o">();</span>
<span class="o">}</span>
<span class="cm">/**
 * The decryption function
 * @param encrypted - the text to be decrypted
 * @param algorithm - the algorithm used
 * @param sk - the secret key
 * @param iv - the initialization vector
 * @return
 */</span>
<span class="kd">static</span> <span class="nc">String</span> <span class="nf">decryptAES</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">encrypted</span><span class="o">,</span> <span class="nc">String</span> <span class="n">algorithm</span><span class="o">,</span> <span class="nc">SecretKey</span> <span class="n">sk</span><span class="o">,</span> <span class="nc">IvParameterSpec</span> <span class="n">iv</span><span class="o">)</span><span class="kd">throws</span>
            <span class="nc">InvalidAlgorithmParameterException</span><span class="o">,</span> 
            <span class="nc">InvalidKeyException</span><span class="o">,</span> 
            <span class="nc">NoSuchPaddingException</span><span class="o">,</span>
            <span class="nc">NoSuchAlgorithmException</span> <span class="o">{</span>

    <span class="nc">Cipher</span> <span class="n">c</span> <span class="o">=</span> <span class="nc">Cipher</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="n">algorithm</span><span class="o">);</span>
    <span class="n">c</span><span class="o">.</span><span class="na">init</span> <span class="o">(</span><span class="nc">Cipher</span><span class="o">.</span><span class="na">DECRYPT_MODE</span><span class="o">,</span> <span class="n">sk</span><span class="o">,</span> <span class="n">iv</span><span class="o">);</span>

    <span class="k">try</span><span class="o">(</span><span class="kt">var</span> <span class="n">bais</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ByteArrayInputStream</span><span class="o">(</span><span class="n">encrypted</span><span class="o">);</span>
        <span class="kt">var</span> <span class="n">cis</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">CipherInputStream</span> <span class="o">(</span><span class="n">bais</span><span class="o">,</span> <span class="n">c</span><span class="o">)){</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">String</span><span class="o">(</span><span class="n">cis</span><span class="o">.</span><span class="na">readAllBytes</span> <span class="o">());</span>

    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span> <span class="o">();</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>

<span class="cm">/**
 * Start here
 */</span>
<span class="kd">static</span> <span class="kt">void</span> <span class="nf">test_symmetricJCE</span><span class="o">()</span> 
            <span class="kd">throws</span> <span class="nc">NoSuchAlgorithmException</span><span class="o">,</span> 
            <span class="nc">NoSuchPaddingException</span><span class="o">,</span>
            <span class="nc">InvalidAlgorithmParameterException</span><span class="o">,</span> 
            <span class="nc">InvalidKeyException</span> <span class="o">{</span>

    <span class="c1">// Generate the secret key</span>
    <span class="nc">KeyGenerator</span> <span class="n">keyGen</span> <span class="o">=</span> <span class="nc">KeyGenerator</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"AES"</span><span class="o">);</span>
    <span class="n">keyGen</span><span class="o">.</span><span class="na">init</span> <span class="o">(</span><span class="mi">256</span><span class="o">);</span>

    <span class="nc">SecretKey</span> <span class="n">sk</span> <span class="o">=</span> <span class="n">keyGen</span><span class="o">.</span><span class="na">generateKey</span> <span class="o">();</span>
    <span class="k">assert</span> <span class="n">sk</span><span class="o">.</span><span class="na">getAlgorithm</span> <span class="o">().</span><span class="na">equals</span> <span class="o">(</span><span class="s">"AES"</span><span class="o">);</span> <span class="c1">// algorithm</span>
    <span class="k">assert</span> <span class="n">sk</span><span class="o">.</span><span class="na">getEncoded</span> <span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">32</span><span class="o">;</span> <span class="c1">// key size in bytes</span>
    
    <span class="c1">// Create an instance of the AES cypher, with CBS and</span>
    <span class="c1">// a padding to fill the missing bytes at the end of the message.</span>
    <span class="c1">// Generate the initialization vector for our CBC.</span>
    <span class="c1">// We use the block size from the algorithm for the size of our iv</span>
    <span class="nc">SecureRandom</span> <span class="n">sr</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SecureRandom</span> <span class="o">();</span>
    <span class="kt">byte</span><span class="o">[]</span> <span class="n">ivbytes</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">byte</span><span class="o">[</span><span class="nc">Cipher</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"AES/CBC/PKCS5Padding"</span><span class="o">).</span><span class="na">getBlockSize</span> <span class="o">()];</span>
    <span class="n">sr</span><span class="o">.</span><span class="na">nextBytes</span> <span class="o">(</span><span class="n">ivbytes</span><span class="o">);</span>
    <span class="nc">IvParameterSpec</span> <span class="n">iv</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">IvParameterSpec</span> <span class="o">(</span><span class="n">ivbytes</span><span class="o">);</span>

    <span class="c1">// encrypt and decrypt</span>
    <span class="kt">var</span> <span class="n">msg</span> <span class="o">=</span> <span class="s">"This is my first long message encrypted with AES / CBC"</span><span class="o">;</span>
    <span class="kt">var</span> <span class="n">encrypted</span> <span class="o">=</span> <span class="n">encryptAES</span><span class="o">(</span><span class="n">msg</span><span class="o">,</span> <span class="s">"AES/CBC/PKCS5Padding"</span><span class="o">,</span> <span class="n">sk</span><span class="o">,</span> <span class="n">iv</span><span class="o">);</span>
    <span class="kt">var</span> <span class="n">decrypted</span> <span class="o">=</span> <span class="n">decryptAES</span><span class="o">(</span><span class="n">encrypted</span><span class="o">,</span> <span class="s">"AES/CBC/PKCS5Padding"</span><span class="o">,</span> <span class="n">sk</span><span class="o">,</span> <span class="n">iv</span><span class="o">);</span>
    
    <span class="k">assert</span> <span class="n">msg</span><span class="o">.</span><span class="na">equals</span> <span class="o">(</span><span class="n">decrypted</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>In the picture below we can observe that the secret key is just an array of bytes, similar to what we have seen when we implemented the algorithm from scratch, in the previous post.</p>

<p><img src="https://alexandrugris.github.io/assets/crypto3_2.png" alt="Secret Key" /></p>

<p>It is important to note that, if two messages start with the same bytes, the first bytes in the encrypted string for both of them will be the same, if we use the same initialization vector. Therefore, it is good practice to change the initialization vector with each message.</p>

<p>For the asymmetric encryption, the process is very similar. The only differences are in the methods we call on the <code class="language-plaintext highlighter-rouge">Cipher</code> class. Since <code class="language-plaintext highlighter-rouge">Cipher</code> works iteratively on blocks, to encrypt / decrypt with <code class="language-plaintext highlighter-rouge">RSA</code> which is not a block cipher, we need to invoke <code class="language-plaintext highlighter-rouge">Cipher::doFinal()</code> on the cipher, as if the whole message is a single block. Example below.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">test_asymmetricJCE</span><span class="o">()</span> <span class="kd">throws</span> 
        <span class="nc">NoSuchAlgorithmException</span><span class="o">,</span> 
        <span class="nc">NoSuchPaddingException</span><span class="o">,</span>
        <span class="nc">InvalidKeyException</span><span class="o">,</span> 
        <span class="nc">BadPaddingException</span><span class="o">,</span> 
        <span class="nc">IllegalBlockSizeException</span> <span class="o">{</span>

    <span class="kt">var</span> <span class="n">msg</span> <span class="o">=</span> <span class="s">"This is my first long message encrypted with RSA"</span><span class="o">;</span>
    <span class="nc">KeyPairGenerator</span> <span class="n">kg</span> <span class="o">=</span> <span class="nc">KeyPairGenerator</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"RSA"</span><span class="o">);</span>
    <span class="n">kg</span><span class="o">.</span><span class="na">initialize</span> <span class="o">(</span><span class="mi">2048</span><span class="o">);</span>

    <span class="kt">var</span> <span class="n">kp</span> <span class="o">=</span> <span class="n">kg</span><span class="o">.</span><span class="na">generateKeyPair</span> <span class="o">();</span>

    <span class="c1">// encrypt</span>
    <span class="kt">var</span> <span class="n">c1</span> <span class="o">=</span> <span class="nc">Cipher</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"RSA/ECB/PKCS1Padding"</span><span class="o">);</span>
    <span class="n">c1</span><span class="o">.</span><span class="na">init</span> <span class="o">(</span><span class="nc">Cipher</span><span class="o">.</span><span class="na">ENCRYPT_MODE</span><span class="o">,</span> <span class="n">kp</span><span class="o">.</span><span class="na">getPrivate</span> <span class="o">());</span>
    <span class="kt">byte</span><span class="o">[]</span> <span class="n">encrypt</span> <span class="o">=</span>  <span class="n">c1</span><span class="o">.</span><span class="na">doFinal</span> <span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">getBytes</span> <span class="o">());</span>

    <span class="c1">// decrypt</span>
    <span class="kt">var</span> <span class="n">c2</span> <span class="o">=</span> <span class="nc">Cipher</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"RSA/ECB/PKCS1Padding"</span><span class="o">);</span>
    <span class="n">c2</span><span class="o">.</span><span class="na">init</span> <span class="o">(</span><span class="nc">Cipher</span><span class="o">.</span><span class="na">DECRYPT_MODE</span><span class="o">,</span> <span class="n">kp</span><span class="o">.</span><span class="na">getPublic</span> <span class="o">());</span>
    <span class="kt">var</span> <span class="n">ret</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">String</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">doFinal</span> <span class="o">(</span><span class="n">encrypt</span><span class="o">));</span>
    <span class="k">assert</span> <span class="n">ret</span><span class="o">.</span><span class="na">equals</span> <span class="o">(</span><span class="n">msg</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>In the picture below we can see the public / private key pair expanded. We observe the same elements that we spoke about when we implemented the algorithm from scratch, in the previous post:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">p</code> and <code class="language-plaintext highlighter-rouge">q</code> my private two large prime numbers</li>
  <li><code class="language-plaintext highlighter-rouge">n = p*q</code>, the modulo, shared</li>
  <li><code class="language-plaintext highlighter-rouge">e</code>, the public exponent - shared (encrypting) - the requirement for this is to be relatively prime to <code class="language-plaintext highlighter-rouge">p-1</code> and <code class="language-plaintext highlighter-rouge">q-1</code>. A commonly used exponent is <code class="language-plaintext highlighter-rouge">65537</code> since it is a prime number all together .</li>
  <li><code class="language-plaintext highlighter-rouge">d</code>, the private exponent - shared (decrypting) -</li>
</ul>

<p><img src="https://alexandrugris.github.io/assets/crypto3_3.png" alt="Public / Private Key Pair" /></p>

<p><em>Several important notes:</em></p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">KeyPairGenerator::generateKeyPair()</code> might take several seconds. Therefore, it is better to store / read the keys from a secure key store.</p>
  </li>
  <li>
    <p>The RSA algorithm is generally slow so, in practice, it is used to <code class="language-plaintext highlighter-rouge">encrypt -&gt; transmit -&gt; decrypt</code> a key that will be used further with a symmetric encryption algorithm. In our case, we would have had encrypted the <code class="language-plaintext highlighter-rouge">SecretKey</code> from the first example, transmit it over the wire, then use that <code class="language-plaintext highlighter-rouge">SecretKey</code> to encrypt the rest of the communication.</p>
  </li>
</ul>

<p>Now, let’s use the private / public key pair to sign a message:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">test_signaturesJCE</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">NoSuchAlgorithmException</span><span class="o">,</span> <span class="nc">InvalidKeyException</span><span class="o">,</span> <span class="nc">SignatureException</span> <span class="o">{</span>

    <span class="kt">var</span> <span class="n">msg</span> <span class="o">=</span> <span class="s">"This is my first long message signed with RSA"</span><span class="o">;</span>

    <span class="nc">KeyPairGenerator</span> <span class="n">kg</span> <span class="o">=</span> <span class="nc">KeyPairGenerator</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"RSA"</span><span class="o">);</span>
    <span class="n">kg</span><span class="o">.</span><span class="na">initialize</span> <span class="o">(</span><span class="mi">2048</span><span class="o">);</span>

    <span class="kt">var</span> <span class="n">kp</span> <span class="o">=</span> <span class="n">kg</span><span class="o">.</span><span class="na">generateKeyPair</span> <span class="o">();</span>

    <span class="c1">// sign</span>
    <span class="kt">var</span> <span class="n">sigSign</span> <span class="o">=</span> <span class="nc">Signature</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"SHA256withRSA"</span><span class="o">);</span>
    <span class="n">sigSign</span><span class="o">.</span><span class="na">initSign</span> <span class="o">(</span><span class="n">kp</span><span class="o">.</span><span class="na">getPrivate</span> <span class="o">());</span>
    <span class="n">sigSign</span><span class="o">.</span><span class="na">update</span> <span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">getBytes</span> <span class="o">());</span>
    <span class="kt">var</span> <span class="n">sig</span> <span class="o">=</span> <span class="n">sigSign</span><span class="o">.</span><span class="na">sign</span> <span class="o">();</span>

    <span class="c1">// verify</span>
    <span class="kt">var</span> <span class="n">sigVerify</span> <span class="o">=</span> <span class="nc">Signature</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"SHA256withRSA"</span><span class="o">);</span>
    <span class="n">sigVerify</span><span class="o">.</span><span class="na">initVerify</span> <span class="o">(</span><span class="n">kp</span><span class="o">.</span><span class="na">getPublic</span> <span class="o">());</span>
    <span class="n">sigVerify</span><span class="o">.</span><span class="na">update</span> <span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">getBytes</span> <span class="o">());</span>
    <span class="kt">var</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">sigVerify</span><span class="o">.</span><span class="na">verify</span> <span class="o">(</span><span class="n">sig</span><span class="o">);</span>

    <span class="k">assert</span> <span class="n">ret</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="authentication-and-authorization">Authentication and Authorization</h3>

<p>The first thing to know about passwords is that you never store them in clear text. More precisely you don’t even need to store the full password in any form. Since the verification is just one way, it is enough to store a password hash that is checked against every time the password is entered. The most basic form for checking whether a site keeps passwords in clear text is so see if they offer a password retrieval function. If they do, better close the account and never use that password again.</p>

<p>A more common form of attack are leaked password hashes. We could use dictionary attacks to match hashes to known passwords and that would lead to dictionaries being extremely large. A method that trades the size of the dictionary for a bit of additional computation is the rainbow table. The principle is to compute a series of chains, pairs of <code class="language-plaintext highlighter-rouge">(starting password, ending hash)</code>. Each chain is, in fact, like (starting password -&gt; hash -&gt; new password -&gt; hash … -&gt; ending hash), but, since we know the transform function from password to hash and then from hash to a new potential password, we don’t need to store the intermediate results. We don’t want to reverse the hash, but to try to find a collision. What is needed for rainbow table to work are (a) a leaked the password hash and (b) the algorithm used for obtaining that hash. The algorithm starts by identifying which chain the leaked hash belongs to and then, iterating through the chain, find a password that generates that very same hash.</p>

<p>Here is a very basic example of the principle, written in Java. The code is based on this <a href="https://www.ionos.com/digitalguide/server/security/rainbow-tables/">excellent article</a>.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">ro.alexandrugris</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">java.nio.charset.StandardCharsets</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.HashMap</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>

    <span class="c1">// compute password -&gt; hash -&gt; password chain</span>
    <span class="c1">// for simplicity, in our case, hash -&gt; password function is just the identity function</span>
    <span class="kd">static</span> <span class="nc">String</span> <span class="nf">hash</span><span class="o">(</span><span class="nc">String</span> <span class="n">s</span><span class="o">){</span>

        <span class="kt">byte</span><span class="o">[]</span> <span class="n">str</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="na">toUpperCase</span> <span class="o">().</span><span class="na">getBytes</span> <span class="o">(</span><span class="nc">StandardCharsets</span><span class="o">.</span><span class="na">US_ASCII</span><span class="o">);</span>
        <span class="kt">byte</span><span class="o">[]</span> <span class="n">n_pass</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">byte</span><span class="o">[</span><span class="n">str</span><span class="o">.</span><span class="na">length</span><span class="o">];</span>

        <span class="c1">// a very basic and a very bad hash function</span>
        <span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">str</span><span class="o">.</span><span class="na">length</span><span class="o">;</span> <span class="n">i</span><span class="o">++){</span>
            <span class="kt">var</span> <span class="n">x</span> <span class="o">=</span> <span class="n">str</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">-</span> <span class="sc">'A'</span><span class="o">;</span>
            <span class="kt">var</span> <span class="n">hash</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)(</span><span class="mi">2000</span> <span class="o">*</span> <span class="o">(</span><span class="n">x</span> <span class="o">*</span> <span class="mf">1.618</span> <span class="o">%</span> <span class="mi">1</span><span class="o">));</span>
            <span class="n">n_pass</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">byte</span><span class="o">)(</span><span class="n">hash</span> <span class="o">%</span> <span class="o">(</span><span class="sc">'A'</span> <span class="o">-</span> <span class="sc">'Z'</span><span class="o">)</span> <span class="o">+</span> <span class="sc">'A'</span><span class="o">);</span>
        <span class="o">}</span>

        <span class="k">return</span> <span class="k">new</span> <span class="nf">String</span> <span class="o">(</span><span class="n">n_pass</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">static</span> <span class="nc">String</span> <span class="nf">computeChain</span><span class="o">(</span><span class="nc">String</span> <span class="n">start</span><span class="o">){</span>

        <span class="c1">// chains of 4, because our hash function is very weak and it loops very quickly.</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="o">;</span> <span class="n">i</span><span class="o">++){</span>
            <span class="n">start</span> <span class="o">=</span> <span class="n">hash</span> <span class="o">(</span><span class="n">start</span><span class="o">);</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">start</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">static</span> <span class="nc">String</span> <span class="nf">guessPassword</span><span class="o">(</span><span class="nc">String</span> <span class="n">initial</span><span class="o">,</span> <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;</span> <span class="n">map</span><span class="o">){</span>

        <span class="nc">String</span> <span class="n">hash</span> <span class="o">=</span> <span class="n">initial</span><span class="o">;</span>

        <span class="c1">// N = 100 tries</span>
        <span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100</span><span class="o">;</span> <span class="n">i</span> <span class="o">++){</span>
            <span class="c1">// 3. try to find the hash in the rainbow table</span>
            <span class="kt">var</span> <span class="n">chain</span> <span class="o">=</span> <span class="n">map</span><span class="o">.</span><span class="na">get</span> <span class="o">(</span><span class="n">hash</span><span class="o">);</span>

            <span class="c1">// 4. if the hash was not found, compute the next password and the next hash</span>
            <span class="k">if</span><span class="o">(</span><span class="n">chain</span> <span class="o">==</span> <span class="kc">null</span><span class="o">){</span>
                <span class="n">hash</span> <span class="o">=</span> <span class="n">computeChain</span> <span class="o">(</span><span class="n">hash</span><span class="o">);</span>
            <span class="o">}</span>
            <span class="k">else</span><span class="o">{</span>
                <span class="c1">// 5. the hash was found, which means I found the chain</span>
                <span class="c1">// start from the beginning of the chain,</span>
                <span class="c1">// compute the hash.</span>
                <span class="c1">// When the hash is equal to the hash I want to break,</span>
                <span class="c1">// that is a working password!</span>
                <span class="k">while</span><span class="o">(</span><span class="kc">true</span><span class="o">){</span>
                    <span class="kt">var</span> <span class="n">next</span> <span class="o">=</span> <span class="n">computeChain</span> <span class="o">(</span><span class="n">chain</span><span class="o">);</span>
                    <span class="k">if</span><span class="o">(</span><span class="n">next</span><span class="o">.</span><span class="na">equals</span> <span class="o">(</span><span class="n">initial</span><span class="o">))</span>
                        <span class="k">return</span> <span class="n">chain</span><span class="o">;</span>
                    <span class="k">else</span>
                        <span class="n">chain</span> <span class="o">=</span> <span class="n">next</span><span class="o">;</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">// not found</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>

        <span class="c1">// 1. compute rainbow table, a hashmap of &lt;hash, starting point&gt;</span>
        <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;</span> <span class="n">myRainbowTable</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;&gt;</span> <span class="o">();</span>

        <span class="nc">String</span><span class="o">[]</span> <span class="n">startingPoints</span> <span class="o">=</span> <span class="o">{</span>
                <span class="s">"HELL"</span><span class="o">,</span>
                <span class="s">"BUBU"</span><span class="o">,</span>
                <span class="s">"FUFU"</span><span class="o">,</span>
                <span class="s">"ROCK"</span>
        <span class="o">};</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">var</span> <span class="n">s</span> <span class="o">:</span> <span class="n">startingPoints</span><span class="o">){</span>
            <span class="n">myRainbowTable</span><span class="o">.</span><span class="na">put</span> <span class="o">(</span><span class="n">computeChain</span> <span class="o">(</span><span class="n">s</span><span class="o">),</span> <span class="n">s</span><span class="o">);</span>
        <span class="o">}</span>

        <span class="c1">// 2. obtain the password hash we want to reverse</span>
        <span class="kt">var</span> <span class="n">passHash</span> <span class="o">=</span> <span class="s">"WJGG"</span><span class="o">;</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span> <span class="o">(</span><span class="n">guessPassword</span><span class="o">(</span><span class="n">passHash</span><span class="o">,</span> <span class="n">myRainbowTable</span><span class="o">));</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The interesting thing to observe is how an increased password complexity increases exponentially the complexity of generating and searching the rainbow table. It also shows that for salted passwords an attacker will have a harder time reversing it as it has to start by generating the rainbow table for those specific salts. The salt itself, a string pre-pended or appended to the password, does not need to be protected. It can be stored in plain text in the passwords table, but, for good protection, it should different for every user.</p>

<p>To make it unfeasible for an attacker to brute force our passwords, the algorithm used to compute the hash should be (a) irreversible (b) take a long time. The application only runs this algorithm for each login, but the attacker would have to run it for every password retry. The recommended approach is called <a href="https://en.wikipedia.org/wiki/PBKDF2"><code class="language-plaintext highlighter-rouge">PBKDF</code></a> and the general concept is called <em>key stretching</em>.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">static</span> <span class="nc">String</span> <span class="nf">passwordHash</span><span class="o">(</span><span class="nc">String</span> <span class="n">password</span><span class="o">,</span> <span class="nc">String</span> <span class="n">salt</span><span class="o">,</span> <span class="kt">int</span> <span class="n">iterations</span><span class="o">,</span> <span class="kt">int</span> <span class="n">keyLength</span><span class="o">)</span> 
    <span class="kd">throws</span> <span class="nc">NoSuchAlgorithmException</span><span class="o">,</span> <span class="nc">InvalidKeySpecException</span> <span class="o">{</span>

    <span class="nc">SecretKeyFactory</span> <span class="n">f</span> <span class="o">=</span> <span class="nc">SecretKeyFactory</span><span class="o">.</span><span class="na">getInstance</span> <span class="o">(</span><span class="s">"PBKDF2WithHmacSHA1"</span><span class="o">);</span>
    
    <span class="c1">// iterations should be minimum 1000, preferably 10000</span>
    <span class="c1">// should be increased as computers become more powerful</span>
    <span class="c1">// the idea is to have a time-consuming operation </span>
    <span class="c1">// that makes it computationally hard for the attacker to brute force the password</span>
    <span class="nc">KeySpec</span> <span class="n">ks</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PBEKeySpec</span> <span class="o">(</span><span class="n">password</span><span class="o">.</span><span class="na">toCharArray</span> <span class="o">(),</span> <span class="n">salt</span><span class="o">.</span><span class="na">getBytes</span> <span class="o">(),</span> <span class="n">iterations</span><span class="o">,</span> <span class="n">keyLength</span><span class="o">);</span>
    <span class="nc">SecretKey</span> <span class="n">s</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="na">generateSecret</span> <span class="o">(</span><span class="n">ks</span><span class="o">);</span>

    <span class="k">return</span> <span class="k">new</span> <span class="nf">String</span><span class="o">(</span><span class="nc">Base64</span><span class="o">.</span><span class="na">getEncoder</span> <span class="o">().</span><span class="na">encode</span> <span class="o">(</span><span class="n">s</span><span class="o">.</span><span class="na">getEncoded</span> <span class="o">()));</span>
<span class="o">}</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="cryptography" /><summary type="html"><![CDATA[This is the third part of Introduction to Cryptography. The post covers the Java APIs that implement the same algorithms that we spoke about in the previous posts, symmetric and asymmetric encryption, as well as digital signatures. We also talk a little bit about password security and the principle behind rainbow tables.]]></summary></entry></feed>