validate_args_compare <-
  function(true_mean,
           true_method = true_method,
           true_method_args = true_method_args,
           true_covariance,
           true_X,
           true_data,
           theta,
           n,
           reps,
           prog,
           err_dist_fun,
           err_dist_args,
           keep,
           manual,
           update_args,
           arg_list){
    if(is.function(true_mean) && !is.null(true_data)){
      stop("true_data must not be supplied when true_mean is a function")
    }
    
    if(is(true_mean, "formula")){
      strict_match(arg = true_method, choices = valid_model_methods())
      if(!is.null(true_method_args) && !is.list(true_method_args))
        stop("true_method_args must be NULL or a list")
      if(is.null(true_data)) stop("true_data must be supplied when true_mean is a formula")
      if(!is.null(theta)) stop("theta must be NULL when true_mean is 'formula'")
    } else {
      if(!is.null(true_method)) stop("true_method must be NULL when true_mean is not a formula")
      if(!is.null(true_method_args)) stop("true_method_args must be NULL when true_mean is not a formula")
      if(!is.function(true_mean)){
        if(!is.null(true_data)) stop("true_data must be NULL when true_mean is a model object")
      }
    }
    
    if(!is.null(theta) && isModel(true_mean))
      stop("theta must be NULL when true_mean is a model object")

    test_mean <- arg_list[["test_mean"]]
    if(is.null(test_mean)) stop("test_mean must be specified")
    data <- arg_list[["data"]]
    X <- arg_list[["X"]]
    
    if(!is.null(arg_list[["Y"]])){
      warning("Y supplied to compare() is ignored")
      arg_list[["Y"]] <- NULL
    }
    
    
    if(!is.null(data)){
      if(is.matrix(data)){
        data <- as.data.frame(data)
      } else {
        if(!is.data.frame(data)) stop("data must be a data frame or a matrix")
      }
      if(nrow(data) == 0) stop("data cannot be an empty matrix or data frame")
    }
    
    # Check for appropriate test covariate specification.
    if(isModel(test_mean) && !is.null(data)){
      stop("data must be NULL when test_mean is a model object")
    }
    if(is.function(test_mean)){
      if(isTRUE("x" %in% names(formals(test_mean))) && is.null(X))
        stop("X must be specified when test_mean is a function with an 'x' argument")
    }
    
    test_mean_formula <- tryCatch(formula(test_mean), error = function(e) NULL)
    
    if(is(test_mean_formula, "formula")){
      if(!is.null(X)) stop("X must be NULL when test_mean has a formula method")
      if(is(test_mean, "formula") && is.null(data))
        stop("data must be supplied when test_mean is a formula")
      test_Y <- tryCatch(get_response(test_mean),
                         error = function(e) warning("Error in extracting response variable name: ", e))
      stopifnot("Response variable name not found in test_mean object's formula" = !is.null(test_Y),
                "Response variable name found in test_mean object is not a character!" = is.character(test_Y))
      if(length(test_Y) != 1) stop("Response in test_mean object must be exactly one term")
      data_for_verifying_y <- if(is.null(data)) get_data(test_mean, generation = 3) else data
      if(!(test_Y %in% colnames(data_for_verifying_y))) stop("Response variable '", test_Y, "' not found in data")
    } else {
      if(!is.null(data)) stop("data must be NULL when test_mean has no formula method")
      test_Y <- NULL
    }
    
    if(!is.null(X)){
      validate_numeric(x = X)
      X <- as.matrix(X)
    }
    
    if(is.function(true_mean)){
      if(is.null(true_X)){
        if(any(c("x", "X") %in% names(formals(true_mean))))
          stop("true_mean must have neither 'x' nor 'X' as an argument when true_X is NULL")
      } else {
        if(!(any(c("x", "X") %in% names(formals(true_mean)))))
          stop("true_mean must have 'x' or 'X' as an argument when true_X is not NULL")
        validate_numeric(x = true_X)
        true_X <- as.matrix(true_X)
      }
    } else {
      if(!is.null(true_X)) stop("true_X must be NULL if true_mean is not a function")
    }
    
    # Determine n    
    if(!is.null(n)){
      validate_numeric(x = n, pos_int = TRUE, len = 1)
      n <- as.integer(n)
    }
    n <- get_n(n = n, true_X = true_X, X = X, true_data = true_data,
               data = data, true_mean = true_mean, test_mean = test_mean)
    
    # Define default sym_tol value if NULL.
    if(is.null(arg_list[["control"]][["sym_tol"]])){
      sym_tol <- default_distfreereg_tol()[["sym_tol"]]
    } else {
      sym_tol <- arg_list[["control"]][["sym_tol"]]
    }
    validate_numeric(sym_tol, positive = TRUE, len = 1)
    
    # Define default sym_tol1 value if NULL.
    if(is.null(arg_list[["control"]][["sym_tol1"]])){
      sym_tol1 <- default_distfreereg_tol()[["sym_tol1"]]
    } else {
      sym_tol1 <- arg_list[["control"]][["sym_tol1"]]
    }
    validate_numeric(sym_tol1, positive = TRUE, len = 1)
    
    # Validate format of covariance lists.
    if(is.function(true_mean) || is(true_mean, "nls") || identical(true_method, "nls")){
      if(is.null(true_covariance))
        stop("'true_covariance' must be specified when 'true_mean' is a function or nls object, ",
             "or 'true_method' is 'nls'")
      validate_covariance_list(true_covariance, n = n, sym_tol = sym_tol,
                               sym_tol1 = sym_tol1)
    } else {
      if(!is.null(true_covariance))
        stop("'true_covariance' must be NULL when 'true_mean' is neither a function nor nls object, ",
             "and 'true_method' is not 'nls'")
    }
    if(!is.null(arg_list[["covariance"]])){
      validate_covariance_list(arg_list[["covariance"]], n = n, sym_tol = sym_tol,
                               sym_tol1 = sym_tol1)
    }
    
    # Validate true mean function.
    if(is.function(true_mean)){
      validate_mean_function_arg_names(f = true_mean)
      validate_numeric(x = theta, min_len = 1)
      validate_function_behavior(f = true_mean, X = true_X, n = n, theta = theta)
    }
    
    
    # Validate other arguments.
    validate_numeric(x = reps, min_val = 0, len = 1)
    reps <- as.integer(reps)
    
    # Note that the following call to validate_numeric() prog does not use
    # pos_int, since the default value reps/10 is 0 for reps < 10, so only
    # require positive and then convert 0 to 1.
    validate_numeric(x = prog, finite = FALSE, positive = TRUE, len = 1)
    if(is.finite(prog)) prog <- as.integer(prog)
    if(prog == 0) prog <- 1
    
    # Check for compatibility of err_dist_fun and err_dist_args.
    if(is(true_mean, "function") || is(true_mean, "nls") || identical(true_method, "nls")){
      if(!is.null(err_dist_fun)){
        if(!is.character(err_dist_fun) || length(err_dist_fun) != 1){
          stop("'err_dist_fun' must be a character string of length 1")
        }
        err_dist_fun <- get(err_dist_fun)
        if(!isTRUE(is.function(err_dist_fun)))
          stop("'err_dist_fun' must specify a function")
      } else {
        err_dist_fun <- rmvnorm
      }
      if(!is.null(err_dist_args) && !is.list(err_dist_args))
        stop("'err_dist_args' must be a list")
    } else {
      if(!is.null(err_dist_fun)){
        stop("'err_dist_fun' must be NULL when class(true_mean) is ", paste(class(true_mean), collapse = ", "),
             if(is(true_mean, "formula")) " (unless 'true_method' is 'nls')")
      }
      if(!is.null(err_dist_args)){
        stop("'err_dist_args' must be NULL when class(true_mean) is ", paste(class(true_mean), collapse = ", "),
             if(is(true_mean, "formula")) " (unless 'true_method' is 'nls')")
      }
    }
    
    if(!is.null(keep) && !identical("all", keep)){
      if(!is.numeric(keep)){
        stop("keep_all must be NULL, 'all', or a vector of positive integers")
      } else {
        validate_numeric(keep, pos_int = TRUE, min_len = 1, max_len = reps,
                         min_val = 1, max_val = reps)
        keep <- sort(unique(keep))
      }
    }
    
    if(!is.null(manual) && !is.function(manual))
      stop("'manual' must be NULL or a function")
    
    # Define default matsqrt_tol value if NULL.
    if(is.null(arg_list[["control"]][["matsqrt_tol"]])){
      matsqrt_tol <- default_distfreereg_tol()[["matsqrt_tol"]]
    } else {
      matsqrt_tol <- arg_list[["control"]][["matsqrt_tol"]]
    }
    validate_numeric(matsqrt_tol, max_val = 0, len = 1)
    
    # Define default solve_tol value if NULL.
    if(is.null(arg_list[["control"]][["solve_tol"]])){
      solve_tol <- default_distfreereg_tol()[["solve_tol"]]
    } else {
      solve_tol <- arg_list[["control"]][["solve_tol"]]
    }
    validate_numeric(solve_tol, positive = TRUE, len = 1)
    
    return(list(reps = reps, prog = prog, true_X = true_X, test_mean = test_mean,
                X = X, test_Y = test_Y, data = data, n = n, err_dist_fun = err_dist_fun,
                keep = keep, arg_list = arg_list, solve_tol = solve_tol,
                matsqrt_tol = matsqrt_tol))
  }
