2012-01-26 7 views
12

Chciałbym funkcji, która może generować pseudolosową sekwencję wartości, ale aby ta sekwencja była powtarzalna w każdym przebiegu. Dane, które chcę, muszą być dość dobrze losowo rozłożone w danym zakresie, nie muszą być idealne.Jak wygenerować powtarzalną losową sekwencję liczb?

Chcę napisać kod, na którym będą wykonywane testy wydajności oparte na losowych danych. Chciałbym, aby dane były takie same dla każdego testu, na każdej maszynie, ale nie chcę wysyłać losowych danych z testami dla celów przechowywania (może to w końcu być wiele megabajtów).

Biblioteka modułu random nie wydaje się mówić, że ten sam materiał siewny zawsze da taką samą sekwencję na dowolnym komputerze.

EDYCJA: Jeśli zamierzasz zasiać dane (jak wspomniałem powyżej), podaj dokumentację, która mówi, że podejście jest prawidłowe, i będzie działać na wielu maszynach/implementacjach.

EDYCJA: CPython 2.7.1 i PyPy 1.7 na Mac OS X i CPython 2.7.1 i CPython 2.52 = .2 Ubuntu wydaje się dawać takie same wyniki. Nadal nie ma dokumentów, które przewidują to w czerni i bieli.

Wszelkie pomysły?

+2

Czy próbowałeś * generować sekwencję z danym nasieniem wiele razy? – bdares

+0

Mam tylko jeden komputer i jeden system operacyjny, więc nie mogę tego wiarygodnie przetestować. – Joe

+0

Jak myślę, fundamentalne pytanie brzmi "po co?" Jeśli szyfr - to bardzo zły pomysł i nie rób tego. Musisz napisać "za co". – theWalker

Odpowiedz

4

Dokumentacja nie mówi jednoznacznie, że dostarczanie materiału siewnego zawsze gwarantuje takie same wyniki, ale jest to zagwarantowane przy użyciu losowego użycia Pythona na podstawie używanego algorytmu.

Zgodnie z dokumentacją, Python używa Mersenne Twister jako generatora rdzeni. Po zaimplementowaniu tego algorytmu nie otrzymuje żadnego zewnętrznego wyjścia, które zmieniałoby kolejne wywołania, więc daj mu ten sam materiał siewny, a Ty uzyskasz takie same wyniki.

Oczywiście można to również zaobserwować, ustawiając materiał siewny i generując duże listy liczb losowych i sprawdzając, że są one takie same, ale rozumiem, że nie chcę ufać temu samemu.

Nie sprawdziłem innych implementacji Pythona poza CPythonem, ale mam duże wątpliwości, czy zaimplementują moduł losowy za pomocą zupełnie innego algorytmu.

+0

Tak myślałem. Prawdopodobnie skończę z robieniem tego jako najgorszym rozwiązaniem. – Joe

+0

Nawet jeśli użyliby zupełnie innego algorytmu, gdybyś dał to samo nasienie do tego samego algorytmu pseudolosowego, wypluje on tę samą sekwencję liczb - natknąłbyś się na problemy, gdybyś chciał przetestować na dwóch różnych implementacjach Pythona, używał innego algorytmu, ale o to chodzi. Ale jak rozumiem dokumenty, gwarantują one również algorytm bazowy, więc wszystko jest w porządku. – Voo

+0

Wydaje mi się, że nadal możesz uzyskać różne wyniki, jeśli masz 32-bitowy Twister Mersenne vs 64-bitowy Twister Mersenne – DrRobotNinja

6

Podaj nasienie do generatora liczb losowych. Jeśli zapewnisz to samo nasienie, liczby losowe powinny być takie same.

http://docs.python.org/library/random.html#random.seed

+0

Tak właśnie myślałem, ale jak powiedziałem w pytaniu, nie widzę żadnej dokumentacji, która by to poparła. – Joe

+1

Czy próbowałeś używać tego samego nasienia i obserwować wyjście? – Oleksi

+2

http://www.tutorialspoint.com/python/number_seed.htm –

4

Korzystanie random.seed (...) można wygenerować powtarzalną sekwencję. Demonstracja:

import random 

random.seed(321) 
list1 = [random.randint(1,10) for x in range(5)] 

random.seed(321) 
list2 = [random.randint(1,10) for x in range(5)] 

assert(list1==list2) 

To działa, ponieważ random.seed (...) nie jest prawdziwie losowych: to pseudo-losowych, przy czym kolejne numery są produkowane przez permutację jakieś machiny państwowej, biorąc pod uwagę wstępny warunek początkowy, The ' nasionko'.

0

Właśnie próbowałem następujące:

import random 
random.seed(1) 
random.random() 
random.random() 
random.random() 

random.seed(1) 
random.random() 
random.random() 
random.random() 

wszedłem każdą linię na CLI przy różnych prędkościach ponad wiele razy. Wyprodukowane te same wartości za każdym razem.

4

Jeśli jakość liczb losowych nie jest tak krytyczny jak powtarzalności przekrojowego-platform, można użyć jednego z tradycyjnym linear congruential generators:

class lcg(object): 
    def __init__(self, seed=1): 
     self.state = seed 

    def random(self): 
     self.state = (self.state * 1103515245 + 12345) & 0x7FFFFFFF 
     return self.state 

Od tego jest kodowana w programie za pomocą arytmetyki liczb całkowitych powinno być powtarzalne deterministycznie na każdej rozsądnej platformie.

+0

Świetnie, przyjrzę się temu. – Joe

20

Do tego celu użyłem powtarzającego się skrótu MD5, ponieważ intencją funkcji mieszającej jest wieloplatformowa transformacja jeden-do-jednego, więc zawsze będzie taka sama na różnych platformach.

import md5 

def repeatable_random(seed): 
    hash = seed 
    while True: 
     hash = md5.md5(hash).digest() 
     for c in hash: 
      yield ord(c) 

def test(): 
    for i, v in zip(range(100), repeatable_random("SEED_GOES_HERE")): 
     print v 

wyjściowa:

184 207 76 134 103 171 90 41 12 142 167 107 84 89 149 131 142 43 241 211 224 157 47 59 34 233 41 219 73 37 251 194 15 253 75 145 96 80 39 179 249 202 159 83 209 225 250 7 69 218 6 118 30 4 223 205 91 10 122 203 150 202 99 38 192 105 76 100 117 19 25 131 17 60 251 77 246 242 80 163 13 138 36 213 200 135 216 173 92 32 9 122 53 250 80 128 6 139 49 94 

Zasadniczo kod zajmie swoje nasienie (dowolny prawidłowy ciąg) i wielokrotnie go hash, generując w ten sposób liczby całkowite od 0 do 255.

+0

To genialny pomysł! – Joe

9

Istnieją różnice platformy , więc jeśli przeniesiesz swój kod pomiędzy różne platformy, wybrałbym metodę opisaną przez DrRobotNinja.

Proszę spojrzeć na następujący przykład. Python na moim komputerze stacjonarnym (64-bitowe Ubuntu z Core i7, Python 2.7.3) daje mi następujące:

> import random 
> r = random.Random() 
> r.seed("test") 
> r.randint(1,100) 
18 

Ale jeśli uruchomię ten sam kod na moim Raspberry Pi (Raspbian na ARM11), I dostać aa inny wynik (dla tej samej wersji Pythona)

> import random 
> r = random.Random() 
> r.seed("test") 
> r.randint(1,100) 
34 
+0

Interesujące! Dzięki za wskazanie tego. – Joe

+0

Nie wiem, czy jest to udokumentowane zachowanie. Wydaje się dziwne, że powinno to być zależne od platformy, kiedy tak duża część standardowej biblioteki Pythona jest zaprojektowana do pracy na różnych platformach. Może powinienem zgłosić błąd do zespołu Pythona? – Joppe

+0

To dobry pomysł (po pierwszym przejrzeniu raportów o błędach). Jeśli nie jest to błąd, będzie to dobre wyjaśnienie. – Joe

5

także odpowiedź, dlaczego przykład z this answer wywołuje inny wyjście na różnych maszynach:

to dlatego, że gdy zaszczepienie losowy generator nasienie ma być liczbą całkowitą. Jeśli zaszczepiasz generator pewną liczbą niecałkowitą, musi on zostać najpierw zaszyty. Funkcje hashowe same w sobie nie są niezależne od platformy (oczywiście przynajmniej nie wszystkie z nich, popraw mnie, jeśli wiesz więcej).

Tak więc, aby wyciągnąć wszystko razem: Python używa generatora liczb pseudolosowych. Dlatego też, gdy zaczniemy od tego samego stanu, wytworzona sekwencja liczb losowych będzie zawsze taka sama, niezależnie od platformy. To po prostu deteministyczny algorytm bez dalszego wkładu ze świata zewnętrznego.

Oznacza to: dopóki zainicjujesz generator losowy o tym samym stanie, wygeneruje on tę samą sekwencję liczb. Dojście do tego samego stanu można wykonać za pomocą tego samego zera lub poprzez zapisanie i ponowne zastosowanie starego stanu (random.getstate() i random.setstate()).

+0

Wydaje się to być prawdziwą, choć częściową odpowiedzią, a na pewno dodaje informacji. Gdybym był tobą, usunęłbym przeprosiny na szczycie! – Joe

+0

Zaczęło się znacznie krócej, ale rozwinęło się w rozwiniętą odpowiedź, więc masz rację, a ja ją usunąłem/zmieniłem. –