
Uno dei modi più affascinanti di esplorare la bellezza intrinseca dei numeri primi è attraverso la Spirale di Ulam. Questa particolare disposizione dei numeri rivela una struttura nascosta tra i numeri primi che altrimenti potrebbe passare inosservata.

La Spirale di Ulam è una matrice quadrata che inizia con il numero 1 al centro e procede verso l’esterno in senso orario, numerando sequenzialmente ogni cella lungo la spirale. Quando si evidenziano i numeri primi all’interno di questa spirale, emergono sorprendenti modelli a forma di diagonale. Questo fenomeno, scoperto dall’inventore e matematico Stanislaw Ulam nel 1963, è ancora oggetto di studio e di dibattito tra i matematici.
La generazione di una Spirale di Ulam può essere un ottimo esercizio per imparare a manipolare gli array in Python e per visualizzare dati con Matplotlib. Ecco un esempio di come farlo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import numpy as np # Importa la libreria numpy per la manipolazione di array import matplotlib.pyplot as plt # Importa la libreria matplotlib per la creazione di grafici import matplotlib.cm as cm # Importa il modulo cm da matplotlib per la gestione dei colori def make_spiral(arr): nrows, ncols = arr.shape # Ottiene il numero di righe e colonne dell'array idx = np.arange(nrows * ncols).reshape(nrows,ncols)[:: - 1 ] # Crea un array di indici e lo inverte spiral_idx = [] # Inizializza una lista vuota per gli indici della spirale while idx.size: # Mentre ci sono ancora elementi in idx spiral_idx.append(idx[ 0 ]) # Aggiunge la prima riga di idx a spiral_idx # Rimuove la prima riga (quella che abbiamo appena aggiunto a spiral). idx = idx[ 1 :] # Ruota il resto dell'array in senso antiorario idx = idx.T[:: - 1 ] # Crea un array piatto di indici che formano una spirale nell'array. spiral_idx = np.hstack(spiral_idx) # Index into a flattened version of our target array with spiral indices. spiral = np.empty_like(arr) # Crea un nuovo array vuoto con la stessa forma di arr spiral.flat[spiral_idx] = arr.flat[:: - 1 ] # Assegna i valori di arr a spiral secondo l'ordine degli indici nella spirale return spiral # Dimensione del lato dell'array quadrato. w = 251 # Numeri primi fino a e compreso w**2. primes = np.array([n for n in range ( 2 ,w * * 2 + 1 ) if all ( (n % m) ! = 0 for m in range ( 2 , int (np.sqrt(n)) + 1 ))]) # Crea un array di valori booleani: 1 per i numeri primi, 0 per i numeri composti arr = np.zeros(w * * 2 , dtype = 'u1' ) arr[primes - 1 ] = 1 # Spiraleggia i valori in senso orario partendo dal centro arr = make_spiral(arr.reshape((w,w))) plt.matshow(arr, cmap = cm.binary) # Crea una visualizzazione della matrice usando una colormap binaria plt.axis( 'off' ) # Nasconde gli assi plt.show() # Mostra il grafico |
In questo script Python, iniziamo importando le librerie necessarie: numpy
per la manipolazione degli array, matplotlib.pyplot
per la creazione dei grafici e matplotlib.cm
per la gestione dei colori.
La funzione make_spiral
prende un array e lo trasforma in un array a spirale. Per fare questo, genera prima un array di indici idx
e poi crea una lista spiral_idx
per contenere gli indici nell’ordine in cui dovrebbero apparire nella spirale. Questa lista viene poi utilizzata per riordinare l’array originale in un ordine a spirale.
Successivamente, definiamo la dimensione w
del lato della nostra matrice quadrata e generiamo un array di numeri primi fino a w**2
. Questo array di numeri primi viene utilizzato per creare un array di zeri e uni, dove gli uni rappresentano i numeri primi.
Infine, trasformiamo il nostro array in una spirale con la funzione make_spiral
e visualizziamo il risultato con plt.matshow
, utilizzando una colormap binaria per distinguere i numeri primi (rappresentati in bianco) dai numeri non primi (rappresentati in nero). Il risultato è una bella rappresentazione della Spirale di Ulam, che evidenzia la misteriosa struttura dei numeri primi.

Nella figura, i numeri primi sembrano concentrarsi lungo certe linee diagonali. Nella spirale di Ulam di dimensione 250×250 mostrata sopra, le linee diagonali sono chiaramente visibili, confermando che il modello continua. Sono evidenti anche linee orizzontali e verticali con un’alta densità di numeri primi, sebbene meno evidenti.
1 2 3 4 5 6 7 | # Creiamo una nuova colormap personalizzata. # I colori sono specificati in formato RGBA; (0, 0, 0, 1) è nero e (0, 1, 0, 1) è verde. cmap = ListedColormap([( 0 , 0 , 0 , 1 ), ( 0 , 1 , 0 , 1 )]) plt.matshow(arr, cmap = cmap) # Usiamo la nostra nuova colormap plt.axis( 'off' ) plt.show() |
Qui, di seguito, con la piccola modifica allo script sopra indicata, si ottiene una visualizzazione più contrastata della spirale di Ulam

La Spirale di Ulam è un perfetto esempio di come la matematica possa rivelare pattern nascosti nel caos apparente. Con poche linee di codice Python, possiamo esplorare queste meravigliose strutture e forse avvicinarci un po’ di più alla comprensione del mistero dei numeri primi.