Pagina Principale
Percolazione e polimini

Una griglia quadrata le cui celle sono selezionate casualmente con probabilità $p$ uguale per tutte è un modello di percolazione Si generano così, sconnessi tra loro, numerosi polimini di dimensioni diverse, detti cluster relativamente al fenomeno della percolazione, sacche che ad esempio potrebbero riempirsi di un fluido. La percolazione avviene quando si formano cluster-polimini che uniscono due lati opposti della griglia. La soglia di percolazione teorica per una griglia quadrata 2D, cioè al di sopra del quale avviene percolazione, è $p_c = 0.592746$, un valore fondamentale della fisica statistica.
Particolarmente utile risulta il metodo .label() della libreria scipy.ndimage, potente metodo che fa esattamente quello che trova tutti i gruppi di 1 connessi e assegna a ciascuno un'etichetta intera che corrisponde a un singolo polimino. Anche il metodo .unique() della libreria numpy che fornisce gli elementi univoci ordinati di un array con tre output opzionali oltre agli elementi univoci: gli indici dell'array di input che forniscono i valori univoci, gli indici dell'array univoco che ricostruiscono l'array di input, il numero di volte in cui ciascun valore univoco compare nell'array di input.

import matplotlib.colors as mcolors from scipy.ndimage import label def percolation_simulation(size, p, ax): # 1. GENERAZIONE DELLA GRIGLIA CASUALE # Crea una griglia di numeri casuali e la trasforma in una griglia binaria (0 o 1) grid = np.random.rand(size, size) < p # 2. IDENTIFICAZIONE DEI CLUSTER (POLIMINI) structure = np.array([ [0, 1, 0], [1, 1, 1], [0, 1, 0]]) # Connessione a 4 vicini labeled_grid, num_clusters = label(grid, structure=structure) if num_clusters == 0: ax.set_title(f'p = {p:.2f}\nNessun polimino (griglia vuota)') ax.imshow(grid, cmap='gray_r') return # 3. ANALISI DEI POLIMINI # Calcola la dimensione di ogni polimino labels, sizes = np.unique(labeled_grid, return_counts=True) cluster_sizes = sizes[1:] # Ignoriamo lo sfondo (etichetta 0) largest_polyomino_size = 0 if len(cluster_sizes) > 0: largest_polyomino_size = np.max(cluster_sizes) # Verifica se esiste un polimino che attraversa la griglia (percolazione) top_row = labeled_grid[0, :] bottom_row = labeled_grid[-1, :] spanning_labels = np.intersect1d(np.unique(top_row), np.unique(bottom_row)) spanning_labels = spanning_labels[spanning_labels != 0] # Rimuovi lo sfondo percolates = len(spanning_labels) > 0 # 4. VISUALIZZAZIONE # Crea una mappa di colori casuale per visualizzare ogni polimino cmap = mcolors.ListedColormap(np.random.rand(num_clusters + 1, 3)) cmap.colors[0] = (1, 1, 1) # Sfondo bianco ax.imshow(labeled_grid, cmap=cmap, interpolation='nearest') title = f'p = {p:.4f}\n' title += f'{num_clusters} polimini generati\n' title += f'Dimensione max: {largest_polyomino_size} celle\n' title += f'Percola: {"SÌ" if percolates else "NO"}' ax.set_title(title, fontsize=10) ax.set_xticks([]) ax.set_yticks([]) grid_size = 10 # Dimensione della griglia # Creiamo una figura con 3 subplot per confrontare i risultati fig, axes = plt.subplots(1, 3, figsize=(18, 6)) fig.suptitle(f'Connessione tra Percolazione e Polimini (Griglia {grid_size}x{grid_size})', fontsize=16) # --- SIMULAZIONE 1: SOTTO LA SOGLIA CRITICA --- p_low = 0.5 percolation_simulation(grid_size, p_low, axes[0]) # --- SIMULAZIONE 2: ALLA SOGLIA CRITICA --- p_critical = P_CRITICAL percolation_simulation(grid_size, p_critical, axes[1]) # --- SIMULAZIONE 3: SOPRA LA SOGLIA CRITICA --- p_high = 0.65 percolation_simulation(grid_size, p_high, axes[2]) plt.tight_layout(rect=[0, 0, 1, 0.95]) plt.show()

Per approfondimenti: