This vignette illustrates the component engine introduced in version 0.4.0. The schedule contains four assigned treatment states: Control, A, B, and A+B. Unlike a cumulative rollout, a component may be withdrawn and later restarted. The data-generating model can retain a prespecified residual component effect after withdrawal.
The following example contains both
Control -> A -> A+B -> B and
Control -> B -> A+B paths. Numeric state codes are 0
for Control, 1 for A, 2 for B, and 3 for A+B.
library(stepwedgepower)
state <- rbind(
S1 = c(0, 0, 1, 1, 3, 3, 2, 2, 2, 2),
S2 = c(0, 0, 0, 1, 1, 3, 3, 2, 2, 2),
S3 = c(0, 0, 2, 2, 3, 3, 3, 3, 3, 3),
S4 = c(0, 0, 0, 2, 2, 3, 3, 3, 3, 3),
S5 = c(0, 0, 1, 1, 1, 3, 3, 3, 3, 3),
S6 = c(0, 0, 2, 2, 2, 3, 3, 3, 3, 3),
S7 = c(0, 0, 0, 0, 0, 1, 1, 3, 2, 2),
S8 = c(0, 0, 0, 0, 0, 2, 2, 3, 1, 1)
)
design <- sw_component_design(
clusters_per_sequence = rep(5L, 8),
state = state
)
design
#> <sw_component_design>
#> 8 sequences, 10 calendar periods, 40 clusters total
#> clusters per sequence: 5, 5, 5, 5, 5, 5, 5, 5
#> observed cluster-periods: 400 of 400
#> observed states present: Control, A, B, A+B
#> withdrawals: A = 3, B = 1; restarts: A = 0, B = 0
#> Period 1 Period 2 Period 3 Period 4 Period 5 Period 6 Period 7 Period 8
#> S1 Control Control A A A+B A+B B B
#> S2 Control Control Control A A A+B A+B B
#> S3 Control Control B B A+B A+B A+B A+B
#> S4 Control Control Control B B A+B A+B A+B
#> S5 Control Control A A A A+B A+B A+B
#> S6 Control Control B B B A+B A+B A+B
#> S7 Control Control Control Control Control A A A+B
#> S8 Control Control Control Control Control B B A+B
#> Period 9 Period 10
#> S1 B B
#> S2 B B
#> S3 A+B A+B
#> S4 A+B A+B
#> S5 A+B A+B
#> S6 A+B A+B
#> S7 B B
#> S8 A AThe schedule is represented internally by separate binary assignment matrices for A and B. It is not treated as an ordinal 0–3 dose.
assumptions <- sw_component_assumptions(
baseline_prob = 0.15,
treatment_or_a = 1.35,
treatment_or_b = 1.25,
interaction_or = 1.10,
delay_a = 1L,
delay_b = 1L,
carryover_periods_a = 2L,
carryover_periods_b = 2L,
carryover_weights_a = c(0.60, 0.30),
carryover_weights_b = c(0.50, 0.25),
restart_rule_a = "reset",
restart_rule_b = "reset",
interaction_mode = "effective_overlap",
icc = 0.05,
period_effects = log(seq(1.00, 1.10, length.out = ncol(state))),
n_per_cluster_period = 25L
)
assumptions
#> <sw_component_assumptions>
#> A vs Control: OR = 1.350; wash-in = 1 period(s)
#> B vs Control: OR = 1.250; wash-in = 1 period(s)
#> A-by-B interaction OR = 1.100; mode = effective_overlap
#> A carryover weights: 0.600, 0.300
#> B carryover weights: 0.500, 0.250
#> restart rules: A = reset; B = reset
#> cluster_sd = 0.416 (latent ICC = 0.050)
#> baseline probabilities: 0.150
#> period effects (log-odds): 0.000, 0.011, 0.022, 0.033, 0.043, 0.054, 0.065, 0.075, 0.085, 0.095A one-period delay means that a component first contributes its full
effect in the second consecutive assigned period. After A is withdrawn,
60 percent and 30 percent of its full log-odds effect persist for two
periods. With interaction_mode = "effective_overlap", the
interaction weight is the product of the effective A and B weights, so
interaction carryover is possible while both effective components
overlap.
audit <- audit_component_design(design, assumptions)
audit
#> <sw_component_audit>
#> observed-data fixed-effect rank: 13 of 13 (full)
#> observed cluster-periods: 400 of 400; missing: 0
#> requested contrasts:
#> contrast label estimable
#> A_vs_control A vs Control TRUE
#> B_vs_control B vs Control TRUE
#> B_vs_A B vs A TRUE
#> AB_vs_control A+B vs Control TRUE
#> AB_vs_A A+B vs A TRUE
#> AB_vs_B A+B vs B TRUE
#> interaction A-by-B interaction TRUE
#> withdrawals: A = 3, B = 1; restarts: A = 0, B = 0
#> no structural cautions detectedThe audit checks the rank of the intended fixed-effect model and formal estimability of seven standard contrasts. It also reports concurrent state comparisons and notes any withdrawal for which immediate washout has been assumed.
one_trial <- simulate_component_swcrt(design, assumptions, seed = 123)
fit <- fit_component_model(
one_trial,
multiplicity = "holm",
multiplicity_family = c("A_vs_control", "B_vs_control", "interaction")
)
fit$contrasts
#> contrast label estimate std_error z_value
#> 1 A_vs_control A vs Control 0.28167648 0.12624162 2.2312489
#> 2 B_vs_control B vs Control 0.24813868 0.13065804 1.8991459
#> 3 B_vs_A B vs A -0.03353779 0.10279759 -0.3262507
#> 4 AB_vs_control A+B vs Control 0.74970708 0.16120443 4.6506604
#> 5 AB_vs_A A+B vs A 0.46803060 0.12204672 3.8348480
#> 6 AB_vs_B A+B vs B 0.50156840 0.09744417 5.1472385
#> 7 interaction A-by-B interaction 0.21989192 0.14437806 1.5230286
#> p_value conf_low conf_high odds_ratio p_adjusted reject
#> 1 2.566465e-02 0.034247446 0.5291055 1.3253499 0.07699394 TRUE
#> 2 5.754530e-02 -0.007946378 0.5042237 1.2816377 0.11509060 FALSE
#> 3 7.442346e-01 -0.235017370 0.1679418 0.9670184 NA FALSE
#> 4 3.308737e-06 0.433752196 1.0656620 2.1163800 NA TRUE
#> 5 1.256420e-04 0.228823437 0.7072378 1.5968463 NA TRUE
#> 6 2.643491e-07 0.310581328 0.6925555 1.6513091 NA TRUE
#> 7 1.277515e-01 -0.063083881 0.5028677 1.2459421 0.12775154 FALSE
#> reject_adjusted
#> 1 FALSE
#> 2 FALSE
#> 3 NA
#> 4 NA
#> 5 NA
#> 6 NA
#> 7 FALSEThe standard contrasts are:
The interaction coefficient is the departure from additivity on the log-odds scale. A B-only state is required to separate the B main effect from the interaction when the interaction is fitted.
A short exploratory run is shown below. A final analysis should use a
simulation count chosen from a prespecified Monte Carlo precision target
and should also run the global-null design through
type1_component_swcrt().
power <- power_component_swcrt(
design,
assumptions,
nsim = 5000,
multiplicity = "holm",
multiplicity_family = c("A_vs_control", "B_vs_control", "interaction"),
nAGQ = 1,
n_cores = 4,
seed = 2026
)
summary(power)
power$fit_diagnostics
power$replicate_diagnostics
type1 <- type1_component_swcrt(
design,
assumptions,
nsim = 5000,
multiplicity = "holm",
multiplicity_family = c("A_vs_control", "B_vs_control", "interaction"),
nAGQ = 1,
n_cores = 4,
seed = 22026
)
summary(type1)The primary fit statuses are hard GLMM error, nonconverged fit, converged fit with a non-finite requested contrast, and successful fit. Singular fit is a separate, non-exclusive property.
Both conditional power and failure-aware power are reported. Their difference shows how much the apparent operating performance depends on excluding failed or non-estimable analyses.