Prime-aligned spiral

97 Views Asked by At

A while ago, I came up with an algorithm that I called the arbitrary spiral. It lets me align whatever integers I'd like to lay on the positive $x$-axis in a spiral. This is what I got when I had it align prime numbers: small view of prime aligned spiral

It’s more symmetric than I thought.

Further out, more patterns appear (primes are in orange, all other integers are in black): zoomed out view of spiral (image limit ≈ 1 million)

larger view (limit ≈ 18 million)

even larger view (limit ≈70 million)

(An aligned spiral with random non-primes doesn’t produce quite a symmetric image)

What I have already noticed is that numbers along the spokes at $\pm 60$ degrees (360 / (5 + 1) or $\frac{\pi}{3}$ rad) are not divisible by $5$. This appears to be true for numbers along $90$ (360/(3+1)) degrees, not divisible by $3$, as well as numbers along ±360/(7+1) = $45$ degrees not divisible by $7$ and so on. I have also learned of the interprimes along the negative x-axis.


The question is: What else can be observed in this image? Has anyone else done a spiral in this manner before?

Here's a Python script with the spiraling method:

# required modules: Pillow, primesieve (both can be installed via pip)
from PIL import Image, ImageDraw
import primesieve

from math import cos, sin, atan2, pi, degrees, sqrt
import random

size = (1500, 1500)  # image size
scale = .5 # image scaling
num = 80000000  # max value to iterate through


pnum = primesieve.count_primes(num)
arb_lst = primesieve.n_primes(pnum + 1)
arb_hgh, arb_low, arb_idx = 0, -1, 0
def arbi(n):
    '''Will spiral a number line such that
     an arbitrary set of given numbers
     are alined to the +x axis'''
    global arb_hgh, arb_low, arb_idx, arb_lst
    # while one can calculate n's position directly,
    # it's much faster to cycle through it in this manner

    while n > arb_hgh:  # cycle to next range
        arb_low = arb_hgh  # current high is now new low
        arb_hgh = arb_lst[arb_idx]  # move to next high position
        arb_idx += 1  # advance index for next time
    
    # calc. position for n on spiral
    c = (n - arb_low) / float(arb_hgh - arb_low)
    x = cos(c * 2 * pi) * sqrt(n)#n
    y = sin(c * 2 * pi) * sqrt(n)#n
    return x, -y  # image y coords are opposite of math coords


img = Image.new('RGB', size, (198, 176, 139))
drw = ImageDraw.Draw(img)

# colors (default is black)
p_col = (250, 150,  25)  # primes
s_col = ( 25, 150, 200)  # squares
c_col = (255, 255,  10)  # cubes

# lists to plot
ints = range(num)
squ = (i * i for i in ints)
cub = (i * i * i for i in ints)
prms = arb_lst[:-1]
query = []

arrangement = [(0, ints), #(s_col, squ), (c_col, cub),
               (p_col, prms)]

lim = sqrt(sum(i * i for i in size))  # image limit
for idx, (col, seq) in enumerate(arrangement, 1):
    arb_hgh, arb_low, arb_idx = 0, -1, 0  # reset spiral bounds

    tmp = col
    print('loop {}/{}'.format(idx, len(arrangement)))
    for i in seq:
        x, y = arbi(i)

        #if round(degrees(atan2(-y, x))) in (60,):# -7.5):
        #    col = (255, 0, 0); query.append(i)
        #else: col = tmp

        x *= scale; x += (size[0] / 2)
        y *= scale; y += (size[1] / 2)

        if sqrt(x * x + y * y) > lim:
            print('breakout at', i)
            break

        drw.point((x, y), fill=col)


img = img.convert("RGB")
#img.save('large.png') 
img.show()