# modify to add new kernels ----------------------------------------------------
kVoilaValidKernels = c("exp_kernel", "rq_kernel",
"sum_exp_kernels", "exp_const_kernel", "clamped_exp_lin_kernel")
is_valid_kernel_pointer = function(kernel) {
any(sapply(paste0("Rcpp_", kVoilaValidKernels),
FUN = inherits, x = kernel))
}
create_kernel_pointer = function(obj, ...) {
UseMethod("create_kernel_pointer", obj)
}
kVoilaRequiredParameters = list(
'exp_kernel' = c('amplitude','lengthScales'),
'rq_kernel' = c('amplitude', 'alpha', 'lengthScales'),
'sum_exp_kernels' = c('maxAmplitude','amplitude1', 'lengthScales1', 'lengthScales2'),
'exp_const_kernel' = c('maxAmplitude', 'expAmplitude', 'lengthScales'),
'clamped_exp_lin_kernel' = c('maxAmplitude', 'linAmplitude', 'linCenter', 'lengthScales')
)
create_kernel_pointer.default = function(type, parameters, inputDimension, epsilon,
lowerBound = NULL, upperBound = NULL) {
# correct a typical mistake
if ('scaleLengths' %in% names(parameters)) {
parameters$lengthScales = parameters$scaleLengths
}
kernel = switch(
type,
'exp_kernel' = new(exp_kernel, inputDimension, parameters$amplitude,
parameters$lengthScales, epsilon),
'rq_kernel' = new(rq_kernel, inputDimension, parameters$amplitude,
parameters$alpha, parameters$lengthScales, epsilon),
'sum_exp_kernels' = new(sum_exp_kernels, inputDimension, parameters$maxAmplitude,
parameters$amplitude1, parameters$lengthScales1,
parameters$lengthScales2, epsilon),
'exp_const_kernel' = new(exp_const_kernel, inputDimension, parameters$maxAmplitude,
parameters$expAmplitude, parameters$lengthScales,
epsilon),
'clamped_exp_lin_kernel' = new(clamped_exp_lin_kernel, inputDimension,
parameters$maxAmplitude,
parameters$linAmplitude, parameters$linCenter,
parameters$lengthScales,
epsilon)
)
if (!is.null(lowerBound)) {
kernel$increase_lower_bound(as.numeric(lowerBound))
}
if (!is.null(upperBound)) {
kernel$decrease_upper_bound(as.numeric(upperBound))
}
kernel
}
create_kernel_attributes = function(type, parameters, inputDimension, epsilon) {
# common to all kernels
kernelAttributes = list(inputDimension = inputDimension, epsilon = epsilon)
# the attributes MUST appear in the order used by the cpp constructor
switch(
type,
'exp_kernel' = {
kernelAttributes$amplitude = parameters$amplitude
kernelAttributes$hyperparams = list(lengthScales = parameters$lengthScales)
kernelAttributes
},
'rq_kernel' = {
kernelAttributes$amplitude = parameters$amplitude
kernelAttributes$hyperparams = list(alpha = parameters$alpha,
lengthScales = parameters$lengthScales)
kernelAttributes
},
'sum_exp_kernels' = {
kernelAttributes$maxAmplitude = parameters$maxAmplitude
kernelAttributes$hyperparams = list(amplitude1 = parameters$amplitude1,
lengthScales1 = parameters$lengthScales1,
lengthScales2 = parameters$lengthScales2)
kernelAttributes
},
'exp_const_kernel' = {
kernelAttributes$maxAmplitude = parameters$maxAmplitude
kernelAttributes$hyperparams = list(expAmplitude = parameters$expAmplitude,
lengthScales = parameters$lengthScales)
kernelAttributes
},
'clamped_exp_lin_kernel' = {
kernelAttributes$maxAmplitude = parameters$maxAmplitude
kernelAttributes$hyperparams = list(linAmplitude = parameters$linAmplitude,
linCenter = parameters$linCenter,
lengthScales = parameters$lengthScales)
kernelAttributes
})
}
# TODO: ADD ALSO TO THE TYPE ARGUMENT IN THE SDE_KERNEL FUNCTION
# end of required modifications for new kernels --------------------------------
#' Create a gaussian process' kernel
#'
#' Creates a kernel defining the properties of a gaussian process
#' @param type A string specifying the type of kernel to create
#' @param parameters A NAMED list with the parameters that the kernel needs for
#' its proper creation. The easiest way of seeing which parameters are required
#' is to make this function fail. For example:
#' \emph{sde_kernel("exp_kernel",list())}
#' @param inputDimension The input dimension of the kernel
#' @param epsilon A small value to be added to the diagonal of the kernel
#' covariance matrices to regularize them. This improves the numerical stability
#' of the computations.
#' @return A \emph{sde_kernel} S3 object
#' @examples
#' # See demo/ornstein for a complete example
#' data("ornstein")
#' uncertainty = 5
#' inputDim = 1
#' # A small value to regularize covariance matrices
#' epsilon = 1e-5
#' # Create a exponential kernel with lengthScale = 1 and amplitude = uncertainty
#' # to model the drift function. We may select the amplitude from the fact that it
#' # is a gaussian process and the 95% confidence interval would be
#' # (-2 * sqrt(amplitude), 2 * sqrt(amplitude)).
#' driftKer = sde_kernel("exp_kernel",
#' list('amplitude' = uncertainty,
#' 'lengthScales' = 1),
#' inputDim, epsilon)
#' # The selection of the amplitude parameters for gaussian process modelling the
#' # diffusion term is more complicated since voila actually uses a lognormal
#' # process. This function helps with the selection of the parameters from
#' # an uncertainty parameter and the time series
#' diffPars = select_diffusion_parameters(ornstein, deltat(ornstein),
#' priorOnSd = uncertainty)
#' # Create another exponential kernel with lengtScale=1
#' diffKer = sde_kernel("exp_kernel",
#' list('amplitude' = diffPars$kernelAmplitude,
#' 'lengthScales' = 1),
#' inputDim, epsilon)
#' @seealso \code{\link{covmat}}, \code{\link{autocovmat}}, \code{\link{vars}},
#' \code{\link{get_hyperparams}}, \code{\link{set_hyperparams}},
#' \code{\link{decrease_upper_bound}} and \code{\link{increase_lower_bound}}
#' @export
sde_kernel = function(type = c("exp_kernel", "rq_kernel", "sum_exp_kernels",
"exp_const_kernel", "clamped_exp_lin_kernel"),
parameters, inputDimension = 1, epsilon = 0) {
type = match.arg(type)
if ((length(names(parameters)) < length(kVoilaRequiredParameters[[type]])) ||
!all(names(parameters) %in% kVoilaRequiredParameters[[type]])) {
stop(paste0("Missing parameters:'", type, "' kernel requires the NAMED parameters c('",
paste(collapse = "', '", kVoilaRequiredParameters[[type]]), "')"))
}
# create kernel just to check the parameters correction (use C++ code to
# avoid replication) and get default bounds
junk = create_kernel_pointer(type, parameters, inputDimension, epsilon)
kernelAttr = create_kernel_attributes(type, parameters, inputDimension, epsilon)
# TODO: change bounds to vector!!
kernelAttr$lowerBound = lapply(junk$get_lower_bound(), function(x) x)
kernelAttr$upperBound = lapply(junk$get_upper_bound(), function(x) x)
boundIdx = 1
for (paramName in names(kernelAttr$hyperparams)) {
hpLen = length(kernelAttr$hyperparams[[paramName]])
indices = boundIdx:(boundIdx + hpLen - 1)
names(kernelAttr$lowerBound)[indices] = rep(paramName, hpLen)
names(kernelAttr$upperBound)[indices] = rep(paramName, hpLen)
}
attr(kernelAttr, 'type') = type
class(kernelAttr) = 'sde_kernel'
kernelAttr
}
create_kernel_pointer.sde_kernel = function(kernel) {
parameters = kernel
parameters = c(parameters, kernel$hyperparams)
create_kernel_pointer.default(attr(kernel, 'type'), parameters,
kernel$inputDimension, kernel$epsilon,
kernel$lowerBound, kernel$upperBound)
}
#' Covariance matrix
#'
#' Computes the covariance matrix of the input vectors represented with
#' matrices (in which each row represents an input vector).
#'
#' @param kernel An object representing a gaussian process' kernel, e.g. a
#' \emph{sde_kernel} object.
#' @param x,y A matrix in which each row represents an input vector. Note that
#' if the inputs are univariate, a matrix with just one column should
#' be used.
#' @export
covmat = function(kernel, x, y) {
UseMethod("covmat", kernel)
}
#' @export
covmat.sde_kernel = function(kernel, x, y) {
kernelPointer = create_kernel_pointer(kernel)
kernelPointer$covmat(x, y)
}
#' @export
covmat.default = function(kernel, x, y) {
# use default function to join in a single entry all the kernel pointers
if (!is_valid_kernel_pointer(kernel)) {
stop("A C++ kernel pointer was expected")
}
kernel$covmat(x, y)
}
#' Autocovariance matrix
#'
#' Computes the autocovariance matrix of the input vectors represented with
#' a matrix (in which each row represents an input vector).
#'
#' @inheritParams covmat
#' @export
autocovmat = function(kernel, x) {
UseMethod("autocovmat", kernel)
}
#' @export
autocovmat.sde_kernel = function(kernel, x) {
kernelPointer = create_kernel_pointer(kernel)
kernelPointer$autocovmat(x)
}
#' @export
autocovmat.default = function(kernel, x) {
# use default function to join in a single entry all the kernel pointers
if (!is_valid_kernel_pointer(kernel)) {
stop("A C++ kernel pointer was expected")
}
kernel$autocovmat(x)
}
#' Variance vector
#'
#' Calculates the variances of each of the input vectors represented with
#' a matrix (in which each row represents an input vector).
#'
#' @inheritParams autocovmat
#' @export
vars = function(kernel, x) {
UseMethod("vars", kernel)
}
#' @export
vars.sde_kernel = function(kernel, x) {
kernelPointer = create_kernel_pointer(kernel)
kernelPointer$vars(x)
}
#' @export
vars.default = function(kernel, x) {
# use default function to join in a single entry all the kernel pointers
if (!is_valid_kernel_pointer(kernel)) {
stop("A C++ kernel pointer was expected")
}
kernel$vars(x)
}
#' Get the hyperparameters of a kernel
#' @inheritParams autocovmat
#' @export
get_hyperparams = function(kernel) {
UseMethod("get_hyperparams", kernel)
}
#' @export
get_hyperparams.sde_kernel = function(kernel) {
kernel$hyperparams
}
#' Set the hyperparameters of a kernel
#' @inheritParams autocovmat
#' @param hyperparams The new hyperparameters of the kernel
#' @export
set_hyperparams = function(kernel, hyperparams) {
UseMethod("set_hyperparams", kernel)
}
#' @export
set_hyperparams.sde_kernel = function(kernel, hyperparams) {
if (is.list(hyperparams)) {
hyperparams = arrange_hyperparams_list(kernel, hyperparams)
} else {
# hyperparams is a vector: we assume default order.
# get name and sizes of the hyperparams
oldHp = get_hyperparams(kernel)
hpNames = names(oldHp)
hpDims = sapply(oldHp, length)
begin = c(1, head(cumsum(hpDims), -1) + 1)
end = begin + hpDims - 1
hyperparamsList = list()
for (i in seq_along(hpNames)) {
hyperparamsList[[ hpNames[i] ]] = hyperparams[ begin[i]:end[i] ]
}
hyperparams = hyperparamsList
}
# avoid replication of code using the hyperparameters' checks included in
# C++ code
kernelPointer = create_kernel_pointer(kernel)
kernelPointer$set_hyperparams(as.numeric(unlist(hyperparams)))
# if no exception is given the parameters are correct...
kernel$hyperparams = hyperparams
kernel
}
#' @export
set_hyperparams.default = function(kernel, hyperparams) {
# use default function to join in a single entry all the kernel pointers
if (!is_valid_kernel_pointer(kernel)) {
stop("A C++ kernel pointer was expected")
}
kernel$set_hyperparams(as.numeric(unlist(hyperparams)))
kernel
}
#' Decreases the upper bound of the kernel
#'
#' Decreases the maximum values that each of the hyperparameters of the kernel
#' may take.
#'
#' @inheritParams autocovmat
#' @param upperBound A vector with the new values of the upper bound.
#' @export
decrease_upper_bound = function(kernel, upperBound) {
UseMethod("decrease_upper_bound", kernel)
}
#' @export
decrease_upper_bound.sde_kernel = function(kernel, upperBound) {
upperBound = arrange_hyperparams_list(kernel, upperBound)
# avoid replication of code using the checks included in C++ code
kernelPointer = create_kernel_pointer(kernel)
kernelPointer$decrease_upper_bound(as.numeric(upperBound))
# if no exception is given the parameters are correct...
kernel$upperBound = upperBound
kernel
}
#' Decreases the lower bound of the kernel
#'
#' Decreases the minimum values that each of the hyperparameters of the kernel
#' may take.
#'
#' @inheritParams autocovmat
#' @param lowerBound A vector with the new values of the lower bound.
#' @export
increase_lower_bound = function(kernel, lowerBound) {
UseMethod("increase_lower_bound", kernel)
}
#' @export
increase_lower_bound = function(kernel, lowerBound) {
lowerBound = arrange_hyperparams_list(kernel, lowerBound)
# avoid replication of code using the checks included in C++ code
kernelPointer = create_kernel_pointer(kernel)
kernelPointer$increase_lower_bound(as.numeric(lowerBound))
# if no exception is given the parameters are correct...
kernel$lowerBound = lowerBound
kernel
}
arrange_hyperparams_list = function(kernel, hyperparams) {
if ((length(names(hyperparams)) < length(kernel$hyperparams)) ||
!all(names(hyperparams) %in% names(kernel$hyperparams))) {
stop(paste0("Missing hyperparameter in 'hyperparams'. ",
"The following NAMED hyperparameters must be present: c('",
paste0(collapse = "', '", names(kernel$hyperparams))),
"')")
}
hyperparams[names(kernel$hyperparams)]
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.