The Yarrow Stick Algorithm

by Nancy A. Killia, Thousand Leaf College

(Originally published in Fall 1997 issue of JOAC.)

Abstract: The historical data is examined in order to create a rigorous program describing the famous Yarrow Stick Algorithm.

It is generally recognized that the "yarrow stick method" is one of the true cornerstones of Chinese oracular sciences. Few ideas or methods, even the theory of yin and yang itself, comes close to holding such a central and revered position. It apparently has existed unchanged for several millennia and has served as the primary means of accessing numerous oracles, not just the Q-Ching. Yet surprisingly, there seems to be no contemporary text describing the technique fully, unlike the occasional instructional texts (albeit sketchy) for calculating hexagrams that are sometimes found. Based on more modern accounts of the method and some student notes unearthed at the Oracle Temple site, we have tried to make a precise outline of the yarrow stick algorithm.

The mechanics of the yarrow stick method are complicated and seemingly arbitrary. It is still not certain why the old sages would go to such lengths to consult their oracles. Even more mystifying, what was their mathematical justification for constructing so convoluted an algorithm? It must have been equally confusing for the young programmer at the temple. Despite constant practice, many an initiate failed at "Yarrow Stick 101" the first year or two. The subtleties of the technique simply eluded those without the proper discipline. Because of this confusion, the sages decided to lay down the algorithm in a more formal form, akin to our modern programming languages, as a teaching aid to the young students. These rudimentary programs came in handy later on as the Oracle Temple gradually shifted from throwing the yarrow sticks manually to their more mechanized computing devices. Every computer needs a precise program. It won't operate on tradition.

This program is just as useful today as it was then, especially for modern students of archeocomputing, as well as the serious layperson who wishes to consult the Q-Ching in the traditional manner.


The Yarrow Stick Method in Outline

Because of the many layers of poetic meaning in each Chinese ideogram, their native language is excellent for writing oracular texts, but quite deficient for communicating computer algorithms exactly. Each instruction in the program is open to various interpretations, which makes it impossible to know exactly which operations are intended. The problem is especially severe when consulting the oracle, since no practitioner would want to be accused of misrepresenting the will of heaven because they couldn't handle yarrow sticks correctly. This deficiency of natural language led to the development of artificial computer languages that were free of multi-valent meanings. This not only made it easier to program their computers to emulate the traditional methods, but it made the teaching of students less cumbersome.

The traditional yarrow stick algorithm is basically a three level process. (We will omit from further discusion certain non-mathematical steps in the basic ritual, such as the burning of incense or prostrations in various directions. While helping one attune to the oracle more deeply, they contribute little to the task of building a hexagram.) The aim of this algorithm is to produce a hexagram in answer to a querent's question, which was then interpreted via some oracular text such as the Q-Ching. At the highest level, the program states how to create the hexagram by generating the six individual lines in order from bottom to top. At the next level is a subroutine that tells how to produce a single emblematic line through the creation of three "changes" or one bit decisions. At the lowest level is the description of how to manipulate the yarrow sticks to produce the individual changes.

The high level part of the program is very straightforward. A series of six emblematic lines is generated in order. These lines are stacked vertically, starting with line 1 at the bottom and ending with line 6 on top, forming the complete hexagram.

Each emblematic line is the result of combining three changes. A change is a one bit choice, a yes-no decision. Traditionally, a change was represented as either yin (which had the numerical equivalent of 2) or yang (equals 3). In most descriptions of the algorithm, the numerical values of these three changes were added together, giving a sum between 6 and 9. Alternatively, the three changes could be arranged into a trigram, which were also associated with the numbers 6 to 9. Either way, standard data compression techniques would yield one of the four emblematic lines: moving yin, static yang, static yin or moving yang. The appropriate line would then be drawn in the hexagram being created. (For a fuller discusion of these operations, see McFnordland [1995].)

All that's left is to relate these changes to the manipulation of the sticks.


Manipulating the Yarrow Sticks

At this point, the crisp mathematical model becomes rather murky. Essentially the sages were trying to design a method for allowing the will of heaven to be expressed through a random and meaningless manipulation. It requires some kind of operation that is beyond the control of the conscious mind of the practitioner, since that would subvert the "randomness" of the procedure. The sages chose to achieve randomness through large numbers.

The traditional Q-Ching bundle contains exactly 50 yarrow sticks. For reasons never explained, one stick is taken from the bundle and set aside at the beginning of the ritual, never to be used. So effectively, the bundle starts with 49 sticks. The following procedure is carried out three times on this bundle to generate the three changes.

First, the bundle is randomly split into two piles, which are placed side by side in front of the practitioner. One stick is removed from the right hand pile and placed between the fourth and fifth fingers of the left hand. Next, the left hand pile is subjected to an operation called "counting by fours". In this process, sticks are removed from the pile four at a time until there are only four or fewer sticks remaining, which are then placed between the third and fourth fingers of the left hand. The sticks that were counted out remain in the left hand pile. Finally, the right hand pile is also counted down by fours; the remaining sticks (four or fewer) are placed between fingers two and three of the left hand. All the sticks in the left hand are set aside for the moment until we compute the value of the first change, while the two piles are recombined to make a bundle, again.

This process is repeated on the new bundle. The sticks in the left hand are again set aside for the computation of the second change. The piles are recombined into a bundle and the process is repeated a third time for the third change.

The results are analyzed in the following manner. The number of sticks set aside for the first change will be either 5 or 9; for the second and third changes, the numbers will be either 4 or 8. A 4 or 5 value indicates a yang change with a value of 3, while an 8 or 9 pile is considered yin with a value of 2.

Having created the three changes for one emblematic line, the 49 sticks are recombined into a bundle and the next line calculated.


Problems with the Algorithm

While this description may seem clear enough, in practice there are a number of subtle problems that were frequently encountered. The removal of these problems was one of the major motivations for formalizing the algorithm. Several of these issues arose because the sages didn't know how to handle zeros.

Depletion of the Bundle

One of the potential problems is called "depletion of the bundle". Since some sticks are siphoned off to form a change at each step, the bundle grows smaller as the program progresses. The original bundle of 49 sticks is only 40 or 44 sticks as you start determining the second change. At the start of the third change, the bundle is down to 32, 36 or 40 sticks. In the worst case (a moving yin line), only 24 sticks remain at the end of the procedure. Since the algorithm depends on large numbers to maintain randomness, decreasing the size of the bundle is a serious concern. Below a certain threshold, the conscious mind is able to intuit the size of a pile by look or feel, seriously compromising the lack of conscious intervention necessary to insure randomness. Bundle depletion also prevented the algorithm from being expanded to generate more than three changes at a time. Even if loss of randomness weren't a problem, a mere 7 changes could conceivably totally exhaust the bundle before the algorithm completed. In the case of a computer, the program would literally crash (which was always considered an extremely inauspicious omen). Either way, the utility of the bundle as a random number generator was seriously limited by the size of the bundle. Suggestions to expand the bundle to at least 100 sticks were generally dismissed as tinkering with tradition, however.

Counting by Fours

In modern computer languages, we have a similar operation to counting by fours. Called the "integer remainder" or "modulo" operation (represented by the "%" symbol), it calculates the remainder when an integer division is computed. When dividing by 4, the remainder is always 0, 1, 2 or 3. However, the sages did not have any concept of zero, so they always used a remainder of 1, 2, 3 or 4 instead. (This operation is termed an "upper remainder function" in the literature.) When a pile is a multiple of 4, the remainder was always 4, not zero. Thus, to prevent "zero sticks" from being placed in the left hand, they chose instead to diminish the pile instead. Many of the bundle depletion problems could have been minimized if only they had used the modern modulo function.

The Empty Pile Paradox

Just as the sages could not imagine zero as a number, they couldn't comprehend the concept of an empty pile of sticks. A pile of sticks couldn't possibly have no sticks in it, so an empty pile was literally a "no-thing" for them.

There are many teaching stories in the oral tradition of students practicing their yarrow sticks. Occasionally a bright student would break the rules and "divide the bundle" into one big pile containing the entire bundle and one pile containing nothing. If the division is truly random, the creation of empty piles should happen every now and then. Usually, the teacher would get very angry and yell at the student to get serious, quit playing around and divide the bundle, not realizing a division had in fact been made. Some teachers took a more direct Zen approach: they would pick up the "undivided" bundle and hit the student over the head with it. It's even said that Lao Tse Kaud and some of the other high masters would go one step further. LTK would generally hit the student on the head with the empty pile instead. Students that "got the message" passed the initiation, while the ones that simply ducked the master's empty fist would fail. Needless to say, empty piles were frowned upon.

A sneaky form of the Empty Pile Paradox occurs if the bundle is divided so the right hand pile contains only one stick. Since one stick is removed and placed in the left hand, an empty pile is produced, causing the counting by fours step to fail (because there is "nothing" to count).

Random Division

The instruction "divide the bundle into two piles randomly" is probably the slipperiest part of the entire yarrow stick algorithm. As we've seen, empty piles were not allowed. But small piles were also discouraged, since a small number of sticks reduces the "randomness" of the operation.

As the theory of probability in mathematics demonstrates, not to mention the whole field of random number generators in computer science, the idea of "randomness" is difficult to capture. This part of the algorithm always reminds me of a cartoon of two mathematicians discussing a proof at the blackboard. On the middle board is the remark "and then a miracle happens...", to which one of the professors comments, "Now about that step there..."

The random division of the bundle is the crucial step in the algorithm, the only "miraculous step" that allows the will of heaven to intrude in an otherwise deterministic procedure. Yet nowhere is it spelled out what "random division" means. Somehow, the student was supposed to pick up this skill by osmosis. Avoiding small or empty piles was just the start. In general, beginning students divide the bundle into two piles of roughly equal size, usually a ratio of 2:1 or less. While it minimizes the danger of subliminal counting of the piles (which would skew the oracle's answers), such a method hardly counts as "random" by modern standards. Clearly, this part of the algorithm needs clarification, especially when the procedure is transfered to a computer.

The 50th Stick

One of the most nonsensical parts of the algorithm is that unused 50th stick. Why include a piece of equipment in the standard package that is totally superfluous? Perhaps it was to provide a "spare" in case one of the sticks was lost or broken, but the common presence of yarrow as a garden weed weakens that argument considerably. Plus, any self respecting oracle user would be unlikely to use an untraditional 49 stick bundle. This may always be a mystery without a solution.

Some revisionists have suggested a change in the algorithm to set aside two sticks initially and start with only 48. This would have the advantage of making the beginning state of all three changes a multiple of four sticks. Each manipulation of the sticks would thus always produce a result of 4 or 8 sticks in the left hand. In the traditional way, the first change is different from the other two, producing 5 or 9 sticks. While this would "rationalize" the algorithm some, removing a special case from the program, it has the unintended effect of altering the probabilities for various lines in the hexagram. Such "wreckless tinkering" with the oracle is considered unwise by most people who have considered the matter.


The Yarrow Stick Program

In order to remove these kinds of ambiguities and to ensure the ritual was transmitted faithfully, the Oracle Temple sages created some rudimentary programming languages and the machines to go with them. In this way, the basic ritual would not be subject to interpretation when misunderstandings arose.

While it is still not certain what the details of this programming language were, we can be fairly certain that it didn't resemble our modern high level languages. In fact, it probably more closely resembled our machine or assembly language, a primitive form of encoding that has few practitioners anymore. Nonetheless, it managed to keep the ritual alive. The following piece of code, while not a direct translation of the original program, certainly presents the important details of the algorithm for modern readers.


A Modern Implementation of the Yarrow Stick Algorithm

The following code is in the modern language JAVA, which is currently gaining popularity on the Internet. While it is not a complete program (and certain parts would not even compile correctly), it does describe the yarrow stick algorithm in accurate detail.

What is omitted are the details of the user interface and the graphics, for a number of reasons. First, such tedious details contribute nothing to our understanding of the algorithm. Also, these kinds of details are definitely "implementation specific" and depend on the particular platform being used. The details of drawing a hexagram on a computer monitor have litte to do with drawing a hexagram on parchment with a quill. While I have attempted to hint at how these graphics elements would be drawn, the details have been glossed over. Also, the calling of the main method or procedure called Hexagram.oracle() is assumed, without using pulldown menus or other GUI techniques. The old oracular computers obviously would have had very different means of calling this procedure.

Similarly, certain procedures of the original ritual, such as burnIncense() and prostrateBody() have been deleted, as they contribute little to our understanding of how to draw hexagrams.

A generic random generator function, "rnd()", is used to create a random floating point number between 0.0 and 1.0. The actual implementation specific version of this function should be substituted in a "real" version of the program.

There are three "classes" in this program. "Hexagram" describes the basic algorithm for creating a hexagram from the yarrow stick bundle. The main procedure here is called "oracle()", which in turn calls "createHexagram()" and "getChange()". As mentioned, the actual graphics routines to draw the hexagram have not been fleshed out. The class called "Heap" captures the idea of a bundle of sticks and the various manipulations applied to these bundles. The entire program essentially consists of creating, manipulating and destroying Heaps of sticks. The last class, "Emblematic Line", captures the notion of the lines used in a hexagram. Obviously, in a full fledged implementation, this class would be more robust than our purposes require.

As always, any text after the symbols "//" or "/*" are simply comments to explain tricky parts of the program or to enlighten the reader. They contribute nothing to the actual program.

/**
* Hexagram describes the yarrow stick technique for accessing the Q-Ching.
*
*/

// ********************************************************
class Hexagram extends Frame
{
  Heap bundle, aside, notused;
  EmblematicLine[] embline = new EmblematicLine[7]; // [0] not used

// constructors
  public Hexagram()
  {
    // implementation specific setup (graphics, user interface, etc.)

    // main algorithm
    bundle = new Heap(50);
    aside = new Heap(); 
    notused = new Heap();
  }

// methods
  void oracle() // main routine to call via the user interface
  {
    notused = bundle.remove(1); // use only 49 sticks
    createHexagram();
    repaint(); // trigger the graphics routine to draw the hexagram
    bundle = new Heap(bundle, notused); // put all 50 sticks away
  }

  void createHexagram()
  {
    int i, chg1, chg2, chg3;
    for (i = 1; i <= 6; i++)
    {
      chg1 = getChange();
      chg2 = getChange();
      chg3 = getChange();
      embline[i] = new EmblematicLine(chg1 + chg2 + chg3);
      bundle = new Heap(bundle, aside); // = L + R + aside, 49 sticks
    }
  }

  int getChange();
  {
    int val;
    Heap L, R, h, L45, L34, L23;
    // split the bundle into two piles, left and right
    bundle.split(); L = bundle.getLeft(); R = bundle.getRight();
    // start counting the piles and put the sticks between the fingers of left hand.
    // the total number of these sticks determines the value of the change.
    L45 = R.remove(1);   
    L34 = L.countby4();
    L23 = R.countby4();
    h = new Heap(L45, L34, L23);
    switch (h.numSticks)
    {
      case 8: case 9: { val = 2; break; }
      case 4: case 5: { val = 3; break; }
      default: val = 0; // should not happen
    }
    layAside(h); // the sticks between fingers are laid aside
    bundle = new Heap(L, R); // recombine the remaining left and right piles
    return val;
  }

  void layAside(Heap h)
  {
    aside.addSticks(h);
  }

  public void paint(Graphics g)
  { drawHexagram(g); }

  void drawHexagram(Graphics g) // implementation specific
  {
    // erase(); 
    int i;
    for (i = 1; i <= 6; i++)
    {
      // draw embline[i] at pos i
    }
  }

} // eoc -- Hexagram
// ********************************************************
class Heap
{
  int numSticks = 0;
  int left = 0, right = 0;

// constructors
  public Heap()
  { }

  public Heap(int n)
  { numSticks = n; }

  public Heap(Heap L, Heap R)
  {
    numSticks = L.numSticks + R.numSticks;
    L.empty(); R.empty();
  }

  public Heap(Heap h1, Heap h2, Heap h3)
  {
    numSticks = h1.numSticks + h2.numSticks + h3.numSticks;
    h1.empty(); h2.empty(); h3.empty();
  }

// methods
  void addSticks(Heap h)
  {
    numSticks += h.numSticks; h.empty();
  }

  Heap remove(int n)
  {
    // if ( (n < 0) | (n > numSticks)) { error(); return; }
    numSticks -= n;
    return new Heap(n);
  }

  Heap countby4()
  {
    int i = (numSticks -1) % 4 +1;
    numSticks -= i;
    return new Heap(i);
  } 

  void split() // split this Heap into two sub-Heaps randomly
  {
    // this method assumes rnd() is a random number generator over [0.0, 1.0].
    // the peculiar form of the next calculation for i is to avoid "empty pile" problems.
    int i = 1 + (int)( (numSticks - 2) * rnd());
    left = i; right = numsticks - i;
    numSticks = 0;
  }

  Heap getLeft()
  { return new Heap(left); }

  Heap getRight()
  { return new Heap(right); }

  void empty()
  { numSticks = 0; }

} // eoc -- Heap

// ********************************************************
class EmblematicLine
{
  // static vals
  static String dirname = "??"; // implementation specific

  // instance vals
  int val;

// constructors
  public EmblematicLine(int n)
  {
    val = n;
  }

// methods
  String getFilename() // implementation specific
  {
    switch (val)
    {
      case 6: return dirname + "line6.gif";
      case 7: return dirname + "line7.gif";
      case 8: return dirname + "line8.gif";
      case 9: return dirname + "line9.gif";
      default: return "";
    }
  }

} // eoc -- EmblematicLine

// ********************************************************