Source code for montecarlo.ising
"""Ising Hamiltonian class for computing energies and thermodynamic averages."""
import numpy as np
import networkx as nx
from .bitstring import BitString
[docs]
class IsingHamiltonian:
"""Ising Hamiltonian defined on a graph.
H = sum_{(i,j) in E} J_ij s_i s_j + sum_i mu_i s_i
where s_i = +1 if bit i is 1 (up) and s_i = -1 if bit i is 0 (down).
"""
def __init__(self, G: nx.Graph):
self.G = G
self.N = G.number_of_nodes()
self.mu = np.zeros(self.N)
self.J = G
[docs]
def set_mu(self, mus):
"""Set the local magnetic field terms.
Parameters
----------
mus : array-like
Magnetic field values for each site
Returns
-------
self
Returns self for chaining
"""
self.mu = np.array(mus)
return self
[docs]
def energy(self, config: BitString):
"""Compute the energy of a BitString configuration.
Parameters
----------
config : BitString
Input spin configuration
Returns
-------
float
Energy of the configuration
"""
spins = 2 * config.config - 1
e = 0.0
for (i, j) in self.G.edges():
Jij = self.G.edges[i, j]['weight']
e += Jij * spins[i] * spins[j]
e += np.dot(self.mu, spins)
return e
[docs]
def compute_average_values(self, T: float):
"""Compute exact thermodynamic averages at temperature T.
Enumerates all 2^N configurations and computes Boltzmann-weighted
averages of energy, magnetization, heat capacity, and magnetic
susceptibility.
Parameters
----------
T : float
Temperature
Returns
-------
tuple of (E, M, HC, MS)
E : average energy
M : average magnetization
HC : heat capacity
MS : magnetic susceptibility
"""
beta = 1.0 / T
bs = BitString(self.N)
n_configs = 2 ** self.N
energies = np.zeros(n_configs)
magnetizations = np.zeros(n_configs)
for i in range(n_configs):
bs.set_integer_config(i)
energies[i] = self.energy(bs)
magnetizations[i] = bs.on() - bs.off()
# Shift energies for numerical stability
e_min = np.min(energies)
boltzmann = np.exp(-beta * (energies - e_min))
Z = np.sum(boltzmann)
probs = boltzmann / Z
E = np.dot(probs, energies)
E2 = np.dot(probs, energies ** 2)
M = np.dot(probs, magnetizations)
M2 = np.dot(probs, magnetizations ** 2)
HC = (E2 - E ** 2) / (T ** 2)
MS = (M2 - M ** 2) / T
return E, M, HC, MS