Other Methods for sampling Ising models#

Wolf Algorithm (cluster methods):

Near the critical point \(T_c\) where the system develops a magnetization, any single-spin-flip dynamics becomes very slow (the correlation time diverges). Wolff came up with a clever method to flip whole clusters of spins!

  1. Pick a spin at random, remember its direction \(s = \pm 1\), and flip it.

  2. For each of the four neighboring spins, if it is in the direction \(s\), flip it with probability \(p = 1 - e^{\beta 2J}\).

  3. For each of the new flipped spins, recursively flip their neighbors as in step 2

from numba import njit
import numpy as np

@njit
def run_wolf_mc(spins=np.random.choice([-1, 1], size=(20, 20)), 
            J=1, 
            T=1, 
            nsteps = 10000):
  '''Sampling 2D ising lattice with Wolff algorithm. 
  Returns:
  - S: trajectory of lattice
  - M: Magnetization'''

  N = len(spins)
  n = N**2
  S, M = [], []

  for step in range(nsteps):

    # Pick random spin
    i, j = np.random.randint(N), np.random.randint(N)

    #Initial pocket and cluster lists
    Pocket, Cluster = [(i,j)], [(i,j)]

    #Start looking for pockets of spins pointing in same direction
    while len(Pocket)>0:
        i, j = Pocket.pop(0)   
        
        # interogate neighbours of spin[i,j]
        for m, n in [((j+1)%N, j), ((i-1)%N, j), (i, (j+1)%N), (i, (j-1)%N)]:

            #If neighbouring spin is in same direction and not already in the Cluster 
            if spins[m, n] == spins[i, j] and (m, n) not in Cluster:
    
                #Accept/reject move according to Wolff criteria
                if np.random.random() < 1.0 - math.exp(- J / T):   
                    Pocket.append((m,n))
                    Cluster.append((m,n))

    #Update cluster move and save data
    for c in Cluster:
        spins[c] *= -1

    S.append(spins.copy())
    M.append(np.mean(spins))

  return S, M