1 The local level model

The local level model, also known as first order dynamic linear model (aka DLM) where \[\begin{eqnarray*} y_t &=& \theta_t + \epsilon_t\\ \theta_t &=& \theta_{t-1} + \omega_t, \end{eqnarray*}\] with observational errors \(\epsilon_t\) iid \(N(0,\sigma^2)\) and systems errors \(\omega_t\) iid \(N(0,\tau^2)\) for \(t=1,\ldots,n\). Let \(y=(y_1,\ldots,y_n)'\) and \(\theta=(\theta_1,\ldots,\theta_n)'\), then we can show that

\[ p(\theta|\sigma^2, \tau^2) \propto \exp\left\{ -\frac{1}{2\tau^2} \sum_{t=1}^n (\theta_t - \theta_{t-1})^2 \right\} \]

An alternative representation based on the precision matrix \(K\): \[ \theta \sim N(0, \tau^2 K^{-1}), \] where the covariance matrix is written as \[ K^{-1} = \begin{pmatrix} 1 & 1 & 1 & \cdots & 1 \\ 1 & 2 & 2 & \cdots & 2 \\ 1 & 2 & 3 & \cdots & 3 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & 2 & 3 & \cdots & n \end{pmatrix} \]

This is a very common way to present the random walk prior in the closed-form versus MC-based inference, say, in Gaussian Markov Random Field (GMRF) models.

It can be easily shown that the precision matrix is given by \[ K = \begin{pmatrix} 2 & -1 & 0 & \cdots & 0 \\ -1 & 2 & -1 & \cdots & 0 \\ 0 & -1 & 2 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & -1 \\ 0 & 0 & 0 & -1 & 1 \end{pmatrix} \]

To sample from the posterior \(p(\theta|\sigma^2,\tau^2,y)\), we leverage the fact that for a Gaussian state-space model, the posterior is also a multivariate Gaussian distribution. In fact, the posterior precision matrix is given by \[ P = \frac{1}{\sigma^2}I + \frac{1}{\tau^2}K, \] while the posterior mean \(\widehat{\theta}\) solves \[ P\widehat{\theta} = \frac{1}{\sigma^2}y. \] To sample efficiently, we use the Cholesky decomposition \(P = LL'\).

2 Simulation exercise

library(Matrix)

# 1. Setup parameters and synthetic data
set.seed(42)
n      = 100
sigma2 = 1.0
tau2   = 0.5
theta_true = cumsum(rnorm(n, 0, sqrt(tau2)))
y          = theta_true + rnorm(n, 0, sqrt(sigma2))

# 2. Construct the Sparse Precision Matrix K
# Diagonals: 2 for all except the last element which is 1
diag_elements = c(rep(2, n-1), 1)
off_diag = rep(-1, n-1)

K = sparseMatrix(
  i = c(1:n, 1:(n-1), 2:n),
  j = c(1:n, 2:n, 1:(n-1)),
  x = c(diag_elements, off_diag, off_diag)
)

# 3. Compute Posterior Precision P and Mean
# P = (1/sigma^2)*I + (1/tau^2)*K
P = (1/sigma2) * Diagonal(n) + (1/tau2) * K

# 4. Cholesky Decomposition
# P = L %*% t(L)
L = chol(P) 

# 5. Sample from the Posterior
# Step A: Solve for the posterior mean (P * m = (1/sigma2) * y)
m = solve(P, y / sigma2)

# Step B: Generate Z ~ N(0, I) and solve L' * v = Z
z = rnorm(n)
v = solve(t(L), z)

# Step C: theta_sample = m + v
theta_sample = as.vector(m + v)

# 6. Quick Plot
plot(y, col = "grey", pch = 16, main = "Posterior Sample via Cholesky")
lines(theta_true, col = "black", lwd = 2, lty = 2)
lines(theta_sample, col = "blue", lwd = 2)
legend("topleft", legend=c("True", "Sample"), col=c("black", "blue"), lty=c(2,1))

3 Sampling from the posterior

To generate \(M=1000\) draws efficiently, we only perform the Cholesky decomposition once. Since the precision matrix \(P\) depends only on the hyperparameters (\(\sigma^2, \tau^2\)) and the model structure, it remains constant for all draws of \(\theta\).

library(Matrix)

M      = 1000

# Construct Sparse Precision Matrix K
# K is tridiagonal with 2 on diag (1 at the end) and -1 on off-diagonals
K = bandSparse(n,k=0:1,diagonals=list(c(rep(2,n-1),1),rep(-1, n-1)),symmetric=TRUE)

# Posterior Precision P and its Cholesky Decomposition
# P = (1/sigma^2)*I + (1/tau^2)*K
# L is upper triangular such that t(L) %*% L = P
P = (1/sigma2) * Diagonal(n) + (1/tau2) * K
L = chol(P) 

# Posterior Mean (m)
# Solve P*m = (1/sigma2)*y
m = solve(P, y / sigma2)

# Efficient Sampling: theta = m + inv(L) * Z
# We generate an n x M matrix of standard normal draws
Z = matrix(rnorm(n * M), nrow = n, ncol = M)

# Solve L*v = Z for all columns (since L is upper triangular)
# Note: backsolve/solve is very fast for sparse triangular matrices
v = solve(L, Z)

# Final draws: Add the mean vector to each column of v
# theta_draws: (n x M) matrix where each column is a draw
theta_draws = as.matrix(m + v)

We use the property that if \(Z \sim N(0, I)\), then \(\theta = m + L^{-1}Z\) results in \(\theta \sim N(m, (L'L)^{-1})\), which is exactly \(N(m, P^{-1})\).

plot(y, type = "n", main = "1,000 Posterior Draws of Theta")
matlines(theta_draws, col = rgb(0.1, 0.1, 0.9, 0.05), lty = 1) # Transparent blue lines
lines(as.numeric(m), col = "red", lwd = 2)                   # Posterior mean

4 Learning \(\theta\), \(\sigma^2\) and \(\tau^2\)

library(Matrix)

# 1. Priors and Initial Values
a_sig = b_sig = 0.01
a_tau = b_tau = 0.01

burnin = 5000
M = burnin + 5000
n = length(y)
theta_samples = matrix(0, n, M)
sig2_samples  = numeric(M)
tau2_samples  = numeric(M)

# Initial values
curr_sig2 = var(y)
curr_tau2 = var(diff(y))
K = bandSparse(n, k = 0:1, diagonals = list(c(rep(2, n-1), 1), rep(-1, n-1)), symmetric = TRUE)

# 2. Gibbs Loop
for (m in 1:M) {
  # --- Step A: Sample Theta ---
  P = (1/curr_sig2) * Diagonal(n) + (1/curr_tau2) * K
  L = chol(P)
  post_mean = solve(P, y / curr_sig2)
  theta_samples[, m] = as.vector(post_mean + solve(L, rnorm(n)))
  
  curr_theta = theta_samples[, m]
  
  # --- Step B: Sample sigma^2 ---
  sse_y = sum((y - curr_theta)^2)
  curr_sig2 = 1 / rgamma(1, a_sig + n/2, b_sig + sse_y/2)
  sig2_samples[m] = curr_sig2
  
  # --- Step C: Sample tau^2 ---
  # Using the quadratic form theta' * K * theta
  sse_theta = as.numeric(t(curr_theta) %*% K %*% curr_theta)
  curr_tau2 = 1 / rgamma(1, a_tau + n/2, b_tau + sse_theta/2)
  tau2_samples[m] = curr_tau2
}


theta_samples = theta_samples[,(burnin+1):M]
sig2_samples = sig2_samples[(burnin+1):M]
tau2_samples = tau2_samples[(burnin+1):M]

# Setup a 3x2 plotting area
# Layout: Rows = (Trace, ACF, Histogram), Cols = (sigma2, tau2)
par(mfrow = c(3, 2), mar = c(4, 4, 2, 1), oma = c(0, 0, 2, 0))

# --- Row 1: Trace Plots ---
plot(sig2_samples, type = "l", col = "steelblue", 
     main = expression(paste("Trace of ", sigma^2)), ylab = "Value")
plot(tau2_samples, type = "l", col = "darkorange", 
     main = expression(paste("Trace of ", tau^2)), ylab = "Value")

# --- Row 2: Autocorrelation Functions (ACF) ---
acf(sig2_samples, main = expression(paste("ACF of ", sigma^2)))
acf(tau2_samples, main = expression(paste("ACF of ", tau^2)))

# --- Row 3: Histograms ---
hist(sig2_samples, breaks = 30, col = "steelblue", border = "white",
     main = expression(paste("Posterior of ", sigma^2)), xlab = "Value")
abline(v = mean(sig2_samples), col = "red", lwd = 2, lty = 2)

hist(tau2_samples, breaks = 30, col = "darkorange", border = "white",
     main = expression(paste("Posterior of ", tau^2)), xlab = "Value")
abline(v = mean(tau2_samples), col = "red", lwd = 2, lty = 2)

# Add a main title for the article
mtext("MCMC Diagnostics for Variance Parameters", outer = TRUE, cex = 1.2, font = 2)

plot(y,type="n",xlab="Time",main=paste(M-burnin," posterior draws of theta",sep=""))
matlines(theta_draws, col = rgb(0.1, 0.1, 0.9, 0.05), lty = 1) # Transparent blue lines
points(y,pch=16)
lines(apply(theta_draws,1,mean),col="red",lwd=2)

LS0tCnRpdGxlOiAiR2F1c3NpYW4gZHluYW1pYyBsaW5lYXIgbW9kZWwiCnN1YnRpdGxlOiAiVGhlIGxvY2FsIGxldmVsIG1vZGVsIgphdXRob3I6ICJIZWRpYmVydCBGcmVpdGFzIExvcGVzIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHBhcGVyCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQojICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKCiMgVGhlIGxvY2FsIGxldmVsIG1vZGVsClRoZSBsb2NhbCBsZXZlbCBtb2RlbCwgYWxzbyBrbm93biBhcyBmaXJzdCBvcmRlciBkeW5hbWljIGxpbmVhciBtb2RlbCAoYWthIERMTSkgd2hlcmUKXGJlZ2lue2VxbmFycmF5Kn0KeV90ICY9JiBcdGhldGFfdCArIFxlcHNpbG9uX3RcXApcdGhldGFfdCAmPSYgXHRoZXRhX3t0LTF9ICsgXG9tZWdhX3QsIApcZW5ke2VxbmFycmF5Kn0Kd2l0aCBvYnNlcnZhdGlvbmFsIGVycm9ycyAkXGVwc2lsb25fdCQgaWlkICROKDAsXHNpZ21hXjIpJCBhbmQgc3lzdGVtcyBlcnJvcnMgJFxvbWVnYV90JCBpaWQgJE4oMCxcdGF1XjIpJCBmb3IgJHQ9MSxcbGRvdHMsbiQuICBMZXQgJHk9KHlfMSxcbGRvdHMseV9uKSckIGFuZCAkXHRoZXRhPShcdGhldGFfMSxcbGRvdHMsXHRoZXRhX24pJyQsIHRoZW4gd2UgY2FuIHNob3cgdGhhdAoKJCQKcChcdGhldGF8XHNpZ21hXjIsIFx0YXVeMikgXHByb3B0byBcZXhwXGxlZnRceyAtXGZyYWN7MX17Mlx0YXVeMn0gXHN1bV97dD0xfV5uIChcdGhldGFfdCAtIFx0aGV0YV97dC0xfSleMiBccmlnaHRcfQokJAoKQW4gYWx0ZXJuYXRpdmUgcmVwcmVzZW50YXRpb24gYmFzZWQgb24gdGhlIHByZWNpc2lvbiBtYXRyaXggJEskOiAKJCQKXHRoZXRhIFxzaW0gTigwLCBcdGF1XjIgS157LTF9KSwKJCQKd2hlcmUgdGhlIGNvdmFyaWFuY2UgbWF0cml4IGlzIHdyaXR0ZW4gYXMKJCQKS157LTF9ID0gXGJlZ2lue3BtYXRyaXh9CjEgJiAxICYgMSAmIFxjZG90cyAmIDEgXFwKMSAmIDIgJiAyICYgXGNkb3RzICYgMiBcXAoxICYgMiAmIDMgJiBcY2RvdHMgJiAzIFxcClx2ZG90cyAmIFx2ZG90cyAmIFx2ZG90cyAmIFxkZG90cyAmIFx2ZG90cyBcXAoxICYgMiAmIDMgJiBcY2RvdHMgJiBuClxlbmR7cG1hdHJpeH0KJCQKClRoaXMgaXMgYSB2ZXJ5IGNvbW1vbiB3YXkgdG8gcHJlc2VudCB0aGUgKnJhbmRvbSB3YWxrKiBwcmlvciBpbiB0aGUgY2xvc2VkLWZvcm0gdmVyc3VzIE1DLWJhc2VkIGluZmVyZW5jZSwgc2F5LCBpbiBHYXVzc2lhbiBNYXJrb3YgUmFuZG9tIEZpZWxkIChHTVJGKSBtb2RlbHMuCgpJdCBjYW4gYmUgZWFzaWx5IHNob3duIHRoYXQgdGhlIHByZWNpc2lvbiBtYXRyaXggaXMgZ2l2ZW4gYnkgCiQkCksgPSBcYmVnaW57cG1hdHJpeH0gCjIgJiAtMSAmIDAgJiBcY2RvdHMgJiAwIFxcCi0xICYgMiAmIC0xICYgXGNkb3RzICYgMCBcXAowICYgLTEgJiAyICYgXGNkb3RzICYgMCBcXApcdmRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgJiBcZGRvdHMgJiAtMSBcXAowICYgMCAmIDAgJiAtMSAmIDEgClxlbmR7cG1hdHJpeH0KJCQKClRvIHNhbXBsZSBmcm9tIHRoZSBwb3N0ZXJpb3IgJHAoXHRoZXRhfFxzaWdtYV4yLFx0YXVeMix5KSQsIHdlIGxldmVyYWdlIHRoZSBmYWN0IHRoYXQgZm9yIGEgR2F1c3NpYW4gc3RhdGUtc3BhY2UgbW9kZWwsIHRoZSBwb3N0ZXJpb3IgaXMgYWxzbyBhIG11bHRpdmFyaWF0ZSBHYXVzc2lhbiBkaXN0cmlidXRpb24uICBJbiBmYWN0LCB0aGUgcG9zdGVyaW9yIHByZWNpc2lvbiBtYXRyaXggaXMgZ2l2ZW4gYnkKJCQKUCA9IFxmcmFjezF9e1xzaWdtYV4yfUkgKyBcZnJhY3sxfXtcdGF1XjJ9SywKJCQKd2hpbGUgdGhlIHBvc3RlcmlvciBtZWFuICRcd2lkZWhhdHtcdGhldGF9JCBzb2x2ZXMgCiQkClBcd2lkZWhhdHtcdGhldGF9ID0gXGZyYWN7MX17XHNpZ21hXjJ9eS4KJCQKVG8gc2FtcGxlIGVmZmljaWVudGx5LCB3ZSB1c2UgdGhlIENob2xlc2t5IGRlY29tcG9zaXRpb24gJFAgPSBMTCckLgoKCiMgU2ltdWxhdGlvbiBleGVyY2lzZQoKYGBge3J9CmxpYnJhcnkoTWF0cml4KQoKIyAxLiBTZXR1cCBwYXJhbWV0ZXJzIGFuZCBzeW50aGV0aWMgZGF0YQpzZXQuc2VlZCg0MikKbiAgICAgID0gMTAwCnNpZ21hMiA9IDEuMAp0YXUyICAgPSAwLjUKdGhldGFfdHJ1ZSA9IGN1bXN1bShybm9ybShuLCAwLCBzcXJ0KHRhdTIpKSkKeSAgICAgICAgICA9IHRoZXRhX3RydWUgKyBybm9ybShuLCAwLCBzcXJ0KHNpZ21hMikpCgojIDIuIENvbnN0cnVjdCB0aGUgU3BhcnNlIFByZWNpc2lvbiBNYXRyaXggSwojIERpYWdvbmFsczogMiBmb3IgYWxsIGV4Y2VwdCB0aGUgbGFzdCBlbGVtZW50IHdoaWNoIGlzIDEKZGlhZ19lbGVtZW50cyA9IGMocmVwKDIsIG4tMSksIDEpCm9mZl9kaWFnID0gcmVwKC0xLCBuLTEpCgpLID0gc3BhcnNlTWF0cml4KAogIGkgPSBjKDE6biwgMToobi0xKSwgMjpuKSwKICBqID0gYygxOm4sIDI6biwgMToobi0xKSksCiAgeCA9IGMoZGlhZ19lbGVtZW50cywgb2ZmX2RpYWcsIG9mZl9kaWFnKQopCgojIDMuIENvbXB1dGUgUG9zdGVyaW9yIFByZWNpc2lvbiBQIGFuZCBNZWFuCiMgUCA9ICgxL3NpZ21hXjIpKkkgKyAoMS90YXVeMikqSwpQID0gKDEvc2lnbWEyKSAqIERpYWdvbmFsKG4pICsgKDEvdGF1MikgKiBLCgojIDQuIENob2xlc2t5IERlY29tcG9zaXRpb24KIyBQID0gTCAlKiUgdChMKQpMID0gY2hvbChQKSAKCiMgNS4gU2FtcGxlIGZyb20gdGhlIFBvc3RlcmlvcgojIFN0ZXAgQTogU29sdmUgZm9yIHRoZSBwb3N0ZXJpb3IgbWVhbiAoUCAqIG0gPSAoMS9zaWdtYTIpICogeSkKbSA9IHNvbHZlKFAsIHkgLyBzaWdtYTIpCgojIFN0ZXAgQjogR2VuZXJhdGUgWiB+IE4oMCwgSSkgYW5kIHNvbHZlIEwnICogdiA9IFoKeiA9IHJub3JtKG4pCnYgPSBzb2x2ZSh0KEwpLCB6KQoKIyBTdGVwIEM6IHRoZXRhX3NhbXBsZSA9IG0gKyB2CnRoZXRhX3NhbXBsZSA9IGFzLnZlY3RvcihtICsgdikKCiMgNi4gUXVpY2sgUGxvdApwbG90KHksIGNvbCA9ICJncmV5IiwgcGNoID0gMTYsIG1haW4gPSAiUG9zdGVyaW9yIFNhbXBsZSB2aWEgQ2hvbGVza3kiKQpsaW5lcyh0aGV0YV90cnVlLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAyLCBsdHkgPSAyKQpsaW5lcyh0aGV0YV9zYW1wbGUsIGNvbCA9ICJibHVlIiwgbHdkID0gMikKbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kPWMoIlRydWUiLCAiU2FtcGxlIiksIGNvbD1jKCJibGFjayIsICJibHVlIiksIGx0eT1jKDIsMSkpCmBgYAoKCiMgU2FtcGxpbmcgZnJvbSB0aGUgcG9zdGVyaW9yCgpUbyBnZW5lcmF0ZSAkTT0xMDAwJCBkcmF3cyBlZmZpY2llbnRseSwgd2Ugb25seSBwZXJmb3JtIHRoZSBDaG9sZXNreSBkZWNvbXBvc2l0aW9uIG9uY2UuIApTaW5jZSB0aGUgcHJlY2lzaW9uIG1hdHJpeCAkUCQgZGVwZW5kcyBvbmx5IG9uIHRoZSBoeXBlcnBhcmFtZXRlcnMgKCRcc2lnbWFeMiwgXHRhdV4yJCkgCmFuZCB0aGUgbW9kZWwgc3RydWN0dXJlLCBpdCByZW1haW5zIGNvbnN0YW50IGZvciBhbGwgZHJhd3Mgb2YgJFx0aGV0YSQuCgpgYGB7cn0KbGlicmFyeShNYXRyaXgpCgpNICAgICAgPSAxMDAwCgojIENvbnN0cnVjdCBTcGFyc2UgUHJlY2lzaW9uIE1hdHJpeCBLCiMgSyBpcyB0cmlkaWFnb25hbCB3aXRoIDIgb24gZGlhZyAoMSBhdCB0aGUgZW5kKSBhbmQgLTEgb24gb2ZmLWRpYWdvbmFscwpLID0gYmFuZFNwYXJzZShuLGs9MDoxLGRpYWdvbmFscz1saXN0KGMocmVwKDIsbi0xKSwxKSxyZXAoLTEsIG4tMSkpLHN5bW1ldHJpYz1UUlVFKQoKIyBQb3N0ZXJpb3IgUHJlY2lzaW9uIFAgYW5kIGl0cyBDaG9sZXNreSBEZWNvbXBvc2l0aW9uCiMgUCA9ICgxL3NpZ21hXjIpKkkgKyAoMS90YXVeMikqSwojIEwgaXMgdXBwZXIgdHJpYW5ndWxhciBzdWNoIHRoYXQgdChMKSAlKiUgTCA9IFAKUCA9ICgxL3NpZ21hMikgKiBEaWFnb25hbChuKSArICgxL3RhdTIpICogSwpMID0gY2hvbChQKSAKCiMgUG9zdGVyaW9yIE1lYW4gKG0pCiMgU29sdmUgUCptID0gKDEvc2lnbWEyKSp5Cm0gPSBzb2x2ZShQLCB5IC8gc2lnbWEyKQoKIyBFZmZpY2llbnQgU2FtcGxpbmc6IHRoZXRhID0gbSArIGludihMKSAqIFoKIyBXZSBnZW5lcmF0ZSBhbiBuIHggTSBtYXRyaXggb2Ygc3RhbmRhcmQgbm9ybWFsIGRyYXdzClogPSBtYXRyaXgocm5vcm0obiAqIE0pLCBucm93ID0gbiwgbmNvbCA9IE0pCgojIFNvbHZlIEwqdiA9IFogZm9yIGFsbCBjb2x1bW5zIChzaW5jZSBMIGlzIHVwcGVyIHRyaWFuZ3VsYXIpCiMgTm90ZTogYmFja3NvbHZlL3NvbHZlIGlzIHZlcnkgZmFzdCBmb3Igc3BhcnNlIHRyaWFuZ3VsYXIgbWF0cmljZXMKdiA9IHNvbHZlKEwsIFopCgojIEZpbmFsIGRyYXdzOiBBZGQgdGhlIG1lYW4gdmVjdG9yIHRvIGVhY2ggY29sdW1uIG9mIHYKIyB0aGV0YV9kcmF3czogKG4geCBNKSBtYXRyaXggd2hlcmUgZWFjaCBjb2x1bW4gaXMgYSBkcmF3CnRoZXRhX2RyYXdzID0gYXMubWF0cml4KG0gKyB2KQpgYGAKCldlIHVzZSB0aGUgcHJvcGVydHkgdGhhdCBpZiAkWiBcc2ltIE4oMCwgSSkkLCB0aGVuICRcdGhldGEgPSBtICsgTF57LTF9WiQgcmVzdWx0cyBpbiAkXHRoZXRhIFxzaW0gTihtLCAoTCdMKV57LTF9KSQsIHdoaWNoIGlzIGV4YWN0bHkgJE4obSwgUF57LTF9KSQuCgpgYGB7cn0KcGxvdCh5LCB0eXBlID0gIm4iLCBtYWluID0gIjEsMDAwIFBvc3RlcmlvciBEcmF3cyBvZiBUaGV0YSIpCm1hdGxpbmVzKHRoZXRhX2RyYXdzLCBjb2wgPSByZ2IoMC4xLCAwLjEsIDAuOSwgMC4wNSksIGx0eSA9IDEpICMgVHJhbnNwYXJlbnQgYmx1ZSBsaW5lcwpsaW5lcyhhcy5udW1lcmljKG0pLCBjb2wgPSAicmVkIiwgbHdkID0gMikgICAgICAgICAgICAgICAgICAgIyBQb3N0ZXJpb3IgbWVhbgpgYGAKCiMgTGVhcm5pbmcgJFx0aGV0YSQsICRcc2lnbWFeMiQgYW5kICRcdGF1XjIkCgpgYGB7cn0KbGlicmFyeShNYXRyaXgpCgojIDEuIFByaW9ycyBhbmQgSW5pdGlhbCBWYWx1ZXMKYV9zaWcgPSBiX3NpZyA9IDAuMDEKYV90YXUgPSBiX3RhdSA9IDAuMDEKCmJ1cm5pbiA9IDUwMDAKTSA9IGJ1cm5pbiArIDUwMDAKbiA9IGxlbmd0aCh5KQp0aGV0YV9zYW1wbGVzID0gbWF0cml4KDAsIG4sIE0pCnNpZzJfc2FtcGxlcyAgPSBudW1lcmljKE0pCnRhdTJfc2FtcGxlcyAgPSBudW1lcmljKE0pCgojIEluaXRpYWwgdmFsdWVzCmN1cnJfc2lnMiA9IHZhcih5KQpjdXJyX3RhdTIgPSB2YXIoZGlmZih5KSkKSyA9IGJhbmRTcGFyc2UobiwgayA9IDA6MSwgZGlhZ29uYWxzID0gbGlzdChjKHJlcCgyLCBuLTEpLCAxKSwgcmVwKC0xLCBuLTEpKSwgc3ltbWV0cmljID0gVFJVRSkKCiMgMi4gR2liYnMgTG9vcApmb3IgKG0gaW4gMTpNKSB7CiAgIyAtLS0gU3RlcCBBOiBTYW1wbGUgVGhldGEgLS0tCiAgUCA9ICgxL2N1cnJfc2lnMikgKiBEaWFnb25hbChuKSArICgxL2N1cnJfdGF1MikgKiBLCiAgTCA9IGNob2woUCkKICBwb3N0X21lYW4gPSBzb2x2ZShQLCB5IC8gY3Vycl9zaWcyKQogIHRoZXRhX3NhbXBsZXNbLCBtXSA9IGFzLnZlY3Rvcihwb3N0X21lYW4gKyBzb2x2ZShMLCBybm9ybShuKSkpCiAgCiAgY3Vycl90aGV0YSA9IHRoZXRhX3NhbXBsZXNbLCBtXQogIAogICMgLS0tIFN0ZXAgQjogU2FtcGxlIHNpZ21hXjIgLS0tCiAgc3NlX3kgPSBzdW0oKHkgLSBjdXJyX3RoZXRhKV4yKQogIGN1cnJfc2lnMiA9IDEgLyByZ2FtbWEoMSwgYV9zaWcgKyBuLzIsIGJfc2lnICsgc3NlX3kvMikKICBzaWcyX3NhbXBsZXNbbV0gPSBjdXJyX3NpZzIKICAKICAjIC0tLSBTdGVwIEM6IFNhbXBsZSB0YXVeMiAtLS0KICAjIFVzaW5nIHRoZSBxdWFkcmF0aWMgZm9ybSB0aGV0YScgKiBLICogdGhldGEKICBzc2VfdGhldGEgPSBhcy5udW1lcmljKHQoY3Vycl90aGV0YSkgJSolIEsgJSolIGN1cnJfdGhldGEpCiAgY3Vycl90YXUyID0gMSAvIHJnYW1tYSgxLCBhX3RhdSArIG4vMiwgYl90YXUgKyBzc2VfdGhldGEvMikKICB0YXUyX3NhbXBsZXNbbV0gPSBjdXJyX3RhdTIKfQoKCnRoZXRhX3NhbXBsZXMgPSB0aGV0YV9zYW1wbGVzWywoYnVybmluKzEpOk1dCnNpZzJfc2FtcGxlcyA9IHNpZzJfc2FtcGxlc1soYnVybmluKzEpOk1dCnRhdTJfc2FtcGxlcyA9IHRhdTJfc2FtcGxlc1soYnVybmluKzEpOk1dCgojIFNldHVwIGEgM3gyIHBsb3R0aW5nIGFyZWEKIyBMYXlvdXQ6IFJvd3MgPSAoVHJhY2UsIEFDRiwgSGlzdG9ncmFtKSwgQ29scyA9IChzaWdtYTIsIHRhdTIpCnBhcihtZnJvdyA9IGMoMywgMiksIG1hciA9IGMoNCwgNCwgMiwgMSksIG9tYSA9IGMoMCwgMCwgMiwgMCkpCgojIC0tLSBSb3cgMTogVHJhY2UgUGxvdHMgLS0tCnBsb3Qoc2lnMl9zYW1wbGVzLCB0eXBlID0gImwiLCBjb2wgPSAic3RlZWxibHVlIiwgCiAgICAgbWFpbiA9IGV4cHJlc3Npb24ocGFzdGUoIlRyYWNlIG9mICIsIHNpZ21hXjIpKSwgeWxhYiA9ICJWYWx1ZSIpCnBsb3QodGF1Ml9zYW1wbGVzLCB0eXBlID0gImwiLCBjb2wgPSAiZGFya29yYW5nZSIsIAogICAgIG1haW4gPSBleHByZXNzaW9uKHBhc3RlKCJUcmFjZSBvZiAiLCB0YXVeMikpLCB5bGFiID0gIlZhbHVlIikKCiMgLS0tIFJvdyAyOiBBdXRvY29ycmVsYXRpb24gRnVuY3Rpb25zIChBQ0YpIC0tLQphY2Yoc2lnMl9zYW1wbGVzLCBtYWluID0gZXhwcmVzc2lvbihwYXN0ZSgiQUNGIG9mICIsIHNpZ21hXjIpKSkKYWNmKHRhdTJfc2FtcGxlcywgbWFpbiA9IGV4cHJlc3Npb24ocGFzdGUoIkFDRiBvZiAiLCB0YXVeMikpKQoKIyAtLS0gUm93IDM6IEhpc3RvZ3JhbXMgLS0tCmhpc3Qoc2lnMl9zYW1wbGVzLCBicmVha3MgPSAzMCwgY29sID0gInN0ZWVsYmx1ZSIsIGJvcmRlciA9ICJ3aGl0ZSIsCiAgICAgbWFpbiA9IGV4cHJlc3Npb24ocGFzdGUoIlBvc3RlcmlvciBvZiAiLCBzaWdtYV4yKSksIHhsYWIgPSAiVmFsdWUiKQphYmxpbmUodiA9IG1lYW4oc2lnMl9zYW1wbGVzKSwgY29sID0gInJlZCIsIGx3ZCA9IDIsIGx0eSA9IDIpCgpoaXN0KHRhdTJfc2FtcGxlcywgYnJlYWtzID0gMzAsIGNvbCA9ICJkYXJrb3JhbmdlIiwgYm9yZGVyID0gIndoaXRlIiwKICAgICBtYWluID0gZXhwcmVzc2lvbihwYXN0ZSgiUG9zdGVyaW9yIG9mICIsIHRhdV4yKSksIHhsYWIgPSAiVmFsdWUiKQphYmxpbmUodiA9IG1lYW4odGF1Ml9zYW1wbGVzKSwgY29sID0gInJlZCIsIGx3ZCA9IDIsIGx0eSA9IDIpCgojIEFkZCBhIG1haW4gdGl0bGUgZm9yIHRoZSBhcnRpY2xlCm10ZXh0KCJNQ01DIERpYWdub3N0aWNzIGZvciBWYXJpYW5jZSBQYXJhbWV0ZXJzIiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjIsIGZvbnQgPSAyKQpgYGAKCmBgYHtyfQpwbG90KHksdHlwZT0ibiIseGxhYj0iVGltZSIsbWFpbj1wYXN0ZShNLWJ1cm5pbiwiIHBvc3RlcmlvciBkcmF3cyBvZiB0aGV0YSIsc2VwPSIiKSkKbWF0bGluZXModGhldGFfZHJhd3MsIGNvbCA9IHJnYigwLjEsIDAuMSwgMC45LCAwLjA1KSwgbHR5ID0gMSkgIyBUcmFuc3BhcmVudCBibHVlIGxpbmVzCnBvaW50cyh5LHBjaD0xNikKbGluZXMoYXBwbHkodGhldGFfZHJhd3MsMSxtZWFuKSxjb2w9InJlZCIsbHdkPTIpCmBgYAo=