[DISCUSSION] Refactor string interpolation
While I still like the overall approach of our string interpolation by classes (Outcome, Borrowing, Treatment, Covariate), I think Outcome and Borrowing are much more related than we had anticipated at the outset, and that has led to a lot of undesirable control flow / multiple dispatch to consider all the different combinations:
In the end, there are only currently 2 borrowing types (full/none and commensurate prior) and 4 outcomes (2 TTE, logistic, continuous), which means we could easily write STAN templates for each of the 8 combinations. The remaining interpolation would then:
- set the priors (in model block)
- add covariates (impacts data block, parameter block, prior block)
- add weights (model block)
I think this should be easy to implement. For instance, can put templates in /R/templates.R or somewhere
stan_bdb_surv_exp <- "
data {
int<lower=0> N;
vector[N] trt;
vector[N] time;
vector[N] cens;
{{cov_data}};
{{weight_data}};
}
parameters {
real beta_trt;
real<lower=0> tau;
vector[2] alpha;
}
transformed parameters {
real HR_trt = exp(beta_trt);
}
model {
vector[N] lp;
vector[N] elp;
beta_trt ~ {{trt_prior}};
tau ~ {{tau_prior}};
lp = Z * alpha + trt * beta_trt {{add_covs_model}};
elp = exp(lp) ;
real sigma;
sigma = 1 / tau;
alpha[2] ~ {{baseline_prior}};
alpha[1] ~ normal(alpha[2], sqrt(sigma)) ;
for (i in 1:N) {
if (cens[i] == 1) {
target += exponential_lccdf(time[i] | elp[i] ) {{add_weights_model}};
} else {
target += exponential_lpdf(time[i] | elp[i] {{add_weights_model}});
}
}
}
Then in create_analysis_obj, the objects can all add their relevant bits (and while they do, add to the data to be put in). It is pretty straightforward this way and I suspect would be simpler to implement. We can have create_analysis_obj call a generic that dispatches based on Outcome and Borrowing. @gravesti at a high-level, do you see any downsides to this? I think it would cut out a lot of code. It might also be easier as we prepare to implement some outcomes that only go with some borrowing methods. I'm assumign that the case weighted power priors will have a borrowing type of power priors and an outcome type of pem_case_weights or something.
@mattsecrest I agree with this proposal. Should make our lives a bit easier. Maybe we can look at what jmpost is doing with their templates. The models are much more complicated, but maybe there's some learnings
Yeah the appraoch is similar in jmpost, and I think the results are much cleaner!
https://github.com/Genentech/jmpost/blob/main/inst/stan/base/base.stan
Their interpolation is also quite easy to follow. Can borrow inspiration from that as well.
I'll try to do this by the end of the week enxt week. Maybe we can hold on other dev for now?
Sounsd good. I'll try to make progress on the other weighting method until then