Problema 1

Estimación del valor de \(\pi\)

La siguiente figura sugiere como estimar el valor de \(\pi\) con una simulación.

En la figura, un circuito con un área igual a \(\frac{\pi}{4}\), está inscrito en un cuadrado cuya área es igual a 1. Se elige de forma aleatoria n puntos dentro del cuadrado. La probabilidad de que un punto esté dentro del círculo es igual a la fracción del área del cuadrado que abarca a este, la cual es \(\frac{\pi}{4}\). Por tanto, se puede estimar el valor de \(\frac{\pi}{4}\) al contar el número de puntos dentro del círculo, para obtener la estimación de \(\frac{\pi}{4}\). De este último resultado se encontrar una aproximación para el valor de \(\pi\).

Pasos sugeridos:

  1. Genere n coordenadas \(x: x_1, \dots, x_n\). Utilice la distribución uniforme con valor mínimo de 0 y valor máximo de 1. La distribución uniforme genera variables aleatorias que tienen la misma probabilidad de venir de cualquier parte del intervalo \((0,1)\).
  2. Genere 1000 coordenadas \(y: y_1,\dots, y_n\), utilizando nuevamente la distribución uniforme con valor mínimo de 0 y valor máximo de 1.
  3. Cada punto \((x_i\),\(y_i)\) se encuentra dentro del círculo si su distancia desde el centro \((0.5,0.5)\) es menor a 0.5. Para cada par \((x_i\),\(y_i)\) determine si la distancia desde el centro es menor a 0.5. Esto último se puede realizar al calcular el valor \((x_i−0.5)^2+(y_i−0.5)^2\), que es el cuadrado de la distancia, y al determinar si es menor que 0.25.
  4. ¿Cuántos de los puntos están dentro del círculo? ¿Cuál es su estimación de \(\pi\)?

Nota

  • Con sólo 1000 puntos, es probable que la estimación presente un error de 0.05 o más. Una simulación con 10000 y 100000 puntos tiene mayores probabilidades de dar como resultado una estimación muy cercana al valor verdadero.
  • Funciones recomendadas : runif(), funtion(){}
  • Entregable : enlace en RPubs con informe 1
  • Problema tomado de Navidi(2006)

Desarrollo

Se nos presentan 2 figuras geométricas concéntricas, un cuadrado rectángulo y un círculo. El área del cuadrado es base x altura, y la del círculo es \(\pi r^2\). El radio mide 0,5, luego cada lado del cuadrado es 2 x 0,5, es decir 1. Las áreas serían: * Área Círculo: \(\pi r^2 = \pi(0,5)^2 = 0,7854\) * Área Cuadrado: base x altura \(= (2r)*(2r) = 4r^2 = 4 * 0,5^2 = 4 * 0,25 = 1\)

Como se quiere calcular la probabilidad de que un punto esté dentro del circulo (siendo la superficie del cuadrado la superficie en donde se encuentran todos los puntos), esta sería la razón del área del círculo y del área del cuadrado. Entonces,

  • Área círculo / Área cuadrado = \(\frac{\pi r^2}{4r^2} = \frac{\pi}{4}\)

Se realizarán los pasos mencionados en el siguiente código:

# Function to estimate the value of π
estimation_of_pi <- function(iterations = 1000, seed = 689){
  set.seed(seed)
  # [iterations] values to each coordinate (x,y) in a uniform distribution for numbers between 0 and 1 (Inside the area of the square)
  # step 1 and 2
  x <- runif(iterations, min = 0, max = 1) 
  y <- runif(iterations, min = 0, max = 1)
  # step 3. Separation from the center of the circle (0.5,0.5)
  point <- (x - 0.5)^2 + (y - 0.5)^2
  # The point is inside the circle if _point_ is smaller than 0.25
  reference = 0.25
  inside_the_circle <- which(point <= reference) 
  # step 4. Number of points within the circle
  number_of_points <- length(inside_the_circle)
  # Estimation of π is 4 * inside_the_circle
  estimated_pi <- 4 * number_of_points / iterations 
  
  #cat("Percentage of points inside the circle:", number_of_points/iterations*100,"%")
  
  return(estimated_pi)
}

Revisión del método

Se sabe que \(\pi\) = 3.1415926535. Probemos la lógica utilizada con mil iteraciones (El valor establecido por defecto) para ver cuál es el valor estimado.

estimation_of_pi()
## [1] 3.172

Solo hay un decimal correcto. Todavía estamos lejos. Se sabe que para conjuntos de datos más numerosos, mejorará la estimación, entonces ejecutamos la función para valores más grandes:

number_of_iterations <- c(123456, 5123456, 99999999, 55999999)
res <- sapply(number_of_iterations, function(n)estimation_of_pi(iterations = n))
names(res) <- number_of_iterations
res
##   123456  5123456 99999999 55999999 
## 3.138381 3.141848 3.141654 3.141591

Tal como se puede ver en la tabla, el valor estimado de π se acerca al valor real entre más iteraciones se realicen.

Gráficamente se puede representar el cambio del valor de π pintándolo con cada número de iteraciones. Para esto, al ejecutar la función, debemos guardar el valor estimado de \(\pi\), para después poder usar todos sus valores estimados en una sola gráfica.

# Function to estimate the value of π
estimation_of_pi <- function(iterations = 1000, seed = 689){
  set.seed(seed)
  # store the values in a data frame
  df <- data.frame(x <- runif(n = iterations, min = 0, max = 1),
                   y <- runif(n = iterations, min = 0, max = 1))
  # store the number of iterations in the data frame
  df$iteration <- 1:iterations
  
  # count the number of points inside the circle
  reference = 0.25
  df$points_inside_circle <- ifelse (((x - 0.5)^2 + (y - 0.5)^2) <= reference, 1, 0)
  
  # Estimation of π is 4 * inside_the_circle
  df$estimated_pi <- 4 * cumsum(df$points_inside_circle) / df$iteration 
  
  return(df)
}

Con esta función, podemos generar los valores estimados de \(\pi\) de los primeros 100 mil puntos

pi_data <- estimation_of_pi(iterations = 100000)

# plot showing estimated pi as number of points increases
ggplot(pi_data, aes(x = iteration, y = estimated_pi)) +
            geom_line(col = "blue") +
            geom_hline(yintercept = pi, col = "darkgreen") +
            ylim(c(3, 3.3)) +
            labs(title = expression(paste("Aproximación de ", pi)),
                 x = "Cantidad de puntos",
                 y = expression(paste("Valor estimado de ",pi)))
## Warning: Removed 7 rows containing missing values (`geom_line()`).

Podemos ver que en la medida en que hay mas puntos, el valor estimado de π se acerca a su valor real!

LS0tDQpzdWJ0aXRsZTogIkFjdGl2aWRhZCAyLiBNw6l0b2RvcyB5IFNpbXVsYWNpw7NuIg0KdGl0bGU6ICJQcm9ibGVtYSAxIg0KYXV0aG9yOiAiRW5yaXF1ZSBKb3PDqSBQZcOxYSB5IExlYW5kcm8gTXXDsW96Ig0KZGF0ZTogIjIwMjQtMDMtMDQiDQpvdXRwdXQ6ICANCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICB0b2M6IGZhbHNlDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29sbGFwc2VkOiB0cnVlDQogICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICBoaWdobGlnaHQ6IGthdGUNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQpudW1iZXItc2VjdGlvbnM6IHRydWUNCi0tLQ0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gNSkNCg0KaWYoIXJlcXVpcmVOYW1lc3BhY2UoImdncGxvdDIiLCBxdWlldGx5ID0gVFJVRSkpew0KICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCn0NCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KDQojIFByb2JsZW1hIDENCiMjIEVzdGltYWNpw7NuIGRlbCB2YWxvciBkZSAkXHBpJA0KDQpMYSBzaWd1aWVudGUgZmlndXJhIHN1Z2llcmUgY29tbyBlc3RpbWFyIGVsIHZhbG9yIGRlICRccGkkIGNvbiB1bmEgc2ltdWxhY2nDs24uIA0KYGBge3IgZmlndXJlLCBlY2hvID0gRkFMU0V9DQogIGl0ZXJhdGlvbnMgPSAzMDAwDQogIHNldC5zZWVkKDY4OSkNCiAgcmVmZXJlbmNlID0gMC4yNQ0KICAjIHN0b3JlIHRoZSB2YWx1ZXMgaW4gYSBkYXRhIGZyYW1lDQogIGRmIDwtIGRhdGEuZnJhbWUoeHBvcyA8LSBydW5pZihuID0gaXRlcmF0aW9ucywgbWluID0gMCwgbWF4ID0gMSksDQogICAgICAgICAgICAgICAgICAgeXBvcyA8LSBydW5pZihuID0gaXRlcmF0aW9ucywgbWluID0gMCwgbWF4ID0gMSksDQogICAgICAgICAgICAgICAgICAgcGljIDwtIGlmZWxzZSAoKCh4cG9zIC0gMC41KV4yICsgKHlwb3MgLSAwLjUpXjIpIDw9IHJlZmVyZW5jZSwgMSwgMCkpDQogICMgc3RvcmUgdGhlIG51bWJlciBvZiBpdGVyYXRpb25zIGluIHRoZSBkYXRhIGZyYW1lDQogIGRmJGl0ZXJhdGlvbiA8LSAxOml0ZXJhdGlvbnMNCiAgDQogICMgRXN0aW1hdGlvbiBvZiDPgCBpcyA0ICogaW5zaWRlX3RoZV9jaXJjbGUNCiAgZGYkZXN0aW1hdGVkX3BpIDwtIDQgKiBjdW1zdW0oZGYkcGljKSAvIGRmJGl0ZXJhdGlvbiANCg0KICBnZ19jaXJjbGUgPC0gZnVuY3Rpb24ociwgeGMsIHljLCBjb2xvcj0icmVkIiwgZmlsbD1OQSwgLi4uKSB7DQogICAgeCA8LSB4YyArIHIqY29zKHNlcSgwLCBwaSwgbGVuZ3RoLm91dD0xMDApKQ0KICAgIHltYXggPC0geWMgKyByKnNpbihzZXEoMCwgcGksIGxlbmd0aC5vdXQ9MTAwKSkNCiAgICB5bWluIDwtIHljICsgcipzaW4oc2VxKDAsIC1waSwgbGVuZ3RoLm91dD0xMDApKQ0KICAgIGFubm90YXRlKCJyaWJib24iLCB4PXgsIHltaW49eW1pbiwgeW1heD15bWF4LCBjb2xvcj1jb2xvciwgZmlsbD1maWxsLCAuLi4pDQp9DQogIA0KICBncmFwaCA8LSBnZ3Bsb3QoZGYsICBhZXMoeD14cG9zLHk9eXBvcywgY29sb3IgPSBwaWMsIHNoYXBlID0gcGljKSkgKw0KICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuOCkgKw0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgYXNwZWN0LnJhdGlvID0gMSkgKyANCiAgICBzY2FsZV9zaGFwZV9iaW5uZWQoKSANCiAgDQogIGdyYXBoICsgDQogICAgYW5ub3RhdGUoInJlY3QiLCB4bWluPTAsIHhtYXg9MSwgeW1pbj0wLCB5bWF4PTEsIGZpbGw9ImJsYWNrIiwgYWxwaGE9MC4wNSkgIysNCiAgICAjZ2dfY2lyY2xlKHI9MC41LCB4Yz0wLjUsIHljPTAuNSwgY29sb3I9ImRhcmtibHVlIiwgZmlsbD0iYmx1ZSIsIGFscGhhPTAuMDUpIA0KYGBgDQoNCg0KRW4gbGEgZmlndXJhLCB1biBjaXJjdWl0byBjb24gdW4gw6FyZWEgaWd1YWwgYSAkXGZyYWN7XHBpfXs0fSQsIGVzdMOhIGluc2NyaXRvIGVuIHVuIGN1YWRyYWRvIGN1eWEgw6FyZWEgZXMgaWd1YWwgYSAxLiBTZSBlbGlnZSBkZSBmb3JtYSBhbGVhdG9yaWEgbiBwdW50b3MgZGVudHJvIGRlbCBjdWFkcmFkby4gTGEgcHJvYmFiaWxpZGFkIGRlIHF1ZSB1biBwdW50byBlc3TDqSBkZW50cm8gZGVsIGPDrXJjdWxvIGVzIGlndWFsIGEgbGEgZnJhY2Npw7NuIGRlbCDDoXJlYSBkZWwgY3VhZHJhZG8gcXVlIGFiYXJjYSBhIGVzdGUsIGxhIGN1YWwgZXMgJFxmcmFje1xwaX17NH0kLiBQb3IgdGFudG8sIHNlIHB1ZWRlIGVzdGltYXIgZWwgdmFsb3IgZGUgJFxmcmFje1xwaX17NH0kIGFsIGNvbnRhciBlbCBuw7ptZXJvIGRlIHB1bnRvcyBkZW50cm8gZGVsIGPDrXJjdWxvLCBwYXJhIG9idGVuZXIgbGEgZXN0aW1hY2nDs24gZGUgJFxmcmFje1xwaX17NH0kLiBEZSBlc3RlIMO6bHRpbW8gcmVzdWx0YWRvIHNlIGVuY29udHJhciB1bmEgYXByb3hpbWFjacOzbiBwYXJhIGVsIHZhbG9yIGRlICRccGkkLg0KDQpQYXNvcyBzdWdlcmlkb3M6DQoNCjEuICAgR2VuZXJlIG4gY29vcmRlbmFkYXMgJHg6IHhfMSwgXGRvdHMsIHhfbiQuIFV0aWxpY2UgbGEgZGlzdHJpYnVjacOzbiB1bmlmb3JtZSBjb24gdmFsb3IgbcOtbmltbyBkZSAwIHkgdmFsb3IgbcOheGltbyBkZSAxLiBMYSBkaXN0cmlidWNpw7NuIHVuaWZvcm1lIGdlbmVyYSB2YXJpYWJsZXMgYWxlYXRvcmlhcyBxdWUgdGllbmVuIGxhIG1pc21hIHByb2JhYmlsaWRhZCBkZSB2ZW5pciBkZSBjdWFscXVpZXIgcGFydGUgZGVsIGludGVydmFsbyAkKDAsMSkkLg0KMi4gICBHZW5lcmUgMTAwMCBjb29yZGVuYWRhcyAkeTogeV8xLFxkb3RzLCB5X24kLCB1dGlsaXphbmRvIG51ZXZhbWVudGUgbGEgZGlzdHJpYnVjacOzbiB1bmlmb3JtZSBjb24gdmFsb3IgbcOtbmltbyBkZSAwIHkgdmFsb3IgbcOheGltbyBkZSAxLg0KMy4gICBDYWRhIHB1bnRvICQoeF9pJCwkeV9pKSQgc2UgZW5jdWVudHJhIGRlbnRybyBkZWwgY8OtcmN1bG8gc2kgc3UgZGlzdGFuY2lhIGRlc2RlIGVsIGNlbnRybyAkKDAuNSwwLjUpJCBlcyBtZW5vciBhIDAuNS4gUGFyYSBjYWRhIHBhciAkKHhfaSQsJHlfaSkkIGRldGVybWluZSBzaSBsYSBkaXN0YW5jaWEgZGVzZGUgZWwgY2VudHJvIGVzIG1lbm9yIGEgMC41LiBFc3RvIMO6bHRpbW8gc2UgcHVlZGUgcmVhbGl6YXIgYWwgY2FsY3VsYXIgZWwgdmFsb3IgJCh4X2niiJIwLjUpXjIrKHlfaeKIkjAuNSleMiQsIHF1ZSBlcyBlbCBjdWFkcmFkbyBkZSBsYSBkaXN0YW5jaWEsIHkgYWwgZGV0ZXJtaW5hciBzaSBlcyBtZW5vciBxdWUgMC4yNS4NCjQuICAgwr9DdcOhbnRvcyBkZSBsb3MgcHVudG9zIGVzdMOhbiBkZW50cm8gZGVsIGPDrXJjdWxvPyDCv0N1w6FsIGVzIHN1IGVzdGltYWNpw7NuIGRlICRccGkkPw0KDQoNCiMjIyBOb3RhDQoqIENvbiBzw7NsbyAxMDAwIHB1bnRvcywgZXMgcHJvYmFibGUgcXVlIGxhIGVzdGltYWNpw7NuIHByZXNlbnRlIHVuIGVycm9yIGRlIDAuMDUgbyBtw6FzLiBVbmEgc2ltdWxhY2nDs24gY29uIDEwMDAwIHkgMTAwMDAwIHB1bnRvcyB0aWVuZSBtYXlvcmVzIHByb2JhYmlsaWRhZGVzIGRlIGRhciBjb21vIHJlc3VsdGFkbyB1bmEgZXN0aW1hY2nDs24gbXV5IGNlcmNhbmEgYWwgdmFsb3IgdmVyZGFkZXJvLg0KKiBGdW5jaW9uZXMgcmVjb21lbmRhZGFzIDogcnVuaWYoKSwgZnVudGlvbigpe30NCiogRW50cmVnYWJsZSA6IGVubGFjZSBlbiBSUHVicyBjb24gaW5mb3JtZSAxDQoqIFByb2JsZW1hIHRvbWFkbyBkZSBOYXZpZGkoMjAwNikNCg0KIyMjIERlc2Fycm9sbG8NCg0KU2Ugbm9zIHByZXNlbnRhbiAyIGZpZ3VyYXMgZ2VvbcOpdHJpY2FzIGNvbmPDqW50cmljYXMsIHVuIGN1YWRyYWRvIHJlY3TDoW5ndWxvIHkgdW4gY8OtcmN1bG8uICBFbCDDoXJlYSBkZWwgY3VhZHJhZG8gZXMgYmFzZSB4IGFsdHVyYSwgeSBsYSBkZWwgY8OtcmN1bG8gZXMgJFxwaSByXjIkLiBFbCByYWRpbyBtaWRlIDAsNSwgbHVlZ28gY2FkYSBsYWRvIGRlbCBjdWFkcmFkbyBlcyAyIHggMCw1LCBlcyBkZWNpciAxLiBMYXMgw6FyZWFzIHNlcsOtYW46DQoqIMOBcmVhIEPDrXJjdWxvOiAkXHBpIHJeMiA9IFxwaSgwLDUpXjIgPSAwLDc4NTQkDQoqIMOBcmVhIEN1YWRyYWRvOiBiYXNlIHggYWx0dXJhICQ9ICgycikqKDJyKSA9IDRyXjIgPSA0ICogMCw1XjIgPSA0ICogMCwyNSA9IDEkIA0KDQpDb21vIHNlIHF1aWVyZSBjYWxjdWxhciBsYSBwcm9iYWJpbGlkYWQgZGUgcXVlIHVuIHB1bnRvIGVzdMOpIGRlbnRybyBkZWwgY2lyY3VsbyAoc2llbmRvIGxhIHN1cGVyZmljaWUgZGVsIGN1YWRyYWRvIGxhIHN1cGVyZmljaWUgZW4gZG9uZGUgc2UgZW5jdWVudHJhbiB0b2RvcyBsb3MgcHVudG9zKSwgZXN0YSBzZXLDrWEgbGEgcmF6w7NuIGRlbCDDoXJlYSBkZWwgY8OtcmN1bG8geSBkZWwgw6FyZWEgZGVsIGN1YWRyYWRvLiBFbnRvbmNlcywNCg0KKiDDgXJlYSBjw61yY3VsbyAvIMOBcmVhIGN1YWRyYWRvID0gJFxmcmFje1xwaSByXjJ9ezRyXjJ9ID0gIFxmcmFje1xwaX17NH0kDQoNClNlIHJlYWxpemFyw6FuIGxvcyBwYXNvcyBtZW5jaW9uYWRvcyBlbiBlbCBzaWd1aWVudGUgY8OzZGlnbzoNCg0KYGBge3IgZnVuY3Rpb259DQojIEZ1bmN0aW9uIHRvIGVzdGltYXRlIHRoZSB2YWx1ZSBvZiDPgA0KZXN0aW1hdGlvbl9vZl9waSA8LSBmdW5jdGlvbihpdGVyYXRpb25zID0gMTAwMCwgc2VlZCA9IDY4OSl7DQogIHNldC5zZWVkKHNlZWQpDQogICMgW2l0ZXJhdGlvbnNdIHZhbHVlcyB0byBlYWNoIGNvb3JkaW5hdGUgKHgseSkgaW4gYSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBmb3IgbnVtYmVycyBiZXR3ZWVuIDAgYW5kIDEgKEluc2lkZSB0aGUgYXJlYSBvZiB0aGUgc3F1YXJlKQ0KICAjIHN0ZXAgMSBhbmQgMg0KICB4IDwtIHJ1bmlmKGl0ZXJhdGlvbnMsIG1pbiA9IDAsIG1heCA9IDEpIA0KICB5IDwtIHJ1bmlmKGl0ZXJhdGlvbnMsIG1pbiA9IDAsIG1heCA9IDEpDQogICMgc3RlcCAzLiBTZXBhcmF0aW9uIGZyb20gdGhlIGNlbnRlciBvZiB0aGUgY2lyY2xlICgwLjUsMC41KQ0KICBwb2ludCA8LSAoeCAtIDAuNSleMiArICh5IC0gMC41KV4yDQogICMgVGhlIHBvaW50IGlzIGluc2lkZSB0aGUgY2lyY2xlIGlmIF9wb2ludF8gaXMgc21hbGxlciB0aGFuIDAuMjUNCiAgcmVmZXJlbmNlID0gMC4yNQ0KICBpbnNpZGVfdGhlX2NpcmNsZSA8LSB3aGljaChwb2ludCA8PSByZWZlcmVuY2UpIA0KICAjIHN0ZXAgNC4gTnVtYmVyIG9mIHBvaW50cyB3aXRoaW4gdGhlIGNpcmNsZQ0KICBudW1iZXJfb2ZfcG9pbnRzIDwtIGxlbmd0aChpbnNpZGVfdGhlX2NpcmNsZSkNCiAgIyBFc3RpbWF0aW9uIG9mIM+AIGlzIDQgKiBpbnNpZGVfdGhlX2NpcmNsZQ0KICBlc3RpbWF0ZWRfcGkgPC0gNCAqIG51bWJlcl9vZl9wb2ludHMgLyBpdGVyYXRpb25zIA0KICANCiAgI2NhdCgiUGVyY2VudGFnZSBvZiBwb2ludHMgaW5zaWRlIHRoZSBjaXJjbGU6IiwgbnVtYmVyX29mX3BvaW50cy9pdGVyYXRpb25zKjEwMCwiJSIpDQogIA0KICByZXR1cm4oZXN0aW1hdGVkX3BpKQ0KfQ0KYGBgDQoNCiMjIFJldmlzacOzbiBkZWwgbcOpdG9kbw0KDQpTZSBzYWJlIHF1ZSAkXHBpJCA9IDMuMTQxNTkyNjUzNS4gIFByb2JlbW9zIGxhIGzDs2dpY2EgdXRpbGl6YWRhIGNvbiBtaWwgaXRlcmFjaW9uZXMgKEVsIHZhbG9yIGVzdGFibGVjaWRvIHBvciBkZWZlY3RvKSBwYXJhIHZlciBjdcOhbCBlcyBlbCB2YWxvciBlc3RpbWFkby4NCg0KYGBge3IgMTAwMH0NCmVzdGltYXRpb25fb2ZfcGkoKQ0KYGBgDQpTb2xvIGhheSB1biBkZWNpbWFsIGNvcnJlY3RvLiBUb2RhdsOtYSBlc3RhbW9zIGxlam9zLiBTZSBzYWJlIHF1ZSBwYXJhIGNvbmp1bnRvcyBkZSBkYXRvcyBtw6FzIG51bWVyb3NvcywgbWVqb3JhcsOhIGxhIGVzdGltYWNpw7NuLCBlbnRvbmNlcyBlamVjdXRhbW9zIGxhIGZ1bmNpw7NuIHBhcmEgdmFsb3JlcyBtw6FzIGdyYW5kZXM6DQpgYGB7ciBtb3JlfQ0KbnVtYmVyX29mX2l0ZXJhdGlvbnMgPC0gYygxMjM0NTYsIDUxMjM0NTYsIDk5OTk5OTk5LCA1NTk5OTk5OSkNCnJlcyA8LSBzYXBwbHkobnVtYmVyX29mX2l0ZXJhdGlvbnMsIGZ1bmN0aW9uKG4pZXN0aW1hdGlvbl9vZl9waShpdGVyYXRpb25zID0gbikpDQpuYW1lcyhyZXMpIDwtIG51bWJlcl9vZl9pdGVyYXRpb25zDQpyZXMNCmBgYA0KVGFsIGNvbW8gc2UgcHVlZGUgdmVyIGVuIGxhIHRhYmxhLCBlbCB2YWxvciBlc3RpbWFkbyBkZSDPgCBzZSBhY2VyY2EgYWwgdmFsb3IgcmVhbCBlbnRyZSBtw6FzIGl0ZXJhY2lvbmVzIHNlIHJlYWxpY2VuLg0KDQpHcsOhZmljYW1lbnRlIHNlIHB1ZWRlIHJlcHJlc2VudGFyIGVsIGNhbWJpbyBkZWwgdmFsb3IgZGUgz4AgcGludMOhbmRvbG8gY29uIGNhZGEgbsO6bWVybyBkZSBpdGVyYWNpb25lcy4gUGFyYSBlc3RvLCBhbCBlamVjdXRhciBsYSBmdW5jacOzbiwgZGViZW1vcyBndWFyZGFyIGVsIHZhbG9yIGVzdGltYWRvIGRlICRccGkkLCBwYXJhIGRlc3B1w6lzIHBvZGVyIHVzYXIgdG9kb3Mgc3VzIHZhbG9yZXMgZXN0aW1hZG9zIGVuIHVuYSBzb2xhIGdyw6FmaWNhLg0KDQpgYGB7ciBuZXdfZnVuY3Rpb259DQojIEZ1bmN0aW9uIHRvIGVzdGltYXRlIHRoZSB2YWx1ZSBvZiDPgA0KZXN0aW1hdGlvbl9vZl9waSA8LSBmdW5jdGlvbihpdGVyYXRpb25zID0gMTAwMCwgc2VlZCA9IDY4OSl7DQogIHNldC5zZWVkKHNlZWQpDQogICMgc3RvcmUgdGhlIHZhbHVlcyBpbiBhIGRhdGEgZnJhbWUNCiAgZGYgPC0gZGF0YS5mcmFtZSh4IDwtIHJ1bmlmKG4gPSBpdGVyYXRpb25zLCBtaW4gPSAwLCBtYXggPSAxKSwNCiAgICAgICAgICAgICAgICAgICB5IDwtIHJ1bmlmKG4gPSBpdGVyYXRpb25zLCBtaW4gPSAwLCBtYXggPSAxKSkNCiAgIyBzdG9yZSB0aGUgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgaW4gdGhlIGRhdGEgZnJhbWUNCiAgZGYkaXRlcmF0aW9uIDwtIDE6aXRlcmF0aW9ucw0KICANCiAgIyBjb3VudCB0aGUgbnVtYmVyIG9mIHBvaW50cyBpbnNpZGUgdGhlIGNpcmNsZQ0KICByZWZlcmVuY2UgPSAwLjI1DQogIGRmJHBvaW50c19pbnNpZGVfY2lyY2xlIDwtIGlmZWxzZSAoKCh4IC0gMC41KV4yICsgKHkgLSAwLjUpXjIpIDw9IHJlZmVyZW5jZSwgMSwgMCkNCiAgDQogICMgRXN0aW1hdGlvbiBvZiDPgCBpcyA0ICogaW5zaWRlX3RoZV9jaXJjbGUNCiAgZGYkZXN0aW1hdGVkX3BpIDwtIDQgKiBjdW1zdW0oZGYkcG9pbnRzX2luc2lkZV9jaXJjbGUpIC8gZGYkaXRlcmF0aW9uIA0KICANCiAgcmV0dXJuKGRmKQ0KfQ0KYGBgDQoNCkNvbiBlc3RhIGZ1bmNpw7NuLCBwb2RlbW9zIGdlbmVyYXIgbG9zIHZhbG9yZXMgZXN0aW1hZG9zIGRlICRccGkkIGRlIGxvcyBwcmltZXJvcyAxMDAgbWlsIHB1bnRvcw0KDQpgYGB7ciBtaWxsaW9uX2dyYXBofQ0KcGlfZGF0YSA8LSBlc3RpbWF0aW9uX29mX3BpKGl0ZXJhdGlvbnMgPSAxMDAwMDApDQoNCiMgcGxvdCBzaG93aW5nIGVzdGltYXRlZCBwaSBhcyBudW1iZXIgb2YgcG9pbnRzIGluY3JlYXNlcw0KZ2dwbG90KHBpX2RhdGEsIGFlcyh4ID0gaXRlcmF0aW9uLCB5ID0gZXN0aW1hdGVkX3BpKSkgKw0KICAgICAgICAgICAgZ2VvbV9saW5lKGNvbCA9ICJibHVlIikgKw0KICAgICAgICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gcGksIGNvbCA9ICJkYXJrZ3JlZW4iKSArDQogICAgICAgICAgICB5bGltKGMoMywgMy4zKSkgKw0KICAgICAgICAgICAgbGFicyh0aXRsZSA9IGV4cHJlc3Npb24ocGFzdGUoIkFwcm94aW1hY2nDs24gZGUgIiwgcGkpKSwNCiAgICAgICAgICAgICAgICAgeCA9ICJDYW50aWRhZCBkZSBwdW50b3MiLA0KICAgICAgICAgICAgICAgICB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiVmFsb3IgZXN0aW1hZG8gZGUgIixwaSkpKQ0KYGBgDQoNClBvZGVtb3MgdmVyIHF1ZSBlbiBsYSBtZWRpZGEgZW4gcXVlIGhheSBtYXMgcHVudG9zLCBlbCB2YWxvciBlc3RpbWFkbyBkZSDPgCBzZSBhY2VyY2EgYSBzdSB2YWxvciByZWFsIQ0KDQoNCg==