From e99ef80b917b54e92b2643e52b8cbc08de64b4d0 Mon Sep 17 00:00:00 2001 From: Dominic Muston Date: Sat, 10 Jan 2026 18:19:44 -0500 Subject: [PATCH 1/4] After CRAN submission --- CRAN-SUBMISSION | 6 +++--- cran-comments.md | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION index 1ace11f..ebb163d 100644 --- a/CRAN-SUBMISSION +++ b/CRAN-SUBMISSION @@ -1,3 +1,3 @@ -Version: 0.4.0 -Date: 2026-01-07 00:45:35 UTC -SHA: 986f44179c3fb67d474c9a965f5643004c47e70c +Version: 0.4.1 +Date: 2026-01-10 23:19:31 UTC +SHA: ed329f5dac07bdbb36b0093216bc30c4d0a57514 diff --git a/cran-comments.md b/cran-comments.md index 858617d..ec0dc23 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,3 +1,9 @@ +## Resubmission +This is a resubmission. In this version I have: + +* Extended the description text in DESCRIPTION +* Revised the vignettes + ## R CMD check results 0 errors | 0 warnings | 1 note From 046def436c037d1ad77a4ec0feed8313a68041b9 Mon Sep 17 00:00:00 2001 From: Dominic Muston Date: Sat, 24 Jan 2026 14:14:26 -0500 Subject: [PATCH 2/4] Update to development version --- DESCRIPTION | 2 +- NEWS.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index fe302ac..94a4581 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: dynamicpv Title: Evaluates Present Values and Health Economic Models with Dynamic Pricing and Uptake -Version: 0.4.1 +Version: 0.4.1.9000 Authors@R: c( person("Dominic", "Muston", , "dominic.muston@msd.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-4876-7940")), diff --git a/NEWS.md b/NEWS.md index 4f5e516..229df24 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,5 @@ +# dynamicpv (development version) + # dynamicpv 0.4.1 * Revised vignettes From f5737146f5a155e35df042f70420ff505f75a26c Mon Sep 17 00:00:00 2001 From: Dominic Muston Date: Sat, 24 Jan 2026 14:19:53 -0500 Subject: [PATCH 3/4] Minor readme/news update --- NEWS.md | 2 ++ README.Rmd | 11 ++--------- README.md | 18 ++++++------------ 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/NEWS.md b/NEWS.md index 229df24..fea47a3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # dynamicpv (development version) +* So far, only minor changes to the readme page + # dynamicpv 0.4.1 * Revised vignettes diff --git a/README.Rmd b/README.Rmd index 6732125..3362996 100644 --- a/README.Rmd +++ b/README.Rmd @@ -29,7 +29,7 @@ Through the [dynpv()](https://msdllcpapers.github.io/dynamicpv/reference/dynpv.h ## Installation -The package should shortly be available on [CRAN](https://cran.r-project.org/web/packages/index.html). Installing from here is simplest, once available. +The package is now available on [CRAN](https://cran.r-project.org/web/packages/index.html). Installing from here is simplest, as follows. ```{r inst_cran} #| eval: false @@ -48,14 +48,7 @@ install.packages("devtools") pak::pak("MSDLLCpapers/dynamicpv") ``` -Note that the above does not install vignettes. Vignettes may be viewed on the [package website](https://msdllcpapers.github.io/dynamicpv/) or by instead running the following. - -```{r instal2} -#| eval: false -devtools::install_github("MSDLLCpapers/dynamicpv", build_vignettes=TRUE) -``` - -You should then load the package, alongside some other packages used here. +Installing the development version in this way does not include vignettes. Vignettes may be viewed on the [package website](https://msdllcpapers.github.io/dynamicpv/). You can then load the package, alongside other packages you may find helpful. ```{r instal3} #| eval: false diff --git a/README.md b/README.md index c019151..5770010 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,9 @@ cost-effectiveness model, such as one computed using the ## Installation -The package should shortly be available on +The package is now available on [CRAN](https://cran.r-project.org/web/packages/index.html). Installing -from here is simplest, once available. +from here is simplest, as follows. ``` r # CRAN installation - when available @@ -56,16 +56,10 @@ install.packages("devtools") pak::pak("MSDLLCpapers/dynamicpv") ``` -Note that the above does not install vignettes. Vignettes may be viewed -on the [package website](https://msdllcpapers.github.io/dynamicpv/) or -by instead running the following. - -``` r -devtools::install_github("MSDLLCpapers/dynamicpv", build_vignettes=TRUE) -``` - -You should then load the package, alongside some other packages used -here. +Installing the development version in this way does not include +vignettes. Vignettes may be viewed on the [package +website](https://msdllcpapers.github.io/dynamicpv/). You can then load +the package, alongside other packages you may find helpful. ``` r # Load the dynamicpv package From 9ab72a383b73164aff5eb8d2e191aa2a65950757 Mon Sep 17 00:00:00 2001 From: Dominic Muston Date: Sat, 24 Jan 2026 16:12:00 -0500 Subject: [PATCH 4/4] Functionality for continuous inputs --- R/dynamic.R | 66 ++++++++++++++++++++++++++++++++-- tests/testthat/test-fullycts.R | 15 ++++++++ tests/testthat/test-semicts.R | 19 ++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 tests/testthat/test-fullycts.R create mode 100644 tests/testthat/test-semicts.R diff --git a/R/dynamic.R b/R/dynamic.R index 95184bd..fd9a6dc 100644 --- a/R/dynamic.R +++ b/R/dynamic.R @@ -98,11 +98,34 @@ dynpv <- function( uptakes = 1, payoffs, - horizon = length(payoffs), + horizon = NA, tzero = 0, - prices = rep(1, length(payoffs)+tzero), + prices = NA, discrate = 0 ){ + # If payoffs are discrete + if (class(payoffs)=="numeric") { + # Horizon defaults to length of payoffs + if (class(horizon)=="logical") {horizon <- length(payoffs)} + # Price index defaults to (1, ..., 1) + if (class(prices)=="logical") {prices <- rep(1, length(payoffs)+tzero)} + # Call calculation + dpv <- dynpv_discrete(uptakes, payoffs, horizon, tzero, prices, discrate) + } + # If payoffs are not discrete and uptake is discrete + if ((class(uptakes)=="numeric") & (class(payoffs)=="function")) { + dpv <- dynpv_semicts(uptakes, payoffs, horizon, tzero, prices, discrate) + } + # If payoffs and uptake are not discrete + if ((class(uptakes)=="function") & (class(payoffs)=="function")) { + dpv <- dynpv_fullycts(uptakes, payoffs, horizon, tzero, prices, discrate) + } + # Return + return(dpv) +} + +# Discrete function +dynpv_discrete <- function(uptakes, payoffs, horizon, tzero, prices, discrate){ # Avoid no visible binding note j <- k <- l <- uj <- pk <- R <- v <- NULL # Trim @@ -137,3 +160,42 @@ trim_vec <- function(vec){ # Return trimmed vector return(vec[1:trimto]) } + +# Function if payoffs, prices and discounting are functions; but uptakes is a vector +dynpv_semicts <- function(uptakes, payoffs, horizon, tzero, prices, discrate){ + # Avoid no visible binding note + j <- uj <- pRv <- pv <- NULL + # Trim + uptakes <- trim_vec(uptakes) + # Integrand function + integrand <- function(k, j) { + payoffs(k) * prices(j+k+tzero) * discrate(j+k) + } + # Create a dataset for each combination of time + df <- expand_grid(j=1:length(uptakes)) |> + dplyr::mutate( + uj = uptakes[j], + pRv = stats::integrate(integrand, lower=0, upper=horizon-j, j=j)$value, + pv = uj * pRv + ) + class(df) <- c("dynpv", class(df)) + return(df) +} + +# Function if uptakes, payoffs, prices and discounting are functions +dynpv_fullycts <- function(uptakes, payoffs, horizon, tzero, prices, discrate){ + # First integrand function - pRv, to be integrated between k=0 and k=T-j + integrand1 <- function(k, j) { + payoffs(k) * prices(j+k+tzero) * discrate(j+k) + } + # Second integrand function, uj I, to be integrated between j=0 and j=T + integrand2 <- function(j) { + pRv <- stats::integrate(integrand1, lower=0, upper=horizon-j, j=j)$value + uptakes(j) * pRv + } + # Needs to be vectorized before integrating + integrand2 <- Vectorize(integrand2, "j") + # Calculate double integral + df <- stats::integrate(integrand2, lower=0, upper=horizon) + return(df$value) +} \ No newline at end of file diff --git a/tests/testthat/test-fullycts.R b/tests/testthat/test-fullycts.R new file mode 100644 index 0000000..5a67003 --- /dev/null +++ b/tests/testthat/test-fullycts.R @@ -0,0 +1,15 @@ +# Test new fullycts calculations + +# Example +payoffs <- function(t) {100+50*t} +prices <- function(t) {1.03 ^ (floor(t))} +discrate <- function(t) {0.97 ^ t} +uptakes <- function(t) {exp(-t/2)} + +# 1. Full function calls intermediate function ok +test_that("Full function calls intermediate function ok", { + int <- dynpv_fullycts(uptakes=uptakes, payoffs=payoffs, horizon=5, tzero=0, prices=prices, discrate=discrate) + full <- dynpv(uptakes=uptakes, payoffs=payoffs, horizon=5, prices=prices, discrate=discrate) + expect_equal(int, full) + } +) \ No newline at end of file diff --git a/tests/testthat/test-semicts.R b/tests/testthat/test-semicts.R new file mode 100644 index 0000000..87504d9 --- /dev/null +++ b/tests/testthat/test-semicts.R @@ -0,0 +1,19 @@ +# Test new semicts calculations + +# Example +payoffs <- function(t) {100+50*t} +prices <- function(t) {1.03 ^ (floor(t))} +discrate <- function(t) {0.97 ^ t} + +# 1. Full function calls intermediate function ok +test_that("Full function calls intermediate function ok", { + int <- dynpv_semicts(uptakes=1, payoffs=payoffs, horizon=5, tzero=0, prices=prices, discrate=discrate) + full <- dynpv(payoffs=payoffs, horizon=5, prices=prices, discrate=discrate) + expect_equal(int, full) + } +) + + + + +