El Mersenne Twister fue diseñado específicamente para corregir la mayoría de los defectos encontrados en los PRNG más antiguos.
La versión más utilizada del algoritmo Mersenne Twister se basa en el primo de Mersenne . La implementación estándar de este, MT19937, utiliza una longitud de palabra de 32 bits . Existe otra implementación (con cinco variantes [3] ) que utiliza una longitud de palabra de 64 bits, MT19937-64; genera una secuencia diferente.
a-distribución
Se dice que una secuencia pseudoaleatoria de números enteros de w bits de período P tiene una distribución k con una precisión de v bits si se cumple lo siguiente.
Sea trunc v ( x ) el número formado por los v bits iniciales de x y considere P de los k vectores de v bits
.
Entonces, cada una de las posibles combinaciones de bits ocurre la misma cantidad de veces en un período, excepto la combinación de todos ceros, que ocurre una vez menos.
Detalle algorítmico
Para una longitud de palabra de w bits, Mersenne Twister genera números enteros en el rango .
El algoritmo general se caracteriza por las siguientes cantidades:
w : tamaño de la palabra (en número de bits)
n : grado de recurrencia
m : palabra intermedia, un desplazamiento utilizado en la relación de recurrencia que define la serie ,
r : punto de separación de una palabra, o el número de bits de la máscara de bits inferior,
a : coeficientes de la matriz de torsión en forma normal racional
b , c : máscaras de bits de templado TGFSR(R)
s , t : TGFSR(R) cambios de bits de templado
u , d , l : cambios/máscaras adicionales de las brocas de templado Mersenne Twister
con la restricción de que sea un primo de Mersenne. Esta elección simplifica la prueba de primitividad y la prueba de distribución k que se necesitan en la búsqueda de parámetros.
La serie se define como una serie de cantidades de w -bits con la relación de recurrencia:
donde denota la concatenación de vectores de bits (con los bits superiores a la izquierda), la operación exclusiva bit a bit (XOR), significa los w − r bits superiores de , y significa los r bits inferiores de .
Todos los subíndices pueden compensarse con -n
donde ahora el LHS, , es el siguiente valor generado en la serie en términos de valores generados en el pasado, que están en el RHS.
La transformación de torsión A se define en forma normal racional como:
con como matriz identidad. La forma normal racional tiene la ventaja de que la multiplicación por A se puede expresar de manera eficiente como: (recuerde que aquí la multiplicación de matrices se realiza en , y por lo tanto, la operación XOR bit a bit reemplaza a la suma) donde es el bit de orden más bajo de .
Al igual que TGFSR(R), el Mersenne Twister se combina en cascada con una transformación de templado para compensar la dimensionalidad reducida de la equidistribución (debido a la elección de que A esté en la forma normal racional). Nótese que esto es equivalente a usar la matriz A, donde T es una matriz invertible y, por lo tanto, el análisis del polinomio característico mencionado a continuación aún se cumple.
Al igual que con A , elegimos una transformación de templado que sea fácilmente computable y, por lo tanto, no construimos realmente T. Este templado se define en el caso de Mersenne Twister como
donde es el siguiente valor de la serie, es un valor intermedio temporal y es el valor devuelto por el algoritmo, con y como los desplazamientos a la izquierda y a la derecha bit a bit y como el AND bit a bit . La primera y la última transformada se añaden para mejorar la equidistribución de los bits inferiores. A partir de la propiedad de TGFSR, se requiere alcanzar el límite superior de la equidistribución para los bits superiores.
Los coeficientes para MT19937 son:
Tenga en cuenta que las implementaciones de 32 bits del Mersenne Twister generalmente tienen d = FFFFFFFF 16. Como resultado, la d se omite ocasionalmente de la descripción del algoritmo, ya que el y bit a bit con d en ese caso no tiene efecto.
Los coeficientes para MT19937-64 son: [5]
Inicialización
El estado necesario para la implementación de Mersenne Twister es una matriz de n valores de w bits cada uno. Para inicializar la matriz, se utiliza un valor de semilla de w bits para proporcionarlo mediante la configuración del valor de semilla y, a continuación, la configuración
para desde hasta .
El primer valor que genera el algoritmo se basa en , no en .
La constante f forma otro parámetro para el generador, aunque no es parte del algoritmo propiamente dicho.
El valor de f para MT19937 es 1812433253.
El valor de f para MT19937-64 es 6364136223846793005. [5]
Código C
#include <stdint.h>#define n 624 #define m 397 #define w 32 #define r 31 #define UMASK (0xffffffffUL << r) #define LMASK (0xffffffffUL >> (wr)) #define a 0x9908b0dfUL #define u 11 #define s 7 #define t 15 #define l 18 #define b 0x9d2c5680UL #define c 0xefc60000UL #define f 1812433253ULtypedef struct { uint32_t state_array [ n ]; // la matriz para el vector de estado int state_index ; // índice en la matriz de vectores de estado, 0 <= state_index <= n-1 siempre } mt_state ;void initialize_state ( mt_state * state , uint32_t seed ) { uint32_t * state_array = & ( state -> state_array [ 0 ]); state_array [ 0 ] = seed ; // seed inicial sugerida = 19650218UL para ( int i = 1 ; i < n ; i ++ ) { seed = f * ( seed ^ ( seed >> ( w -2 ))) + i ; // Knuth TAOCP Vol2. 3ra Ed. P.106 para multiplicador. state_array [ i ] = seed ; } state -> state_index = 0 ; }uint32_t random_uint32 ( mt_state * state ) { uint32_t * state_array = & ( state -> state_array [ 0 ]); int k = state -> state_index ; // apunta a la ubicación del estado actual // 0 <= state_index <= n-1 always // int k = k - n; // apunta al estado n iteraciones antes // if (k < 0) k += n; // indexación circular módulo n // las 2 líneas anteriores en realidad no hacen nada // solo a modo ilustrativo int j = k - ( n -1 ); // apunta al estado n-1 iteraciones antes if ( j < 0 ) j += n ; // indexación circular módulo nuint32_t x = ( state_array [ k ] & UMASK ) | ( state_array [ j ] & LMASK ); uint32_t xA = x >> 1 ; if ( x & 0x00000001UL ) xA ^= a ; j = k - ( n - m ); // apuntar al estado nm iteraciones antes if ( j < 0 ) j += n ; // indexación circular módulo n x = state_array [ j ] ^ xA ; // calcular el siguiente valor en el estado state_array [ k ++ ] = x ; // actualizar el nuevo valor del estado if ( k >= n ) k = 0 ; // indexación circular módulo n state -> state_index = k ; uint32_t y = x ^ ( x >> u ); // atenuación y = y ^ (( y << s ) & b ); y = y ^ (( y << t ) & c ); uint32_t z = y ^ ( y >> l ); devolver z ; }
La transformación de torsión mejora el GFSR clásico con las siguientes propiedades clave:
El período alcanza el límite superior teórico (excepto si se inicializa con 0)
Equidistribución en n dimensiones (por ejemplo, los generadores congruenciales lineales pueden, en el mejor de los casos, gestionar una distribución razonable en cinco dimensiones)
MTGP es una variante de Mersenne Twister optimizada para unidades de procesamiento gráfico publicada por Mutsuo Saito y Makoto Matsumoto. [8] Las operaciones de recurrencia lineal básicas se extienden desde MT y los parámetros se eligen para permitir que muchos subprocesos calculen la recursión en paralelo, mientras comparten su espacio de estado para reducir la carga de memoria. El documento afirma una equidistribución mejorada sobre MT y un rendimiento en una GPU antigua (de la era de 2008) ( Nvidia GTX260 con 192 núcleos) de 4,7 ms para 5 × 10 7 números enteros aleatorios de 32 bits.
Tiene una recuperación más rápida del estado inicial de exceso cero que MT, pero más lenta que WELL.
Admite varios periodos desde 2 607 − 1 hasta 2 216091 − 1.
SFMT es compatible con Intel SSE2 y PowerPC AltiVec. También se utiliza para juegos con Cell BE en PlayStation 3. [ 11]
TinyMT es una variante de Mersenne Twister, propuesta por Saito y Matsumoto en 2011. [12] TinyMT utiliza solo 127 bits de espacio de estado, una disminución significativa en comparación con los 2,5 KiB de estado del original. Sin embargo, tiene un período de , mucho más corto que el original, por lo que los autores solo lo recomiendan en casos en los que la memoria es un bien escaso.
Pasa numerosas pruebas de aleatoriedad estadística, incluidas las pruebas Diehard y la mayoría, pero no todas, las pruebas TestU01 . [13]
Un período muy largo de . Tenga en cuenta que, si bien un período largo no es una garantía de calidad en un generador de números aleatorios, los períodos cortos, como los que son comunes en muchos paquetes de software antiguos, pueden ser problemáticos. [14]
k-distribuido con una precisión de 32 bits para cada (para una definición de k -distribuido, consulte a continuación)
Búfer de estado relativamente grande, de casi 2,5 kB , a menos que se utilice la variante TinyMT.
Rendimiento mediocre según los estándares modernos, a menos que se utilice la variante SFMT (que se analiza a continuación). [16]
Presenta dos fallas claras (complejidad lineal) tanto en Crush como en BigCrush en la suite TestU01. La prueba, al igual que Mersenne Twister, se basa en un álgebra. [13]
Las instancias múltiples que difieren solo en el valor inicial (pero no en otros parámetros) generalmente no son apropiadas para simulaciones de Monte Carlo que requieren generadores de números aleatorios independientes, aunque existe un método para elegir múltiples conjuntos de valores de parámetros. [17] [18]
Difusión deficiente: puede llevar mucho tiempo comenzar a generar una salida que pase las pruebas de aleatoriedad , si el estado inicial es altamente no aleatorio, particularmente si el estado inicial tiene muchos ceros. Una consecuencia de esto es que dos instancias del generador, iniciadas con estados iniciales que son casi iguales, generalmente generarán casi la misma secuencia durante muchas iteraciones, antes de divergir finalmente. La actualización de 2002 del algoritmo MT ha mejorado la inicialización, por lo que comenzar con un estado así es muy poco probable. [19] Se dice que la versión GPU (MTGP) es incluso mejor. [20]
Contiene subsecuencias con más 0 que 1. Esto se suma a la pobre propiedad de difusión y dificulta la recuperación de estados con muchos ceros.
No es criptográficamente seguro , a menos que se utilice la variante CryptMT (que se analiza a continuación). La razón es que observar una cantidad suficiente de iteraciones (624 en el caso de MT19937, ya que este es el tamaño del vector de estado a partir del cual se producen las iteraciones futuras) permite predecir todas las iteraciones futuras.
Aplicaciones
El Mersenne Twister se utiliza como PRNG predeterminado por el siguiente software:
Lenguajes de programación: Dyalog APL , [21] IDL , [22] R , [23] Ruby , [24] Free Pascal , [25] PHP , [26] Python (también disponible en NumPy , sin embargo, el valor predeterminado se cambió a PCG64 a partir de la versión 1.17 [27] ), [28] [29] [30] CMU Common Lisp , [31] Embeddable Common Lisp , [32] Steel Bank Common Lisp , [33] Julia (hasta Julia 1.6 LTS, aún disponible en versiones posteriores, pero se usa un RNG mejor/más rápido de manera predeterminada a partir de la versión 1.7) [34]
Mersenne Twister es uno de los dos PRNG en SPSS : el otro generador se mantiene solo por compatibilidad con programas más antiguos, y se afirma que Mersenne Twister es "más confiable". [54] Mersenne Twister es de manera similar uno de los PRNG en SAS : los otros generadores son más antiguos y están obsoletos. [55] Mersenne Twister es el PRNG predeterminado en Stata , el otro es KISS , por compatibilidad con versiones anteriores de Stata. [56]
Alternativas
Un generador alternativo, WELL ("Well Equidistributed Long-period Linear"), ofrece una recuperación más rápida, una aleatoriedad igual y una velocidad casi igual. [57]
Los MELG de 64 bits ("Generadores lineales máximamente equidistribuidos de 64 bits con período primo de Mersenne") están completamente optimizados en términos de las propiedades de distribución k . [59]
La familia ACORN (publicada en 1989) es otro PRNG distribuido en k , que muestra una velocidad computacional similar a MT y mejores propiedades estadísticas ya que satisface todos los criterios actuales (2019) de TestU01; cuando se usa con opciones apropiadas de parámetros, ACORN puede tener un período y una precisión arbitrariamente largos.
La familia PCG es un generador de período largo más moderno, con mejor localidad de caché y un sesgo menos detectable utilizando métodos de análisis modernos. [60]
Referencias
^ Matsumoto, M.; Nishimura, T. (1998). "Tornado de Mersenne: un generador de números pseudoaleatorios uniforme equidistribuido de 623 dimensiones". ACM Transactions on Modeling and Computer Simulation . 8 (1): 3–30. CiteSeerX 10.1.1.215.1141 . doi :10.1145/272991.272995. S2CID 3332028.
^ Por ejemplo, Marsland S. (2011) Machine Learning ( CRC Press ), §4.1.1. Véase también la sección "Adopción en sistemas de software".
^ John Savard. "El Mersenne Twister". Un artículo posterior, publicado en el año 2000, proporcionó cinco formas adicionales del Mersenne Twister con período 2^19937-1. Las cinco fueron diseñadas para implementarse con aritmética de 64 bits en lugar de 32 bits.
^ Matsumoto, M.; Kurita, Y. (1992). "Generadores GFSR retorcidos". ACM Transactions on Modeling and Computer Simulation . 2 (3): 179–194. doi :10.1145/146382.146383. S2CID 15246234.
^ ab "std::mersenne_twister_engine". Generación de números pseudoaleatorios . Consultado el 20 de julio de 2015 .
^ ab "CryptMt y Fubuki". eCRYPT . Archivado desde el original el 1 de julio de 2012 . Consultado el 12 de noviembre de 2017 .
^ Mutsuo Saito; Makoto Matsumoto (2010). "Variantes de Mersenne Twister adecuadas para procesadores gráficos". arXiv : 1005.4973v3 [cs.MS].
^ "Tornado rápido de Mersenne orientado a SIMD (SFMT)". hiroshima-u.ac.jp . Consultado el 4 de octubre de 2015 .
^ "SFMT: Comparación de velocidad". hiroshima-u.ac.jp . Consultado el 4 de octubre de 2015 .
^ "Licencia de PlayStation3". scei.co.jp . Consultado el 4 de octubre de 2015 .
^ "Tiny Mersenne Twister (TinyMT)". hiroshima-u.ac.jp . Consultado el 4 de octubre de 2015 .
^ ab P. L'Ecuyer y R. Simard, "TestU01: "Biblioteca AC para pruebas empíricas de generadores de números aleatorios", ACM Transactions on Mathematical Software , 33, 4, artículo 22 (agosto de 2007).
^ Nota: 2 19937 es aproximadamente 4,3 × 10 6001 ; esto es muchos órdenes de magnitud mayor que el número estimado de partículas en el universo observable , que es 10 87 .
^ Route, Matthew (10 de agosto de 2017). "Síntesis de población de enanas ultrafrías con llamaradas de radio". The Astrophysical Journal . 845 (1): 66. arXiv : 1707.02212 . Bibcode :2017ApJ...845...66R. doi : 10.3847/1538-4357/aa7ede . S2CID 118895524.
^ "Fast Mersenne Twister (SFMT) orientado a SIMD: dos veces más rápido que Mersenne Twister". Sociedad Japonesa para la Promoción de la Ciencia . Consultado el 27 de marzo de 2017 .
^ Makoto Matsumoto; Takuji Nishimura. "Creación dinámica de generadores de números pseudoaleatorios" (PDF) . Consultado el 19 de julio de 2015 .
^ Hiroshi Haramoto; Makoto Matsumoto; Takuji Nishimura; François Panneton; Pierre L'Ecuyer. "Salto eficiente para generadores de números aleatorios lineales F2" (PDF) . Consultado el 12 de noviembre de 2015 .
^ "mt19937ar: Mersenne Twister con inicialización mejorada". hiroshima-u.ac.jp . Consultado el 4 de octubre de 2015 .
^ Fog, Agner (1 de mayo de 2015). "Generadores de números pseudoaleatorios para procesadores vectoriales y procesadores multinúcleo". Journal of Modern Applied Statistical Methods . 14 (1): 308–334. doi : 10.22237/jmasm/1430454120 .
^ "Enlace aleatorio". Guía de referencia del lenguaje Dyalog . Consultado el 4 de junio de 2020 .
^ "RANDOMU (referencia IDL)". Centro de documentación de Exelis VIS . Consultado el 23 de agosto de 2013 .
^ "Generadores de números aleatorios". Vista de tareas de CRAN: distribuciones de probabilidad . Consultado el 29 de mayo de 2012 .
^ "Documentación de la clase "Random"". Documentación de Ruby 1.9.3 . Consultado el 29 de mayo de 2012 .
^ "random". documentación de free pascal . Consultado el 28 de noviembre de 2013 .
^ "mt_rand — Generar un valor aleatorio mejor". Manual de PHP . Consultado el 2 de marzo de 2016 .
^ "Notas de la versión de NumPy 1.17.0: Manual de NumPy v1.21". numpy.org . Consultado el 29 de junio de 2021 .
^ "9.6 random — Generar números pseudoaleatorios". Documentación de Python v2.6.8 . Consultado el 29 de mayo de 2012 .
^ "8.6 random — Generar números pseudoaleatorios". Documentación de Python v3.2 . Consultado el 29 de mayo de 2012 .
^ "random — Generar números pseudoaleatorios — Documentación de Python 3.8.3". Documentación de Python 3.8.3 . Consultado el 23 de junio de 2020 .
^ "Opciones de diseño y extensiones". Manual del usuario de CMUCL . Consultado el 3 de febrero de 2014 .
^ "Estados aleatorios". El manual de ECL . Consultado el 20 de septiembre de 2015 .
^ "Generación de números aleatorios". Manual del usuario de SBCL .
^ "Números aleatorios · El lenguaje Julia". docs.julialang.org . Consultado el 21 de junio de 2022 .
^ "Números aleatorios: Manual de referencia de GLib".
^ "Algoritmos de números aleatorios". GNU MP . Consultado el 21 de noviembre de 2013 .
^ "16.3 Matrices de utilidad especial". GNU Octave . Función incorporada: rand
^ "Variables de entorno de números aleatorios". Biblioteca científica GNU . Consultado el 24 de noviembre de 2013 .
^ Mélard, G. (2014), "Sobre la precisión de los procedimientos estadísticos en Microsoft Excel 2010", Computational Statistics , 29 (5): 1095–1128, CiteSeerX 10.1.1.455.5508 , doi :10.1007/s00180-014-0482-5, S2CID 54032450 .
^ "Referencia del lenguaje GAUSS 14" (PDF) .
^ "uniforme". Referencia de funciones de Gretl .
^ "Nuevo generador de números aleatorios: Mersenne Twister de 64 bits".
^ "Distribuciones de probabilidad — Manual de referencia de Sage v7.2: Probabilidad".
^ "grand - Números aleatorios". Ayuda de Scilab .
^ "generador de números aleatorios". Ayuda en línea de Maple . Consultado el 21 de noviembre de 2013 .
^ "Algoritmos generadores de números aleatorios". Centro de documentación, MathWorks .
^ "Generación de datos". Guía del usuario de Apache Commons Math .
^ "Generación de números aleatorios en C++11" (PDF) . Fundamentos de C++ estándar .
^ "std::mersenne_twister_engine". Generación de números pseudoaleatorios . Consultado el 25 de septiembre de 2012 .
^ [1] Documentación de Mathematica
^ "boost/random/mersenne_twister.hpp". Bibliotecas Boost C++ . Consultado el 29 de mayo de 2012 .
^ "Descripción general de la API del host". Documentación del kit de herramientas CUDA . Consultado el 2 de agosto de 2016 .
^ "G05 – Generadores de números aleatorios". Capítulo Introducción de la Biblioteca NAG . Consultado el 29 de mayo de 2012 .
^ "Generadores de números aleatorios". IBM SPSS Statistics . Consultado el 21 de noviembre de 2013 .
^ "Uso de funciones de números aleatorios". Referencia del lenguaje SAS . Consultado el 21 de noviembre de 2013 .
^ Ayuda de Stata: set rng - Establece qué generador de números aleatorios (RNG) utilizar
^ "Generadores xorshift*/xorshift+ y el tiroteo PRNG".
^ Harase, S.; Kimoto, T. (2018). "Implementación de generadores lineales F2 de distribución máxima equidistribuida de 64 bits con período primo de Mersenne". ACM Transactions on Mathematical Software . 44 (3): 30:1–30:11. arXiv : 1505.06582 . doi :10.1145/3159444. S2CID 14923086.
^ "El documento del PCG". 27 de julio de 2017.
Lectura adicional
Harase, S. (2014), "Sobre las relaciones lineales de los generadores de números pseudoaleatorios Mersenne Twister", Mathematics and Computers in Simulation , 100 : 103–113, arXiv : 1301.5435 , doi : 10.1016/j.matcom.2014.02.002, S2CID 6984431.
Harase, S. (2019), "Conversión de Mersenne Twister a números de punto flotante de doble precisión", Mathematics and Computers in Simulation , 161 : 76–83, arXiv : 1708.06018 , doi : 10.1016/j.matcom.2018.08.006, S2CID 19777310.
Enlaces externos
El artículo académico de MT y artículos relacionados de Makoto Matsumoto
Página de inicio de Mersenne Twister, con códigos en C, Fortran, Java, Lisp y algunos otros lenguajes
Ejemplos de Mersenne Twister: una colección de implementaciones de Mersenne Twister en varios lenguajes de programación, en GitHub
SFMT en acción: Parte I – Generación de una DLL que incluya soporte SSE2 – en Code Project