10.6 行列、ベクトルのコピー (とその周辺, copy(), .=)

Julia では、Array a に対して、 b=a としても a のコピーが作られる訳でなく、 ba の参照になる。 もしもコピーがしたければ b=copy(a) とする。 いうようなことが某説明に書いてあった。

非常に分かりにくい。一度は「間違い」と思ったくらいである。

配列 a に対して、 b=ac=copy(a) でどう違うかを見てみよう。
julia> a=ones(3)
3-element Array{Float64,1}:
 1.0
 1.0
 1.0

julia> b=a
3-element Array{Float64,1}:
 1.0
 1.0
 1.0

julia> c=copy(a)
3-element Array{Float64,1}:
 1.0
 1.0
 1.0

julia> a==b
true

julia> a==c
true

julia> a===b
true

julia> a===c
false

== で値を調べると、bca と同じ値を持つことが分かるが、 === で等しいか調べると、 ba に等しいが、 ca に等しくない。

ここで a の要素を書き換えてみよう。

julia> a[1]=2
2

julia> a
3-element Array{Float64,1}:
 2.0
 1.0
 1.0

julia> b
3-element Array{Float64,1}:
 2.0
 1.0
 1.0

julia> c
3-element Array{Float64,1}:
 1.0
 1.0
 1.0

以上を見ると、次のことが観察される。

ここで a の要素 a[$ i$] でなく、 a そのものに代入を行うと、 a の内容は書き換わるが、 b は代入前の a の内容を保持することになる。

ba の参照であるとき、a に代入を行うと
julia> a=zeros(2)
2-element Array{Float64,1}:
 0.0
 0.0

julia> b
3-element Array{Float64,1}:
 2.0
 1.0
 1.0
(この辺は、 C言語のような言語の低い水準の命令を使ったプログラムを書いた経験がないと、 理解しにくいかもしれない、と感じた。)


関数の引数にするときは、Array は参照渡しであり、 関数の中で引数を書き換えると、元に戻ったとき変更されてしまう。


(ここも、C言語などでプログラムを書いた経験があると、 何をやっているか、分かりやすいと思う。 そういう経験がない人にとって、 どのように感じられるか、なかなかおっかない。)


時々、同じサイズの配列が必要になることがある。 b=similar(a) とすると、 a と同じ大きさの Array b が用意される。 中身は初期化されていない (要するに値はゴミである)。

MATLAB で近いことをしようとすると、 b=zeros(size(a)) とするのだろうか (これは Julia でも有効である)。 これだと初期化という手間をかけることになる。

この辺、Julia は、一切の無駄なことはしない、 というポリシーが感じられる。


ab が既に存在していて、 ディメンションが一致するとき、 b .= a とすると、 b の各要素に a の対応する要素がコピーされる。


copy()similar() を使うと新しいメモリ領域を用意することになるが、 =.= ではそうならない。


慣れるまでは色々うっかりミスをしそうだ…



桂田 祐史