Skip to content

481: Add TGI covariate models - #489

Open
danielinteractive wants to merge 12 commits into
mainfrom
tgi-covs-devel
Open

danielinteractive wants to merge 12 commits into
mainfrom
tgi-covs-devel

Conversation

@danielinteractive

Copy link
Copy Markdown
Collaborator

closes #481

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It introduces new Bayesian Stan statistical models whose correctness rests on parameter-recovery tests gated behind a full-test flag plus semantic changes to shared generated-quantities threading, which warrant human statistical review.

Pull request overview

This PR implements the covariate formulation of the four TGI longitudinal models (LongitudinalRandomSlopeCov, LongitudinalSteinFojoCov, LongitudinalGSFCov, LongitudinalClaretBrunoCov), closing #481. Instead of one set of parameters per treatment arm/study, model parameters are now driven by subject-level baseline covariates through design-matrix predictors (linear / proportional / exponential / log-linear). The diffs shown here are the documentation and test portions of that work: statistical specification math, a quickstart example, custom-model extension guidance with runnable Stan snippets, and supporting test/tolerance updates.

Changes:

  • Document the covariate versions of the random-slope, Stein-Fojo, GSF, and Claret-Bruno models in the statistical specification, and add a covariate walkthrough to the quickstart and extending vignettes (with new custom-cov-model*.stan snippets).
  • Add parameter-recovery / behavior tests for the new simulation classes and adjust two existing test expectations (test-SurvivalExponential.R upper bound, test-simulate.R event-rate tolerance).
  • Clean up stale "work-in-progress" banners and a phi-related population-quantities note.
File summaries
File Description
vignettes/statistical-specification.qmd Adds "Covariate Version" sections and predictor math; corrects exp/logit notation and phi cleanup
vignettes/quickstart.qmd Adds a runnable covariate longitudinal-model example and covariate overview
vignettes/extending-jmpost.qmd Documents covariate-aware custom-model interfaces and links to the new custom-cov vignette
vignettes/custom-cov-model.stan New illustrative model with baseline/growth covariate design matrices
vignettes/custom-cov-model-gq.stan New lm_predict_value wrapper for the custom model
vignettes/custom-cov-model-gq-population.stan New population generated-quantities using gq design matrices
vignettes/custom-cov-model-gq-individual.stan New per-subject generated-quantities matrix
vignettes/custom-cov-model-enable-link.stan New link-input matrix for the custom model
vignettes/custom-cov-model-dsld.stan New dSLD link contribution (derivative verified correct)
tests/testthat/test-SurvivalExponential.R Updates regex to expect the new upper=8000 lambda bound
tests/testthat/test-simulate.R Loosens the lambda_censor event-rate expectation
tests/testthat/test-SimLongitudinalRandomSlopeCov.R New tests for the covariate random-slope simulator
Review details
  • Files reviewed: 106/107 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

badge

Code Coverage Summary

Filename                             Stmts    Miss  Cover    Missing
---------------------------------  -------  ------  -------  ------------------------------------------------------------
R/brier_score.R                        173       1  99.42%   278
R/DataJoint.R                           89       0  100.00%
R/DataLongitudinal.R                   126       1  99.21%   258
R/DataSubject.R                         85       1  98.82%   150
R/DataSurvival.R                       106       0  100.00%
R/defaults.R                            13       9  30.77%   22-71, 98
R/generics.R                            46       5  89.13%   64, 563, 589, 667, 737
R/Grid.R                                27       1  96.30%   215
R/GridEven.R                            36       0  100.00%
R/GridEvent.R                           22       0  100.00%
R/GridFixed.R                           30       0  100.00%
R/GridGrouped.R                         54       0  100.00%
R/GridManual.R                          23       3  86.96%   81-83
R/GridObserved.R                        24       0  100.00%
R/GridPopulation.R                      90       6  93.33%   53, 147, 155-158
R/GridPrediction.R                      37       6  83.78%   87, 95-99
R/JointModel.R                         132      10  92.42%   159-165, 215, 219, 266, 339
R/JointModelSamples.R                  110       0  100.00%
R/link_generics.R                       39      16  58.97%   82-85, 112-115, 138-141, 168-171
R/Link.R                                66       4  93.94%   210-213
R/LinkComponent.R                       24       3  87.50%   101, 134-135
R/LongitudinalClaretBruno.R            123       6  95.12%   234-238, 259
R/LongitudinalClaretBrunoCov.R         283      48  83.04%   314-330, 361-389, 446-467
R/LongitudinalGSF.R                    138       0  100.00%
R/LongitudinalGSFCov.R                 300      53  82.33%   332-348, 373-413, 466-484
R/LongitudinalModel.R                   31       2  93.55%   93, 95
R/LongitudinalQuantities.R              82       0  100.00%
R/LongitudinalRandomEffects.R           65      17  73.85%   90-115
R/LongitudinalRandomSlope.R             62       6  90.32%   154-158, 171
R/LongitudinalRandomSlopeCov.R         370      20  94.59%   121, 167-173, 228, 231, 574-593
R/LongitudinalSteinFojo.R              117      10  91.45%   219-223, 266-270
R/LongitudinalSteinFojoCov.R           278      45  83.81%   330-342, 379-425, 497-508
R/Parameter.R                           67       0  100.00%
R/ParameterList.R                       62       1  98.39%   227
R/populationHR.R                        63       0  100.00%
R/Prior.R                              518       6  98.84%   437, 469, 1072, 1253-1258
R/Promise.R                             29       0  100.00%
R/Quantities.R                          61       0  100.00%
R/QuantityGeneratorPopulation.R         38       1  97.37%   85
R/QuantityGeneratorPrediction.R         48       0  100.00%
R/QuantityGeneratorSubject.R            21       0  100.00%
R/settings.R                            15      15  0.00%    61-80
R/SimGroup.R                             5       0  100.00%
R/SimJointData.R                       180      10  94.44%   147, 321-329
R/SimLongitudinal.R                      5       2  60.00%   27, 46
R/SimLongitudinalClaretBruno.R         107       0  100.00%
R/SimLongitudinalClaretBrunoCov.R      134       1  99.25%   259
R/SimLongitudinalGSF.R                 107       0  100.00%
R/SimLongitudinalGSFCov.R              140       1  99.29%   267
R/SimLongitudinalRandomSlope.R          55       0  100.00%
R/SimLongitudinalRandomSlopeCov.R      133       1  99.25%   250
R/SimLongitudinalSteinFojo.R            77       0  100.00%
R/SimLongitudinalSteinFojoCov.R         96       1  98.96%   207
R/SimSurvival.R                        165       0  100.00%
R/simulate.R                           499     167  66.53%   49-141, 177-186, 231-244, 295-311, 360-375, 429-484, 723-726
R/StanModel.R                           16       0  100.00%
R/StanModule.R                         186       6  96.77%   217-218, 266, 277, 430, 458
R/SurvivalExponential.R                 19       0  100.00%
R/SurvivalGamma.R                       17       0  100.00%
R/SurvivalLoglogistic.R                 17       0  100.00%
R/SurvivalModel.R                       20       0  100.00%
R/SurvivalQuantities.R                 172       1  99.42%   136
R/SurvivalWeibullPH.R                   25       0  100.00%
R/utilities.R                          149       2  98.66%   15, 353
R/zzz.R                                 31      28  9.68%    3-7, 9-32, 39-48
TOTAL                                 6478     516  92.03%

Diff against main

Filename                             Stmts    Miss  Cover
---------------------------------  -------  ------  --------
R/DataJoint.R                          +11       0  +100.00%
R/generics.R                            +6       0  +1.63%
R/GridPopulation.R                     +53      +2  +4.14%
R/JointModelSamples.R                  +14       0  +100.00%
R/LongitudinalClaretBrunoCov.R        +283     +48  +83.04%
R/LongitudinalGSFCov.R                +300     +53  +82.33%
R/LongitudinalModel.R                   +2       0  +0.44%
R/LongitudinalQuantities.R              +8       0  +100.00%
R/LongitudinalRandomSlopeCov.R        +370     +20  +94.59%
R/LongitudinalSteinFojoCov.R          +278     +45  +83.81%
R/QuantityGeneratorPopulation.R        +15      +1  -2.63%
R/SimLongitudinalClaretBrunoCov.R     +134      +1  +99.25%
R/SimLongitudinalGSFCov.R             +140      +1  +99.29%
R/SimLongitudinalRandomSlopeCov.R     +133      +1  +99.25%
R/SimLongitudinalSteinFojoCov.R        +96      +1  +98.96%
R/simulate.R                          +135    -197  +66.53%
R/SurvivalExponential.R                 +4       0  +100.00%
TOTAL                                +1982     -24  +4.05%

Results for commit: a941ab8

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Unit Tests Summary

    1 files    255 suites   11m 46s ⏱️
  233 tests   212 ✅ 21 💤 0 ❌
1 454 runs  1 431 ✅ 23 💤 0 ❌

Results for commit a941ab8.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Unit Test Performance Difference

Test Suite $Status$ Time on main $±Time$ $±Tests$ $±Skipped$ $±Failures$ $±Errors$
LongitudinalClaretBrunoCov 👶 $+0.00$ $+1$ $+1$ $0$ $0$
LongitudinalGSFCov 👶 $+0.00$ $+1$ $+1$ $0$ $0$
LongitudinalRandomEffects 💚 $100.51$ $-52.33$ $0$ $0$ $0$ $0$
LongitudinalRandomSlopeCov 👶 $+0.00$ $+1$ $+1$ $0$ $0$
LongitudinalSteinFojoCov 👶 $+0.00$ $+1$ $+1$ $0$ $0$
SimLongitudinalRandomSlopeCov 👶 $+0.00$ $+4$ $0$ $0$ $0$
compile 💚 $10.11$ $-2.83$ $0$ $0$ $0$ $0$
extract_quantities 💚 $11.50$ $-11.37$ $0$ $0$ $0$ $0$
model_multi_chain 💔 $37.74$ $+3.04$ $0$ $0$ $0$ $0$
Additional test case details
Test Suite $Status$ Time on main $±Time$ Test Case
Grid 💚 $80.01$ $-46.51$ Grid_objects_work_with_QuantityGenerator_and_QuantityCollapser
GridPrediction 💔 $110.85$ $+22.01$ GridPrediction_works_as_expected_for_Survival_models
JointModelSamples 💔 $11.17$ $+25.94$ print_works_as_expected_for_JointModelSamples
LongitudinalClaretBruno 💚 $1881.32$ $-1873.50$ LongitudinalClaretBruno_works_as_expected_with_default_arguments
LongitudinalClaretBrunoCov 👶 $+0.00$ Claret_Bruno_covariate_model_generates_correctly_named_initial_values
LongitudinalClaretBrunoCov 👶 $+0.00$ Claret_Bruno_covariate_model_recovers_its_parameters
LongitudinalClaretBrunoCov 👶 $+0.01$ Claret_Bruno_covariate_model_supports_links_and_simulation
LongitudinalClaretBrunoCov 👶 $+3.66$ LongitudinalClaretBrunoCov_constructs_and_renders
LongitudinalClaretBrunoCov 👶 $+0.00$ posterior_Claret_Bruno_covariate_draws_create_a_simulator
LongitudinalGSF 👶 $+0.00$ LongitudinalGSF_keeps_phi_within_its_positive_epsilon_bounds
LongitudinalGSF 💚 $2010.82$ $-2001.74$ LongitudinalGSF_works_as_expected_with_default_arguments
LongitudinalGSFCov 👶 $+0.00$ GSF_covariate_model_generates_correctly_named_initial_values
LongitudinalGSFCov 👶 $+0.00$ GSF_covariate_model_recovers_its_parameters
LongitudinalGSFCov 👶 $+7.00$ LongitudinalGSFCov_constructs_all_covariate_predictors
LongitudinalGSFCov 👶 $+0.00$ LongitudinalGSFCov_keeps_phi_within_its_positive_epsilon_bounds
LongitudinalGSFCov 👶 $+0.01$ LongitudinalGSFCov_supports_links_quantities_and_simulation
LongitudinalGSFCov 👶 $+0.00$ centred_GSF_covariate_phi_uses_the_logit_scale_location_directly
LongitudinalGSFCov 👶 $+0.00$ posterior_GSF_covariate_draws_create_a_matching_simulator
LongitudinalQuantiles 💚 $46.44$ $-21.71$ Test_that_LongitudinalQuantities_works_as_expected
LongitudinalRandomEffects 💚 $100.51$ $-52.33$ LongitudinalRandomEffects_works_as_expected
LongitudinalRandomSlope 💚 $82.96$ $-74.57$ Print_method_for_LongitudinalRandomSlope_works_as_expected
LongitudinalRandomSlopeCov 👶 $+0.00$ LongitudinalRandomEffects_extracts_covariate_random_slopes
LongitudinalRandomSlopeCov 👶 $+7.01$ LongitudinalRandomSlopeCov_constructs_its_parameters_and_Stan_code
LongitudinalRandomSlopeCov 👶 $+0.00$ LongitudinalRandomSlopeCov_validates_formulas_and_parametrizations
LongitudinalRandomSlopeCov 👶 $+0.00$ covariate_formula_helpers_cover_validation_and_edge_cases
LongitudinalRandomSlopeCov 👶 $+0.01$ covariate_predictor_helpers_implement_all_parametrizations
LongitudinalRandomSlopeCov 👶 $+0.00$ covariate_random_slope_model_exposes_downstream_parameter_names
LongitudinalRandomSlopeCov 👶 $+0.00$ covariate_random_slope_quantity_models_pass_the_parser
LongitudinalRandomSlopeCov 👶 $+0.00$ generated_quantities_rebuild_model_aware_Stan_data
LongitudinalRandomSlopeCov 👶 $+0.00$ gq_population_stan_data_dispatches_to_user_longitudinal_models
LongitudinalRandomSlopeCov 👶 $+0.00$ model_aware_as_stan_list_creates_subject_covariate_designs
LongitudinalRandomSlopeCov 👶 $+0.00$ model_aware_as_stan_list_handles_one_level_factors
LongitudinalRandomSlopeCov 👶 $+0.00$ old_and_covariate_model_parametrizations_are_consistent
LongitudinalRandomSlopeCov 👶 $+0.00$ population_quantities_accept_all_predictor_covariates_in_newdata
LongitudinalRandomSlopeCov 👶 $+0.00$ population_quantities_infer_study_arm_profiles_when_sufficient
LongitudinalRandomSlopeCov 👶 $+0.00$ population_quantities_require_newdata_for_additional_covariates
LongitudinalRandomSlopeCov 👶 $+0.00$ posterior_random_slope_covariate_draws_create_a_matching_simulator
LongitudinalRandomSlopeCov 👶 $+0.00$ posterior_simulation_preserves_longitudinal_covariates
LongitudinalRandomSlopeCov 👶 $+0.00$ random_slope_covariate_model_recovers_its_parameters
LongitudinalRandomSlopeCov 👶 $+0.00$ required_longitudinal_covs_returns_population_predictor_covariates
LongitudinalRandomSlopeCov 👶 $+0.00$ required_simulation_covariates_includes_variability_predictors
LongitudinalSteinFojo 💚 $2007.76$ $-2007.01$ LongitudinalSteinFojo_works_as_expected_with_default_arguments
LongitudinalSteinFojoCov 👶 $+1.42$ LongitudinalSteinFojoCov_constructs_predictors_and_model_data
LongitudinalSteinFojoCov 👶 $+0.00$ SimLongitudinalSteinFojoCov_uses_covariate_predictors
LongitudinalSteinFojoCov 👶 $+0.00$ Stein_Fojo_covariate_model_recovers_its_parameters
LongitudinalSteinFojoCov 👶 $+0.01$ covariate_Stein_Fojo_effects_can_be_centred_independently
LongitudinalSteinFojoCov 👶 $+0.00$ covariate_Stein_Fojo_reduces_to_the_original_formulation
LongitudinalSteinFojoCov 👶 $+0.00$ covariate_Stein_Fojo_supports_links_and_generated_quantities
LongitudinalSteinFojoCov 👶 $+0.00$ non_centred_Stein_Fojo_effects_are_floored_at_the_positive_epsilon
LongitudinalSteinFojoCov 👶 $+0.00$ posterior_Stein_Fojo_covariate_draws_create_a_matching_simulator
SimLongitudinalRandomSlopeCov 👶 $+0.15$ SimLongitudinalRandomSlopeCov_uses_its_covariate_predictors
SimLongitudinalRandomSlopeCov 👶 $+0.00$ SimLongitudinalRandomSlopeCov_works_in_SimJointData
SimLongitudinalRandomSlopeCov 👶 $+0.00$ old_and_covariate_random_slope_simulators_are_exactly_consistent
SimLongitudinalRandomSlopeCov 👶 $+0.00$ simulation_coefficient_helpers_normalise_supported_inputs
SurvivalExponential 💚 $74.25$ $-73.51$ Can_load_and_compile_SurvivalExponential_model
SurvivalGamma 💚 $197.49$ $-195.88$ Print_method_for_SurvivalGamma_works_as_expected
SurvivalLoglogistic 💚 $35.46$ $-34.51$ Can_load_and_compile_SurvivalLogLogistic_model
SurvivalQuantities 💚 $92.37$ $-31.15$ SurvivalQuantities_and_autoplot.SurvivalQuantities_works_as_expected
SurvivalWeibullPH 💚 $15.39$ $-13.78$ Print_method_for_SurvivalWeibullPH_works_as_expected
brierScore 💚 $61.81$ $-56.17$ brierScore_SurvivalQuantities_returns_same_results_as_survreg
brms_compare 💚 $657.59$ $-657.48$ jmpost_and_brms_get_similar_loo_for_longitudinal_models
compile 💚 $10.11$ $-2.83$ compileStanModel_doesn_t_error_if_the_directory_doesn_t_exist
extract_quantities 💚 $11.50$ $-11.37$ extract_quantities_works_as_expected
initialValues 💚 $3.13$ $-1.04$ initialValues_works_as_expected
misc_models 💚 $410.44$ $-245.05$ Longitudinal_Model_doesn_t_print_sampler_rejection_messages
model_multi_chain 💔 $37.74$ $+3.04$ Can_recover_known_distribution_parameters_from_random_slope_model_when_using_multiple_chains
populationHR 💔 $16.90$ $+3.10$ populationHR_works_as_expected_for_default_parameters
simulate 💚 $416.97$ $-416.91$ simulate_works_with_default_options
stan_functions 💔 $36.50$ $+13.97$ GSF_SLD_function_works_as_expected

Results for commit c8622ce

♻️ This comment has been updated with latest results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TGI covariate models

2 participants