tests/testthat/test-execute.R

library(future)
library(tidyr)
library(dplyr)
library(rlang)

values_x = exprs("a", 0, 5, 10, 14)
values_y = exprs("b", 2, 1, 4, 3)
values_z = exprs(0, 0, 5, 10, 14, 28)

test_that("auto-executes the default analysis in the multiverse", {
  M <- multiverse()
  inside(M, {x <- branch(value_x, "a", 0, 5, 10, 14)} )
  y <- M$x
  expect_equal(y, "a")
})

test_that("`execute_multiverse` executes all the analyses in the multiverse", {
  M <- multiverse()
  inside(M, {x <- branch(value_x, "a", 0, 5, 10, 14)} )
  
  execute_multiverse(M)
  expect_equal(extract_variable_from_universe(M, 1, x), values_x[[1]])
  expect_equal(extract_variable_from_universe(M, 2, x), values_x[[2]])
  expect_equal(extract_variable_from_universe(M, 3, x), values_x[[3]])
  expect_equal(extract_variable_from_universe(M, 4, x), values_x[[4]])
  expect_equal(extract_variable_from_universe(M, 5, x), values_x[[5]])
})

test_that("`execute_multiverse` executes all the analyses across two inside blocks", {
  M <- multiverse()
  inside(M, {x <- branch(value_x, 0, 5, 14)} )
  
  inside(M, {
    y <- branch(value_y, 1, 2)
    
    z <- x * y
  })
  
  execute_multiverse(M)
  expect_equal(extract_variable_from_universe(M, 1, z), values_z[[1]])
  expect_equal(extract_variable_from_universe(M, 2, z), values_z[[2]])
  expect_equal(extract_variable_from_universe(M, 3, z), values_z[[3]])
  expect_equal(extract_variable_from_universe(M, 4, z), values_z[[4]])
  expect_equal(extract_variable_from_universe(M, 5, z), values_z[[5]])
  expect_equal(extract_variable_from_universe(M, 6, z), values_z[[6]])
})

test_that("`execute_linear` executes all the analyses across two inside blocks", {
  M <- multiverse()
  inside(M, {x <- branch(value_x, 0, 5, 14)} )
  
  inside(M, {
    y <- branch(value_y, 1, 2)
    
    z <- x * y
  } )
  
  execute_linear(M, FALSE, FALSE)
  expect_equal(extract_variable_from_universe(M, 1, z), values_z[[1]])
  expect_equal(extract_variable_from_universe(M, 2, z), values_z[[2]])
  expect_equal(extract_variable_from_universe(M, 3, z), values_z[[3]])
  expect_equal(extract_variable_from_universe(M, 4, z), values_z[[4]])
  expect_equal(extract_variable_from_universe(M, 5, z), values_z[[5]])
  expect_equal(extract_variable_from_universe(M, 6, z), values_z[[6]])
})

test_that("`execute_linear` executes all the analyses across two inside blocks during parallel computation", {
  M <- multiverse()
  
  inside(M, {x <- branch(value_x, 0, 5, 14)} )
  
  inside(M, {
    y <- branch(value_y, 1, 2)
    
    z <- x * y
  } )
  
  plan(multisession, workers = 2)
  execute_linear(M, TRUE, FALSE)
  plan(sequential)
  
  expect_equal(extract_variable_from_universe(M, 1, z), values_z[[1]])
  expect_equal(extract_variable_from_universe(M, 2, z), values_z[[2]])
  expect_equal(extract_variable_from_universe(M, 3, z), values_z[[3]])
  expect_equal(extract_variable_from_universe(M, 4, z), values_z[[4]])
  expect_equal(extract_variable_from_universe(M, 5, z), values_z[[5]])
  expect_equal(extract_variable_from_universe(M, 6, z), values_z[[6]])
})

test_that("parallel computation is supported", {
  M_cores_2.1 <- multiverse()

  inside(M_cores_2.1, {x <- branch(value_x, 0, 5, 10, 14)} )
  inside(M_cores_2.1, {y <- branch(value_y, 1, 2, 3, 4)} )
  
  ref_list.1 = crossing(
    x = c(0, 5, 10, 14),
    y = c(1, 2, 3, 4)
  )
  
  M_cores_2.2 <- multiverse()
  
  inside(M_cores_2.2, {
    var1 <- branch(
      var_num,
      "var1" ~ 1,
      "var2" ~ 2,
      "var3" ~ 3
    )
  })
  
  inside(M_cores_2.2, {
    var2 <- branch(
      var_char,
      "vara" ~ "a",
      "varb" ~ "b",
      "varc" ~ "c"
    )
  })
  
  ref_list.2 = crossing(
    var1 = c(1, 2, 3),
    var2 = c("a", "b", "c")
  )
  
  plan(multisession, workers = 2)
  execute_multiverse(M_cores_2.1, parallel = TRUE)
  execute_multiverse(M_cores_2.2, parallel = TRUE)
  plan(sequential)
  
  expect_equal(
    as.list(select(extract_variables(M_cores_2.1, x, y), x, y)), 
    as.list( ref_list.1 )
  )
  
  expect_equal(
    as.list(select(extract_variables(M_cores_2.2, var1, var2), var1, var2)),
    as.list( ref_list.2)
  )
})

test_that("`execute_multiverse` sends error and warning messages but does not stop execution", {
  M <- multiverse()
  inside(M, {
    y <- 10
    x <- branch(value_x, 1, 0, stop("error"), 10, 14)
  } )
  
  expect_warning(execute_multiverse(M))
  
  df.extracted <- extract_variables(M, x) %>%
    select(-.parameter_assignment, -.code, -.results, -.errors)
  
  ref <- tibble(
    .universe = 1:5,
    value_x = c('1', '0', expr('stop("error")'), '10', '14'),
    x = c(1, 0, NA, 10, 14)
  )
  
  expect_equal(as.list(df.extracted), as.list(ref))
})


test_that("`execute_universe` sends message about error but does not stop execution", {
  M <- multiverse()
  an_expr <- expr({
    y <- runif(10, 2, 1)
    x <- branch(value_x, 1, 0, stop("error"), 10, 14)
  })
  
  expect_warning( inside(M, !! an_expr) )
  
  M2 <- multiverse()
  inside(M2, {
    y <- runif(10, 0, 1)
    x <- branch(value_x, 1, 0, stop("error"), 10, 14)
  })
  expect_warning(execute_multiverse(M2))
  
  expect_true( env_has(expand(M2)$.results[[4]], "x") )
  expect_equal( env_get(expand(M2)$.results[[4]], "x"), 10 )
  expect_true( env_has(expand(M2)$.results[[5]], "x") )
  expect_equal( env_get(expand(M2)$.results[[5]], "x"), 14 )
})

test_that("`execute_universe` executes the correct universe", {
  M <- multiverse()
  an_expr <- expr({
    x <- branch(value_x, 1, 2, 3, 4)
  })
  
  inside(M, !!an_expr)
  
  execute_universe(M, .universe = 3)
  expect_true(env_has(expand(M)$.results[[3]], "x"))
  expect_equal(env_get(expand(M)$.results[[3]], "x"), 3)
  expect_false(env_has(expand(M)$.results[[2]], "x"))
})

test_that("test 1/N: `execute_universe` executes the correct universe with multiple levels", {
  M <- multiverse()
  an_expr.1 <- expr({
    x <- branch(value_x, 1, 2, 3, 4)
  })
  
  an_expr.2 <- expr({
    y <- branch(value_y, 5, 6, 7)
    z <- x + y
  })
  
  inside(M, !!an_expr.1)
  inside(M, !!an_expr.2)
  
  execute_universe(M, .universe = 3)
  expect_true(env_has(expand(M)$.results[[3]], "z"))
  expect_equal(env_get(expand(M)$.results[[3]], "z"), 8)
  expect_false(env_has(expand(M)$.results[[10]], "x"))
  expect_false(env_has(expand(M)$.results[[10]], "z"))
  
  execute_universe(M, .universe = 10)
  expect_true(env_has(expand(M)$.results[[10]], "x"))
  expect_equal(env_get(expand(M)$.results[[10]], "x"), 4)
  expect_equal(env_get(expand(M)$.results[[10]], "z"), 9)
})

test_that("test 2/N: `execute_universe` executes the correct universe with multiple levels", {
  M <- multiverse()
  an_expr.1 <- expr({
    x <- branch(value_x, 4, 5, 6)
  })
  
  an_expr.2 <- expr({
    y <- branch(value_y, 11, 21, 31)
  })
  
  an_expr.3 <- expr({
    z <- branch(calc, x + y, x * y)
  })
  
  inside(M, !!an_expr.1, .execute_default = FALSE)
  inside(M, !!an_expr.2, .execute_default = FALSE)
  inside(M, !!an_expr.3, .execute_default = FALSE)
  
  execute_universe(M, .universe = 2)
  expect_true(env_has(expand(M)$.results[[2]], "z"))
  expect_true(env_has(expand(M)$.results[[2]], "x"))
  expect_true(env_has(expand(M)$.results[[2]], "y"))
  expect_equal(env_get(expand(M)$.results[[2]], "z"), 44)
  expect_false(env_has(expand(M)$.results[[1]], "x"))
  expect_false(env_has(expand(M)$.results[[1]], "y"))
  expect_false(env_has(expand(M)$.results[[5]], "x"))
  expect_false(env_has(expand(M)$.results[[5]], "y"))
  
  execute_universe(M, .universe = 9)
  expect_equal(env_get(expand(M)$.results[[9]], "z"), 26)
})

test_that("multiverse sends warning message and continues to execute when warnings are encountered", {
  M <- multiverse()
  
  inside(M, {
    x <- branch(a_param,
                "1" ~ 1,
                "warning" ~ warning(10),
                "3" ~ 3
    )
  })
  
  expect_warning(execute_multiverse(M))
  expect_true(env_has(expand(M)$.results[[2]], "x"))
})

test_that("multiverses created with `tree = FALSE` executes all analyses correctly", {
  options(tree = FALSE)
  
  M <- multiverse()
  inside(M, {x <- branch(value_x, 0, 5, 14)}, .execute_default = FALSE )
  inside(M, {
    y <- branch(value_y, 1, 2)
    
    z <- x * y
  }, .execute_default = FALSE)
  
  execute_multiverse(M, FALSE, FALSE)
  options(tree = TRUE)
  
  expect_equal(extract_variable_from_universe(M, 1, z), values_z[[1]])
  expect_equal(extract_variable_from_universe(M, 2, z), values_z[[2]])
  expect_equal(extract_variable_from_universe(M, 3, z), values_z[[3]])
  expect_equal(extract_variable_from_universe(M, 4, z), values_z[[4]])
  expect_equal(extract_variable_from_universe(M, 5, z), values_z[[5]])
  expect_equal(extract_variable_from_universe(M, 6, z), values_z[[6]])
})

test_that("`execute_linear` executes all the analyses across two inside blocks during parallel computation when tree = FALSE", {
  options(tree = FALSE)
  
  M <- multiverse()
  inside(M, {x <- branch(value_x, 0, 5, 14)}, .execute_default = FALSE )
  inside(M, {
    y <- branch(value_y, 1, 2)
    
    z <- x * y
  }, .execute_default = FALSE)
  
  plan(multisession, workers = 2)
  execute_linear(M, TRUE, FALSE)
  plan(sequential)
  
  options(tree = TRUE)
  
  expect_equal(extract_variable_from_universe(M, 1, z), values_z[[1]])
  expect_equal(extract_variable_from_universe(M, 2, z), values_z[[2]])
  expect_equal(extract_variable_from_universe(M, 3, z), values_z[[3]])
  expect_equal(extract_variable_from_universe(M, 4, z), values_z[[4]])
  expect_equal(extract_variable_from_universe(M, 5, z), values_z[[5]])
  expect_equal(extract_variable_from_universe(M, 6, z), values_z[[6]])
})

test_that("execute_universe outputs correct result during parallel execution", {
  M = multiverse()
  
  df = data.frame(a = 1, b = 2)
  
  inside(M, {
    x = branch(x_values, 1, 2, 3)
    y = "a"
  }, .execute_default = FALSE)
  
  inside(M, {
    z = branch(z_values, 4, 5, 6)
    w = "b"
    df = df %>%
      mutate(
        astr = paste0(y, w),
        anmbr = x*z + a
      )
  }, .execute_default = FALSE) 

  plan(multisession, workers = 3)
  execute_universe(M, 4:6)
  plan(sequential)
  
  .res = expand(M) %>%
    extract_variables(df) %>%
    unnest(df) %>%
    select(-c(.parameter_assignment, .code, .results, .errors))
  
  .res_ref = expand.grid(z_values = c('4', '5', '6'), x_values = c('1', '2', '3'), KEEP.OUT.ATTRS = FALSE, stringsAsFactors=FALSE) %>%
    mutate(
      .universe = row_number(),
      a = 1, b = 2, 
      astr = c(rep(NA, 3), rep("ab", 3), rep(NA, 3)),
      anmbr = c(rep(NA, 3), 4:6*2 + 1, rep(NA, 3))
    ) %>%
    select(.universe, x_values, z_values, everything())
  
  expect_equal(as.list(.res), as.list(.res_ref))
})

test_that("execute_universe outputs correct result during parallel execution", {
  M = multiverse()
  
  df = data.frame(a = 1, b = 2)
  
  inside(M, {
    x = branch(x_values, 1, 2, 3)
    y = "a"
  }, .execute_default = FALSE)
  
  inside(M, {
    z = branch(z_values, 4, 5, 6)
    w = "b"
    df = df %>%
      mutate(
        astr = paste0(y, w),
        anmbr = x*z + a
      )
  }, .execute_default = FALSE) 
  
  N = nrow(expand(M))
  
  plan(multisession, workers = 3)
  execute_universe(M, 1:N, TRUE)
  plan(sequential)
  
  .res = expand(M) %>%
    extract_variables(df) %>%
    unnest(df) %>%
    select(-c(.parameter_assignment, .code, .results, .errors))
  
  .res_ref = expand.grid(z_values = c('4', '5', '6'), x_values = c('1', '2', '3'), KEEP.OUT.ATTRS = FALSE, stringsAsFactors=FALSE) %>%
    mutate(
      .universe = row_number(),
      a = 1, b = 2, 
      astr = 'ab',
      anmbr = c(4:6, 4:6*2, 4:6*3) + 1
    ) %>%
    select(.universe, x_values, z_values, everything())
  
  expect_equal(as.list(.res), as.list(.res_ref))
})

test_that("execute_universe outputs correct result during parallel execution of a partial multiverse", {
  M = multiverse()
  
  df = data.frame(a = 1, b = 2)
  
  inside(M, {
    x = branch(x_values, 1, 2, 3)
    y = "a"
  }, .execute_default = FALSE)
  
  inside(M, {
    z = branch(z_values, 4, 5, 6)
    w = "b"
    df = df %>%
      mutate(
        astr = paste0(y, w),
        anmbr = x*z + a
      )
    
    astr = df$astr
    anmbr = df$anmbr
  }, .execute_default = FALSE) 
  
  N = 3:6
  
  plan(multisession, workers = 3)
  execute_universe(M, N, TRUE)
  plan(sequential)
  
  .res = expand(M) %>%
    extract_variables(astr, anmbr) %>%
    select(-c(.parameter_assignment, .code, .results, .errors))
  
  .res_ref = expand.grid(z_values = c('4', '5', '6'), x_values = c('1', '2', '3'), KEEP.OUT.ATTRS = FALSE, stringsAsFactors=FALSE) %>%
    mutate(
      .universe = row_number(),
      astr = c(rep(NA, 2), rep("ab", 4), rep(NA, 3)),
      anmbr = c(rep(NA, 2), N*2 + 1, rep(NA, 3))
    ) %>%
    select(.universe, x_values, z_values, everything())
  
  expect_equal(as.list(.res), as.list(.res_ref))
})
MUCollective/multidy documentation built on Jan. 27, 2024, 9:52 a.m.