Skip to content

Instantly share code, notes, and snippets.

@enpedasi
Last active May 6, 2018 15:43
Show Gist options
  • Save enpedasi/72cfae35ba59cdaefc863fcc48fc4436 to your computer and use it in GitHub Desktop.
Save enpedasi/72cfae35ba59cdaefc863fcc48fc4436 to your computer and use it in GitHub Desktop.
ising model ets version
defmodule IsingEts do
@moduledoc """
Documentation for Ising.
map reduce version
Iex > Ising.main()
"""
defp get_state(ary2d, idx) do
:ets.lookup_element(ary2d, elem(idx,0)*1000+elem(idx,1) , 2)
end
def ising2d_sum_of_adjacent_spins(s, m, n, i, j) do
i_bottom = if i + 1 < m ,do: i + 1, else: 0
i_top = if i - 1 >=0, do: i - 1, else: m - 1
j_right = if j + 1 < n, do: j + 1, else: 0
j_left = if j - 1 >= 0,do: j - 1, else: n - 1
round( get_state(s, {i_bottom, j}) +
get_state(s, {i_top, j}) +
get_state(s, {i, j_right}) +
get_state(s, {i, j_left}) )
end
def ising2d_sweep(m, n, ary2d, beta, niter) do
# {{m, n}, _} = Enum.max_by(agent_ary, fn {{x, y}, _} -> x * y end )
# IO.inspect [Integer.to_string(m), n]
prob = {-2*beta*(-4), -2*beta*(-3), -2*beta*(-2), -2*beta*(-1),
1, -2*beta* 2 , -2*beta* 3 , -2*beta*4 }
iteration = round(niter/((m+1)*(n+1)))
iteration = 1000
# IO.inspect iteration
Enum.reduce(0..iteration, 0, fn _, _ ->
Enum.reduce(0..(m-1), 0,
fn i, _ ->
Enum.reduce(0..(n-1), 0,
fn j, _ ->
s1 = :ets.lookup_element(ary2d, i*1000+j ,2)
spin = ising2d_sum_of_adjacent_spins(ary2d, m, n, i , j)
# spin = 1
s_s = round(s1) * spin + 4
s_s2 = cond do
s_s < 0 -> 7
s_s > 7 -> 0
true -> s_s
end
new_s1 = case :rand.uniform <
elem(prob, s_s2 ) do
true -> - s1
_ -> s1
end
:ets.update_element(ary2d, i*1000+j, {2, new_s1})
new_s1
end)
end)
end)
end
def ising2d_sweep2(m, n, ary2d, beta, niter) do
# {{m, n}, _} = Enum.max_by(agent_ary, fn {{x, y}, _} -> x * y end )
# IO.inspect [Integer.to_string(m), n]
prob = {-2*beta*(-4), -2*beta*(-3), -2*beta*(-2), -2*beta*(-1),
1, -2*beta* 2 , -2*beta* 3 , -2*beta*4 }
iteration = round(niter/((m+1)*(n+1)))
# iteration = 1000
# IO.inspect iteration
Enum.reduce(0..iteration, 0, fn _, _ ->
Enum.reduce(0..(m-1), 0,
fn i, _ ->
Enum.reduce(0..(n-1), 0,
fn j, _ ->
s1 = :ets.lookup_element(ary2d, i*1000 + j ,2)
new_s1 = case :rand.uniform <
elem(prob, round(s1) * ising2d_sum_of_adjacent_spins(ary2d, m, n, i , j) +4) do
true -> - s1
_ -> s1
end
:ets.update_element(ary2d, {i, j}, {2, new_s1})
new_s1
end)
end)
end)
end
defp mloop(0), do: 0
defp mloop(i) when i>0 do
mloop(i-1)
end
defp ok( {:ok, pid} = _agent), do: pid
def main do
n = 100
# generate following map
#
# %{ { {0, 0} , pid }, { {0, 1} , pid }, ... }
s = :ets.new :table2d,[:set, :protected]
for x <- 0..n, y <- 0..n do
:ets.insert s, { x*1000+y , (if :rand.uniform < 0.5, do: -1, else: 1) }
end
beta = :math.log(1 + :math.sqrt(2.0)) / 2
{elapsed, result} = :timer.tc(fn -> ising2d_sweep(100, 100, s, beta, round(1.0e+09)) end)
# stop the agents
{result, elapsed/1_000_000}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment