R/fHMM_controls.R

Defines functions print.fHMM_controls set_controls

Documented in print.fHMM_controls set_controls

#' Set and validate controls
#' 
#' @description
#' This function sets and validates the specification of controls for model 
#' estimation with the \{fHMM\} package.
#' 
#' @details
#' See the vignettes for more details on how to specify \code{controls}.
#' 
#' @param controls
#' A \code{list} of controls, see below.
#' 
#' Either none, all, or selected parameters can be specified.
#' Unspecified parameters are set to default values 
#' (see the values in brackets below).
#' 
#' If \code{hierarchy = TRUE}, parameters marked with a \code{(*)} must be a 
#' \code{vector} of length 2, where the first entry corresponds to the 
#' coarse-scale and the second entry to the fine-scale layer.
#' 
#' \itemize{
#'   \item \code{hierarchy} (\code{FALSE}):
#'   A \code{logical}, set to \code{TRUE} for an hierarchical HMM.
#'   \item \code{states} \code{(*)} (\code{2}):
#'   An \code{integer}, the number of states of the underlying Markov chain.
#'   \item \code{sdds} \code{(*)} (\code{"t(df = Inf)"}):
#'   A \code{character}, specifying the state-dependent distribution.
#'   One of \code{"t"} (the t-distribution), or \code{"gamma"} 
#'   (the gamma distribution), or \code{"lnorm"} (the log-normal distribution).
#'   You can fix the parameters (mean \code{mu}, standard deviation 
#'   \code{sigma}, degrees of freedom \code{df}) of these distributions via, 
#'   e.g., \code{"t(df = Inf)"} or \code{"gamma(mu = 0, sigma = 1)"}.
#'   To fix different values of a parameter for different states, separate by
#'   "|", e.g. \code{"t(mu = -1|1)"}.
#'   \item \code{horizon} \code{(*)} (\code{100}):
#'   A \code{numeric}, specifying the length of the time horizon. 
#'   The first entry of \code{horizon} is ignored if \code{data} is specified.
#'   \item \code{period} (\code{"m"}):
#'   Only relevant if \code{hierarchy = TRUE} and 
#'   \code{horizon[2] = NA}.
#'   In this case, a \code{character} which specifies a flexible, periodic 
#'   fine-scale time horizon and can be one of
#'   \itemize{
#'     \item \code{"w"} for a week,
#'     \item \code{"m"} for a month,
#'     \item \code{"q"} for a quarter,
#'     \item \code{"y"} for a year.
#'   }
#'   \item \code{data} (\code{NA}): A \code{list} of controls specifying the 
#'   data. If \code{data = NA}, data gets simulated (default). Otherwise:
#'   \itemize{
#'     \item \code{file} \code{(*)}: Either:
#'     \itemize{
#'       \item A \code{data.frame}, which must have a column named 
#'             \code{date_column} (with dates) and
#'             \code{data_column} (with financial data). 
#'             If \code{hierarchy = TRUE}, this \code{data.frame} is used for
#'             both the coarse- and the fine-scale layer. To have different 
#'             data sets for theses layers, \code{file} can be a \code{list}
#'             of two \code{data.frame}.
#'       \item A \code{character}, the path to a .csv-file with financial data, 
#'             which must have a column named \code{date_column} (with dates) 
#'             and \code{data_column} (with financial data).
#'     }
#'     \item \code{date_column} \code{(*)} (\code{"Date"}):
#'     A \code{character}, the name of the column in \code{file} with dates. 
#'     Can be \code{NA} in which case consecutive integers are used 
#'     as time points.
#'     \item \code{data_column} \code{(*)} (\code{"Close"}):
#'     A \code{character}, the name of the column in \code{file} with financial 
#'     data.
#'     \item \code{from} (\code{NA}):
#'     A \code{character} of the format \code{"YYYY-MM-DD"}, setting a lower 
#'     data limit. No lower limit if \code{from = NA}. Ignored if
#'     \code{controls$data$date_column} is \code{NA}.
#'     \item \code{to} (\code{NA}):
#'     A \code{character} of the format \code{"YYYY-MM-DD"}, setting an upper 
#'     data limit. No upper limit if \code{from = NA}. Ignored if
#'     \code{controls$data$date_column} is \code{NA}.
#'     \item \code{logreturns} \code{(*)} (\code{FALSE}):
#'     A \code{logical}, if \code{TRUE} the data is transformed to log-returns.
#'     \item \code{merge} (\code{function(x) mean(x)}):
#'     Only relevant if \code{hierarchy = TRUE}. In this case, a \code{function}
#'     with one argument \code{x},
#'     which merges a numeric vector of fine-scale data \code{x} into one
#'     coarse-scale observation. For example,
#'     \itemize{
#'       \item \code{merge = function(x) mean(x)} defines the mean of the
#'       fine-scale data as the coarse-scale observation,
#'       \item \code{merge = function(x) mean(abs(x))} for the mean of the
#'       absolute values,
#'       \item \code{merge = function(x) sum(abs(x))} for the sum of the
#'       absolute values,
#'       \item \code{merge = function(x) (tail(x,1)-head(x,1))/head(x,1)} for
#'       the relative change of the first to the last fine-scale observation.
#'     }
#'   }
#'   \item \code{fit}: A \code{list} of controls specifying the model fitting:
#'   \itemize{
#'     \item \code{runs} (\code{100}):
#'     An \code{integer}, setting the number of randomly initialized 
#'     optimization runs from which the best one is selected as the final model.
#'     \item \code{origin} (\code{FALSE}):
#'     A \code{logical}, if \code{TRUE} the optimization is initialized at the 
#'     true parameter values. Only for simulated data. If \code{origin = TRUE}, 
#'     this sets \code{run = 1} and \code{accept = 1:5}.
#'     \item \code{accept} (\code{1:3}):
#'     An \code{integer} (vector), specifying which optimization runs are 
#'     accepted based on the output code of \code{\link[stats]{nlm}}.
#'     \item \code{gradtol} (\code{1e-6}):
#'     A positive \code{numeric} value, passed on to \code{\link[stats]{nlm}}.
#'     \item \code{iterlim} (\code{200}):
#'     A positive \code{integer}, passed on to \code{\link[stats]{nlm}}.
#'     \item \code{print.level} (\code{0}):
#'     One of \code{0}, \code{1}, and \code{2} to control the verbosity of the 
#'     optimization, passed on to \code{\link[stats]{nlm}}.
#'     \item \code{steptol} (\code{1e-6}):
#'     A positive \code{numeric} value, passed on to \code{\link[stats]{nlm}}.
#'   }
#' }
#' 
#' @return
#' An object of class \code{fHMM_controls}.
#' 
#' @examples
#' ### HMM controls for simulation
#' controls <- list(
#'   states  = 2,
#'   sdds    = "t(mu = 0)",
#'   fit     = list("runs" = 50)
#' )
#' set_controls(controls)
#' 
#' ### HMM controls with empirical data 
#' data <- download_data("^GDAXI", file = NULL)
#' controls <- list(
#'   states  = 3,
#'   sdds    = "lnorm",
#'   data    = list(
#'     "file"        = data, 
#'     "date_column" = "Date", 
#'     "data_column" = "Adj.Close"
#'   )
#' )
#' set_controls(controls)
#' 
#' ### HMM controls with empirical data from .csv-file
#' controls <- list(
#'   states  = 4,
#'   sdds    = "t",
#'   data    = list(
#'     "file"        = system.file("extdata", "dax.csv", package = "fHMM"), 
#'     "date_column" = "Date", 
#'     "data_column" = "Close",
#'     "logreturns"  = TRUE
#'   )
#' )
#' set_controls(controls)
#'
#' ### HHMM controls for simulation
#' controls <- list(
#'   hierarchy = TRUE,
#'   states    = c(3, 2)
#' )
#' set_controls(controls)
#' 
#' ### HHMM controls with empirical data
#' controls <- list(
#'   hierarchy = TRUE,
#'   states  = c(3, 2),
#'   sdds    = c("t", "t"),
#'   data    = list(
#'     "file"        = list(dax, vw), 
#'     "date_column" = c("Date", "Date"), 
#'     "data_column" = c("Close", "Close"),
#'     "logreturns"  = c(TRUE, TRUE)
#'   )
#' )
#' set_controls(controls)
#' 
#' @export
#' 
#' @importFrom utils read.csv

set_controls <- function(controls = NULL) {
  
  ### check if controls already is an 'fHMM_controls' object
  if (!inherits(controls,"fHMM_controls")) {
    ### initialize controls
    if (is.null(controls)) {
      controls <- list()
    }
    if (!is.list(controls)) {
      stop("Input 'controls' must be a list.", call. = FALSE)
    }

    ### define names of all controls
    all_controls <- c("hierarchy", "states", "sdds", "horizon", "period", "data", "fit")
    data_controls <- c("file", "date_column", "data_column", "from", "to", "logreturns", "merge")
    fit_controls <- c("runs", "origin", "accept", "gradtol", "iterlim", "print.level", "steptol")

    ### check redundant controls
    if (length(controls) > 0) {
      redundant_controls <- setdiff(names(controls), all_controls)
      if (length(redundant_controls) > 0) {
        warning(
          "Element(s) ", paste(redundant_controls, collapse = ", "), 
          " in 'controls' ignored.", 
          " Did you missplled it?",
          call. = FALSE
        )
        controls[redundant_controls] <- NULL
      }
      if (!is.null(controls[["data"]])) {
        redundant_controls <- setdiff(names(controls[["data"]]), data_controls)
        if (length(redundant_controls) > 0) {
          warning(
            "Element(s) ", paste(redundant_controls, collapse = ", "), 
            " in 'controls$data' ignored.", 
            " Did you missplled it?",
            call. = FALSE
          )
          controls[["data"]][redundant_controls] <- NULL
        }
      }
      if (!is.null(controls[["fit"]])) {
        redundant_controls <- setdiff(names(controls[["fit"]]), fit_controls)
        if (length(redundant_controls) > 0) {
          warning(
            "Element(s) ", paste(redundant_controls, collapse = ", "), 
            " in 'controls$fit' ignored.", 
            " Did you missplled it?",
            call. = FALSE
          )
          controls[["fit"]][redundant_controls] <- NULL
        }
      }
    }
  }

  ### set missing controls to default control values
  if (!"hierarchy" %in% names(controls)) {
    controls[["hierarchy"]] <- FALSE
  }
  if (!isTRUE(controls[["hierarchy"]]) && !isFALSE(controls[["hierarchy"]])) {
    stop("The control 'hierarchy' must be a TRUE or FALSE.", call. = FALSE)
  }
  if (!"states" %in% names(controls)) {
    controls[["states"]] <- if (controls[["hierarchy"]]) c(2, 2) else 2
  }
  if (!"sdds" %in% names(controls)) {
    controls[["sdds"]] <- if (controls[["hierarchy"]]) c("t", "t") else "t"
  }
  if (!"horizon" %in% names(controls)) {
    if (!"period" %in% names(controls)) {
      controls[["horizon"]] <- if (controls[["hierarchy"]]) c(100, 30) else 100
    } else {
      controls[["horizon"]] <- if (controls[["hierarchy"]]) c(NA_integer_, NA_integer_) else NA_integer_
    }
  }
  if (!"period" %in% names(controls)) {
    controls[["period"]] <- "m"
  }
  if (!"data" %in% names(controls) || identical(controls[["data"]], NA)) {
    controls[["data"]] <- NA
    controls[["simulated"]] <- TRUE
  } else {
    if (!"file" %in% names(controls[["data"]])) {
      controls[["data"]][["file"]] <- if (controls[["hierarchy"]]) {
        c(NA_character_, NA_character_) 
      } else {
        NA_character_
      }
      controls[["simulated"]] <- TRUE
    } else {
      controls[["simulated"]] <- FALSE
      if (!"date_column" %in% names(controls[["data"]])) {
        controls[["data"]][["date_column"]] <- if (controls[["hierarchy"]]) c("Date", "Date") else "Date"
      }
      if (!"data_column" %in% names(controls[["data"]])) {
        controls[["data"]][["data_column"]] <- if (controls[["hierarchy"]]) c("Close", "Close") else "Close"
      }
      if (!"from" %in% names(controls[["data"]])) {
        controls[["data"]][["from"]] <- NA_character_
      }
      if (!"to" %in% names(controls[["data"]])) {
        controls[["data"]][["to"]] <- NA_character_
      }
      if (!"logreturns" %in% names(controls[["data"]])) {
        controls[["data"]][["logreturns"]] <- if (controls[["hierarchy"]]) c(FALSE, FALSE) else FALSE
      }
      if (!"merge" %in% names(controls[["data"]])) {
        controls[["data"]][["merge"]] <- function(x) mean(x)
      }
    }
  }
  if (!"fit" %in% names(controls)) {
    controls[["fit"]] <- list()
  }
  if (!"runs" %in% names(controls[["fit"]])) {
    controls[["fit"]][["runs"]] <- 100
  }
  if (!"origin" %in% names(controls[["fit"]])) {
    controls[["fit"]][["origin"]] <- FALSE
  }
  if (!"accept" %in% names(controls[["fit"]])) {
    controls[["fit"]][["accept"]] <- 1:3
  }
  if (!"gradtol" %in% names(controls[["fit"]])) {
    controls[["fit"]][["gradtol"]] <- 1e-6
  }
  if (!"iterlim" %in% names(controls[["fit"]])) {
    controls[["fit"]][["iterlim"]] <- 200
  }
  if (!"print.level" %in% names(controls[["fit"]])) {
    controls[["fit"]][["print.level"]] <- 0
  }
  if (!"steptol" %in% names(controls[["fit"]])) {
    controls[["fit"]][["steptol"]] <- 1e-6
  }

  ### check single controls
  if (controls[["hierarchy"]]) {
    ### controls with hierarchy
    if (!(all(is_number(controls[["states"]], int = TRUE)) &&
      length(controls[["states"]]) == 2 && all(controls[["states"]] >= 2))) {
      stop("The control 'states' must be a vector of length 2 containing integers greater or equal 2.",
           call. = FALSE)
    }
    if (!controls[["simulated"]]) {
      controls[["horizon"]][1] <- NA_integer_
    }
    if (is.na(controls[["horizon"]][1])) {
      controls[["horizon"]][1] <- NA_integer_
    }
    if (is.na(controls[["horizon"]][2])) {
      controls[["horizon"]][2] <- NA_integer_
    }
    if (all(is.na(controls[["horizon"]]))) {
      if (length(controls[["horizon"]]) != 2) {
        stop("The control 'horizon' must be a vector of length 2.",
            call. = FALSE)
      }
    } else if (!(length(controls[["horizon"]]) == 2 && all(is_number(controls[["horizon"]][!is.na(controls[["horizon"]])], int = TRUE, pos = TRUE)))) {
      stop("The control 'horizon' must be an integer vector of length 2.",
           call. = FALSE)
    }
    if (!is.na(controls[["horizon"]][2])) {
      controls[["period"]] <- NA
    }
    if (!is.na(controls[["period"]])) {
      if (!controls[["period"]] %in% c("w", "m", "q", "y")) {
        stop("The control 'period' must be eiter 'NA' or one of 'w', 'm', 'q', 'y'.",
             call. = FALSE)
      }
    }
  } else {
    ### controls without hierarchy
    if (!(is_number(controls[["states"]], int = TRUE) &&
      length(controls[["states"]]) == 1 && all(controls[["states"]] >= 2))) {
      stop("The control 'states' must be an integer greater or equal 2.",
           call. = FALSE)
    }
    if (!controls[["simulated"]]) {
      controls[["horizon"]] <- NA
    } else {
      if (!(length(controls[["horizon"]]) == 1 && is_number(controls[["horizon"]], int = TRUE, pos = TRUE))) {
        stop("The control 'horizon' must be an integer.",
             call. = FALSE)
      }
    }
    controls[["period"]] <- NA
    controls[["data"]][["merge"]] <- NA
  }
  if (!inherits(controls[["sdds"]], "fHMM_sdds")) {
    if (!is.character(controls[["sdds"]]) ||
      length(controls[["sdds"]]) != ifelse(controls[["hierarchy"]], 2, 1)) {
      stop(
        "The control 'sdds' must be a character ",
        if (controls[["hierarchy"]]) "vector ", "of length ",
        ifelse(controls[["hierarchy"]], 2, 1), ".",
        call. = FALSE
      )
    }
    controls[["sdds"]] <- fHMM_sdds(sdds = controls[["sdds"]])
  }

  ### check 'data' controls
  if (controls[["simulated"]]) {
    controls[["data"]] <- NA
  } else {
    if (controls[["hierarchy"]]) {
      ### controls with hierarchy
      if (is.data.frame(controls[["data"]][["file"]])) {
        controls[["data"]][["file"]] <- list(controls[["data"]][["file"]], controls[["data"]][["file"]])
        controls[["data"]][["data_inside"]] <- TRUE
      } else if (is.list(controls[["data"]][["file"]])) {
        data_list <- controls[["data"]][["file"]]
        if (length(data_list) != 2) {
          stop("The control 'file' in 'data' must be a list of length two.",
               call. = FALSE)
        }
        if (!all(sapply(data_list, is.data.frame))) {
          stop("The control 'file' in 'data' must be a list of two data.frame.",
               call. = FALSE)
        }
        controls[["data"]][["data_inside"]] <- TRUE
      } else {
        controls[["data"]][["data_inside"]] <- FALSE
        if (!(is.character(controls[["data"]][["file"]]) && length(controls[["data"]][["file"]]) == 2)) {
          stop("The control 'file' in 'data' must be a character vector of length two.",
              call. = FALSE)
        }
      }
      if (!(all(is.na(controls[["data"]][["date_column"]])) || (all(!is.na(controls[["data"]][["date_column"]])) && all(is.character(controls[["data"]][["date_column"]]))) &&
        length(controls[["data"]][["date_column"]]) == 2)) {
        stop("The control 'date_column' in 'data' must be a vector with two characters or two NA's.",
             call. = FALSE)
      }
      if (!(all(!is.na(controls[["data"]][["data_column"]])) && is.character(controls[["data"]][["data_column"]]) && length(controls[["data"]][["data_column"]]) == 2)) {
        stop("The control 'data_column' in 'data' must be a character vector of length two.",
             call. = FALSE)
      }
      if (!(is.logical(controls[["data"]][["logreturns"]]) && length(controls[["data"]][["logreturns"]]) == 2)) {
        stop("The control 'logreturns' in 'data' must be a boolean vector of length two.",
             call. = FALSE)
      }
      if (!is.function(controls[["data"]][["merge"]])) {
        stop("The control 'merge' in 'data' must be of class 'function'.",
             call. = FALSE)
      }
      try_merge <- try(controls[["data"]][["merge"]](-10:10), silent = TRUE)
      if (inherits(try_merge,"try-error") || !is.numeric(try_merge) || length(try_merge) != 1) {
        stop("The controls 'merge' in 'data' must merge a numeric vector into a single numeric value.",
             call. = FALSE)
      }
    } else {
      ### controls without hierarchy
      if (is.data.frame(controls[["data"]][["file"]])) {
        controls[["data"]][["file"]] <- list(controls[["data"]][["file"]])
        controls[["data"]][["data_inside"]] <- TRUE
      } else {
        controls[["data"]][["data_inside"]] <- FALSE
        if (!(is.character(controls[["data"]][["file"]]) && length(controls[["data"]][["file"]]) == 1)) {
          stop("The control 'file' in 'data' must be a character.",
               call. = FALSE)
        }
      }
      if (!((is.character(controls[["data"]][["date_column"]]) || is.na(controls[["data"]][["date_column"]])) && length(controls[["data"]][["date_column"]]) == 1)) {
        stop("The control 'date_column' in 'data' must be a character or NA.",
             call. = FALSE)
      }
      if (!(is.character(controls[["data"]][["data_column"]])) && length(controls[["data"]][["data_column"]]) == 1) {
        stop("The control 'data_column' in 'data' must be a character or NA.",
             call. = FALSE)
      }
      if (!(is.logical(controls[["data"]][["logreturns"]])) && length(controls[["data"]][["logreturns"]]) == 1) {
        stop("The control 'logreturns' in 'data' must be a boolean.",
             call. = FALSE)
      }
      controls[["data"]][["merge"]] <- NA
    }
    if (all(is.na(controls[["data"]][["date_column"]]))) {
      controls[["data"]][["from"]] <- NA_character_
      controls[["data"]][["to"]] <- NA_character_
    }
    if (!is.na(controls[["data"]][["from"]])) {
      controls[["data"]][["from"]] <- check_date(controls[["data"]][["from"]])
    }
    if (!is.na(controls[["data"]][["to"]])) {
      controls[["data"]][["to"]] <- check_date(controls[["data"]][["to"]])
    }
  }

  ### check 'fit' controls
  if (!is_number(controls[["fit"]][["runs"]], int = TRUE, pos = TRUE)) {
    stop("The control 'runs' in 'fit' must be an integer.", 
         call. = FALSE)
  }
  if (!isTRUE(controls[["fit"]][["origin"]]) && 
      !isFALSE(controls[["fit"]][["origin"]])) {
    stop("The control 'origin' in 'fit' must be a boolean.",
         call. = FALSE)
  }
  if (controls[["fit"]][["origin"]]) {
    controls[["fit"]][["runs"]] <- 1
    controls[["fit"]][["accept"]] <- 1:5
  }
  if (any(controls[["fit"]][["accept"]] == "all")) {
    controls[["fit"]][["accept"]] <- 1:5
  }
  if (!all(controls[["fit"]][["accept"]] %in% 1:5)) {
    stop("The control 'accept' in 'fit' must be vector of integers from 1 to 5.",
         call. = FALSE)
  }
  if (!(length(controls[["fit"]][["gradtol"]]) == 1 && is_number(controls[["fit"]][["gradtol"]], pos = TRUE))) {
    stop("The control 'gradtol' in 'fit' must be positive numeric value.",
         call. = FALSE)
  }
  if (!(length(controls[["fit"]][["iterlim"]]) == 1 && is_number(controls[["fit"]][["iterlim"]], int = TRUE, pos = TRUE))) {
    stop("The control 'iterlim' in 'fit' must be a positive integer.",
         call. = FALSE)
  }
  if (!(length(controls[["fit"]][["print.level"]]) == 1 && controls[["fit"]][["print.level"]] %in% 0:2)) {
    stop("The control 'print.level' in 'fit' must be one of 0, 1, and 2.",
         call. = FALSE)
  }
  if (!(length(controls[["fit"]][["steptol"]]) == 1 && is_number(controls[["fit"]][["steptol"]], pos = TRUE))) {
    stop("The control 'steptol' in 'fit' must be positive numeric value.",
         call. = FALSE)
  }

  ### check if data paths and column names are correct
  if (!controls[["simulated"]]) {
    indices <- if (controls[["hierarchy"]]) 1:2 else 1
    for (i in indices) {
      if (controls[["data"]][["data_inside"]]) {
        data <- controls[["data"]][["file"]][[i]]
        if (!is.na(controls[["data"]][["date_column"]][i])) {
          if (!controls[["data"]][["date_column"]][i] %in% colnames(data)) {
            stop("Date column '", controls[["data"]][["date_column"]][i], 
                 "' not found in supplied data.frame.",
                 call. = FALSE)
          }
        }
        if (!controls[["data"]][["data_column"]][i] %in% colnames(data)) {
          stop("Data column '", controls[["data"]][["data_column"]][i], 
               "' not found in supplied data.frame.",
               call. = FALSE)
        }
        
      } else {
        controls[["data"]][["file"]][i] <- suppressWarnings(normalizePath(controls[["data"]][["file"]][i]))
        if (!file.exists(controls[["data"]][["file"]][i])) {
          stop("File '", controls[["data"]][["file"]][i], "' not found.",
              call. = FALSE)
        }
        read_try <- suppressWarnings(
          try(utils::read.csv(file = controls[["data"]][["file"]][i]), silent = TRUE)
        )
        if (inherits(read_try,"try-error")) {
          stop("Unable to read '", controls[["data"]][["file"]][i], "'.",
              call. = FALSE)
        }
        if (!is.na(controls[["data"]][["date_column"]][i])) {
          if (!controls[["data"]][["date_column"]][i] %in% colnames(read_try)) {
            stop("Date column '", controls[["data"]][["date_column"]][i], "' not found in '", 
                 controls[["data"]][["file"]][i], "'.",
                 call. = FALSE)
          }
        }
        if (!controls[["data"]][["data_column"]][i] %in% colnames(read_try)) {
          stop("Data column '", controls[["data"]][["data_column"]][i], 
               "' not found in '", controls[["data"]][["file"]][i], "'.",
               call. = FALSE)
        }
      }
    }
  }

  ### return controls
  class(controls) <- "fHMM_controls"
  return(controls)
}

#' @rdname set_controls
#' @param x
#' An object of class \code{fHMM_controls}.
#' @param ...
#' Currently not used.
#' @exportS3Method 

print.fHMM_controls <- function(x, ...) {
  cat("fHMM controls:\n")
  cat("* hierarchy:", x[["hierarchy"]], "\n")
  cat("* data type:", ifelse(x[["simulated"]], "simulated", "empirical"), "\n")
  cat("* number of states:", x[["states"]], "\n")
  cat("* sdds: ")
  print(x[["sdds"]])
  cat("\n")
  cat(
    "* number of runs:", x[["fit"]][["runs"]],
    ifelse(x[["fit"]][["at_true"]], "(initialised at true values)", ""), "\n"
  )
  invisible(x)
}

Try the fHMM package in your browser

Any scripts or data that you put into this service are public.

fHMM documentation built on Oct. 12, 2023, 5:10 p.m.