A palindromic number
is a “symmetric” number whose value remains unchanged when its digits are written in reverse order. Examples include the numbers 2, 55, 121, 1991, and 12345678987654321.
If we take any natural number and add its mirror image (the same number written in reverse order) to it, and repeat this operation over and over, we will very often obtain a palindromic number after a finite number of repetitions.
This is a very simple process:
- Let x be any natural number and y be its mirror image
- Perform the operation x+y
- If the sum is not a palindrome, return to the second step
For example:
123 + 321 = 444
or
78 + 87 = 165, 165 + 561 = 726, 726 + 627 = 1353, 1353 + 3531 = 4884.
However, there are numbers for which it is unknown whether a palindromic number can be obtained after a finite number of repetitions of the algorithm. We call such numbers candidates for Lychrel numbers. A Lychrel number is therefore a natural number that cannot form a palindromic number by repeating the process of adding the original number to its mirror image. Some numbers form a palindrome after a few repetitions (iterations) of this process; more precisely, 80% of natural numbers up to 10,000 form a palindrome after four or fewer steps, and 90% form a palindrome within seven steps. But, for example, the number 89 forms a palindrome (8 813 200 023 188) only after 24 steps. The smallest candidate for a Lychrel number is therefore 196, followed by 295, 394, 493, 592, 689, 691, 790, 879… Different numbers thus require a different number of iterations to form a palindrome. To visualize the number of steps needed to create a palindrome from certain numbers, I created a square table and entered integers ranging from 0 to 99 into it. This table can be mathematically understood as a 10x10 matrix. Depending on how many steps were needed to create a palindrome from a number in a specific cell of the table, I colored the cell according to the assigned colors (see the spectrum to the right of the table), thus creating the resulting pattern.
I decided to continue this process, so I created subsequent tables in the number ranges 100–199, 200–299, 300–399…
An infinite number of these tables can be generated. For a preview, I sorted the first 300 tables chronologically and turned them into an animated GIF. As can be seen, the tables follow one another much like a real animation.
It is very important to note that no one has yet mathematically proven that candidates for Lychrel numbers are actually Lychrel numbers. In other words—no one knows whether, for example, the number 196 might eventually form a palindrome after many steps. In 2012, Jason Doucette, Wade VanLandingham, and Romain Dolbeau attempted to create a palindrome from this number. They tried over a trillion steps, but did not find a palindrome. However, this is not proof that a palindrome cannot be created from this number. Perhaps it will emerge only after the trillionth step. One thing is certain—if a palindrome cannot be created from this number, this brute-force method will never answer this question. Since I wrote a program in Python to generate these patterns, for practical reasons I had to set up a sort of “brake” (set to 50 steps in my program) that limits the maximum number of steps. That is why the number 50 is the maximum value in the spectrum to the right of the tables. If such a limit did not exist, the program would get stuck in an endless loop of attempts to create a palindrome from numbers from which it is likely impossible to create one. It is important to realize that these palindromes are tied to our decimal system. For example, the number 255 is definitely not a palindrome in our decimal system, but in the hexadecimal system we would write this number as FF—and that is a palindrome! These different number systems are also called bases. We can thus call the decimal system base 10, the hexadecimal system base 16, the binary system base 2, and so on. This raises the question: What would the tables look like in other bases? Since our original table for base 10 had dimensions of 10x10 cells, tables for higher bases (say, base N) will have dimensions of NxN cells. As can be seen in the animated GIF for Table 1 below, the larger the base, the “sharper” the pattern.
Only now has this structure revealed itself in all its glory, and as we can see, the structure of Table 1 is the same in all bases. But what about other tables? Is the structure of Table 2 also the same in all bases? As can be seen in the GIF below, the answer is yes.
In Table 2, we can now see signs of recursion. We shouldn’t be too surprised by this—after all, the pattern was created through a recursive process. One could say that we have just created a fractal, because Table 2 meets all the conditions for an object to be called a fractal:
- It is self-similar—meaning that if we observe the shape at any scale or resolution, we see a certain characteristic shape (motif) repeating itself;
- At first glance, it usually has a very complex shape, but it is generated by the repeated application of simple rules. In the first GIF, we already saw the first 300 tables. But that revealed only the tip of the iceberg! So what does the millionth table look like at higher bases? Or the trillionth table? And what will it look like if I scroll through the tables chronologically and create an animation from them, as was done in the first GIF? Below are images of such “higher” tables. As can be seen from them, the higher the table’s order, the more Lychrel numbers the table contains (and therefore the shapes are whiter).
With this, we have uncovered this structure to such an extent that I don’t know how to proceed further. However, I still see one possibility for experimentation here. At the beginning of this article, individual steps are listed that serve as a guide for how to arrive at (or fail to arrive at) a palindrome. For the sake of interest, I will modify these steps and define a new process:
- Let x be any natural number and y be its mirror image
- Perform the operation (x+y) mod x
- If the resulting number is not a palindrome, go back to the second step
When we create tables using these new rules, as we did before, and scroll through them, this animation is created:
The result is truly remarkable. And as is evident, there are infinitely many variations of the rules. Here are a few more examples of such modified rules, each accompanied by the corresponding visualizations:
- Let x be any natural number and y its mirror image
- Perform the operation (x+y) mod x+x
- If the resulting number is not a palindrome, go back to the second step
- Let x be any natural number
- Perform the operation (2 * x) ÷ 3
- Round the result of the second step up
- If the resulting number is not a palindrome, go back to step 2
If anyone is interested in experimenting with a program to generate these patterns, here is the source code in Python that I created:
import numpy as np
import matplotlib.pyplot as plt
import math
# convert positive whole number n in base10 to baseB
def base10_to_baseB(B, n):
# create base symbols list
abc = []
result = []
for symbol in range(B):
abc.append([symbol])
# convert number to baseB
if n==0:
result.append(abc[n])
elif math.log(n, B) < 1:
result.append(abc[n])
elif math.log(n, B) >= 1:
x = math.floor(n / B)
result.append(abc[n % B])
result.append(abc[x % B])
if math.log(n, B) >= 2:
for digits in range(2, math.ceil(math.log(n, B)+0.00001)):
x = math.floor(x / B)
result.append(abc[x % B])
result.reverse()
return result
# convert positive whole number n in baseB to base10
def baseB_to_base10(B, n):
result2=0
for digits in range(0,len(n)):
result2+=n[digits][0]*B**(len(n)-digits-1)
return result2
#ENTER START AND LAST FRAME and BASE
start_frame=1
last_frame=1+100
B=256
start_frame-=1
last_frame-=1
for images_number in range(start_frame,last_frame):
#calculate first number of matrix (not iterations of this number!)
x = images_number
x = (x) * (B ** 2)
x_static=x
#do all iterations to get whole matrix
matOLD=np.array([])
for l in range(1,(B*B)+1):
#convert number from base10 to baseB
x = base10_to_baseB(B, x)
j = 0
z = False
while z == False:
z = True
# check if number is palindrome
for k in range(len(x)-1):
if x[k] != x[(len(x) - 1) - k]:
z = False
if z == True:
break
# add number and it's reverse version
y=x
x=baseB_to_base10(B,x)
y.reverse()
y=baseB_to_base10(B, y)
x=x+y #change this to generate different images
x=base10_to_baseB(B,x)
j+=1
#max iterations limit
if j>50:
j=50
break
#create matrices
matNEW=np.array([j])
matOLD=np.concatenate((matOLD, matNEW))
#add 1 to iterate next number
x=x_static
x+=l
print("{}/{}".format(x-x_static, (B ** 2))) #report about process
#reshape matrices to base x base
matOLD=matOLD.reshape(B,B)
print(matOLD)
#plot on image
plt.subplot(211)
plt.imshow(matOLD, cmap=plt.cm.nipy_spectral)
plt.title("tabulka {} pro čísla {} až {}, base {}".format(images_number+1,x_static,x_static+(B**2)-1,B),fontsize=8)
plt.subplots_adjust(bottom=-0.9, right=0.8, top=0.9)
cax = plt.axes([0.8, 0.09, 0.02, 0.81])
plt.clim(0, 50) # set limit to colorbar maximal value
cb = plt.colorbar(cax=cax)
plt.savefig('{}_lychrel {} - {}, base {}.png'.format(images_number+1,x_static,x_static+(B**2)-1,B),dpi=200)
cb.remove() #remove colorbar to prevent "border summing"
plt.draw() #refresh figure
plt.show()
And here you can play around with an interactive demo: