Gray Code Example
=================

For an educational/understanding point of view, gray codes can be
generated by a recursive algorithm that is also a straightforward proof
by induction for its main property: a sequence of binary numbers that
has only one bit different from its previous value. The recursive
approach is to get a n-bit code like ``["0", "1"]`` and just append the
reversed list with each value prefixed by ``"1"``, resulting in a new
(n+1)-bit gray code.

Let's implement that recursion using a scan instead of a function call:

.. code-block:: python

  >>> from pyscanprev import enable_scan, prepend, last

  >>> def prefixall(prefix, iterable):
  ...     return [prefix + el for el in iterable]

  >>> @enable_scan("prev")
  ... def gray_upto(n):
  ...     return [prefixall("0", prev) + prefixall("1", prev[::-1])
  ...             for unused in prepend([""], range(n))]

And that's it. Testing with a 4-bits code:

.. code-block:: python

  >>> gray_upto(4)
  [[''],
   ['0', '1'],
   ['00', '01', '11', '10'],
   ['000', '001', '011', '010', '110', '111', '101', '100'],
   ['0000',
    '0001',
    '0011',
    '0010',
    '0110',
    '0111',
    '0101',
    '0100',
    '1100',
    '1101',
    '1111',
    '1110',
    '1010',
    '1011',
    '1001',
    '1000']]

Actually, there's a more straightforward and non-recursive way to generate
such numbers, using the bit shifting and bitwise xor operators.

.. code-block:: python

  >>> def gray(n):
  ...     return [(i >> 1) ^ i for i in range(1 << n)]

With a helper to show us the binary code from integers:

.. code-block:: python

  >>> def to_binary_strings(iterable, n):
  ...     fmt = "{:0%db}" % n
  ...     return [fmt.format(value) for value in iterable]

Let's find the 5-bits gray code:

.. code-block:: python

  >>> to_binary_strings(gray(5), 5)
  ['00000',
   '00001',
   '00011',
   '00010',
   '00110',
   '00111',
   '00101',
   '00100',
   '01100',
   '01101',
   '01111',
   '01110',
   '01010',
   '01011',
   '01001',
   '01000',
   '11000',
   '11001',
   '11011',
   '11010',
   '11110',
   '11111',
   '11101',
   '11100',
   '10100',
   '10101',
   '10111',
   '10110',
   '10010',
   '10011',
   '10001',
   '10000']

Using ``last`` on the previous recursive approach, we would get that same
result when ``n > 0``. For example, with ``n = 8``:

.. code-block:: python

  >>> last(gray_upto(8)) == to_binary_strings(gray(8), 8)
  True
