こんにちは。情報発信すると反応があるのがとても良いところです。色々juliaの勉強になりましたので、せっかくなので、コードの改善と一緒にみてみます。
Juliaの情報もまだ少ないので、せっかくなのでみんなで勉強しましょう!
品岡先生に、twitterで添削いただき、さらにgithubで改善コードまで出していただきました!
https://twitter.com/HShinaoka/status/1336497601286295553?s=20
ありがとうございます!
https://gist.github.com/shinaoka/ada5a6db8d8f3fe4ff81a0a90370b6dc
関数でまとめる
富谷先生からも指摘があった通り、丸ごと関数でまとめた方が良さそうです。
function run_opt!(q, T::Float64, r::Float64, Tf::Float64, ite, rng)
N = length(q)
#温度が終了温度以上の場合、
ene = energy(q)
beta = 1/T
while T > Tf
for i=1:ite
x = rand(rng, 1:N)
q[x] *= -1
#エネルギー差を計算 (注: エネルギー差を直接計算すればさらにコストは下がる)
ene\_prop = energy(q)
dx = ene\_prop - ene
#評価if exp(dx \* beta) < rand(rng)
ene = ene\_prop
elseq\[x\] \*= -1
end
end
#温度を下げる
T \*= r
end
return T
end
q = ones(N)
rng = MersenneTwister(4649)
Tf_ = run_opt!(q, T, r, Tf, N, rng)
引用:https://gist.github.com/shinaoka/ada5a6db8d8f3fe4ff81a0a90370b6dc
乱数生成にはメルセンヌツイスターを設定しています。僕はやりがちなのですが、最初にエネルギーを求めてからの指定のビットだけ反転させて計算させれば、配列複製しなくていいですね!自分の書いたコードよりも三倍以上早くなり、メモリの使用量も劇的に減りました。
あとは、BenchmarkToolsというみんなが欲しい便利ツールが良さそうです。
using BenchmarkTools, Random
で読み込み、
In [3]:
@benchmark run(T, r, Tf, q, ite)
Out[3]:
memory estimate: 1.16 MiB
allocs estimate: 8484
BenchmarkTools.Trial:
median time: 648.125 μs (0.00% GC)
mean time: 672.268 μs (2.16% GC)
maximum time: 4.169 ms (0.00% GC)
minimum time: 630.291 μs (0.00% GC)samples: 7423
evals/sample: 1
まず、上は自分が書いたコードです。速度もかかっています。
In [5]:
rng = MersenneTwister(4649)
q = ones(N)
@benchmark run_opt!(q, T, r, Tf, N, rng)
Out[5]:
memory estimate: 16 bytes
allocs estimate: 1
BenchmarkTools.Trial:
median time: 193.958 μs (0.00% GC)
mean time: 197.269 μs (0.00% GC)
maximum time: 1.498 ms (0.00% GC)
minimum time: 190.208 μs (0.00% GC)samples: 10000
evals/sample: 1
かなりの高速化と資源の節約に成功です。アルゴリズムってすごいですね。初めてJuliaを使いましたが、かなりいい感じですので、この調子でもう少し学習してみたいと思います。
本当はこのあと量子モンテカルロを使って、横磁場イジングの量子アニーリング実装でもしようかと思いましたが、先に品岡先生に紹介いただいた、Juliaの例題をやってみたいと思います。
https://shinaoka.github.io/hpc_julia/docs/1dIsing.html
皆さんJuliaとともに!