Reference


library(progress)


Example 1


Sample from the standard normal density,

\[ f(x) \propto \mathrm{exp}(-x^2/2), ~~ -\infty < x < \infty. \]

set.seed(0)

# total number of iterations for slice sampler
N = 10000

# initializing the space for the samples
us = rep(1, N)  # auxiliary variable
xs = rep(1, N)

# slice sampler
for(i in 2:N){
  us[i] = runif(1, min = 0, max = exp(-0.5*(xs[i-1]^2)))
  xs[i] = runif(1, min = -sqrt(-2*log(us[i])), max = sqrt(-2*log(us[i])))
}
true = seq(-5, 5, 0.01)
true_f = dnorm(true)

hist(xs, freq=F, breaks=200, main = "Histogram of slice samples", xlab = "x")
lines(true, true_f, type="l", col="red")
legend("topright", legend = "True density", col = "red", lty = 1)



Example 2


Sample from exponential(1),

\[ f(x) \propto \mathrm{exp}(-x), ~~ 0 < x < \infty. \]

set.seed(0)

# total number of iterations for slice sampler
N = 10000

# initializing the space for the samples
us = rep(1, N)  # auxiliary variable
xs = rep(1, N)

# slice sampler
for(i in 2:N){
  us[i] = runif(1, min = 0, max = exp(-xs[i-1]))
  xs[i] = runif(1, min = 0, max = -log(us[i]))
}
true = seq(0, 10, 0.01)
true_f = dgamma(true, shape = 1, scale = 1)

hist(xs, freq=F, breaks=200, main = "Histogram of slice samples", xlab=expression(x))
lines(true, true_f, type="l", col="red")
legend("topright", legend = "True density", col = "red", lty = 1)



Example 3 (Numerical method)


Let \(Y_i \overset{ind}{\sim} N(\theta, 1)\) and \(\theta \sim \mathrm{exp}(1)\). Then,

\[ P(\theta|y) \propto \prod_{i=1}^{n} \left [ N(y_i; \theta, 1) \right ] \mathrm{exp}(\theta; 1). \]


Let \(\theta = 0.2\). Since it is hard to derive the inverse function for the slice sampler from,

\[ \begin{aligned} u|\theta &\sim U(0, P(\theta|y)), \\ \theta|u &\sim U \left \{ \theta: u < P(\theta|y) \right \}, \end{aligned} \]

we solve it numerically using the function uniroot() for the two end points of \(\theta\).

set.seed(0)

### Observations
n = 500
true_theta = 0.2
y = rnorm(n, mean = true_theta, sd = 1)

### PDF of the posterior dstn
f = function(theta, y. = y){
    exp(sum(dnorm(y., mean = theta, sd = 1, log = TRUE)) + dexp(abs(theta), log = TRUE))
}

### Function to numerically find endpoints
A = function(u, xx, f. = f){
  left_endpoint = uniroot(function(x) f.(x) - u, c(-10^10, xx)) 
  right_endpoint = uniroot(function(x) f.(x) - u, c(10^10, xx))
  return(c(left_endpoint$root, right_endpoint$root))
}
### Slice sampler
slice_sampler = function(N, init_theta, target, A){
  ## Initialization
  u = rep(NA, N)
  theta = rep(NA, N)
  theta[1] = init_theta
  u[1] = runif(1, 0, target(theta[1]))
  
  pb = progress_bar$new(
    format = "  MCMC [:bar] :percent eta: :eta",
    total = N-1, clear = FALSE, width= 60)
  
  ## MCMC algorithm iterations
  for(i in 2:N){
    pb$tick()
    
    u[i] = runif(1, 0, target(theta[i-1]))
    endpoints = A(u[i], theta[i-1])
    theta[i] = runif(1, endpoints[1], endpoints[2])
  }
  
  return(theta)
}
set.seed(0)

N = 5000  # number of iterations for the MCMC algorithm
ptm = proc.time()  # to time the algorithm
theta = slice_sampler(N, mean(y), f, A)
proc.time() - ptm 
   user  system elapsed 
 15.960   0.537  19.359 
### Traceplot
plot(1:N, theta, type = "l", xlab = "Iterations", ylab = expression(theta))

### Posterior mean
mean(theta)
[1] 0.1980653



Example 4 (Augmentation method)


Let \(Y_i \overset{ind}{\sim} N(\theta, 1)\) and \(\theta \sim \mathrm{exp}(1)\). Then,

\[ P(\theta|y) \propto \prod_{i=1}^{n} \left [ N(y_i; \theta, 1) \right ] \mathrm{exp}(\theta; 1). \]

Unlike example 3, we will now use augmentation,

\[ P(u, \theta) \propto P(\theta)I(0 < u < P(y|\theta)). \]

The full conditional distributions are now,

\[ \begin{aligned} u|\theta, y &\sim U(0, P(y|\theta)), \\ \theta|u, y &\sim P(\theta)I(u < P(y|\theta)). \end{aligned} \]

If \(P(\theta)\) is unimodal, the conditional dstn for \(\theta|u, y\) is equivalent to

\[ P(\theta)I(\theta_L(u) < \theta < \theta_U(u)), \]

for some bounds \(\theta_L(u)\) and \(\theta_U(u)\) which depend on \(u\). To learn these bounds we can sample from \(P(\theta)\) and update the bounds. For example, if \(\theta^{(t-1)}\) is our current value in the chain, we know \(u < P(y|\theta^{(t-1)})\), or equivalently,

\[ \theta_L(u) < \theta^{(t-1)} < \theta_U(u). \]

Letting \(u^{(t)}\) be the current value for the auxiliary variable and setting \(\theta_L(u^{(t)})\) and \(\theta_U(u^{(t)})\) for the lower and upper bounds of the support for \(\theta\) respectively, the slice sampler algorithm goes as follows.


For \(t = 1, ..., T\),

  1. Sample \(\theta^*\) from

\[ \theta^* \sim P(\theta)I(\theta_L(u^{(t)}) < \theta < \theta_U(u^{(t)})). \]

  1. Set \(\theta^{(t)} = \theta^*\) if

\[ u^{(t)} < P(y|\theta^*), \]

otherwise set

\[ \begin{aligned} \theta_L(u^{(t)}) &= \theta^* ~~ \mathrm{if} ~~ \theta^* < \theta^{(t-1)}, \\ \theta_U(u^{(t)}) &= \theta^* ~~ \mathrm{if} ~~ \theta^* > \theta^{(t-1)}, \end{aligned} \]

and return to Step (1).


### Slice sampler
aug_slice_sampler = function(N, init_theta, like, qprior){ 
  ## Initialization
  u = rep(NA, N)
  theta = rep(NA, N)
  theta[1] = init_theta
  u[1] = runif(1, 0, like(theta[1]))
  
  pb = progress_bar$new(
    format = "  MCMC [:bar] :percent eta: :eta",
    total = N-1, clear = FALSE, width= 60)
  
  ## MCMC algorithm iterations
  for (i in 2:N){
    pb$tick()
    
    u[i] = runif(1, 0, like(theta[i - 1])) 
    success = FALSE
    endpoints = 0:1
    
    while(!success){
    # Inverse CDF
    up = runif(1, endpoints[1], endpoints[2]) 
    theta[i] = qprior(up)
    if (u[i] < like(theta[i])) { 
      success = TRUE
    } else {
      if(theta[i] < theta[i - 1]){endpoints[1] = up}
      else{endpoints[2] = up}
      }
    } 
  }
  return(theta) 
}
set.seed(0)

### Observations
n = 500
true_theta = 0.2
y = rnorm(n, mean = true_theta, sd = 1)

### Likelihood function for a given theta
like = function(tht) exp(sum(dnorm(y, mean = tht, sd = 1, log = TRUE)))

### inverse CDF of prior
qprior = function(tht) qexp(tht)
set.seed(0)

N = 5000  # number of iterations for the MCMC algorithm
ptm = proc.time()  # to time the algorithm
theta = aug_slice_sampler(N, mean(y), like, qprior)
proc.time() - ptm 
   user  system elapsed 
  5.552   0.289   8.261 


We can see that this is much faster than the slice sampler with numerical method.


### Traceplot
plot(1:N, theta, type = "l", xlab = "Iterations", ylab = expression(theta))

### Posterior mean
mean(theta)
[1] 0.1984192



LS0tCnRpdGxlOiAiU2xpY2Ugc2FtcGxlciIKYXV0aG9yOiAiSmFleW9uZyBMZWUiCmRhdGU6ICIyMDIzLTA2LTI3IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwotLS0KCltSZWZlcmVuY2VdKGh0dHBzOi8vd3d3LmphcmFkLm1lL2NvdXJzZXMvc3RhdDYxNS9zbGlkZXMvU2xpY2Uvc2xpY2UucGRmKQoKXAoKYGBge3J9CmxpYnJhcnkocHJvZ3Jlc3MpCmBgYAoKXAoKIyMgRXhhbXBsZSAxCgpcCgpTYW1wbGUgZnJvbSB0aGUgc3RhbmRhcmQgbm9ybWFsIGRlbnNpdHksCgokJApmKHgpIFxwcm9wdG8gXG1hdGhybXtleHB9KC14XjIvMiksIH5+IC1caW5mdHkgPCB4IDwgXGluZnR5LgokJAoKIVtdKC9Vc2Vycy9qYWV5b25nbGVlL0RvY3VtZW50cy9Db2xsZWdlL01hc3Rlci/hhInhha7hhIvhhaXhhrgvdGhpcmQvR3JhZEJheWVzL0Fzc2lnbm1lbnQvUi9zbGljZV9pbWdzL0lNR18yMkFDOUE0NjEwRUEtMS5qcGVnKQoKYGBge3J9CnNldC5zZWVkKDApCgojIHRvdGFsIG51bWJlciBvZiBpdGVyYXRpb25zIGZvciBzbGljZSBzYW1wbGVyCk4gPSAxMDAwMAoKIyBpbml0aWFsaXppbmcgdGhlIHNwYWNlIGZvciB0aGUgc2FtcGxlcwp1cyA9IHJlcCgxLCBOKSAgIyBhdXhpbGlhcnkgdmFyaWFibGUKeHMgPSByZXAoMSwgTikKCiMgc2xpY2Ugc2FtcGxlcgpmb3IoaSBpbiAyOk4pewogIHVzW2ldID0gcnVuaWYoMSwgbWluID0gMCwgbWF4ID0gZXhwKC0wLjUqKHhzW2ktMV1eMikpKQogIHhzW2ldID0gcnVuaWYoMSwgbWluID0gLXNxcnQoLTIqbG9nKHVzW2ldKSksIG1heCA9IHNxcnQoLTIqbG9nKHVzW2ldKSkpCn0KYGBgCgpgYGB7cn0KdHJ1ZSA9IHNlcSgtNSwgNSwgMC4wMSkKdHJ1ZV9mID0gZG5vcm0odHJ1ZSkKCmhpc3QoeHMsIGZyZXE9RiwgYnJlYWtzPTIwMCwgbWFpbiA9ICJIaXN0b2dyYW0gb2Ygc2xpY2Ugc2FtcGxlcyIsIHhsYWIgPSAieCIpCmxpbmVzKHRydWUsIHRydWVfZiwgdHlwZT0ibCIsIGNvbD0icmVkIikKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9ICJUcnVlIGRlbnNpdHkiLCBjb2wgPSAicmVkIiwgbHR5ID0gMSkKYGBgCgpcClwKCiMjIEV4YW1wbGUgMgoKXAoKU2FtcGxlIGZyb20gZXhwb25lbnRpYWwoMSksCgokJApmKHgpIFxwcm9wdG8gXG1hdGhybXtleHB9KC14KSwgfn4gMCA8IHggPCBcaW5mdHkuCiQkCgohW10oL1VzZXJzL2phZXlvbmdsZWUvRG9jdW1lbnRzL0NvbGxlZ2UvTWFzdGVyL+GEieGFruGEi+GFpeGGuC90aGlyZC9HcmFkQmF5ZXMvQXNzaWdubWVudC9SL3NsaWNlX2ltZ3MvSU1HXzBCMzkwREY3MjJBOC0xLmpwZWcpCgpgYGB7cn0Kc2V0LnNlZWQoMCkKCiMgdG90YWwgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgZm9yIHNsaWNlIHNhbXBsZXIKTiA9IDEwMDAwCgojIGluaXRpYWxpemluZyB0aGUgc3BhY2UgZm9yIHRoZSBzYW1wbGVzCnVzID0gcmVwKDEsIE4pICAjIGF1eGlsaWFyeSB2YXJpYWJsZQp4cyA9IHJlcCgxLCBOKQoKIyBzbGljZSBzYW1wbGVyCmZvcihpIGluIDI6Til7CiAgdXNbaV0gPSBydW5pZigxLCBtaW4gPSAwLCBtYXggPSBleHAoLXhzW2ktMV0pKQogIHhzW2ldID0gcnVuaWYoMSwgbWluID0gMCwgbWF4ID0gLWxvZyh1c1tpXSkpCn0KYGBgCgpgYGB7cn0KdHJ1ZSA9IHNlcSgwLCAxMCwgMC4wMSkKdHJ1ZV9mID0gZGdhbW1hKHRydWUsIHNoYXBlID0gMSwgc2NhbGUgPSAxKQoKaGlzdCh4cywgZnJlcT1GLCBicmVha3M9MjAwLCBtYWluID0gIkhpc3RvZ3JhbSBvZiBzbGljZSBzYW1wbGVzIiwgeGxhYj1leHByZXNzaW9uKHgpKQpsaW5lcyh0cnVlLCB0cnVlX2YsIHR5cGU9ImwiLCBjb2w9InJlZCIpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSAiVHJ1ZSBkZW5zaXR5IiwgY29sID0gInJlZCIsIGx0eSA9IDEpCmBgYAoKXApcCgojIyBFeGFtcGxlIDMgKE51bWVyaWNhbCBtZXRob2QpCgpcCgpMZXQgJFlfaSBcb3ZlcnNldHtpbmR9e1xzaW19IE4oXHRoZXRhLCAxKSQgYW5kICRcdGhldGEgXHNpbSBcbWF0aHJte2V4cH0oMSkkLiBUaGVuLAoKJCQKUChcdGhldGF8eSkgXHByb3B0byBccHJvZF97aT0xfV57bn0gXGxlZnQgWyBOKHlfaTsgXHRoZXRhLCAxKSBccmlnaHQgXSBcbWF0aHJte2V4cH0oXHRoZXRhOyAxKS4KJCQKClwKCkxldCAkXHRoZXRhID0gMC4yJC4gU2luY2UgaXQgaXMgaGFyZCB0byBkZXJpdmUgdGhlIGludmVyc2UgZnVuY3Rpb24gZm9yIHRoZSBzbGljZSBzYW1wbGVyIGZyb20sCgokJApcYmVnaW57YWxpZ25lZH0KdXxcdGhldGEgJlxzaW0gVSgwLCBQKFx0aGV0YXx5KSksIFxcClx0aGV0YXx1ICZcc2ltIFUgXGxlZnQgXHsgXHRoZXRhOiB1IDwgUChcdGhldGF8eSkgXHJpZ2h0IFx9LApcZW5ke2FsaWduZWR9CiQkCgp3ZSBzb2x2ZSBpdCBudW1lcmljYWxseSB1c2luZyB0aGUgZnVuY3Rpb24gdW5pcm9vdCgpIGZvciB0aGUgdHdvIGVuZCBwb2ludHMgb2YgJFx0aGV0YSQuCgpgYGB7cn0Kc2V0LnNlZWQoMCkKCiMjIyBPYnNlcnZhdGlvbnMKbiA9IDUwMAp0cnVlX3RoZXRhID0gMC4yCnkgPSBybm9ybShuLCBtZWFuID0gdHJ1ZV90aGV0YSwgc2QgPSAxKQoKIyMjIFBERiBvZiB0aGUgcG9zdGVyaW9yIGRzdG4KZiA9IGZ1bmN0aW9uKHRoZXRhLCB5LiA9IHkpewogICAgZXhwKHN1bShkbm9ybSh5LiwgbWVhbiA9IHRoZXRhLCBzZCA9IDEsIGxvZyA9IFRSVUUpKSArIGRleHAoYWJzKHRoZXRhKSwgbG9nID0gVFJVRSkpCn0KCiMjIyBGdW5jdGlvbiB0byBudW1lcmljYWxseSBmaW5kIGVuZHBvaW50cwpBID0gZnVuY3Rpb24odSwgeHgsIGYuID0gZil7CiAgbGVmdF9lbmRwb2ludCA9IHVuaXJvb3QoZnVuY3Rpb24oeCkgZi4oeCkgLSB1LCBjKC0xMF4xMCwgeHgpKSAKICByaWdodF9lbmRwb2ludCA9IHVuaXJvb3QoZnVuY3Rpb24oeCkgZi4oeCkgLSB1LCBjKDEwXjEwLCB4eCkpCiAgcmV0dXJuKGMobGVmdF9lbmRwb2ludCRyb290LCByaWdodF9lbmRwb2ludCRyb290KSkKfQpgYGAKCmBgYHtyfQojIyMgU2xpY2Ugc2FtcGxlcgpzbGljZV9zYW1wbGVyID0gZnVuY3Rpb24oTiwgaW5pdF90aGV0YSwgdGFyZ2V0LCBBKXsKICAjIyBJbml0aWFsaXphdGlvbgogIHUgPSByZXAoTkEsIE4pCiAgdGhldGEgPSByZXAoTkEsIE4pCiAgdGhldGFbMV0gPSBpbml0X3RoZXRhCiAgdVsxXSA9IHJ1bmlmKDEsIDAsIHRhcmdldCh0aGV0YVsxXSkpCiAgCiAgcGIgPSBwcm9ncmVzc19iYXIkbmV3KAogICAgZm9ybWF0ID0gIiAgTUNNQyBbOmJhcl0gOnBlcmNlbnQgZXRhOiA6ZXRhIiwKICAgIHRvdGFsID0gTi0xLCBjbGVhciA9IEZBTFNFLCB3aWR0aD0gNjApCiAgCiAgIyMgTUNNQyBhbGdvcml0aG0gaXRlcmF0aW9ucwogIGZvcihpIGluIDI6Til7CiAgICBwYiR0aWNrKCkKICAgIAogICAgdVtpXSA9IHJ1bmlmKDEsIDAsIHRhcmdldCh0aGV0YVtpLTFdKSkKICAgIGVuZHBvaW50cyA9IEEodVtpXSwgdGhldGFbaS0xXSkKICAgIHRoZXRhW2ldID0gcnVuaWYoMSwgZW5kcG9pbnRzWzFdLCBlbmRwb2ludHNbMl0pCiAgfQogIAogIHJldHVybih0aGV0YSkKfQpgYGAKCmBgYHtyLCByZXN1bHRzID0gJ2hpZGUnfQpzZXQuc2VlZCgwKQoKTiA9IDUwMDAgICMgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgZm9yIHRoZSBNQ01DIGFsZ29yaXRobQpwdG0gPSBwcm9jLnRpbWUoKSAgIyB0byB0aW1lIHRoZSBhbGdvcml0aG0KdGhldGEgPSBzbGljZV9zYW1wbGVyKE4sIG1lYW4oeSksIGYsIEEpCmBgYAoKYGBge3J9CnByb2MudGltZSgpIC0gcHRtIApgYGAKCmBgYHtyfQojIyMgVHJhY2VwbG90CnBsb3QoMTpOLCB0aGV0YSwgdHlwZSA9ICJsIiwgeGxhYiA9ICJJdGVyYXRpb25zIiwgeWxhYiA9IGV4cHJlc3Npb24odGhldGEpKQpgYGAKCmBgYHtyfQojIyMgUG9zdGVyaW9yIG1lYW4KbWVhbih0aGV0YSkKYGBgCgpcClwKCiMjIEV4YW1wbGUgNCAoQXVnbWVudGF0aW9uIG1ldGhvZCkKClwKCkxldCAkWV9pIFxvdmVyc2V0e2luZH17XHNpbX0gTihcdGhldGEsIDEpJCBhbmQgJFx0aGV0YSBcc2ltIFxtYXRocm17ZXhwfSgxKSQuIFRoZW4sCgokJApQKFx0aGV0YXx5KSBccHJvcHRvIFxwcm9kX3tpPTF9XntufSBcbGVmdCBbIE4oeV9pOyBcdGhldGEsIDEpIFxyaWdodCBdIFxtYXRocm17ZXhwfShcdGhldGE7IDEpLgokJAoKVW5saWtlIGV4YW1wbGUgMywgd2Ugd2lsbCBub3cgdXNlIGF1Z21lbnRhdGlvbiwKCiQkClAodSwgXHRoZXRhKSBccHJvcHRvIFAoXHRoZXRhKUkoMCA8IHUgPCBQKHl8XHRoZXRhKSkuCiQkCgpUaGUgZnVsbCBjb25kaXRpb25hbCBkaXN0cmlidXRpb25zIGFyZSBub3csCgokJApcYmVnaW57YWxpZ25lZH0KdXxcdGhldGEsIHkgJlxzaW0gVSgwLCBQKHl8XHRoZXRhKSksIFxcClx0aGV0YXx1LCB5ICZcc2ltIFAoXHRoZXRhKUkodSA8IFAoeXxcdGhldGEpKS4KXGVuZHthbGlnbmVkfQokJAoKSWYgJFAoXHRoZXRhKSQgaXMgdW5pbW9kYWwsIHRoZSBjb25kaXRpb25hbCBkc3RuIGZvciAkXHRoZXRhfHUsIHkkIGlzIGVxdWl2YWxlbnQgdG8KCiQkClAoXHRoZXRhKUkoXHRoZXRhX0wodSkgPCBcdGhldGEgPCBcdGhldGFfVSh1KSksCiQkCgpmb3Igc29tZSBib3VuZHMgJFx0aGV0YV9MKHUpJCBhbmQgJFx0aGV0YV9VKHUpJCB3aGljaCBkZXBlbmQgb24gJHUkLiBUbyBsZWFybiB0aGVzZSBib3VuZHMgd2UgY2FuIHNhbXBsZSBmcm9tICRQKFx0aGV0YSkkIGFuZCB1cGRhdGUgdGhlIGJvdW5kcy4gRm9yIGV4YW1wbGUsIGlmICRcdGhldGFeeyh0LTEpfSQgaXMgb3VyIGN1cnJlbnQgdmFsdWUgaW4gdGhlIGNoYWluLCB3ZSBrbm93ICR1IDwgUCh5fFx0aGV0YV57KHQtMSl9KSQsIG9yIGVxdWl2YWxlbnRseSwKCiQkClx0aGV0YV9MKHUpIDwgXHRoZXRhXnsodC0xKX0gPCBcdGhldGFfVSh1KS4KJCQKCkxldHRpbmcgJHVeeyh0KX0kIGJlIHRoZSBjdXJyZW50IHZhbHVlIGZvciB0aGUgYXV4aWxpYXJ5IHZhcmlhYmxlIGFuZCBzZXR0aW5nICRcdGhldGFfTCh1XnsodCl9KSQgYW5kICRcdGhldGFfVSh1XnsodCl9KSQgZm9yIHRoZSBsb3dlciBhbmQgdXBwZXIgYm91bmRzIG9mIHRoZSBzdXBwb3J0IGZvciAkXHRoZXRhJCByZXNwZWN0aXZlbHksIHRoZSBzbGljZSBzYW1wbGVyIGFsZ29yaXRobSBnb2VzIGFzIGZvbGxvd3MuIAoKXAoKRm9yICR0ID0gMSwgLi4uLCBUJCwKCigxKSBTYW1wbGUgJFx0aGV0YV4qJCBmcm9tCgokJApcdGhldGFeKiBcc2ltIFAoXHRoZXRhKUkoXHRoZXRhX0wodV57KHQpfSkgPCBcdGhldGEgPCBcdGhldGFfVSh1XnsodCl9KSkuCiQkCgooMikgU2V0ICRcdGhldGFeeyh0KX0gPSBcdGhldGFeKiQgaWYgCgokJAp1XnsodCl9IDwgUCh5fFx0aGV0YV4qKSwKJCQgCgpvdGhlcndpc2Ugc2V0CgokJApcYmVnaW57YWxpZ25lZH0KXHRoZXRhX0wodV57KHQpfSkgJj0gXHRoZXRhXiogfn4gXG1hdGhybXtpZn0gfn4gXHRoZXRhXiogPCBcdGhldGFeeyh0LTEpfSwgXFwKXHRoZXRhX1UodV57KHQpfSkgJj0gXHRoZXRhXiogfn4gXG1hdGhybXtpZn0gfn4gXHRoZXRhXiogPiBcdGhldGFeeyh0LTEpfSwKXGVuZHthbGlnbmVkfQokJAoKYW5kIHJldHVybiB0byBTdGVwICgxKS4KClwKCmBgYHtyfQojIyMgU2xpY2Ugc2FtcGxlcgphdWdfc2xpY2Vfc2FtcGxlciA9IGZ1bmN0aW9uKE4sIGluaXRfdGhldGEsIGxpa2UsIHFwcmlvcil7IAogICMjIEluaXRpYWxpemF0aW9uCiAgdSA9IHJlcChOQSwgTikKICB0aGV0YSA9IHJlcChOQSwgTikKICB0aGV0YVsxXSA9IGluaXRfdGhldGEKICB1WzFdID0gcnVuaWYoMSwgMCwgbGlrZSh0aGV0YVsxXSkpCiAgCiAgcGIgPSBwcm9ncmVzc19iYXIkbmV3KAogICAgZm9ybWF0ID0gIiAgTUNNQyBbOmJhcl0gOnBlcmNlbnQgZXRhOiA6ZXRhIiwKICAgIHRvdGFsID0gTi0xLCBjbGVhciA9IEZBTFNFLCB3aWR0aD0gNjApCiAgCiAgIyMgTUNNQyBhbGdvcml0aG0gaXRlcmF0aW9ucwogIGZvciAoaSBpbiAyOk4pewogICAgcGIkdGljaygpCiAgICAKICAgIHVbaV0gPSBydW5pZigxLCAwLCBsaWtlKHRoZXRhW2kgLSAxXSkpIAogICAgc3VjY2VzcyA9IEZBTFNFCiAgICBlbmRwb2ludHMgPSAwOjEKICAgIAogICAgd2hpbGUoIXN1Y2Nlc3MpewogICAgIyBJbnZlcnNlIENERgogICAgdXAgPSBydW5pZigxLCBlbmRwb2ludHNbMV0sIGVuZHBvaW50c1syXSkgCiAgICB0aGV0YVtpXSA9IHFwcmlvcih1cCkKICAgIGlmICh1W2ldIDwgbGlrZSh0aGV0YVtpXSkpIHsgCiAgICAgIHN1Y2Nlc3MgPSBUUlVFCiAgICB9IGVsc2UgewogICAgICBpZih0aGV0YVtpXSA8IHRoZXRhW2kgLSAxXSl7ZW5kcG9pbnRzWzFdID0gdXB9CiAgICAgIGVsc2V7ZW5kcG9pbnRzWzJdID0gdXB9CiAgICAgIH0KICAgIH0gCiAgfQogIHJldHVybih0aGV0YSkgCn0KYGBgCgpgYGB7cn0Kc2V0LnNlZWQoMCkKCiMjIyBPYnNlcnZhdGlvbnMKbiA9IDUwMAp0cnVlX3RoZXRhID0gMC4yCnkgPSBybm9ybShuLCBtZWFuID0gdHJ1ZV90aGV0YSwgc2QgPSAxKQoKIyMjIExpa2VsaWhvb2QgZnVuY3Rpb24gZm9yIGEgZ2l2ZW4gdGhldGEKbGlrZSA9IGZ1bmN0aW9uKHRodCkgZXhwKHN1bShkbm9ybSh5LCBtZWFuID0gdGh0LCBzZCA9IDEsIGxvZyA9IFRSVUUpKSkKCiMjIyBpbnZlcnNlIENERiBvZiBwcmlvcgpxcHJpb3IgPSBmdW5jdGlvbih0aHQpIHFleHAodGh0KQpgYGAKCmBgYHtyLCByZXN1bHRzID0gJ2hpZGUnfQpzZXQuc2VlZCgwKQoKTiA9IDUwMDAgICMgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgZm9yIHRoZSBNQ01DIGFsZ29yaXRobQpwdG0gPSBwcm9jLnRpbWUoKSAgIyB0byB0aW1lIHRoZSBhbGdvcml0aG0KdGhldGEgPSBhdWdfc2xpY2Vfc2FtcGxlcihOLCBtZWFuKHkpLCBsaWtlLCBxcHJpb3IpCmBgYAoKYGBge3J9CnByb2MudGltZSgpIC0gcHRtIApgYGAKClwKCldlIGNhbiBzZWUgdGhhdCB0aGlzIGlzIG11Y2ggZmFzdGVyIHRoYW4gdGhlIHNsaWNlIHNhbXBsZXIgd2l0aCBudW1lcmljYWwgbWV0aG9kLgoKXAoKYGBge3J9CiMjIyBUcmFjZXBsb3QKcGxvdCgxOk4sIHRoZXRhLCB0eXBlID0gImwiLCB4bGFiID0gIkl0ZXJhdGlvbnMiLCB5bGFiID0gZXhwcmVzc2lvbih0aGV0YSkpCmBgYAoKYGBge3J9CiMjIyBQb3N0ZXJpb3IgbWVhbgptZWFuKHRoZXRhKQpgYGAKClwKXAoKCgoKCgoK