fix: multi-line and conditional sec blocks in analytical models#302
fix: multi-line and conditional sec blocks in analytical models#302
Conversation
Thanks to Hector Julian Perez Madrid for finding this bug.
There was a problem hiding this comment.
Pull request overview
This PR fixes a failure in analytical (template-based) model handling where deparse() could return a multi-element character vector for multi-line expressions, which then broke purrr::map_chr()/template-detection logic (e.g., “Result must be length 1”).
Changes:
- Collapse multi-line
deparse()output into a single string when scanning EQN statements intranspile_analytic_eqn(). - Apply the same
deparse()collapsing approach inget_found_model()to make template detection robust to multi-line expressions. - Add a regression test covering an analytical model with a multi-line
secblock containing anifconditional. - (Unrelated) Large-scale formatting changes in
PMutilities.R.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
R/model_transpiler.R |
Collapses deparse() output during analytic EQN parsing to prevent map_chr() length errors. |
R/mod_lib.R |
Collapses deparse() output during template detection; switches to map_lgl() for clearer boolean results. |
tests/testthat/test-Examples.R |
Adds regression test for a multi-line sec block with conditionals in an analytical model. |
R/PMutilities.R |
Contains extensive formatting-only changes unrelated to the stated PR purpose. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| eqn = function() { | ||
| two_comp_bolus | ||
| }, | ||
| lag = function() { |
There was a problem hiding this comment.
The new regression test doesn’t currently exercise the code paths changed in get_found_model()/transpile_analytic_eqn() (i.e., deparse() returning a multi-element character vector for a multi-line expression inside the EQN/template-detection scan). As written, the EQN block only contains a single symbol, so the pre-fix code would likely not fail here. Consider adjusting/adding a case where the EQN block contains an if-block or another multi-line statement alongside the template name, so the test would fail without this PR and pass with it.
| expect_s3_class(mod, "PM_model") | ||
| sec_code <- paste(deparse(mod$arg_list$sec), collapse = "\n") | ||
| expect_true(grepl("if (gender < 1)", sec_code, fixed = TRUE)) | ||
| expect_true(grepl("v = v0 * wt", sec_code, fixed = TRUE)) | ||
| }) |
There was a problem hiding this comment.
Since the bug is specific to analytical/template-based models, it would be good for this test to assert that the model was detected as Analytical (e.g., via mod$model_list$type) before checking sec contents. Otherwise, a future change that accidentally routes this model through the ODE path could let the test pass while no longer covering the intended behavior.
| dmv_norm <- function( | ||
| x, mean = rep(0, p), sigma = diag(p), log = FALSE, | ||
| checkSymmetry = TRUE) { |
There was a problem hiding this comment.
This PR includes a very large reformatting-only change set in PMutilities.R that isn’t mentioned in the PR description and appears unrelated to the analytical SEC/EQN deparse fix. This makes the review noisy and increases merge-conflict risk; consider reverting these formatting changes or splitting them into a separate PR focused on styling/formatting.
|
Apparently the CI is breaking because of |
| blocks <- parseBlocks(model) | ||
|
|
||
| # check for reserved variable names | ||
| reserved <- c( |
There was a problem hiding this comment.
We can probably revise this list, many of these are no longer really reserved.
There was a problem hiding this comment.
But that doesn't have to be in this PR.
Running cargo update to get the latest version of spindle
Summary
Fix
secblock failing with"Result must be length 1"when it contains multiple statements orif-conditionals in analytical (template-based) models.Example that was failing
This also failed with multiple assignments (no conditionals):
Root cause
deparse()on multi-line R expressions (e.g.if-blocks) returns a character vector longer than 1, which brokemap_chr()calls that assumed single-element output in the transpiler and template detection code.Changes
model_transpiler.R: collapsedeparse()output intranspile_analytic_eqn()mod_lib.R: same fix inget_found_model()for template detectiontest-Examples.R: regression test for multi-line sec with conditionalsThanks to Hector Julian Perez Madrid for finding this bug.