Add improved versions to the MCFF package

This commit is contained in:
Tom Hodson 2022-06-16 14:00:01 +02:00
parent 99974d506b
commit a772b43fa7
2 changed files with 50 additions and 1 deletions

View File

@ -6,6 +6,15 @@ States are represented by NxM numpy arrays with values +/-1. These functions are
import numpy as np
from numba import jit
from matplotlib import pyplot as plt
def show_state(state, ax=None):
"Plot an Ising state to axis or make a new figure to plot to"
if ax is None:
f, ax = plt.subplots()
ax.matshow(state, cmap="Greys", vmin=-1, vmax=1)
ax.set(xticks=[], yticks=[])
def all_up_state(N):
@ -85,3 +94,18 @@ def energy_numpy(state):
"""
E = -np.sum(state[:-1, :] * state[1:, :]) - np.sum(state[:, :-1] * state[:, 1:])
return 2 * E / np.product(state.shape)
@jit(nopython=True, nogil=True)
def energy_difference(state, site):
"The change in energy if we flipped site of state"
# loop over the four neighbours of the site, skipping if the site is near an edge
N, M = state.shape
i, j = site
h = 0
for di, dj in [[-1, 0], [1, 0], [0, -1], [0, 1]]: # loop over N,E,S,W neighbours
if (0 <= (i + di) < N) and (
0 <= (j + dj) < M
): # ignore neighbours not in the NxN grid
h += state[i + di, j + dj]
return 4 * state[i, j] * h / (N * M)

View File

@ -2,6 +2,9 @@
"""
import numpy as np
from numba import jit
from .ising_model import energy, energy_difference
def mcmc(initial_state, steps, T, rng=np.random.default_rng()):
@ -27,7 +30,7 @@ def mcmc(initial_state, steps, T, rng=np.random.default_rng()):
assert N == M
current_state = initial_state.copy()
E = N**2 * energy(state)
E = N**2 * energy(initial_state)
for i in range(steps):
i, j = rng.integers(N, size=2)
@ -40,3 +43,25 @@ def mcmc(initial_state, steps, T, rng=np.random.default_rng()):
E = new_E
return current_state
@jit(nopython=True, nogil=True)
def mcmc_generator(
initial_state, steps, T, stepsize=1000, energy_difference=energy_difference
):
N, M = initial_state.shape
assert N == M
current_state = initial_state.copy()
for _ in range(steps):
for _ in range(stepsize):
i, j = np.random.randint(N), np.random.randint(N)
# calculate the energy change if we were to flip this pixel but don't actually do it
change_in_E = N**2 * energy_difference(current_state, (i, j))
if change_in_E < 0 or np.exp(-change_in_E / T) > np.random.random():
current_state[i, j] *= -1 # accept the change!
yield current_state.copy()
return