Incrementing Gray Codes
Jelly, 10 8 bytes
Thanks to Dennis for saving 2 bytes.
^\Ḅ‘^H$B
Input and output are lists of 0s and 1s.
Try it online!
Explanation
The inverse of the Gray code is given by A006068. Using this we don't need to generate a large number of Gray codes to look up the input. One classification of this sequence given on OEIS is this:
a(n) = n XOR [n/2] XOR [n/4] XOR [n/8] ...
Where the []
are floor brackets. Consider the example of 44
whose binary representation is 101100
. Dividing by 2 and flooring is just a right-shift, chopping off the least-significant bit. So we're trying to XOR the following numbers
1 0 1 1 0 0
1 0 1 1 0
1 0 1 1
1 0 1
1 0
1
Notice that the n
th column contains the first n
bits. Hence, this formula can be computed trivially on the binary input as the cumulative reduction of XOR over the list (which basically applies XOR to each prefix of the list and gives us a list of the results).
This gives us a simple way to invert the Gray code. Afterwards, we just increment the result and convert it back to the Gray code. For the latter step we use the following definition:
a(n) = n XOR floor(n/2)
Thankfully, Jelly seems to floor the inputs automatically when trying to XOR them. Anyway, here is the code:
^\ Cumulative reduce of XOR over the input.
Ḅ Convert binary list to integer.
‘ Increment.
^H$ XOR with half of itself.
B Convert integer to binary list.
JavaScript (ES6), 58 bytes
s=>s.replace(s.split`1`.length%2?/.$/:/.?(?=10*$)/,c=>1-c)
Directly toggles the appropriate bit. Explanation: As shown in MartinEnder♦'s answer, each bit in a decoded Gray code is the cumulative XOR, or parity, of itself and the bits to its left. We then need to increment the number which causes a carry ripple that toggles all the rightmost 1 bits to 0 and then the next 0 bit to 1. Re-encoding results in a code with just that one 0 bit position toggled. If the parity of all the 1 bits is even, then the rightmost bit is 0 and we therefore just toggle the last bit. If the parity of all the 1 bits is odd, then the rightmost bits are 1, and we need to find the last 1 bit. This is now the last of the carried bits, so the bit we need to toggle is the next bit from the right.
Perl, 27 25 bytes
Includes +1 for -p
Give input string on STDIN, e.g.
gray.pl <<< 1010
gray.pl
:
#!/usr/bin/perl -p
s%(10*\K1(\K0)*)*%1-$&%e
Perl has no cheap infinite-precision integers. So directly toggle the right bit which is the one just before where the last odd-numbered 1 would be.