2010-05-26 16 views
6

Estoy usando la implementación boost mt19937 para una simulación.Boost Mersenne Twister: ¿cómo sembrar con más de un valor?

La simulación debe ser reproducible, y eso significa almacenar y potencialmente reutilizar las semillas RNG más adelante. Estoy usando windows crypto api para generar los valores de inicialización porque necesito una fuente externa para las semillas y no debido a ninguna garantía particular de aleatoriedad. La salida de cualquier ejecución de simulación tendrá una nota que incluya la semilla RNG, por lo que la semilla debe ser razonablemente corta. Por otro lado, como parte del análisis de la simulación, compararé varias ejecuciones, pero para estar seguro de que estas ejecuciones son realmente diferentes, tendré que usar semillas diferentes, por lo que la semilla debe ser larga. suficiente para evitar colisiones accidentales.

He determinado que 64 bits de siembra deberían ser suficientes; la probabilidad de una colisión alcanzará el 50% después de aproximadamente 2^32 carreras, esa probabilidad es lo suficientemente baja como para que el error promedio causado por ella sea insignificante para mí. Usar solo 32 bits de semilla es complicado; la probabilidad de una colisión alcanza el 50% después de 2^16 carreras; y eso es demasiado probable para mi gusto.

Desafortunadamente, la implementación de refuerzo genera un vector de estado completo, que es demasiado, muy largo o solo un bit largo de 32 bits, lo que no es ideal.

¿Cómo puedo sembrar el generador con más de 32 bits pero menos que un vector de estado completo? Intenté simplemente rellenar el vector o repetir las semillas para llenar el vector de estado, pero incluso una mirada superficial a los resultados muestra que eso genera resultados pobres.

+0

Acaba de obtener el estado actual y modificarlo ... – kennytm

+0

Su cálculo de colisión no es del todo correcto. Por ejemplo, para una semilla de 64 bits, la probabilidad de un duplicado es> = 0.5 después de 77163! = 65536 ejecuciones. – user168715

+0

Las matemáticas de colisión son solo una aproximación fácil. Supongo que te refieres a una semilla de 32 bits, por cierto, ¿no una semilla de 64 bits? –

Respuesta

2

Sus suposiciones son erróneas. Para una simulación, no necesitas semillas criptográficamente fuertes. De hecho, usar semillas 1,2,3,4, etcétera es a menudo una mejor idea. Los valores de salida de Mersenne Twister no estarán correlacionados, sin embargo, nadie se preguntará si seleccionó sus semillas para obtener las salidas de simulación deseadas.

Para otras personas que sí tienen una necesidad real, una manera fácil es descartar los primeros valores (semilla >> 32) generados. Esto le proporciona log2 (seed >> 32) bits de estado adicionales. Sin embargo, solo funciona de manera eficiente si necesita algunos bits adicionales. Agregar 32 bits de esta manera es probablemente demasiado lento.

Un algoritmo más rápido es generar el vector de estado completo para el generador aleatorio bueno. Las soluciones mencionadas en la pregunta (repetición o relleno) no son tan buenas debido a la aleatoriedad limitada en el vector de estado resultante. Pero si completa el vector de estado inicial a partir de la salida mersenne_twister(seed1)^mersenne_twister(seed2), esto no es un problema en absoluto.

+0

No me preocupa ser criptográficamente seguro; Solo necesito obtener los valores iniciales de * somewhere *. La desventaja de usar semillas secuenciales es parcialmente de gestión: si utilizo una secuencia predeterminada de semillas, significa que cada carrera será idéntica a menos que de alguna manera administre esas semillas (es decir, use un archivo en alguna parte para asegurarme de no reutilizar las semillas accidentalmente). –

+0

Un problema con 'mersenne_twister (seed1)^mersenne_twister (seed2)' es que los valores de inicialización pueden ser idénticos, en cuyo caso la salida es, en cuyo caso el XOR de la salida es 0, completando el vector de estado completo con ceros resulta en un trabalenguas (no estoy seguro de que pueda escapar del todo, pero ciertamente no rápidamente). –

+0

Sin embargo, podría utilizar su idea de usar semillas secuenciales si distinguí entre las ejecuciones inspeccionables individualmente (para las cuales una semilla de 32 bits es buena) y las ejecuciones de análisis agregado (para las cuales las semillas secuenciales están perfectamente bien). –

3

Mirando a boost sources of mersenne_twister template:

void seed(UIntType value) 
    { 
    // New seeding algorithm from 
    // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html 
    // In the previous versions, MSBs of the seed affected only MSBs of the 
    // state x[]. 
    const UIntType mask = ~0u; 
    x[0] = value & mask; 
    for (i = 1; i < n; i++) { 
     // See Knuth "The Art of Computer Programming" Vol. 2, 3rd ed., page 106 
     x[i] = (1812433253UL * (x[i-1]^(x[i-1] >> (w-2))) + i) & mask; 
    } 
    } 

Para mt19937 UIntType es uint32_t, se w 32. Para las semillas de 64 bits, tal vez usted podría utilizar los 32 bits inferiores para calcular todos los índices incluso del estado (x) y los 32 bits más altos para calcular los índices impares del estado, usando ese algoritmo.

(Esta es la carga sugerencia de culto sin embargo)

Cuestiones relacionadas