从一定数量开始,每隔几次迭代,我计算该网格的熵。网格被切成25x25的小方块。然后,我使用Shannon熵来计算系统的熵。
使用i5-6500(无需GPU)在适当的时间内进行1e8 +次迭代。
function advance_multi_lattice(grid) #Find the next state of the system
rnd=rand(1:count(!iszero,grid)) #Random number to be used for a random molecule.
slots=find(!iszero,grid) #Cells containing molecules.
chosen_slot=find(!iszero,grid)[rnd] #Random cell. May contain multiple molecules.
dim=size(grid)[1] #Need this for rnd=3,4 later.
grid[chosen_slot]-=1 #Remove the molecules from the cell
rnd_arr=[1,2,3,4] #Array to random from.
while true
rnd=rand(rnd_arr) #Random number to see which side should the molecules go.
if rnd==1 #Right for example.
try #In case moving right is impossible, ie: moving right gets the molecule out. Remove 1 from rnd_arr and repeat.
grid[chosen_slot+1]+=1
break
catch
filter!(e->e!=1,rnd_arr)
end
elseif rnd==2
try #Same
grid[chosen_slot-1]+=1
break
catch
filter!(e->e!=2,rnd_arr)
end
#Repeat for the other numbers : 3 and 4...
return Grid
end
function S(P) #Entropy, if no molecules then return 0.
s=[]
for k in P
if k==0
push!(s,0)
else
push!(s,-k*log(k))
end
end
return s
end
function find_molecules(grid) #How many molecules in the array
s=0
for slot in grid
s+=slot
end
return s
end
function entropy_scale(grid,total_molecules) #Calculate the entropy of the grid.
P_array=Array{Float64}([])
for i=1:8
for j=1:8
push!(P_array,find_molecules(grid[(i-1)*25+1:i*25,(j-1)*25+1:j*25]))
end
end
P_array=P_array./total_molecules
return sum(S(P_array))
end
function entropy_evolution(grid,n) #The loop function. Changes the grid and returns the entropy as a function of steps.
t_arr=Array{Int64}([])
S_arr=Array{Float64}([])
p=Progress(Int(n)) #Progress bar, using ProgressMeter.
total_molecules=find_molecules(grid)
for k=1:1e3
grid=advance_multi_lattice(grid)
next!(p)
end
for k=1e3+1:n
grid=advance_multi_lattice(grid)
if k%500==0 #Only record entropy every 500 steps
push!(S_arr,entropy_scale(grid,totel_molecules))
end
next!(p)
end
return S_arr,grid
end
对于1e5迭代,我得到43秒。这意味着如果我想要一个有趣的结果(1e9 +),我需要很多时间,直到1hour +。除非它很小,否则更改熵计算阈值几乎不会影响性能。
答案 0 :(得分:3)
我假设您正在使用Julia 1.0(对于Julia 0.6,则需要进行一些小的更改-我在代码中已指出)。
为了提高性能,您应该保留一个分子向量-而不是一个网格(您不需要它,因为您可以让分子占据相同的位置)。
我们将分子的位置编码为元组(x,y)
。现在,您需要一个随机移动一个分子的功能。这是实现它的方法(我对边界进行了硬编码,但是您当然可以将其更改为参数):
function move_molecule((x,y)) # in Julia 0.6 it should be move_molecule(t)
# and here in Julia 0.6 you should add: x, y = t
if x == 1
if y == 1
((1,2), (2,1))[rand(1:2)]
elseif y == 200
((1,199), (2,200))[rand(1:2)]
else
((2,y), (1,y-1), (1, y+1))[rand(1:3)]
end
elseif x == 200
if y == 1
((200,2), (199,1))[rand(1:2)]
elseif y == 200
((200,199), (199,200))[rand(1:2)]
else
((200,y), (200,y-1), (200, y+1))[rand(1:3)]
end
else
if y == 1
((x,2), (x-1,1), (x+1, 1))[rand(1:3)]
elseif y == 200
((x,199), (x-1,200), (x+1, 200))[rand(1:3)]
else
((x+1,y), (x-1,y), (x, y+1), (x,y-1))[rand(1:4)]
end
end
end
现在,将给定数量的steps
一步移动随机分子的函数是:
function go_sim!(molecules, steps)
for k in 1:steps
i = rand(axes(molecules, 1)) # in Julia 0.6 it should be: i = rand(1:length(molecules))
@inbounds molecules[i] = move_molecule(molecules[i])
if k % 500 == 0
# here do entropy calculation
end
end
end
您没有提供完全可复制的示例,所以我在这里停止-但是使用此数据结构来重写用于熵计算的其余代码应该足够容易(实际上,它甚至可能更简单)。这是一个基准(性能不取决于网格的大小也不取决于分子的数量,这是比使用网格的代码重要的优势):
julia> molecules = [(rand(1:200), rand(1:200)) for i in 1:1000];
julia> @time go_sim!(molecules, 1e9)
66.212943 seconds (22.64 k allocations: 1.191 MiB)
大约一分钟,您将获得1e9
个步骤(无需进行熵计算)。
取得良好性能需要哪些关键要素:
move_molecule
函数中使用矩阵,但性能会差2倍左右)希望这会有所帮助。