1 Data

Below we have \(n=10\) observations that we will model as Student’s \(t\) with known degree of freedom \(\nu\).

x = c(-2.33,-0.52,-0.51,-0.38,0.25,0.77,0.79,0.80,1.35,1.40)
n = length(x)

2 Student’s \(t\) model

For a random variable \(x\) following a non-standardized Student’s \(t\)-distribution with \(\nu\) degrees of freedom, location parameter \(\theta\), and scale \(\sigma = 1\), the probability density function (PDF) is given by: \[ f(x | \nu, \theta, 1) = \frac{\Gamma\left(\frac{\nu+1}{2}\right)} {\Gamma\left(\frac{\nu}{2}\right) (\nu\pi)^{1/2}} \left[ 1 + \frac{1}{\nu} (x - \theta)^2 \right]^{-\frac{\nu+1}{2}}. \] Therefore, the likelihood for the \(n\) observations is given by \[ L(\theta;\mbox{data}) \propto \prod_{i=1}^n \left[ 1 + \frac{1}{\nu} (x_i - \theta)^2 \right]^{-\frac{\nu+1}{2}}. \] For simplicity, we will assume a standard normal prior for \(\theta\), ie. \(p(\theta) \propto \exp\left\{-0.5 \theta^2\right\}\).

Obviously, the posterior distribtuion \[ p(\theta|\mbox{data}) \propto \exp\left\{-0.5 \theta^2\right\}\prod_{i=1}^n \left[ 1 + \frac{1}{\nu} (x_i - \theta)^2 \right]^{-\frac{\nu+1}{2}}. \] is of unknown form and posterior inference will be feasible via Monte Carlo integration and simulation. For comparison, below we evaluate the posterior density on a fine grid. Most posterior mass lies between \(-1\) and \(1\), with a location measure around \(0.25\).

nu = 4
N  = 100
thetas = seq(-2,2,length=N)
like = rep(0,N)
for (i in 1:N)
  like[i] = prod(dt(x-thetas[i],df=nu))
prior = exp(-thetas^2/2)
post = prior*like
h = thetas[2]-thetas[1]
post = post/(h*sum(post))
plot(thetas,post,type="l",xlab=expression(theta),ylab="Posterior density")

3 SIR

Here we implement SIR where the proposal density is the prior, \(p(\theta)\)

Recall that the SIR algorithm works as follows:

  1. Sample (large) \(M\) draws from the prior \(p(\theta)\) \[ \{\widetilde{\theta}^{(1)},\ldots,\widetilde{\theta}^{(M)}\}; \]

  2. Evalute the weights \(\omega^{(i)} \propto L(\widetilde{\theta}^{(i)};\mbox{data})\);

  3. Resample \(M_1 \leq M\) from the discrete set \(\{\widetilde{\theta}^{(1)},\ldots,\widetilde{\theta}^{(M)}\}\) with probabilities \(\{\omega^{(1)},\ldots,\omega^{(M)}\}\).

It can be shown that the final sampled set, say \[ \{\theta^{(1)},\ldots,\theta^{(M_1)}\}, \] approximates a sample from \(p(\theta|\mbox{data})\). More details about Monte Carlo integration, MC simulation, SIR and other Monte Carlo schemes, can be found in my course notes here.

M  = 100000
M1 = 20000
time.sir = system.time({
theta.draw = rnorm(M)
w = rep(0,M)
for (i in 1:M)
  w[i] = prod(dt(x-theta.draw[i],df=nu))
theta.sir = sample(theta.draw,size=M1,replace=TRUE,prob=w)
})

hist(theta.sir,prob=TRUE,xlab=expression(theta),ylab="Posterior",main="")
lines(thetas,post,col=2,lwd=3)

4 Random-walk Metropolis

The random-walk Metropolis-Hastings variance is pretty small, \(tau=0.14\). With starting value at \(\theta^{(0)}=0\), the random-walk mMetropolis-Hastings algorithm works as follows, assuming the algorithm is at iteration \(i\):

  1. Sample \(\theta^* \sim N(\theta^{(i-1)},\tau^2)\)

  2. Compute acceptance probability \[ \alpha = \min\left\{1,\frac{p(\theta^*)L(\theta^*;\mbox{data})}{p(\theta^{(i-1)})L(\theta^{(i-1)};\mbox{data})}\right\} \]

  3. With probability \(\alpha\), make \(\theta^{(i)}=\theta^*\); otherwise, make \(\theta^{(i)}=\theta^{(i-1)}\).

  4. Make \(i=i+1\) and repeat steps 1 to 4 until \(i=M\).

theta = 0
tau = 0.1
M0 = M-M1
theta.mh = rep(0,M)
time.mh = system.time({
for (iter in 1:M){
  theta1 = rnorm(1,theta,tau)
  accept = min(1,prod(dt(x-theta1,df=nu))/prod(dt(x-theta,df=nu))*
                 dnorm(theta1)/dnorm(theta))
  if (runif(1)<accept){
  theta = theta1
  }
  theta.mh[iter] = theta
}
})

par(mfrow=c(2,2))
ts.plot(theta.mh,ylab="",xlab="Iterations")
abline(v=M0,col=2,lwd=2)
theta.mh = theta.mh[(M0+1):M]
acf(theta.mh,main="")
hist(theta.mh,prob=TRUE,xlab=expression(theta),ylab="Posterior",main="")
lines(thetas,post,col=2,lwd=3)
plot(thetas,post,main="",xlab="",lwd=2,type="l")
lines(density(theta.sir),col=2,lwd=2)
lines(density(theta.mh),col=4,lwd=2)

5 Independent Metropolis-Hastings

The proposal distribution is Gaussian with mean \(\mu=0\) and variance \(v^2=16\). With starting value at \(\theta^{(0)}=0\), the independent Metropolis-Hastings algorithm works as follows, assuming the algorithm is at iteration \(i\):

  1. Sample \(\theta^* \sim N(\mu,v^2)\)

  2. Compute acceptance probability \[ \alpha = \min\left\{1,\frac{p(\theta^*)L(\theta^*;\mbox{data})}{p(\theta^{(i-1)})L(\theta^{(i-1)};\mbox{data})} \frac{p_N(\theta^{(i-1)}|\mu,v^2)}{p_N(\theta^*|\mu,v^2)} \right\} \]

  3. With probability \(\alpha\), make \(\theta^{(i)}=\theta^*\); otherwise, make \(\theta^{(i)}=\theta^{(i-1)}\).

  4. Make \(i=i+1\) and repeat steps 1 to 4 until \(i=M\).

theta0 = 0
mu = 0
v = 2
theta.imh = rep(0,M)
time.imh = system.time({
for (iter in 1:M){
  theta1 = rnorm(1,mu,v)
  accept = min(1,prod(dt(x-theta1,df=nu))/prod(dt(x-theta,df=nu))*
                 dnorm(theta1)/dnorm(theta)*
                 dnorm(theta,mu,v)/dnorm(theta1,mu,v))
  if (runif(1)<accept){
    theta = theta1
  }
  theta.imh[iter] = theta
}
})

par(mfrow=c(2,2))
ts.plot(theta.imh,ylab="",xlab="Iterations")
abline(v=M0,col=2,lwd=2)
theta.imh = theta.imh[(M0+1):M]
acf(theta.imh,main="")
hist(theta.imh,prob=TRUE,xlab=expression(theta),ylab="Posterior",main="")
lines(thetas,post,col=2,lwd=3)

par(mfrow=c(2,3))

ts.plot(theta.sir,main="SIR",ylab="")
ts.plot(theta.mh,main="Random walk MH",ylab="")
ts.plot(theta.imh,main="Independent MH",ylab="")
acf(theta.sir,lag.max=80,main="")
acf(theta.mh,lag.max=80,main="")
acf(theta.imh,lag.max=80,main="")

par(mfrow=c(1,1))
plot(thetas,post,main="",xlab="",lwd=2,type="l")
lines(density(theta.sir),col=2,lwd=2)
lines(density(theta.mh),col=3,lwd=2)
lines(density(theta.imh),col=4,lwd=2)
legend("topleft",legend=c("Exact posterior","SIR","RW-MH","I-MH"),col=1:4,bty="n",lwd=2)

6 Gibbs sampler based on data augmentation

The Student’s \(t\) distribution \[ x|\theta \sim t_\nu(\theta,1), \] can be rewritten as follows \[\begin{eqnarray*} x|\theta,\lambda \sim N(\theta,1/\lambda)\\ \lambda \sim IG(\nu/2,\nu/2). \end{eqnarray*}\] More precisely, the Student’s \(t\) distribution is a continuous scale-mixture of Gaussians with mixing distribution the Inverse Gamma: \[ p_t(x|\theta,\nu) = \int_0^\infty p_N(x|\theta,\lambda)p_{IG}(\lambda|\nu/2,\nu/2)d\lambda. \]

Therefore, augmented vector of unknown becomes \((\theta,\lambda)\), where \(\lambda=(\lambda_1,\ldots,\lambda_n)\) and the Gibbs sampler cycles through the full conditionals \(p(\theta|\mbox{data},\lambda_1,\ldots,\lambda_n)\) and \(p(\lambda_i|\mbox{data},\theta)\), for \(i=1,\ldots,n\).

  • Sampling \(\theta\): It is easy to see that \((\theta|\mbox{data},\lambda) \sim N(b,B)\), where \[ B^{-1} = 1+\sum_{i=1}^n \lambda_i^{-1} \qquad \mbox{and} \qquad b = B\sum_{i=1}^n x_i/\lambda_i. \]

  • Sampling \(\lambda_i\): It is also easy to see that \[ (\lambda_i|\mbox{data},\theta) \sim IG\left(\frac{\nu+1}{2},\frac{\nu+(x_i-\theta)^2}{2}\right), \] for \(i=1,\ldots,n\).

theta.gs = rep(0,M)
lambdas = rep(1,n)
time.gs = system.time({
for (i in 1:M){
  var     = 1/(1+sum(1/lambdas))
  mean    = var*sum(x/lambdas)
  theta   = rnorm(1,mean,sqrt(var))
  lambdas = 1/rgamma(n,(nu+1)/2,(nu+(x-theta)^2)/2)
  theta.gs[i] = theta
}
})

par(mfrow=c(2,2))
ts.plot(theta.gs,ylab="",xlab="Iterations")
abline(v=M0,col=2,lwd=2)
theta.gs = theta.gs[(M0+1):M]
acf(theta.gs,main="")
hist(theta.gs,prob=TRUE,xlab=expression(theta),ylab="Posterior",main="")
lines(thetas,post,col=2,lwd=3)

7 Comparison

ind = seq(1,M-M0,by=10)
par(mfrow=c(2,4))
plot(ind,theta.sir[ind],main="SIR",ylab="",type="l")
plot(ind,theta.mh[ind],main="Random walk MH",ylab="",type="l")
plot(ind,theta.imh[ind],main="Independent MH",ylab="",type="l")
plot(ind,theta.gs[ind],main="Data augmentation",ylab="",type="l")
acf(theta.sir,lag.max=80,main="")
acf(theta.mh,lag.max=80,main="")
acf(theta.imh,lag.max=80,main="")
acf(theta.gs,lag.max=80,main="")

par(mfrow=c(1,1))
plot(thetas,post,main="",xlab="",lwd=2,type="l")
lines(density(theta.sir),col=2,lwd=2)
lines(density(theta.mh),col=3,lwd=2)
lines(density(theta.imh),col=4,lwd=2)
lines(density(theta.gs),col=5,lwd=2)
#legend("topleft",legend=c("Exact posterior","SIR","RW-MH","I-MH","GS"),col=1:5,bty="n",lwd=2)
legend("topleft",legend=c("Exact posterior",
paste("SIR (",round(time.sir[3],2)," sec)",sep=""),
paste("RW-MH (",round(time.mh[3],2)," sec)",sep=""),
paste("I-MH (",round(time.imh[3],2)," sec)",sep=""),
paste("GS (",round(time.gs[3],2)," sec)",sep="")),col=1:5,bty="n",lwd=2)

LS0tCnRpdGxlOiAiU3R1ZGVudCdzIHQgZGF0YSIKc3VidGl0bGU6ICJTSVIsIFJXLU1ILCBJTkQtTUggYW5kIEdTIgphdXRob3I6ICJIZWRpYmVydCBGcmVpdGFzIExvcGVzIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHBhcGVyCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgoKIyBEYXRhCkJlbG93IHdlIGhhdmUgJG49MTAkIG9ic2VydmF0aW9ucyB0aGF0IHdlIHdpbGwgbW9kZWwgYXMgU3R1ZGVudCdzICR0JCB3aXRoIGtub3duIGRlZ3JlZSBvZiBmcmVlZG9tICRcbnUkLgoKYGBge3J9CnggPSBjKC0yLjMzLC0wLjUyLC0wLjUxLC0wLjM4LDAuMjUsMC43NywwLjc5LDAuODAsMS4zNSwxLjQwKQpuID0gbGVuZ3RoKHgpCmBgYAoKIyBTdHVkZW50J3MgJHQkIG1vZGVsCkZvciBhIHJhbmRvbSB2YXJpYWJsZSAkeCQgZm9sbG93aW5nIGEgbm9uLXN0YW5kYXJkaXplZCBTdHVkZW50J3MgCiR0JC1kaXN0cmlidXRpb24gd2l0aCAkXG51JCBkZWdyZWVzIG9mIGZyZWVkb20sIGxvY2F0aW9uIHBhcmFtZXRlciAKJFx0aGV0YSQsIGFuZCBzY2FsZSAkXHNpZ21hID0gMSQsIHRoZSBwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9uIAooUERGKSBpcyBnaXZlbiBieToKJCQKZih4IHwgXG51LCBcdGhldGEsIDEpID0gXGZyYWN7XEdhbW1hXGxlZnQoXGZyYWN7XG51KzF9ezJ9XHJpZ2h0KX0Ke1xHYW1tYVxsZWZ0KFxmcmFje1xudX17Mn1ccmlnaHQpIChcbnVccGkpXnsxLzJ9fSBcbGVmdFsgMSArIApcZnJhY3sxfXtcbnV9ICh4IC0gXHRoZXRhKV4yIFxyaWdodF1eey1cZnJhY3tcbnUrMX17Mn19LgokJApUaGVyZWZvcmUsIHRoZSBsaWtlbGlob29kIGZvciB0aGUgJG4kIG9ic2VydmF0aW9ucyBpcyBnaXZlbiBieQokJApMKFx0aGV0YTtcbWJveHtkYXRhfSkgXHByb3B0byBccHJvZF97aT0xfV5uIFxsZWZ0WyAxICsgClxmcmFjezF9e1xudX0gKHhfaSAtIFx0aGV0YSleMiBccmlnaHRdXnstXGZyYWN7XG51KzF9ezJ9fS4KJCQKRm9yIHNpbXBsaWNpdHksIHdlIHdpbGwgYXNzdW1lIGEgc3RhbmRhcmQgbm9ybWFsIHByaW9yIGZvciAkXHRoZXRhJCwgaWUuIAokcChcdGhldGEpIFxwcm9wdG8gXGV4cFxsZWZ0XHstMC41IFx0aGV0YV4yXHJpZ2h0XH0kLgoKT2J2aW91c2x5LCB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ0dWlvbgokJApwKFx0aGV0YXxcbWJveHtkYXRhfSkgXHByb3B0byBcZXhwXGxlZnRcey0wLjUgXHRoZXRhXjJccmlnaHRcfVxwcm9kX3tpPTF9Xm4gXGxlZnRbIDEgKyAKXGZyYWN7MX17XG51fSAoeF9pIC0gXHRoZXRhKV4yIFxyaWdodF1eey1cZnJhY3tcbnUrMX17Mn19LgokJAppcyBvZiB1bmtub3duIGZvcm0gYW5kIHBvc3RlcmlvciBpbmZlcmVuY2Ugd2lsbCBiZSBmZWFzaWJsZSB2aWEgTW9udGUgQ2FybG8gaW50ZWdyYXRpb24gYW5kIHNpbXVsYXRpb24uCkZvciBjb21wYXJpc29uLCBiZWxvdyB3ZSBldmFsdWF0ZSB0aGUgcG9zdGVyaW9yIGRlbnNpdHkgb24gYSBmaW5lIGdyaWQuICBNb3N0IHBvc3RlcmlvciBtYXNzIGxpZXMgYmV0d2VlbiAKJC0xJCBhbmQgJDEkLCB3aXRoIGEgbG9jYXRpb24gbWVhc3VyZSBhcm91bmQgJDAuMjUkLgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQpudSA9IDQKTiAgPSAxMDAKdGhldGFzID0gc2VxKC0yLDIsbGVuZ3RoPU4pCmxpa2UgPSByZXAoMCxOKQpmb3IgKGkgaW4gMTpOKQogIGxpa2VbaV0gPSBwcm9kKGR0KHgtdGhldGFzW2ldLGRmPW51KSkKcHJpb3IgPSBleHAoLXRoZXRhc14yLzIpCnBvc3QgPSBwcmlvcipsaWtlCmggPSB0aGV0YXNbMl0tdGhldGFzWzFdCnBvc3QgPSBwb3N0LyhoKnN1bShwb3N0KSkKcGxvdCh0aGV0YXMscG9zdCx0eXBlPSJsIix4bGFiPWV4cHJlc3Npb24odGhldGEpLHlsYWI9IlBvc3RlcmlvciBkZW5zaXR5IikKYGBgCgojIFNJUgoKSGVyZSB3ZSBpbXBsZW1lbnQgU0lSIHdoZXJlIHRoZSBwcm9wb3NhbCBkZW5zaXR5IGlzIHRoZSBwcmlvciwgJHAoXHRoZXRhKSQKClJlY2FsbCB0aGF0IHRoZSBTSVIgYWxnb3JpdGhtIHdvcmtzIGFzIGZvbGxvd3M6CgoxKSBTYW1wbGUgKGxhcmdlKSAkTSQgZHJhd3MgZnJvbSB0aGUgcHJpb3IgJHAoXHRoZXRhKSQKJCQKXHtcd2lkZXRpbGRle1x0aGV0YX1eeygxKX0sXGxkb3RzLFx3aWRldGlsZGV7XHRoZXRhfV57KE0pfVx9OwokJAoKMikgRXZhbHV0ZSB0aGUgd2VpZ2h0cyAkXG9tZWdhXnsoaSl9IFxwcm9wdG8gTChcd2lkZXRpbGRle1x0aGV0YX1eeyhpKX07XG1ib3h7ZGF0YX0pJDsKCjMpIFJlc2FtcGxlICRNXzEgXGxlcSBNJCBmcm9tIHRoZSBkaXNjcmV0ZSBzZXQgJFx7XHdpZGV0aWxkZXtcdGhldGF9XnsoMSl9LFxsZG90cyxcd2lkZXRpbGRle1x0aGV0YX1eeyhNKX1cfSQgIHdpdGggcHJvYmFiaWxpdGllcyAkXHtcb21lZ2FeeygxKX0sXGxkb3RzLFxvbWVnYV57KE0pfVx9JC4KCkl0IGNhbiBiZSBzaG93biB0aGF0IHRoZSBmaW5hbCBzYW1wbGVkIHNldCwgc2F5IAokJApce1x0aGV0YV57KDEpfSxcbGRvdHMsXHRoZXRhXnsoTV8xKX1cfSwKJCQKYXBwcm94aW1hdGVzIGEgc2FtcGxlIGZyb20gJHAoXHRoZXRhfFxtYm94e2RhdGF9KSQuICBNb3JlIGRldGFpbHMgYWJvdXQgTW9udGUgQ2FybG8gaW50ZWdyYXRpb24sIE1DIHNpbXVsYXRpb24sIFNJUiBhbmQgb3RoZXIgTW9udGUgQ2FybG8gc2NoZW1lcywgY2FuIGJlIGZvdW5kIGluIG15IGNvdXJzZSBub3RlcyBbaGVyZV0oaHR0cHM6Ly9oZWRpYmVydC5vcmcvd3AtY29udGVudC91cGxvYWRzLzIwMjAvMDEvYXByZW5kaXphZ2VtYmF5ZXNpYW5hLWJheWVzaWFuY29tcHV0YXRpb24ucGRmKS4KCgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQpNICA9IDEwMDAwMApNMSA9IDIwMDAwCnRpbWUuc2lyID0gc3lzdGVtLnRpbWUoewp0aGV0YS5kcmF3ID0gcm5vcm0oTSkKdyA9IHJlcCgwLE0pCmZvciAoaSBpbiAxOk0pCiAgd1tpXSA9IHByb2QoZHQoeC10aGV0YS5kcmF3W2ldLGRmPW51KSkKdGhldGEuc2lyID0gc2FtcGxlKHRoZXRhLmRyYXcsc2l6ZT1NMSxyZXBsYWNlPVRSVUUscHJvYj13KQp9KQoKaGlzdCh0aGV0YS5zaXIscHJvYj1UUlVFLHhsYWI9ZXhwcmVzc2lvbih0aGV0YSkseWxhYj0iUG9zdGVyaW9yIixtYWluPSIiKQpsaW5lcyh0aGV0YXMscG9zdCxjb2w9Mixsd2Q9MykKYGBgCgojIFJhbmRvbS13YWxrIE1ldHJvcG9saXMKClRoZSByYW5kb20td2FsayBNZXRyb3BvbGlzLUhhc3RpbmdzIHZhcmlhbmNlIGlzIHByZXR0eSBzbWFsbCwgJHRhdT0wLjE0JC4gIFdpdGggc3RhcnRpbmcgdmFsdWUgYXQgJFx0aGV0YV57KDApfT0wJCwgdGhlIHJhbmRvbS13YWxrIG1NZXRyb3BvbGlzLUhhc3RpbmdzIGFsZ29yaXRobSB3b3JrcyBhcyBmb2xsb3dzLCBhc3N1bWluZyB0aGUgYWxnb3JpdGhtIGlzIGF0IGl0ZXJhdGlvbiAkaSQ6CgoxLiBTYW1wbGUgJFx0aGV0YV4qIFxzaW0gTihcdGhldGFeeyhpLTEpfSxcdGF1XjIpJAoyLiBDb21wdXRlIGFjY2VwdGFuY2UgcHJvYmFiaWxpdHkKJCQKXGFscGhhID0gXG1pblxsZWZ0XHsxLFxmcmFje3AoXHRoZXRhXiopTChcdGhldGFeKjtcbWJveHtkYXRhfSl9e3AoXHRoZXRhXnsoaS0xKX0pTChcdGhldGFeeyhpLTEpfTtcbWJveHtkYXRhfSl9XHJpZ2h0XH0KJCQKMy4gV2l0aCBwcm9iYWJpbGl0eSAkXGFscGhhJCwgbWFrZSAkXHRoZXRhXnsoaSl9PVx0aGV0YV4qJDsgb3RoZXJ3aXNlLCBtYWtlICRcdGhldGFeeyhpKX09XHRoZXRhXnsoaS0xKX0kLgoKNC4gTWFrZSAkaT1pKzEkIGFuZCByZXBlYXQgc3RlcHMgMSB0byA0IHVudGlsICRpPU0kLiAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTd9CnRoZXRhID0gMAp0YXUgPSAwLjEKTTAgPSBNLU0xCnRoZXRhLm1oID0gcmVwKDAsTSkKdGltZS5taCA9IHN5c3RlbS50aW1lKHsKZm9yIChpdGVyIGluIDE6TSl7CiAgdGhldGExID0gcm5vcm0oMSx0aGV0YSx0YXUpCiAgYWNjZXB0ID0gbWluKDEscHJvZChkdCh4LXRoZXRhMSxkZj1udSkpL3Byb2QoZHQoeC10aGV0YSxkZj1udSkpKgogICAgICAgICAgICAgICAgIGRub3JtKHRoZXRhMSkvZG5vcm0odGhldGEpKQogIGlmIChydW5pZigxKTxhY2NlcHQpewogIHRoZXRhID0gdGhldGExCiAgfQogIHRoZXRhLm1oW2l0ZXJdID0gdGhldGEKfQp9KQoKcGFyKG1mcm93PWMoMiwyKSkKdHMucGxvdCh0aGV0YS5taCx5bGFiPSIiLHhsYWI9Ikl0ZXJhdGlvbnMiKQphYmxpbmUodj1NMCxjb2w9Mixsd2Q9MikKdGhldGEubWggPSB0aGV0YS5taFsoTTArMSk6TV0KYWNmKHRoZXRhLm1oLG1haW49IiIpCmhpc3QodGhldGEubWgscHJvYj1UUlVFLHhsYWI9ZXhwcmVzc2lvbih0aGV0YSkseWxhYj0iUG9zdGVyaW9yIixtYWluPSIiKQpsaW5lcyh0aGV0YXMscG9zdCxjb2w9Mixsd2Q9MykKcGxvdCh0aGV0YXMscG9zdCxtYWluPSIiLHhsYWI9IiIsbHdkPTIsdHlwZT0ibCIpCmxpbmVzKGRlbnNpdHkodGhldGEuc2lyKSxjb2w9Mixsd2Q9MikKbGluZXMoZGVuc2l0eSh0aGV0YS5taCksY29sPTQsbHdkPTIpCmBgYAoKIyBJbmRlcGVuZGVudCBNZXRyb3BvbGlzLUhhc3RpbmdzCgpUaGUgcHJvcG9zYWwgZGlzdHJpYnV0aW9uIGlzIEdhdXNzaWFuIHdpdGggbWVhbiAkXG11PTAkIGFuZCB2YXJpYW5jZSAkdl4yPTE2JC4KV2l0aCBzdGFydGluZyB2YWx1ZSBhdCAkXHRoZXRhXnsoMCl9PTAkLCB0aGUgaW5kZXBlbmRlbnQgTWV0cm9wb2xpcy1IYXN0aW5ncyBhbGdvcml0aG0gd29ya3MgYXMgZm9sbG93cywgYXNzdW1pbmcgdGhlIGFsZ29yaXRobSBpcyBhdCBpdGVyYXRpb24gJGkkOgoKMS4gU2FtcGxlICRcdGhldGFeKiBcc2ltIE4oXG11LHZeMikkCjIuIENvbXB1dGUgYWNjZXB0YW5jZSBwcm9iYWJpbGl0eQokJApcYWxwaGEgPSBcbWluXGxlZnRcezEsXGZyYWN7cChcdGhldGFeKilMKFx0aGV0YV4qO1xtYm94e2RhdGF9KX17cChcdGhldGFeeyhpLTEpfSlMKFx0aGV0YV57KGktMSl9O1xtYm94e2RhdGF9KX0KXGZyYWN7cF9OKFx0aGV0YV57KGktMSl9fFxtdSx2XjIpfXtwX04oXHRoZXRhXip8XG11LHZeMil9ClxyaWdodFx9CiQkCjMuIFdpdGggcHJvYmFiaWxpdHkgJFxhbHBoYSQsIG1ha2UgJFx0aGV0YV57KGkpfT1cdGhldGFeKiQ7IG90aGVyd2lzZSwgbWFrZSAkXHRoZXRhXnsoaSl9PVx0aGV0YV57KGktMSl9JC4KCjQuIE1ha2UgJGk9aSsxJCBhbmQgcmVwZWF0IHN0ZXBzIDEgdG8gNCB1bnRpbCAkaT1NJC4gCgoKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTd9CnRoZXRhMCA9IDAKbXUgPSAwCnYgPSAyCnRoZXRhLmltaCA9IHJlcCgwLE0pCnRpbWUuaW1oID0gc3lzdGVtLnRpbWUoewpmb3IgKGl0ZXIgaW4gMTpNKXsKICB0aGV0YTEgPSBybm9ybSgxLG11LHYpCiAgYWNjZXB0ID0gbWluKDEscHJvZChkdCh4LXRoZXRhMSxkZj1udSkpL3Byb2QoZHQoeC10aGV0YSxkZj1udSkpKgogICAgICAgICAgICAgICAgIGRub3JtKHRoZXRhMSkvZG5vcm0odGhldGEpKgogICAgICAgICAgICAgICAgIGRub3JtKHRoZXRhLG11LHYpL2Rub3JtKHRoZXRhMSxtdSx2KSkKICBpZiAocnVuaWYoMSk8YWNjZXB0KXsKICAgIHRoZXRhID0gdGhldGExCiAgfQogIHRoZXRhLmltaFtpdGVyXSA9IHRoZXRhCn0KfSkKCnBhcihtZnJvdz1jKDIsMikpCnRzLnBsb3QodGhldGEuaW1oLHlsYWI9IiIseGxhYj0iSXRlcmF0aW9ucyIpCmFibGluZSh2PU0wLGNvbD0yLGx3ZD0yKQp0aGV0YS5pbWggPSB0aGV0YS5pbWhbKE0wKzEpOk1dCmFjZih0aGV0YS5pbWgsbWFpbj0iIikKaGlzdCh0aGV0YS5pbWgscHJvYj1UUlVFLHhsYWI9ZXhwcmVzc2lvbih0aGV0YSkseWxhYj0iUG9zdGVyaW9yIixtYWluPSIiKQpsaW5lcyh0aGV0YXMscG9zdCxjb2w9Mixsd2Q9MykKCnBhcihtZnJvdz1jKDIsMykpCnRzLnBsb3QodGhldGEuc2lyLG1haW49IlNJUiIseWxhYj0iIikKdHMucGxvdCh0aGV0YS5taCxtYWluPSJSYW5kb20gd2FsayBNSCIseWxhYj0iIikKdHMucGxvdCh0aGV0YS5pbWgsbWFpbj0iSW5kZXBlbmRlbnQgTUgiLHlsYWI9IiIpCmFjZih0aGV0YS5zaXIsbGFnLm1heD04MCxtYWluPSIiKQphY2YodGhldGEubWgsbGFnLm1heD04MCxtYWluPSIiKQphY2YodGhldGEuaW1oLGxhZy5tYXg9ODAsbWFpbj0iIikKCnBhcihtZnJvdz1jKDEsMSkpCnBsb3QodGhldGFzLHBvc3QsbWFpbj0iIix4bGFiPSIiLGx3ZD0yLHR5cGU9ImwiKQpsaW5lcyhkZW5zaXR5KHRoZXRhLnNpciksY29sPTIsbHdkPTIpCmxpbmVzKGRlbnNpdHkodGhldGEubWgpLGNvbD0zLGx3ZD0yKQpsaW5lcyhkZW5zaXR5KHRoZXRhLmltaCksY29sPTQsbHdkPTIpCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWMoIkV4YWN0IHBvc3RlcmlvciIsIlNJUiIsIlJXLU1IIiwiSS1NSCIpLGNvbD0xOjQsYnR5PSJuIixsd2Q9MikKYGBgCgojIEdpYmJzIHNhbXBsZXIgYmFzZWQgb24gZGF0YSBhdWdtZW50YXRpb24KClRoZSBTdHVkZW50J3MgJHQkIGRpc3RyaWJ1dGlvbiAKJCQKeHxcdGhldGEgXHNpbSB0X1xudShcdGhldGEsMSksCiQkCmNhbiBiZSByZXdyaXR0ZW4gYXMgZm9sbG93cwpcYmVnaW57ZXFuYXJyYXkqfQp4fFx0aGV0YSxcbGFtYmRhIFxzaW0gTihcdGhldGEsMS9cbGFtYmRhKVxcClxsYW1iZGEgXHNpbSBJRyhcbnUvMixcbnUvMikuClxlbmR7ZXFuYXJyYXkqfQpNb3JlIHByZWNpc2VseSwgdGhlIFN0dWRlbnQncyAkdCQgZGlzdHJpYnV0aW9uIGlzIGEgY29udGludW91cyBzY2FsZS1taXh0dXJlIG9mIEdhdXNzaWFucyB3aXRoIG1peGluZyBkaXN0cmlidXRpb24gdGhlIEludmVyc2UgR2FtbWE6CiQkCnBfdCh4fFx0aGV0YSxcbnUpID0gXGludF8wXlxpbmZ0eSBwX04oeHxcdGhldGEsXGxhbWJkYSlwX3tJR30oXGxhbWJkYXxcbnUvMixcbnUvMilkXGxhbWJkYS4KJCQKClRoZXJlZm9yZSwgYXVnbWVudGVkIHZlY3RvciBvZiB1bmtub3duIGJlY29tZXMgJChcdGhldGEsXGxhbWJkYSkkLCB3aGVyZSAkXGxhbWJkYT0oXGxhbWJkYV8xLFxsZG90cyxcbGFtYmRhX24pJCBhbmQgdGhlIEdpYmJzIHNhbXBsZXIgY3ljbGVzIHRocm91Z2ggdGhlIGZ1bGwgY29uZGl0aW9uYWxzICRwKFx0aGV0YXxcbWJveHtkYXRhfSxcbGFtYmRhXzEsXGxkb3RzLFxsYW1iZGFfbikkIGFuZCAkcChcbGFtYmRhX2l8XG1ib3h7ZGF0YX0sXHRoZXRhKSQsIGZvciAkaT0xLFxsZG90cyxuJC4KCiogU2FtcGxpbmcgJFx0aGV0YSQ6IEl0IGlzIGVhc3kgdG8gc2VlIHRoYXQgJChcdGhldGF8XG1ib3h7ZGF0YX0sXGxhbWJkYSkgXHNpbSBOKGIsQikkLAp3aGVyZSAKJCQKQl57LTF9ID0gMStcc3VtX3tpPTF9Xm4gXGxhbWJkYV9pXnstMX0gXHFxdWFkIFxtYm94e2FuZH0gXHFxdWFkCmIgPSBCXHN1bV97aT0xfV5uIHhfaS9cbGFtYmRhX2kuCiQkCgoqIFNhbXBsaW5nICRcbGFtYmRhX2kkOiBJdCBpcyBhbHNvIGVhc3kgdG8gc2VlIHRoYXQgCiQkCihcbGFtYmRhX2l8XG1ib3h7ZGF0YX0sXHRoZXRhKSBcc2ltIElHXGxlZnQoXGZyYWN7XG51KzF9ezJ9LFxmcmFje1xudSsoeF9pLVx0aGV0YSleMn17Mn1ccmlnaHQpLAokJApmb3IgJGk9MSxcbGRvdHMsbiQuCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fQp0aGV0YS5ncyA9IHJlcCgwLE0pCmxhbWJkYXMgPSByZXAoMSxuKQp0aW1lLmdzID0gc3lzdGVtLnRpbWUoewpmb3IgKGkgaW4gMTpNKXsKICB2YXIgICAgID0gMS8oMStzdW0oMS9sYW1iZGFzKSkKICBtZWFuICAgID0gdmFyKnN1bSh4L2xhbWJkYXMpCiAgdGhldGEgICA9IHJub3JtKDEsbWVhbixzcXJ0KHZhcikpCiAgbGFtYmRhcyA9IDEvcmdhbW1hKG4sKG51KzEpLzIsKG51Kyh4LXRoZXRhKV4yKS8yKQogIHRoZXRhLmdzW2ldID0gdGhldGEKfQp9KQoKcGFyKG1mcm93PWMoMiwyKSkKdHMucGxvdCh0aGV0YS5ncyx5bGFiPSIiLHhsYWI9Ikl0ZXJhdGlvbnMiKQphYmxpbmUodj1NMCxjb2w9Mixsd2Q9MikKdGhldGEuZ3MgPSB0aGV0YS5nc1soTTArMSk6TV0KYWNmKHRoZXRhLmdzLG1haW49IiIpCmhpc3QodGhldGEuZ3MscHJvYj1UUlVFLHhsYWI9ZXhwcmVzc2lvbih0aGV0YSkseWxhYj0iUG9zdGVyaW9yIixtYWluPSIiKQpsaW5lcyh0aGV0YXMscG9zdCxjb2w9Mixsd2Q9MykKYGBgCgoKIyBDb21wYXJpc29uCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQppbmQgPSBzZXEoMSxNLU0wLGJ5PTEwKQpwYXIobWZyb3c9YygyLDQpKQpwbG90KGluZCx0aGV0YS5zaXJbaW5kXSxtYWluPSJTSVIiLHlsYWI9IiIsdHlwZT0ibCIpCnBsb3QoaW5kLHRoZXRhLm1oW2luZF0sbWFpbj0iUmFuZG9tIHdhbGsgTUgiLHlsYWI9IiIsdHlwZT0ibCIpCnBsb3QoaW5kLHRoZXRhLmltaFtpbmRdLG1haW49IkluZGVwZW5kZW50IE1IIix5bGFiPSIiLHR5cGU9ImwiKQpwbG90KGluZCx0aGV0YS5nc1tpbmRdLG1haW49IkRhdGEgYXVnbWVudGF0aW9uIix5bGFiPSIiLHR5cGU9ImwiKQphY2YodGhldGEuc2lyLGxhZy5tYXg9ODAsbWFpbj0iIikKYWNmKHRoZXRhLm1oLGxhZy5tYXg9ODAsbWFpbj0iIikKYWNmKHRoZXRhLmltaCxsYWcubWF4PTgwLG1haW49IiIpCmFjZih0aGV0YS5ncyxsYWcubWF4PTgwLG1haW49IiIpCgoKcGFyKG1mcm93PWMoMSwxKSkKcGxvdCh0aGV0YXMscG9zdCxtYWluPSIiLHhsYWI9IiIsbHdkPTIsdHlwZT0ibCIpCmxpbmVzKGRlbnNpdHkodGhldGEuc2lyKSxjb2w9Mixsd2Q9MikKbGluZXMoZGVuc2l0eSh0aGV0YS5taCksY29sPTMsbHdkPTIpCmxpbmVzKGRlbnNpdHkodGhldGEuaW1oKSxjb2w9NCxsd2Q9MikKbGluZXMoZGVuc2l0eSh0aGV0YS5ncyksY29sPTUsbHdkPTIpCiNsZWdlbmQoInRvcGxlZnQiLGxlZ2VuZD1jKCJFeGFjdCBwb3N0ZXJpb3IiLCJTSVIiLCJSVy1NSCIsIkktTUgiLCJHUyIpLGNvbD0xOjUsYnR5PSJuIixsd2Q9MikKbGVnZW5kKCJ0b3BsZWZ0IixsZWdlbmQ9YygiRXhhY3QgcG9zdGVyaW9yIiwKcGFzdGUoIlNJUiAoIixyb3VuZCh0aW1lLnNpclszXSwyKSwiIHNlYykiLHNlcD0iIiksCnBhc3RlKCJSVy1NSCAoIixyb3VuZCh0aW1lLm1oWzNdLDIpLCIgc2VjKSIsc2VwPSIiKSwKcGFzdGUoIkktTUggKCIscm91bmQodGltZS5pbWhbM10sMiksIiBzZWMpIixzZXA9IiIpLApwYXN0ZSgiR1MgKCIscm91bmQodGltZS5nc1szXSwyKSwiIHNlYykiLHNlcD0iIikpLGNvbD0xOjUsYnR5PSJuIixsd2Q9MikKYGBgCg==