From 4c8334796134d5bcd83fd64495448b73955e8dfb Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Fri, 21 Jul 2023 16:08:42 +0100 Subject: [PATCH 01/32] Improved the description of the mu parameter --- R/borel.r | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/borel.r b/R/borel.r index 7ce580ab..73b8b7a3 100644 --- a/R/borel.r +++ b/R/borel.r @@ -1,7 +1,7 @@ ##' Density of the Borel distribution ##' ##' @param x vector of integers. -##' @param mu mu parameter. +##' @param mu mu parameter (the Poisson mean). ##' @param log logical; if TRUE, probabilities p are given as log(p). ##' @return probability mass. ##' @author Sebastian Funk @@ -16,7 +16,7 @@ dborel <- function(x, mu, log = FALSE) { ##' ##' Random numbers are generated by simulating from a Poisson branching process ##' @param n number of random variates to generate. -##' @param mu mu parameter. +##' @param mu mu parameter (the Poisson mean). ##' @param infinite any number to treat as infinite; simulations will be stopped ##' if this number is reached ##' @return vector of random numbers From 5dfce95dffcbeb9bbc50a316481fa1ddfc47c3df Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Fri, 21 Jul 2023 16:09:00 +0100 Subject: [PATCH 02/32] Added input checking of the mu argument --- R/borel.r | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/R/borel.r b/R/borel.r index 73b8b7a3..cb56de54 100644 --- a/R/borel.r +++ b/R/borel.r @@ -7,6 +7,9 @@ ##' @author Sebastian Funk dborel <- function(x, mu, log = FALSE) { if (x < 1) stop("'x' must be greater than 0") + if (mu <= 0 || is.infinite(mu)) { + stop("'mu' must not be Inf or less than 0") + } ld <- -mu * x + (x - 1) * log(mu * x) - lgamma(x + 1) if (!log) ld <- exp(ld) return(ld) @@ -22,5 +25,8 @@ dborel <- function(x, mu, log = FALSE) { ##' @return vector of random numbers ##' @author Sebastian Funk rborel <- function(n, mu, infinite = Inf) { + if (mu <= 0 || is.infinite(mu)) { + stop("'mu' must not be Inf or less than 0") + } chain_sim(n, "pois", "size", infinite = infinite, lambda = mu) } From 1d75784036513a0023870e52bbba4581c79981ab Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Fri, 21 Jul 2023 16:35:47 +0100 Subject: [PATCH 03/32] Linting --- R/borel.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/borel.r b/R/borel.r index cb56de54..89621ab8 100644 --- a/R/borel.r +++ b/R/borel.r @@ -9,7 +9,7 @@ dborel <- function(x, mu, log = FALSE) { if (x < 1) stop("'x' must be greater than 0") if (mu <= 0 || is.infinite(mu)) { stop("'mu' must not be Inf or less than 0") - } + } ld <- -mu * x + (x - 1) * log(mu * x) - lgamma(x + 1) if (!log) ld <- exp(ld) return(ld) From e9e605601f8e07a577cdaceea04d40fa8c569de5 Mon Sep 17 00:00:00 2001 From: James Azam Date: Mon, 24 Jul 2023 18:43:46 +0100 Subject: [PATCH 04/32] Improved the error messages --- R/borel.r | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/borel.r b/R/borel.r index 89621ab8..2a9ab38e 100644 --- a/R/borel.r +++ b/R/borel.r @@ -8,7 +8,7 @@ dborel <- function(x, mu, log = FALSE) { if (x < 1) stop("'x' must be greater than 0") if (mu <= 0 || is.infinite(mu)) { - stop("'mu' must not be Inf or less than 0") + stop("'mu' must be greater 0 but less than Inf") } ld <- -mu * x + (x - 1) * log(mu * x) - lgamma(x + 1) if (!log) ld <- exp(ld) @@ -26,7 +26,7 @@ dborel <- function(x, mu, log = FALSE) { ##' @author Sebastian Funk rborel <- function(n, mu, infinite = Inf) { if (mu <= 0 || is.infinite(mu)) { - stop("'mu' must not be Inf or less than 0") + stop("'mu' must be greater 0 but less than Inf") } chain_sim(n, "pois", "size", infinite = infinite, lambda = mu) } From 526344f40fb2176b14e712fff8608289d058aa3d Mon Sep 17 00:00:00 2001 From: James Azam Date: Mon, 24 Jul 2023 18:44:04 +0100 Subject: [PATCH 05/32] Added tests for the borel functions --- tests/testthat/tests-borel.r | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/testthat/tests-borel.r b/tests/testthat/tests-borel.r index e17512e1..3aa56939 100644 --- a/tests/testthat/tests-borel.r +++ b/tests/testthat/tests-borel.r @@ -5,5 +5,19 @@ test_that("We can calculate probabilities and sample", { }) test_that("Errors are thrown", { - expect_error(dborel(0, 0.5), "greater than 0") + expect_error(dborel(x = 0, mu = 0.5), + "'x' must be greater than 0" + ) + expect_error(dborel(x = 1, mu = -0.5), + "'mu' must be greater 0 but less than Inf" + ) + expect_error(dborel(x = 1, mu = Inf), + "'mu' must be greater 0 but less than Inf" + ) + expect_error(rborel(n = 0, mu = -0.5), + "'mu' must be greater 0 but less than Inf" + ) + expect_error(rborel(n = 0, mu = Inf), + "'mu' must be greater 0 but less than Inf" + ) }) From 20a2616f1e57ef60687445c30faa89c95f0b6ba2 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 19:11:49 +0100 Subject: [PATCH 06/32] Added input checking to rnbinom_mean_disp() --- R/utils.r | 1 + 1 file changed, 1 insertion(+) diff --git a/R/utils.r b/R/utils.r index c4d135a5..e294ed32 100644 --- a/R/utils.r +++ b/R/utils.r @@ -51,6 +51,7 @@ rgen_length <- function(n, x, prob) { #' @examples #' rnbinom_mean_disp(n = 5, mn = 4, disp = 2) rnbinom_mean_disp <- function(n, mn, disp) { + if (disp < 1) stop("'disp' must be at least 1") size <- mn / (disp - 1) stats::rnbinom(n, size = size, mu = mn) } From 3818eb3b14c4e524009e43e37097d61e87b55b45 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 19:12:09 +0100 Subject: [PATCH 07/32] Added tests for the utils functions --- tests/testthat/test-utils.R | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/testthat/test-utils.R diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R new file mode 100644 index 00000000..82ee371d --- /dev/null +++ b/tests/testthat/test-utils.R @@ -0,0 +1,19 @@ +test_that("Util functions work", { + expect_length(rnbinom_mean_disp(n = 5, mn = 4, disp = 2), 5) + expect_length(rgen_length(n = 1, x = c(1, 2, 3), prob = 0.3), 3) + expect_length(rbinom_size(n = 1, x = c(1, 2, 3), prob = 0.3), 3) + expect_identical(complementary_logprob(x = 0), -Inf) + expect_identical(complementary_logprob(x = -Inf), 0) + expect_lt(complementary_logprob(x = -0.1), 0) +}) + +test_that("Errors are thrown", { + expect_error(rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), + "'disp' must be at least 1" + ) +}) + +test_that("Warnings are thrown", { + expect_warning(complementary_logprob(0.1), "NaNs produced") + expect_warning(complementary_logprob(Inf), "NaNs produced") +}) From 7fcbb543f749a8dfa5052dd3c9800e725dbdc51d Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 19:14:11 +0100 Subject: [PATCH 08/32] Regenerated the doc files for the the borel functions --- man/dborel.Rd | 2 +- man/rborel.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/dborel.Rd b/man/dborel.Rd index 14d269d0..bbd04672 100644 --- a/man/dborel.Rd +++ b/man/dborel.Rd @@ -9,7 +9,7 @@ dborel(x, mu, log = FALSE) \arguments{ \item{x}{vector of integers.} -\item{mu}{mu parameter.} +\item{mu}{mu parameter (the Poisson mean).} \item{log}{logical; if TRUE, probabilities p are given as log(p).} } diff --git a/man/rborel.Rd b/man/rborel.Rd index 5562f7e1..0303b4e0 100644 --- a/man/rborel.Rd +++ b/man/rborel.Rd @@ -9,7 +9,7 @@ rborel(n, mu, infinite = Inf) \arguments{ \item{n}{number of random variates to generate.} -\item{mu}{mu parameter.} +\item{mu}{mu parameter (the Poisson mean).} \item{infinite}{any number to treat as infinite; simulations will be stopped if this number is reached} From a05957eee513a16442b604029bd68fc180ae4eab Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 19:23:30 +0100 Subject: [PATCH 09/32] Linting --- tests/testthat/test-utils.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 82ee371d..199d29df 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -8,9 +8,10 @@ test_that("Util functions work", { }) test_that("Errors are thrown", { - expect_error(rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), - "'disp' must be at least 1" - ) + expect_error( + rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), + "'disp' must be at least 1" + ) }) test_that("Warnings are thrown", { From c426ae27c22036b8b85eaa9c90b19f0ea0fdc94d Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 19:31:13 +0100 Subject: [PATCH 10/32] Linting --- tests/testthat/test-utils.R | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 199d29df..60948079 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -8,10 +8,8 @@ test_that("Util functions work", { }) test_that("Errors are thrown", { - expect_error( - rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), - "'disp' must be at least 1" - ) + expect_error(rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), + "'disp' must be at least 1") }) test_that("Warnings are thrown", { From d665889f955ce2c10f1bdb7a6c7ff1eb4c0a8e33 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 22:27:40 +0100 Subject: [PATCH 11/32] Added a test for chain_sim() --- tests/testthat/tests-sim.r | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/testthat/tests-sim.r b/tests/testthat/tests-sim.r index bb053a43..8b134584 100644 --- a/tests/testthat/tests-sim.r +++ b/tests/testthat/tests-sim.r @@ -18,6 +18,17 @@ test_that("Chains can be simulated", { n = 2, offspring = "pois", "size", lambda = 0.9, tree = TRUE )) + + tf <- 3 + set.seed(12) + expect_true( + all(chain_sim( + n = 2, offspring = "pois", "size", lambda = 0.9, + tree = TRUE, serial = function(n) { + rlnorm(n, meanlog = 0.58, sdlog = 1.58) + }, tf = tf + )$time < tf) + ) }) test_that("Errors are thrown", { From b38b3e3ec8fa29fc4e2aadfed96b95c30de15f07 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 23:28:46 +0100 Subject: [PATCH 12/32] Linted all the test scripts --- tests/testthat/test-utils.R | 6 ++- tests/testthat/tests-borel.r | 31 ++++++++------ tests/testthat/tests-sim.r | 81 +++++++++++++++++++----------------- 3 files changed, 64 insertions(+), 54 deletions(-) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 60948079..199d29df 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -8,8 +8,10 @@ test_that("Util functions work", { }) test_that("Errors are thrown", { - expect_error(rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), - "'disp' must be at least 1") + expect_error( + rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), + "'disp' must be at least 1" + ) }) test_that("Warnings are thrown", { diff --git a/tests/testthat/tests-borel.r b/tests/testthat/tests-borel.r index 3aa56939..7ae10e4f 100644 --- a/tests/testthat/tests-borel.r +++ b/tests/testthat/tests-borel.r @@ -5,19 +5,24 @@ test_that("We can calculate probabilities and sample", { }) test_that("Errors are thrown", { - expect_error(dborel(x = 0, mu = 0.5), - "'x' must be greater than 0" - ) - expect_error(dborel(x = 1, mu = -0.5), - "'mu' must be greater 0 but less than Inf" - ) - expect_error(dborel(x = 1, mu = Inf), - "'mu' must be greater 0 but less than Inf" + expect_error( + dborel(x = 0, mu = 0.5), + "'x' must be greater than 0" ) - expect_error(rborel(n = 0, mu = -0.5), - "'mu' must be greater 0 but less than Inf" - ) - expect_error(rborel(n = 0, mu = Inf), - "'mu' must be greater 0 but less than Inf" + expect_error( + dborel(x = 1, mu = -0.5), + "'mu' must be greater 0 but less than Inf" + ) + expect_error( + dborel(x = 1, mu = Inf), + "'mu' must be greater 0 but less than Inf" + ) + expect_error( + rborel(n = 0, mu = -0.5), + "'mu' must be greater 0 but less than Inf" + ) + expect_error( + rborel(n = 0, mu = Inf), + "'mu' must be greater 0 but less than Inf" ) }) diff --git a/tests/testthat/tests-sim.r b/tests/testthat/tests-sim.r index 8b134584..ef1e26ef 100644 --- a/tests/testthat/tests-sim.r +++ b/tests/testthat/tests-sim.r @@ -2,14 +2,15 @@ test_that("Chains can be simulated", { expect_length(chain_sim(n = 2, "pois", lambda = 0.5), 2) expect_length(chain_sim(n = 10, "pois", "length", lambda = 0.9), 10) expect_s3_class( - chain_sim(n = 10, - "pois", - lambda = 2, - tree = TRUE, - infinite = 10 - ), + chain_sim( + n = 10, + "pois", + lambda = 2, + tree = TRUE, + infinite = 10 + ), "data.frame" - ) + ) expect_false(any(is.finite(chain_sim( n = 2, "pois", "length", lambda = 0.5, infinite = 1 @@ -19,16 +20,16 @@ test_that("Chains can be simulated", { tree = TRUE )) - tf <- 3 - set.seed(12) - expect_true( - all(chain_sim( - n = 2, offspring = "pois", "size", lambda = 0.9, - tree = TRUE, serial = function(n) { - rlnorm(n, meanlog = 0.58, sdlog = 1.58) - }, tf = tf - )$time < tf) - ) + tf <- 3 + set.seed(12) + expect_true( + all(chain_sim( + n = 2, offspring = "pois", "size", lambda = 0.9, + tree = TRUE, serial = function(n) { + rlnorm(n, meanlog = 0.58, sdlog = 1.58) + }, tf = tf + )$time < tf) + ) }) test_that("Errors are thrown", { @@ -65,24 +66,24 @@ test_that("Errors are thrown", { test_that("Chains can be simulated", { expect_s3_class( - chain_sim_susc( - "pois", - mn_offspring = 2, - serial = function(x) 3, - pop = 100 - ), - "data.frame" + chain_sim_susc( + "pois", + mn_offspring = 2, + serial = function(x) 3, + pop = 100 + ), + "data.frame" ) expect_s3_class( - chain_sim_susc( - "nbinom", - mn_offspring = 2, - disp_offspring = 1.5, - serial = function(x) 3, - pop = 100 - ), - "data.frame" + chain_sim_susc( + "nbinom", + mn_offspring = 2, + disp_offspring = 1.5, + serial = function(x) 3, + pop = 100 + ), + "data.frame" ) expect_identical( @@ -142,11 +143,12 @@ test_that("Errors are thrown", { serial = function(x) 3, pop = 100 ), - paste("Offspring distribution 'nbinom'", - "requires argument 'disp_offspring' > 1.", - "Use 'pois' if there is no overdispersion." - ) + paste( + "Offspring distribution 'nbinom'", + "requires argument 'disp_offspring' > 1.", + "Use 'pois' if there is no overdispersion." ) + ) expect_error( chain_sim_susc( "nbinom", @@ -178,9 +180,10 @@ test_that("warnings work as expected", { serial = function(x) rpois(x, 0.9), tree = FALSE ), - sprintf("%s %s", - "`serial` can't be used with `tree = FALSE`;", - "Setting `tree = TRUE` internally." + sprintf( + "%s %s", + "`serial` can't be used with `tree = FALSE`;", + "Setting `tree = TRUE` internally." ) ) }) From caae30fd0601bc205a1847a871ef7339e4e2956c Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 23:44:24 +0100 Subject: [PATCH 13/32] Incremented the minor version --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index ec22a9a8..cea9969d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: bpmodels Title: Simulating and Analysing Transmission Chain Statistics using Branching Process Models -Version: 0.3.0 +Version: 0.3.1 Authors@R: c( person("James M.", "Azam", , "james.azam@lshtm.ac.uk", role = c("aut", "cre"), comment = c(ORCID = "https://orcid.org/0000-0001-5782-7330")), From b97fe0bac0ff23dc59ffdf244d5a464cebfa0f6b Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 24 Jul 2023 23:44:39 +0100 Subject: [PATCH 14/32] Added news items to describe new changes --- NEWS.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/NEWS.md b/NEWS.md index c73baebe..dad1c265 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,12 @@ +# bpmodels 0.3.1 + +## Unit tests and input validation + +* `rborel()` and `dborel()` now have input checking in place. +* Package coverage has been improved with new tests from `rborel()`, +`dborel()`, and the internal functions stored in the `utils.R` script, +and additional tests for `chain_sim()`. + # bpmodels 0.3.0 ## Website From 577d1b520c78a99a9283993f9a5611bf0eac6837 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 24 Jul 2023 22:59:49 +0000 Subject: [PATCH 15/32] Update CITATION.cff --- CITATION.cff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CITATION.cff b/CITATION.cff index 9c457910..9823121f 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -9,7 +9,7 @@ type: software license: MIT title: 'bpmodels: Simulating and Analysing Transmission Chain Statistics using Branching Process Models' -version: 0.3.0 +version: 0.3.1 abstract: Provides methods to simulate and analyse the size and length of branching processes with an arbitrary offspring distribution. These can be used, for example, to analyse the distribution of chain sizes or length of infectious disease outbreaks, From 61333cf769928f2cb3b61bc6f277a2c82e53849b Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 10:11:53 +0000 Subject: [PATCH 16/32] Check all elements of x --- R/borel.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/borel.r b/R/borel.r index 2a9ab38e..2d3b7635 100644 --- a/R/borel.r +++ b/R/borel.r @@ -6,7 +6,7 @@ ##' @return probability mass. ##' @author Sebastian Funk dborel <- function(x, mu, log = FALSE) { - if (x < 1) stop("'x' must be greater than 0") + if (any(x < 1)) stop("All 'x' elements must be greater than 0") if (mu <= 0 || is.infinite(mu)) { stop("'mu' must be greater 0 but less than Inf") } From 1234b39a4c8108a387e68ea8ca760145ed81b3ce Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 10:36:00 +0000 Subject: [PATCH 17/32] Import checkmate --- DESCRIPTION | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION index cea9969d..36ceeab7 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -48,3 +48,5 @@ LazyData: true Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 Language: en-GB +Imports: + checkmate From f8b988a5d8e204e2a793043539a0053d3c52c055 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 10:36:59 +0000 Subject: [PATCH 18/32] Add checks on x, n, and mu --- R/borel.r | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/R/borel.r b/R/borel.r index 2d3b7635..ca5deb29 100644 --- a/R/borel.r +++ b/R/borel.r @@ -6,10 +6,12 @@ ##' @return probability mass. ##' @author Sebastian Funk dborel <- function(x, mu, log = FALSE) { - if (any(x < 1)) stop("All 'x' elements must be greater than 0") - if (mu <= 0 || is.infinite(mu)) { - stop("'mu' must be greater 0 but less than Inf") - } + checkmate::assert_numeric( + x, lower = 0, upper = Inf + ) + checkmate::assert_number( + mu, lower = 0, finite = TRUE, na.ok = FALSE + ) ld <- -mu * x + (x - 1) * log(mu * x) - lgamma(x + 1) if (!log) ld <- exp(ld) return(ld) @@ -25,8 +27,11 @@ dborel <- function(x, mu, log = FALSE) { ##' @return vector of random numbers ##' @author Sebastian Funk rborel <- function(n, mu, infinite = Inf) { - if (mu <= 0 || is.infinite(mu)) { - stop("'mu' must be greater 0 but less than Inf") - } + checkmate::assert_number( + n, lower = 1, finite = TRUE, na.ok = FALSE + ) + checkmate::assert_number( + mu, lower = 0, finite = TRUE, na.ok = FALSE + ) chain_sim(n, "pois", "size", infinite = infinite, lambda = mu) } From 48e36cc1951aa3f5acb762b2a3540b7ecab68db1 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 10:37:16 +0000 Subject: [PATCH 19/32] Update docs to reflect input types --- R/borel.r | 4 ++-- man/dborel.Rd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/borel.r b/R/borel.r index ca5deb29..283c0500 100644 --- a/R/borel.r +++ b/R/borel.r @@ -1,7 +1,7 @@ ##' Density of the Borel distribution ##' -##' @param x vector of integers. -##' @param mu mu parameter (the Poisson mean). +##' @param x vector of quantiles; integer. +##' @param mu mu parameter (the poisson mean); non-negative. ##' @param log logical; if TRUE, probabilities p are given as log(p). ##' @return probability mass. ##' @author Sebastian Funk diff --git a/man/dborel.Rd b/man/dborel.Rd index bbd04672..7871bf46 100644 --- a/man/dborel.Rd +++ b/man/dborel.Rd @@ -7,9 +7,9 @@ dborel(x, mu, log = FALSE) } \arguments{ -\item{x}{vector of integers.} +\item{x}{vector of quantiles; integer.} -\item{mu}{mu parameter (the Poisson mean).} +\item{mu}{mu parameter (the poisson mean); non-negative.} \item{log}{logical; if TRUE, probabilities p are given as log(p).} } From 6195f3dcd0f6fcdd08fbd877447cdad75973ac2c Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 10:43:28 +0000 Subject: [PATCH 20/32] Add input checks for args of rnbinom_mean_disp() --- R/utils.r | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/R/utils.r b/R/utils.r index e294ed32..adc16df6 100644 --- a/R/utils.r +++ b/R/utils.r @@ -44,14 +44,22 @@ rgen_length <- function(n, x, prob) { #' in terms of mean and dispersion coefficient #' @param n number of samples to draw #' @param mn mean of distribution -#' @param disp dispersion coefficient (var/mean) +#' @param disp dispersion coefficient (var/mean); Must be > 1. #' @return vector containing the random numbers #' @author Flavio Finger #' @export #' @examples #' rnbinom_mean_disp(n = 5, mn = 4, disp = 2) rnbinom_mean_disp <- function(n, mn, disp) { - if (disp < 1) stop("'disp' must be at least 1") + checkmate::assert_number( + n, lower = 0, finite = TRUE, na.ok = FALSE + ) + checkmate::assert_number( + disp, lower = 1, finite = TRUE, na.ok = FALSE + ) + checkmate::assert_number( + mn, lower = 0, finite = TRUE, na.ok = FALSE + ) size <- mn / (disp - 1) stats::rnbinom(n, size = size, mu = mn) } From b4cc22d629bf3deb8629a005e4b21bd52eef9bea Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 12:19:13 +0000 Subject: [PATCH 21/32] Fix error message regex --- tests/testthat/test-utils.R | 2 +- tests/testthat/tests-borel.r | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 199d29df..c5444ad4 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -10,7 +10,7 @@ test_that("Util functions work", { test_that("Errors are thrown", { expect_error( rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), - "'disp' must be at least 1" + "is not >= 1" ) }) diff --git a/tests/testthat/tests-borel.r b/tests/testthat/tests-borel.r index 7ae10e4f..2c2829b5 100644 --- a/tests/testthat/tests-borel.r +++ b/tests/testthat/tests-borel.r @@ -7,22 +7,22 @@ test_that("We can calculate probabilities and sample", { test_that("Errors are thrown", { expect_error( dborel(x = 0, mu = 0.5), - "'x' must be greater than 0" + "is not >= 1" ) expect_error( dborel(x = 1, mu = -0.5), - "'mu' must be greater 0 but less than Inf" + "is not >= 0" ) expect_error( dborel(x = 1, mu = Inf), - "'mu' must be greater 0 but less than Inf" + "Must be finite" ) expect_error( rborel(n = 0, mu = -0.5), - "'mu' must be greater 0 but less than Inf" + "is not >= 1" ) expect_error( rborel(n = 0, mu = Inf), - "'mu' must be greater 0 but less than Inf" + "is not >= 1" ) }) From b439f36b362be867382e0ad3510c78a836fea22a Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 12:23:25 +0000 Subject: [PATCH 22/32] Fix test file name --- tests/testthat/{tests-borel.r => test-borel.r} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/testthat/{tests-borel.r => test-borel.r} (100%) diff --git a/tests/testthat/tests-borel.r b/tests/testthat/test-borel.r similarity index 100% rename from tests/testthat/tests-borel.r rename to tests/testthat/test-borel.r From efa41ed546b2aa4ab339444140801328396a655f Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 12:23:39 +0000 Subject: [PATCH 23/32] Fix lower value of x --- R/borel.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/borel.r b/R/borel.r index 283c0500..9ec85985 100644 --- a/R/borel.r +++ b/R/borel.r @@ -7,7 +7,7 @@ ##' @author Sebastian Funk dborel <- function(x, mu, log = FALSE) { checkmate::assert_numeric( - x, lower = 0, upper = Inf + x, lower = 1, upper = Inf ) checkmate::assert_number( mu, lower = 0, finite = TRUE, na.ok = FALSE From 944ffc2fb284079952d52393c184a3b200ef9d24 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 12:26:02 +0000 Subject: [PATCH 24/32] Explicitly assign arguments --- tests/testthat/tests-sim.r | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/testthat/tests-sim.r b/tests/testthat/tests-sim.r index ef1e26ef..b3786583 100644 --- a/tests/testthat/tests-sim.r +++ b/tests/testthat/tests-sim.r @@ -4,7 +4,7 @@ test_that("Chains can be simulated", { expect_s3_class( chain_sim( n = 10, - "pois", + offspring = "pois", lambda = 2, tree = TRUE, infinite = 10 @@ -37,6 +37,7 @@ test_that("Errors are thrown", { expect_error(chain_sim(n = 2, "lnorm", meanlog = log(1.6)), "integer") expect_error( chain_sim(n = 2, offspring = pois, "length", lambda = 0.9), + stat = "length", "not found" ) expect_error(chain_sim( @@ -45,17 +46,19 @@ test_that("Errors are thrown", { )) expect_error( chain_sim(n = 2, offspring = c(1, 2), "length", lambda = 0.9), + stat = "length", "not a character string" ) expect_error( chain_sim(n = 2, offspring = list(1, 2), "length", lambda = 0.9), + stat = "length", "not a character string" ) expect_error( chain_sim( n = 2, offspring = "pois", - "size", + stat = "size", lambda = 0.9, tf = 5, tree = FALSE @@ -67,7 +70,7 @@ test_that("Errors are thrown", { test_that("Chains can be simulated", { expect_s3_class( chain_sim_susc( - "pois", + offspring = "pois", mn_offspring = 2, serial = function(x) 3, pop = 100 @@ -77,7 +80,7 @@ test_that("Chains can be simulated", { expect_s3_class( chain_sim_susc( - "nbinom", + offspring = "nbinom", mn_offspring = 2, disp_offspring = 1.5, serial = function(x) 3, @@ -89,7 +92,7 @@ test_that("Chains can be simulated", { expect_identical( nrow( chain_sim_susc( - "pois", + offspring = "pois", mn_offspring = 2, serial = function(x) 3, pop = 1 @@ -101,7 +104,7 @@ test_that("Chains can be simulated", { expect_identical( nrow( chain_sim_susc( - "pois", + offspring = "pois", mn_offspring = 100, tf = 2, serial = function(x) 3, @@ -114,7 +117,7 @@ test_that("Chains can be simulated", { expect_identical( nrow( chain_sim_susc( - "pois", + offspring = "pois", mn_offspring = 100, serial = function(x) 3, pop = 999, @@ -128,7 +131,7 @@ test_that("Chains can be simulated", { test_that("Errors are thrown", { expect_error( chain_sim_susc( - "dummy", + offspring = "dummy", mn_offspring = 3, serial = function(x) 3, pop = 100 @@ -137,7 +140,7 @@ test_that("Errors are thrown", { ) expect_error( chain_sim_susc( - "nbinom", + offspring = "nbinom", mn_offspring = 3, disp_offspring = 1, serial = function(x) 3, @@ -151,7 +154,7 @@ test_that("Errors are thrown", { ) expect_error( chain_sim_susc( - "nbinom", + offspring = "nbinom", mn_offspring = 3, serial = function(x) 3, pop = 100 @@ -163,7 +166,7 @@ test_that("Errors are thrown", { test_that("warnings work as expected", { expect_warning( chain_sim_susc( - "pois", + offspring = "pois", mn_offspring = 3, disp_offspring = 1, serial = function(x) 3, @@ -175,7 +178,7 @@ test_that("warnings work as expected", { chain_sim( n = 2, offspring = "pois", - "size", + stat = "size", lambda = 0.9, serial = function(x) rpois(x, 0.9), tree = FALSE From 039062aa633f7cce8d6c9dd79144034a46378172 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 12:36:07 +0000 Subject: [PATCH 25/32] Restructure test block for readability --- tests/testthat/tests-sim.r | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/testthat/tests-sim.r b/tests/testthat/tests-sim.r index b3786583..2723ec45 100644 --- a/tests/testthat/tests-sim.r +++ b/tests/testthat/tests-sim.r @@ -1,6 +1,24 @@ test_that("Chains can be simulated", { - expect_length(chain_sim(n = 2, "pois", lambda = 0.5), 2) - expect_length(chain_sim(n = 10, "pois", "length", lambda = 0.9), 10) + set.seed(12) + tf <- 3 + chain_sim_test_df <- chain_sim( + n = 2, + offspring = "pois", + stat = "size", + lambda = 0.9, + tree = TRUE, + serial = function(n) { + rlnorm(n, meanlog = 0.58, sdlog = 1.58) + }, + tf = tf + ) + # Check that all the simulated times are less than tf + expect_true( + all( + chain_sim_test_df$time < tf + ) + ) + # Other checks expect_s3_class( chain_sim( n = 10, From add81c82a0ff3712a10c26bdc1e72876c03918c6 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 12:38:09 +0000 Subject: [PATCH 26/32] Style the tests for readability --- tests/testthat/tests-sim.r | 105 +++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 27 deletions(-) diff --git a/tests/testthat/tests-sim.r b/tests/testthat/tests-sim.r index 2723ec45..fd8c961a 100644 --- a/tests/testthat/tests-sim.r +++ b/tests/testthat/tests-sim.r @@ -19,6 +19,23 @@ test_that("Chains can be simulated", { ) ) # Other checks + expect_length( + chain_sim( + n = 2, + offspring = "pois", + lambda = 0.5 + ), + 2 + ) + expect_length( + chain_sim( + n = 10, + offspring = "pois", + stat = "length", + lambda = 0.9 + ), + 10 + ) expect_s3_class( chain_sim( n = 10, @@ -29,47 +46,81 @@ test_that("Chains can be simulated", { ), "data.frame" ) - expect_false(any(is.finite(chain_sim( - n = 2, "pois", "length", lambda = 0.5, - infinite = 1 - )))) - expect_no_error(chain_sim( - n = 2, offspring = "pois", "size", lambda = 0.9, - tree = TRUE - )) - - tf <- 3 - set.seed(12) - expect_true( - all(chain_sim( - n = 2, offspring = "pois", "size", lambda = 0.9, - tree = TRUE, serial = function(n) { - rlnorm(n, meanlog = 0.58, sdlog = 1.58) - }, tf = tf - )$time < tf) + expect_false( + any( + is.finite( + chain_sim( + n = 2, + offspring = "pois", + stat = "length", + lambda = 0.5, + infinite = 1 + ) + ) + ) + ) + expect_no_error( + chain_sim( + n = 2, + offspring = "pois", + stat = "size", + lambda = 0.9, + tree = TRUE + ) ) }) test_that("Errors are thrown", { - expect_error(chain_sim(n = 2, "dummy"), "does not exist") - expect_error(chain_sim(n = 2, "lnorm", meanlog = log(1.6)), "integer") expect_error( - chain_sim(n = 2, offspring = pois, "length", lambda = 0.9), + chain_sim( + n = 2, + "dummy" + ), + "does not exist" + ) + expect_error( + chain_sim( + n = 2, + offspring = "lnorm", + meanlog = log(1.6) + ), + "integer" + ) + expect_error( + chain_sim( + n = 2, + offspring = pois, stat = "length", + lambda = 0.9 + ), "not found" ) - expect_error(chain_sim( - n = 2, offspring = "pois", "size", lambda = 0.9, - serial = c(1, 2), "must be a function" - )) expect_error( - chain_sim(n = 2, offspring = c(1, 2), "length", lambda = 0.9), + chain_sim( + n = 2, + offspring = "pois", + stat = "size", + lambda = 0.9, + serial = c(1, 2) + ), + "must be a function" + ) + expect_error( + chain_sim( + n = 2, + offspring = c(1, 2), stat = "length", + lambda = 0.9 + ), "not a character string" ) expect_error( - chain_sim(n = 2, offspring = list(1, 2), "length", lambda = 0.9), + chain_sim( + n = 2, + offspring = list(1, 2), stat = "length", + lambda = 0.9 + ), "not a character string" ) expect_error( From 0db7607a52f63b0d2783fbccbf24e8c27db84f6e Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 13:11:50 +0000 Subject: [PATCH 27/32] Check that x is below 0 --- R/utils.r | 3 +++ tests/testthat/test-utils.R | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/R/utils.r b/R/utils.r index adc16df6..d50a9bf8 100644 --- a/R/utils.r +++ b/R/utils.r @@ -6,6 +6,9 @@ #' @author Sebastian Funk #' @keywords internal complementary_logprob <- function(x) { + checkmate::assert_numeric( + x, lower = -Inf, upper = 0 + ) tryCatch(log1p(-sum(exp(x))), error = function(e) -Inf) } diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index c5444ad4..235e4595 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -14,7 +14,13 @@ test_that("Errors are thrown", { ) }) -test_that("Warnings are thrown", { - expect_warning(complementary_logprob(0.1), "NaNs produced") - expect_warning(complementary_logprob(Inf), "NaNs produced") +test_that("Errors are thrown", { + expect_error( + complementary_logprob(0.1), + "is not <= 0" + ) + expect_error( + complementary_logprob(Inf), + "is not <= 0" + ) }) From 5e2790a8e4361b99768a4a8e409aae143d6d66c0 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 13:12:27 +0000 Subject: [PATCH 28/32] Add checks and tests for all arguments of rnbinom_mean_disp() --- R/utils.r | 6 +++--- tests/testthat/test-utils.R | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/R/utils.r b/R/utils.r index d50a9bf8..76397c50 100644 --- a/R/utils.r +++ b/R/utils.r @@ -46,7 +46,7 @@ rgen_length <- function(n, x, prob) { #' Negative binomial random numbers parametrized #' in terms of mean and dispersion coefficient #' @param n number of samples to draw -#' @param mn mean of distribution +#' @param mn mean of distribution; Must be > 0. #' @param disp dispersion coefficient (var/mean); Must be > 1. #' @return vector containing the random numbers #' @author Flavio Finger @@ -55,13 +55,13 @@ rgen_length <- function(n, x, prob) { #' rnbinom_mean_disp(n = 5, mn = 4, disp = 2) rnbinom_mean_disp <- function(n, mn, disp) { checkmate::assert_number( - n, lower = 0, finite = TRUE, na.ok = FALSE + n, lower = 1, finite = TRUE, na.ok = FALSE ) checkmate::assert_number( disp, lower = 1, finite = TRUE, na.ok = FALSE ) checkmate::assert_number( - mn, lower = 0, finite = TRUE, na.ok = FALSE + mn, lower = 1E-100, finite = TRUE, na.ok = FALSE ) size <- mn / (disp - 1) stats::rnbinom(n, size = size, mu = mn) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 235e4595..d96e78bf 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -8,10 +8,44 @@ test_that("Util functions work", { }) test_that("Errors are thrown", { + # Checks on 'disp' argument expect_error( rnbinom_mean_disp(n = 5, mn = 4, disp = 0.9), "is not >= 1" ) + expect_error( + rnbinom_mean_disp(n = 5, mn = 4, disp = NA), + "May not be NA" + ) + expect_error( + rnbinom_mean_disp(n = 5, mn = 4, disp = Inf), + "Must be finite" + ) + # Checks on 'n' argument + expect_error( + rnbinom_mean_disp(n = 0, mn = 4, disp = 2), + "is not >= 1" + ) + expect_error( + rnbinom_mean_disp(n = NA, mn = 4, disp = 2), + "May not be NA" + ) + expect_error( + rnbinom_mean_disp(n = Inf, mn = 4, disp = 2), + "Must be finite" + ) + # Checks on 'mn' argument + expect_error( + rnbinom_mean_disp(n = 2, mn = 0, disp = 2) + ) + expect_error( + rnbinom_mean_disp(n = 2, mn = NA, disp = 2), + "May not be NA" + ) + expect_error( + rnbinom_mean_disp(n = 2, mn = Inf, disp = 2), + "Must be finite" + ) }) test_that("Errors are thrown", { From 3435d1280af991cbf61101059d54e46c95f4efb1 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 13:24:42 +0000 Subject: [PATCH 29/32] Generate docs --- man/rnbinom_mean_disp.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/rnbinom_mean_disp.Rd b/man/rnbinom_mean_disp.Rd index 698836d6..fb9df0aa 100644 --- a/man/rnbinom_mean_disp.Rd +++ b/man/rnbinom_mean_disp.Rd @@ -10,9 +10,9 @@ rnbinom_mean_disp(n, mn, disp) \arguments{ \item{n}{number of samples to draw} -\item{mn}{mean of distribution} +\item{mn}{mean of distribution; Must be > 0.} -\item{disp}{dispersion coefficient (var/mean)} +\item{disp}{dispersion coefficient (var/mean); Must be > 1.} } \value{ vector containing the random numbers From 3d58f99ecdf9919b9ab8aed2bba8c41f61f81522 Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 13:50:15 +0000 Subject: [PATCH 30/32] Linting: Fix indentation --- tests/testthat/tests-sim.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/tests-sim.r b/tests/testthat/tests-sim.r index fd8c961a..c284b323 100644 --- a/tests/testthat/tests-sim.r +++ b/tests/testthat/tests-sim.r @@ -12,7 +12,7 @@ test_that("Chains can be simulated", { }, tf = tf ) - # Check that all the simulated times are less than tf + # Check that all the simulated times are less than tf expect_true( all( chain_sim_test_df$time < tf From 78bd84a19ce0aaa2042286c539789b69e35bc3ff Mon Sep 17 00:00:00 2001 From: jamesaazam Date: Mon, 6 Nov 2023 14:00:27 +0000 Subject: [PATCH 31/32] Finalise NEWS item --- NEWS.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index dad1c265..a77841fe 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,10 +2,8 @@ ## Unit tests and input validation -* `rborel()` and `dborel()` now have input checking in place. -* Package coverage has been improved with new tests from `rborel()`, -`dborel()`, and the internal functions stored in the `utils.R` script, -and additional tests for `chain_sim()`. +* The following internal functions now have input validation: `rborel()`, `dborel()`, `complementary_logprob()`, and `rnbinom_mean_disp()`. +* Code coverage has been improved with more tests on the following functions: `rborel()`, `dborel()`, `chain_sim()`, `rnbinom_mean_disp()`, `complementary_logprob()`, `rgen_length()`, and `rbinom_size()`. # bpmodels 0.3.0 From 309fa34d9adae189a10d93f05ebea3f9471f7425 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 6 Nov 2023 14:11:46 +0000 Subject: [PATCH 32/32] Update CITATION.cff --- CITATION.cff | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CITATION.cff b/CITATION.cff index 9823121f..6352874f 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -249,3 +249,15 @@ references: given-names: Saralees email: saralees.nadarajah@manchester.ac.uk year: '2023' +- type: software + title: checkmate + abstract: 'checkmate: Fast and Versatile Argument Checks' + notes: Imports + url: https://mllg.github.io/checkmate/ + repository: https://CRAN.R-project.org/package=checkmate + authors: + - family-names: Lang + given-names: Michel + email: michellang@gmail.com + orcid: https://orcid.org/0000-0001-9754-0393 + year: '2023'