<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[dihedral.group]]></title><description><![CDATA[the mathblog]]></description><link>https://www.dihedral.group</link><image><url>https://www.dihedral.group/img/substack.png</url><title>dihedral.group</title><link>https://www.dihedral.group</link></image><generator>Substack</generator><lastBuildDate>Wed, 06 May 2026 11:48:51 GMT</lastBuildDate><atom:link href="https://www.dihedral.group/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Dan Hoffman]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[dihedral@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[dihedral@substack.com]]></itunes:email><itunes:name><![CDATA[Dan Hoffman]]></itunes:name></itunes:owner><itunes:author><![CDATA[Dan Hoffman]]></itunes:author><googleplay:owner><![CDATA[dihedral@substack.com]]></googleplay:owner><googleplay:email><![CDATA[dihedral@substack.com]]></googleplay:email><googleplay:author><![CDATA[Dan Hoffman]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Morris Counters]]></title><description><![CDATA[convergence is just compression with extra (discrete) steps]]></description><link>https://www.dihedral.group/p/morris-counters</link><guid isPermaLink="false">https://www.dihedral.group/p/morris-counters</guid><dc:creator><![CDATA[Dan Hoffman]]></dc:creator><pubDate>Tue, 19 Dec 2023 05:52:14 GMT</pubDate><content:encoded><![CDATA[<p>A few things before we begin:</p><ol><li><p>This all seems pretty simple, but it is worth sharing anyways as a primer on the subject (there may be a follow-up on the same subject)</p></li><li><p>I&#8217;ve done this as an exercise in deriving things from first principles (no internet, pick three textbooks and go away for a while)</p></li><li><p>I&#8217;ve primarily done this to solve a problem, and like many problems, the solution involves touching computational grass, so my interest in this is limited to what can be applied directly</p></li></ol><p></p><p>I work with hard-real-time hardware systems in my day-to-day by writing firmware and such system have a lot of constraints, namely:</p><ol><li><p>There is not a lot of RAM</p></li><li><p>Many paths are bottlenecks to full system performance</p></li><li><p>Many paths have lower speed limits before quality-of-service issues cause functional problems</p></li></ol><p></p><p>I&#8217;m interested in pulling a lot of data out of this system, but the above points are pretty annoying constraints. However, if we assume the following:</p><ol><li><p>Measurements are independent from each other</p></li><li><p>Flows are (reasonably) deterministic</p></li></ol><p>then we can spread the impact in at least one of two ways:</p><ol><li><p>Probabilistically measure all values at once along a certain flow</p></li><li><p>Measure the values exactly and split those counters, running multiple versions along the same flow</p></li></ol><p>This blog post is all about (1). (2) has shown itself to be very useful, but given what I do that&#8217;s off limits.</p><p></p><h4>Counters</h4><p>A lot of the data I&#8217;d like to collect involves counting the frequency of events. This has a few interesting properties:</p><ol><li><p>Although the values of the counters may be related, the act of measurement is independent</p></li><li><p>A counter is relatively small, the number of counters is relatively large</p></li></ol><p>Additionally, I&#8217;m only interested in orders of magnitude difference in values.</p><p></p><p>Think of a counter like a function, like this:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;x => x + 1&quot;,&quot;id&quot;:&quot;FHBUHWSGKR&quot;}" data-component-name="LatexBlockToDOM"></div><p>Obviously, it has a &#8220;derivative&#8221; of 1. </p><p></p><p>Consider another type of counter, like this:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;x=> x + 1_n(x)&quot;,&quot;id&quot;:&quot;JZRMGIBXIQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>This derivative depends on the indicator variable sampling from some probability distribution. That isn&#8217;t specified beyond the fact it depends on the current value. The key difference here is the value is <strong>not the number of increments, but the value after some number of trials</strong>. The relationship between the number of increments and the stored value is determined by the underlying distribution. Counters of this type are called <strong>Morris counters</strong> and the algorithm is called the <strong>approximate counting algorithm</strong>.</p><p>Calculus is tempting, but let&#8217;s not use that for now. I&#8217;ve found the following two ways of reasoning about this effective: nested polynomials and Markov Chains.</p><p></p><h4>Nested Polynomials</h4><p>Let&#8217;s define the following (for the case of log base 2):</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;H_1 = (1/2^n)&quot;,&quot;id&quot;:&quot;IUOEUXTWXX&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;M_1 = 1 - H_1 = (1 - 1/2^n)&quot;,&quot;id&quot;:&quot;XUYKGBOAEL&quot;}" data-component-name="LatexBlockToDOM"></div><p>Let&#8217;s also define a split, which defines the total number of hits (H). Splits 3, 2, 1 and 0 are defined as follows (items in braces are to be interpreted as a sequence of events in the order listed):</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S_3 = \\lbrace H_1,H_2,H_3 \\rbrace&quot;,&quot;id&quot;:&quot;EROWLHBJIU&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S_2 = \\lbrace H_1,H_2,M_3 \\rbrace, \\lbrace H_1,M_2,H_2 \\rbrace, \\lbrace M_1,H_1,H_2 \\rbrace&quot;,&quot;id&quot;:&quot;SWUWDTPPSY&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S_1 = \\lbrace M_1,M_1,H_1 \\rbrace, \\lbrace M_1,H_1,M_2 \\rbrace, \\lbrace H_1,M_2,M_2 \\rbrace&quot;,&quot;id&quot;:&quot;ETDHYUCTNI&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S_0 = \\lbrace M_1,M_1,M_1 \\rbrace&quot;,&quot;id&quot;:&quot;PQCFAXJDBL&quot;}" data-component-name="LatexBlockToDOM"></div><p>Each hit is an increment by one, so an interpretation as products and a summation should provide us with an expected value. From a probability perspective, the order of events does not matter, so all &#8220;hits&#8221; can be factored out to the front:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E[S_1] = 1 * H_1((M_1^0 * M_2^2) + (M_1^1 * M_2^1) + (M_2^2 + M_1^0))&quot;,&quot;id&quot;:&quot;BKWZUQYESR&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E[S_1] = 1 * H_1(M_2M_2 + M_1M_2 + M_1M_1)&quot;,&quot;id&quot;:&quot;SOBEAXHZWR&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E[S_1] = 1 * H_1(M_1(M_1 + M_2) + M_2(M_2))&quot;,&quot;id&quot;:&quot;DFBPGMUWLS&quot;}" data-component-name="LatexBlockToDOM"></div><p>The polynomial can be seen as a valid probability because the events are all disjoint from each other (as each addition represents a unique path in the expansion and all paths are disjoint by definition). This can generalize to nested summations for arbitrary values across all possible splits. I&#8217;ve done this for my own purposes, but the pattern should be self-evident.</p><p></p><h4>Markov Chain</h4><p>Another approach is with Markov chains. The transition matrix is defined as such:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P_{ii} = 1 - \\frac{1}{2^i}&quot;,&quot;id&quot;:&quot;KQKPGZCYJA&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P_{i,i+1} = \\frac{1}{2^i}&quot;,&quot;id&quot;:&quot;TRWRTZJUPN&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>The initial state is the vector with only the first element set to 1, all other values 0. We need to know up-front how many trials to run to determine some constants (the number of constants is denoted by &#8220;n&#8221;):</p><ol><li><p>The matrix is of size (n + 1)x(n + 1) since the initial state starts with a constant value</p></li><li><p>The transition matrix is multiplied n times</p></li></ol><p>The resulting vector needs to be item-wise multiplied by its position to produce an expected value.</p><p></p><h4>Final Notes</h4><p>Both of these approaches are different lenses into fundamentally the same concept. The matrix approach encodes extra information, but in a structure that we all know and love (matrices). All algorithms listed have numerical stability issues that may be addressable with more thought. I&#8217;ve just deployed arbitrary precision rational arithmetic libraries at the problem. I may have a follow-up blog-post reasoning about the variance, but I need better performance on the numerics side (mostly accuracy with floating point numbers) before I venture onto that (I&#8217;ve done work on that front, but the numerics aren&#8217;t consistent with the theory, so I&#8217;m skeptical to publish that as-is).</p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Linux RAM-MM]]></title><description><![CDATA[RAM Market Maker]]></description><link>https://www.dihedral.group/p/linux-ram-mm</link><guid isPermaLink="false">https://www.dihedral.group/p/linux-ram-mm</guid><dc:creator><![CDATA[Dan Hoffman]]></dc:creator><pubDate>Wed, 27 Jul 2022 14:26:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!saWd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>NOTE: This post is a bit old because it was copied from elsewhere as-is. I&#8217;m consolidating platforms and moved this here.</strong></p><p>SIGECOM is an "economics and computation" ACM SIG at UIUC. RAM-MM is a set of patches for Linux that treat RAM allocations as a set of evictable commodities contracts with relative prices/priorities. Everything it attempts to do can be classified either as an engineering goal or a social goal.</p><p><strong>Engineering Goals</strong></p><p>The docs and presentations I've written explain it well (but aren't recent), so I'll refer you to...</p><div class="file-embed-wrapper" data-component-name="FileToDOM"><div class="file-embed-container-reader"><div class="file-embed-container-top"><image class="file-embed-thumbnail-default" src="https://substackcdn.com/image/fetch/$s_!0Cy0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack.com%2Fimg%2Fattachment_icon.svg"></image><div class="file-embed-details"><div class="file-embed-details-h1">Linux RAM-MM</div><div class="file-embed-details-h2">93.4KB &#8729; PDF file</div></div><a class="file-embed-button wide" href="https://www.dihedral.group/api/v1/file/f617d4a0-9899-48b0-b651-54cabe197a92.pdf"><span class="file-embed-button-text">Download</span></a></div><a class="file-embed-button narrow" href="https://www.dihedral.group/api/v1/file/f617d4a0-9899-48b0-b651-54cabe197a92.pdf"><span class="file-embed-button-text">Download</span></a></div></div><p></p><div class="file-embed-wrapper" data-component-name="FileToDOM"><div class="file-embed-container-reader"><div class="file-embed-container-top"><image class="file-embed-thumbnail-default" src="https://substackcdn.com/image/fetch/$s_!0Cy0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack.com%2Fimg%2Fattachment_icon.svg"></image><div class="file-embed-details"><div class="file-embed-details-h1">Linux RAM-MM Part 2</div><div class="file-embed-details-h2">28.2KB &#8729; PDF file</div></div><a class="file-embed-button wide" href="https://www.dihedral.group/api/v1/file/1d12a4ec-5271-4ace-9d6b-e7eafb8e3610.pdf"><span class="file-embed-button-text">Download</span></a></div><a class="file-embed-button narrow" href="https://www.dihedral.group/api/v1/file/1d12a4ec-5271-4ace-9d6b-e7eafb8e3610.pdf"><span class="file-embed-button-text">Download</span></a></div></div><p></p><p>Here is an except from the Kconfig that summarizes it well.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!saWd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!saWd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png 424w, https://substackcdn.com/image/fetch/$s_!saWd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png 848w, https://substackcdn.com/image/fetch/$s_!saWd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png 1272w, https://substackcdn.com/image/fetch/$s_!saWd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!saWd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png" width="838" height="553" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:553,&quot;width&quot;:838,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:117803,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!saWd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png 424w, https://substackcdn.com/image/fetch/$s_!saWd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png 848w, https://substackcdn.com/image/fetch/$s_!saWd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png 1272w, https://substackcdn.com/image/fetch/$s_!saWd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6c4825ad-6c6a-4dcc-94b1-8e6bff8d29a8_838x553.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The GitHub repo is internal to SIGECOM, but feel free to contact me if you want to contribute. It will remain internal until some set of programs can reasonably use these APIs to more efficiently allocate RAM (i.e. validating demand for such a platform).</p><p><strong>Social Goals</strong></p><p>RAM-MM also exists to be a platform that other people can independently contribute towards. This has a few advantages, such as:</p><ul><li><p>Clear boundaries between programs already exist</p></li><li><p>Programs are already developed independently</p></li><li><p>Benchmarks to track system efficiency/progress over time are easy to make</p></li><li><p>Individual people can take ownership of their respective piece(s)</p></li></ul><p>This is an attempt to align smaller contributions to something larger. You can also think of it like <a href="https://en.wikipedia.org/wiki/Price_discrimination">price discrimination</a> of people's effort or <a href="https://sigpwny.com">cybersecurity capture-the-flags</a>.</p><p><strong>Today</strong></p><p>The project is dormant mostly because of lack of interest/participation from others. The engineering goals are sound and worth pursuing, but the scope of this project is vast enough that there need to be incentives to contribute (which the social goals aim to accomplish). If you want to enable some userspace program to take advantage of these APIs (i.e. enable elastic demand), feel free to reach out.</p><p><a href="https://discord.gg/ezwgdEquqU">Here is a link to the SIGECOM Discord</a>. Feel free to join and talk about whatever, we don't bother with staying on topic.</p>]]></content:encoded></item><item><title><![CDATA[Polyomino Calculator Final Project]]></title><description><![CDATA[CS 498TC: Computational Geometry at the University of Illinois Urbana-Champaign]]></description><link>https://www.dihedral.group/p/polyomino-calculator-final-project</link><guid isPermaLink="false">https://www.dihedral.group/p/polyomino-calculator-final-project</guid><dc:creator><![CDATA[Dan Hoffman]]></dc:creator><pubDate>Mon, 09 May 2022 05:19:22 GMT</pubDate><content:encoded><![CDATA[<p>I (very broadly) <a href="https://github.com/thedanhoffman/polyomino">implemented</a> the algorithms described in <a href="http://www.bumblebeagle.org/polyominoes/tilingcounting/index.html">Counting Nonomino Tilings and Other Things of that Ilk</a> as a final project. The implementation I have written has <em>many</em> low-hanging fruit optimizations, but this blog post is the start of a series where I make it faster and track &#8220;real-world&#8221; performance over time. The paper (as well as the latest version of my calculator at the time of writing) likes brute-force, so keep that in mind.</p><p>The paper defines four distinct problems:</p><ol><li><p>Generate all valid &#8220;slice states&#8221;</p></li><li><p>Generate all valid relations between slice states</p></li><li><p>Generate all compositions of slice states (similar to a recurrence relation)</p></li><li><p>Generate a distinct tiling given a valid composition</p></li></ol><p></p><h1>The Basics</h1><p><strong>Slice States</strong></p><p>A slice state is a layer in the recurrence relation. A slice state is defined by the following:</p><ol><li><p>The length of each piece ID and the area beneath it in future slice states</p></li><li><p>The piece ID at each position in the slice sate</p></li></ol><p>Here are some requirements that a slice state must satisfy:</p><ol><li><p>Each position has a mapped piece ID</p></li><li><p>Each piece ID has a non-zero length</p></li><li><p>The sum of all volume under a piece ID (inclusive) must be divisible by the width of the board</p></li><li><p>Horizontal flips of the same piece are considered identical</p></li><li><p>Every position of a piece ID must be connect-able to every other position on the same slice through another slice</p></li></ol><p>There are others, but these have the clearest goemetric interpretations (an example of a non-geometric requirement is a unique isomorphism of IDs).</p><p><strong>Slice Relation</strong></p><p>A slice relation is a mapping from one slice state to another slice state. A slice relation is defined by the following:</p><ol><li><p>A source slice state and a destination slice state</p></li><li><p>A mapping from the source slice state piece IDs to the destination slice state piece IDs</p></li><li><p>Whether to flip the first slice state (the choice of first is arbitrary, continue to learn more)</p></li></ol><p>The search space is much larger, but there are fewer constraints. Here are some requirements that a slice relation must satisfy:</p><ol><li><p>There are no internal borders (i.e. the interiors of distinct pieces aren&#8217;t connected)</p></li><li><p>Either the volume of every piece increases by the number of occurrences in the new slice state or the piece does not exist in the next slice state</p></li><li><p>The mapping of pieces from the source to destination is valid</p></li><li><p>Every mapping of a piece has at least one point where the two connect at an edge</p></li><li><p>Only unique flips will generate a flip, non-unique flips must only be represented once</p></li></ol><p><strong>Recurrence Relation</strong></p><p>The beginning and end of the tiling region is determined by the n-wide piece (it behaves in the same way as the outside). I can adjust the execution of the recurrence relation so it only generates the height with no excess on the left/right, but there is a 1-1 mapping between the two tilings so it does not matter at this time. Every function and it&#8217;s flip is checked, so we don&#8217;t consider flips of entire functions but do consider flips of only the source slice state (the choice of first is arbitrary, as the flip of the entire mapping is equivalent to only flipping the bottom).</p><h1>Beyond the Basics</h1><p><strong>Generating a Tiling</strong></p><p><em>Technically</em>, the paper only &#8220;outlines&#8221; a method for generating an explicit tiling, so any generated result is beyond the original paper (granted, I haven&#8217;t ran to the 9x9 case, but computing some visual representation for any single tiling isn&#8217;t hard, the issues are storing the results and specifying which subset to run it on).</p><p><strong>Reasonable Visualization</strong></p><p>The basics are correct but the representation is pretty ugly. It looks like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!W953!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W953!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png 424w, https://substackcdn.com/image/fetch/$s_!W953!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png 848w, https://substackcdn.com/image/fetch/$s_!W953!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png 1272w, https://substackcdn.com/image/fetch/$s_!W953!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W953!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png" width="214" height="200" data-attrs="{&quot;src&quot;:&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:200,&quot;width&quot;:214,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2795,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!W953!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png 424w, https://substackcdn.com/image/fetch/$s_!W953!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png 848w, https://substackcdn.com/image/fetch/$s_!W953!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png 1272w, https://substackcdn.com/image/fetch/$s_!W953!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43c93da9-152f-459d-859a-a3ef924fcdee_214x200.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I understand how to read this, but it&#8217;s very ugly and difficult to find bugs. I need a representation that looks like Tetris. Adjacency information is encoded on a slice-by-slice basis, and I can back-solve for mappings by composing piece maps together. Using these tools, I can:</p><ol><li><p>Construct global graph piece IDs by reversing the piece maps of every slice relation above it</p></li><li><p>Construct a graph of global piece IDs by connecting all global piece IDs together by adjacent local slice state piece IDs</p></li><li><p>Color the graph (currently via brute-force, but the Four-Color Theorem gives us an upper complexity bound, which works well for us)</p></li></ol><p>I did this and now have the following:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jtrw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jtrw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png 424w, https://substackcdn.com/image/fetch/$s_!Jtrw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png 848w, https://substackcdn.com/image/fetch/$s_!Jtrw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png 1272w, https://substackcdn.com/image/fetch/$s_!Jtrw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jtrw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png" width="90" height="186" data-attrs="{&quot;src&quot;:&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:186,&quot;width&quot;:90,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2311,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Jtrw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png 424w, https://substackcdn.com/image/fetch/$s_!Jtrw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png 848w, https://substackcdn.com/image/fetch/$s_!Jtrw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png 1272w, https://substackcdn.com/image/fetch/$s_!Jtrw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F188e21dc-6ea4-42c6-89e1-1682227b47c8_90x186.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This looks much better, doesn&#8217;t it?</p><h1>Future Steps</h1><p>I&#8217;ll make it much faster, allow for rendering a specific tiling, and optimize for memory use. I&#8217;ll detail specific optimizations as I write them as individual blog posts in a series. </p>]]></content:encoded></item></channel></rss>