Supongamos que tengo un dado cargado de n lados donde cada lado k tiene alguna probabilidad p k de aparecer cuando lo saco. Tengo curiosidad por saber si hay un buen algoritmo para almacenar esta información estáticamente (es decir, para un conjunto fijo de probabilidades) para poder simular de manera eficiente una tirada aleatoria del dado.
Actualmente, tengo una solución O (lg n) para este problema. La idea es almacenar una tabla de la probabilidad acumulativa de los primeros k lados para todos los k, generar un número real aleatorio en el rango [0, 1) y realizar una búsqueda binaria sobre la tabla para obtener el índice más grande cuyo acumulado el valor no es mayor que el valor elegido. Prefiero esta solución, pero parece extraño que el tiempo de ejecución no tenga en cuenta las probabilidades. En particular, en los casos extremos de un lado que siempre aparece o que los valores se distribuyen uniformemente, es posible generar el resultado del rollo en O (1) usando un enfoque ingenuo, aunque mi solución aún tomará muchos pasos logarítmica.
¿Alguien tiene alguna sugerencia sobre cómo resolver este problema de una manera que sea de alguna manera "adaptativa" en su tiempo de ejecución?
EDITAR : Basado en las respuestas a esta pregunta, he escrito un artículo que describe muchos enfoques a este problema , junto con sus análisis. Parece que la implementación de Vose del método de alias da time (n) tiempo de preprocesamiento y O (1) tiempo por tirada, lo cual es realmente impresionante. ¡Ojalá sea una adición útil a la información contenida en las respuestas!
fuente
Respuestas:
Está buscando el método de alias que proporciona un método O (1) para generar una distribución de probabilidad discreta fija (suponiendo que puede acceder a las entradas en una matriz de longitud n en tiempo constante) con una configuración única de O (n) . Puede encontrarlo documentado en el capítulo 3 (PDF) de "Generación de varianza aleatoria no uniforme" de Luc Devroye.
La idea es tomar su conjunto de probabilidades p k y producir tres nuevos conjuntos de elementos n, q k , a k y b k . Cada q k es una probabilidad entre 0 y 1, y cada a k y b k es un número entero entre 1 y n.
Generamos números aleatorios entre 1 yn generando dos números aleatorios, rys, entre 0 y 1. Sea i = floor (r * N) +1. Si q i <s, entonces devuelve a i else return b i . El trabajo en el método de alias es descubrir cómo producir q k , a k y b k .
fuente
n
número de números aleatorios a generar debido a factores constantes involucrados en la implementación de algoritmos.Utilice un árbol de búsqueda binario equilibrado (o búsqueda binaria en una matriz) y obtenga la complejidad O (log n). Tenga un nodo para cada resultado de dado y haga que las claves sean el intervalo que activará ese resultado.
Lo bueno de esta solución es que es muy simple de implementar pero aún tiene buena complejidad.
fuente
Estoy pensando en granular tu mesa.
En lugar de tener una tabla con el valor acumulado para cada valor de dado, podría crear una matriz entera de longitud xN, donde x es idealmente un número alto para aumentar la precisión de la probabilidad.
Rellene esta matriz utilizando el índice (normalizado por xN) como el valor acumulativo y, en cada 'ranura' en la matriz, almacene la posible tirada de dados si aparece este índice.
Tal vez podría explicar más fácilmente con un ejemplo:
Usando tres dados: P (1) = 0.2, P (2) = 0.5, P (3) = 0.3
Cree una matriz, en este caso elegiré una longitud simple, digamos 10. (es decir, x = 3.33333)
Luego, para obtener la probabilidad, simplemente aleatorice un número entre 0 y 10 y simplemente acceda a ese índice.
Este método puede perder precisión, pero aumentar xy la precisión será suficiente.
fuente
Hay muchas formas de generar un número entero aleatorio con una distribución personalizada (también conocida como distribución discreta ). La elección depende de muchas cosas, incluido el número de números enteros para elegir, la forma de la distribución y si la distribución cambiará con el tiempo.
Una de las formas más simples de elegir un número entero con una función de peso personalizada
f(x)
es el método de muestreo de rechazo . Lo siguiente supone que el valor más alto posible def
esmax
. La complejidad del tiempo para el muestreo de rechazo es constante en promedio, pero depende en gran medida de la forma de la distribución y tiene el peor de los casos de ejecución para siempre. Para elegir un número entero en [1,k
] usando el muestreo de rechazo:i
en [1,k
].f(i)/max
, regresoi
. De lo contrario, vaya al paso 1.Otros algoritmos tienen un tiempo de muestreo promedio que no depende en gran medida de la distribución (generalmente constante o logarítmica), pero a menudo requieren que precalcule los pesos en un paso de configuración y los almacene en una estructura de datos. Algunos de ellos también son económicos en términos de la cantidad de bits aleatorios que usan en promedio. Muchos de estos algoritmos se introdujeron después de 2011, e incluyen:
Otros algoritmos incluyen el método de alias (ya mencionado en su artículo), el algoritmo Knuth-Yao, la estructura de datos MVN y más. Consulte mi sección " Una nota sobre algoritmos de elección ponderada " para una encuesta.
fuente