乱数発生器の制御
この例では、乱数発生器を制御する関数 rng
を使用する方法を示します。
MATLAB® の (疑似) 乱数は、関数 rand
、randi
、および randn
で生成されます。他の多くの関数がこの 3 つの関数を呼び出しますが、これらは基本ブロックです。3 つの関数はすべて、rng
を使って制御できる 1 つの共有乱数発生器に依存します。
MATLAB の "乱数" は予測不可能ですが、決定性アルゴリズムによって生成されるということを理解しておいてください。このアルゴリズムは、アルゴリズムを知らなければその出力が独立した乱数列に "見える" ように十分に複雑になるように設計されていて、ランダム性のさまざまな統計検定にも合格できます。ここで紹介する関数を使用すると、次の項目を実行するために確定性を利用できます。
乱数に関連する計算を反復して同じ結果を取得する。
反復計算で異なる乱数が使用されることを保証する。
また、見かけのランダム性を利用して個々の計算結果の組み合わせが正しいことを証明します。
"やり直し"
新しい MATLAB セッションで rand
、randi
、または randn
の出力を確認すると、MATLAB を再起動するたびに同じ数列が返されることに気付きます。これは、実際に MATLAB を再起動しなくても乱数発生器を起動時の状態にリセットできるので多くの場面で役立ちます。たとえば、乱数を含む計算を反復して同じ結果を得る必要がある場合などです。
rng
を使用すると、乱数発生器を既定の設定に簡単に戻すことができます。
rng default rand % returns the same value as at startup
ans = 0.8147
MATLAB の起動時の "既定の" 乱数設定はどのような内容で、rng default
にはどのような機能があるのでしょう。入力なしで rng
を呼び出すと、シードが 0 のメルセンヌ・ツイスター発生器アルゴリズムであることがわかります。
rng
ans = struct with fields:
Type: 'twister'
Seed: 0
State: [625x1 uint32]
State
フィールドなどの上記の出力を使用して MATLAB が乱数を生成する方法を制御および変更する方法の詳細については、以下を参照してください。ここでは、発生器 rand
、randi
、および randn
が現在使用しているものを確認するために使用されています。
非反復性
rand
、randi
、または randn
は呼び出されるたびに共有乱数発生器から新しい値を取り出し、連続した値は統計的に独立した値として処理されます。しかし前述のように、MATLAB を再起動するたびにこれらの関数はリセットされて同じ数列を返します。"同一の乱数" を使用する計算が統計的に独立しているとは考えられないことは明らかです。そのため、複数の MATLAB セッションで実行される計算が統計的に "独立しているように" その計算を組み合わせる必要がある場合、既定の発生器の設定は使用できません。
新しい MATLAB セッションで同じ乱数が繰り返されないようにするには、乱数発生器に異なるシードを選択する方法が簡単です。rng
を使うと、現在時刻に基づいたシードを作成することによって同じ乱数の発生を簡単に回避できます。
rng shuffle
rand
ans = 0.9539
'shuffle'
は、使用されるたびに異なるシードで発生器を再シードします。入力なしで rng
を呼び出すと、実際に使用されるシードの内容を確認できます。
rng
ans = struct with fields:
Type: 'twister'
Seed: 2091190526
State: [625x1 uint32]
rng shuffle % creates a different seed each time rng
ans = struct with fields:
Type: 'twister'
Seed: 2091190537
State: [625x1 uint32]
rand
ans = 0.8117
'shuffle'
を使用すると、非常に簡単に乱数発生器を再シードできます。MATLAB で "本来の" ランダム性を確保するには shuffle の使用が便利な場合も必要な場合もあります。ただし、多くの場合、'shuffle'
を "使用する必要はまったくありません"。現在時刻に基づいてシードを選択すると、rand
、randi
、および randn
から得られる値の統計的な特性は向上せず、本当の意味で "ランダム性を高める" ことはできません。MATLAB の起動時や乱数を含む大規模な計算を実行する前に発生器を再シードしてもよいですが、乱数の統計的な特性に影響を及ぼす可能性があるため、実際には 1 つのセッションで何回も発生器の再シードを行うのはお勧めできません。
'shuffle'
を使用すると同一の値の系列の繰り返しを回避できますが、これが重要な場合もあれば、"便利" であるにすぎない場合もあり、さほど重要でない場合がほとんどです。'shuffle'
を使用する場合は、後で計算を繰り返せるように rng
が作成したシードを保存することを忘れないでください。以下にその方法を示します。
反復性と非反復性の強力な制御
これまでのところ、乱数発生器を既定の設定にリセットする方法と、現在時刻から作成されるシードを使用して発生器を再シードする方法を確認してきました。また、rng
を使用すると特定のシードを使って発生器を再シードできることも説明しました。
同じシードを何回も使用して同じ計算を繰り返すことができます。たとえば、次のコードを 2 回実行します。
rng(1) % the seed is any non-negative integer < 2^32
x = randn(1,5)
x = 1×5
-0.6490 1.1812 -0.7585 -1.1096 -0.8456
rng(1) x = randn(1,5)
x = 1×5
-0.6490 1.1812 -0.7585 -1.1096 -0.8456
... まったく同じ結果が得られます。これを実行するのは、特定の値を使用して x
に依存するその後の計算内容を繰り返すことができるように、消去後に x
を再び作成する場合などです。
一方で、同じ計算を繰り返さないように、"異なる" シードを選択する場合があります。たとえば、1 つの MATLAB セッションで次のコードを実行します。
rng(2)
x2 = sum(randn(50,1000),1); % 1000 trials of a random walk
別のセッションでは次のコードを実行します。
rng(3) x3 = sum(randn(50,1000),1);
... 2 つの結果を組み合わせると、単に 2 回繰り返されて同じ結果になったのではないことがわかります。
x = [x2 x3];
'shuffle'
と同様に、MATLAB の乱数発生器を再シードする際は注意してください。rand
、randi
、および randn
のその後のすべての出力に影響するためです。反復性または一意性が必要ない場合、一般的には発生器を再シードしないで単に乱数を生成することをお勧めします。発生器を再シードする必要がある場合は、コマンド ラインで行うか、コード内の見落としにくい場所で行ってください。
発生器のタイプの選択
前述のように乱数発生器を再シードできるだけでなく、使用する乱数発生器のタイプを選択することもできます。発生器のタイプが異なると発生する乱数列も異なります。たとえば統計的な特性に基づいて特定のタイプを選択する場合もあります。また、MATLAB の古いバージョンで使われていた別の既定の発生器タイプの結果を再作成する場合もあります。
他に発生器のタイプを選択する理由として、"ランダムな" 入力データを生成する検証試験を記述して、その検定で常にまったく同じ予測どおりの結果が得られることを保証する場合があります。入力データを作成する前にシードで rng
を呼び出すと、乱数発生器が再シードされます。しかし、何らかの理由で発生器のタイプが変更されていると、rand
、randi
、および randn
の出力はそのシードから予測される出力とは異なる内容になります。したがって、反復性を確実にするには、発生器のタイプも指定します。
たとえば、次のコマンドを実行します。
rng(0,'twister')
これにより、rand
、randi
、および randn
はメルセンヌ・ツイスター発生器アルゴリズムを 0 でシードしてから使用します。
次のように 'combRecursive'
を使用するとします。
rng(0,'combRecursive')
これにより、結合多重再帰発生器アルゴリズムが選択されます。このアルゴリズムは、メルセンヌ・ツイスターではサポートされないいくつかの並列機能をサポートします。
次のコマンドを実行するとします。
rng(0,'v4')
これにより、MATLAB 4.0 の既定の設定だった発生器アルゴリズムが選択されます。
次のコマンドは乱数発生器を既定の設定に戻します。
rng default
ただし、乱数発生器の既定の設定は MATLAB リリース間で変更されている場合があることから、'default'
による予測結果については長期的な保証はありません。'default'
は乱数発生器をリセットするには便利ですが、より高い予想精度を求める場合は、発生器のタイプとシードを指定してください。
一方、対話的に操作して反復性が必要な場合は、シードを指定して rng
を呼び出す方法が簡単であり、通常はこの方法で十分です。
乱数発生器の設定内容の保存と復元
入力なしで rng
を呼び出すと、前述の 2 つの情報である、発生器のタイプと発生器を前回再シードしたときの整数値を含むフィールドをもつスカラー構造体が返されます。
s = rng
s = struct with fields:
Type: 'twister'
Seed: 0
State: [625x1 uint32]
3 番目のフィールド State
には、発生器の現在の状態ベクトルのコピーが含まれています。この状態ベクトルは、発生器が乱数列の次の値を生成するために内部で保持する情報です。rand
、randi
、または randn
が呼び出されるたびに、これらが共有する発生器は内部状態を更新します。したがって、rng
によって返される設定構造体の状態ベクトルには、その状態がキャプチャされた点から始まる数列を繰り返すために必要な情報が含まれています。
この出力を確認することも有益ですが、rng
は "入力" として設定構造体も受け入れるため、状態ベクトルなどの設定内容を保存し、それを復元して後で計算を繰り返すことができます。設定には発生器のタイプも含まれるため、出力の内容を正確に把握できます。また、上述の "後で" は、同じ MATLAB セッションの数秒後から、いくつもの MATLAB リリースを経た数年後まで含まれます。発生器の設定を保存した乱数列の点から結果を繰り返すことができます。例を次に示します。
x1 = randn(10,10); % move ahead in the random number sequence s = rng; % save the settings at this point x2 = randn(1,5)
x2 = 1×5
0.8404 -0.8880 0.1001 -0.5445 0.3035
x3 = randn(5,5); % move ahead in the random number sequence rng(s); % return the generator back to the saved state x2 = randn(1,5) % repeat the same numbers
x2 = 1×5
0.8404 -0.8880 0.1001 -0.5445 0.3035
再シードでは大まかな再初期化が行われるだけですが、設定構造体を使用して発生器の状態を保存および復元すると、乱数列の "どの部分" でも繰り返すことができます。
設定構造体の一般的な使用方法は、発生器の状態の復元です。ただし、構造体には状態だけでなく発生器のタイプとシードも含まれているため、発生器のタイプを一時的に切り替えるときにも便利です。たとえば、MATLAB 5.0 の従来の発生器のいずれかを使用して値を作成する場合は、古い発生器を使用するために切り替えるのと同時に現在の設定を保存できます。
previousSettings = rng(0,'v5uniform')
previousSettings = struct with fields:
Type: 'twister'
Seed: 0
State: [625x1 uint32]
... さらに、後で元の設定を復元できます。
rng(previousSettings)
設定構造体のフィールドの内容を変更すべきではありません。具体的には、独自の状態ベクトルを構成すべきではなく、発生器の状態の形式に頼るべきでもありません。
簡潔で柔軟性の高いコードの記述
rng
を使用すると、次のいずれかを実行できます。
乱数発生器の再シード
乱数発生器の設定の保存と復元
発生器のタイプを把握する必要はありません。また、乱数発生器の設定内容を知らなくても、既定の設定に戻すことができます。発生器のタイプを指定する "必要がある" 場合でも、rng
を使用すると指定する "必要がなくなります"。
発生器のタイプを指定する必要がなくなれば、使用する発生器が異なる場合にもコードが自動的に適合して、新しい既定の乱数発生器のタイプがもつ改良された特性を自動的に活用することができます。
rng
と RandStream
一般的な必要性に応じて MATLAB で乱数発生器を制御するには、rng
が最も便利です。ただし、複数の乱数ストリームや並列乱数生成を含む複雑な状況では、より複雑なツールが必要です。RandStream
クラスがそのツールで、乱数発生を最も強力に制御できます。この 2 つのツールは相補的な関係にあり、rng
では RandStream
の柔軟性に基づいて構築される単純で簡潔な構文を作成できます。