Как я должен использовать random.jumpahead в Python - PullRequest
3 голосов
/ 30 марта 2010

У меня есть приложение, которое проводит определенный эксперимент 1000 раз (многопоточное, так что несколько экспериментов выполняются одновременно). Каждый эксперимент требует ок. 50 000 вызовов random.random ().

Какой лучший способ получить это действительно случайно. Я мог бы скопировать случайный объект для каждого эксперимента и сделать прыжок на 50.000 * expid. Документация предполагает, что jumpahead (1) уже шифрует состояние, но так ли это на самом деле?

Или есть другой способ сделать это «наилучшим образом»?

(Нет, случайные числа используются не для обеспечения безопасности, а для алгоритма хастинга в мегаполисе. Единственное требование - эксперименты независимы, а не то, является ли случайная последовательность как-то предсказуемой или около того)

Ответы [ 4 ]

5 голосов
/ 30 марта 2010

Я мог бы скопировать случайный объект в каждый эксперимент и сделать больше, чем прыгун в 50.000 * expid.

Примерно правильно. Каждый поток получает свой собственный экземпляр Random.

Посеять их все на одно и то же значение. Используйте константу для тестирования, используйте / dev / random, когда вы «запустите запись».

Редактировать . Вне Python и в более старых реализациях используйте jumpahead( 50000 * expid ), чтобы избежать ситуации, когда два генератора сталкиваются с параллельными последовательностями значений. В любом достаточно текущем (после 2.3) Python jumpahead больше не является линейным, и для шифрования состояния достаточно использовать expid.

Вы не можете просто сделать jumpahead(1) в каждом потоке, так как это обеспечит их синхронизацию. Используйте jumpahead( expid ), чтобы убедиться, что каждая нить явно зашифрована.

Документация предполагает, что jumpahead (1) уже шифрует состояние, но так ли это на самом деле?

Да, прыгун действительно "вскарабкается" на государство. Напомним, что для данного семени вы получаете одну - длинную - но фиксированную последовательность псевдослучайных чисел. Вы прыгаете вперед в этой последовательности. Чтобы пройти тесты случайности, вы должны получить все свои значения из этой последовательности one .

Редактировать . Когда-то прыжок (1) был ограничен. Теперь jumpahead (1) действительно делает большее шифрование. Скремблирование, однако, является детерминированным. Вы не можете просто сделать jumpahead(1) в каждой теме.

Если у вас есть несколько генераторов с разными семенами, вы нарушаете предположение «одна последовательность из одного семени», и ваши числа не будут такими случайными, как если бы вы получали их из одной последовательности.

Если у вас только парашютист 1, вы можете получить параллельные последовательности, которые могут быть похожими. [Это сходство не может быть обнаружено; теоретически , есть сходство.]

Когда вы прыгаете вперед 50 000, вы гарантируете, что вы следуете посылке 1-sequence-1-seed. Вы также гарантируете, что в двух экспериментах у вас не будет смежных последовательностей чисел.

Наконец, у вас также есть повторяемость. Для данного семени вы получаете последовательные результаты.

Тот же прыгун: Не хорошо.

>>> y=random.Random( 1 )
>>> z=random.Random( 1 )
>>> y.jumpahead(1)
>>> z.jumpahead(1)
>>> [ y.random() for i in range(5) ]
[0.99510321786951772, 0.92436920169905545, 0.21932404923057958, 0.20867489035315723, 0.91525579001682567]
>>> [ z.random() for i in range(5) ]
[0.99510321786951772, 0.92436920169905545, 0.21932404923057958, 0.20867489035315723, 0.91525579001682567]
3 голосов
/ 07 июля 2011

Вы не должны использовать эту функцию. Нет никаких доказательств того, что он может работать на генераторе Мерсенна Твистера. Действительно, он был удален из Python 3 по этой причине .

Для получения дополнительной информации о генерации псевдослучайных чисел в параллельных средах см. эту статью от David Hill .

3 голосов
/ 30 марта 2010

jumpahead(1) действительно достаточно (и идентично jumpahead(50000) или любому другому подобному вызову в текущей реализации random - я полагаю, что это произошло одновременно с реализацией на основе Mersenne Twister). Поэтому используйте любой аргумент, хорошо вписывающийся в логику ваших программ. (Конечно, для обеспечения безопасности потоков используйте отдельный экземпляр random.Random для каждого потока, поскольку ваш вопрос уже намекает).

(random числа, сгенерированные модулем, не должны быть криптографически стойкими, поэтому хорошо, что вы не используете их в целях безопасности; -).

0 голосов
/ 30 марта 2010

По случайным модулям документации на python.org:

«Вы можете создавать свои собственные экземпляры Random, чтобы получить генераторы, которые не разделяют состояние».

И, как вы упомянули, на прыжке также есть соответствующая заметка. Но гарантии там немного расплывчаты. Если вызовы случайности, предоставляемой ОС, не так дороги, чтобы доминировать во времени выполнения, я пропущу все тонкости и сделаю что-то вроде:

randoms = [random.Random(os.urandom(4)) for _ in range(num_expts)]

Если num_expts равен ~ 1000, то вряд ли у вас будут какие-либо коллизии в вашем семени (парадокс дня рождения говорит, что вам нужно около 65000 экспериментов, прежде чем есть> 50% вероятность того, что у вас коллизия). Если для вас этого недостаточно, или если количество экспериментов больше похоже на 100 КБ, а не на 1 КБ, то я думаю, что разумно продолжить это с

for idx, r in enumerate(randoms):
  r.jumpahead(idx)

Обратите внимание, что я не думаю, что это будет работать, просто сделав ваше семя длиннее (например, os.urandom (8)), так как случайные документы утверждают, что семя должно быть хешируемым, и так далее в 32-битном платформу, вы получите только 32 бита (4 байта) полезной энтропии в вашем семени.

Этот вопрос пробудил мое любопытство, поэтому я пошел и посмотрел на код , реализующий случайный модуль. Я определенно не эксперт по PRNG, но кажется, что слегка отличающиеся значения n в jumpahead (n) приведут к заметно различным случайным состояниям экземпляра. (Всегда страшно противоречить Алексу Мартелли, но код действительно использует значение n при перемешивании случайного состояния).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...