『機械学習のエッセンス(http://isbn.sbcr.jp/93965/)』のPythonサンプルをJuliaで書き換えてみる。（第04章06乱数）

# はじめに

[『機械学習のエッセンス(http://isbn.sbcr.jp/93965/)』のPythonサンプルをJuliaで書き換えてみる。（第04章05NumPy/SciPyによる線形代数）](https://qiita.com/yshutaro/items/5bab7b6014fb3003b97f)の続きです。

## rand関数を使う

Juliaでは`rand`関数を使います。
https://docs.julialang.org/en/v1/stdlib/Random/index.html
日本語訳はこちら。
https://code.i-harness.com/ja/docs/julia~1.0/stdlib/random/index

+ 0〜1の範囲の浮動小数点数を返す

```julia
julia> rand()
0.8168800696780041

julia> rand()
0.7217680180694137
```

+ 引数を指定すると配列を返す

```julia
julia> rand(3, 2)
3×2 Array{Float64,2}:
 0.0957013  0.284191
 0.0393057  0.781931
 0.614824   0.77722 
```

+ 整数型の乱数を返す

```julia
julia> rand(1:4)
4

julia> rand(10:20)
15
```

+ 範囲の後に行列のサイズを指定するとその行列を返す

```julia
julia> rand(1:5, 3, 3)
3×3 Array{Int64,2}:
 5  1  1
 4  5  5
 3  4  3
```

# 再現性と乱数の種

```dice1a.jl
function throw_dice(n)
  sum(rand(1:6, n))
end
```

## `throw_dice`関数の実行

```julia
julia> include("dice1a.jl")
throw_dice (generic function with 1 method)

julia> throw_dice(10)
35

julia> throw_dice(10)
30

julia> throw_dice(10)
38
```

## 乱数の種を指定する

Juliaでseedを設定するには`Random.seed!`関数を使います。
https://docs.julialang.org/en/v1/stdlib/Random/index.html#Generators-(creation-and-seeding)-1

引数の内容を変更する場合関数に`!`を付ける慣例になっているようです。
https://docs.julialang.org/en/latest/manual/style-guide/#Append-!-to-names-of-functions-that-modify-their-arguments-1

`using Random`を実行しても`seed!`だけではエラーになりました。

```julia
julia> using Random

julia> seed!(10)
ERROR: UndefVarError: seed! not defined
Stacktrace:
 [1] top-level scope at none:0

julia> Random.seed!(10)
MersenneTwister(UInt32[0x0000000a], Random.DSFMT.DSFMT_state(Int32[1007524736, 1073256705, 415953332, 1072893275, -601364280, 1073193666, -1335760268, 1072926448, 1521827180, 1073499520  …  -439825479, 1072978026, -411693740, 1073111955, -1611334130, 1963385220, 236575170, -789052601, 382, 0]), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0
.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], UInt128[0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000  …  0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000], 1002, 0)

julia> rand(5)
5-element Array{Float64,1}:
 0.11258244478647295
 0.36831406658084287
 0.3444540231363058 
 0.05664544616214151
 0.12078054506961555

julia> Random.seed!(10)
MersenneTwister(UInt32[0x0000000a], Random.DSFMT.DSFMT_state(Int32[1007524736, 1073256705, 415953332, 1072893275, -601364280, 1073193666, -1335760268, 1072926448, 1521827180, 1073499520  …  -439825479, 1072978026, -411693740, 1073111955, -1611334130, 1963385220, 236575170, -789052601, 382, 0]), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], UInt128[0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000  …  0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000], 1002, 0)

julia> rand(5)
5-element Array{Float64,1}:
 0.11258244478647295
 0.36831406658084287
 0.3444540231363058 
 0.05664544616214151
 0.12078054506961555

julia> Random.seed!(100)
MersenneTwister(UInt32[0x00000064], Random.DSFMT.DSFMT_state(Int32[-2036630343, 1072818225, 1299231502, 1073154435, 1563612565, 1073206618, 176198161, 1073683625, 381415896, 1073699088  …  163992627, 1073241259, 385818456, 1072878963, 399273729, 595433664, 390891112, 1704156657, 382, 0]), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], UInt128[0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000  …  0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000], 1002, 0)

julia> rand(5)
5-element Array{Float64,1}:
 0.2601250914736861 
 0.19031281518127185
 0.6609109399808133 
 0.06719317094984745
 0.9675998379215747 

julia> Random.seed!(100)
MersenneTwister(UInt32[0x00000064], Random.DSFMT.DSFMT_state(Int32[-2036630343, 1072818225, 1299231502, 1073154435, 1563612565, 1073206618, 176198161, 1073683625, 381415896, 1073699088  …  163992627, 1073241259, 385818456, 1072878963, 399273729, 595433664, 390891112, 1704156657, 382, 0]), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], UInt128[0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000  …  0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000], 1002, 0)

julia> rand(5)
5-element Array{Float64,1}:
 0.2601250914736861 
 0.19031281518127185
 0.6609109399808133 
 0.06719317094984745
 0.9675998379215747 
```

+ `Random.seed!`関数を使って、結果が再現するように`throw_dice`を書き換える。

```dice1b.jl
using Random

function throw_dice(n, random_seed = 10)
  Random.seed!(random_seed)
  sum(rand(1:6, n))
end
```

## 改良した`throw_dice`関数を使う

```julia
julia> include("dice1b.jl")
throw_dice (generic function with 2 methods)

julia> throw_dice(10)
31

julia> throw_dice(10)
31

julia> throw_dice(100)
363

julia> throw_dice(100)
363
```

## よくない実装の例

+ Juliaのオブジェクト指向について

Juliaはクラスベースのオブジェクト指向言語ではなく、`struct`で型を決めるようです。
https://docs.julialang.org/en/v1/manual/types/#Composite-Types-1

クラスがないので、実はここの書き換えは苦労しました。`struct`にはコンストラクタはあるけどメソッドの定義はできなさそうだし、下記は試行錯誤した結果です。`throw`関数は個別になっています。もっといい書き方があるのかもしれません。またプロパティは`.`で取得できるので、`get_sum`関数は作りませんでした。

```dice2a.jl
using Random

mutable struct Dice
  sum_::Float64

  function Dice()
    Random.seed!(0)
    new(0)
  end

end

function throw(x::Dice)
  x.sum_ += rand(1:6)
end
```

## Diceクラスを使う

+ 合計が同じになる

```julia
julia> include("dice2a.jl")
throw (generic function with 1 method)

julia> d1 = Dice()
Dice(0.0)

julia> for i in 1:10
       throw(d1)
       end

julia> d1.sum_
28.0

julia> d2 = Dice()
Dice(0.0)

julia> for i in 1:10
       throw(d2)
       end

julia> d2.sum_
28.0
```

+ 合計が異なる

```julia
julia> d1 = Dice()
Dice(0.0)

julia> d2 = Dice()
Dice(0.0)

julia> for i in 1:10
       throw(d1)
       throw(d2)
       end

julia> d1.sum_
24.0

julia> d2.sum_
42.0
```

## RandomStateクラスに相当するもの

下記マニュアルを見たのですが、明確にはわかりませんでした。
https://docs.julialang.org/en/v1/stdlib/Random/#Random.seed!
Examplesを見る限り`MersenneTwister`を`rand`の引数に入れることで出来そうな感じだったので下記のように作ってみたところ想定した結果にはなりました。
ただし、すみませんがあまり自信はありません。

※ `random_seed`のデフォルトを`None`にする部分も実装できていません。

```dice2b.jl
using Random

mutable struct Dice
  sum_::Float64
  rng::MersenneTwister

  function Dice(random_seed::Int)
    rng = MersenneTwister(random_seed)
    new(0, rng)
  end

end

function throw(x::Dice)
  x.sum_ += rand(x.rng, 1:6)
end
```

## 動作の確認

```julia
julia> include("dice2b.jl")
throw (generic function with 1 method)

julia> d1 = Dice(123)
Dice(0.0, MersenneTwister(UInt32[0x0000007b], Random.DSFMT.DSFMT_state(Int32[1464307935, 1073116007, 222134151, 1073120226, -290652630, 1072956456, -580276323, 1073476387, 1332671753, 1073438661  …  138346874, 1073030449, 1049893279, 1073166535, -1999907543, 1597138926, -775229811, 32947490, 382, 0]), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], UInt128[0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000  …  0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000], 1002, 0))

julia> d2 = Dice(123)
Dice(0.0, MersenneTwister(UInt32[0x0000007b], Random.DSFMT.DSFMT_state(Int32[1464307935, 1073116007, 222134151, 1073120226, -290652630, 1072956456, -580276323, 1073476387, 1332671753, 1073438661  …  138346874, 1073030449, 1049893279, 1073166535, -1999907543, 1597138926, -775229811, 32947490, 382, 0]), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], UInt128[0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000  …  0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000], 1002, 0))

julia> for i in 1:10
       throw(d1)
       throw(d2)
       end

julia> d1.sum_
33.0

julia> d2.sum_
33.0
```