## Archive for **October 2017**

## The Tortoise and the Hare in TLA+

Problem: Determine if a linked list contains a cycle, using O(1) space.

Robert Floyd invented an algorithm for solving this problem in the late 60s, which is called “The Tortoise and the Hare”[1].

(This is supposedly a popular question to ask in technical interviews. I’m not a fan of expecting interviewees to re-invent the algorithms of famous computer scientists on the spot).

As an exercise, I implemented the algorithm in TLA+, using PlusCal.

The algorithm itself is very simple: the hardest part was deciding how to model linked lists in TLA+. We want to model *the set of all linked lists, *to express that algorithm should work for any element of the set. However, the model checker can only work with finite sets. The typical approach is to do something like “the set of all linked lists which contain up to *N* nodes”, and then run the checker against different values of *N*.

What I ended up doing was generating *N* nodes, giving each node a successor

(a *next* element, which could be the terminal value `NIL`

), and then selecting

the start of the list from the set of nodes:

```
CONSTANTS N, NIL
Nodes == 1..N
start \in Nodes
succ \in [Nodes -> Nodes \union {NIL}]
```

This is not the most efficient way from a model checker point of view, because the model checker will generate nodes that are irrelevant because they aren’t in the list. However, it does generate all possible linked lists up to length *N*.

Superficially, this doesn’t look like the pointer-and-structure linked list you’d see in C, but it behaves the same way at a high level. It’s possible to model a memory address space and pointers in TLA+, but I chose not to do so.

In addition, the nodes of a linked list typically have an associated value, but Floyd’s algorithm doesn’t use this value, so I didn’t model it.

Here’s my implementation of the algorithm:

```
EXTENDS Naturals
CONSTANTS N, NIL
Nodes == 1..N
(*
--fair algorithm TortoiseAndHare
variables
start \in Nodes,
succ \in [Nodes -> Nodes \union {NIL}],
cycle, tortoise, hare, done;
begin
h0: tortoise := start;
hare := start;
done := FALSE;
h1: while ~done do
h2: tortoise := succ[tortoise];
hare := LET hare1 == succ[hare] IN
IF hare1 \in DOMAIN succ THEN succ[hare1] ELSE NIL;
h3: if tortoise = NIL \/ hare = NIL then
cycle := FALSE;
done := TRUE;
elsif tortoise = hare then
cycle := TRUE;
done := TRUE;
end if;
end while;
end algorithm
*)
```

I wanted to use the model checker to verify the the implementation was correct:

```
PartialCorrectness == pc="Done" => (cycle <=> HasCycle(start))
```

(See the Correctness wikipedia page for why this is called “partial correctness”).

To check correctness, I needed to implement my `HasCycle`

operator (without resorting to Floyd’s algorithm). I used the transitive closure of the successor function for this, which is called `TC`

here. If the transitive closure contains the pair `(node, NIL)`

, then the list that starts with `node`

does not contain a cycle:

```
HasCycle(node) == LET R == {<<s, t>> \in Nodes \X (Nodes \union {NIL}): succ[s] = t }
IN <<node, NIL>> \notin TC(R)
```

To implement the transitive closure in TLA+, I used an existing implementation

from the TLA+ repository itself:

```
TC(R) ==
LET Support(X) == {r[1] : r \in X} \cup {r[2] : r \in X}
S == Support(R)
RECURSIVE TCR(_)
TCR(T) == IF T = {}
THEN R
ELSE LET r == CHOOSE s \in T : TRUE
RR == TCR(T \ {r})
IN RR \cup {<<s, t>> \in S \X S :
<<s, r>> \in RR /\ <<r, t>> \in RR}
IN TCR(S)
```

The full model is the lorin/tla-tortoise-hare repo on GitHub.

- Thanks to Reginald Braithwaite for the reference in his excellent book Javascript Allongé. ↩

## Death of a pledge as systems failure

Caitlin Flanagan has written a fantastic and disturbing piece for the Atlantic entitled Death at a Penn State Fraternity.

This line really jumped out at me:

Fraternities do have a zero-tolerance policy regarding hazing. And that’s probably one of the reasons Tim Piazza is dead.

The official policy of the fraternities is that hazing is forbidden. Because this is the official policy, it is the individuals in a particular frat house that are held responsible if hazing happens, not the national fraternity organization.

This policy has had the effect of insulating the organizations from being liable, but it hasn’t stopped hazing from being widespread: according to Flanagan, 80% of fraternity members report being hazed.

Because individual fraternity members are the ones that are on the hook if something goes wrong during hazing, reporting an injury carries risk, which means the member must make a decision involving a tradeoff. In the case documented above, that tradeoff led to a nineteen year old dying of his injuries.

This example really reinforces ideas around systems thinking: the introduction of the zero-tolerance policy did not have the intended effect. Because the culture of hazing remains, the policy ended up making things worse.