小林 未知数の備忘録
Julia

Juliaメモ

頻繁に混同するjuliaとpython (numpy)とfortran

python,numpy julia fortran
配列の形状 np.shape size
配列の全要素数 np.size length
配列の次元 np.ndim ndims
配列の型の確認 .dtype typeof
sumやmeanにおける軸の指定 axis= dims= dim=
配列の最大、最小 np.max, np.min maximum, minimum maxval, minval
最大、最小の場所 np.argmax, np.argmin argmax, argmin maxloc, minloc
ゼロ要素の配列 np.zeros zeros
(最初、最後、間隔) を指定した配列 np.arange range(step=)
(最初、最後、要素数) を指定した配列 np.linspace range(length=)
整数の割り算 A//B A÷B A/B
文字の結合 A+B A*B A//B
配列の巡回シフト np.roll circshift cshift
数値→文字 str string write
ループ強制終了 break break exit
ループの始めに戻る continue continue cycle
剰余 % % mod
論理和、論理積 or, and ||, && or, and
\((-\pi,\pi]\)を返す逆正接 np.arctan2(y,x) atan(y,x) atan2(y,x)

手っ取り早く高速化 (経験に基づいて書いている)

  • プログラムはすべて関数化する

    関数の外のプログラムは高速化の恩恵を受けにくいので関数の外でなにか計算するのは避ける。
  • グローバル変数は使わない

    関数の外で変数を定義すると、すべての関数でその変数を使うことができる。
    これをグローバル変数と言い、便利であるが動作は遅くなる。
    結局関数の外では計算しないだけでなく、変数の定義も避ける。
  • 値を変更しない定数にはconstを付けておく

    例外としてconstによって与えられた定数は関数の外側であっても遅くなる影響を受けない。
    当然ではあるが、値はプログラム内で変更したりしないこと。
  • 配列を別の関数に渡すときは引数にする

    グローバル変数が使えない以上、関数から別の関数へ配列を渡すには関数の引数として渡す。
    数学関数と違って、引数を変更することもできるので、returnを使わずに引数として渡して関数の中で変更すると良い。
    ただしmoduleを使うという方法もあり、こちらの方が便利であるが、fortranと違って適当なことをすると遅くなる傾向にある。
  • 用いる配列 (ベクトルや行列) は全て最初に定義しておき、上書き更新する

    JuliaやPythonの特徴として、計算の途中でベクトルや行列を簡単に新規作成することができるという点があるが、高速を目指すのであれば、必要なベクトルや行列は最初に全て定義しておき、それを上書きする形で用いる。
  • in placeの演算が用意されているときは積極的に使う

    in place演算とout of place演算ではin-placeの方が速い場合が多い 。
    また、out of place演算は意図せずにメモリを大量に消費することがあるので使用を避ける。
  • in placeの演算が用意されていないときは配列式ではなくforを使う

    Pythonではforをなるべく使わず、配列の式は配列のままで書くことが推奨されるが、Juliaは逆にforを使って成分毎に計算したほうが速いケースがよくある。

要はある程度fortranを意識して書いたほうが速いということか。

I / O

  • (Fortranによくある) 空白で区切られたテキストファイルの読み込み

    					using CSV
    					using DataFrames
    					data = CSV.read("file.txt", delim = " ", ignorerepeated = true)
    				
  • アスキーデータのフォーマット付き書き出し

    実数が5つの例
    					using Printf
    					fmt1 = Printf.Format("%16s" ^ 5 * "\n")
    					fmt2 = Printf.Format("%16.6e" ^ 5)
    					open("value.txt", "w") do file
    					    Printf.format(file, fmt1, "π", "ℯ", "√2", "(1 + √5) / 2", "ζ(2)")
    					    Printf.format(file, fmt2, π, ℯ, √2, 0.5 * (1 + √5), π ^ 2 / 6)
    					end
    				
    value.txtの中身は
    					               π               ℯ              √2    (1 + √5) / 2            ζ(2)
    					    3.141593e+00    2.718282e+00    1.414214e+00    1.618034e+00    3.321928e+00
    				
  • バイナリデータの読み書き

    書き出し
    					using Random # 乱数のために呼び出しているだけなので必要なし
    					using HDF5
    					v1 = rand(5)
    					v2 = rand(6, 3)
    					h5open("value.bin", "w") do file
    					    write(file, "Vec", v1)
    					    write(file, "Mat", v2)
    					end
    				
    読み込み
    					using HDF5
    					v1 = zeros(5)
    					v2 = zeros(ComplexF64, 6, 3) # 書き出したときは実数だが、読み込むときに複素数の実部として読み込むことも可能
    					h5open("value.bin", "r") do file
    					    v1 .= read(file, "Vec")
    					    v2 .= read(file, "Mat")
    					end
    				
  • すぐに書き込み

    flush(file)ですぐに書き込まれる。fileはファイル識別子。標準出力の場合はstdout。