Josh MermelsteinPlease enjoy my musings
http://www.joshmermelstein.com
Siteswap Puzzles<h1 id="first-attempt">First Attempt</h1>
<p>In October, 2018, I had the idea to make a puzzle in the shape of a crossword
puzzle where all the “words” are replaced by sitewaps. For more info on siteswap
validation, I previously wrote a
<a href="http://joshmermelstein.com/Introduction-To-Siteswap/">blog post on that topic</a>.
I tried to generate a solved puzzle by hand but had way more trouble than I
expected.</p>
<p>I decided to use the only crossword generation tool I knew about - the
<a href="http://jbuckland.com/puzzle-pong-i/">one
James Buckland wrote in response to a puzzle I gave him</a>.
His program takes a dictionary and generates all n x n squares such that all
the rows and columns are valid words. All I had to do was generate a list of
all siteswaps with length 6 and pass that in as the dictionary. This worked
perfectly and I had a huge list of all valid 6x6 grids.</p>
<p>Now that I had all these solved puzzles, I needed to generate unsolved puzzles.
I did some research on how sudoku are generated. Sudoku is a pretty mature
puzzle so there are many answers but the simplest one looks like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>start with a solved puzzle
for (cell in shuffled list of all cells):
clear that cell
if (modified puzzle doesn’t has a unique solution):
put the number back in that cell
</code></pre></div></div>
<p>This is pretty easy to implement, runs quickly, and is randomized enough that I
don’t expect it to generate the same puzzle twice. All I had to do was implement
as solution counter for partially solved puzzles.</p>
<p>I chose to represent the board as a 2d array a bitsets (representing cells)
where biset.test(v) meant that v was a plausible value for that cell. My
algorithm chose a cell with more than one possible value and created a candidate
board as though that value was the only option. It also removed possibilities
from the row/col of the modified cell that were no longer valid. Then for each
board that wasn’t obviously invalid (some cell has 0 possibilities), it called
itself recursively. I considered trying to pick unsolved cells in some clever
way but the code already ran so quickly that it didn’t seem worth it.</p>
<p>I ended up
<a href="https://www.instagram.com/p/BofY05ZnluX/">publishing one of these puzzles to my instagram</a>
and was sent one correct solution. I chatted with the solver a bit and their
opinions were really similar to mine - the novelty of the puzzle was fun but too
much of the solve was tedious bookkeeping and not enough was clever inference. I
decided that I’d had my fun with this project and mostly forgot about it for 5
month.</p>
<h1 id="variations">Variations</h1>
<p>Out of nowhere, I realized that there are some valid sudoku solutions which are
also valid in my puzzle. I decided to see if I could use this to make a more
interesting second draft.</p>
<p>Generating a list of all siteswaps containing 1-9 exactly once was pretty easy
and James’s tool would happily make me grids out of them. However, the tool
didn’t have any built in way to handle the 3x3 block restrictions of sudoku.
Rather that updating it, I decided to reuse some bits of my solver. I realized
that generating a puzzle is exactly the same as solving a puzzle that as 0 cells
filled in. Rather that early returning when more than one solution is found, my
puzzle generator would early return the first time it found any solution will
all cells filled in. One other difference from the earlier solver is that I
iterated over possible values for a cell in random order. This was just in case
iterating in value order introduced some bias. I’m not sure this matters but the
overhead is so small that I don’t care.</p>
<p>The heart of my generator was a function called ConsiderBoard(). It took a
board, the row and col of the cell to be changed, and the value to put in that
cell - and it returned a new board where the constrained implied by putting that
value into that row/col had been enforced. In this case there were 5
constraints:</p>
<ul>
<li>Sudoku rows</li>
<li>Siteswap rows</li>
<li>Sudoku columns</li>
<li>Siteswap columns</li>
<li>Sudoku 3x3 blocks</li>
</ul>
<p>This meant placing each number could remove as many as 40 possible values from
the board! Since possibilities were removed so quickly, board generation took a
tiny fraction of a second.</p>
<p>My strategy here was the same as before - write a solution counter for unsolved
puzzles and use it to remove values while keeping the solution unique. I did
this mostly by reusing the ConsiderBoard() method.</p>
<p>As a fun side effect, that meant I could comment out the siteswap constraints and
my program would generate unsolved sudoku puzzles. Or I could comment out the
sudoku rules and my program would generate unsolved siteswap puzzle. Or any
combination of constraints!</p>
<p>The first time I ran my reducer, the unsolved puzzle it spit out only had 4
numbers filled in. In retrospect this makes some sense. The more constraints I
added, the smaller I made the number of legal solutions (to any puzzle); the
fewer solutions exist, the fewer numbers are needed to specify each one.</p>
<p>Unfortunately, a puzzle with 4 numbers filled in is unapproachable for human
solvers. I needed a way to stop reducing the puzzle once it had reached a goal
difficulty.</p>
<p>I started by researching how sudoku difficulty is decided. The answer was much
more interesting than I expected! AI solvers use a list of heuristics for
inference and have a number of points associated with each one. Simpler ones
cost fewer points to use than more complex ones. Once the AI has solved the
puzzle, it counts up how many points it spent and what the most complicated
inference technique was and uses those to assign a difficulty.</p>
<p>I considered something like this for my puzzle but decided it was too much work.
In order to come up with the right heuristics and point values, I’d need to
become an expert solver and I didn’t care enough. Instead I tried to think of a
simpler solution that would be easier to implement.</p>
<p>I ended up writing a modified solver that picked cells at random and recorded
how many guesses it took it to find the unique solution. Then, as I reduced from
solved puzzle to unsolved one, I ran this random solver 100 times and took the
mean of the number of guesses. This doesn’t look at all like how humans solve
puzzles but the average number of guesses trended upward as pre-populated cells
went away so it approximated something related to difficulty.</p>
<p>What I found was that the number of guesses sometimes had notable points
where number of guesses jumped from <10 to >20. I tried to see if there was
anything interesting about these points but didn’t think they were that
different as a human. Also at some point the number of guesses max out at around
30 and stayed there as all remaining numbers were removed. As a human, I think
these puzzles feel the most different in difficulty but the computer disagreed.</p>
<p>In the end, I decided that I’m only going to publish a few puzzles and I can
just evaluate the difficulty by hand. If I were publishing a book of puzzle or
something, I’d need to think a lot more critically about this.</p>
<p>I asked my roommate to test one of the puzzles for me and he quickly spotted a
pattern I hadn’t. I was so focused on how I expected the puzzle to be solved
that I didn’t notice some recurring structure. In this case, {4,6,8}, {2,7,9},
and {1,3,5} always appeared contiguously in rows. In additon to that, {4,5,9},
{3,7,8}, and {1,2,6} always appear contiguously in columns. In fact, there are
only 3 distinct 3x3 blocks in this solution.</p>
<p><img src="/images/siteswap_puzzle/symmetry.png" style="max-height: 400px" /></p>
<p>Once I knew that this could happen, I found that it happened to a lesser degree
pretty often. I never found a nice way to exclude solved puzzles with too much
repition. Luckily, even with 100 solves with every number removed, my program
still ran in under a second. I decided it was easier to just filter these out by
hand. This is another thing I’d need to revisit if I were trying to publish
more than a handful of puzzles.</p>
<p>So far, I’ve <a href="https://www.instagram.com/p/BusjJ_dAwgU/">published 3 puzzles</a>, an
easy, a medium, and a hard, also to my instagram. All 3 are unsolvable if you
only use sudoku type inference but have unique solution if you use both sudoku
and siteswap rules. I’ve been mailed one correct solution to the easy puzzle. I
also plan to publish another trio of puzzles with sudoku row/col rules removed
but sudoku 3x3 cell rules still present. This is yet another novel solving
experience that is worth trying once but probably not twice.</p>
Sun, 10 Mar 2019 00:00:00 +0000
http://www.joshmermelstein.com/siteswap-puzzles/
http://www.joshmermelstein.com/siteswap-puzzles/The Area Enclosed by Hamiltonian Cycles on Highly Regular Planar Graphs<p>This post was inspired by some doodles I drew on a notepad during some
meetings at work. I vividly remember watching <a href="https://www.youtube.com/watch?v=38rf9FLhl-8">the youtube
video</a> which introduced me to the
mathematics of juggling and listening to the lecturer spend several minutes
justifying why juggling ought to have a mathematics. I often think back to this
when observing phenomena in my day to day life. I think it is valuable to look
at simple patterns around us and consider them from a mathematical perspective -
even if we skimp on the formality and rigor.</p>
<h1 id="the-doodles">The Doodles</h1>
<p>During a meeting, I doodled some square-ish grids of dots on my notepad. I then
started connecting these dots with vertical and horizontal lines. As I kept
connecting, I ended with a Hamiltonian cycle over the dots. For those who
haven’t taken any graph theory, a <a href="https://en.wikipedia.org/wiki/Hamiltonian_path">Hamiltonian
cycle</a> is a cycle (a path which
starts and ends in the same place) which visits every vertex in a graph exactly
once.</p>
<p>The cycle I’d drawn was quite irregular so I redrew the same grid of dots and
tried to find a more symmetric way to connect them. Here are a three examples of
such cycles on a six by six grid of dots.</p>
<p><img src="/images/hampath/6x6.png" style="max-height: 400px" /></p>
<h1 id="an-unexpected-pattern">An Unexpected Pattern</h1>
<p>As I looked at these grids, I noticed something surprising - they all enclosed
the same number of cells. If we take the edge length to 1 then each one encloses
17 squares of area.</p>
<p>I started experimenting with larger grids found that for a given set of
vertices, the area enclosed by a Hamiltonian cycle never seemed to depend on my
choice of cycle.</p>
<h1 id="proof">“Proof”</h1>
<p>I mentioned this to a coworker who suggested a useful paradigm shift. Instead of
thinking about the dots in isolation, think about them as the centers of squares
whose side length matches the edge length in our grid. Now, at each vertex, the
angle of the line going through it determines how much of its square is enclosed
by the cycle. For convenience, of notation I’m going to assume that the cycle
starts in the bottom left corner of the graph and goes up. If you prefer to go
the other way, just swap some negative signs and the math is all the same.</p>
<p><img src="/images/hampath/6x6_overlay.png" style="max-height: 400px" /></p>
<p>When the line is straight (0°), half the cell containing that dot is enclosed by
the cycle. When the line through a vertex turns to to the right (90°), one
quarter of the cell is enclosed by the cycle. Finally, when the line through a
vertex turns left, (-90°), three quarters of the cell is enclosed by the cycle.</p>
<p>More concretely, we can express the area enclosed by a vertex of angle
<script type="math/tex">\theta</script></p>
<script type="math/tex; mode=display">\frac{1}{2} - \frac{1}{4} * \frac{\theta}{90}</script>
<p>This means we can compute the area enclosed by the cycle as</p>
<script type="math/tex; mode=display">\sum_{\text{vertices}} \left(\frac{1}{2} - \frac{1}{4} * \frac{\theta}{90}\right)</script>
<p>We can do a little rearrangement to express this sum as</p>
<script type="math/tex; mode=display">\sum_{\text{vertices}} \left(\frac{1}{2}\right) - \frac{1}{360} * \sum_{\text{vertices}} \left( \theta \right)</script>
<p>This is where we get to bring in a fun fact. In a closed loop whose corners are
a square and which does not cross itself, the sum of the angles is 360°. This
means that everything in the above expression is a constant which means the area
enclosed by the curve is a constant.</p>
<h1 id="extensions">Extensions</h1>
<p>This “proof” applies equally well if we replace our grid graph with a tiling of
equaliteral triangles.</p>
<p><img src="/images/hampath/triangular.png" style="max-height: 400px" /></p>
<p>A few of the constants change but the overall structure of looking at the area
bounded by a angle through each vertex remains the same.</p>
<p>Both of the examples I’ve shown in this post have a certain regularity which
makes this argument flow very naturally. I’m curioius if it is possible to
characterize the this regularity and describe other families of graph which
tesselate the plane and for which the area enclosed by all hamilton cycles on a
subgraph is constant.</p>
<p>I have a hypothesis that the condition required on the original graph is “the
graph is planar and all cells in the original graph are the same”. I use cells
here to mean cycles which cannot be subdivided into unions of (geometrically)
smaller cycles. This hypothesis feel intuitive to me and covers cases like
affine transformations of known tesselations.</p>
<p><img src="/images/hampath/affine.png" style="max-height: 400px" /></p>
<p>I would not be suprised if an even looser restriction is sufficient like “all
cells have the same number of edges and bound the same area.” I need to think
more about what such a tesselation looks like.</p>
<h1 id="holes-in-the-subgraph">“Holes” in the Subgraph</h1>
<p>My math knowledge is getting thin here so this subsection will probably use some
terms incorrectly.</p>
<p>All of the graphs I’ve shown in this post have had no gaps in their vertices.
That is to say, if they can be generated by tiling of the cartesian plane with
one of the tesselations discussed, drawing a close loop, and taking the subgraph
whose vertices are enclosed in the loop. But what about subgraphs like the one
below:</p>
<p><img src="/images/hampath/triangular_hole_graph.png" style="max-height: 400px" /></p>
<p>Unfortunately, the property does not hold on all such graphs. It is possible for
the missing vertex to be inside or outside the shape enclosed by the Hamiltonian
Cycle. These two scenarios lead to different amounts of enclosed space. In the
following example, the cycle on the left encloses 34 triangles and the cycle on
the right encloses 36 triangles.</p>
<p><img src="/images/hampath/triangular_hole.png" style="max-height: 400px" /></p>
<h1 id="how-much-is-enclosed">How Much is Enclosed</h1>
<p>In the case of a square grid which is n verticies wide and m verticies high, the
cycle which encloses the maximum area is the perimiter with <script type="math/tex">(n-1) * (m - 1)</script>. The Hamiltonian cycle on such grids falls short of this maximum by half the
number of non-perimeter vertices. This value is always an integer since a square
grid where both dimensions are odd has no Hamiltonian cycle.</p>
<p>In the case of a regular tiling of equalerateral triangles, the the Hamiltonian
Cycle falls short of the perimeter by as many triangular cells as there are
non-perimeter vertices.</p>
<p>I suspect that in a tiling of n-gons, the number of cells that the Hamaltonian
cycle will fall short of the perimeter will be $ \frac{\text{number of interanl
vertices}}{n-2} $ . My hand-wavey explanation of this guess is that it takes n-2
added vertices to carve out a cell from the perimeter. If this is true, it would
have interesting implications on determining whether graphs of certain families
have Hamiltonian cycles or not simply by counting the internal vertices</p>
Sat, 17 Jun 2017 00:00:00 +0000
http://www.joshmermelstein.com/hampath/
http://www.joshmermelstein.com/hampath/Puzzle Pong - part 1<p><a href="jbuckland.com">James Buckland</a> and I have decided to start a game of Puzzle
Pong. These puzzles are more about the design of the program than about the
actual answer; so I’ve decided to cover some of my inferior designs in this blog
post. If you are only interested in the best solution, see the subsection titled
“Third Approach”.</p>
<p>He challenged me to solve the following puzzle in his <a href="http://jbuckland.com/crossword/">blog
post</a> about enumerating crossword puzzles. I
recommend you give it a read.</p>
<h1 id="the-puzzle">The Puzzle</h1>
<p>For every subset of the 26 character English alphabet, there is a set of words
which can be spelled using only characters from that subset. For example, given
the set {a, b, c, d}, /usr/share/dict/american-english says there are 24 words
which can be spelled - {A, Ac, Ada, B, Ba, C, Ca, Cd, D, Dacca, Dada, a, ad,
add, b, baa, bad, c, cab, cad, d, dB, dab, dad}.</p>
<p>Which such subset has the highest words to characters ratio?</p>
<h1 id="first-approach">First Approach</h1>
<p>(Spoiler - this approach is fundamentally wrong.)</p>
<p>My first idea was to encode every word in the dictionary as a set of characters.
Then construct a map from set-of-characters to the count of how many times I’ve
seen that set. Lastly I’d iterate over the map and pick the set with the best
ratio.</p>
<h3 id="implementation-details">Implementation details</h3>
<p>The representation of character sets is critical to making this program
performant. I chose to implement them in C++ as bit sets inside a uint32_t. I
chose C++ because wanted to use a C like language so I could easily do efficient
bitwise operations. Since there are only 26 characters in the alphabet, 32 bits
is plenty to encode each word. The encoding function is pretty straightforward.
I made the decision to ignore characters outside [a-zA-Z] for simplicity.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 uint32_t WordToSet(const std::string& word) {
2 uint32_t ret = 0;
3 for (const char c : word) {
4 if (c >= 'a' && c <= 'z') {
5 ret |= (1 << (c - 'a'));
6 } else if (c >= 'A' && c <= 'Z') {
7 ret |= (1 << (c - 'A'));
8 }
9 }
10 return ret;
11 }
</code></pre></div></div>
<p>While I was at it, I wrote the decoding function. This will be used at the end
for printing the winning set.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 std::string SetToWord(uint32_t set) {
2 std::string ret = "";
3 uint32_t mask = 1;
4 for (int i = 0; i < 25; i++) {
5 if (set & (1 << i)) {
6 ret += ('a' + i);
7 }
8 }
9 return ret;
10 }
</code></pre></div></div>
<p>I usually try to avoid string appending but this function is only called once so
it didn’t seem like a big deal.</p>
<p>I also needed a function that told me the size of each set. The <a href="http://www.hackersdelight.org/hdcodetxt/pop.c.txt">Hacker’s
Delight</a> gave me several
promising choices. I initially went with pop4() since it supposedly has the
best performance when the number of bits is small.</p>
<p>I was planning to bechmark this choice against some others until I found out
about
<a href="https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html">__builtin_popcount()</a>.
This lets the compiler use CPU specific instructions when counting the number of
1-bits in an int.</p>
<p>In practice, this program spends a minority of its time counting the sizes of
sets so the benefit is minimal.</p>
<h3 id="putting-it-all-together">Putting it all together</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 int main() {
2 // Key is a bit set encoding the characters of a string.
3 // Value is the number of times that key has been seen so far.
4 static uint32_t counts [(1 << 26) - 1] = {0};
5
6 std::ifstream infile("/usr/share/dict/american-english");
7 std::string word;
8 // Populate counts.
9 while (infile >> word) {
10 ++counts[wordtoset(word)];
11 }
12
13 // Find best ratio in counts.
14 uint32_t best_chars = 0;
15 int best_num_chars = 0;
16 int best_count = 0;
17 for (auto it = counts.begin(); it != counts.end(); ++it) {
18 int num_chars = Pop(it->first);
19 int count = it->second;
20 // Equivelent to (count / num_chars) > (best_count / best_num_chars)
21 // but avoids floats.
22 if (count * best_num_chars >= best_count * num_chars) {
23 best_num_chars = num_chars;
24 best_count = it->second;
25 best_chars = it->first;
26 }
27 }
28
29 std::cout << best_num_chars << " " << best_count << " "
30 << SetToWord(best_chars) << std::endl;
31
32 return 0;
33 }
</code></pre></div></div>
<p>There is not much to comment on here. I enjoyed my method of fraction comparison
that avoided floats. This made me comfortable using -Ofast (which is faster than
O3 but might have out of spec behavior on float math in some
situations).</p>
<h3 id="performance-and-correctness">Performance (and Correctness)</h3>
<p>This program is quite speedy! On my 6 year old laptop, it ran in about a 20th of
a second. It says the best set {‘a’, ‘e’, ‘r’, ‘s’, ‘t’} which contains 60
words:</p>
<p>60 seems like a surprisingly small number for such common characters so I asked
the program to print me which words it though were in this set. It retuned back
to me with the following:</p>
<p>{“Astarte”, “Astarte’s”, “Easter”, “Easter’s”, “Easters”, “Sartre”, “Teresa”,
“Teresa’s”, “Terra’s”, “aerates”, “arrest”, “arrest’s”, “arrests”, “assert”,
“asserts”, “aster”, “aster’s”, “asters”, “eater’s”, “eaters”, “errata’s”,
“erratas”, “rarest”, “raster”, “rate’s”, “rates”, “reassert”, “reasserts”,
“restart”, “restart’s”, “restarts”, “restate”, “restates”, “retreat’s”,
“retreats”, “stare”, “stare’s”, “stares”, “starter”, “starter’s”, “starters”,
“stater”, “tare’s”, “tares”, “tartest”, “taster”, “taster’s”, “tasters”,
“tatter’s”, “tatters”, “tear’s”, “tears”, “teaser”, “teaser’s”, “teasers”,
“treat’s”, “treats”}</p>
<p>Now I could see that there was an error in my design; I being far to strict. I
was counting words that could be spelled using the characters in {‘a’, ‘e’, ‘r’,
‘s’, ‘t’} but I was also requiring that all those characters be used. And
likewise for every other set of characters. This result was interesting but
ultimately not what I wanted.</p>
<h1 id="second-approach">Second Approach</h1>
<p>My second idea was to solve this problem by brute force. As before, encode the
dictionary 32 bit ints, but this time, loop over the all 2^26 sets of characters
and see what their ratio is. This is not elegant but I was confident it would
get me the correct answer.</p>
<h3 id="implementation-details-1">Implementation details</h3>
<p>This approach mostly reused helper functions from the previous one. The only new
function I needed was for determining if one bit set was a subset of another.</p>
<p>My first idea was</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 // Args: two bit sets stored in uint32_t's
2 // Returns true if the first set is a subset of the second.
3 bool Subset(uint32_t first, uint32_t second) {
4 return ~(~first | second) == 0;
5 }
</code></pre></div></div>
<p>A coworker pointed out the much more elegant:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 bool Subset(uint32_t first, uint32_t second) {
2 return (first | second) == second;
3 }
</code></pre></div></div>
<p>Both of these only use a handful of assembly instructions.</p>
<h3 id="putting-it-all-together-1">Putting it all together</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 int main() {
2 std::vector<uint32_t> char_sets;
3
4 std::ifstream infile("/usr/share/dict/american-english");
5 std::string word;
6 while (infile >> word) {
7 char_sets.emplace_back(WordToSet(word));
8 }
9
10 int best_num_chars = 0;
11 int best_num_words = 0;
12 int best_char_set = 0;
13 for (uint32_t i = 0; i < ((1 << 26) - 1); ++i) {
14 int num_words = 0;
15 int num_chars = __builtin_popcount(i);
16
17 // Count the number of words in the dictionary which can be spelled using
18 // only the letters represented by i.
19 for (const uint32_t char_set : char_sets) {
20 if (Subset(char_set, i)) {
21 ++num_words;
22 }
23 }
24
25 // Equivalent to if(num_words/num_chars >= best_num_words/best_num_chars)
26 // but without needing to use floating point numbers
27 if (num_words * best_num_chars >= best_num_words * num_chars) {
28 best_num_words = num_words;
29 best_num_chars = num_chars;
30 best_char_set = i;
31 }
32 }
33
34 std:: cout << "num_words: " << best_num_words << std::endl
35 << "set was: " << SetToWord(best_char_set) << std::endl;
36
37 return 0;
38 }
</code></pre></div></div>
<h3 id="performance-and-correctness-1">Performance (and Correctness)</h3>
<p>This code runs in about 25 minutes at produces the answer:
abcdefghiklmnorstuvwy. That is to say, all characters except {‘j’, ‘q’, ‘x’,
‘z’}. Upon reflection, this isn’t such a surprising answer.</p>
<p>This program’s memory use is quite nice. I allocate one 32 bit int for each word
in the dictionary and a handful to temp and accumulation variables. The memory
use scales linearly with the size of the dictionary and is not effected by the
number of characters in the language.</p>
<p>Performancewise, this solution leaves a lot to be desired. For each of 2^26 sets
of characters, I am looping for ~100,000 words in the dictionary. What if there
was a way to do less work for each character set…?</p>
<h1 id="third-approach">Third Approach</h1>
<p>What if instead of looping over ~100k words, I did subset lookups in the map
from the first approach? So for a set like {‘a, ‘e’, ‘r’}, sum the values at {},
{‘a’}, {‘e’}, {‘r’}, {‘a’, ‘e’}, {‘a’, ‘r’}, {‘e’, ‘r’} and {‘a’, ‘e’, ‘r’}. If
the initial set has n elements, then it has 2^n subsets. When n is small, this
is less work than looping over the whole dictionary; when n is large, this is
more work than looping over the whole dictionary.</p>
<p>This felt like a promising strategy but I didn’t have an good ideas how to
efficiently iterate over all subsets of a bit set. I mentioned this to a
coworker and he suggested I check out the chess programming wiki. Apparently,
chess programs use bit sets for internal representations so this wiki has lots of
helpful functions for doing computations in bit sets. Indeed, it has a page on
<a href="https://chessprogramming.wikispaces.com/Traversing+Subsets+of+a+Set">Traversing Subsets of a Set</a>.</p>
<p>Armed with this, I modified my solution from approach 2 into the following:</p>
<h3 id="putting-it-all-together-2">Putting it all together</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 int main() {
2 // For sets with many characters.
3 std::vector<uint32_t> char_sets;
4 // For sets with not many characters.
5 static uint32_t counts [(1 << 26) - 1] = {0};
6
7 std::ifstream infile("/usr/share/dict/american-english");
8 std::string word;
9 while (infile >> word) {
10 char_sets.emplace_back(WordToSet(word));
11 ++counts[WordToSet(word)];
12 }
13
14 int best_num_chars = 0;
15 int best_num_words = 0;
16 int best_char_set = 0;
17 for (uint32_t i = 0; i < ((1 << 26) - 1); ++i) {
18 int num_chars = __builtin_popcount(i);
19
20 // Compute how many words can be spelled with those letters.
21 int num_words = 0;
22 if (num_chars <= 14) {
23 uint32_t n = 0;
24 do {
25 num_words += counts[n];
26 n = (n - i) & i;
27 } while ( n );
28 } else {
29 for (const uint32_t char_set : char_sets) {
30 if (Subset(char_set, i)) {
31 ++num_words;
32 }
33 }
34 }
35
36 if (num_words * best_num_chars >= best_num_words * num_chars) {
37 best_num_words = num_words;
38 best_num_chars = num_chars;
39 best_char_set = i;
40 }
41
42 std:: cout << "num_words: " << best_num_words << std::endl
43 << "set was: " << SetToWord(best_char_set) << std::endl;
44
45 return 0;
46 }
</code></pre></div></div>
<h3 id="performance">Performance</h3>
<p>This program runs in about 16 minutes and produces the same answer as my second
one. I’m sure more improvements are possible but overall I’m much happier with
this design.</p>
<p>On the negative side, this approach uses more memory than the previous one. As
before, it allocates a 32 bit int for each word in the dictionary; but now it
additionally allocates a 32 bit int for each possible subset of the alphabet.
This amount of memory scales exponentially with the number of characters!
Luckily for me 26 characters corresponds to about 250 megabytes which is a
manageable amount. If English had 32 characters then my laptop would not have
had enough RAM to allocate such a map.</p>
<p>One interesting feature I’d like to point out is choice of 14 in line 22. Log
base 2 of 100,000 is around 16.6 so my initial guess for this value was 16. This
is because for sets of size 15 and 16, it costs fewer than 100k lookups in
counts to compute how many words can be spelled with those characters. In
practice, I get best performance with this threshold at 14. My suspicion is
that this is a cache locality issue. Looping over a vector probably has
favorable cache behavior but indexing into a table probably has more cache
misses.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I challenge James to solve the following puzzle:</p>
<blockquote>
<p>Given the list of numbers [1, 2, 3, 4, 5] unlimited parentheses, and the
operations {+, -, *, /, ^, !}, it is possible to construct many integers. For
example,</p>
<p>1 = 1 + 2 - 3 - 4 + 5</p>
<p>2 = 1 + (((2 + 3) * 4!) / 5!)</p>
<p>3 = …</p>
<p>What is the smallest positive integer that cannot be written this way?</p>
<p>For some inspiration, please enjoy:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=ukUkVaOyI0o">https://www.youtube.com/watch?v=ukUkVaOyI0o</a></li>
<li><a href="https://www.youtube.com/watch?v=-ruC5A9EzzE">https://www.youtube.com/watch?v=-ruC5A9EzzE</a></li>
</ul>
<p>To formalize the rules slightly.</p>
<ol>
<li>Numbers must appear in order, each exactly once.</li>
<li>You may not take the factorial of a factorial (i.e. (3!)! = 720).</li>
<li>Concatination is forbidden (i.e. 1 + 23 + 4 + 5).</li>
<li>Unary negative is forbidden (i.e. 13 = (-1) + 2 + 3 + 4 + 5)</li>
</ol>
</blockquote>
<blockquote>
<p>Bonus problem - For what list of five integers (all between 0 and 9
inclusive), is the answer to this puzzle the smallest? If this is not unique,
please provide all lists which have the lowest non-expressable value.</p>
</blockquote>
<blockquote>
<p>Bonus bonus problem - What list of five positive integers has the smallest sum
and cannot construct 1. Again, if there is more than one list with this
minimal sum, please provide all of them.</p>
</blockquote>
<blockquote>
<p>Yet another bonus problem (feel free to ignore these). For the starting list
[1,2,3,4,5], what is the smallest non-negative integer which can only be made
in one way? For what starting list of five integers (all between 0 and 9
inclusive) is the answer to the previous question the smallest?</p>
</blockquote>
Sat, 17 Jun 2017 00:00:00 +0000
http://www.joshmermelstein.com/Puzzle-Pong-1/
http://www.joshmermelstein.com/Puzzle-Pong-1/Vim macro and g/pattern/normal<p>If you find yourself doing the same thing over and over in Vim, there is probably a better way. Here is an example of how to use macros and regex matching to avoid repetitive but mindless work.</p>
<p>Lets say you have a config file of the form:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>foo = bar
baz = "nort"
qux = qat
</code></pre></div></div>
<p>where all of the string on the right hand sides of each equals sign are supposed to have quotes around them but many do not. We can fix this pretty easily without needing to leave Vim.</p>
<p>First we go to an offending line and record a macro:</p>
<p><code class="highlighter-rouge">qqf=wi"<esc>A"<esc>q</code></p>
<p>Lets break that down:</p>
<ul>
<li><code class="highlighter-rouge">qq</code> - begin recording a macro in register q</li>
<li><code class="highlighter-rouge">f=</code> - go to the first equals sign on the line</li>
<li><code class="highlighter-rouge">w</code> - go forward one word</li>
<li><code class="highlighter-rouge">i"<esc></code> - insert a quotation mark here</li>
<li><code class="highlighter-rouge">A"<esc></code> - insert a quotation mark at the end of the line</li>
</ul>
<p>We could manually execute this macro with <code class="highlighter-rouge">@q</code> on each necessary line. But there is an easier way:</p>
<p><code class="highlighter-rouge">:g/= [^"]/normal @q</code></p>
<p>Lets break this down too:</p>
<ul>
<li><code class="highlighter-rouge">:g</code> - begin executing an <code class="highlighter-rouge">Ex</code> command (by default on every line of the file)</li>
<li><code class="highlighter-rouge">= [^"]</code> - a regex to match meaning “an equals sign followed by a space, followed by something other than a quotation mark”</li>
<li><code class="highlighter-rouge">normal @q</code> - execute the normal mode vim command stored in macro q</li>
</ul>
<p>This runs the macro we recorded above on every line that needes it. Voila!</p>
Fri, 22 Jan 2016 00:00:00 +0000
http://www.joshmermelstein.com/vim-macro-and-g-normal/
http://www.joshmermelstein.com/vim-macro-and-g-normal/Numbering lines of pseudocode in Vim<p>Another short one today. When I write pseudocode that I want to share with
others, I like to number the lines so that I can easily refer to them.
In Vim this is easy thanks to the <code class="highlighter-rouge">nl</code> command.</p>
<p>Select the desired line to number and then type <code class="highlighter-rouge">:!nl</code>. By default
<code class="highlighter-rouge">nl</code> uses tabs. I prefer spaces so I use <code class="highlighter-rouge">:!nl -s " "</code> instead.
<code class="highlighter-rouge">man nl</code> details the other twiddling options that you may find useful.</p>
<p>Piping text blocks in vim through bash is a powerful method of text interaction.
Some other times I use it are to sort my #inclues and to evaluate simple math
expressions with <code class="highlighter-rouge">bc</code>.</p>
Sun, 17 Jan 2016 00:00:00 +0000
http://www.joshmermelstein.com/numberline/
http://www.joshmermelstein.com/numberline/Top of a code block<p>Here is a command that I don’t use often but when I use it, I’m glad I have
access to it.</p>
<p><code class="highlighter-rouge">[{</code> - <code class="highlighter-rouge">go to [count] previous unmatched {</code></p>
<p>When editing code, I sometimes find myself in the middle of a gigantic code
block and want to know what conditional or loop led me there. This command
does exactly that. It scans backward for the previous <em>unmatched</em> curly brace
and moves the cursor there.</p>
<p>Example:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mf">1.</span> <span class="k">if</span> <span class="p">(</span><span class="n">bar</span> <span class="o"><</span> <span class="mi">5</span><span class="p">)</span> <span class="p">{</span>
<span class="mf">2.</span> <span class="n">baz</span><span class="p">();</span>
<span class="mf">3.</span> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">bar</span> <span class="o">>=</span> <span class="mi">13</span><span class="p">)</span> <span class="p">{</span>
<span class="mf">4.</span> <span class="n">vector</span><span class="o"><</span><span class="kt">int</span><span class="o">></span> <span class="n">nort</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">8</span><span class="p">};</span>
<span class="o">--</span> <span class="c1">// 100 lines of C++ code
</span><span class="mf">105.</span> <span class="n">baz</span><span class="p">();</span>
<span class="mf">106.</span> <span class="p">}</span>
</code></pre></div></div>
<p>Lets say my cursor is on line 105 and I can’t remember what branch of the
conditional I’m on. If I input <code class="highlighter-rouge">[{</code>, the cursor will jump to the open curly brace
on line 20. It skips the curley braces on line 6 because they match each other.
It also skips any matched curley braces in the omitted block, regardless of if
they are on the same line.</p>
<p>I hope you find this useful.</p>
Sat, 16 Jan 2016 00:00:00 +0000
http://www.joshmermelstein.com/vim-tip/
http://www.joshmermelstein.com/vim-tip/Unexpected Vim behavior when repeating indent<h2 id="composability-of-commands-in-vim">Composability of commands in Vim</h2>
<p>The reason that Vim is my text editor of choice is because Vim commands are
composable. Each command has a verb and an object so every time I learn a new
verb, I already know how to use it with each object. Whenever I learn a new
object I already have a lexicon of verbs to use with it. This idea is summarized
well in [this article]
(https://medium.com/@mkozlows/why-atom-cant-replace-vim-433852f4b4d1).</p>
<h2 id="the-notion-of-count">The notion of [count]</h2>
<p>A feature of many Vim commands is that they optionally accept a count. This
number tells the command how many times it should happen. For example, to go
down five lines, you could hit <code class="highlighter-rouge">j</code> five time. Or you could hit <code class="highlighter-rouge">5j</code>. This
feature lets you cut down on key mashing and get right to the meat of text
editing.</p>
<h2>»</h2>
<p>The <code class="highlighter-rouge">></code> command is a verb that can be read “indent by one line.” It take a
motion and indents everything between the cursor and the destination by one
shiftwidth. Some examples are <code class="highlighter-rouge">>ip</code> for “indent all lines of this paragraph” or
<code class="highlighter-rouge">gg>G</code> for “indent the whole file by one shiftwidth”</p>
<h2 id="weirdness-with-count">Weirdness with [count]»</h2>
<p>Recently I wanted to indent a line by three shiftwidths. I’d never done this
particular action before but with my understanding of [count] I assumed the
right thing to do was <code class="highlighter-rouge">3>></code>.</p>
<p>To my surprise, this command indented the next three lines by one shiftwidth
each. If I had wanted that I would have used <code class="highlighter-rouge">>2j</code>. I tried several variations
on these commands and found that <code class="highlighter-rouge">2>j</code> and <code class="highlighter-rouge">>3></code> both did the same thing.</p>
<p>Looking at the Vim help documentation (<code class="highlighter-rouge">:help <<</code>), I found that this behaviour
was documented.</p>
<p><code class="highlighter-rouge">>> Shift [count] lines one 'shiftwidth' rightward.</code></p>
<p>Here I also found some sequences that did I wanted - shift the current line
right by three shift widths.</p>
<p><code class="highlighter-rouge">{Visual}[count]> Shift the highlighted lines [count] 'shiftwidth'</code></p>
<p>So one solution to my original problem is <code class="highlighter-rouge">v3>></code>. This distinction doesn’t feel
good to me. It feels like a waste of entering visual mode and there is no
intuition why the effect is different in visual versus normal.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:[range]> {count} [flags]
Shift {count} lines one 'shiftwidth' right, starting
with [range] (default current line |cmdline-ranges|).
Repeat '>' for shifting multiple 'shiftwidth's.
</code></pre></div></div>
<p>Another solution is to use command mode. <code class="highlighter-rouge">:>>></code> indents the current line by 3.
This sequence also feels bad to me.</p>
<h2 id="similarities-to-y-and-closing">Similarities to y and closing</h2>
<p>The <code class="highlighter-rouge">y</code> command (copy) has very similar semantics to the <code class="highlighter-rouge">></code> command. In normal
mode <code class="highlighter-rouge">[count]yy</code> yanks [count] lines. In visual mode, <code class="highlighter-rouge">[count]yy</code> yanks the
selected text (we can think of this as happening [count] times for convenience.)</p>
<p>However for the <code class="highlighter-rouge">y</code> command, repeating an action on the same line doesn’t do
anything. With the indent action, repeating several time on the same line makes
sense and is sometimes desirable. The interaction of [count] and <code class="highlighter-rouge">></code> in normal
mode is well documented and consistent. I feel that a doccumented design mistake
is still a mistake. In the grand scheme of things it is pretty minor but I think
it would be more intuitive and more in the spirit of Vim of <code class="highlighter-rouge">[count]>></code> indented
the current line count times.</p>
Sun, 15 Nov 2015 00:00:00 +0000
http://www.joshmermelstein.com/Vim-repeat-indent/
http://www.joshmermelstein.com/Vim-repeat-indent/3-SAT in Clue<p>Consider a game of clue. Now consider the set of queries answered by a given player by showing the queries a card. That player’s hand must satisfy the expression:</p>
<script type="math/tex; mode=display">(\text{Suspect}_1 \vee \text{Weapon}_1 \vee \text{Room}_1) \wedge (\text{Suspect}_2 \vee \text{Weapon}_2 \vee \text{Room}_2) \wedge \dots</script>
<p>At first glace it looks a lot like 3-SAT! There are a few reasons I can think of that it might not by 3-SAT though.</p>
<ul>
<li>Many tuples cannot occur i.e. (knife or wrench or gun)</li>
<li>Setting all variables to true satisfies the expression. We need to also encode the size of the hand somehow. I can’t think of a way to do so that guarantees we stay in 3CNF.</li>
<li>We gain a ton of information when a player cannot show a card. We now know three cards they don’ t have. This could potentially simplify our 3-SAT to 2-SAT (boring).
<ul>
<li>Similarly we know that several variables are false since the player can’t have cards that we have. That will also help us simplify to 2-SAT.</li>
</ul>
</li>
<li>We have one 3CNF expression for each player but they aren’t independent. If one player has the wrench then the other does not.</li>
</ul>
<p>I’m pretty convinced that there is no trivial reduction from determing a clue hand to 3-SAT but am not yet convinced one way or the other if it is NP. It seems like we have some pretty strong tools to simplify the problem but I’m not sure if they are enough to bring us down from NP.</p>
Tue, 29 Sep 2015 00:00:00 +0000
http://www.joshmermelstein.com/3-SAT-Clue/
http://www.joshmermelstein.com/3-SAT-Clue/Starting Out With tmux<p><a href="https://tmux.github.io/">tmux</a> is a terminal multiplexer. It allows for near
arbitrary layout of terminals in panes and windows (their words for splits and
tabs) and supports detaching and reattaching terminals. I’ve been curious
about tmux for a while and finally decided to give it a try a few weeks ago.</p>
<p>Like many powerful tools, tmux has a rich configuration language and a myriad of
commands. In the long run I think these options are beneficial to the user but
starting out they can be overwhelming. To my dismay, most tmux tutorials were
effectively lists of commands with no sense of progression or order. I am a big
fan of
<a href="http://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/">Learn Vim Progressively</a>
and think that many other complicated program can benefit from a similarly well
structured guide.</p>
<p>Unfortunately I am just a beginner at tmux so I don’t have the knowledge to
write the advanced part of such a guide. Instead I can relay the path I took to
becoming comfortable in tmux and comment on what went well and what didn’t.</p>
<h2 id="starting-out">Starting Out</h2>
<ul>
<li>Install tmux</li>
<li>Launch tmux</li>
<li>Use it like a normal terminal</li>
</ul>
<p>For most purposes, tmux will behave just like your regular terminal except for a
bar on the bottom listing some information like the date and your hostname. For
now, scrollback won’t work for you (sorry).</p>
<h2 id="using-windows-and-panes">Using Windows And Panes</h2>
<p>A reason that tmux was attractive to me was that it let me clean up my alt-tab
list. When working on projects I usually had a browser, a terminal for building,
a terminal for testing and a vim window. I had to mash alt-tab to get where I
wanted and sometimes pressed it an incorrect number of times. tmux lets me
consolidate all My my terminal applications in one place and provides tools for
organizing them.</p>
<p>Often while coding I would find myself carefully arranging my terminals so each
one took up just the right amount of space on the screen. tmux solves this
problem with panes.</p>
<p>When you open tmux, it will show you a single terminal. This terminal can be
split with a vertical line down the middle using <code class="highlighter-rouge">C-b %</code> or split with a
horizontal line through the middle using <code class="highlighter-rouge">C-b "</code>. Furthermore, these splits
(called panes) can be further split with the same commands to generate
relatively complex layouts. Moving between panes is easy, we press <code class="highlighter-rouge">C-b</code> (this
sequence lets tmux know that the next character presses is intended as a command
to it) and then the arrow key of the direction we want to move in.</p>
<p>I tend to use panes to group related tasks. Most of the time, all of my panes in
a given window will be in the same directory. As I write this blog post I have
one pane with vim running where I’m typing and another where I’m running git
commands.</p>
<p>In parallel to panes, tmux has the idea of windows, which are analogous to tabs
in most applications. Each window contains an arbitrary number of panes (get
it). When you open tmux there will be one window by default. Its name will be
the name of the program you are running in that window. New windows are created
with <code class="highlighter-rouge">C-b c</code>. There is a shortcut to kill a window but I tend to just close all
the panes with <code class="highlighter-rouge">C-d</code> which closes the window containing them as well.</p>
<p>You can move to a window using its index with <code class="highlighter-rouge">C-b</code> and then the index of the
window. You can also move one window forward with <code class="highlighter-rouge">C-b n</code> or one window
backward with <code class="highlighter-rouge">C-b p</code>.</p>
<p>I admit, I in a way just did the thing I wanted to not do and wrote a bit list
of commands. The nice thing about tmux is that it is perfectly usable with a
subset of even the ones I’ve listed here. I recommend picking either panes or
windows and trying to use that one without the other. Once you feel comfortable
with that, try incorporating the other one as well.</p>
<h3 id="some-additional-window-and-pane-commands">Some Additional Window and Pane Commands</h3>
<p>Here are some lower priority commands that may make windows and panes slightly
more useful to you.</p>
<p>Sometimes a small pane contains long lines that are being wrapped and you wish
it were larger. <code class="highlighter-rouge">C-b z</code> zooms in on just that terminal and makes it take up the
entire tmux window. Repeating this command unzooms.</p>
<p>Sometimes I forget what is in a window when its title is just “bash” or “vim”.
Windows can be manually renamed with <code class="highlighter-rouge">C-b ,</code>.</p>
<p>Sometimes tmux’s pane layout isn’t enough for me and I want to manually resize
a pane. You do this by holding <code class="highlighter-rouge">C-b</code> and then pressing an arrow key.</p>
<h2 id="workflows-at-this-point">Workflows at this point</h2>
<h2 id="copy-mode-and-scrollback">Copy mode and scrollback</h2>
<p>Remember when scrollback didn’t work. Here is a way to scroll back with
limitations. What is it so bad? I should see if I can get mousewheel to work</p>
<h2 id="messing-with-tmuxconf">Messing With .tmux.conf</h2>
<p>warn about not resetting defaults to unspecified fields.</p>
<p>Some stuff I do</p>
<ul>
<li>C-b C-b for last window</li>
<li>mouse</li>
<li>vim keys for movement</li>
<li>swap window position</li>
<li>clearing scrollback</li>
</ul>
<p>Some stuff I don’t do</p>
<ul>
<li>remap C-b</li>
<li>remap % and “ to | and - even if it is cute</li>
<li>use any defalt layouts</li>
</ul>
<h2 id="using-sessions">Using Sessions?</h2>
<p>I don’t do this but its a strength of tmux I guess.
I probably should start using these…</p>
Wed, 16 Sep 2015 00:00:00 +0000
http://www.joshmermelstein.com/Starting-Out-With-Tmux/
http://www.joshmermelstein.com/Starting-Out-With-Tmux/Corollaries in Siteswap<h2 id="lack-of-intro">Lack of Intro</h2>
<p>Siteswap, the mathematical notation for juggling is relatively well researched
and well understood. Rather than start this blog post with a few paragraphs
about its history and some simple examples, I’m going to provide some links that
do that and jump right into the meat.</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=38rf9FLhl-8">An hour long and comprehensive lecture at Cornell</a></li>
<li><a href="http://juggle.wikia.com/wiki/Siteswap">A comprehensive wiki article</a></li>
<li><a href="http://www.math.ucsd.edu/~ronspubs/94_01_juggling.pdf">A well written paper proving some fundamental results</a></li>
<li><a href="http://www.amazon.com/gp/product/0387955135?psc=1&redirect=true&ref_=od_aui_detailpages00">A more modern book proving additional theorems</a></li>
</ul>
<h2 id="validation-of-vanilla-siteswaps">Validation of Vanilla Siteswaps</h2>
<p>It is well known that a vanilla siteswap which does not average to an integer is
invalid. What is less well known is why certain vanilla siteswaps that average
to an integer are invalid.</p>
<p>The premise of siteswap is that discretized time into a number of evenly space
units. Every throw and every catch must occur at one of those units. When we say
that a pattern is valid we really mean that the indegree each time unit (the
number of objects being caught then) is equal to the outdegree (the number of
objects being thrown then). In vanilla siteswap, that means at every time unit,
at most one ball can be caught. Thus, a pattern is forbidden if there exist two
throws that land at the same time. We can express this formally as follows.</p>
<p>For all siteswaps <script type="math/tex">a_1 a_2 \cdots a_n</script>,
<script type="math/tex">\forall x \in \{1 \cdots n\} \forall y \in \{1 \cdots n\}, x \ne y \implies
a_x + x \not \equiv a_y + y \pmod n</script></p>
<p>If we wanted to verify these pairwise relations individually, we would need to
do quadratically many checks. A cheaper way to to note that the above statement
is equivalent to saying that the set <script type="math/tex">\{a_x + x\} \pmod n</script> is equivalent to a
permutation of the numbers 0 through <script type="math/tex">n-1</script>. The following code takes a list of
integers and does just that.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 1 def verify_vanilla(siteswap):
2 multiplicity = [False] * len(siteswap);
3 for i in range (0, len(siteswap)):
4 index = (siteswap[i]+i) % len(siteswap)
5 if multiplicity[index]:
6 return False
7 multiplicity[index] = True
8 return True
</code></pre></div></div>
<h2 id="generating-new-siteswaps-from-existing-ones">Generating New Siteswaps From Existing Ones</h2>
<p>From this algorithm for verifying a siteswap, we can easily define several ways
of mutating a siteswap without compromising its validity.</p>
<h3 id="add-1-to-every-number">Add 1 to Every Number</h3>
<p>If it is the case that <script type="math/tex">{a_x + x} \pmod n</script> is a permutation of the set <script type="math/tex">\{0
\cdots n-1\}</script> then adding one to each <script type="math/tex">a_x</script> will not modify this property.</p>
<ul>
<li>423 becomes 534</li>
<li>633 becomes 744</li>
</ul>
<p>If all of the values of the siteswap are greater than 0, this process work in
reverse too. You can subtract 1 from each number in a valid siteswap to generate
another valid siteswap.</p>
<h3 id="add-pattern-length-to-one-number">Add Pattern Length to One Number</h3>
<p>Similarly, added <script type="math/tex">n</script> to one <script type="math/tex">a_x</script> will not change its value modulo n.
Therefore the siteswap will still be valid.</p>
<ul>
<li>441 becomes 4, 741 or 714</li>
<li>71 becomes 91 and 73</li>
</ul>
<p>If any value in the siteswap is greater than the pattern length then this
process can be done in reverse as well. Subtracting the pattern length from any
value in a valid siteswap will produce another valid siteswap so long as all the
value remain positive.</p>
<h3 id="swap-sites-of-two-throws">Swap Sites of Two Throws</h3>
<p>The above two mutation methods both modify the number of objects being juggled;
This strategy does not. Lets start with an example, 441.</p>
<p><img src="/images/Siteswap/441_end_locations.png" style="max-height: 400px" /></p>
<p>In this image shows which time unit each throw will land on. To modify this
siteswap, we are going to swap the ending locations of the two 4s. The first of
our three throws now goes forward 5, the second throw goes forward 3, and the
third is unmodified and goes forward 1. We have just discovered the patter 531.</p>
<p><img src="/images/Siteswap/531_end_locations.png" style="max-height: 400px" /></p>
<p>More generally, if we select two throws <script type="math/tex">a_i</script> and <script type="math/tex">a_j</script>, such that <script type="math/tex">% <![CDATA[
i < j %]]></script>
and <script type="math/tex">% <![CDATA[
a_i + i < j %]]></script>, then we can replace $a_i$ with <script type="math/tex">a_j + j - i</script> and <script type="math/tex">a_j</script>
with <script type="math/tex">a_i + i - j</script> - effectively swapping the sites they land at. This method
of pattern generation is the origin of the name siteswap.</p>
<h3 id="extending-to-multiplex-siteswaps">Extending to Multiplex Siteswaps</h3>
<p>We can model multiplex siteswaps very similarly to vanilla siteswaps by relaxing
the condition that indegree and outdegree can be at most 1. We now only require
that they be equal at each time unit. This means that much of the reasoning that
we applied to vanilla siteswaps is still applicable. Unfortunately our easy to
describe mutation strategies can’t be said as easily anymore.</p>
<p>If we can identify a subset of the pattern which is a valid vanilla pattern then
we can increment every element of that subset and get a valid pattern. For
example [43]41 contains 441 so we can create the pattern [53]52. I’m actually
not sure if this is always possible - probably not.</p>
<p>When counting patten length we count a multiplex as a single throw. Then the
strategy of adding pattern length to any one number still works as before. For
example 23[34] goes to 53[34], 26[34], 23[46] and 23[37] all of which are valid
4 ball multiplex patterns.</p>
<p>Swapping sites works exactly as before. We pick two throws where the first
doesn’t doesn’t land before the second is thrown and swap their sites.</p>
<h3 id="extending-to-sync-siteswaps">Extending to Sync Siteswaps</h3>
<p>Sync siteswaps are doubled in a way that is subtle but convenient. I’ll probably
go into it more in another blog post. On the topic of mutating sync siteswaps
though, we need to add 2 to every number which increases the total number of
balls by 2. For example (4x,2x) goes to (6x,4x)</p>
<p>When counting pattern length, each (a,b) throw counts as two throws. For example
(4,2x)(2x,4) maps to (8,2x)(2x,4) or (4,6x)(2x,4).</p>
<p>Swapping sites works as before but with a more complicated notion of a site. At
each time unit there is a left site and a right site and we can swap between
time units or within time units.</p>
<h2 id="understanding-transitions">Understanding Transitions</h2>
<p>When describing a pattern that isn’t in ground state, jugglers sometimes list
the sequence of throws to enter it from ground state and the sequence of throws
to exit it.</p>
<h3 id="entry--exit-is-a-valid-siteswap">Entry + Exit is a Valid Siteswap</h3>
<p>A fact that isn’t commonly known is that the concatenation of the entry and exit
sequences is always a valid siteswap. If we think about siteswaps as cycles in a
state machine, the reason for this is apparent. The transitions are paths from a
node in one cycle to a node in the other and back. Therefore the concatenation
of the two is a cycle in the graph as well and must also be a valid siteswap.
Furthermore if the starting pattern was ground state then the generated
Entry+Exit siteswap will also be ground state.</p>
<p>This fact is less useful for generating new siteswaps than it is for quickly
computing the exit from a siteswap of known entry. For example to enter 933 from
a 5 ball cascade we can throw a 7. A five ball ground state move that starts
with 7 is 744. Therefore 44 is a valid exit from 933 back to 5.</p>
<p>We can repeat this process to generate other transitions. A five ball ground
state siteswap that ends in 44 is 94444. Therefore we can also enter 933 from 5
with a 944.</p>
<p>How to get an initial transition between two patterns is a somewhat interesting
question that I think I’ll leave for another blog post.</p>
Sat, 12 Sep 2015 00:00:00 +0000
http://www.joshmermelstein.com/Introduction-To-Siteswap/
http://www.joshmermelstein.com/Introduction-To-Siteswap/