`2018-11-11`

*
status

It’s been a year since my last blog post. Many things have happened since that time.

Below are some of the more interesting items.

I got laid off at IMVU in September 2017. It was a difficult time for me as I had become good friends with the people there. After almost 2 months of searching for jobs, I somehow managed to land a job at Google! My title is Release Engineer. I’ve been there almost a year now and I am still happy and excited to work there.

I started learning Golang a few months ago, because, I felt that this is the best time to learn it (while I’m employed by Google). I haven’t really done any of the advanced things yet, but I like how the language tries really hard to keep the syntax simple. It’s a lot like C in that regard.

The only pain point in Go for me is the packaging/installation system. The whole opintionated $GOPATH thing just feels a bit clunky because of the shared folder namespace with other projects. But I guess that’s unavoidable in any language’s ecosystem.

I started writing a short (informal) book on Git. I am using LuaTeX to write it; I started in March 2018 but have yet to cross the 1/2 way mark. Hopefully I’ll get it done before March 2019 rolls around.

Back in 2016’s status update I said that I still planned to finish the Haskell book I was working on. That project is definitely dead. One reason is that due to the rising popularity of the language, I feel that other people have already said what I had meant to say in my book.

I’ve grown interested in these languages because well, I feel like they are important. My hope is to find some interesting problems that can be solved idiomatically in each language. That might take years, but, it is my hope that in the future I’ll be able to write about these languages.

Apparently HTTPS support for custom domains on Github have been a thing since earlier this year. I never got around to it but thanks to this post I finally enabled it.

]]>`2017-11-11`

*
linux, git

A while ago I discovered that there is a manpage for the ASCII character set. It got a bunch of upvotes, and since then I wondered what other manpages were worth knowing about. Below is a small table of manpages that I found interesting.

Manpage | Description |
---|---|

`ascii(7)` |
the ASCII character set (in octal, decimal, and hex) |

`units(7)` |
megabytes vs mebibytes, etc. |

`hier(7)` |
traditional filesystem hierarchy (e.g., `/bin` vs `/usr/bin` ) |

`file-hierarchy(7)` |
(systemd) filesystem hierarchy |

`operator(7)` |
C operator precedence rules (listed in descending order) |

`console_codes(4)` |
Linux console escape and control sequences |

`terminal-colors.d(5)` |
among other things, ANSI color sequences |

`boot(7)` |
UNIX System V Release 4 bootup process |

`daemon(7)` |
(systemd) how to write/package daemons |

`proc(5)` |
proc filesystem (`/proc` ) |

`ip(7)` |
Linux IPv4 protocol implementation (a bit low-level, but still useful) |

`ipv6(7)` |
Linux IPv6 protocol implementation |

`socket(7)` |
Linux socket interface |

`unix(7)` |
UNIX domain sockets |

`fifo(7)` |
named pipes |

Note that you need to run

```
sudo mandb
```

to be able to invoke `apropos <SEARCH_TERM>`

or `man -k <SEARCH_TERM>`

(`man -k`

is equivalent to `apropos`

— see `man(1)`

).

You probably knew already that Git has many manpages dedicated to each of its subcommands, such as `git-clone(1)`

or `git-commit(1)`

, but did you know that it also comes with a suite of tutorials? Behold!

Manpage | Description |
---|---|

`giteveryday(7)` |
the top ~20 useful git commands you should know |

`gitglossary(7)` |
a glossary of all git concepts (blob object, working tree, etc.) |

`gittutorial(7)` |
a high-level view of using git |

`gittutorial-2(7)` |
explains the object database and index file (git architecture internals) |

`gitcore-tutorial(7)` |
like `gittutorial-2(7)` , but much more detailed |

`gitworkflows(7)` |
recommended workflows, esp. branching strategies for maintainers |

Happy hacking!

]]>`2017-05-13`

*
math

In the very first chapter of the book *Concrete Mathematics* 2ed there is a discussion about the Tower of Hanoi. This post is a distillation of that discussion.

There are 3 rods, with 8 discs (with holes) resting on one rod; the discs are sorted in size like a pyramid, with the smallest disc on top. We want to move all discs to another rod, but with the following rules: (1) a move consists of moving a single disc onto a rod; (2) you may never place a bigger disc on top of a smaller one. A question arises — **how many steps are required to move the entire tower of disks onto another rod?**

First consider the simplest case, without any discs. Because there are no discs to move, we cannot make any moves, and so the number of steps required is 0. We can write this as

\[ S_0 = 0 \]

with \(S\) meaning the number of steps and the subscript representing the number of discs in the tower.

Now let’s consider how the problem scales. With 1 disc, the answer is a single step since the one disc is itself the entire tower. With 2 discs, the answer is three steps — one step to move the top (small) disc to another rod, one step to move the big disc to the destination rod, and lastly one step to move the small disc on top of the big disc. With 3 discs, the answer is seven steps — the insight here is that we treat the top two discs exactly the same as the previous problem; so we need 3 moves to move the top two to another rod, then one move to move the biggest disc to the destination rod, then again 3 moves to move the 2-disc sub-tower to the destination rod.

The example with 3 discs is quite telling. We can use the insights gained there to set an upper bound to the number of steps required for the general case of \(n\) discs; if we take more steps than this upper bound, we would know that we made mistakes. For a tower of size \(n\), we require \(S_{n - 1}\) steps to move all discs except the biggest one, then move the biggest disc, then move the sub-tower on top of that disc with (again) \(S_{n - 1}\) steps. So the upper bound is

\[ \begin{equation} \label{eq:recurrence} S_n = \begin{cases} 0 & \text{if } n = 0 \\ 2 * (S_{n - 1}) + 1 & \text{if } n > 0. \end{cases} \end{equation} \]

If that’s the upper bound, then is there a separate formula for the *lower bound* (optimal solution)? Nope! It’s because there must come a time in solving the puzzle where we move the biggest disc to the destination rod. To get to the biggest disc, we must have moved all discs on top of it to another rod (the sub-tower); and, after having moved the biggest disc, we must move this sub-tower back on top of that rod (back onto the biggest disc). Because of these constraints stemming the definition of the puzzle itself, we know that for \(n\) > 0 we must take *at least* \(2 * (S_{n - 1}) + 1\) steps.

The upper and lower bounds agree in their formulation, and this formulation (Equation \(\ref{eq:recurrence}\)) is our recurrence. In mathematics, a recurrence relation is basically a recursively-defined equation, where a *base case* in the recurrence defines the starting point. In Equation \(\ref{eq:recurrence}\), the base case is \(n = 0\); for \(n > 0\), we define the number of steps required in a recursive manner.

In our discussion of finding the upper and lower bounds, there were two key concepts — the need to move the biggest disc, and the need to move the sub-tower twice (before and after moving the biggest disc). Our recurrence clearly agrees with these two concepts. The “\(+ 1\)” in the non-base case is the step of moving the biggest disc, whereas the \(2 * (S_{n - 1})\) is the number of steps required to move the sub-tower *twice*.

Recurrences are great, but they are painful to compute. For example, it’s not immediately clear what \(S_{11}\) or \(S_{54}\) evaluates to. It would be really nice if we could avoid defining \(S_n\) recursively.

And this is where math meets science. In the scientific method, we have to come up with a hypothesis and then test that hypothesis with one or more experiments. We can do the same thing here by trying to guess the solution to the recurrence.

For one thing, we know that \(S_n\) grows as \(n\) grows (it will never be the case that \(S_n\) somehow plateaus or decreases down the road). The more discs there are, the more work we have to do, right? So let’s look at small cases to see how the numbers grow, and see if there is a pattern to the growth rate of \(S_n\).

\(n\) | \(S_n\) |
---|---|

0 | 0 |

1 | 1 |

2 | 3 |

3 | 7 |

4 | 15 |

5 | 31 |

6 | 63 |

7 | 127 |

8 | 255 |

We don’t have to actually simulate the puzzle to derive these values; using the recurrence Equation \(\ref{eq:recurrence}\) we start off from the first row (the base case) and then calculate our way down, reusing \(S_n\) from the previous row as \(S_{n - 1}\). ^{1}

Anyway, the values of \(S_n\) sure look familiar — especially if we use base 2.

\(n\) | binary(\(S_n\)) |
---|---|

0 | \(0_2\) |

1 | \(1_2\) |

2 | \(11_2\) |

3 | \(111_2\) |

4 | \(1111_2\) |

5 | \(11111_2\) |

6 | \(111111_2\) |

7 | \(1111111_2\) |

8 | \(11111111_2\) |

It looks like our recurrence simplifies to just

\[ \begin{equation} \label{eq:solution} S_n = 2^n - 1 \quad \text{for } n \geq 0, \end{equation} \]

except it is no longer a recurrence as there is no need to define a base case. We’ll call it a *solution* to the recurrence.

Although the empirical evidence looks very good, we have not formally proved that the solution (Equation \(\ref{eq:solution}\)) holds for *all* \(n\). It’s one thing to say that something is true for all *observed* cases (scientific experiment), and quite another to say that something is true for *all* cases (mathematical proof).

Can we prove it? Yes! Fortunately for us, Equation \(\ref{eq:recurrence}\) lends itself to proof by induction. Induction requires you to first prove some number \(k_0\) as a starting point (the base case) using some proposition \(P\). Then you prove that \(P\) holds for \(k + 1\) (the next number); i.e., show that going from \(k\) to \(k + 1\) does not change \(P\). This is the *inductive step*. In this way, we prove the “totality” of \(P\) as it applies to all numbers in the range \([k_0, k_{m}]\) and we are done. ^{2}

Here we want to prove that Equation \(\ref{eq:solution}\) holds for all \(n\) (all natural numbers). ^{3} For this proof let’s rewrite Equation \(\ref{eq:solution}\) to use \(k\) instead of \(n\):

\[ \begin{equation} \label{eq:proposition} S_k = 2^k - 1 \quad \text{for } k \geq 0. \end{equation} \]

Equation \(\ref{eq:proposition}\) is our proposition \(P\). The base case is easy enough to prove: \(S_0 = 0\) because there are no disks to move. For the inductive step, we use the non-base part of our recurrence from Equation \(\ref{eq:recurrence}\) to get

\[ \begin{align} S_k &= 2 * (S_{k - 1}) + 1 \label{eq:induct1} \end{align} \]

and rewrite it in terms of \(k + 1\):

\[ \begin{align} S_{k + 1} &= 2 * (S_{k}) + 1. \label{eq:induct2} \end{align} \]

Now the critical part: we replace \(S_k\) with Equation \(\ref{eq:proposition}\) (our proposition), because we assume that our proposition is true for all steps up to \(k\) (but not \(k + 1\), which is what we’re trying to prove):

\[ \begin{align} S_{k + 1} &= 2 * (2^k - 1) + 1. \end{align} \]

In case you forgot algebra, \(2 * 2^k = 2^1 * 2^k = 2^{k + 1}\) and we can use this to simplify our equation.

\[ \begin{align} S_{k + 1} &= 2 * (2^k - 1) + 1\\ &= [2 * (2^k - 1)] + 1\\ &= [(2 * 2^k - 2)] + 1\\ &= (2^{k + 1} - 2) + 1\\ &= 2^{k + 1} - 1 \label{eq:induct3}. \end{align} \]

And now we can see that Equation \(\ref{eq:induct3}\) (our “evolved” proposition \(P\), if you will) is the same as our solution (Equation \(\ref{eq:solution}\)), even though we increased \(k\) to \(k + 1\)! This is because simple substitution allows us to replace “\(k + 1\)” with “\(n\)”. We have completed our proof by induction. ^{4}

The book goes on to offer an alternate recurrence to Equation \(\ref{eq:recurrence}\), by adding 1 to both sides:

\[ \begin{align} (S_n) + 1 &= \begin{cases} 0 + 1 & \text{if } n = 0 \\ 2 * (S_{n - 1}) + 1 + 1 & \text{if } n > 0 \\ \end{cases}\\ &= \begin{cases} 1 & \text{if } n = 0 \\ 2 * (S_{n - 1}) + 2 & \text{if } n > 0. \label{eq:recurrence2} \end{cases} \end{align} \]

This recurrence is the same as the original, except that it adds 1 to the answer. Now we let \(W_n = (S_n) + 1\) and \(W_{n - 1} = (S_{n - 1}) + 1\) and rewrite everything in terms of \(W\):

\[ \begin{align} W_n &= \begin{cases} 1 & \text{if } n = 0 \\ 2 * (W_{n - 1}) & \text{if } n > 0. \label{eq:recurrence3} \end{cases} \end{align} \]

Notice how the “\( + 2\)” in Equation \(\ref{eq:recurrence2}\) goes away, because the coefficient \(2\) in Equation \(\ref{eq:recurrence3}\) will multiply with the “\( + 1\)” from \(W_{n - 1}\) to get it back. Using this alternate recurrence, it’s easy to see that the solution is just \(W_n = 2^n\), because \(W\) can only grow by multiplying \(2\) to itself! Hence

\[ \begin{align} W_n = (S_n) + 1 = 2^n \end{align} \]

and subtracting 1 from all sides gives us

\[ \begin{align} (W_n) - 1 =S_n = 2^n - 1. \end{align} \]

The lesson here is that if it is difficult to find the solution to a recurrence, we can use basic algebra rules to transform the recurrence to something more amenable. In this case, all it took was adding 1 to the original recurrence.

I thoroughly enjoyed figuring this stuff out because possibly for the first time in my life I used my programming experience (recurrence/recursion, memoization) to help myself understand mathematics — not the other way around. The other way around was never enjoyable — calculating what `i`

was in some \(n\)th iteration of a `for`

-loop never really excited me.

I hope this explanation helps you better understand the first few pages of *Concrete Mathematics*; I had to read that part three times over to really “get it” (never having learned what induction is). And henceforth, I will never look at a string of consecutive 1’s in binary the same way again. 😃

In computer science, this process of avoiding the recalculation of previously known values is called

*memoization*and is useful in generating the first N values of a recursive algorithm in \(O(N)\) (linear) time.↩Note that if \(k_0 = 0\), then \([k_0, k_{m}]\) is the set of all natural numbers (zero plus the positive integers).↩

There is no need to prove the recurrence (Equation \(\ref{eq:recurrence}\)) as we have already proved it in the process of deriving it.↩

In

*Concrete Mathematics*2 ed. p. 3 (where the book uses \(T_n\) instead of \(S_n\)), the proof is simply a one-liner: \[ T_n = 2(T_{n - 1}) + 1 = 2(2^{n - 1} - 1) + 1 = 2^n - 1. \] But I find it a bit too terse for my tastes.↩

`2017-04-14`

*
math, programming, python

The Fibonacci Sequence is defined as follows:

\[ \begin{align} \mathrm{F}_{0} = 0\\ \mathrm{F}_{1} = 1\\ \mathrm{F}_{n} = \mathrm{F}_{n - 2} + \mathrm{F}_{n - 1}. \end{align} \]

That is, each Fibonacci number \(\mathrm{F}_{n}\) is the sum of the previous two Fibonacci numbers, except the very first two numbers which are defined to be 0 and 1. ^{1}

From the definition above, it appears that computing \(\mathrm{F}_{n}\) requires one to always compute \(\mathrm{F}_{n - 2}\) and \(\mathrm{F}_{n - 1}\). **This is false:** enter the “doubling method”. ^{2} ^{3}

The doubling method uses a couple of mathematical formulas derived from matrix multiplication as it applies to calculating Fibonacci numbers; it can be seen as an improvement over the matrix multiplication method, although it does not use matrix multplication itself. The matrix multiplication method uses the following formula:

\[ \begin{equation} \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^n = \begin{bmatrix} \mathrm{F}_{n + 1} & \mathrm{F}_{n}\\ \mathrm{F}_{n} & \mathrm{F}_{n - 1} \end{bmatrix}. \end{equation} \]

This result is quite interesting in its own right; to find \(\mathrm{F}_{n}\) you only need to raise the matrix

\[ \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix} \]

to the \(n\)th power. To be more precise, this method is matrix *exponentiation*. The only downside is that much of the answer is wasted — we don’t care about \(\mathrm{F}_{n - 1}\), not to mention how \(\mathrm{F}_{n}\) is redundantly computed twice.

What if we could find \(\mathrm{F}_{n}\) not by multiplying or adding some numbers, but by multiplying and adding *other Fibonacci terms*? Of course, we’re not talking about adding \(\mathrm{F}_{n - 2}\) and \(\mathrm{F}_{n - 1}\) because that would be too slow. Let’s have a look at the matrix identity again (reversed for easier reading):

\[ \begin{equation} \begin{bmatrix} \mathrm{F}_{n + 1} & \mathrm{F}_{n}\\ \mathrm{F}_{n} & \mathrm{F}_{n - 1} \end{bmatrix} = \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^n. \end{equation} \]

If we substitute in \(2n\) for \(n\), we get

\[ \begin{align} \begin{bmatrix} \mathrm{F}_{2n + 1} & \mathrm{F}_{2n}\\ \mathrm{F}_{2n} & \mathrm{F}_{2n - 1} \end{bmatrix} & = \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^{2n} \\ & = \bigg(\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^{n}\bigg)^2 \end{align} \]

and we can substitute in our matrix identity from above to rewrite this as

\[ \begin{align} & = \bigg(\begin{bmatrix} \mathrm{F}_{n + 1} & \mathrm{F}_{n}\\ \mathrm{F}_{n} & \mathrm{F}_{n - 1} \end{bmatrix}\bigg)^2 \end{align} \]

and carry out the squaring to get

\[ \begin{align} & = \begin{bmatrix} {{\mathrm{F}_{n + 1}}^2 + {\mathrm{F}_{n}}^2} & {{\mathrm{F}_{n + 1}\mathrm{F}_{n}} + {\mathrm{F}_{n}\mathrm{F}_{n - 1}}}\\ {{\mathrm{F}_{n}\mathrm{F}_{n + 1}} + {\mathrm{F}_{n - 1}\mathrm{F}_{n}}} & {{\mathrm{F}_{n}}^2 + {\mathrm{F}_{n - 1}}^2} \end{bmatrix}. \end{align} \]

The top right and bottom left terms are identical; we can also rewrite them to be a bit simpler.

\[ \begin{align} {{\mathrm{F}_{n + 1}\mathrm{F}_{n}} + {\mathrm{F}_{n}\mathrm{F}_{n - 1}}} & = \mathrm{F}_{n}(\mathrm{F}_{n + 1} + \mathrm{F}_{n - 1}) \\ & = \mathrm{F}_{n}[\mathrm{F}_{n + 1} + (\mathrm{F}_{n + 1} - \mathrm{F}_{n})] \\ & = \mathrm{F}_{n}(2\mathrm{F}_{n + 1} - \mathrm{F}_{n}). \end{align} \]

This simplication achieves an important task — it obviates \(\mathrm{F}_{n - 1}\) by cleverly defining it as \(\mathrm{F}_{n + 1} - \mathrm{F}_{n}\). Putting everything together, whe have

\[ \begin{align} \begin{bmatrix} \mathrm{F}_{2n + 1} & \mathrm{F}_{2n}\\ \mathrm{F}_{2n} & \mathrm{F}_{2n - 1} \end{bmatrix} & = \begin{bmatrix} {{\mathrm{F}_{n + 1}}^2 + {\mathrm{F}_{n}}^2} & {\mathrm{F}_{n}(2\mathrm{F}_{n + 1} - \mathrm{F}_{n})}\\ {\mathrm{F}_{n}(2\mathrm{F}_{n + 1} - \mathrm{F}_{n})} & {{\mathrm{F}_{n}}^2 + {\mathrm{F}_{n - 1}}^2} \end{bmatrix} \end{align} \]

where the first row (or column) gives us two very useful identities

\[ \begin{align} \mathrm{F}_{2n} & = {\mathrm{F}_{n}(2\mathrm{F}_{n + 1} - \mathrm{F}_{n})} \\ \mathrm{F}_{2n + 1} & = {{\mathrm{F}_{n}}^2 + {\mathrm{F}_{n + 1}}^2}. \end{align} \]

As these identities form the heart of the doubling method, let’s call them the *doubling identities*.

And now we just need one more piece to formulate our doubling method; we need to borrow an idea from number theory. Given any positive integer \(n\), it is the same as either \(2m\) (even) or \(2m + 1\) (odd), where \(m = \lfloor\frac{n}{2}\rfloor\); for our purposes, let us call this property the “halving property”.

Whereas the doubling identities allow us to “double” our way into bigger numbers, the halving property allows us to halve our way down to smaller and smaller numbers. The marriage of these two concepts gives rise to the doubling method.

To compute the \(n\)th Fibonacci term we break \(n\) itself down into its halves (\(2m\)) recursively, until we go down to \(n = 0\). At this point we multiply our way back up using the doubling identities. Because halving and doubling by themselves always calculate \(\mathrm{F}_{2m}\), we have to manually return \(\mathrm{F}_{2m + 1}\) if our current sequence index number \(n\) is odd.

```
def fibonacci_doubling(n):
""" Calculate the Nth Fibonacci number using the doubling method. """
return _fibonacci_doubling(n)[0]
def _fibonacci_doubling(n):
""" Calculate Nth Fibonacci number using the doubling method. Return the
tuple (F(n), F(n+1))."""
if n == 0:
return (0, 1)
else:
a, b = _fibonacci_doubling(n >> 1)
c = a * ((b << 1) - a)
d = a * a + b * b
if n & 1:
return (d, c + d)
else:
return (c, d)
if __name__ == "__main__":
for n in range(20):
print(fibonacci_doubling(n))
# As a demonstration of this algorithm's speed, here is a large n.
print(fibonacci_doubling(10000))
```

Line 12 is where we do the halving. We use the right-shift operator to do this. Lines 13 and 14 are our doubling identities (I use the left-shift operator here because it feels more natural to me). The if-condition on line 15 returns \(\mathrm{F}_{2m + 1}\) if \(n\) was odd, and \(\mathrm{F}_{2m}\) otherwise.

For comparison, here is an iterative version. On the one hand it avoids Python’s recursion limit, but the downside is a small loss of elegance (we have to loop twice — first to build up the halving/doubling points, and again for the main loop).

I hope you enjoyed reading about this method of calculationg Fibonacci numbers as much as I enjoyed learning the math behind it. This algorithm can be sped up if it uses a faster multiplication algorithm as `a`

and `b`

get very large (e.g., Karatsuba multiplication). ^{4} Time complexity is \(\Theta(\log{n})\); it reminds me of the binary search algorithm, in how the problem space is halved repeatedly. Neat!

We can choose to define the first two terms as 1 and 1 instead, but this distinction is needlessly arbitrary.↩

There is actually a known formula for our purposes, where \[ \mathrm{F}_{n} = \frac{\varphi^n - (-\varphi)^{-n}}{2\varphi - 1}\] and \(\varphi = \frac{1 + \sqrt{5}}{2} \approx 1.6180339887\cdots\) (the golden ratio). Unfortunately this requires arbitrary-precision floating point calculations.↩

For more discussion, see https://www.nayuki.io/page/fast-fibonacci-algorithms.↩

Python already uses Karatsuba multiplication natively for large integers.↩

`2017-04-02`

*
programming, haskell

Yesterday I made a minimal working example of calling C from Haskell, where I call a simple C function to compute the greatest common denominator, or “GCD”. The Haskell portion only serves as a wrapper around the C function. This post is a brief look at the whole setup.

I used `ghc`

8.0.1, and `gcc`

5.4.0. ^{1}

```
2017-04-02-calling-c-from-haskell
├── build.sh
├── c
│ ├── gcd.c
│ └── gcd.h
└── hs
├── ffi.hs
└── GCD.hs
2 directories, 5 files
```

To compile the example, run the `build.sh`

script. Here is the expected output of the built executable:

```
$ ./hs/ffi
4
15
12
```

. The `gcd()`

C function is easy to work with because it is a pure function without side effects. You can run the `ffi`

binary against `valgrind`

to make sure that we are not leaking any memory (sample output below).

```
$ valgrind --error-exitcode=1 --leak-check=yes ./hs/ffi
==14582== Memcheck, a memory error detector
==14582== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==14582== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==14582== Command: ./hs/ffi
==14582==
==14582== Warning: set address range perms: large range [0x4200000000, 0x14200100000) (noaccess)
4
15
12
==14582==
==14582== HEAP SUMMARY:
==14582== in use at exit: 0 bytes in 0 blocks
==14582== total heap usage: 48 allocs, 48 frees, 60,006 bytes allocated
==14582==
==14582== All heap blocks were freed -- no leaks are possible
==14582==
==14582== For counts of detected and suppressed errors, rerun with: -v
==14582== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
```

Below are some things I tried, but could not get to work.

- I tried to delete the
`gcd.c`

file by moving the function definition in`gcd.c`

to`gcd.h`

(and delete`gcd.c`

entirely). I compiled the object file with`gcc -c -Wall -Wextra -Werror -o gcd.o gcd.h`

but then I got this error:

```
$ ghc --make ffi.hs ../c/gcd.o
[1 of 2] Compiling GCD ( GCD.hs, GCD.o )
[2 of 2] Compiling Main ( ffi.hs, ffi.o )
Linking ffi ...
../c/gcd.o: file not recognized: File format not recognized
collect2: error: ld returned 1 exit status
`cc' failed in phase `Linker'. (Exit code: 1)
```

- In
`GCD.hs`

you can see the line`foreign import ccall "gcd.h gcd"`

. Instinctively I thought that the`gcd.h`

in`"gcd.h gcd"`

served as a kind of disambiguator, for where the`gcd()`

function came from. So then I defined another function named`gcd()`

in a different C header file (`gcd_other.h`

), compiled it separately, but got a “multple definition” error:

```
$ ghc --make ffi.hs ../c/gcd.o ../c/gcd_other.o
[1 of 2] Compiling GCD ( GCD.hs, GCD.o )
[2 of 2] Compiling Main ( ffi.hs, ffi.o )
Linking ffi ...
../c/gcd_other.o: In function `gcd':
gcd_other.c:(.text+0x0): multiple definition of `gcd'
../c/gcd.o:gcd.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
`cc' failed in phase `Linker'. (Exit code: 1)
```

The version of gcc should not matter at all – actually, any decent C compiler should work.↩

`2016-12-04`

*
programming

I just open-sourced my dotfiles! The repo is probably one of the older Git repos out there and has over 2000 commits! The first commit was made in March 10, 2009, over 7 years ago. Mind you, even by that time I had accumulated a whole suite of configs, and I even had an exotic setup with XMonad 0.8.1!

Here are some takeaways:

It’s nice to have clean commit history — every line of code can answer **why** it exists. You are doing yourself a disservice (in the long run) if you have overly terse commit messages. Generally speaking, be as verbose as you can be, but within reason. Keeping the first line of the commit message down to less than 80 characters goes a long way in setting the tone for any auxiliary paragraphs that follow.

I am quite proud of the richness of my commit messages. Pretty much everything makes sense and I don’t have to use Google to reason about my choices.

I’ve used a stupidly simple build system of creating symlinks to “install” my configuration — all with the help of a single `Makefile`

. It’s not very flexible, and to be honest my Shell sklls are much better than what they used to be such that I could replace this setup with a script. But alas, the need for such a change has not been serious enough to warrant it.

Moreover, having a simple “build” system ensures robustness; the more I get older, the more I value systems that have a long “bit-rot halflife”. I admire Knuth’s TEX system for this very same reason. And this is the same reason why I will probably not use anything higher-level than a shell script for the job.

Every long-living code repository ends up collecting clutter over the years. It’s important to delete such code (and of course any corresponding comments), to keep the codebase nimble. Ultimately, the less code you have to maintain, the better.

Software evolves. Always be on the lookout for better software, and new ways to configure them! Leverage the power of open source (free upgrades!) and make it work for you.

If not, you should definitely consider it — what have you got to lose? Keeping a configuration repo (distributed across home computers) is probably the best way for you to learn how to use a distributed source control system; indeed it was how I learned to use Git properly.

Happy hacking!

]]>`2016-12-03`

*
programming, emacs, vim

I’ve been using Vim (and now, Emacs with Evil mode) for years — and still, every once in a while I get a pleasant surprise. Today I learned that you can replay macros from Visual Line mode! So you don’t always have to record something like `j0`

at the end of your macro to get down to the next line. I.e., after recording your macro for just 1 line, select other lines that you want to replay the macro against with Visual Line mode (`V`

). To replay, do

```
:'<,'>g/^/norm @q
```

(assuming that you recorded your macro into the `q`

register with `qq...q`

).

Thanks to Chris McCord for the tip (seek to about 3:20 in the video).

]]>`2016-10-30`

*
programming, tex

For years, whenever I wanted to interact with the outer shell environment from Latex, I would use one of two methods:

- perform some shell step separately from Latex and inject it into the Latex sources, or
- save it somewhere else and pull it in from Latex with
`\input{foo}`

.

But I learned recently that it can be done much more simply, if you are willing to use Luatex!

Let’s assume that you keep your Latex document in source control and want to inject the Git hash into the document. First, define a new command called `\shell`

.

```
% Call shell! See http://tex.stackexchange.com/a/114939/30920.
\newcommand\shell[1]{\directlua{
local handle, err = io.popen([[#1]])
if not handle then
tex.print(err)
os.exit(1)
end
local result = handle:read("*a")
handle:close()
tex.print(result)
}}
```

Then use it like this:

```
\shell{TZ='America/Los_Angeles' date}
\shell{git describe --always}%
\shell{(( $(git --no-pager diff 2>/dev/null | wc -l) + $(git --no-pager diff --cached 2>/dev/null | wc -l) > 0 )) && echo '*'}
```

. I then use `lualatex --shell-escape foo.tex`

to compile it. This is actual code from a Luatex document of mine.

I am not sure which shell program gets invoked, but for most things it should not matter much.

Now you know how to shell out from Latex!

Happy hacking!

]]>`2016-10-01`

*
programming, c, hardware

I’ve spent quite some time on keyboards in my previous posts, and this post is no different. After several months of tweaking my original layout, I have more or less settled on the final design. You can get the sources at my repo here.

Is for the name “ZQ”, it was originally chosen from the way these keys were arranged; the location of these keys have since changed, but the name has stuck.

```
□ □ □ □ □ □ □ □ □ □ □ □
! # * □ □ □ □ / ~ $
□ □ ; y o p v 1 1 m f t r _ □ □
□ 2 a i e u w 3 2 h j k l n 3 □ <--- Home row
4 z x q ' " b d g c s 4
5 6 7 8 9 5 , 6 7 8 <--------- Thumb row
Left-side legend
1) PageUp
2) Escape
3) Tab
4) Shift
5) Insert
6) Super (Windows key)
7) Space
8) Caps Lock (remapped with xmodmap to Hyper key)
9) Control
Right-side legend
1) PageDown
2) Return
3) Delete
4) Shift
5) FN2
6) FN
7) Alt
8) Right Alt (aka "AltGr" for US International Layout)
```

```
□ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ ? 7 8 9 = a a ` \ . : & □ □
□ □ - 4 5 6 + ^ @ b { ( ) } □ □ <--- Home row
□ 0 1 2 3 % | [ < > ] □
□ □ b □ □ □ □ □ □ □ <--------- Thumb row
Left-side legend
a) Home
b) Space
Right-side legend
a) End
b) Backspace
```

```
□ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ l g h i □ □ □ □ □ □ □ □ □ □
□ □ k d e f □ □ □ a b c d □ □ □ <--- Home row
□ j a b c □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ <--------- Thumb row
Left-side legend
a) F1
b) F2
c) F3
d) F4
e) F5
f) F6
g) F7
h) F8
i) F9
j) F10
k) F11
l) F12
Right-side legend
a) Left Arrow
b) Down Arrow
c) Up Arrow
d) Right Arrow
```

I have not covered this topic before, but I think it is worth mentioning. On the underside of each keycap, there is a number; presumably for the row that the keycap is designed for. I’ve rearranged the default keycap placement to better reflect how I use my keys. The biggest change from the default Esrille setup is that I vertically flip the thumb row keys, so that they are “upside-down”. I find this arrangement more comfortable for my thumbs.

```
n n n n n n n n n n n n
n n n n n n n n n n
n 3 3 3 3 3 3 n n 3 3 3 3 3 3 n
3 3 2 2 2 2 2 n n 2 2 2 2 2 3 3 <--- Home row
1 2 1 1 1 2 2 1 1 1 2 1
1 1 1 1 1 1 1 1 1 1 <--------- Thumb row*
Legend
n) No number
1) Row 1
2) Row 2
3) Row 3
*The thumb row keycaps are flipped upside-down for better comfort.
```

After some time, I realized that the end goal was to design a layout that was not more “optimal” in the sense of mechanical efficiency, but rather to design something more *comfortable* to use. I can readily say that even at this early stage, I tend to like this layout more over Qwerty because my hands stay put as I type. The only time I move my wrists from their default position is when I need to reach the six keys up top in the base layer (`!#*/~$`

).

It may turn out that this new layout does not really improve raw typing speed; but really I don’t care because home-row access to parentheses and the backspace key are too good to let go.

The design has changed quite a bit in these past few months. After some initial trials, I realized that the arrangement recommended by my program was not really optimized the way I wanted it to be. For one, the corpus I fed into the program was not very good because it didn’t realy reflect my real-world use-case; I use Vim-style HJKL keys almost everywhere, and really to get a truly representative histogram of keypresses, I should have used a keylogger for some months to record my actual usage. As time was of the essence, I decided to just evolve the layout gradually, tweaking bits I found annoying.

One hurdle was simply trying to avoid using the same finger in succession. In the current ZQ layout, the right index finger is charged with six keys: MHBFJD. It took a lot of trial and error to arrive at this combination.

I also just kept the original Qwerty placement of the HJKL keys. The main reason is that I use these keys all the time, so much that they deserve their original home-row placement. And, actually they helped in reducing same-finger consecutiveness (J and K are rare letters in English).

Another point of concern was the interaction of some key combinations like YN and <Return>. It is common to type either Y or N and press <Return> immediately after, when dealing with interactive torminal programs. The same goes for some UNIX-y combinations like `~/`

for the home directory in the filesystem, or `*`

and `/`

for interactive search in vim(1) and less(1), respectvely. The current design of ZQ strives to make these combinations easy to type.

Lastly, I paid a great deal of attention for certain common letter combinations — in particular, “gh”, “ch”, “sh”, “th”, and “wh”. Because I decided to keep HJKL keys on the home row, and because H was assigned to the right index finger, I had to make sure that I place the GCSTW keys either on the left side of the keyboard (as I did with “W”), or place them for the other fingers. This effort alone resulted in dictating where most of the keys ended up.

After all that’s been said, time will tell if I truly do end up using this layout. I have a friend who uses Dvorak for work and Qwerty for gaming; perhaps I’ll end up in a similar boat.

]]>`2016-09-24`

*
math, programming, haskell

Almost exactly two years ago, I discussed what I called the Parking Lot Problem. Recently I discovered that it is a widely-known problem, enough to be featured in the very first chapter of *Pearls of Functional Algorithm Design* (2010) by Richard Bird — where it is simply called “smallest free number”. In this post, I want to go over Bird’s explanations in more detail; my aim is to spare you the effort in deciphering his opaque writing style.

Bird presents two solutions — an imperative, array-based solution and a functional solution based on divide-and-conquer.

Bird describes the problem as “computing the smallest natural number not in a given finite set *X* of natural numbers”. Here, **natural numbers** means the set of all positive integers and zero, or just `[0..]`

in Haskell.

I would like to add some further terminology. Let us think of the set *X* as `xs`

(a list of elements in *X*), and call the set of all free numbers as the *free set*. Using our original parking lot analogy, the infinite parking lot is the set of all natural numbers, *X* is the list of parked spots (occupied), and finally the *free set* is the list of all unoccupied (open) parking spots.

The worst case of **minfreeNaive** is \(\Theta(n^2)\), because it translates into imperative pseudocode as follows:

```
# Algorithm P1
minfreeNaive(xs)
{
let freeSpots = array from 0 to infinity
let i = all natural numbers 0 to infinity
let j = i
let xs_max_idx = xs.length - 1
for (i = 0;; i++) {
for (j = 0; j < xs_max_idx; j++) {
if (i == xs[j]) {
remove i from freeSpots
}
}
if (i > xs_max_idx) {
break
}
}
return freeSpots.first_one
}
```

. Now imagine if **xs** looks like **[9,8,7,6,5,4,3,2,1,0]**. Then the first iteration of the outer **i** for-loop would check all 10 values in **xs**, until finally hitting the last value in **xs**, 0 to remove that 0 from **candidates**. Then the second iteration would check all values 9 through 2, until removing **1** from candidates. And so on, until it removed 9 as well. So, the total number of times that single **if** statement gets executed is

\[ 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 55 \]

. The formula for the sum of all positive, consecutive integers 1 through N is

\[ \frac{n(n + 1)}{2} = \frac{n^2 + n}{2}. \]

In Big-O notation, the above reduces to just \(n^2\) because of the first term \(n^2\) in \(n^2 + n\). ^{1} As a side note, the above equation has a colorful history in mathematics, anecdotally attributed to Gauss.

Bird says the following:

The key fact for both the array-based and divide and conquer solutions is that not every number in the range [ 0 ..

length xs] can be inxs. Thus the smallest number not inxsis the smallest number not infilter (<= n) xs, wheren = length xs.

. Let’s examine the first sentence. Consider `length xs = 1`

. That is, what if `xs`

is only 1 element big (only 1 car is parked in the lot)? Intuitively, it appears that we don’t need to perform millions and millions of checks. Since we know that there is only 1 car parked, we just need to consider if that car is in Parking Spot 0 (the first free spot, or *PS0*). If it is, then we can assign the next slot, PS1. Otherwise, we can assign PS0 itself. If there are 2 cars parked (`length xs = 2`

), in total we need only consider the first 2 spots, PS0, PS1 — if those are both taken, then the answer is PS2.

This leads us to the main theorem of this problem (let’s call it the **Fullness Theorem**):

For any

ncars parked, we can consider the spots numbered`[0..(n-1)]`

; if all of those spots are full, we can assign spotnitself.

(This statement may seem elementary, but it plays a crucial role in the divide-and-conquer approach discussed later.) Now, since `length [0..(n-1)]`

coincidentally happens to be just **n**, the total number of spots taken into consideration for this problem is **n + 1** — parking spots `[0..(n-1)]`

and spot `n`

itself. And so we can reduce the free set to just `[0..(n-1)] ++ [n]`

, or the equivalent `[0 .. length xs]`

and ignore all other possible free spots. ^{2} To restate, our answer to the original problem statement lies somewhere in this range `[0 .. length xs]`

, which we will call **reducedFrees**.

Now let’s look at the second sentence. It describes the set `filter (<n) xs`

, which we will call **reducedXs**. ^{3} The set **reducedXs** is found by removing all elements in **xs** that are too big for our problem size of **n + 1** spots — i.e., beyond the range in **reducedFrees**.

Using the insight gained above, we can restate the problem as follows:

```
import Data.Array (Array, accumArray, elems)
minfreeArray1 :: [Int] -> Int
minfreeArray1 = search . checklist
-- Look for first False value (empty space).
search :: Array Int Bool -> Int
search = length . takeWhile id . elems
-- Convert a list of parked spaces into an ordered list of Boolean values in the
-- range *reducedXs*.
checklist :: [Int] -> Array Int Bool
checklist xs = accumArray
(||) -- accumulating function
False -- initial value
(0, n) -- bounds of the array
(zip (filter (<n) xs) (repeat True)) -- association list of `(index, value)' pairs
where
n = length xs
```

.

Bird says “[t]he function *search* takes an array of Booleans, converts the array into a list of Booleans and returns the length of the longest initial segment consisting of *True* entries. This number will be the position of the first *False* entry.” This is true, and we’ll soon see why this is the case.

In order to understand how **minfreeArray1** works, let’s first examine a further simplification of the problem. Conceptually we are only interested in the very first group of consecutively parked cars (if it exists at all), because as soon as this first group of cars ends, we are at the lowest-numbered free parking spot. In binary, we can represent an empty spot as 0 and a parked car as 1. The set of parked cars in **reducedXs** might look something like this (using a `.`

for `0`

):

```
111111.11.1.111.1.111.111.11.1......1.1.111.1
^^^^^^
```

. Although there are many groups of parked cars, we are only interested in the **first** group, denoted by the hat signs. Consider another example:

```
.111.1.111.11...
^^^
```

. In this there is the triplet of cars, but it starts after an empty spot at PS0. Lastly let’s consider

```
..........1..111111.111.1.1.111.1
^
```

; again, the first group of cars (in this case just 1 car) is preceded by an empty spot (actually, many such empty spots). In the last two examples, the answer is simply 0, for the very first spot PS0. For all other cases, the first group of cars starts from PS0, and extends some arbitrary number of spots, until “breaking” by an available spot. So there are two cases really as far as **reducedXs** is concerned:

- there is a contiguous group of car(s) from PS0 onwards, or
- PS0 is empty.

The algorithm then is simply `length $ takeWhile (==True) checklist`

, where `checklist`

is a list of Boolean values with a 1:1 mapping of the parking spots, in order (with `True`

representing a parked car and `False`

representing an empty spot). If we’re in case 2) as above, then we get 0 because `takeWhile`

never grows. If we’re in case 1), `takeWhile`

keeps growing until the first empty spot; coincidentally, the length of `takeWhile`

’s return list happens to be the index of the next free spot, we can just use the size of the return list of `takeWhile`

as-is.

And this is exactly what the `search`

function does in the algorithm Bird describes. `elems`

returns all the elements of an Array. `takeWhile`

grows a list so long as the given predicate evaluates to **True**; since we already have Booleans, we can just use **id**. All we need to give as an argument to `search`

is a Boolean list that is ordered from PS0 to PSn (the range of **reducedXs**). This conversion of a list of unordered natural numbers into a sorted list of Boolean values in the range covered by **reducedXs** is handled by `checklist`

.

Bird uses the library function `Data.Array.accumArray`

to populate `checklist`

. `accumArray`

takes a list of index-value pairs, and if there are multiple pairs with the same index, combines the values of those pairs using the accumulating function. A common use case of `accumArray`

is to use it to create a histogram of values, by using `(+)`

as the accumulating function (so that all values at a particular index are summed together). In the `checklist`

implementation by Bird, the accumulating function is `(||)`

(logical OR function) to account for the possibility of duplicate numbers in `xs`

. E.g., if `xs = [1, 2, 1]`

, then the ordered pairs are `[(0, False), (1, True), (2, True), (1, True)]`

, and `checklist`

evaluates to `[False, True, True]`

, because the `True`

value in the two instances of `(1, True)`

are simply OR-ed together by `(||)`

.

`accumArray`

to sort numbersBird mentions that you can use `accumArray`

to sort positive integers. The code is as follows:

```
import Data.Array (Array, accumArray)
countlist :: [Int] -> Array Int Int
countlist xs = accumArray (+) 0 (0, n) (zip xs (repeat 1))
sort xs = concat [ replicate k x | (x, k) <- assocs $ countlist xs ]
```

. (Bird defines `sort`

without the use of `assocs`

which gives a list of tuples of the form `(index, element-at-index)`

, but that is in error.) The way it works is, `countlist`

essentially builds a histogram of numbers we want to sort. So, given `[0, 6, 2, 0, 0]`

, we get `[(0,3),(2,1),(6,1)]`

. We then use `replicate`

in `sort`

to “unpack” each element of the histogram. Continuing with the example, `(0,3)`

becomes `[0, 0, 0]`

, `(2,1)`

becomes `[2]`

, and so on. Since the result looks like `[[0,0,0],[2],[6]]`

we have to `concat`

it to get `[0,0,0,2,6]`

, our sorted list.

It should be reiterated here that ultimately we want to have an ordered list of Booleans that preserves the occupied parking spot information in the original list of “taken” spots. The way in which `checklist`

performs the conversion of unordered numbers into a nice list of Booleans in the range `[0..n]`

is virtually identical in design to the algorithm described by Jon Bentley in the very first chapter of his book *Programming Pearls* (2nd Ed., 2000). There Bentley used a bitmap to represent a Boolean array because of strict memory requirements — but otherwise the spirit of the data structure remains the same.

Bird’s final array-based algorithm uses the ST Monad to squeeze out some more performance of the `checklist`

function. Here is the code:

```
import Data.Array (Array, elems)
import Data.Array.ST (runSTArray, newArray, writeArray)
minfreeArray2 :: [Int] -> Int
minfreeArray2 = search . checklist
search :: Array Int Bool -> Int
search = length . takeWhile id . elems
checklist :: [Int] -> Array Int Bool
checklist xs = runSTArray $ do
a <- newArray (0, n) False
sequence [writeArray a x True | x <- xs, x < n]
return a
where
n = length xs
```

. The use of the ST monad here reduces memory overhead, and according to Bird it is the most efficient approach using an imperative style on top of arrays.

Ah, recursion. Bird describes the following divide-and-conquer algorithm as a faster alternative to `accumArray`

. ^{4}

```
import Data.List (partition)
minfreeRecurse :: [Int] -> Int
minfreeRecurse xs = minfrom 0 (length xs, xs)
minfrom :: Int -> (Int, [Int]) -> Int
minfrom a (n, xs)
| (n == 0) = a
| (m == b - a) = minfrom b (n - m, bs)
| otherwise = minfrom a (m, as)
where
(as, bs) = partition (<b) xs
b = a + (div n 2) + 1
m = length as
```

The overall idea is that we can define the problem `minimum of ([0..] \\ xs)`

by dividing up `xs`

into 2 halves, and then look into the correct sub-part for the solution. Notice that we are partitioning the `xs`

(soley the list of parked spots), and *not* the parking lot itself.

For example, we can divide up `xs`

into `as`

and `bs`

, where `(as, bs) = partition (<b) xs`

. (The `partition`

library function simply splits up a given list into 2 subsets, those that satisfy the given condition, and those that do not.) Deciding which partition to look at is simple: look in the upper partition if the lower partition (containing the smaller-numbered parking spots) is full.

The line `(n == 0) = a`

merely means that, if the list of cars is empty, simply choose the lowest number (which is, by definition, `a`

). The line `(m == b - a) = minfrom b (n -m, bs)`

chooses the bigger partition of the two partitions, on the condition `(m == b - a)`

. This condition asks whether the *length* of `as`

(the first partition) equal to the distance of `b - a`

— in other words, whether `as`

fills up the entire range `[a..(b-1)]`

. If it does fill up the entire range, then this parking lot subsection is completely packed with cars, so there is no point in looking; we must look into the other partition (`[b..]`

) for the first empty spot. Otherwise, we look into the first partition.

The hard part here is choosing the value of `b`

(the pivot at which we decide to partition `xs`

). By definition, our partitions are `as`

and `bs`

, where `(as, bs) = partition (<b) xs`

.) There are two things we want:

- minimum difference in size between
`as`

and`bs`

, and - nonzero length partition for the first partition
`as`

.

We want minimal size difference between `as`

and `bs`

because otherwise we might end up calling `minfrom`

many times; we want it so that whether we use `as`

or `bs`

(in whichever sequence), we deal with smaller and smaller lists of parked cars. The only way to do this is to divide the list of cars by half each time. This is where we get `div n 2`

. This is, more or less, the spirit of binary search.

The requirement of the second condition is more subtle — we want to avoid taking a zero-length partition for `as`

, because our main conditional `m == b - a`

relies on the fact that this distance, `b - a`

, is nonzero. This is because it must ask the question, “do the parking spots in the first partition fill up all spots in the range that it can cover?”, and this question loses its meaning if we give it an empty partition. Seen another way, the statement `partition (<b) xs`

, and the act of choosing those `xs`

that are `b`

or bigger *if the first partition is completely full*, is the recursive analogue of the Fullness Theorem. Whereas the Fullness Theorem did not really help much in the iterative array-based solution, it plays a key role in this recursive solution, because it correctly describes how to partition `xs`

with minimum fuss. The phrase “otherwise assign spot **n** itself” in that Theorem translates to choosing the non-full, bigger partition, because it starts with spot **n** — the only twist here is that instead of assigning spot **n** directly, we re-assign ourselves a new problem of looking for parking spots *starting* with spot **n**. To be clear, this partitioning scheme merely discards consecutive runs of parked cars, about `div n 2`

spots at a time.

For demonstrative purposes, let’s consider what would happen if we ignored what we just said and really did define `b`

as

for the case of `xs = [0]`

and `n = 1`

; we would start off with

and

\[ b = 0 + (\mathrm{div}\;1\,2) = 0 + 0 = 0, \]

such that

and since

we would in turn execute

, resulting in an infinite loop! Thus the correct way to choose `b`

is with

Bird gives the running time as \(\Theta(n)\). He offers this cryptic phrase:

… the number of steps \(T(n)\) for evaluating

minfrom 0 xswhenn = length xssatisfies \(T(n) = T(n\,div\,2) + \Theta(n)\), with the solution \(T(n) = \Theta(n)\).

Alas, I am not sure what this means. Here’s my own justification of why we have running time \(\Theta(n)\). The two most expensive operations in the recursive algorithm are `m = length as`

and `partition (<b) xs`

. The thing is that both of these calculations take \(\Theta(n)\) time, and both occur only once each, for every call to `minfrom`

. Now, `minfrom`

calculates `length as`

, but *it does not calculate* `length bs`

. This is again, because of the Fullness Theorem — we only care about the first partition being completely packed with cars. Thus, we never really calculate `m = length as`

over the same range. The worst case is an input like `xs = [0..1000]`

where the entire range of concern is packed with cars; in this case we would calculate the length of `[0..500]`

, then see that it’s full and choose the second partition. We’d then choose `[501..750]`

, and so on, such that the sum of these calculations effectively cost as much as `length xs`

, or \(n\) itself.

In my sister post, I also described a similar problem, dubbed the Parking Load problem. At the time, I was quite surprised at how the answer was much simpler and easier to calculate. From the insight I gained from the Fullness Theorem, I think it is clear why that is the case. Indeed, the Parking Load problem is just a slight wrinkle of the Fullness Theorem, where `n`

(number of parked cars) is known, but `b`

(the endpoint of the “partition”), if you will, is unknown. The problem is to simply compute \(b + 1 - n\). (We have to add 1 to `b`

because we use 0-based indexing.) I love it when you can explain something in a new way — don’t you?

I think this lays to rest (for now) the intricacies of the Parking Lot problem, or as Bird puts it, finding the smallest free number. Still, I like my parking lot analogy better because I believe it’s important to talk about problems in a way that can be related to the real world.

Big-O only cares about growth of the algorithm; the \(n^2\) will come to dominate the growth rate as \(n\) gets bigger.↩

It is for this reason, apart from looping indefinitely, that justifies the

**break**condition for the outer loop in Algorithm P1.↩Bird wrote (<=n) as the filter condition, but this is in error. The simpler

`(<n)`

does the job just as well.↩According to Bird, it is 20% faster than the array-based algorithm.↩