我正在编写一个仿真(2D Ising模型仿真)。它需要在2D数组中选取一个随机元素,并将该值乘以-1。 2D数组中的元素是自旋位点,其值为+1或-1。
我忘记添加一行代码,但实际上会更改旋转位置。添加此(一行!)代码行会大大降低程序速度。所有自旋位点均默认为-1。
我尝试编辑其他函数,这些函数执行一些基本数学运算(计算自旋位点的总能量,基本上只是乘法和加法)来偷偷将-1翻转,方法是更改一些减法来解决-1翻转,从而避免了必须访问该数组元素。仍然疯狂地放慢速度。
这是时间命令的结果,没有翻转随机数组元素。
真实0m1.425s 用户0m1.685s sys 0m1.078s
然后添加一行代码即可得到结果(如下所示) 真正的0m26.615s 用户0m27.019s sys 0m0.920s
import numpy as np
import matplotlib.pyplot as plt
# As seen in lecture:
# Ising model implementation with Metropolis algorithm
# Based on IsingViz.py from Landau, et al.
N = (2000, 2000) # number of spin sites
num_steps = 20*N[0]*N[1] # number of iterations
B = 0.05 # magnetic field
mu = .33 # g mu (not needed if B=0)
J = 1. # exchange energy
k = 1.
t = 1.
np.random.seed()
state0 = -1*np.ones(N) # Start with an arbitrary spin configuration
Evals = []
def energy(State, J, mu, B):
# Energy will call row_energy on every row in State, and on
# every row of its transpose.
total_energy = 0
for row in State:
total_energy += row_energy(row, J, mu, B)
for col in State.transpose():
total_energy += row_energy(col, J, mu, B)
return total_energy
def row_energy(S, J, mu, B):
first_set = np.concatenate([np.array([S[-1]]), S[:-1]])
FirstTerm = np.sum(-J*first_set[:-1]*first_set[1:])
SecondTerm = np.sum(-mu*S*B)
return (FirstTerm + SecondTerm)
def energy_change(S, coor):
"""Determine the change in energy if spin `i` is flipped
`(i+1) % len(S)` implements the periodic boundary condition.
"""
x = coor[0]
y = coor[1]
# Multiply spin site by all adjacent elements
S_left = S[x-1,y]
S_right = S[(x+1) % len(S),y]
S_up = S[x,(y+1) % len(S)]
S_down = S[x,y-1]
return 2*J*S[x,y]*(S_left + S_right + S_up + S_down % len(S)) + 2*B*mu*S[x,y]
def TwoDIsing(state0, num_steps, J, mu, B, kT):
ES = energy(state0, J, mu, B)
energy_values = []
energy_values.append(ES)
# Contains a copy of the state configuration so we don't have to store
# 2**N**2 * # of time step elements
state_configs = np.array([state0, state0])
deltas = [] # A lighter way of keeping track of how the state changes.
rands = np.random.randint(2000, size=(num_steps,2))
count = 1
for x, y in rands:
#test_state = state_configs[-1]
# Trial step: flip spin at one random site
#test_state[x,y] *= -1.
state_configs[1][x][y] *= -1
ET = ES + energy_change(state_configs[-1], (x,y))
if np.exp((ES-ET)/(kT)) > np.random.random():
#state_configs[-1] = test_state # replace the state, or
ES = ET
deltas.append((x,y))
else:
# advance the previous state forward
state_configs[-1]=state_configs[-2]
deltas.append(())
energy_values.append(ES)
count += 1
if count % 1000 == 0: print((count / num_steps)*100," %.....................")
return state_configs, energy_values, deltas
答案 0 :(得分:0)
使用state_configs存储状态的两个副本时出错。不这样做的速度要快得多。阅读评论以获取详细信息
def TwoDIsing(state0, num_steps, J, mu, B, kT):
ES = energy(state0, J, mu, B)
energy_values = []
energy_values.append(ES)
# Contains a copy of the state configuration so we don't have to store
# 2**N**2 * # of time step elements
#state_configs = np.array([state0, state0])
deltas = [] # A lighter way of keeping track of how the state changes.
rands = np.random.randint(2000, size=(num_steps,2))
count = 1
for x, y in rands:
#test_state = state_configs[-1]
# Trial step: flip spin at one random site
#test_state[x,y] *= -1.
state0[x][y] *= -1
ET = ES + energy_change(state0, (x,y))
if np.exp((ES-ET)/(kT)) > np.random.random():
#state_configs[-1] = test_state # replace the state, or
ES = ET
deltas.append((x,y))
else:
# advance the previous state forward
state0[x,y] *= -1
deltas.append(())
energy_values.append(ES)
count += 1
if count % 1000 == 0: print((count / num_steps)*100," %.....................")
return state_configs, energy_values, deltas