The Fréchet PSRF, part 4

In this final part of what I initially thought would be a single post, I’m going to reiterate the Fréchet generalization of the PSRF worked on in the last parts and then compare it to Whidden and Matsen (2015)’s Gelman-Rubin-like diagnostic. The math of the comparison is going to change a bit, but the big picture won’t.

Recap

The Fréchet PSRF is

\[\hat{R}_\mathrm{F} = \sqrt{\frac{\hat{\sigma}_\mathrm{F}^2}{s_\mathrm{F}^2}}\]

The pooled Fréchet sample variance is

\[s_\mathrm{F}^2 = \frac{1}{m} \sum_k s_{\mathrm{F}, k}^2\]

and the per-chain sample variance is

\[s_{\mathrm{F}, k}^2 = \frac{1}{n (n - 1)} \sum_{j > i} d(x_{ki}, x_{kj})^2\]

The biased-from-above $\hat{\sigma}_\mathrm{F}^2$ is

\[\hat{\sigma^2} = \left( 1 - \frac{1}{n} \right) s_\mathrm{F}^2 + \frac{1}{n}B_\mathrm{F}\]

and

\[B_{\mathrm{F}} = \frac{n}{m (m - 1)} \sum_{\ell > k} d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2\]

where

\[d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2 = \frac{1}{n^2} \sum_i \sum_j d(x_{k i}, x_{\ell j})^2 - \frac{1}{n^2} \sum_{j > i} d(x_{k i}, x_{k j})^2 - \frac{1}{n^2} \sum_{j > i} d(x_{\ell i}, x_{\ell j})^2\]

This is almost entirely as laid out in Part 1 (and references therein) except this last equation, which I got wrong there and spent a lot of time fixing.

Compared to the Gelman-Rubin-like diagnostic

Let’s start again with the easy term,

\[s_{\text{WM}, k}^2 = \frac{1}{n (n - 1)} \sum_{i = 1}^n \sum_{j = 1}^n d(x_{k i}, x_{k j})^2 = \frac{2}{n (n - 1)} \sum_{j > i} d(x_{k i}, x_{k j})^2 = 2 s_{\text{F}, k}^2\]

That is, summing over the entire (squared) distance matrix yields twice the variance.

The harder term is

\[B_{\text{WM}} = \frac{1}{(m - 1)m n^2} \sum_k \sum_\ell \sum_i \sum_j d(x_{ki}, x_{\ell j})^2\]

The sum here is over the (squared) distance matrix of the concatenated chains, so there’s a block structure. The diagonal blocks are clearly variance-only terms, and the off-diagonal blocks are between chain comparison terms (which end up including variance terms too). Last time I tackled this by splitting it up, but having wrangled with these terms more, I’m not sure we want to. But, note that, per Detour 1, our work from Part 3 holds for both these blocks.

So, rewriting this we get,

\[B_{\text{WM}} = \frac{1}{(m - 1)m n^2} \sum_k \sum_\ell \left[ n(n - 1) s_{\mathrm{F}, k}^2 + n(n - 1) s_{\mathrm{F}, \ell}^2 + n^2 \times d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2 \right]\]

Now let’s tackle these terms separately. We get the first two via Detour 2

\[B_{\text{WM}} = \frac{1}{(m - 1)m n^2} \left( 2m^2 n(n - 1) s_{\mathrm{F}}^2 + \sum_k \sum_\ell \left[ n^2 \times d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2 \right] \right)\]

And by Detour 3

\[B_{\text{WM}} = \frac{1}{(m - 1)m n^2} \left( 2m^2 n(n - 1) s_{\mathrm{F}}^2 + 2 n m (m - 1) B_{\mathrm{F}} \right)\]

Cleaning up, we get,

\[B_{\text{WM}} = \frac{2m}{(m - 1) n (n - 1)} s_{\mathrm{F}}^2 + \frac{2}{n} B_{\mathrm{F}}\]

The factor of 2 in $s_{\text{WM}}^2$ and $\hat{\sigma}_{\text{WM}}^2$ cancel, but I don’t think we need to finish the math because the overall story is the same as we concluded in Part 1. As the sample size $n$ goes to infinity, $B_{\text{WM}}$ goes to 0, so the between-chain component here is asymptotically negligible.

Detours

Treat this like an appendix and ignore it if you like.

Detour 1

Synthesizing some equations from Part 3, we have, for chains $k$ and $\ell$,

\[\frac{1}{n^2} \sum_i \sum_j d(x_{k i}, x_{\ell j})^2 = \frac{n - 1}{n} s_{\mathrm{F}, k}^2 + \frac{n - 1}{n} s_{\mathrm{F}, \ell}^2 + d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2\]

Multiplying through by $n^2$, we get

\[\sum_i \sum_j d(x_{k i}, x_{\ell j})^2 = n(n - 1) s_{\mathrm{F}, k}^2 + n(n - 1) s_{\mathrm{F}, \ell}^2 + n^2 \times d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2\]

In the case where $k = \ell$, the distance between means is 0, so,

\[\sum_i \sum_j d(x_{k i}, x_{k j})^2 = n(n - 1) s_{\mathrm{F}, k}^2 + n(n - 1) s_{\mathrm{F}, k}^2 = 2 n (n - 1) s_{\mathrm{F}, k}^2\]

We can also get to this identity by starting from our variance identity,

\[s_{\mathrm{F}, k}^2 = \frac{1}{n (n - 1)} \sum_{j > i} d(x_{ki}, x_{kj})^2\] \[2 n (n - 1) s_{\mathrm{F}, k}^2 = \sum_i \sum_j d(x_{ki}, x_{kj})^2\]

Detour 2

\[\sum_k \sum_\ell n(n - 1) s_{\mathrm{F}, k}^2 = \sum_k m n(n - 1) s_{\mathrm{F}, k}^2\] \[\sum_k \sum_\ell n(n - 1) s_{\mathrm{F}, k}^2 = m^2 n(n - 1) s_{\mathrm{F}}^2\]

In parallel,

\[\sum_k \sum_\ell n(n - 1) s_{\mathrm{F}, \ell}^2 = m^2 n(n - 1) s_{\mathrm{F}}^2\]

So in total,

\[\sum_k \sum_\ell \left[ n(n - 1) s_{\mathrm{F}, k}^2 + n(n - 1) s_{\mathrm{F}, \ell}^2 \right] = 2m^2 n(n - 1) s_{\mathrm{F}}^2\]

Detour 3

We have that,

\[B_{\mathrm{F}} = \frac{n}{m (m - 1)} \sum_{\ell > k} d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2\]

But we want to work with all $k$ and $\ell$. We apply symmetry and the fact that for $k = \ell$ the distance between averages is 0, to note that this simply doubles things.

\[2 B_{\mathrm{F}} = \frac{n}{m (m - 1)} \sum_k \sum_\ell d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2\]

so

\[\sum_k \sum_\ell d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2 = \frac{2 m (m - 1) B_{\mathrm{F}}}{n}\]

and

\[\sum_k \sum_\ell \left[ n^2 \times d(\bar{X}_{k \cdot}, \bar{X}_{\ell \cdot})^2 \right] = 2 n m (m - 1) B_{\mathrm{F}}\]

Code check

set.seed(42)

psrf <- function(x) {
  m <- length(x)
  n <- length(x[[1]])

  stopifnot(class(x) == "list", all(lengths(x) == n))

  chain_means <- sapply(x, mean)
  grand_mean <- mean(chain_means)

  b_n <- sum((chain_means - grand_mean)^2) / (m - 1)

  s_sq <- mean(sapply(x, var))
  hat_sigma_sq <- (1 - 1 / n) * s_sq + b_n

  r_hat <- sqrt((hat_sigma_sq) / s_sq)

  r_hat
}

psrf_frechet <- function(x, dist_fun) {
  m <- length(x)
  n <- length(x[[1]])

  stopifnot(
    class(x) == "list",
    all(lengths(x) == n),
    class(dist_fun) == "function"
  )

  d_sq <- as.matrix(dist_fun(do.call(c, x)))^2

  vars <- sapply(1:m, function(k) {
    idx <- ((k - 1) * n + 1):(k * n)
    sum(d_sq[idx, idx]) / (2 * n * (n - 1))
  })

  d_sq_bars <- matrix(0, nrow = m, ncol = m)

  for (k in 1:(m - 1)) {
    k_idx <- ((k - 1) * n + 1):(k * n)
    for (l in (k + 1):m) {
      l_idx <- ((l - 1) * n + 1):(l * n)
      d_sq_bars[k, l] <- 1 /
        (n^2) *
        sum(d_sq[k_idx, l_idx]) -
        (n - 1) / n * vars[k] -
        (n - 1) / n * vars[l]
    }
  }

  b_n <- sum(d_sq_bars) / (m * (m - 1))

  s_sq <- mean(vars)
  hat_sigma_sq <- (1 - 1 / n) * s_sq + b_n

  r_hat <- sqrt(hat_sigma_sq / s_sq)

  r_hat
}

wm_stat <- function(x, dist_fun) {
  m <- length(x)
  n <- length(x[[1]])

  stopifnot(
    class(x) == "list",
    all(lengths(x) == n),
    class(dist_fun) == "function"
  )

  d_sq <- as.matrix(dist_fun(do.call(c, x)))^2

  vars <- sapply(1:m, function(k) {
    idx <- ((k - 1) * n + 1):(k * n)
    sum(d_sq[idx, idx]) / (n * (n - 1))
  })

  b_n <- 1 / ((m - 1) * m * n^3) * sum(d_sq)

  s_sq <- mean(vars)
  hat_sigma_sq <- (1 - 1 / n) * s_sq + b_n

  r_hat <- sqrt((hat_sigma_sq) / s_sq)

  r_hat
}

sim_norms <- function(m, n, means = 1:m, vars = rep(1, m)) {
  lapply(1:m, function(k) {
    rnorm(n, means[k], vars[k])
  })
}


nrep <- 100
nsamp <- 100

four_chain_psrf <- t(sapply(1:nrep, function(idx) {
  x <- sim_norms(4, nsamp)
  c(
    euclidean = psrf(x),
    frechet = psrf_frechet(x, dist),
    wm_2015 = wm_stat(x, dist)
  )
}))

r <- range(four_chain_psrf)

plot(
  four_chain_psrf[, 1:2],
  xlim = r,
  ylim = r,
  xlab = "Standard PSRF",
  ylab = "Frechet comparisons"
)
abline(a = 0, b = 1, col = "red")
legend(
  "topleft",
  legend = c("Fréchet", "WM2015"),
  fill = c("black", "blue"),
  border = NA,
  bty = "n"
)
points(four_chain_psrf[, c(1, 3)], col = "blue")

Updated: