a b/R/custom_moves.R
1
2
3
#' Customise samplers for outbreaker
4
#'
5
#' This function is used to specify customised movement functions
6
#' (a.k.a. samplers) for outbreaker. Custom functions are specified as a named
7
#' list or series of comma-separated, named arguments, indicating which type of
8
#' movement they implement. Values currently available are:
9
#'
10
#' \itemize{
11
#'
12
#' \item \code{mu}: movement of the mutation rate; by default, the function
13
#' \code{cpp_move_mu} is used.
14
#'
15
#' \item \code{pi}: movement of the reporting probability; by default, the function
16
#' \code{cpp_move_pi} is used.
17
#'
18
#' \item \code{eps}: movement of the contact reporting coverage; by default, the
19
#' function \code{cpp_move_eps} is used.
20
#'
21
#' \item \code{lambda}: the movement of the non-infectious contact rate; the
22
#' function \code{cpp_move_lambda} is used.
23
#'
24
#' \item \code{alpha}: movement of the transmission tree, by randomly proposing
25
#' infectors in the pool of cases infected before; by default, the function
26
#' \code{cpp_move_alpha} is used.
27
#'
28
#' \item \code{swap_cases}: movement of the transmission tree, by swapping
29
#' infectors and infected cases; by default, the function
30
#' \code{cpp_move_swap_cases} is used.
31
#'
32
#' \item \code{t_inf}: movement of the date of infection; by default, the
33
#' function \code{cpp_move_t_inf} is used.
34
#'
35
#' \item \code{kappa}: movement of the number generations between cases; by
36
#' default, the function \code{cpp_move_kappa} is used.
37
#'
38
#' }
39
#'
40
#'
41
#' Movement functions must have an argument \code{param}, which is a list of
42
#' parameters and augmented data of the class \code{\link{create_param}}.
43
#' Each movement function will be enclosed with its other arguments, so that the
44
#' resulting function will have a single argument 'param'. For non-standard
45
#' movements (i.e. none of the names specified above), the closure will contain:
46
#'
47
#' \itemize{
48
#'
49
#' \item \code{data}: a list of named items containing input data as returned by
50
#' \code{\link{outbreaker_data}}.
51
#'
52
#' \item \code{config}:  a list of named items containing input data as returned by
53
#' \code{\link{create_config}}.
54
#'
55
#' \item \code{likelihoods}: a list of named custom likelihood functions as returned by
56
#' \code{\link{custom_likelihoods}}.
57
#'
58
#' \item \code{priors}: a list of named custom prior functions as returned by
59
#' \code{\link{custom_priors}}.
60
#'
61
#' }
62
#'
63
#' @author Thibaut Jombart (\email{thibautjombart@@gmail.com}).
64
#'
65
#' @seealso See \href{http://www.repidemicsconsortium.org/outbreaker2/articles/customisation.html#customising-movements}{customization vignette} for detailed examples on how to customise movement functions.
66
#' 
67
#' @export
68
#'
69
#' @param ... A list or a series of named, comma-separated functions
70
#'     implementing movements of parameters or augmented data.
71
#'
72
#' @return A list of movement functions with a single argument 'param', with
73
#'     class \code{outbreaker_moves}.
74
75
custom_moves <- function(...) {
76
77
    move_functions <- list(...)
78
79
    if (length(move_functions) == 1L && is.list(move_functions[[1]])) {
80
        move_functions <- move_functions[[1]]
81
    }
82
83
84
    defaults <- list(mu = cpp_move_mu,
85
                     pi = cpp_move_pi,
86
                     eps = cpp_move_eps,
87
                     lambda = cpp_move_lambda,
88
                     alpha = cpp_move_alpha,
89
                     swap_cases = cpp_move_swap_cases,
90
                     t_inf = cpp_move_t_inf,
91
                     kappa = cpp_move_kappa
92
                     )
93
94
95
    moves <-  modify_defaults(defaults, move_functions, FALSE)
96
    moves_names <- names(moves)
97
98
99
100
    ## check all moves are functions
101
102
    function_or_null <- function(x) {
103
        is.null(x) || is.function(x)
104
    }
105
106
    is_ok <- vapply(moves, function_or_null, logical(1))
107
108
    if (!all(is_ok)) {
109
        culprits <- moves_names[!is_ok]
110
        msg <- paste0("The following moves are not functions: ",
111
                      paste(culprits, collapse = ", "))
112
        stop(msg)
113
    }
114
115
116
    ## check they all have a 'param' argument
117
118
    param_is_arg <- function(x) {
119
        if(is.function(x)) {
120
            return ("param" %in% methods::formalArgs(x))
121
        }
122
123
        return(TRUE)
124
    }
125
126
    param_ok <- vapply(moves, param_is_arg, logical(1))
127
128
    if (!all(param_ok)) {
129
        culprits <- moves_names[!param_ok]
130
        msg <- paste0("The following moves dont' have a 'param' argument: ",
131
                      paste(culprits, collapse = ", "))
132
        stop(msg)
133
    }
134
135
136
    class(moves) <- c("outbreaker_moves", "list")
137
    return(moves)
138
}
139
140
141
142
143
144
#' @rdname custom_moves
145
#'
146
#' @export
147
#'
148
#' @aliases print.outbreaker_moves
149
#'
150
#' @param x an \code{outbreaker_moves} object as returned by \code{create_moves}.
151
#'
152
153
print.outbreaker_moves <- function(x, ...) {
154
    cat("\n\n ///// outbreaker movement functions ///\n")
155
    cat("\nclass:", class(x))
156
    cat("\nnumber of items:", length(x))
157
158
    cat("\n\n/// movement functions //\n")
159
    print(x[])
160
161
162
    ##  is_custom <- !vapply(x, is.null, FALSE)
163
164
    ##  names_default <- names(x)[!is_custom]
165
    ##  if (length(names_default) > 0) {
166
    ##      cat("/// custom priors set to NULL (default used) //\n")
167
    ##      print(x[!is_custom])
168
    ## }
169
170
171
    ##  names_custom <- names(x)[is_custom]
172
    ##  if (length(names_custom) > 0) {
173
    ##      cat("/// custom priors //\n")
174
    ##      print(x[is_custom])
175
    ##  }
176
177
    return(invisible(NULL))
178
}
179