Diff of /R/custom_moves.R [000000] .. [dfe06d]

Switch to side-by-side view

--- a
+++ b/R/custom_moves.R
@@ -0,0 +1,179 @@
+
+
+#' Customise samplers for outbreaker
+#'
+#' This function is used to specify customised movement functions
+#' (a.k.a. samplers) for outbreaker. Custom functions are specified as a named
+#' list or series of comma-separated, named arguments, indicating which type of
+#' movement they implement. Values currently available are:
+#'
+#' \itemize{
+#'
+#' \item \code{mu}: movement of the mutation rate; by default, the function
+#' \code{cpp_move_mu} is used.
+#'
+#' \item \code{pi}: movement of the reporting probability; by default, the function
+#' \code{cpp_move_pi} is used.
+#'
+#' \item \code{eps}: movement of the contact reporting coverage; by default, the
+#' function \code{cpp_move_eps} is used.
+#'
+#' \item \code{lambda}: the movement of the non-infectious contact rate; the
+#' function \code{cpp_move_lambda} is used.
+#'
+#' \item \code{alpha}: movement of the transmission tree, by randomly proposing
+#' infectors in the pool of cases infected before; by default, the function
+#' \code{cpp_move_alpha} is used.
+#'
+#' \item \code{swap_cases}: movement of the transmission tree, by swapping
+#' infectors and infected cases; by default, the function
+#' \code{cpp_move_swap_cases} is used.
+#'
+#' \item \code{t_inf}: movement of the date of infection; by default, the
+#' function \code{cpp_move_t_inf} is used.
+#'
+#' \item \code{kappa}: movement of the number generations between cases; by
+#' default, the function \code{cpp_move_kappa} is used.
+#'
+#' }
+#'
+#'
+#' Movement functions must have an argument \code{param}, which is a list of
+#' parameters and augmented data of the class \code{\link{create_param}}.
+#' Each movement function will be enclosed with its other arguments, so that the
+#' resulting function will have a single argument 'param'. For non-standard
+#' movements (i.e. none of the names specified above), the closure will contain:
+#'
+#' \itemize{
+#'
+#' \item \code{data}: a list of named items containing input data as returned by
+#' \code{\link{outbreaker_data}}.
+#'
+#' \item \code{config}:  a list of named items containing input data as returned by
+#' \code{\link{create_config}}.
+#'
+#' \item \code{likelihoods}: a list of named custom likelihood functions as returned by
+#' \code{\link{custom_likelihoods}}.
+#'
+#' \item \code{priors}: a list of named custom prior functions as returned by
+#' \code{\link{custom_priors}}.
+#'
+#' }
+#'
+#' @author Thibaut Jombart (\email{thibautjombart@@gmail.com}).
+#'
+#' @seealso See \href{http://www.repidemicsconsortium.org/outbreaker2/articles/customisation.html#customising-movements}{customization vignette} for detailed examples on how to customise movement functions.
+#' 
+#' @export
+#'
+#' @param ... A list or a series of named, comma-separated functions
+#'     implementing movements of parameters or augmented data.
+#'
+#' @return A list of movement functions with a single argument 'param', with
+#'     class \code{outbreaker_moves}.
+
+custom_moves <- function(...) {
+
+    move_functions <- list(...)
+
+    if (length(move_functions) == 1L && is.list(move_functions[[1]])) {
+        move_functions <- move_functions[[1]]
+    }
+
+
+    defaults <- list(mu = cpp_move_mu,
+                     pi = cpp_move_pi,
+                     eps = cpp_move_eps,
+                     lambda = cpp_move_lambda,
+                     alpha = cpp_move_alpha,
+                     swap_cases = cpp_move_swap_cases,
+                     t_inf = cpp_move_t_inf,
+                     kappa = cpp_move_kappa
+                     )
+
+
+    moves <-  modify_defaults(defaults, move_functions, FALSE)
+    moves_names <- names(moves)
+
+
+
+    ## check all moves are functions
+
+    function_or_null <- function(x) {
+        is.null(x) || is.function(x)
+    }
+
+    is_ok <- vapply(moves, function_or_null, logical(1))
+
+    if (!all(is_ok)) {
+        culprits <- moves_names[!is_ok]
+        msg <- paste0("The following moves are not functions: ",
+                      paste(culprits, collapse = ", "))
+        stop(msg)
+    }
+
+
+    ## check they all have a 'param' argument
+
+    param_is_arg <- function(x) {
+        if(is.function(x)) {
+            return ("param" %in% methods::formalArgs(x))
+        }
+
+        return(TRUE)
+    }
+
+    param_ok <- vapply(moves, param_is_arg, logical(1))
+
+    if (!all(param_ok)) {
+        culprits <- moves_names[!param_ok]
+        msg <- paste0("The following moves dont' have a 'param' argument: ",
+                      paste(culprits, collapse = ", "))
+        stop(msg)
+    }
+
+
+    class(moves) <- c("outbreaker_moves", "list")
+    return(moves)
+}
+
+
+
+
+
+#' @rdname custom_moves
+#'
+#' @export
+#'
+#' @aliases print.outbreaker_moves
+#'
+#' @param x an \code{outbreaker_moves} object as returned by \code{create_moves}.
+#'
+
+print.outbreaker_moves <- function(x, ...) {
+    cat("\n\n ///// outbreaker movement functions ///\n")
+    cat("\nclass:", class(x))
+    cat("\nnumber of items:", length(x))
+
+    cat("\n\n/// movement functions //\n")
+    print(x[])
+
+
+    ##  is_custom <- !vapply(x, is.null, FALSE)
+
+    ##  names_default <- names(x)[!is_custom]
+    ##  if (length(names_default) > 0) {
+    ##      cat("/// custom priors set to NULL (default used) //\n")
+    ##      print(x[!is_custom])
+    ## }
+
+
+    ##  names_custom <- names(x)[is_custom]
+    ##  if (length(names_custom) > 0) {
+    ##      cat("/// custom priors //\n")
+    ##      print(x[is_custom])
+    ##  }
+
+    return(invisible(NULL))
+}
+