Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
gowerc committed Aug 1, 2024
1 parent 3f28788 commit 187ac27
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 49 deletions.
6 changes: 3 additions & 3 deletions R/LongitudinalSteinFojo.R
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ LongitudinalSteinFojo <- function(
Parameter(name = "lm_sf_mu_ks", prior = mu_ks, size = "n_arms"),
Parameter(name = "lm_sf_mu_kg", prior = mu_kg, size = "n_arms"),

Parameter(name = "lm_sf_omega_bsld", prior = omega_bsld, size = 1),
Parameter(name = "lm_sf_omega_ks", prior = omega_ks, size = 1),
Parameter(name = "lm_sf_omega_kg", prior = omega_kg, size = 1),
Parameter(name = "lm_sf_omega_bsld", prior = omega_bsld, size = "n_studies"),
Parameter(name = "lm_sf_omega_ks", prior = omega_ks, size = "n_arms"),
Parameter(name = "lm_sf_omega_kg", prior = omega_kg, size = "n_arms"),

Parameter(name = "lm_sf_sigma", prior = sigma, size = 1)
)
Expand Down
39 changes: 35 additions & 4 deletions R/SimLongitudinalSteinFojo.R
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ SimLongitudinalSteinFojo <- function(
link_growth = 0,
link_shrinkage = 0
) {

if (length(omega_b) == 1) omega_b <- rep(omega_b, length(mu_b))
if (length(omega_s) == 1) omega_s <- rep(omega_s, length(mu_s))
if (length(omega_g) == 1) omega_g <- rep(omega_g, length(mu_g))

.SimLongitudinalSteinFojo(
times = times,
sigma = sigma,
Expand Down Expand Up @@ -99,8 +104,22 @@ setValidity(
if (length(unique(par_lengths)) != 1) {
return("The parameters `mu_s` and `mu_g` must have the same length.")
}
pairs <- list(
"omega_b" = "mu_b",
"omega_s" = "mu_s",
"omega_g" = "mu_g"
)
for (i in seq_along(pairs)) {
omega <- slot(object, names(pairs)[[i]])
mu <- slot(object, pairs[[i]])
if (!(length(omega) == length(mu))) {
return(
sprintf("`%s` must be length 1 or the same length as `%s`", omega, mu)
)
}
}
len_1_pars <- c(
"sigma", "omega_b", "omega_s", "omega_g",
"sigma",
"link_dsld", "link_ttg", "link_identity",
"link_growth", "link_shrinkage"
)
Expand Down Expand Up @@ -151,9 +170,21 @@ sampleSubjects.SimLongitudinalSteinFojo <- function(object, subjects_df) {
dplyr::distinct(.data$subject, .data$arm, .data$study) |>
dplyr::mutate(study_idx = as.numeric(.data$study)) |>
dplyr::mutate(arm_idx = as.numeric(.data$arm)) |>
dplyr::mutate(psi_b = stats::rlnorm(dplyr::n(), object@mu_b[.data$study_idx], object@omega_b)) |>
dplyr::mutate(psi_s = stats::rlnorm(dplyr::n(), object@mu_s[.data$arm_idx], object@omega_s)) |>
dplyr::mutate(psi_g = stats::rlnorm(dplyr::n(), object@mu_g[.data$arm_idx], object@omega_g))
dplyr::mutate(psi_b = stats::rlnorm(
dplyr::n(),
object@mu_b[.data$study_idx],
object@omega_b[.data$study_idx]
)) |>
dplyr::mutate(psi_s = stats::rlnorm(
dplyr::n(),
object@mu_s[.data$arm_idx],
object@omega_s[.data$arm_idx]
)) |>
dplyr::mutate(psi_g = stats::rlnorm(
dplyr::n(),
object@mu_g[.data$arm_idx],
object@omega_g[.data$arm_idx]
))

res[, c("subject", "arm", "study", "psi_b", "psi_s", "psi_g")]
}
Expand Down
18 changes: 9 additions & 9 deletions inst/stan/lm-stein-fojo/model.stan
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ parameters{
vector[n_arms] lm_sf_mu_ks;
vector[n_arms] lm_sf_mu_kg;

real<lower={{ machine_double_eps }}> lm_sf_omega_bsld;
real<lower={{ machine_double_eps }}> lm_sf_omega_ks;
real<lower={{ machine_double_eps }}> lm_sf_omega_kg;
vector<lower={{ machine_double_eps }}>[n_studies] lm_sf_omega_bsld;
vector<lower={{ machine_double_eps }}>[n_arms] lm_sf_omega_ks;
vector<lower={{ machine_double_eps }}>[n_arms] lm_sf_omega_kg;

{% if centred -%}
vector<lower={{ machine_double_eps }}>[n_subjects] lm_sf_psi_bsld;
Expand Down Expand Up @@ -41,13 +41,13 @@ transformed parameters{

{% if not centred -%}
vector<lower={{ machine_double_eps }}>[n_subjects] lm_sf_psi_bsld = exp(
lm_sf_mu_bsld[subject_study_index] + (lm_sf_eta_tilde_bsld * lm_sf_omega_bsld)
lm_sf_mu_bsld[subject_study_index] + (lm_sf_eta_tilde_bsld * lm_sf_omega_bsld[subject_study_index])
);
vector<lower={{ machine_double_eps }}>[n_subjects] lm_sf_psi_ks = exp(
lm_sf_mu_ks[subject_arm_index] + (lm_sf_eta_tilde_ks * lm_sf_omega_ks)
lm_sf_mu_ks[subject_arm_index] + (lm_sf_eta_tilde_ks * lm_sf_omega_ks[subject_arm_index])
);
vector<lower={{ machine_double_eps }}>[n_subjects] lm_sf_psi_kg = exp(
lm_sf_mu_kg[subject_arm_index] + (lm_sf_eta_tilde_kg * lm_sf_omega_kg)
lm_sf_mu_kg[subject_arm_index] + (lm_sf_eta_tilde_kg * lm_sf_omega_kg[subject_arm_index])
);
{%- endif -%}

Expand Down Expand Up @@ -80,9 +80,9 @@ model {
// Source - lm-stein-fojo/model.stan
//
{% if centred %}
lm_sf_psi_bsld ~ lognormal(lm_sf_mu_bsld[subject_study_index], lm_sf_omega_bsld);
lm_sf_psi_ks ~ lognormal(lm_sf_mu_ks[subject_arm_index], lm_sf_omega_ks);
lm_sf_psi_kg ~ lognormal(lm_sf_mu_kg[subject_arm_index], lm_sf_omega_kg);
lm_sf_psi_bsld ~ lognormal(lm_sf_mu_bsld[subject_study_index], lm_sf_omega_bsld[subject_study_index]);
lm_sf_psi_ks ~ lognormal(lm_sf_mu_ks[subject_arm_index], lm_sf_omega_ks[subject_arm_index]);
lm_sf_psi_kg ~ lognormal(lm_sf_mu_kg[subject_arm_index], lm_sf_omega_kg[subject_arm_index]);
{%- endif -%}
}

73 changes: 49 additions & 24 deletions tests/testthat/test-LongitudinalSteinFojo.R
Original file line number Diff line number Diff line change
Expand Up @@ -108,38 +108,54 @@ test_that("Can load and compile growth + shrinkage links", {
test_that("Can recover known distributional parameters from a SF joint model", {

skip_if_not(is_full_test())

set.seed(9438)
pars <- list(
sigma = 0.01,
mu_s = log(c(0.6, 0.4)),
mu_g = log(c(0.25, 0.35)),
mu_b = log(60),
omega_b = c(0.2),
omega_s = c(0.3, 0.1),
omega_g = c(0.1, 0.3),
omega_phi = c(0.3, 0.1),
link_dsld = 0.1,
link_ttg = 0.2,
link_identity = 0,
beta_cat_B = 0.5,
beta_cat_C = -0.1,
beta_cont = 0.3,
lambda = 1 / (400 / 365)
)
set.seed(9898)
## Generate Test data with known parameters
jlist <- SimJointData(
design = list(
SimGroup(120, "Arm-A", "Study-X"),
SimGroup(120, "Arm-B", "Study-X")
SimGroup(180, "Arm-A", "Study-X"),
SimGroup(190, "Arm-B", "Study-X")
),
longitudinal = SimLongitudinalSteinFojo(
times = c(-100, -50, -10, 1, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900) * (1 / 365),
sigma = 0.005,
mu_s = log(c(0.2, 0.25)),
mu_g = log(c(0.15, 0.2)),
mu_b = log(60),
omega_b = 0.1,
omega_s = 0.1,
omega_g = 0.1,
link_ttg = -0.2,
link_dsld = 0.2
sigma = pars$sigma,
mu_s = pars$mu_s,
mu_g = pars$mu_g,
mu_b = pars$mu_b,
omega_b = pars$omega_b,
omega_s = pars$omega_s,
omega_g = pars$omega_g,
link_ttg = pars$link_ttg,
link_dsld = pars$link_dsld,
link_identity = pars$link_identity
),
survival = SimSurvivalWeibullPH(
survival = SimSurvivalExponential(
time_max = 4,
time_step = 1 / 365,
lambda = 1,
gamma = 1,
lambda = pars$lambda,
lambda_cen = 1 / 9000,
beta_cat = c(
"A" = 0,
"B" = -0.1,
"C" = 0.5
"B" = pars$beta_cat_B,
"C" = pars$beta_cat_C
),
beta_cont = 0.3
beta_cont = pars$beta_cont
),
.silent = TRUE
)
Expand Down Expand Up @@ -221,20 +237,29 @@ test_that("Can recover known distributional parameters from a SF joint model", {

dat <- summary_post(
as.CmdStanMCMC(mp),
c("lm_sf_mu_bsld", "lm_sf_mu_ks", "lm_sf_mu_kg"),
TRUE
c("lm_sf_mu_bsld", "lm_sf_mu_ks", "lm_sf_mu_kg")
)
true_values <- c(60, 0.2, 0.25, 0.15, 0.2)
true_values <- c(pars$mu_b, pars$mu_s, pars$mu_g)
expect_true(all(dat$q01 <= true_values))
expect_true(all(dat$q99 >= true_values))
expect_true(all(dat$ess_bulk > 100))


dat <- summary_post(
as.CmdStanMCMC(mp),
c("link_dsld", "link_ttg", "sm_exp_lambda")
c("lm_sf_sigma", "lm_sf_omega_bsld", "lm_sf_omega_kg", "lm_sf_omega_ks")
)
true_values <- c(pars$sigma, pars$omega_b, pars$omega_g, pars$omega_s)
expect_true(all(dat$q01 <= true_values))
expect_true(all(dat$q99 >= true_values))
expect_true(all(dat$ess_bulk > 100))


true_values <- c(0.2, -0.2, 1)
dat <- summary_post(
as.CmdStanMCMC(mp),
c("link_dsld", "link_ttg", "sm_exp_lambda", "beta_os_cov")
)
true_values <- c(pars$link_dsld, pars$link_ttg, pars$lambda, pars$beta_cat_B, pars$beta_cat_C, pars$beta_cont)
expect_true(all(dat$q01 <= true_values))
expect_true(all(dat$q99 >= true_values))
expect_true(all(dat$ess_bulk > 100))
Expand Down
18 changes: 9 additions & 9 deletions vignettes/statistical-specification.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ SLD_{ij} &=
b_i[e^{-s_it_{ij}} + e^{g_i t_{ij}} - 1] & \text{if } t_{ij}\geq 0 \\
b_i e^{g_i t_{ij}} & \text{if } t_{ij}\lt 0
\end{cases}\\\\
b_i &\sim \text{LogNormal}(\mu_{bl(i)}, \omega_b) \\
s_i &\sim \text{LogNormal}(\mu_{sk(i)}, \omega_s) \\
g_i &\sim \text{LogNormal}(\mu_{gk(i)}, \omega_g) \\
b_i &\sim \text{LogNormal}(\mu_{bl(i)}, \omega_{b l(i)}) \\
s_i &\sim \text{LogNormal}(\mu_{sk(i)}, \omega_{s k(i)}) \\
g_i &\sim \text{LogNormal}(\mu_{gk(i)}, \omega_{g k(i)}) \\
\end{align*}
$$

Expand All @@ -162,19 +162,19 @@ Where:
* $k(i)$ is the treatment arm index for subject $i$
* $l(i)$ is the study index for subject $i$
* $\mu_{\theta k(i)}$ is the population mean for parameter $\theta$ in group $k(i)$
* $\omega_{\theta}$ is the population variance for parameter $\theta$.
* $\omega_{\theta k(i)}$ is the population variance for parameter $\theta$.


If using the non-centred parameterisation then the following alternative formulation is used:
$$
\begin{align*}
b_i &= exp(\mu_{bl(i)} + \omega_b * \eta_{b i}) \\
s_i &= exp(\mu_{sk(i)} + \omega_s * \eta_{s i}) \\
g_i &= exp(\mu_{gk(i)} + \omega_g * \eta_{g i}) \\
b_i &= exp(\mu_{bl(i)} + \omega_{b l(i)} * \eta_{b i}) \\
s_i &= exp(\mu_{sk(i)} + \omega_{s k(i)} * \eta_{s i}) \\
g_i &= exp(\mu_{gk(i)} + \omega_{g k(i)} * \eta_{g i}) \\
\\
\eta_{b i} &\sim N(0, 1)\\
\eta_{s i} &\sim N(0, 1) \\
\eta_{g i} &\sim N(0, 1) \\
\eta_{s i} &\sim N(0, 1) \\
\eta_{g i} &\sim N(0, 1) \\
\end{align*}
$$

Expand Down

0 comments on commit 187ac27

Please sign in to comment.