2次元 Ising 模型
2次元 Ising 模型の分配関数などを定義に従って計算する落書きコード. 遅すぎて役に立たないですが...
Python
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
rc("text", usetex=True)
plt.rcParams["mathtext.fontset"] = "cm"
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['font.size'] = 16
def state(n, N):
'''
入力: n: 状態の名前 (0,1,...,N-1), N: 格子サイズ
出力: N*N 行列
'''
s = np.zeros((N,N))
for l in range(N*N):
if (n >> l)&1 == 0:
s[l//N, l%N] = 1
else:
s[l//N, l%N] = -1
return s
def hamiltonian(s, N):
e = 0.
for i in range(N):
for j in range(N):
e += s[i,j]*( s[i, (j+1)%N] + s[(i+1)%N, j] )
return e
Tmin, Tmax, div = 0.1, 4, 128
T = np.linspace(Tmin, Tmax, div)
def ising(N):
Z = 0. # 分配関数
S = 0. # 磁化
E = 0. # エネルギー
C = 0. # エネルギー分散 (比熱)
for n in range(2**(N*N)):
s = state(n,N)
e = hamiltonian(s,N)
p = np.exp(-e/T)
Z += p
S += np.sum(s) * p
E += e * p
C += e**2 * p
return Z, S/Z, E/Z, C/Z
fig = plt.figure()
ax = fig.add_subplot(111)
for N in [2, 4]:
Z, S, E, C = ising(N)
ax.plot(T, (C - E**2)/(N*T)**2, label="N={}".format(N))
ax.grid()
plt.show()
Rust
/// 2次元 Ising 模型の状態を表す struct.
#[derive(Debug, Clone)]
struct State {
// /// スピン状態 \pm 1 の一覧
// vec: Vec<f64>,
idx: usize,
/// 格子サイズ (vec.len = size * size)
size: usize,
}
impl State {
/// 与えられた size を持つ Ising 模型の状態の総数.
fn number(size: usize) -> usize {
2usize.pow((size*size) as u32)
}
/// 与えられた size を持つ, n 番目の状態を生成する.
fn new(n: usize, size: usize) -> Self {
// let vec = (0..(size*size))
// .map(|l|
// if (n >> l)&1 == 0 { 1. } else { -1. }
// ).collect();
// State { vec, size }
State { idx: n, size }
}
/// 与えられた状態における, 格子点 (i, j) のスピンの値.
fn spin(&self, i: usize, j: usize) -> f64 {
//self.vec[self.size * (i%self.size) + (j%self.size)]
let l = self.size * (i%self.size) + (j%self.size);
if (self.idx >> l)&1 == 0 { 1. } else { -1. }
}
/// 与えられた状態における, 模型全体でのスピンの平均値
fn mag(&self) -> f64 {
//self.vec.iter().sum::<f64>() / (self.size.pow(2) as f64)
let s = (0..self.size*self.size)
.map(|l| (self.idx >> l)&1)
.sum::<usize>();
(self.size*self.size - 2*s) as f64
}
/// 与えられた状態における, Hamiltonian の値.
fn energy(&self) -> f64 {
let mut e = 0.;
for i in 0..self.size {
for j in 0..self.size {
e -= self.spin(i,j)*( self.spin(i,j+1) + self.spin(i+1, j) );
}
}
e
}
}
fn ising(temp: &[f64], size: usize) -> (Vec<f64>, Vec<f64>, Vec<f64>) {
let mut z = vec![ 0.; temp.len() ];
let mut mag = vec![ 0.; temp.len() ];
let mut ene = vec![ 0.; temp.len() ];
let mut cov = vec![ 0.; temp.len() ];
for n in 0..State::number(size) {
let state = State::new(n as usize, size as usize);
let e = state.energy();
for idx in 0..temp.len() {
let prob = (- e / temp[idx]).exp();
z[idx] += prob;
mag[idx] += state.mag() * prob;
ene[idx] += e * prob;
cov[idx] += e*e * prob;
}
}
for idx in 0..temp.len() {
mag[idx] /= z[idx];
ene[idx] /= z[idx];
cov[idx] /= z[idx];
}
(mag, ene, cov)
}
fn main() {
let temp: Vec<f64> = (1..8).map(|i| i as f64 * 0.5).collect();
let size = 4;
let (mag, ene, cov) = ising(&temp, size);
println!("{:?}\n{:?}\n{:?}", &mag, &ene, &cov);
for idx in 0..temp.len() {
print!("{} ", ( cov[idx] - ene[idx].powi(2) )/(size as f64 * temp[idx]).powi(2) )
}
}