I've written this code to simulate the Ising Model. The idea is a system represented as a matrix with each element having value 1 or -1. The input is an initial matrix of 1 and -1; it is then being subjected to this algorithm:
- Pick a random element of the matrix
- calculate the energy change of the system if that element is flipped (turn 1 to -1 vice versa)
- if the flipping reduces total energy (after/before < 0): do it, else: flip it with probability
$$ P = \exp(-\text{constant}*\text{energy difference}) $$ $$0 \le P \le 1$$
(I added an extra term in the code to modify its dynamics.)
Energy is calculated by observing the spin of an element with its neighbor, so I use two matrices for this calculation:
- the main matrix (the one subjected to the function),
- an adjacency matrix (representing connection between each elements from the main matrix: 1 if connected, else 0).
The idea is to multiply the row from the adjacency matrix to all elements of the main matrix.
The code works but since I have to apply the function for thousands of times and it uses two (rather large) matrices, the calculation takes a lot of time. Perhaps ideas for speed-ups (or just for writing a better code in general) and possibility to use numba which currently gives me complicated error messages.
import numpy as np
n = 64
n2 = n**2
main_matrix = 2*np.random.randint(2, size=(n, n))-1
adj_matrix = np.random.randint(2, size=(n2, n2)) # Assume random network is used
def mcmove(beta):
a = np.random.randint(0, n)
b = np.random.randint(0, n)
s = main_matrix[a, b]
energy_difference = np.sum(np.multiply(adj_matrix[a*n + b], main_matrix.reshape(1,-1)[0]))/np.sum(adj_matrix[a*n + b])
cost = 2*s*(energy_difference - s*abs(np.sum(main_matrix))/n2)
if cost < 0:
s *= -1
elif np.random.rand() < np.exp(-cost*beta):
s *= -1
main_matrix[a, b] = s
return main_matrix
# How this function is used
total_spin = []
for i in range(1000):
for i in range(n2):
mcmove(0.001*i)
total_spin.append(np.sum(main_matrix)) # sum all spins
total_spin