Skip to content

Commit 7c9186d

Browse files
skpr v1.8.1: Update moment matrix API for evaluation functions to require candidate set if user wants I optimality calculated. Use non-constrained by default.
-Fix skprGUI table color bug
1 parent 44399d7 commit 7c9186d

8 files changed

+89
-40
lines changed

DESCRIPTION

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: skpr
22
Title: Design of Experiments Suite: Generate and Evaluate Optimal Designs
33
Date: 2025-02-24
4-
Version: 1.8.0
4+
Version: 1.8.1
55
Authors@R: c(person("Tyler", "Morgan-Wall", email = "[email protected]", role = c("aut", "cre")),
66
person("George", "Khoury", email = "[email protected]", role = c("aut")))
77
Description: Generates and evaluates D, I, A, Alias, E, T, and G optimal designs. Supports generation and evaluation of blocked and split/split-split/.../N-split plot designs. Includes parametric and Monte Carlo power evaluation functions, and supports calculating power for censored responses. Provides a framework to evaluate power using functions provided in other packages or written by the user. Includes a Shiny graphical user interface that displays the underlying code used to create and evaluate the design to improve ease-of-use and make analyses more reproducible. For details, see Morgan-Wall et al. (2021) <doi:10.18637/jss.v099.i01>.
@@ -26,11 +26,11 @@ Imports:
2626
lmerTest,
2727
methods,
2828
progress,
29-
scales,
3029
doRNG,
3130
doFuture,
3231
progressr,
33-
geometry
32+
geometry,
33+
digest
3434
LinkingTo: Rcpp, RcppEigen
3535
Suggests: testthat, mbest, ggplot2, lmtest, cli, gridExtra, rintrojs, shinythemes, shiny, shinyjs, gt, shinytest2
3636
Encoding: UTF-8

R/eval_design.R

+28-14
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
#'The reordering will be presenting in the output when `detailedoutput = TRUE`.
3838
#'@param advancedoptions Default `NULL`. A named list with parameters to specify additional attributes to calculate. Options: `aliaspower`
3939
#'gives the degree at which the Alias matrix should be calculated.
40+
#'@param candidate_set Default `NA`. If you generated your design externally from skpr and there are disallowed combinations in your design,
41+
#'the calculated I-optimality values will not be correct, as it assumes an unconstrained unit hypercube. To calculate the restricted regions,
42+
#'skpr will find the convex hull of the point set and generate a higher density of points in that region. Note that this only supports
43+
#'convex constraints.
44+
#'@param mm_sample_density Default `20`. The density of points to sample when calculating the moment matrix to compute I-optimality. Only
45+
#'required if the design was generated outside of skpr and there are disallowed combinations.
4046
#'@param ... Additional arguments.
4147
#'@return A data frame with the parameters of the model, the type of power analysis, and the power. Several
4248
#'design diagnostics are stored as attributes of the data frame. In particular,
@@ -173,6 +179,8 @@ eval_design = function(
173179
reorder_factors = FALSE,
174180
detailedoutput = FALSE,
175181
advancedoptions = NULL,
182+
candidate_set = NA,
183+
mm_sample_density = 20,
176184
...
177185
) {
178186
if (missing(design)) {
@@ -501,24 +509,30 @@ eval_design = function(
501509
if(!is.null(attr(input_design, "generating.model"))) {
502510
og_design_factors = attr(terms.formula(attr(input_design, "generating.model")),"factors")
503511
new_model_factors = attr(terms.formula(model),"factors")
504-
identical_main_effects = all(rownames(og_design_factors) == rownames(new_model_factors))
505-
identical_interactions = all(colnames(og_design_factors) == colnames(new_model_factors))
506-
if(identical_interactions && identical_main_effects) {
507-
mm = attr(input_design, "moments.matrix")
508-
imported_mm = TRUE
512+
if(all(dim(og_design_factors) == dim(new_model_factors))) {
513+
identical_main_effects = all(rownames(og_design_factors) == rownames(new_model_factors))
514+
identical_interactions = all(colnames(og_design_factors) == colnames(new_model_factors))
515+
if(identical_interactions && identical_main_effects) {
516+
mm = attr(input_design, "moments.matrix")
517+
imported_mm = TRUE
518+
}
509519
}
510520
}
511521
if(!imported_mm) {
512-
if(all(classvector)) {
513-
mm = gen_momentsmatrix(colnames(attr(run_matrix_processed, "modelmatrix")), levelvector, classvector)
514-
} else {
515-
if(!is.null(attr(design, "candidate_set"))) {
516-
mm = gen_momentsmatrix_continuous(formula = model,
517-
candidate_set = attr(input_design, "candidate_set"),
518-
n_samples_per_dimension = 20)
522+
mm = gen_momentsmatrix(colnames(attr(run_matrix_processed, "modelmatrix") ), levelvector, classvector)
523+
if(!is.na(candidate_set)) {
524+
if(!all(classvector)) {
525+
hash_mm = digest::digest(list(model, candidate_set, mm_sample_density))
526+
if(!exists(hash_mm, envir = skpr_moment_matrix_cache)) {
527+
mm = gen_momentsmatrix_continuous(formula = model,
528+
candidate_set = candidate_set,
529+
n_samples_per_dimension = mm_sample_density)
530+
assign(hash_mm, mm, envir = skpr_moment_matrix_cache)
531+
} else {
532+
mm = get(hash_mm,envir = skpr_moment_matrix_cache)
533+
}
519534
} else {
520-
warning("Candidate set not included with design: assuming no disallowed combinations when calculating moment matrix.")
521-
mm = gen_momentsmatrix(colnames(attr(run_matrix_processed, "modelmatrix")), levelvector, classvector)
535+
mm = gen_momentsmatrix(colnames(attr(run_matrix_processed, "modelmatrix") ), levelvector, classvector)
522536
}
523537
}
524538
}

R/eval_design_mc.R

+29-15
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
#'set the confidence level for power intervals, which are printed when `detailedoutput = TRUE`.
5454
#'@param parallel Default `FALSE`. If `TRUE`, the Monte Carlo power calculation will use all but one of the available cores. If the user wants to set the number of cores manually, they can do this by setting `options("cores")` to the desired number (e.g. `options("cores" = parallel::detectCores())`).
5555
#' NOTE: If you have installed BLAS libraries that include multicore support (e.g. Intel MKL that comes with Microsoft R Open), turning on parallel could result in reduced performance.
56+
#'@param candidate_set Default `NA`. If you generated your design externally from skpr and there are disallowed combinations in your design,
57+
#'the calculated I-optimality values will not be correct, as it assumes an unconstrained unit hypercube. To calculate the restricted regions,
58+
#'skpr will find the convex hull of the point set and generate a higher density of points in that region. Note that this only supports
59+
#'convex constraints.
60+
#'@param mm_sample_density Default `20`. The density of points to sample when calculating the moment matrix to compute I-optimality. Only
61+
#'required if the design was generated outside of skpr and there are disallowed combinations.
5662
#'@param ... Additional arguments.
5763
#'@return A data frame consisting of the parameters and their powers, with supplementary information
5864
#'stored in the data frame's attributes. The parameter estimates from the simulations are stored in the "estimates"
@@ -254,6 +260,8 @@ eval_design_mc = function(
254260
detailedoutput = FALSE,
255261
progress = TRUE,
256262
advancedoptions = NULL,
263+
candidate_set = NA,
264+
mm_sample_density = 20,
257265
...
258266
) {
259267
if (!firth || glmfamily != "binomial") {
@@ -1294,25 +1302,31 @@ eval_design_mc = function(
12941302
imported_mm = FALSE
12951303
if(!is.null(attr(design, "generating.model"))) {
12961304
og_design_factors = attr(terms.formula(attr(design, "generating.model")),"factors")
1297-
new_model_factors = attr(terms.formula(model),"factors")
1298-
identical_main_effects = all(rownames(og_design_factors) == rownames(new_model_factors))
1299-
identical_interactions = all(colnames(og_design_factors) == colnames(new_model_factors))
1300-
if(identical_interactions && identical_main_effects) {
1301-
mm = attr(design, "moments.matrix")
1302-
imported_mm = TRUE
1305+
new_model_factors = attr(terms.formula(model_formula),"factors")
1306+
if(all(dim(og_design_factors) == dim(new_model_factors))) {
1307+
identical_main_effects = all(rownames(og_design_factors) == rownames(new_model_factors))
1308+
identical_interactions = all(colnames(og_design_factors) == colnames(new_model_factors))
1309+
if(identical_interactions && identical_main_effects) {
1310+
mm = attr(design, "moments.matrix")
1311+
imported_mm = TRUE
1312+
}
13031313
}
13041314
}
13051315
if(!imported_mm) {
1306-
if(all(classvector)) {
1307-
mm = gen_momentsmatrix(colnames(attr(run_matrix_processed, "modelmatrix")), levelvector, classvector)
1308-
} else {
1309-
if(!is.null(attr(design, "candidate_set"))) {
1310-
mm = gen_momentsmatrix_continuous(formula = model,
1311-
candidate_set = attr(design, "candidate_set"),
1312-
n_samples_per_dimension = 20)
1316+
mm = gen_momentsmatrix(colnames(ModelMatrix), levelvector, classvector)
1317+
if(!is.na(candidate_set)) {
1318+
if(!all(classvector)) {
1319+
hash_mm = digest::digest(list(model_formula, candidate_set, mm_sample_density))
1320+
if(!exists(hash_mm, envir = skpr_moment_matrix_cache)) {
1321+
mm = gen_momentsmatrix_continuous(formula = model_formula,
1322+
candidate_set = candidate_set,
1323+
n_samples_per_dimension = mm_sample_density)
1324+
assign(hash_mm, mm, envir = skpr_moment_matrix_cache)
1325+
} else {
1326+
mm = get(hash_mm,envir = skpr_moment_matrix_cache)
1327+
}
13131328
} else {
1314-
warning("Candidate set not included with design: assuming no disallowed combinations when calculating moment matrix.")
1315-
mm = gen_momentsmatrix(colnames(attr(run_matrix_processed, "modelmatrix")), levelvector, classvector)
1329+
mm = gen_momentsmatrix(colnames(ModelMatrix), levelvector, classvector)
13161330
}
13171331
}
13181332
}

R/skprGUI.R

+4-7
Original file line numberDiff line numberDiff line change
@@ -2727,10 +2727,7 @@ skprGUI = function(
27272727
display_table = display_table %>%
27282728
gt::data_color(
27292729
columns = "power",
2730-
palette = scales::col_numeric(
2731-
palette = colorRampPalette(c("white", "darkgreen"))(100),
2732-
domain = c(0, 1)
2733-
),
2730+
palette = colorRampPalette(c("white", "darkgreen"))(100),
27342731
domain = c(0, 1),
27352732
alpha = 0.3,
27362733
autocolor_text = FALSE
@@ -2766,7 +2763,7 @@ skprGUI = function(
27662763
) %>%
27672764
gt::tab_source_note(
27682765
source_note = sprintf(
2769-
"Note: Power values marked in %s are within the simulation uncertainty for user-specified Type-I error (increase the number of simulations)",
2766+
"Note: Power values marked in %s are within the simulation uncertainty for user-specified minimum power: increase the number of simulations.",
27702767
color_maybe
27712768
)
27722769
)
@@ -2784,9 +2781,9 @@ skprGUI = function(
27842781
) %>%
27852782
gt::tab_source_note(
27862783
source_note = sprintf(
2787-
"Note: Power values marked in %s fall below the user-specified Type-I error (%0.2f)",
2784+
"Note: Power values marked in %s fall below the user-specified minimum power (%0.2f)",
27882785
color_bad,
2789-
alpha
2786+
desired_power_level
27902787
)
27912788
)
27922789
}

R/zzz.R

+3
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,6 @@ assign(
4646
detect_multicore_support(),
4747
envir = skpr_system_setup_env
4848
)
49+
50+
skpr_moment_matrix_cache = new.env(parent = emptyenv())
51+

man/eval_design.Rd

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/eval_design_mc.Rd

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-shinytest2.R

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ library(shiny)
44
test_that("{shinytest2} recording: apps", {
55
options("in_skpr_test_environment" = TRUE)
66
on.exit(options("in_skpr_test_environment" = NULL), add = TRUE)
7-
app <- AppDriver$new(app_dir = testthat::test_path("apps"),
7+
app <- AppDriver$new(app_dir = testthat::test_path("apps"), screenshot_args = FALSE,
8+
expect_values_screenshot_args = FALSE,
89
variant = platform_variant(), name = "apps", height = 923,
910
width = 1619, timeout = 10*1000, wait = TRUE)
1011
app$set_inputs(setseed = TRUE)

0 commit comments

Comments
 (0)