¿Servirán dos millones de puntos por segundo?
La distribución es simétrica: sólo tenemos que calcular la distribución para un octavo del círculo completo y luego copiarla alrededor de los otros octantes. En coordenadas polares $(r,\theta)$ la distribución acumulativa del ángulo $\Theta$ para la ubicación aleatoria $(X,Y)$ en el valor $\theta$ viene dada por el área entre el triángulo $(0,0), (1,0), (1,\tan\theta)$ y el arco del círculo que se extiende desde $(1,0)$ a $(\cos\theta,\sin\theta)$ . Por lo tanto, es proporcional a
$$F_\Theta(\theta) = \Pr(\Theta \le \theta) \propto \frac{1}{2}\tan(\theta) - \frac{\theta}{2},$$
por lo que su densidad es
$$f_\Theta(\theta) = \frac{d}{d\theta} F_\Theta(\theta) \propto \tan^2(\theta).$$
Podemos muestrear a partir de esta densidad utilizando, por ejemplo, un método de rechazo (que tiene una eficiencia $8/\pi-2 \approx 54.6479\%$ ).
La densidad condicional de la coordenada radial $R$ es proporcional a $rdr$ entre $r=1$ y $r=\sec\theta$ . Eso se puede muestrear con una fácil inversión de la FCD.
Si generamos muestras independientes $(r_i,\theta_i)$ , conversión de nuevo a coordenadas cartesianas $(x_i,y_i)$ muestra este octante. Dado que las muestras son independientes, el intercambio aleatorio de las coordenadas produce una muestra aleatoria independiente del primer cuadrante, tal como se desea. (Los intercambios aleatorios requieren la generación de una sola variable binomial para determinar cuántas de las realizaciones hay que intercambiar).
Cada una de estas realizaciones de $(X,Y)$ requiere, por término medio, una variante uniforme (para $R$ ) y además $1/(8\pi-2)$ por dos variantes uniformes (para $\Theta$ ) y una pequeña cantidad de cálculos (rápidos). Es decir $4/(\pi-4) \approx 4.66$ variantes por punto (que, por supuesto, tiene dos coordenadas). Los detalles completos se encuentran en el ejemplo de código más abajo. Esta figura muestra 10.000 de los más de medio millón de puntos generados.
Aquí está el R
código que produjo esta simulación y la cronometró.
n.sim <- 1e6
x.time <- system.time({
# Generate trial angles `theta`
theta <- sqrt(runif(n.sim)) * pi/4
# Rejection step.
theta <- theta[runif(n.sim) * 4 * theta <= pi * tan(theta)^2]
# Generate radial coordinates `r`.
n <- length(theta)
r <- sqrt(1 + runif(n) * tan(theta)^2)
# Convert to Cartesian coordinates.
# (The products will generate a full circle)
x <- r * cos(theta) #* c(1,1,-1,-1)
y <- r * sin(theta) #* c(1,-1,1,-1)
# Swap approximately half the coordinates.
k <- rbinom(1, n, 1/2)
if (k > 0) {
z <- y[1:k]
y[1:k] <- x[1:k]
x[1:k] <- z
}
})
message(signif(x.time[3] * 1e6/n, 2), " seconds per million points.")
#
# Plot the result to confirm.
#
plot(c(0,1), c(0,1), type="n", bty="n", asp=1, xlab="x", ylab="y")
rect(-1, -1, 1, 1, col="White", border="#00000040")
m <- sample.int(n, min(n, 1e4))
points(x[m],y[m], pch=19, cex=1/2, col="#0000e010")
6 votos
Sugerencia : Utiliza la simetría para duplicar trivialmente tu eficiencia.
3 votos
Oh, como: si el valor es (0,0), este puede ser mapeado a (1,1)? Me encanta esa idea
0 votos
@cardinal ¿No debería ser 4x la eficiencia? Puedes hacer una muestra en $[0,\ldots,1] \times [0,\ldots,1]$ y luego reflejarlo a través del eje x, el eje y y el origen.
1 votos
@Martin: A través de las cuatro regiones simétricas, tienes solapamiento, que tienes que tratar con más cuidado.
0 votos
@cardinal: Puede que esté denso, pero ¿el solapamiento no es sólo exactamente el eje x y el eje y, que juntos tienen un área de $0$ ?
0 votos
No veo cómo es relevante para la eficiencia, ya que golpeas la zona de solapamiento con la probabilidad $0$ (ignorando la discretización).
0 votos
@Martin: Puede ser que no esté entendiendo bien tu sugerencia. Tenga en cuenta que puede aceptar trivialmente los puntos siguientes $y = 1 - \sqrt{1-(1-x)^2}$ y reflejarlos para duplicar su eficacia, ya que esta región es completamente disjunta de la del PO. Pero, si se quiere considerar también los puntos "por encima" $y = \sqrt{1-(1-x)^2}$ entonces esa región se cruza con cada una de las dos regiones mencionadas. Por lo tanto, si $(x,y)$ cae en una de esas intersecciones (¡área positiva!), hay que manejar cómo hacer la reflexión para esa región adecuadamente para mantener la propiedad de área igual del muestreo resultante.
0 votos
@cardinal Mi idea era probar un punto $p = (x,y)$ donde muestreamos $x$ y $y$ de una distribución uniforme sobre $[0,\ldots,1]$ . Entonces podemos calcular $y_{circle} = \sqrt{1 - x^2}$ . Si $y_{circle} < y$ , $y$ forma parte de la zona azul, si $y_{circle} \geq y$ , $y$ no forma parte de la zona azul. Dado que $p$ forma parte de la zona azul o no, podemos deducir que $p_{mirror\_x} = (-x,y)$ , $p_{mirror\_y} = (x,-y)$ y $p_{mirror\_origin} = (-x,-y)$ comparten la misma propiedad, por lo que la eficiencia es 4x.
0 votos
Los puntos donde $x$ o $y$ sería 0, es decir, los ejes, darían lugar a una eficiencia inferior a 4x, pero como los golpeamos con probabilidad $0$ no cambiaría la eficiencia global de 4x. Esa era mi línea de pensamiento.
3 votos
@Martin: Si estoy entendiendo lo que describes, eso no aumenta la eficiencia en absoluto . (Has encontrado un punto, y ahora conoces otros tres -en un área cuatro veces mayor- que se encuentran o no dentro del disco unitario con probabilidad uno según si $(x,y)$ lo hace. ¿Cómo ayuda eso?) El objetivo de aumentar la eficiencia es aumentar la probabilidad de aceptación de cada $(x,y)$ generado. ¿Quizás soy yo el que está siendo denso?
0 votos
@cardinal. Ah, vale, ahora lo entiendo. Gracias. Sí, tienes razón. Me refería a que esto es 4 veces más eficiente que el muestreo en $[-1,\ldots,1] \times [-1,\ldots,1]$ ya que cada muestra daría 4 puntos en lugar de 1. Pero, por supuesto, no cambia la probabilidad de la aceptación en sí.