Я хотел бы иметь возможность конвертировать туда и обратно между стандартным Random Python и np.random.RandomState numpy. Оба они используют алгоритм 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
.
Второе состояние — это кортеж размера 3 с len(state2[1]) = 625
. Кажется, что последний элемент в state2 на самом деле является 624 в state1, что означает, что массивы на самом деле имеют одинаковый размер. Все идет нормально. Они кажутся разумно совместимыми.
К сожалению, внутренние числа не имеют очевидного соответствия, поэтому начальное значение 0 приводит к разным состояниям, что имеет смысл, поскольку rng1.rand() = .548
и rng2.random() = .844
. Таким образом, алгоритм выглядит немного другим.
Однако мне не нужно, чтобы они идеально соответствовали друг другу. Мне просто нужно иметь возможность устанавливать состояние одного кольца из другого детерминированным образом, не влияя на состояние первого.
В идеале, как только я использовал состояние первого для установки состояния второго, не вызывая никаких случайных методов, а затем использовал второй для установки состояния первого, первое состояние осталось бы неизменным, но это не требование. .
В настоящее время у меня есть взломанный метод, который просто меняет местами список длиной 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 целых числа, кажется, не меняются. Всегда ли это так?
Тем не менее, я все еще не уверен, что означает окончательный None в версии Python, а последние 2 числа - в версии numpy.