<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Hillel Wayne</title>
    <link>https://www.hillelwayne.com/</link>
    <description>Recent content on Hillel Wayne</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Mon, 15 Jul 2024 00:00:00 +0000</lastBuildDate>
    
        <atom:link href="https://www.hillelwayne.com/index.xml" rel="self" type="application/rss+xml" />
    
    
      
    
      
    
      
    
      
    
      
    
      
      <item>
        <title>Toolbox languages</title>
        <link>https://www.hillelwayne.com/post/toolbox-languages/</link>
        <pubDate>Mon, 15 Jul 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/toolbox-languages/</guid>
        <description>

&lt;p&gt;A &lt;dfn&gt;toolbox language&lt;/dfn&gt; is a programming language that&amp;rsquo;s good at solving problems without requiring third party packages. My default toolbox languages are Python and shell scripts, which you probably already know about. Here are some of my more obscure ones.&lt;/p&gt;

&lt;h3 id=&#34;autohotkey-https-www-autohotkey-com&#34;&gt;&lt;a href=&#34;https://www.autohotkey.com/&#34;&gt;AutoHotKey&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Had to show up! Autohotkey is basically &amp;ldquo;shell scripting for GUIs&amp;rdquo;. Just a fantastic tool to smooth over using unprogrammable applications. It&amp;rsquo;s Windows-only but similar things exist for Mac and Linux.&lt;/p&gt;

&lt;h4 id=&#34;useful-features&#34;&gt;Useful features:&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can configure shortcuts that are only active for certain programs, if a global flag is set, if certain text appears on screen, etc.&lt;/li&gt;
&lt;li&gt;Simple access to lots of basic win32 functionality. Opening the file selection dialog is just &lt;code&gt;f := FileSelect()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The GUI framework is really, really good. Honestly the best of any language I&amp;rsquo;ve used, at least for small things.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;example-problems&#34;&gt;Example problems:&lt;/h4&gt;

&lt;p&gt;&lt;a href=&#34;https://www.audacityteam.org/&#34;&gt;Audacity&lt;/a&gt; doesn&amp;rsquo;t let you configure mouse shortcuts, so I used AutoHotKey to map the middle-mouse to a keyboard shortcut anyway.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;#HotIf&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;WinActive&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ahk_exe audacity.exe&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;MButton::Send&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;^l&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt; ; silence selection&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;#HotIf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I made typing `&lt;code&gt;;iso&lt;/code&gt;` fill in the current date.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;R&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;iso&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;::&lt;/span&gt; 
&lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;Send(FormatTime(,&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;yyyy-MM-dd&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;))&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a tool I use to take timestamped notes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;; right-ctrl + d&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;^&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;::&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;TimeString&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;FormatTime(,&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;MM/dd hh:mm tt&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;t_msg&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;InputBox(,TimeString,&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;w200 h100&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;if t_msg&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Result&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;OK&amp;quot;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;timestampfile&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;A_WorkingDir&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;\Config\timestamps.txt&amp;quot;&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;FileAppend(TimeString&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;`t&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;t_msg&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;`r`n&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;timestampfile)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Other uses: launch REPLs for toolbox languages. Input the 100-keypress sequence required to beat one videogame (if you know, you know).&lt;/p&gt;

&lt;p&gt;Further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/ahk-scripts-project/&#34;&gt;Learn AutoHotKey by stealing my scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/ahk-v2/&#34;&gt;Somehow AutoHotKey is Kinda Good Now&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/ahk/&#34;&gt;In Praise of AutoHotKey&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;j-https-code-jsoftware-com-wiki-main-page&#34;&gt;&lt;a href=&#34;https://code.jsoftware.com/wiki/Main_Page&#34;&gt;J&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;An array language, like &lt;a href=&#34;https://en.wikipedia.org/wiki/APL_(programming_language)&#34;&gt;APL&lt;/a&gt;. Really good at doing arithmetic on arrays, hair-pullingly frustrating at doing anything with strings or structured data. I used to use it a lot but I&amp;rsquo;ve mostly switched to other tools, like &lt;a href=&#34;https://buttondown.email/hillelwayne/archive/excel-is-pretty-dang-cool/&#34;&gt;Excel&lt;/a&gt; and Raku. But it&amp;rsquo;s still amazing for its niches.&lt;/p&gt;

&lt;h4 id=&#34;useful-features-1&#34;&gt;Useful features:&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;It is &lt;em&gt;insanely&lt;/em&gt; terse. Things that would take a several lines in most languages take a few characters in J, so I like it for quickly doing a bunch of math.&lt;/li&gt;
&lt;li&gt;First-class multidimensional arrays. &lt;code&gt;+&lt;/code&gt; can add two numbers together, two arrays elementwise, a single number to every element of an array, or an array to every row (or column) of an higher-dimension array.&lt;/li&gt;
&lt;li&gt;There are lots of top-level primitives that do special case mathematical things, like decompose a number into its prime factors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;example-problems-1&#34;&gt;Example problems:&lt;/h4&gt;

&lt;p&gt;Get all of the prime factors of a number:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-j&#34; data-lang=&#34;j&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;    q&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2520&lt;/span&gt;
&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Given two processes, each running a four step algorithm, &lt;a href=&#34;https://buttondown.email/hillelwayne/archive/what-makes-concurrency-so-hard/&#34;&gt;how many possible interleavings are there&lt;/a&gt;?&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-j&#34; data-lang=&#34;j&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;    ni &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=:&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;!@:&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;+/&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;) &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;%&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*/@:!&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    ni &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;4&lt;/span&gt;
&lt;span style=&#34;color: #ae81ff&#34;&gt;70&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What if I wanted a table of interleavings for each value of 1 to 3 processors and 1 to 3 steps?&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-j&#34; data-lang=&#34;j&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;   (ni&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;@:$&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;/~&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;:&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; i&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;   &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;20&lt;/span&gt;
&lt;span style=&#34;color: #ae81ff&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;90&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1680&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/j-notation/&#34;&gt;J notation as a tool of thought&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/j-as-a-desktop-calculator/&#34;&gt;J as a desktop calculator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/sudoku/&#34;&gt;How to solve sudoku&lt;/a&gt; (The appendix, mostly)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;frink-https-frinklang-org&#34;&gt;&lt;a href=&#34;https://frinklang.org/&#34;&gt;Frink&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Possibly the most obscure language on this list. Frink is designed for dimensional analysis (math with units), but it&amp;rsquo;s also got a bunch of features for covering whatever the developer thinks is interesting. Which is quite a lot of things! It&amp;rsquo;s probably the closest to &amp;ldquo;a better calculator&amp;rdquo; of any programming language I&amp;rsquo;ve seen: easy to get started with, powerful, and doesn&amp;rsquo;t have the unfamiliar syntax of J or Raku.&lt;/p&gt;

&lt;h4 id=&#34;useful-features-2&#34;&gt;Useful features:&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Lots of builtin units and unit modifiers. &lt;code&gt;calendaryear&lt;/code&gt; is exactly 365 days, &lt;code&gt;tropicalyear&lt;/code&gt; is 365.24, and &lt;code&gt;half nanocentury&lt;/code&gt; is about 1.6 seconds.&lt;/li&gt;
&lt;li&gt;Date literal notation: &lt;code&gt;# 2000-01-01 # - # 200 BC #&lt;/code&gt; is 2199.01 years.&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s a builtin interval type for working with uncertainties. It&amp;rsquo;s a little clunky but it works.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;example-problems-2&#34;&gt;Example problems:&lt;/h4&gt;

&lt;p&gt;If someone was born at midnight on Jan 1st 1970, when do they become a billion seconds old?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   # 1970 # + 1 billion seconds
AD 2001-09-09 AM 02:46:40.000 (Sun) Central Daylight Time
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If I run a certain distance in a certain time, what&amp;rsquo;s my average pace?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   // In miles per hour
   2.5 miles / (27 minutes + 16 seconds) -&amp;gt; mph
5.5012224938875305623

   // In meters per hour
   2.5 miles / (27 minutes + 16 seconds) -&amp;gt; meters / hour
8853.3594132029339854

   // In (minutes, seconds) per mile
   1 / (4.5 miles / hour) -&amp;gt; [minutes/mile, seconds/mile, 0]
13, 19
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What&amp;rsquo;s (6 ± 2) * (8 ± 1)?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   x = new interval [2, -2]
   (6 + x) * (8 + x/2)
[28, 72] // range is between 28 and 72
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;further-reading&#34;&gt;Further reading:&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/frink/&#34;&gt;The Frink is Good, the Unit is Evil&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/a-brief-introduction-to-interval-arithmetic/&#34;&gt;A brief introduction to interval arithmetic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;raku-https-raku-org&#34;&gt;&lt;a href=&#34;https://raku.org/&#34;&gt;Raku&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Raku (née Perl 6) is a &lt;em&gt;really&lt;/em&gt; weird language filled to the brim with dark magic. It&amp;rsquo;s very powerful and also very easy to screw up. I&amp;rsquo;m not yet comfortable running it for a production program. But for personal scripting and toolkits, it&amp;rsquo;s incredible.&lt;/p&gt;

&lt;h4 id=&#34;useful-features-3&#34;&gt;Useful features&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can define your own &lt;a href=&#34;https://docs.raku.org/language/functions#Defining_operators&#34;&gt;infix operators&lt;/a&gt;! And postfix operators. And &lt;a href=&#34;https://docs.raku.org/language/operators#Operator_classification&#34;&gt;&lt;em&gt;circumfix&lt;/em&gt; operators&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Lots and &lt;em&gt;lots&lt;/em&gt; of syntactic sugar, to a level that worries me. Like instead of &lt;code&gt;[1, 2]&lt;/code&gt; you can write &lt;code&gt;&amp;lt;1 2&amp;gt;&lt;/code&gt;. And instead of &lt;code&gt;[&amp;quot;a&amp;quot;, &amp;quot;bc&amp;quot;]&lt;/code&gt; you can write &lt;code&gt;&amp;lt;a bc&amp;gt;&lt;/code&gt;. Raku Just Knows&amp;trade; what to do.&lt;/li&gt;
&lt;li&gt;If you define a &lt;code&gt;MAIN&lt;/code&gt; function then its parameters are turned into CLI arguments.&lt;/li&gt;
&lt;li&gt;Multimethods with multiple dispatch, based on runtime values. Combining this with &lt;code&gt;MAIN&lt;/code&gt; makes small CLI tooling really easy.&lt;/li&gt;
&lt;li&gt;Many of the mathematical operators have unicode equivalents (like ∈ for `&lt;code&gt;(elem)&lt;/code&gt;`), which synergizes well with all of my AutoHotKey hotstrings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;example-problems-3&#34;&gt;Example problems&lt;/h4&gt;

&lt;p&gt;Generate three random 10-character lowercase strings.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&amp;gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt; ^&lt;span style=&#34;color: #ae81ff&#34;&gt;3&lt;/span&gt; {&lt;span style=&#34;color: #f8f8f2&#34;&gt;say&lt;/span&gt; (&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;..&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;#39;z&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;roll&lt;/span&gt;(&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;join&lt;/span&gt;}
&lt;span style=&#34;color: #f8f8f2&#34;&gt;fflqymxapa&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;znyxehaqvo&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;qwqxusudqw&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Parse unusual structured data formats with &lt;a href=&#34;https://gist.github.com/hwayne/94ca3b23078234ca7e803c061b9338f3#file-format_picat-raku&#34;&gt;grammars&lt;/a&gt; (see link).&lt;/p&gt;

&lt;p&gt;Copy a bunch of SVG ids over into inkscape labels.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;XML&lt;/span&gt;;

&lt;span style=&#34;color: #66d9ef&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$xml&lt;/span&gt; = &lt;span style=&#34;color: #f8f8f2&#34;&gt;from-xml-file&lt;/span&gt;(&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;file.svg&amp;quot;&lt;/span&gt;);

&lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$xml&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;elements&lt;/span&gt;(:&lt;span style=&#34;color: #f8f8f2&#34;&gt;NEST&lt;/span&gt;, :&lt;span style=&#34;color: #f8f8f2&#34;&gt;RECURSE&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;lt;99&amp;gt;&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$e&lt;/span&gt; {
  &lt;span style=&#34;color: #66d9ef&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$e&amp;lt;id&amp;gt;&lt;/span&gt; ~~&lt;span style=&#34;color: #e6db74&#34;&gt; /k\w/&lt;/span&gt; {
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;say&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$_&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;target&lt;/span&gt;;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;$e&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;set&lt;/span&gt;(&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;inkscape:label&amp;quot;&lt;/span&gt;, &lt;span style=&#34;color: #f8f8f2&#34;&gt;$_&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;target&lt;/span&gt;);
  }
}
&lt;span style=&#34;color: #f8f8f2&#34;&gt;$xml&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;save&lt;/span&gt;()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Write a CLI with a few fiddly combinations of options (&lt;a href=&#34;https://www.hillelwayne.com/post/randomness/src/rng.raku&#34;&gt;example&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/raku-a-language-for-gremlins/&#34;&gt;Raku, a Language for Gremlins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/randomness/&#34;&gt;An RNG that runs in your brain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/raku-is-surprisingly-good-for-clis/&#34;&gt;Raku is Surprisingly good for CLIs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;picat-http-picat-lang-org&#34;&gt;&lt;a href=&#34;http://picat-lang.org/&#34;&gt;Picat&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;My newest toolbox language, and the language that got me thinking about toolboxes in general. A heady mix of logic programming, constraint solving, and imperative escape hatches. I first picked it up as a Better Constraint Solver and kept finding new uses for it.&lt;/p&gt;

&lt;h4 id=&#34;useful-features-4&#34;&gt;Useful features:&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Assignment to variables. Shockingly useful in a logic language. Lots of problems felt &lt;em&gt;almost&lt;/em&gt; right for logic programming, but there&amp;rsquo;d always be one small part of the algorithm I couldn&amp;rsquo;t figure out how to represent 100% logically. Imperative provided the escape hatch I needed.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;planner&lt;/code&gt; module. I &lt;strong&gt;love&lt;/strong&gt; the &lt;code&gt;planner&lt;/code&gt; module. It is my best friend. Give it a goal and a list of possible actions, Picat will find a sequence of actions that reaches the goal. It is extremely cool.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;example-problems-4&#34;&gt;Example problems:&lt;/h4&gt;

&lt;p&gt;If I run at 4.5 miles/hour for X minutes and 5.1 for Y minutes, what should X and Y be to run 3.1 miles in 38 minutes?&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;cp&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;[X,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Y]&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1..60&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;45&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;51&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Y&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;#=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;X&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Y&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;#=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;38&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;solve&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([X,Y]).&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;13&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Y&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;25&lt;/span&gt;
&lt;span style=&#34;color: #e6db74&#34;&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Given a bunch of activities, time constraints, and incompatibilities, &lt;a href=&#34;https://gist.github.com/hwayne/c2e7d928d16de4ce3d117cf2e45d464d&#34;&gt;figure out a vacation plan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Checking if a logic puzzle has multiple solutions. Checking if the clues of a logic puzzle are redundant, or if one could be removed and preserve the unique solution.&lt;/p&gt;

&lt;p&gt;Mocking up a quick Petri net &lt;a href=&#34;https://gist.github.com/hwayne/846faf9a841eb90a37221cebaba6d74b&#34;&gt;reachability solver&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&#34;further-reading-1&#34;&gt;Further reading:&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/picat/&#34;&gt;Planner programming blows my mind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/picat-is-my-favorite-new-toolbox-language/&#34;&gt;Picat is my favorite new toolbox language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/solving-a-math-problem-with-planner-programming/&#34;&gt;Solving a math problem with planner programming&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;what-makes-a-good-toolbox-language&#34;&gt;What makes a good toolbox language?&lt;/h2&gt;

&lt;p&gt;Most of the good toolbox languages I&amp;rsquo;ve seen are for computation and calculation. I think toolbox languages for effects and automation are possible (like AutoHotKey) but that space is less explored.&lt;/p&gt;

&lt;p&gt;A toolbox language should be really, REALLY fast to write. At the very least, faster than Python. Compare &amp;ldquo;ten pairs of random numbers&amp;rdquo;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# python

from random import randint
[(randint(10), randint(10)) for _ in range(10)]

# Raku
^10 .roll(2) xx 10

# J
10 2 ?@$ 10
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things lead to this: a terse syntax means typing less. Lots of builtins means less writing basic stuff myself. Importing from a standard library is less than ideal, but acceptable. Having to install a third-party package bothers me. Raku does something cool here; the &lt;a href=&#34;https://rakudo.org/star&#34;&gt;Rakudo Star Bundle&lt;/a&gt; comes with a bunch of useful community packages preinstalled.&lt;/p&gt;

&lt;p&gt;If you can do something in a single line, you can throw it in a REPL. So you want a good REPL. Most of the languages I use have good repls, though I imagine my lisp and Smalltalk readers will have words about what &amp;ldquo;good REPL&amp;rdquo; means.&lt;/p&gt;

&lt;p&gt;Ideally the language has a smooth on-ramp. Raku has a lot of complexity but you can learn just a little bit and still be useful, while J&amp;rsquo;s learning curve is too steep to recommend to most people. This tends to conflict with being &amp;ldquo;fast to write&amp;rdquo;, though.&lt;/p&gt;

&lt;h2 id=&#34;other-tools-i-want-in-my-toolbox&#34;&gt;Other tools I want in my toolbox&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/jqlang/jq&#34;&gt;jq&lt;/a&gt; for json processing&lt;/li&gt;
&lt;li&gt;Javascript, so I can modify other people&amp;rsquo;s websites via the dev console&lt;/li&gt;
&lt;li&gt;Some kind of APL that offers the benefits of J but without the same frustrations I keep having&lt;/li&gt;
&lt;li&gt;A concatenative PL if I ever find out what small problems a CPL is really good for&lt;/li&gt;
&lt;li&gt;Something that makes webscraping and parsing as easy as calculation. Requests and bs4 ain&amp;rsquo;t it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://saul.pw/&#34;&gt;Saul Pwanson&lt;/a&gt; for feedback. If you liked this post, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write new essays there every week.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I train companies in formal methods, making software development faster, cheaper, and safer. Learn more &lt;a href=&#34;https://www.hillelwayne.com/consulting/&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;My new book, &lt;a href=&#34;https://leanpub.com/logic/&#34;&gt;Logic for Programmers&lt;/a&gt;, is now in early access! Find it &lt;a href=&#34;https://leanpub.com/logic/&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Composing TLA&#43; Specifications with State Machines</title>
        <link>https://www.hillelwayne.com/post/composing-tla/</link>
        <pubDate>Mon, 17 Jun 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/composing-tla/</guid>
        <description>

&lt;p&gt;Last year a client asked me to solve a problem: they wanted to be able to compose two large TLA+ specs as part of a larger system. Normally you&amp;rsquo;re &lt;a href=&#34;https://www.hillelwayne.com/post/spec-composition/&#34;&gt;not supposed to do this&lt;/a&gt; and instead write one large spec with both systems hardcoded in, but these specs were &lt;em&gt;enormous&lt;/em&gt; and had many internal invariants of their own. They needed a way to develop the two specs independently and then integrate them with minimal overhead.&lt;/p&gt;

&lt;p&gt;This is what I came up with. Warning: this is a complex solution is aimed at advanced TLA+ users. For a much (much) gentler introduction, check out my website &lt;a href=&#34;https://learntla.com/&#34;&gt;learntla&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;the-example&#34;&gt;The example&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s start by giving a motivating system:
a &lt;strong&gt;Worker&lt;/strong&gt; sends an authentication request to a &lt;strong&gt;Server&lt;/strong&gt;. If the password matches the server&amp;rsquo;s internal password, the server responds &amp;ldquo;valid&amp;rdquo;, otherwise it responds &amp;ldquo;invalid&amp;rdquo;. If the worker receives &amp;ldquo;invalid&amp;rdquo; as a response, it goes into an error state. The worker can retry from that state and submit a new authentication request.&lt;/p&gt;

&lt;p&gt;The worker and server have shared state via the request/response. As an additional complication, we&amp;rsquo;ll add internal state to the server, in the form of a request log that is hidden from the worker.&lt;/p&gt;

&lt;p&gt;We can use this example to show the problems of composition and my solution (though I&amp;rsquo;ll say the example is a little too simple to make it worthwhile).&lt;/p&gt;

&lt;h3 id=&#34;the-problem-with-composition&#34;&gt;The problem with composition&lt;/h3&gt;

&lt;p&gt;What we &lt;em&gt;want&lt;/em&gt; is for the composition to be as simple and painless as possible. If our specs are &lt;code&gt;WorkerSpec&lt;/code&gt; and &lt;code&gt;ServerSpec&lt;/code&gt;, the easiest composition would just be&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CombinedSpec == WorkerSpec /\ ServerSpec
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I talk about the problems we have in-depth &lt;a href=&#34;https://www.hillelwayne.com/post/spec-composition/&#34;&gt;here&lt;/a&gt;, but the gist is that if &lt;code&gt;ServerSpec&lt;/code&gt; and &lt;code&gt;WorkerSpec&lt;/code&gt; are &amp;ldquo;normal&amp;rdquo; specs, they&amp;rsquo;ll place contradictory constraints on the shared variables.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;WorkerSpec&lt;/code&gt; will likely read the server response, but not modify it. So to run &lt;code&gt;WorkerSpec&lt;/code&gt; independently of the composition, we have to say the response never changes, which is equivalent to saying we &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; change it, which makes it impossible for &lt;code&gt;ServerSpec&lt;/code&gt; to send a response!&lt;/p&gt;

&lt;p&gt;The normal way around this is to break apart both &lt;code&gt;WorkerSpec&lt;/code&gt; and &lt;code&gt;ServerSpec&lt;/code&gt; into collections of actions, and then carefully stitch them together in non-contradictory ways. Which is about as complex as it sounds: composing two specs can be as much work as writing them in the first place.&lt;/p&gt;

&lt;p&gt;This is why I&amp;rsquo;m trying to find a better way.&lt;/p&gt;

&lt;h3 id=&#34;the-big-idea&#34;&gt;The big idea&lt;/h3&gt;

&lt;p&gt;What we need to do is write specs intended to represent &lt;em&gt;part&lt;/em&gt; of the world and then incorporate them into a &amp;ldquo;whole world&amp;rdquo; main spec. To do this, we&amp;rsquo;ll use one of TLA+&amp;rsquo;s most powerful features: we can use &lt;code&gt;x&#39;&lt;/code&gt; to both &lt;em&gt;assign the next value to x&lt;/em&gt; and &lt;em&gt;constrain what the next value can be.&lt;/em&gt; Say we have&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;VARIABLE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;y&lt;/span&gt; 

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Foo&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
  &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
  &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;y&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Bar&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;y&amp;#39;&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Foo&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Bar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When &lt;abbr title=&#34;The model checker&#34;&gt;TLC&lt;/abbr&gt;
 evaluates &lt;code&gt;Next&lt;/code&gt;, it reads &lt;code&gt;x&#39;&lt;/code&gt; and &lt;code&gt;y&#39;&lt;/code&gt; in &lt;code&gt;Foo&lt;/code&gt; as &lt;em&gt;assignments&lt;/em&gt;. There are four possible assignments, so the model checker evaluates them all.&lt;/p&gt;

&lt;p&gt;Then, since &lt;code&gt;x&#39;&lt;/code&gt; and &lt;code&gt;y&#39;&lt;/code&gt; are already chosen, TLC reads the statement in &lt;code&gt;Bar&lt;/code&gt; as a &lt;em&gt;constraint&lt;/em&gt;. Three of the possible assignments break that constraint, so TLC eliminates those possibilities, leaving us with a unique next state.&lt;/p&gt;

&lt;p&gt;This means that a Spec Q can take two specs, X and Y, and &lt;em&gt;constrain&lt;/em&gt; them against each other. X can have an action &lt;code&gt;Inc&lt;/code&gt; that increments &lt;code&gt;x_log&lt;/code&gt;, and then Q says that &lt;code&gt;Inc&lt;/code&gt; can only happen if &lt;code&gt;y_flag&lt;/code&gt; is true. Similarly, Q can make one assignment trigger another:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Inc&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
  &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x_log&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x_log&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
  &lt;span style=&#34;color: #66d9ef&#34;&gt;IF&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;~&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;y_flag&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;y_flag&amp;#39;&lt;/span&gt; 
  &lt;span style=&#34;color: #66d9ef&#34;&gt;THEN&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Inc&lt;/span&gt; 
  &lt;span style=&#34;color: #66d9ef&#34;&gt;ELSE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;TRUE&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;(X!Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Y!Next)&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, changing &lt;code&gt;y_flag&lt;/code&gt; to true &lt;em&gt;forces&lt;/em&gt; an increment in &lt;code&gt;x_log&lt;/code&gt;. Q is using one spec to drive side-effects in the system.&lt;/p&gt;

&lt;p&gt;This is just a state machine! Constraints on transitions are just &lt;a href=&#34;https://en.wikipedia.org/wiki/Guard_(computer_science)&#34;&gt;guard clauses&lt;/a&gt; and assignments on transitions are just effects. These can be enforced on &lt;em&gt;other specifications&lt;/em&gt; that the state machine doesn&amp;rsquo;t know about.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s how to make this idea work in practice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write an abstract state machine for all of the high-level state transitions of the core component&lt;/li&gt;
&lt;li&gt;Write the other components as &amp;ldquo;open&amp;rdquo; specs that don&amp;rsquo;t fully describe their next states.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/refinement/&#34;&gt;Refine&lt;/a&gt; the core component into the main spec, with a &lt;code&gt;Sync&lt;/code&gt; action that adds guards and side-effects to the state transitions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;the-solution&#34;&gt;The Solution&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ll model this with three separate specs: &lt;code&gt;workerSM.tla&lt;/code&gt;, &lt;code&gt;server.tla&lt;/code&gt;, and &lt;code&gt;system.tla&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;the-state-machine&#34;&gt;The state machine&lt;/h3&gt;

&lt;p&gt;Since the whole system is based around the worker&amp;rsquo;s state machine, let&amp;rsquo;s start with &lt;code&gt;workerSM.tla&lt;/code&gt;. This won&amp;rsquo;t represent what &lt;em&gt;happens&lt;/em&gt; when the worker transitions states, just what the transitions are.&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/sm.gv.png&#34;    title=&#34;A graphviz diagram of the state machine, see caption for accessible version&#34; &gt; 

  &lt;figcaption&gt;
     

  &lt;a href=&#34;img/sm.gv&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;



&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;-------------------&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;MODULE&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;workerSM&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;-------------------&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;EXTENDS&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Integers&lt;/span&gt;

&lt;span style=&#34;color: #f92672&#34;&gt;VARIABLES&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;state&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Transitions&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;[from&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;init&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ready&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[from&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ready&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[from&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[from&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[from&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;|-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ready&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Init&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;state&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;init&amp;quot;&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Valid(t)&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;state&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;t&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;from&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;ValidTransitions&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{t&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Transitions:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Valid(t)}&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;ValidOutcomes&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{t&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ValidTransitions}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Done&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;state&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ValidOutcomes:&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;state&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;t&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Fairness&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;WF_state(Next)&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;SF_state(state&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Spec&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Init&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[][Next]_state&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fairness&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Liveness&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;&amp;lt;&amp;gt;Done&lt;/span&gt;

&lt;span style=&#34;color: #75715e&#34;&gt;=========================================================&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Transitions&lt;/code&gt; represents the set of valid transitions. The three &lt;code&gt;Valid-&lt;/code&gt; operators are just helpers. Adding them is good practice; most TLA+ specs don&amp;rsquo;t have enough helpers.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Fairness&lt;/code&gt; constraint is a little complex, but all it&amp;rsquo;s saying is that we can&amp;rsquo;t &lt;em&gt;always&lt;/em&gt; transition from &lt;code&gt;requesting&lt;/code&gt; to &lt;code&gt;error&lt;/code&gt;. If we get there often enough, we&amp;rsquo;ll eventually transition to &lt;code&gt;done&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;Otherwise this spec doesn&amp;rsquo;t put any conditions on the transfers: we don&amp;rsquo;t need to &amp;ldquo;do anything&amp;rdquo; to go to &lt;code&gt;done&lt;/code&gt;. That&amp;rsquo;s what &lt;code&gt;system.tla&lt;/code&gt; is for.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    show cfg
  &lt;/summary&gt;
  &lt;p&gt;I used this to directly test the worker.&lt;/p&gt;

&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;SPECIFICATION&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Spec&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;PROPERTY&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Liveness&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;CHECK_DEADLOCK&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;FALSE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It passes, meaning this spec guarantees &lt;code&gt;&amp;lt;&amp;gt;Done&lt;/code&gt;.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Next, the outside component we&amp;rsquo;ll integrate with the worker.&lt;/p&gt;

&lt;h3 id=&#34;the-server&#34;&gt;The server&lt;/h3&gt;


&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;-------------------&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;MODULE&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;server&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;-------------------&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;CONSTANTS&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Password,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;

&lt;span style=&#34;color: #f92672&#34;&gt;VARIABLE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;req,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;resp,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;log&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;internal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;             &lt;span style=&#34;color: #75715e&#34;&gt;\* (a)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;external&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;req,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;resp&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;       &lt;span style=&#34;color: #75715e&#34;&gt;\* (a)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;vars&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;external,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;internal&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color: #75715e&#34;&gt;\* (a)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Init&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;log&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;CheckRequest&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;log&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;log&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;\union&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{req}&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;IF&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Password&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;THEN&lt;/span&gt;
         &lt;span style=&#34;color: #f8f8f2&#34;&gt;resp&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;valid&amp;quot;&lt;/span&gt;
       &lt;span style=&#34;color: #66d9ef&#34;&gt;ELSE&lt;/span&gt;
         &lt;span style=&#34;color: #f8f8f2&#34;&gt;resp&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;invalid&amp;quot;&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;req&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* (b) &lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;CheckRequest&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Spec&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Init&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[][Next]_internal&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* (c)&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;====&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We&amp;rsquo;re doing three unusual things in this spec. First is that we split the variables into &lt;code&gt;internal&lt;/code&gt; and &lt;code&gt;external&lt;/code&gt; vars &lt;strong&gt;(a)&lt;/strong&gt;. External vars represent state that&amp;rsquo;s shared with other parts of the composed specification, while internal only pertains to the &lt;code&gt;server&lt;/code&gt;&amp;rsquo;s properties. Here we represent requests to the server with &lt;code&gt;req&lt;/code&gt; and responses with &lt;code&gt;resp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Second, the spec will trivially deadlock &lt;strong&gt;(b)&lt;/strong&gt;. &lt;code&gt;Next&lt;/code&gt; only contains the &lt;code&gt;CheckRequest&lt;/code&gt; action, &lt;code&gt;CheckRequest&lt;/code&gt; is only enabled if &lt;code&gt;req&lt;/code&gt; isn&amp;rsquo;t null, but nothing in the spec makes &lt;code&gt;req&lt;/code&gt; not-null. This spec isn&amp;rsquo;t &amp;ldquo;self-contained&amp;rdquo;, and it needs to be used by another specification to be meaningful.&lt;/p&gt;

&lt;p&gt;Third, Spec is only stuttering invariant with respect to &lt;code&gt;internal&lt;/code&gt; variables. This is done by writing &lt;code&gt;[][Next]_internals&lt;/code&gt; instead of &lt;code&gt;[][Next]_vars&lt;/code&gt; &lt;strong&gt;(c)&lt;/strong&gt;. This is the easiest part to miss but will make both spec composition and spec refinement easier down the line.&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s put the server and the worker together.&lt;/p&gt;

&lt;h3 id=&#34;the-system&#34;&gt;The system&lt;/h3&gt;

&lt;p&gt;This is by far the most complex part. Let&amp;rsquo;s start with the whole spec, and then cover a breakdown of the most important sections.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    system spec
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;----&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;MODULE&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;system&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;----&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;EXTENDS&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;TLC,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Integers,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Sequences&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;CONSTANT&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;VARIABLES&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ws&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* worker state&lt;/span&gt;
 &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* requests to server&lt;/span&gt;
 &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* server response&lt;/span&gt;
 &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_log&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* log (internal to server)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Strings&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;vars&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;ws,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_log,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;INSTANCE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;workerSM&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;WITH&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;state&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ws&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Server&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;INSTANCE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;WITH&lt;/span&gt; 
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req,&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp,&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;log&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_log,&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Password&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;LET&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;ws,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ws&amp;#39;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;IN&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;CASE&lt;/span&gt;
            &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ready&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
            &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Strings:&lt;/span&gt;
                &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt;
            &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;[]&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
            &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;invalid&amp;quot;&lt;/span&gt;
            &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;[]&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
            &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;valid&amp;quot;&lt;/span&gt;
            &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;OTHER&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Init&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker!Init&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server!Init&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Done&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* No deadlock on finish&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker!Done&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;vars&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;ServerNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server!Next&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ws&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;WorkerNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker!Next&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_log&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;WorkerNext&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ServerNext&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Done&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Fairness&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;WF_vars(Next)&lt;/span&gt; 

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Spec&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Init&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[][Next]_vars&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fairness&lt;/span&gt; 

&lt;span style=&#34;color: #f8f8f2&#34;&gt;RefinesServer&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server!Spec&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;RefinesWorker&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker!Spec&lt;/span&gt;

&lt;span style=&#34;color: #75715e&#34;&gt;====&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;


&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;VARIABLES&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ws&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* worker state&lt;/span&gt;
 &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* requests to server&lt;/span&gt;
 &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* server response&lt;/span&gt;
 &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_log&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* log (internal to server)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Strings&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;vars&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;ws,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_log,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I like to group my &lt;code&gt;vars&lt;/code&gt; by purpose and spec. Since both the server and the worker use &lt;code&gt;server_req&lt;/code&gt; and &lt;code&gt;_resp&lt;/code&gt;, I put them in a separate &lt;code&gt;comm_vars&lt;/code&gt; grouping.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;INSTANCE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;workerSM&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;WITH&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;state&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ws&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Server&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;INSTANCE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;WITH&lt;/span&gt; 
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req,&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp,&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;log&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_log,&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Password&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I hard-coded the server&amp;rsquo;s &lt;code&gt;Password&lt;/code&gt; constant for pedagogical convenience. We don&amp;rsquo;t have to instantiate the &lt;code&gt;NULL&lt;/code&gt; constant because it&amp;rsquo;s the same name in both &lt;code&gt;system.tla&lt;/code&gt; and &lt;code&gt;server.tla&lt;/code&gt;, so it propagates automatically.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
  &lt;span style=&#34;color: #75715e&#34;&gt;\* See next section&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Init&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker!Init&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server!Init&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;ServerNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server!Next&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ws&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;WorkerNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker!Next&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_log&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Done&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* No deadlock on finish&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker!Done&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;vars&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;WorkerNext&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ServerNext&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Init&lt;/code&gt; just shells out to both &lt;code&gt;Worker!Init&lt;/code&gt; and &lt;code&gt;Server!Init&lt;/code&gt; to set up their respective variables. It&amp;rsquo;s easy here because they don&amp;rsquo;t share any variables. &lt;em&gt;If&lt;/em&gt; there was something that they both used or if &lt;code&gt;system&lt;/code&gt; needed any extra booking variables, I&amp;rsquo;d handle them specially here.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;ServerNext&lt;/code&gt; just says &amp;ldquo;the server can handle its own state updates&amp;rdquo;, but accounts for &lt;code&gt;ws&lt;/code&gt; stuttering (because every variable needs to be assigned a value on every step). The server is independently active in the system and its behavior doesn&amp;rsquo;t synchronously depend on the worker. Keeping the components separate isn&amp;rsquo;t always possible when composing, but it makes things more convenient when applicable.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;WorkerNext&lt;/code&gt; is the same: it behaves independently of &lt;code&gt;ServerNext&lt;/code&gt;. But here&amp;rsquo;s where the &amp;ldquo;system&amp;rdquo; starts to play a role, in &lt;code&gt;Sync&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;sync&#34;&gt;Sync&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Sync&lt;/code&gt; is where things get interesting.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;LET&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;ws,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ws&amp;#39;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;IN&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;CASE&lt;/span&gt;
          &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ready&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Strings:&lt;/span&gt;
              &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;[]&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;invalid&amp;quot;&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;[]&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;valid&amp;quot;&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;OTHER&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To recap the earlier explanation, primed variables can be used in other expressions after being assigned. This means we can attempt a transition in one action and then check if the transition is valid in a later action. &lt;strong&gt;This is the key to making this all work.&lt;/strong&gt; Without this, we&amp;rsquo;d have to put the guards and side effects in the same action as the transitions. For example, in this line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;      &lt;span style=&#34;color: #f8f8f2&#34;&gt;[]&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;invalid&amp;quot;&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;comm_vars&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We are constraining the &lt;code&gt;requesting -&amp;gt; error&lt;/code&gt; transition to only be possible &lt;em&gt;if&lt;/em&gt; the server response was &amp;ldquo;invalid&amp;rdquo;. That&amp;rsquo;s only possible if &lt;code&gt;Server!Next&lt;/code&gt; rejected the password. But &lt;em&gt;our worker doesn&amp;rsquo;t need to know this&lt;/em&gt;. We can develop them independently and rely on the &lt;code&gt;Sync&lt;/code&gt; to correctly compose their behaviors.&lt;/p&gt;

&lt;p&gt;We can also use this to drive effects on the system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;      &lt;span style=&#34;color: #f8f8f2&#34;&gt;[]&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ready&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;requesting&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Strings:&lt;/span&gt;
              &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_req&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt;
          &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server_resp&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This makes a &lt;code&gt;ready -&amp;gt; requesting&lt;/code&gt; transition also trigger a request (and clear any outstanding response). This then enables &lt;code&gt;Server!CheckRequest&lt;/code&gt;, which enables &lt;code&gt;ServerNext&lt;/code&gt;, so the server can react to the system.&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/sm_annot.gv.png&#34;    title=&#34;Three state transitions of workerSM, with guards and labels added by system.&#34; &gt; 

  &lt;figcaption&gt;
     

  &lt;a href=&#34;img/file_graph__01.gv&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;h3 id=&#34;refinements&#34;&gt;Refinements&lt;/h3&gt;

&lt;p&gt;Remember, we added all of this machinery in first place in order to compose two complex specifications together. We need to make sure we&amp;rsquo;re composing them in a way that doesn&amp;rsquo;t violate either of their own properties. That&amp;rsquo;s handled by these lines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;RefinesServer&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server!Spec&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;RefinesWorker&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Worker!Spec&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These are &lt;a href=&#34;https://www.hillelwayne.com/post/refinement/&#34;&gt;refinement properties&lt;/a&gt;. At a high level, these check that &lt;code&gt;system.tla&lt;/code&gt; doesn&amp;rsquo;t make the &lt;code&gt;Server&lt;/code&gt; or &lt;code&gt;Worker&lt;/code&gt; do anything they&amp;rsquo;re not normally able to do. For example, this property would fail if we removed something from &lt;code&gt;log&lt;/code&gt;, since that&amp;rsquo;s not possible in &lt;code&gt;Server!Spec&lt;/code&gt;. &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:internal&#34;&gt;&lt;a href=&#34;#fn:internal&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;In TLA+, &lt;strong&gt;refinements are transitive&lt;/strong&gt;. &lt;code&gt;workerSM.tla&lt;/code&gt; had the &lt;a href=&#34;https://www.hillelwayne.com/post/safety-and-liveness/&#34;&gt;liveness property&lt;/a&gt; &lt;code&gt;&amp;lt;&amp;gt;Done&lt;/code&gt;. Since I already verified it in &lt;code&gt;workerSM.cfg&lt;/code&gt;, I don&amp;rsquo;t need to test it in &lt;code&gt;system.tla&lt;/code&gt;. If &lt;code&gt;RefinesWorker&lt;/code&gt; passes, then &lt;code&gt;Worker!Liveness&lt;/code&gt; is guaranteed to pass, too!&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Why refinement is transitive
  &lt;/summary&gt;
  &lt;p&gt;When we test &lt;code&gt;RefinesWorker&lt;/code&gt;, what we&amp;rsquo;re verifying is&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Spec =&amp;gt; Worker!Spec 
(S)     (WS)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We already know from model checking &lt;code&gt;workerSM.tla&lt;/code&gt; that&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Worker!Spec =&amp;gt; Worker!Liveness (2)
(WS)           (WL)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Implication is transitive: if &lt;code&gt;S =&amp;gt; WS&lt;/code&gt; and &lt;code&gt;WS =&amp;gt; WL&lt;/code&gt;, then &lt;code&gt;S =&amp;gt; WL&lt;/code&gt;.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;And currently it &lt;em&gt;fails&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    show cfg
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;SPECIFICATION&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Spec&lt;/span&gt;

&lt;span style=&#34;color: #f92672&#34;&gt;CONSTANTS&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;PROPERTY&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;RefinesServer&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;RefinesWorker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/error_trace.png&#34;    title=&#34;The error trace, see caption for accessible version&#34; &gt; 

  &lt;figcaption&gt;
    The error trace in VSCode. 

  &lt;a href=&#34;img/error_trace.txt&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;The problem is that the worker can keep picking the wrong password, so the server keeps rejecting it and the worker never completes. One fix is to say the system never retries the same password:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync ==&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;   \* ...
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;           /\ \E x \in Strings:
&lt;span style=&#34;color: #a6e22e&#34;&gt;+               /\ x \notin server_log&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;               /\ server_req&amp;#39; = x
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This makes the spec pass. If you&amp;rsquo;re concerned about leaking the server&amp;rsquo;s internal log to the system, you can add a log to the worker, too, either in &lt;code&gt;system.tla&lt;/code&gt; or in a separate component that you include in the &lt;code&gt;Sync&lt;/code&gt;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:stacked-specs&#34;&gt;&lt;a href=&#34;#fn:stacked-specs&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; An alternative fix uses a &lt;a href=&#34;https://www.hillelwayne.com/post/fairness/&#34;&gt;strong fairness constraint&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync ==&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;   \* ...
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;           /\ \E x \in Strings:
&lt;span style=&#34;color: #f92672&#34;&gt;-               /\ x \notin server_log&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;               /\ server_req&amp;#39; = x

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Fairness == &lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;   /\ WF_vars(Next) 
&lt;span style=&#34;color: #a6e22e&#34;&gt;+   /\ SF_vars(WorkerNext /\ server_req&amp;#39; = &amp;quot;a&amp;quot;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This says that if it&amp;rsquo;s always-eventually possible to execute &lt;code&gt;WorkerNext&lt;/code&gt; in a way that sends the right password, the spec eventually will. This makes the spec pass without changing the essential logic of the system.&lt;/p&gt;

&lt;h3 id=&#34;closing-the-open-world&#34;&gt;Closing the open world&lt;/h3&gt;

&lt;p&gt;One last thing we need to do: make &lt;code&gt;server.tla&lt;/code&gt; model-checkable. We can&amp;rsquo;t test it directly because it&amp;rsquo;s not a &amp;ldquo;closed&amp;rdquo; specification: it relies on some other spec to send requests. For more complex specs we want to be able to test that spec&amp;rsquo;s properties independently of the composition.&lt;/p&gt;

&lt;p&gt;Fortunately, this is an &amp;ldquo;already solved problem&amp;rdquo; in the TLA+ community: refine the open spec into a closed one. We do this with a new file &lt;code&gt;MCserver.tla&lt;/code&gt;:&lt;/p&gt;


&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;----&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;MODULE&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;MCserver&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;----&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;EXTENDS&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;TLC,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;server&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Strings&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;ASSUME&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Password&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Strings&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;MCInit&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Init&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;WorldNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Strings:&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;req&amp;#39;&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;log,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;resp&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;MCNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;WorldNext&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;MCSpec&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;MCInit&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[][MCNext]_vars&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;====&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This augments the server with an external &lt;code&gt;World&lt;/code&gt; that can send requests. Now we can test the behavior of &lt;code&gt;server.tla&lt;/code&gt; by model checking &lt;code&gt;MCserver.tla&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    show cfg
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;SPECIFICATION&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;MCSpec&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;CONSTANT&lt;/span&gt; 
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NULL&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;Password&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;b&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;If you&amp;rsquo;re on the VSCode TLA+ extension nightly, running the &amp;ldquo;Check model with TLC&amp;rdquo; command on &lt;code&gt;server.tla&lt;/code&gt; will automatically run the model checker with &lt;code&gt;MCserver.tla&lt;/code&gt;. It also comes with a TLA+ debugger. The VSCode extension is great.&lt;/p&gt;

&lt;h2 id=&#34;advantages-and-drawbacks&#34;&gt;Advantages and Drawbacks&lt;/h2&gt;

&lt;p&gt;This is a lot of work! So why do this instead writing one large spec?&lt;/p&gt;

&lt;p&gt;The point of composing specs at all is so we can work on them independently. It&amp;rsquo;s not a big deal when each spec is ~30 lines, but when they&amp;rsquo;re each 200+ lines, you can&amp;rsquo;t just rewrite them as one spec.&lt;/p&gt;

&lt;p&gt;So let&amp;rsquo;s compare it to a more conventional approach to composition. I&amp;rsquo;ll use the &lt;a href=&#34;https://github.com/will62794/logless-reconfig&#34;&gt;MongoDB Raft composition&lt;/a&gt;, which &lt;a href=&#34;https://muratbuffalo.blogspot.com/2024/02/tla-modeling-of-mongodb-logless.html&#34;&gt;Murat Demirbas analyzes here&lt;/a&gt;. The independent specs are  &lt;a href=&#34;https://github.com/will62794/logless-reconfig/blob/f7a89c745837ceadfe7149fa522e2d4504bb20a6/MongoStaticRaft.tla&#34;&gt;MongoStaticRaft&lt;/a&gt; and &lt;a href=&#34;https://github.com/will62794/logless-reconfig/blob/f7a89c745837ceadfe7149fa522e2d4504bb20a6/MongoLoglessDynamicRaft.tla&#34;&gt;MongoLoglessDynamicRaft&lt;/a&gt;, which composed together in &lt;a href=&#34;https://github.com/will62794/logless-reconfig/blob/f7a89c745837ceadfe7149fa522e2d4504bb20a6/MongoRaftReconfig.tla&#34;&gt;MongoRaftReconfig&lt;/a&gt;. The &lt;code&gt;Next&lt;/code&gt; for &lt;code&gt;MongoStaticRaft&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;\* MongoStaticRaft&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #75715e&#34;&gt;\* (a)&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;ClientRequest(s)&lt;/span&gt;
    &lt;span style=&#34;color: #75715e&#34;&gt;\* etc&lt;/span&gt;
    &lt;span style=&#34;color: #75715e&#34;&gt;\* (b)&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Q&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Quorums(config[s])&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;BecomeLeader(s,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Q)&lt;/span&gt;
    &lt;span style=&#34;color: #75715e&#34;&gt;\* etc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While the compositional &lt;code&gt;Next&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;\* MongoRaftReconfig&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;OSMNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;csmVars&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;CSMNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;osmVars&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;JointNext&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;OSMNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #75715e&#34;&gt;\* (a)&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;OSM!ClientRequest(s)&lt;/span&gt;
    &lt;span style=&#34;color: #75715e&#34;&gt;\* etc&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;JointNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #75715e&#34;&gt;\* (b)&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Q&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Quorums(config[i])&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; 
        &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;OSM!BecomeLeader(i,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Q)&lt;/span&gt;
        &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;CSM!BecomeLeader(i,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Q)&lt;/span&gt;
    &lt;span style=&#34;color: #75715e&#34;&gt;\* etc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The actions under &lt;strong&gt;(a)&lt;/strong&gt; must be manually repeated in &lt;code&gt;OSMNext&lt;/code&gt;, while the actions under  &lt;strong&gt;(b)&lt;/strong&gt; must be be carefully interlaced with the other spec under &lt;code&gt;JointNext&lt;/code&gt;. This is the standard way of composing two specs, which gets progressively more difficult the more specs you need to integrate. It&amp;rsquo;s also hard to check refinements in this paradigm.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m trying to avoid both issues with my &lt;code&gt;Sync&lt;/code&gt;-based approach. Each component already has its own &lt;code&gt;Next&lt;/code&gt; that we can use without changes. Anything that affects shared variables is handled by the additional &lt;code&gt;Sync&lt;/code&gt; operator.&lt;/p&gt;

&lt;p&gt;Would &lt;em&gt;this spec&lt;/em&gt; benefit from my approach? I don&amp;rsquo;t know. I designed the approach for a primary &amp;ldquo;machine&amp;rdquo; interacting with external components, where here the two specs are on equal footing. I have a sketch for what the conversion would look like, but I don&amp;rsquo;t know if it&amp;rsquo;s necessarily better.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Sketch of changes
  &lt;/summary&gt;
  &lt;p&gt;This is all without adding an extra state machine. Pick one &amp;ldquo;primary&amp;rdquo; spec, say &lt;code&gt;CSM&lt;/code&gt;. &lt;code&gt;Spec&lt;/code&gt; then becomes&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Next&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; 
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;OSMNext&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;CSMNext&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;OSMNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;OSM!Next&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;csmVars&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;sharedVars&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* new op&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;CSMNext&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;CSM!Next&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;osmVars&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We need to add &lt;code&gt;sharedVars&lt;/code&gt; to &lt;code&gt;OSMNext&lt;/code&gt; so it doesn&amp;rsquo;t call &lt;code&gt;OSM!BecomeLeader&lt;/code&gt; on its own— that needs to happen through &lt;code&gt;Sync&lt;/code&gt;. &lt;code&gt;sharedVars&lt;/code&gt; will share some variables in common with with &lt;code&gt;csmVars&lt;/code&gt; and &lt;code&gt;osmVars&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Sync&lt;/code&gt; would look similar to &lt;code&gt;JointNext&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Sync&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Server&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\E&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Q&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Quorums(config[i])&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; 
        &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;OSM!BecomeLeader(i,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Q)&lt;/span&gt;
        &lt;span style=&#34;color: #f92672&#34;&gt;/\&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;CSM!BecomeLeader(i,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Q)&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* ...&lt;/span&gt;
    &lt;span style=&#34;color: #f92672&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UNCHANGED&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;sharedVars&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It annoys me that we&amp;rsquo;re repeating &lt;code&gt;CSM!BecomeLeader&lt;/code&gt; in both &lt;code&gt;CSMNext&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;Sync&lt;/code&gt;, but it&amp;rsquo;s the most straightforward way to ensure that both &lt;code&gt;OSM&lt;/code&gt; and &lt;code&gt;CSM&lt;/code&gt; use the same values for &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt;. I figured out some ways to deduplicate this but they all rely on creative misuse of TLA+ semantics.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;My prediction is that conventional composition works for a wider variety of cases, but the &lt;code&gt;Sync&lt;/code&gt; is more maintainable and scales better in the cases where it does work.&lt;/p&gt;

&lt;p&gt;Neither approach handles the &amp;ldquo;one-to-many&amp;rdquo; case well. That&amp;rsquo;s where you have a spec for a single worker and try to use it to add N workers, where N is a model parameter. I discuss why this is so difficult in my article &lt;a href=&#34;https://www.hillelwayne.com/post/tla-adt/&#34;&gt;Using Abstract Data Types in TLA+&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This is a powerful technique, but also one that takes experience and adds complexity. It&amp;rsquo;s good if you need to write a very large specification or need a library of reusable components. For smaller specifications, I&amp;rsquo;d recommend the standard technique of putting all of the components in one spec.&lt;/p&gt;

&lt;p&gt;This was developed for a consulting client and worked beautifully. I&amp;rsquo;m excited to share it with all of you! If you liked this, you can read other advanced TLA+ techniques &lt;a href=&#34;https://learntla.com/topics/index.html&#34;&gt;here&lt;/a&gt;, like how to &lt;a href=&#34;https://learntla.com/topics/optimization.html&#34;&gt;make model-checking faster.&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://muratbuffalo.blogspot.com/&#34;&gt;Murat Demirbas&lt;/a&gt; and &lt;a href=&#34;https://ahelwer.ca/&#34;&gt;Andrew Helwer&lt;/a&gt; for feedback. If you liked this post, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write new essays there every week.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I train companies in formal methods, making software development faster, cheaper, and safer. Learn more &lt;a href=&#34;https://www.hillelwayne.com/consulting/&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;appendix-sync-without-primes&#34;&gt;Appendix: &lt;code&gt;Sync&lt;/code&gt; without primes&lt;/h3&gt;

&lt;p&gt;Some company styleguides forbid using primed variables as an expression in later actions. In that case, you can get the same effect like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;-Sync ==&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;-   LET i == &amp;lt;&amp;lt;ws, ws&amp;#39;&amp;gt;&amp;gt; IN&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+Sync(t) ==&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+   LET i == &amp;lt;&amp;lt;t.from, t.to&amp;gt;&amp;gt; IN&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;+Do(t) ==&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+    /\ ws = t.from&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+    /\ ws&amp;#39; = t.to  &lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;WorkerNext ==&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;-   /\ Worker!Next&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;-   /\ Sync&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+   /\ \E t \in Worker!ValidTransitions:&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+       /\ Do(t)&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+       /\ Sync(t)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;   /\ UNCHANGED server_log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Do(t)&lt;/code&gt; is effectively just emulating the behavior of &lt;code&gt;Worker!Next&lt;/code&gt;, except it lets us &amp;ldquo;save&amp;rdquo; the transition we use and pass it into &lt;code&gt;Sync&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is also useful for preserving parameters passed into an action, which is sometimes necessary for composition.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:internal&#34;&gt;This is why we needed to write &lt;code&gt;Server!Spec&lt;/code&gt; as &lt;code&gt;[][Next]_internal&lt;/code&gt; and not &lt;code&gt;[][Next]_vars&lt;/code&gt;. &lt;code&gt;Server!Next&lt;/code&gt; only needs to hold for the &lt;em&gt;internal&lt;/em&gt; variables, not the shared ones!
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:internal&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:stacked-specs&#34;&gt;I had a long section on composition via multilayer refinement: &lt;code&gt;system.tla&lt;/code&gt; refines &lt;code&gt;worker.tla&lt;/code&gt; refines &lt;code&gt;workerSM.tla&lt;/code&gt;. But it ended up being too complex to thoroughly explain. Maybe that&amp;rsquo;ll be a part 2! 
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:stacked-specs&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>What We Know We Don&#39;t Know: Empirical Software Engineering</title>
        <link>https://www.hillelwayne.com/talks/ese/ddd/</link>
        <pubDate>Wed, 29 May 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/talks/ese/ddd/</guid>
        <description>

&lt;p&gt;&lt;em&gt;This version of the talk was given at &lt;a href=&#34;https://2024.dddeurope.com/&#34;&gt;DDD Europe, 2024&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Technology is a multitrillion dollar industry, but we know almost nothing about how it&amp;rsquo;s best practiced. Empirical Software Engineering, or ESE, is the study of what works in software and why. Instead of trusting our instincts we collect data, run studies, and peer-review our results. This talk is all about how we empirically find the facts in software and some of the challenges we face, concluding with a guide on how to find existing research and an overview on some things we&amp;rsquo;ve learned about DDD.&lt;/p&gt;

&lt;p&gt;Slides are &lt;a href=&#34;../slides/ESE-DDD.pptx&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;sources&#34;&gt;Sources&lt;/h2&gt;

&lt;p&gt;I referenced a bunch of papers in my talk. These are links so you can read them yourself:&lt;/p&gt;

&lt;h3 id=&#34;intro&#34;&gt;Intro&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;Big Data is slower than laptops&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;https://www.usenix.org/system/files/conference/hotos15/hotos15-paper-mcsherry.pdf&#34;&gt;Scalability! But at what COST?&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;

&lt;h3 id=&#34;why-we-care&#34;&gt;Why we care&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;Section references&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;https://blog.cleancoder.com/uncle-bob/2013/03/06/ThePragmaticsOfTDD.html&#34;&gt;The Pragmatics of TDD&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://dhh.dk/2014/tdd-is-dead-long-live-testing.html&#34;&gt;TDD is dead. Long live testing.&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;

&lt;h3 id=&#34;methods&#34;&gt;Methods&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;Controlled Trials&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;https://www.semanticscholar.org/paper/Comparing-syntax-highlightings-and-their-effects-on-H%C3%A4reg%C3%A5rd-Kruger/e9d292caa5332d4322f3f3f4268d8f51b5c2ca54&#34;&gt;Comparing syntax highlightings and their effects on code comprehension&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;Natural Experiments&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;https://www.usenix.org/system/files/conference/osdi14/osdi14-paper-yuan.pdf&#34;&gt;Simple Testing Can Prevent Most Critical Failures&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;Natural Experiments Gone Rogue&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;http://web.cs.ucdavis.edu/~filkov/papers/lang_github.pdf&#34;&gt;A Large Scale Study of Programming Languages and Code Quality in Github&lt;/a&gt; (original faulty study)&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://arxiv.org/pdf/1901.10220.pdf&#34;&gt;On the Impact of Programming Languages on Code Quality&lt;/a&gt; (replication study)&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.hillelwayne.com/post/this-is-how-science-happens/&#34;&gt;My 6,000 word writeup of the whole fiasco&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;Observational Studies&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;http://www2.unibas.it/gscanniello/Giuseppe_Scanniello%40unibas/Home_files/TOSEM.pdf&#34;&gt;Fixing Faults in C and Java Source Code: Abbreviated vs. Full-Word Identifier Names&lt;/a&gt; (preprint)&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;

&lt;h3 id=&#34;ddd&#34;&gt;DDD&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;Survey Paper&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;https://arxiv.org/abs/2310.01905&#34;&gt;Domain-Driven Design in Software Development: A Systematic Literature Review on Implementation, Challenges, and Effectiveness&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;Interesting Papers&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;https://arxiv.org/abs/2108.03384&#34;&gt;Design, Monitoring, and Testing of Microservices Systems: The Practitioners&amp;rsquo; Perspective&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://ieeexplore.ieee.org/document/9426760&#34;&gt;Practitioner Views on the Interrelation of Microservice APIs and Domain-Driven Design: A Grey Literature Study Based on Grounded Theory&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://doi.org/10.1007/s10664-023-10310-1&#34;&gt;Refactoring with domain-driven design in an industrial context&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://arxiv.org/abs/2108.03758&#34;&gt;Tackling Consistency-related Design Challenges of Distributed Data-Intensive Systems - An Action Research Study&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that there are other interesting papers in the survey paper, these are just the ones I brought up in the talk.&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;

&lt;h3 id=&#34;additional-sources&#34;&gt;Additional Sources&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;Recommended Reading&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;http://teachtogether.tech/en/index.html&#34;&gt;Teaching tech together&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://leanpub.com/leprechauns&#34;&gt;Leprechauns of Software Engineering&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.manning.com/books/the-programmers-brain&#34;&gt;The Programmer&amp;rsquo;s Brain&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://shop.oreilly.com/product/9780596808303.do&#34;&gt;Making Software&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;Free research&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a href=&#34;http://neverworkintheory.org/&#34;&gt;It Will Never Work In Theory&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://dl.acm.org/&#34;&gt;ACM digital library&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://arxiv.org&#34;&gt;ArXiv&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Comment Section: Software Friction</title>
        <link>https://www.hillelwayne.com/comments/software-friction/</link>
        <pubDate>Tue, 14 May 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/comments/software-friction/</guid>
        <description>

&lt;p&gt;These are some of the responses to &lt;a href=&#34;https://www.hillelwayne.com/post/software-friction/&#34;&gt;Software Friction&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;blogs-on-a-similar-topic&#34;&gt;Blogs on a similar topic&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://tratt.net/laurie/&#34;&gt;Laurie Tratt&lt;/a&gt; wrote &lt;a href=&#34;https://tratt.net/laurie/blog/2024/what_factors_explain_the_nature_of_software.html&#34;&gt;What Factors Explain the Nature of Software?&lt;/a&gt; which touches on the topic of friction, too.&lt;/p&gt;

&lt;h2 id=&#34;emails-and-comments&#34;&gt;Emails and Comments&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;m an Infantry Officer in the US Marine Corps, we talk quite a bit about friction. One book you may be interested in if you&amp;rsquo;re reading Clausewitz is Marine Corps Doctrinal Publication 1 (MCDP 1) Warfighting (link to PDF at bottom). It&amp;rsquo;s a pretty quick read.&lt;/p&gt;

&lt;p&gt;We approach it largely in the ways you just laid out, we train people early in their careers about friction and that helps prime people to identify ways to solve it as they gain experience.&lt;/p&gt;

&lt;p&gt;One tactic we use quite a bit that I don&amp;rsquo;t see you mention but that I think would work really well for software teams as well is using &amp;ldquo;hot washes&amp;rdquo;. Basically, immediately after an operation, whether in training or real-life, sitting down with all the key players to go over what went well, what went poorly, and whether or not there should be updates to Standard Operating Procedures for better future performance. Doing these regularly also helps take the &amp;ldquo;ego sting&amp;rdquo; out of it, for lack of a better phrase, where it can be hard to get called out about a mistake you made in a public setting with peers but like anything else it gets easier with repetition. Regular hot washes also build shared understanding between teammates which helps communication and reduces friction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I asked how &amp;ldquo;hot washes&amp;rdquo; compare to postmortems. The response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The main difference I would say (and maybe this is common in agile circles and I just don’t know about it) is that typically there will be a “scribe” that will record the points in a specific format (typically Topic-Discussion-Recommendation) and then these points are saved for posterity and stored in libraries at the unit, or frequently at the service level. This lets you reference mistakes you previously made, or even reference mistakes made years ago by units facing similar problems that you are about to face. The Marine Corps Center for Lessons Learned maintains the service-level library of these.&lt;/p&gt;

&lt;p&gt;One of the challenges that I think is a bit more unique to us relative to a large software firm is that we have higher turnover, with people rotating out of a unit typically after around two years. So a persistent store of knowledge is hard to maintain in the heads of staff, it needs to get written down to be effective.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Software Friction</title>
        <link>https://www.hillelwayne.com/post/software-friction/</link>
        <pubDate>Wed, 01 May 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/software-friction/</guid>
        <description>

&lt;p&gt;In his book &lt;a href=&#34;https://www.clausewitz.com/readings/OnWar1873/BK1ch07.html&#34;&gt;&lt;em&gt;On War&lt;/em&gt;&lt;/a&gt;, Clausewitz defines &lt;dfn&gt;friction&lt;/dfn&gt; as the difference between military theory and reality:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thus, then, in strategy everything is very simple, but not on that account very easy.
Everything is very simple in war, but the simplest thing is difficult. These difficulties accumulate and produce a friction, which no man can imagine exactly who has not seen war.&lt;/p&gt;

&lt;p&gt;As an instance of [friction], take the weather. Here, the fog prevents the enemy from being discovered in time, a battery from firing at the right moment, a report from reaching the general; there, the rain prevents a battalion from arriving, another from reaching in right time, because, instead of three, it had to march perhaps eight hours; the cavalry from charging effectively because it is stuck fast in heavy ground.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ever since reading this, I&amp;rsquo;ve been seeing &amp;ldquo;friction&amp;rdquo; everywhere in software development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A vendor&amp;rsquo;s API doesn&amp;rsquo;t work quite as you thought it did, or it did and then they changed it.&lt;/li&gt;
&lt;li&gt;Bugs. Security alerts. A dependency upgrade breaks something.&lt;/li&gt;
&lt;li&gt;Someone gets sick. Someone&amp;rsquo;s kid gets sick. Someone leaves the company. Someone leaves for Burning Man.&lt;/li&gt;
&lt;li&gt;The requirements are unclear, or a client changes what they want during development. A client changes what they want &lt;em&gt;after&lt;/em&gt; development.&lt;/li&gt;
&lt;li&gt;A laptop breaks or gets stolen. Slack goes down for the day.&lt;/li&gt;
&lt;li&gt;Tooling breaks. Word changes every font to wingdings. (&lt;a href=&#34;https://answers.microsoft.com/en-us/msoffice/forum/all/word-changes-font-to-wingdings/688e0253-1fb7-4b4f-8407-568715e69e99&#34;&gt;This is a real thing&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This list is non-exhaustive and it&amp;rsquo;s not possible to catalogue all possible sources of friction.&lt;/p&gt;

&lt;h3 id=&#34;some-properties-of-friction&#34;&gt;Some Properties of Friction&lt;/h3&gt;

&lt;p&gt;Friction matters more over large time horizons and large scopes, simply because more things can go wrong.&lt;/p&gt;

&lt;p&gt;Friction compounds with itself: two setbacks are more than twice as bad as one setback. This is because most systems are at least &lt;em&gt;somewhat&lt;/em&gt; resilient and can adjust itself around some problem, but that makes the next issue harder to deal with.&lt;/p&gt;

&lt;p&gt;(This is a factor in the controversial idea of &amp;ldquo;don&amp;rsquo;t deploy on Fridays&amp;rdquo;. The friction caused by a mistake during deployment, or of needing to doing a rollback, would be made much worse by the friction of people going offline for the weekends. The controversy is between people saying &amp;ldquo;don&amp;rsquo;t do this&amp;rdquo; and people advocating for &lt;a href=&#34;https://charity.wtf/2019/05/01/friday-deploy-freezes-are-exactly-like-murdering-puppies/&#34;&gt;systemic changes to the process&lt;/a&gt;. Either way the goal is to make sure friction doesn&amp;rsquo;t cause problems, it&amp;rsquo;s a debate over &lt;em&gt;how&lt;/em&gt; exactly to do this.)&lt;/p&gt;

&lt;p&gt;Addressing friction can also create other sources of friction, like if you upgrade a dependency to fix a security alert but the new version is subtly backwards incompatible. And then if you&amp;rsquo;re trying to fix this with a teammate who lives in a different timezone&amp;hellip;&lt;/p&gt;

&lt;h2 id=&#34;addressing-friction&#34;&gt;Addressing Friction&lt;/h2&gt;

&lt;p&gt;Friction is inevitable and impossible to fully remove. I don&amp;rsquo;t think it&amp;rsquo;s possible to even fully anticipate. But there are things that can be done to reduce it, and plans can be made more resilient to it. I don&amp;rsquo;t have insight into how military planners reduce friction. This is stuff I&amp;rsquo;ve seen in software:&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;Smaller scopes and shorter iterations&lt;/dt&gt;
&lt;dd&gt;This is the justification for &amp;ldquo;agile&amp;rdquo; over &amp;ldquo;waterfall&amp;rdquo;. When you have short timelines then there&amp;rsquo;s less room for friction to compound. The more you&amp;rsquo;re doing and the longer your timeline the more uncertainty you have and the more places things can go wrong. You still have room for friction if you&amp;rsquo;re doing lots of small sprints back to back, though. Then you&amp;rsquo;re just running an inefficient marathon.&lt;/dd&gt;
&lt;dt&gt;More autonomy&lt;/dt&gt;
&lt;dd&gt;Friction is the difference between the model and the world, and at a high level you can only see models. If people have enough autonomy to make locally smart decisions, then they can recover from friction more easily. But if people get so much autonomy they isolate, they can make things much worse. I once saw an engineer with a lot of autonomy delete a database that was &amp;ldquo;too slow&amp;rdquo;.&lt;/dd&gt;
&lt;dt&gt;Redundancy&lt;/dt&gt;
&lt;dd&gt;This could be spare equipment in storage, high bus factors, or adding slack to a schedule. Then if something goes wrong you can fix it more quickly, leaving less room for another problem to compound. This comes at the cost of efficiency under normal circumstances, which is why projects naturally drift towards less redundancy.&lt;/dd&gt;
&lt;dt&gt;Better planning&lt;/dt&gt;
&lt;dd&gt;Good planning won&amp;rsquo;t identify all sources of friction, but planning will identify &lt;em&gt;more sources&lt;/em&gt;, and that&amp;rsquo;s a big benefit. For example, writing formal specifications can expose &lt;a href=&#34;https://www.hillelwayne.com/post/feature-interaction/&#34;&gt;problems in the design&lt;/a&gt; or turn &lt;a href=&#34;https://increment.com/planning/formal-specifications-and-planning/&#34;&gt;unknown-unknowns into known-unknowns&lt;/a&gt; (which you can then study into more detail). This can be the difference between being blindsided by 5 things and being blindsided by 15 things. This is why I&amp;rsquo;m so bullish on formal methods.&lt;/dd&gt;
&lt;dt&gt;Automation&lt;/dt&gt;
&lt;dd&gt;This is a double-edged sword. On one hand, automating processes leaves less room for people to make mistakes. On the other, automated processes can have their own bugs, which creates their own sources of friction. Also, if the automation runs long enough people will forget how it works or the full scope of what it does, leaving everyone completely unprepared for if it breaks. Automation can come at the cost of experience.&lt;/dd&gt;
&lt;dt&gt;Experience&lt;/dt&gt;
&lt;dd&gt;The more problems you&amp;rsquo;ve encountered, the more problems you will see coming, and the more experience you&amp;rsquo;ll have recovering from problems. Unfortunately this is something you mostly have to learn the hard way. But one shortcut is&amp;hellip;&lt;/dd&gt;
&lt;dt&gt;Gaming&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;One interesting book on this is the Naval War College &lt;a href=&#34;https://bookstore.gpo.gov/products/united-states-naval-war-college-fundamentals-war-gaming&#34;&gt;Fundamentals of War Gaming&lt;/a&gt;. In it they argue that there&amp;rsquo;s two purpose to wargaming: gathering information on how situations can develop, and giving commanders (some) experience in a safe environment. If a trainee learns that &amp;ldquo;weather can disrupt your plan&amp;rdquo; in a wargame, they don&amp;rsquo;t have to learn it with real human lives. Similarly, I&amp;rsquo;d rather practice how to retrieve database backups when I&amp;rsquo;m not desperately trying to restore a dropped table. To my understanding, both security and operations teams use gaming for this reason.&lt;/p&gt;

&lt;p&gt;(At the same time, people have to devote time to running participate in games, which is inefficient in the same way adding redundancy is.)&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;Checklists and runbooks&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Ways of formalizing tacit knowledge of dealing with particular problems.&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;

&lt;h3 id=&#34;questions-i-have-about-friction&#34;&gt;Questions I have about friction&lt;/h3&gt;

&lt;p&gt;Is it useful to subcategorize sources of friction? Does calling a tooling problem &amp;ldquo;technical&amp;rdquo; as opposed to &amp;ldquo;social&amp;rdquo; friction do anything useful to us?&lt;/p&gt;

&lt;p&gt;How do other fields handle friction? I asked some people in the construction industry about friction and they recognized the idea but didn&amp;rsquo;t have a word for it. What about event planners, nurses, military officers?&lt;/p&gt;

&lt;p&gt;How do we find the right balance between &amp;ldquo;doing X reduces the effect of friction&amp;rdquo; and &amp;ldquo;&lt;em&gt;not&lt;/em&gt; doing X is more efficient right now&amp;rdquo;?&lt;/p&gt;

&lt;p&gt;Is friction important to &lt;em&gt;individuals&lt;/em&gt;? Do I benefit from thinking about friction on a project, even if nobody else on my team does?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks for &lt;a href=&#34;http://www.jameskoppel.com/&#34;&gt;Jimmy Koppel&lt;/a&gt; for feedback. If you liked this post, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write new essays there every week.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I train companies in formal methods, making software development faster, cheaper, and safer. Learn more &lt;a href=&#34;https://www.hillelwayne.com/consulting/&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;update-2024-05-30&#34;&gt;Update 2024-05-30&lt;/h3&gt;

&lt;p&gt;I&amp;rsquo;ve collected some of the comments I received on this post &lt;a href=&#34;https://www.hillelwayne.com/comments/software-friction/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Don&#39;t let Alloy facts make your specs a fiction</title>
        <link>https://www.hillelwayne.com/post/alloy-facts/</link>
        <pubDate>Wed, 10 Apr 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/alloy-facts/</guid>
        <description>

&lt;p&gt;I&amp;rsquo;ve recently done a lot of work in &lt;a href=&#34;https://alloytools.org/&#34;&gt;Alloy&lt;/a&gt; and it&amp;rsquo;s got me thinking about a common specification pitfall. Everything in the main post applies to all formal specifications, everything in dropdowns is for experienced Alloy users.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Consider a simple model of a dependency tree. We have a set of top-level dependencies for our program, which have their own dependencies, etc. We can model it this way in Alloy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Package &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  , depends_on: &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;set&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Package&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;some&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; depends_on&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show Alloy tip
  &lt;/summary&gt;
  &lt;p&gt;I&amp;rsquo;m going to use a slightly different model for the next example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;abstract&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Package &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  , depends_on: &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;set&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Package&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;lone&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; A, B &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;extends&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Package &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;some&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; depends_on&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I do things this way because it gives visualizations with &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; instead of &lt;code&gt;Package$0&lt;/code&gt; and &lt;code&gt;Package$1&lt;/code&gt;. Alloy has built-in enums but they don&amp;rsquo;t play nice with the rest of the language (you can&amp;rsquo;t extend them or give them fields).&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;If we look through some of the generated examples, we see something odd: a package can depend on itself!&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;./img/alloy-problem.png&#34; alt=&#34;A depends on B, B depends on... B?&#34; /&gt;&lt;/p&gt;

&lt;p&gt;These kinds of nonsensical situations arise often when we&amp;rsquo;re specifying, because we have an &lt;em&gt;intent&lt;/em&gt; of what the system should be but don&amp;rsquo;t explicitly encode it. When this happens, we need to add additional constraints to prevent it. For this reason, Alloy has a special &amp;ldquo;fact&amp;rdquo; keyword:&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:other-langs&#34;&gt;&lt;a href=&#34;#fn:other-langs&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;fact&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; no_self_deps &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;all&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; p: Package &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;       p not &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;in&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; p&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;depends_on &lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show Alloy tip
  &lt;/summary&gt;
  &lt;p&gt;You can write the same fact purely relationally:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;fact&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;no&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; depends_on &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;iden&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In general, the model checker evaluates purely-relational expressions &lt;em&gt;much&lt;/em&gt; faster than quantified expressions. This can make a big difference in large models!&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Alloy will not generate any models that violate a fact, nor will it look for invariant violations in them. It&amp;rsquo;s a &amp;ldquo;fact of reality&amp;rdquo; and doesn&amp;rsquo;t need to be explored at all.&lt;/p&gt;

&lt;h2 id=&#34;the-pitfall-of-facts&#34;&gt;The pitfall of facts&lt;/h2&gt;

&lt;p&gt;&amp;ldquo;No self-deps&amp;rdquo; is a great example of a fact. It&amp;rsquo;s also an example of a terrible fact. Beginners often make this mistake where they use facts to &lt;em&gt;model&lt;/em&gt; the system, which quickly leads to problems.&lt;/p&gt;

&lt;p&gt;Consider the real system for a second, not the spec. Where do the package manager dependencies come from? Usually a plain text file like &lt;code&gt;package.json&lt;/code&gt; or &lt;code&gt;Cargo.toml&lt;/code&gt;. What if someone puts manually a self-dependency in that file? Presumably, you want the package manager to detect the self-dep and reject the input as an error. How do you know the error-handling works? By having the checker verify that it accepts valid manifests and rejects ones with self-loops.&lt;/p&gt;

&lt;p&gt;Except it can&amp;rsquo;t test the rejection because we told it not to generate any self-dependencies. Our fact made the self-deps &lt;em&gt;unrepresentable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Normally in programming languages, &amp;ldquo;making illegal states unrepresentable&amp;rdquo; (MISU) is a &lt;em&gt;good&lt;/em&gt; thing (&lt;a href=&#34;https://fsharpforfunandprofit.com/posts/designing-with-types-making-illegal-states-unrepresentable/&#34;&gt;1&lt;/a&gt; &lt;a href=&#34;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&#34;&gt;2&lt;/a&gt; &lt;a href=&#34;https://www.hillelwayne.com/post/constructive/&#34;&gt;3&lt;/a&gt; &lt;a href=&#34;https://corrode.dev/blog/illegal-state/&#34;&gt;4&lt;/a&gt;). But specification covers both the software you are writing and the environment the software is running in, &lt;a href=&#34;https://www.hillelwayne.com/post/world-vs-machine/&#34;&gt;the machine and the world&lt;/a&gt;. If you cannot represent the illegal state, you cannot represent the world &lt;em&gt;creating&lt;/em&gt; an illegal state that your software needs to handle.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show Alloy tip
  &lt;/summary&gt;
  &lt;p&gt;There is a technique to make invalid states representable in the world &lt;em&gt;but not in the machine&lt;/em&gt;: &lt;a href=&#34;https://www.hillelwayne.com/post/refinement/&#34;&gt;refinement&lt;/a&gt;. The link goes to a TLA+ explanation but the same principle works in Alloy too: write an abstract spec without MISU, write an implementation spec with it, then show that the implementation refines the abstract spec. But you&amp;rsquo;ll do this with signatures and predicates, not with facts.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Instead of facts, you want predicates. Then you can test for the predicate being true or check that it&amp;rsquo;s necessary to get other properties. Make the constraint explicit instead of implicit.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;// instead of&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;fact&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; no_self_deps &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;/*body*/&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;some_case&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;check&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;some_property&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #75715e&#34;&gt;// do&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;pred&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; no_cycles &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;/*body*/&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  no_cycles &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;and&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; some_case&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;check&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;no_cycles &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;implies&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; some_property&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Predicates have the additional benefit of being &amp;ldquo;locally scoped&amp;rdquo;: if you have three facts and want to check a model with only two of them, you have to comment the third fact out.&lt;/p&gt;

&lt;h2 id=&#34;when-to-use-facts&#34;&gt;When to use facts&lt;/h2&gt;

&lt;p&gt;So where &lt;em&gt;should&lt;/em&gt; we use facts? When does it make sense to universally enforce constraints, when doing so could potentially weaken our model?&lt;/p&gt;

&lt;p&gt;First, facts are useful for narrowing the scope of a problem. &amp;ldquo;No self-deps&amp;rdquo; is a perfectly reasonable fact &lt;strong&gt;if&lt;/strong&gt; we&amp;rsquo;re only specifying the package installer and something else is responsible for validating the manifests. Writing the as a fact makes it clear to the reader that we&amp;rsquo;re not supposed to validate the manifest. This means we don&amp;rsquo;t make any guarantees if the assumption is false.&lt;/p&gt;

&lt;p&gt;Second, facts rule out &lt;em&gt;fundamentally uninteresting&lt;/em&gt; cases. Say I&amp;rsquo;m modeling linked lists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  next: &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;lone&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;//lone: 0 or 1&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This generates regular lists and lists with cycles, which are interesting to me. I don&amp;rsquo;t want to constrain away either case. But it &lt;em&gt;also&lt;/em&gt; generates models with two disjoint lists. If I only care about single linked lists, I can eliminate extra lists with a fact:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;fact&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; one_list &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;some&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; root: Node &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; root&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show Alloy tip
  &lt;/summary&gt;
  &lt;p&gt;&lt;code&gt;one_list&lt;/code&gt; also rules out &amp;ldquo;two link lists that merge into one&amp;rdquo;. If that&amp;rsquo;s something you want to keep, use the &lt;a href=&#34;https://alloy.readthedocs.io/en/latest/modules/graph.html&#34;&gt;graph&lt;/a&gt; module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; util&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;graph&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Node&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;]&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;fact&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    weaklyConnected&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;next&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Similarly, you can use facts to eliminate extraneous detail. If I&amp;rsquo;m modeling users and groups, I don&amp;rsquo;t want any empty groups. I&amp;rsquo;d add a fact like &lt;code&gt;Users.groups = Group&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Third, you can use constraints to optimize a slow model. This is usually through &lt;a href=&#34;https://en.wikipedia.org/wiki/Symmetry-breaking_constraints&#34;&gt;symmetry breaking&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, you can use facts to define necessary relationships that Alloy can&amp;rsquo;t can&amp;rsquo;t express natively. In the project I worked on, we had Red and Blue nodes in our graph. Red nodes had &lt;em&gt;at least one&lt;/em&gt; edge to another node, Blue nodes had &lt;em&gt;at most one&lt;/em&gt;. We wrote this as&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;abstract&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Red &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;extends&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  edge: &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;some&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Blue &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;extends&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  edge: &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;lone&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But then we couldn&amp;rsquo;t write generic predicates on nodes that use &lt;code&gt;edge&lt;/code&gt;, because Alloy treated it as a type error. Instead we wrote it with a fact:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;abstract&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  edge: &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;set&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;sig&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Blue, Red &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;extends&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Node &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;fact&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;all&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; r: Red  &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;some&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; r&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;edge&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;all&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; r: Blue &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;lone&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; r&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;edge&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show Alloy tip
  &lt;/summary&gt;
  &lt;p&gt;Okay, one more (rather niche) use case. Say you have a temporal model and a canonical &lt;code&gt;spec&lt;/code&gt; predicate for system behavior. Then a lot of your assertions look like&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;module&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; main&lt;/span&gt;

&lt;span style=&#34;color: #75715e&#34;&gt;// spec&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;check&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;spec &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;always&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;prop1&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;)}&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;check&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;spec &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;always&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;prop2&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;)}&lt;/span&gt;

&lt;span style=&#34;color: #75715e&#34;&gt;// etc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can clean this up a lot by exporting all of properties to &lt;code&gt;properties.als&lt;/code&gt; and writing it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-alloy&#34; data-lang=&#34;alloy&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; main&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;fact&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;check&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;always&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;prop1&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;)}&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;check&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;always&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;prop2&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;)}&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;// etc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Constraints are dangerous because you need error states in order to check that your program avoids error states.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re interested in learning more about Alloy, there&amp;rsquo;s a good book &lt;a href=&#34;https://alloytools.org/book.html&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;https://alloy.readthedocs.io/en/latest/&#34;&gt;I maintain some reference documentation&lt;/a&gt;. I&amp;rsquo;m also working on a new Alloy workshop. I ran an alpha test last month and plan to run a beta test later this summer. Sign up for &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;my newsletter&lt;/a&gt; to stay updated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks for &lt;a href=&#34;https://twitter.com/parlar&#34;&gt;Jay Parlar&lt;/a&gt; and &lt;a href=&#34;http://lorinhochstein.org/&#34;&gt;Lorin Hochstein&lt;/a&gt; for feedback. If you liked this post, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write new essays there every week.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I train companies in formal methods, making software development faster, cheaper, and safer. Learn more &lt;a href=&#34;https://www.hillelwayne.com/consulting/&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:other-langs&#34;&gt;In other specification languages this is usually either a runtime constraint (like in &lt;a href=&#34;https://learntla.com/topics/toolbox.html#additional-spec-options&#34;&gt;TLA+&lt;/a&gt;) or a direct modification to the system spec itself. 
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:other-langs&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>The Tale of Daniel</title>
        <link>https://www.hillelwayne.com/post/tale-of-daniel/</link>
        <pubDate>Mon, 01 Apr 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/tale-of-daniel/</guid>
        <description>

&lt;p&gt;&lt;em&gt;It&amp;rsquo;s &lt;a href=&#34;https://www.aprilcools.club/&#34;&gt;April Cools&lt;/a&gt;! It&amp;rsquo;s like April Fools, except instead of cringe comedy you make genuine content that&amp;rsquo;s different what you usually do. For example, last year I talked about &lt;a href=&#34;https://www.hillelwayne.com/post/weird-things-you-can-buy/&#34;&gt;the strangest markets on the internet&lt;/a&gt;. This year I went down a different rabbit hole.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Daniel has been a &lt;a href=&#34;https://www.ssa.gov/oact/babynames/top5names.html&#34;&gt;top 5 baby name twice since 2000&lt;/a&gt;. There are &lt;a href=&#34;https://www.mynamestats.com/First-Names/D/DA/DANIEL/index.html&#34;&gt;over 1.5 million Daniels&lt;/a&gt;  in the United States (and almost 100,000 last-name Danielses). There are who knows how many Dans, Dannies, and Daniellas out there. &amp;ldquo;Daniel&amp;rdquo; is, by any way you slice it, a very modern name.&lt;/p&gt;

&lt;p&gt;It may be the oldest attested name in common use.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Last year was Chicago&amp;rsquo;s last &lt;a href=&#34;https://blockclubchicago.org/2023/10/23/why-is-the-newberry-library-ending-its-popular-book-fair/&#34;&gt;Newberry Library book sale&lt;/a&gt;. Part of my haul was several collections of ancient literature:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/books.jpg&#34; alt=&#34;Three books, two on Egypt, one on near-east&#34; /&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m interested in ancient history, which shouldn&amp;rsquo;t be a surprise to anybody who reads this blog. And I love how their literature reflects the modern human experience. Take this lament carved in a pyramid from the Egyptian Middle Kingdom:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have heard the words of Imohotep and Hardedef \ Whose sayings are recited whole. \ What of their places?&lt;/p&gt;

&lt;p&gt;Their walls have crumbled, \ Their places are gone, \ As though they had never been! (&lt;a href=&#34;https://archive.org/details/MiriamLichtheimAncientEgyptianLiteratureVolI&#34;&gt;pg 196&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This anonymous poet, writing 4500 years ago, shares our fears about losing our past and of our memories being forgotten. Beautiful.&lt;/p&gt;

&lt;p&gt;But I found something far more relevant in the Mesopotamian literature.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/books2-crop.jpg&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Straightway Daniel the Raphaman … gives oblations to the gods to eat (&lt;a href=&#34;https://www.amazon.com/Ancient-Near-East-Anthology-Pictures/dp/0691002002&#34;&gt;pg 118&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Daniel&lt;/strong&gt; the Raphaman&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DANIEL&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The story comes from the &lt;a href=&#34;https://en.wikipedia.org/wiki/Tale_of_Aqhat&#34;&gt;Tale of Aqhat&lt;/a&gt;, pulled out of the ruins of a forgotten city, estimated to approximately 1350 BCE. That&amp;rsquo;s a hundred years older than the oldest known &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Oracle_bone_script&#34;&gt;Chinese writing&lt;/a&gt;, one &lt;em&gt;thousand&lt;/em&gt; years older than the book of Daniel, and thirty-four hundred years before today. I needed to know if this was the &lt;em&gt;same&lt;/em&gt; name, transmitted across cultures, stretching 3400 years of unbroken &amp;ldquo;Daniels&amp;rdquo; to our modern day. Is this where &amp;ldquo;Daniel&amp;rdquo; comes from, or is just a strange coincidence?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A historian of the modern world has to learn how to sip from a firehose of evidence, while the historian of the ancient world must learn how to find water in the desert. — &lt;a href=&#34;https://acoup.blog/2021/03/26/fireside-friday-march-26-2021-on-the-nature-of-ancient-evidence/&#34;&gt;Bret Devereaux&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&amp;rsquo;ve done some historical work before, but all of it was in software, a &amp;ldquo;history of the modern world&amp;rdquo;. I decided to try anyway. This is what I&amp;rsquo;ve put together from reading books and trawling JSTOR.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:JSTOR&#34;&gt;&lt;a href=&#34;#fn:JSTOR&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This is the tale of Daniel.&lt;/p&gt;

&lt;h3 id=&#34;ugarit&#34;&gt;Ugarit&lt;/h3&gt;

&lt;p&gt;Obviously, finding an unbroken lineage of specific Daniels across three millennia is impossible. Instead, I want to learn if the name was in the &amp;ldquo;cultural consciousness&amp;rdquo;. If so, we can be modestly confident that &lt;em&gt;real people&lt;/em&gt; are getting named Daniel, like how real people are being named &lt;a href=&#34;https://en.wikipedia.org/wiki/Khaleesi_%28given_name%29&#34;&gt;Khaleesi&lt;/a&gt; today.&lt;/p&gt;

&lt;p&gt;So let&amp;rsquo;s start with where the name was first found. &lt;strong&gt;Ugarit&lt;/strong&gt; was a port city of the shores of Ras Shamra, unknown until 1928. Scholars believe that it was a city of roughly 8,000 people and the capitol of a kingdom of 20,000 (&lt;a href=&#34;http://www.jstor.org/stable/43303580&#34;&gt;ref&lt;/a&gt;). While never a great power, Ugarit was &lt;a href=&#34;https://www.jstor.org/stable/j.ctv2npq9cv.12?seq=4&#34;&gt;a fairly &amp;ldquo;literate&amp;rdquo; society&lt;/a&gt;  and had &lt;a href=&#34;https://www.jstor.org/stable/j.ctv2npq9cv.5?seq=18&#34;&gt;extensive trade relations&lt;/a&gt; with all of the regional powers.&lt;/p&gt;

&lt;p&gt;Along with a trove of archaeological material (pots and doodads), excavators also found large collections of clay tablets. Like with many Bronze Age civilizations, most of these recovered documents are either religious, diplomatic, or administrative. That&amp;rsquo;s because clay tablets are expensive and only reserved for important matters. Most of these were dated to very approximately 1500-1200 BCE.&lt;/p&gt;

&lt;p&gt;But also in that collection, we found three piece of literature. The first, the Baal Cycle, tells of how Baal Hadad became one of the great gods of the Ugaritic pantheon. The second, the Legend of Keret, probably matters a lot to another person chasing a completely different white whale, but doesn&amp;rsquo;t matter to me. The final one, the one that started this obsession of mine, is the Tale of Aqhat.&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/aqhat-stone.jpg&#34;    title=&#34;Image of the stone&#34; &gt; 

  &lt;figcaption&gt;
    One of three recovered tablets that make up the tale. 

  &lt;a href=&#34;https://digitallibrary.usc.edu/asset-management/2A3BF1S2SSRR0?WS=SearchResults&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;I found this picture in the &lt;a href=&#34;https://digitallibrary.usc.edu/CS.aspx?VP3=SearchResult&amp;amp;VBID=2A3BXZ8ODTDTD&amp;amp;PN=1&amp;amp;WS=SearchResults#/SearchResult&amp;amp;VBID=2A3BXZ79NBNBN&amp;amp;PN=1&amp;amp;WS=SearchResults&#34;&gt;InscriptiFact collection&lt;/a&gt;. Sadly no digital transcription! It tells of the story of the great hero Aqhat, who was loved and murdered by the goddess Anath. But I don&amp;rsquo;t actually care about any of that, I&amp;rsquo;m only after the Daniel. I&amp;rsquo;m &lt;em&gt;pretty sure&lt;/em&gt; this is Daniel&amp;rsquo;s name:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/daniel-zoom-markup.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;I have a few friends who can read cuneiform, so I asked if any understood this text. I found out 1) that&amp;rsquo;s like asking a person who &amp;ldquo;can read ASCII&amp;rdquo; if they can understand Spanish, and 2) this is &lt;em&gt;not actually&lt;/em&gt; cuneiform. It&amp;rsquo;s just an alphabet that &lt;em&gt;looks&lt;/em&gt; like cuneiform.&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/Ugaritic-alphabet-chart.svg&#34;    title=&#34;Ugaritic alphabet&#34; &gt; 

  &lt;figcaption&gt;
    The Ugaritic alphabet. 

  &lt;a href=&#34;https://en.wikipedia.org/wiki/Ugaritic_alphabet#/media/File:Ugaritic-alphabet-chart.svg&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;Aqhat&amp;rsquo;s father is 𐎄𐎐𐎛𐎍. Left to right: D, N, &amp;lsquo;I, L. &amp;ldquo;Judged by El&amp;rdquo;, El being the chief God in the Ugaritic pantheon.&lt;/p&gt;

&lt;p&gt;The name &lt;em&gt;could&lt;/em&gt; be older than this text, since most early written myths were first oral traditions. This is just the first time the name &amp;ldquo;Daniel&amp;rdquo; is attested. The name &lt;em&gt;could&lt;/em&gt; also be a lot younger, at least the modern name. The old name could just be an unusual coincidence, like how people in both England and China have the last name &amp;ldquo;Lee&amp;rdquo;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:China&#34;&gt;&lt;a href=&#34;#fn:China&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; For &amp;ldquo;Daniel&amp;rdquo; to be that old, it&amp;rsquo;s not enough for the Ugarits to have had the name, it has to &lt;em&gt;come from&lt;/em&gt; them, in a chain of Daniels reaching into present.&lt;/p&gt;

&lt;p&gt;And here we run into a problem. We know roughly how old the tablets are because we know roughly when the city collapsed. By cross-referencing names of Egyptian rulers that appear in Ugarit tablets with the much better preserved Egyptian corpus, historians estimate that the city collapsed around 1190 BCE. This corresponds with the &amp;ldquo;Bronze Age Collapse&amp;rdquo;, a cataclysmic era where dozens of cities and kingdoms in the region are turned to ruins. Scholars still don&amp;rsquo;t have a clear picture why.&lt;/p&gt;

&lt;p&gt;Regardless of the &lt;em&gt;why&lt;/em&gt;, the Ugarites disappeared from history. The name Daniel would have to be carried by a new generation.&lt;/p&gt;

&lt;p&gt;But this is also where the chain breaks.&lt;/p&gt;

&lt;h3 id=&#34;phoenicia&#34;&gt;Phoenicia&lt;/h3&gt;

&lt;p&gt;The Ras Shamra find was a one-in-a-million miracle, an enormous corpus of about 40,000 words, roughly as much as one Harlequin romance novel. After that? Well, here&amp;rsquo;s the &lt;a href=&#34;https:/en.wikipedia.org/wiki/Hadad_Statue&#34;&gt;Hadad Statue&lt;/a&gt;:&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/hadad-statue.jpeg&#34;    title=&#34;A statue of a god. The bottom has faint inscriptions.&#34; &gt; 

  &lt;figcaption&gt;
    The Hadad Statue 

  &lt;a href=&#34;https://en.wikipedia.org/wiki/Hadad_Statue#/media/File:Statue_of_Weather_God_Haddad.jpg&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;If you look closely, you can see the bottom is covered in faint writing. The language is &amp;ldquo;&lt;a href=&#34;https://en.wikipedia.org/wiki/Samalian_language&#34;&gt;Samalian&lt;/a&gt;&amp;rdquo;, one of the many languages in the region. The engraving is roughly 400 words long and represents &lt;em&gt;over half of all Samalian.&lt;/em&gt; This essay is four times longer than the Samalian corpus.&lt;/p&gt;

&lt;p&gt;So what happened? It&amp;rsquo;s easy to imagine the Bronze Age Collapse turning the broader region into a Stone Age wasteland, but the archaeological evidence suggests the opposite. Rather, it points to a &lt;a href=&#34;https://www.jstor.org/stable/3632872&#34;&gt;rapid economic recovery of the region&lt;/a&gt;, with new kingdoms soon establishing a large number of seafaring trade routes. Eventually they&amp;rsquo;d come in contact with the Greeks, who&amp;rsquo;d call all of the many distinct groups &amp;ldquo;Phoenicians&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;But we know so little of what the &amp;ldquo;Phoenicians&amp;rdquo; (in all their languages) wrote because of &lt;em&gt;how&lt;/em&gt; they wrote it. Instead of Ugarit&amp;rsquo;s clay tablets, the Phoenicians used papyrus. Papyrus is lighter and cheaper, but also rots after a few decades. The fragments of text we do have— with one big exception— are engravings.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:preservation&#34;&gt;&lt;a href=&#34;#fn:preservation&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; Inscriptions on tombs, statues, weapons, etc. This is a major problem for historians, but an even bigger problem for &lt;em&gt;me&lt;/em&gt;, because it makes the question of Daniel impossible to answer.&lt;/p&gt;

&lt;p&gt;Nonetheless, we can look for clues that the same stories persisted, even if we don&amp;rsquo;t have concrete evidence. Let&amp;rsquo;s start with the &lt;a href=&#34;https://en.wikipedia.org/wiki/Hadad_Statue#Text&#34;&gt;first two lines&lt;/a&gt; of the Hadad statue:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;𐤀𐤍𐤊 𐤐𐤍𐤌𐤅 · 𐤁𐤓 · 𐤒𐤓𐤋 · 𐤌𐤋𐤊 · 𐤉𐤀𐤃𐤉 · 𐤆𐤉 · 𐤄𐤒𐤌𐤕 · 𐤍𐤑𐤁 · 𐤆𐤍 · 𐤋𐤄𐤃𐤃 · 𐤁𐤏𐤋𐤌𐤉‎· 𐤒𐤌𐤅 · 𐤏𐤌𐤉̇ ·· 𐤀̇𐤋𐤄𐤅 ·· 𐤄𐤃𐤃 · 𐤅𐤀𐤋 · 𐤅𐤓𐤔𐤐 · 𐤅𐤓𐤊𐤁𐤀𐤋 · 𐤅𐤔𐤌𐤔 · 𐤅𐤍𐤕𐤍 · 𐤁𐤉𐤃𐤉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the &amp;ldquo;Phoenician alphabet&amp;rdquo;—the same one that inspired the Greek alphabet— which many distinct cultures in the region used for their own languages. Unlike Ugaritic, it&amp;rsquo;s read right-to-left. Scholars don&amp;rsquo;t think this alphabet descended from Ugaritic, but the two writing systems are closely related: the same sounds appear in roughly the same places in the alphabet.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:order&#34;&gt;&lt;a href=&#34;#fn:order&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; Here&amp;rsquo;s the translation (from wiki):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am Panamuwa, son of Qarli, king of Y’DY, who have erected this statue for Hadad in my eternal abode (burial chamber). The gods Hadad and El and Rašap and Rākib-El and Šamaš supported me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same gods, El and Baal Hadad, are important gods in the Ugarit corpus! And this is coming four hundred years after the fall of Ugarit. It suggests the Baal Hadad and El weren&amp;rsquo;t local gods to the Ugarits, but regional gods, part of a shared culture. The tale of Aqhat could have been preserved as a literary tradition, just on sources we don&amp;rsquo;t have anymore. And with Aqhat comes his dad(niel).&lt;/p&gt;

&lt;p&gt;To get out of the Daniel dark ages, we have to look at a different inscription found 600 miles away.&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/misha-stele.jpeg&#34;    title=&#34;A large stone tablet with Phoenician alphabet&#34; &gt; 

  &lt;figcaption&gt;
    The Misha Stele 

  &lt;a href=&#34;https://en.wikipedia.org/wiki/Mesha_Stele#/media/File:P1120870_Louvre_st%C3%A8le_de_M%C3%A9sha_AO5066_rwk.JPG&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;Like the Hadad statue, the &lt;a href=&#34;https://en.wikipedia.org/wiki/Mesha_Stele&#34;&gt;Misha Stele&lt;/a&gt; is one of our only sources on a long-dead language. In this case, Moabite. It&amp;rsquo;s a distinct language from Samalian but this uses the same Phoenician alphabet. Here&amp;rsquo;s a sample (also from wiki):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have built its gates and I have built its towers. I have built the palace of the king, and I made the prisons for the criminals within the wall. And there were no wells in the interior of the wall in Karchah. And I said to all the people, &amp;lsquo;Make you every man a well in his house.&amp;rsquo; And I dug the ditch for Karchah with the chosen men of Israel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;israel&#34;&gt;Israel?&lt;/h3&gt;

&lt;p&gt;Yes, Israel.&lt;/p&gt;

&lt;p&gt;The Greeks called this region Phoenicia, but the locals always called it &lt;em&gt;Canaan&lt;/em&gt;. The same &amp;ldquo;Canaan&amp;rdquo; from the Bible. The Israelites were a Canaanite population with Canaanite religions: Israel literally means &lt;a href=&#34;https://www.thetorah.com/article/jacob-is-renamed-israel-twice-why-does-the-name-jacob-remain&#34;&gt;One who fought El&lt;/a&gt;. Slowly, over years and centuries, they developed their own ethnic identity. At some point, there were two Israelite kingdoms: the kingdom of Israel/Samaria in the north and the kingdom of Judah (where we get &amp;ldquo;Jew&amp;rdquo;) in the south.&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/israel-and-judah.png&#34;    title=&#34;A map of Israel and Judah and neighboring kingdoms.&#34; &gt; 

  &lt;figcaption&gt;
    Moab is here, too 

  &lt;a href=&#34;https://en.wikipedia.org/wiki/History_of_ancient_Israel_and_Judah#/media/File:Kingdoms_of_Israel_and_Judah_map_830.svg&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;Israel was conquered in 720 BCE while the kingdom of Judah limps along, in one form or another, until 130 CE.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:date&#34;&gt;&lt;a href=&#34;#fn:date&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; And it&amp;rsquo;s through the people of Judah that we have the best corpus of that region&amp;rsquo;s writing.&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/torah.jpg&#34;    title=&#34;A man holding up a torah (Présentation de la Loi).&#34; &gt; 

  &lt;figcaption&gt;
    &amp;#34;Présentation  de la Loi&amp;#34; 

  &lt;a href=&#34;https://en.wikipedia.org/wiki/File:Pr%C3%A9sentation_de_la_Loi,_Edouard_Moyse_%281860%29_-_Mus%C3%A9e_d%27art_et_d%27histoire_du_Juda%C3%AFsme.jpg&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;The Tanakh&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:torah&#34;&gt;&lt;a href=&#34;#fn:torah&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;, or &amp;ldquo;Old Testament&amp;rdquo;, is a 300,000 word corpus of ancient Hebrew, chronicling the stories, religious practices, and history (mythic and attested) of the Jews.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:orthodox&#34;&gt;&lt;a href=&#34;#fn:orthodox&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; It&amp;rsquo;s the reason we can decipher the scant inscriptions of other Canaanite languages like Moabite, Samalian, and &lt;a href=&#34;https://forward.com/culture/182321/cracking-the-ugaritic-code/&#34;&gt;even Ugaritic itself&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;And it&amp;rsquo;s where the tale of Daniel continues.&lt;/p&gt;

&lt;h3 id=&#34;judah&#34;&gt;Judah&lt;/h3&gt;

&lt;p&gt;Quick recap on Daniel so far: we know the Ugarites wrote about a son of Daniel, the Canaanites (nee Phoenicians) shared a culture with the Ugarites, and the Israelites shared a culture with the Canaanites.&lt;/p&gt;

&lt;p&gt;In 600 BCE, the Neo-Babylonian empire conquered Judah, which leads to the sixty year &amp;ldquo;Babylonian exile&amp;rdquo; of Jews from Canaan. It&amp;rsquo;s &lt;em&gt;allegedly&lt;/em&gt; during this time that we get the collection of prophecies known as the &amp;ldquo;Book of Ezekiel&amp;rdquo;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:Ezekiel&#34;&gt;&lt;a href=&#34;#fn:Ezekiel&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; Mostly it&amp;rsquo;s about how the Jews lost the favor of God and will one day earn it back, and with it redemption.&lt;/p&gt;

&lt;p&gt;Far, &lt;strong&gt;far&lt;/strong&gt; more importantly, it marks the triumphant return of Daniel.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Son of man, if a land sins against Me by trespassing grievously, I shall stretch forth My hand upon it and break its staff of bread, and I shall send famine upon it and cut off from it both man and beast. Now should these three men be in its midst- Noah, &lt;strong&gt;Daniel&lt;/strong&gt;, and Job-they would save themselves with their righteousness, says the Lord God.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:translations&#34;&gt;&lt;a href=&#34;#fn:translations&#34;&gt;9&lt;/a&gt;&lt;/sup&gt; — Ezekiel 14:13-14&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Daniel is written (דנאל). As a distant descendent of Phoenician, Hebrew reads right-to-left: Daled, Nun, Aleph, Lamed. &amp;ldquo;God judged me.&amp;rdquo; Same meaning as the Ugaritic name, same letters as 𐎄𐎐𐎛𐎍.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m amazed that the same meaning can be preserved across so many centuries. But I also want to be as thorough as possible. Two names, eight hundred years apart, with the same meaning, is still not enough for me. I still worry that it could just be an enormous coincidence that two cultures in the same region, speaking sister languages, came up with the same &lt;a href=&#34;https://en.wikipedia.org/wiki/Onomastics&#34;&gt;name-meaning&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ezekiel provides the missing link. In the Tanakh, both Noah and Job are treated as pious men, but critically, &lt;em&gt;neither are Israelites&lt;/em&gt;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:job&#34;&gt;&lt;a href=&#34;#fn:job&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; Making Daniel part of the trio implies he was also a righteous non-Jew.&lt;/p&gt;

&lt;p&gt;Ezekiel would expect people would know who &amp;ldquo;Daniel&amp;rdquo; was if he used that name. This would make sense if Daniel was, say, a righteous figure in the broader Canaanite folklore. At least the Tale of Aqhat implies he was a righteous and just man who was worthy of El&amp;rsquo;s blessing. He prayed for a son and his wish was granted. He&amp;rsquo;d be a distinct character, a known righteous non-Israelite, which Ezekiel used as a point of reference.&lt;/p&gt;

&lt;p&gt;A tenuous chain, I know, but enough to persuade me at least. &lt;a href=&#34;https://www.jstor.org/stable/1517522&#34;&gt;Enough to persuade other scholars too&lt;/a&gt;. It may be the best we&amp;rsquo;ll ever do.&lt;/p&gt;

&lt;p&gt;We can finally use the Bible to establish that Daniel wasn&amp;rsquo;t just a folkloric name, but a name people actually used. From the Book of Ezra:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And these are the heads of their father&amp;rsquo;s houses and the lineage of those who ascended with me in the kingdom of King Artaxerxes from Babylon. Of the sons of Phinehas, Gershom: of the sons of Ithamar, &lt;strong&gt;Daniel&lt;/strong&gt;; of the sons of David, Hattush. — Ezra 8:1-2&lt;/p&gt;

&lt;p&gt;And these were the sons of David who were born to him in Hebron: the firstborn, Amnon, to Ahinoam the Jezreelitess; the second, &lt;strong&gt;Daniel&lt;/strong&gt;, to Abigail the Carmelitess. — Chronicles 3:1&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If they&amp;rsquo;re using Daniel as the name of a minor son of a minor figure, it&amp;rsquo;s probably a real name.&lt;/p&gt;

&lt;h3 id=&#34;the-false-daniel&#34;&gt;The False Daniel&lt;/h3&gt;

&lt;p&gt;But now we have a problem.&lt;/p&gt;

&lt;p&gt;The Ezekiel Daniel has four letters. But all of the later Daniels have &lt;em&gt;five&lt;/em&gt;: Daled, Nun, &lt;em&gt;Yud&lt;/em&gt;, Aleph, Lamed (דניאל) .&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s still possible to read the four-letter version as &amp;ldquo;Daniel&amp;rdquo; but it&amp;rsquo;s more likely to be &amp;ldquo;Danel&amp;rdquo; or &amp;ldquo;Danil&amp;rdquo;. And, Ezekiel&amp;rsquo;s Daniel being closest to the Ugaritic DN&amp;rsquo;IL, suggests that DN&amp;rsquo;IL was &lt;em&gt;also&lt;/em&gt; &amp;ldquo;Danel&amp;rdquo;. That&amp;rsquo;s how most modern scholars now transliterate the name.&lt;/p&gt;

&lt;p&gt;So yes, I may have been chasing a false Daniel this whole time. &lt;a href=&#34;https://www.youtube.com/watch?v=9LMr5XTgeyI&#34;&gt;Theophanu is not Tiffany&lt;/a&gt;, after all. Maybe &amp;ldquo;Daniel&amp;rdquo; is &lt;em&gt;at best&lt;/em&gt; attested from 600 BCE, putting it in contention with things like Debrah and &lt;a href=&#34;https://en.wikipedia.org/wiki/Zhou_dynasty&#34;&gt;Zhou&lt;/a&gt;. There is a &lt;em&gt;tradition&lt;/em&gt; to pronounce the Ezekiel DN&amp;rsquo;IL as &amp;ldquo;Daniel&amp;rdquo;, so it could be the actual pronunciation and the Yud was added later. I don&amp;rsquo;t know when the tradition started, though. At the very least, this strengthens the connection between Ezekiel&amp;rsquo;s דנאל and the Ugarite&amp;rsquo;s 𐎄𐎐𐎛𐎍: Ezekiel was working off a different name than the rest of the Tanakh authors.&lt;/p&gt;

&lt;p&gt;Then again, maybe this is all just quibbling over specifics. The Latin alphabet wasn&amp;rsquo;t meant for Canaanite names, and the Hebrew alphabet wasn&amp;rsquo;t meant for Ugaritic ones. The Biblical שרה could be Romanized as &amp;ldquo;Sarah&amp;rdquo; or &amp;ldquo;Sara&amp;rdquo;, חנכה could be Hannukah, Channuka, or Chanukah. Maybe it doesn&amp;rsquo;t matter whether 𐎄𐎐𐎛𐎍  is דניאל or Danel or דנאל or Daniel. It&amp;rsquo;s still the same name.&lt;/p&gt;

&lt;p&gt;Regardless, we&amp;rsquo;re following a chain, and there&amp;rsquo;s still one more link.&lt;/p&gt;

&lt;h3 id=&#34;from-daniel-to-today&#34;&gt;From Daniel to Today&lt;/h3&gt;

&lt;p&gt;There&amp;rsquo;s one last question here: lots of people use Tanakh names, like Sarah and Benjamin and David. But many Tanakh names, like Tamar and Yehuda and Hillel, are only used by Jews. Why is Daniel in the former group and not the latter?&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;d speculate that the difference is how likely it is for a &lt;em&gt;Christian&lt;/em&gt; reader to encounter the name. &amp;ldquo;Adam&amp;rdquo; appears in the first book of Genesis, while Shamgar is a minor figure in the book of Judges. Christians would most likely encounter names that appear either really early, have entertaining stories, or are directly relevant to the New Testament.&lt;/p&gt;

&lt;p&gt;And here&amp;rsquo;s where we finally get to the last link between then and now: the Book of Daniel. Like the Book of Ezekiel, this recounts the story of someone living during the Babylonian exile. &lt;em&gt;Unlike&lt;/em&gt; Ezekiel, it was pretty clearly &lt;a href=&#34;https://www.jstor.org/stable/3209969&#34;&gt;written four hundred years after&lt;/a&gt; the exile. Daniel contains an awful lot of prophecies that &lt;a href=&#34;https://www.thetorah.com/article/chanukah-daniel-11-and-the-rabbis-limited-knowledge-of-history&#34;&gt;seem &lt;em&gt;very&lt;/em&gt; relevant to the Greek occupation&lt;/a&gt; (the one that leads to the story of Channukah).  The most famous of them is the &lt;a href=&#34;https://en.wikipedia.org/wiki/Prophecy_of_Seventy_Weeks&#34;&gt;prophecy of 70 weeks&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And you shall know and understand that from the emergence of the word to restore and to rebuild Jerusalem until the anointed king [shall be] seven weeks, and [for] sixty-two weeks it will return and be built street and moat, but in troubled times. — Daniel 9:25&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Later writers took this to be a prophecy about &lt;em&gt;Jesus&lt;/em&gt;. I don&amp;rsquo;t admit to understand &lt;em&gt;how&lt;/em&gt; it&amp;rsquo;s supposed to be about Jesus, but it is. So the book of Daniel is really important in Christian thought. This kept  the name &amp;ldquo;Daniel&amp;rdquo; in the Christian mainstream for the next 2000 years, carrying it across the world to  &lt;a href=&#34;https://en.wikipedia.org/wiki/Daniel_Gabriel_Fahrenheit&#34;&gt;Europe&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/Daniyal_Mirza&#34;&gt;India&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/Daniel_Nushiro&#34;&gt;East Asia&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/Daniel_Paiola&#34;&gt;South America&lt;/a&gt;, all the way to the present daytoday. The end of a 3400 year chain.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;So that&amp;rsquo;s the story of the name of Daniel, from an ancient clay tablet to the millions of Daniels alive now.&lt;/p&gt;

&lt;p&gt;I want to reiterate that &lt;strong&gt;I&amp;rsquo;m not a trained historian&lt;/strong&gt; and almost certainly got a lot of details wrong. Also, this isn&amp;rsquo;t and wouldn&amp;rsquo;t pass peer review. Don&amp;rsquo;t cite this for a class paper. Happy April Cools!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://predr.ag/blog/mediocrity-can-be-a-sign-of-excellence/&#34;&gt;Predrag Gruevski&lt;/a&gt; for feedback. If you enjoyed this, check out the &lt;a href=&#34;https://www.aprilcools.club/&#34;&gt;April Cools website&lt;/a&gt; for all the other pieces this year!&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:JSTOR&#34;&gt;I accessed JSTOR as a UChicago Alumnus benefit, but I also found out that anyone with a &lt;a href=&#34;https://www.chipublib.org/resource/#azindex-letter-J&#34;&gt;Chicago public library card&lt;/a&gt; has access too! Hundreds of public libraries do this!
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:JSTOR&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:China&#34;&gt;Note though that the Chinese &amp;ldquo;Lee&amp;rdquo; is just one possible Romanization of 李. &amp;ldquo;Li&amp;rdquo; is another.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:China&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:preservation&#34;&gt;We have a much larger Egyptian corpus because papyrus lasts longer in Egypt&amp;rsquo;s hot and arid climate. We have large Greek and Roman corpuses because monks tirelessly copied old texts into new books for centuries. &lt;a href=&#34;https://en.wikipedia.org/wiki/Pompeii&#34;&gt;Volcanoes helped&lt;/a&gt;. 
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:preservation&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:order&#34;&gt;We know the order because &lt;a href=&#34;https://www.jstor.org/stable/3264672&#34;&gt;we&amp;rsquo;ve recovered Ugarit abedecaries&lt;/a&gt; (inscriptions of all an alphabet&amp;rsquo;s letters in order).
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:order&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:date&#34;&gt;At least, that&amp;rsquo;s when Jews were permanently expelled from the region. Growing up I was taught that the &lt;em&gt;important&lt;/em&gt; event was the burning of the Second Temple, which happened in 70 CE.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:date&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:torah&#34;&gt;I originally wrote &amp;ldquo;the Torah&amp;rdquo; here, but as one commenter pointed out, the Torah is just the &lt;em&gt;first five books of Moses&lt;/em&gt;. The Tanakh also includes the Nevi&amp;rsquo;im and Ketuvim, both of which I rely on later in the essay. I know all my old Rebbes are &lt;em&gt;very&lt;/em&gt; disappointed in me.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:torah&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:orthodox&#34;&gt;I grew up an Orthodox Jew, and it&amp;rsquo;s extremely weird to study the actual history of your religion. Like vivisecting holy books.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:orthodox&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:Ezekiel&#34;&gt;From my research it seems that it&amp;rsquo;s generally accepted that most of Ezekiel is written contemporaneously with the Babylonian exile, though it may have been smoothed out later.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:Ezekiel&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:translations&#34;&gt;For Old Testament verses I&amp;rsquo;m using the Chabad translations. My Hebrew never got past a first grade level.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:translations&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:job&#34;&gt;Noah is obvious: his story takes place before Abraham&amp;rsquo;s. Job is tougher, as there&amp;rsquo;s nothing in the story that makes it clear he&amp;rsquo;s not Jewish. I&amp;rsquo;m basing this off the claims of &lt;a href=&#34;https://en.wikipedia.org/wiki/Job_in_rabbinic_literature&#34;&gt;many different Rabbis&lt;/a&gt; and &lt;a href=&#34;https://www.jstor.org/stable/3268592&#34;&gt;modern scholars&lt;/a&gt;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:job&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Comment Section: The Hunt For The Missing Data Type</title>
        <link>https://www.hillelwayne.com/comments/graph-types/</link>
        <pubDate>Mon, 18 Mar 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/comments/graph-types/</guid>
        <description>

&lt;p&gt;I got a lot of responses to &lt;a href=&#34;https://www.hillelwayne.com/post/graph-types/&#34;&gt;The Hunt For the Missing Data Type&lt;/a&gt;. I&amp;rsquo;ve included some of the most interesting ones below.&lt;/p&gt;

&lt;h2 id=&#34;response-blogs&#34;&gt;Response Blogs&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://tylerhou.com/posts/datalog-go-brrr/&#34;&gt;The &amp;ldquo;missing&amp;rdquo; graph datatype already exists. It was invented in the &amp;lsquo;70s&lt;/a&gt;, about datalog.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;emails-and-comments&#34;&gt;Emails and Comments&lt;/h2&gt;

&lt;p&gt;Everything in quotes is verbatim.&lt;/p&gt;

&lt;h3 id=&#34;graphblas&#34;&gt;GraphBLAS&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;My name is Michel Pelletier, I&amp;rsquo;m one of the contributors to the GraphBLAS API standard and python bindings.&lt;/p&gt;

&lt;p&gt;Congrats on your blog going up to the front page on HN.   I replied with some information that I think you might find useful to your question, but it&amp;rsquo;s pretty buried under a lot of the discussion there.  I noticed that you invite people to email you, so I decided to send you the information directly.&lt;/p&gt;

&lt;p&gt;The graph data type you&amp;rsquo;re missing is the one you already mentioned, a matrix.  You mention adjacency matrices, but in the context of your blog post, they&amp;rsquo;re considered only a storage format, not the graph itself.  But graphs and matrices are conceptually and algebraically isomorphic.  All graphs, and thus all composite data structures, are mathematically matrices, and all matrices are graphs.  Hypergraphs and Multigraphs are represented by &amp;ldquo;Incidence Matrices&amp;rdquo; which are node-to-edge to edge-to-node adjacencies using two rectangular matrices.&lt;/p&gt;

&lt;p&gt;A really excellent introductory paper by a large group of researchers, spearheaded by Dr. Jeremy Kepner, Director of the Supercomputing Center and MITs Lincoln Laboratory is:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://arxiv.org/pdf/1606.05790.pdf&#34;&gt;https://arxiv.org/pdf/1606.05790.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The issue with computers and thinking of graphs as matrices is that most graphs are sparse, and most matrix libraries (like numpy) are dense.  This makes using adjacency matrices very expensive, since most of the &amp;ldquo;space&amp;rdquo; in a dense matrix ends up being zero.  This is extremely inefficient and defeats cache hierarchies typical of von Neumann architectures.  These two worlds have not quite converged yet.&lt;/p&gt;

&lt;p&gt;There is however a lot of research and development around efficient sparse matrix computation, and thus, sparse graph analysis.  While these may seem different, they are actually one in the same: matrix multiplication is a breadth first step across a graph.  This is part of the isomorphic nature between them.  A lot of ML and AI research involves both sparse matrices and graphs, and this research is very much unified in improving the performance of both paradigms.&lt;/p&gt;

&lt;p&gt;A big question I get about this is &amp;ldquo;why&amp;rdquo;.  Why write a linear algebraic formula instead of a function that traverses the nodes and edges?  And one of the most important answers is parallelization over huge graphs.  When graphs get really, really big, billions or trillions of edges, you need to divide the work of your algorithm efficiently.  How are you going to do that?  Fork every edge?  Use a thread pool?  How to schedule the work and partition the graph efficiently?  Now do that on CUDA&amp;hellip; the problem becomes almost impossible for even the smartest programmers to tackle.&lt;/p&gt;

&lt;p&gt;With the GraphBLAS, a graph operation is a linear algebraic formula, decomposed into a series of matrix multiplications, you just say something like Ax = b, and the underlying library figures out how to do the work most efficiently on a specific target architecture.  Run it on a chromebook or a supercomputer, the code doesn&amp;rsquo;t change, just the capacity of the machine for bigger graphs.  You can think of the GraphBLAS as a language that can be &amp;ldquo;JIT&amp;rdquo; compiled based not only on the underlying architecture but also the shape and type of problem you feed it.  Since LA is the universal language of math, science and engineering, this technique has natural application to a lot of existing work.&lt;/p&gt;

&lt;p&gt;So I just wanted to send that your way, good luck on your further exploration of the subject.  I&amp;rsquo;m happy to chat with you anytime if you&amp;rsquo;d like to find out more, as a member of the C API Committee, evangelizing is part of my job and I enjoy introducing the subject.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;gremlin&#34;&gt;Gremlin&lt;/h3&gt;

&lt;p&gt;In earlier drafts of the essay I talked about TinkerPop, Apache&amp;rsquo;s graph computing framework, and Gremlin, the query language. I removed it from the final version, and several people noticed it was missing. Here&amp;rsquo;s one response.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You mentioned Cypher, but didn’t talk about Gremlin, which is an expressive graph query language for Neo4j/TinkerPop:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://tinkerpop.apache.org/&#34;&gt;https://tinkerpop.apache.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was used to power the Joern SAST tool that was acquired by ShiftLeft, and I think is used a lot in the finance world.&lt;/p&gt;

&lt;p&gt;I last used it to make a graph of all of the software packages in Maven and their interdependencies.&lt;/p&gt;

&lt;p&gt;It’s got nice bindings into programming languages - I used Python Gremlin so I could drive it from a familiar scripting language, since the default REPL/script is Groovy that I’m not so handy with.&lt;/p&gt;

&lt;p&gt;You can interchange between querying the graph with Gremlin and doing “normal” imperative scripting in Python, then do further querying from the results. It felt quite natural.&lt;/p&gt;

&lt;p&gt;I don’t know about the state of whole graph algorithms for it - I was always interested in traversal-based queries vs whole graph statistics like centrality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;rubik-s-cubes&#34;&gt;Rubik&amp;rsquo;s Cubes&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I ran across your article about missing software libraries for graphs because it was linked from the CodeProject newsletter. It was a wonderful article. I&amp;rsquo;m not of the same caliber as the people you consulted when you were writing the article, but nevertheless I thought I would offer you one more example of the difficulties in creating generic software libraries for graphs. Namely, I&amp;rsquo;m a part of a very informal group of people who have been using computers for years to investigate the mathematics of Rubik&amp;rsquo;s Cube.&lt;/p&gt;

&lt;p&gt;The math underlying Rubik&amp;rsquo;s Cube is called group theory and one of the things you can do with groups is to map them out with graphs called Cayley graphs. That know-it-all called Google describes it as follows:
&amp;ldquo;Cayley graphs are frequently used to render the abstract structure of a group easily visible by way of representing this structure in graph form. Properties of a group G, such as its size or number of generators, become much easier to examine when G is rendered as a Cayley graph.&amp;rdquo; In particular, each possible Rubik&amp;rsquo;s Cube position can be represented as a node in a Cayley graph and adjacent nodes are those which can be reached in exactly one move. You mentioned the 15 puzzle your article. It turns out that one of the Rubik&amp;rsquo;s Cube investigators has written a complete and very fast solver for the 15 puzzle. And it also turns out that the size of the 15 puzzle is a drop in the bucket as compared to the size of the Cayley graph for Rubik&amp;rsquo;s Cube.&lt;/p&gt;

&lt;p&gt;In any case, I have been writing code since 1985 to investigate Rubik&amp;rsquo;s Cube. This is not just to &amp;ldquo;solve&amp;rdquo; Rubik&amp;rsquo;s Cube, which is actually quite easy. Rather, it&amp;rsquo;s to determine for each of the nearly 10^20 positions the least number of moves that are required to solve position. The problem remains unsolved simply because it is so large. It has been determined that any position can be solved in either 20 moves or in 26 moves, depending on what you count as one move. But that&amp;rsquo;s not the same thing as finding the solution for each possible position that requires the least possible number of moves.&lt;/p&gt;

&lt;p&gt;In any case, I know from much experience that I have had to develop my own data structures that are quite specific to Rubik&amp;rsquo;s Cube in order to address the problem in any practical manner. The key issue (and here I&amp;rsquo;m quoting from your article) is that Performance Is Too Important. No libraries I could find did what I needed, so I rolled my own.&lt;/p&gt;

&lt;p&gt;Thanks for a wonderful article,&lt;/p&gt;

&lt;p&gt;Jerry&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I asked for more information on what &amp;ldquo;20 or 26&amp;rdquo; moves meant and whether he could share more about the data structures he uses. His reply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As you guessed, whether you count a single half rotation as one move or two is the primary example of what counts as one move. If you only count quarter rotations as one move, then that&amp;rsquo;s called the quarter turn metric. Any position can be solved in 26 moves in this metric. If you count either quarter rotations or half rotations as one move, then that&amp;rsquo;s called the face turn metric. Any position can be solved in 20 moves in this metric. But there are other ways to choose what counts as one move. A Rubik&amp;rsquo;s Cube has three layers in any direction. Typically you only count moves of the outer layers such as the top and bottom but not the layer in between the top and bottom or the outer layers such as the right and left but not the layer between the right and left. But it is sometimes interesting to count moves of those middle layers as one move. Another variation is the stuck axle problem where you pretend one of the axles is stuck. For example, you don&amp;rsquo;t move the top face and only move the layers on the other five faces of the cube. With this variation, you can still reach all the possible positions but the Cayley graph does not have the same symmetry as it would have if none of the axles were stuck. Also, many more moves can be required to solve a cube with a stuck axle than the standard 20 moves or 26 moves.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t think there is any standard data structure for Rubik&amp;rsquo;s Cube.
Each person working on the cube has their own, except that there is an obvious sense that any data structure that faithfully represents the cube has to be somewhat isomorphic to any other data structure that faithfully represents the cube. A big distinction is whether the data structure consists only of positions or whether it consists both of positions and moves. For example, two consecutive clockwise quarter turns of the front face results in the same position as two consecutive counter-clockwise quarter turns of the front face. In a Cayley graph, these move sequences become a loop if continued. The loop is a four move cycle (a 4-cycle). So do you store moves and positions, or do you just store positions?&lt;/p&gt;

&lt;p&gt;I really don&amp;rsquo;t know how anybody else&amp;rsquo;s data structures handles these issues. For myself, I don&amp;rsquo;t explicitly store the entire Cayley graph.
Instead, I store positions and with each position I store single bit for each possible move from that position that indicates whether the move takes you further from the solved position or closer to the solved position. There are 12 such bits for each position in the quarter turn metric and 18 such bits for each position in the face turn metric. Those bits implicitly define a Cayley graph, but I do not store the graph explicitly. Other people working on the problem talk about using canonical sequences of moves, for example you can make two successive clockwise moves of the front face but not two successive counter-clockwise moves of the front face. I do something similar but not exactly the same using my bits.&lt;/p&gt;

&lt;p&gt;The other issue is that I needed a tree structure and a tree can be thought of as a special case of a graph. Which is to say, a tree is just a graph where one node is declared to be a root node and where there are no loops in the graph. I had to roll my own tree structure. The tree structure I needed arises as follows. There are 54 color tabs on a standard Rubik&amp;rsquo;s Cube. In the standard mathematical model, the center color tab on each face does not move which leaves 48 color tabs which move. Of the 48 color tabs, 24 are on the corners of 3x3 squares and 24 are on the edges of 3x3 squares. The corner color tabs and edge color tabs are disjoint, so I represent a cube position by labeling each corner color tab with a letter from A to X and by labeling each edge color tab with a letter from A to X. Each position is then an ordered pair of words where each word consists of 24 letters and where each letter appears exactly one time in each word.&lt;/p&gt;

&lt;p&gt;So why do I need a tree? Well, I need to be able to find these words very quickly. It&amp;rsquo;s like finding words very quickly in a spell check dictionary. Nominally, each node in the tree needs 24 pointers to other nodes in the tree. Except that unlike real words in a real spell check dictionary, each letter can appear only one time in each word. So as I get towards the leaf nodes of the tree, each node is going to consist mostly of null pointers, a huge waste of very valuable memory. So I had to create a tree structure to accommodate the storage of the positions for fast retrieval. No standard library routines were fast enough and conservative enough of memory.&lt;/p&gt;

&lt;p&gt;So essentially I have two data structures layered together. One of them uses bit switches to define the Cayley graph for the cube, and the other of them uses a spell check dictionary style tree to locate specific positions very quickly. And trees are just special cases of graphs.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t know if that answers your questions, but I hope it helps.&lt;/p&gt;

&lt;p&gt;Jerry&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;graphs-and-knowledge-databases&#34;&gt;Graphs and knowledge databases&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Hillel — Thank you for sharing your exploration of graph representations with clear explanations as to why there is no clear winner. I’m wondering if the problems you cite aren’t so large as to preclude viable alternatives.&lt;/p&gt;

&lt;p&gt;I come to this question first as a Smalltalk programmer and then as the creator of Wiki. Both have a graph like structure assembled in bits and persistent in use. The small community around my most recent wiki implementation is highly motivated to add graphs to pages along with paragraphs, images, outline, and tables. We have partially met this with Graphviz using Dot as a markup. But this does not yield to the computation and sharing as we get with files of yaml or csv.&lt;/p&gt;

&lt;p&gt;We’ve recently adopted the practice of representing graphs (in javascript, for example) as an object with arrays for nodes and relations. The empty graph would be:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{nodes:[], rels:[]}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nodes and relations are themselves objects with a string for type and an additional object for properties and some managed indices that hook them together. This then serializes conveniently into (loop free) json, a format widespread and adequate  for graphs measured in kilobytes.&lt;/p&gt;

&lt;p&gt;These graphs converts easily into Neo4j objects for which we have considerable experience. More often we avoid maintaining a database beyond wiki itself. Although we have also built a modest Cypher interpreter we have not found that useful. We have made the surprising discovery that we are more likely to merge many small graphs into the one that solves the problem at hand rather than build one large Neo4j graph and query out the graph needed to solve the same problem.&lt;/p&gt;

&lt;p&gt;More recently we have come to separate problems into “aspects” based on cross-cutting concerns in the problem space. We might have tens of these graphs or even hundreds. We browse these as one might browse a wiki where the equivalent of a wiki-link comes from recognizing the same node appearing in yet-to-be-included graphs. This is a “recommending” process and query is replaced by choosing and un-choosing recommendations with work-in-progress rendered immediately with Graphviz running in the browser.&lt;/p&gt;

&lt;p&gt;I started this email with a more complete description of our graph abstraction but stepped back from that as I was unsure you would find our experience interesting. I could also describe applications where this has proven useful usually involving some collaboration problem within a community.&lt;/p&gt;

&lt;p&gt;I would love to correspond if you think there is any overlap in interests.&lt;/p&gt;

&lt;p&gt;Thank you and best regards — Ward&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;His code for this is avaiable &lt;a href=&#34;https://github.com/WardCunningham/graph&#34;&gt;here&lt;/a&gt;, along with docs and examples. Followup email:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hillel — We are on the hunt for small graphs representing aspects of larger problems. Here is a case where when asked to read a paper headed to the European Patterns conference I chose to read it very carefully and map every “relational” sentence in their patterns. Here is a picture where the an unexpected overlap between aspects is shown in yellow.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/wiki-graph.png&#34; alt=&#34;image of the graph&#34; /&gt;&lt;/p&gt;

&lt;p&gt;This particular graph viewer has had a circuitous life: started as scripts on wiki pages; extracted as a stand-alone web app on top of Croquet for online collaboration; then here as a single-user “solo” application heading back into wiki. It is not yet self-explanatory. But you can bring it up with the “open” link in the last paragraph of the wiki page where I coordinated with a co-reviewer who shares an interest in this sort of exploration. &lt;a href=&#34;http://ward.dojo.fed.wiki/aspects-of-pattern-relations.html&#34;&gt;http://ward.dojo.fed.wiki/aspects-of-pattern-relations.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two more similar projects that show off different “aspect” possibilities: Chopping up a year of recent changes, and, annotating a search engine source code with node-relation comments and extracting them into graph files with GitHub actions.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
      </item>
      
    
      
      <item>
        <title>The Hunt for the Missing Data Type</title>
        <link>https://www.hillelwayne.com/post/graph-types/</link>
        <pubDate>Sat, 02 Mar 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/graph-types/</guid>
        <description>

&lt;p&gt;A (directed) &lt;dfn&gt;graph&lt;/dfn&gt; is a set of nodes, connected by arrows (&lt;dfn&gt;edges&lt;/dfn&gt;). The nodes and edges may contain data. Here are some graphs:&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/graph-examples.gv.png&#34;    title=&#34;Four graphs, with circles for nodes and arrows for edges.&#34; &gt; 

  &lt;figcaption&gt;
    All graphs made with graphviz 

  &lt;a href=&#34;img/graph-examples.gv&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;Graphs are ubiquitous in software engineering:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Package dependencies form directed graphs, as do module imports.&lt;/li&gt;
&lt;li&gt;The internet is a graph of links between webpages.&lt;/li&gt;
&lt;li&gt;Model checkers analyze software by exploring the &amp;ldquo;state space&amp;rdquo; of all possible configurations. Nodes are states, edges are valid transitions between states.&lt;/li&gt;
&lt;li&gt;Relational databases are graphs where the nodes are records and the edges are foreign keys.&lt;/li&gt;
&lt;li&gt;Graphs are a generalization of linked lists, binary trees, and hash tables.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:hash-tables&#34;&gt;&lt;a href=&#34;#fn:hash-tables&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Graphs are also widespread in business logic. Whitepapers with references form graphs of citations. Transportation networks are graphs of routes. Social networks are graphs of connections. If you work in software development long enough, you will end up encountering graphs &lt;em&gt;somewhere&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I see graphs everywhere and use them to analyze all sorts of systems. At the same time, I dread actually using graphs in my code. There is almost no graph support in any mainstream language. None have it as a built-in type, very few have them in the standard library, and many don&amp;rsquo;t have a robust third-party library in the ecosystem. Most of the time, I have to roll graphs from scratch. There&amp;rsquo;s a gap between how often software engineers could use graphs and how little our programming ecosystems support them. Where are all the graph types?&lt;/p&gt;

&lt;p&gt;As I ran into more and more graphs in my work, this question became more and more intriguing to me. So late last year I finally looked for an answer. I put a &lt;a href=&#34;https://buttondown.email/hillelwayne/archive/if-you-work-on-a-big-language-id-like-to-talk/&#34;&gt;call out&lt;/a&gt; on &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;my newsletter&lt;/a&gt; asking for people with relevant expertise— graph algorithm inventors, language committee members, graph library maintainers— to reach out. I expected to interview a dozen people, but in the end I only needed to talk to four:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Zayenz&lt;/strong&gt;: Former core developer of the &lt;a href=&#34;https://www.gecode.org/&#34;&gt;Gecode constraint solver&lt;/a&gt;, and who has &amp;ldquo;implemented every graph algorithm there is&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bradford&lt;/strong&gt;: Author of the &lt;a href=&#34;https://github.com/praetorian-inc/noseyparker/&#34;&gt;Nosey Parker&lt;/a&gt; security library and inventor of several new graph algorithms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://ntietz.com/&#34;&gt;Nicole&lt;/a&gt;&lt;/strong&gt;: Former graph database engineer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kelly&lt;/strong&gt;: Maintainer on the &lt;a href=&#34;https://networkx.org/&#34;&gt;NetworkX&lt;/a&gt; python graph library and &lt;a href=&#34;https://github.com/boothby/repiet&#34;&gt;compiler developer&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After these four people all gave similar answers, I stopped interviewing and start writing.&lt;/p&gt;

&lt;h2 id=&#34;the-reasons&#34;&gt;The reasons&lt;/h2&gt;

&lt;h3 id=&#34;there-are-too-many-design-choices&#34;&gt;There are too many design choices&lt;/h3&gt;

&lt;p&gt;So far I&amp;rsquo;ve been describing &lt;em&gt;directed&lt;/em&gt; graphs. There are also &lt;em&gt;undirected&lt;/em&gt; graphs, where edges don&amp;rsquo;t have a direction. Both directed and undirected graphs can either be &lt;dfn&gt;simple graphs&lt;/dfn&gt;, where there is a maximum of one edge between two nodes, or &lt;dfn&gt;multigraphs&lt;/dfn&gt;, where there can be many edges. And then for each of &lt;em&gt;those&lt;/em&gt; types we have hypergraphs, where an edge can connect three or more nodes, and ubergraphs, where edges can point to other edges. For each possible variation you have more choices to make: do you assign ids to edges or just to nodes? What data can be stored in a node, and what can be stored in an edge? That&amp;rsquo;s a lot of decisions for a library to make!&lt;/p&gt;

&lt;p&gt;But wait, do these distinctions matter at all? A simple graph is just a degenerate multigraph, and and undirected edge can be losslessly transformed into two directed edges. A language could just provide directed hyperubermultigraphs and let users restrict it however they want.&lt;/p&gt;

&lt;p&gt;There are two problems with this. First of all, it changes the interface, like whether various operations return single values or lists. Second, as I&amp;rsquo;ll discuss later, graph algorithm performance is a serious consideration and the special cases &lt;em&gt;really matter&lt;/em&gt;. Kelly raised the example of &lt;a href=&#34;https://en.wikipedia.org/wiki/Maximum_weight_matching&#34;&gt;maximum weight matching&lt;/a&gt;. If you know that your graph is &amp;ldquo;bipartite&amp;rdquo;, you can use a particular fast algorithm to find a matching, while for other graphs you need to use a slow, more general algorithm.&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/bipartite.gv.png&#34;    title=&#34;A bipartite graph&#34; &gt; 

  &lt;figcaption&gt;
    A bipartite graph 

  &lt;a href=&#34;img/bipartite.gv&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;blockquote&gt;
&lt;p&gt;[It] ties back to the &amp;ldquo;algorithm dispatch problem.&amp;rdquo;  Given a Problem P, a Graph G, and Algorithms A, B, C to solve P on G&amp;hellip; which one do you run?  If we don&amp;rsquo;t know that G is bipartite, and Algorithm C only works on bipartite graphs, how much time can we afford to determine whether or not G is bipartite? — &lt;em&gt;Kelly&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The perfect graph library would support a lot of different kinds of graphs. But that takes time away from supporting what people want to &lt;em&gt;do&lt;/em&gt; with graphs. Graph algorithms are notoriously hard to get right. In &lt;a href=&#34;https://www.python.org/doc/essays/graphs/&#34;&gt;this essay&lt;/a&gt;, the inventor of Python implemented his own &lt;code&gt;find_shortest_path&lt;/code&gt; algorithm. It had to be updated with corrections five times!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every single implementation of pagerank that I compared to was wrong. — &lt;em&gt;Nicole&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So which algorithms should come with the library? &amp;ldquo;The amount of things people want to do with graphs is absurd,&amp;rdquo; Kelly told me. That matches my experience, and the experiences of all my interviewees. It sometimes seems like graphs are &lt;em&gt;too powerful&lt;/em&gt;, that all their possibilities are beyond my understanding. &amp;ldquo;The question is,&amp;rdquo; Kelly said, &amp;ldquo;where do you draw the line?&amp;rdquo;&lt;/p&gt;

&lt;p&gt;For NetworkX, &amp;ldquo;the line&amp;rdquo; is approximately 500 distinct graph algorithms, by themselves making up almost 60,000 lines of code. By comparison, the entire Python standard library, composed of 300 packages, is just under 600,000 lines.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:derivation&#34;&gt;&lt;a href=&#34;#fn:derivation&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;With all that, it&amp;rsquo;s unsurprising that you don&amp;rsquo;t see graphs in standard libraries. The language maintainers would have to decide which types of graphs to support, what topologies to special-case, and what algorithms to include. It makes sense to push this maintenance work onto third parties. This is already the mainstream trend in language development; even Python, famous for being &amp;ldquo;batteries included&amp;rdquo;, is &lt;a href=&#34;https://peps.python.org/pep-0594/&#34;&gt;removing 20 batteries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Third parties can make opinionated decisions on how to design graphs and what algorithms to include. But then they&amp;rsquo;re faced with the next problem: once you have a graph interface, how do you represent it?&lt;/p&gt;

&lt;h3 id=&#34;there-are-too-many-implementation-choices&#34;&gt;There are too many implementation choices&lt;/h3&gt;

&lt;p&gt;Let&amp;rsquo;s imagine we&amp;rsquo;re supporting only barebones simple directed graphs: nodes have identities, edges do not, neither has any associated data. How do we encode this graph?&lt;/p&gt;

&lt;center&gt;
&lt;figure&gt; 
  &lt;img  src=&#34;img/many-encodings.gv.png&#34;    title=&#34;A graph diagram of `a -&amp;gt; b -&amp;gt; c -&amp;gt; {a, b}`&#34; &gt; 

  &lt;figcaption&gt;
     

  &lt;a href=&#34;img/many-encodings.gv&#34;&gt;(source)&lt;/a&gt;

  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;


&lt;p&gt;Here are four possible ways a programming language could internally store it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edge list: &lt;code&gt;[[a, b], [b, c], [c, a], [c, b]]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Adjacency list: &lt;code&gt;[[b], [c], [a, b]]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Adjacency matrix: &lt;code&gt;[0 1 0; 0 0 1; 1 1 0]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A set of three structs with references to each other&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Different graph operations have different performance characteristics on different representations. Take a directed graph with 100 nodes and 200 edges. If we use an adjacency matrix representation, we need a 100×100 matrix containing 200 ones and 9,800 zeros.  If we instead use an edge list we need only 200 pairs of nodes. Depending on your PL and level of optimizations that could be a memory difference of 20x or more.&lt;/p&gt;

&lt;p&gt;Now instead take a graph with 100 nodes and 8,000 edges and try to find whether an edge exists between node 0 and node 93. In the matrix representation, that&amp;rsquo;s an O(1) lookup on &lt;code&gt;graph[0][93]&lt;/code&gt;. In the edge list representation, that&amp;rsquo;s an O(|edge|) iteration through all 8,000 edges.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:variations&#34;&gt;&lt;a href=&#34;#fn:variations&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Graphs with only a few edges are &lt;dfn&gt;sparse&lt;/dfn&gt; and graphs with almost all edges are &lt;dfn&gt;dense&lt;/dfn&gt;. The same program may need to do both operations on both kinds of graph topologies: if you&amp;rsquo;re constructing a graph from external data, you could start out with a sparse graph and later have a dense one. There&amp;rsquo;s no &amp;ldquo;good option&amp;rdquo; for the internal graph representation.&lt;/p&gt;

&lt;p&gt;And all this trouble is just for the most barebones directed graph! What about implementing node data? Edge data? Different types of nodes and edges? Most third party libraries roughly fall in one of two categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Offer a single rich datatype that covers all use-cases at the cost of efficiency. NetworkX stores graph as a dict of dicts of dicts, so that both nodes and edges can have arbitrary data.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:networkx-representations&#34;&gt;&lt;a href=&#34;#fn:networkx-representations&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Offer separate graph types for each representation, and rely on the user to store node and edge data separately from the graph type.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An example of the second case would be &lt;a href=&#34;https://docs.rs/petgraph/latest/petgraph/index.html&#34;&gt;Petgraph&lt;/a&gt;, the most popular graph library for Rust. Petgraph has &lt;code&gt;graph&lt;/code&gt;, &lt;code&gt;graphmap&lt;/code&gt;, and &lt;code&gt;matrix_graph&lt;/code&gt; for different use-cases. Bradford used Petgraph for &lt;a href=&#34;https://github.com/praetorian-inc/noseyparker/&#34;&gt;Nosey Parker&lt;/a&gt;, a security tool that scans for secrets across an entire history of a git repo. His benchmarking graph is CPython, which has 250k commits and 1.3M objects but only a few edges per commit node. He went with an adjacency list.&lt;/p&gt;

&lt;p&gt;Supporting many representations has a serious downside: you have to do a lot more work to add algorithms. If you write a separate version of the algorithm for each graph representation, you&amp;rsquo;re tripling or quadrupling the maintenance burden. If you instead write a generic abstraction over polymorphic types, then your library is less performant. One programmer I talked to estimated that a hand-rolled graph algorithm can be 20x faster or more than a generic algorithm.&lt;/p&gt;

&lt;p&gt;And this gets into every interviewee&amp;rsquo;s major complaint.&lt;/p&gt;

&lt;h3 id=&#34;performance-is-too-important&#34;&gt;Performance is too important&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A &amp;ldquo;generic&amp;rdquo; graph implementation often doesn&amp;rsquo;t cut it. &lt;em&gt;— Bradford&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the big one.&lt;/p&gt;

&lt;p&gt;Many, many graph algorithms are NP-complete or harder.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:np&#34;&gt;&lt;a href=&#34;#fn:np&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; While NP-complete is often tractable &lt;a href=&#34;https://www.hillelwayne.com/post/np-hard/&#34;&gt;for large problems&lt;/a&gt;, graphs can be &lt;em&gt;enormous&lt;/em&gt; problems. The choice of representation plays a big role in how fast you can complete it, as do the specifics of your algorithm implementation.&lt;/p&gt;

&lt;p&gt;Everyone I talked to had stories about this. In Nosey Parker, Bradford needed to reconstruct a snapshot of the filesystem for each commit, which meant traversing the object graph. None of the &lt;a href=&#34;https://docs.rs/petgraph/latest/petgraph/visit/index.html&#34;&gt;four provided graph walkers&lt;/a&gt; scaled to his use case. Instead he had to design a &amp;ldquo;semi-novel&amp;rdquo; &lt;a href=&#34;https://github.com/praetorian-inc/noseyparker/blob/aaacceaa4baf0fb6a9c98c95b9b063ed74654349/crates/input-enumerator/src/git_metadata_graph.rs#L337&#34;&gt;graph traversal algorithm&lt;/a&gt; on the fly, which reduced the memory footprint by a factor of a thousand.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I was able to get working a proof of concept pretty quickly with [petgraph], but then&amp;hellip; this is one of those cases where the performance constraints end up meeting reality. &lt;em&gt;— Bradford&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Zayenz raised a different problem: what if the graph is simply too big to work with? He gave the example of finding a solution to the &lt;a href=&#34;https://en.wikipedia.org/wiki/15_Puzzle&#34;&gt;15 puzzle&lt;/a&gt;. This is done by running a &lt;a href=&#34;https://en.wikipedia.org/wiki/A*_search_algorithm&#34;&gt;A* search&lt;/a&gt; on the state space. A state space with &lt;a href=&#34;https://mediatum.ub.tum.de/doc/1283911/60434.pdf&#34;&gt;over 20 trillion states&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you generate all the nodes, you&amp;rsquo;ve lost already. — &lt;em&gt;Zayenz&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Zayenz oversaw one research project to add graphs to the Gecode constraint solver. They eventually found that a generic graph type simply couldn&amp;rsquo;t compete with handpicking the representation for the problem.&lt;/p&gt;

&lt;p&gt;Even graph databases, designed entirely around running complex graph algorithms, struggle with this problem. Nicole, the graph database engineer, told me about some of the challenges with optimizing even basic graph operations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you&amp;rsquo;re doing a traversal, you either have to limit your depth or accept you&amp;rsquo;re going to visit the entire graph. When you do a depth search, like &amp;ldquo;go out three steps from this and find the path if it exists&amp;rdquo;, then you&amp;rsquo;re just committing to visiting quite a bit of data. &lt;em&gt;— Nicole&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After leaving that job, she worked as a graph query performance consultant. This usually meant migrating off the graph database. She told me about one such project: to speed the graph queries up, she left one computation as-is and rewrote the rest as MapReduce procedures. &amp;ldquo;Which was a lot harder to understand,&amp;rdquo; she said, &amp;ldquo;But would actually finish overnight.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;All of this means that if you have graph problems you want to solve, you need a lot of control over the specifics of your data representation and algorithm. You simply cannot afford to leave performance on the table.&lt;/p&gt;

&lt;h2 id=&#34;it-was-unanimous&#34;&gt;It was unanimous&lt;/h2&gt;

&lt;p&gt;So, the reasons we don&amp;rsquo;t have widespread graph support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are many different kinds of graphs&lt;/li&gt;
&lt;li&gt;There are many different representations of each kind of graph&lt;/li&gt;
&lt;li&gt;There are many different graph algorithms&lt;/li&gt;
&lt;li&gt;Graph algorithm performance is very sensitive to graph representation and implementation details&lt;/li&gt;
&lt;li&gt;People run very expensive algorithms on very big graphs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This explains why languages don&amp;rsquo;t support graphs in their standard libraries: too many design decisions, too many tradeoffs, and too much maintenance burden. It explains why programmers might avoid third party graph libraries, because they&amp;rsquo;re either too limited or too slow. And it explains why programmers might not want to think about things in terms of graphs except in extreme circumstances: it&amp;rsquo;s just too hard to work with them.&lt;/p&gt;

&lt;p&gt;Since starting this research, I&amp;rsquo;ve run into several new graph problems in my job. I still appreciate analyzing systems as graphs and dread implementing them. But now I know why everybody else dreads them, too. Thank you for reading!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://predr.ag/&#34;&gt;Predrag Gruevski&lt;/a&gt; for research help, &lt;a href=&#34;https://lars.hupel.info/&#34;&gt;Lars Hupel&lt;/a&gt;, &lt;a href=&#34;https://predr.ag/&#34;&gt;Predrag Gruevski&lt;/a&gt;, &lt;a href=&#34;https://www.danluu.com&#34;&gt;Dan Luu&lt;/a&gt;, and &lt;a href=&#34;https://medium.com/@bellmar&#34;&gt;Marianne Bellotti&lt;/a&gt; for feedback, and to all of the people who agreed to do interviews. If you liked this post, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write new essays there every week.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I train companies in formal methods, making software development faster, cheaper, and safer. Learn more &lt;a href=&#34;https://www.hillelwayne.com/consulting/&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&#34;appendix-languages-with-graph-types&#34;&gt;Appendix: Languages with Graph Types&lt;/h2&gt;

&lt;h3 id=&#34;graph-querying-languages&#34;&gt;Graph Querying Languages&lt;/h3&gt;

&lt;p&gt;Graph querying languages (GQLs)&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:GQL&#34;&gt;&lt;a href=&#34;#fn:GQL&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; are to graph databases what SQL is to relational databases. There is no widely-used standard, but two of the most popular are &lt;a href=&#34;https://www.w3.org/TR/sparql11-query/&#34;&gt;SPARQL&lt;/a&gt; for querying &lt;a href=&#34;https://en.wikipedia.org/wiki/Resource_Description_Framework&#34;&gt;RDF triples&lt;/a&gt; and Neo4j&amp;rsquo;s &lt;a href=&#34;https://neo4j.com/product/cypher-graph-query-language/&#34;&gt;cypher&lt;/a&gt;. Ironically, &lt;a href=&#34;https://graphql.org/&#34;&gt;GraphQL&lt;/a&gt; is &lt;a href=&#34;https://graphql.org/faq/#is-graphql-a-database-language-like-sql&#34;&gt;&lt;em&gt;not&lt;/em&gt;&lt;/a&gt; a graph querying language, instead being named for its connection to the &lt;a href=&#34;https://en.wikipedia.org/wiki/Facebook_Graph_Search&#34;&gt;Facebook Graph Search&lt;/a&gt;. I considered graph databases themselves mostly distinct from graphs in programming languages, but their query languages show how graphs could work in a PL.&lt;/p&gt;

&lt;p&gt;The main difference between all GQLs and SQL is that the &amp;ldquo;joins&amp;rdquo; (relationships) are first-class entities. Imagine a dataset of movies and people, where people act in, direct, or produce movies. In SQL you&amp;rsquo;d implement each relationship as a many-to-many tables, which makes it easy to query &amp;ldquo;who acted in movie X&amp;rdquo; but hard to query &amp;ldquo;who had any role in movie Y, and what was that role&amp;rdquo;. In SPARQL relationships are just edges, making the same query easy.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-sparql&#34; data-lang=&#34;sparql&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;PREFIX&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;mv:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;&amp;lt;your_movie_ontology_URL&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;?person&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;?role&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;WHERE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;?person&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;?role&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;mv:&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;casablanca&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cypher has a similar construct. GQLs can also manipulate edges: reverse them, compose them together, take the transitive closure, etc. If we wanted to find all actors with some degree of separation from Kevin Bacon, we could write&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-sparql&#34; data-lang=&#34;sparql&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;PREFIX&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;mv:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;&amp;lt;your_movie_ontology_URL&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;?a&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;WHERE&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;mv:&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;kbacon&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;(:&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;acted_in/&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;^:&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;acted_in&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;?a.&lt;/span&gt;
    &lt;span style=&#34;color: #75715e&#34;&gt;# a/b = join two lookups&lt;/span&gt;
    &lt;span style=&#34;color: #75715e&#34;&gt;# ^a = reverse a&lt;/span&gt;
    &lt;span style=&#34;color: #75715e&#34;&gt;# a+ = transitive closure&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;SPARQL cannot give the length of the path nor do computation &lt;em&gt;along&lt;/em&gt; the path, like collecting the chain of movies linking two actors. GQLs that support this are significantly more complicated.&lt;/p&gt;

&lt;p&gt;My main takeaway from looking at GQLs is that there&amp;rsquo;s a set of useful traversal primitives that a PL with graph support would need to provide. Interestingly, the formal specification language &lt;a href=&#34;https://alloytools.org/&#34;&gt;Alloy&lt;/a&gt; has all of these primitives for its &amp;ldquo;relation&amp;rdquo; datatype. For this reason I find working with a graph representation in Alloy much easier than in a proper programming language. That said, these all work with labeled edges and may not work for other graph representations.&lt;/p&gt;

&lt;h3 id=&#34;mainstream-languages-with-graphs-in-the-standard-library&#34;&gt;Mainstream Languages with Graphs in the Standard Library&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt; added a &lt;a href=&#34;https://docs.python.org/3/library/graphlib.html&#34;&gt;graphlib&lt;/a&gt; in 2020. Based on the discussion &lt;a href=&#34;https://bugs.python.org/issue17005&#34;&gt;here&lt;/a&gt;, it was because topological sorting is a &amp;ldquo;fundamental algorithm&amp;rdquo; and it would be useful for &amp;ldquo;pure Python implementations of MRO [Method Resolution Order] logic&amp;rdquo;. Graphlib has no other methods besides &lt;code&gt;TopologicalSorter&lt;/code&gt;, which only takes graphs represented as node dicts. Unusually, the direction of the node dict is &lt;em&gt;reversed&lt;/em&gt;: the graph &lt;code&gt;a -&amp;gt; b&lt;/code&gt; is represented as &lt;code&gt;{b: [a]}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As of 2023, nothing in &lt;a href=&#34;https://github.com/search?q=repo%3Apython%2Fcpython%20TopologicalSorter&amp;amp;type=code&#34;&gt;CPython uses graphlib&lt;/a&gt; and there are &lt;a href=&#34;https://github.com/search?q=%2F%28from%7Cimport%29+graphlib%2F+language%3Apython+NOT+is%3Afork&amp;amp;type=code&#34;&gt;fewer than 900 files referencing it on Github&lt;/a&gt;. By comparison, another package added in 2020, zoneinfo, appears in over 6,000 files, and the term &lt;code&gt;def topological_sort(&lt;/code&gt; appears in 4,000. I&amp;rsquo;d guess a lot of these are from before 2020, though. Some skimming suggests that all of these custom topological sorts take different graph representations than graphlib, so they wouldn&amp;rsquo;t be convertable regardless. Graph representation matters.&lt;/p&gt;

&lt;p&gt;There are two other languages I found with graph types: &lt;a href=&#34;https://www.erlang.org/doc/man/digraph.html#&#34;&gt;Erlang&lt;/a&gt; and &lt;a href=&#34;https://www.swi-prolog.org/pldoc/man?section=ugraphs&#34;&gt;SWI-Prolog&lt;/a&gt;. I don&amp;rsquo;t know either language and cannot tell when they were added; with Erlang, at least, it was before 2008. I reached out to a person on the Erlang core language committee but did not hear back.&lt;/p&gt;

&lt;h3 id=&#34;graph-languages&#34;&gt;Graph languages&lt;/h3&gt;

&lt;p&gt;Programming languages where &amp;ldquo;everything is a graph&amp;rdquo; in the same way that everything in bash a string and everything in lisp is a list. Some examples include &lt;a href=&#34;https://github.com/UoYCS-plasma/GP2&#34;&gt;GP2&lt;/a&gt; and &lt;a href=&#34;http://jenshweber.github.io/grape/&#34;&gt;Grape&lt;/a&gt;. Based on some correspondence with people in the field, right now this is still highly academic.&lt;/p&gt;

&lt;h3 id=&#34;mathematics-software-languages&#34;&gt;Mathematics Software Languages&lt;/h3&gt;

&lt;p&gt;Mathematica, MATLAB, Maple, etc all have graph libraries of some form or another. I am not paying the thousands of dollars in licensing needed to learn more.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;update-2024-03-18&#34;&gt;Update 2024-03-18&lt;/h3&gt;

&lt;p&gt;I&amp;rsquo;ve collected some of the comments I received on this post &lt;a href=&#34;https://www.hillelwayne.com/comments/graph-types/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:hash-tables&#34;&gt;No, really. Hash tables are &lt;a href=&#34;https://en.wikipedia.org/wiki/Bipartite_graph&#34;&gt;bipartite graphs&lt;/a&gt;. This was used to &lt;a href=&#34;https://dmg.tuwien.ac.at/drmota/cuckoo_hashing_diss_version3.pdf&#34;&gt;prove performance of cuckoo hashing operations&lt;/a&gt;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:hash-tables&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:derivation&#34;&gt;I derived both computations with &lt;a href=&#34;https://github.com/AlDanial/cloc&#34;&gt;cloc&lt;/a&gt; 1.96. I ran cloc in &lt;code&gt;networkx/networkx/algorithms&lt;/code&gt; (56989) and in &lt;code&gt;cpython/Lib&lt;/code&gt; (588167). The whole networkX library is ~90,000 lines of code.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:derivation&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:variations&#34;&gt;You can make this more efficient by keeping the edge list sorted and doing an &lt;code&gt;O(log(|e|))&lt;/code&gt; binary search, at the cost of making edge insertions more expensive.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:variations&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:networkx-representations&#34;&gt;NetworkX has functions to convert graphs &lt;a href=&#34;https://networkx.org/documentation/stable/reference/generated/networkx.linalg.graphmatrix.adjacency_matrix.html#networkx.linalg.graphmatrix.adjacency_matrix&#34;&gt;into other representations&lt;/a&gt; but not for working with those representations directly.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:networkx-representations&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:np&#34;&gt;14 of the 21 &lt;a href=&#34;https://en.wikipedia.org/wiki/Karp%27s_21_NP-complete_problems&#34;&gt;canonical NP-complete problems&lt;/a&gt; are graph problems.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:np&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:GQL&#34;&gt;Not to be confused with the &lt;a href=&#34;https://www.gqlstandards.org/&#34;&gt;GQL&lt;/a&gt; language, a proposed GQL standard that&amp;rsquo;s still under development.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:GQL&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Planner programming blows my mind</title>
        <link>https://www.hillelwayne.com/post/picat/</link>
        <pubDate>Tue, 20 Feb 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/picat/</guid>
        <description>

&lt;p&gt;&lt;a href=&#34;http://picat-lang.org/&#34;&gt;Picat&lt;/a&gt; is a research language intended to combine logic programming, imperative programming, and &lt;a href=&#34;https://www.hillelwayne.com/post/minizinc/&#34;&gt;constraint solving&lt;/a&gt;. I originally learned it to help with vacation scheduling but soon discovered its &lt;code&gt;planner&lt;/code&gt; module, which is one of the most fascinating programming models I&amp;rsquo;ve ever seen.&lt;/p&gt;

&lt;p&gt;First, a brief explanation of &lt;dfn&gt;logic programming&lt;/dfn&gt; (LP). In imperative and functional programming, we take inputs and write algorithms that produce outputs. In LP and constraint solving, we instead provide a set of equations and find assignments that satisfy those relationships. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Arr&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;b&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;],&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt;
  &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(X,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Arr),&lt;/span&gt;
  &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Y,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Arr),&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Y,&lt;/span&gt;
  &lt;span style=&#34;color: #a6e22e&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([X,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Y]).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Non-function identifiers that start with lowercase letters are &amp;ldquo;atoms&amp;rdquo;, or unique tokens. Identifiers that start with uppercase letters are variables. So &lt;code&gt;[a, b, c, a]&lt;/code&gt; is a list of four atoms, while &lt;code&gt;Arr&lt;/code&gt; and &lt;code&gt;X&lt;/code&gt; are variables. So &lt;code&gt;Member(X, Arr)&lt;/code&gt; returns true as you&amp;rsquo;d expect.&lt;/p&gt;

&lt;p&gt;The interesting thing is &lt;code&gt;Member(Y, Arr)&lt;/code&gt;. Y wasn&amp;rsquo;t defined yet! So Picat finds a value for Y that &lt;em&gt;makes&lt;/em&gt; the equation true. Y could be any of &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, or &lt;code&gt;c&lt;/code&gt;. Then the line after that makes it impossible for &lt;code&gt;Y&lt;/code&gt; to be &lt;code&gt;a&lt;/code&gt;, so this prints either &lt;code&gt;ab&lt;/code&gt; or &lt;code&gt;ac&lt;/code&gt;. Picat can even handle expressions like &lt;code&gt;member(a, Z)&lt;/code&gt;, instantiating Z as a list!&lt;/p&gt;

&lt;p&gt;&lt;dfn&gt;Planning&lt;/dfn&gt; pushes this all one step further: instead of finding variable assignments that satisfy equations, we find variable &lt;em&gt;mutations&lt;/em&gt; that reach a certain end state. And this opens up some really cool possibilities.&lt;/p&gt;

&lt;p&gt;To showcase this, we&amp;rsquo;ll use Picat to solve a pathing problem.&lt;/p&gt;

&lt;h2 id=&#34;the-problem&#34;&gt;The problem&lt;/h2&gt;

&lt;p&gt;We place a marker on the grid, starting at the &lt;em&gt;origin&lt;/em&gt; (0, 0), and pick another coordinate as the &lt;em&gt;goal&lt;/em&gt;. At each step we can move one step in any cardinal direction, but cannot go off the boundaries of the grid. The program is successful when the marker is at the goal coordinate. As a small example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+---+
|   |
| G |
|O  |
+---+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One solution would be to move to (1, 0) and then to (1, 1).&lt;/p&gt;

&lt;p&gt;To solve this with planning, we need to provide three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A starting state &lt;code&gt;Start&lt;/code&gt;, which contains both the origin and goal coordinates.&lt;/li&gt;
&lt;li&gt;A set of &lt;dfn&gt;action&lt;/dfn&gt; functions that represent state transitions. In Picat these functions &lt;em&gt;must&lt;/em&gt; all be named &lt;code&gt;action&lt;/code&gt; and take four parameters: a current state, a next state, an action name, and a cost. We&amp;rsquo;ll see that all below.&lt;/li&gt;
&lt;li&gt;A function named &lt;code&gt;final(S)&lt;/code&gt; that determines if S is a final state.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once we define all of these, we can call the builtin &lt;code&gt;best_plan(Start, Plan)&lt;/code&gt; which will assign &lt;code&gt;Plan&lt;/code&gt; to the shortest sequence of steps needed to reach a final state.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:best-plan&#34;&gt;&lt;a href=&#34;#fn:best-plan&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3 id=&#34;our-first-implementation&#34;&gt;Our first implementation&lt;/h3&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;planner&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;util&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #e6db74&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;Origin&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Start&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Origin,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;best_plan&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Start,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan)&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Plan)&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;p&gt;&lt;code&gt;main&lt;/code&gt; is the default entry point into a Picat program. Here we&amp;rsquo;re just setting up the initial state, calling &lt;code&gt;best_plan&lt;/code&gt;, and printing &lt;code&gt;Plan&lt;/code&gt;. &lt;code&gt;{a, b}&lt;/code&gt; is the syntax for a Picat array, which is basically a tuple.&lt;/p&gt;

&lt;p&gt;Every expression in a Picat body must be followed by a comma &lt;em&gt;except&lt;/em&gt; the last clause, which must be followed with a period. This makes moving lines around &lt;em&gt;really annoying&lt;/em&gt;. Writing it in that &amp;ldquo;bullet point&amp;rdquo; style helps a little.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Since &lt;code&gt;final&lt;/code&gt; takes just one argument, we&amp;rsquo;ll need to store both the current position and the goal into said argument. Picat has great pattern matching so we can just write it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;final&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;({Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal})&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Pos&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;p&gt;Without the pattern matching, we&amp;rsquo;d have to write it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;final&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(S)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;S&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Pos&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we write a second &lt;code&gt;final&lt;/code&gt; predicate, the plan succeeds if &lt;em&gt;either&lt;/em&gt; &lt;code&gt;final&lt;/code&gt; returns true.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Finally, we need to define the actions which the planner can take. We only need one action here.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;?=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;From&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{{Fx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fy},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dir&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[{&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}]&lt;/span&gt; 
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;({Dx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dy},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dir)&lt;/span&gt;                    &lt;span style=&#34;color: #75715e&#34;&gt;% (a)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Tx&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fx&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dx&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Ty&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fy&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dy&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Tx,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;                        &lt;span style=&#34;color: #75715e&#34;&gt;% (b)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Ty,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;                        &lt;span style=&#34;color: #75715e&#34;&gt;% (b)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{{Tx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Ty},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;move&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;p&gt;&lt;code&gt;From&lt;/code&gt; is the initial state, &lt;code&gt;To&lt;/code&gt; is the next state, &lt;code&gt;Action&lt;/code&gt; is the name of the action— in this case, &lt;code&gt;move&lt;/code&gt;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:structures&#34;&gt;&lt;a href=&#34;#fn:structures&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; You can store metadata in the action, which we use to store the new coordinates.&lt;/p&gt;

&lt;p&gt;Writing &lt;code&gt;action ?=&amp;gt;&lt;/code&gt; instead of &lt;code&gt;action =&amp;gt;&lt;/code&gt; makes &lt;code&gt;action&lt;/code&gt; backtrackable, which I&amp;rsquo;ll admit I don&amp;rsquo;t &lt;em&gt;fully&lt;/em&gt; understand? I&amp;rsquo;m &lt;em&gt;pretty sure&lt;/em&gt; it means that if &lt;em&gt;this&lt;/em&gt; definition of &lt;code&gt;action&lt;/code&gt; pattern-matches but doesn&amp;rsquo;t lead to a viable plan, then Picat can try &lt;em&gt;other&lt;/em&gt; definitions of action. This&amp;rsquo;ll matter more for later versions.&lt;/p&gt;

&lt;p&gt;As with the introductory example up top, we&amp;rsquo;re using &lt;code&gt;member&lt;/code&gt; to both &lt;em&gt;find&lt;/em&gt; values (on line &lt;code&gt;(a)&lt;/code&gt;) and &lt;em&gt;test values&lt;/em&gt; (on lines &lt;code&gt;(b)&lt;/code&gt;). Picat also has a non-assigning predicate, &lt;code&gt;membchk&lt;/code&gt;, which just does testing. If I wasn&amp;rsquo;t trying to showcase Picat I could instead have use &lt;code&gt;membchk&lt;/code&gt; for the testing part, which cannot assign.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cost&lt;/code&gt; is the &amp;ldquo;cost&amp;rdquo; of the action. &lt;code&gt;best_plan&lt;/code&gt; tries to minimize the total cost. Leaving it at 1 means the cost of a plan is the total number of steps.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:structures&#34;&gt;After writing this I realize I should have instead used a &lt;a href=&#34;http://retina.inf.ufsc.br/picat_guide/#x1-530003.4.3&#34;&gt;structure&lt;/a&gt; for the action, writing it instead as &lt;code&gt;$move(T[1])&lt;/code&gt;. I didn&amp;rsquo;t want to rewrite all of my code though so I&amp;rsquo;m leaving it like this.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:structures&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;And that&amp;rsquo;s it, we&amp;rsquo;re done with the program. Here&amp;rsquo;s the output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; picat planner1.pi

[{move,{1,0}},{move,{2,0}},{move,{2,1}},{move,{2,2}}]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s a little tough to read, so I had Picat output structured data that I could process into a picture.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;main =&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; Origin = {0, 0}
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; , Goal = {2, 2}
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; , Start = {Origin, Goal}
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; , best_plan(Start, Path)
&lt;span style=&#34;color: #f92672&#34;&gt;- , println(Plan)&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , printf(&amp;quot;Origin: %w\n&amp;quot;, Origin)&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , printf(&amp;quot;Goal: %w\n&amp;quot;, Goal)&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , printf(&amp;quot;Bounds: {10, 10}\n&amp;quot;)&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , printf(&amp;quot;Path: &amp;quot;)&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , println(join([to_string(A[2]): A in Plan], &amp;quot;, &amp;quot;))&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I used a &lt;a href=&#34;src/format_path.raku&#34;&gt;Raku script&lt;/a&gt; to visualize it.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:patreon1&#34;&gt;&lt;a href=&#34;#fn:patreon1&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; Here&amp;rsquo;s what we now get:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; raku format_path.raku -bf planner1.pi

+-----+
|     |
|     |
|  G  |
|  •  |
|O••  |
+-----+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To show that the planner can route around an &amp;ldquo;obstacle&amp;rdquo;, I&amp;rsquo;ll add a rule that the state &lt;em&gt;cannot&lt;/em&gt; be a certain value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; , Tx = Fx + Dx
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; , Ty = Fy + Dy
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , {Tx, Ty} != {2, 1}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;pre&gt;&lt;code&gt;+-----+
|     |
|     |
| •G  |
| •   |
|O•   |
+-----+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s comment that out for now, leaving this as our current version of the code:&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Code
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;planner&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;util&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #e6db74&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Origin&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Start&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Origin,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;best_plan&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Start,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan)&lt;/span&gt;
  &lt;span style=&#34;color: #75715e&#34;&gt;% , println(Plan) &lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Origin: %w\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Origin)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Goal: %w\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Bounds: {10, 10}\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Path: &amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;join&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;to_string&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(A[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;])&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan],&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;))&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;final&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(S)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;S&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal},&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Pos&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal.&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;?=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;From&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{{Fx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fy},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dir&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[{&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;({Dx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dy},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dir)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Tx&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fx&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dx&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Ty&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fy&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dy&lt;/span&gt;
  &lt;span style=&#34;color: #75715e&#34;&gt;% , {Tx, Ty} != {2, 1}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Tx,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Ty,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{{Tx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Ty},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;move&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;h3 id=&#34;adding-multiple-goals&#34;&gt;Adding multiple goals&lt;/h3&gt;

&lt;p&gt;Next I&amp;rsquo;ll add multiple goals. In order to succeed, the planner needs to reach every single goal in order. We start with one change to &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;main =&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; Origin = {0, 0}
&lt;span style=&#34;color: #f92672&#34;&gt;- , Goal = {2, 2}&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , Goal = [{2, 2}, {3, 4}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Goal now represents a &amp;ldquo;queue&amp;rdquo; of goals to reach, in order. Then we add a &lt;em&gt;new&lt;/em&gt; action which removes a goal from our queue once we&amp;rsquo;ve reached it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;?=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;From&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[Pos|Rest]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Rest}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;mark&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;From[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;p&gt;&lt;code&gt;[Head|Tail]&lt;/code&gt; splits a list into the first element and the rest. Since &lt;code&gt;Pos&lt;/code&gt; was defined in the line before, &lt;code&gt;Goal = [Pos|Rest]&lt;/code&gt; is &lt;em&gt;only&lt;/em&gt; true if the first goal on the list is equal to &lt;code&gt;Pos&lt;/code&gt;. Then we drop that goal from our new state by declaring the new goal state to just be &lt;code&gt;Rest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(This is where backtracking with &lt;code&gt;?=&amp;gt;&lt;/code&gt; becomes important: if we didn&amp;rsquo;t make the actions backtrackable, Picat would match on the &lt;code&gt;move&lt;/code&gt; first and never &lt;code&gt;mark&lt;/code&gt;.)&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Since we&amp;rsquo;re now destructively removing goals from our list when we reach them, &lt;code&gt;final&lt;/code&gt; needs to be adjusted:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;final({Pos, Goal}) =&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;- Pos = Goal.&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ Goal = [].&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that&amp;rsquo;s it. We didn&amp;rsquo;t even have to update our first action!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+-----+
|   G |
|   • |
|  G• |
|  •  |
|O••  |
+-----+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Code
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;planner&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;util&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #e6db74&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Origin&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}]&lt;/span&gt;
  &lt;span style=&#34;color: #75715e&#34;&gt;%, Goal = [{9, 2}, {0, 4}, {9, 6}, {0, 9}]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Start&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Origin,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;best_plan&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Start,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Origin: %w\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Origin)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Goal: %w\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Bounds: {10, 10}\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Path: &amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;join&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;to_string&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(A[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;])&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan],&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;))&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;final&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;({Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal})&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[].&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;?=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;From&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{{Fx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fy},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dir&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[{&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;({Dx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dy},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dir)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Tx&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fx&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dx&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Ty&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fy&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dy&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Tx,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Ty,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{{Tx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Ty},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;move&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;?=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;From&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[Pos|Rest]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Rest}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;mark&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;From[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;h3 id=&#34;cost-minimization&#34;&gt;Cost minimization&lt;/h3&gt;

&lt;p&gt;Going through the goals in order doesn&amp;rsquo;t always lead to the shortest &lt;em&gt;total&lt;/em&gt; path.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;main =&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; Origin = {0, 0}
&lt;span style=&#34;color: #f92672&#34;&gt;- , Goal = [{2, 2}, {3, 4}]&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , Goal = [{9, 2}, {0, 4}, {9, 6}, {0, 9}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;pre&gt;&lt;code&gt;+----------+
|G         |
|•         |
|•         |
|•••••••••G|
|         •|
|G•••••••••|
|•         |
|•••••••••G|
|         •|
|O•••••••••|
+----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What if we didn&amp;rsquo;t care about the order of the goals and just wanted to find the shortest path? Then we only need to change two lines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;action(From, T, Action, Cost) ?=&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; From = {Pos, Goal}
&lt;span style=&#34;color: #f92672&#34;&gt;- , Goal = [Pos|Rest]&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;- , T = {Pos, Rest}&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , member(Pos, Goal)&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;+ , T = {Pos, delete(Goal, Pos)}&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; , Action = {mark, From[1]}
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; , Cost = 1
&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt; .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now the planner can delete any goal it&amp;rsquo;s passing over regardless of where it is in the &lt;code&gt;Goal&lt;/code&gt; list. So Picat can &amp;ldquo;choose&amp;rdquo; which goal it moves to next so as to minimize the overall path length.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+----------+
|G•••••••••|
|•        •|
|•        •|
|•        G|
|•        •|
|G        •|
|•        •|
|•        G|
|•         |
|O         |
+----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Final code:&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Code
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;planner&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;util&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #e6db74&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Origin&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Start&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Origin,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;best_plan&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Start,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Origin: %w\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Origin)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Goal: %w\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Bounds: {10, 10}\n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Path: &amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;join&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;to_string&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(A[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;])&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan],&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;))&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;final&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;({Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal})&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[].&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;?=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;From&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{{Fx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fy},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dir&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[{&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;}]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;({Dx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dy},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dir)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Tx&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fx&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dx&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Ty&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Fy&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Dy&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Tx,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Ty,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{{Tx,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Ty},&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;move&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;?=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;From&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Pos,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Goal)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{Pos,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;delete&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Goal,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Pos)}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;mark&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;From[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]}&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt; 
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;h3 id=&#34;other-variations&#34;&gt;Other variations&lt;/h3&gt;

&lt;p&gt;Picat supports a lot more variations on planning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;best_plan(S, Limit, Plan)&lt;/code&gt; caps the maximum cost at &lt;code&gt;Limit&lt;/code&gt;— good for failing early.&lt;/li&gt;
&lt;li&gt;For each &lt;code&gt;best_plan&lt;/code&gt;, there&amp;rsquo;s a &lt;code&gt;best_plan_nondet&lt;/code&gt; that finds every possible best plan.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sequence(P, Action)&lt;/code&gt; restricts the possible actions based on the current partial plan, so we can add restrictions like &amp;ldquo;you have to move twice before you turn&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The coolest thing to me is that the planning integrates with all the other Picat features. I whipped up a quick demo that combines planning and constraint solving. The &lt;dfn&gt;partition problem&lt;/dfn&gt; is an NP-complete problem where you partition a list of numbers into two equal sums. This program takes a list of numbers and finds the sublist with the largest possible equal partitioning:&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:patreon2&#34;&gt;&lt;a href=&#34;#fn:patreon2&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Code
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-prolog&#34; data-lang=&#34;prolog&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;% got help from http://www.hakank.org/picat/set_partition.pi &lt;/span&gt;
&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;planner&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;util&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;color: #e6db74&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;cp&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #e6db74&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Numbers&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;122&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;77&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;86&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;59&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;47&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;154&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;141&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;172&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;49&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;62&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;99&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;109&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;977&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;final&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;then&lt;/span&gt;
      &lt;span style=&#34;color: #a6e22e&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Input already has a partition!&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;explain_solution&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers)&lt;/span&gt;
    &lt;span style=&#34;color: #e6db74&#34;&gt;else&lt;/span&gt;
        &lt;span style=&#34;color: #a6e22e&#34;&gt;best_plan&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan)&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Removed: %w%n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,[R&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #960050; background-color: #1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;remove&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(R,&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan])&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #960050; background-color: #1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;remove&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Last,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;FinalState)&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Plan[Plan.&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Final: %w%n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;FinalState)&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;explain_solution&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(FinalState)&lt;/span&gt;
    &lt;span style=&#34;color: #e6db74&#34;&gt;end&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;final&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;get_solutions&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers)&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[].&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;get_solutions&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers)&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;S&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;new_list&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers.&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0..1&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;X[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;#=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;% symmetry breaking&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;sum&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;#=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;sum&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([Numbers[I]&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;X[I]&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;I&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.Numbers.&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;])&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;S&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;solve_all&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([&lt;/span&gt;&lt;span style=&#34;color: #960050; background-color: #1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;limit&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)],&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;X)&lt;/span&gt; 
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
  
&lt;span style=&#34;color: #a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
   &lt;span style=&#34;color: #a6e22e&#34;&gt;member&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Element,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;From)&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;delete&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(From,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Element)&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Action&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #960050; background-color: #1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;remove&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Element,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;To)&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Cost&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Element&lt;/span&gt;
   &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;explain_solution&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers)&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;[Sol]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;get_solutions&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Numbers)&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Left&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;[Numbers[I]&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;I&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.Numbers.&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Sol[I]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Right&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[Numbers[I]&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;I&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;.Numbers.&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Sol[I]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;%s=%d%n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;join&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;to_string&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(N)&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;N&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Left],&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;+&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;sum&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Left))&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;printf&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;%s=%d%n&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;join&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;([&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;to_string&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(N)&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;N&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Right],&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;+&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;sum&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Right))&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;pre&gt;&lt;code&gt;Removed: [5,17]
Final: [32,122,77,86,59,47,154,141,172,49,62,99,109,30,977]
32+99+977=1108
122+77+86+59+47+154+141+172+49+62+109+30=1108
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is all so mindblowing to me. It&amp;rsquo;s almost like a metaconstraint solver, allowing me to express constraints &lt;em&gt;on the valid constraints&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&#34;should-i-use-picat&#34;&gt;Should I use Picat?&lt;/h2&gt;

&lt;p&gt;Depends?&lt;/p&gt;

&lt;p&gt;I would not recommend using Picat in production. It&amp;rsquo;s a research language and doesn&amp;rsquo;t have a lot of affordances, like good documentation or clear error messages. Here&amp;rsquo;s what you get when there&amp;rsquo;s no plan that solves the problem:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;*** error(failed,main/0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But hey it runs on Windows, which is better than 99% of research languages.&lt;/p&gt;

&lt;p&gt;Picat seems more useful as a &amp;ldquo;toolkit&amp;rdquo; language, one you learn to solve a specific class of computational problems, and where you&amp;rsquo;re not expecting to maintain or share the code afterwards. But it&amp;rsquo;s really good in that niche! There&amp;rsquo;s a handful of problems I struggled to do with regular programming languages and constraint solvers. Picat solves a lot of them quite elegantly.&lt;/p&gt;

&lt;h2 id=&#34;appendix-other-planning-languages&#34;&gt;Appendix: Other planning languages&lt;/h2&gt;

&lt;p&gt;While originally pioneered for robotics and AI, &amp;ldquo;planning&amp;rdquo; is most-often used for video game AIs, where it&amp;rsquo;s called &amp;ldquo;Goal Oriented Action Planning&amp;rdquo; (GOAP).  Usually it&amp;rsquo;s built as libraries on top of other languages, or implemented as a &lt;a href=&#34;https://artint.info/3e/html/ArtInt3e.Ch3.html&#34;&gt;custom search strategy&lt;/a&gt;. You can read more about GOAP &lt;a href=&#34;https://web.archive.org/web/20140613121607/http://alumni.media.mit.edu/~jorkin/goap.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is also &lt;a href=&#34;https://planning.wiki/guide/whatis/pddl&#34;&gt;PDDL&lt;/a&gt;, a planning description language that independent planners take as input, in the same way that DIMACS is a description format for &lt;a href=&#34;https://www.hillelwayne.com/post/sudoku/&#34;&gt;SAT&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://predr.ag/&#34;&gt;Predrag Gruevski&lt;/a&gt; for feedback. I first shared &lt;a href=&#34;https://buttondown.email/hillelwayne/archive/picat-is-my-favorite-new-toolbox-language/&#34;&gt;my thoughts on Picat&lt;/a&gt; on &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;my newsletter&lt;/a&gt;. I write new newsletter posts weekly.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:best-plan&#34;&gt;If you want just &lt;em&gt;any&lt;/em&gt; plan, regardless of how long it is, you can call &lt;code&gt;plan(Start, Plan)&lt;/code&gt; instead.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:best-plan&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:patreon1&#34;&gt;The commented version of the formatter was originally up on &lt;a href=&#34;https://www.patreon.com/posts/98616250&#34;&gt;my Patreon&lt;/a&gt;. You can now see it &lt;a href=&#34;https://gist.github.com/hwayne/94ca3b23078234ca7e803c061b9338f3#file-format_picat-raku&#34;&gt;here&lt;/a&gt;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:patreon1&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:patreon2&#34;&gt;&amp;ldquo;Find the most elements you can remove &lt;em&gt;without&lt;/em&gt; getting you a valid partition&amp;rdquo; is a little more convoluted, but you can see it &lt;a href=&#34;https://gist.github.com/hwayne/94ca3b23078234ca7e803c061b9338f3#file-partition_planner-pi&#34;&gt;here&lt;/a&gt;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:patreon2&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>An RNG that runs in your brain</title>
        <link>https://www.hillelwayne.com/post/randomness/</link>
        <pubDate>Mon, 22 Jan 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/randomness/</guid>
        <description>

&lt;p&gt;Humans are notoriously bad at coming up with random numbers. I wanted to be able to quickly generate &amp;ldquo;random enough&amp;rdquo; numbers. I&amp;rsquo;m not looking for anything that great, I just want to be able to come up with the random digits in half a minute. Some looking around brought me to &lt;a href=&#34;https://groups.google.com/g/sci.math/c/6BIYd0cafQo/m/Ucipn_5T_TMJ?hl=en&#34;&gt;an old usenet post&lt;/a&gt; by George Marsaglia:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Choose a 2-digit number, say 23, your &amp;ldquo;seed&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Form a new 2-digit number:
the 10&amp;rsquo;s digit plus 6 times the units digit.&lt;/p&gt;

&lt;p&gt;The example sequence is
23 &amp;ndash;&amp;gt; 20 &amp;ndash;&amp;gt; 02 &amp;ndash;&amp;gt; 12 &amp;ndash;&amp;gt; 13 &amp;ndash;&amp;gt; 19 &amp;ndash;&amp;gt; 55 &amp;ndash;&amp;gt; 35 &amp;ndash;&amp;gt; &amp;hellip;&lt;/p&gt;

&lt;p&gt;and its period is the order of the multiplier, 6, in the group of
residues relatively prime to the modulus, 10. (59 in this case).&lt;/p&gt;

&lt;p&gt;The &amp;ldquo;random digits&amp;rdquo; are the units digits of the 2-digit numbers,
ie, 3,0,2,2,3,9,5,&amp;hellip; the sequence mod 10.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Marsaglia is most famous for the &lt;a href=&#34;https://en.wikipedia.org/wiki/Diehard_tests&#34;&gt;diehard suite&lt;/a&gt; of RNG tests, so he knows his stuff.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:RNG&#34;&gt;&lt;a href=&#34;#fn:RNG&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I&amp;rsquo;m curious why this works and why he chose 6.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re going to use &lt;a href=&#34;https://www.raku.org&#34;&gt;Raku&lt;/a&gt;, the &lt;a href=&#34;https://buttondown.email/hillelwayne/archive/raku-a-language-for-gremlins/&#34;&gt;language for gremlins&lt;/a&gt;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:gremlins&#34;&gt;&lt;a href=&#34;#fn:gremlins&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; I&amp;rsquo;ll be explaining all the weird features I use in dropdowns in case you&amp;rsquo;re a bit of a gremlin, too.&lt;/p&gt;

&lt;h1 id=&#34;intro&#34;&gt;Intro&lt;/h1&gt;

&lt;p&gt;The sequence is periodic, meaning that if we iteratively apply it we&amp;rsquo;ll eventually get the same element. Let&amp;rsquo;s start with a function (&amp;ldquo;subroutine&amp;rdquo;) that produces the whole sequence:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;next-rng&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$start&lt;/span&gt;, &lt;span style=&#34;color: #f8f8f2&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$unitmult&lt;/span&gt; = &lt;span style=&#34;color: #ae81ff&#34;&gt;6&lt;/span&gt;, --&amp;gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;List&lt;/span&gt;) {
    &lt;span style=&#34;color: #66d9ef&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;@out&lt;/span&gt;;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$next&lt;/span&gt; = &lt;span style=&#34;color: #f8f8f2&#34;&gt;$start&lt;/span&gt;;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;repeat&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$next&lt;/span&gt; !(&lt;span style=&#34;color: #f8f8f2&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color: #f8f8f2&#34;&gt;@out&lt;/span&gt; {
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;@out&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;append&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;$next&lt;/span&gt;);
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;$next&lt;/span&gt; = &lt;span style=&#34;color: #f8f8f2&#34;&gt;sum&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;$next&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;polymod&lt;/span&gt;(&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;) &lt;span style=&#34;color: #f92672&#34;&gt;Z&lt;/span&gt;* &lt;span style=&#34;color: #f8f8f2&#34;&gt;$unitmult&lt;/span&gt;,&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;);
    };
    &lt;span style=&#34;color: #66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;@out&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;p&gt;Raku is an extremely weird language but I&amp;rsquo;ll keep it as straightforward as I can.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; are &lt;a href=&#34;https://docs.raku.org/language/variables#Sigils&#34;&gt;sigils&lt;/a&gt; for &amp;ldquo;positional&amp;rdquo; (listlike) and &amp;ldquo;scalar&amp;rdquo; respectively. Defining a positional without assigning anything defaults it to the empty array.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(elem)&lt;/code&gt; checks for membership, and &lt;code&gt;!&lt;/code&gt; can be applied to negate any infix operator. &lt;code&gt;(elem)&lt;/code&gt; is the ASCII version— Raku also accepts ∈.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.raku.org/type/Int#method_polymod&#34;&gt;polymod&lt;/a&gt; splits a number into a remainder and dividend, ie &lt;code&gt;346.polymod(10) = (6 34)&lt;/code&gt;. It takes multiple parameters, so you can do things like &lt;code&gt;num.polymod(60, 60, 24)&lt;/code&gt; to get hours-minutes-seconds.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.raku.org/language/operators#Zip_metaoperator&#34;&gt;Z&lt;/a&gt; is the &amp;ldquo;zip&amp;rdquo; metaoperator, applying a infix op elementwise between two lists. &lt;code&gt;(4, 6) Z* (6, 1)&lt;/code&gt; = &lt;code&gt;(4*6, 6*1)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Once we have a sequence we can print it with the &lt;code&gt;put&lt;/code&gt; or &lt;code&gt;say&lt;/code&gt; commands, which have &lt;a href=&#34;https://docs.raku.org/language/faq#How_and_why_do_say,_put_and_print_differ%3F&#34;&gt;subtly different behaviors&lt;/a&gt; I&amp;rsquo;m not going to get into.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;next-rng&lt;/span&gt;(&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;pre&gt;&lt;code&gt;01 06 36 39 57 47 46 40 04 24 26 38 51 11 07 42 16 
37 45 34 27 44 28 50 05 30 03 18 49 58 53 23 20 02 
12 13 19 55 35 33 21 08 48 52 17 43 22 14 25 32 15 
31 09 54 29 56 41 10 01
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remember, the random numbers are the &lt;em&gt;last&lt;/em&gt; digit. So the RNG goes 1 -&amp;gt; 6 -&amp;gt; 6 -&amp;gt; 9 -&amp;gt; 7 -&amp;gt; 7 -&amp;gt; &amp;hellip;&lt;/p&gt;

&lt;h2 id=&#34;investigating-properties&#34;&gt;Investigating Properties&lt;/h2&gt;

&lt;p&gt;If the RNG is uniform then each digit should appear in the sequence the same number of times. We can check this by casting the last digits to a multiset, or &amp;ldquo;bag&amp;rdquo;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;say bag(next-rng(1) &amp;lt;&amp;lt;%&amp;gt;&amp;gt; 10);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;op&amp;gt;&amp;gt;&lt;/code&gt; is the &lt;a href=&#34;https://docs.raku.org/language/operators#Hyper_operators&#34;&gt;hyper metaoperator&lt;/a&gt; and &amp;ldquo;maps&amp;rdquo; the inside operator across both lists, &lt;em&gt;recursively going into list of lists too&lt;/em&gt;. IE &lt;code&gt;((1, 2), 3) &amp;lt;&amp;lt;+&amp;gt;&amp;gt; 10&lt;/code&gt; is &lt;code&gt;((11, 12), 13)&lt;/code&gt;! Hyperoperators have a lot of other weird properties that make them both useful and confusing.&lt;/li&gt;
&lt;li&gt;Bags count the number of elements in something. &lt;code&gt;bag((4, 5, 4)){4} = 2&lt;/code&gt;. Confusingly though they can only contain scalars, not arrays or lists or the like.&lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;pre&gt;&lt;code&gt;Bag(0(5) 1(6) 2(6) 3(6) 4(6) 5(6) 6(6) 7(6) 8(6) 9(5))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That seems to be a uniform-enough distribution, though I&amp;rsquo;m a bit less likely to get a 0 or a 9.&lt;/p&gt;

&lt;p&gt;My next idea comes from the diehard tests. From &lt;a href=&#34;https://en.wikipedia.org/wiki/Diehard_tests#Test_overview&#34;&gt;the wiki&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Overlapping permutations&lt;/strong&gt;: Analyze sequences of five consecutive random numbers. The 120 possible orderings should occur with statistically equal probability.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are only 54 5-number sequences in the dataset, so I&amp;rsquo;ll instead apply this to 2-number &amp;ldquo;transitions&amp;rdquo;. I&amp;rsquo;ll do this by outputting a 10-by-10 grid where the (i, j)th index (from 0) is the number of transitions from last-digit &lt;code&gt;i&lt;/code&gt; to &lt;code&gt;j&lt;/code&gt;. For example, the sequence includes the transition &lt;code&gt;28 -&amp;gt; 50&lt;/code&gt;, and no other transitions of form &lt;code&gt;X8 -&amp;gt; Y0&lt;/code&gt;, so cell (8, 0) should be a &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;successions-grid&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;@orbit&lt;/span&gt;) {
  &lt;span style=&#34;color: #66d9ef&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;@pairs&lt;/span&gt; = (|&lt;span style=&#34;color: #f8f8f2&#34;&gt;@orbit&lt;/span&gt; , &lt;span style=&#34;color: #f8f8f2&#34;&gt;@orbit&lt;/span&gt;[&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;]).&lt;span style=&#34;color: #f8f8f2&#34;&gt;map&lt;/span&gt;(* % &lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;rotor&lt;/span&gt;(&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt; =&amp;gt; -&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;);
  &lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt; ^&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt; -&amp;gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$x&lt;/span&gt; {&lt;span style=&#34;color: #f8f8f2&#34;&gt;put&lt;/span&gt; (&lt;span style=&#34;color: #f8f8f2&#34;&gt;$x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;X&lt;/span&gt; ^&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;map&lt;/span&gt;({&lt;span style=&#34;color: #f8f8f2&#34;&gt;@pairs&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;grep&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;$_&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;elems&lt;/span&gt;})}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;code&gt;| @f, $x&lt;/code&gt; concats &lt;code&gt;$x&lt;/code&gt; directly onto &lt;code&gt;@f&lt;/code&gt;. Without the &lt;code&gt;|&lt;/code&gt; it&amp;rsquo;d be a two-element list instead.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;*&lt;/code&gt; in &lt;code&gt;`* % 10`&lt;/code&gt; is a &lt;a href=&#34;https://docs.raku.org/type/Whatever&#34;&gt;whatever&lt;/a&gt;, a weird little operator that does a lot of things in a lot of different contexts, but usually in this case lifts the expression into a closure. &lt;em&gt;Usually&lt;/em&gt;. It&amp;rsquo;s the same as writing &lt;code&gt;map({$_ % 10})&lt;/code&gt;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:map-whatever&#34;&gt;&lt;a href=&#34;#fn:map-whatever&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.raku.org/type/List#routine_rotor&#34;&gt;rotor&lt;/a&gt;&lt;code&gt;(2 =&amp;gt; -1)&lt;/code&gt; gets two elements, then goes one element back, then gets two more, etc. &lt;code&gt;[1, 2, 3, 4].rotor(2 =&amp;gt; -1)&lt;/code&gt; is &lt;code&gt;[(1, 2), (2, 3), (3, 4)]&lt;/code&gt;. You could also do &lt;code&gt;rotor(2)&lt;/code&gt; to get &lt;code&gt;[(1, 2), (3, 4)]&lt;/code&gt;, or &lt;code&gt;rotor(1 =&amp;gt; 1)&lt;/code&gt; to get &lt;code&gt;[1, 3]&lt;/code&gt;. Rotor is really cool.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;^10&lt;/code&gt; is just &lt;code&gt;0..9&lt;/code&gt;. For once something easy!&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.raku.org/language/operators#Cross_metaoperators&#34;&gt;X&lt;/a&gt; is the cross product &lt;a href=&#34;https://docs.raku.org/language/operators#Metaoperators&#34;&gt;metaoperator&lt;/a&gt;. So if &lt;code&gt;$x = 2&lt;/code&gt;, then &lt;code&gt;$x X ^4&lt;/code&gt; would be &lt;code&gt;((2 0), (2 1), (2 2), (2 3))&lt;/code&gt;. And yes, the operator can get much, much stranger.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grep(foo)&lt;/code&gt; returns a list of all elements &lt;a href=&#34;https://docs.raku.org/language/operators#infix_~~&#34;&gt;smart-matching&lt;/a&gt; &lt;code&gt;foo&lt;/code&gt;, and &lt;code&gt;.elems&lt;/code&gt; is the number of elements in a list. So &lt;code&gt;@pairs.grep($_).elems&lt;/code&gt; is the number of elements of the list matching &lt;code&gt;$_&lt;/code&gt;. This took me &lt;em&gt;way&lt;/em&gt; too long to figure out&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:map-whatever&#34;&gt;Actually &lt;code&gt;-&amp;gt; $x {$x % 10}&lt;/code&gt; but close enough
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:map-whatever&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;pre&gt;&lt;code&gt;&amp;gt; successions-grid(next-rng(1, 6))

0 1 1 1 1 1 0 0 0 0
1 1 0 0 0 0 1 1 1 1
0 0 1 1 1 1 1 1 0 0
1 1 1 1 0 0 0 0 1 1
0 0 0 0 1 1 1 1 1 1
1 1 1 1 1 1 0 0 0 0
1 1 0 0 0 0 1 1 1 1
0 0 1 1 1 1 1 1 0 0
1 1 1 1 0 0 0 0 1 1
0 0 0 0 1 1 1 1 1 0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see from this table that some transitions are impossible. If I generate a 0, I can&amp;rsquo;t get a 6 right after. Obviously not a great RNG, but my expectations were pretty low anyway.&lt;/p&gt;

&lt;h2 id=&#34;why-6&#34;&gt;Why 6?&lt;/h2&gt;

&lt;p&gt;What if instead of multiplying the last digit by 6, I multiply by 4?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; say next-rng(1, 4);
01 04 16 25 22 10 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I dunno, I kinda like an RNG that never gives me 3. The distinct sequences are called &lt;dfn&gt;orbits&lt;/dfn&gt; and their lengths are called &lt;dfn&gt;periods&lt;/dfn&gt;. Let&amp;rsquo;s see all the possible orbits we can get by using 4 as the multiplier:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;orbits-for-mod&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;$mult&lt;/span&gt;, &lt;span style=&#34;color: #f8f8f2&#34;&gt;$top&lt;/span&gt; = &lt;span style=&#34;color: #ae81ff&#34;&gt;20&lt;/span&gt;) {
  &lt;span style=&#34;color: #66d9ef&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;&amp;amp;f&lt;/span&gt; = &lt;span style=&#34;color: #f8f8f2&#34;&gt;&amp;amp;next-rng&lt;/span&gt;.&lt;span style=&#34;color: #f8f8f2&#34;&gt;assuming&lt;/span&gt;(*, &lt;span style=&#34;color: #f8f8f2&#34;&gt;$mult&lt;/span&gt;);
  (&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;..&lt;span style=&#34;color: #f8f8f2&#34;&gt;$top&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;map&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;&amp;amp;f&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;unique&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;as&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;&amp;amp;set&lt;/span&gt;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; is the &lt;a href=&#34;https://docs.raku.org/language/variables#Sigils&#34;&gt;sigil&lt;/a&gt; for &amp;ldquo;callable&amp;rdquo; or &lt;del&gt;function&lt;/del&gt; subroutine. The &lt;code&gt;.assuming&lt;/code&gt; method does a partial function application, and passing a &lt;code&gt;*&lt;/code&gt; makes it partially apply the &lt;em&gt;second&lt;/em&gt; parameter.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:assuming&#34;&gt;&lt;a href=&#34;#fn:assuming&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The &lt;code&gt;map&lt;/code&gt; returns a sequence of lists, which we pass to &lt;a href=&#34;https://docs.raku.org/type/independent-routines#routine_unique&#34;&gt;&lt;code&gt;unique&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;as =&amp;gt; &amp;amp;set&lt;/code&gt; converts every sequence in the &lt;code&gt;map&lt;/code&gt; to a set and compares &lt;em&gt;those&lt;/em&gt; for uniqueness, instead of the original lists. But the final result uses the elements prior to conversion.&lt;/p&gt;

&lt;p&gt;If that&amp;rsquo;s confusing, a simpler example is that &lt;code&gt;[-1, 1].unique(as =&amp;gt; &amp;amp;abs)&lt;/code&gt; returns &lt;code&gt;[-1]&lt;/code&gt;, while &lt;code&gt;[1, -1].unique(as =&amp;gt; &amp;amp;abs)&lt;/code&gt; is &lt;code&gt;[1]&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:assuming&#34;&gt;&lt;a href=&#34;https://www.codesections.com/&#34;&gt;Daniel Sockwell&lt;/a&gt; (aka codesections) kindly agreed to read a first draft of this post, and he told me about &lt;code&gt;assume&lt;/code&gt;. Thanks Daniel!
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:assuming&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;pre&gt;&lt;code&gt;&amp;gt; say orbits-for-mod(4, 38).map(*.gist).join(&amp;quot;\n&amp;quot;);
[1 4 16 25 22 10]
[2 8 32 11 5 20]
[3 12 9 36 27 30]
[6 24 18 33 15 21]
[7 28 34 19 37 31]
[13]
[14 17 29 38 35 23]
[26]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;p&gt;Quoting &lt;a href=&#34;https://www.codesections.com/&#34;&gt;Daniel Sockwell&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;.map(*.gist).join(&amp;quot;\n&amp;quot;)&lt;/code&gt; is just there to prettify the output. &lt;code&gt;cycles-for-mod&lt;/code&gt; returns a &lt;code&gt;Seq&lt;/code&gt; of &lt;code&gt;Array&lt;/code&gt;s; mapping over each &lt;code&gt;Array&lt;/code&gt; with &lt;code&gt;.gist&lt;/code&gt; converts it into a string surrounded by square brackets and &lt;code&gt;.join(&amp;quot;\n&amp;quot;)&lt;/code&gt; puts a newline between each of these strings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;If you picked 13 as your starting value, your random digits would be 3, 3, 3, 3, 3, 3.&lt;/p&gt;

&lt;p&gt;&lt;center&gt;
&lt;figure&gt;
  &lt;img src=&#34;img/random_number.png&#34; title=&#34;That xkcd where `getrandomnumber` always returns 4&#34;&gt;
  &lt;figcaption&gt;Preempting 50,000 emails&lt;a href=&#34;https://xkcd.com/221/&#34;&gt;(source)&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;&lt;/p&gt;

&lt;p&gt;For obvious reasons, 4 should never be our multiplier. In fact for a multiplier to give a &amp;ldquo;good&amp;rdquo; RNG, it needs to have exactly one orbit. As we&amp;rsquo;ll see later, this guarantees a(n almost) uniform distribution.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&amp;gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;say&lt;/span&gt; (&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;..&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;30&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;grep&lt;/span&gt;(*.&lt;span style=&#34;color: #f8f8f2&#34;&gt;&amp;amp;orbits-for-mod&lt;/span&gt; == &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;)
(&lt;span style=&#34;color: #ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;11&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;15&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;18&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;23&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;27&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;ul&gt;
&lt;li&gt;&lt;code&gt;.&amp;amp;&lt;/code&gt; applies a top-level routine as a method. &lt;code&gt;grep(*.&amp;amp;f)&lt;/code&gt; is the equivalent of &lt;code&gt;grep({f($_)})&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;orbits-for-mod&lt;/code&gt; returns a list. &lt;code&gt;==&lt;/code&gt; coerces both inputs to numbers, and coercing a list to a number returns the number of elements. So we&amp;rsquo;re testing if the returned list has one element, ie there&amp;rsquo;s exactly one orbit. (If you don&amp;rsquo;t want to compare without coercion, use either &lt;a href=&#34;https://docs.raku.org/language/operators#infix_===,_infix_%E2%A9%B6&#34;&gt;===&lt;/a&gt; or &lt;a href=&#34;https://docs.raku.org/language/operators#infix_eqv&#34;&gt;eqv&lt;/a&gt;.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way of doing things is pretty slow and also only looks for orbits that &lt;em&gt;start with&lt;/em&gt; a number up to 20. So it would miss the &lt;code&gt;26 -&amp;gt; 26&lt;/code&gt; orbit for &lt;code&gt;x=4&lt;/code&gt;. We&amp;rsquo;ll fix both of these issues later.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;So some &amp;ldquo;good&amp;rdquo; choices for &lt;code&gt;n&lt;/code&gt; are 6, 11, and 18.&lt;/p&gt;

&lt;p&gt;Note that if you end up with a three digit number, you treat the first two digits as a single number. For &lt;code&gt;n=11&lt;/code&gt;, &lt;code&gt;162&lt;/code&gt; leads to &lt;code&gt;16 + 22&lt;/code&gt;, not &lt;code&gt;6 + 22&lt;/code&gt; (or &lt;code&gt;6 + 1 + 22&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&#34;why-does-this-work&#34;&gt;Why does this work?&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s a part of the explanation that really confused me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;and its period is the order of the multiplier, 6, in the group of
residues relatively prime to the modulus, 10. (59 in this case).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After talking with some friends and a lot of reading Wiki articles, it started making more sense. I&amp;rsquo;m mentally computing a &amp;ldquo;&lt;a href=&#34;https://en.wikipedia.org/wiki/Multiply-with-carry_pseudorandom_number_generator&#34;&gt;multiply with carry&lt;/a&gt;&amp;rdquo; RNG with constants &lt;code&gt;a=x&lt;/code&gt; and &lt;code&gt;c=10&lt;/code&gt;. This choice has a cool property: if &lt;code&gt;MWC(x) = y&lt;/code&gt;, then &lt;code&gt;10y mod (10mult-1) = x&lt;/code&gt;!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MWC:    01 -&amp;gt; 06 -&amp;gt; 36 -&amp;gt; ... -&amp;gt; 41 -&amp;gt; 10 -&amp;gt; 01
10y%59: 01 -&amp;gt; 10 -&amp;gt; 41 -&amp;gt; ... -&amp;gt; 36 -&amp;gt; 06 -&amp;gt; 01
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s pretty neat! It&amp;rsquo;s easier for me to mathematically reason about &lt;code&gt;10y mod 59&lt;/code&gt; than &amp;ldquo;multiply the last digit by six and add the first digit&amp;rdquo;. For example, it&amp;rsquo;s clear why the RNG generates 0 and 9 slightly less often than the other digits: no matter which multiplier we pick, the generated sequence will go from 1 to 10n-2, &amp;ldquo;leaving out&amp;rdquo; 10n-1 (which ends with 9) and 10n (ends with 0).&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Multiply and modulo&amp;rdquo; is also known as the &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Lehmer_random_number_generator&#34;&gt;Lehmer RNG&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;finding-better-rngs&#34;&gt;Finding better RNGs&lt;/h2&gt;

&lt;p&gt;So what other numbers work? We already know that a good multiplier will produce only one orbit, and I showed some code above for calculating that. Unfortunately, it&amp;rsquo;s an O(n²) worst-case algorithm.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:big-o&#34;&gt;&lt;a href=&#34;#fn:big-o&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; Thinking about the MWC algorithm as &amp;ldquo;Lehmer in reverse&amp;rdquo; gives us a better method: if &lt;code&gt;n&lt;/code&gt; is a good multiplier, then the period of the orbit starting from 1 should be &lt;code&gt;10n-2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Lehmer approach also gives us a faster way of computing the orbit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;oneorbit&lt;/span&gt;(\&lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt;) {
  &lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;, * *&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;% (&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; - &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;) … &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Explanation
  &lt;/summary&gt;
  &lt;p&gt;&lt;center&gt;
&lt;figure&gt;
  &lt;img src=&#34;img/fault-tolerance.png&#34; title=&#34;GREMLINS&#34;&gt;
  &lt;figcaption&gt;&lt;a href=&#34;http://howfuckedismydatabase.com/nosql/&#34;&gt;(source)&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Real Explanation
  &lt;/summary&gt;
  &lt;ul&gt;
&lt;li&gt;Writing &lt;code&gt;\x&lt;/code&gt; instead of &lt;code&gt;$x&lt;/code&gt; as a param lets use use &lt;code&gt;x&lt;/code&gt; instead of &lt;code&gt;$x&lt;/code&gt; in the body.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;...&lt;/code&gt; is the &lt;a href=&#34;https://docs.raku.org/language/operators#infix_...&#34;&gt;sequence operator&lt;/a&gt;. It can do a &lt;em&gt;lot&lt;/em&gt; of different things, but the important one for us is that if you write &lt;code&gt;10, &amp;amp;f … 1&lt;/code&gt;, it will start with 10 and then keep applying &lt;code&gt;&amp;amp;f&lt;/code&gt; until it eventually generates &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;* *10%[etc]&lt;/code&gt;, the first &lt;code&gt;*&lt;/code&gt; is a Whatever and the second &lt;code&gt;*&lt;/code&gt; is regular multiply. This then lifts into the function &lt;code&gt;-&amp;gt; $a {$a * 10 % (10*x - 1)}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This actually produces the orbit in reverse but we&amp;rsquo;re only interested in the period so nbd.&lt;/p&gt;

&lt;p&gt;&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Then we check the period using the same &amp;ldquo;&lt;code&gt;==&lt;/code&gt; coerces lists to lengths&amp;rdquo; trick as before.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-raku&#34; data-lang=&#34;raku&#34;&gt;&lt;span&gt;&lt;/span&gt;&amp;gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;say&lt;/span&gt; (&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;..&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;100&lt;/span&gt;).&lt;span style=&#34;color: #f8f8f2&#34;&gt;grep&lt;/span&gt;({&lt;span style=&#34;color: #f8f8f2&#34;&gt;oneorbit&lt;/span&gt;(&lt;span style=&#34;color: #f8f8f2&#34;&gt;$_&lt;/span&gt;) == &lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;*&lt;span style=&#34;color: #f8f8f2&#34;&gt;$_-2&lt;/span&gt;});

(&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;11&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;15&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;18&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;23&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;27&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;38&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;39&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;42&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;50&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;51&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;62&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;66&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;71&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I can see why Marsaglia chose 6: most programmers know their 6 times-table and it never returns a 3-digit number, so the addition step is real easy. The orbit has only 58 numbers and you won&amp;rsquo;t get some digit sequences, but if you need to pull out a few random digits quickly it&amp;rsquo;s totally fine.&lt;/p&gt;

&lt;p&gt;If you want more randomness, I see a couple of candidates. 50 has a period of 498 and is incredibly easy to compute. If the final digit is even then you don&amp;rsquo;t need to do any carries: &lt;strong&gt;23&lt;/strong&gt;8 -&amp;gt; 4&lt;strong&gt;23&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;That said, the 50-sequence doesn&amp;rsquo;t &lt;em&gt;seem&lt;/em&gt; as random as other sequences. There&amp;rsquo;s a point where it generates 9 even numbers followed by 8 odd ones. Don&amp;rsquo;t use it to simulate coin flips.&lt;/p&gt;

&lt;p&gt;The last interesting number is 18. It has a respectable period of 178 and has every possible digit transition:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; successions-grid(next-rng(1, 18))

1 2 2 2 2 2 2 2 1 1
2 2 2 2 2 2 1 1 2 2
2 2 2 2 1 1 2 2 2 2
2 2 1 1 2 2 2 2 2 2
1 1 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 1 1
2 2 2 2 2 2 1 1 2 2
2 2 2 2 1 1 2 2 2 2
2 2 1 1 2 2 2 2 2 2
1 1 2 2 2 2 2 2 2 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The downside is that you have to learn the 18 times-table. This isn&amp;rsquo;t too bad: I internalized it with maybe 10 minutes of practice. I&amp;rsquo;m still not &lt;em&gt;great&lt;/em&gt; at doing the whole MWC step but I can consistently produce another random digit every five seconds or so. That&amp;rsquo;s good enough for me.&lt;/p&gt;

&lt;p&gt;You can see the Raku code I used to research this &lt;a href=&#34;./src/rng.raku&#34;&gt;here&lt;/a&gt;. It&amp;rsquo;s set up &lt;a href=&#34;https://buttondown.email/hillelwayne/archive/raku-is-surprisingly-good-for-clis/&#34;&gt;as a CLI&lt;/a&gt; so you can use it in a few different ways; see the file for more info.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://www.codesections.com/&#34;&gt;Codesections&lt;/a&gt; for feedback and &lt;a href=&#34;https://twitter.com/wilton_quinn&#34;&gt;Quinn Wilton&lt;/a&gt; and &lt;a href=&#34;https://jeremykun.com/&#34;&gt;Jeremy Kun&lt;/a&gt; for helping me understand the math.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:RNG&#34;&gt;Assume that every time I say &amp;ldquo;RNG&amp;rdquo; I mean &amp;ldquo;PRNG&amp;rdquo;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:RNG&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:gremlins&#34;&gt;Also full disclosure the code I&amp;rsquo;m showing is &lt;em&gt;less gremliny&lt;/em&gt; than the code I originally wrote. So just know it can be &lt;em&gt;more gremlins&lt;/em&gt; than this.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:gremlins&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:big-o&#34;&gt;if multiplier &lt;code&gt;n&lt;/code&gt; has a single orbit, then we&amp;rsquo;ll run &lt;code&gt;next-rng&lt;/code&gt; on ~10n-2 numbers, and the function will iterate 10n-2 times (since it has to go through every number in the orbit). If I bothered to skip numbers I&amp;rsquo;d already seen in an orbit then the runtime would collapse to O(n).
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:big-o&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>The World and the Machine</title>
        <link>https://www.hillelwayne.com/post/world-vs-machine/</link>
        <pubDate>Thu, 04 Jan 2024 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/world-vs-machine/</guid>
        <description>

&lt;p&gt;This is just a way of thinking about formal specification that I find really useful. The terms originally come from Michael Jackson&amp;rsquo;s &lt;a href=&#34;https://www.amazon.com/Software-Requirements-Specifications-Principles-Prejudices/dp/0201877120&#34;&gt;&lt;em&gt;Software Requirements and Specifications&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In specification, the &lt;dfn&gt;machine&lt;/dfn&gt; is the part of the system you have direct control over and the &lt;dfn&gt;world&lt;/dfn&gt; is all the parts that you don&amp;rsquo;t. Take a simple &lt;a href=&#34;https://learntla.com/intro/conceptual-overview.html#specifications&#34;&gt;transfer&lt;/a&gt; spec:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;----&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;MODULE&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;transfer&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;----&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;EXTENDS&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;TLC,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Integers&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;CONSTANTS&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;People,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Money,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;NumTransfers&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;(* --algorithm transfer&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;variables&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;acct&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[People&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Money];&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;define&lt;/span&gt;
  &lt;span style=&#34;color: #75715e&#34;&gt;\* Invariant&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;NoOverdrafts&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt;
    &lt;span style=&#34;color: #e6db74&#34;&gt;\A&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;People:&lt;/span&gt;
      &lt;span style=&#34;color: #f8f8f2&#34;&gt;acct[p]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;end define&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;

&lt;span style=&#34;color: #f92672&#34;&gt;process&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;cheque&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;..&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;NumTransfers&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;variable&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;amnt&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;..&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;People;&lt;/span&gt;
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;People&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;begin&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;  Check:&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;acct[from]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;amnt&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;then&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;      Withdraw:&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;acct[from]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;acct[from]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;amnt;&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;      Deposit:&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;acct[to]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;acct[to]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;amnt;&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;if&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;end process&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;end algorithm; *)&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;====&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code that handles the transfer (represented by the &lt;code&gt;cheque&lt;/code&gt; process) is the &lt;em&gt;machine&lt;/em&gt;. It currently has a race condition that can break the invariant &lt;code&gt;NoOverdrafts&lt;/code&gt;, where someone with $5 can submit two checks for $4 each and get them both past the guard clause.&lt;/p&gt;

&lt;p&gt;One way you could solve this is by adding a lock so that the banking service only resolves one cheque at a time. One way you &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; solve it is by forcing people to deposit one cheque at a time. You don&amp;rsquo;t have any control over what people do with their chequebook! The people and their behavior is part of the &lt;em&gt;world&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Whether something belongs to the world or the machine depends on your scope in the system. If you maintain one service and the other teams aren&amp;rsquo;t returning your calls, then their components are part of the world. If they&amp;rsquo;re sending you bad data, you need to faithfully model receiving that bad data in your spec as part of designing your machine.&lt;/p&gt;

&lt;h3 id=&#34;some-notes-on-this-model&#34;&gt;Some notes on this model&lt;/h3&gt;

&lt;p&gt;While you need to model the whole system, you&amp;rsquo;re only &lt;em&gt;designing&lt;/em&gt; the machine. So the implementation details of the machine matter, but you don&amp;rsquo;t need to implement the world. It can be abstracted away, except for how it affects the machine. In the above example, we don&amp;rsquo;t need to model a person deciding to write a cheque or the person depositing it, just the transfer entering the system.&lt;/p&gt;

&lt;h4 id=&#34;observability-and-observable-properties&#34;&gt;Observability and observable properties&lt;/h4&gt;

&lt;p&gt;Like in OOP, some system state is restricted to the world or machine.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The world can both read and write the &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;to&lt;/code&gt; variables, but the machine can only read them. In most specifications these restrictions are implicit; you &lt;em&gt;could&lt;/em&gt; write the spec so that the machine changes &lt;code&gt;from&lt;/code&gt;, but your boss wouldn&amp;rsquo;t let you build it.&lt;/li&gt;
&lt;li&gt;The &amp;ldquo;program counter&amp;rdquo;, or line each process is currently executing, isn&amp;rsquo;t readable or writable by the world. It&amp;rsquo;s an implementation detail of the machine.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acct&lt;/code&gt; can be written by the machine and read by the world. I call these &lt;dfn&gt;observable&lt;/dfn&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can divide properties into &lt;em&gt;internal&lt;/em&gt; properties that concern just the machine and &lt;em&gt;external&lt;/em&gt; (observable) properties that can be seen by the outside world. &lt;code&gt;NoOverdrafts&lt;/code&gt; is observable: if it&amp;rsquo;s violated, someone will be able to see that they have a negative bank balance. By contrast, &amp;ldquo;at most one process can be in the withdraw step&amp;rdquo; (&lt;code&gt;OnlyOneWithdraw&lt;/code&gt;) is internal. The world doesn&amp;rsquo;t have access to your transaction logs, nobody can &lt;em&gt;tell&lt;/em&gt; whether &lt;code&gt;OnlyOneWithdraw&lt;/code&gt; is satisfied or not.&lt;/p&gt;

&lt;p&gt;Internal properties are useful but they&amp;rsquo;re less important than observable properties. An &lt;code&gt;OnlyOneWithdraw&lt;/code&gt; violation might be the root cause of a &lt;code&gt;NoOverdrafts&lt;/code&gt; violation, but &lt;code&gt;NoOverdrafts&lt;/code&gt; is what actually matters to people. If a property isn&amp;rsquo;t observable, it doesn&amp;rsquo;t have any connection to the broader world, so nobody is actually affected by it breaking.&lt;/p&gt;

&lt;h4 id=&#34;misc&#34;&gt;Misc&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If both the world and machine can write to a variable, generally the world should be able to do more with the variable than the machine can. IE the machine can only modify &lt;code&gt;acct&lt;/code&gt; by processing transfers, while the world can also do deposits and withdrawals. It&amp;rsquo;s exceedingly hard to enforce &lt;a href=&#34;https://fsharpforfunandprofit.com/posts/designing-with-types-making-illegal-states-unrepresentable/&#34;&gt;MISU&lt;/a&gt; on state the world can modify.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;If the world can break an invariant, it&amp;rsquo;s not an invariant. Instead you want &amp;ldquo;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/formalizing-stability-and-resilience-properties/&#34;&gt;resilience&lt;/a&gt;&amp;rdquo;, the ability to restore some system property after it&amp;rsquo;s been broken. See &lt;a href=&#34;https://www.hillelwayne.com/post/adversaries/&#34;&gt;here&lt;/a&gt; for more on modeling resilience.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;It&amp;rsquo;s not uncommon for a spec to break not because the machine has a bug, but because the surrounding world has changed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://ahelwer.ca/&#34;&gt;Andrew Helwer&lt;/a&gt; and &lt;a href=&#34;https://lars.hupel.info/&#34;&gt;Lars Hupel&lt;/a&gt; for feedback. If you liked this, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write new essays there every week.&lt;/em&gt;&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Notes on Every Strangeloop 2023 Talk I Attended</title>
        <link>https://www.hillelwayne.com/post/strangeloop-23/</link>
        <pubDate>Tue, 05 Dec 2023 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/strangeloop-23/</guid>
        <description>

&lt;p&gt;This is my writeup of all the talks I saw at Strangeloop, written on the train ride back, while the talks were still fresh in my mind. Now that all the talks are online I can share it. This should have gone up like a month ago but I was busy and then sick. Enjoy!&lt;/p&gt;

&lt;h3 id=&#34;how-to-build-a-meaningful-career-https-www-youtube-com-watch-v-egqrm13qym&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=_egQrM13qyM&#34;&gt;How to build a meaningful career&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Topic: How to define what &amp;ldquo;success&amp;rdquo; means to you in your career and then be successful. Mostly focused on psychological maxims, like &amp;ldquo;put in the work&amp;rdquo; and &amp;ldquo;embrace the unknown&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;I feel like I wasn&amp;rsquo;t the appropriate audience for this; it seemed intended for people early in their career. I like that they said it&amp;rsquo;s okay to be in it for the money. Between the &amp;ldquo;hurr dur you must be in it for the passion&amp;rdquo; people and the &amp;ldquo;hurr durr smash capitalism&amp;rdquo; people, it&amp;rsquo;s nice to hear some acknowledgement that money makes your life nice.&lt;/p&gt;

&lt;h3 id=&#34;playing-with-engineering-https-www-youtube-com-watch-v-6ao8gs488ha&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=6Ao8GS488hA&#34;&gt;Playing with Engineering&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Topic: the value of &amp;ldquo;play&amp;rdquo; (as in &amp;ldquo;play make believe&amp;rdquo;, or &amp;ldquo;play with blocks&amp;rdquo;) in engineering. Some examples of how play leads to innovation, collaboration, and cool new things.&lt;/p&gt;

&lt;p&gt;Most of the talk is about the unexpected directions her &amp;ldquo;play&amp;rdquo; went in, like how her work in education eventually lead to a series of collaborations with OK Go. I think it was more inspirational than informative, to try to get people to &amp;ldquo;play&amp;rdquo; rather than to provide deep insight into the nature of the world. Still pretty fun.&lt;/p&gt;

&lt;h3 id=&#34;is-my-large-language-model-a-strange-loop-https-www-youtube-com-watch-v-gx2mduvaclo&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=Gx2mDuVAClo&#34;&gt;Is my Large Language Model a Strange Loop?&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;(Disclosure, I didn&amp;rsquo;t actually see this talk live, I watched &lt;a href=&#34;https://zhd.dev/&#34;&gt;Zac Hatfield-Dodds&lt;/a&gt; rehearse and gave feedback. Also Zac is a friend and we&amp;rsquo;ve collaborated before on &lt;a href=&#34;https://hypothesis.works/&#34;&gt;Hypothesis&lt;/a&gt; stuff.)&lt;/p&gt;

&lt;p&gt;Topic: Some of the unexpected things we observe in working LLMs, and some of the unexpected ways they&amp;rsquo;re able to self-reference themselves.&lt;/p&gt;

&lt;p&gt;Zac was asked to give the talk at the last minute due to a sickness cancellation by another speaker. Given the time crunch, I think he pulled it together pretty well. Even so it was a bit too technical for me; I don&amp;rsquo;t know if he was able to simplify it in time for the final presentation.&lt;/p&gt;

&lt;p&gt;Like most practical talks on AI, intentionally or not he slipped in a few tricks to eke more performance out of an LLM. Like if you ask them to answer a question, and then rate the confidence of the question they asked, they tend to be decently accurate at their confidence.&lt;/p&gt;

&lt;p&gt;Zac&amp;rsquo;s also a manager at &lt;a href=&#34;anthropic,com&#34;&gt;Anthropic&lt;/a&gt;, which gave the whole talk some neat &amp;ldquo;forbidden knowledge&amp;rdquo; vibes.&lt;/p&gt;

&lt;h3 id=&#34;concatenative-languages-talk-https-www-youtube-com-watch-v-umsulpjfuf8&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=umSuLpjFUf8&#34;&gt;Concatenative Languages Talk&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;(Disclaimer: Douglas is a friend, too.)&lt;/p&gt;

&lt;p&gt;Topic: Why stack-based languages are an interesting computational model, how they can be Turing-complete, and some of the unusual features you get from stack programming.&lt;/p&gt;

&lt;p&gt;The first time I&amp;rsquo;ve seen a stack-based language talk that wasn&amp;rsquo;t about Forth. Instead, it used his own homegrown stack language so he could just focus on the computer science aspects. The two properties that stick out to me are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stack programs don&amp;rsquo;t need to start from an empty stack, which means entire programs will naturally compose. Like you can theoretically pipe the output of a stack program into another stack program, since they&amp;rsquo;re all effectively functions of type &lt;code&gt;Stack -&amp;gt; Stack&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Stack ops are associative: if you chop a stack program into subprograms and pipe them into each other, it doesn&amp;rsquo;t matter where you make the cuts, you still get the same final stack. That&amp;rsquo;s really, really cool.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My only experience with stack machines is &lt;a href=&#34;https://www.hillelwayne.com/talks/esolangs/&#34;&gt;golfscript&lt;/a&gt;. Maybe I&amp;rsquo;ll try to pick up &lt;a href=&#34;https://www.uiua.org/&#34;&gt;uiua&lt;/a&gt; or something.&lt;/p&gt;

&lt;h3 id=&#34;comedy-writing-with-small-generative-models-https-www-youtube-com-watch-v-m2o4f-2l0no&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=M2o4f_2L0No&#34;&gt;Comedy Writing With Small Generative Models&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Topic: &amp;ldquo;Small&amp;rdquo; generative AI models, like &amp;ldquo;taking all one-star amazon reviews for the statue of liberty and throwing them into a &lt;a href=&#34;https://benhoyt.com/writings/markov-chain/&#34;&gt;Markov chain&lt;/a&gt;&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;This was my favorite session of the conference. The technical aspects are pretty basic, and it&amp;rsquo;s explained simply enough that even layfolk should be able to follow. His approach generates dreamy nonsense that should be familiar to anyone who&amp;rsquo;s played with Markov chains before.&lt;/p&gt;

&lt;p&gt;And then he pulls out a guitar.&lt;/p&gt;

&lt;p&gt;The high point was his &amp;ldquo;Weird Algorithm&amp;rdquo;, which was like a karaoke machine which replaced the lyrics of songs with corpus selections that matched the same meter and syllables. Like replacing &amp;ldquo;oh I believe in yesterday&amp;rdquo; with &amp;ldquo;this is a really nice Hyundai&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t know how funny it&amp;rsquo;ll be in the video, it might be one of those &amp;ldquo;you had to be there&amp;rdquo; things.&lt;/p&gt;

&lt;h3 id=&#34;an-approach-to-computing-and-sustainability-inspired-from-permaculture-https-www-youtube-com-watch-v-t3u7bggvspm&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=T3u7bGgVspM&#34;&gt;An approach to computing and sustainability inspired from permaculture&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Topic: The modern pace of tech leaves a lot of software, hardware, and people behind. How can we make software more sustainable, drawn from the author&amp;rsquo;s experiences living on a boat.&lt;/p&gt;

&lt;p&gt;Lots of thoughts on this one. The talk was a crash course on all the different kinds of sustainability: making software run on old devices, getting software guaranteed to run on &lt;em&gt;future&lt;/em&gt; devices, computing under significant power/space/internet constraints, and everything in between. I think it&amp;rsquo;s intended as a call to arms for us to think about doing better.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m sympathetic to the goals of permacomputing; what do I do with the five old phones in my closet? That&amp;rsquo;s a huge amount of computing power just gone to waste. The tension I always have is how this scales. &lt;a href=&#34;https://100r.co/site/home.html&#34;&gt;Devine Lu Levinga&lt;/a&gt; is an artistic savant (they made &lt;a href=&#34;https://metasyn.srht.site/learn-orca/&#34;&gt;Orca&lt;/a&gt;!) and the kind of person who can live on a 200-watt boat for seven years. I&amp;rsquo;m not willing to give up my creature comforts of central heating and Geforce gaming. Obviously there&amp;rsquo;s a huge spectrum between &amp;ldquo;uses less electricity than a &lt;a href=&#34;https://www.trainerroad.com/forum/t/targeting-200-watts-for-1-hour/40043&#34;&gt;good cyclist&lt;/a&gt;&amp;rdquo; and &amp;ldquo;buys the newest iPhone every year&amp;rdquo;, the question is what&amp;rsquo;s the right balance between sustainability and achievability.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s also the whole aesthetic/cultural aspect to permacomputing. Devine used images in dithered black/white. &lt;abbr title=&#34;As far as I can tell&#34;&gt;AFAICT&lt;/abbr&gt;
 this is because &lt;a href=&#34;https://en.wikipedia.org/wiki/HyperCard&#34;&gt;Hypercard&lt;/a&gt; was black/white, lots of retrocomputing fans love hypercard, and there&amp;rsquo;s a huge overlap between retrocomputing and permacomputing. But &lt;a href=&#34;https://en.wikipedia.org/wiki/Kid_Pix&#34;&gt;Kid Pix&lt;/a&gt; is just as old as Hypercard and does full color. It&amp;rsquo;s just not part of the culture.&lt;/p&gt;

&lt;p&gt;Nit: at the end Devine discussed how they were making software preservation easier by writing a special VM. This was interesting but the discussion on how it worked ended up going way over time and I had to run to the next session.&lt;/p&gt;

&lt;h3 id=&#34;can-a-programming-language-reason-about-systems-https-www-youtube-com-watch-v-fuhehupexso&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=FuhEHuPExso&#34;&gt;Can a Programming Language Reason About Systems?&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;(Disclaimer: Jesus I&amp;rsquo;m friends with way too many people on the conference circuit now)&lt;/p&gt;

&lt;p&gt;Topic: Formal methods is useful to reason about existing legacy systems, but has too high a barrier to entry. Marianne made a new FM language called &amp;ldquo;Fault&amp;rdquo; with a higher levels of abstraction. Some discussion of how it&amp;rsquo;s implemented.&lt;/p&gt;

&lt;p&gt;This might just be the friendship talking, but Fault looks like one of the more interesting FM languages to come out recently. I&amp;rsquo;m painfully aware of just how &lt;em&gt;hard&lt;/em&gt; grokking FM can be, and anything that makes it more accessible is good. I&amp;rsquo;ll have to check it out.&lt;/p&gt;

&lt;p&gt;When she said that the hardest part is output formatting I felt it in my soul.&lt;/p&gt;

&lt;h3 id=&#34;making-hard-things-easy-https-www-youtube-com-watch-v-30ywsgdr8ma&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=30YWsGDr8mA&#34;&gt;Making Hard Things Easy&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Topic: Lots of &amp;ldquo;simple&amp;rdquo; things take years to learn, like Bash or DNS. How can we make it easier for people to learn these things? Four difficult technologies, and different approaches to making them tractable.&lt;/p&gt;

&lt;p&gt;I consider myself a very good teacher. This talk made me a better one.&lt;/p&gt;

&lt;p&gt;Best line was &amp;ldquo;behind every best practice is a gruesome story.&amp;rdquo; That&amp;rsquo;ll stick with me.&lt;/p&gt;

&lt;h3 id=&#34;drawing-comics-at-work&#34;&gt;Drawing Comics at Work&lt;/h3&gt;

&lt;p&gt;Topic: Randal Munroe (the xkcd guy)&amp;rsquo;s closing keynote. No deep engineering lessons, just a lot of fun.&lt;/p&gt;

&lt;h2 id=&#34;postmortem&#34;&gt;Postmortem&lt;/h2&gt;

&lt;p&gt;Before Julia Evans&amp;rsquo; talk, Alex did &lt;a href=&#34;https://www.youtube.com/watch?v=suv76aL0NrA&#34;&gt;A Long Strange Loop&lt;/a&gt;, how it went from an idea to the monolith it is today. Strange Loop was his vision, an eclectic mix of academia, industry, art, and activism. And it drew a diverse crowd because of that. I&amp;rsquo;ve made many friends at Strangeloop, people like &lt;a href=&#34;https://www.bellotti.tech/about&#34;&gt;Marianne&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/Felienne_Hermans&#34;&gt;Felienne&lt;/a&gt;. I don&amp;rsquo;t know if I&amp;rsquo;ll run into them at any other conferences, because I don&amp;rsquo;t think other conferences will capture that lightning in a bottle. I&amp;rsquo;ll miss them.&lt;/p&gt;

&lt;p&gt;I also owe my career to Strangeloop. Eight years ago they accepted &lt;a href=&#34;https://www.youtube.com/watch?v=_9B__0S21y8&#34;&gt;Tackling concurrency bugs with TLA+&lt;/a&gt;, which got me started both speaking and writing formal methods professionally.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s been some talk about running a successor conference (someone came up with the name &amp;ldquo;estranged loop&amp;rdquo;) but I don&amp;rsquo;t know if it will ever be the same. There are lots of people can run a good conference, but there&amp;rsquo;s only one person who can run &lt;em&gt;Alex&amp;rsquo;s conference&lt;/em&gt;. Whatever comes next will be fundamentally different. Still good, I&amp;rsquo;m sure, but different.&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>A better explanation of the Liskov Substitution Principle</title>
        <link>https://www.hillelwayne.com/post/lsp/</link>
        <pubDate>Tue, 07 Nov 2023 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/lsp/</guid>
        <description>

&lt;p&gt;Short version: &lt;em&gt;If X inherits from Y, then X should pass all of Y&amp;rsquo;s black box tests.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I first encountered this idea at &lt;a href=&#34;https://2021.splashcon.org/details/splash-2021-SPLASH-E/7/Reframing-the-Liskov-Substitution-Principle-through-the-Lens-of-Testing&#34;&gt;SPLASH 2021&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;the-longer-explanation&#34;&gt;The longer explanation&lt;/h2&gt;

&lt;h3 id=&#34;a-bit-of-background&#34;&gt;A bit of background&lt;/h3&gt;

&lt;p&gt;In &lt;a href=&#34;https://www.cs.cmu.edu/~wing/publications/LiskovWing94.pdf&#34;&gt;A Behavioral Notion of Subtyping&lt;/a&gt; Liskov originally defined &lt;dfn&gt;subtyping&lt;/dfn&gt; in inherited objects as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Subtype Requirement: Let P(x) be a property provable about objects x of type T. Then P(y) should be true for objects y of type S where S is a subtype of T.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Later, Robert Martin &lt;a href=&#34;https://web.archive.org/web/20150905081111/http://www.objectmentor.com/resources/articles/lsp.pdf&#34;&gt;named&lt;/a&gt; the &lt;dfn&gt;Liskov Substitution Principle&lt;/dfn&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you had &lt;code&gt;fly_to(Bird, location)&lt;/code&gt;, then you should be able to call &lt;code&gt;fly_to&lt;/code&gt; on any subtype of &lt;code&gt;Bird&lt;/code&gt;. This means that &lt;code&gt;Penguin&lt;/code&gt; and &lt;code&gt;Ostrich&lt;/code&gt; couldn&amp;rsquo;t be subtypes of &lt;code&gt;Bird&lt;/code&gt;, since you cannot call &lt;code&gt;fly_to&lt;/code&gt; on a flightless bird!&lt;/p&gt;

&lt;p&gt;Liskov would later &amp;ldquo;approve&amp;rdquo; of the rule in her book &lt;em&gt;Program Development in Java&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&#34;the-devil-is-in-the-details&#34;&gt;The Devil is in the Details&lt;/h3&gt;

&lt;p&gt;The LSP looks simple; the problem is applying it. How do you &lt;em&gt;check&lt;/em&gt; that a function works on all subclasses of a class? Functions can do a lot of things! So we have a set of enforceable rules, where if you follow all the rules, you (presumably) satisfy LSP. The most well known of these rules is that inherited methods of a class must not &lt;em&gt;strengthen preconditions&lt;/em&gt; or &lt;em&gt;weaken postconditions&lt;/em&gt;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:methods-vs-functions&#34;&gt;&lt;a href=&#34;#fn:methods-vs-functions&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; That means it must accept a &lt;em&gt;superset&lt;/em&gt; of the values the parent method accepts and output a &lt;em&gt;subset&lt;/em&gt; of the parent&amp;rsquo;s possible outputs. Given&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Parent {
   run(x: int): out {
    require {x &amp;gt;= 4}
    # some code that computes out
    ensures {out % 2 == 0}
   }
}

class Child extends Parent {
# stuff
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;Child.run&lt;/code&gt; cannot be overloaded to take only &lt;em&gt;even&lt;/em&gt; integers, or to also output odd numbers. Preconditions and postconditions together are called &lt;dfn&gt;contracts&lt;/dfn&gt;.&lt;/p&gt;

&lt;p&gt;This is just the first rule and already we have three problems. First, it&amp;rsquo;s not super clear why this follows from the LSP. Second, it&amp;rsquo;s hard to remember whether it&amp;rsquo;s &lt;em&gt;weaken preconditions&lt;/em&gt; and &lt;em&gt;strengthen postconditions&lt;/em&gt; or the other way around. Third, most languages don&amp;rsquo;t have dedicated pre/postcondition syntax. For these languages the rule is taught as a restriction on the method&amp;rsquo;s &lt;em&gt;type signature&lt;/em&gt;: the parameters must be &lt;dfn&gt;contravariant&lt;/dfn&gt; and the return values &lt;dfn&gt;covariant&lt;/dfn&gt;. This makes things even more arbitrary and confusing and isn&amp;rsquo;t as accurate as the original version.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Long tangent on types and contracts
  &lt;/summary&gt;
  &lt;p&gt;The above is historically inaccurate: the original Liskov paper lists &lt;em&gt;both&lt;/em&gt; the contract rule and the type rule as separate requirements for subtyping. But IMHO the type rule is equivalent to the contract rule. Saying &amp;ldquo;parameters must be contravariant&amp;rdquo; is the same as saying &amp;ldquo;preconditions must not be strengthened.&amp;rdquo; Consider this case of contravariant parameters:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Parent.foo(x: Cat) {
    # code 
}

Child.foo(x: Animal) {
    # code
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can rewrite it purely as contracts:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Parent.foo(x) {
    requires typeof(x) == Cat;
    # code
}

Child.foo(x) {
    requires typeof(x) == Animal;
    # code
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;rsquo;s less intuitive that we can rewrite contracts as types, but that&amp;rsquo;s also possible:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;foo(x: Int): out {
    require {x &amp;gt;= 4}
    # code
    ensure {out % 2 == 0}
}

# becomes

foo(x: AtLeastFour): (out: EvenNumber) {
    # code
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;rsquo;s true that most languages can&amp;rsquo;t statically typecheck this, but that&amp;rsquo;s a limitation on our current typecheckers, not an &lt;em&gt;essential&lt;/em&gt; problem. Some languages, like &lt;a href=&#34;https://ucsd-progsys.github.io/liquidhaskell/&#34;&gt;Liquid Haskell&lt;/a&gt;, handle it just fine.&lt;/p&gt;

&lt;p&gt;That said, even if the two rules are theoretically equivalent, in practice your programming language will favor checking some things as contracts and other things as types.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;We can&amp;rsquo;t ensure LSP with function contracts alone. Consider!&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:pythonica&#34;&gt;&lt;a href=&#34;#fn:pythonica&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;@dataclass&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;WrappedCounter&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;val:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;# assume that 0 &amp;lt;= val &amp;lt; 1000&lt;/span&gt;

    &lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(self,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x):&lt;/span&gt;
        &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;# Precondition&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;(self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x)&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1000&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;Counter&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(WrappedCounter):&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(self,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x):&lt;/span&gt;
        &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;# Precondition&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Counter&lt;/code&gt; is &lt;em&gt;obviously not&lt;/em&gt; a subtype of &lt;code&gt;WrappedCounter&lt;/code&gt;, but it has the same method contracts! The difference is that &lt;code&gt;WrappedCounter&lt;/code&gt; has an extra &lt;dfn&gt;invariant&lt;/dfn&gt;, a property that holds true of an object at all times. &lt;code&gt;Counter&lt;/code&gt; doesn&amp;rsquo;t have that property, so it can&amp;rsquo;t be a child class. That leads to rule two, subtypes must not weaken the &lt;em&gt;class invariants&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The method rule and the invariant rule look somewhat related, but the next one comes out of left field.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;@dataclass&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;WrappedCounter&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;val:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Nat&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;limit:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Nat&lt;/span&gt;

    &lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(self,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x):&lt;/span&gt;
        &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;limit&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;# Precondition&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;(self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x)&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;limit&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;EvilCounter&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(WrappedCounter):&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(self,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x):&lt;/span&gt;
        &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;limit&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;# Precondition&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;limit&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;(self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x)&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;limit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;rsquo;s look at our two rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does it pass the method test? Yup, both have the exact same type signatures and preconditions.&lt;/li&gt;
&lt;li&gt;Does it pass the invariant test? Yup, they both guarantee that &lt;code&gt;self.val ∈ [0, limit)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But &lt;code&gt;EvilCounter&lt;/code&gt; is clearly &lt;em&gt;not&lt;/em&gt; a subtype of &lt;code&gt;WrappedCounter&lt;/code&gt;. It doesn&amp;rsquo;t wrap!&lt;/p&gt;

&lt;p&gt;We need a third rule, the &lt;dfn&gt;history rule&lt;/dfn&gt;: the subtype cannot &lt;em&gt;change&lt;/em&gt; in a way prohibited by the supertype. In this case, this means that &lt;code&gt;limit&lt;/code&gt; must remain unchanged. &lt;code&gt;WrappedCounter&lt;/code&gt; follows this rule and &lt;code&gt;EvilCounter&lt;/code&gt; violates it, so it&amp;rsquo;s not a subtyping relation.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:history-rule&#34;&gt;&lt;a href=&#34;#fn:history-rule&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The history rule always felt like a tack-on. It makes me worry that we&amp;rsquo;re just patching up holes as we find them, and that somebody will come up with a counterexample that follows all three rules but still isn&amp;rsquo;t a subtype. Like what happens when we add in exceptions or generics? We might have to add another arbitrary rule. It all just makes me lose trust in the applicability of LSP.&lt;/p&gt;

&lt;h2 id=&#34;the-fix&#34;&gt;The Fix&lt;/h2&gt;

&lt;p&gt;In their college classes, Elisa Baniassad and Alexander J Summers &lt;a href=&#34;https://www.cs.ubc.ca/~alexsumm/papers/BaniassadSummers21.pdf&#34;&gt;found a different approach&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For a class to be substitutable for its supertype, it must pass all the supertype&amp;rsquo;s black box tests.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:black-box&#34;&gt;&lt;a href=&#34;#fn:black-box&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To check substitutability, we come up with a test:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;test_add_five&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;():&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;WrappedCounter(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;add(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This passes, so we&amp;rsquo;d expect the equivalent test to pass for &lt;code&gt;Counter&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;test_add_five&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;():&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Counter(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;add(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This also passes. If every test we write passes, then &lt;code&gt;Counter&lt;/code&gt; is a subtype of &lt;code&gt;WrappedCounter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So let&amp;rsquo;s write a second test:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;test_add_million&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;():&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;WrappedCounter(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;add(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1_000_000&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt; 
    &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And this passes for &lt;code&gt;WrappedCounter&lt;/code&gt; but &lt;em&gt;fails&lt;/em&gt; for &lt;code&gt;Counter&lt;/code&gt;. Therefore &lt;code&gt;Counter&lt;/code&gt; is not a subtype of &lt;code&gt;WrappedCounter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show limitation
  &lt;/summary&gt;
  &lt;p&gt;Note that passing tests doesn&amp;rsquo;t &lt;em&gt;guarantee&lt;/em&gt; you&amp;rsquo;ve got a subtype, since there might be a failing test you just haven&amp;rsquo;t considered writing. It&amp;rsquo;s similar to how, even if you have a rule violation, you might never actually run into a subtype violation in production. This is more a &lt;em&gt;pedagogical&lt;/em&gt; technique to help people internalize LSP.&lt;/p&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;h3 id=&#34;this-explains-a-lot&#34;&gt;This explains a lot&lt;/h3&gt;

&lt;p&gt;I like how the testing approach to LSP explains all the rules. If you give me a case where an LSP rule violation causes a problem, I can give you back a test case which fails for the same reason. Let&amp;rsquo;s Pythonize my earlier example of a precondition rule violation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;Parent&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(self,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x:&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Int):&lt;/span&gt;
        &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;4&lt;/span&gt;
        &lt;span style=&#34;color: #66d9ef&#34;&gt;pass&lt;/span&gt;
        &lt;span style=&#34;color: #75715e&#34;&gt;# return something&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;Child&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(Parent):&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(self,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x):&lt;/span&gt;
        &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;super()&lt;/span&gt;
        &lt;span style=&#34;color: #66d9ef&#34;&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s my test:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;test_parent&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;():&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Parent()&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;run(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;test_child&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;():&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Child()&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;run(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We don&amp;rsquo;t need to &lt;em&gt;do&lt;/em&gt; anything with the output of &lt;code&gt;run&lt;/code&gt;, just call it. The first test (with &lt;code&gt;c = Parent()&lt;/code&gt;) will do nothing while the second test (with &lt;code&gt;c = Child()&lt;/code&gt;) will throw an error, failing the test. &lt;code&gt;Child&lt;/code&gt; is not a subtype.&lt;/p&gt;

&lt;p&gt;So that&amp;rsquo;s one way the testing approach makes things easier. It also shows why the history rule is necessary &lt;em&gt;and also&lt;/em&gt; why it originally seemed like a crude hack to me.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;test_history_rule&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;():&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;WrappedCounter(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;add(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;add(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We originally needed the history rule because contracts and invariants only span the lifetime of &lt;em&gt;one&lt;/em&gt; method. But now we can just call a sequence of methods in one test!&lt;/p&gt;

&lt;h2 id=&#34;does-this-work&#34;&gt;Does this work?&lt;/h2&gt;

&lt;p&gt;By &amp;ldquo;work&amp;rdquo;, I mean &amp;ldquo;does it help students internalize the LSP.&amp;rdquo; I found the paper a little confusing here: it says they &amp;ldquo;observed that students were able to better understand the responsibilities of the subtype in a general sense&amp;rdquo;, but also that &amp;ldquo;the same proportion of students&amp;rdquo; understood the rules, which kinda sounds like &amp;lsquo;no impact&amp;rsquo;? I emailed the researchers for a clarification and here&amp;rsquo;s their response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It was a big improvement.  Students went from not demonstrating any intuition around the rule, to “getting it”.  “Oh - subclass has to pass all superclass black box tests! I get it!”.  And then you can delve into ways tests can break (narrowing preconditions, etc). But at the root of it all - it’s about the tests.  They did way better on LSP questions, and I believe there was one question in particular that we asked before and after, and it was way better done (like from a failing grade to a good passing grade on average) with the testing approach.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They also told me about an indirect benefit: it also helped students understand the difference between black- and white-box tests! Once you get a sense for LSP in the original&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It helped clearly delineate whether tests were about “the packaging” (like what’s written on the box) or the “how” you’ve done it (which is specific to the implementation, and can change if you make different choices).  You have to test both, and make sure both the packaging is okay, and check that the underlying implementation is not having unwanted side effects, or introducing errors — and it then became clear to students why we needed both kinds of tests, and why differentiating was useful.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pretty cool!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://www.linkedin.com/in/elizabeth-denhup/&#34;&gt;Liz Denhup&lt;/a&gt; for feedback. If you liked this, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write new essays there every week.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:methods-vs-functions&#34;&gt;How did we go from functions to methods? Think of the method &lt;code&gt;obj.run(x: int)&lt;/code&gt; as being syntactic sugar for the function &lt;code&gt;run(obj: Class, x: int)&lt;/code&gt;, kind of like how Python methods have a required &lt;code&gt;self&lt;/code&gt; parameter.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:methods-vs-functions&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:pythonica&#34;&gt;If I wanted to actually &lt;em&gt;guarantee&lt;/em&gt; that &lt;code&gt;val &amp;gt;= 0&lt;/code&gt;, I could add a &lt;a href=&#34;https://docs.python.org/3/library/dataclasses.html#post-init-processing&#34;&gt;post_init&lt;/a&gt; method to the dataclass.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:pythonica&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:history-rule&#34;&gt;In this specific case you can catch this violation with the postcondition &lt;code&gt;self.limit == old.limit&lt;/code&gt;, but this is just a simple illustrative example.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:history-rule&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:black-box&#34;&gt;Where &amp;ldquo;black box&amp;rdquo; means &amp;ldquo;public methods and accesses only&amp;rdquo;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:black-box&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Learn AutoHotKey by stealing my scripts</title>
        <link>https://www.hillelwayne.com/post/ahk-scripts-project/</link>
        <pubDate>Mon, 21 Aug 2023 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/ahk-scripts-project/</guid>
        <description>&lt;p&gt;&lt;em&gt;tl;dr annotated AHK scripts &lt;a href=&#34;https://github.com/hwayne/autohotkey-scripts/&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Anybody who&amp;rsquo;s spent time with me knows how much I love &lt;a href=&#34;https://www.autohotkey.com/&#34;&gt;AutoHotKey&lt;/a&gt;, the flat-out best Windows automation tool in the world. Anybody&amp;rsquo;s who&amp;rsquo;s &lt;em&gt;tried&lt;/em&gt; to use AutoHotKey knows how intimidating it can be. So to help with that, I&amp;rsquo;m sharing (almost) &lt;a href=&#34;https://github.com/hwayne/autohotkey-scripts/&#34;&gt;all of my scripts&lt;/a&gt; along with extensive explanations. There&amp;rsquo;s fourteen files in total, covering (among other things):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hwayne/autohotkey-scripts/blob/main/Lib/Launchers/Folders.ahk&#34;&gt;Fast open&lt;/a&gt; specific folders on your computer&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hwayne/autohotkey-scripts/blob/main/Hotstrings.ahk&#34;&gt;Fast insertion&lt;/a&gt; of the current date, em-dashes, and ¯\_(ツ)_/¯s&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hwayne/autohotkey-scripts/blob/main/Lib/SpecificPrograms/FirefoxStuff.ahk&#34;&gt;How to extend&lt;/a&gt; any program with new hotkeys&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hwayne/autohotkey-scripts/blob/main/Lib/ModesModal.ahk&#34;&gt;A modal hotkey system&lt;/a&gt; if you&amp;rsquo;re a vim fan like me&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hwayne/autohotkey-scripts/blob/main/Lib/GUI.ahk&#34;&gt;A simple GUI&lt;/a&gt; demo&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hwayne/autohotkey-scripts/blob/main/Lib/Timezone.ahk&#34;&gt;A script&lt;/a&gt; to convert any timestamp into UTC and your local time:&lt;/li&gt;
&lt;/ol&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; padding-top: 30px; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube.com/embed/RLd8GdGf8uI&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&#34; allowfullscreen frameborder=&#34;0&#34; title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
 &lt;/div&gt;


&lt;p&gt;This is also an example of an &lt;dfn&gt;educational codebase&lt;/dfn&gt;, a codebase designed specifically from people to learn from. So everything is heavily commented with &amp;ldquo;what&amp;rdquo; it&amp;rsquo;s doing and sometimes why I&amp;rsquo;m doing it that specific way. I wrote a bit about the theory of educational codebases over &lt;a href=&#34;https://buttondown.email/hillelwayne/archive/educational-codebases/&#34;&gt;at my newsletter&lt;/a&gt;. Feel free to file an issue if you&amp;rsquo;d like to see something explained better!&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>My Problem With the Four-Document Model</title>
        <link>https://www.hillelwayne.com/post/problems-with-the-4doc-model/</link>
        <pubDate>Wed, 05 Jul 2023 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/problems-with-the-4doc-model/</guid>
        <description>

&lt;p&gt;Two universal facts about user documentation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Documentation is really important.&lt;/li&gt;
&lt;li&gt;We are really bad at writing it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We don&amp;rsquo;t have good theories on what makes for useful documentation. That is except for the &lt;a href=&#34;https://documentation.divio.com/&#34;&gt;four document model&lt;/a&gt;, or &lt;a href=&#34;https://diataxis.fr/&#34;&gt;Diátaxis&lt;/a&gt;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:diataxis&#34;&gt;&lt;a href=&#34;#fn:diataxis&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I&amp;rsquo;m glad that people use it. I&amp;rsquo;m also a little frustrated that people use it even when its inappropriate. My problem is that it&amp;rsquo;s not a universal or comprehensive model: there&amp;rsquo;s a lot of documentation people need to write that doesn&amp;rsquo;t neatly fit the model.&lt;/p&gt;

&lt;h2 id=&#34;what-is-the-4doc-model&#34;&gt;What is the 4doc model?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&#34;https://documentation.divio.com/_images/overview.png&#34; alt=&#34;four document types on two axes&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The 4doc model says that user-facing documentation should fall into four categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tutorials&lt;/strong&gt; describe how to get up and running as fast as possible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How-tos&lt;/strong&gt; describe how to do &lt;em&gt;specific&lt;/em&gt; things.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explanations&lt;/strong&gt; teach a topic you already know in-depth.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;References&lt;/strong&gt; describe exactly what things are and what they do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each category serves a different purpose, targets a different audience, and is written in a special style. Tutorials are friendly and simplified, while references are dry and comprehensive.&lt;/p&gt;

&lt;p&gt;4doc was originally started by Daniele Procida at Divio to improve their documentation, and has since become popular in the broader tooling ecosystem.&lt;/p&gt;

&lt;h2 id=&#34;my-problems&#34;&gt;My problems&lt;/h2&gt;

&lt;p&gt;I think of the 4doc model like the five-paragraph essay. In the US, kids are taught to write essays in three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A starting paragraph the context and the main thesis,&lt;/li&gt;
&lt;li&gt;Three body paragraphs that each independently support the thesis&lt;/li&gt;
&lt;li&gt;A concluding paragraph with summarizing the arguments and thesis.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It&amp;rsquo;s a good starting point to learn essay writing. The problem is that students think it&amp;rsquo;s the &lt;em&gt;only&lt;/em&gt; way to write essays, and then they cram everything they write into a format straitjacket.&lt;/p&gt;

&lt;p&gt;4doc is &lt;em&gt;much&lt;/em&gt; better than 5para: I&amp;rsquo;ve never read a halfway-decent 5-paragraph essay but I&amp;rsquo;ve read plenty of good 4doc pages. Even so, it still leads to the same kind of &amp;ldquo;this is the only way&amp;rdquo; thinking. People use the model even when it&amp;rsquo;s not the right choice and they don&amp;rsquo;t vary up the format even when they should.&lt;/p&gt;

&lt;p&gt;My specific issue is that the model is not &lt;strong&gt;universal&lt;/strong&gt; and it&amp;rsquo;s not &lt;strong&gt;comprehensive&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&#34;it-s-not-universal&#34;&gt;It&amp;rsquo;s not universal&lt;/h3&gt;

&lt;p&gt;From &lt;a href=&#34;https://documentation.divio.com/structure/&#34;&gt;the structure page&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Good examples of the scheme in substantial projects include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the &lt;a href=&#34;https://docs.divio.com&#34;&gt;Divio Developer Handbook&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://docs.djangoproject.com/en/3.0/#how-the-documentation-is-organized&#34;&gt;Django’s documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://docs.django-cms.org&#34;&gt;django CMS’s documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Divio and Django CMS are &lt;em&gt;tools&lt;/em&gt;. Tools and libraries are different than frameworks and languages. Tools have simple &lt;a href=&#34;https://en.wikipedia.org/wiki/Conceptual_model&#34;&gt;conceptual models&lt;/a&gt;, the set of interrelated ideas you need to internalize to use them properly. You just need to know &lt;em&gt;what&lt;/em&gt; they do and &lt;em&gt;how&lt;/em&gt; to use them. The 4doc model, developed at Divio, most reflects the documentation needs of tools.&lt;/p&gt;

&lt;p&gt;Look at django. Frameworks are one step up from tools and are still mostly about &amp;ldquo;what and how&amp;rdquo;, but they also have a lot of interrelated concepts you need to understand. While it still ostensibly follows the 4doc model, the &lt;a href=&#34;https://docs.djangoproject.com/en/4.0/topics/&#34;&gt;&amp;ldquo;explanation&amp;rdquo; section&lt;/a&gt; is triple the size of the tutorial and how-to sections combined.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:django-measurement&#34;&gt;&lt;a href=&#34;#fn:django-measurement&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; The explanation section also &lt;em&gt;teaches&lt;/em&gt; the user, which isn&amp;rsquo;t supposed to happen:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s not the place of an explanation to instruct the user in how to do something. Nor should it provide technical description. These functions of documentation are already taken care of in other sections. — &lt;a href=&#34;https://documentation.divio.com/explanation/&#34;&gt;divio&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It&amp;rsquo;s only possible to separate explanation and instruction for things if you don&amp;rsquo;t need a good mental model. Things like tools.&lt;/p&gt;

&lt;p&gt;If we zoom out to programming languages (PLs), the 4doc model breaks down entirely. If you look at the &lt;a href=&#34;https://docs.python.org/3/&#34;&gt;Python&lt;/a&gt; docs, the tutorial section needs to also explain and reference, and the references are both explanation and how-to. Language concept maps are just too dense to separate.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve seen some languages try to strictly follow the 4doc model and it doesn&amp;rsquo;t work. 4doc is oriented around random-access, languages are taught in a sequence-of-lessons. The two don&amp;rsquo;t mix well.&lt;/p&gt;

&lt;p&gt;In short, the 4doc model is &lt;strong&gt;not universal&lt;/strong&gt;. It was designed for documenting &lt;em&gt;tools&lt;/em&gt; and doesn&amp;rsquo;t fully address the needs of frameworks and programming languages.&lt;/p&gt;

&lt;h3 id=&#34;it-s-not-comprehensive&#34;&gt;It&amp;rsquo;s not comprehensive&lt;/h3&gt;

&lt;p&gt;4doc would be comprehensive if all useful forms of documentation fell into one of the four types. This isn&amp;rsquo;t true for the same reason 4doc is nonuniversal: it only covers documentation forms that are necessary for tools.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re documenting a complex topic like a programming language, there&amp;rsquo;s at least (at least) two more kinds of docs you&amp;rsquo;ll want:&lt;/p&gt;

&lt;h4 id=&#34;1-conceptual-overviews&#34;&gt;1. Conceptual Overviews&lt;/h4&gt;

&lt;p&gt;If I was presented with 4doc-following documentation and had to add just one thing to it, I&amp;rsquo;d write a conceptual overview.&lt;/p&gt;

&lt;p&gt;&lt;dfn&gt;Conceptual overviews&lt;/dfn&gt; cover the concepts of the tool/framework/language. It presents what the big picture of what this is all &lt;em&gt;for&lt;/em&gt; and previews the conceptual model users will learn. The denser the model, the more you need a conceptual overview.&lt;/p&gt;

&lt;p&gt;The 4doc model describes documentation types in terms of cooking, so here&amp;rsquo;s one for conceptual overviews:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All soups work in the same basic way: prepare ingredients like vegetables and meat and boil them in water. This softens the ingredients and flavors the water (&amp;ldquo;broth&amp;rdquo;). We can make higher-quality soups by first cooking some ingredients in oil (which develops more flavors), adding some ingredients later in the boil (so they don&amp;rsquo;t get &lt;em&gt;too&lt;/em&gt; soft), using a boiling different liquid (like chicken stock or beer), or using spices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a more in-depth example of an overview, you can see &lt;a href=&#34;https://learntla.com/intro/conceptual-overview.html&#34;&gt;one I wrote for TLA+&lt;/a&gt;. It first explains the problem TLA+ is trying to solve (designing complex concurrent systems), introduces the concepts involved (specs, behaviors, properties, models), and only &lt;em&gt;then&lt;/em&gt; shows any code. And even then it doesn&amp;rsquo;t explain how to &lt;em&gt;run&lt;/em&gt; the code, just how various aspects of the code relate to the concepts.&lt;/p&gt;

&lt;p&gt;(&amp;ldquo;Aren&amp;rsquo;t these just a kind of explanations?&amp;rdquo; Explanations are intended for people who already know, or are in the process of learning, your subject. It comes after the tutorial. Conceptual overviews come &lt;em&gt;before&lt;/em&gt; the tutorial. They are for people who are &lt;em&gt;getting ready&lt;/em&gt; to learn the subject, or for outsiders evaluating if they &lt;em&gt;want to learn it&lt;/em&gt;.)&lt;/p&gt;

&lt;h4 id=&#34;2-snippets-and-examples&#34;&gt;2. Snippets and Examples&lt;/h4&gt;

&lt;p&gt;Examples are complete code intended to be studied. Snippets are samples of code intended to be used. As much as we make fun of Stackoverflow-based development, we copy and paste from websites because that works and makes us productive. If you provide them from the start, developers don&amp;rsquo;t have to find them from sketchy third parties.&lt;/p&gt;

&lt;p&gt;Examples also show &lt;em&gt;how something is done&lt;/em&gt;, which is subtly-but-fundamentally different from &lt;em&gt;how-to do something&lt;/em&gt;. Imagine I present you an example of a code, and then an example of the same code, optimized. I&amp;rsquo;m not giving you a rote how-to on optimizing code, I&amp;rsquo;m demonstrating a way of &lt;em&gt;thinking&lt;/em&gt; about optimizing code. It all comes back to the mental model.&lt;/p&gt;

&lt;p&gt;Or take Julia Evans&amp;rsquo; &lt;a href=&#34;https://mysteries.wizardzines.com/&#34;&gt;debugging mysteries&lt;/a&gt;, a set of &lt;a href=&#34;https://en.wikipedia.org/wiki/Choose_Your_Own_Adventure&#34;&gt;Choose Your Own Adventures&lt;/a&gt; where the reader debugs a problem. It looks like a how-to, but it&amp;rsquo;s a branching path, not a linear set of steps.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;./img/wizardzines.png&#34; alt=&#34;An example of a debugging mystery, where the user can try a few different things and see why they do (or don&#39;t) work&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The cooking analogy would be a video of a chef making a dish and explaining what she&amp;rsquo;s thinking while she makes it. Or maybe doing a taste-test of undersalted dishes. It&amp;rsquo;s not a perfect analogy. Written examples don&amp;rsquo;t make a whole lot of sense in tradecraft.&lt;/p&gt;

&lt;h2 id=&#34;good-is-the-enemy-of-better&#34;&gt;Good is the enemy of better&lt;/h2&gt;

&lt;p&gt;I want to be clear: I don&amp;rsquo;t think 4doc is &lt;em&gt;bad&lt;/em&gt;. I think it&amp;rsquo;s quite good! But I think you have to think about &lt;em&gt;how&lt;/em&gt; you&amp;rsquo;re using it. Like any other tool, you have to evaluate what it does for you. The model says at much:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Diátaxis is based on sound theoretical principles and has been proven in practice, but it’s not the final word in documentation. … the structure it proposes is not intended to be a plan, something you must complete in your documentation. It’s a guide, a map to help you check that you’re in the right place and going in the right directions. — &lt;a href=&#34;https://diataxis.fr/how-to-use-diataxis/&#34;&gt;How to use Diátaxis&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&amp;rsquo;m unhappy that the original Divio page doesn&amp;rsquo;t have this disclaimer and instead has big quote calling it the &amp;ldquo;The Grand Unified Theory of Documentation&amp;rdquo;. Procida doesn&amp;rsquo;t seem to be believe this and I wish divio would stop pitching 4doc as the one-and-only documentation system. It might be good for getting people on board but it&amp;rsquo;s bad for broader documentation innovation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to Lito Nicolai for feedback. If you liked this, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write essays once a week.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:diataxis&#34;&gt;Some people see the two sites and assume Divio plagiarized the 4doc model from Diátaxis.  I looked into it and can happily say it&amp;rsquo;s not true. Daniele Procida came up with it while working at Divio and then &lt;a href=&#34;https://github.com/evildmp/diataxis-documentation-framework/issues/14&#34;&gt;got their permission&lt;/a&gt; to spin it off into Diátaxis.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:diataxis&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:django-measurement&#34;&gt;In &lt;a href=&#34;https://buildmedia.readthedocs.org/media/pdf/django/4.0.x/django.pdf&#34;&gt;the pdf build&lt;/a&gt; the tutorial is 70 pages, the how-to is 90, and the &amp;ldquo;using Django&amp;rdquo; section is 500.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:django-measurement&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Is Software Engineering Real Engineering?</title>
        <link>https://www.hillelwayne.com/talks/crossover-project/</link>
        <pubDate>Wed, 24 May 2023 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/talks/crossover-project/</guid>
        <description>

&lt;p&gt;Description: What makes software engineering different from “traditional” engineering? To find out, I interviewed 17 “crossovers”: people who have worked professionally as both a software and a traditional engineer. In aggregate, we learn three things: we are in fact engineers, we’re not actually that different as a field, and there’s a lot we can both teach and learn.&lt;/p&gt;

&lt;p&gt;Slides are &lt;a href=&#34;https://1drv.ms/p/s!Ajof90_miFF-m_NHGiD-6EkWbqCsWQ?e=mxuDy8&amp;amp;nav=eyJzSWQiOjQ3NywiY0lkIjozNzkxODg2OTUwfQ&#34;&gt;here&lt;/a&gt;. Video is &lt;a href=&#34;https://www.youtube.com/watch?v=CmIGPGPdxTI&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; padding-top: 30px; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube.com/embed/CmIGPGPdxTI&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&#34; allowfullscreen frameborder=&#34;0&#34; title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
 &lt;/div&gt;


&lt;h2 id=&#34;faq&#34;&gt;FAQ&lt;/h2&gt;

&lt;p&gt;These are some of the questions I remember people asking me after the talk. I&amp;rsquo;ll also put up questions emailed too.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why does it even matter if we&amp;rsquo;re engineers or not? Why can&amp;rsquo;t we just be software developers?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two reasons. First, lots of people do have strong opinions on the &amp;ldquo;engineering&amp;rdquo; question and use it to make strong value judgements on software as a field. I can&amp;rsquo;t tell people to &lt;em&gt;stop caring&lt;/em&gt; about this question, but I can try to make sure that if they compare &amp;ldquo;software&amp;rdquo; to &amp;ldquo;engineering&amp;rdquo;, they don&amp;rsquo;t have misconceptions about what &amp;ldquo;engineering&amp;rdquo; is.&lt;/p&gt;

&lt;p&gt;Second, I deeply, &lt;strong&gt;deeply&lt;/strong&gt; believe in the value of interdisciplinary dialogue. If software &lt;em&gt;is&lt;/em&gt; like engineering, then we can learn a lot &lt;em&gt;about&lt;/em&gt; software by studying engineering. Like, a lot of devs talk about how incredibly unpredictable software projects are, but every engineer I talked to said the same thing was true about their old jobs. So how do &lt;em&gt;they&lt;/em&gt; deal with unpredictability? Is it anything we could do, too?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you talk to people about job satisfaction?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A little. Most of the people strongly preferred their jobs in software than their old jobs in classical engineering.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you talk about meetings?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I did not. There&amp;rsquo;s still a lot to learn about software and trad engineering!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why didn&amp;rsquo;t you talk to biomedical/audio/environmental/etc engineers?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While I think there&amp;rsquo;s insights to learn from these people, too, I wanted to define &amp;ldquo;engineering&amp;rdquo; as conservatively as possible. I was worried that if I used a more liberal definition, software folk would be more skeptical of what I learned. By sticking to &amp;ldquo;stereotypical&amp;rdquo; engineering fields I can avoid that specific objection.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why do other fields think software is &amp;ldquo;easy&amp;rdquo;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every field seems easy until you actually get into it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Waterfall was originally agile from the start.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Winston Royce originally introduced &amp;ldquo;Waterfall&amp;rdquo; in &lt;a href=&#34;https://web.archive.org/web/20230308124552/https://www-scf.usc.edu/~csci201/lectures/Lecture11/royce1970.pdf&#34;&gt;Managing The Development of Large Software Systems&lt;/a&gt;. It&amp;rsquo;s a common misconception that he was originally &lt;em&gt;rejecting&lt;/em&gt; waterfall and advocating something more Agile-like. However, a close reading of the paper shows that while he recommends some changes to the basic waterfall approach, they remain highly waterfall and his result is still &amp;ldquo;highly waterfall&amp;rdquo; him support waterfall and most of his recommendations are to keep in the waterfall style. See &lt;a href=&#34;https://leanpub.com/leprechauns&#34;&gt;Leprechauns of Software Engineering&lt;/a&gt; for a more in-depth discussion.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Isn&amp;rsquo;t it too early to start collecting information about software &amp;ldquo;snapfits&amp;rdquo;? How do we know current solutions to EX plugin systems aren&amp;rsquo;t all fundamentally flawed?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I discuss this question in depth in &lt;a href=&#34;https://buttondown.email/hillelwayne/archive/in-defense-of/&#34;&gt;this&lt;/a&gt; essay.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So what &lt;em&gt;is&lt;/em&gt; the most important videogame ever made?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/the-most-important-video-game-ever-made/&#34;&gt;Space Traveler&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;

&lt;dl&gt;
&lt;dt&gt;Certification regulations&lt;/dt&gt;
&lt;dd&gt;&lt;ul&gt;
&lt;li&gt;Australia: &lt;a href=&#34;https://www.engineersaustralia.org.au/credentials/registration/state-registration&#34;&gt;https://www.engineersaustralia.org.au/credentials/registration/state-registration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Canada: &lt;a href=&#34;https://engineerscanada.ca/become-an-engineer/use-of-professional-title-and-designations&#34;&gt;https://engineerscanada.ca/become-an-engineer/use-of-professional-title-and-designations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;China: &lt;a href=&#34;https://www.atlantis-press.com/article/125938448.pdf&#34;&gt;https://www.atlantis-press.com/article/125938448.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Germany: &lt;a href=&#34;https://www.anerkennung-in-deutschland.de/html/en/2722.php&#34;&gt;https://www.anerkennung-in-deutschland.de/html/en/2722.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;UK: &lt;a href=&#34;https://www.engc.org.uk/ceng&#34;&gt;https://www.engc.org.uk/ceng&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;USA: &lt;a href=&#34;https://www.nspe.org/resources/licensure/what-pe&#34;&gt;https://www.nspe.org/resources/licensure/what-pe&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/dd&gt;
&lt;dt&gt;Books&lt;/dt&gt;
&lt;dd&gt;&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Software Craftsmanship:&lt;/em&gt; &lt;a href=&#34;https://www.oreilly.com/library/view/software-craftsmanship-the/0201733862/&#34;&gt;https://www.oreilly.com/library/view/software-craftsmanship-the/0201733862/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The Handbook of Industrial Engineering:&lt;/em&gt; &lt;a href=&#34;https://onlinelibrary.wiley.com/doi/book/10.1002/9780470172339&#34;&gt;https://onlinelibrary.wiley.com/doi/book/10.1002/9780470172339&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Engineering a Safer World:&lt;/em&gt; &lt;a href=&#34;https://direct.mit.edu/books/oa-monograph/2908/Engineering-a-Safer-WorldSystems-Thinking-Applied&#34;&gt;https://direct.mit.edu/books/oa-monograph/2908/Engineering-a-Safer-WorldSystems-Thinking-Applied&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The first snap-fit handbook:&lt;/em&gt; &lt;a href=&#34;https://www.sciencedirect.com/book/9783446227538/the-first-snap-fit-handbook&#34;&gt;https://www.sciencedirect.com/book/9783446227538/the-first-snap-fit-handbook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/dd&gt;
&lt;dt&gt;Quotations&lt;/dt&gt;
&lt;dd&gt;&lt;ul&gt;
&lt;li&gt;Jeff Atwood: &lt;a href=&#34;https://blog.codinghorror.com/bridges-software-engineering-and-god/&#34;&gt;https://blog.codinghorror.com/bridges-software-engineering-and-god/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Systems guy: No direct quote, but see &lt;a href=&#34;https://quoteinvestigator.com/2019/09/19/woodpecker/&#34;&gt;https://quoteinvestigator.com/2019/09/19/woodpecker/&lt;/a&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/dd&gt;
&lt;dt&gt;Misc&lt;/dt&gt;
&lt;dd&gt;&lt;ul&gt;
&lt;li&gt;The formal methods sample code is the &lt;a href=&#34;https://github.com/hwayne/lets-prove-leftpad/tree/master/isabelle&#34;&gt;Isabelle proof&lt;/a&gt; from &lt;a href=&#34;https://github.com/hwayne/lets-prove-leftpad&#34;&gt;let&amp;rsquo;s prove leftpad&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.theverge.com/2014/10/20/7014705/coding-error-911-fcc-washington&#34;&gt;A preventable coding error knocked out 911 service for millions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Capacitor specsheet: &lt;a href=&#34;https://store.comet.bg/download-file.php?id=10107&#34;&gt;https://store.comet.bg/download-file.php?id=10107&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/dd&gt;
&lt;/dl&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Somehow AutoHotKey is kinda good now</title>
        <link>https://www.hillelwayne.com/post/ahk-v2/</link>
        <pubDate>Wed, 03 May 2023 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/ahk-v2/</guid>
        <description>

&lt;style&gt; img {border-style: groove; border-width: 1px;}&lt;/style&gt;

&lt;p&gt;I love &lt;a href=&#34;https://www.autohotkey.com/&#34;&gt;Autohotkey&lt;/a&gt; so much that &lt;a href=&#34;https://www.hillelwayne.com/post/ahk/&#34;&gt;it keeps me on Windows&lt;/a&gt;. It&amp;rsquo;s the best GUI automation tool out there. Here&amp;rsquo;s a shortcut that opens my current browser tab in the &lt;a href=&#34;https://web.archive.org/&#34;&gt;Wayback Machine&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;#HotIf&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;WinActive&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ahk_exe firefox.exe&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;!^&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;::&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;Keywait(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;RControl&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;Keywait(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;RAlt&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;SendEvent(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;^l&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;SendInput(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;{left}https://web.archive.org/web/*/{enter}&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;#HotIf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By comparison, the &lt;a href=&#34;https://github.com/internetarchive/wayback-machine-webextension/blob/master/webextension/scripts/archive.js&#34;&gt;official extension&lt;/a&gt; takes four &lt;em&gt;files&lt;/em&gt; to do the same thing. Four files!&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:caveat&#34;&gt;&lt;a href=&#34;#fn:caveat&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;But I come here to bury AHK, not to praise it. In January AutoHotKey v2 got released and it&amp;rsquo;s wildly backwards incompatible with v1. I had to change maybe 20% of my code to get it working again. And I got off easy, I don&amp;rsquo;t have any third party scripts!&lt;/p&gt;

&lt;p&gt;The trauma of Python replacing &lt;code&gt;print x&lt;/code&gt; with &lt;code&gt;print(x)&lt;/code&gt; is legendary. Couldn&amp;rsquo;t they have updated AHK without breaking everything?&lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;You see, AHK v1 was very, very bad.&lt;/p&gt;

&lt;h2 id=&#34;why-ahk-was-bad&#34;&gt;Why AHK was bad&lt;/h2&gt;

&lt;h3 id=&#34;implicit-strings&#34;&gt;Implicit Strings&lt;/h3&gt;

&lt;p&gt;So imagine you just got started with AHK and want to show a message box. You boot up v1 and write&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;MsgBox&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Hello&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In v1 you don&amp;rsquo;t have to surround strings with quotes. It means less syntax— easier for normies— up until the point you want to include a variable. In most languages you&amp;rsquo;d write something like &lt;code&gt;&amp;quot;Hello &amp;quot; . name&lt;/code&gt; but AHK will take that a little too literally:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/msgbox.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Fortunately you can still %interpolate% the variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Jeff&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;MsgBox&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Hello&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;%name%&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now what if you want to show the name in ALLCAPS? Easy, just do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Jeff&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;tmp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;StringUpper(name)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;MsgBox&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Hello&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;%tmp%&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Surprise! The hacked on interpolation syntax isn&amp;rsquo;t &lt;em&gt;real&lt;/em&gt; interpolation and anything besides a single variable name is a syntax error. This implicit-stringness plagued all the commands, many of which took variables &lt;em&gt;and&lt;/em&gt; strings. In &lt;code&gt;WinWait y, y, y&lt;/code&gt; the first two y&amp;rsquo;s are the &lt;em&gt;string&lt;/em&gt; &amp;ldquo;y&amp;rdquo; while the last y is the value of the &lt;em&gt;variable&lt;/em&gt; &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;v2 got rid of implicit strings, so now you instead do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Jeff&amp;quot;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;MsgBox(Format(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Hello {1}!&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;StrUpper(name)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I removed six different &lt;code&gt;tmp&lt;/code&gt; hacks.&lt;/p&gt;

&lt;h3 id=&#34;inconsistent-function-command-syntax&#34;&gt;Inconsistent function/command syntax&lt;/h3&gt;

&lt;p&gt;My sample above isn&amp;rsquo;t actually valid AHKv1. It calls &lt;code&gt;StringUpper&lt;/code&gt; like a function, but it&amp;rsquo;s actually a command. Since it&amp;rsquo;s a command, you instead write:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Jeff&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;StringUpper,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;name,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;tmp&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;MsgBox&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Hello&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;%tmp%&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yes, &lt;code&gt;StringUpper&lt;/code&gt; is implicitly defining a new variable, yes you &lt;em&gt;have&lt;/em&gt; to assign the output if you want to do anything with it, yes v1 had regular functions too and the whole distinction is pointless.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:functions&#34;&gt;&lt;a href=&#34;#fn:functions&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; It&amp;rsquo;s just that functions were added &lt;a href=&#34;https://web.archive.org/web/20130620190653/http://www.autohotkey.com/changelog/#.UcNSzvbP0Q8&#34;&gt;circa 2005&lt;/a&gt;, so all of the existing commands stayed commands for backwards compatibility.&lt;/p&gt;

&lt;p&gt;In v2 everything&amp;rsquo;s just a function. &lt;code&gt;tmp := StrUpper(name)&lt;/code&gt; works fine. There&amp;rsquo;s still functions like &lt;code&gt;MouseGetPos&lt;/code&gt; that assign output to its arguments but at least you now have to explicitly pass in references, like &lt;code&gt;MouseGetPos &amp;amp;xpos, &amp;amp;ypos&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&#34;other-command-function-problems&#34;&gt;Other command/function problems&lt;/h4&gt;

&lt;p&gt;How do you check if &lt;code&gt;x&lt;/code&gt; is equal to &lt;code&gt;10&lt;/code&gt;? &lt;code&gt;IfEquals x, 10&lt;/code&gt;. How do you check if a keypress &lt;code&gt;k&lt;/code&gt; isn&amp;rsquo;t in &amp;ldquo;aeiou&amp;rdquo;? &lt;code&gt;IfNotInString k, aeiou&lt;/code&gt;.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:if&#34;&gt;&lt;a href=&#34;#fn:if&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;There were nineteen special &lt;code&gt;if&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;v1 got a generalized function &lt;code&gt;if&lt;/code&gt; in 2009, but beginners would regularly use the command &lt;code&gt;if&lt;/code&gt;s instead of the function &lt;code&gt;if&lt;/code&gt;. Thirteen years later v2 disarmed this footgun once and for all.&lt;/p&gt;

&lt;h3 id=&#34;error-level&#34;&gt;Error level&lt;/h3&gt;

&lt;p&gt;v1 had a global value called &lt;code&gt;ErrorLevel&lt;/code&gt;, which roughly &lt;a href=&#34;https://www.hillelwayne.com/post/software-mimicry/&#34;&gt;mimics&lt;/a&gt; return codes from shell programs. If you tried calling &lt;a href=&#34;https://www.autohotkey.com/docs/v1/lib/SoundPlay.htm&#34;&gt;SoundPlay&lt;/a&gt; but it couldn&amp;rsquo;t play the sound, AHK would set ErrorLevel to 1.&lt;/p&gt;

&lt;p&gt;Now there&amp;rsquo;s an obvious problem with this, which is that it was global state &lt;em&gt;changed by everything&lt;/em&gt;. You could never be 100% sure that the ErrorLevel you read came from the command you expected it. v1 did keep a separate ErrorLevel for each thread so at least it was mostly thread safe. Mostly but not completely: thread interrupts would truncate ErrorLevel strings longer than 127 characters.&lt;/p&gt;

&lt;p&gt;You may be asking why ErrorLevel could even &lt;em&gt;be&lt;/em&gt; a string, and it&amp;rsquo;s because v1 was terrible. While &lt;code&gt;SoundPlay&lt;/code&gt; would only set 0 or 1, &lt;a href=&#34;https://www.autohotkey.com/docs/v1/lib/SoundGet.htm&#34;&gt;SoundGet&lt;/a&gt; would set ErrorLevel to&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Invalid Control Type or Component Type&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Can&amp;rsquo;t Open Specified Mixer&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Mixer Doesn&amp;rsquo;t Support This Component Type&amp;rdquo;&lt;/li&gt;
&lt;li&gt;[etc]&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;In fact you can stuff whatever arbitrary thing you want in ErrorLevel, and at some point v1 abandoned the pretence that it was for &amp;ldquo;errors&amp;rdquo;. For example, calling &lt;code&gt;StringReplace&lt;/code&gt; would set the ErrorLevel to the number of substrings it replaced.&lt;/p&gt;

&lt;p&gt;v2 just uses try/catch blocks.&lt;/p&gt;

&lt;h3 id=&#34;the-goddamn-object-hash-tables&#34;&gt;The goddamn object hash tables&lt;/h3&gt;

&lt;p&gt;This one has a special place in hell. v1 didn&amp;rsquo;t have proper hash tables; you instead defined a new object where the fields were your &amp;ldquo;keys&amp;rdquo;. In AHK, then and now, all identifiers are case insensitive. So the &amp;ldquo;hash table&amp;rdquo; &lt;code&gt;{a: 1, A: 2}&lt;/code&gt; is equivalent to &lt;code&gt;{a: 2}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While small in comparison to the other problems, this one had the extra twist of being completely undocumented. You were just supposed to know that because commands weren&amp;rsquo;t case sensitive, hash keys weren&amp;rsquo;t either. I wasted so much time debugging this.&lt;/p&gt;

&lt;p&gt;v2 still doesn&amp;rsquo;t have case sensitive identifiers but it &lt;em&gt;does&lt;/em&gt; have a dedicated &lt;code&gt;Map&lt;/code&gt; class which behaves as it should.&lt;/p&gt;

&lt;h3 id=&#34;miscellaneous-terriblenesses&#34;&gt;Miscellaneous terriblenesses&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Most errors would create anomalous behavior: invalid array lookups returned empty values, as would referencing missing variables.&lt;/li&gt;
&lt;li&gt;Instead of taking function callbacks, commands like &lt;code&gt;SetTimer&lt;/code&gt; and &lt;code&gt;OnClick&lt;/code&gt; took labels. Then they&amp;rsquo;d invoke a &lt;code&gt;goto&lt;/code&gt;. This was exactly as bad as you think.&lt;/li&gt;
&lt;li&gt;Just kidding, it was worse. &lt;code&gt;goto&lt;/code&gt; could take dynamically computed labels and it could jump from inside a function to outside.&lt;/li&gt;
&lt;li&gt;Multiline hotkeys had to end with a &lt;code&gt;return&lt;/code&gt; statement, while single-line ones didn&amp;rsquo;t. Not a deal-breaker, just annoying.&lt;/li&gt;
&lt;li&gt;v1 ignored any script setup or global assignments after the first defined hotkey, even if that hotkey was in an included file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;ahkv2-is-worth-it&#34;&gt;AHKv2 is worth it&lt;/h2&gt;

&lt;p&gt;So with all those issues, you&amp;rsquo;d probably wonder why anybody would bother. The language was terrible, now it&amp;rsquo;s passable. But passable is a very low bar, and there&amp;rsquo;s plenty of good languages out there already.&lt;/p&gt;

&lt;p&gt;The thing is, even when it was a terrible language, AHK was still worth using. Nothing else filled or even cared about its niche: modifying the behavior of other programs. Normally, if I want to extend a program, I need to use its plugin system. That means learning:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The provided APIs&lt;/li&gt;
&lt;li&gt;The capabilities, limits, and idiosyncrasies of the system&lt;/li&gt;
&lt;li&gt;The entire development environment needed to write plugins in whatever language&lt;/li&gt;
&lt;li&gt;How to actually deploy the plugin, which always takes way more time than I&amp;rsquo;d hope.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that&amp;rsquo;s &lt;em&gt;if&lt;/em&gt; there&amp;rsquo;s a plugin system in the first place; there is no way to extend the desktop Spotify app short of writing a new client from scratch.&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s why AutoHotKey is so useful. It can &lt;a href=&#34;https://www.autohotkey.com/docs/v2/lib/WinActivate.htm&#34;&gt;target windows&lt;/a&gt;, &lt;a href=&#34;https://www.autohotkey.com/docs/v2/lib/ImageSearch.htm&#34;&gt;find pictures&lt;/a&gt;, and &lt;a href=&#34;https://www.autohotkey.com/docs/v2/lib/Click.htm&#34;&gt;send input&lt;/a&gt;, which is enough to jury rig my own &amp;ldquo;plugins&amp;rdquo; regardless of what the program actually supports. v1 may have sucked but the alternative was &lt;em&gt;not&lt;/em&gt; being able to do that. And now the language is actually okay! Life is great!&lt;/p&gt;

&lt;h3 id=&#34;v2-in-action&#34;&gt;v2 in action&lt;/h3&gt;

&lt;p&gt;I run formal methods workshops. FM tools have unfamiliar syntax and semantics to programmers, and many have terrible error messages. To keep classes from getting bogged down in people having syntax errors, I go through a list of &amp;ldquo;checkpoints&amp;rdquo; for each spec. We start with a blank file and modify it to checkpoint 1, then modify it to checkpoint 2, etc. If someone&amp;rsquo;s spec won&amp;rsquo;t compile, they can just run a &lt;code&gt;diff&lt;/code&gt; to see their mistake.&lt;/p&gt;

&lt;p&gt;I like this approach but had two problems I needed to fix. First, people need to know &lt;em&gt;which&lt;/em&gt; checkpoint we&amp;rsquo;re on, and they must be able to find out without disrupting the class. Second, if I don&amp;rsquo;t follow the checkpoints &lt;em&gt;exactly&lt;/em&gt;, the diffs won&amp;rsquo;t show people what they got wrong.&lt;/p&gt;

&lt;p&gt;I solved both of these with AHK. The script shows the current checkpoint on my shared screen, the checkpoint content on my private screen, and switches to the next checkpoint when I press &lt;code&gt;6&lt;/code&gt; on the numpad. Here&amp;rsquo;s what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;img/workshop-script.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;And here&amp;rsquo;s the whole program:&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show code
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-ahk&#34; data-lang=&#34;ahk&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;#SingleInstance&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Force&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Gui(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;AlwaysOnTop Resize&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Workshop Spec Controller&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Display&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Gui(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ToolWindow AlwaysOnTop +Owner&amp;quot;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Hwnd,&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Workshop Spec&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Display&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;SetFont(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Display&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;MarginY&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Display&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Add(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Text&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;section&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Current Spec:&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Display&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;SetFont(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;s16&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;SpecNum&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Display&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Add(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Text&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;W230 vSpecNum&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;SpecNameCtrl&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;AddComboBox(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;vName&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;example1&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;example2&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;etc&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;])&lt;/span&gt;
                &lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;AddEdit(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;vSpecNumber yp&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;SpecNumberCtrl&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;AddUpDown(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Range1-20&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;cSpecText&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;AddEdit(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;r40 vSpecText xm w300 -WantReturn&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;cSpecText&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;SetFont(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;s12&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;consolas&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;UpdateSpecBtn&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Add(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Button&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Default w0&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;SpecNumberCtrl&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;OnEvent(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Change&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UpdateSpecTracker)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;UpdateSpecBtn&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;OnEvent(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Click&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;UpdateSpecTracker)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Display&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;OnEvent(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Close&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;CloseAll)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;OnEvent(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Close&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;CloseAll)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;Display&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Show(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;W230 x60 y1200&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Show(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;x2700 y500&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;set_text(text,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;num)&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;specname&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Format(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;{1}__{2:02}.tla&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;text,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;num)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;SpecNum&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Text&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;specname&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;path\to\specs&amp;quot;&lt;/span&gt;  &lt;span style=&#34;color: #f8f8f2&#34;&gt;text&lt;/span&gt;  &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;\&amp;quot;&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;specname&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;FileExist&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(file)&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;spec&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;FileRead(file)&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;cSpecText&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;spec&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;Controller&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Show(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;AutoSize&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color: #f8f8f2&#34;&gt;cSpecText&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;file&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;UpdateSpecTracker(ctrl,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;info)&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;set_text(SpecNameCtrl&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;text,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;SpecNumberCtrl&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;value)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;CloseAll(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;ExitApp&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;NumpadRight::ControlSend&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;{up}&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Edit2&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Workshop Spec Controller&amp;quot;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;NumpadLeft::ControlSend&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;{down}&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Edit2&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Workshop Spec Controller&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Two GUIs, communicating state, two global hotkeys, less than 50 lines of code. AHK is &lt;em&gt;wonderful&lt;/em&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;If you&amp;rsquo;re on Windows you can download AHKv2 &lt;a href=&#34;https://www.autohotkey.com/&#34;&gt;here&lt;/a&gt; or via &lt;code&gt;winget install AutoHotkey.AutoHotkey&lt;/code&gt;. Mac users may be able to get similar benefits with a mix of &lt;a href=&#34;https://www.hammerspoon.org/&#34;&gt;Hammerspoon&lt;/a&gt; and &lt;a href=&#34;https://support.apple.com/guide/shortcuts-mac/welcome/mac&#34;&gt;Shortcuts&lt;/a&gt; (which I&amp;rsquo;m very jealous of). Feel free to email me if you have questions about AHK— I love helping other devs get started.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://predr.ag/&#34;&gt;Predrag Gruevski&lt;/a&gt; for feedback. If you liked this, come join my &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt;! I write essays once a week.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:caveat&#34;&gt;I mean it&amp;rsquo;s doing a lot of other stuff too, but it&amp;rsquo;s stuff I don&amp;rsquo;t need. My five-minute script solves my needs just fine.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:caveat&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:functions&#34;&gt;No, you can&amp;rsquo;t use normal functions in a variable interpolation, either.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:functions&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:if&#34;&gt;And of course, if you wanted to check that the string &lt;code&gt;&amp;quot;k&amp;quot;&lt;/code&gt; wasn&amp;rsquo;t in the variable &lt;code&gt;aeiou&lt;/code&gt;, it&amp;rsquo;d be &lt;code&gt;tmp = k&lt;/code&gt;, &lt;code&gt;ifNotInString tmp, %aeiou%&lt;/code&gt;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:if&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Breaking the limits of TLA&#43; model checking</title>
        <link>https://www.hillelwayne.com/post/graphing-tla/</link>
        <pubDate>Mon, 17 Apr 2023 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/post/graphing-tla/</guid>
        <description>

&lt;p&gt;I haven&amp;rsquo;t written much about TLA+ on the blog since the new &lt;a href=&#34;https://learntla.com/&#34;&gt;learntla&lt;/a&gt; went up. Any examples or special topics I think of go there instead. But I recently thought of a cool demo that doesn&amp;rsquo;t quite fit the theme of that book: there are some things you can&amp;rsquo;t easily check with the model checker but &lt;em&gt;can&lt;/em&gt; check if you work with the state space as a directed graph.&lt;/p&gt;

&lt;p&gt;Take for example &lt;dfn&gt;observational determinism&lt;/dfn&gt; (OD): does an algorithm always converge on the &lt;em&gt;same&lt;/em&gt; answer? Let&amp;rsquo;s use the example of four threads, each nonatomically incrementing a counter once. To show that the final value of &lt;code&gt;x&lt;/code&gt; isn&amp;rsquo;t always 4, you just have find one trace where it&amp;rsquo;s not 4. But to show that the final value is &lt;em&gt;inconsistent&lt;/em&gt;, you have to find &lt;em&gt;two&lt;/em&gt; traces that get different answers! The TLA+ model checker (TLC) can do the first but not the second.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show spec
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-tla&#34; data-lang=&#34;tla&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;------------------------------&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;MODULE&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;threads&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;------------------------------&lt;/span&gt;

&lt;span style=&#34;color: #f92672&#34;&gt;EXTENDS&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Integers&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Threads&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;..&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color: #75715e&#34;&gt;\* four threads!&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;(* --algorithm threads&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;variables&lt;/span&gt; 
  &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;

&lt;span style=&#34;color: #f92672&#34;&gt;process&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;thread&lt;/span&gt; &lt;span style=&#34;color: #e6db74&#34;&gt;\in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Threads&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;variables&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;tmp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;begin&lt;/span&gt;
&lt;span style=&#34;color: #f92672&#34;&gt;  Get:&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;tmp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;x;&lt;/span&gt;

&lt;span style=&#34;color: #f92672&#34;&gt;  Inc:&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;tmp&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;end process&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;

&lt;span style=&#34;color: #a6e22e&#34;&gt;end algorithm; *)&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;====&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;If you wanted to test for observational determinism, you&amp;rsquo;d normally have to &lt;a href=&#34;https://www.hillelwayne.com/post/software-mimicry/&#34;&gt;mimic&lt;/a&gt; it with some hairy &amp;ldquo;hypermodeling&amp;rdquo; tricks I &lt;a href=&#34;https://www.hillelwayne.com/post/hyperproperties/&#34;&gt;wrote about here&lt;/a&gt;. Not only is this difficult and fragile, it&amp;rsquo;s also really inefficient. The regular model has only 755 distinct states, while the hypermodel has over 100,000! It&amp;rsquo;d be much easier if we could &amp;ldquo;step outside&amp;rdquo; the model checker and just examine the state space directly.&lt;/p&gt;

&lt;p&gt;So I started looking for a way. And I got a lot further than I expected, well past checking OD and all the way into finding probabilities! If you want to poke around with any of the components, you can download the whole project &lt;a href=&#34;https://github.com/hwayne/tla-graphing-demo&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;steps&#34;&gt;Steps&lt;/h1&gt;

&lt;h2 id=&#34;1-get-the-state-space-dump&#34;&gt;1. Get the state space dump&lt;/h2&gt;

&lt;p&gt;This is easy, just model check with &lt;code&gt;-dump dot,actionlabels file&lt;/code&gt;. TLC will output a &lt;a href=&#34;https://graphviz.org/&#34;&gt;graphviz&lt;/a&gt; file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-graphviz&#34; data-lang=&#34;graphviz&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;strict&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;digraph&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;DiskGraph&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; {&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;nodesep&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0.35&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;subgraph&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;cluster_graph&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; {&lt;/span&gt;
&lt;span style=&#34;color: #a6e22e&#34;&gt;color&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;white&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #ae81ff&#34;&gt;2665600213816166005&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; [&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;label&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;/\\ x = 0\n/\\ pc = &amp;lt;&amp;lt;\&amp;quot;Get\&amp;quot;, \&amp;quot;Get\&amp;quot;, \&amp;quot;Get\&amp;quot;, \&amp;quot;Get\&amp;quot;&amp;gt;&amp;gt;\n/\\ tmp = &amp;lt;&amp;lt;0, 0, 0, 0&amp;gt;&amp;gt;&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;style&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; = &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;filled&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;color: #ae81ff&#34;&gt;2665600213816166005&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;-1245546546836852765&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; [&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;label&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Get&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;color&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;black&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;fontcolor&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;black&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;// 2000 more lines&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s…   going to be hard to work with.&lt;/p&gt;

&lt;h2 id=&#34;2-clean-up-the-file&#34;&gt;2. Clean up the file&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s replace the node ids with something a little more readable. I wrote a script to replace each node id with a short string. The first node in the file is renamed to &amp;ldquo;a&amp;rdquo;, the second to &amp;ldquo;b&amp;rdquo;, the twenty-seventh to &amp;ldquo;ab&amp;rdquo;, and the 5796th to &amp;ldquo;aaa&amp;rdquo;. I took this as an opportunity to learn some Rust.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:rust&#34;&gt;&lt;a href=&#34;#fn:rust&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show code
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;//use std::io;&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;#![allow(unused_imports)]&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;#![allow(dead_code)]&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;#![allow(unused_variables)]&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;use&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; std&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;fmt;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;use&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; std&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;fs;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;use&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; std&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;path&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;Path;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;use&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; std&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;env;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;use&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; regex&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;Regex; &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;// 1.7.1&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;use&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; std&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;collections&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;HashMap;&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;num_to_id_str&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(id&lt;/span&gt;: &lt;span style=&#34;color: #66d9ef&#34;&gt;u32&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;) &lt;/span&gt;-&amp;gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; out&lt;/span&gt;: &lt;span style=&#34;color: #f8f8f2&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; String&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;with_capacity(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;);&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id&lt;/span&gt;: &lt;span style=&#34;color: #66d9ef&#34;&gt;u32&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id;&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;while&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;!=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        id &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        out.push(((id &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;%&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;) &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;97&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;) &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;as&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;u8&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;as&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        id &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    };&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    out.chars().rev().collect&lt;/span&gt;::&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;next_id_str&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(id&lt;/span&gt;: &lt;span style=&#34;color: #66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;u32&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;) &lt;/span&gt;-&amp;gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;id &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;id &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    num_to_id_str(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;id)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;


&lt;span style=&#34;color: #66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;() {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id&lt;/span&gt;: &lt;span style=&#34;color: #66d9ef&#34;&gt;u32&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; replacement_table&lt;/span&gt;: &lt;span style=&#34;color: #a6e22e&#34;&gt;HashMap&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;str&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, String&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; HashMap&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;new();&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; args&lt;/span&gt;: &lt;span style=&#34;color: #f8f8f2&#34;&gt;Vec&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; env&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;args().collect();&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; file_path&lt;/span&gt;: &lt;span style=&#34;color: #66d9ef&#34;&gt;&amp;amp;str&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;args[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; out_path&lt;/span&gt;: &lt;span style=&#34;color: #66d9ef&#34;&gt;&amp;amp;str&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;args[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; graph &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; fs&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;read_to_string(file_path)&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        .expect(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Should have been able to read the file&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; out &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; String&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;with_capacity((&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;graph).len());&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; re &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; Regex&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;new(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;r&amp;quot;-?[[:digit:]]{10,}&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;).unwrap();&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; unchanged_chunks &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; re.split(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;graph);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; text_words &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; re.find_iter(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;graph); &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;//needs to be mut for iteration&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; chunk &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;in&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; unchanged_chunks {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        out.push_str(chunk);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;match&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; text_words.next() {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;            Some(mat) &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;                &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; key &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; mat.as_str();&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;                &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;if&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;replacement_table.contains_key(key) {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;                    replacement_table.insert(key, next_id_str(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id));&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;                }&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;                out.push_str(replacement_table.get(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;key).unwrap());&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;            }&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;            None &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        };&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    }&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    fs&lt;/span&gt;::&lt;span style=&#34;color: #f8f8f2&#34;&gt;write(out_path, out).expect(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;Unable to write file&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;


&lt;span style=&#34;color: #75715e&#34;&gt;#[cfg(test)]&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;tests {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;use&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;super&lt;/span&gt;::&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;#[test]&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;it_increments&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;() {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id&lt;/span&gt;: &lt;span style=&#34;color: #66d9ef&#34;&gt;u32&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        next_id_str(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        next_id_str(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;assert_eq!&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(id, &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;); &lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    }&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;#[test]&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;str_generator&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;() {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; results&lt;/span&gt;: &lt;span style=&#34;color: #f8f8f2&#34;&gt;Vec&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;vec!&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;25&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;28&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;52&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;53&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;].iter().map(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;|&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; num_to_id_str(x)).collect();&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;assert_eq!&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(results, &lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;vec!&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;y&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;z&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;aa&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ab&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;az&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;ba&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    }&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;#[test]&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color: #a6e22e&#34;&gt;incrementor_and_generator&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;() {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;let&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id&lt;/span&gt;: &lt;span style=&#34;color: #66d9ef&#34;&gt;u32&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        next_id_str(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;assert_eq!&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(next_id_str(&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;mut&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; id), &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;);&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;    }&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;h2 id=&#34;3-try-gephi&#34;&gt;3. Try Gephi&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://gephi.org/&#34;&gt;Gephi&lt;/a&gt; is a graph analysis tool. I used it because it was the first tool I found. There&amp;rsquo;s probably better ones out there.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;img/graph1.png&#34;&gt;&lt;img src=&#34;img/graph1.png&#34; alt=&#34;The Gephi IDE, randomly shoving all the nodes in a square&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uhhhhhh that&amp;rsquo;s a mess. Let&amp;rsquo;s run a layout algorithm to make it at least tractable.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;img/forcegraph.png&#34;&gt;&lt;img src=&#34;img/forcegraph.png&#34; alt=&#34;The graph laid out slightly better&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s a little better. Those little dots on the bottom of the graph are graphviz options that got accidentally turned into nodes. I went through the data table and manually deleted them.&lt;/p&gt;

&lt;h2 id=&#34;4-discover-that-gephi-is-terrible&#34;&gt;4. Discover that Gephi is terrible&lt;/h2&gt;

&lt;p&gt;Gephi can make nice looking graphs and not much else. After fighting through the terrible documentation and UX I managed to filter for initial and terminal states. You can see the queries on the right-hand side of the window. Once I got the filters working I added a &amp;ldquo;Type&amp;rdquo; data column and labelled the corresponding states. That way I could assign special colors to root and terminal nodes.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;img/graph-colored.png&#34;&gt;&lt;img src=&#34;img/graph-colored.png&#34; alt=&#34;Same layout, but now the nodes have colors&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, I could manually look through the terminal nodes and see that they have different values of &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;img/graph-terminal.png&#34;&gt;&lt;img src=&#34;img/graph-terminal.png&#34; alt=&#34;Looking at the labels of the terminal states&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, so OD is refuted. I&amp;rsquo;m interested in checking more than just observational determinism, though, and I wanted to see what else Gephi could do. To start with, I wanted to extract the &lt;code&gt;x&lt;/code&gt; value from the label and put it in its own column. After that, I&amp;rsquo;d see which values are most common in terminal states.&lt;/p&gt;

&lt;p&gt;This is where I learned that Gephi hates me.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;only&lt;/em&gt; way to extract &lt;code&gt;x&lt;/code&gt; is to duplicate the column and do a regex find/replace on the whole string. Gephi defaults to running the find/replace on every single column and resets that default every time you reopen the find/replace modal. If you forget to re-enable it just once then it&amp;rsquo;s time to reload the graph and start over, because &lt;strong&gt;there&amp;rsquo;s no way to undo changes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In fact nothing in Gephi is undoable, and nothing is well documented, which together make the system inscrutable. You can&amp;rsquo;t learn what buttons do and you can&amp;rsquo;t safely try them out, especially when some buttons do things like &amp;ldquo;wipe all your layout and customizations and go back to grey blobs.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;…In retrospect, I should&amp;rsquo;ve guessed Gephi was a dead end.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:gephi-lite&#34;&gt;&lt;a href=&#34;#fn:gephi-lite&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; I don&amp;rsquo;t want to repeat painstaking manual labor every time I change the spec. What I really want is a software library.&lt;/p&gt;

&lt;p&gt;(Unrelated, it&amp;rsquo;s interesting that most languages don&amp;rsquo;t have a &lt;code&gt;graph&lt;/code&gt; type in their standard library. I&amp;rsquo;m guessing it&amp;rsquo;s because graphs have lots of different representations, which also have very different performance and API considerations.)&lt;/p&gt;

&lt;h2 id=&#34;5-start-over-with-networkx&#34;&gt;5. Start over with NetworkX&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://networkx.org/&#34;&gt;NetworkX&lt;/a&gt; is a graph analysis library. I used it because I already know Python. There&amp;rsquo;s probably better ones out there.&lt;/p&gt;

&lt;p&gt;NetworkX represents graphs as a dict of dicts of dicts.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:dict-of-dicts&#34;&gt;&lt;a href=&#34;#fn:dict-of-dicts&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; As far as I could figure out, you have to implement graph operations imperatively. For example, to extract &lt;code&gt;x&lt;/code&gt; from the label, I had to iterate through every node and add &lt;code&gt;x&lt;/code&gt; as an attribute.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;node&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;G:&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;label&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;G&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;nodes[node][&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;label&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;re&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;search(&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;r&amp;#39;x\s*=\s*(\d+)&amp;#39;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;label)&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;group(&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color: #f8f8f2&#34;&gt;G&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;nodes[node][&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;int(x)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To find the terminal states, I first removed all the self-loops, and then filtered for all the nodes with zero outbound degree (no outbound edges).&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;G&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;remove_edges_from(nx&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;selfloop_edges(G))&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;terminals&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;[n&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;n,&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;deg&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;G&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;out_degree()&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;deg&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After that, I can pull all their &lt;code&gt;x&lt;/code&gt; attributes to see the spread.&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;collections&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;Counter&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Counter([G&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;nodes[t][&lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color: #f92672&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color: #f8f8f2&#34;&gt;terminals])&lt;/span&gt;

&lt;span style=&#34;color: #75715e&#34;&gt;# output&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;Counter({&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;36&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color: #ae81ff&#34;&gt;23&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So there are some end states where &lt;code&gt;x=4&lt;/code&gt; and some where &lt;code&gt;x=3&lt;/code&gt;, proving that our system is &lt;em&gt;not&lt;/em&gt; observationally deterministic.&lt;/p&gt;

&lt;h2 id=&#34;6-go-mad-with-power-and-probability&#34;&gt;6. Go mad with power (and probability)&lt;/h2&gt;

&lt;p&gt;Something I wasn&amp;rsquo;t expecting: &lt;code&gt;x != 4&lt;/code&gt; in three quarters of the end states. That seems really high for a race condition! I implemented the spec in C++ and it only had the race condition 0.1% of the time.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:cpp&#34;&gt;&lt;a href=&#34;#fn:cpp&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;p&gt;
&lt;div class=&#34;details-container&#34;&gt;

&lt;details&gt;

  &lt;summary&gt;
    Show C&amp;#43;&amp;#43; code
  &lt;/summary&gt;
  &lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;#include&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;#include&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;&amp;lt;thread&amp;gt;&lt;/span&gt;
&lt;span style=&#34;color: #75715e&#34;&gt;#include&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #75715e&#34;&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;const&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; NUMRUNS &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;30000&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;const&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; NUMTHREADS &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; x &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #66d9ef&#34;&gt;bool&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; wait &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; true;&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;increment_x&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;while&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; (wait) {;}&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; tmp &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; x;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    tmp &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; tmp &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    x &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; tmp;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;return&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; NULL;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #a6e22e&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; results[NUMTHREADS] {&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;};&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    std&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;vector&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;std&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;thread&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; threads(NUMTHREADS);&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; i &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;; i &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; NUMRUNS; i&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;++&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;) {&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;      x &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;      wait &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; true;&lt;/span&gt;

&lt;span style=&#34;color: #f8f8f2&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; j&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;; j &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; NUMTHREADS; j&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;++&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;) threads[j] &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; std&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;thread&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(increment_x);&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;      &lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;      wait &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; false;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; (&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;auto&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; th &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; threads) th.join();&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;      results[x&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;-1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;] &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;; &lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    }&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color: #66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; i &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;; i &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; NUMTHREADS; i&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;++&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;) std&lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;cout &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;  results[i] &lt;/span&gt;&lt;span style=&#34;color: #f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #e6db74&#34;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span style=&#34;color: #f8f8f2&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;color: #f8f8f2&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/details&gt;
&lt;button class=&#34;details-open-all&#34;&gt;show all&lt;/button&gt;
&lt;/div&gt;
&lt;/p&gt;

&lt;/p&gt;

&lt;p&gt;There are two reasons why &amp;ldquo;count the end states&amp;rdquo; misestimates the likelihood. First, it assumes there&amp;rsquo;s only one path per end state. To see why this is a problem, here&amp;rsquo;s the state space for two threads:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;img/2threads.png&#34;&gt;&lt;img src=&#34;img/2threads.png&#34; alt=&#34;The state space for 2 threads with a race condition&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The space has three end states, and &lt;code&gt;x = 2&lt;/code&gt; in two of those. But there are four &lt;em&gt;paths&lt;/em&gt; to those three end states; two of them end in &lt;code&gt;x = 1&lt;/code&gt;. That means it&amp;rsquo;s twice as likely to happen as either of the other states, &lt;em&gt;assuming&lt;/em&gt; all transitions are equally likely.&lt;/p&gt;

&lt;p&gt;And that&amp;rsquo;s the second issue: all transitions are &lt;em&gt;not&lt;/em&gt; equally likely. In the spec, a Get followed by a second Get represents one thread interrupting another. Threads (on Windows) get 20ms slices at a time, and both assignment and increment operations both happen on the nanosecond scale. Each thread will more often complete both operations than complete one and then get interrupted. So two consecutive Gets should happen pretty rarely.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Pretty rarely&amp;rdquo; isn&amp;rsquo;t a concept in TLA+: either a state is possible or it isn&amp;rsquo;t.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:prism&#34;&gt;&lt;a href=&#34;#fn:prism&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; Figuring out the state&amp;rsquo;s &lt;em&gt;likelihood&lt;/em&gt; is out of scope for the language. But with graph analysis, we&amp;rsquo;ve expanded the scope, and maybe that&amp;rsquo;ll be enough to get something interesting. I feel really out of my depth here and am learning this all as I go, but let&amp;rsquo;s give it a shot anyway.&lt;/p&gt;

&lt;p&gt;So let&amp;rsquo;s say that if a thread takes an action, like Get, it&amp;rsquo;s more likely that thread will Inc than that the other thread will interrupt it and Get. As a &lt;strong&gt;&lt;em&gt;very&lt;/em&gt;&lt;/strong&gt; rough substitute, we&amp;rsquo;ll say that Inc transitions have more &amp;ldquo;weight&amp;rdquo; than Get transitions do.&lt;/p&gt;

&lt;figure&gt; 
  &lt;img src=&#34;img/transitions.png&#34; title=&#34;Three examples of a root with two edges: get/get, inc/inc, get/inc&#34;&gt; 
  &lt;figcaption&gt;&lt;a href=&#34;code/transitions.tex&#34;&gt;(TikZ source)&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In the first two images, we have only Gets and only Incs, so each transition is equally likely to happen. In the final image, we have one of each. If I weight each Inc as 3 times heavier than a Get, then it&amp;rsquo;ll happen 75% of the time. If we instead had 2 Incs and a Get, each Inc would happen 3/7ths the time and the Get would happen 1/7th.&lt;/p&gt;

&lt;p&gt;That gives us the probability, given a state, of which edge we take. Now what&amp;rsquo;s the likelihood of &lt;em&gt;reaching&lt;/em&gt; a given state? Let&amp;rsquo;s walk through an example state space:&lt;/p&gt;

&lt;figure&gt; 
  &lt;img src=&#34;img/likelihoods.png&#34; title=&#34;Root transitions to two states, A B transition to three states (they share one), all edges have different weights&#34;&gt; 
  &lt;figcaption&gt;&lt;a href=&#34;code/likelihoods.tex&#34;&gt;(TikZ source)&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I marked the weight of each edge. Now let&amp;rsquo;s walk through the likelihoods of each node:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt; is the single root node, so it has likelihood &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;R is equally likely of going to &lt;strong&gt;A&lt;/strong&gt; or &lt;strong&gt;B&lt;/strong&gt;, so they each have likelihood &lt;code&gt;0.5&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A goes to &lt;strong&gt;C&lt;/strong&gt; 50% of the time. But we have to get to A to get to C, and that only happens 50% of the time! So the likelihood of C is &lt;code&gt;0.5*0.5 = 0.25&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Similar logic shows that the likelihood of &lt;strong&gt;E&lt;/strong&gt; is &lt;code&gt;0.5*0.75 = 0.375&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The most interesting case is &lt;strong&gt;D&lt;/strong&gt;. We can reach it from &lt;em&gt;either&lt;/em&gt; A or B. So its likelihood is the sum of the two paths, or &lt;code&gt;0.375&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(This only works because there are no cycles in the state space. IIRC the technique broadly works with cycles, but you have to keep doing iterations over the graph until the likelihoods converge. This is basically the idea behind representing probabilistic systems as a &lt;a href=&#34;https://en.wikipedia.org/wiki/Stochastic_matrix&#34;&gt;stochastic matrix&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Now we have our algorithm for calculating each state likelihood. Then if we take all the terminal states with &lt;code&gt;x={k}&lt;/code&gt; and sum their likelihoods, we&amp;rsquo;ll have the proper probability that we end with &lt;code&gt;x={k}&lt;/code&gt;. Repeat for every &lt;code&gt;{k}&lt;/code&gt; and we have the distribution of end values!&lt;/p&gt;

&lt;p&gt;I implemented this algorithm, but explaining the code took 1,000 words and this essay is already long enough as it is. So I hosted the code elsewhere.&lt;/p&gt;

&lt;h2 id=&#34;7-compile-this-all-into-a-github-repo-https-github-com-hwayne-tla-graphing-demo&#34;&gt;7. Compile this all into &lt;a href=&#34;https://github.com/hwayne/tla-graphing-demo&#34;&gt;a github repo&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/hwayne/tla-graphing-demo&#34;&gt;Link here&lt;/a&gt;. It contains all of the work I put into this experiment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A copy of the &lt;a href=&#34;https://github.com/hwayne/tla-graphing-demo/blob/master/threads.tla&#34;&gt;TLA+ spec&lt;/a&gt;, which you can use to generate new state space graphs&lt;/li&gt;
&lt;li&gt;Five premade state space graphs, so you don&amp;rsquo;t have to learn how to use TLA+&lt;/li&gt;
&lt;li&gt;A (python) script to make the graph nodes a little more readable&lt;/li&gt;
&lt;li&gt;A python script that calculates the probabilistic property, along with &lt;a href=&#34;https://github.com/hwayne/tla-graphing-demo/blob/master/notes.md&#34;&gt;notes and commentary&lt;/a&gt; on the code&lt;/li&gt;
&lt;li&gt;A &lt;a href=&#34;https://github.com/hwayne/tla-graphing-demo/tree/master/gephi&#34;&gt;Gephi workspace&lt;/a&gt; with all the hard cleanup work already done for you&lt;/li&gt;
&lt;li&gt;A &lt;a href=&#34;https://github.com/hwayne/tla-graphing-demo/tree/master/PRISM&#34;&gt;PRISM probabilistic model&lt;/a&gt; of the same problem, just because.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wrote it to be easy to study, so you can experiment with it too. I hope you find it useful!&lt;/p&gt;

&lt;p&gt;To close out the experiment, let&amp;rsquo;s find some likelihoods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34; style=&#34;background: #272822&#34;&gt;&lt;pre style=&#34;line-height: 125%;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span&gt;&lt;/span&gt;python&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;likelihoods.py&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;graphs/2_threads.dot&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;--weight&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;
Counter&lt;span style=&#34;color: #f92672&#34;&gt;({&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;:&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;.5,&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;:&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;.5&lt;span style=&#34;color: #f92672&#34;&gt;})&lt;/span&gt;

python&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;likelihoods.py&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;graphs/2_threads.dot&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;--weight&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;10&lt;/span&gt;
Counter&lt;span style=&#34;color: #f92672&#34;&gt;({&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;:&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;.91,&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;:&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;.09&lt;span style=&#34;color: #f92672&#34;&gt;})&lt;/span&gt;

python&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;likelihoods.py&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;graphs/2_threads.dot&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;--weight&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;100&lt;/span&gt;
Counter&lt;span style=&#34;color: #f92672&#34;&gt;({&lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;2&lt;/span&gt;:&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;.9901,&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;1&lt;/span&gt;:&lt;span style=&#34;color: #f8f8f2&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color: #ae81ff&#34;&gt;0&lt;/span&gt;.0099&lt;span style=&#34;color: #f92672&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id=&#34;thoughts&#34;&gt;Thoughts&lt;/h1&gt;

&lt;p&gt;I&amp;rsquo;m excited about what this opens up! I&amp;rsquo;m hopeful the approach scales up to larger state spaces, too; it seems the majority of the script runtime is spent on importing the graphviz into NetworkX, the actual graph computations finish much faster. Even if it NetworkX doesn&amp;rsquo;t scale, maybe a more ergonomic graph analysis library would.&lt;/p&gt;

&lt;p&gt;And man it&amp;rsquo;s feels good doing a blog post on advanced TLA+ use again. It&amp;rsquo;s been &lt;a href=&#34;https://www.hillelwayne.com/post/tla-adt/&#34;&gt;over a year&lt;/a&gt; since the last time. I enjoy writing &lt;a href=&#34;https://www.learntla.com&#34;&gt;material for beginners&lt;/a&gt; but it doesn&amp;rsquo;t scratch the same itch.&lt;/p&gt;

&lt;p&gt;Anyway if you enjoyed this, I&amp;rsquo;m running a &lt;a href=&#34;https://www.eventbrite.com/e/software-modeling-with-tla-workshop-tickets-520030754987?aff=website&#34;&gt;1 day TLA+ workshop&lt;/a&gt; in May and have a &lt;a href=&#34;https://buttondown.email/hillelwayne/&#34;&gt;newsletter&lt;/a&gt; I update weekly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://twitter.com/parlar&#34;&gt;Jay Parlar&lt;/a&gt;, &lt;a href=&#34;http://lorinhochstein.org/&#34;&gt;Lorin Hochstein&lt;/a&gt;, and &lt;a href=&#34;https://ahelwer.ca/&#34;&gt;Andrew Helwer&lt;/a&gt; for feedback.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:rust&#34;&gt;The project repo uses a python script instead to cut down on the number of dependencies.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:rust&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:gephi-lite&#34;&gt;Recently the Gephi team announced &lt;a href=&#34;https://t.co/hqzSvnbpt1&#34;&gt;Gephi Lite&lt;/a&gt;, which among other things supports custom javascript node attributes. It doesn&amp;rsquo;t yet support graphviz import, though it&amp;rsquo;s still a work in progress.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:gephi-lite&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:dict-of-dicts&#34;&gt;Nodes have node neighbors, node neighbors have connecting edges, connecting edges have attributes.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:dict-of-dicts&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:cpp&#34;&gt;I couldn&amp;rsquo;t get shared memory working in Rust and I was suspicious Python&amp;rsquo;s &lt;a href=&#34;https://docs.python.org/3/glossary.html#term-global-interpreter-lock&#34;&gt;Global Interpreter Lock&lt;/a&gt; would artificially depress the racecond rate. Shoutout to GPT4 for helping me bumble my way through C++
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:cpp&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:prism&#34;&gt;In contrast, &lt;a href=&#34;https://www.hillelwayne.com/post/prism/&#34;&gt;PRISM&lt;/a&gt; is a probabilistic model checker that can calculate state likelihoods without you having to dump state spaces into another program. Then again PRISM doesn&amp;rsquo;t have functions or arrays so writing the spec in the first place is a big pain in the butt. I ended up modeling the system in PRISM for fun; you can see it &lt;a href=&#34;https://github.com/hwayne/tla-graphing-demo/tree/master/PRISM&#34;&gt;here&lt;/a&gt;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:prism&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      </item>
      
    
      
      <item>
        <title>OCR Everywhere</title>
        <link>https://www.hillelwayne.com/tipjar/windows-01/</link>
        <pubDate>Sat, 15 Apr 2023 00:00:00 +0000</pubDate>
        
        <guid>https://www.hillelwayne.com/tipjar/windows-01/</guid>
        <description>&lt;p&gt;&lt;a href=&#34;https://learn.microsoft.com/en-us/windows/powertoys/&#34;&gt;Powertoys&lt;/a&gt; is &amp;ldquo;a set of utilities for power users&amp;rdquo; that Microsoft keeps separate from Windows so they can get away with less testing. My favorite one is &amp;ldquo;Text Extractor&amp;rdquo;, which lets you OCR capture anything on the screen. Win-Shift-T:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.hillelwayne.com/tipjar/img/windows-01-before.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Text in the selected field is stored to your clipboard.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.hillelwayne.com/tipjar/img/windows-01-ocr.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;It doesn&amp;rsquo;t work well with photographs or non-computer fonts, though.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</description>
      </item>
      
    
  </channel>
</rss>
