diff --git a/NAMESPACE b/NAMESPACE index d886cf72..2dcd3bfe 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -50,6 +50,7 @@ S3method(dim,Quantities) S3method(extractVariableNames,DataSubject) S3method(extractVariableNames,DataSurvival) S3method(generateQuantities,JointModelSamples) +S3method(getParameters,default) S3method(initialValues,JointModel) S3method(initialValues,Parameter) S3method(initialValues,ParameterList) @@ -107,10 +108,15 @@ export(merge) export(prior_beta) export(prior_cauchy) export(prior_gamma) +export(prior_invgamma) +export(prior_logistic) +export(prior_loglogistic) export(prior_lognormal) export(prior_none) export(prior_normal) export(prior_std_normal) +export(prior_student_t) +export(prior_uniform) export(sampleStanModel) export(show) export(sim_lm_gsf) diff --git a/R/StanModule.R b/R/StanModule.R index 65a2a3ad..03fcffb6 100755 --- a/R/StanModule.R +++ b/R/StanModule.R @@ -144,11 +144,13 @@ setMethod( stan_fragments <- lapply( names(stan_blocks), \(par) { - new_string <- c(slot(x, par), slot(y, par)) - if (all(new_string == "")) { - return("") + if (all(slot(y, par) == "")) { + return(slot(x, par)) } - return(new_string) + if (all(slot(x, par) == "")) { + return(slot(y, par)) + } + return(c(slot(x, par), slot(y, par))) } ) names(stan_fragments) <- names(stan_blocks) diff --git a/R/defaults.R b/R/defaults.R index 6b00fce4..3ede8bdd 100755 --- a/R/defaults.R +++ b/R/defaults.R @@ -37,7 +37,7 @@ setMethod( ) # getParameters ---- - +#' @export getParameters.default <- function(object) { if (missing(object) || is.null(object)) { return(NULL) diff --git a/_pkgdown.yml b/_pkgdown.yml index 06ff0637..e626c09c 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -50,10 +50,15 @@ reference: - prior_beta - prior_cauchy - prior_gamma + - prior_invgamma + - prior_logistic + - prior_loglogistic - prior_lognormal - prior_none - prior_normal + - prior_uniform - prior_std_normal + - prior_student_t - title: Longitudinal Model Specification contents: diff --git a/man/prior_beta.Rd b/man/prior_beta.Rd index 68df5403..64da7843 100644 --- a/man/prior_beta.Rd +++ b/man/prior_beta.Rd @@ -20,9 +20,14 @@ Beta Prior Distribution Other Prior: \code{\link{prior_cauchy}()}, \code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, \code{\link{prior_lognormal}()}, \code{\link{prior_none}()}, \code{\link{prior_normal}()}, -\code{\link{prior_std_normal}()} +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} } \concept{Prior} diff --git a/man/prior_cauchy.Rd b/man/prior_cauchy.Rd index 3c4dea04..85614625 100644 --- a/man/prior_cauchy.Rd +++ b/man/prior_cauchy.Rd @@ -20,9 +20,14 @@ Cauchy Prior Distribution Other Prior: \code{\link{prior_beta}()}, \code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, \code{\link{prior_lognormal}()}, \code{\link{prior_none}()}, \code{\link{prior_normal}()}, -\code{\link{prior_std_normal}()} +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} } \concept{Prior} diff --git a/man/prior_gamma.Rd b/man/prior_gamma.Rd index 89fa27e3..a1e7667c 100644 --- a/man/prior_gamma.Rd +++ b/man/prior_gamma.Rd @@ -20,9 +20,14 @@ Gamma Prior Distribution Other Prior: \code{\link{prior_beta}()}, \code{\link{prior_cauchy}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, \code{\link{prior_lognormal}()}, \code{\link{prior_none}()}, \code{\link{prior_normal}()}, -\code{\link{prior_std_normal}()} +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} } \concept{Prior} diff --git a/man/prior_invgamma.Rd b/man/prior_invgamma.Rd new file mode 100644 index 00000000..82fdaaa7 --- /dev/null +++ b/man/prior_invgamma.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Prior.R +\name{prior_invgamma} +\alias{prior_invgamma} +\title{Inverse-Gamma Prior Distribution} +\usage{ +prior_invgamma(alpha, beta, init = beta/(alpha - 1)) +} +\arguments{ +\item{alpha}{(\code{number})\cr Shape parameter.} + +\item{beta}{(\code{number})\cr Scale parameter.} + +\item{init}{(\code{number})\cr initial value.} +} +\description{ +Inverse-Gamma Prior Distribution +} +\seealso{ +Other Prior: +\code{\link{prior_beta}()}, +\code{\link{prior_cauchy}()}, +\code{\link{prior_gamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, +\code{\link{prior_lognormal}()}, +\code{\link{prior_none}()}, +\code{\link{prior_normal}()}, +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} +} +\concept{Prior} diff --git a/man/prior_logistic.Rd b/man/prior_logistic.Rd new file mode 100644 index 00000000..cdaadae0 --- /dev/null +++ b/man/prior_logistic.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Prior.R +\name{prior_logistic} +\alias{prior_logistic} +\title{Logistic Prior Distribution} +\usage{ +prior_logistic(mu, sigma, init = mu) +} +\arguments{ +\item{mu}{(\code{number})\cr Location parameter.} + +\item{sigma}{(\code{number})\cr Scale parameter.} + +\item{init}{(\code{number})\cr initial value.} +} +\description{ +Logistic Prior Distribution +} +\seealso{ +Other Prior: +\code{\link{prior_beta}()}, +\code{\link{prior_cauchy}()}, +\code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_loglogistic}()}, +\code{\link{prior_lognormal}()}, +\code{\link{prior_none}()}, +\code{\link{prior_normal}()}, +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} +} +\concept{Prior} diff --git a/man/prior_loglogistic.Rd b/man/prior_loglogistic.Rd new file mode 100644 index 00000000..89581e94 --- /dev/null +++ b/man/prior_loglogistic.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Prior.R +\name{prior_loglogistic} +\alias{prior_loglogistic} +\title{Log-Logistic Prior Distribution} +\usage{ +prior_loglogistic(alpha, beta, init = alpha * pi/(beta * sin(pi/beta))) +} +\arguments{ +\item{alpha}{(\code{number})\cr Scale parameter.} + +\item{beta}{(\code{number})\cr Shape parameter.} + +\item{init}{(\code{number})\cr initial value.} +} +\description{ +Log-Logistic Prior Distribution +} +\seealso{ +Other Prior: +\code{\link{prior_beta}()}, +\code{\link{prior_cauchy}()}, +\code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_lognormal}()}, +\code{\link{prior_none}()}, +\code{\link{prior_normal}()}, +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} +} +\concept{Prior} diff --git a/man/prior_lognormal.Rd b/man/prior_lognormal.Rd index 88c8419f..9aebbcae 100644 --- a/man/prior_lognormal.Rd +++ b/man/prior_lognormal.Rd @@ -21,8 +21,13 @@ Other Prior: \code{\link{prior_beta}()}, \code{\link{prior_cauchy}()}, \code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, \code{\link{prior_none}()}, \code{\link{prior_normal}()}, -\code{\link{prior_std_normal}()} +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} } \concept{Prior} diff --git a/man/prior_none.Rd b/man/prior_none.Rd index 958a4a7d..b5e272f0 100644 --- a/man/prior_none.Rd +++ b/man/prior_none.Rd @@ -17,8 +17,13 @@ Other Prior: \code{\link{prior_beta}()}, \code{\link{prior_cauchy}()}, \code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, \code{\link{prior_lognormal}()}, \code{\link{prior_normal}()}, -\code{\link{prior_std_normal}()} +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} } \concept{Prior} diff --git a/man/prior_normal.Rd b/man/prior_normal.Rd index 2216ebae..6f311e90 100644 --- a/man/prior_normal.Rd +++ b/man/prior_normal.Rd @@ -21,8 +21,13 @@ Other Prior: \code{\link{prior_beta}()}, \code{\link{prior_cauchy}()}, \code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, \code{\link{prior_lognormal}()}, \code{\link{prior_none}()}, -\code{\link{prior_std_normal}()} +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} } \concept{Prior} diff --git a/man/prior_std_normal.Rd b/man/prior_std_normal.Rd index 62530aea..2dcee02d 100644 --- a/man/prior_std_normal.Rd +++ b/man/prior_std_normal.Rd @@ -17,8 +17,13 @@ Other Prior: \code{\link{prior_beta}()}, \code{\link{prior_cauchy}()}, \code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, \code{\link{prior_lognormal}()}, \code{\link{prior_none}()}, -\code{\link{prior_normal}()} +\code{\link{prior_normal}()}, +\code{\link{prior_student_t}()}, +\code{\link{prior_uniform}()} } \concept{Prior} diff --git a/man/prior_student_t.Rd b/man/prior_student_t.Rd new file mode 100644 index 00000000..939d1d94 --- /dev/null +++ b/man/prior_student_t.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Prior.R +\name{prior_student_t} +\alias{prior_student_t} +\title{Student-t Prior Distribution} +\usage{ +prior_student_t(nu, mu, sigma, init = mu) +} +\arguments{ +\item{nu}{(\code{number})\cr Degrees of freedom parameter.} + +\item{mu}{(\code{number})\cr Location parameter.} + +\item{sigma}{(\code{number})\cr Scale parameter.} + +\item{init}{(\code{number})\cr initial value.} +} +\description{ +Student-t Prior Distribution +} +\seealso{ +Other Prior: +\code{\link{prior_beta}()}, +\code{\link{prior_cauchy}()}, +\code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, +\code{\link{prior_lognormal}()}, +\code{\link{prior_none}()}, +\code{\link{prior_normal}()}, +\code{\link{prior_std_normal}()}, +\code{\link{prior_uniform}()} +} +\concept{Prior} diff --git a/man/prior_uniform.Rd b/man/prior_uniform.Rd new file mode 100644 index 00000000..c9b926c2 --- /dev/null +++ b/man/prior_uniform.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Prior.R +\name{prior_uniform} +\alias{prior_uniform} +\title{Uniform Prior Distribution} +\usage{ +prior_uniform(alpha, beta, init = 0.5 * (alpha + beta)) +} +\arguments{ +\item{alpha}{(\code{number})\cr minimum value parameter.} + +\item{beta}{(\code{number})\cr maximum value parameter.} + +\item{init}{(\code{number})\cr initial value.} +} +\description{ +Uniform Prior Distribution +} +\seealso{ +Other Prior: +\code{\link{prior_beta}()}, +\code{\link{prior_cauchy}()}, +\code{\link{prior_gamma}()}, +\code{\link{prior_invgamma}()}, +\code{\link{prior_logistic}()}, +\code{\link{prior_loglogistic}()}, +\code{\link{prior_lognormal}()}, +\code{\link{prior_none}()}, +\code{\link{prior_normal}()}, +\code{\link{prior_std_normal}()}, +\code{\link{prior_student_t}()} +} +\concept{Prior} diff --git a/tests/testthat/_snaps/Prior.md b/tests/testthat/_snaps/Prior.md index 90c11131..b9c26610 100644 --- a/tests/testthat/_snaps/Prior.md +++ b/tests/testthat/_snaps/Prior.md @@ -58,3 +58,53 @@ +--- + + Code + print(prior_uniform(8, 10)) + Output + + Prior Object: + uniform(alpha = 8, beta = 10) + + +--- + + Code + print(prior_student_t(3, 10, 4)) + Output + + Prior Object: + student_t(nu = 3, mu = 10, sigma = 4) + + +--- + + Code + print(prior_logistic(sigma = 2, init = 1, 10)) + Output + + Prior Object: + logistic(mu = 10, sigma = 2) + + +--- + + Code + print(prior_loglogistic(1, 2)) + Output + + Prior Object: + loglogistic(alpha = 1, beta = 2) + + +--- + + Code + print(prior_invgamma(alpha = 1, beta = 2)) + Output + + Prior Object: + inv_gamma(alpha = 1, beta = 2) + + diff --git a/tests/testthat/test-Prior.R b/tests/testthat/test-Prior.R index 368a14c8..e2ee6032 100644 --- a/tests/testthat/test-Prior.R +++ b/tests/testthat/test-Prior.R @@ -45,6 +45,41 @@ test_that("Priors work as expected", { list(prior_mu_tim = log(4), prior_sigma_tim = 2) ) + + + tom <- prior_logistic(1, 2) + dave <- prior_loglogistic(3, 4) + jim <- prior_invgamma(5, 6) + ben <- prior_student_t(7, 8, 9) + kim <- prior_uniform(10, 11) + + header <- StanModule("parameters { + real tom; + real dave; + real jim; + real ben; + real kim; +}") + tom_sm <- as.StanModule(tom, name = "tom") + dave_sm <- as.StanModule(dave, name = "dave") + jim_sm <- as.StanModule(jim, name = "jim") + ben_sm <- as.StanModule(ben, name = "ben") + kim_sm <- as.StanModule(kim, name = "kim") + + full_sm <- list(header, tom_sm, dave_sm, jim_sm, ben_sm, kim_sm) %>% + Reduce(merge, .) + expect_equal( + full_sm, + StanModule(test_path("models", "Prior_3.stan")) + ) + + ## Check that the model syntax is correct (e.g. that we have + ## correctly specified the stan prior distribution function names) + model_obj <- cmdstanr::cmdstan_model( + test_path("models", "Prior_3.stan"), + compile = FALSE + ) + expect_true(model_obj$check_syntax(quiet = TRUE)) }) @@ -74,6 +109,40 @@ test_that("Invalid prior parameters are rejected", { regexp = "Invalid.*`sigma`" ) + expect_error( + prior_logistic(5, -1), + regexp = "Invalid.*`sigma`" + ) + + expect_error( + prior_loglogistic(5, -1), + regexp = "Invalid.*`beta`" + ) + + expect_error( + prior_loglogistic(-1, 6), + regexp = "Invalid.*`alpha`" + ) + + expect_error( + prior_student_t(-1, 6, 2), + regexp = "Invalid.*`nu`" + ) + expect_error( + prior_student_t(1, 6, -2), + regexp = "Invalid.*`sigma`" + ) + + expect_error( + prior_invgamma(alpha = -1, beta = 2), + regexp = "Invalid.*`alpha`" + ) + expect_error( + prior_invgamma(alpha = 1, beta = -2), + regexp = "Invalid.*`beta`" + ) + + # Ensure that validation doesn't wrongly reject priors with no user specified parameters expect_s4_class(prior_none(), "Prior") expect_s4_class(prior_std_normal(), "Prior") @@ -88,4 +157,9 @@ test_that("show() works for Prior objects", { expect_snapshot(print(prior_beta(5, 1))) expect_snapshot(print(prior_gamma(2.56, 12))) expect_snapshot(print(prior_none())) + expect_snapshot(print(prior_uniform(8, 10))) + expect_snapshot(print(prior_student_t(3, 10, 4))) + expect_snapshot(print(prior_logistic(sigma = 2, init = 1, 10))) + expect_snapshot(print(prior_loglogistic(1, 2))) + expect_snapshot(print(prior_invgamma(alpha = 1, beta = 2))) })