
context("Variance modelling")

set.seed(1, kind="Mersenne-Twister", normal.kind="Inversion")

n <- 250L
df <- data.frame(x=runif(n), f=factor(sample(1:8, n, replace=TRUE)))
Vmodel <- ~ vfac(factor="f", prior=pr_invchisq(df=5))
dat <- generate_data(~ reg(~ x + f, prior=pr_normal(precision=1)),
                     family=f_gaussian(var.prior=1, var.model = Vmodel), data=df)

test_that("generated data based on vfac model is OK", {
  expect_length(dat$y, n)
  expect_false(anyNA(dat$y))
})

test_that("modelling vfac variance structure works", {
  df$y <- dat$y
  Vmodel <- ~ vfac(factor="f", prior=pr_invchisq(df=2), name="varf")
  expect_warning(
    sampler <- create_sampler(y ~ x + f, sigma.fixed=TRUE, formula.V=Vmodel, data=df),
    "deprecated"
  )
  sampler <- create_sampler(y ~ x + f, family=f_gaussian(var.prior=1, var.model=Vmodel), data=df)
  sim <- MCMCsim(sampler, burnin=100, n.iter=400, n.chain=2, store.all=TRUE, verbose=FALSE)
  expect_is(sim$varf, "dc")
  summ <- summary(sim)
  compute_DIC(sim)
  compute_WAIC(sim)
})

test_that("pr_fixed prior in vfac works", {
  Vmodel <- ~ vfac(factor="f", prior=pr_fixed(value=1:8))
  dat <- generate_data(~ reg(~ x + f, prior=pr_normal(precision=1)),
                       family=f_gaussian(var.prior=1, var.model=Vmodel), data=df)
  expect_equal(unname(dat$pars$vfac1), 1:8)
  expect_length(dat$y, n)
  expect_false(anyNA(dat$y))
  df$y <- dat$y
  sampler <- create_sampler(
    y ~ reg(~ x + f),
    family = f_gaussian(var.prior = 1, var.model =  ~ vfac(factor="f")),
    data=df
  )
  sim <- MCMCsim(sampler, store.all=TRUE, verbose=FALSE)
  summ <- summary(sim)
  expect_between(summ$vfac1[, "Mean"], 0.5 * (1:8) - 0.5, 2*(1:8) + 1)
  sampler <- create_sampler(
    y ~ reg(~ x + f),
    family=f_gaussian(var.prior=1, var.model = ~ vfac(factor="f", prior=pr_fixed(1:8))),
    data=df
  )
  sim <- MCMCsim(sampler, store.all=TRUE, verbose=FALSE)
  summ <- summary(sim)
  expect_equal(unname(summ$vfac1[, "q0.05"]), 1:8)
})

# non-diagonal sampling covariance matrix (NB very contrived example)
subdiv <- c(110,10,70,45,8,7)
df$f <- as.factor(rep(1:6, subdiv))
Q0 <- bdiag(mapply(Q_RW2, subdiv)) + Diagonal(n)
Vmodel <- ~ vfac(factor="f", prior=pr_invchisq(df=5))
dat <- generate_data(~ reg(~ x + f, prior=pr_normal(precision=1)),
         family=f_gaussian(var.prior=1, prec.mat=Q0, var.model=Vmodel), data=df)

test_that("vfac variance structure works for compatible non-diagonal sampling variance matrix", {
  df$y <- dat$y
  Vmodel <- ~ vfac(factor="f", prior=pr_invchisq(df=2), name="varf")
  expect_warning(
    sampler <- create_sampler(y ~ x + f, sigma.fixed=TRUE, Q0=Q0, formula.V=Vmodel, data=df),
    "deprecated"
  )
  sampler <- create_sampler(y ~ x + f,
    family = f_gaussian(var.prior=1, prec.mat=Q0, var.model=Vmodel), data=df)
  sim <- MCMCsim(sampler, burnin=100, n.iter=400, n.chain=2, store.all=TRUE, verbose=FALSE)
  expect_is(sim$varf, "dc")
  summ <- summary(sim)
  compute_DIC(sim)
  compute_WAIC(sim)
})


test_that("generated data based on vreg model is OK", {
  Vmodel <- ~ vreg(~ x, prior=pr_normal(precision=1))
  dat <- generate_data(~ reg(~ x + f, prior=pr_normal(precision=1)),
    family=f_gaussian(var.prior=pr_fixed(1), var.model=Vmodel), data=df)
  expect_length(dat$y, n)
  expect_false(anyNA(dat$y))
})

Vmodel <- ~ vreg(~ x, prior=pr_fixed(1))
dat <- generate_data(~ reg(~ x + f, prior=pr_normal(precision=1)),
                     family=f_gaussian(var.prior=1, var.model=Vmodel), data=df)
df$y <- dat$y
test_that("vreg variance model works", {
  expect_equal(dat$pars$vreg1, c(`(Intercept)` = 1, x = 1))
  Vmodel <- ~ vreg(formula = ~ x, name="varf")
  sampler <- create_sampler(y ~ x + f, family=f_gaussian(var.prior=1, var.model=Vmodel), data=df)
  sim <- MCMCsim(sampler, burnin=100, n.iter=400, n.chain=2, store.all=TRUE, verbose=FALSE)
  expect_is(sim$varf, "dc")
  summ <- summary(sim)
  expect_between(summ$varf[, "Mean"], 0.4, 2.5)
  compute_DIC(sim)
  compute_WAIC(sim)
})

n <- 900
dat <- data.frame(
  x = runif(n),
  z = rnorm(n)
)
dat$y <- rnorm(n, 1 + dat$x + dat$z, sd=exp(0.5*(0.5 - 0.5*dat$x)))
test_that("reg variance model works", {
  sampler <- create_sampler(y ~
    reg(~ x + z, name="beta"),
    family=f_gaussian(var.prior=1, var.model = ~ reg(~ x, name="vbeta")),
    data=dat
  )
  sim <- MCMCsim(sampler, burnin=150, n.iter=500, n.chain=2, store.all=TRUE, verbose=FALSE)
  expect_is(sim$vbeta, "dc")
  summ <- summary(sim)
  expect_between(summ$beta[, "q0.5"], 0.3 * c(1, 1, 1), 3 * c(1, 1, 1))
  expect_between(summ$vbeta[, "q0.5"], c(0.5 * 0.3, -0.5 * 3), c(0.5 * 3, -0.5 * 0.3))
  compute_DIC(sim)
  compute_WAIC(sim)
})

n <- 1200
dat <- data.frame(
  x = runif(n),
  z = rnorm(n),
  f = factor(sample(22, n, replace=TRUE))
)
test_that("mixed effects for both mean and variance work", {
  gd <- generate_data(
    ~ reg(~ 1 + x + z, prior=pr_fixed(c(1,0.5,-0.3)), name="beta") +
      gen(factor = ~ f, PX=FALSE, prior=pr_invchisq(1e6, 0.5), name="v"),
    family = f_gaussian(
      var.model = ~ reg(~ 1 + x, prior=pr_fixed(c(0.4,1)), name="vbeta") +
                    gen(factor = ~ f, prior=pr_invchisq(1e6, 1), name="vv"),
      var.prior = pr_fixed(1)
    ), data=dat
  )
  expect_equal(unname(gd$pars$beta), c(1,0.5,-0.3))
  expect_equal(unname(gd$pars$vbeta), c(0.4,1))
  expect_between(gd$pars$v_sigma, 0.9*sqrt(0.5), 1.1*sqrt(0.5))
  expect_between(gd$pars$vv_sigma, 0.9*sqrt(1), 1.1*sqrt(1))
  sampler <- create_sampler(
    gd$y ~ reg(~ 1 + x + z, name="beta") +
        gen(factor = ~ f, name="v"),
    family = f_gaussian(
      var.model = ~ reg(~ 1 + x, name="vbeta") +
                    gen(factor = ~ f, name="vv"),
      var.prior = pr_fixed(1)
    ), data=dat
  )
  expect_false(sampler$Vmod$vv$usePX)
  sim <- MCMCsim(sampler, burnin=200, n.iter=600, n.chain=2, store.all=TRUE, verbose=FALSE)
  summ <- summary(sim)
  expect_between(summ$beta[, "q0.5"], c(1*0.3, 0.5*0.3, -0.3*3), c(1*3, 0.5*3, -0.3*0.3))
  expect_between(summ$vbeta[, "q0.5"], 0.2*c(0.4, 1), 5*c(0.4, 1))
  #plot(gd$pars$v, summ$v[, "Mean"]); abline(0, 1)
  #plot(gd$pars$vv, summ$vv[, "Mean"]); abline(0, 1)
  #mean(summ$vv[, "Mean"])
  compute_DIC(sim)
  compute_WAIC(sim)
  # test with cMVN sampler
  sampler <- create_sampler(
    gd$y ~ reg(~ 1 + x + z, name="beta") +
      gen(factor = ~ f, name="v"),
    family = f_gaussian(
      var.model = ~ reg(~ 1 + x, name="vbeta") +
        gen(factor = ~ f, name="vv"),
      var.prior = pr_fixed(1)
    ), data=dat,
    control = sampler_control(cMVN.sampler = TRUE)
  )
  expect_true(sampler$control$cMVN.sampler)
  sim <- MCMCsim(sampler, burnin=200, n.iter=600, n.chain=2, store.all=TRUE, verbose=FALSE)
  summ <- summary(sim)
  expect_between(summ$beta[, "q0.5"], c(1*0.3, 0.5*0.3, -0.3*3), c(1*3, 0.5*3, -0.3*0.3))
  expect_between(summ$vbeta[, "q0.5"], 0.2*c(0.4, 1), 5*c(0.4, 1))
})
