So I made a modification to the algorithm which appears to make it work. So the way the algorithm seems to work is that initially all the numbers (with the exception of $1$ and $2$) are initially set to being not Ulam (which we denote with the bit $0$). For each integer $n$, every time we findsome combination of two distinct Ulam numbers that add to $n$, we flip the bit.
The first time the $n$th bit is flipped (from $0$ to $1$) marks the first time we find a combination of two distinct Ulam numbers that add to $n$. Assuming this bit is never flipped again, then we know that $n$ is indeed an Ulam number since the combination of distinct Ulam numbers that add up to $n$ is unique. The second time we flip the bit (from $1$ to $0$) that is also fine since that means we've found two combinations of distinct Ulam numbers that add to $n$, and thus $n$ is not an Ulam number (which is denoted by $0$). The issue arises if we flip the bit a third time (from 0 to 1) since that means that we've found three pairs of distinct Ulam numbers that add to $n$ and thus $n$ is not Ulam, yet the $n$th bit is $1$ which represents that it is.
If you run through the algorithm, you'll find that $14$ is the first number whose bit is flipped three times which is why it's the first discrepancy between the actual and computed sequence. After this point, the algorithm then returns incorrect results because it believes that $14$ is an Ulam number.
I've remedied this by keeping track of a list of numbers called $Not\_Ulam$. Before we flip any bits, we see if the number is in the $Not\_Ulam$ list, if it is, we ignore it. If it isn't and if we want to flip the bit from $0$ to $1$, we do so. If we want to flip the bit from $1$ to $0$, we do so and then include that number in the $Not\_Ulam$ list.
Below is my Python code that computes using the modified algorithm described. Please excuse the auxiliary functions and some of the inefficiencies in the program; I was trying to have the program stay true to the original algorithm as close as possible. (The auxiliary functions are to take care of the fact that Python has 0-indexed arrays and I didn't want to deal with constant off-by-one errors throughout).
global V
upper = 1000
V = [0]*upper
def getV(i):
return V[i-1]
def setV(i,a):
V[i-1] = a
setV(1,1)
setV(2,1)
k=2
L = []
notUlam = []
while True and k < upper/2:
i = k+1
while i <=2*k-1:
if i not in notUlam:
if getV(i) == 1 and getV(i-k) == 1:
setV(i,(getV(i)+getV(i-k))%2)
notUlam.append(i)
else:
setV(i,(getV(i)+getV(i-k))%2)
i += 1
L = [j for j in range(k+1,upper) if getV(j) == 1]
if L == []:
break
else:
k = min(L)
print([i+1 for i in range(0, len(V)) if V[i]==1])
EDIT:
I've changed the code to make it a bit more "bitwisey" by introducing a list $W$ which serves a similar function to $Not\_Ulam$. I couldn't get the bitwise operations to be "nice" though, although maybe it could be cleaned up using a bit of Boolean algebra to simplify the Boolean expression.
upper = 100
V = [0]*upper
W = [1]*upper
V[0] = 1
V[1] = 1
W[0] = 0
W[1] = 0
k=2
while True and k < upper/2:
V[k:2*k-1] = [((not a) and b and c) or (a and (not b) and (not c)) or (a and (not b) and c) for a,b,c in zip(V[k:2*k-1], V[0:k-1], W[k:2*k-1])]
W[k:2*k-1] = [(not a) and b for a,b in zip(V[0:k-1], W[k:2*k-1])]
print(V)
L = [j for j in range(k+1,upper) if V[j-1] == 1]
if L == []:
break
else:
k = min(L)
print([i+1 for i in range(0, len(V)) if V[i]==1])