tests/testthat/test-serial-fit-missing-robustness.R

# Focused, fast regression tests for serial fitting + missing-data flow.

make_serial_smoke_data <- function(n = 40, pG = 5, pZ = 4, seed = 2026) {
  set.seed(seed)
  G <- matrix(rnorm(n * pG), nrow = n)
  Z1 <- matrix(rnorm(n * pZ), nrow = n)
  Z2 <- matrix(rnorm(n * pZ), nrow = n)
  Z3 <- matrix(rnorm(n * pZ), nrow = n)
  Z4 <- matrix(rnorm(n * pZ), nrow = n)
  Z1[1, ] <- NA
  Z2[2, 1] <- NA
  Z3[3, ] <- NA
  Yn <- rnorm(n)
  Yb <- rbinom(n, 1, 0.4)
  CoG <- matrix(rnorm(n * 2), nrow = n)
  CoY <- matrix(rnorm(n * 2), nrow = n)
  list(G = G, Z1 = Z1, Z2 = Z2, Z3 = Z3, Z4 = Z4, Yn = Yn, Yb = Yb, CoG = CoG, CoY = CoY)
}

test_that("serial estimate_lucid fits mixed topology with missing data and stores stage summaries", {
  d <- make_serial_smoke_data(seed = 1008)

  suppressWarnings(invisible(capture.output(
    fit <- estimate_lucid(
      lucid_model = "serial",
      G = d$G,
      Z = list(d$Z1, list(d$Z2, d$Z3), d$Z4),
      Y = d$Yb,
      CoG = d$CoG,
      CoY = d$CoY,
      K = list(2, list(2, 2), 2),
      family = "binary",
      max_itr = 5,
      max_tot.itr = 20,
      seed = 1008
    )
  )))

  expect_s3_class(fit, "lucid_serial")
  expect_equal(length(fit$submodel), 3)
  expect_true(is.list(fit$missing_summary))
  expect_equal(fit$missing_summary$n_stages, 3)
  expect_equal(length(fit$missing_summary$stage), 3)
  expect_true(all(sapply(fit$submodel, function(m) !is.null(m$missing_summary))))
})

test_that("serial accepts data.frame omics blocks when K topology is valid", {
  d <- make_serial_smoke_data(seed = 1010)

  suppressWarnings(invisible(capture.output(
    fit <- estimate_lucid(
      lucid_model = "serial",
      G = d$G,
      Z = list(as.data.frame(d$Z1), list(as.data.frame(d$Z2), as.data.frame(d$Z3))),
      Y = d$Yn,
      CoG = d$CoG,
      CoY = d$CoY,
      K = list(2, list(2, 2)),
      family = "normal",
      max_itr = 5,
      max_tot.itr = 20,
      seed = 1010
    )
  )))

  expect_s3_class(fit, "lucid_serial")
  expect_equal(length(fit$submodel), 2)
})

test_that("serial wrapper tune_lucid/lucid works and handles stage with single-column G under Rho_G", {
  d <- make_serial_smoke_data(seed = 1012)

  suppressWarnings(invisible(capture.output(
    tune <- tune_lucid(
      G = d$G,
      Z = list(d$Z1, d$Z2),
      Y = d$Yn,
      CoG = d$CoG,
      CoY = d$CoY,
      family = "normal",
      K = list(2, 2:3),
      lucid_model = "serial",
      Rho_G = 0.2,
      max_itr = 4,
      max_tot.itr = 16,
      seed = 1012
    )
  )))

  suppressWarnings(invisible(capture.output(
    fit <- lucid(
      G = d$G,
      Z = list(d$Z1, d$Z2),
      Y = d$Yn,
      CoG = d$CoG,
      CoY = d$CoY,
      family = "normal",
      K = list(2, 2:3),
      lucid_model = "serial",
      Rho_G = 0.2,
      max_itr = 4,
      max_tot.itr = 16,
      seed = 1012
    )
  )))

  expect_true(nrow(as.data.frame(tune$tune_K)) >= 1)
  expect_s3_class(fit, "lucid_serial")
  expect_equal(fit$submodel[[1]]$Rho$Rho_G, 0.2)
  expect_equal(fit$submodel[[2]]$Rho$Rho_G, 0)
})

test_that("serial summary uses structured style and keeps detailed stage parameter tables", {
  d <- make_serial_smoke_data(seed = 1014)

  suppressWarnings(invisible(capture.output(
    fit <- estimate_lucid(
      lucid_model = "serial",
      G = d$G,
      Z = list(d$Z1, list(d$Z2, d$Z3), d$Z4),
      Y = d$Yn,
      CoG = d$CoG,
      CoY = d$CoY,
      K = list(2, list(2, 2), 2),
      family = "normal",
      max_itr = 4,
      max_tot.itr = 16,
      seed = 1014
    )
  )))

  s <- summary_lucid(fit)
  expect_s3_class(s, "sumlucid_serial")
  expect_true(is.list(s$model_info))
  expect_equal(s$model_info$n_stages, 3)
  expect_true(is.list(s$stage_summary))
  expect_equal(length(s$stage_summary), 3)
  expect_true(any(sapply(s$stage_summary, inherits, what = "sumlucid_parallel")))
  expect_true(any(sapply(s$stage_summary, inherits, what = "sumlucid_early")))

  txt <- capture.output(print(s))
  expect_true(any(grepl("LUCID Serial: Model Summary", txt)))
  expect_true(any(grepl("Missing-data profile by stage", txt)))
  expect_true(any(grepl("Stage-wise detailed parameter estimates", txt)))
  expect_true(any(grepl("LUCID Early Integration: Model Summary", txt)))
  expect_true(any(grepl("LUCID Parallel: Model Summary", txt)))
})

Try the LUCIDus package in your browser

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

LUCIDus documentation built on March 11, 2026, 9:06 a.m.