Example 1: a local-level dynamic linear model

Here we revisit the most basic normal dynamic linear model: \[\begin{eqnarray*} y_t &=& x_t + \epsilon_t \qquad \epsilon_t \sim N(0,\sigma^2)\\ x_t &=& x_{t-1} + \omega_t \qquad \omega_t \sim N(0,\tau^2). \end{eqnarray*}\]

Below we simulated some data from this model.

set.seed(54321)
n     = 100
sig2  = 1.00
tau2  = 0.25
x     = rnorm(n)
for (t in 2:n)
  x[t] = x[t-1]+rnorm(1,0,sqrt(tau2))
y = x + rnorm(n,0,sqrt(sig2))

par(mfrow=c(1,1))
plot(y,xlab="Time",ylab="",type="b",pch=16,lwd=2)
lines(x,col=2,lwd=2,type="b",pch=16)
legend("topright",legend=c("Y(t)","X(t)"),col=1:2,lwd=2,lty=1)

The Kalman filter

Let us assume that \(x_0|D_0 \sim N(m_0,C_0)\), for known \((\sigma^2,\tau^2,m_0,C_0)\) and \(D_0\) the information set up to time \(t=0\), so \(D_t=\{D_{t-1},y_t\}\). As we learned in class, the Kalman recursions can be used to show that, for \(x_{t-1}|D_{t-1} \sim N(m_{t-1},C_{t-1})\), we can derive the sequential distributions: \[\begin{eqnarray*} x_t|D_{t-1} &\sim& N(m_{t-1},C_{t-1}+\tau^2)\\ x_t|D_t &\sim& N(m_t,C_t), \end{eqnarray*}\] where \[\begin{eqnarray*} m_t &=& (1-A_t)m_{t-1} + A_t y_t\\ C_t &=& C_{t-1} + \tau^2 - A_t^2(C_{t-1}+\tau^2+\sigma^2)\\ A_t &=& \frac{C_{t-1}+\tau^2}{C_{t-1}+\tau^2+\sigma^2}. \end{eqnarray*}\]

m0   = 0
C0   = 1
m    = m0
C    = C0
mf   = rep(0,n)
Cf   = rep(0,n)

for (t in 1:n){
  A     = (C+tau2)/(C+tau2+sig2)
  m     = (1-A)*m + A*y[t]
  C     = C + tau2 - A^2*(C+tau2+sig2)
  mf[t] = m
  Cf[t] = C
}
qf = cbind(mf+qnorm(0.025)*sqrt(Cf),mf,mf+qnorm(0.975)*sqrt(Cf))

par(mfrow=c(1,1))
ts.plot(qf,lwd=2,lty=c(2,1,2),ylab="State")
points(y,col=2,pch=16)
lines(x,col=6,lwd=2)
legend("topright",legend=c("data","states","posterior"),col=c(2,6,1),lwd=2)

Revisiting sampling importance resampling (SIR)

The SIR scheme uses samples from a proposal distribution, \(q(\theta)\), in order to sample from the target distribution, \(p(\theta)\). Below, we assume that \(p(\theta)\) is \(N(0,3)\) and that \(q(\theta)\) is \(t_3(0,1)\). To sum up, the SIR is implemented as follows:

set.seed(123567)
M        = 100000
thetas.q = rt(M,df=3)
w        = dnorm(thetas.q,0,sqrt(3))/dt(thetas.q,df=3)
thetas.p = sample(thetas.q,size=M,replace=TRUE,prob=w)

par(mfrow=c(1,2))
xbreaks = seq(min(thetas.q),max(thetas.q),length=200)
hist(thetas.q,breaks=xbreaks,prob=TRUE,main="Draws from proposal",xlim=c(-10,10),ylim=c(0,0.4),xlab="Theta")
xx = seq(min(thetas.q),max(thetas.q),length=1000)
lines(xx,dt(xx,df=3),col=2,lwd=2)
xbreaks = seq(min(thetas.p),max(thetas.p),length=30)
hist(thetas.p,breaks=xbreaks,prob=TRUE,main="Draws from target\nvia SIR",
     xlim=c(-10,10),ylim=c(0,0.4),xlab="Theta")
xx = seq(min(thetas.p),max(thetas.p),length=1000)
lines(xx,dnorm(xx,0,sqrt(3)),col=2,lwd=2)

Example 1: The Bootstrap filter

The Boostrap filter is basically the SIR applied sequentially in the dynamic model framework. More precisely, let \(\{x_{t-1}^{(1)},\ldots,x_{t-1}^{(M)}\}\) be a sample from \(p(x_{t-1}|D_{t-1})\).

Closer look at from \(t=0\) to \(t=1\)

set.seed(12345)
m0     = 0
C0     = 1
M      = 10000

# x0|D0
x0post   = rnorm(M,m0,sqrt(C0))

# x1|D0
x1prior = rnorm(M,x0post,sqrt(tau2))

# x1|D1
w      = dnorm(y[1],x1prior,sqrt(sig2))
x1post = sample(x1prior,size=M,replace=TRUE,prob=w)

par(mfrow=c(1,3))
hist(x0post,xlab="",prob=TRUE,main="p(x0|D0)")
hist(x1prior,xlab="",prob=TRUE,main="p(x1|D0)")
hist(x1post,xlab="",prob=TRUE,main="p(x1|D1)")
points(y[1],0,col=3,pch=16,cex=2)

For \(t=2,\ldots,n\)

xdraws     = matrix(0,n,M)
x          = x1post
xdraws[1,] = x

for (t in 2:n){
  xprior  = rnorm(M,x,sqrt(tau2))
  weights = dnorm(y[t],xprior,sqrt(sig2))
  x       = sample(xprior,size=M,replace=TRUE,prob=weights)
  xdraws[t,] = x
}
qpf = t(apply(xdraws,1,quantile,c(0.025,0.5,0.975)))
ind = c(5,6,7,42,43,44,98,99,n)
par(mfrow=c(3,3))
for (i in ind){
  hist(xdraws[i,],xlab="",prob=TRUE,main=paste("p(x",i,"|D",i,")",sep=""))
  points(y[i],0,col=3,pch=16,cex=2)
  xxx = seq(min(xdraws[i,]),max(xdraws[i,]),length=200)
  lines(xxx,dnorm(xxx,mf[i],sqrt(Cf[i])),col=2,lwd=2)
}

par(mfrow=c(1,1))
ts.plot(qf,lwd=2,ylim=range(qf,qpf))
lines(qpf[,1],col=2,lwd=2)
lines(qpf[,2],col=2,lwd=2)
lines(qpf[,3],col=2,lwd=2)
legend("topleft",legend=c("Kalman filter","Particle filter"),col=1:2,lwd=2)
title(paste("M=",M," particles",sep=""))

Example 2: a nonlinear dynamic model

Let us now illustrate the Bootstrap filter for a nonlinear dynamic model, where the nonlinearity appears in the observation equation: \[\begin{eqnarray*} y_t &=& |x_t| + \epsilon_t \qquad \epsilon_t \sim N(0,\sigma^2)\\ x_t &=& x_{t-1} + \omega_t \qquad \omega_t \sim N(0,\tau^2). \end{eqnarray*}\]

set.seed(54321)
n     = 100
sig2  = 1.00
tau2  = 0.25
x     = rep(0,n)
for (t in 2:n)
  x[t] = x[t-1] + rnorm(1,0,sqrt(tau2))
y = abs(x) + rnorm(n,0,sqrt(sig2))
x.true = x

par(mfrow=c(1,1))
plot(y,xlab="Time",ylab="",type="b",pch=16,lwd=2,ylim=range(x,y))
lines(x,col=2,lwd=2,type="b",pch=16)
legend("top",legend=c("Y(t)","X(t)"),col=1:2,lwd=2,lty=1)
abline(h=0,lty=2,lwd=2)

The Boostrap filter

set.seed(12345)
m0     = 0
C0     = 1
M      = 10000
xdraws = matrix(0,n,M)
x      = rnorm(M,m0,sqrt(C0))
for (t in 1:n){
  xprior  = rnorm(M,x,sqrt(tau2))
  weights = dnorm(y[t],abs(xprior),sqrt(sig2))
  x       = sample(xprior,size=M,replace=TRUE,prob=weights)
  xdraws[t,] = x
}
ts = c(1:5,(n/2-2):(n/2+2),(n-4):n)
par(mfrow=c(3,5))
for (t in (n-14):n){
  hist(xdraws[t,],xlab="",prob=TRUE,main="",ylab="Posterior density",xlim=range(xdraws),ylim=c(0,0.5))
  legend("topleft",legend=paste("t=",t,sep=""),bty="n")
  points(y[t],0,col=2,pch=16,cex=2)
}

N = 100
dens = matrix(0,n,N)
for (t in 1:n){
  den = density(abs(xdraws[t,]),from=-8,to=7,n=N)
  dens[t,] = den$y
}
xx = den$x

par(mfrow=c(1,1))
contour(1:n,xx,dens,nlevels=20,ylim=range(y))
points(abs(x.true),col=3,pch=16)
abline(h=0,col=4,lwd=2)
points(y,col=2,pch=16)
legend("topleft",legend=c("Data","|States|","Posteriors"),col=c(2,3,1),lwd=2,lty=1)

LS0tCnRpdGxlOiAiU2VxdWVudGlhbCBNb250ZSBDYXJsbyIKc3VidGl0bGU6ICJUaGUgQm9vc3RyYXAgZmlsdGVyIgphdXRob3I6ICJIZWRpYmVydCBGcmVpdGFzIExvcGVzIgpkYXRlOiAiNC8xNC8yMDIyIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMgRXhhbXBsZSAxOiBhIGxvY2FsLWxldmVsIGR5bmFtaWMgbGluZWFyIG1vZGVsCgpIZXJlIHdlIHJldmlzaXQgdGhlIG1vc3QgYmFzaWMgbm9ybWFsIGR5bmFtaWMgbGluZWFyIG1vZGVsOgpcYmVnaW57ZXFuYXJyYXkqfQp5X3QgJj0mIHhfdCArIFxlcHNpbG9uX3QgXHFxdWFkIFxlcHNpbG9uX3QgXHNpbSBOKDAsXHNpZ21hXjIpXFwKeF90ICY9JiB4X3t0LTF9ICsgXG9tZWdhX3QgXHFxdWFkIFxvbWVnYV90IFxzaW0gTigwLFx0YXVeMikuClxlbmR7ZXFuYXJyYXkqfQoKQmVsb3cgd2Ugc2ltdWxhdGVkIHNvbWUgZGF0YSBmcm9tIHRoaXMgbW9kZWwuCgpgYGB7ciBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD02fQpzZXQuc2VlZCg1NDMyMSkKbiAgICAgPSAxMDAKc2lnMiAgPSAxLjAwCnRhdTIgID0gMC4yNQp4ICAgICA9IHJub3JtKG4pCmZvciAodCBpbiAyOm4pCiAgeFt0XSA9IHhbdC0xXStybm9ybSgxLDAsc3FydCh0YXUyKSkKeSA9IHggKyBybm9ybShuLDAsc3FydChzaWcyKSkKCnBhcihtZnJvdz1jKDEsMSkpCnBsb3QoeSx4bGFiPSJUaW1lIix5bGFiPSIiLHR5cGU9ImIiLHBjaD0xNixsd2Q9MikKbGluZXMoeCxjb2w9Mixsd2Q9Mix0eXBlPSJiIixwY2g9MTYpCmxlZ2VuZCgidG9wcmlnaHQiLGxlZ2VuZD1jKCJZKHQpIiwiWCh0KSIpLGNvbD0xOjIsbHdkPTIsbHR5PTEpCmBgYAoKIyMgVGhlIEthbG1hbiBmaWx0ZXIKCkxldCB1cyBhc3N1bWUgdGhhdCAkeF8wfERfMCBcc2ltIE4obV8wLENfMCkkLCBmb3Iga25vd24gJChcc2lnbWFeMixcdGF1XjIsbV8wLENfMCkkIGFuZCAKJERfMCQgdGhlIGluZm9ybWF0aW9uIHNldCB1cCB0byB0aW1lICR0PTAkLCBzbyAkRF90PVx7RF97dC0xfSx5X3RcfSQuCkFzIHdlIGxlYXJuZWQgaW4gY2xhc3MsIHRoZSBLYWxtYW4gcmVjdXJzaW9ucyBjYW4gYmUgdXNlZCB0byBzaG93IHRoYXQsIGZvciAkeF97dC0xfXxEX3t0LTF9IFxzaW0gTihtX3t0LTF9LENfe3QtMX0pJCwgd2UgY2FuIGRlcml2ZSB0aGUgc2VxdWVudGlhbCBkaXN0cmlidXRpb25zOgpcYmVnaW57ZXFuYXJyYXkqfQp4X3R8RF97dC0xfSAmXHNpbSYgTihtX3t0LTF9LENfe3QtMX0rXHRhdV4yKVxcCnhfdHxEX3QgJlxzaW0mIE4obV90LENfdCksClxlbmR7ZXFuYXJyYXkqfQp3aGVyZSAKXGJlZ2lue2VxbmFycmF5Kn0KbV90ICY9JiAoMS1BX3QpbV97dC0xfSArIEFfdCB5X3RcXApDX3QgJj0mIENfe3QtMX0gKyBcdGF1XjIgLSBBX3ReMihDX3t0LTF9K1x0YXVeMitcc2lnbWFeMilcXApBX3QgJj0mIFxmcmFje0Nfe3QtMX0rXHRhdV4yfXtDX3t0LTF9K1x0YXVeMitcc2lnbWFeMn0uClxlbmR7ZXFuYXJyYXkqfQoKYGBge3IgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9Nn0KbTAgICA9IDAKQzAgICA9IDEKbSAgICA9IG0wCkMgICAgPSBDMAptZiAgID0gcmVwKDAsbikKQ2YgICA9IHJlcCgwLG4pCgpmb3IgKHQgaW4gMTpuKXsKICBBICAgICA9IChDK3RhdTIpLyhDK3RhdTIrc2lnMikKICBtICAgICA9ICgxLUEpKm0gKyBBKnlbdF0KICBDICAgICA9IEMgKyB0YXUyIC0gQV4yKihDK3RhdTIrc2lnMikKICBtZlt0XSA9IG0KICBDZlt0XSA9IEMKfQpxZiA9IGNiaW5kKG1mK3Fub3JtKDAuMDI1KSpzcXJ0KENmKSxtZixtZitxbm9ybSgwLjk3NSkqc3FydChDZikpCgpwYXIobWZyb3c9YygxLDEpKQp0cy5wbG90KHFmLGx3ZD0yLGx0eT1jKDIsMSwyKSx5bGFiPSJTdGF0ZSIpCnBvaW50cyh5LGNvbD0yLHBjaD0xNikKbGluZXMoeCxjb2w9Nixsd2Q9MikKbGVnZW5kKCJ0b3ByaWdodCIsbGVnZW5kPWMoImRhdGEiLCJzdGF0ZXMiLCJwb3N0ZXJpb3IiKSxjb2w9YygyLDYsMSksbHdkPTIpCmBgYAoKIyBSZXZpc2l0aW5nIHNhbXBsaW5nIGltcG9ydGFuY2UgcmVzYW1wbGluZyAoU0lSKQoKVGhlIFNJUiBzY2hlbWUgdXNlcyBzYW1wbGVzIGZyb20gYSBwcm9wb3NhbCBkaXN0cmlidXRpb24sICRxKFx0aGV0YSkkLCBpbiBvcmRlciB0byBzYW1wbGUgZnJvbSB0aGUgdGFyZ2V0IGRpc3RyaWJ1dGlvbiwgJHAoXHRoZXRhKSQuICBCZWxvdywgd2UgYXNzdW1lIHRoYXQgJHAoXHRoZXRhKSQgaXMgJE4oMCwzKSQgYW5kIHRoYXQgJHEoXHRoZXRhKSQgaXMgJHRfMygwLDEpJC4gIFRvIHN1bSB1cCwgdGhlIFNJUiBpcyBpbXBsZW1lbnRlZCBhcyBmb2xsb3dzOgoKKiBTYW1wbGUgJFx7e1x0aWxkZSBcdGhldGF9XnsoMSl9LFxsZG90cyx7XHRpbGRlIFx0aGV0YX1eeyhNKX1cfSQgZnJvbSAkcShcdGhldGEpJC4KCiogQ29tcHV0ZSByZXNhbXBsaW5nIHdlaWdodHMsIGZvciAkaT0xLFxsZG90cyxNJAokJApcb21lZ2FeeyhpKX0gXHByb3B0byBcZnJhY3twKHtcdGlsZGUgXHRoZXRhfV57KGkpfSl9e3Eoe1x0aWxkZSBcdGhldGF9XnsoaSl9KX0uCiQkCgoqIEZvciAkaj0xLFxsZG90cyxNJCwgc2FtcGxlICRcdGhldGFeeyhqKX0kIGZyb20gJFx7e1x0aWxkZSBcdGhldGF9XnsoMSl9LFxsZG90cyx7XHRpbGRlIFx0aGV0YX1eeyhNKX1cfSQgd2l0aCBwcm9iYWJpbGl0aWVzICRce1xvbWVnYV57KDEpfSxcbGRvdHMsXG9tZWdhXnsoTSl9XH0kLgoKYGBge3IgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9Nn0Kc2V0LnNlZWQoMTIzNTY3KQpNICAgICAgICA9IDEwMDAwMAp0aGV0YXMucSA9IHJ0KE0sZGY9MykKdyAgICAgICAgPSBkbm9ybSh0aGV0YXMucSwwLHNxcnQoMykpL2R0KHRoZXRhcy5xLGRmPTMpCnRoZXRhcy5wID0gc2FtcGxlKHRoZXRhcy5xLHNpemU9TSxyZXBsYWNlPVRSVUUscHJvYj13KQoKcGFyKG1mcm93PWMoMSwyKSkKeGJyZWFrcyA9IHNlcShtaW4odGhldGFzLnEpLG1heCh0aGV0YXMucSksbGVuZ3RoPTIwMCkKaGlzdCh0aGV0YXMucSxicmVha3M9eGJyZWFrcyxwcm9iPVRSVUUsbWFpbj0iRHJhd3MgZnJvbSBwcm9wb3NhbCIseGxpbT1jKC0xMCwxMCkseWxpbT1jKDAsMC40KSx4bGFiPSJUaGV0YSIpCnh4ID0gc2VxKG1pbih0aGV0YXMucSksbWF4KHRoZXRhcy5xKSxsZW5ndGg9MTAwMCkKbGluZXMoeHgsZHQoeHgsZGY9MyksY29sPTIsbHdkPTIpCnhicmVha3MgPSBzZXEobWluKHRoZXRhcy5wKSxtYXgodGhldGFzLnApLGxlbmd0aD0zMCkKaGlzdCh0aGV0YXMucCxicmVha3M9eGJyZWFrcyxwcm9iPVRSVUUsbWFpbj0iRHJhd3MgZnJvbSB0YXJnZXRcbnZpYSBTSVIiLAogICAgIHhsaW09YygtMTAsMTApLHlsaW09YygwLDAuNCkseGxhYj0iVGhldGEiKQp4eCA9IHNlcShtaW4odGhldGFzLnApLG1heCh0aGV0YXMucCksbGVuZ3RoPTEwMDApCmxpbmVzKHh4LGRub3JtKHh4LDAsc3FydCgzKSksY29sPTIsbHdkPTIpCmBgYAoKCiMgRXhhbXBsZSAxOiBUaGUgQm9vdHN0cmFwIGZpbHRlcgoKVGhlIEJvb3N0cmFwIGZpbHRlciBpcyBiYXNpY2FsbHkgdGhlIFNJUiBhcHBsaWVkIHNlcXVlbnRpYWxseSBpbiB0aGUgZHluYW1pYyBtb2RlbCBmcmFtZXdvcmsuIE1vcmUgcHJlY2lzZWx5LCBsZXQgJFx7eF97dC0xfV57KDEpfSxcbGRvdHMseF97dC0xfV57KE0pfVx9JCBiZSBhIHNhbXBsZSBmcm9tICRwKHhfe3QtMX18RF97dC0xfSkkLgoKCiogRm9yICRpPTEsXGxkb3RzLE0kLCBwcm9wYWdhdGUgcG9zdGVyaW9yIGRyYXdzIGF0ICR0LTEkIHRvIHByaW9yIGRyYXdzIGF0ICR0JDoKJCQKe1x0aWxkZSB4fV90XnsoaSl9IFxzaW0gTih4X3t0LTF9XnsoaSl9LFx0YXVeMikKJCQKCiogRm9yICRpPTEsXGxkb3RzLE0kLCBjb21wdXRlIHJlc2FtcGxpbmcgd2VpZ2h0czogCiQkClxvbWVnYV57KGkpfSBccHJvcHRvIHAoeV90fHtcdGlsZGUgeH1fdF57KGkpfSkuCiQkCgoqIEZvciAkaj0xLFxsZG90cyxNJCwgc2FtcGxlICR4X3ReeyhqKX0kIGZyb20gJFx7e1x0aWxkZSB4fV57KDEpfSxcbGRvdHMse1x0aWxkZSB4fV57KE0pfVx9JCB3aXRoIHByb2JhYmlsaXRpZXMgJFx7XG9tZWdhXnsoMSl9LFxsZG90cyxcb21lZ2FeeyhNKX1cfSQuCgojIyBDbG9zZXIgbG9vayBhdCBmcm9tICR0PTAkIHRvICR0PTEkCmBgYHtyIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTR9CnNldC5zZWVkKDEyMzQ1KQptMCAgICAgPSAwCkMwICAgICA9IDEKTSAgICAgID0gMTAwMDAKCiMgeDB8RDAKeDBwb3N0ICAgPSBybm9ybShNLG0wLHNxcnQoQzApKQoKIyB4MXxEMAp4MXByaW9yID0gcm5vcm0oTSx4MHBvc3Qsc3FydCh0YXUyKSkKCiMgeDF8RDEKdyAgICAgID0gZG5vcm0oeVsxXSx4MXByaW9yLHNxcnQoc2lnMikpCngxcG9zdCA9IHNhbXBsZSh4MXByaW9yLHNpemU9TSxyZXBsYWNlPVRSVUUscHJvYj13KQoKcGFyKG1mcm93PWMoMSwzKSkKaGlzdCh4MHBvc3QseGxhYj0iIixwcm9iPVRSVUUsbWFpbj0icCh4MHxEMCkiKQpoaXN0KHgxcHJpb3IseGxhYj0iIixwcm9iPVRSVUUsbWFpbj0icCh4MXxEMCkiKQpoaXN0KHgxcG9zdCx4bGFiPSIiLHByb2I9VFJVRSxtYWluPSJwKHgxfEQxKSIpCnBvaW50cyh5WzFdLDAsY29sPTMscGNoPTE2LGNleD0yKQpgYGAKCiMjIEZvciAkdD0yLFxsZG90cyxuJAoKYGBge3J9CnhkcmF3cyAgICAgPSBtYXRyaXgoMCxuLE0pCnggICAgICAgICAgPSB4MXBvc3QKeGRyYXdzWzEsXSA9IHgKCmZvciAodCBpbiAyOm4pewogIHhwcmlvciAgPSBybm9ybShNLHgsc3FydCh0YXUyKSkKICB3ZWlnaHRzID0gZG5vcm0oeVt0XSx4cHJpb3Isc3FydChzaWcyKSkKICB4ICAgICAgID0gc2FtcGxlKHhwcmlvcixzaXplPU0scmVwbGFjZT1UUlVFLHByb2I9d2VpZ2h0cykKICB4ZHJhd3NbdCxdID0geAp9CnFwZiA9IHQoYXBwbHkoeGRyYXdzLDEscXVhbnRpbGUsYygwLjAyNSwwLjUsMC45NzUpKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD04fQppbmQgPSBjKDUsNiw3LDQyLDQzLDQ0LDk4LDk5LG4pCnBhcihtZnJvdz1jKDMsMykpCmZvciAoaSBpbiBpbmQpewogIGhpc3QoeGRyYXdzW2ksXSx4bGFiPSIiLHByb2I9VFJVRSxtYWluPXBhc3RlKCJwKHgiLGksInxEIixpLCIpIixzZXA9IiIpKQogIHBvaW50cyh5W2ldLDAsY29sPTMscGNoPTE2LGNleD0yKQogIHh4eCA9IHNlcShtaW4oeGRyYXdzW2ksXSksbWF4KHhkcmF3c1tpLF0pLGxlbmd0aD0yMDApCiAgbGluZXMoeHh4LGRub3JtKHh4eCxtZltpXSxzcXJ0KENmW2ldKSksY29sPTIsbHdkPTIpCn0KYGBgCgpgYGB7ciBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD02fQpwYXIobWZyb3c9YygxLDEpKQp0cy5wbG90KHFmLGx3ZD0yLHlsaW09cmFuZ2UocWYscXBmKSkKbGluZXMocXBmWywxXSxjb2w9Mixsd2Q9MikKbGluZXMocXBmWywyXSxjb2w9Mixsd2Q9MikKbGluZXMocXBmWywzXSxjb2w9Mixsd2Q9MikKbGVnZW5kKCJ0b3BsZWZ0IixsZWdlbmQ9YygiS2FsbWFuIGZpbHRlciIsIlBhcnRpY2xlIGZpbHRlciIpLGNvbD0xOjIsbHdkPTIpCnRpdGxlKHBhc3RlKCJNPSIsTSwiIHBhcnRpY2xlcyIsc2VwPSIiKSkKYGBgCgoKCgojIEV4YW1wbGUgMjogYSBub25saW5lYXIgZHluYW1pYyBtb2RlbApMZXQgdXMgbm93IGlsbHVzdHJhdGUgdGhlIEJvb3RzdHJhcCBmaWx0ZXIgZm9yIGEgbm9ubGluZWFyIGR5bmFtaWMgbW9kZWwsIHdoZXJlIHRoZSBub25saW5lYXJpdHkgYXBwZWFycyBpbiB0aGUgb2JzZXJ2YXRpb24gZXF1YXRpb246ClxiZWdpbntlcW5hcnJheSp9CnlfdCAmPSYgfHhfdHwgKyBcZXBzaWxvbl90IFxxcXVhZCBcZXBzaWxvbl90IFxzaW0gTigwLFxzaWdtYV4yKVxcCnhfdCAmPSYgeF97dC0xfSArIFxvbWVnYV90IFxxcXVhZCBcb21lZ2FfdCBcc2ltIE4oMCxcdGF1XjIpLgpcZW5ke2VxbmFycmF5Kn0KCmBgYHtyIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTZ9CnNldC5zZWVkKDU0MzIxKQpuICAgICA9IDEwMApzaWcyICA9IDEuMDAKdGF1MiAgPSAwLjI1CnggICAgID0gcmVwKDAsbikKZm9yICh0IGluIDI6bikKICB4W3RdID0geFt0LTFdICsgcm5vcm0oMSwwLHNxcnQodGF1MikpCnkgPSBhYnMoeCkgKyBybm9ybShuLDAsc3FydChzaWcyKSkKeC50cnVlID0geAoKcGFyKG1mcm93PWMoMSwxKSkKcGxvdCh5LHhsYWI9IlRpbWUiLHlsYWI9IiIsdHlwZT0iYiIscGNoPTE2LGx3ZD0yLHlsaW09cmFuZ2UoeCx5KSkKbGluZXMoeCxjb2w9Mixsd2Q9Mix0eXBlPSJiIixwY2g9MTYpCmxlZ2VuZCgidG9wIixsZWdlbmQ9YygiWSh0KSIsIlgodCkiKSxjb2w9MToyLGx3ZD0yLGx0eT0xKQphYmxpbmUoaD0wLGx0eT0yLGx3ZD0yKQpgYGAKCiMjIFRoZSBCb29zdHJhcCBmaWx0ZXIKCmBgYHtyfQpzZXQuc2VlZCgxMjM0NSkKbTAgICAgID0gMApDMCAgICAgPSAxCk0gICAgICA9IDEwMDAwCnhkcmF3cyA9IG1hdHJpeCgwLG4sTSkKeCAgICAgID0gcm5vcm0oTSxtMCxzcXJ0KEMwKSkKZm9yICh0IGluIDE6bil7CiAgeHByaW9yICA9IHJub3JtKE0seCxzcXJ0KHRhdTIpKQogIHdlaWdodHMgPSBkbm9ybSh5W3RdLGFicyh4cHJpb3IpLHNxcnQoc2lnMikpCiAgeCAgICAgICA9IHNhbXBsZSh4cHJpb3Isc2l6ZT1NLHJlcGxhY2U9VFJVRSxwcm9iPXdlaWdodHMpCiAgeGRyYXdzW3QsXSA9IHgKfQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTh9CnRzID0gYygxOjUsKG4vMi0yKToobi8yKzIpLChuLTQpOm4pCnBhcihtZnJvdz1jKDMsNSkpCmZvciAodCBpbiAobi0xNCk6bil7CiAgaGlzdCh4ZHJhd3NbdCxdLHhsYWI9IiIscHJvYj1UUlVFLG1haW49IiIseWxhYj0iUG9zdGVyaW9yIGRlbnNpdHkiLHhsaW09cmFuZ2UoeGRyYXdzKSx5bGltPWMoMCwwLjUpKQogIGxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPXBhc3RlKCJ0PSIsdCxzZXA9IiIpLGJ0eT0ibiIpCiAgcG9pbnRzKHlbdF0sMCxjb2w9MixwY2g9MTYsY2V4PTIpCn0KYGBgCgpgYGB7ciBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD02fQpOID0gMTAwCmRlbnMgPSBtYXRyaXgoMCxuLE4pCmZvciAodCBpbiAxOm4pewogIGRlbiA9IGRlbnNpdHkoYWJzKHhkcmF3c1t0LF0pLGZyb209LTgsdG89NyxuPU4pCiAgZGVuc1t0LF0gPSBkZW4keQp9Cnh4ID0gZGVuJHgKCnBhcihtZnJvdz1jKDEsMSkpCmNvbnRvdXIoMTpuLHh4LGRlbnMsbmxldmVscz0yMCx5bGltPXJhbmdlKHkpKQpwb2ludHMoYWJzKHgudHJ1ZSksY29sPTMscGNoPTE2KQphYmxpbmUoaD0wLGNvbD00LGx3ZD0yKQpwb2ludHMoeSxjb2w9MixwY2g9MTYpCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWMoIkRhdGEiLCJ8U3RhdGVzfCIsIlBvc3RlcmlvcnMiKSxjb2w9YygyLDMsMSksbHdkPTIsbHR5PTEpCmBgYAoK