Loopless Gray Code Enumeration and the Tower of Bucharest

We give new algorithms for generating all n-tuples over an alphabet of m letters, changing only one letter at a time (Gray codes). These algorithms are based on the connection with variations of the Towers of Hanoi game. Our algorithms are loopless, in the sense that the next change can be determined in a constant number of steps, and they can be implemented in hardware. We also give another family of loopless algorithms that is based on the idea of working ahead and saving the work in a buffer.


1
Introduction: the binary reflected Gray code and the Towers of Hanoi

Loopless algorithms
The Gray code has an advantage over alternative algorithms for enumerating the binary strings, for example in lexicographic order: one can change a binary string a n a n−1 . . . a 1 to the successor in the sequence by a single update of the form a i := 1 − a i in constant time. However, we also have to compute the position i of the bit which has to be updated. A straightforward implementation of the recursive definition (1) leads to an algorithm with an optimal overall runtime of O(2 n ), i.e., constant average time per enumerated bit string.
A stricter requirement is to compute each successor string in constant worst-case time. Such an algorithm is called a loopless generation algorithm. Loopless enumeration algorithms for various combinatorial structures were pioneered by Ehrlich [3], and different loopless algorithms for Gray codes are known, see Bitner, Ehrlich, and Reingold [1] and Knuth [

The Tower of Hanoi
The Tower of Hanoi is the standard textbook example for illustrating the principle of recursive algorithms. It has n disks D 1 , D 2 , . . . , D n of increasing radii and three pegs P 0 , P 1 , P 2 , see Fig. 2. The goal is to move all disks from the peg P 0 , where they initially rest, to another peg, subject to the following rules: 1. Only one disk may be moved at a time: the topmost disk from one peg can be moved on top of the disks of another peg 2. A disk can never lie on top of a smaller disk.

Figure 2
The Towers of Hanoi with n = 6 (square) disks. When running the algorithm HANOI from Section 1.5, the configuration in this picture occurs together with the bit string 110011. (There is no easy relation between the positions of the disks and this bit string.) The next disk to move is D1; it moves clockwise to peg P0, and the last bit is complemented. The successor in the Gray code is the string 110010. After that, D1 pauses for one step, while disk D3 moves, again clockwise, from P1 to P2, and the third bit from the right is complemented, leading to the string 110110.
For moving a tower of height n, one has to move disk D n at some point. But before moving disk D n from peg A to B, one has to move the disks D 1 , . . . , D n−1 , which lie on top of D n , out of the way, onto the third peg. After moving D n to B, these disks have to be moved from the third peg to B. This reduces the problem for a tower of height n to two towers of height n − 1, leading to the following recursive procedure.
(auxiliary is the third peg, different from A and B.)

Connections between the Towers of Hanoi and Gray codes
The delta sequence of the Gray code is the sequence 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, . . . of bit positions that are updated. (In contrast to the usual convention, we number the bits starting from 1.) This sequence has an obvious recursive structure which results from (1). It also describes the number of changed bits when incrementing from i to i + 1 in binary counting. Moreover, it is easy to observe that the same sequence also describes the disks that are moved by the recursive algorithm move_tower above. It has thus been noted that the Gray code G n can be used to solve the Tower of Hanoi puzzle, cf. Scorer, Grundy, and Smith [8] or Gardner [4].
In the other direction, the Tower of Hanoi puzzle can be used to generate the Gray code G n , see Buneman and Levy [2]. Several loopless ways to compute the next move for the Towers of Hanoi are known, and they lead directly to loopless algorithms for the Gray code. We describe one such algorithm.

Loopless Tower of Hanoi and binary Gray code
From the recursive algorithm move_tower, it is not hard to derive the following fact.

Proposition 1.
If the tower should be moved from P 0 to P 1 and n is odd, or if the tower should be moved from P 0 to P 2 and n is even, the moves of the odd-numbered disks always proceed in forward ("clockwise") circular direction: P 0 → P 1 → P 2 → P 0 , and the evennumbered disks always proceed in the opposite circular direction: In the other case, when the assumption does not hold, the directions are simply swapped. Since we are interested not in moving the tower to a specific target peg, but in generating the Gray code, we stick with the proposition as stated.
Algorithm HANOI. Loopless algorithm for the binary Gray code.
Initialize: Put all disks on P 0 .

loop:
Move D 1 clockwise. Let D k be the smaller of the topmost disks on the two pegs that don't carry D 1 . If there is no such disk, terminate. Move D k clockwise if k is odd; otherwise, move it counterclockwise.
To obtain the Gray code, we simply set a k := 1 − a k whenever we move the disk D k [2]. See Fig. 2 for a snapshot of the procedure. We would not need the clockwise/counterclockwise rule for D k : Since we must not put D k on top of D 1 , there is anyway no choice of where to move it [2]. We have chosen the above formulation since it is better suited for generalization.

Overview
In the remainder of this paper, we will generalize these connections to Gray codes for larger radixes (alphabet sizes). Section 2 is devoted to ternary Gray codes and their connections to the so-called Towers of Bucharest. After defining Gray codes with general radixes in Section 3, we extend the ternary algorithm from Section 2 to arbitrary odd radixes m in Section 4, and even to mixed (odd) radixes (Section 6). In Section 5, we generalize the binary Gray code algorithm of Section 1.5 to arbitrary even m. Finally, in Section 8, we develop loopless algorithms bases on an entirely different idea of "working ahead" that is related to converting amortized running-time bounds to worst-case bounds. In the appendix, we give prototype code for simulating all our algorithms in Python.

Ternary Gray codes and the Towers of Bucharest
A ternary Gray code enumerates the 3 n n-tuples (a n , . . . , a 1 ) with a i ∈ {0, 1, 2}. Successive tuples differ in one entry, and in this entry they differ by ±1.
The following simple variation of the Towers of Hanoi will yield a ternary Gray code (m = 3): We disallow the direct movement of a disk between pegs P 0 and P 2 : a disk can only be moved to an adjacent peg. We call this the Towers of Bucharest. 1 The state graphs of (a) the Tower of Hanoi and (b) the Tower of Bucharest with 5 disks Figure 3 shows the state space of the Towers of Bucharest in comparison with the Towers of Hanoi. In accordance with this figure, we can make the following easy observations: Proposition 2. 1. In the towers of Hanoi, there are three possible moves from any position, except when the whole tower is on one peg: In these cases, there are only two possible moves.

2.
In the towers of Bucharest, there are two possible moves from any position, except when the whole tower is on peg P 0 or P 2 : In those cases, there is only one possible move. 1 The custom of naming variations of the Tower of Hanoi game after different cities, instead of using ordinary names such as "three-in-a-row" [7], has a long tradition. The name "Towers of Bucharest" has been suggested by Günter M. Ziegler. Several legends rank themselves around these towers. A little count from Transylvania had conquered the whole country and had become a powerful Lord. In order to celebrate his glory, he built a magnificent palace in the capital city Bucharest, and he suppressed his people as best he could. He also had a dog named Heisenberg. In a nearby monastery, the monks had golden disks of different sizes on three pegs, and they had played the Towers of Hanoi game for centuries. It was already forseeable that the game was drawing towards its conclusion. According to an ancient prophecy, the palace of the ruler of the country would crumble and his rule would come to an end when the game would be finished. When the count, who called himself king by this time, heard this story, he did not like it. First of all, he had the monks beheaded and told them to do some useful job instead. Secondly, he removed the pegs with the discs and took them to his palace. He made sure that they were placed very far away from each other: The first peg was put in the South wing, the second peg in the North wing, and the third peg again in the South wing. One may wonder why he did not place them in some more logical arrangement like South-South-North or South-North-North, or perhaps North-middle-South or South-middle-North. The reader will soon understand that this placement was a clever decision when she or he learns what else he did. The North wing could only be reached from the South wing through the middle wing, or by going out on the street and reentering on the other side, but I don't think it is very wise to go into the street carrying a heavy golden disk. Anyway, his third action was his most wicked and smartest move: It occurred to him that he was powerful and he was the ruler, and he therefore had the power to change the rules. He decreed that the discs can only be moved between the first and the second peg or between the second and the third peg. Direct moves between the first and third peg were henceforth forbidden. This would delay the moves of Proof. 1. The disk D 1 can be moved to any of the other pegs (two possible moves). In addition, the smaller of the topmost disks on the other pegs (if those pegs aren't both empty) can be moved to the other peg which is not occupied by D 1 .

2.
If the disk D 1 is in the middle, it can be moved to any of the other pegs, but no other move is possible. If the disk D 1 is on P 0 or P 2 , it has only one possible move, and the smaller of the topmost disks on the other pegs (if those pegs aren't empty) also has one possible move, similarly as above. Both games have the same set of 3 n states, corresponding to the possible ways of assigning each disk to one of the pegs P 0 , P 1 , P 2 . The nodes in the corners marked P 0 , P 1 , P 2 represent the states where all disks are on one peg. The graph of the Towers of Hanoi in Figure 3a approaches the Sierpiński gasket. The optimal path of length 2 n − 1 is the straight path from P 0 to P 2 . (The directions of the edges in this drawing of the state graph are not directly related to the pegs that are involved in the exchange, and the relation between a state and its position on the drawing is not straightforward.) By contrast, we see that the graph of the Towers of Bucharest in Figure 3b is a single path through all nodes.
Let us see why this is true. By Proposition 2, this graph has maximum degree 2, and it follows that it must consist of a path between P 0 and P 2 (the only degree-1 nodes), plus a number of disjoint cycles. However, it is known that the path has length 3 n − 1 and does therefore indeed go through all nodes. Since we will prove a more general statement later (Theorem 3), we only sketch the argument here: Solving the problem recursively in an analogous way to the procedure move_tower, we reduce the problem of moving a tower of n disks from P 0 to P 2 (or vice versa) to three problem instances with n − 1 disks, plus two movements of disk D n , and the resulting recursion establishes that 3 n − 1 moves are required.
The states of the Towers of Bucharest correspond in a natural way to the ternary n-tuples: The digit a i ∈ {0, 1, 2} gives the position of disk D i . It follows now easily that the solution of the Towers of Bucharest yields a ternary Gray code: Since we can move only one disk at a time, it means that we change only one digit at a time, and by the special rules of the Towers of Bucharest, we change it by ±1. (This connection has apparently not been made before.) In fact, the algorithm produces the ternary reflected Gray code, which we are about to define below in Section 3; see also Theorem 3.
the disks, since they always had to be carried all the way from the South wing to the North wing and back. As shown in this article, the consequences of the new rule in delaying the game are even more spectacular. These measures were definitely overcautious, in particular since nobody was there to move the discs any more, and moreover, the pegs with the golden discs were carefully guarded. Nevertheless, he was worried that his wife and children would wander around in the palace and play with the disks, thereby setting the prophecy into motion again, like in that movie, "Jumanji" with Robin Williams. He was not sure how the guarding officers would behave in a conflict between the loyalty to their orders and the authority of his family members. You may draw your own conclusions, but in my opinion, this count, or king if you wish, was pretty paranoid. In the end, it served him nothing. He was swept away by the revolution. What became of the golden disks? Nobody knows. It is sometimes claimed that they were hidden in a subterranean cave, and hobby archaeologists are still looking for them occasionally. But probably they have found their way to the black market. Today, tourists that visit the palace are led to a stump on the floor in the North wing, which is supposedly the remainder of one of the pegs. The South wing is closed for restoration. Another story, even more unbelievable but no less bloody than the first one, puts the Towers of Bucharest in the context of the legendary caliph Harun-al-Rashid. One night, the caliph was again wandering through the streets of Baghdad, as usual dressed like an ordinary businessman, in order to assure himself that the people were still loving his reign, admiring his wisdom, and praising his justice. He noticed a crowd of lookers-on who were gathered around a man and a woman sitting on the ground side by side, silently and solemnly executing the moves of the Towers of Bucharest. One of them would pick up a disk and set it on an adjacent peg. By the rules of the game, there was always one of them for whom the two involved pegs were easy to reach, and this was the one who carried out the move. Only on the infrequent occasions when one of the larger and heavier disks had to be moved, they helped each other. The man wore a Moreover, since there are only two possible moves, one just has to always choose the move which does not undo the previous move, and this leads to a very easy loopless Gray code enumeration algorithm.
It is remarkable that ternary Gray codes can be generated on the same hardware as binary Gray codes (Fig. 2). In the context of generating the ternary Gray code, the Gray code string can be directly read off the disks. For example, the configuration in Fig. 2 represents the string 211102. It is D 1 's turn to move, and the disk D 1 will make two steps to the left, generating the strings 211101 and 211100, and pauses there for one step, while disk D 3 moves to the right, leading to the string 211200, etc.

Gray codes with general radixes
An m-ary Gray code enumerates the n-tuples (a n , . . . , a 1 ) with 0 ≤ a i < m, changing a single digit at a time by ±1. The m-ary reflected Gray code can be recursively described as follows: Let C 1 , C 2 , . . . , C m n be the Gray code for the strings of length n. Then the strings of length n + 1 are generated in the order Each digit alternates between an upward sweep from 0 to m − 1 and a return sweep from m − 1 to 0.

Generating the m-ary Gray code with odd m
For odd m, the ternary algorithm can be generalized. We need m pegs P 0 , . . . , P m−1 . The leftmost peg P 0 and the rightmost peg P m−1 play a special role. The other pegs are called the intermediate pegs.
Algorithm ODD. Generation of the m-ary Gray code for odd m.
Initialize: Put all disks on P 0 .

loop:
Move D 1 for m − 1 steps, from P 0 to P m−1 or vice versa. Let D k be the smallest of the topmost disks on the m − 1 pegs that don't carry D 1 . If there is no such disk, terminate.
Move D k by one step: If D k is on P 0 or P m−1 , there is only one possible direction where to go. Otherwise, the disk D k continues in the same direction as in its last move.
cowboy hat, and the woman was in her bikini. After all, it might have been the Towers of Hanoi that they played. Some witnesses have later reported that they had seen a disc jumping between the first and the third peg, but this has never been conclusively confirmed.
May that as it be, something unexpected happened. As the khaliph was engrossed in watching the spectacle and drew a bit closer, a small door in the wall beside him opened, which he had not noticed before. It gave onto a small garden. The moon had risen over the rooftops, and her light gave a sort-of surreal atmosphere to the whole scene. In the middle of the garden, at the corner of a fountain, a woman sang, accompanying herself on the lute. She had a beautiful voice, a bit like Mariah Carey or Adele. The calif would have listened longer, but he was quickly escorted into a house, where a maid-servant took charge of him and handed him a black gown. "Hurry up, you are late. We were waiting only for you!" The gown covered his whole stature and hid his face, and he entered a room that was barely lit by an open fire. Seven other men in black gowns were already sitting on small stools in a circle around the fire. One stool was free, and he sat down. Beside the fire, there was a small ivory model of the Towers of Bucharest, with the four largest of the n = 6 disks on the final peg. Disc 1 was on the middle peg, and disk 2 was on the first peg. The kaliph, having watched the game just before, understood immediately what that meant. Nowbody said a word. The tension rose. After six minutes, a lady entered and addressed them. She was the singer from the fountain. "Gentlemen. You have sworn to come to my rescue when I would be in need. Now the time has come to fulfill your oath. You see seven discs of different sizes. He who will draw the smallest disk will bring me the head of the detestable caliph Harun-al-Rashid (ca. 763-809). Should he fail to fulfill this task, the other eight will kill him, and we will come together and draw again." With these words, she dropped the discs into a chalice. In silence, each man picked a disk. The kaliph was last to draw. As he opened his hand, sure enough, he found the smallest disc, disc number 1. He rose and said: "Fair lady, I will fulfill your order as I have promised. But pray tell me: by which deeds or words has the kalif enraged you so much that you wish him to Figure 4 shows an example with m = 5. The game with 5 pegs is called the Tower of Klagenfurt, after the birthplace of the senior author. 2 Figure 4 The Towers of Klagenfurt. This configuration represents the string 321411 over the radix m = 5. The next step of the Gray code moves the smallest disk D1 onto peg P0, changing the string to 321410. After that, disk D2 moves from P1 to P2 and the next string is 321420. In the background, the two-headed Lindworm monster.
In this procedure, the movement of D 1 is "externally given", whereas the movement of the other disks, whenever D 1 is at rest, is somehow "determined by the algorithm". It is not obvious that the algorithm does not put a larger disk on top of D 1 .

Theorem 3. Algorithm ODD generates the m-ary reflected Gray code defined in (2).
Proof. It is clear from the algorithm that the last digit, which is controlled by the movement of D 1 , changes in accordance with (2). We still have to show that when we discard the last digit and observe only the movement of the disks D 2 , . . . , D n , the algorithm produces the Gray code for the strings of length n − 1. This is proved by induction.
By the rules of the algorithm, whenever D 1 rests, the disk that moves is D 2 , unless D 2 is covered by D 1 . Let us now observe the motion pattern of D 1 and D 2 that results from this rule. We start with D 1 on top of D 2 , say, on peg P 0 , with D 1 about to start its sweep. Whenever D 1 pauses for one step, D 2 will make a step towards P m−1 . After D 2 reaches P m−1 , it turns out that, because m is odd, D 1 will make its next sweep from P 0 to P m−1 , resting on top of D 2 . Now, since D 2 is covered, it will be one of the other disks D 3 , D 4 , . . . that will move. Then the same routine repeats in the other direction.
If we now ignore D 1 and look only at the motions of the other disks, the following pattern emerges: D 2 makes m − 1 steps from one end to the other, and then the smallest disk that is not covered by D 2 makes its move, according to the rules. This is precisely the same procedure as Algorithm ODD, with D 2 taking the role of the "externally controlled" disk D 1 , and we have assumed by induction that this algorithm correctly produces the Gray code for the strings of length n − 1, and it does not put a larger disk on top of D 2 . Since the larger disks are moved only when D 2 lies under D 1 , it follows that a larger disk cannot be moved on top of D 1 either.
One can actually apply one induction step of the proof in the opposite direction, introducing an additional "control disk" D 0 which does not have a digit associated with it. Its only role is to alternately cover P 0 and P m−1 and exclude these pegs from the selection of the disk D k that should be moved. The algorithm becomes simpler because it does not have to treat D 1 separately from the other disks. (See Appendix A.3, where this idea is applied to the algorithm of Section 6 below).

5
Generating the m-ary Gray code with even m For even m, we generalize Algorithm HANOI, which solves the case m = 2. We use m + 1 pegs P 0 , . . . , P m , which we arrange in a cyclic clockwise order. We stipulate that disks D i with odd i move only clockwise, and disks with even i move only counterclockwise.  Figure 4 appears when the string is 211030. Disk D 1 has just made three steps and is going to rest for one step. The next step moves D 3 clockwise, since 3 is odd, and the string is changed to 211130. After that, D 1 resumes its clockwise motion, and the string changes into 211131.

Theorem 4. Algorithm EVEN generates the m-ary reflected Gray code defined in (2).
Proof. This follows along the same lines as Theorem 3. When we look at the pattern of motion of D 1 and D 2 , we observe again that D 2 makes m − 1 steps until it is covered by D 1 , see Fig. 5: After the first move of D 2 , the clockwise cyclic distance from D 1 to D 2 is 1, and with each move of D 2 , this distance increases by 1. Thus, after m − 1 moves, the distance becomes m − 1, and D 1 will land on top of D 2 with its next sweep.
Algorithms ODD and EVEN do not generate a shortest sequence of moves to the target configuration except when m = 3 or m = 2. We could not come up with some set of natural constraints under which our algorithms give a shortest solution.

The Towers of Bucharest++
In Algorithm ODD, the intermediate pegs P 1 , . . . , P m−2 will always be available for selecting the smallest disk D k to be moved. Thus, one can coalesce these pegs into one peg, keeping only the two extreme pegs separate. With three pegs, we can use the same hardware as the tower of Bucharest, but we have to record the value of the digits, since they are no longer expressed by the position. A simple method is to provide the disks with marks that indicate  Figure 5 One period of movement of the two smallest disks D1 and D2 when Algorithm EVEN generates all tuples over an alphabet of size m = 4 using m + 1 = 5 pegs.
the value as well as the direction of movement, which we have to remember anyway. Each disk cycles through 2m − 2 values, potentially augmented with direction information: It makes sense to encode this information like a dial with 2m − 2 equally spaced directions, as shown in Fig. 6a. A disk whose mark shows 0 is always on the left peg P 0 . A disk whose mark shows m − 1 is always on the right peg P 2 . Otherwise, it is on the middle peg P 1 . When we say we turn a disk, this means that we turn it clockwise to the next dial position, and if necessary, move it to the appropriate peg. Initialize: Put all disks on P 0 , and turn them to show 0.

loop:
Turn disk D 1 m − 1 times until it arrives at one of the extreme pegs P 0 or P 2 . Let D k be the smaller of the topmost disks on the two pegs not covered by D 1 .
If there is no such disk, terminate.
Turn D k once.
The digits a i can be read off from the dial positions. Correctness follows by comparison with Algorithm ODD, checking that the transition between successive states is preserved when merging the intermediate pegs into one peg.
This algorithm can now even be generalized to mixed-radix Gray codes for the n-tuples (a n , . . . , a 1 ) with 0 ≤ a i < m i , for some sequence of radixes m i ≥ 2, provided that all m i are odd.

Simulation
All our algorithms can be easily simulated in software on a digital computer. 3 A stack will do for each peg. If there are k pegs, the algorithm takes O(k) time to compute the next move and accordingly produce the next element of the Gray code sequence. If m is constant, then k = m or k = m + 1 in Algorithms ODD and EVEN, and these algorithms can pass as loopless algorithms. If k is large, Algorithm ODD can be replaced by ODD-COMPRESSED, which has only 3 pegs, independent of m.
To make a truly loopless algorithm out of Algorithm EVEN, at the expense of an increased overhead, we can use the following easy fact, which follows directly from the algorithm statement. To get a loopless implementation, the set of disks on a peg has to be maintained as a sequence of maximal intervals of successive integers, instead of storing them as a stack in the usual way. Then, whenever D 1 is at rest, the disk D k to be moved can be determined in constant time as the smallest missing disk on the peg containing D 1 .

Working ahead
While we are at the topic of Gray codes, we might as well mention another approach for loopless generation of Gray codes, which results from a generally applicable technique for converting amortized bounds into worst-case bounds. We start from the observation that was already mentioned in connection with the delta-sequence in Section 1.4: Proposition 6. Consider the enumeration of the n-tuples (b n , . . . , b 1 ) with 0 ≤ b i < m i in lexicographic order. If, between two successive tuples of the sequence, the j rightmost digits are changed, then, at the corresponding transition in the Gray code, the j-th digit from the right is changed.
We can thus find the position j that has to be changed in the Gray code by lexicographically "incrementing" n-tuples (b n , . . . , b 1 ) in a straightforward way: Algorithm DELTA. Generation of the delta-sequence for the Gray code.
Initialize: (b n , . . . , b 2 , b 1 ) := (0, 0, . . . , 0, 0) Q := an empty list loop: The delta sequence is stored in Q. It is known that the average number of loop iterations for producing an entry of Q is less than 2. We use this fact to coordinate the production of entries Q by Algorithm DELTA with their consumption in the Gray code generation, turning Q into a buffer of bounded capacity. This leads to the following loopless algorithm: Algorithm WORK-AHEAD. Generation of the Gray code. procedure STEP: visit the n-tuple (a n , . . . , a 2 , a 1 ) STEP STEP remove j from Q if j = n + 1: TERMINATE a j := a j + d j if a j = 0 or a j = m j − 1: The procedure STEP on the left side encompasses one loop iteration of Algorithm DELTA. By programmer's license, we have moved the initialization j := 1 of the loop variable to the end of the previous loop. We have also moved the termination test j = n + 1 to the side of the consumer. Accordingly, we had to extend the n-tuple b into an (n + 1)-tuple, setting m n+1 arbitrarily to 2. When Q is full, nothing is done in the procedure STEP, and the repeated call of STEP will try to insert the same value into Q. Thus, apart from the termination test, a repeated execution of STEP will faithfully carry out Algorithm DELTA.
The Gray code algorithm on the right couples two production STEPs with one consumption step, which takes out an entry j of Q and carries out the update a j := a j ± 1. Every digit a j must cycle up and down through its values in the sequence (3), and thus, we have to remember the direction d j = ±1 in which it moves, as in Algorithm ODD.
To show that the algorithm is correct, we have to ensure that the queue Q is never empty when the algorithm retrieves an element from it. This is proved below in Lemma 7.
The clean way to terminate the algorithm would be to stop inserting elements into Q as soon as j = n + 1 is produced in STEP, as in Algorithm DELTA. Instead, termination is triggered when the value j = n + 1 is removed from Q. Due to this delayed termination test, a few more iterations of STEP can be carried out, but they cause no harm.
For the binary Gray code (m i = 2 for all i = 1, . . . , n), the algorithm can be simplified. With a slightly larger buffer Q of size B := max{ n+1 2 , 2}, the test whether Q is filled to capacity can be omitted, see Lemma 9 below. The reason is that the average number of production STEPs per item approaches 2 in the limit, and accordingly, the queue automatically does not grow beyond the minimum necessary size. The directions d i are of course also superfluous in the binary case.
The idea of "working ahead" is opposite to the approach of delaying work as long as possible that underlies many "lazy" data structures and also lazy evaluation in some functional programming languages. In a similar vein, Guibas, McCreight, Plass, and Janet R. Roberts [5] have obtained worst-case bounds of O(log k) for updating a sorted linear list at distance k from the beginning. 4 Their algorithm works ahead to hedge against sudden bursts of activity. Our setting is much simpler, because we do not depend on the update requests of a "user" and we can plan everything in advance.
At a different level of complexity, the idea of working ahead occurs in an algorithm of Wettstein [9,Section 6]. This trick, credited to Emo Welzl, is used to achieve polynomial delay between successive solutions when enumerating non-crossing perfect matching of a planar point set, despite having to build up a network with exponential space in a preprocessing phase.

An alternative STEP procedure
As an alternative to the organization of Algorithm WORK-AHEAD, we can incorporate the termination test into the STEP procedure: if Q is not filled to capacity: b j := b j + 1 Q.append(j) j := 1 With this modified procedure STEP , the termination test in the main part of Algorithm WORK-AHEAD can of course be omitted. We also need not extend the arrays b and m to n + 1 elements.
The algorithm still works correctly because there are no unused entries in the queue when STEP signals termination. Let us prove this: The termination signal is sent instead of producing the value j =ρ(k) = n + 1 for k = m 0 m 1 . . . m n−1 . Generating this signal takes n + 1 iterations of STEP. In this time, no new values are added to the queue. Let us assume that the production ofρ(k) was started during iteration k 0 , and the buffer was filled with B 0 ≤ B entries at that time. The first of these entries is consumed at the end of iteration k 0 , and all B 0 entries of the buffer have been used up at the beginning of iteration k 0 + B 0 . By this time, at most 2B 0 ≤ 2B ≤ n + 1 iterations of STEP were carried out and contributed to the production of the termination signal. It follows that when STEP discovers that j = n + 1, no unused entries are in the stack, and it is safe to terminate the program.
It is important not to "speed up" the program by moving the termination test into the if -branch after the statement j := j + 1. Also, we must use exactly the prescribed buffer size for Q. Therefore, this variation is incompatible with the simplification for the binary case mentioned above.

Correctness proofs for the work-ahead algorithms
We define the ruler function ρ and the modified ruler functionρ with respect to a sequence of radixes m 1 , . . . , m n as follows: Then the k-th value that is entered into Q isρ(k), and for computing this value, Algorithm DELTA needsρ(k) iterations, and accordingly, Algorithm WORK-AHEAD needsρ(k) STEPs.

Lemma 7. In Algorithm WORK-AHEAD, the buffer Q never becomes empty.
Proof. We number the iterations of the main loop as 1, 2, . . . , m 1 m 2 . . . m n . In the last iteration, the algorithm terminates.
Let us show that the queue Q is not empty in iteration k. We distinguish two cases.
(i) Up to and including iteration k, two repetitions of STEP were always completed.
(ii) Some repetitions of STEP had no effect because the buffer Q was full.
In case (i), production of all values ρ(i) for i = 1, . . . , k requires calls to STEP. To show that these calls are completed by the time whenρ(k) is needed, we have to show In case (ii), let k 0 be the last iteration when an execution of STEP was "skipped". This means that the queue Q was filled to capacity B just before removing the value j =ρ(k 0 ), and it contained the valuesρ(k 0 ),ρ(k 0 + 1), . . . ,ρ(k 0 + B − 1). Since then, STEP was called 2(k − k 0 ) times, andρ(k) is ready when it is needed, provided that The left-hand side of this inequality is the number of necessary STEPs for computing the values up toρ(k). Computingρ(k 0 + B) takes just one more STEP, since the STEP that would have stored this value in Q was abandoned in iteration k 0 . Setting k = k 0 + B, we can express the inequality equivalently as We can write an explicit formula for S(k): Since all m i ≥ 2, we get S(k) ≤ k + k/2 + k/4 + k/8 + · · · + k/2 n < 2k, proving (4). For the other bound (5), we use the relation The following lemma shows that production of the STEPs may overrun their target by at most one. Since the algorithm has already made provisions to generateρ(N ) = n + 1 by extending the arrays b and m to size n + 1 instead of n, this one extra entry does not cause any harm.

Lemma 8.
In Algorithm WORK-AHEAD, the last entry that is added to Q isρ(N ) or ρ(N + 1).
Proof. The production ofρ(N ) = n + 1 takes n + 1 ≥ 2B STEPs. It follows that the buffer Q is empty whenρ(N ) = n + 1 is inserted, regardless of whether the production ofρ(N ) is started in the first or second STEP of an iteration.
If the production ofρ(N ) = n + 1 is completed in the second STEP of an iteration, it is thus immediately consumed, which leads to termination. Ifρ(N ) is completed in the first STEP of an iteration, the second STEP will produce the valueρ(N + 1) = 1, but then the algorithm will terminate as well.
Finally, we prove the simplification of the algorithm for the binary case. Proof. Let us assume for contradiction that the buffer becomes overfull in iteration k, 1 ≤ k ≤ 2 n . This means that, before j =ρ(k) is removed from Q, the 2k STEP operations have produced more than k − 1 + B values. But this is impossible, since, as we will show, the production of the first k 1 = k + B values would have taken STEPs. To show the last inequality, we first consider the case k 1 < 2 n . We apply the inequality x > x − 1 and obtain S(k 1 ) > 2k 1 − k 1 /2 n − n, and since k 1 /2 n < 1 and S(k 1 ) is an integer, we get Let us now see at what timeρ(k 1 ) for k 1 ≥ 2 n is entered into Q. When k 1 = 2 n , no round-off takes place in the formula for S(k 1 ), and we have S(2 n ) = 2 · 2 n − 1. This shows that the production ofρ(2 n ) is completed in the first STEP of iteration 2 n . In the second STEP of this iteration,ρ(2 n + 1) = 1 is added to Q. Thus, whenρ(2 n ) is about to be retrieved, the buffer contains 2 ≤ B elements. Then the algorithm terminates, and no more elements are produced.

Concluding Remarks
By our approach of modeling the Gray code in terms of a motion-planning game, we were able get a mixed-radix Gray code only when all radixes m i are odd. It remains to find a model that would work for different even radixes or even for radixes of mixed parity.
Another motion-planning game which is related to the binary Gray code is the Chinese rings puzzle, see Scorer, Grundy, and Smith [8], Gardner [4], or Knuth [6, pp. 285-6]. In this puzzle, there are at most two possible moves in every state, like in the towers of Bucharest, and by simulating the Chinese rings directly, one can obtain another loopless algorithm for the binary Gray code. However, this algorithm does not seem to extend to other radixes.

A.3 Algorithm ODD-COMPRESSED, Section 6
This implementation uses the idea of a "control disk" D 0 mentioned at the end of section 4. For uniformiy, we attach a direction also to the dial positions 0 and m − 1, namely the direction in with the next move will proceed (in contrast to the convention (3)

A.5 Truly loopless implementation of Algorithm EVEN, Section 7
A peg is a list of pairs (a, b) with a ≤ b, denoting a maximal subset a, a+1, . . . , b of consecutive disks (an interval). The pairs are sorted, with the smallest disks at the end (at the "top").

A.9 General mixed-radix Gray code generation according to the recursive definition of Section 3
In order to have a reference implementation for comparing the results, we give a program straight from the definition (2) of Section 3, extended to arbitrary mixed radices (m 1 , . . . , m n ). When this program is run with the data specified below, it should produce the same Gray codes as all the previous example programs combined (apart from the additional state of the pegs that is reported by these programs). The outputs coincide precisely after stripping everything after the first blank on each line. The source files of this arXiv preprint include scripts that will extract the program code from the L A T E X file of this appendix (extract-code-from-appendix.py) and compare the outputs to check the results print ("".join(str(x) for x in g))