Python の標準の Random と numpy の np.random.RandomState の間で相互に変換できるようにしたいと考えています。これらはどちらも Mersenne Twister アルゴリズムを使用しているため、可能であるはずです (このアルゴリズムの異なるバージョンを使用していない限り)。
これらのオブジェクトの getstate/setstate メソッドと get_state/set_state メソッドを調べ始めました。しかし、それらの詳細を変換する方法がわかりません。
import numpy as np
import random
rng1 = np.random.RandomState(seed=0)
rng2 = random.Random(seed=0)
state1 = rng1.get_state()
state2 = rng2.getstate()
私が見る各状態を調べる:
>>> print(state1)
('MT19937', array([0, 1, 1812433255, ..., 1796872496], dtype=uint32), 624, 0, 0.0)
>>> print(state2)
(3, (2147483648, 766982754, ..., 1057334138, 2902720905, 624), None)
最初の状態は、サイズ 5 のタプルで、len(state1[1]) = 624
.
2 番目の状態は、サイズ 3 のタプルですlen(state2[1]) = 625
。state2 の最後の項目は実際には state1 の 624 のようです。これは、配列が実際には同じサイズであることを意味します。ここまでは順調ですね。これらは合理的に互換性があるようです。
残念ながら、内部の数値には明らかな対応がないため、シード 0 は異なる状態にrng1.rand() = .548
なりrng2.random() = .844
ます。そのため、アルゴリズムは少し異なるようです。
ただし、完全に一致する必要はありません。最初の rng の状態に影響を与えることなく、決定論的に 1 つの rng の状態を別の rng から設定できる必要があります。
理想的には、ランダム メソッドを呼び出さずに最初の状態を使用して 2 番目の状態を設定し、次に 2 番目の状態を使用して最初の状態を設定すると、最初の状態は変更されませんが、これは必須ではありません。 .
現在、両方の rng から抽出できる 624 の長さのリストを交換するだけのハッキングされた方法があります。ただし、このアプローチに問題があるかどうかはわかりません。この件についてもっと詳しい人は誰でも光を当てることができますか?
これが私のアプローチですが、それが正しく機能するかどうかはわかりません。
np_rng = np.random.RandomState(seed=0)
py_rng = random.Random(0)
# Convert python to numpy random state (incomplete)
py_state = py_rng.getstate()
np_rng = np.random.RandomState(seed=0)
np_state = np_rng.get_state()
new_np_state = (
np_state[0],
np.array(py_state[1][0:-1], dtype=np.uint32),
np_state[2], np_state[3], np_state[4])
np_rng.set_state(new_np_state)
# Convert numpy to python random state (incomplete)
np_state = np_rng.get_state()
py_rng = random.Random(0)
py_state = py_rng.getstate()
new_py_state = (
py_state[0], tuple(np_state[1].tolist() + [len(np_state[1])]),
py_state[1]
)
py_rng.setstate(new_py_state)
編集:
いくつかの調査を行って、ランダム関数への 10 回の呼び出しで状態がどうなるかを確認しました。
np_rng = np.random.RandomState(seed=0)
py_rng = random.Random(0)
for i in range(10):
np_rng.rand()
npstate = np_rng.get_state()
print([npstate[0], npstate[1][[0, 1, 2, -2, -1]], npstate[2], npstate[3], npstate[4]])
for i in range(10):
py_rng.random()
pystate = py_rng.getstate()
print([pystate[0], pystate[1][0:3] + pystate[1][-2:], pystate[2]])
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 2, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 4, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 6, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 8, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 10, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 12, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 14, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 16, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 18, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 20, 0, 0.0]
[3, (1372342863, 3221959423, 4180954279, 418789356, 2), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 4), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 6), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 8), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 10), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 12), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 14), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 16), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 18), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 20), None]
各タプルの最初の項目は、使用しているアルゴリズムのバージョンにすぎないと思います。
624 の整数が変化していないように見えるのは興味深いことです。これは常に当てはまりますか?
ただし、Python バージョンで最後の None が何を意味し、最後の 2 つの数字が numpy バージョンで何を意味するのかはまだわかりません。