tests/testthat/test_LINPRED.R

context("LINPRED and related functions")

skip_on_cran()

test_that("LINPRED basic fixed effects models", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants=list(y = rnorm(10), x=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x3=round(rnorm(10),3), x4=round(rnorm(10), 3), n = 10),
                  inits=list(beta_Intercept=0))

  # Intercept-only model
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~1)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    })
  )

  new_const <- modInfo$constants
  new_const$x <- as.numeric(new_const$x)
  new_const$x2 <- as.numeric(new_const$x2)
  expect_equal(mod$getConstants(), new_const)
  expect_equal(mod$modelDef$macroInits, list(beta_Intercept = 0))

  # Covariates both factor and continous
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + x3)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1]] + beta_x3 * 
            x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] ~ dnorm(0, sd = 1000)
    beta_x[3] ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    })
  )

  expect_equivalent(mod$modelDef$macroInits, list(beta_Intercept = 0, 
                                                  beta_x= structure(c(0, 0, 0), dim = 3L),
                                                  beta_x3=0))
  expect_equivalent(mod$beta_x3, 0)

  # Drop intercept
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + x3 - 1)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_x[x[i_1]] + beta_x3 * x3[i_1]
    }
    beta_x[1] ~ dnorm(0, sd = 1000)
    beta_x[2] ~ dnorm(0, sd = 1000)
    beta_x[3] ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    })
  )

  # Change prefix
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x, coefPrefix=alpha_)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({    
    for (i_1 in 1:n) {
        mu[i_1] <- alpha_Intercept + alpha_x[x[i_1]]
    }
    alpha_Intercept ~ dnorm(0, sd = 1000)
    alpha_x[1] <- 0
    alpha_x[2] ~ dnorm(0, sd = 1000)
    alpha_x[3] ~ dnorm(0, sd = 1000)
    })
  )
  expect_equivalent(mod$modelDef$macroInits, list(alpha_Intercept = 0, 
                                                  alpha_x = structure(c(0, 0, 0), dim = 3L)))

  # With link function
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x3, link = log)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        log(mu[i_1]) <- beta_Intercept + beta_x3 * x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    })
  )

  # Set custom priors
  priors <- setPriors(intercept="dnorm(0, sd=1)", coefficient="dnorm(0, sd=2)")
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x3, priors=priors)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x3 * x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1)
    beta_x3 ~ dnorm(0, sd = 2)
    })
  )

  # No priors
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x3, priors=NULL)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x3 * x3[i_1]
    }
    })
  )

  # Modmatnames = TRUE
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + x3, modelMatrixNames = TRUE)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
      for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1]] + beta_x3 * 
            x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] <- beta_xb
    beta_xb ~ dnorm(0, sd = 1000)
    beta_x[3] <- beta_xc
    beta_xc ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    })
  )

  # Continous-continous interaction
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x3*x4)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x3 * x3[i_1] + beta_x4 * 
            x4[i_1] + beta_x3_x4 * x3[i_1] * x4[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    beta_x4 ~ dnorm(0, sd = 1000)
    beta_x3_x4 ~ dnorm(0, sd = 1000)
    })
  )
  expect_equivalent(mod$modelDef$macroInits, 
                    list(beta_Intercept=0, beta_x3=0, beta_x4=0, beta_x3_x4=0))


  # Continous-factor interaction
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x*x3)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1]] + beta_x3 * 
            x3[i_1] + beta_x_x3[x[i_1]] * x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] ~ dnorm(0, sd = 1000)
    beta_x[3] ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    beta_x_x3[1] <- 0
    beta_x_x3[2] ~ dnorm(0, sd = 1000)
    beta_x_x3[3] ~ dnorm(0, sd = 1000)
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = structure(c(0, 0, 0), dim = 3L), 
    beta_x3 = 0, beta_x_x3 = c(0, 0, 0))
  )

  # continuous-factor interaction with modelMatrixNames = TRUE
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x*x3, modelMatrixNames = TRUE)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1]] + beta_x3 * 
            x3[i_1] + beta_x_x3[x[i_1]] * x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] <- beta_xb
    beta_xb ~ dnorm(0, sd = 1000)
    beta_x[3] <- beta_xc
    beta_xc ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    beta_x_x3[1] <- 0
    beta_x_x3[2] <- beta_xb_x3
    beta_xb_x3 ~ dnorm(0, sd = 1000)
    beta_x_x3[3] <- beta_xc_x3
    beta_xc_x3 ~ dnorm(0, sd = 1000)
    })
  )

  # Drop some terms in interaction
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x*x3-1-x)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_x3 * x3[i_1] + beta_x_x3[x[i_1]] * x3[i_1]
    }
    beta_x3 ~ dnorm(0, sd = 1000)
    beta_x_x3[1] ~ dnorm(0, sd = 1000)
    beta_x_x3[2] ~ dnorm(0, sd = 1000)
    beta_x_x3[3] ~ dnorm(0, sd = 1000)
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_x3 = 0, beta_x_x3 = c(0, 0, 0))
  )

  # continuous-factor interaction with modelMatrixNames = TRUE
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x*x3, modelMatrixNames = TRUE)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1]] + beta_x3 * 
            x3[i_1] + beta_x_x3[x[i_1]] * x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] <- beta_xb
    beta_xb ~ dnorm(0, sd = 1000)
    beta_x[3] <- beta_xc
    beta_xc ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    beta_x_x3[1] <- 0
    beta_x_x3[2] <- beta_xb_x3
    beta_xb_x3 ~ dnorm(0, sd = 1000)
    beta_x_x3[3] <- beta_xc_x3
    beta_xc_x3 ~ dnorm(0, sd = 1000)
    })
  )


  # Factor-factor interaction
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x*x2)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  # For reference
  mm <- model.matrix(~x*x2, as.data.frame(modInfo$constants[c("x", "x2")]))

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1]] + beta_x2[x2[i_1]] + 
            beta_x_x2[x[i_1], x2[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] ~ dnorm(0, sd = 1000)
    beta_x[3] ~ dnorm(0, sd = 1000)
    beta_x2[1] <- 0
    beta_x2[2] ~ dnorm(0, sd = 1000)
    beta_x_x2[1, 1] <- 0
    beta_x_x2[2, 1] <- 0
    beta_x_x2[3, 1] <- 0
    beta_x_x2[1, 2] <- 0
    beta_x_x2[2, 2] ~ dnorm(0, sd = 1000)
    beta_x_x2[3, 2] ~ dnorm(0, sd = 1000)
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = structure(c(0, 0, 0), dim = 3L), 
      beta_x2 = structure(c(0, 0), dim = 2L), beta_x_x2 = structure(c(0, 
      0, 0, 0, 0, 0), dim = 3:2))
  )

  # Factor-factor interaction with modelMatrixNames = TRUE
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x*x2, modelMatrixNames = TRUE)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  # For reference
  mm <- model.matrix(~x*x2, as.data.frame(modInfo$constants[c("x", "x2")]))

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1]] + beta_x2[x2[i_1]] + 
            beta_x_x2[x[i_1], x2[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] <- beta_xb
    beta_xb ~ dnorm(0, sd = 1000)
    beta_x[3] <- beta_xc
    beta_xc ~ dnorm(0, sd = 1000)
    beta_x2[1] <- 0
    beta_x2[2] <- beta_x2e
    beta_x2e ~ dnorm(0, sd = 1000)
    beta_x_x2[1, 1] <- 0
    beta_x_x2[2, 1] <- 0
    beta_x_x2[3, 1] <- 0
    beta_x_x2[1, 2] <- 0
    beta_x_x2[2, 2] <- beta_xb_x2e
    beta_xb_x2e ~ dnorm(0, sd = 1000)
    beta_x_x2[3, 2] <- beta_xc_x2e
    beta_xc_x2e ~ dnorm(0, sd = 1000)
    })
  )

  # Covariate not in constants works (but is assumed to be continuous)
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x5, modelMatrixNames = TRUE)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  mod$getCode()

  nimbleOptions(enableMacroComments = TRUE)
})

test_that("LINPRED error traps LHS in formula", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants=list(y = rnorm(10), x=round(rnorm(10), 3), n = 10))

  # Missing LHS error trapping must be handled by buildMacro() in nimble
  # Enable the test below when the use3pieces error trap PR in nimble is merged
  #code <- quote(LINPRED(~1))
  
  #expect_error(
  #  LINPRED$process(code, modelInfo=modInfo, environment()),
  #  "This macro must be used as part of an assignment"
  #)

  # LHS in formula
  code <- quote(mu[1:n] <- LINPRED(y~1))
  
  expect_error(
    LINPRED$process(code, modelInfo=modInfo, environment()),
    "Formula should be RHS-only"
  )

})

test_that("LINPRED with uncorrelated random effects", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants= list(y = rnorm(10), group=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x=round(rnorm(10),3), x3=round(rnorm(10), 3), 
                    x4 = factor(sample(letters[6:8], 10, replace=T)), n=10))

  # Random intercept
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (1|group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1)
  )

  # Set SD prefix
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (1|group), sdPrefix=alpha_)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    alpha_sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = alpha_sd_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         alpha_sd_group = 1)
  )

  # Set custom priors
  pr <- setPriors(intercept="dnorm(0, sd=1)", sd="dunif(0, 1)")
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (1|group), priors=pr)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 1)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    })
  )

  # Uncorrelated random continuous slopes and intercepts
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x||group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x_group[group[i_1]] * x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    sd_x_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x_group[i_3] ~ dnorm(0, sd = sd_x_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, beta_x_group = c(0, 0, 0), sd_x_group = 1)
  )

  # Just random slopes, not intercepts
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x-1||group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_x_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_x_group[i_2] ~ dnorm(0, sd = sd_x_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, 
         beta_x_group = c(0, 0, 0), sd_x_group = 1)
  )

  # No fixed effects
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~0 + (x||group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_group[group[i_1]] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    sd_x_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x_group[i_3] ~ dnorm(0, sd = sd_x_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, beta_x_group = c(0, 0, 0), sd_x_group = 1)
  )

  # Factor random slope
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x2 + (x2||group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x2[x2[i_1]] + beta_group[group[i_1]] + 
            beta_x2_group[x2[i_1], group[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x2[1] <- 0
    beta_x2[2] ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    sd_x2d_group ~ dunif(0, 100)
    sd_x2e_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x2_group[1, i_3] ~ dnorm(0, sd = sd_x2d_group)
    }
    for (i_4 in 1:3) {
        beta_x2_group[2, i_4] ~ dnorm(0, sd = sd_x2e_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x2 = structure(c(0, 0), dim = 2L), 
      beta_group = structure(c(0, 0, 0), dim = 3L), sd_group = 1, 
      beta_x2_group = structure(c(0, 0, 0, 0, 0, 0), dim = 2:3), 
      sd_x2d_group = 1, sd_x2e_group = 1)
  )

  # Continuous-continous Interaction in random term
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x:x3||group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x_x3_group[group[i_1]] * x[i_1] * x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    sd_x_x3_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x_x3_group[i_3] ~ dnorm(0, sd = sd_x_x3_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, beta_x_x3_group = c(0, 0, 0), sd_x_x3_group = 1)
  )

  # Continuous-factor interaction in random term
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x:x2||group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x_x2_group[x2[i_1], group[i_1]] * x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    sd_x_x2d_group ~ dunif(0, 100)
    sd_x_x2e_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x_x2_group[1, i_3] ~ dnorm(0, sd = sd_x_x2d_group)
    }
    for (i_4 in 1:3) {
        beta_x_x2_group[2, i_4] ~ dnorm(0, sd = sd_x_x2e_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, beta_x_x2_group = structure(c(0, 0, 0, 0, 0, 0), dim = 2:3), 
         sd_x_x2d_group = 1, sd_x_x2e_group = 1)
  )

  # Factor-factor interaction in random term
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x2:x4||group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x2_x4_group[x2[i_1], x4[i_1], group[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    sd_x2d_x4f_group ~ dunif(0, 100)
    sd_x2e_x4f_group ~ dunif(0, 100)
    sd_x2d_x4g_group ~ dunif(0, 100)
    sd_x2e_x4g_group ~ dunif(0, 100)
    sd_x2d_x4h_group ~ dunif(0, 100)
    sd_x2e_x4h_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x2_x4_group[1, 1, i_3] ~ dnorm(0, sd = sd_x2d_x4f_group)
    }
    for (i_4 in 1:3) {
        beta_x2_x4_group[2, 1, i_4] ~ dnorm(0, sd = sd_x2e_x4f_group)
    }
    for (i_5 in 1:3) {
        beta_x2_x4_group[1, 2, i_5] ~ dnorm(0, sd = sd_x2d_x4g_group)
    }
    for (i_6 in 1:3) {
        beta_x2_x4_group[2, 2, i_6] ~ dnorm(0, sd = sd_x2e_x4g_group)
    }
    for (i_7 in 1:3) {
        beta_x2_x4_group[1, 3, i_7] ~ dnorm(0, sd = sd_x2d_x4h_group)
    }
    for (i_8 in 1:3) {
        beta_x2_x4_group[2, 3, i_8] ~ dnorm(0, sd = sd_x2e_x4h_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, 
         beta_x2_x4_group = structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), dim = c(2L, 3L, 3L)), 
         sd_x2d_x4f_group = 1, sd_x2e_x4f_group = 1, sd_x2d_x4g_group = 1, 
    sd_x2e_x4g_group = 1, sd_x2d_x4h_group = 1, sd_x2e_x4h_group = 1)
  )

  # Drop terms in random expression
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x-1||group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_x_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_x_group[i_2] ~ dnorm(0, sd = sd_x_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_x_group = c(0, 0, 0), sd_x_group = 1)
  )

  nimbleOptions(enableMacroComments=TRUE)
})

test_that("Centering with uncorrelated random effects", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants= list(y = rnorm(10), group=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x=round(rnorm(10),3), x3=round(rnorm(10), 3), 
                    x4 = factor(sample(letters[6:8], 10, replace=T)), n=10))
  
  # Center random effects on group instead of 0
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x||group), centerVar=group)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_group[group[i_1]] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(beta_Intercept, sd = sd_group)
    }
    sd_x_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x_group[i_3] ~ dnorm(beta_x, sd = sd_x_group)
    }
  })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, beta_x_group = c(0, 0, 0), sd_x_group = 1)
  )

  # Centering when there are multiple grouping factors
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x||group) + (1|x4), centerVar=group)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_group[group[i_1]] + beta_x_group[group[i_1]] * 
            x[i_1] + beta_x4[x4[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(beta_Intercept, sd = sd_group)
    }
    sd_x_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x_group[i_3] ~ dnorm(beta_x, sd = sd_x_group)
    }
    sd_x4 ~ dunif(0, 100)
    for (i_4 in 1:3) {
        beta_x4[i_4] ~ dnorm(0, sd = sd_x4)
    }
    })
  )

  # Centering with no intercept
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~0 + x + (x||group), centerVar=group)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_group[group[i_1]] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    sd_x_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x_group[i_3] ~ dnorm(beta_x, sd = sd_x_group)
    }
  })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, beta_x_group = c(0, 0, 0), sd_x_group = 1)
  )

  # Centering when there are no fixed effects
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~0 + (x||group), centerVar=group)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_group[group[i_1]] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    sd_x_group ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x_group[i_3] ~ dnorm(0, sd = sd_x_group)
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, beta_x_group = c(0, 0, 0), sd_x_group = 1)
  )

  nimbleOptions(enableMacroComments = TRUE)
})

test_that("noncentered parameterization with uncorrelated random effects", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants= list(y = rnorm(10), group=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x=round(rnorm(10),3), x3=round(rnorm(10), 3), 
                    x4 = factor(sample(letters[6:8], 10, replace=T)), n=10))

  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x||group), noncentered=TRUE)
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x_group[group[i_1]] * x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group_raw[i_2] ~ dnorm(0, sd = 1)
    }
    for (i_3 in 1:3) {
        beta_group[i_3] <- 0 + sd_group * beta_group_raw[i_3]
    }
    sd_x_group ~ dunif(0, 100)
    for (i_4 in 1:3) {
        beta_x_group_raw[i_4] ~ dnorm(0, sd = 1)
    }
    for (i_5 in 1:3) {
        beta_x_group[i_5] <- 0 + sd_x_group * beta_x_group_raw[i_5]
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
      sd_group = 1, beta_x_group = c(0, 0, 0), sd_x_group = 1, 
      beta_group_raw = structure(c(0, 0, 0), dim = 3L), beta_x_group_raw = c(0, 0, 0))
  )

  # With centering variable also
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x||group), noncentered=TRUE, centerVar=group)
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_group[group[i_1]] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group_raw[i_2] ~ dnorm(0, sd = 1)
    }
    for (i_3 in 1:3) {
        beta_group[i_3] <- beta_Intercept + sd_group * beta_group_raw[i_3]
    }
    sd_x_group ~ dunif(0, 100)
    for (i_4 in 1:3) {
        beta_x_group_raw[i_4] ~ dnorm(0, sd = 1)
    }
    for (i_5 in 1:3) {
        beta_x_group[i_5] <- beta_x + sd_x_group * beta_x_group_raw[i_5]
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
      sd_group = 1, beta_x_group = c(0, 0, 0), sd_x_group = 1, 
      beta_group_raw = structure(c(0, 0, 0), dim = 3L), beta_x_group_raw = c(0, 0, 0))
  )

  # Factor slope
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x2||group), noncentered=TRUE)
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x2_group[x2[i_1], group[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_group_raw[i_2] ~ dnorm(0, sd = 1)
    }
    for (i_3 in 1:3) {
        beta_group[i_3] <- 0 + sd_group * beta_group_raw[i_3]
    }
    sd_x2d_group ~ dunif(0, 100)
    sd_x2e_group ~ dunif(0, 100)
    for (i_4 in 1:3) {
        beta_x2_group_raw[1, i_4] ~ dnorm(0, sd = 1)
    }
    for (i_5 in 1:3) {
        beta_x2_group[1, i_5] <- 0 + sd_x2d_group * beta_x2_group_raw[1, 
            i_5]
    }
    for (i_6 in 1:3) {
        beta_x2_group_raw[2, i_6] ~ dnorm(0, sd = 1)
    }
    for (i_7 in 1:3) {
        beta_x2_group[2, i_7] <- 0 + sd_x2e_group * beta_x2_group_raw[2, 
            i_7]
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         sd_group = 1, beta_x2_group = structure(c(0, 0, 0, 0, 0, 0), dim = 2:3), 
         sd_x2d_group = 1, sd_x2e_group = 1, beta_group_raw = structure(c(0, 0, 0), dim = 3L), 
         beta_x2_group_raw = structure(c(0, 0, 0, 0, 0, 0), dim = 2:3))
  )

  nimbleOptions(enableMacroComments = TRUE)
})

test_that("correlated random effects", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants= list(y = rnorm(10), group=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x=round(rnorm(10),3), x3=round(rnorm(10), 3), 
                    x4 = factor(sample(letters[6:8], 10, replace=T)), n=10))

  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x|group))
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x_group[group[i_1]] * x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    sd_x_group ~ dunif(0, 100)
    re_sds_group[1] <- sd_group
    re_sds_group[2] <- sd_x_group
    Ustar_group[1:2, 1:2] ~ dlkj_corr_cholesky(1, 2)
    U_group[1:2, 1:2] <- uppertri_mult_diag(Ustar_group[1:2, 
        1:2], re_sds_group[1:2])
    re_means_group[1] <- 0
    re_means_group[2] <- 0
    for (i_2 in 1:3) {
        B_group[i_2, 1:2] ~ dmnorm(re_means_group[1:2], cholesky = U_group[1:2, 
            1:2], prec_param = 0)
        beta_group[i_2] <- B_group[i_2, 1]
        beta_x_group[i_2] <- B_group[i_2, 2]
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         beta_x_group = c(0, 0, 0), sd_group = 1, sd_x_group = 1)
  )

  # Set LKJ shape value
  pr <- setPriors(lkjShape=3)
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x|group), priors=pr)
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x_group[group[i_1]] * x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    sd_x_group ~ dunif(0, 100)
    re_sds_group[1] <- sd_group
    re_sds_group[2] <- sd_x_group
    Ustar_group[1:2, 1:2] ~ dlkj_corr_cholesky(3, 2)
    U_group[1:2, 1:2] <- uppertri_mult_diag(Ustar_group[1:2, 
        1:2], re_sds_group[1:2])
    re_means_group[1] <- 0
    re_means_group[2] <- 0
    for (i_2 in 1:3) {
        B_group[i_2, 1:2] ~ dmnorm(re_means_group[1:2], cholesky = U_group[1:2, 
            1:2], prec_param = 0)
        beta_group[i_2] <- B_group[i_2, 1]
        beta_x_group[i_2] <- B_group[i_2, 2]
    }
    })
  )

  # More than two correlated params
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x + x3|group))
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]] + 
            beta_x_group[group[i_1]] * x[i_1] + beta_x3_group[group[i_1]] * 
            x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    sd_x_group ~ dunif(0, 100)
    sd_x3_group ~ dunif(0, 100)
    re_sds_group[1] <- sd_group
    re_sds_group[2] <- sd_x_group
    re_sds_group[3] <- sd_x3_group
    Ustar_group[1:3, 1:3] ~ dlkj_corr_cholesky(1, 3)
    U_group[1:3, 1:3] <- uppertri_mult_diag(Ustar_group[1:3, 
        1:3], re_sds_group[1:3])
    re_means_group[1] <- 0
    re_means_group[2] <- 0
    re_means_group[3] <- 0
    for (i_2 in 1:3) {
        B_group[i_2, 1:3] ~ dmnorm(re_means_group[1:3], cholesky = U_group[1:3, 
            1:3], prec_param = 0)
        beta_group[i_2] <- B_group[i_2, 1]
        beta_x_group[i_2] <- B_group[i_2, 2]
        beta_x3_group[i_2] <- B_group[i_2, 3]
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         beta_x_group = c(0, 0, 0), beta_x3_group = c(0, 0, 0), sd_group = 1, 
         sd_x_group = 1, sd_x3_group = 1)
  )

  # Factor random slopes don't work
  code <- quote(LINPRED_PRIORS(~x + (x2|group)))
  expect_error(LINPRED_PRIORS$process(code, modInfo, NULL), "Correlated")

  nimbleOptions(enableMacroComments = TRUE)
})

test_that("Centering with correlated random effects", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants= list(y = rnorm(10), group=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x=round(rnorm(10),3), x3=round(rnorm(10), 3), 
                    x4 = factor(sample(letters[6:8], 10, replace=T)), n=10))

  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (x|group), centerVar=group)
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_group[group[i_1]] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    sd_x_group ~ dunif(0, 100)
    re_sds_group[1] <- sd_group
    re_sds_group[2] <- sd_x_group
    Ustar_group[1:2, 1:2] ~ dlkj_corr_cholesky(1, 2)
    U_group[1:2, 1:2] <- uppertri_mult_diag(Ustar_group[1:2, 
        1:2], re_sds_group[1:2])
    re_means_group[1] <- beta_Intercept
    re_means_group[2] <- beta_x
    for (i_2 in 1:3) {
        B_group[i_2, 1:2] ~ dmnorm(re_means_group[1:2], cholesky = U_group[1:2, 
            1:2], prec_param = 0)
        beta_group[i_2] <- B_group[i_2, 1]
        beta_x_group[i_2] <- B_group[i_2, 2]
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_Intercept = 0, beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         beta_x_group = c(0, 0, 0), sd_group = 1, sd_x_group = 1)
  )

  # With intercept dropped
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~0 + x + (x|group), centerVar=group)
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_group[group[i_1]] + beta_x_group[group[i_1]] * 
            x[i_1]
    }
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    sd_x_group ~ dunif(0, 100)
    re_sds_group[1] <- sd_group
    re_sds_group[2] <- sd_x_group
    Ustar_group[1:2, 1:2] ~ dlkj_corr_cholesky(1, 2)
    U_group[1:2, 1:2] <- uppertri_mult_diag(Ustar_group[1:2, 
        1:2], re_sds_group[1:2])
    re_means_group[1] <- 0
    re_means_group[2] <- beta_x
    for (i_2 in 1:3) {
        B_group[i_2, 1:2] ~ dmnorm(re_means_group[1:2], cholesky = U_group[1:2, 
            1:2], prec_param = 0)
        beta_group[i_2] <- B_group[i_2, 1]
        beta_x_group[i_2] <- B_group[i_2, 2]
    }
    })
  )
  expect_equal(
    mod$modelDef$macroInits,
    list(beta_x = 0, beta_group = structure(c(0, 0, 0), dim = 3L), 
         beta_x_group = c(0, 0, 0), sd_group = 1, sd_x_group = 1)
  )

  nimbleOptions(enableMacroComments = TRUE)
})

test_that("Noncentered parameterization doesn't work with correlated random effects", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants= list(y = rnorm(10), group=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x=round(rnorm(10),3), x3=round(rnorm(10), 3), 
                    x4 = factor(sample(letters[6:8], 10, replace=T)), n=10))
  # Noncentered doesn't work with correlated random effects  
  code <- quote(LINPRED_PRIORS(~x + (x|group), noncentered=TRUE))
  expect_error(LINPRED_PRIORS$process(code, modInfo, NULL)$code, "Noncentered")

  nimbleOptions(enableMacroComments = TRUE)
})


test_that("LINPRED with brackets on RHS of formula", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants=list(y = rnorm(10), 
                  x=matrix(sample(letters[1:3], 10, replace=T), ncol=1),
                  x2=factor(sample(letters[4:5], 10, replace=T)),
                  site = sample(1:10, 10, replace=TRUE),
                  x3=round(rnorm(10),3), x4=round(rnorm(10), 3), n = 10, J =3),
                  inits=list(beta_Intercept=0))

  # Different dimensions on RHS
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x[1:n, 1] + x3)
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1, 1]] + beta_x3 * 
            x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] ~ dnorm(0, sd = 1000)
    beta_x[3] ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    })
  )

  # Nested indexing
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x2 + x3[site[1:n]])
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x2[x2[i_1]] + beta_x3 * 
            x3[site[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x2[1] <- 0
    beta_x2[2] ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    })
  )

  # Interaction with different indices
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x[1:n,1]*x3[site[1:n]])
  })
  mod <- nimbleModel(code, constants = modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1, 1]] + beta_x3 * 
            x3[site[i_1]] + beta_x_x3[x[i_1, 1]] * x3[site[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] ~ dnorm(0, sd = 1000)
    beta_x[3] ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    beta_x_x3[1] <- 0
    beta_x_x3[2] ~ dnorm(0, sd = 1000)
    beta_x_x3[3] ~ dnorm(0, sd = 1000)
    })
  )

  # Random effect
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~(x3[site[1:n]]||x[1:n,1]))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x[x[i_1, 1]] + beta_x3_x[x[i_1, 
            1]] * x3[site[i_1]]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    sd_x ~ dunif(0, 100)
    for (i_2 in 1:3) {
        beta_x[i_2] ~ dnorm(0, sd = sd_x)
    }
    sd_x3_x ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_x3_x[i_3] ~ dnorm(0, sd = sd_x3_x)
    }
    })
  )

  nimbleOptions(enableMacroComments = TRUE)
})


test_that("LINPRED with factor array covariate", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants=list(y=matrix(rnorm(12), 3, 4),
                                 x=matrix(sample(letters[1:3], 12, replace=T), 3, 4),
                                 M=3, J=4))

  code <- nimbleCode({
    mu[1:M, 1:J] <- LINPRED(~x)
  })
  mod <- nimbleModel(code, constants=modInfo$constants)
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:M) {
        for (i_2 in 1:J) {
            mu[i_1, i_2] <- beta_Intercept + beta_x[x[i_1, i_2]]
        }
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x[1] <- 0
    beta_x[2] ~ dnorm(0, sd = 1000)
    beta_x[3] ~ dnorm(0, sd = 1000)
    })
  )
  expect_equal(dim(mod$getConstants()$x), dim(modInfo$constants$x))
  nimbleOptions(enableMacroComments = TRUE)
})


test_that("Nested random effects", {
  nimbleOptions(enableMacroComments = FALSE)
  set.seed(123)
  modInfo <- list(constants=list(y = rnorm(10), 
                               x=factor(sample(letters[1:3], 10, replace=T)),
                               w = factor(sample(letters[6:8], 10, replace=T)),
                    x3=round(rnorm(10),3), n=10),
                indexCreator=nimble:::labelFunctionCreator("i"))

  # w:x notation
  # Linear predictor
  code <- quote(mu[1:n] <- LINPRED(~x3 + (x3||x:w), priors=NULL))
  out <- LINPRED$process(code, modelInfo=modInfo, NULL)
  # Make sure new combined levels constant is added
  expect_equal(
    out$modelInfo$constants$x_w,
    factor(paste(modInfo$constants$x, modInfo$constants$w, sep=":"))
  )
  expect_equal(length(levels(out$modelInfo$constants$x_w)), 7)

  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x3 + (x3||x:w))
  })
  mod <- nimbleModel(code, constants=modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x3 * x3[i_1] + beta_x_w[x_w[i_1]] + 
            beta_x3_x_w[x_w[i_1]] * x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    sd_x_w ~ dunif(0, 100)
    for (i_2 in 1:7) {
        beta_x_w[i_2] ~ dnorm(0, sd = sd_x_w)
    }
    sd_x3_x_w ~ dunif(0, 100)
    for (i_3 in 1:7) {
        beta_x3_x_w[i_3] ~ dnorm(0, sd = sd_x3_x_w)
    }
  })
  )
  expect_equal(mod$getConstants()$x_w, as.numeric(out$modelInfo$constants$x_w))

  # w/x notation, which adds |w random effect(s)
  bars <- reformulas::findbars(~x3 + (x3||w/x)) # for reference
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x3 + (x3||w/x))
  })
  mod <- nimbleModel(code, constants=modInfo$constants)

  expect_equal(
    mod$getCode(),
    quote({
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x3 * x3[i_1] + beta_x_w[x_w[i_1]] + 
            beta_w[w[i_1]] + beta_x3_x_w[x_w[i_1]] * x3[i_1] + 
            beta_x3_w[w[i_1]] * x3[i_1]
    }
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x3 ~ dnorm(0, sd = 1000)
    sd_x_w ~ dunif(0, 100)
    for (i_2 in 1:7) {
        beta_x_w[i_2] ~ dnorm(0, sd = sd_x_w)
    }
    sd_w ~ dunif(0, 100)
    for (i_3 in 1:3) {
        beta_w[i_3] ~ dnorm(0, sd = sd_w)
    }
    sd_x3_x_w ~ dunif(0, 100)
    for (i_4 in 1:7) {
        beta_x3_x_w[i_4] ~ dnorm(0, sd = sd_x3_x_w)
    }
    sd_x3_w ~ dunif(0, 100)
    for (i_5 in 1:3) {
        beta_x3_w[i_5] ~ dnorm(0, sd = sd_x3_w)
    }
    }) 
  )
  expect_equal(mod$getConstants()$x_w, as.numeric(out$modelInfo$constants$x_w))

  nimbleOptions(enableMacroComments = TRUE)
})


test_that("Macro comments work with LINPRED", {

  nimbleOptions(enableMacroComments = TRUE)
  set.seed(123)
  modInfo <- list(constants= list(y = rnorm(10), group=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x=round(rnorm(10),3), x3=round(rnorm(10), 3), 
                    x4 = factor(sample(letters[6:8], 10, replace=T)), n=10))

  # Random intercept
  code <- nimbleCode({
    mu[1:n] <- LINPRED(~x + (1|group))
  })
  mod <- nimbleModel(code, constants = modInfo$constants)
  
  expect_equal(
    mod$getCode(),
    quote({
    "# LINPRED"
    "  ## nimbleMacros::FORLOOP"
    for (i_1 in 1:n) {
        mu[i_1] <- beta_Intercept + beta_x * x[i_1] + beta_group[group[i_1]]
    }
    "  ## ----"
    "  ## nimbleMacros::LINPRED_PRIORS"
    beta_Intercept ~ dnorm(0, sd = 1000)
    beta_x ~ dnorm(0, sd = 1000)
    sd_group ~ dunif(0, 100)
    "    ### nimbleMacros::FORLOOP"
    for (i_2 in 1:3) {
        beta_group[i_2] ~ dnorm(0, sd = sd_group)
    }
    "    ### ----"
    "  ## ----"
    "# ----"
    })
  )
})


test_that("removeBracketsFromFormula",{  
  expect_equal(
    removeBracketsFromFormula(~x + x2),
    ~x + x2
  )
  expect_equal(
    removeBracketsFromFormula(~x[1:n] + x2),
    ~x + x2
  )
  expect_equal(
    removeBracketsFromFormula(~x[1:n] + x2[1:m]),
    ~x + x2
  )
  expect_equal(
    removeBracketsFromFormula(~x[alpha[1:n]] + x2[1:m]),
    ~x + x2
  )
  expect_equal(
    removeBracketsFromFormula(~x[1:N, 1:J, 1:K[1:N]] + x2[1:m]),
    ~x + x2
  )
})

test_that("extractBracket", {
  expect_error(extractBracket(quote(x)))
  expect_equal(
    extractBracket(quote(x[1:n])),
    c(x="[1:n]")
  )
  expect_equal(
    extractBracket(quote(x[alpha[1:n]])),
    c(x="[alpha[1:n]]")
  )
})

test_that("extractAllBrackets", {
  expect_equal(
    extractAllBrackets(~x+x2),
    NULL
  )
  expect_equal(
    extractAllBrackets(~x[1:n]),
    c(x="[1:n]")
  )
  expect_equal(
    extractAllBrackets(~x[1:n]+x2),
    c(x="[1:n]")
  )
  expect_equal(
    extractAllBrackets(~x[1:n]+x2[1:k]),
    c(x="[1:n]", x2="[1:k]")
  )
  expect_equal(
    extractAllBrackets(~x[1:n]*x2[1:k]),
    c(x="[1:n]", x2="[1:k]")
  )
  expect_equal(
    extractAllBrackets(~x[alpha[1:n]]+x2[1:k]),
    c(x="[alpha[1:n]]", x2="[1:k]")
  )
})

test_that("makeDummyDataFrame", {
  set.seed(123)
  dat <- list(x=factor(sample(letters[1:3], 10, replace=T)),
                    x2=factor(sample(letters[4:5], 10, replace=T)),
                    x3=round(rnorm(10),3))
  expect_equal(
    makeDummyDataFrame(~x + x3, dat),
    data.frame(x=factor("c", levels=levels(dat$x)), x3=1.224)
  )
  expect_equal(
    makeDummyDataFrame(~x + x3 + x4, dat),
    data.frame(x=factor("c", levels=levels(dat$x)), x3=1.224, x4=0)
  )
  dat <- list(x=rnorm(3), z=NULL)
  expect_error(
    makeDummyDataFrame(~x + z, dat),
    "List element z in constants is NULL"
  )
})

test_that("processNestedRandomEffects", {
  dat <- list(group=factor(c("a","b","c")), group2=factor(c("d","e","f")))
  
  out1 <- processNestedRandomEffects(quote(1|group), dat)
  expect_equal(out1$barExp, quote(1|group))
  expect_equal(out1$constants, NULL)

  out2 <- processNestedRandomEffects(quote(1|group:group2), dat)
  expect_equal(out2$barExp, quote(1|group_group2))
  expect_equal(out2$constants, list(group_group2=factor(c("a:d", "b:e", "c:f"))))
  
  # Check the new factor is not duplicated
  dat2 <- c(dat, out2$constants)
  out3 <- processNestedRandomEffects(quote(1|group:group2), dat2)
  expect_equal(out3$constants, list())

  # Handle character matrices
  dat2 <- list(group=matrix(c("a","b","b","a"), 2, 2),
              group2=matrix(c("c","d","c","d"), 2, 2))

  out4 <- processNestedRandomEffects(quote(1|group:group2), dat2)
  expect_equal(out4$constants$group_group2,
               matrix(c("a:c","b:d","b:c","a:d"), 2, 2))
  
  # Mismatched array sizes should error
  dat3 <- list(group=matrix(c("a","b","b","a","z","z"), 3, 2),
              group2=matrix(c("c","d","c","d"), 2, 2))
  expect_error(processNestedRandomEffects(quote(1|group:group2), dat3))
})

Try the nimbleMacros package in your browser

Any scripts or data that you put into this service are public.

nimbleMacros documentation built on April 3, 2025, 11:38 p.m.