Incrementing Gray Codes

36

4

Introduction

A Gray Code is an alternative to binary representation in which a number is incremented by toggling only one bit, rather than a variable amount of bits. Here are some gray codes along with their decimal and binary equivalents:

 decimal | binary | gray
-------------------------
       0 |      0 |    0
-------------------------
       1 |      1 |    1
-------------------------
       2 |     10 |   11
-------------------------
       3 |     11 |   10
-------------------------
       4 |    100 |  110
-------------------------
       5 |    101 |  111
-------------------------
       6 |    110 |  101
-------------------------
       7 |    111 |  100
-------------------------
       8 |   1000 | 1100
-------------------------
       9 |   1001 | 1101
-------------------------
      10 |   1010 | 1111
-------------------------
      11 |   1011 | 1110
-------------------------
      12 |   1100 | 1010
-------------------------
      13 |   1101 | 1011
-------------------------
      14 |   1110 | 1001
-------------------------
      15 |   1111 | 1000

Cyclic Bit Pattern of a Gray Code

Sometimes called "reflected binary", the property of changing only one bit at a time is easily achieved with cyclic bit patterns for each column starting from the least significant bit:

bit 0: 0110011001100110011001100110011001100110011001100110011001100110
bit 1: 0011110000111100001111000011110000111100001111000011110000111100
bit 2: 0000111111110000000011111111000000001111111100000000111111110000
bit 3: 0000000011111111111111110000000000000000111111111111111100000000
bit 4: 0000000000000000111111111111111111111111111111110000000000000000
bit 5: 0000000000000000000000000000000011111111111111111111111111111111

...and so on.

Objective

Given a non-padded input string of a gray code, increment the gray code by alternating a single character in the sequence or prepending a 1 (when incrementing to the next power of 2), then output the result as a non-padded gray code.

Caveats

  • Do not worry about taking 0 or an empty string as input.
  • The lowest input will be 1, and there is no upper-bound to the string length other than memory limitations imposed by the environment.
  • By non-padded string, I mean there will be no leading or trailing whitespace (other than an optional trailing newline), and no leading 0s in the input or output.

I/O formats

The following formats are accepted form for input and output, but strings are encouraged over other formats:

  • most significant "bit" first
  • non-padded character array or string of ASCII '1's and '0's
  • non-padded integer array of 1s and 0s
  • non-padded boolean array

What's not allowed:

  • least significant "bit" first
  • decimal, binary or unary integer
  • fixed-length data-structure
  • character array or string of non-printable ASCII indices 1 and 0

Tests

input -> output
1 -> 11
11 -> 10
111 -> 101
1011 -> 1001
1111 -> 1110
10111 -> 10110
101100 -> 100100
100000 -> 1100000

More tests can be added by request.

Criteria

This is , so shortest program in bytes wins! All ties will be broken by favoring earlier submissions; standard loopholes apply. The best submitted answer will be accepted October 9th, 2016, and updated whenever better answers are given.

Patrick Roberts

Posted 2016-10-02T21:05:35.577

Reputation: 2 475

1Related. Related. – Martin Ender – 2016-10-02T21:08:18.647

Can we take input as a number? – xnor – 2016-10-02T21:12:01.200

1

Less obviously, also related.

– Martin Ender – 2016-10-02T21:12:50.607

@xnor No. That sort of defeats the purpose of the string manipulation challenge. – Patrick Roberts – 2016-10-02T21:12:59.233

According to your table (and wikipedia) 1011 is incremented to 1001 and not 1010 as in the testcases. – Laikoni – 2016-10-02T22:36:38.013

@Laikoni good catch, thank you. Corrected. – Patrick Roberts – 2016-10-02T22:42:29.347

Can we take an array of zeros and ones instead of a string? – Luis Mendo – 2016-10-02T22:52:19.090

@LuisMendo, do you mean a boolean array or an integer array of 1s and 0s? Both are acceptable, I'm just curious which one you meant. But please make your program or function have a reasonable output: either equivalent as input, or as specified in the question. – Patrick Roberts – 2016-10-02T22:53:47.380

@PatrickRoberts I meant integer array. Thanks for the reply! – Luis Mendo – 2016-10-02T22:54:17.587

1Can I take both input and output reversed, e.g. 0011 for 8 – Ton Hospel – 2016-10-03T06:32:45.787

Can I take input and output as a string of unprintable ASCII codes 0 and 1 – Ton Hospel – 2016-10-03T06:48:53.640

@TonHospel I'm gonna say no, just because that makes it harder to verify code. You might as well use an integer array if you're going to do that. – Patrick Roberts – 2016-10-03T12:17:18.663

Is there a maximum length of input that our program will have to process? I too am curious about whether we can take input reversed. – 0 ' – 2016-10-03T18:29:37.680

@1000000000 To demonstrate that the program can process an arbitrarily long string, make sure it works for a string input at least 65 bytes long. Also, no. It must be most significant bit first. – Patrick Roberts – 2016-10-03T18:37:34.150

@PatrickRoberts and it's okay if it behaves unexpectedly for a string longer than 65 bytes? – 0 ' – 2016-10-03T18:39:34.590

@1000000000 No. As I stated in the challenge, the only limitation should be the amount of memory your program is able to allocate to process the string. If your run exits with an out of memory error in the case the string is too long, that is the only acceptable "unexpected behavior." In short, don't hardcode an upper-bound. – Patrick Roberts – 2016-10-03T18:41:54.870

1@TonHospel sorry I didn't see your question about reversed I/O. As I told 1000000000 my answer is no. – Patrick Roberts – 2016-10-03T18:45:41.167

@TonHospel I just thought of something though. If your input is stack-based and each bit (or character) is pushed separately, you'd have access to the least significant bit first, and it would satisfy my requirement of most significant bit first. Assuming FILO stack. – Patrick Roberts – 2016-10-04T16:41:57.347

Answers

13

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 nth 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.

Martin Ender

Posted 2016-10-02T21:05:35.577

Reputation: 184 808

You don't need the Ḟ$; bitwise operators cast to int. – Dennis – 2016-10-03T00:25:14.110

@Dennis Thanks, I discovered that while writing up. :) – Martin Ender – 2016-10-03T00:25:56.743

@MartinEnder Is the integer it converts to internally a big integer? – Patrick Roberts – 2016-10-03T01:54:21.987

@PatrickRoberts yes, if necessary - it's Python under the hood. – Jonathan Allan – 2016-10-03T02:20:11.263

Nice analysis and explanation. – Wayne Conrad – 2016-10-04T13:55:51.627

Congratulations on the shortest answer – Patrick Roberts – 2016-10-09T05:15:11.050

8

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.

Neil

Posted 2016-10-02T21:05:35.577

Reputation: 95 035

Very nice method. Is the first ? in /.?(?=10*$)/ really required? Oh, nevermind. Yes it is. :-) – Arnauld – 2016-10-03T05:57:18.613

8

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.

Ton Hospel

Posted 2016-10-02T21:05:35.577

Reputation: 14 114

1Wow, \G really makes things easy for you! – Neil – 2016-10-03T07:41:23.080

1On the other hand, \K makes things even easier for you. – Neil – 2016-10-03T09:06:05.887

Haaaaa... Now I want to see the \G implementation as well. – Magic Octopus Urn – 2016-10-04T01:02:01.623

2

@carusocomputing You can see older versions of a submission by clicking on the edited link

– Ton Hospel – 2016-10-04T06:58:22.857

6

Haskell, 118 115 108 bytes

g 0=[""]
g n|a<-g$n-1=map('0':)a++map('1':)(reverse a)
d=dropWhile
f s=d(=='0')$(d(/='0':s)$g$1+length s)!!1

Try it on Ideone.
Naive approach: g generates the set of all gray codes with length n (with 0-padding), f calls g with length(input)+1, removes all elements until 0<inputstring> is found and returns the next element (truncating a possibly leading 0).

Laikoni

Posted 2016-10-02T21:05:35.577

Reputation: 23 676

1Good first answer! I hope we can get some more efficient ones soon. – Patrick Roberts – 2016-10-02T23:01:56.020

5

MATL, 18 bytes

ZBtE:t2/kZ~tb=fQ)B

Try it online! Or verify all test cases.

Explanation

Let a(n) denote the sequence of integers corresponding to Gray codes (OEIS A003188). The program uses the characterization a(n) = n XOR floor(n/2), where XOR is bit-wise.

Essentially, the code converts the input to an integer a0, finds that integer in the sequence, and then selects the next term. This requires generating a sufficiently large number of terms of the sequence a(n). It turns out that 2·a0 is sufficiently large. This stems from the fact that the Gray code a(n) never has more binary digits than n.

Let's take input '101' as an example.

ZB      % Input string implicitly. Convert from binary string to integer
        %   STACK: 5
t       % Duplicate
        %   STACK: 5, 5
E       % Multiply by 2. This is the number of terms we'll generate from the sequence
        %   STACK: 5, 10
:       % Range
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10]
t       % Duplicate
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10], [1 2 3 4 5 6 7 8 9 10]
2/k     % Divide by 2 and round down, element-wise
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10], [0 1 1 2 2 3 3 4 4 5]
Z~      % Bit-wise XOR, element-wise
        %   STACK: 5, [1 3 2 6 7 5 4 12 13 15]
t       % Duplicate
        %   STACK: 5, [1 3 2 6 7 5 4 12 13 15], [1 3 2 6 7 5 4 12 13 15]
b       % Bubble up
        %   STACK: [1 3 2 6 7 5 4 12 13 15], [1 3 2 6 7 5 4 12 13 15], 5
=       % Equality test, element-wise
        %   STACK: [1 3 2 6 7 5 4 12 13 15], [0 0 0 0 0 1 0 0 0 0]
f       % Find: yield (1-based) index of nonzero values (here there's only one)
        %   STACK: [1 3 2 6 7 5 4 12 13 15], 6
Q       % Increase by 1
        %   STACK: [1 3 2 6 7 5 4 12 13 15], 7
)       % Apply as index
        %   STACK: 4
B       % Convert to binary array
        %   STACK: [1 0 0]
        % Implicitly display

Luis Mendo

Posted 2016-10-02T21:05:35.577

Reputation: 87 464

I notice the output is space-delimited characters... is it printing some sort of array? – Patrick Roberts – 2016-10-02T23:06:51.037

@PatrickRoberts Yes, exactly. I assumed it's acceptable, is it? – Luis Mendo – 2016-10-02T23:07:44.133

I'll accept it as-is. I've already loosened my requirements on I/O format, so there's no point in making it more strict again. Nice job. – Patrick Roberts – 2016-10-02T23:09:01.487

5

JavaScript (ES6), 53 bytes (non-competing)

A recursive function which builds all gray codes until the input is found, then stops at the next iteration.

The highest possible input depends on the browser recursion limit (about 13 bits in Firefox and 15 bits in Chrome).

f=(s,n=1)=>(b=(n^n/2).toString(2),s)?f(b!=s&&s,n+1):b

console.log(f("1"));      // -> 11
console.log(f("11"));     // -> 10
console.log(f("111"));    // -> 101
console.log(f("1011"));   // -> 1001
console.log(f("1111"));   // -> 1110
console.log(f("10111"));  // -> 10110
console.log(f("101100")); // -> 100100
console.log(f("100000")); // -> 1100000

Arnauld

Posted 2016-10-02T21:05:35.577

Reputation: 111 334

I'm afraid this submission doesn't qualify, since the method does not work for unbounded string lengths. Please change to non-competitive if you want to keep this answer on here. – Patrick Roberts – 2016-10-03T12:37:10.120

@PatrickRoberts - Sure. That makes sense. – Arnauld – 2016-10-03T12:53:38.583

@PatrickRoberts Really? How does a recursion limit not fall under "memory limitations imposed by the environment."? – Sanchises – 2016-10-09T14:53:21.810

@sanchises I was referring to heap memory, but more to the point, this program recurses for every possible gray code up to the one being tested, which is extremely inefficient. Technically this could be submitted as "Node.js 6.5" and have --harmony added for penalty bytes in order to have access to tail-call recursion optimization, which appears to be possible here. – Patrick Roberts – 2016-10-09T15:58:49.610

@sanchises Looking over my reply, that was a poor argument. The main issue is that the limitation isn't imposed by the environment, it's imposed by the algorithm. There are other answers which recurse for every bit rather than for every incremental value, and I find those to be more acceptable since it works for a much wider range of values. – Patrick Roberts – 2016-10-09T16:47:30.777

@PatrickRoberts I disagree. The algorithm itself does not impose a fundamental limit. It's inefficient, yes, but I feel that efficiency is not a requirement for [tag:code-golf]. I don't think some thing that is less or "more acceptable" is a good criterion for disqualifying an entire answer. Personally, I would let this one go. Judging by your challenge description, it seems you fell for this trap - it seems that you wanted people to work on 'string level' rather than 'number' level.

– Sanchises – 2016-10-09T20:35:28.340

@sanchises That's why I clarified my statement. Yes I agree efficiency is not a criteria for whether or not this is an acceptable answer. The problem is that this doesn't satisfy the acceptable level of "arbitrary precision" that I specified in the criteria. The answerer agreed with my claim, if you don't then please take it up with meta rather than complaining about it here. – Patrick Roberts – 2016-10-09T21:50:30.977

5

CJam (19 bytes)

{_2b__(^@1b1&*)^2b}

Online demo. This is an anonymous block (function) from bit array to bit array, which the demo executes in a loop.

It works on the simple principle that if the number of set bits is even we should toggle the least significant bit, and otherwise we should toggle the bit to the left of the least significant set bit. Actually identifying that bit turns out to be much easier using bit hacks on an integer than using the list of bits.

Dissection

{         e# Declare a block:
  _2b     e#   Convert the bit array to a binary number
  __(^    e#   x ^ (x-1) gives 1s from the least significant set bit down
  @1b1&   e#   Get the parity of the number of set bits from the original array
  *       e#   Multiply: if we have an even number of set bits, we get 0;
          e#   otherwise we have 2**(lssb + 1) - 1
  )^      e#   Increment and xor by 1 or 2**(lssb + 1)
  2b      e#   Base convert back to a bit array
}

Working solely with the bit array, I think it's necessary to reverse it: working with the left-most 1 is much easier than the right-most. The best I've found so far is (24 bytes):

{W%_1b)1&1$+1#0a*1+.^W%}

Alternative approach (19 bytes)

{[{1$^}*]2b)_2/^2b}

This converts from Gray code to index, increments, and converts back to Gray code.

Peter Taylor

Posted 2016-10-02T21:05:35.577

Reputation: 41 901

2

Retina, 25 bytes

^(10*10*)*
$1:
1:
0
.?:
1

I feel sure there should be a better way of doing this...

Neil

Posted 2016-10-02T21:05:35.577

Reputation: 95 035

Do you actually need the ^ ? – Ton Hospel – 2016-10-03T09:07:40.887

@TonHospel The regex tried to match everywhere without it. (Replace mode defaults to a global replacement.) – Neil – 2016-10-03T09:13:52.333

2

05AB1E, 12 bytes

Uses CP-1252 encoding.

CÐ<^¹SOÉ*>^b

Try it online!

Explanation

Example for input 1011.

C              # convert to int (bigint if necessary)
               # STACK: 11
 Ð             # triplicate
               # STACK: 11, 11, 11
  <            # decrease by 1
               # STACK: 11, 11, 10
   ^           # XOR
               # STACK: 11, 1
    ¹          # push first input
               # STACK: 11, 1, 1011
     S         # split to list
               # STACK: 11, 1, [1,0,1,1]
      O        # sum
               # STACK: 11, 1, 3
       É       # mod 2
               # STACK: 11, 1, 1
        *      # multiply
               # STACK: 11, 1
         >     # increase by 1
               # STACK: 11, 2
          ^    # XOR
               # STACK: 9
           b   # convert to binary
               # STACK: 1001
               # implicitly print top of stack

Emigna

Posted 2016-10-02T21:05:35.577

Reputation: 50 798

2

Batch, 199 197 bytes

@echo off
set/ps=
set r=
set t=%s:0=%
if 1%t:11=%==1 goto g
:l
set b=%s:~-1%
set s=%s:~,-1%
set r=%b%%r%
if %b%==0 goto l
if 0%s%==0 set s=0
:g
set/ab=1-%s:~-1%
echo %s:~,-1%%b%%r%

Reads input from STDIN into variable s. Removes the 0s and does a parity check on the 1s and if there are an odd number it strips the rightmost 0s in a loop, stopping when it strips a 1. s therefore contains the even parity prefix and r the rest of the string. s is set to zero if it was blank so that its last digit can be toggled, and then everything is concatenated.

Neil

Posted 2016-10-02T21:05:35.577

Reputation: 95 035

2

Python 2.7, 68 characters

def f(s):i=long(s,2);print bin(i^(1,(i&-i)<<1)[s.count('1')&1])[2:]

Python 3, 68 characters

def f(s):i=int(s,2);print(bin(i^(1,(i&-i)<<1)[s.count('1')&1])[2:])

This function converts the given binary string to an integer then xor the last bit if the number of set bits in the original string is even, or its swaps the bit to the left of the rightmost set bit if the number of set bits in the original string is odd. Then it converts the result to a binary string and removes the 0b boolean prefix.

Morwenn

Posted 2016-10-02T21:05:35.577

Reputation: 121

1You can save 1 byte by removing the space after def f(s): and (assuming Python 2) another by using print instead of return. – ElPedro – 2016-10-04T10:21:41.840

@ElPedro Thanks, I also applied a condition trick and factored out the left-hand size of a xor to save a few additional characters :) – Morwenn – 2016-10-04T10:25:12.897

Just saw that. Nice answer :-) – ElPedro – 2016-10-04T10:27:03.990

Um.. checking python documentation, it looks like int() generates a 32 bit integer, although my requirement is for you to increment any length string. I'm not sure that this qualifies as a valid submission – Patrick Roberts – 2016-10-04T14:45:28.943

1@PatrickRoberts I'll check later. long instead of int might solve the problem. – Morwenn – 2016-10-04T14:46:48.177

@Morwenn It would, yes. – Patrick Roberts – 2016-10-04T14:49:03.053

2

C++, 205 bytes

#include <string>
std::string g(std::string s){int i,z;if(s=="1")return"11";for(i=z=0;i<s.length();i++)if(s[i]=='1')z++;i--;if(z%2){char c=s[i];s.erase(i);s=g(s);s+=c;}else{s[i]=s[i]==49?48:49;}return s;}

Description: Even numbers have even number of ones. Variable z counts ones; if z is even (z mod 2 = z%2 = 0 - else branch), alter the last bit; if z is odd, call this function again without the last character and calculate new value, then append the last character afterwards.

Click here to try it for the test cases.

AlexRacer

Posted 2016-10-02T21:05:35.577

Reputation: 979

Thanks for your submission. If you could provide a short description of your approach and a link to an online compilation of this as a demo, I'd really appreciate that. – Patrick Roberts – 2016-10-09T03:40:22.427

1@PatrickRoberts Added the link and the description as you requested. – AlexRacer – 2016-10-10T23:16:33.173

1

J, 38 bytes

[:#:@(22 b.<.@-:)@>:@#.[:22 b./[:#:#.\

Try it online!

This is essentially Martin's algorithm in J.

Note that 22 b. is XOR.

                                    [: #: #.\   Creates the prefixes of the input
                                                converts to a number, then converts
                                                back to binary.  Needed to get the
                                                padding on the left.

                          [: 22 b./             Reduce the rows of the resulting 
                                                matrix with XOR, giving us the 
                                                normal binary
                      @#.                       Convert to int and...
                   @>:                          Increment and...
      (22 b. <.@-:)                             XOR that with its own floored half
[: #:@                                          And turn the result back to binary

Jonah

Posted 2016-10-02T21:05:35.577

Reputation: 8 729

Nice job, dude! – Patrick Roberts – 2018-07-09T04:28:59.203

1

Actually, 20 19 13 bytes

Based on Martin Ender's Jelly answer with my own version of "cumulative reduce of XOR over the input". Golfing suggestions welcome. Try it online!

σ1♀&2@¿u;½≈^├

Ungolfing

      Implicit input a as a list, such as [1,0,1,1,0,0].
σ     Get the cumulative sums of a.
1♀&   Map x&1 (equivalent to x%2) over every member of the cumulative sum.
2@¿   Convert from binary to decimal.
u     Increment x.
;½≈   Duplicate and integer divide by 2.
^     XOR x and x//2.
├     Convert to binary to obtain our incremented Gray code.
      Implicit return as a string, such as "100100".

Sherlock9

Posted 2016-10-02T21:05:35.577

Reputation: 11 664