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:
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.
# 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.